/* * Code used to trim text segments for alternative display of sticky note anchors * * /// <summary> * /// ctor that initializes the TextSegments array by cloning and trimming the input segment Array * /// </summary> * /// <param name="segments">input segment</param> * /// <remarks>This is used to convert a TextRange into TextAnchor. * /// Input segments must be ordered and non overlapping</remarks> * internal TextAnchor(IList<TextSegment> segments) * { * if (segments == null) * return; * * ITextPointer lastPointer = null; * for (int i = 0; i < segments.Count; i++) * { * Invariant.Assert((lastPointer == null) || (lastPointer.CompareTo(segments[i].Start) <= 0), "overlapped segments found"); * TextSegment newSegment = TextAnchor.Trim(segments[i]); * if (newSegment.IsNull) * continue; * * _segments.Add(newSegment); * lastPointer = newSegment.End; * } * } */ #endregion Constructors //------------------------------------------------------ // // Public Methods // //------------------------------------------------------ #region Public Methods /// <summary> /// Determines if the text pointer is contained by one of the /// anchor's TextSegment.s /// </summary> /// <param name="textPointer">text pointer to test</param> internal bool Contains(ITextPointer textPointer) { if (textPointer == null) { throw new ArgumentNullException("textPointer"); } if (textPointer.TextContainer != this.Start.TextContainer) { throw new ArgumentException(SR.Get(SRID.NotInAssociatedTree, "textPointer")); } // Correct position normalization on range boundary so that // our test would not depend on what side of formatting tags // pointer is located. if (textPointer.CompareTo(this.Start) < 0) { textPointer = textPointer.GetInsertionPosition(LogicalDirection.Forward); } else if (textPointer.CompareTo(this.End) > 0) { textPointer = textPointer.GetInsertionPosition(LogicalDirection.Backward); } // Check if at least one segment contains this position. for (int i = 0; i < _segments.Count; i++) { if (_segments[i].Contains(textPointer)) { return(true); } } return(false); }
// Token: 0x06006761 RID: 26465 RVA: 0x001CE628 File Offset: 0x001CC828 private void GetAffectedPages(ITextPointer start, ITextPointer end, out int pageStart, out int pageCount) { for (pageStart = 0; pageStart < this._breakRecords.Count; pageStart++) { Invariant.Assert(this._breakRecords[pageStart] != null, "Invalid BreakRecordTable entry."); TextPointer dependentMax = this._breakRecords[pageStart].DependentMax; if (dependentMax != null && start.CompareTo(dependentMax) <= 0) { break; } ReadOnlyCollection <TextSegment> textSegments = this._breakRecords[pageStart].TextSegments; if (textSegments == null) { break; } bool flag = false; foreach (TextSegment textSegment in textSegments) { if (start.CompareTo(textSegment.End) <= 0) { flag = true; break; } } if (flag) { break; } } pageCount = this._breakRecords.Count - pageStart; }
// Token: 0x0600625B RID: 25179 RVA: 0x001B9470 File Offset: 0x001B7670 private static TextSegment CreateNormalizedSegment(ITextPointer start, ITextPointer end) { if (start.CompareTo(end) == 0) { if (!TextPointerBase.IsAtInsertionPosition(start, start.LogicalDirection)) { start = start.GetInsertionPosition(start.LogicalDirection); end = start; } } else { if (!TextPointerBase.IsAtInsertionPosition(start, start.LogicalDirection)) { start = start.GetInsertionPosition(LogicalDirection.Forward); } if (!TextPointerBase.IsAtInsertionPosition(end, start.LogicalDirection)) { end = end.GetInsertionPosition(LogicalDirection.Backward); } if (start.CompareTo(end) >= 0) { if (start.LogicalDirection == LogicalDirection.Backward) { start = end.GetFrozenPointer(LogicalDirection.Backward); } end = start; } } return(new TextSegment(start, end)); }
// Token: 0x0600624A RID: 25162 RVA: 0x001B8AC4 File Offset: 0x001B6CC4 internal bool Contains(ITextPointer textPointer) { if (textPointer == null) { throw new ArgumentNullException("textPointer"); } if (textPointer.TextContainer != this.Start.TextContainer) { throw new ArgumentException(SR.Get("NotInAssociatedTree", new object[] { "textPointer" })); } if (textPointer.CompareTo(this.Start) < 0) { textPointer = textPointer.GetInsertionPosition(LogicalDirection.Forward); } else if (textPointer.CompareTo(this.End) > 0) { textPointer = textPointer.GetInsertionPosition(LogicalDirection.Backward); } for (int i = 0; i < this._segments.Count; i++) { if (this._segments[i].Contains(textPointer)) { return(true); } } return(false); }
// Token: 0x06002BD3 RID: 11219 RVA: 0x000C7B28 File Offset: 0x000C5D28 private void _OnHighlightChanged(object sender, HighlightChangedEventArgs args) { int i = 0; DocumentSequenceTextPointer documentSequenceTextPointer = null; ChildDocumentBlock childDocumentBlock = null; List <TextSegment> list = new List <TextSegment>(4); while (i < args.Ranges.Count) { TextSegment textSegment = (TextSegment)args.Ranges[i]; DocumentSequenceTextPointer documentSequenceTextPointer2 = (DocumentSequenceTextPointer)textSegment.End; if (documentSequenceTextPointer == null) { documentSequenceTextPointer = (DocumentSequenceTextPointer)textSegment.Start; } ChildDocumentBlock childDocumentBlock2 = childDocumentBlock; childDocumentBlock = documentSequenceTextPointer.ChildBlock; if (childDocumentBlock2 != null && childDocumentBlock != childDocumentBlock2 && !(childDocumentBlock2.ChildContainer is NullTextContainer) && list.Count != 0) { childDocumentBlock2.ChildHighlightLayer.RaiseHighlightChangedEvent(new ReadOnlyCollection <TextSegment>(list)); list.Clear(); } ITextPointer childPointer = documentSequenceTextPointer.ChildPointer; if (documentSequenceTextPointer2.ChildBlock != childDocumentBlock) { ITextPointer textPointer = documentSequenceTextPointer.ChildPointer.TextContainer.End; if (childPointer.CompareTo(textPointer) != 0) { list.Add(new TextSegment(childPointer, textPointer)); } if (!(childDocumentBlock.ChildContainer is NullTextContainer) && list.Count != 0) { childDocumentBlock.ChildHighlightLayer.RaiseHighlightChangedEvent(new ReadOnlyCollection <TextSegment>(list)); } childDocumentBlock = childDocumentBlock.NextBlock; documentSequenceTextPointer = new DocumentSequenceTextPointer(childDocumentBlock, childDocumentBlock.ChildContainer.Start); list.Clear(); } else { ITextPointer textPointer = documentSequenceTextPointer2.ChildPointer; if (childPointer.CompareTo(textPointer) != 0) { list.Add(new TextSegment(childPointer, textPointer)); } i++; documentSequenceTextPointer = null; } } if (list.Count > 0 && childDocumentBlock != null && !(childDocumentBlock.ChildContainer is NullTextContainer)) { childDocumentBlock.ChildHighlightLayer.RaiseHighlightChangedEvent(new ReadOnlyCollection <TextSegment>(list)); } }
// Token: 0x060039B3 RID: 14771 RVA: 0x00105B0C File Offset: 0x00103D0C internal static TextRange InternalFind(ITextPointer startPosition, ITextPointer endPosition, string findPattern, CultureInfo cultureInfo, bool matchCase, bool matchWholeWord, bool matchLast, bool matchDiacritics, bool matchKashida, bool matchAlefHamza) { Invariant.Assert(startPosition.CompareTo(endPosition) <= 0); ITextPointer textPointer; LogicalDirection direction; if (matchLast) { textPointer = endPosition; direction = LogicalDirection.Backward; } else { textPointer = startPosition; direction = LogicalDirection.Forward; } int num = Math.Max(64, findPattern.Length * 2 * 2); textPointer = textPointer.CreatePointer(); while ((matchLast ? startPosition.CompareTo(textPointer) : textPointer.CompareTo(endPosition)) < 0) { ITextPointer textPointer2 = textPointer.CreatePointer(); char[] array = new char[num]; int[] array2 = new int[num + 1]; int num2 = TextFindEngine.SetFindTextAndFindTextPositionMap(startPosition, endPosition, textPointer, direction, matchLast, array, array2); if (!matchDiacritics || num2 >= findPattern.Length) { int num3 = matchLast ? (array.Length - num2) : 0; bool hasPreceedingSeparatorChar = false; bool hasFollowingSeparatorChar = false; if (matchWholeWord) { TextFindEngine.GetContextualInformation(textPointer2, matchLast ? (-array2[array2.Length - num2 - 1]) : array2[num2], out hasPreceedingSeparatorChar, out hasFollowingSeparatorChar); } string textString = new string(array, num3, num2); int num5; int num4 = TextFindEngine.FindMatchIndexFromFindContent(textString, findPattern, cultureInfo, matchCase, matchWholeWord, matchLast, matchDiacritics, matchKashida, matchAlefHamza, hasPreceedingSeparatorChar, hasFollowingSeparatorChar, out num5); if (num4 != -1) { ITextPointer textPointer3 = textPointer2.CreatePointer(); textPointer3.MoveByOffset(matchLast ? (-array2[num3 + num4]) : array2[num4]); ITextPointer textPointer4 = textPointer2.CreatePointer(); textPointer4.MoveByOffset(matchLast ? (-array2[num3 + num4 + num5]) : array2[num4 + num5]); return(new TextRange(textPointer3, textPointer4)); } if (num2 > findPattern.Length) { textPointer = textPointer2.CreatePointer(); textPointer.MoveByOffset(matchLast ? (-array2[array.Length - num2 + findPattern.Length]) : array2[num2 - findPattern.Length]); } } } return(null); }
/// <summary> /// Retrieves indices of affected pages by specified content range. /// </summary> /// <param name="start">Content change start position.</param> /// <param name="end">Content change end position.</param> /// <param name="pageStart">The first affected page.</param> /// <param name="pageCount">Number of affected pages.</param> private void GetAffectedPages(ITextPointer start, ITextPointer end, out int pageStart, out int pageCount) { bool affects; ReadOnlyCollection <TextSegment> textSegments; TextPointer dependentMax; // Find the first affected page. pageStart = 0; while (pageStart < _breakRecords.Count) { Invariant.Assert(_breakRecords[pageStart] != null, "Invalid BreakRecordTable entry."); // If the start position is before last position affecting the output break record, // this page is affected. dependentMax = _breakRecords[pageStart].DependentMax; if (dependentMax != null) { if (start.CompareTo(dependentMax) <= 0) { break; } } textSegments = _breakRecords[pageStart].TextSegments; if (textSegments != null) { affects = false; foreach (TextSegment textSegment in textSegments) { if (start.CompareTo(textSegment.End) <= 0) { affects = true; break; } } if (affects) { break; } } else { // There is no information about this page, so assume that it is // affected. break; } ++pageStart; } // Find the last affected page // For now assume that all following pages are affected. pageCount = _breakRecords.Count - pageStart; }
// Token: 0x06003C07 RID: 15367 RVA: 0x0011500C File Offset: 0x0011320C internal TextSegment(ITextPointer startPosition, ITextPointer endPosition, bool preserveLogicalDirection) { ValidationHelper.VerifyPositionPair(startPosition, endPosition); if (startPosition.CompareTo(endPosition) == 0) { this._start = startPosition.GetFrozenPointer(startPosition.LogicalDirection); this._end = this._start; return; } Invariant.Assert(startPosition.CompareTo(endPosition) < 0); this._start = startPosition.GetFrozenPointer(preserveLogicalDirection ? startPosition.LogicalDirection : LogicalDirection.Backward); this._end = endPosition.GetFrozenPointer(preserveLogicalDirection ? endPosition.LogicalDirection : LogicalDirection.Forward); }
// Token: 0x06005B55 RID: 23381 RVA: 0x0019C11A File Offset: 0x0019A31A internal SpellingError(Speller speller, ITextPointer start, ITextPointer end) { Invariant.Assert(start.CompareTo(end) < 0); this._speller = speller; this._start = start.GetFrozenPointer(LogicalDirection.Forward); this._end = end.GetFrozenPointer(LogicalDirection.Backward); }
// Token: 0x06007C33 RID: 31795 RVA: 0x0022EB24 File Offset: 0x0022CD24 public static IList <DependencyObject> GetSelectedNodes(object selection) { if (selection == null) { throw new ArgumentNullException("selection"); } ITextPointer textPointer = null; ITextPointer position = null; IList <TextSegment> list; TextSelectionHelper.CheckSelection(selection, out textPointer, out position, out list); IList <DependencyObject> list2 = new List <DependencyObject>(); if (textPointer.CompareTo(position) == 0) { list2.Add(((TextPointer)textPointer).Parent); return(list2); } TextPointer textPointer2 = (TextPointer)textPointer.CreatePointer(); while (((ITextPointer)textPointer2).CompareTo(position) < 0) { DependencyObject parent = textPointer2.Parent; if (!list2.Contains(parent)) { list2.Add(parent); } textPointer2.MoveToNextContextPosition(LogicalDirection.Forward); } return(list2); }
// Token: 0x06007C39 RID: 31801 RVA: 0x0022EDE4 File Offset: 0x0022CFE4 public static Rect GetAnchorRectangle(ITextPointer pointer) { if (pointer == null) { throw new ArgumentNullException("pointer"); } bool flag = false; ITextView documentPageTextView = TextSelectionHelper.GetDocumentPageTextView(pointer); if (pointer.CompareTo(pointer.TextContainer.End) == 0) { Point point = new Point(double.MaxValue, double.MaxValue); pointer = documentPageTextView.GetTextPositionFromPoint(point, true); flag = true; } if (documentPageTextView != null && documentPageTextView.IsValid && TextDocumentView.Contains(pointer, documentPageTextView.TextSegments)) { Rect rectangleFromTextPosition = documentPageTextView.GetRectangleFromTextPosition(pointer); if (flag && rectangleFromTextPosition != Rect.Empty) { rectangleFromTextPosition.X += rectangleFromTextPosition.Height / 2.0; } return(rectangleFromTextPosition); } return(Rect.Empty); }
/// <summary> /// Is AutometionPeer represented by 'elementStart' is immediate child of AutomationPeer /// represented by 'ownerContentStart'. /// </summary> internal static bool IsImmediateAutomationChild(ITextPointer elementStart, ITextPointer ownerContentStart) { Invariant.Assert(elementStart.CompareTo(ownerContentStart) >= 0); bool immediateChild = true; // Walk element tree up looking for AutomationPeers. ITextPointer position = elementStart.CreatePointer(); while (typeof(TextElement).IsAssignableFrom(position.ParentType)) { position.MoveToElementEdge(ElementEdge.BeforeStart); if (position.CompareTo(ownerContentStart) <= 0) { break; } AutomationPeer peer = null; object element = position.GetAdjacentElement(LogicalDirection.Forward); if (element is UIElement) { peer = UIElementAutomationPeer.CreatePeerForElement((UIElement)element); } else if (element is ContentElement) { peer = ContentElementAutomationPeer.CreatePeerForElement((ContentElement)element); } if (peer != null) { immediateChild = false; break; } } return(immediateChild); }
// Constructor. internal TextSelectionHighlightChangedEventArgs(ITextPointer invalidRangeLeftStart, ITextPointer invalidRangeLeftEnd, ITextPointer invalidRangeRightStart, ITextPointer invalidRangeRightEnd) { List <TextSegment> rangeArray; Invariant.Assert(invalidRangeLeftStart != invalidRangeLeftEnd || invalidRangeRightStart != invalidRangeRightEnd, "Unexpected empty range!"); if (invalidRangeLeftStart.CompareTo(invalidRangeLeftEnd) == 0) { rangeArray = new List <TextSegment>(1); rangeArray.Add(new TextSegment(invalidRangeRightStart, invalidRangeRightEnd)); } else if (invalidRangeRightStart.CompareTo(invalidRangeRightEnd) == 0) { rangeArray = new List <TextSegment>(1); rangeArray.Add(new TextSegment(invalidRangeLeftStart, invalidRangeLeftEnd)); } else { rangeArray = new List <TextSegment>(2); rangeArray.Add(new TextSegment(invalidRangeLeftStart, invalidRangeLeftEnd)); rangeArray.Add(new TextSegment(invalidRangeRightStart, invalidRangeRightEnd)); } _ranges = new ReadOnlyCollection <TextSegment>(rangeArray); }
/// <summary> /// Gets the rectangle for this ITextPointer /// </summary> /// <param name="pointer">the pointer to examine</param> /// <returns> /// The anchor point of the selection; /// If there is no valid AnchorPoint returns Point(Double.NaN, Double.NaN). /// </returns> /// <exception cref="ArgumentNullException">pointer is null</exception> public static Rect GetAnchorRectangle(ITextPointer pointer) { if (pointer == null) { throw new ArgumentNullException("pointer"); } bool extension = false; ITextView textView = GetDocumentPageTextView(pointer); if (pointer.CompareTo(pointer.TextContainer.End) == 0) { //we can not get rectangle for the end of the TextContainer //so get the last symbol Point endPoint = new Point(Double.MaxValue, Double.MaxValue); pointer = textView.GetTextPositionFromPoint(endPoint, true); //we need to move the resulting rectangle at half space because //the geometry calculating function does the same extension = true; } if (textView != null && textView.IsValid && TextDocumentView.Contains(pointer, textView.TextSegments)) { Rect rect = textView.GetRectangleFromTextPosition(pointer); if (extension && rect != Rect.Empty) { rect.X += rect.Height / 2.0; } return(rect); } return(Rect.Empty); }
// Token: 0x06003EEE RID: 16110 RVA: 0x0011F2FC File Offset: 0x0011D4FC internal static void VerifyPositionPair(ITextPointer startPosition, ITextPointer endPosition) { if (startPosition == null) { throw new ArgumentNullException("startPosition"); } if (endPosition == null) { throw new ArgumentNullException("endPosition"); } if (startPosition.TextContainer != endPosition.TextContainer) { throw new ArgumentException(SR.Get("InDifferentTextContainers", new object[] { "startPosition", "endPosition" })); } if (startPosition.CompareTo(endPosition) > 0) { throw new ArgumentException(SR.Get("BadTextPositionOrder", new object[] { "startPosition", "endPosition" })); } }
// Token: 0x0600676F RID: 26479 RVA: 0x001CECD4 File Offset: 0x001CCED4 internal Geometry GetTightBoundingGeometryFromTextPositions(ITextPointer startPosition, ITextPointer endPosition, Rect visibleRect) { Geometry geometry = null; if (endPosition.CompareTo(this.Cell.StaticElementEnd) >= 0) { geometry = new RectangleGeometry(this._rect.FromTextDpi()); } else { SubpageParagraphResult subpageParagraphResult = (SubpageParagraphResult)this.CreateParagraphResult(); ReadOnlyCollection <ColumnResult> columns = subpageParagraphResult.Columns; Transform transform = new TranslateTransform(-TextDpi.FromTextDpi(base.ContentRect.u), -TextDpi.FromTextDpi(base.ContentRect.v)); visibleRect = transform.TransformBounds(visibleRect); geometry = TextDocumentView.GetTightBoundingGeometryFromTextPositionsHelper(columns[0].Paragraphs, subpageParagraphResult.FloatingElements, startPosition, endPosition, 0.0, visibleRect); if (geometry != null) { Rect viewport = new Rect(0.0, 0.0, TextDpi.FromTextDpi(base.ContentRect.du), TextDpi.FromTextDpi(base.ContentRect.dv)); CaretElement.ClipGeometryByViewport(ref geometry, viewport); transform = new TranslateTransform(TextDpi.FromTextDpi(base.ContentRect.u), TextDpi.FromTextDpi(base.ContentRect.v)); CaretElement.AddTransformToGeometry(geometry, transform); } } return(geometry); }
// 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: 0x06007246 RID: 29254 RVA: 0x0020AB60 File Offset: 0x00208D60 internal static bool IsImmediateAutomationChild(ITextPointer elementStart, ITextPointer ownerContentStart) { Invariant.Assert(elementStart.CompareTo(ownerContentStart) >= 0); bool result = true; ITextPointer textPointer = elementStart.CreatePointer(); while (typeof(TextElement).IsAssignableFrom(textPointer.ParentType)) { textPointer.MoveToElementEdge(ElementEdge.BeforeStart); if (textPointer.CompareTo(ownerContentStart) <= 0) { break; } AutomationPeer automationPeer = null; object adjacentElement = textPointer.GetAdjacentElement(LogicalDirection.Forward); if (adjacentElement is UIElement) { automationPeer = UIElementAutomationPeer.CreatePeerForElement((UIElement)adjacentElement); } else if (adjacentElement is ContentElement) { automationPeer = ContentElementAutomationPeer.CreatePeerForElement((ContentElement)adjacentElement); } if (automationPeer != null) { result = false; break; } } return(result); }
/// <summary> /// Gets start and end offset for a text segment but clamps those values to the start and end /// of a given element. This way if a large text range is being resolved on a node that only contains /// a portion of the text range (such as a paragraph) the result only includes the content in that node. /// </summary> private void GetTextSegmentValues(TextSegment segment, ITextPointer elementStart, ITextPointer elementEnd, out int startOffset, out int endOffset) { startOffset = 0; endOffset = 0; if (elementStart.CompareTo(segment.Start) >= 0) { // segment starts before the start of the element startOffset = 0; } else { startOffset = elementStart.GetOffsetToPosition(segment.Start); } if (elementEnd.CompareTo(segment.End) >= 0) { endOffset = elementStart.GetOffsetToPosition(segment.End); } else { // segment ends after the end of the element endOffset = elementStart.GetOffsetToPosition(elementEnd); } }
// Token: 0x060085BD RID: 34237 RVA: 0x0024AA08 File Offset: 0x00248C08 private ITextPointer GetDropPosition(Visual target, Point point) { Invariant.Assert(target != null); Invariant.Assert(this._textEditor.TextView.IsValid); if (target != this._textEditor.TextView.RenderScope && target != null && this._textEditor.TextView.RenderScope.IsAncestorOf(target)) { GeneralTransform generalTransform = target.TransformToAncestor(this._textEditor.TextView.RenderScope); generalTransform.TryTransform(point, out point); } ITextPointer textPointer = this.TextView.GetTextPositionFromPoint(point, true); if (textPointer != null) { textPointer = textPointer.GetInsertionPosition(textPointer.LogicalDirection); if (this._textEditor.AcceptsRichContent) { TextSegment normalizedLineRange = TextEditorSelection.GetNormalizedLineRange(this.TextView, textPointer); if (!normalizedLineRange.IsNull && textPointer.CompareTo(normalizedLineRange.End) < 0 && !TextPointerBase.IsAtWordBoundary(textPointer, LogicalDirection.Forward) && this._dragSourceTextRange != null && TextPointerBase.IsAtWordBoundary(this._dragSourceTextRange.Start, LogicalDirection.Forward) && TextPointerBase.IsAtWordBoundary(this._dragSourceTextRange.End, LogicalDirection.Forward)) { TextSegment wordRange = TextPointerBase.GetWordRange(textPointer); string textInternal = TextRangeBase.GetTextInternal(wordRange.Start, wordRange.End); int offsetToPosition = wordRange.Start.GetOffsetToPosition(textPointer); textPointer = ((offsetToPosition < textInternal.Length / 2) ? wordRange.Start : wordRange.End); } } } return(textPointer); }
// Token: 0x060035AF RID: 13743 RVA: 0x000F3B94 File Offset: 0x000F1D94 private void MarkRange(ITextPointer start, ITextPointer end, SpellerStatusTable.RunType runType) { if (start.CompareTo(end) == 0) { return; } Invariant.Assert(runType == SpellerStatusTable.RunType.Clean || runType == SpellerStatusTable.RunType.Dirty); int num = this.FindIndex(start.CreateStaticPointer(), LogicalDirection.Forward); int num2 = this.FindIndex(end.CreateStaticPointer(), LogicalDirection.Backward); Invariant.Assert(num >= 0); Invariant.Assert(num2 >= 0); if (num + 1 < num2) { for (int i = num + 1; i < num2; i++) { this.NotifyHighlightLayerBeforeRunChange(i); } this._runList.RemoveRange(num + 1, num2 - num - 1); num2 = num + 1; } if (num == num2) { this.AddRun(num, start, end, runType); return; } Invariant.Assert(num == num2 - 1); this.AddRun(num, start, end, runType); num2 = this.FindIndex(end.CreateStaticPointer(), LogicalDirection.Backward); Invariant.Assert(num2 >= 0); this.AddRun(num2, start, end, runType); }
// 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: 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); }
// Returns the next non-white space character in the forward direction // from position, or null if no such position exists. // The return value will equal position if position is immediately followed // by a non-whitespace char. // // This method expects that limit is never null. The scan will halt if // limit is encountered. private static ITextPointer GetNextNonWhiteSpacePosition(ITextPointer position, ITextPointer limit) { char character; Invariant.Assert(limit != null); while (true) { if (position.CompareTo(limit) == 0) { position = null; break; } position = GetNextTextPosition(position, limit, LogicalDirection.Forward, out character); if (position == null) { break; } if (!Char.IsWhiteSpace(character)) { break; } position = position.CreatePointer(+1); } ; return(position); }
// convert a range given by TextPointers to a UIA TextRange // (helper method for raising ActiveTextPositionChanged event) internal ITextRangeProvider TextRangeFromTextPointers(ITextPointer rangeStart, ITextPointer rangeEnd) { // special case for the entire range if (rangeStart == null && rangeEnd == null) { return(null); } // map null into the appropriate endpoint rangeStart = rangeStart ?? _textContainer.Start; rangeEnd = rangeEnd ?? _textContainer.End; // if either pointer belongs to the wrong tree, return null (meaning "entire range") if (rangeStart.TextContainer != _textContainer || rangeEnd.TextContainer != _textContainer) { return(null); } // swap the pointers, if necessary if (rangeStart.CompareTo(rangeEnd) > 0) { ITextPointer temp = rangeStart; rangeStart = rangeEnd; rangeEnd = rangeStart; } // return the resulting range, wrapped so that it's ready for use by UIA ITextRangeProvider textRange = new TextRangeAdaptor(this, rangeStart, rangeEnd, _textPeer); return(TextRangeProviderWrapper.WrapArgument(textRange, _textPeer)); }
// Token: 0x060035B0 RID: 13744 RVA: 0x000F3C68 File Offset: 0x000F1E68 private void AddRun(int index, ITextPointer start, ITextPointer end, SpellerStatusTable.RunType runType) { Invariant.Assert(runType == SpellerStatusTable.RunType.Clean || runType == SpellerStatusTable.RunType.Dirty); Invariant.Assert(start.CompareTo(end) < 0); SpellerStatusTable.RunType runType2 = (runType == SpellerStatusTable.RunType.Clean) ? SpellerStatusTable.RunType.Dirty : SpellerStatusTable.RunType.Clean; SpellerStatusTable.Run run = this.GetRun(index); if (run.RunType == runType) { this.TryToMergeRunWithNeighbors(index); return; } if (run.RunType != runType2) { run.RunType = runType; ITextPointer position = run.Position; ITextPointer runEndPositionDynamic = this.GetRunEndPositionDynamic(index); this.TryToMergeRunWithNeighbors(index); this._highlightLayer.FireChangedEvent(position, runEndPositionDynamic); return; } if (run.Position.CompareTo(start) >= 0) { if (this.GetRunEndPosition(index).CompareTo(end) <= 0) { run.RunType = runType; this.TryToMergeRunWithNeighbors(index); return; } if (index > 0 && this.GetRun(index - 1).RunType == runType) { run.Position = end; return; } run.RunType = runType; SpellerStatusTable.Run value = new SpellerStatusTable.Run(end, runType2); this._runList.Insert(index + 1, value); return; } else { SpellerStatusTable.Run value; if (this.GetRunEndPosition(index).CompareTo(end) > 0) { value = new SpellerStatusTable.Run(start, runType); this._runList.Insert(index + 1, value); value = new SpellerStatusTable.Run(end, runType2); this._runList.Insert(index + 2, value); return; } if (index < this._runList.Count - 1 && this.GetRun(index + 1).RunType == runType) { this.GetRun(index + 1).Position = start; return; } value = new SpellerStatusTable.Run(start, runType); this._runList.Insert(index + 1, value); return; } }
//----------------------------------------------------- // // Constructors // //----------------------------------------------------- #region Constructors // Creates a new instance. internal SpellingError(Speller speller, ITextPointer start, ITextPointer end) { Invariant.Assert(start.CompareTo(end) < 0); _speller = speller; _start = start.GetFrozenPointer(LogicalDirection.Forward); _end = end.GetFrozenPointer(LogicalDirection.Backward); }
//-------------------------------------------------------------------- // TextContainer Element //--------------------------------------------------------------------- // given a TextPointer range, find out all fixed position included in this range and // offset into the begin and end fixed element private bool _GetFixedNodesForFlowRange(ITextPointer start, ITextPointer end, out FixedSOMElement[] elements, out int startIndex, out int endIndex) { Debug.Assert(start.CompareTo(end) <= 0); elements = null; startIndex = 0; endIndex = 0; if (start.CompareTo(end) == 0) { return(false); } FixedTextPointer pStart = (FixedTextPointer)start; FixedTextPointer pEnd = (FixedTextPointer)end; return(this.FixedTextBuilder.GetFixedNodesForFlowRange(pStart.FlowPosition, pEnd.FlowPosition, out elements, out startIndex, out endIndex)); } //endofGetFixedNodes
// Token: 0x060084BE RID: 33982 RVA: 0x00249888 File Offset: 0x00247A88 internal SpellerHighlightChangedEventArgs(ITextPointer start, ITextPointer end) { Invariant.Assert(start.CompareTo(end) < 0, "Bogus start/end combination!"); this._ranges = new ReadOnlyCollection <TextSegment>(new List <TextSegment>(1) { new TextSegment(start, end) }); }
// Token: 0x06006B6F RID: 27503 RVA: 0x001F0B08 File Offset: 0x001EED08 internal Geometry GetTightBoundingGeometryFromTextPositions(ITextPointer startPosition, ITextPointer endPosition) { if (startPosition.CompareTo(((BlockUIContainer)base.Paragraph.Element).ContentEnd) < 0 && endPosition.CompareTo(((BlockUIContainer)base.Paragraph.Element).ContentStart) > 0) { return(new RectangleGeometry(this._rect.FromTextDpi())); } return(null); }
/// <summary> /// Constructor. /// </summary> /// <param name="startPosition"> /// Position preceeding the TextSegment's content. /// </param> /// <param name="endPosition"> /// Position following the TextSegment's content. /// </param> /// <param name="preserveLogicalDirection"> /// Whether preserves LogicalDirection of start and end positions. /// </param> internal TextSegment(ITextPointer startPosition, ITextPointer endPosition, bool preserveLogicalDirection) { ValidationHelper.VerifyPositionPair(startPosition, endPosition); if (startPosition.CompareTo(endPosition) == 0) { // To preserve segment emptiness // we use the same instance of a pointer // for both segment ends. _start = startPosition.GetFrozenPointer(startPosition.LogicalDirection); _end = _start; } else { Invariant.Assert(startPosition.CompareTo(endPosition) < 0); _start = startPosition.GetFrozenPointer(preserveLogicalDirection ? startPosition.LogicalDirection : LogicalDirection.Backward); _end = endPosition.GetFrozenPointer(preserveLogicalDirection ? endPosition.LogicalDirection : LogicalDirection.Forward); } }
// Token: 0x0600717A RID: 29050 RVA: 0x00207344 File Offset: 0x00205544 internal override bool Contains(ITextPointer position, bool strict) { bool flag = base.Contains(position, strict); if (!flag && strict) { flag = (position.CompareTo(base.EndPosition) == 0); } return(flag); }
//----------------------------------------------------- // // ITextRange Methods // //----------------------------------------------------- #region ITextRange Methods //...................................................... // // Selection Building // //...................................................... /// <summary> /// </summary> // internal static bool Contains(ITextRange thisRange, ITextPointer textPointer) { NormalizeRange(thisRange); if (textPointer == null) { throw new ArgumentNullException("textPointer"); } if (textPointer.TextContainer != thisRange.Start.TextContainer) { throw new ArgumentException(SR.Get(SRID.NotInAssociatedTree), "textPointer"); } // Correct position normalization on range boundary so that // our test would not depend on what side of formatting tags // pointer is located. if (textPointer.CompareTo(thisRange.Start) < 0) { textPointer = textPointer.GetFormatNormalizedPosition(LogicalDirection.Forward); } else if (textPointer.CompareTo(thisRange.End) > 0) { textPointer = textPointer.GetFormatNormalizedPosition(LogicalDirection.Backward); } // Check if at least one segment contains this position. for (int i = 0; i < thisRange._TextSegments.Count; i++) { if (thisRange._TextSegments[i].Contains(textPointer)) { return true; } } return false; }
// Verifies two positions are safe to use as a logical text span. // // Throws ArgumentNullException if startPosition == null || endPosition == null // ArgumentException if startPosition.TextContainer != endPosition.TextContainer or // startPosition > endPosition internal static void VerifyPositionPair(ITextPointer startPosition, ITextPointer endPosition) { if (startPosition == null) { throw new ArgumentNullException("startPosition"); } if (endPosition == null) { throw new ArgumentNullException("endPosition"); } if (startPosition.TextContainer != endPosition.TextContainer) { throw new ArgumentException(SR.Get(SRID.InDifferentTextContainers, "startPosition", "endPosition")); } if (startPosition.CompareTo(endPosition) > 0) { throw new ArgumentException(SR.Get(SRID.BadTextPositionOrder, "startPosition", "endPosition")); } }
// Deletes a specified run of content. // // On exit, // symbolsRemoved <== count of symbols actually removed. // removeStartIndex <== offset of first symbol affected by the edit. // // removeStartIndex is always <= endPosition.Offset, but it does not necessarily // match the position of the logically removed content. In some rare cases // a scoping element may be removed, meaning we have two or more runs of // removed content, and removeStartIndex + symbolsRemoved < the offset of // the last position affected by the operation. private void RemoveContent(ITextPointer startPosition, ITextPointer endPosition, out int symbolsRemoved, out int removeStartIndex) { symbolsRemoved = 0; removeStartIndex = startPosition.Offset; if (startPosition.CompareTo(endPosition) == 0) return; TextContainer container = (TextContainer)startPosition.TextContainer; symbolsRemoved = container.SymbolCount; if (startPosition is TextPointer) { _minSymbolsRemovedIndex = Int32.MaxValue; } startPosition.DeleteContentToPosition(endPosition); if (startPosition is TextPointer) { removeStartIndex = _minSymbolsRemovedIndex; } symbolsRemoved = symbolsRemoved - container.SymbolCount; }
/// <summary> /// Checks if line wrapping is happening at this position /// </summary> internal static bool IsAtLineWrappingPosition(ITextPointer position, ITextView textView) { Invariant.Assert(position != null, "null check: position"); if (!position.HasValidLayout) { return false; } Invariant.Assert(textView != null, "textView cannot be null because the position has valid layout"); TextSegment lineSegment = textView.GetLineRange(position); if (lineSegment.IsNull) { return false; } bool isAtLineWrappingPosition = position.LogicalDirection == LogicalDirection.Forward ? position.CompareTo(lineSegment.Start) == 0 : position.CompareTo(lineSegment.End) == 0; return isAtLineWrappingPosition; }
//------------------------------------------------------ // // 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; } }
// Extends the selection to the mouse cursor position. void ITextSelection.ExtendSelectionByMouse(ITextPointer cursorPosition, bool forceWordSelection, bool forceParagraphSelection) { ITextSelection thisSelection = (ITextSelection)this; // Check whether the cursor has been actually moved - compare with the previous position if (forceParagraphSelection || _previousCursorPosition != null && cursorPosition.CompareTo(_previousCursorPosition) == 0) { // Mouse was not actually moved. Ignore the event. return; } thisSelection.BeginChange(); try { if (!BeginMouseSelectionProcess(cursorPosition)) { return; } // Get anchor position ITextPointer anchorPosition = ((ITextSelection)this).AnchorPosition; // Identify words on selection ends TextSegment anchorWordRange; TextSegment cursorWordRange; IdentifyWordsOnSelectionEnds(anchorPosition, cursorPosition, forceWordSelection, out anchorWordRange, out cursorWordRange); // Calculate selection boundary positions ITextPointer startPosition; ITextPointer movingPosition; if (anchorWordRange.Start.CompareTo(cursorWordRange.Start) <= 0) { startPosition = anchorWordRange.Start.GetFrozenPointer(LogicalDirection.Forward); movingPosition = cursorWordRange.End.GetFrozenPointer(LogicalDirection.Backward); ; } else { startPosition = anchorWordRange.End.GetFrozenPointer(LogicalDirection.Backward); movingPosition = cursorWordRange.Start.GetFrozenPointer(LogicalDirection.Forward); ; } // Note that we use includeCellAtMovingPosition=true because we want that hit-tested table cell // be included into selection no matter whether it's empty or not. TextRangeBase.Select(this, startPosition, movingPosition, /*includeCellAtMovingPosition:*/true); SetActivePositions(anchorPosition, movingPosition); // Store previous cursor position - for the next extension event _previousCursorPosition = cursorPosition.CreatePointer(); Invariant.Assert(thisSelection.Contains(thisSelection.AnchorPosition)); } finally { thisSelection.EndChange(); } }
// Part of ExtendSelectionByMouse method: // Identifies words on selection ends. private void IdentifyWordsOnSelectionEnds(ITextPointer anchorPosition, ITextPointer cursorPosition, bool forceWordSelection, out TextSegment anchorWordRange, out TextSegment cursorWordRange) { if (forceWordSelection) { anchorWordRange = TextPointerBase.GetWordRange(anchorPosition); cursorWordRange = TextPointerBase.GetWordRange(cursorPosition, cursorPosition.LogicalDirection); } else { // Define whether word adjustment is allowed. Pressing Shift+Control prevents from auto-word expansion. bool disableWordExpansion = _textEditor.AutoWordSelection == false || ((Keyboard.Modifiers & ModifierKeys.Shift) != 0 && (Keyboard.Modifiers & ModifierKeys.Control) != 0); if (disableWordExpansion) { anchorWordRange = new TextSegment(anchorPosition, anchorPosition); cursorWordRange = new TextSegment(cursorPosition, cursorPosition); } else { // Autoword expansion heuristics // ----------------------------- // Word autoword heuristics: // a) After active end returned to selected area, autoword expansion on active end is disabled // b) After active end returned to the very first word, expansion on anchor word is disabled either // We do this though only if selection has crossed initial word boundary at least once. // c) After active end crosses new word, autoword expansion of active end is enabled again // Calculate a word range for anchor position anchorWordRange = TextPointerBase.GetWordRange(anchorPosition); // Check if we re-entering selection or moving outside // and set autoexpansion flags accordingly if (_previousCursorPosition != null && (anchorPosition.CompareTo(cursorPosition) < 0 && cursorPosition.CompareTo(_previousCursorPosition) < 0 || _previousCursorPosition.CompareTo(cursorPosition) < 0 && cursorPosition.CompareTo(anchorPosition) < 0)) { // Re-entering selection. // Store position of reentering _reenterPosition = cursorPosition.CreatePointer(); // When re-entering reaches initial word, disable word expansion on anchor end either if (_anchorWordRangeHasBeenCrossedOnce && anchorWordRange.Contains(cursorPosition)) { _allowWordExpansionOnAnchorEnd = false; } } else { // Extending the selection. // Check if we are crossing a boundary of last reentered word to re-enable word expansion on moving end if (_reenterPosition != null) { TextSegment lastReenteredWordRange = TextPointerBase.GetWordRange(_reenterPosition); if (!lastReenteredWordRange.Contains(cursorPosition)) { _reenterPosition = null; } } } // Identify expanded range on both ends // if (anchorWordRange.Contains(cursorPosition) || anchorWordRange.Contains(cursorPosition.GetInsertionPosition(LogicalDirection.Forward)) || anchorWordRange.Contains(cursorPosition.GetInsertionPosition(LogicalDirection.Backward))) { // Selection does not cross word boundary, so shrink selection to exact anchor/cursor positions anchorWordRange = new TextSegment(anchorPosition, anchorPosition); cursorWordRange = new TextSegment(cursorPosition, cursorPosition); } else { // Selection crosses word boundary. _anchorWordRangeHasBeenCrossedOnce = true; if (!_allowWordExpansionOnAnchorEnd || // TextPointerBase.IsAtWordBoundary(anchorPosition, /*insideWordDirection:*/LogicalDirection.Forward)) { // We collapse anchorPosition in two cases: // If we have been re-entering the initial word before - // then we treat it as an indicator that user wants exact position on anchor end // or // if selection starts exactly on word boundary - // then we should not include the following word (when selection extends backward). // // So in the both cases we collapse anchorWordRange to exact _anchorPosition anchorWordRange = new TextSegment(anchorPosition, anchorPosition); } if (TextPointerBase.IsAfterLastParagraph(cursorPosition) || TextPointerBase.IsAtWordBoundary(cursorPosition, /*insideWordDirection:*/LogicalDirection.Forward)) { cursorWordRange = new TextSegment(cursorPosition, cursorPosition); } else { if (_reenterPosition == null) { // We are not in re-entering mode; expand moving end to word boundary cursorWordRange = TextPointerBase.GetWordRange(cursorPosition, cursorPosition.LogicalDirection); } else { // We are in re-entering mode; use exact moving end position cursorWordRange = new TextSegment(cursorPosition, cursorPosition); } } } } } }
/// <summary> /// <see cref="TextViewBase.GetTightBoundingGeometryFromTextPositions"/> /// </summary> internal override Geometry GetTightBoundingGeometryFromTextPositions(ITextPointer startPosition, ITextPointer endPosition) { // verify that layout information is valid. Cannot continue if not valid. if (!IsValid) { throw new InvalidOperationException(SR.Get(SRID.TextViewInvalidLayout)); } Geometry geometry = null; for (int i = 0, count = _pageTextViews.Count; i < count; ++i) { ReadOnlyCollection<TextSegment> textSegments = _pageTextViews[i].TextSegments; for (int segmentIndex = 0; segmentIndex < textSegments.Count; segmentIndex++) { TextSegment textSegment = textSegments[segmentIndex]; ITextPointer startPositionInTextSegment = startPosition.CompareTo(textSegment.Start) > 0 ? startPosition : textSegment.Start; ITextPointer endPositionInTextSegment = endPosition.CompareTo(textSegment.End) < 0 ? endPosition : textSegment.End; if (startPositionInTextSegment.CompareTo(endPositionInTextSegment) >= 0) { continue; } Geometry pageGeometry = _pageTextViews[i].GetTightBoundingGeometryFromTextPositions(startPositionInTextSegment, endPositionInTextSegment); if (pageGeometry != null) { Transform transform = _pageTextViews[i].RenderScope.TransformToAncestor(_renderScope).AffineTransform; CaretElement.AddTransformToGeometry(pageGeometry, transform); CaretElement.AddGeometry(ref geometry, pageGeometry); } } } return (geometry); }
// Uses the current selection state to match an ITextPointer to one of the possible // moving position edges. private MovingEdge ConvertToMovingEdge(ITextPointer anchorPosition, ITextPointer movingPosition) { ITextSelection thisSelection = this; MovingEdge movingEdge; if (thisSelection.IsEmpty) { // Empty selections have no moving edge. movingEdge = MovingEdge.None; } else if (thisSelection.TextSegments.Count < 2) { // Simple text selections move opposite their anchor positions. movingEdge = (anchorPosition.CompareTo(movingPosition) <= 0) ? MovingEdge.End : MovingEdge.Start; } else { // Table selection. Look for an exact match. if (movingPosition.CompareTo(thisSelection.Start) == 0) { movingEdge = MovingEdge.Start; } else if (movingPosition.CompareTo(thisSelection.End) == 0) { movingEdge = MovingEdge.End; } else if (movingPosition.CompareTo(thisSelection.TextSegments[0].End) == 0) { movingEdge = MovingEdge.StartInner; } else if (movingPosition.CompareTo(thisSelection.TextSegments[thisSelection.TextSegments.Count-1].Start) == 0) { movingEdge = MovingEdge.EndInner; } else { movingEdge = (anchorPosition.CompareTo(movingPosition) <= 0) ? MovingEdge.End : MovingEdge.Start; } } return movingEdge; }
//-------------------------------------------------------------------- // TextContainer Element //--------------------------------------------------------------------- // given a TextPointer range, find out all fixed position included in this range and // offset into the begin and end fixed element private bool _GetFixedNodesForFlowRange(ITextPointer start, ITextPointer end, out FixedSOMElement[] elements, out int startIndex, out int endIndex) { Debug.Assert(start.CompareTo(end) <= 0); elements = null; startIndex = 0; endIndex = 0; if (start.CompareTo(end) == 0) { return false; } FixedTextPointer pStart = (FixedTextPointer)start; FixedTextPointer pEnd = (FixedTextPointer)end; return this.FixedTextBuilder.GetFixedNodesForFlowRange(pStart.FlowPosition, pEnd.FlowPosition, out elements, out startIndex, out endIndex); } //endofGetFixedNodes
internal Geometry GetTightBoundingGeometryFromTextPositions(ITextPointer startPosition, ITextPointer endPosition, Rect visibleRect) { Debug.Assert( TableParagraph.Table != null && CalculatedColumns != null ); Geometry geometry = null; PTS.FSTABLEROWDESCRIPTION[] arrayTableRowDesc; PTS.FSKUPDATE fskupdTable; PTS.FSRECT rectTable; if (QueryTableDetails(out arrayTableRowDesc, out fskupdTable, out rectTable)) { bool passedEndPosition = false; for (int iR = 0; iR < arrayTableRowDesc.Length && !passedEndPosition; ++iR) { PTS.FSKUPDATE[] arrayUpdate; IntPtr[] arrayFsCell; PTS.FSTABLEKCELLMERGE[] arrayTableCellMerge; QueryRowDetails( arrayTableRowDesc[iR].pfstablerow, out arrayFsCell, out arrayUpdate, out arrayTableCellMerge); for (int iC = 0; iC < arrayFsCell.Length; ++iC) { if (arrayFsCell[iC] == IntPtr.Zero) { // paginated case - cell may be null continue; } CellParaClient cpc = (CellParaClient)(PtsContext.HandleToObject(arrayFsCell[iC])); if (endPosition.CompareTo(cpc.Cell.ContentStart) <= 0) { // remember that at least one cell in this row starts after the range's end. // in this case it is safe to break after this whole row is processed. // Note: can not break right away because cells in arrayFsCell come not // necessarily in backing store (cp) order. passedEndPosition = true; } else { if (startPosition.CompareTo(cpc.Cell.ContentEnd) <= 0) { Geometry cellGeometry = cpc.GetTightBoundingGeometryFromTextPositions(startPosition, endPosition, visibleRect); CaretElement.AddGeometry(ref geometry, cellGeometry); } } } } } if (geometry != null) { geometry = Geometry.Combine(geometry, Visual.Clip, GeometryCombineMode.Intersect, null); } return geometry; }
// Marks a text run as clean or dirty. private void MarkRange(ITextPointer start, ITextPointer end, RunType runType) { if (start.CompareTo(end) == 0) { return; } int startIndex; int endIndex; Invariant.Assert(runType == RunType.Clean || runType == RunType.Dirty); startIndex = FindIndex(start.CreateStaticPointer(), LogicalDirection.Forward); endIndex = FindIndex(end.CreateStaticPointer(), LogicalDirection.Backward); // We don't expect start/end to ever point off the edge of the document. Invariant.Assert(startIndex >= 0); Invariant.Assert(endIndex >= 0); // Remove wholly covered runs. if (startIndex + 1 < endIndex) { // Tell the HighlightLayer about any error runs that are going away. for (int i = startIndex + 1; i < endIndex; i++) { NotifyHighlightLayerBeforeRunChange(i); } _runList.RemoveRange(startIndex + 1, endIndex - startIndex - 1); endIndex = startIndex + 1; } // Merge the bordering edge runs. if (startIndex == endIndex) { // We're contained in a single run. AddRun(startIndex, start, end, runType); } else { // We cover two runs. Invariant.Assert(startIndex == endIndex - 1); // Handle the first run. AddRun(startIndex, start, end, runType); // Recalc endIndex, since it may have changed in the merge. endIndex = FindIndex(end.CreateStaticPointer(), LogicalDirection.Backward); Invariant.Assert(endIndex >= 0); // Handle the second run. AddRun(endIndex, start, end, runType); } }
// Like GetText, excepts also accepts a limit parameter -- no text is returned past // this second position. // limit may be null, in which case it is ignored. internal static int GetTextWithLimit(ITextPointer thisPointer, LogicalDirection direction, char[] textBuffer, int startIndex, int count, ITextPointer limit) { int charsCopied; if (limit == null) { // No limit, just call GetText. charsCopied = thisPointer.GetTextInRun(direction, textBuffer, startIndex, count); } else if (direction == LogicalDirection.Forward && limit.CompareTo(thisPointer) <= 0) { // Limit completely blocks the read. charsCopied = 0; } else if (direction == LogicalDirection.Backward && limit.CompareTo(thisPointer) >= 0) { // Limit completely blocks the read. charsCopied = 0; } else { int maxCount; // Get an upper bound on the amount of text to copy. // Since GetText always stops on non-text boundaries, it's // ok if the count too high, it will get truncated anyways. if (direction == LogicalDirection.Forward) { maxCount = Math.Min(count, thisPointer.GetOffsetToPosition(limit)); } else { maxCount = Math.Min(count, limit.GetOffsetToPosition(thisPointer)); } maxCount = Math.Min(count, maxCount); charsCopied = thisPointer.GetTextInRun(direction, textBuffer, startIndex, maxCount); } return charsCopied; }
// Opens the composition undo unit if it exists on the top // of the stack. Otherwise, create a new composition undo unit // and add it to the undo stack. private CompositionParentUndoUnit OpenCompositionUndoUnit(ITextPointer compositionStart, ITextPointer compositionEnd) { UndoManager undoManager = UndoManager.GetUndoManager(this.TextContainer.Parent); if (undoManager == null || !undoManager.IsEnabled) { return null; } // The start position is where we'll put the caret if this composition is later // undone by a user. // // At this point some IMEs will not have updated the selection to a // position within the composition, suggesting that we always want to // use selection start. However, some IMEs will expand the composition backward on input // so the composition covers unmodified text. (E.g.: chinese prc pinyin IME // will expand to cover previously finalized text on <space> input.) // // So we use a hueristic: take the rightmost of the selection start or composition // start. ITextPointer start; if (compositionStart == null) { Invariant.Assert(compositionEnd == null); GetCompositionPositions(out compositionStart, out compositionEnd); } if (compositionStart != null && compositionStart.CompareTo(this.TextSelection.Start) > 0) { start = compositionStart; } else { start = this.TextSelection.Start; } CompositionParentUndoUnit unit = new CompositionParentUndoUnit(this.TextSelection, start, start, _nextUndoUnitIsFirstCompositionUnit); _nextUndoUnitIsFirstCompositionUnit = false; // Add the given composition undo unit to the undo manager and making it // as the opened undo unit. undoManager.Open(unit); return unit; }
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 Blocks and TableCell to add '\n' or TS_CHAR_REGION. private static bool WalkRegionBoundary(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.ElementStart || navigator.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementEnd); Invariant.Assert(limit == null || navigator.CompareTo(limit) <= 0); // If the caller passed in a non-null limit, we don't do anything and just return true. // we've passed it. if (limit != null) { if (navigator.CompareTo(limit) >= 0) { return true; } } hitLimit = false; if (cchReq > 0) { // Add one TS_CHAR_REGION (TableCell) or '\n' (everything else) char. char ch = (navigator.GetAdjacentElement(LogicalDirection.Forward) is TableCell) ? UnsafeNativeMethods.TS_CHAR_REGION : '\n'; text[charsCopied] = ch; navigator.MoveByOffset(1); charsCopied += 1; hitLimit = (text.Length == charsCopied) || (limit != null && navigator.CompareTo(limit) == 0); } else { // Caller doesn't want text, just run info. // Advance the navigator. // Add one TS_CHAR_REGION char. navigator.MoveByOffset(1); } 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 += 1; } else { runInfo[cRunInfoRcv].count = 1; runInfo[cRunInfoRcv].type = UnsafeNativeMethods.TsRunType.TS_RT_PLAIN; cRunInfoRcv++; } } return hitLimit; }
/// <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; }
// 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; }
// Adds a new run into an old one, merging the two. private void AddRun(int index, ITextPointer start, ITextPointer end, RunType runType) { Run run; Run newRun; RunType oppositeRunType; // We don't expect runType.Error, just clean or dirty. Invariant.Assert(runType == RunType.Clean || runType == RunType.Dirty); // We don't expect empty runs here. Invariant.Assert(start.CompareTo(end) < 0); oppositeRunType = (runType == RunType.Clean) ? RunType.Dirty : RunType.Clean; run = GetRun(index); if (run.RunType == runType) { // Existing run value matches new one. TryToMergeRunWithNeighbors(index); } else if (run.RunType == oppositeRunType) { // We're merging a new clean run with an old dirty one, or vice versa. // Split the run, insert a new run in the middle. if (run.Position.CompareTo(start) >= 0) { if (GetRunEndPosition(index).CompareTo(end) <= 0) { // We entirely cover this run, just flip the RunType. run.RunType = runType; TryToMergeRunWithNeighbors(index); } else { // We cover the left half. if (index > 0 && GetRun(index - 1).RunType == runType) { // Previous run matches the new value, merge with it. run.Position = end; } else { run.RunType = runType; newRun = new Run(end, oppositeRunType); _runList.Insert(index + 1, newRun); } } } else if (GetRunEndPosition(index).CompareTo(end) <= 0) { // We cover the right half. if (index < _runList.Count - 1 && GetRun(index + 1).RunType == runType) { // Following run matches the new value, merge with it. GetRun(index + 1).Position = start; } else { // Insert new run. newRun = new Run(start, runType); _runList.Insert(index + 1, newRun); } } else { // We're in the middle of the run. // Split the run, adding a new run and a new second // half of the original run. newRun = new Run(start, runType); _runList.Insert(index + 1, newRun); newRun = new Run(end, oppositeRunType); _runList.Insert(index + 2, newRun); } } else { ITextPointer errorStart; ITextPointer errorEnd; // We hit an error run, the whole thing becomes dirty/clean. run.RunType = runType; errorStart = run.Position; errorEnd = GetRunEndPositionDynamic(index); // This call might remove run... TryToMergeRunWithNeighbors(index); // Tell the HighlightLayer about this change. _highlightLayer.FireChangedEvent(errorStart, errorEnd); } }
// Repositions an ITextRange to comply with limitations on IME input. // We cannot modify Table structure, or insert content // before or after Tables or BlockUIContainers while maintaing our // contract with the cicero interfaces (without major refactoring of // our code). private static void GetAdjustedSelection(ITextPointer startIn, ITextPointer endIn, out ITextPointer startOut, out ITextPointer endOut) { startOut = startIn; endOut = endIn; TextPointer start = startOut as TextPointer; // Tables and BlockUIContainers only exist in TextContainers, if // we're in some other kind of document no adjustments are needed. if (start == null) { return; } TextPointer end = (TextPointer)endOut; if (startIn.CompareTo(endIn) != 0) { bool scopingBlockUIContainer = TextPointerBase.IsInBlockUIContainer(start) || TextPointerBase.IsInBlockUIContainer(end); TableCell startCell = TextRangeEditTables.GetTableCellFromPosition(start); TableCell endCell = TextRangeEditTables.GetTableCellFromPosition(end); bool singleScopingTableCell = (startCell != null && startCell == endCell); bool scopingTable = TextRangeEditTables.GetTableFromPosition(start) != null || TextRangeEditTables.GetTableFromPosition(end) != null; // With a non-empty selection, if neither end of the selection is inside a Table or BlockUIContainer, // there's nothing to adjust. if (!scopingBlockUIContainer && (singleScopingTableCell || !scopingTable)) { return; } } // From this point forward, we know selection will collapse to // a single insertion point, so we ignore end. if (start.IsAtRowEnd) { TextPointer previousPosition = start.GetNextInsertionPosition(LogicalDirection.Backward); Table currentTable = TextRangeEditTables.GetTableFromPosition(start); start = TextRangeEditTables.GetAdjustedRowEndPosition(currentTable, start); if (!start.IsAtInsertionPosition) { // The document ends with a Table, and position is just past that. // Back up to the previous TableCell proceding. start = previousPosition; } } else if (TextPointerBase.IsInBlockUIContainer(start)) { if (start.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.ElementStart) { start = start.GetNextInsertionPosition(LogicalDirection.Backward); } else { start = start.GetNextInsertionPosition(LogicalDirection.Forward); } } while (start != null && TextPointerBase.IsBeforeFirstTable(start)) { // Note that the symmetrical case, AfterLastTable, is handled by // the IsAtRowEnd test above. start = start.GetNextInsertionPosition(LogicalDirection.Forward); } // If we have non-canonical format, give up. if (start == null || start.IsAtRowEnd || TextPointerBase.IsInBlockUIContainer(start)) { throw new COMException(SR.Get(SRID.TextStore_CompositionRejected), NativeMethods.E_FAIL); } startOut = start; endOut = start; }
// 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); } }
// 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 the bounding rectangles for the text lines of a given range. /// </summary> /// <param name="start">Start of range to measure</param> /// <param name="end">End of range to measure</param> /// <param name="clipToView">Specifies whether the caller wants the full bounds (false) or the bounds of visible portions /// of the viewable line only ('true')</param> /// <param name="transformToScreen">Requests the results in screen coordinates</param> /// <returns>An array of bounding rectangles for each line or portion of a line within the client area of the text provider. /// No bounding rectangles will be returned for lines that are empty or scrolled out of view. Note that even though a /// bounding rectangle is returned the corresponding text may not be visible due to overlapping windows. /// This will not return null, but may return an empty array.</returns> internal Rect[] GetBoundingRectangles(ITextPointer start, ITextPointer end, bool clipToView, bool transformToScreen) { ITextView textView = GetUpdatedTextView(); if (textView == null) { return new Rect[0]; } // If start/end positions are not in the visible range, move them to the first/last visible positions. ReadOnlyCollection<TextSegment> textSegments = textView.TextSegments; if (textSegments.Count > 0) { if (!textView.Contains(start) && start.CompareTo(textSegments[0].Start) < 0) { start = textSegments[0].Start.CreatePointer(); ; } if (!textView.Contains(end) && end.CompareTo(textSegments[textSegments.Count-1].End) > 0) { end = textSegments[textSegments.Count - 1].End.CreatePointer(); } } if (!textView.Contains(start) || !textView.Contains(end)) { return new Rect[0]; } TextRangeAdaptor.MoveToInsertionPosition(start, LogicalDirection.Forward); TextRangeAdaptor.MoveToInsertionPosition(end, LogicalDirection.Backward); Rect visibleRect = Rect.Empty; if (clipToView) { visibleRect = GetVisibleRectangle(textView); // If clipping into view and visible rect is empty, return. if (visibleRect.IsEmpty) { return new Rect[0]; } } List<Rect> rectangles = new List<Rect>(); ITextPointer position = start.CreatePointer(); while (position.CompareTo(end) < 0) { TextSegment lineRange = textView.GetLineRange(position); if (!lineRange.IsNull) { // Since range is limited to just one line, GetTightBoundingGeometry will return tight bounding // rectangle for given range. It will also work correctly with bidi text. ITextPointer first = (lineRange.Start.CompareTo(start) <= 0) ? start : lineRange.Start; ITextPointer last = (lineRange.End.CompareTo(end) >= 0) ? end : lineRange.End; Rect lineRect = Rect.Empty; Geometry geometry = textView.GetTightBoundingGeometryFromTextPositions(first, last); if (geometry != null) { lineRect = geometry.Bounds; if (clipToView) { lineRect.Intersect(visibleRect); } if (!lineRect.IsEmpty) { if (transformToScreen) { lineRect = new Rect(ClientToScreen(lineRect.TopLeft, textView.RenderScope), ClientToScreen(lineRect.BottomRight, textView.RenderScope)); } rectangles.Add(lineRect); } } } if (position.MoveToLineBoundary(1) == 0) { position = end; } } return rectangles.ToArray(); }
// Constructor. internal TextSelectionHighlightChangedEventArgs(ITextPointer invalidRangeLeftStart, ITextPointer invalidRangeLeftEnd, ITextPointer invalidRangeRightStart, ITextPointer invalidRangeRightEnd) { List<TextSegment> rangeArray; Invariant.Assert(invalidRangeLeftStart != invalidRangeLeftEnd || invalidRangeRightStart != invalidRangeRightEnd, "Unexpected empty range!"); if (invalidRangeLeftStart.CompareTo(invalidRangeLeftEnd) == 0) { rangeArray = new List<TextSegment>(1); rangeArray.Add(new TextSegment(invalidRangeRightStart, invalidRangeRightEnd)); } else if (invalidRangeRightStart.CompareTo(invalidRangeRightEnd) == 0) { rangeArray = new List<TextSegment>(1); rangeArray.Add(new TextSegment(invalidRangeLeftStart, invalidRangeLeftEnd)); } else { rangeArray = new List<TextSegment>(2); rangeArray.Add(new TextSegment(invalidRangeLeftStart, invalidRangeLeftEnd)); rangeArray.Add(new TextSegment(invalidRangeRightStart, invalidRangeRightEnd)); } _ranges = new ReadOnlyCollection<TextSegment>(rangeArray); }
/// <summary> /// Returns the following TextPointer of a pair. /// </summary> /// <param name="position1"> /// TextPointer to compare. /// </param> /// <param name="position2"> /// TextPointer to compare. /// </param> internal static ITextPointer Max(ITextPointer position1, ITextPointer position2) { return position1.CompareTo(position2) >= 0 ? position1 : position2; }
internal CellParaClient GetCellParaClientFromPosition(ITextPointer position) { Debug.Assert( TableParagraph.Table != null && CalculatedColumns != null ); PTS.FSTABLEROWDESCRIPTION[] arrayTableRowDesc; PTS.FSKUPDATE fskupdTable; PTS.FSRECT rectTable; if (QueryTableDetails(out arrayTableRowDesc, out fskupdTable, out rectTable)) { for (int iR = 0; iR < arrayTableRowDesc.Length; ++iR) { PTS.FSKUPDATE[] arrayUpdate; IntPtr[] arrayFsCell; PTS.FSTABLEKCELLMERGE[] arrayTableCellMerge; QueryRowDetails( arrayTableRowDesc[iR].pfstablerow, out arrayFsCell, out arrayUpdate, out arrayTableCellMerge); for (int iC = 0; iC < arrayFsCell.Length; ++iC) { if (arrayFsCell[iC] == IntPtr.Zero) { // paginated case - cell may be null continue; } CellParaClient cpc = (CellParaClient)(PtsContext.HandleToObject(arrayFsCell[iC])); if(position.CompareTo(cpc.Cell.ContentStart) >= 0 && position.CompareTo(cpc.Cell.ContentEnd) <= 0) { return cpc; } } } } return (null); }
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); }