Esempio n. 1
0
        // Token: 0x060038DB RID: 14555 RVA: 0x00100F94 File Offset: 0x000FF194
        private static ITextPointer GetNextTextPosition(ITextPointer position, ITextPointer limit, LogicalDirection direction, out char character)
        {
            bool flag = false;

            character = '\0';
            while (position != null && !flag && (limit == null || position.CompareTo(limit) < 0))
            {
                switch (position.GetPointerContext(direction))
                {
                case TextPointerContext.Text:
                {
                    char[] array = new char[1];
                    position.GetTextInRun(direction, array, 0, 1);
                    character = array[0];
                    flag      = true;
                    continue;
                }

                case TextPointerContext.ElementStart:
                case TextPointerContext.ElementEnd:
                    if (TextSchema.IsFormattingType(position.GetElementType(direction)))
                    {
                        position = position.CreatePointer(1);
                        continue;
                    }
                    position = null;
                    continue;
                }
                position = null;
            }
            return(position);
        }
        // Token: 0x06002EFA RID: 12026 RVA: 0x000D47DC File Offset: 0x000D29DC
        private void _SkipFormattingTags(ITextPointer textPointer)
        {
            LogicalDirection logicalDirection = textPointer.LogicalDirection;
            int offset = (logicalDirection == LogicalDirection.Forward) ? 1 : -1;

            while (TextSchema.IsFormattingType(textPointer.GetElementType(logicalDirection)))
            {
                textPointer.MoveByOffset(offset);
            }
        }
