Beispiel #1
0
        /// <summary>
        /// Re-positions the given position by an integral number of text units, but it does
        /// not guarantee that position is snapped to TextUnit boundary.
        /// This method assumes that input position is already snapped to appropriate TextUnit boundary.
        /// </summary>
        /// <param name="position">The position to move</param>
        /// <param name="unit">Text units to step by</param>
        /// <param name="count">Number of units to step over. Also specifies the direction of moving: 
        /// forward if positive, backward otherwise</param>
        /// <returns>The actual number of units the position was moved over</returns>
        private int MovePositionByUnits(ITextPointer position, TextUnit unit, int count)
        {
            ITextView textView;
            int moved = 0;
            int absCount = (count == int.MinValue) ? int.MaxValue : Math.Abs(count);
            LogicalDirection direction = (count > 0) ? LogicalDirection.Forward : LogicalDirection.Backward;

            // This method assumes that position is already snapped to appropriate TextUnit.

            switch (unit)
            {
                case TextUnit.Character:
                    while (moved < absCount)
                    {
                        if (!TextPointerBase.MoveToNextInsertionPosition(position, direction))
                        {
                            break;
                        }
                        moved++;
                    }
                    break;

                case TextUnit.Word:
                    while (moved < absCount)
                    {
                        if (!MoveToNextWordBoundary(position, direction))
                        {
                            break;
                        }
                        moved++;
                    }
                    break;

                case TextUnit.Format:
                    // Formatting changes can be introduced by elements. Hence it is fair to 
                    // assume that formatting boundaries are defined by non-text context.
                    while (moved < absCount)
                    {
                        ITextPointer positionOrig = position.CreatePointer();

                        // First skip all text in given direction.
                        while (position.GetPointerContext(direction) == TextPointerContext.Text)
                        {
                            if (!position.MoveToNextContextPosition(direction))
                            {
                                break;
                            }
                        }
                        // Move to next context
                        if (!position.MoveToNextContextPosition(direction))
                        {
                            break;
                        }
                        // Skip all formatting elements and position the pointer next to text.
                        while (position.GetPointerContext(direction) != TextPointerContext.Text)
                        {
                            if (!position.MoveToNextContextPosition(direction))
                            {
                                break;
                            }
                        }
                        // If moving backwards, position the pointer at the beginning of formatting range.
                        if (direction == LogicalDirection.Backward)
                        {
                            while (position.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.Text)
                            {
                                if (!position.MoveToNextContextPosition(LogicalDirection.Backward))
                                {
                                    break;
                                }
                            }
                        }
                        if (position.GetPointerContext(direction) != TextPointerContext.None)
                        {
                            moved++;
                        }
                        else
                        {
                            position.MoveToPosition(positionOrig);
                            break;
                        }
                    }

                    // Adjust logical direction to point to the following text (forward or backward movement).
                    // If we don't do this, we'll normalize in the wrong direction and get stuck in a loop
                    // if caller tries to advance again.
                    position.SetLogicalDirection(LogicalDirection.Forward);

                    break;

                case TextUnit.Line:
                    // Position is snapped to nearest line boundary. But since line information
                    // is based on the layout, position is not changed, if:
                    // a) it is not currently in the view, or
                    // b) containing line cannot be found.
                    textView = _textAdaptor.GetUpdatedTextView();
                    if (textView != null && textView.IsValid && textView.Contains(position))
                    {
                        // ITextPointer.MoveToLineBoundary can't handle Table row end positions.
                        // Mimic TextEditor's caret navigation code and move into the preceding
                        // TableCell.
                        if (TextPointerBase.IsAtRowEnd(position))
                        {
                            position.MoveToNextInsertionPosition(LogicalDirection.Backward);
                        }

                        moved = position.MoveToLineBoundary(count);
                        
                        MoveToInsertionPosition(position, LogicalDirection.Forward);

                        if (moved < 0)
                        {
                            moved = -moved; // Will be reversed below.
                        }
                    }
                    break; 

                case TextUnit.Paragraph:
                    // Utilize TextRange logic to determine paragraph boundaries.
                    ITextRange paragraphRange = new TextRange(position, position);
                    paragraphRange.SelectParagraph(position);
                    while (moved < absCount)
                    {
                        position.MoveToPosition(direction == LogicalDirection.Forward ? paragraphRange.End : paragraphRange.Start);
                        if (!position.MoveToNextInsertionPosition(direction))
                        {
                            break;
                        }
                        moved++;
                        paragraphRange.SelectParagraph(position);
                        position.MoveToPosition(paragraphRange.Start); // Position it always at the beginning of the paragraph.
                    }
                    break;

                case TextUnit.Page:
                    // But since page information is based on the layout, position is not changed, if:
                    // a) it is not currently in the view, or
                    // b) containing page cannot be found.
                    // Page movement is possible only in multi-page scenario.
                    textView = _textAdaptor.GetUpdatedTextView();
                    if (textView != null && textView.IsValid && textView.Contains(position))
                    {
                        if (textView is MultiPageTextView)
                        {
                            // Get embedded page ITextView for given position.
                            ITextView pageTextView = ((MultiPageTextView)textView).GetPageTextViewFromPosition(position);
                            ReadOnlyCollection<TextSegment> textSegments = pageTextView.TextSegments;
                            while (moved < absCount)
                            {
                                if (textSegments == null || textSegments.Count == 0)
                                {
                                    break;
                                }
                                // Move the position to appropriate edge.
                                if (direction == LogicalDirection.Backward)
                                {
                                    position.MoveToPosition(textSegments[0].Start);
                                    MoveToInsertionPosition(position, LogicalDirection.Backward);
                                }
                                else
                                {
                                    position.MoveToPosition(textSegments[textSegments.Count - 1].End);
                                    MoveToInsertionPosition(position, LogicalDirection.Forward);
                                }
                                // Try to move the position to the next page.
                                ITextPointer positionTemp = position.CreatePointer();
                                if (!positionTemp.MoveToNextInsertionPosition(direction))
                                {
                                    break;
                                }
                                else
                                {
                                    // MoveToNextInsertionPosition may return 'true' and move the position
                                    // in oposite direction.
                                    if (direction == LogicalDirection.Forward)
                                    {
                                        if (positionTemp.CompareTo(position) <= 0)
                                        {
                                            break;
                                        }
                                    }
                                    else
                                    {
                                        if (positionTemp.CompareTo(position) >= 0)
                                        {
                                            break;
                                        }
                                    }
                                }
                                // Get embedded page ITextView for given position.
                                if (!textView.Contains(positionTemp))
                                {
                                    break;
                                }
                                pageTextView = ((MultiPageTextView)textView).GetPageTextViewFromPosition(positionTemp);
                                textSegments = pageTextView.TextSegments;
                                moved++;
                            }
                        }
                    }
                    break;

                case TextUnit.Document:
                    // This method assumes that position is already snapped to appropriate TextUnit.
                    break;
            }

            return (direction == LogicalDirection.Forward) ? moved : -moved;
        }
