// 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); }
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); }
} // 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); }
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); }
/// <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); }
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); }
/// <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); }
internal static TextPointer GetOffsetTextPointer(this TextPointer start, int offset) { return(start.GetInsertionPosition(LogicalDirection.Forward).GetPositionAtOffset(offset)); }