예제 #1
0
        // Helper for GetPositionAtWordBoundary.
        // Returns true when passed TextPointer is next to a wordBreak in requested direction.
        private static bool IsPositionNextToWordBreak(TextPointer position, LogicalDirection wordBreakDirection)
        {
            bool isAtWordBoundary = false;

            // Skip over any formatting.
            if (position.GetPointerContext(wordBreakDirection) != TextPointerContext.Text)
            {
                position = position.GetInsertionPosition(wordBreakDirection);
            }

            if (position.GetPointerContext(wordBreakDirection) == TextPointerContext.Text)
            {
                LogicalDirection oppositeDirection = (wordBreakDirection == LogicalDirection.Forward) ?
                                                     LogicalDirection.Backward : LogicalDirection.Forward;

                char[] runBuffer         = new char[1];
                char[] oppositeRunBuffer = new char[1];

                position.GetTextInRun(wordBreakDirection, runBuffer, /*startIndex*/ 0, /*count*/ 1);
                position.GetTextInRun(oppositeDirection, oppositeRunBuffer, /*startIndex*/ 0, /*count*/ 1);

                if (runBuffer[0] == ' ' && !(oppositeRunBuffer[0] == ' '))
                {
                    isAtWordBoundary = true;
                }
            }
            else
            {
                // If we're not adjacent to text then we always want to consider this position a "word break".
                // In practice, we're most likely next to an embedded object or a block boundary.
                isAtWordBoundary = true;
            }

            return(isAtWordBoundary);
        }
예제 #2
0
        public int GetIndex(TextPointer tp, LogicalDirection dir)
        {
            Debug.Assert(tp.IsInSameDocument(Doc.ContentStart));

            tp = tp.GetInsertionPosition(dir);

            if (tp.Parent is FlowDocument)
            {
                return(0);
            }

            TextElement parent = (TextElement)tp.Parent;

            int index = FindStartIndex(parent);

            if (index < 0)
            {
                return(-1);
            }

            if (parent is Run)
            {
                return(index + parent.ContentStart.GetOffsetToPosition(tp));
            }
            else
            {
                return(index);
            }
        }
        private static bool IsPositionNextToWordBreak(TextPointer position, LogicalDirection wordBreakDirection)
        {
            // Skip over any formatting.
            if (position.GetPointerContext(wordBreakDirection) != TextPointerContext.Text)
            {
                position = position.GetInsertionPosition(wordBreakDirection);
            }

            if (position.GetPointerContext(wordBreakDirection) == TextPointerContext.Text)
            {
                var oppositeDirection = wordBreakDirection == LogicalDirection.Forward ? LogicalDirection.Backward : LogicalDirection.Forward;

                var runBuffer         = new char[1];
                var oppositeRunBuffer = new char[1];

                position.GetTextInRun(wordBreakDirection, runBuffer, 0, 1);
                position.GetTextInRun(oppositeDirection, oppositeRunBuffer, 0, 1);

                if ((runBuffer[0] == ' ' || runBuffer[0] == '\t') && oppositeRunBuffer[0] != ' ' && oppositeRunBuffer[0] != '\t')
                {
                    return(true);
                }
                else
                {
                    return(false);
                }
            }

            // We are next to an embedded object or a block boundary
            // -> consider as word break
            return(true);
        }
예제 #4
0
        } // End GetElementTagBalance
        // </Snippet_TextPointer_GetOffsetToPosition2>

        // <Snippet_TextPointer_GetPositionAtOffset>
        // Returns the offset for the specified position relative to any containing paragraph.
        int GetOffsetRelativeToParagraph(TextPointer position)
        {
            // Adjust the pointer to the closest forward insertion position, and look for any
            // containing paragraph.
            Paragraph paragraph = (position.GetInsertionPosition(LogicalDirection.Forward)).Paragraph;

            // Some positions may be not within any Paragraph; 
            // this method returns an offset of -1 to indicate this condition.
            return (paragraph == null) ? -1 : paragraph.ContentStart.GetOffsetToPosition(position);
        }
