//------------------------------------------------------
        //
        //  Internal Methods
        //
        //------------------------------------------------------

        #region Internal Methods

        // Called by the Speller whenever document state changes.
        // Returns true if any new dirty runs are created.
        internal void OnTextChange(TextContainerChangeEventArgs e)
        {
            if (e.TextChange == TextChangeType.ContentAdded)
            {
                // Content was added.  Update the run list.
                OnContentAdded(e);
            }
            else if (e.TextChange == TextChangeType.ContentRemoved)
            {
                // Content was deleted.  Update the run list.
                OnContentRemoved(e.ITextPosition);
            }
            else
            {
                // Language or SpellingReform property changed.
                ITextPointer end = e.ITextPosition.CreatePointer(e.Count);
                end.Freeze();
                MarkDirtyRange(e.ITextPosition, end);
            }

            DebugAssertRunList();
        }
        // ------------------------------------------------------------------
        // Constructor
        //
        //      change - TextContainer change data.
        // ------------------------------------------------------------------
        internal DirtyTextRange(TextContainerChangeEventArgs change)
        {
            StartIndex = change.ITextPosition.Offset;

            PositionsAdded = 0;
            PositionsRemoved = 0;

            switch (change.TextChange)
            {
                case TextChangeType.ContentAdded:
                    PositionsAdded = change.Count;
                    break;

                case TextChangeType.ContentRemoved:
                    PositionsRemoved = change.Count;
                    break;

                case TextChangeType.PropertyModified:
                    PositionsAdded = change.Count;
                    PositionsRemoved = change.Count;
                    break;
            }
        }
        /// <summary>
        /// Handler for TextContainer change notifications.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void OnTextContainerChange(object sender, TextContainerChangeEventArgs args)
        {
            DirtyTextRange dtr;
            ITextPointer segmentEnd;

            Invariant.Assert(args != null);
            Invariant.Assert(sender == _structuralCache.TextContainer);
            Invariant.Assert(_structuralCache != null && _structuralCache.IsFormattedOnce, "Unexpected TextContainer.Change callback before first format!");

            if (args.Count == 0)
            {
                // A no-op for this control.  Happens when IMECharCount updates happen
                // without corresponding SymbolCount changes.
                return;
            }

            try
            {
                // Detect invalid content change operations.
                if (_structuralCache.IsFormattingInProgress)
                {
                    _structuralCache.OnInvalidOperationDetected();
                    throw new InvalidOperationException(SR.Get(SRID.FlowDocumentInvalidContnetChange));
                }

                // Since content is changeing, do partial invalidation of BreakRecordTable.
                if (args.TextChange != TextChangeType.ContentRemoved)
                {
                    segmentEnd = args.ITextPosition.CreatePointer(args.Count, LogicalDirection.Forward);
                }
                else
                {
                    segmentEnd = args.ITextPosition;
                }

                // Invalidate affected pages and break records.
                // We DTR invalidate if we're using a formatter as well for incremental update.
                if (!args.AffectsRenderOnly || (_formatter != null && _formatter is FlowDocumentFormatter))
                {
                    // Create new DTR for changing range and add it to DRTList.
                    dtr = new DirtyTextRange(args);
                    _structuralCache.AddDirtyTextRange(dtr);
                }
                else
                {
                    // Clear format caches.
                    _structuralCache.InvalidateFormatCache(/*Clear structure*/ false);
                }

                // Notify formatter about content invalidation.
                if (_formatter != null)
                {
                    _formatter.OnContentInvalidated(!args.AffectsRenderOnly, args.ITextPosition, segmentEnd);
                }
            }
            finally
            {
                // Content has been changed, so reset appropriate flag.
                _structuralCache.IsContentChangeInProgress = false;
            }
        }
