// Token: 0x06002EE3 RID: 12003 RVA: 0x000D3B5C File Offset: 0x000D1D5C internal override ITextPointer GetNextCaretUnitPosition(ITextPointer position, LogicalDirection direction) { FixedTextPointer ftp = this.Container.VerifyPosition(position); FixedPosition fixedPosition; if (this._GetFixedPosition(ftp, out fixedPosition)) { DependencyObject element = this.FixedPage.GetElement(fixedPosition.Node); if (element is Glyphs) { Glyphs glyphs = (Glyphs)element; GlyphRun glyphRun = glyphs.ToGlyphRun(); int num = (glyphRun.Characters == null) ? 0 : glyphRun.Characters.Count; CharacterHit characterHit = (fixedPosition.Offset == num) ? new CharacterHit(fixedPosition.Offset - 1, 1) : new CharacterHit(fixedPosition.Offset, 0); CharacterHit obj = (direction == LogicalDirection.Forward) ? glyphRun.GetNextCaretCharacterHit(characterHit) : glyphRun.GetPreviousCaretCharacterHit(characterHit); if (!characterHit.Equals(obj)) { LogicalDirection edge = LogicalDirection.Forward; if (obj.TrailingLength > 0) { edge = LogicalDirection.Backward; } int offset = obj.FirstCharacterIndex + obj.TrailingLength; return(this._CreateTextPointer(new FixedPosition(fixedPosition.Node, offset), edge)); } } } ITextPointer textPointer = position.CreatePointer(); textPointer.MoveToNextInsertionPosition(direction); return(textPointer); }
// Candidate for replacing MoveToNextInsertionPosition for immutable TextPointer model ITextPointer ITextPointer.GetNextInsertionPosition(LogicalDirection direction) { ITextPointer pointer = ((ITextPointer)this).CreatePointer(); if (pointer.MoveToNextInsertionPosition(direction)) { pointer.Freeze(); } else { pointer = null; } return(pointer); }
/// <summary> /// Finds the next position at the edge of a caret unit in /// specified direction. /// </summary> /// <param name="position"> /// Initial text position of an object/character. /// </param> /// <param name="direction"> /// If Forward, this method returns the "caret unit" position following /// the initial position. /// If Backward, this method returns the caret unit" position preceding /// the initial position. /// </param> /// <returns> /// The next caret unit break position in specified direction. /// </returns> /// <exception cref="System.InvalidOperationException"> /// Throws InvalidOperationException if IsValid is false. /// If IsValid returns false, Validate method must be called before /// calling this method. /// </exception> /// <remarks> /// In the context of this method, "caret unit" refers to a group of one /// or more Unicode code points that map to a single rendered glyph. /// /// If position is located between two caret units, this method returns /// a new position located at the opposite edge of the caret unit in /// the indicated direction. /// If position is located within a group of Unicode code points that map /// to a single caret unit, this method returns a new position at /// the indicated edge of the containing caret unit. /// If position is located at the beginning of end of content -- there is /// no content in the indicated direction -- then this method returns /// a position located at the same location as initial position. /// </remarks> internal override ITextPointer GetNextCaretUnitPosition(ITextPointer position, LogicalDirection direction) { FixedTextPointer ftp = Container.VerifyPosition(position); FixedPosition fixedp; if (_GetFixedPosition(ftp, out fixedp)) { DependencyObject element = this.FixedPage.GetElement(fixedp.Node); if (element is Glyphs) { Glyphs g = (Glyphs)element; GlyphRun run = g.ToGlyphRun(); int characterCount = (run.Characters == null) ? 0 : run.Characters.Count; CharacterHit start = (fixedp.Offset == characterCount) ? new CharacterHit(fixedp.Offset - 1, 1) : new CharacterHit(fixedp.Offset, 0); CharacterHit next = (direction == LogicalDirection.Forward) ? run.GetNextCaretCharacterHit(start) : run.GetPreviousCaretCharacterHit(start); if (!start.Equals(next)) { LogicalDirection edge = LogicalDirection.Forward; if (next.TrailingLength > 0) { edge = LogicalDirection.Backward; } int index = next.FirstCharacterIndex + next.TrailingLength; return(_CreateTextPointer(new FixedPosition(fixedp.Node, index), edge)); } } } //default behavior is to simply move textpointer ITextPointer pointer = position.CreatePointer(); pointer.MoveToNextInsertionPosition(direction); return(pointer); }
// Token: 0x0600535A RID: 21338 RVA: 0x00172AC8 File Offset: 0x00170CC8 private void Select(int start, int length) { if (start < 0) { throw new ArgumentOutOfRangeException("start", SR.Get("ParameterCannotBeNegative")); } if (length < 0) { throw new ArgumentOutOfRangeException("length", SR.Get("ParameterCannotBeNegative")); } ITextPointer textPointer = this.TextContainer.Start.CreatePointer(); while (start-- > 0 && textPointer.MoveToNextInsertionPosition(LogicalDirection.Forward)) { } ITextPointer textPointer2 = textPointer.CreatePointer(); while (length-- > 0 && textPointer2.MoveToNextInsertionPosition(LogicalDirection.Forward)) { } this.Selection.Select(textPointer, textPointer2); }
// Token: 0x060062D3 RID: 25299 RVA: 0x001BB8C4 File Offset: 0x001B9AC4 private static IList <IAttachedAnnotation> GetSpannedAnnotationsForFlow(AnnotationService service, ITextSelection selection) { Invariant.Assert(service != null); ITextPointer textPointer = selection.Start.CreatePointer(); ITextPointer textPointer2 = selection.End.CreatePointer(); textPointer.MoveToNextInsertionPosition(LogicalDirection.Backward); textPointer2.MoveToNextInsertionPosition(LogicalDirection.Forward); ITextRange selection2 = new TextRange(textPointer, textPointer2); IList <ContentLocatorBase> list = service.LocatorManager.GenerateLocators(selection2); Invariant.Assert(list != null && list.Count > 0); TextSelectionProcessor textSelectionProcessor = service.LocatorManager.GetSelectionProcessor(typeof(TextRange)) as TextSelectionProcessor; TextSelectionProcessor textSelectionProcessor2 = service.LocatorManager.GetSelectionProcessor(typeof(TextAnchor)) as TextSelectionProcessor; Invariant.Assert(textSelectionProcessor != null, "TextSelectionProcessor should be available for TextRange if we are processing flow content."); Invariant.Assert(textSelectionProcessor2 != null, "TextSelectionProcessor should be available for TextAnchor if we are processing flow content."); IList <IAttachedAnnotation> result = null; try { textSelectionProcessor.Clamping = false; textSelectionProcessor2.Clamping = false; ContentLocator contentLocator = list[0] as ContentLocator; Invariant.Assert(contentLocator != null, "Locators for selection in Flow should always be ContentLocators. ContentLocatorSets not supported."); contentLocator.Parts[contentLocator.Parts.Count - 1].NameValuePairs.Add("IncludeOverlaps", bool.TrueString); IList <Annotation> annotations = service.Store.GetAnnotations(contentLocator); result = AnnotationHelper.ResolveAnnotations(service, annotations); } finally { textSelectionProcessor.Clamping = true; textSelectionProcessor2.Clamping = true; } return(result); }
/// <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; }
/// <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> /// Moves the range the specified number of units in the text. Note that the text is not altered. Instead the /// range spans a different part of the text. /// If the range is degenerate, this method tries to move the insertion point count units. If the range is nondegenerate /// and count is greater than zero, this method collapses the range at its end point, moves the resulting range forward /// to a unit boundary (if it is not already at one), and then tries to move count - 1 units forward. If the range is /// nondegenerate and count is less than zero, this method collapses the range at the starting point, moves the resulting /// range backward to a unit boundary (if it isn't already at one), and then tries to move |count| - 1 units backward. /// Thus, in both cases, collapsing a nondegenerate range, whether or not moving to the start or end of the unit following /// the collapse, counts as a unit. /// </summary> /// <param name="unit">The textual unit for moving.</param> /// <param name="count">The number of units to move. A positive count moves the range forward. /// A negative count moves backward. A count of 0 has no effect.</param> /// <returns>The number of units actually moved, which can be less than the number requested if /// moving the range runs into the beginning or end of the document.</returns> int ITextRangeProvider.Move(TextUnit unit, int count) { Normalize(); int movedCount = 0; // Do not expand range for Paragraphs, because TextRange.SelectParagraph will take care of it. if (unit != TextUnit.Paragraph) { ExpandToEnclosingUnit(unit, true, true); } if (count != 0) { // Move start position by number of units. ITextPointer position = _start.CreatePointer(); movedCount = MovePositionByUnits(position, unit, count); // If endpoint has been moved at least by one unit or its direction has changed, snap it to TextUnit boundary, // because movement done by MovePositionByUnits does not guarantee position snapping. if ((position.CompareTo(_start)==0 && position.LogicalDirection != _start.LogicalDirection) || (count > 0 && position.CompareTo(_start) > 0) || (count < 0 && position.CompareTo(_start) < 0)) { _start = position; // Move end position by 1 offset forward, so it does not point to _start. // Later ExpandToEnclosingUnit will position it at appropriate unit boundary. _end = position.CreatePointer(); if (unit != TextUnit.Page) { _end.MoveToNextInsertionPosition(LogicalDirection.Forward); } ExpandToEnclosingUnit(unit, true, true); // If endpoint has been moved, but 'movedCount' is 0, it means that we snapped to neariest // unit boundary. Treat this situation as actual move. if (movedCount == 0) { movedCount = (count > 0) ? 1 : -1; } } } return movedCount; }
/// <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; }