// Token: 0x06006B2D RID: 27437 RVA: 0x001EF394 File Offset: 0x001ED594 private List <TextElement> GetAttachedObjectElements(int dcpFirst, int dcpLast) { List <TextElement> list = new List <TextElement>(); ITextPointer contentStart = TextContainerHelper.GetContentStart(base.StructuralCache.TextContainer, base.Element); ITextPointer textPointerFromCP = TextContainerHelper.GetTextPointerFromCP(base.StructuralCache.TextContainer, base.ParagraphStartCharacterPosition + dcpFirst, LogicalDirection.Forward); if (dcpLast > base.Cch) { dcpLast = base.Cch; } while (contentStart.GetOffsetToPosition(textPointerFromCP) < dcpLast) { if (textPointerFromCP.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementStart) { TextElement adjacentElementFromOuterPosition = ((TextPointer)textPointerFromCP).GetAdjacentElementFromOuterPosition(LogicalDirection.Forward); if (adjacentElementFromOuterPosition is Figure || adjacentElementFromOuterPosition is Floater) { list.Add(adjacentElementFromOuterPosition); textPointerFromCP.MoveByOffset(adjacentElementFromOuterPosition.SymbolCount); } else { textPointerFromCP.MoveToNextContextPosition(LogicalDirection.Forward); } } else { textPointerFromCP.MoveToNextContextPosition(LogicalDirection.Forward); } } return(list); }
// Token: 0x06007245 RID: 29253 RVA: 0x0020AA54 File Offset: 0x00208C54 internal static List <AutomationPeer> GetAutomationPeersFromRange(ITextPointer start, ITextPointer end, ITextPointer ownerContentStart) { List <AutomationPeer> list = new List <AutomationPeer>(); start = start.CreatePointer(); while (start.CompareTo(end) < 0) { bool flag = false; if (start.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementStart) { object adjacentElement = start.GetAdjacentElement(LogicalDirection.Forward); if (adjacentElement is ContentElement) { AutomationPeer automationPeer = ContentElementAutomationPeer.CreatePeerForElement((ContentElement)adjacentElement); if (automationPeer != null) { if (ownerContentStart == null || TextContainerHelper.IsImmediateAutomationChild(start, ownerContentStart)) { list.Add(automationPeer); } start.MoveToNextContextPosition(LogicalDirection.Forward); start.MoveToElementEdge(ElementEdge.AfterEnd); flag = true; } } } else if (start.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.EmbeddedElement) { object adjacentElement = start.GetAdjacentElement(LogicalDirection.Forward); if (adjacentElement is UIElement) { if (ownerContentStart == null || TextContainerHelper.IsImmediateAutomationChild(start, ownerContentStart)) { AutomationPeer automationPeer = UIElementAutomationPeer.CreatePeerForElement((UIElement)adjacentElement); if (automationPeer != null) { list.Add(automationPeer); } else { TextContainerHelper.iterate((Visual)adjacentElement, list); } } } else if (adjacentElement is ContentElement) { AutomationPeer automationPeer = ContentElementAutomationPeer.CreatePeerForElement((ContentElement)adjacentElement); if (automationPeer != null && (ownerContentStart == null || TextContainerHelper.IsImmediateAutomationChild(start, ownerContentStart))) { list.Add(automationPeer); } } } if (!flag && !start.MoveToNextContextPosition(LogicalDirection.Forward)) { break; } } return(list); }
// Token: 0x060068B0 RID: 26800 RVA: 0x001D8BE4 File Offset: 0x001D6DE4 protected override BaseParagraph GetParagraph(ITextPointer textPointer, bool fEmptyOk) { Invariant.Assert(textPointer is TextPointer); BaseParagraph baseParagraph = null; while (baseParagraph == null) { TextPointerContext pointerContext = textPointer.GetPointerContext(LogicalDirection.Forward); if (pointerContext == TextPointerContext.ElementStart) { TextElement adjacentElementFromOuterPosition = ((TextPointer)textPointer).GetAdjacentElementFromOuterPosition(LogicalDirection.Forward); if (adjacentElementFromOuterPosition is ListItem) { baseParagraph = new ListItemParagraph(adjacentElementFromOuterPosition, base.StructuralCache); break; } if (adjacentElementFromOuterPosition is List) { baseParagraph = new ListParagraph(adjacentElementFromOuterPosition, base.StructuralCache); break; } if (((TextPointer)textPointer).IsFrozen) { textPointer = textPointer.CreatePointer(); } textPointer.MoveToPosition(adjacentElementFromOuterPosition.ElementEnd); } else if (pointerContext == TextPointerContext.ElementEnd) { if (base.Element == ((TextPointer)textPointer).Parent) { break; } if (((TextPointer)textPointer).IsFrozen) { textPointer = textPointer.CreatePointer(); } textPointer.MoveToNextContextPosition(LogicalDirection.Forward); } else { if (((TextPointer)textPointer).IsFrozen) { textPointer = textPointer.CreatePointer(); } textPointer.MoveToNextContextPosition(LogicalDirection.Forward); } } if (baseParagraph != null) { base.StructuralCache.CurrentFormatContext.DependentMax = (TextPointer)textPointer; } return(baseParagraph); }
// Token: 0x060038D8 RID: 14552 RVA: 0x00100E4C File Offset: 0x000FF04C private static bool IsErrorAtNonMergeableInlineEdge(SpellingError spellingError, out ITextPointer textStart, out ITextPointer textEnd) { bool result = false; textStart = spellingError.Start.CreatePointer(LogicalDirection.Backward); while (textStart.CompareTo(spellingError.End) < 0 && textStart.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.Text) { textStart.MoveToNextContextPosition(LogicalDirection.Forward); } textEnd = spellingError.End.CreatePointer(); while (textEnd.CompareTo(spellingError.Start) > 0 && textEnd.GetPointerContext(LogicalDirection.Backward) != TextPointerContext.Text) { textEnd.MoveToNextContextPosition(LogicalDirection.Backward); } if (textStart.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.Text || textStart.CompareTo(spellingError.End) == 0) { return(false); } Invariant.Assert(textEnd.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.Text && textEnd.CompareTo(spellingError.Start) != 0); if ((TextPointerBase.IsAtNonMergeableInlineStart(textStart) || TextPointerBase.IsAtNonMergeableInlineEnd(textEnd)) && typeof(Run).IsAssignableFrom(textStart.ParentType) && textStart.HasEqualScope(textEnd)) { result = true; } return(result); }
// 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); }
// Candidate for replacing MoveToNextContextPosition for immutable TextPointer model ITextPointer ITextPointer.GetNextContextPosition(LogicalDirection direction) { ITextPointer pointer = ((ITextPointer)this).CreatePointer(); if (pointer.MoveToNextContextPosition(direction)) { pointer.Freeze(); } else { pointer = null; } return(pointer); }
// Token: 0x06003282 RID: 12930 RVA: 0x000DD010 File Offset: 0x000DB210 internal static bool HasNoTextContent(Paragraph paragraph) { ITextPointer textPointer = paragraph.ContentStart.CreatePointer(); ITextPointer contentEnd = paragraph.ContentEnd; while (textPointer.CompareTo(contentEnd) < 0) { TextPointerContext pointerContext = textPointer.GetPointerContext(LogicalDirection.Forward); if (pointerContext == TextPointerContext.Text || pointerContext == TextPointerContext.EmbeddedElement || typeof(LineBreak).IsAssignableFrom(textPointer.ParentType) || typeof(AnchoredBlock).IsAssignableFrom(textPointer.ParentType)) { return(false); } textPointer.MoveToNextContextPosition(LogicalDirection.Forward); } return(true); }
// Token: 0x06008465 RID: 33893 RVA: 0x002480A0 File Offset: 0x002462A0 private void AddMultipleCompositionLines(ITextPointer start, ITextPointer end) { ITextPointer textPointer = start; ITextPointer textPointer2 = textPointer; while (textPointer2.CompareTo(end) < 0) { TextSegment lineRange = this._textView.GetLineRange(textPointer2); if (lineRange.IsNull) { textPointer = textPointer2; } else { if (textPointer.CompareTo(lineRange.Start) < 0) { textPointer = lineRange.Start; } if (textPointer2.CompareTo(lineRange.End) < 0) { if (end.CompareTo(lineRange.End) < 0) { textPointer2 = end.CreatePointer(); } else { textPointer2 = lineRange.End.CreatePointer(LogicalDirection.Backward); } } Rect rectangleFromTextPosition = this._textView.GetRectangleFromTextPosition(textPointer); Rect rectangleFromTextPosition2 = this._textView.GetRectangleFromTextPosition(textPointer2); this._compositionLines.Add(new CompositionAdorner.CompositionLine(rectangleFromTextPosition, rectangleFromTextPosition2, this._textServicesDisplayAttribute.GetLineColor(textPointer))); textPointer = lineRange.End.CreatePointer(LogicalDirection.Forward); } while (textPointer.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.None && textPointer.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.Text) { textPointer.MoveToNextContextPosition(LogicalDirection.Forward); } textPointer2 = textPointer; } }
//------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ #region Internal Methods // Add the composition lines for rendering the composition lines. internal void AddCompositionLines() { // Erase any current lines. _compositionLines.Clear(); ITextPointer start = _textView.TextContainer.Start.CreatePointer(_startOffset, LogicalDirection.Forward); ITextPointer end = _textView.TextContainer.Start.CreatePointer(_endOffset, LogicalDirection.Backward); while (start.CompareTo(end) < 0 && start.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.Text) { start.MoveToNextContextPosition(LogicalDirection.Forward); } Invariant.Assert(start.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text); if (end.HasValidLayout) { // Get the rectangle for start/end position _startRect = _textView.GetRectangleFromTextPosition(start); _endRect = _textView.GetRectangleFromTextPosition(end); // Check whether the composition line is single or multiple lines if (_startRect.Top != _endRect.Top) { // Add the composition lines to be rendered for the composition string AddMultipleCompositionLines(start, end); } else { // Set the start/end pointer to draw the line Color lineColor = _textServicesDisplayAttribute.GetLineColor(start); // Add the composition line to be rendered _compositionLines.Add(new CompositionLine(_startRect, _endRect, lineColor)); } } }
// Token: 0x06008461 RID: 33889 RVA: 0x00247F80 File Offset: 0x00246180 internal void AddCompositionLines() { this._compositionLines.Clear(); ITextPointer textPointer = this._textView.TextContainer.Start.CreatePointer(this._startOffset, LogicalDirection.Forward); ITextPointer textPointer2 = this._textView.TextContainer.Start.CreatePointer(this._endOffset, LogicalDirection.Backward); while (textPointer.CompareTo(textPointer2) < 0 && textPointer.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.Text) { textPointer.MoveToNextContextPosition(LogicalDirection.Forward); } Invariant.Assert(textPointer.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text); if (textPointer2.HasValidLayout) { this._startRect = this._textView.GetRectangleFromTextPosition(textPointer); this._endRect = this._textView.GetRectangleFromTextPosition(textPointer2); if (this._startRect.Top != this._endRect.Top) { this.AddMultipleCompositionLines(textPointer, textPointer2); return; } Color lineColor = this._textServicesDisplayAttribute.GetLineColor(textPointer); this._compositionLines.Add(new CompositionAdorner.CompositionLine(this._startRect, this._endRect, lineColor)); } }
// Token: 0x06002C1F RID: 11295 RVA: 0x000C8584 File Offset: 0x000C6784 private static bool xGapAwareScan(DocumentSequenceTextPointer thisTp, int distance) { ChildDocumentBlock childDocumentBlock = thisTp.ChildBlock; bool flag = true; ITextPointer textPointer = thisTp.ChildPointer; if (textPointer == null) { flag = false; textPointer = thisTp.ChildPointer.CreatePointer(); } LogicalDirection logicalDirection = (distance > 0) ? LogicalDirection.Forward : LogicalDirection.Backward; distance = Math.Abs(distance); while (distance > 0) { switch (textPointer.GetPointerContext(logicalDirection)) { case TextPointerContext.None: if ((childDocumentBlock.IsHead && logicalDirection == LogicalDirection.Backward) || (childDocumentBlock.IsTail && logicalDirection == LogicalDirection.Forward)) { return(false); } childDocumentBlock = ((logicalDirection == LogicalDirection.Forward) ? childDocumentBlock.NextBlock : childDocumentBlock.PreviousBlock); textPointer = ((logicalDirection == LogicalDirection.Forward) ? childDocumentBlock.ChildContainer.Start.CreatePointer(textPointer.LogicalDirection) : childDocumentBlock.ChildContainer.End.CreatePointer(textPointer.LogicalDirection)); break; case TextPointerContext.Text: { int textRunLength = textPointer.GetTextRunLength(logicalDirection); int num = (textRunLength < distance) ? textRunLength : distance; distance -= num; if (logicalDirection == LogicalDirection.Backward) { num *= -1; } textPointer.MoveByOffset(num); break; } case TextPointerContext.EmbeddedElement: textPointer.MoveToNextContextPosition(logicalDirection); distance--; break; case TextPointerContext.ElementStart: textPointer.MoveToNextContextPosition(logicalDirection); distance--; break; case TextPointerContext.ElementEnd: textPointer.MoveToNextContextPosition(logicalDirection); distance--; break; } } thisTp.ChildBlock = childDocumentBlock; if (flag) { thisTp.ChildPointer = textPointer; } else { thisTp.ChildPointer = textPointer.CreatePointer(); } return(true); }
private void TextPositionsFromITfRange(UnsafeNativeMethods.ITfRange range, out ITextPointer start, out ITextPointer end) { UnsafeNativeMethods.ITfRangeACP rangeACP; int startIndex; int length; rangeACP = range as UnsafeNativeMethods.ITfRangeACP; rangeACP.GetExtent(out startIndex, out length); start = CreatePointerAtCharOffset(startIndex, LogicalDirection.Backward); end = CreatePointerAtCharOffset(startIndex + length, LogicalDirection.Forward); while (start.CompareTo(end) < 0 && start.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.Text) { start.MoveToNextContextPosition(LogicalDirection.Forward); } }
// GetText handler for text runs. private static bool WalkTextRun(ITextPointer navigator, ITextPointer limit, char[] text, int cchReq, ref int charsCopied, UnsafeNativeMethods.TS_RUNINFO[] runInfo, int cRunInfoReq, ref int cRunInfoRcv) { int runCount; int offset; bool hitLimit; Invariant.Assert(navigator.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text); Invariant.Assert(limit == null || navigator.CompareTo(limit) <= 0); hitLimit = false; if (cchReq > 0) { runCount = TextPointerBase.GetTextWithLimit(navigator, LogicalDirection.Forward, text, charsCopied, Math.Min(cchReq, text.Length - charsCopied), limit); navigator.MoveByOffset(runCount); charsCopied += runCount; hitLimit = (text.Length == charsCopied) || (limit != null && navigator.CompareTo(limit) == 0); } else { // Caller doesn't want text, just run info. // Advance the navigator. runCount = navigator.GetTextRunLength(LogicalDirection.Forward); navigator.MoveToNextContextPosition(LogicalDirection.Forward); // If the caller passed in a non-null limit, backup to the limit if // we've passed it. if (limit != null) { if (navigator.CompareTo(limit) >= 0) { offset = limit.GetOffsetToPosition(navigator); Invariant.Assert(offset >= 0 && offset <= runCount, "Bogus offset -- extends past run!"); runCount -= offset; navigator.MoveToPosition(limit); hitLimit = true; } } } if (cRunInfoReq > 0 && runCount > 0) { // Be sure to merge this text run with the previous run, if they are both text runs. // (A good robustness fix would be to make cicero handle this, if we ever get the chance.) if (cRunInfoRcv > 0 && runInfo[cRunInfoRcv - 1].type == UnsafeNativeMethods.TsRunType.TS_RT_PLAIN) { runInfo[cRunInfoRcv - 1].count += runCount; } else { runInfo[cRunInfoRcv].count = runCount; runInfo[cRunInfoRcv].type = UnsafeNativeMethods.TsRunType.TS_RT_PLAIN; cRunInfoRcv++; } } return hitLimit; }
// Exits the scope of a non-mergeable inline with inner edge in the direction indicated. private static int LeaveNonMergeableAncestor(ITextPointer thisNavigator, LogicalDirection direction) { int symbolCount = 0; int increment = (direction == LogicalDirection.Forward) ? +1 : -1; while (TextSchema.IsMergeableInline(thisNavigator.ParentType)) { thisNavigator.MoveToNextContextPosition(direction); symbolCount += increment; } thisNavigator.MoveToNextContextPosition(direction); symbolCount += increment; return symbolCount; }
/// <summary> /// Moves the navigator in the given direction to a position of the next /// word boundary. /// </summary> /// <param name="thisNavigator">ITextPointer to advance.</param> /// <param name="movingDirection"> /// Direction to move. /// </param> /// <returns></returns> // internal static bool MoveToNextWordBoundary(ITextPointer thisNavigator, LogicalDirection movingDirection) { int moveCounter = 0; Invariant.Assert(!thisNavigator.IsFrozen, "Can't reposition a frozen pointer!"); ITextPointer startPosition = thisNavigator.CreatePointer(); while (thisNavigator.MoveToNextInsertionPosition(movingDirection)) { moveCounter++; // Need to break the loop for weird case when there is no word break in text content. // When the word looks too long, consider end of textRun as a word break. // if (moveCounter > 64) // 64 was taken as a random number. Probably not big enough though... { thisNavigator.MoveToPosition(startPosition); thisNavigator.MoveToNextContextPosition(movingDirection); break; } if (IsAtWordBoundary(thisNavigator, /*insideWordDirection:*/LogicalDirection.Forward)) { // Note that we always use Forward direction for word orientation. break; } } return moveCounter > 0; }
// Part of plain text converter: called from GetTextInternal when processing ElementEnd for Listelements // Pops a current value from a stack of list item indices. private static void PlainConvertListEnd(ITextPointer navigator, ref Stack<int> listItemCounter) { // Note that we do not expect List tag balansing: // We can get more List closing tags than we had opening ones - // it happens when range starts in the middle of a list. if (listItemCounter != null && listItemCounter.Count > 0) { listItemCounter.Pop(); } navigator.MoveToNextContextPosition(LogicalDirection.Forward); }
// Part of plain text converter: called from GetTextInternal when processing Text runs private static void PlainConvertTextRun(StringBuilder textBuffer, ITextPointer navigator, ITextPointer endPosition, ref Char[] charArray) { // Copy this text run into destination int runLength = navigator.GetTextRunLength(LogicalDirection.Forward); charArray = EnsureCharArraySize(charArray, runLength); runLength = TextPointerBase.GetTextWithLimit(navigator, LogicalDirection.Forward, charArray, 0, runLength, endPosition); textBuffer.Append(charArray, 0, runLength); navigator.MoveToNextContextPosition(LogicalDirection.Forward); }
// Token: 0x060065D1 RID: 26065 RVA: 0x001C8918 File Offset: 0x001C6B18 ITextRangeProvider ITextProvider.RangeFromChild(IRawElementProviderSimple childElementProvider) { if (childElementProvider == null) { throw new ArgumentNullException("childElementProvider"); } DependencyObject dependencyObject; if (this._textPeer is TextAutomationPeer) { dependencyObject = ((TextAutomationPeer)this._textPeer).ElementFromProvider(childElementProvider); } else { dependencyObject = ((ContentTextAutomationPeer)this._textPeer).ElementFromProvider(childElementProvider); } TextRangeAdaptor textRangeAdaptor = null; if (dependencyObject != null) { ITextPointer textPointer = null; ITextPointer textPointer2 = null; if (dependencyObject is TextElement) { textPointer = ((TextElement)dependencyObject).ElementStart; textPointer2 = ((TextElement)dependencyObject).ElementEnd; } else { DependencyObject parent = LogicalTreeHelper.GetParent(dependencyObject); if (parent is InlineUIContainer || parent is BlockUIContainer) { textPointer = ((TextElement)parent).ContentStart; textPointer2 = ((TextElement)parent).ContentEnd; } else { ITextPointer textPointer3 = this._textContainer.Start.CreatePointer(); while (textPointer3.CompareTo(this._textContainer.End) < 0) { TextPointerContext pointerContext = textPointer3.GetPointerContext(LogicalDirection.Forward); if (pointerContext == TextPointerContext.ElementStart) { if (dependencyObject == textPointer3.GetAdjacentElement(LogicalDirection.Forward)) { textPointer = textPointer3.CreatePointer(LogicalDirection.Forward); textPointer3.MoveToElementEdge(ElementEdge.AfterEnd); textPointer2 = textPointer3.CreatePointer(LogicalDirection.Backward); break; } } else if (pointerContext == TextPointerContext.EmbeddedElement && dependencyObject == textPointer3.GetAdjacentElement(LogicalDirection.Forward)) { textPointer = textPointer3.CreatePointer(LogicalDirection.Forward); textPointer3.MoveToNextContextPosition(LogicalDirection.Forward); textPointer2 = textPointer3.CreatePointer(LogicalDirection.Backward); break; } textPointer3.MoveToNextContextPosition(LogicalDirection.Forward); } } } if (textPointer != null && textPointer2 != null) { textRangeAdaptor = new TextRangeAdaptor(this, textPointer, textPointer2, this._textPeer); } } if (textRangeAdaptor == null) { throw new InvalidOperationException(SR.Get("TextProvider_InvalidChildElement")); } return(textRangeAdaptor); }
//------------------------------------------------------------------- // // Internal Methods // //------------------------------------------------------------------- #region Internal Methods /// <summary> /// Retrieves a collection of AutomationPeers that fall within the range. /// Children that overlap with the range but are not entirely enclosed by /// it will also be included in the collection. /// </summary> internal static List<AutomationPeer> GetAutomationPeersFromRange(ITextPointer start, ITextPointer end, ITextPointer ownerContentStart) { bool positionMoved; AutomationPeer peer = null; object element; List<AutomationPeer> peers = new List<AutomationPeer>(); start = start.CreatePointer(); while (start.CompareTo(end) < 0) { // Indicate that 'start' position is not moved yet. positionMoved = false; if (start.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementStart) { // Get adjacent element and try to retrive AutomationPeer for it. element = start.GetAdjacentElement(LogicalDirection.Forward); if (element is ContentElement) { peer = ContentElementAutomationPeer.CreatePeerForElement((ContentElement)element); // If AutomationPeer has been retrieved, add it to the collection. // And skip entire element. if (peer != null) { if (ownerContentStart == null || IsImmediateAutomationChild(start, ownerContentStart)) { peers.Add(peer); } start.MoveToNextContextPosition(LogicalDirection.Forward); start.MoveToElementEdge(ElementEdge.AfterEnd); positionMoved = true; } } } else if (start.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.EmbeddedElement) { // Get adjacent element and try to retrive AutomationPeer for it. element = start.GetAdjacentElement(LogicalDirection.Forward); if (element is UIElement) { if (ownerContentStart == null || IsImmediateAutomationChild(start, ownerContentStart)) { peer = UIElementAutomationPeer.CreatePeerForElement((UIElement)element); // If AutomationPeer has been retrieved, add it to the collection. if (peer != null) { peers.Add(peer); } else { iterate((Visual)element, peers); } } } else if (element is ContentElement) { peer = ContentElementAutomationPeer.CreatePeerForElement((ContentElement)element); // If AutomationPeer has been retrieved, add it to the collection. if (peer != null) { if (ownerContentStart == null || IsImmediateAutomationChild(start, ownerContentStart)) { peers.Add(peer); } } } } // Move to the next content position, if position has not been moved already. if (!positionMoved) { if (!start.MoveToNextContextPosition(LogicalDirection.Forward)) { break; } } } return peers; }
// Returns true when one or both ends of the error lies at the inner edge of non-mergeable inline // such as Hyperlink. In this case, a TextRange will normalize its ends outside // the scope of the inline, and the corrected text will not be covered by it. // // We work around the common case, when the error is contained within a single // Run. In more complex cases we'll fail and fall back to using a TextRange. private static bool IsErrorAtNonMergeableInlineEdge(SpellingError spellingError, out ITextPointer textStart, out ITextPointer textEnd) { bool result = false; textStart = spellingError.Start.CreatePointer(LogicalDirection.Backward); while (textStart.CompareTo(spellingError.End) < 0 && textStart.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.Text) { textStart.MoveToNextContextPosition(LogicalDirection.Forward); } textEnd = spellingError.End.CreatePointer(); while (textEnd.CompareTo(spellingError.Start) > 0 && textEnd.GetPointerContext(LogicalDirection.Backward) != TextPointerContext.Text) { textEnd.MoveToNextContextPosition(LogicalDirection.Backward); } if (textStart.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.Text || textStart.CompareTo(spellingError.End) == 0) { return false; } Invariant.Assert(textEnd.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.Text && textEnd.CompareTo(spellingError.Start) != 0); if (TextPointerBase.IsAtNonMergeableInlineStart(textStart) || TextPointerBase.IsAtNonMergeableInlineEnd(textEnd)) { if (typeof(Run).IsAssignableFrom(textStart.ParentType) && textStart.HasEqualScope(textEnd)) { result = true; } } return result; }
// Token: 0x06002D1F RID: 11551 RVA: 0x000CBAC0 File Offset: 0x000C9CC0 internal object BuildObjectTree() { FixedElement.ElementType type = this._type; IAddChild addChild; if (type != FixedElement.ElementType.Paragraph) { switch (type) { case FixedElement.ElementType.Table: addChild = new Table(); goto IL_C7; case FixedElement.ElementType.TableRowGroup: addChild = new TableRowGroup(); goto IL_C7; case FixedElement.ElementType.TableRow: addChild = new TableRow(); goto IL_C7; case FixedElement.ElementType.TableCell: addChild = new TableCell(); goto IL_C7; case FixedElement.ElementType.Hyperlink: { Hyperlink hyperlink = new Hyperlink(); hyperlink.NavigateUri = (base.GetValue(FixedElement.NavigateUriProperty) as Uri); hyperlink.RequestNavigate += this.ClickHyperlink; AutomationProperties.SetHelpText(hyperlink, (string)base.GetValue(FixedElement.HelpTextProperty)); AutomationProperties.SetName(hyperlink, (string)base.GetValue(FixedElement.NameProperty)); addChild = hyperlink; goto IL_C7; } } addChild = null; } else { addChild = new Paragraph(); } IL_C7: ITextPointer textPointer = ((ITextPointer)this._start).CreatePointer(); while (textPointer.CompareTo(this._end) < 0) { TextPointerContext pointerContext = textPointer.GetPointerContext(LogicalDirection.Forward); if (pointerContext == TextPointerContext.Text) { addChild.AddText(textPointer.GetTextInRun(LogicalDirection.Forward)); } else if (pointerContext == TextPointerContext.EmbeddedElement) { addChild.AddChild(textPointer.GetAdjacentElement(LogicalDirection.Forward)); } else if (pointerContext == TextPointerContext.ElementStart) { object adjacentElement = textPointer.GetAdjacentElement(LogicalDirection.Forward); if (adjacentElement != null) { addChild.AddChild(adjacentElement); textPointer.MoveToNextContextPosition(LogicalDirection.Forward); textPointer.MoveToElementEdge(ElementEdge.BeforeEnd); } } textPointer.MoveToNextContextPosition(LogicalDirection.Forward); } return(addChild); }
// Move this TP by distance, and respect virtualization of child TextContainer // Return true if distance is within boundary of the aggregated container, false otherwise private static bool xGapAwareScan(DocumentSequenceTextPointer thisTp, int distance) { // // Note: To calculate distance between thisTp.ChildPointer to // it container Start/End position would have been devastating // for those who implemented vitualization. // Ideally we would need a new API on ITextPointer // ITextPointer.IsDistanceOutOfRange ChildDocumentBlock cdb = thisTp.ChildBlock; bool isNavigator = true; ITextPointer childTn = thisTp.ChildPointer; if (childTn == null) { isNavigator = false; childTn = thisTp.ChildPointer.CreatePointer(); } LogicalDirection scanDir = (distance > 0 ? LogicalDirection.Forward : LogicalDirection.Backward); distance = Math.Abs(distance); while (distance > 0) { TextPointerContext tst = childTn.GetPointerContext(scanDir); switch (tst) { case TextPointerContext.ElementStart: childTn.MoveToNextContextPosition(scanDir); distance--; break; case TextPointerContext.ElementEnd: childTn.MoveToNextContextPosition(scanDir); distance--; break; case TextPointerContext.EmbeddedElement: childTn.MoveToNextContextPosition(scanDir); distance--; break; case TextPointerContext.Text: int runLength = childTn.GetTextRunLength(scanDir); int moveLength = runLength < distance ? runLength : distance; distance -= moveLength; //agurcan: Fix for 1098225 //We need to propagate direction info to MoveByOffset if (scanDir == LogicalDirection.Backward) { moveLength *= -1; } childTn.MoveByOffset(moveLength); break; case TextPointerContext.None: if (!((cdb.IsHead && scanDir == LogicalDirection.Backward) || (cdb.IsTail && scanDir == LogicalDirection.Forward) ) ) { cdb = (scanDir == LogicalDirection.Forward ? cdb.NextBlock : cdb.PreviousBlock); childTn = (scanDir == LogicalDirection.Forward ? cdb.ChildContainer.Start.CreatePointer(childTn.LogicalDirection) : cdb.ChildContainer.End.CreatePointer(childTn.LogicalDirection) ); } else { return(false); } break; default: Debug.Assert(false, "invalid TextPointerContext"); break; } } // Re-position thisTp to the new location. thisTp.ChildBlock = cdb; if (isNavigator) { thisTp.ChildPointer = childTn; } else { thisTp.ChildPointer = childTn.CreatePointer(); } return(true); }
internal object BuildObjectTree() { IAddChild root; switch (_type) { case ElementType.Table: root = new Table(); break; case ElementType.TableRowGroup: root = new TableRowGroup(); break; case ElementType.TableRow: root = new TableRow(); break; case ElementType.TableCell: root = new TableCell(); break; case ElementType.Paragraph: root = new Paragraph(); break; case ElementType.Hyperlink: Hyperlink link = new Hyperlink(); link.NavigateUri = GetValue(NavigateUriProperty) as Uri; link.RequestNavigate += new RequestNavigateEventHandler(ClickHyperlink); AutomationProperties.SetHelpText(link, (String)this.GetValue(HelpTextProperty)); AutomationProperties.SetName(link, (String)this.GetValue(NameProperty)); root = link; break; default: Debug.Assert(false); root = null; break; } ITextPointer pos = ((ITextPointer)_start).CreatePointer(); while (pos.CompareTo((ITextPointer)_end) < 0) { TextPointerContext tpc = pos.GetPointerContext(LogicalDirection.Forward); if (tpc == TextPointerContext.Text) { root.AddText(pos.GetTextInRun(LogicalDirection.Forward)); } else if (tpc == TextPointerContext.EmbeddedElement) { root.AddChild(pos.GetAdjacentElement(LogicalDirection.Forward)); } else if (tpc == TextPointerContext.ElementStart) { object obj = pos.GetAdjacentElement(LogicalDirection.Forward); if (obj != null) { root.AddChild(obj); pos.MoveToNextContextPosition(LogicalDirection.Forward); pos.MoveToElementEdge(ElementEdge.BeforeEnd); } } pos.MoveToNextContextPosition(LogicalDirection.Forward); } return(root); }
//------------------------------------------------------ // // Private Methods // //------------------------------------------------------ #region Private Methods private void AddMultipleCompositionLines(ITextPointer start, ITextPointer end) { // Initalize the start/end line pointer ITextPointer startLinePointer = start; ITextPointer endLinePointer = startLinePointer; // Get all composition lines that includes the start/end pointer while (endLinePointer.CompareTo(end) < 0) { TextSegment textSegment = _textView.GetLineRange(endLinePointer); if (textSegment.IsNull) { // endLinePointer is not within the TextView's definition of a line. // Skip ahead to text on the next iteration. startLinePointer = endLinePointer; } else { Debug.Assert(start.CompareTo(startLinePointer) <= 0, "The start pointer is positioned after the composition start line pointer!"); if (startLinePointer.CompareTo(textSegment.Start) < 0) { // Update the start line pointer startLinePointer = textSegment.Start; } if (endLinePointer.CompareTo(textSegment.End) < 0) { if (end.CompareTo(textSegment.End) < 0) { // Update the end line pointer endLinePointer = end.CreatePointer(); } else { // Update the end line pointer endLinePointer = textSegment.End.CreatePointer(LogicalDirection.Backward); } } else { Debug.Assert(endLinePointer.CompareTo(textSegment.End) == 0, "The end line pointer is positioned after the composition text range end pointer!"); } // Get the rectangle for start/end position Rect startRect = _textView.GetRectangleFromTextPosition(startLinePointer); Rect endRect = _textView.GetRectangleFromTextPosition(endLinePointer); // Add the composition line to be rendered _compositionLines.Add(new CompositionLine(startRect, endRect, _textServicesDisplayAttribute.GetLineColor(startLinePointer))); startLinePointer = textSegment.End.CreatePointer(LogicalDirection.Forward); } // Move the start pointer to the next text line. startLinePointer must be a pointer to start // text. while ((startLinePointer.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.None) && (startLinePointer.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.Text)) { startLinePointer.MoveToNextContextPosition(LogicalDirection.Forward); } endLinePointer = startLinePointer; } }
// Part of plain text converter: called from GetTextInternal when processing ElementEnd for Paragraph elements. // Outputs \n - for regular paragraphs and TableRow ends or \t for TableCell ends. private static void PlainConvertParagraphEnd(StringBuilder textBuffer, ITextPointer navigator) { // Check for a special case for a single paragraph within a TableCell // which must be serialized as "\t" character. navigator.MoveToElementEdge(ElementEdge.BeforeStart); bool theParagraphIsTheFirstInCollection = navigator.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.ElementStart; navigator.MoveToNextContextPosition(LogicalDirection.Forward); navigator.MoveToElementEdge(ElementEdge.AfterEnd); TextPointerContext symbolType = navigator.GetPointerContext(LogicalDirection.Forward); if (theParagraphIsTheFirstInCollection && symbolType == TextPointerContext.ElementEnd && typeof(TableCell).IsAssignableFrom(navigator.ParentType)) { // This is an end of a table cell navigator.MoveToNextContextPosition(LogicalDirection.Forward); symbolType = navigator.GetPointerContext(LogicalDirection.Forward); if (symbolType == TextPointerContext.ElementStart) { // Next table cell starts after this one. Use '\t' as a cell separator textBuffer.Append('\t'); } else { // This was the last cell in a row. Use '\r\n' as a line separator textBuffer.Append(Environment.NewLine); } } else { // Ordinary paragraph end textBuffer.Append(Environment.NewLine); } }
// Token: 0x060039BC RID: 14780 RVA: 0x00106178 File Offset: 0x00104378 private static int SetFindTextAndFindTextPositionMap(ITextPointer startPosition, ITextPointer endPosition, ITextPointer navigator, LogicalDirection direction, bool matchLast, char[] findText, int[] findTextPositionMap) { Invariant.Assert(startPosition.CompareTo(navigator) <= 0); Invariant.Assert(endPosition.CompareTo(navigator) >= 0); int num = 0; int num2 = 0; if (matchLast && num2 == 0) { findTextPositionMap[findTextPositionMap.Length - 1] = 0; } while ((matchLast ? startPosition.CompareTo(navigator) : navigator.CompareTo(endPosition)) < 0) { switch (navigator.GetPointerContext(direction)) { case TextPointerContext.None: case TextPointerContext.ElementStart: case TextPointerContext.ElementEnd: if (TextFindEngine.IsAdjacentToFormatElement(navigator, direction)) { num++; } else if (!matchLast) { findText[num2] = '\n'; findTextPositionMap[num2] = num2 + num; num2++; } else { num2++; findText[findText.Length - num2] = '\n'; findTextPositionMap[findText.Length - num2] = num2 + num; } navigator.MoveToNextContextPosition(direction); break; case TextPointerContext.Text: { int num3 = navigator.GetTextRunLength(direction); num3 = Math.Min(num3, findText.Length - num2); if (!matchLast) { num3 = Math.Min(num3, navigator.GetOffsetToPosition(endPosition)); navigator.GetTextInRun(direction, findText, num2, num3); for (int i = num2; i < num2 + num3; i++) { findTextPositionMap[i] = i + num; } } else { num3 = Math.Min(num3, startPosition.GetOffsetToPosition(navigator)); navigator.GetTextInRun(direction, findText, findText.Length - num2 - num3, num3); int num4 = findText.Length - num2 - 1; for (int j = num2; j < num2 + num3; j++) { findTextPositionMap[num4--] = j + num + 1; } } navigator.MoveByOffset(matchLast ? (-num3) : num3); num2 += num3; break; } case TextPointerContext.EmbeddedElement: if (!matchLast) { findText[num2] = ''; findTextPositionMap[num2] = num2 + num; num2++; } else { num2++; findText[findText.Length - num2] = ''; findTextPositionMap[findText.Length - num2] = num2 + num; } navigator.MoveToNextContextPosition(direction); break; } if (num2 >= findText.Length) { break; } } if (!matchLast) { if (num2 > 0) { findTextPositionMap[num2] = findTextPositionMap[num2 - 1] + 1; } else { findTextPositionMap[0] = 0; } } return(num2); }
/// <summary> /// Determine paragraph type at the current TextPointer and /// create it. Only ListItem elements are considered. Any other /// content is skipped. /// </summary> /// <param name="textPointer"> /// TextPointer at which paragraph is to be created /// </param> /// <param name="fEmptyOk"> /// True if empty paragraph is acceptable /// </param> /// <returns> /// BaseParagraph that was created /// </returns> protected override BaseParagraph GetParagraph(ITextPointer textPointer, bool fEmptyOk) { Invariant.Assert(textPointer is TextPointer); BaseParagraph paragraph = null; while (paragraph == null) { TextPointerContext runType = textPointer.GetPointerContext(LogicalDirection.Forward); if (runType == TextPointerContext.ElementStart) { TextElement element = ((TextPointer)textPointer).GetAdjacentElementFromOuterPosition(LogicalDirection.Forward); if (element is ListItem) { // paragraph = new ListItemParagraph(element, StructuralCache); break; } else if (element is List) { // paragraph = new ListParagraph(element, StructuralCache); break; } // Skip all elements, which are not valid list item children if (((TextPointer)textPointer).IsFrozen) { // Need to clone TextPointer before moving it. textPointer = textPointer.CreatePointer(); } textPointer.MoveToPosition(element.ElementEnd); } else if (runType == TextPointerContext.ElementEnd) { // End of list, if the same as Owner of associated element // Skip content otherwise if (Element == ((TextPointer)textPointer).Parent) { break; } if (((TextPointer)textPointer).IsFrozen) { // Need to clone TextPointer before moving it. textPointer = textPointer.CreatePointer(); } textPointer.MoveToNextContextPosition(LogicalDirection.Forward); } else { // Skip content if (((TextPointer)textPointer).IsFrozen) { // Need to clone TextPointer before moving it. textPointer = textPointer.CreatePointer(); } textPointer.MoveToNextContextPosition(LogicalDirection.Forward); } } if (paragraph != null) { StructuralCache.CurrentFormatContext.DependentMax = (TextPointer)textPointer; } return paragraph; }
/// <summary> /// Determine paragraph type at the current TextPointer and /// create it. Only ListItem elements are considered. Any other /// content is skipped. /// </summary> /// <param name="textPointer"> /// TextPointer at which paragraph is to be created /// </param> /// <param name="fEmptyOk"> /// True if empty paragraph is acceptable /// </param> /// <returns> /// BaseParagraph that was created /// </returns> protected override BaseParagraph GetParagraph(ITextPointer textPointer, bool fEmptyOk) { Invariant.Assert(textPointer is TextPointer); BaseParagraph paragraph = null; while (paragraph == null) { TextPointerContext runType = textPointer.GetPointerContext(LogicalDirection.Forward); if (runType == TextPointerContext.ElementStart) { TextElement element = ((TextPointer)textPointer).GetAdjacentElementFromOuterPosition(LogicalDirection.Forward); if (element is ListItem) { // Need to handle visibility collapsed. //Visibility visibility = Retriever.Visibility(treePtr.CPPtr.Element); //if (visibility != Visibility.Collapsed) //{ // para = new //} //else skip the element paragraph = new ListItemParagraph(element, StructuralCache); break; } else if (element is List) { // Need to handle visibility collapsed. //Visibility visibility = Retriever.Visibility(treePtr.CPPtr.Element); //if (visibility != Visibility.Collapsed) //{ // para = new //} //else skip the element paragraph = new ListParagraph(element, StructuralCache); break; } // Skip all elements, which are not valid list item children if (((TextPointer)textPointer).IsFrozen) { // Need to clone TextPointer before moving it. textPointer = textPointer.CreatePointer(); } textPointer.MoveToPosition(element.ElementEnd); } else if (runType == TextPointerContext.ElementEnd) { // End of list, if the same as Owner of associated element // Skip content otherwise if (Element == ((TextPointer)textPointer).Parent) { break; } if (((TextPointer)textPointer).IsFrozen) { // Need to clone TextPointer before moving it. textPointer = textPointer.CreatePointer(); } textPointer.MoveToNextContextPosition(LogicalDirection.Forward); } else { // Skip content if (((TextPointer)textPointer).IsFrozen) { // Need to clone TextPointer before moving it. textPointer = textPointer.CreatePointer(); } textPointer.MoveToNextContextPosition(LogicalDirection.Forward); } } if (paragraph != null) { StructuralCache.CurrentFormatContext.DependentMax = (TextPointer)textPointer; } return(paragraph); }
//------------------------------------------------------ // // 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; }
/// <summary> /// Helper function to move given position to word boundary. TextPointerBase.MoveToNextWordBoundary /// cannot be used directly, because it does not modify LogicalDirection. Because of that, IsAtWordBoundary /// for just moved positions may return FALSE. /// </summary> private static bool MoveToNextWordBoundary(ITextPointer position, LogicalDirection direction) { int moveCounter = 0; ITextPointer startPosition = position.CreatePointer(); // Move the position in the given direction until word boundary is reached. while (position.MoveToNextInsertionPosition(direction)) { moveCounter++; if (IsAtWordBoundary(position)) { break; } // Need to break the loop for weird case when there is no word break in text content. // When the word looks too long, consider end of textRun as a word break. if (moveCounter > 128) // 128 was taken as a random number. Probably not big enough though... { position.MoveToPosition(startPosition); position.MoveToNextContextPosition(direction); break; } } // Note that we always use Forward direction for word orientation. if (moveCounter > 0) { position.SetLogicalDirection(LogicalDirection.Forward); } return moveCounter > 0; }
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; }
/// <summary> /// Moves the position to the closes unit boundary. /// </summary> private bool MoveToUnitBoundary(ITextPointer position, bool isStart, LogicalDirection direction, TextUnit unit) { bool moved = false; ITextView textView; switch (unit) { case TextUnit.Character: if (!TextPointerBase.IsAtInsertionPosition(position)) { if (TextPointerBase.MoveToNextInsertionPosition(position, direction)) { moved = true; } } break; case TextUnit.Word: if (!IsAtWordBoundary(position)) { if (MoveToNextWordBoundary(position, direction)) { moved = true; } } 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 (position.GetPointerContext(direction) == TextPointerContext.Text) { if (position.MoveToNextContextPosition(direction)) { moved = true; } } // Make sure we end with text on the right, so that later ExpandToEnclosingUnit calls // do the right thing. if (moved && direction == LogicalDirection.Forward) { while (true) { TextPointerContext context = position.GetPointerContext(LogicalDirection.Forward); if (context != TextPointerContext.ElementStart && context != TextPointerContext.ElementEnd) break; position.MoveToNextContextPosition(LogicalDirection.Forward); } } break; case TextUnit.Line: // Positions are snapped to closest line boundaries. But since line information // is based on the layout, positions are not changed, if: // a) they are not currently in the view, or // b) containing line cannot be found. textView = _textAdaptor.GetUpdatedTextView(); if (textView != null && textView.IsValid && textView.Contains(position)) { TextSegment lineRange = textView.GetLineRange(position); if (!lineRange.IsNull) { double newSuggestedX; int linesMoved = 0; if (direction == LogicalDirection.Forward) { ITextPointer nextLineStart = null; if (isStart) { nextLineStart = textView.GetPositionAtNextLine(lineRange.End, Double.NaN, 1, out newSuggestedX, out linesMoved); } if (linesMoved != 0) { lineRange = textView.GetLineRange(nextLineStart); nextLineStart = lineRange.Start; } else { nextLineStart = lineRange.End; } nextLineStart = GetInsertionPosition(nextLineStart, LogicalDirection.Forward); if (position.CompareTo(nextLineStart) != 0) { position.MoveToPosition(nextLineStart); position.SetLogicalDirection(isStart ? LogicalDirection.Forward : LogicalDirection.Backward); moved = true; } } else { ITextPointer previousLineEnd = null; if (!isStart) { previousLineEnd = textView.GetPositionAtNextLine(lineRange.Start, Double.NaN, -1, out newSuggestedX, out linesMoved); } if (linesMoved != 0) { lineRange = textView.GetLineRange(previousLineEnd); previousLineEnd = lineRange.End; } else { previousLineEnd = lineRange.Start; } previousLineEnd = GetInsertionPosition(previousLineEnd, LogicalDirection.Backward); if (position.CompareTo(previousLineEnd) != 0) { position.MoveToPosition(previousLineEnd); position.SetLogicalDirection(isStart ? LogicalDirection.Forward : LogicalDirection.Backward); moved = true; } } } } break; case TextUnit.Paragraph: // Utilize TextRange logic to determine paragraph boundaries. ITextRange textRange = new TextRange(position, position); TextRangeBase.SelectParagraph(textRange, position); if (direction == LogicalDirection.Forward) { ITextPointer nextParagraphStart = textRange.End; if (isStart) { nextParagraphStart = nextParagraphStart.CreatePointer(); if (nextParagraphStart.MoveToNextInsertionPosition(LogicalDirection.Forward)) { TextRangeBase.SelectParagraph(textRange, nextParagraphStart); nextParagraphStart = textRange.Start; } } if (position.CompareTo(nextParagraphStart) != 0) { position.MoveToPosition(nextParagraphStart); position.SetLogicalDirection(isStart ? LogicalDirection.Forward : LogicalDirection.Backward); moved = true; } } else { ITextPointer previousParagraphEnd = textRange.Start; if (!isStart) { previousParagraphEnd = previousParagraphEnd.CreatePointer(); if (previousParagraphEnd.MoveToNextInsertionPosition(LogicalDirection.Backward)) { TextRangeBase.SelectParagraph(textRange, previousParagraphEnd); previousParagraphEnd = textRange.End; } } if (position.CompareTo(previousParagraphEnd) != 0) { position.MoveToPosition(previousParagraphEnd); position.SetLogicalDirection(isStart ? LogicalDirection.Forward : LogicalDirection.Backward); moved = true; } } break; case TextUnit.Page: // Positions are snapped to nearest page boundaries. But since page information // is based on the layout, positions are not changed, if they are not currently in the view. // We need to consider 2 types of scenarios: single page and multi-page. // In case of multi-page scenario, first need to find a page associated with the position. // If page is found, move the start position to the beginning of the first range of that page // and move the end position to the end of the last range of that page. textView = _textAdaptor.GetUpdatedTextView(); if (textView != null && textView.IsValid && textView.Contains(position)) { ITextView pageTextView = textView; if (textView is MultiPageTextView) { // This is "multi page" case. Find page associated with the start position. pageTextView = ((MultiPageTextView)textView).GetPageTextViewFromPosition(position); } ReadOnlyCollection<TextSegment> textSegments = pageTextView.TextSegments; if (textSegments != null && textSegments.Count > 0) { //When comparing, we need to take into account if the pointer is not right at //the end of the page (or beginning) because of normalization if (direction == LogicalDirection.Forward) { while (position.CompareTo(textSegments[textSegments.Count - 1].End) != 0) { if (position.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.ElementEnd) { position.MoveToPosition(textSegments[textSegments.Count - 1].End); moved = true; break; } Invariant.Assert(position.MoveToNextContextPosition(LogicalDirection.Forward)); } MoveToInsertionPosition(position, LogicalDirection.Forward); } else { while (position.CompareTo(textSegments[0].Start) != 0) { if (position.GetPointerContext(LogicalDirection.Backward) != TextPointerContext.ElementStart) { position.MoveToPosition(textSegments[0].Start); moved = true; break; } Invariant.Assert(position.MoveToNextContextPosition(LogicalDirection.Backward)); } MoveToInsertionPosition(position, LogicalDirection.Backward); } } } break; case TextUnit.Document: if (direction == LogicalDirection.Forward) { if (position.CompareTo(GetInsertionPosition(position.TextContainer.End, LogicalDirection.Backward)) != 0) { position.MoveToPosition(position.TextContainer.End); moved = true; } } else { if (position.CompareTo(GetInsertionPosition(position.TextContainer.Start, LogicalDirection.Forward)) != 0) { position.MoveToPosition(position.TextContainer.Start); moved = true; } } break; default: // Unknown unit break; } return moved; }
// GetText handler for object runs. private static bool WalkObjectRun(ITextPointer navigator, ITextPointer limit, char[] text, int cchReq, ref int charsCopied, UnsafeNativeMethods.TS_RUNINFO[] runInfo, int cRunInfoReq, ref int cRunInfoRcv) { bool hitLimit; Invariant.Assert(navigator.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.EmbeddedElement); Invariant.Assert(limit == null || navigator.CompareTo(limit) <= 0); if (limit != null && navigator.CompareTo(limit) == 0) { return true; } hitLimit = false; navigator.MoveToNextContextPosition(LogicalDirection.Forward); if (cchReq >= 1) { text[charsCopied] = UnsafeNativeMethods.TS_CHAR_EMBEDDED; charsCopied++; } if (cRunInfoReq > 0) { // Be sure to merge this text run with the previous run, if they are both text runs. // (A good robustness fix would be to make cicero handle this, if we ever get the chance.) if (cRunInfoRcv > 0 && runInfo[cRunInfoRcv - 1].type == UnsafeNativeMethods.TsRunType.TS_RT_PLAIN) { runInfo[cRunInfoRcv - 1].count++; } else { runInfo[cRunInfoRcv].count = 1; runInfo[cRunInfoRcv].type = UnsafeNativeMethods.TsRunType.TS_RT_PLAIN; cRunInfoRcv++; } } return hitLimit; }
//------------------------------------------------------------------- // // Internal Methods // //------------------------------------------------------------------- #region Internal Methods /// <summary> /// Retrieves a collection of AutomationPeers that fall within the range. /// Children that overlap with the range but are not entirely enclosed by /// it will also be included in the collection. /// </summary> internal static List <AutomationPeer> GetAutomationPeersFromRange(ITextPointer start, ITextPointer end, ITextPointer ownerContentStart) { bool positionMoved; AutomationPeer peer = null; object element; List <AutomationPeer> peers = new List <AutomationPeer>(); start = start.CreatePointer(); while (start.CompareTo(end) < 0) { // Indicate that 'start' position is not moved yet. positionMoved = false; if (start.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementStart) { // Get adjacent element and try to retrive AutomationPeer for it. element = start.GetAdjacentElement(LogicalDirection.Forward); if (element is ContentElement) { peer = ContentElementAutomationPeer.CreatePeerForElement((ContentElement)element); // If AutomationPeer has been retrieved, add it to the collection. // And skip entire element. if (peer != null) { if (ownerContentStart == null || IsImmediateAutomationChild(start, ownerContentStart)) { peers.Add(peer); } start.MoveToNextContextPosition(LogicalDirection.Forward); start.MoveToElementEdge(ElementEdge.AfterEnd); positionMoved = true; } } } else if (start.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.EmbeddedElement) { // Get adjacent element and try to retrive AutomationPeer for it. element = start.GetAdjacentElement(LogicalDirection.Forward); if (element is UIElement) { if (ownerContentStart == null || IsImmediateAutomationChild(start, ownerContentStart)) { peer = UIElementAutomationPeer.CreatePeerForElement((UIElement)element); // If AutomationPeer has been retrieved, add it to the collection. if (peer != null) { peers.Add(peer); } else { iterate((Visual)element, peers); } } } else if (element is ContentElement) { peer = ContentElementAutomationPeer.CreatePeerForElement((ContentElement)element); // If AutomationPeer has been retrieved, add it to the collection. if (peer != null) { if (ownerContentStart == null || IsImmediateAutomationChild(start, ownerContentStart)) { peers.Add(peer); } } } } // Move to the next content position, if position has not been moved already. if (!positionMoved) { if (!start.MoveToNextContextPosition(LogicalDirection.Forward)) { break; } } } return(peers); }
// Normalizes a range: // // -The start position is advanced over all element edges not visible // to the IMEs. // -Start and end positions are moved to insertion positions. private void GetNormalizedRange(int startCharOffset, int endCharOffset, out ITextPointer start, out ITextPointer end) { start = CreatePointerAtCharOffset(startCharOffset, LogicalDirection.Forward); end = (startCharOffset == endCharOffset) ? start : CreatePointerAtCharOffset(endCharOffset, LogicalDirection.Backward); // Skip over hidden element edges. while (start.CompareTo(end) < 0) { TextPointerContext forwardContext = start.GetPointerContext(LogicalDirection.Forward); if (forwardContext == TextPointerContext.ElementStart) { TextElement element = start.GetAdjacentElement(LogicalDirection.Forward) as TextElement; if (element == null) break; if (element.IMELeftEdgeCharCount != 0) break; } else if (forwardContext != TextPointerContext.ElementEnd) { break; } start.MoveToNextContextPosition(LogicalDirection.Forward); } // Move to insertion positions. // If the positions are already adjacent to text, we must respect // the IME's decision in regards to exact placement. // MoveToInsertionPosition will skip over surrogates and combining // marks, but the IME needs fine-grained control over these positions. if (start.CompareTo(end) == 0) { start = start.GetFormatNormalizedPosition(LogicalDirection.Backward); end = start; } else { start = start.GetFormatNormalizedPosition(LogicalDirection.Backward); end = end.GetFormatNormalizedPosition(LogicalDirection.Backward); } }
/// <summary> /// Retrieves the range of a child object. /// </summary> /// <param name="childElementProvider">The child element. A provider should check that the /// passed element is a child of the text container, and should throw an /// InvalidOperationException if it is not.</param> /// <returns>A range that spans the child element.</returns> ITextRangeProvider ITextProvider.RangeFromChild(IRawElementProviderSimple childElementProvider) { if (childElementProvider == null) { throw new ArgumentNullException("childElementProvider"); } // Retrieve DependencyObject from AutomationElement DependencyObject childElement; if (_textPeer is TextAutomationPeer) { childElement = ((TextAutomationPeer)_textPeer).ElementFromProvider(childElementProvider); } else { childElement = ((ContentTextAutomationPeer)_textPeer).ElementFromProvider(childElementProvider); } TextRangeAdaptor range = null; if (childElement != null) { ITextPointer rangeStart = null; ITextPointer rangeEnd = null; // Retrieve start and end positions for given element. // If element is TextElement, retrieve its Element Start and End positions. // If element is UIElement hosted by UIContainer (Inlien of Block), // retrieve content Start and End positions of the container. // Otherwise scan ITextContainer to find a range for given element. if (childElement is TextElement) { rangeStart = ((TextElement)childElement).ElementStart; rangeEnd = ((TextElement)childElement).ElementEnd; } else { DependencyObject parent = LogicalTreeHelper.GetParent(childElement); if (parent is InlineUIContainer || parent is BlockUIContainer) { rangeStart = ((TextElement)parent).ContentStart; rangeEnd = ((TextElement)parent).ContentEnd; } else { ITextPointer position = _textContainer.Start.CreatePointer(); while (position.CompareTo(_textContainer.End) < 0) { TextPointerContext context = position.GetPointerContext(LogicalDirection.Forward); if (context == TextPointerContext.ElementStart) { if (childElement == position.GetAdjacentElement(LogicalDirection.Forward)) { rangeStart = position.CreatePointer(LogicalDirection.Forward); position.MoveToElementEdge(ElementEdge.AfterEnd); rangeEnd = position.CreatePointer(LogicalDirection.Backward); break; } } else if (context == TextPointerContext.EmbeddedElement) { if (childElement == position.GetAdjacentElement(LogicalDirection.Forward)) { rangeStart = position.CreatePointer(LogicalDirection.Forward); position.MoveToNextContextPosition(LogicalDirection.Forward); rangeEnd = position.CreatePointer(LogicalDirection.Backward); break; } } position.MoveToNextContextPosition(LogicalDirection.Forward); } } } // Create range if (rangeStart != null && rangeEnd != null) { range = new TextRangeAdaptor(this, rangeStart, rangeEnd, _textPeer); } } if (range == null) { throw new InvalidOperationException(SR.Get(SRID.TextProvider_InvalidChildElement)); } return(range); }
/// <summary> /// Set the find text content from reading the text on the current text position. /// </summary> /// <returns> /// Returns the number of characters actually loaded into the findText array. /// </returns> private static int SetFindTextAndFindTextPositionMap( ITextPointer startPosition, ITextPointer endPosition, ITextPointer navigator, LogicalDirection direction, bool matchLast, char[] findText, int[] findTextPositionMap) { Invariant.Assert(startPosition.CompareTo(navigator) <= 0); Invariant.Assert(endPosition.CompareTo(navigator) >= 0); int runCount; int inlineCount = 0; int findTextLength = 0; // Set the first offset which is zero on TextBufferSize + 1 location of // the text position map in case of the backward searching if (matchLast && findTextLength == 0) { findTextPositionMap[findTextPositionMap.Length - 1] = 0; } while ((matchLast ? startPosition.CompareTo(navigator) : navigator.CompareTo(endPosition)) < 0) { switch (navigator.GetPointerContext(direction)) { case TextPointerContext.Text: runCount = navigator.GetTextRunLength(direction); runCount = Math.Min(runCount, findText.Length - findTextLength); if (!matchLast) { runCount = Math.Min(runCount, navigator.GetOffsetToPosition(endPosition)); navigator.GetTextInRun(direction, findText, findTextLength, runCount); for (int i = findTextLength; i < findTextLength + runCount; i++) { findTextPositionMap[i] = i + inlineCount; } } else { runCount = Math.Min(runCount, startPosition.GetOffsetToPosition(navigator)); navigator.GetTextInRun( direction, findText, findText.Length - findTextLength - runCount, runCount); // Set the text offest for the amount of runCount from the last index // of text position map int mapIndex = findText.Length - findTextLength - 1; for (int i = findTextLength; i < findTextLength + runCount; i++) { findTextPositionMap[mapIndex--] = i + inlineCount + 1; } } // Move the navigator position for the amount of runCount navigator.MoveByOffset(matchLast ? -runCount : runCount); findTextLength += runCount; break; case TextPointerContext.None: case TextPointerContext.ElementStart: case TextPointerContext.ElementEnd: if (IsAdjacentToFormatElement(navigator, direction)) { // Filter out formatting tags since find text content is plain. inlineCount++; } else { if (!matchLast) { // Stick in a line break to account for the block element. findText[findTextLength] = '\n'; findTextPositionMap[findTextLength] = findTextLength + inlineCount; findTextLength++; } else { // Increse the find text length first since adding text and map reversely findTextLength++; // Stick in a line break to account for the block element and // add text offset on the last index of text position map findText[findText.Length - findTextLength] = '\n'; findTextPositionMap[findText.Length - findTextLength] = findTextLength + inlineCount; } } navigator.MoveToNextContextPosition(direction); break; case TextPointerContext.EmbeddedElement: if (!matchLast) { findText[findTextLength] = '\xf8ff'; // Unicode private use. findTextPositionMap[findTextLength] = findTextLength + inlineCount; findTextLength++; } else { // Increse the find text length first since adding text and map reversely findTextLength++; // Set the private unicode value and text offset findText[findText.Length - findTextLength] = '\xf8ff'; findTextPositionMap[findText.Length - findTextLength] = findTextLength + inlineCount; } navigator.MoveToNextContextPosition(direction); break; } if (findTextLength >= findText.Length) { break; } } // Complete the adding the find text position to the position map for only the forward finding. // The backward finding(matchLast) is already added initially as the zero offset at the end of // text position map. if (!matchLast) { if (findTextLength > 0) { findTextPositionMap[findTextLength] = findTextPositionMap[findTextLength - 1] + 1; } else { findTextPositionMap[0] = 0; } } return(findTextLength); }
// 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); } }
/// <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; }
/// <summary> /// Set the find text content from reading the text on the current text position. /// </summary> /// <returns> /// Returns the number of characters actually loaded into the findText array. /// </returns> private static int SetFindTextAndFindTextPositionMap( ITextPointer startPosition, ITextPointer endPosition, ITextPointer navigator, LogicalDirection direction, bool matchLast, char[] findText, int[] findTextPositionMap) { Invariant.Assert(startPosition.CompareTo(navigator) <= 0); Invariant.Assert(endPosition.CompareTo(navigator) >= 0); int runCount; int inlineCount = 0; int findTextLength = 0; // Set the first offset which is zero on TextBufferSize + 1 location of // the text position map in case of the backward searching if (matchLast && findTextLength == 0) { findTextPositionMap[findTextPositionMap.Length - 1] = 0; } while ((matchLast ? startPosition.CompareTo(navigator) : navigator.CompareTo(endPosition)) < 0) { switch (navigator.GetPointerContext(direction)) { case TextPointerContext.Text: runCount = navigator.GetTextRunLength(direction); runCount = Math.Min(runCount, findText.Length - findTextLength); if (!matchLast) { runCount = Math.Min(runCount, navigator.GetOffsetToPosition(endPosition)); navigator.GetTextInRun(direction, findText, findTextLength, runCount); for (int i = findTextLength; i < findTextLength + runCount; i++) { findTextPositionMap[i] = i + inlineCount; } } else { runCount = Math.Min(runCount, startPosition.GetOffsetToPosition(navigator)); navigator.GetTextInRun( direction, findText, findText.Length - findTextLength - runCount, runCount); // Set the text offest for the amount of runCount from the last index // of text position map int mapIndex = findText.Length - findTextLength - 1; for (int i = findTextLength; i < findTextLength + runCount; i++) { findTextPositionMap[mapIndex--] = i + inlineCount + 1; } } // Move the navigator position for the amount of runCount navigator.MoveByOffset(matchLast ? - runCount : runCount); findTextLength += runCount; break; case TextPointerContext.None: case TextPointerContext.ElementStart: case TextPointerContext.ElementEnd: if (IsAdjacentToFormatElement(navigator, direction)) { // Filter out formatting tags since find text content is plain. inlineCount++; } else { if (!matchLast) { // Stick in a line break to account for the block element. findText[findTextLength] = '\n'; findTextPositionMap[findTextLength] = findTextLength + inlineCount; findTextLength++; } else { // Increse the find text length first since adding text and map reversely findTextLength++; // Stick in a line break to account for the block element and // add text offset on the last index of text position map findText[findText.Length - findTextLength] = '\n'; findTextPositionMap[findText.Length - findTextLength] = findTextLength + inlineCount; } } navigator.MoveToNextContextPosition(direction); break; case TextPointerContext.EmbeddedElement: if (!matchLast) { findText[findTextLength] = '\xf8ff'; // Unicode private use. findTextPositionMap[findTextLength] = findTextLength + inlineCount; findTextLength++; } else { // Increse the find text length first since adding text and map reversely findTextLength++; // Set the private unicode value and text offset findText[findText.Length - findTextLength] = '\xf8ff'; findTextPositionMap[findText.Length - findTextLength] = findTextLength + inlineCount; } navigator.MoveToNextContextPosition(direction); break; } if (findTextLength >= findText.Length) { break; } } // Complete the adding the find text position to the position map for only the forward finding. // The backward finding(matchLast) is already added initially as the zero offset at the end of // text position map. if (!matchLast) { if (findTextLength > 0) { findTextPositionMap[findTextLength] = findTextPositionMap[findTextLength - 1] + 1; } else { findTextPositionMap[0] = 0; } } return findTextLength; }