Esempio n. 3
0
        private void _SkipFormattingTags(ITextPointer textPointer)
        {
            Debug.Assert(!textPointer.IsFrozen, "Can't reposition a frozen pointer!");

            LogicalDirection dir = textPointer.LogicalDirection;
            int increment        = (dir == LogicalDirection.Forward ? +1 : -1);

            while (TextSchema.IsFormattingType(textPointer.GetElementType(dir)))
            {
                textPointer.MoveByOffset(increment);
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Returns true if pointer preceeds an Inline start or end edge.
        /// </summary>
        private static bool IsAdjacentToFormatElement(ITextPointer pointer, LogicalDirection direction)
        {
            TextPointerContext context;
            bool isAdjacentToFormatElement;

            isAdjacentToFormatElement = false;

            if (direction == LogicalDirection.Forward)
            {
                context = pointer.GetPointerContext(LogicalDirection.Forward);

                if (context == TextPointerContext.ElementStart &&
                    TextSchema.IsFormattingType(pointer.GetElementType(LogicalDirection.Forward)))
                {
                    isAdjacentToFormatElement = true;
                }
                else if (context == TextPointerContext.ElementEnd &&
                         TextSchema.IsFormattingType(pointer.ParentType))
                {
                    isAdjacentToFormatElement = true;
                }
            }
            else
            {
                context = pointer.GetPointerContext(LogicalDirection.Backward);

                if (context == TextPointerContext.ElementEnd &&
                    TextSchema.IsFormattingType(pointer.GetElementType(LogicalDirection.Backward)))
                {
                    isAdjacentToFormatElement = true;
                }
                else if (context == TextPointerContext.ElementStart &&
                         TextSchema.IsFormattingType(pointer.ParentType))
                {
                    isAdjacentToFormatElement = true;
                }
            }

            return(isAdjacentToFormatElement);
        }
            // Token: 0x06008E5B RID: 36443 RVA: 0x0025BE9C File Offset: 0x0025A09C
            private void GetContent()
            {
                this._contentSegments.Clear();
                ITextPointer textPointer  = this._segment.Start.CreatePointer();
                ITextPointer textPointer2 = null;

                while (textPointer.CompareTo(this._segment.End) < 0)
                {
                    TextPointerContext pointerContext = textPointer.GetPointerContext(LogicalDirection.Forward);
                    if (pointerContext == TextPointerContext.ElementStart)
                    {
                        Type elementType = textPointer.GetElementType(LogicalDirection.Forward);
                        if (typeof(Run).IsAssignableFrom(elementType) || typeof(BlockUIContainer).IsAssignableFrom(elementType))
                        {
                            this.OpenSegment(ref textPointer2, textPointer);
                        }
                        else if (typeof(Table).IsAssignableFrom(elementType) || typeof(Floater).IsAssignableFrom(elementType) || typeof(Figure).IsAssignableFrom(elementType))
                        {
                            this.CloseSegment(ref textPointer2, textPointer, this._segment.End);
                        }
                        textPointer.MoveToNextContextPosition(LogicalDirection.Forward);
                        if (typeof(Run).IsAssignableFrom(elementType) || typeof(BlockUIContainer).IsAssignableFrom(elementType))
                        {
                            textPointer.MoveToElementEdge(ElementEdge.AfterEnd);
                        }
                    }
                    else if (pointerContext == TextPointerContext.ElementEnd)
                    {
                        Type parentType = textPointer.ParentType;
                        if (typeof(TableCell).IsAssignableFrom(parentType) || typeof(Floater).IsAssignableFrom(parentType) || typeof(Figure).IsAssignableFrom(parentType))
                        {
                            this.CloseSegment(ref textPointer2, textPointer, this._segment.End);
                        }
                        textPointer.MoveToNextContextPosition(LogicalDirection.Forward);
                    }
                    else if (pointerContext == TextPointerContext.Text || pointerContext == TextPointerContext.EmbeddedElement)
                    {
                        this.OpenSegment(ref textPointer2, textPointer);
                        textPointer.MoveToNextContextPosition(LogicalDirection.Forward);
                    }
                    else
                    {
                        Invariant.Assert(false, "unexpected TextPointerContext");
                    }
                }
                this.CloseSegment(ref textPointer2, textPointer, this._segment.End);
            }
        // Returns the position preceeding the next text character in a specified
        // direction, or null if no such position exists.
        // The scan will halt if limit is encounted; limit may be null.
        private static ITextPointer GetNextTextPosition(ITextPointer position, ITextPointer limit, LogicalDirection direction, out char character)
        {
            bool foundText = false;

            character = (char)0;

            while (position != null &&
                   !foundText &&
                   (limit == null || position.CompareTo(limit) < 0))
            {
                switch (position.GetPointerContext(direction))
                {
                case TextPointerContext.Text:
                    char[] buffer = new char[1];
                    position.GetTextInRun(direction, buffer, 0, 1);
                    character = buffer[0];
                    foundText = true;
                    break;

                case TextPointerContext.ElementStart:
                case TextPointerContext.ElementEnd:
                    if (TextSchema.IsFormattingType(position.GetElementType(direction)))
                    {
                        position = position.CreatePointer(+1);
                    }
                    else
                    {
                        position = null;
                    }
                    break;

                case TextPointerContext.EmbeddedElement:
                case TextPointerContext.None:
                default:
                    position = null;
                    break;
                }
            }

            return(position);
        }
        // Worker implementing IsAtPotentialRunPosition(position) method.
        // It is used for testing whether an empty Run element is at potential run potision.
        // For this purpose the method is supposed to be called with
        // backwardPosition==run.ElementStart and forwardPosition==run.ElementEnd.
        private static bool IsAtPotentialRunPosition(ITextPointer backwardPosition, ITextPointer forwardPosition)
        {
            Invariant.Assert(backwardPosition.HasEqualScope(forwardPosition));

            if (TextSchema.IsValidChild(/*position*/backwardPosition, /*childType*/typeof(Run)))
            {
                Type forwardType = forwardPosition.GetElementType(LogicalDirection.Forward);
                Type backwardType = backwardPosition.GetElementType(LogicalDirection.Backward);
                if (forwardType != null && backwardType != null)
                {
                    TextPointerContext forwardContext = forwardPosition.GetPointerContext(LogicalDirection.Forward);
                    TextPointerContext backwardContext = backwardPosition.GetPointerContext(LogicalDirection.Backward);
                    if (// Test if the position inside empty Paragraph or Span
                        backwardContext == TextPointerContext.ElementStart &&
                        forwardContext == TextPointerContext.ElementEnd
                        ||
                        // Test if the position between opening tag and an embedded object
                        backwardContext == TextPointerContext.ElementStart && TextSchema.IsNonFormattingInline(forwardType) &&
                        !IsAtNonMergeableInlineStart(backwardPosition)
                        ||
                        // Test if the position between an embedded object and a closing tag
                        forwardContext == TextPointerContext.ElementEnd && TextSchema.IsNonFormattingInline(backwardType) &&
                        !IsAtNonMergeableInlineEnd(forwardPosition)
                        ||
                        // Test if the position between two embedded objects
                        backwardContext == TextPointerContext.ElementEnd && forwardContext == TextPointerContext.ElementStart &&
                        TextSchema.IsNonFormattingInline(backwardType) && TextSchema.IsNonFormattingInline(forwardType)
                        ||
                        // Test if the position is adjacent to a non-mergeable inline (Hyperlink).
                        backwardContext == TextPointerContext.ElementEnd &&
                        typeof(Inline).IsAssignableFrom(backwardType) && !TextSchema.IsMergeableInline(backwardType) && !typeof(Run).IsAssignableFrom(forwardType) &&
                        (forwardContext != TextPointerContext.ElementEnd || !IsAtNonMergeableInlineEnd(forwardPosition))
                        ||
                        forwardContext == TextPointerContext.ElementStart &&
                        typeof(Inline).IsAssignableFrom(forwardType) && !TextSchema.IsMergeableInline(forwardType) && !typeof(Run).IsAssignableFrom(backwardType) &&
                        (backwardContext != TextPointerContext.ElementStart || !IsAtNonMergeableInlineStart(backwardPosition))
                        )
                    {
                        return true;
                    }
                }
            }

            return false;
        }
        /// <summary>
        /// Return true if Hyperlink range is invalid.
        /// Hyperlink is invalid if it include a UiElement except Image or the range end position
        /// is stated before the end position of hyperlink.
        /// This must be called before Hyperlink start element position.
        /// </summary>        
        private static bool IsHyperlinkInvalid(ITextPointer textReader, ITextPointer rangeEnd)
        {
            // TextRead must be on the position before the element start position of Hyperlink
            Invariant.Assert(textReader.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementStart);
            Invariant.Assert(typeof(Hyperlink).IsAssignableFrom(textReader.GetElementType(LogicalDirection.Forward)));

            bool hyperlinkInvalid = false;

            // Get the forward adjacent element and cast Hyperlink hardly since it must be Hyperlink
            Hyperlink hyperlink = (Hyperlink)textReader.GetAdjacentElement(LogicalDirection.Forward);

            ITextPointer hyperlinkNavigation = textReader.CreatePointer();
            ITextPointer hyperlinkEnd = textReader.CreatePointer();

            hyperlinkEnd.MoveToNextContextPosition(LogicalDirection.Forward);

            // Find the hyperlink end position
            hyperlinkEnd.MoveToElementEdge(ElementEdge.AfterEnd);

            // Hyperlink end position is stated after the range end position.
            if (hyperlinkEnd.CompareTo(rangeEnd) > 0)
            {
                hyperlinkInvalid = true;
            }
            else
            {
                // Check whether the hyperlink having a UiElement except Image until hyperlink end position
                while (hyperlinkNavigation.CompareTo(hyperlinkEnd) < 0)
                {
                    InlineUIContainer inlineUIContainer = hyperlinkNavigation.GetAdjacentElement(LogicalDirection.Forward) as InlineUIContainer;
                    if (inlineUIContainer != null && !(inlineUIContainer.Child is Image))
                    {
                        hyperlinkInvalid = true;
                        break;
                    }

                    hyperlinkNavigation.MoveToNextContextPosition(LogicalDirection.Forward);
                }
            }

            return hyperlinkInvalid;
        }
Esempio n. 9
0
        // Returns the position preceeding the next text character in a specified
        // direction, or null if no such position exists.
        // The scan will halt if limit is encounted; limit may be null.
        private static ITextPointer GetNextTextPosition(ITextPointer position, ITextPointer limit, LogicalDirection direction, out char character)
        {
            bool foundText = false;

            character = (char)0;

            while (position != null &&
                   !foundText &&
                   (limit == null || position.CompareTo(limit) < 0))
            {
                switch (position.GetPointerContext(direction))
                {
                    case TextPointerContext.Text:
                        char[] buffer = new char[1];
                        position.GetTextInRun(direction, buffer, 0, 1);
                        character = buffer[0];
                        foundText = true;
                        break;

                    case TextPointerContext.ElementStart:
                    case TextPointerContext.ElementEnd:
                        if (TextSchema.IsFormattingType(position.GetElementType(direction)))
                        {
                            position = position.CreatePointer(+1);
                        }
                        else
                        {
                            position = null;
                        }
                        break;

                    case TextPointerContext.EmbeddedElement:
                    case TextPointerContext.None:
                    default:
                        position = null;
                        break;
                }
            }

            return position;
        }
Esempio n. 10
0
        /// <summary>
        /// </summary>
        void ITextSelection.SetCaretToPosition(ITextPointer caretPosition, LogicalDirection direction, bool allowStopAtLineEnd, bool allowStopNearSpace)
        {
            // We need a pointer with appropriate direction,
            // becasue it will be used in textRangeBase.Select method for
            // pointer normalization.
            caretPosition = caretPosition.CreatePointer(direction);

            // Normalize the position in its logical direction - to get to text content over there.
            caretPosition.MoveToInsertionPosition(direction);

            // We need a pointer with the reverse direction to confirm
            // the line wrapping position. So we can ensure Bidi caret navigation.
            // Bidi can have the different caret position by setting the
            // logical direction, so we have to only set the logical direction
            // as the forward for the real line wrapping position.
            ITextPointer reversePosition = caretPosition.CreatePointer(direction == LogicalDirection.Forward ? LogicalDirection.Backward : LogicalDirection.Forward);

            // Check line wrapping condition
            if (!allowStopAtLineEnd &&
                ((TextPointerBase.IsAtLineWrappingPosition(caretPosition, this.TextView) &&
                  TextPointerBase.IsAtLineWrappingPosition(reversePosition, this.TextView)) ||
                 TextPointerBase.IsNextToPlainLineBreak(caretPosition, LogicalDirection.Backward) ||
                 TextSchema.IsBreak(caretPosition.GetElementType(LogicalDirection.Backward))))
            {
                // Caret is at wrapping position, and we are not allowed to stay at end of line,
                // so we choose forward direction to appear in the begiinning of a second line
                caretPosition.SetLogicalDirection(LogicalDirection.Forward);
            }
            else
            {
                if (caretPosition.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.Text &&
                    caretPosition.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text)
                {
                    // This is statistically most typical case. No "smartness" needed
                    // to choose standard Forward orientation for the caret.
                    // NOTE: By using caretPosition's direction we solve BiDi caret orientation case:
                    // The orietnation reflects a direction from where caret has been moved
                    // or orientation where mouse clicked. So we will stick with appropriate
                    // character.

                    // Nothing to do. The caretPosition is good to go.
                }
                else if (!allowStopNearSpace)
                {
                    // There are some tags around, and we are not allowed to choose a side near to space.
                    // So we need to perform some content analysis.

                    char[] charBuffer = new char[1];

                    if (caretPosition.GetPointerContext(direction) == TextPointerContext.Text &&
                        caretPosition.GetTextInRun(direction, charBuffer, 0, 1) == 1 &&
                        Char.IsWhiteSpace(charBuffer[0]))
                    {
                        LogicalDirection oppositeDirection = direction == LogicalDirection.Forward ? LogicalDirection.Backward : LogicalDirection.Forward;

                        // Check formatting switch condition at this position
                        FlowDirection initialFlowDirection = (FlowDirection)caretPosition.GetValue(FrameworkElement.FlowDirectionProperty);

                        bool moved = caretPosition.MoveToInsertionPosition(oppositeDirection);

                        if (moved &&
                            initialFlowDirection == (FlowDirection)caretPosition.GetValue(FrameworkElement.FlowDirectionProperty) &&
                            (caretPosition.GetPointerContext(oppositeDirection) != TextPointerContext.Text ||
                             caretPosition.GetTextInRun(oppositeDirection, charBuffer, 0, 1) != 1 ||
                             !Char.IsWhiteSpace(charBuffer[0])))
                        {
                            // In the opposite direction we have a non-space
                            // character. So we choose that direction
                            direction = oppositeDirection;
                            caretPosition.SetLogicalDirection(direction);
                        }
                    }
                }
            }

            // Now that orientation of a caretPosition is identified,
            // build an empty selection at this position
            TextRangeBase.BeginChange(this);
            try
            {
                TextRangeBase.Select(this, caretPosition, caretPosition);

                // Note how Select method works for the case of empty range:
                // It creates a single instance TextPointer normalized and oriented
                // in a direction taken from caretPosition:
                ITextSelection thisSelection = this;
                Invariant.Assert(thisSelection.Start.LogicalDirection == caretPosition.LogicalDirection); // orientation must be as passed
                Invariant.Assert(this.IsEmpty);
                //Invariant.Assert((object)thisSelection.Start == (object)thisSelection.End); // it must be the same instance of TextPointer
                //Invariant.Assert(TextPointerBase.IsAtInsertionPosition(thisSelection.Start, caretPosition.LogicalDirection)); // normalization must be done in the same diredction as orientation

                // Clear active positions when selection is empty
                SetActivePositions(null, null);
            }
            finally
            {
                TextRangeBase.EndChange(this);
            }
        }
        /// <summary>
        /// Advances this TextNavigator by a count number of characters.
        /// </summary>
        /// <param name="thisNavigator">ITextPointer to advance.</param>
        /// <param name="direction">
        /// A direction in which to search a next characters.
        /// </param>
        /// <returns>
        /// True if the navigator is advanced, false if the end of document is
        /// encountered and the navigator is not repositioned.
        /// </returns>
        /// <remarks>
        /// A "character" in this context is a sequence of one or several text
        /// symbols: one or more Unicode code points may be a character, every
        /// embedded object is a character, a sequence of closing block tags
        /// followed by opening block tags may also be a unit. Formatting tags
        /// do not contribute in any unit.
        /// </remarks>
        internal static bool MoveToNextInsertionPosition(ITextPointer thisNavigator, LogicalDirection direction)
        {
            Invariant.Assert(!thisNavigator.IsFrozen, "Can't reposition a frozen pointer!");

            bool moved = true;

            int increment = direction == LogicalDirection.Forward ? +1 : -1;

            ITextPointer initialPosition = thisNavigator.CreatePointer();

            if (!IsAtInsertionPosition(thisNavigator))
            {
                // If the TextPointer is not currently at an insertion position,
                // move the TextPointer to the next insertion position in
                // the indicated direction, just like the MoveToInsertionPosition method.

                if (!MoveToInsertionPosition(thisNavigator, direction))
                {
                    // No insertion position in all content. MoveToInsertionPosition() guarantees that navigator is moved back to initial position.
                    moved = false;
                    goto Exit;
                }

                if ((direction == LogicalDirection.Forward && initialPosition.CompareTo(thisNavigator) < 0) ||
                    (direction == LogicalDirection.Backward && thisNavigator.CompareTo(initialPosition) < 0))
                {
                    // We have found an insertion position in requested direction.
                    goto Exit;
                }
            }

            // Start with skipping character formatting tags in this direction
            while (TextSchema.IsFormattingType(thisNavigator.GetElementType(direction)))
            {
                thisNavigator.MoveByOffset(increment);
            }

            do
            {
                if (thisNavigator.GetPointerContext(direction) != TextPointerContext.None)
                {
                    thisNavigator.MoveByOffset(increment);
                }
                else
                {
                    // No insertion position in this direction; Move back
                    thisNavigator.MoveToPosition(initialPosition);
                    moved = false;
                    goto Exit;
                }
            }
            while (!IsAtInsertionPosition(thisNavigator));

            // We must leave position normalized in backward direction
            if (direction == LogicalDirection.Backward)
            {
                // For this we must skip character formatting tags if we have any
                while (TextSchema.IsFormattingType(thisNavigator.GetElementType(direction)))
                {
                    thisNavigator.MoveByOffset(increment);
                }

                // However if it is block start we should back off
                TextPointerContext context = thisNavigator.GetPointerContext(direction);
                if (context == TextPointerContext.ElementStart || context == TextPointerContext.None)
                {
                    increment = -increment;
                    while (TextSchema.IsFormattingType(thisNavigator.GetElementType(LogicalDirection.Forward))
                           && !IsAtInsertionPosition(thisNavigator))
                    {
                        thisNavigator.MoveByOffset(increment);
                    }
                }
            }

        Exit:
            if (moved)
            {
                if (direction == LogicalDirection.Forward)
                {
                    Invariant.Assert(thisNavigator.CompareTo(initialPosition) > 0, "thisNavigator is expected to be moved from initialPosition - 1");
                }
                else
                {
                    Invariant.Assert(thisNavigator.CompareTo(initialPosition) < 0, "thisNavigator is expected to be moved from initialPosition - 2");
                }
            }
            else
            {
                Invariant.Assert(thisNavigator.CompareTo(initialPosition) == 0, "thisNavigator must stay at initial position");
            }
            return moved;
        }
 // Position at document end - after the last paragraph/list/table is
 // considered as valid insertion point position.
 // It has though a special behavior for caret positioning and text insertion
 internal static bool IsAfterLastParagraph(ITextPointer thisPosition)
 {
     return thisPosition.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.None &&
            thisPosition.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.ElementEnd &&
            !typeof(Inline).IsAssignableFrom(thisPosition.GetElementType(LogicalDirection.Backward));
 }
        private static ITextPointer RestrictWithinBlock(ITextPointer position, ITextPointer limit, LogicalDirection direction)
        {
            Invariant.Assert(!(direction == LogicalDirection.Backward) || position.CompareTo(limit) >= 0, "for backward direction position must be >= than limit");
            Invariant.Assert(!(direction == LogicalDirection.Forward) || position.CompareTo(limit) <= 0, "for forward direcion position must be <= than linit");

            while (direction == LogicalDirection.Backward ? position.CompareTo(limit) > 0 : position.CompareTo(limit) < 0)
            {
                TextPointerContext context = position.GetPointerContext(direction);
                if (context == TextPointerContext.ElementStart || context == TextPointerContext.ElementEnd)
                {
                    Type elementType = position.GetElementType(direction);
                    if (!typeof(Inline).IsAssignableFrom(elementType))
                    {
                        limit = position;
                        break;
                    }
                }
                else if (context == TextPointerContext.EmbeddedElement)
                {
                    limit = position;
                    break;
                }
                position = position.GetNextContextPosition(direction);
            }

            // Return normalized position - in the direction towards a center position.
            return limit.GetInsertionPosition(direction == LogicalDirection.Backward ? LogicalDirection.Forward : LogicalDirection.Backward);
        }
        internal static bool IsAtNormalizedPosition(ITextPointer position, LogicalDirection direction, bool respectCaretUnitBoundaries)
        {
            if (!IsAtNormalizedPosition(position, respectCaretUnitBoundaries))
            {
                return false;
            }

            // 

            if (position.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.ElementStart &&
                position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementEnd)
            {
                return true;
            }

            // Check if there is no any formatting tags in the given direction
            if (TextSchema.IsFormattingType(position.GetElementType(direction)))
            {
                position = position.CreatePointer();
                while (TextSchema.IsFormattingType(position.GetElementType(direction)))
                {
                    position.MoveToNextContextPosition(direction);
                }

                if (IsAtNormalizedPosition(position, respectCaretUnitBoundaries))
                {
                    // So there is a possibility to move over formatting tags only
                    // and reach some insertion position. This means
                    // that our position was not normalized in the given direction.
                    return false;
                }
            }

            return true;
        }
        // Tests if position is before the first Table element in a collection of Blocks at that level.
        // We treat this as a potential insertion position to allow editing operations before the table.
        // This property identifies such a position.
        internal static bool IsBeforeFirstTable(ITextPointer position)
        {
            TextPointerContext forwardContext = position.GetPointerContext(LogicalDirection.Forward);
            TextPointerContext backwardContext = position.GetPointerContext(LogicalDirection.Backward);

            return (forwardContext == TextPointerContext.ElementStart &&
                    (backwardContext == TextPointerContext.ElementStart || backwardContext == TextPointerContext.None) &&
                    typeof(Table).IsAssignableFrom(position.GetElementType(LogicalDirection.Forward)));
        }
        // Returns true if the position is adjacent to a LineBreak or Paragraph element,
        // ignoring any intermediate formatting elements.
        //
        // If lineBreakType is null, any line break element is considered valid.
        private static bool IsNextToRichBreak(ITextPointer thisPosition, LogicalDirection direction, Type lineBreakType)
        {
            Invariant.Assert(lineBreakType == null || lineBreakType == typeof(LineBreak) || lineBreakType == typeof(Paragraph));

            bool result = false;

            while (true)
            {
                Type neighbor = thisPosition.GetElementType(direction);

                if (lineBreakType == null)
                {
                    if (typeof(LineBreak).IsAssignableFrom(neighbor) ||
                        typeof(Paragraph).IsAssignableFrom(neighbor))
                    {
                        result = true;
                        break;
                    }
                }
                else if (lineBreakType.IsAssignableFrom(neighbor))
                {
                    result = true;
                    break;
                }

                if (!TextSchema.IsFormattingType(neighbor))
                    break;

                thisPosition = thisPosition.GetNextContextPosition(direction);
            }

            return result;
        }
        //------------------------------------------------------
        //
        //  Private Methods
        //
        //------------------------------------------------------

        #region Private Methods

        // Worker for MoveToNextFormatNormalizedPosition/MoveToNextInsertionPosition.
        private static bool NormalizePosition(ITextPointer thisNavigator, LogicalDirection direction, bool respectCaretUnitBoundaries)
        {
            Invariant.Assert(!thisNavigator.IsFrozen, "Can't reposition a frozen pointer!");

            int symbolCount = 0;
            int increment;
            LogicalDirection oppositeDirection;
            TextPointerContext directEnterScope;
            TextPointerContext oppositeEnterScope;

            if (direction == LogicalDirection.Forward)
            {
                increment = +1;
                oppositeDirection = LogicalDirection.Backward;
                directEnterScope = TextPointerContext.ElementStart;
                oppositeEnterScope = TextPointerContext.ElementEnd;
            }
            else
            {
                increment = -1;
                oppositeDirection = LogicalDirection.Forward;
                directEnterScope = TextPointerContext.ElementEnd;
                oppositeEnterScope = TextPointerContext.ElementStart;
            }

            // When the pointer appears in between structural tags we need to start
            // from sliding into the deepest possible position without
            // leaving any structural units. We need to do that only
            // if we are not at insertion position already.
            if (!IsAtNormalizedPosition(thisNavigator, respectCaretUnitBoundaries))
            {
                // Go inside an innermost structured element (non-inline)
                while (
                    thisNavigator.GetPointerContext(direction) == directEnterScope &&
                    !typeof(Inline).IsAssignableFrom(thisNavigator.GetElementType(direction)) &&
                    !IsAtNormalizedPosition(thisNavigator, respectCaretUnitBoundaries))
                {
                    thisNavigator.MoveToNextContextPosition(direction);
                    symbolCount += increment;
                }
                while (
                    thisNavigator.GetPointerContext(oppositeDirection) == oppositeEnterScope &&
                    !typeof(Inline).IsAssignableFrom(thisNavigator.GetElementType(oppositeDirection)) &&
                    !IsAtNormalizedPosition(thisNavigator, respectCaretUnitBoundaries))
                {
                    thisNavigator.MoveToNextContextPosition(oppositeDirection);
                    symbolCount -= increment;
                }
            }

            // Get out of a Hyperlink, etc. inner edge.
            symbolCount = LeaveNonMergeableInlineBoundary(thisNavigator, direction, symbolCount);

            // Get out of a compound sequence if any.
            if (respectCaretUnitBoundaries)
            {
                while (!IsAtCaretUnitBoundary(thisNavigator))
                {
                    symbolCount += increment;
                    thisNavigator.MoveByOffset(increment);
                }
            }

            // Here is the core part of this method's logic - skipping all formatting tags in the given direction.
            // Skip character formatting tags if they are present in this direction.
            // Even if an insertion position can be in the middle of this formatting sequence,
            // we want to skip it all and reach the farthest possible insertion position in that direction.
            // Such approach guarantees that repeated calls of this normalization will give the same reauls.
            // In case if there is an inserrtion position in the middle (say, in empty Run),
            // the loop moving in opposite direction below will find it if needed.
            while (TextSchema.IsMergeableInline(thisNavigator.GetElementType(direction)))
            {
                thisNavigator.MoveToNextContextPosition(direction);
                symbolCount += increment;
            }

            if (!IsAtNormalizedPosition(thisNavigator, respectCaretUnitBoundaries))
            {
                // If still not at insertion point, try skipping inline tags in the opposite direction
                // now possibly stopping inside of empty element
                while (!IsAtNormalizedPosition(thisNavigator, respectCaretUnitBoundaries) &&
                    TextSchema.IsMergeableInline(thisNavigator.GetElementType(oppositeDirection)))
                {
                    thisNavigator.MoveToNextContextPosition(oppositeDirection);
                    symbolCount -= increment;
                }

                // If still not at insertion point, then try harder - skipping block tags
                // First in "preferred" direction
                while (!IsAtNormalizedPosition(thisNavigator, respectCaretUnitBoundaries) &&
                    thisNavigator.MoveToNextContextPosition(direction))
                {
                    symbolCount += increment;
                }

                // And finally in apposite direction
                while (!IsAtNormalizedPosition(thisNavigator, respectCaretUnitBoundaries) &&
                    thisNavigator.MoveToNextContextPosition(oppositeDirection))
                {
                    symbolCount -= increment;
                }

                if (!IsAtNormalizedPosition(thisNavigator, respectCaretUnitBoundaries))
                {
                    // When there is no insertion positions in the whole document
                    // we return the position back to its original place.
                    thisNavigator.MoveByOffset(-symbolCount);
                }
            }

            return symbolCount != 0;
        }
 private void _SkipFormattingTags(ITextPointer textPointer)
 {
     Debug.Assert(!textPointer.IsFrozen, "Can't reposition a frozen pointer!");
     
     LogicalDirection dir = textPointer.LogicalDirection;
     int increment = (dir == LogicalDirection.Forward ? +1 : -1);
     while (TextSchema.IsFormattingType( textPointer.GetElementType(dir)) )
     {
         textPointer.MoveByOffset(increment);
     }
 }
Esempio n. 19
0
            // Returns true if pointer preceeds an Inline start or end edge. 
            private bool IsAdjacentToFormatElement(ITextPointer pointer)
            { 
                TextPointerContext context; 
                bool isAdjacentToFormatElement;
 
                isAdjacentToFormatElement = false;

                context = pointer.GetPointerContext(LogicalDirection.Forward);
 
                if (context == TextPointerContext.ElementStart &&
                    TextSchema.IsFormattingType(pointer.GetElementType(LogicalDirection.Forward))) 
                { 
                    isAdjacentToFormatElement = true;
                } 
                else if (context == TextPointerContext.ElementEnd &&
                         TextSchema.IsFormattingType(pointer.ParentType))
                {
                    isAdjacentToFormatElement = true; 
                }
 
                return isAdjacentToFormatElement; 
            }
Esempio n. 20
0
        // Moves the navigator in the given direction over all characters,
        // embedded objects and formatting tags. 
        //

        private static void SkipParagraphContent(ITextPointer navigator, LogicalDirection direction)
        { 
            TextPointerContext nextContext = navigator.GetPointerContext(direction);
 
            while (true) 
            {
                if (nextContext == TextPointerContext.None // 
                    || //
                    // Entering non-inline content
                    (nextContext == TextPointerContext.ElementStart && direction == LogicalDirection.Forward || //
                    nextContext == TextPointerContext.ElementEnd && direction == LogicalDirection.Backward) && // 
                    !typeof(Inline).IsAssignableFrom(navigator.GetElementType(direction)) //
                    || 
                    // Exiting non-inline content 
                    (nextContext == TextPointerContext.ElementEnd && direction == LogicalDirection.Forward || //
                    nextContext == TextPointerContext.ElementStart && direction == LogicalDirection.Backward) && // 
                    !typeof(Inline).IsAssignableFrom(navigator.ParentType))
                {
                    // End of paragraph content reached. Stop here.
                    break; 
                }
 
                //Need to bail out if MoveToNextContentPosition fails 
                if (!navigator.MoveToNextContextPosition(direction))
                { 
                    break;
                }
                nextContext = navigator.GetPointerContext(direction);
            } 
        }