Beispiel #2
0
        //-------------------------------------------------------------------
        //
        //  Internal Methods
        //
        //-------------------------------------------------------------------

        #region Internal Methods

        /// <summary>
        /// Retrieves the bounding rectangles for the text lines of a given range.
        /// </summary>
        /// <param name="start">Start of range to measure</param>
        /// <param name="end">End of range to measure</param>
        /// <param name="clipToView">Specifies whether the caller wants the full bounds (false) or the bounds of visible portions
        /// of the viewable line only ('true')</param>
        /// <param name="transformToScreen">Requests the results in screen coordinates</param>
        /// <returns>An array of bounding rectangles for each line or portion of a line within the client area of the text provider.
        /// No bounding rectangles will be returned for lines that are empty or scrolled out of view.  Note that even though a
        /// bounding rectangle is returned the corresponding text may not be visible due to overlapping windows.
        /// This will not return null, but may return an empty array.</returns>
        internal Rect[] GetBoundingRectangles(ITextPointer start, ITextPointer end, bool clipToView, bool transformToScreen)
        {
            ITextView textView = GetUpdatedTextView();

            if (textView == null)
            {
                return(new Rect[0]);
            }

            // If start/end positions are not in the visible range, move them to the first/last visible positions.
            ReadOnlyCollection <TextSegment> textSegments = textView.TextSegments;

            if (textSegments.Count > 0)
            {
                if (!textView.Contains(start) && start.CompareTo(textSegments[0].Start) < 0)
                {
                    start = textSegments[0].Start.CreatePointer();;
                }
                if (!textView.Contains(end) && end.CompareTo(textSegments[textSegments.Count - 1].End) > 0)
                {
                    end = textSegments[textSegments.Count - 1].End.CreatePointer();
                }
            }
            if (!textView.Contains(start) || !textView.Contains(end))
            {
                return(new Rect[0]);
            }

            TextRangeAdaptor.MoveToInsertionPosition(start, LogicalDirection.Forward);
            TextRangeAdaptor.MoveToInsertionPosition(end, LogicalDirection.Backward);

            Rect visibleRect = Rect.Empty;

            if (clipToView)
            {
                visibleRect = GetVisibleRectangle(textView);
                // If clipping into view and visible rect is empty, return.
                if (visibleRect.IsEmpty)
                {
                    return(new Rect[0]);
                }
            }

            List <Rect>  rectangles = new List <Rect>();
            ITextPointer position   = start.CreatePointer();

            while (position.CompareTo(end) < 0)
            {
                TextSegment lineRange = textView.GetLineRange(position);
                if (!lineRange.IsNull)
                {
                    // Since range is limited to just one line, GetTightBoundingGeometry will return tight bounding
                    // rectangle for given range. It will also work correctly with bidi text.
                    ITextPointer first    = (lineRange.Start.CompareTo(start) <= 0) ? start : lineRange.Start;
                    ITextPointer last     = (lineRange.End.CompareTo(end) >= 0) ? end : lineRange.End;
                    Rect         lineRect = Rect.Empty;
                    Geometry     geometry = textView.GetTightBoundingGeometryFromTextPositions(first, last);
                    if (geometry != null)
                    {
                        lineRect = geometry.Bounds;
                        if (clipToView)
                        {
                            lineRect.Intersect(visibleRect);
                        }
                        if (!lineRect.IsEmpty)
                        {
                            if (transformToScreen)
                            {
                                lineRect = new Rect(ClientToScreen(lineRect.TopLeft, textView.RenderScope), ClientToScreen(lineRect.BottomRight, textView.RenderScope));
                            }
                            rectangles.Add(lineRect);
                        }
                    }
                }
                if (position.MoveToLineBoundary(1) == 0)
                {
                    position = end;
                }
            }
            return(rectangles.ToArray());
        }