예제 #5
0
        public static int GetColumnForTextPointer(this RichTextBox rtb, TextPointer tp)
        {
            TextPointer tpColumn = tp.GetInsertionPosition(LogicalDirection.Backward);
            int         columnNr = 1;

            for (TextPointer linePointer = tpColumn.GetLineStartPosition(0).GetNextInsertionPosition(LogicalDirection.Forward);
                 linePointer.CompareTo(tpColumn) < 0; linePointer = linePointer.GetNextInsertionPosition(LogicalDirection.Forward))
            {
                columnNr++;
            }

            return(columnNr);
        }
예제 #6
0
        /// <summary>
        /// 1.  When wordBreakDirection = Forward, returns a position at the end of the word,
        ///     i.e. a position with a wordBreak character (space) following it.
        /// 2.  When wordBreakDirection = Backward, returns a position at the start of the word,
        ///     i.e. a position with a wordBreak character (space) preceeding it.
        /// 3.  Returns null when there is no workbreak in the requested direction.
        /// </summary>
        private static TextPointer GetPositionAtWordBoundary(TextPointer position, LogicalDirection wordBreakDirection)
        {
            if (!position.IsAtInsertionPosition)
            {
                position = position.GetInsertionPosition(wordBreakDirection);
            }
            TextPointer navigator = position;

            while (navigator != null && !IsPositionNextToWordBreak(navigator, wordBreakDirection))
            {
                navigator = navigator.GetNextInsertionPosition(wordBreakDirection);
            }
            return(navigator);
        }
예제 #7
0
        bool CollectEols(ICancellable cnc, TextData td, Rect clip_rect, int top_index)
        {
            if (cnc.IsCancellationRequested)
            {
                return(false);
            }

            var rtb = Rtb;

            List <Rect> positions_eols = new List <Rect>( );

            // lines with no right-to-left segments

            var matches = EolRegex.Matches(td.Text);

            for (int i = 0; i < matches.Count; ++i)
            {
                if (cnc.IsCancellationRequested)
                {
                    return(false);
                }

                int index = matches[i].Index;

                if (index < top_index)
                {
                    continue;
                }

                int previous_index = i == 0 ? 0 : matches[i - 1].Index;

                bool has_RTL = false;

                for (int k = previous_index; k < index; ++k)
                {
                    if (cnc.IsCancellationRequested)
                    {
                        return(false);
                    }

                    if (UnicodeUtilities.IsRTL(td.Text[k]))
                    {
                        has_RTL = true;
                        break;
                    }
                }

                if (has_RTL)
                {
                    // RTL needs more navigation to find the rightmost X

                    Rect   left_rect = Rect.Empty;
                    double max_x     = double.NaN;

                    bool should_continue = false;
                    bool should_break    = false;

                    UITaskHelper.Invoke(rtb,
                                        () =>
                    {
                        TextPointer left = td.TextPointers.GetTextPointer(index);

                        left_rect = left.GetCharacterRect(LogicalDirection.Forward);

                        if (left_rect.Bottom < clip_rect.Top)
                        {
                            should_continue = true; return;
                        }
                        if (left_rect.Top > clip_rect.Bottom)
                        {
                            should_break = true; return;
                        }

                        max_x = left_rect.Left;

                        for (var tp = left.GetInsertionPosition(LogicalDirection.Backward); ;)
                        {
                            if (cnc.IsCancellationRequested)
                            {
                                return;
                            }

                            tp = tp.GetNextInsertionPosition(LogicalDirection.Backward);
                            if (tp == null)
                            {
                                break;
                            }

                            // WORKAROUND for lines like "0ראל", when "0" is matched and highlighted
                            tp = tp.GetInsertionPosition(LogicalDirection.Forward);

                            var rect_b = tp.GetCharacterRect(LogicalDirection.Backward);
                            var rect_f = tp.GetCharacterRect(LogicalDirection.Forward);

                            if (cnc.IsCancellationRequested)
                            {
                                return;
                            }

                            if (rect_b.Bottom < left_rect.Top && rect_f.Bottom < left_rect.Top)
                            {
                                break;
                            }

                            if (rect_b.Bottom > left_rect.Top)
                            {
                                if (max_x < rect_b.Left)
                                {
                                    max_x = rect_b.Left;
                                }
                            }

                            if (rect_f.Bottom > left_rect.Top)
                            {
                                if (max_x < rect_f.Left)
                                {
                                    max_x = rect_f.Left;
                                }
                            }
                        }
                    });

                    if (cnc.IsCancellationRequested)
                    {
                        return(false);
                    }
                    if (should_continue)
                    {
                        continue;
                    }
                    if (should_break)
                    {
                        break;
                    }

                    Rect eol_rect = new Rect(new Point(max_x, left_rect.Top), left_rect.Size);
                    eol_rect.Offset(rtb.HorizontalOffset, rtb.VerticalOffset);

                    positions_eols.Add(eol_rect);
                }
                else
                {
                    // no RTL; quick answer

                    Rect eol_rect = Rect.Empty;

                    UITaskHelper.Invoke(rtb,
                                        () =>
                    {
                        TextPointer left = td.TextPointers.GetTextPointer(index);

                        eol_rect = left.GetCharacterRect(LogicalDirection.Forward);
                    });

                    if (eol_rect.Bottom < clip_rect.Top)
                    {
                        continue;
                    }
                    if (eol_rect.Top > clip_rect.Bottom)
                    {
                        break;
                    }

                    eol_rect.Offset(rtb.HorizontalOffset, rtb.VerticalOffset);

                    positions_eols.Add(eol_rect);
                }
            }

            if (cnc.IsCancellationRequested)
            {
                return(false);
            }

            lock (this)
            {
                PositionsEols = positions_eols;
            }

            DelayedInvalidateVisual( );

            return(true);
        }