Example #4
0
        private void OnTextContainerChange(object sender, TextContainerChangeEventArgs args)
        {
            if (args.IMECharCount > 0 && (args.TextChange == TextChangeType.ContentAdded || args.TextChange == TextChangeType.ContentRemoved))
            {
                _compositionModifiedByEventListener = true;
            }

            if (_compositionEventState == CompositionEventState.RaisingEvents)
            {
                return;
            }

            Invariant.Assert(sender == this.TextContainer);

#if ENABLE_INK_EMBEDDING
            // Record the offset of the first symbol in the document
            // affected by this edit.
            // Used by RemoveContent to track the effects of an edit.
            if (args.TextChange == TextChangeType.ContentRemoved &&
                _minSymbolsRemovedIndex > args.TextPosition.Offset)
            {
                _minSymbolsRemovedIndex = args.TextPosition.Offset;
            }
#endif

            // Don't send TSF events that it initiated (ie, while it holds a lock).
            if (_lockFlags == 0 && HasSink)
            {
                int charsAdded = 0;
                int charsRemoved = 0;

                if (args.TextChange == TextChangeType.ContentAdded)
                {
                    charsAdded = args.IMECharCount;
                }
                else if (args.TextChange == TextChangeType.ContentRemoved)
                {
                    charsRemoved = args.IMECharCount;
                }
                else
                {
                    // This is a TextChange.ContentAffected change, which we
                    // don't want to pass on to cicero.  Cicero doesn't care
                    // about DependencyProperty values, and we don't want it
                    // to invalidate cicero properties unless symbols were
                    // added or removed.
                }

                if (charsAdded > 0 || charsRemoved > 0)
                {
                    UnsafeNativeMethods.TS_TEXTCHANGE change;

                    change.start = args.ITextPosition.CharOffset;
                    change.oldEnd = change.start + charsRemoved;
                    change.newEnd = change.start + charsAdded;

                    ValidateChange(change);
                    // We can't call VerifyTextStoreConsistency() yet because more changes may be pending.

                    // 

                    try
                    {
                        _textChangeReentrencyCount++;
                        _sink.OnTextChange(0 /* flags */, ref change);
                    }
                    finally
                    {
                        _textChangeReentrencyCount--;
                    }
                }
            }
            else if (_isInUpdateLayout)
            {
                _hasTextChangedInUpdateLayout = true;
            }
        }
        // Called when content is added to the document.
        // Updates the run list with a new dirty region.
        private void OnContentAdded(TextContainerChangeEventArgs e)
        {
            ITextPointer start;
            ITextPointer end;

            // Expand the affected region by one char in either direction
            // to make sure we examine surrounding text that might be affected
            // by the addition of new whitespace.
            if (e.ITextPosition.Offset > 0)
            {
                start = e.ITextPosition.CreatePointer(-1);
            }
            else
            {
                start = e.ITextPosition;
            }
            start.Freeze();

            if (e.ITextPosition.Offset + e.Count < e.ITextPosition.TextContainer.SymbolCount - 1)
            {
                end = e.ITextPosition.CreatePointer(e.Count + 1);
            }
            else
            {
                end = e.ITextPosition.CreatePointer(e.Count);
            }
            end.Freeze();

            // Mark the new text dirty.
            MarkRange(start, end, RunType.Dirty);
        }
Example #6
0
        // ------------------------------------------------------------------
        // Handler for TextContainer changed notifications.
        // ------------------------------------------------------------------
        private void OnTextContainerChange(object sender, TextContainerChangeEventArgs args)
        {
            Invariant.Assert(args != null);

            if (_complexContent == null)
            {
                // This shouldn't ever happen (we only hook up this handler when we have complex
                // content)... except that it does happen, in cases where TextBlock is part of
                // a style that gets changed in response to TextContainer.Changed events.  In such a case,
                // we're an obsolete text control and we don't want to do anything, so just return.
                return;
            }
            Invariant.Assert(sender == _complexContent.TextContainer, "Received text change for foreign TextContainer.");

            if (args.Count == 0)
            {
                // A no-op for this control.  Happens when IMECharCount updates happen
                // without corresponding SymbolCount changes.
                return;
            }

            if (CheckFlags(Flags.FormattedOnce))
            {
                // Will throw an exception, if during measure/arrange/render process.
                VerifyTreeIsUnlocked();
                // Content has been changed, so reset appropriate flag.
                SetFlags(false, Flags.ContentChangeInProgress);
                // Invalidate measure in responce to invalidated content.
                InvalidateMeasure();
            }

            if (!CheckFlags(Flags.TextContentChanging) && args.TextChange != TextChangeType.PropertyModified)
            {
                SetFlags(true, Flags.TextContentChanging);
                try
                {
                    // Use a DeferredTextReference instead of calculating the new
                    // value now for better performance.  Most of the time no
                    // one cares what the new is, and loading our content into a
                    // string can be expensive.
                    SetDeferredValue(TextProperty, new DeferredTextReference(this.TextContainer));
                }
                finally
                {
                    SetFlags(false, Flags.TextContentChanging);
                }
            }
        }