Beispiel #3
0
        // Token: 0x060065C4 RID: 26052 RVA: 0x001C8254 File Offset: 0x001C6454
        internal Rect[] GetBoundingRectangles(ITextPointer start, ITextPointer end, bool clipToView, bool transformToScreen)
        {
            ITextView updatedTextView = this.GetUpdatedTextView();

            if (updatedTextView == null)
            {
                return(new Rect[0]);
            }
            ReadOnlyCollection <TextSegment> textSegments = updatedTextView.TextSegments;

            if (textSegments.Count > 0)
            {
                if (!updatedTextView.Contains(start) && start.CompareTo(textSegments[0].Start) < 0)
                {
                    start = textSegments[0].Start.CreatePointer();
                }
                if (!updatedTextView.Contains(end) && end.CompareTo(textSegments[textSegments.Count - 1].End) > 0)
                {
                    end = textSegments[textSegments.Count - 1].End.CreatePointer();
                }
            }
            if (!updatedTextView.Contains(start) || !updatedTextView.Contains(end))
            {
                return(new Rect[0]);
            }
            TextRangeAdaptor.MoveToInsertionPosition(start, LogicalDirection.Forward);
            TextRangeAdaptor.MoveToInsertionPosition(end, LogicalDirection.Backward);
            Rect rect = Rect.Empty;

            if (clipToView)
            {
                rect = this.GetVisibleRectangle(updatedTextView);
                if (rect.IsEmpty)
                {
                    return(new Rect[0]);
                }
            }
            List <Rect>  list        = new List <Rect>();
            ITextPointer textPointer = start.CreatePointer();

            while (textPointer.CompareTo(end) < 0)
            {
                TextSegment lineRange = updatedTextView.GetLineRange(textPointer);
                if (!lineRange.IsNull)
                {
                    ITextPointer startPosition = (lineRange.Start.CompareTo(start) <= 0) ? start : lineRange.Start;
                    ITextPointer endPosition   = (lineRange.End.CompareTo(end) >= 0) ? end : lineRange.End;
                    Rect         item          = Rect.Empty;
                    Geometry     tightBoundingGeometryFromTextPositions = updatedTextView.GetTightBoundingGeometryFromTextPositions(startPosition, endPosition);
                    if (tightBoundingGeometryFromTextPositions != null)
                    {
                        item = tightBoundingGeometryFromTextPositions.Bounds;
                        if (clipToView)
                        {
                            item.Intersect(rect);
                        }
                        if (!item.IsEmpty)
                        {
                            if (transformToScreen)
                            {
                                item = new Rect(this.ClientToScreen(item.TopLeft, updatedTextView.RenderScope), this.ClientToScreen(item.BottomRight, updatedTextView.RenderScope));
                            }
                            list.Add(item);
                        }
                    }
                }
                if (textPointer.MoveToLineBoundary(1) == 0)
                {
                    textPointer = end;
                }
            }
            return(list.ToArray());
        }