예제 #8
0
        /// <remarks>
        /// Often correct for LTR text with fairly uniform height and much much faster than a linear scan
        /// </remarks>
        private static TextPointer GetPositionFromPointByBisection(Point point, TextRange range)
        {
            TextRange currRange = new TextRange(range.Start, range.End);

            int currSpan;

            do
            {
                currSpan = GetSpan(currRange);

                if (currSpan < 1)
                {
                    break;
                }

                TextPointer mid = currRange.Start.GetPositionAtOffset(currSpan / 2);
                mid = mid.GetInsertionPosition(prevCharDirection);
                if (mid == null)
                {
                    break;
                }

                PhysicalCharInfo midCharInfo   = new PhysicalCharInfo(mid);
                Rect             nearEdge      = midCharInfo.GetNearEdge();
                Rect             farEdge       = midCharInfo.GetFarEdge();
                bool             isLeftToRight = nearEdge.X <= farEdge.X;
                Rect             midRect       = Rect.Union(nearEdge, farEdge);

                if (!midRect.IsEmpty)
                {
                    if (midRect.Top > point.Y)
                    {
                        if (BisectRange(currRange, mid, PhysicalDirection.Up, isLeftToRight))
                        {
                            continue;
                        }
                        break;
                    }

                    if (midRect.Bottom < point.Y)
                    {
                        if (BisectRange(currRange, mid, PhysicalDirection.Down, isLeftToRight))
                        {
                            continue;
                        }
                        break;
                    }

                    if (midRect.Left > point.X)
                    {
                        if (BisectRange(currRange, mid, PhysicalDirection.Left, isLeftToRight))
                        {
                            continue;
                        }
                        break;
                    }

                    if (midRect.Right < point.X)
                    {
                        if (BisectRange(currRange, mid, PhysicalDirection.Right, isLeftToRight))
                        {
                            continue;
                        }
                        break;
                    }
                }

                return(midCharInfo.HitTestHorizontal(point));
            }while (GetSpan(currRange) < currSpan);

            return(null);
        }
예제 #9
0
 internal static TextPointer GetOffsetTextPointer(this TextPointer start, int offset)
 {
     return(start.GetInsertionPosition(LogicalDirection.Forward).GetPositionAtOffset(offset));
 }