Example #7
0
        // Callback for document changes. 
        // Marks appropriate sections of the document as dirty then posts
        // an idle request for future analysis. 
        private void OnTextContainerChange(object sender, TextContainerChangeEventArgs e) 
        {
            Invariant.Assert(sender == _textEditor.TextContainer); 

            if (e.Count == 0 ||
                (e.TextChange == TextChangeType.PropertyModified && !IsSpellerAffectingProperty(e.Property)))
            { 
                // Speller doesn't care about most property changes.
                return; 
            } 

            if (_failedToInit) 
            {
                // Speller engine is not available.
                return;
            } 

            if (_statusTable != null) 
            { 
                _statusTable.OnTextChange(e);
            } 

            ScheduleIdleCallback();
        }
Example #8
0
 private void OnTextContainerChange(object sender, TextContainerChangeEventArgs args)
 {
     if (args.IMECharCount > 0 && (args.TextChange == TextChangeType.ContentAdded || args.TextChange == TextChangeType.ContentRemoved))
     {
         _compositionModifiedByEventListener = true;
     }
 }
Example #9
0
        // Callback from the TextContainer on a document edit.
        private void OnTextContainerChange(object sender, TextContainerChangeEventArgs args)
        {
            if (args.Count == 0)
            {
                // A no-op for this control.  Happens when IMECharCount updates happen
                // without corresponding SymbolCount changes.
                return;
            }

            //
            // Add the change to our dirty list.
            //

            if (_dirtyList == null)
            {
                _dirtyList = new DtrList();
            }

            DirtyTextRange dirtyTextRange = new DirtyTextRange(args);
            _dirtyList.Merge(dirtyTextRange);

            //
            // Force a re-measure.
            //
            InvalidateMeasure();
        }
Example #10
0
        // Worker for AddChange, fires a Change event. 
        private void FireChangeEvent(TextPointer startPosition, TextPointer endPosition, int symbolCount,
                                     int leftEdgeCharCount, int childCharCount, 
                                     PrecursorTextChangeType precursorTextChange, DependencyProperty property, bool affectsRenderOnly)
        {
            Invariant.Assert(this.ChangeHandler != null);
 
            // Set a flag to disallow reentrant edits.  We really can't support
            // that here, because any edits to the document would break the 
            // BeginChange/EndChange contract (no edits by listeners in a change 
            // block!).
            // (Note, we will allow re-entrant property changes only, because 
            // property change events are not exposed publicly on TextBox or RTB.)
            SetFlags(true, Flags.ReadOnly);

            try 
            {
                if (precursorTextChange == PrecursorTextChangeType.ElementAdded) 
                { 
                    Invariant.Assert(symbolCount > 2, "ElementAdded must span at least two element edges and one content symbol!");
 
                    TextContainerChangeEventArgs args1 = new TextContainerChangeEventArgs(startPosition, 1, leftEdgeCharCount, TextChangeType.ContentAdded);
                    TextContainerChangeEventArgs args2 = new TextContainerChangeEventArgs(endPosition, 1, 0, TextChangeType.ContentAdded);
                    ChangeHandler(this, args1);
                    ChangeHandler(this, args2); 
                }
                else if (precursorTextChange == PrecursorTextChangeType.ElementExtracted) 
                { 
                    Invariant.Assert(symbolCount > 2, "ElementExtracted must span at least two element edges and one content symbol!");
 
                    TextContainerChangeEventArgs args1 = new TextContainerChangeEventArgs(startPosition, 1, leftEdgeCharCount, TextChangeType.ContentRemoved);
                    TextContainerChangeEventArgs args2 = new TextContainerChangeEventArgs(endPosition, 1, 0, TextChangeType.ContentRemoved);
                    ChangeHandler(this, args1);
                    ChangeHandler(this, args2); 
                }
                else 
                { 
                    TextContainerChangeEventArgs args = new TextContainerChangeEventArgs(startPosition, symbolCount, leftEdgeCharCount + childCharCount, ConvertSimplePrecursorChangeToTextChange(precursorTextChange), property, affectsRenderOnly);
                    ChangeHandler(this, args); 
                }
            }
            finally
            { 
                SetFlags(false, Flags.ReadOnly);
            } 
        }