// Token: 0x060038DB RID: 14555 RVA: 0x00100F94 File Offset: 0x000FF194 private static ITextPointer GetNextTextPosition(ITextPointer position, ITextPointer limit, LogicalDirection direction, out char character) { bool flag = false; character = '\0'; while (position != null && !flag && (limit == null || position.CompareTo(limit) < 0)) { switch (position.GetPointerContext(direction)) { case TextPointerContext.Text: { char[] array = new char[1]; position.GetTextInRun(direction, array, 0, 1); character = array[0]; flag = true; continue; } case TextPointerContext.ElementStart: case TextPointerContext.ElementEnd: if (TextSchema.IsFormattingType(position.GetElementType(direction))) { position = position.CreatePointer(1); continue; } position = null; continue; } position = null; } return(position); }
// Token: 0x06002EFA RID: 12026 RVA: 0x000D47DC File Offset: 0x000D29DC private void _SkipFormattingTags(ITextPointer textPointer) { LogicalDirection logicalDirection = textPointer.LogicalDirection; int offset = (logicalDirection == LogicalDirection.Forward) ? 1 : -1; while (TextSchema.IsFormattingType(textPointer.GetElementType(logicalDirection))) { textPointer.MoveByOffset(offset); } }
private void _SkipFormattingTags(ITextPointer textPointer) { Debug.Assert(!textPointer.IsFrozen, "Can't reposition a frozen pointer!"); LogicalDirection dir = textPointer.LogicalDirection; int increment = (dir == LogicalDirection.Forward ? +1 : -1); while (TextSchema.IsFormattingType(textPointer.GetElementType(dir))) { textPointer.MoveByOffset(increment); } }
/// <summary> /// Returns true if pointer preceeds an Inline start or end edge. /// </summary> private static bool IsAdjacentToFormatElement(ITextPointer pointer, LogicalDirection direction) { TextPointerContext context; bool isAdjacentToFormatElement; isAdjacentToFormatElement = false; if (direction == LogicalDirection.Forward) { context = pointer.GetPointerContext(LogicalDirection.Forward); if (context == TextPointerContext.ElementStart && TextSchema.IsFormattingType(pointer.GetElementType(LogicalDirection.Forward))) { isAdjacentToFormatElement = true; } else if (context == TextPointerContext.ElementEnd && TextSchema.IsFormattingType(pointer.ParentType)) { isAdjacentToFormatElement = true; } } else { context = pointer.GetPointerContext(LogicalDirection.Backward); if (context == TextPointerContext.ElementEnd && TextSchema.IsFormattingType(pointer.GetElementType(LogicalDirection.Backward))) { isAdjacentToFormatElement = true; } else if (context == TextPointerContext.ElementStart && TextSchema.IsFormattingType(pointer.ParentType)) { isAdjacentToFormatElement = true; } } return(isAdjacentToFormatElement); }
// Token: 0x06008E5B RID: 36443 RVA: 0x0025BE9C File Offset: 0x0025A09C private void GetContent() { this._contentSegments.Clear(); ITextPointer textPointer = this._segment.Start.CreatePointer(); ITextPointer textPointer2 = null; while (textPointer.CompareTo(this._segment.End) < 0) { TextPointerContext pointerContext = textPointer.GetPointerContext(LogicalDirection.Forward); if (pointerContext == TextPointerContext.ElementStart) { Type elementType = textPointer.GetElementType(LogicalDirection.Forward); if (typeof(Run).IsAssignableFrom(elementType) || typeof(BlockUIContainer).IsAssignableFrom(elementType)) { this.OpenSegment(ref textPointer2, textPointer); } else if (typeof(Table).IsAssignableFrom(elementType) || typeof(Floater).IsAssignableFrom(elementType) || typeof(Figure).IsAssignableFrom(elementType)) { this.CloseSegment(ref textPointer2, textPointer, this._segment.End); } textPointer.MoveToNextContextPosition(LogicalDirection.Forward); if (typeof(Run).IsAssignableFrom(elementType) || typeof(BlockUIContainer).IsAssignableFrom(elementType)) { textPointer.MoveToElementEdge(ElementEdge.AfterEnd); } } else if (pointerContext == TextPointerContext.ElementEnd) { Type parentType = textPointer.ParentType; if (typeof(TableCell).IsAssignableFrom(parentType) || typeof(Floater).IsAssignableFrom(parentType) || typeof(Figure).IsAssignableFrom(parentType)) { this.CloseSegment(ref textPointer2, textPointer, this._segment.End); } textPointer.MoveToNextContextPosition(LogicalDirection.Forward); } else if (pointerContext == TextPointerContext.Text || pointerContext == TextPointerContext.EmbeddedElement) { this.OpenSegment(ref textPointer2, textPointer); textPointer.MoveToNextContextPosition(LogicalDirection.Forward); } else { Invariant.Assert(false, "unexpected TextPointerContext"); } } this.CloseSegment(ref textPointer2, textPointer, this._segment.End); }
// Returns the position preceeding the next text character in a specified // direction, or null if no such position exists. // The scan will halt if limit is encounted; limit may be null. private static ITextPointer GetNextTextPosition(ITextPointer position, ITextPointer limit, LogicalDirection direction, out char character) { bool foundText = false; character = (char)0; while (position != null && !foundText && (limit == null || position.CompareTo(limit) < 0)) { switch (position.GetPointerContext(direction)) { case TextPointerContext.Text: char[] buffer = new char[1]; position.GetTextInRun(direction, buffer, 0, 1); character = buffer[0]; foundText = true; break; case TextPointerContext.ElementStart: case TextPointerContext.ElementEnd: if (TextSchema.IsFormattingType(position.GetElementType(direction))) { position = position.CreatePointer(+1); } else { position = null; } break; case TextPointerContext.EmbeddedElement: case TextPointerContext.None: default: position = null; break; } } return(position); }
// Worker implementing IsAtPotentialRunPosition(position) method. // It is used for testing whether an empty Run element is at potential run potision. // For this purpose the method is supposed to be called with // backwardPosition==run.ElementStart and forwardPosition==run.ElementEnd. private static bool IsAtPotentialRunPosition(ITextPointer backwardPosition, ITextPointer forwardPosition) { Invariant.Assert(backwardPosition.HasEqualScope(forwardPosition)); if (TextSchema.IsValidChild(/*position*/backwardPosition, /*childType*/typeof(Run))) { Type forwardType = forwardPosition.GetElementType(LogicalDirection.Forward); Type backwardType = backwardPosition.GetElementType(LogicalDirection.Backward); if (forwardType != null && backwardType != null) { TextPointerContext forwardContext = forwardPosition.GetPointerContext(LogicalDirection.Forward); TextPointerContext backwardContext = backwardPosition.GetPointerContext(LogicalDirection.Backward); if (// Test if the position inside empty Paragraph or Span backwardContext == TextPointerContext.ElementStart && forwardContext == TextPointerContext.ElementEnd || // Test if the position between opening tag and an embedded object backwardContext == TextPointerContext.ElementStart && TextSchema.IsNonFormattingInline(forwardType) && !IsAtNonMergeableInlineStart(backwardPosition) || // Test if the position between an embedded object and a closing tag forwardContext == TextPointerContext.ElementEnd && TextSchema.IsNonFormattingInline(backwardType) && !IsAtNonMergeableInlineEnd(forwardPosition) || // Test if the position between two embedded objects backwardContext == TextPointerContext.ElementEnd && forwardContext == TextPointerContext.ElementStart && TextSchema.IsNonFormattingInline(backwardType) && TextSchema.IsNonFormattingInline(forwardType) || // Test if the position is adjacent to a non-mergeable inline (Hyperlink). backwardContext == TextPointerContext.ElementEnd && typeof(Inline).IsAssignableFrom(backwardType) && !TextSchema.IsMergeableInline(backwardType) && !typeof(Run).IsAssignableFrom(forwardType) && (forwardContext != TextPointerContext.ElementEnd || !IsAtNonMergeableInlineEnd(forwardPosition)) || forwardContext == TextPointerContext.ElementStart && typeof(Inline).IsAssignableFrom(forwardType) && !TextSchema.IsMergeableInline(forwardType) && !typeof(Run).IsAssignableFrom(backwardType) && (backwardContext != TextPointerContext.ElementStart || !IsAtNonMergeableInlineStart(backwardPosition)) ) { return true; } } } return false; }
/// <summary> /// Return true if Hyperlink range is invalid. /// Hyperlink is invalid if it include a UiElement except Image or the range end position /// is stated before the end position of hyperlink. /// This must be called before Hyperlink start element position. /// </summary> private static bool IsHyperlinkInvalid(ITextPointer textReader, ITextPointer rangeEnd) { // TextRead must be on the position before the element start position of Hyperlink Invariant.Assert(textReader.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementStart); Invariant.Assert(typeof(Hyperlink).IsAssignableFrom(textReader.GetElementType(LogicalDirection.Forward))); bool hyperlinkInvalid = false; // Get the forward adjacent element and cast Hyperlink hardly since it must be Hyperlink Hyperlink hyperlink = (Hyperlink)textReader.GetAdjacentElement(LogicalDirection.Forward); ITextPointer hyperlinkNavigation = textReader.CreatePointer(); ITextPointer hyperlinkEnd = textReader.CreatePointer(); hyperlinkEnd.MoveToNextContextPosition(LogicalDirection.Forward); // Find the hyperlink end position hyperlinkEnd.MoveToElementEdge(ElementEdge.AfterEnd); // Hyperlink end position is stated after the range end position. if (hyperlinkEnd.CompareTo(rangeEnd) > 0) { hyperlinkInvalid = true; } else { // Check whether the hyperlink having a UiElement except Image until hyperlink end position while (hyperlinkNavigation.CompareTo(hyperlinkEnd) < 0) { InlineUIContainer inlineUIContainer = hyperlinkNavigation.GetAdjacentElement(LogicalDirection.Forward) as InlineUIContainer; if (inlineUIContainer != null && !(inlineUIContainer.Child is Image)) { hyperlinkInvalid = true; break; } hyperlinkNavigation.MoveToNextContextPosition(LogicalDirection.Forward); } } return hyperlinkInvalid; }
// Returns the position preceeding the next text character in a specified // direction, or null if no such position exists. // The scan will halt if limit is encounted; limit may be null. private static ITextPointer GetNextTextPosition(ITextPointer position, ITextPointer limit, LogicalDirection direction, out char character) { bool foundText = false; character = (char)0; while (position != null && !foundText && (limit == null || position.CompareTo(limit) < 0)) { switch (position.GetPointerContext(direction)) { case TextPointerContext.Text: char[] buffer = new char[1]; position.GetTextInRun(direction, buffer, 0, 1); character = buffer[0]; foundText = true; break; case TextPointerContext.ElementStart: case TextPointerContext.ElementEnd: if (TextSchema.IsFormattingType(position.GetElementType(direction))) { position = position.CreatePointer(+1); } else { position = null; } break; case TextPointerContext.EmbeddedElement: case TextPointerContext.None: default: position = null; break; } } return position; }
/// <summary> /// </summary> void ITextSelection.SetCaretToPosition(ITextPointer caretPosition, LogicalDirection direction, bool allowStopAtLineEnd, bool allowStopNearSpace) { // We need a pointer with appropriate direction, // becasue it will be used in textRangeBase.Select method for // pointer normalization. caretPosition = caretPosition.CreatePointer(direction); // Normalize the position in its logical direction - to get to text content over there. caretPosition.MoveToInsertionPosition(direction); // We need a pointer with the reverse direction to confirm // the line wrapping position. So we can ensure Bidi caret navigation. // Bidi can have the different caret position by setting the // logical direction, so we have to only set the logical direction // as the forward for the real line wrapping position. ITextPointer reversePosition = caretPosition.CreatePointer(direction == LogicalDirection.Forward ? LogicalDirection.Backward : LogicalDirection.Forward); // Check line wrapping condition if (!allowStopAtLineEnd && ((TextPointerBase.IsAtLineWrappingPosition(caretPosition, this.TextView) && TextPointerBase.IsAtLineWrappingPosition(reversePosition, this.TextView)) || TextPointerBase.IsNextToPlainLineBreak(caretPosition, LogicalDirection.Backward) || TextSchema.IsBreak(caretPosition.GetElementType(LogicalDirection.Backward)))) { // Caret is at wrapping position, and we are not allowed to stay at end of line, // so we choose forward direction to appear in the begiinning of a second line caretPosition.SetLogicalDirection(LogicalDirection.Forward); } else { if (caretPosition.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.Text && caretPosition.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text) { // This is statistically most typical case. No "smartness" needed // to choose standard Forward orientation for the caret. // NOTE: By using caretPosition's direction we solve BiDi caret orientation case: // The orietnation reflects a direction from where caret has been moved // or orientation where mouse clicked. So we will stick with appropriate // character. // Nothing to do. The caretPosition is good to go. } else if (!allowStopNearSpace) { // There are some tags around, and we are not allowed to choose a side near to space. // So we need to perform some content analysis. char[] charBuffer = new char[1]; if (caretPosition.GetPointerContext(direction) == TextPointerContext.Text && caretPosition.GetTextInRun(direction, charBuffer, 0, 1) == 1 && Char.IsWhiteSpace(charBuffer[0])) { LogicalDirection oppositeDirection = direction == LogicalDirection.Forward ? LogicalDirection.Backward : LogicalDirection.Forward; // Check formatting switch condition at this position FlowDirection initialFlowDirection = (FlowDirection)caretPosition.GetValue(FrameworkElement.FlowDirectionProperty); bool moved = caretPosition.MoveToInsertionPosition(oppositeDirection); if (moved && initialFlowDirection == (FlowDirection)caretPosition.GetValue(FrameworkElement.FlowDirectionProperty) && (caretPosition.GetPointerContext(oppositeDirection) != TextPointerContext.Text || caretPosition.GetTextInRun(oppositeDirection, charBuffer, 0, 1) != 1 || !Char.IsWhiteSpace(charBuffer[0]))) { // In the opposite direction we have a non-space // character. So we choose that direction direction = oppositeDirection; caretPosition.SetLogicalDirection(direction); } } } } // Now that orientation of a caretPosition is identified, // build an empty selection at this position TextRangeBase.BeginChange(this); try { TextRangeBase.Select(this, caretPosition, caretPosition); // Note how Select method works for the case of empty range: // It creates a single instance TextPointer normalized and oriented // in a direction taken from caretPosition: ITextSelection thisSelection = this; Invariant.Assert(thisSelection.Start.LogicalDirection == caretPosition.LogicalDirection); // orientation must be as passed Invariant.Assert(this.IsEmpty); //Invariant.Assert((object)thisSelection.Start == (object)thisSelection.End); // it must be the same instance of TextPointer //Invariant.Assert(TextPointerBase.IsAtInsertionPosition(thisSelection.Start, caretPosition.LogicalDirection)); // normalization must be done in the same diredction as orientation // Clear active positions when selection is empty SetActivePositions(null, null); } finally { TextRangeBase.EndChange(this); } }
/// <summary> /// Advances this TextNavigator by a count number of characters. /// </summary> /// <param name="thisNavigator">ITextPointer to advance.</param> /// <param name="direction"> /// A direction in which to search a next characters. /// </param> /// <returns> /// True if the navigator is advanced, false if the end of document is /// encountered and the navigator is not repositioned. /// </returns> /// <remarks> /// A "character" in this context is a sequence of one or several text /// symbols: one or more Unicode code points may be a character, every /// embedded object is a character, a sequence of closing block tags /// followed by opening block tags may also be a unit. Formatting tags /// do not contribute in any unit. /// </remarks> internal static bool MoveToNextInsertionPosition(ITextPointer thisNavigator, LogicalDirection direction) { Invariant.Assert(!thisNavigator.IsFrozen, "Can't reposition a frozen pointer!"); bool moved = true; int increment = direction == LogicalDirection.Forward ? +1 : -1; ITextPointer initialPosition = thisNavigator.CreatePointer(); if (!IsAtInsertionPosition(thisNavigator)) { // If the TextPointer is not currently at an insertion position, // move the TextPointer to the next insertion position in // the indicated direction, just like the MoveToInsertionPosition method. if (!MoveToInsertionPosition(thisNavigator, direction)) { // No insertion position in all content. MoveToInsertionPosition() guarantees that navigator is moved back to initial position. moved = false; goto Exit; } if ((direction == LogicalDirection.Forward && initialPosition.CompareTo(thisNavigator) < 0) || (direction == LogicalDirection.Backward && thisNavigator.CompareTo(initialPosition) < 0)) { // We have found an insertion position in requested direction. goto Exit; } } // Start with skipping character formatting tags in this direction while (TextSchema.IsFormattingType(thisNavigator.GetElementType(direction))) { thisNavigator.MoveByOffset(increment); } do { if (thisNavigator.GetPointerContext(direction) != TextPointerContext.None) { thisNavigator.MoveByOffset(increment); } else { // No insertion position in this direction; Move back thisNavigator.MoveToPosition(initialPosition); moved = false; goto Exit; } } while (!IsAtInsertionPosition(thisNavigator)); // We must leave position normalized in backward direction if (direction == LogicalDirection.Backward) { // For this we must skip character formatting tags if we have any while (TextSchema.IsFormattingType(thisNavigator.GetElementType(direction))) { thisNavigator.MoveByOffset(increment); } // However if it is block start we should back off TextPointerContext context = thisNavigator.GetPointerContext(direction); if (context == TextPointerContext.ElementStart || context == TextPointerContext.None) { increment = -increment; while (TextSchema.IsFormattingType(thisNavigator.GetElementType(LogicalDirection.Forward)) && !IsAtInsertionPosition(thisNavigator)) { thisNavigator.MoveByOffset(increment); } } } Exit: if (moved) { if (direction == LogicalDirection.Forward) { Invariant.Assert(thisNavigator.CompareTo(initialPosition) > 0, "thisNavigator is expected to be moved from initialPosition - 1"); } else { Invariant.Assert(thisNavigator.CompareTo(initialPosition) < 0, "thisNavigator is expected to be moved from initialPosition - 2"); } } else { Invariant.Assert(thisNavigator.CompareTo(initialPosition) == 0, "thisNavigator must stay at initial position"); } return moved; }
// Position at document end - after the last paragraph/list/table is // considered as valid insertion point position. // It has though a special behavior for caret positioning and text insertion internal static bool IsAfterLastParagraph(ITextPointer thisPosition) { return thisPosition.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.None && thisPosition.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.ElementEnd && !typeof(Inline).IsAssignableFrom(thisPosition.GetElementType(LogicalDirection.Backward)); }
private static ITextPointer RestrictWithinBlock(ITextPointer position, ITextPointer limit, LogicalDirection direction) { Invariant.Assert(!(direction == LogicalDirection.Backward) || position.CompareTo(limit) >= 0, "for backward direction position must be >= than limit"); Invariant.Assert(!(direction == LogicalDirection.Forward) || position.CompareTo(limit) <= 0, "for forward direcion position must be <= than linit"); while (direction == LogicalDirection.Backward ? position.CompareTo(limit) > 0 : position.CompareTo(limit) < 0) { TextPointerContext context = position.GetPointerContext(direction); if (context == TextPointerContext.ElementStart || context == TextPointerContext.ElementEnd) { Type elementType = position.GetElementType(direction); if (!typeof(Inline).IsAssignableFrom(elementType)) { limit = position; break; } } else if (context == TextPointerContext.EmbeddedElement) { limit = position; break; } position = position.GetNextContextPosition(direction); } // Return normalized position - in the direction towards a center position. return limit.GetInsertionPosition(direction == LogicalDirection.Backward ? LogicalDirection.Forward : LogicalDirection.Backward); }
internal static bool IsAtNormalizedPosition(ITextPointer position, LogicalDirection direction, bool respectCaretUnitBoundaries) { if (!IsAtNormalizedPosition(position, respectCaretUnitBoundaries)) { return false; } // if (position.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.ElementStart && position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementEnd) { return true; } // Check if there is no any formatting tags in the given direction if (TextSchema.IsFormattingType(position.GetElementType(direction))) { position = position.CreatePointer(); while (TextSchema.IsFormattingType(position.GetElementType(direction))) { position.MoveToNextContextPosition(direction); } if (IsAtNormalizedPosition(position, respectCaretUnitBoundaries)) { // So there is a possibility to move over formatting tags only // and reach some insertion position. This means // that our position was not normalized in the given direction. return false; } } return true; }
// Tests if position is before the first Table element in a collection of Blocks at that level. // We treat this as a potential insertion position to allow editing operations before the table. // This property identifies such a position. internal static bool IsBeforeFirstTable(ITextPointer position) { TextPointerContext forwardContext = position.GetPointerContext(LogicalDirection.Forward); TextPointerContext backwardContext = position.GetPointerContext(LogicalDirection.Backward); return (forwardContext == TextPointerContext.ElementStart && (backwardContext == TextPointerContext.ElementStart || backwardContext == TextPointerContext.None) && typeof(Table).IsAssignableFrom(position.GetElementType(LogicalDirection.Forward))); }
// Returns true if the position is adjacent to a LineBreak or Paragraph element, // ignoring any intermediate formatting elements. // // If lineBreakType is null, any line break element is considered valid. private static bool IsNextToRichBreak(ITextPointer thisPosition, LogicalDirection direction, Type lineBreakType) { Invariant.Assert(lineBreakType == null || lineBreakType == typeof(LineBreak) || lineBreakType == typeof(Paragraph)); bool result = false; while (true) { Type neighbor = thisPosition.GetElementType(direction); if (lineBreakType == null) { if (typeof(LineBreak).IsAssignableFrom(neighbor) || typeof(Paragraph).IsAssignableFrom(neighbor)) { result = true; break; } } else if (lineBreakType.IsAssignableFrom(neighbor)) { result = true; break; } if (!TextSchema.IsFormattingType(neighbor)) break; thisPosition = thisPosition.GetNextContextPosition(direction); } return result; }
//------------------------------------------------------ // // Private Methods // //------------------------------------------------------ #region Private Methods // Worker for MoveToNextFormatNormalizedPosition/MoveToNextInsertionPosition. private static bool NormalizePosition(ITextPointer thisNavigator, LogicalDirection direction, bool respectCaretUnitBoundaries) { Invariant.Assert(!thisNavigator.IsFrozen, "Can't reposition a frozen pointer!"); int symbolCount = 0; int increment; LogicalDirection oppositeDirection; TextPointerContext directEnterScope; TextPointerContext oppositeEnterScope; if (direction == LogicalDirection.Forward) { increment = +1; oppositeDirection = LogicalDirection.Backward; directEnterScope = TextPointerContext.ElementStart; oppositeEnterScope = TextPointerContext.ElementEnd; } else { increment = -1; oppositeDirection = LogicalDirection.Forward; directEnterScope = TextPointerContext.ElementEnd; oppositeEnterScope = TextPointerContext.ElementStart; } // When the pointer appears in between structural tags we need to start // from sliding into the deepest possible position without // leaving any structural units. We need to do that only // if we are not at insertion position already. if (!IsAtNormalizedPosition(thisNavigator, respectCaretUnitBoundaries)) { // Go inside an innermost structured element (non-inline) while ( thisNavigator.GetPointerContext(direction) == directEnterScope && !typeof(Inline).IsAssignableFrom(thisNavigator.GetElementType(direction)) && !IsAtNormalizedPosition(thisNavigator, respectCaretUnitBoundaries)) { thisNavigator.MoveToNextContextPosition(direction); symbolCount += increment; } while ( thisNavigator.GetPointerContext(oppositeDirection) == oppositeEnterScope && !typeof(Inline).IsAssignableFrom(thisNavigator.GetElementType(oppositeDirection)) && !IsAtNormalizedPosition(thisNavigator, respectCaretUnitBoundaries)) { thisNavigator.MoveToNextContextPosition(oppositeDirection); symbolCount -= increment; } } // Get out of a Hyperlink, etc. inner edge. symbolCount = LeaveNonMergeableInlineBoundary(thisNavigator, direction, symbolCount); // Get out of a compound sequence if any. if (respectCaretUnitBoundaries) { while (!IsAtCaretUnitBoundary(thisNavigator)) { symbolCount += increment; thisNavigator.MoveByOffset(increment); } } // Here is the core part of this method's logic - skipping all formatting tags in the given direction. // Skip character formatting tags if they are present in this direction. // Even if an insertion position can be in the middle of this formatting sequence, // we want to skip it all and reach the farthest possible insertion position in that direction. // Such approach guarantees that repeated calls of this normalization will give the same reauls. // In case if there is an inserrtion position in the middle (say, in empty Run), // the loop moving in opposite direction below will find it if needed. while (TextSchema.IsMergeableInline(thisNavigator.GetElementType(direction))) { thisNavigator.MoveToNextContextPosition(direction); symbolCount += increment; } if (!IsAtNormalizedPosition(thisNavigator, respectCaretUnitBoundaries)) { // If still not at insertion point, try skipping inline tags in the opposite direction // now possibly stopping inside of empty element while (!IsAtNormalizedPosition(thisNavigator, respectCaretUnitBoundaries) && TextSchema.IsMergeableInline(thisNavigator.GetElementType(oppositeDirection))) { thisNavigator.MoveToNextContextPosition(oppositeDirection); symbolCount -= increment; } // If still not at insertion point, then try harder - skipping block tags // First in "preferred" direction while (!IsAtNormalizedPosition(thisNavigator, respectCaretUnitBoundaries) && thisNavigator.MoveToNextContextPosition(direction)) { symbolCount += increment; } // And finally in apposite direction while (!IsAtNormalizedPosition(thisNavigator, respectCaretUnitBoundaries) && thisNavigator.MoveToNextContextPosition(oppositeDirection)) { symbolCount -= increment; } if (!IsAtNormalizedPosition(thisNavigator, respectCaretUnitBoundaries)) { // When there is no insertion positions in the whole document // we return the position back to its original place. thisNavigator.MoveByOffset(-symbolCount); } } return symbolCount != 0; }
private void _SkipFormattingTags(ITextPointer textPointer) { Debug.Assert(!textPointer.IsFrozen, "Can't reposition a frozen pointer!"); LogicalDirection dir = textPointer.LogicalDirection; int increment = (dir == LogicalDirection.Forward ? +1 : -1); while (TextSchema.IsFormattingType( textPointer.GetElementType(dir)) ) { textPointer.MoveByOffset(increment); } }
// Returns true if pointer preceeds an Inline start or end edge. private bool IsAdjacentToFormatElement(ITextPointer pointer) { TextPointerContext context; bool isAdjacentToFormatElement; isAdjacentToFormatElement = false; context = pointer.GetPointerContext(LogicalDirection.Forward); if (context == TextPointerContext.ElementStart && TextSchema.IsFormattingType(pointer.GetElementType(LogicalDirection.Forward))) { isAdjacentToFormatElement = true; } else if (context == TextPointerContext.ElementEnd && TextSchema.IsFormattingType(pointer.ParentType)) { isAdjacentToFormatElement = true; } return isAdjacentToFormatElement; }
// 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); } }