/// <summary> /// Retrieves an oriented text position matching position advanced by /// a number of lines from its initial position. /// </summary> /// <param name="position"> /// Initial text position of an object/character. /// </param> /// <param name="suggestedX"> /// The suggested X offset, in pixels, of text position on the destination /// line. If suggestedX is set to Double.NaN it will be ignored, otherwise /// the method will try to find a position on the destination line closest /// to suggestedX. /// </param> /// <param name="count"> /// Number of lines to advance. Negative means move backwards. /// </param> /// <param name="newSuggestedX"> /// newSuggestedX is the offset at the position moved (useful when moving /// between columns or pages). /// </param> /// <param name="linesMoved"> /// linesMoved indicates the number of lines moved, which may be less /// than count if there is no more content. /// </param> /// <returns> /// A TextPointer and its orientation matching suggestedX on the /// destination line. /// </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> internal override ITextPointer GetPositionAtNextLine(ITextPointer position, double suggestedX, int count, out double newSuggestedX, out int linesMoved) { newSuggestedX = suggestedX; linesMoved = count; DocumentsTrace.FixedDocumentSequence.TextOM.Trace(string.Format("GetPositionAtNextLine {0} {1} {2} {3} ", position, position.LogicalDirection, suggestedX, count)); DocumentSequenceTextPointer newTp = null; LogicalDirection newEdge = LogicalDirection.Forward; DocumentSequenceTextPointer tp = null; if (position != null) { tp = _docPage.FixedDocumentSequence.TextContainer.VerifyPosition(position); } // Note we do not handle cross page navigation if (tp != null) { if (ChildTextView != null) { if (ChildTextView.TextContainer == tp.ChildBlock.ChildContainer) { ITextPointer childOTP = ChildTextView.GetPositionAtNextLine(tp.ChildPointer.CreatePointer(position.LogicalDirection), suggestedX, count, out newSuggestedX, out linesMoved); if (childOTP != null) { newTp = new DocumentSequenceTextPointer(ChildBlock, childOTP); newEdge = childOTP.LogicalDirection; } } } } return(DocumentSequenceTextPointer.CreatePointer(newTp, newEdge)); }
/// <summary> /// Retrieves the height and offset, in pixels, of the edge of /// the object/character represented by position. /// </summary> /// <param name="position"> /// Position of an object/character. /// </param> /// <param name="transform"> /// Transform to be applied to returned rect /// </param> /// <returns> /// The height, in pixels, of the edge of the object/character /// represented by position. /// </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> /// Rect.Width is always 0. /// /// If the document is empty, then this method returns the expected /// height of a character, if placed at the specified position. /// </remarks> internal override Rect GetRawRectangleFromTextPosition(ITextPointer position, out Transform transform) { DocumentsTrace.FixedDocumentSequence.TextOM.Trace(string.Format("GetRawRectangleFromTextPosition {0} {1}", position, position.LogicalDirection)); DocumentSequenceTextPointer tp = null; // Initialize transform to identity transform = Transform.Identity; if (position != null) { tp = _docPage.FixedDocumentSequence.TextContainer.VerifyPosition(position); } if (tp != null) { if (ChildTextView != null) { if (ChildTextView.TextContainer == tp.ChildBlock.ChildContainer) { return(ChildTextView.GetRawRectangleFromTextPosition(tp.ChildPointer.CreatePointer(position.LogicalDirection), out transform)); } } } return(Rect.Empty); }
// Intelligent compare routine that understands block gap // Since there it is assumed that there is an invisible Gap // object between adjancent two blocks, there is no position // overlap. private static int xGapAwareCompareTo(DocumentSequenceTextPointer thisTp, DocumentSequenceTextPointer tp) { Debug.Assert(tp != null); if ((object)thisTp == (object)tp) { return(0); } ChildDocumentBlock thisBlock = thisTp.ChildBlock; ChildDocumentBlock tpBlock = tp.ChildBlock; int comp = thisTp.AggregatedContainer.GetChildBlockDistance(thisBlock, tpBlock); if (comp == 0) { Debug.Assert(thisTp.ChildBlock.ChildContainer == tp.ChildBlock.ChildContainer); return(thisTp.ChildPointer.CompareTo(tp.ChildPointer)); } else if (comp < 0) { // thisBlock is after tpBlock return(xUnseparated(tp, thisTp) ? 0 : 1); } else { // thisBlock is before tpBlock return(xUnseparated(thisTp, tp) ? 0 : -1); } }
// Token: 0x06002B79 RID: 11129 RVA: 0x000C66D0 File Offset: 0x000C48D0 internal int GetPageNumber(ContentPosition contentPosition) { if (contentPosition == null) { throw new ArgumentNullException("contentPosition"); } DynamicDocumentPaginator dynamicDocumentPaginator = null; ContentPosition contentPosition2 = null; if (contentPosition is DocumentSequenceTextPointer) { DocumentSequenceTextPointer documentSequenceTextPointer = (DocumentSequenceTextPointer)contentPosition; dynamicDocumentPaginator = this.GetPaginator(documentSequenceTextPointer.ChildBlock.DocRef); contentPosition2 = (documentSequenceTextPointer.ChildPointer as ContentPosition); } if (contentPosition2 == null) { throw new ArgumentException(SR.Get("IDPInvalidContentPosition")); } int pageNumber = dynamicDocumentPaginator.GetPageNumber(contentPosition2); int result; this._SynthesizeGlobalPageNumber(dynamicDocumentPaginator, pageNumber, out result); return(result); }
// Token: 0x06002E74 RID: 11892 RVA: 0x000D2774 File Offset: 0x000D0974 private static void _GetFirstPageSearchPointers(ITextPointer start, ITextPointer end, int pageNumber, bool matchLast, out ITextPointer firstSearchPageStart, out ITextPointer firstSearchPageEnd) { if (matchLast) { DocumentSequenceTextPointer documentSequenceTextPointer = end as DocumentSequenceTextPointer; if (documentSequenceTextPointer != null) { FlowPosition pageStartFlowPosition = ((FixedTextContainer)documentSequenceTextPointer.ChildBlock.ChildContainer).FixedTextBuilder.GetPageStartFlowPosition(pageNumber); firstSearchPageStart = new DocumentSequenceTextPointer(documentSequenceTextPointer.ChildBlock, new FixedTextPointer(false, LogicalDirection.Forward, pageStartFlowPosition)); } else { FixedTextPointer fixedTextPointer = end as FixedTextPointer; firstSearchPageStart = new FixedTextPointer(false, LogicalDirection.Forward, fixedTextPointer.FixedTextContainer.FixedTextBuilder.GetPageStartFlowPosition(pageNumber)); } firstSearchPageEnd = end; return; } DocumentSequenceTextPointer documentSequenceTextPointer2 = start as DocumentSequenceTextPointer; if (documentSequenceTextPointer2 != null) { FlowPosition pageEndFlowPosition = ((FixedTextContainer)documentSequenceTextPointer2.ChildBlock.ChildContainer).FixedTextBuilder.GetPageEndFlowPosition(pageNumber); firstSearchPageEnd = new DocumentSequenceTextPointer(documentSequenceTextPointer2.ChildBlock, new FixedTextPointer(false, LogicalDirection.Backward, pageEndFlowPosition)); } else { FixedTextPointer fixedTextPointer2 = start as FixedTextPointer; firstSearchPageEnd = new FixedTextPointer(false, LogicalDirection.Backward, fixedTextPointer2.FixedTextContainer.FixedTextBuilder.GetPageEndFlowPosition(pageNumber)); } firstSearchPageStart = start; }
/// <summary> /// Returns a TextSegment that spans the line on which position is located. /// </summary> /// <param name="position"> /// Any oriented text position on the line. /// </param> /// <returns> /// TextSegment that spans the line on which position is located. /// </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> internal override TextSegment GetLineRange(ITextPointer position) { DocumentsTrace.FixedDocumentSequence.TextOM.Trace(string.Format("GetLineRange {0} {1}", position, position.LogicalDirection)); DocumentSequenceTextPointer tpStart = null; DocumentSequenceTextPointer tpEnd = null; DocumentSequenceTextPointer tpLine = null; if (position != null) { if (ChildTextView != null) { tpLine = _docPage.FixedDocumentSequence.TextContainer.VerifyPosition(position); if (ChildTextView.TextContainer == tpLine.ChildBlock.ChildContainer) { TextSegment childTR = ChildTextView.GetLineRange(tpLine.ChildPointer.CreatePointer(position.LogicalDirection)); if (!childTR.IsNull) { tpStart = new DocumentSequenceTextPointer(ChildBlock, childTR.Start); tpEnd = new DocumentSequenceTextPointer(ChildBlock, childTR.End); return(new TextSegment(tpStart, tpEnd, true)); } } } } return(TextSegment.Null); }
// Token: 0x06002C1C RID: 11292 RVA: 0x000C8430 File Offset: 0x000C6630 private static int xGapAwareCompareTo(DocumentSequenceTextPointer thisTp, DocumentSequenceTextPointer tp) { if (thisTp == tp) { return(0); } ChildDocumentBlock childBlock = thisTp.ChildBlock; ChildDocumentBlock childBlock2 = tp.ChildBlock; int childBlockDistance = thisTp.AggregatedContainer.GetChildBlockDistance(childBlock, childBlock2); if (childBlockDistance == 0) { return(thisTp.ChildPointer.CompareTo(tp.ChildPointer)); } if (childBlockDistance < 0) { if (!DocumentSequenceTextPointer.xUnseparated(tp, thisTp)) { return(1); } return(0); } else { if (!DocumentSequenceTextPointer.xUnseparated(thisTp, tp)) { return(-1); } return(0); } }
// Token: 0x06002C0D RID: 11277 RVA: 0x000C81A4 File Offset: 0x000C63A4 public static Type GetElementType(DocumentSequenceTextPointer thisTp, LogicalDirection direction) { ValidationHelper.VerifyDirection(direction, "direction"); DocumentSequenceTextPointer documentSequenceTextPointer = DocumentSequenceTextPointer.xGetClingDSTP(thisTp, direction); return(documentSequenceTextPointer.ChildPointer.GetElementType(direction)); }
// Token: 0x06002C19 RID: 11289 RVA: 0x000C8360 File Offset: 0x000C6560 private static DocumentSequenceTextPointer xGetClingDSTP(DocumentSequenceTextPointer thisTp, LogicalDirection direction) { TextPointerContext pointerContext = thisTp.ChildPointer.GetPointerContext(direction); if (pointerContext != TextPointerContext.None) { return(thisTp); } ChildDocumentBlock childDocumentBlock = thisTp.ChildBlock; ITextPointer textPointer = thisTp.ChildPointer; if (direction == LogicalDirection.Forward) { while (pointerContext == TextPointerContext.None) { if (childDocumentBlock.IsTail) { break; } childDocumentBlock = childDocumentBlock.NextBlock; textPointer = childDocumentBlock.ChildContainer.Start; pointerContext = textPointer.GetPointerContext(direction); } } else { while (pointerContext == TextPointerContext.None && !childDocumentBlock.IsHead) { childDocumentBlock = childDocumentBlock.PreviousBlock; textPointer = childDocumentBlock.ChildContainer.End; pointerContext = textPointer.GetPointerContext(direction); } } return(new DocumentSequenceTextPointer(childDocumentBlock, textPointer)); }
// Token: 0x0600847C RID: 33916 RVA: 0x002483B0 File Offset: 0x002465B0 private StaticTextPointer GetStaticPositionInChildContainer(StaticTextPointer textPosition, LogicalDirection direction, StaticTextPointer originalPosition) { StaticTextPointer result = StaticTextPointer.Null; if (!textPosition.IsNull) { DocumentSequenceTextPointer documentSequenceTextPointer = textPosition.CreateDynamicTextPointer(LogicalDirection.Forward) as DocumentSequenceTextPointer; ITextPointer textPointer = documentSequenceTextPointer.ChildPointer; if (textPointer.TextContainer != originalPosition.TextContainer) { if (this.IsContentHighlighted(originalPosition, direction)) { textPointer = ((direction == LogicalDirection.Forward) ? originalPosition.TextContainer.End : originalPosition.TextContainer.Start); result = textPointer.CreateStaticPointer(); } else { result = StaticTextPointer.Null; } } else { result = textPointer.CreateStaticPointer(); } } return(result); }
// Token: 0x06002BD1 RID: 11217 RVA: 0x000C7918 File Offset: 0x000C5B18 private void AddChange(ITextPointer startPosition, int symbolCount, PrecursorTextChangeType precursorTextChange) { Invariant.Assert(!this._isReadOnly, "Illegal to modify DocumentSequenceTextContainer inside Change event scope!"); ((ITextContainer)this).BeginChange(); try { if (this.Changing != null) { this.Changing(this, EventArgs.Empty); } if (this._changes == null) { this._changes = new TextContainerChangedEventArgs(); } this._changes.AddChange(precursorTextChange, DocumentSequenceTextPointer.GetOffsetToPosition(this._start, startPosition), symbolCount, false); if (this.Change != null) { Invariant.Assert(precursorTextChange == PrecursorTextChangeType.ContentAdded || precursorTextChange == PrecursorTextChangeType.ContentRemoved); TextChangeType textChange = (precursorTextChange == PrecursorTextChangeType.ContentAdded) ? TextChangeType.ContentAdded : TextChangeType.ContentRemoved; this._isReadOnly = true; try { this.Change(this, new TextContainerChangeEventArgs(startPosition, symbolCount, -1, textChange)); } finally { this._isReadOnly = false; } } } finally { ((ITextContainer)this).EndChange(); } }
// ====================================================== // Static part of a class // <summary> // DocumentSequenceTextPointer is a static class that is provided all the // common functions of ITextPointer/ITextNavigaor for DocumentSequence. // Since we don't have multiple inheritance, this is a way to share code between // DocumentSequenceTextPointer and DocumentSequenceTextPointer. // </summary> //------------------------------------------------------ // // Public Methods // //------------------------------------------------------ #region TextPointer Methods /// <summary> /// <see cref="ITextPointer.CompareTo(ITextPointer)"/> /// </summary> public static int CompareTo(DocumentSequenceTextPointer thisTp, ITextPointer position) { DocumentSequenceTextPointer tp = thisTp.AggregatedContainer.VerifyPosition(position); // Now do compare return(xGapAwareCompareTo(thisTp, tp)); }
/// <summary> /// <see cref="ITextPointer.GetTextInRun(LogicalDirection,char[],int,int)"/> /// </summary> /// <remarks>Only reutrn uninterrupted runs of text</remarks> public static int GetTextInRun(DocumentSequenceTextPointer thisTp, LogicalDirection direction, char[] textBuffer, int startIndex, int count) { ValidationHelper.VerifyDirection(direction, "direction"); if (textBuffer == null) { throw new ArgumentNullException("textBuffer"); } if (startIndex < 0) { throw new ArgumentException(SR.Get(SRID.NegativeValue, "startIndex")); } if (startIndex > textBuffer.Length) { throw new ArgumentException(SR.Get(SRID.StartIndexExceedsBufferSize, startIndex, textBuffer.Length)); } if (count < 0) { throw new ArgumentException(SR.Get(SRID.NegativeValue, "count")); } if (count > textBuffer.Length - startIndex) { throw new ArgumentException(SR.Get(SRID.MaxLengthExceedsBufferSize, count, textBuffer.Length, startIndex)); } return(thisTp.ChildPointer.GetTextInRun(direction, textBuffer, startIndex, count)); }
/// <summary> /// <see cref="DynamicDocumentPaginator.GetPageNumber"/> /// </summary> internal int GetPageNumber(ContentPosition contentPosition) { if (contentPosition == null) { throw new ArgumentNullException("contentPosition"); } // ContentPosition may be only created by DynamicDocumentPaginator.GetObjectPosition or // DynamicDocumentPaginator.GetPagePosition. // Because of that we are expecting one of 2 types here. DynamicDocumentPaginator childPaginator = null; ContentPosition childContentPosition = null; if (contentPosition is DocumentSequenceTextPointer) { DocumentSequenceTextPointer dsTextPointer = (DocumentSequenceTextPointer)contentPosition; #pragma warning suppress 6506 // dsTextPointer is obviously not null childPaginator = GetPaginator(dsTextPointer.ChildBlock.DocRef); childContentPosition = dsTextPointer.ChildPointer as ContentPosition; } if (childContentPosition == null) { throw new ArgumentException(SR.Get(SRID.IDPInvalidContentPosition)); } int childPageNumber = childPaginator.GetPageNumber(childContentPosition); int pageNumber; _SynthesizeGlobalPageNumber(childPaginator, childPageNumber, out pageNumber); return(pageNumber); }
// Token: 0x06002C11 RID: 11281 RVA: 0x000C8278 File Offset: 0x000C6478 public static object ReadLocalValue(DocumentSequenceTextPointer thisTp, DependencyProperty property) { if (property == null) { throw new ArgumentNullException("property"); } return(thisTp.ChildPointer.ReadLocalValue(property)); }
internal static string ToString(DocumentSequenceTextPointer thisTp) { return((thisTp is DocumentSequenceTextPointer ? "DSTP" : "DSTN") + " Id=" + thisTp.DebugId + " B=" + thisTp.ChildBlock.DebugId + " G=" + thisTp.ChildPointer.LogicalDirection ); }
// Token: 0x06002C2A RID: 11306 RVA: 0x000C8A64 File Offset: 0x000C6C64 internal override bool Contains(ITextPointer position) { DocumentSequenceTextPointer documentSequenceTextPointer = null; if (position != null) { documentSequenceTextPointer = this._docPage.FixedDocumentSequence.TextContainer.VerifyPosition(position); } return(documentSequenceTextPointer != null && this.ChildTextView != null && this.ChildTextView.TextContainer == documentSequenceTextPointer.ChildBlock.ChildContainer && this.ChildTextView.Contains(documentSequenceTextPointer.ChildPointer.CreatePointer(position.LogicalDirection))); }
//------------------------------------------------------ // // Public Properties // //------------------------------------------------------ //------------------------------------------------------ // // Public Events // //------------------------------------------------------ //------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ #region Internal Methods // Internal Method, input parameter contains TP that is not synced to generation internal static bool iScan(DocumentSequenceTextPointer thisTp, LogicalDirection direction) { bool moved = thisTp.ChildPointer.MoveToNextContextPosition(direction); if (!moved) { moved = xGapAwareScan(thisTp, (direction == LogicalDirection.Forward ? 1 : -1)); } return(moved); }
// Token: 0x06002C0F RID: 11279 RVA: 0x000C81E0 File Offset: 0x000C63E0 public static bool HasEqualScope(DocumentSequenceTextPointer thisTp, ITextPointer position) { DocumentSequenceTextPointer documentSequenceTextPointer = thisTp.AggregatedContainer.VerifyPosition(position); if (thisTp.ChildPointer.TextContainer == documentSequenceTextPointer.ChildPointer.TextContainer) { return(thisTp.ChildPointer.HasEqualScope(documentSequenceTextPointer.ChildPointer)); } return(thisTp.ChildPointer.ParentType == typeof(FixedDocument) && documentSequenceTextPointer.ChildPointer.ParentType == typeof(FixedDocument)); }
// Token: 0x06002C17 RID: 11287 RVA: 0x000C8328 File Offset: 0x000C6528 internal static bool iScan(DocumentSequenceTextPointer thisTp, LogicalDirection direction) { bool flag = thisTp.ChildPointer.MoveToNextContextPosition(direction); if (!flag) { flag = DocumentSequenceTextPointer.xGapAwareScan(thisTp, (direction == LogicalDirection.Forward) ? 1 : -1); } return(flag); }
// Token: 0x06002C16 RID: 11286 RVA: 0x000C82D4 File Offset: 0x000C64D4 public static ITextPointer CreatePointer(DocumentSequenceTextPointer thisTp, int distance, LogicalDirection gravity) { ValidationHelper.VerifyDirection(gravity, "gravity"); DocumentSequenceTextPointer documentSequenceTextPointer = new DocumentSequenceTextPointer(thisTp.ChildBlock, thisTp.ChildPointer.CreatePointer(gravity)); if (distance != 0 && !DocumentSequenceTextPointer.xGapAwareScan(documentSequenceTextPointer, distance)) { throw new ArgumentException(SR.Get("BadDistance"), "distance"); } return(documentSequenceTextPointer); }
// 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)); } }
/// <summary> /// <see cref="ITextPointer.HasEqualScope"/> /// </summary> public static bool HasEqualScope(DocumentSequenceTextPointer thisTp, ITextPointer position) { DocumentSequenceTextPointer tp = thisTp.AggregatedContainer.VerifyPosition(position); if (thisTp.ChildPointer.TextContainer == tp.ChildPointer.TextContainer) { return(thisTp.ChildPointer.HasEqualScope(tp.ChildPointer)); } // The TextOM speced behavior is if both scopes are null, return true. return(thisTp.ChildPointer.ParentType == typeof(FixedDocument) && tp.ChildPointer.ParentType == typeof(FixedDocument)); }
// Token: 0x06002BFB RID: 11259 RVA: 0x000C7F0A File Offset: 0x000C610A int ITextPointer.MoveByOffset(int offset) { if (this._isFrozen) { throw new InvalidOperationException(SR.Get("TextPositionIsFrozen")); } if (DocumentSequenceTextPointer.iScan(this, offset)) { return(offset); } return(0); }
// Token: 0x06002C25 RID: 11301 RVA: 0x000C88C0 File Offset: 0x000C6AC0 internal override bool IsAtCaretUnitBoundary(ITextPointer position) { Invariant.Assert(position != null); if (position == null) { throw new ArgumentNullException("position"); } Invariant.Assert(this.ChildTextView != null); DocumentSequenceTextPointer documentSequenceTextPointer = this.DocumentSequenceTextContainer.VerifyPosition(position); return(this.ChildTextView.IsAtCaretUnitBoundary(documentSequenceTextPointer.ChildPointer)); }
// Token: 0x06002C26 RID: 11302 RVA: 0x000C8910 File Offset: 0x000C6B10 internal override ITextPointer GetNextCaretUnitPosition(ITextPointer position, LogicalDirection direction) { Invariant.Assert(position != null); if (position == null) { throw new ArgumentNullException("position"); } Invariant.Assert(this.ChildTextView != null); DocumentSequenceTextPointer documentSequenceTextPointer = this.DocumentSequenceTextContainer.VerifyPosition(position); return(this.ChildTextView.GetNextCaretUnitPosition(documentSequenceTextPointer.ChildPointer, direction)); }
//-------------------------------------------------------------------- // ContentChange //--------------------------------------------------------------------- private void _OnContentChanged(object sender, NotifyCollectionChangedEventArgs args) { #if DEBUG this._generation++; #endif if (args.Action == NotifyCollectionChangedAction.Add) { if (args.NewItems.Count != 1) { throw new NotSupportedException(SR.Get(SRID.RangeActionsNotSupported)); } else { object item = args.NewItems[0]; int startingIndex = args.NewStartingIndex; if (startingIndex != _parent.References.Count - 1) { throw new NotSupportedException(SR.Get(SRID.UnexpectedCollectionChangeAction, args.Action)); } ChildDocumentBlock newBlock = new ChildDocumentBlock(this, (DocumentReference)item); ChildDocumentBlock insertAfter = _doclistTail.PreviousBlock; insertAfter.InsertNextBlock(newBlock); DocumentSequenceTextPointer changeStart = new DocumentSequenceTextPointer(insertAfter, insertAfter.End); //Update end pointer _end = new DocumentSequenceTextPointer(newBlock, newBlock.ChildContainer.End); if (newBlock.NextBlock == _doclistTail && newBlock.PreviousBlock == _doclistHead) { //Update start pointer for the first block _start = new DocumentSequenceTextPointer(newBlock, newBlock.ChildContainer.Start); } // Record Change Notifications ITextContainer container = newBlock.ChildContainer; int symbolCount = 1; // takes too long to calculate for large documents, and no one will use this info // this does not affect state, only fires event handlers AddChange(changeStart, symbolCount, PrecursorTextChangeType.ContentAdded); } } else { throw new NotSupportedException(SR.Get(SRID.UnexpectedCollectionChangeAction, args.Action)); } }
// Token: 0x06002C23 RID: 11299 RVA: 0x000C87B4 File Offset: 0x000C69B4 internal override Geometry GetTightBoundingGeometryFromTextPositions(ITextPointer startPosition, ITextPointer endPosition) { if (startPosition != null && endPosition != null && this.ChildTextView != null) { DocumentSequenceTextPointer documentSequenceTextPointer = this._docPage.FixedDocumentSequence.TextContainer.VerifyPosition(startPosition); DocumentSequenceTextPointer documentSequenceTextPointer2 = this._docPage.FixedDocumentSequence.TextContainer.VerifyPosition(endPosition); if (documentSequenceTextPointer != null && documentSequenceTextPointer2 != null) { return(this.ChildTextView.GetTightBoundingGeometryFromTextPositions(documentSequenceTextPointer.ChildPointer, documentSequenceTextPointer2.ChildPointer)); } } return(new PathGeometry()); }
/// <summary> /// Finds the previous position at the edge of a caret after backspacing. /// </summary> /// <param name="position"> /// Initial text position of an object/character. /// </param> /// <returns> /// The previous caret unit break position after backspacing. /// </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> internal override ITextPointer GetBackspaceCaretUnitPosition(ITextPointer position) { Invariant.Assert(position != null); if (position == null) { throw new ArgumentNullException("position"); } //Verify the position and propagate the call to the child text view Invariant.Assert(ChildTextView != null); DocumentSequenceTextPointer ftp = this.DocumentSequenceTextContainer.VerifyPosition(position); return(this.ChildTextView.GetBackspaceCaretUnitPosition(ftp.ChildPointer)); }
// Token: 0x06002BFC RID: 11260 RVA: 0x000C7F30 File Offset: 0x000C6130 void ITextPointer.MoveToPosition(ITextPointer position) { DocumentSequenceTextPointer documentSequenceTextPointer = this.AggregatedContainer.VerifyPosition(position); LogicalDirection logicalDirection = this.ChildPointer.LogicalDirection; this.ChildBlock = documentSequenceTextPointer.ChildBlock; if (this.ChildPointer.TextContainer == documentSequenceTextPointer.ChildPointer.TextContainer) { this.ChildPointer.MoveToPosition(documentSequenceTextPointer.ChildPointer); return; } this.ChildPointer = documentSequenceTextPointer.ChildPointer.CreatePointer(); this.ChildPointer.SetLogicalDirection(logicalDirection); }
// Internal Method, input parameter contains TP that is not synced to generation internal static bool iScan(DocumentSequenceTextPointer thisTp, int distance) { return xGapAwareScan(thisTp, distance); }
/// <summary> /// <see cref="ITextPointer.GetTextInRun(LogicalDirection,char[],int,int)"/> /// </summary> /// <remarks>Only reutrn uninterrupted runs of text</remarks> public static int GetTextInRun(DocumentSequenceTextPointer thisTp, LogicalDirection direction, char[] textBuffer, int startIndex, int count) { ValidationHelper.VerifyDirection(direction, "direction"); if (textBuffer == null) { throw new ArgumentNullException("textBuffer"); } if (startIndex < 0) { throw new ArgumentException(SR.Get(SRID.NegativeValue, "startIndex")); } if (startIndex > textBuffer.Length) { throw new ArgumentException(SR.Get(SRID.StartIndexExceedsBufferSize, startIndex, textBuffer.Length)); } if (count < 0) { throw new ArgumentException(SR.Get(SRID.NegativeValue, "count")); } if (count > textBuffer.Length - startIndex) { throw new ArgumentException(SR.Get(SRID.MaxLengthExceedsBufferSize, count, textBuffer.Length, startIndex)); } return thisTp.ChildPointer.GetTextInRun(direction, textBuffer, startIndex, count); }
/// <summary> /// <see cref="ITextPointer.GetElementType"/> /// </summary> public static Type GetElementType(DocumentSequenceTextPointer thisTp) { return thisTp.ChildPointer.ParentType; }
/// <summary> /// <see cref="ITextPointer.GetLocalValueEnumerator"/> /// </summary> /// <remarks>Returns an empty enumerator if there is no scoping element</remarks> public static LocalValueEnumerator GetLocalValueEnumerator(DocumentSequenceTextPointer thisTp) { return thisTp.ChildPointer.GetLocalValueEnumerator(); }
public static ITextPointer CreatePointer(DocumentSequenceTextPointer thisTp, LogicalDirection gravity) { return CreatePointer(thisTp, 0, gravity); }
/// <summary> /// <see cref="ITextPointer.GetOffsetToPosition"/> /// </summary> public static int GetOffsetToPosition(DocumentSequenceTextPointer thisTp, ITextPointer position) { DocumentSequenceTextPointer tp = thisTp.AggregatedContainer.VerifyPosition(position); int comp = xGapAwareCompareTo(thisTp, tp); if (comp == 0) { return 0; } else if (comp <= 0) { return xGapAwareGetDistance(thisTp, tp); } else { return -1 * xGapAwareGetDistance(tp, thisTp); } }
/// <summary> /// <see cref="ITextPointer.CreatePointer(int,LogicalDirection)"/> /// </summary> public static ITextPointer CreatePointer(DocumentSequenceTextPointer thisTp, int distance, LogicalDirection gravity) { ValidationHelper.VerifyDirection(gravity, "gravity"); // Special case for common case of distance == 0 // to avoid calculating child container size, which // could be expansive especially in case where child // container requires virtualization. DocumentSequenceTextPointer newTp = new DocumentSequenceTextPointer(thisTp.ChildBlock, thisTp.ChildPointer.CreatePointer(gravity)); if (distance != 0) { if (!xGapAwareScan(newTp, distance)) { throw new ArgumentException(SR.Get(SRID.BadDistance), "distance"); } } return newTp; }
//----------------------------------------------------------------------- // Trusted Methods -- all positions are in valid blocks // // Each ChildDocumentBlock pair is separated by a gap (DocumentBreak), // which is surfaced as an embedded object. Besides the Head and Tail block, // each block is enclosed by two gap objects, one at each end of the // TextContainer (Before TextContainer.Start and After TextContainer.End) //----------------------------------------------------------------------- private static TextPointerContext xGapAwareGetSymbolType(DocumentSequenceTextPointer thisTp, LogicalDirection direction) { DocumentSequenceTextPointer tp = xGetClingDSTP(thisTp, direction); return tp.ChildPointer.GetPointerContext(direction); }
//------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ #region Internal Methods /// <summary> /// Retrieves a position matching a point. /// </summary> /// <param name="point"> /// Point in pixel coordinates to test. /// </param> /// <param name="snapToText"> /// If true, this method must always return a positioned text position /// (the closest position as calculated by the control's heuristics). /// If false, this method should return null position, if the test /// point does not fall within any character bounding box. /// </param> /// <returns> /// A text position and its orientation matching or closest to the point. /// </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> internal override ITextPointer GetTextPositionFromPoint(Point point, bool snapToText) { DocumentsTrace.FixedDocumentSequence.TextOM.Trace(string.Format("GetTextPositionFromPoint {0}-{1}", point, snapToText)); DocumentSequenceTextPointer tp = null; LogicalDirection edge = LogicalDirection.Forward; if (ChildTextView != null) { ITextPointer childOTP = ChildTextView.GetTextPositionFromPoint(point, snapToText); if (childOTP != null) { tp = new DocumentSequenceTextPointer(ChildBlock, childOTP); edge = childOTP.LogicalDirection; } } // When snapToText is true, ChildTextView.GetTextPositionFromPoint will guranttee to // return a non-null position. // In current code, ChildTextView can't be null. return tp == null ? null : DocumentSequenceTextPointer.CreatePointer(tp, edge); }
/// <summary> /// Returns a TextSegment that spans the line on which position is located. /// </summary> /// <param name="position"> /// Any oriented text position on the line. /// </param> /// <returns> /// TextSegment that spans the line on which position is located. /// </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> internal override TextSegment GetLineRange(ITextPointer position) { DocumentsTrace.FixedDocumentSequence.TextOM.Trace(string.Format("GetLineRange {0} {1}", position, position.LogicalDirection)); DocumentSequenceTextPointer tpStart = null; DocumentSequenceTextPointer tpEnd = null; DocumentSequenceTextPointer tpLine = null; if (position != null) { if (ChildTextView != null) { tpLine = _docPage.FixedDocumentSequence.TextContainer.VerifyPosition(position); if (ChildTextView.TextContainer == tpLine.ChildBlock.ChildContainer) { TextSegment childTR = ChildTextView.GetLineRange(tpLine.ChildPointer.CreatePointer(position.LogicalDirection)); if (!childTR.IsNull) { tpStart = new DocumentSequenceTextPointer(ChildBlock, childTR.Start); tpEnd = new DocumentSequenceTextPointer(ChildBlock, childTR.End); return new TextSegment(tpStart, tpEnd, true); } } } } return TextSegment.Null; }
/// <summary> /// Retrieves an oriented text position matching position advanced by /// a number of lines from its initial position. /// </summary> /// <param name="position"> /// Initial text position of an object/character. /// </param> /// <param name="suggestedX"> /// The suggested X offset, in pixels, of text position on the destination /// line. If suggestedX is set to Double.NaN it will be ignored, otherwise /// the method will try to find a position on the destination line closest /// to suggestedX. /// </param> /// <param name="count"> /// Number of lines to advance. Negative means move backwards. /// </param> /// <param name="newSuggestedX"> /// newSuggestedX is the offset at the position moved (useful when moving /// between columns or pages). /// </param> /// <param name="linesMoved"> /// linesMoved indicates the number of lines moved, which may be less /// than count if there is no more content. /// </param> /// <returns> /// A TextPointer and its orientation matching suggestedX on the /// destination line. /// </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> internal override ITextPointer GetPositionAtNextLine(ITextPointer position, double suggestedX, int count, out double newSuggestedX, out int linesMoved) { newSuggestedX = suggestedX; linesMoved = count; DocumentsTrace.FixedDocumentSequence.TextOM.Trace(string.Format("GetPositionAtNextLine {0} {1} {2} {3} ", position, position.LogicalDirection, suggestedX, count)); DocumentSequenceTextPointer newTp = null; LogicalDirection newEdge = LogicalDirection.Forward; DocumentSequenceTextPointer tp = null; if (position != null) { tp = _docPage.FixedDocumentSequence.TextContainer.VerifyPosition(position); } // Note we do not handle cross page navigation if (tp != null) { if (ChildTextView != null) { if (ChildTextView.TextContainer == tp.ChildBlock.ChildContainer) { ITextPointer childOTP = ChildTextView.GetPositionAtNextLine(tp.ChildPointer.CreatePointer(position.LogicalDirection), suggestedX, count, out newSuggestedX, out linesMoved); if (childOTP != null) { newTp = new DocumentSequenceTextPointer(ChildBlock, childOTP); newEdge = childOTP.LogicalDirection; } } } } return DocumentSequenceTextPointer.CreatePointer(newTp, newEdge); }
/// <summary> /// <see cref="ITextPointer.GetAdjacentElement"/> /// </summary> /// <remarks>Return null if the embedded object does not exist</remarks> public static object GetAdjacentElement(DocumentSequenceTextPointer thisTp, LogicalDirection direction) { ValidationHelper.VerifyDirection(direction, "direction"); return xGapAwareGetEmbeddedElement(thisTp, direction); }
/// <summary> /// <see cref="ITextPointer.GetElementType"/> /// </summary> /// <remarks>Return null if no TextElement in the direction</remarks> public static Type GetElementType(DocumentSequenceTextPointer thisTp, LogicalDirection direction) { ValidationHelper.VerifyDirection(direction, "direction"); DocumentSequenceTextPointer tp = xGetClingDSTP(thisTp, direction); return tp.ChildPointer.GetElementType(direction); }
/// <summary> /// <see cref="ITextPointer.GetTextRunLength"/> /// </summary> /// <remarks>Return 0 if non-text run</remarks> public static int GetTextRunLength(DocumentSequenceTextPointer thisTp, LogicalDirection direction) { ValidationHelper.VerifyDirection(direction, "direction"); return thisTp.ChildPointer.GetTextRunLength(direction); }
//------------------------------------------------------ // // Public Properties // //------------------------------------------------------ //------------------------------------------------------ // // Public Events // //------------------------------------------------------ //------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ #region Internal Methods // Internal Method, input parameter contains TP that is not synced to generation internal static bool iScan(DocumentSequenceTextPointer thisTp, LogicalDirection direction) { bool moved = thisTp.ChildPointer.MoveToNextContextPosition(direction); if (!moved) { moved = xGapAwareScan(thisTp, (direction == LogicalDirection.Forward ? 1 : -1)); } return moved; }
/// <summary> /// <see cref="ITextPointer.ReadLocalValue"/> /// </summary> /// <remarks>Throws InvalidOperationException if there is no scoping element</remarks> public static object ReadLocalValue(DocumentSequenceTextPointer thisTp, DependencyProperty property) { if (property == null) { throw new ArgumentNullException("property"); } return thisTp.ChildPointer.ReadLocalValue(property); }
/// <summary> /// <see cref="ITextPointer.GetPointerContext"/> /// </summary> public static TextPointerContext GetPointerContext(DocumentSequenceTextPointer thisTp, LogicalDirection direction) { ValidationHelper.VerifyDirection(direction, "direction"); return xGapAwareGetSymbolType(thisTp, direction); }
//------------------------------------------------------------------- // Highlight compositing //---------------------------------------------------------------------- private void _OnHighlightChanged(object sender, HighlightChangedEventArgs args) { Debug.Assert(sender != null); Debug.Assert(args != null); Debug.Assert(args.Ranges != null); #if DEBUG { Highlights highlights = this.Highlights; StaticTextPointer highlightTransitionPosition; StaticTextPointer highlightRangeStart; object selected; DocumentsTrace.FixedDocumentSequence.Highlights.Trace("===BeginNewHighlightRange==="); highlightTransitionPosition = ((ITextContainer)this).CreateStaticPointerAtOffset(0); while (true) { // Move to the next highlight start. if (!highlights.IsContentHighlighted(highlightTransitionPosition, LogicalDirection.Forward)) { highlightTransitionPosition = highlights.GetNextHighlightChangePosition(highlightTransitionPosition, LogicalDirection.Forward); // No more highlights? if (highlightTransitionPosition.IsNull) break; } // highlightTransitionPosition is at the start of a new highlight run. selected = highlights.GetHighlightValue(highlightTransitionPosition, LogicalDirection.Forward, typeof(TextSelection)); // Save the start position and find the end. highlightRangeStart = highlightTransitionPosition; highlightTransitionPosition = highlights.GetNextHighlightChangePosition(highlightTransitionPosition, LogicalDirection.Forward); Invariant.Assert(!highlightTransitionPosition.IsNull, "Highlight start not followed by highlight end!"); // Store the highlight. if (selected != DependencyProperty.UnsetValue) { DocumentsTrace.FixedDocumentSequence.Highlights.Trace(string.Format("HightlightRange {0}-{1}", highlightRangeStart.ToString(), highlightTransitionPosition.ToString())); if (highlightRangeStart.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.Text) { DocumentsTrace.FixedDocumentSequence.Highlights.Trace("<HighlightNotOnText>"); } else { char[] sb = new char[256]; TextPointerBase.GetTextWithLimit(highlightRangeStart.CreateDynamicTextPointer(LogicalDirection.Forward), LogicalDirection.Forward, sb, 0, 256, highlightTransitionPosition.CreateDynamicTextPointer(LogicalDirection.Forward)); DocumentsTrace.FixedDocumentSequence.TextOM.Trace(string.Format("HightlightContent [{0}]", new String(sb))); } } } DocumentsTrace.FixedDocumentSequence.TextOM.Trace("===EndNewHighlightRange==="); } #endif Debug.Assert(args.Ranges.Count > 0 && ((TextSegment)args.Ranges[0]).Start.CompareTo(((TextSegment)args.Ranges[0]).End) < 0); // For each change range we received, we need to figure out // affected child TextContainer, and notify it with appropriate // ranges that are in the child's address space. // // We only fire one highlight change notification for any child // TextContainer even if there is multiple change ranges fall // into the same child TextContainer. // // We scan the ranges and the child TextContainer in the same loop, // moving forward two scanning pointers and at boundary of each // TextContainer, we fire a change notification. // int idxScan = 0; DocumentSequenceTextPointer tsScan = null; ChildDocumentBlock cdbScan = null; List<TextSegment> rangeArray = new List<TextSegment>(4); while (idxScan < args.Ranges.Count) { TextSegment ts = (TextSegment)args.Ranges[idxScan]; DocumentSequenceTextPointer tsEnd = (DocumentSequenceTextPointer)ts.End; ITextPointer tpChildStart, tpChildEnd; ChildDocumentBlock lastBlock; // If tsScan == null, we were done with previous range, // so we are going to set tsScan to begining of this range. // Otherwise the previous range was split so we will simply // start from what was left over from previous loop. if (tsScan == null) { tsScan = (DocumentSequenceTextPointer)ts.Start; } lastBlock = cdbScan; cdbScan = tsScan.ChildBlock; if (lastBlock != null && cdbScan != lastBlock && !(lastBlock.ChildContainer is NullTextContainer) && rangeArray.Count != 0) { // This range is in a different block, so take care of old blocks first lastBlock.ChildHighlightLayer.RaiseHighlightChangedEvent(new ReadOnlyCollection<TextSegment>(rangeArray)); rangeArray.Clear(); } tpChildStart = tsScan.ChildPointer; if (tsEnd.ChildBlock != cdbScan) { // If this range crosses blocks, we are done with current block tpChildEnd = tsScan.ChildPointer.TextContainer.End; if (tpChildStart.CompareTo(tpChildEnd) != 0) { rangeArray.Add(new TextSegment(tpChildStart, tpChildEnd)); } // Notify child container if (!(cdbScan.ChildContainer is NullTextContainer) && rangeArray.Count != 0) { cdbScan.ChildHighlightLayer.RaiseHighlightChangedEvent(new ReadOnlyCollection<TextSegment>(rangeArray)); } // Move on to next block; cdbScan = cdbScan.NextBlock; tsScan = new DocumentSequenceTextPointer(cdbScan, cdbScan.ChildContainer.Start); rangeArray.Clear(); } else { // Otherwise we need to go on to see if there is more ranges // fall withing the same block. Simply add this change range tpChildEnd = tsEnd.ChildPointer; if (tpChildStart.CompareTo(tpChildEnd) != 0) { rangeArray.Add(new TextSegment(tpChildStart, tpChildEnd)); } // Move on to next range idxScan++; tsScan = null; } } // Fire change notification for the last child block. if (rangeArray.Count > 0 && (!(cdbScan == null || cdbScan.ChildContainer is NullTextContainer))) { cdbScan.ChildHighlightLayer.RaiseHighlightChangedEvent(new ReadOnlyCollection<TextSegment>(rangeArray)); } }
// ====================================================== // Static part of a class // <summary> // DocumentSequenceTextPointer is a static class that is provided all the // common functions of ITextPointer/ITextNavigaor for DocumentSequence. // Since we don't have multiple inheritance, this is a way to share code between // DocumentSequenceTextPointer and DocumentSequenceTextPointer. // </summary> //------------------------------------------------------ // // Public Methods // //------------------------------------------------------ #region TextPointer Methods /// <summary> /// <see cref="ITextPointer.CompareTo(ITextPointer)"/> /// </summary> public static int CompareTo(DocumentSequenceTextPointer thisTp, ITextPointer position) { DocumentSequenceTextPointer tp = thisTp.AggregatedContainer.VerifyPosition(position); // Now do compare return xGapAwareCompareTo(thisTp, tp); }
//------------------------------------------------------ // // Internal Property // //------------------------------------------------------ //------------------------------------------------------ // // Private Methods // //------------------------------------------------------ #region Private Methods private static DocumentSequenceTextPointer xGetClingDSTP(DocumentSequenceTextPointer thisTp, LogicalDirection direction) { TextPointerContext context = thisTp.ChildPointer.GetPointerContext(direction); if (context != TextPointerContext.None) { return thisTp; } ChildDocumentBlock block = thisTp.ChildBlock; ITextPointer pointer = thisTp.ChildPointer; if (direction == LogicalDirection.Forward) { while (context == TextPointerContext.None && !block.IsTail) { // get next block block = block.NextBlock; // get start pointer = block.ChildContainer.Start; context = pointer.GetPointerContext(direction); } } else { Debug.Assert(direction == LogicalDirection.Backward); while (context == TextPointerContext.None && !block.IsHead) { // get next block block = block.PreviousBlock; // get start pointer = block.ChildContainer.End; context = pointer.GetPointerContext(direction); } } return new DocumentSequenceTextPointer(block, pointer); }
public static ITextPointer CreatePointer(DocumentSequenceTextPointer thisTp, int distance) { return CreatePointer(thisTp, distance, thisTp.ChildPointer.LogicalDirection); }
internal static string ToString(DocumentSequenceTextPointer thisTp) { return (thisTp is DocumentSequenceTextPointer ? "DSTP" : "DSTN") + " Id=" + thisTp.DebugId + " B=" + thisTp.ChildBlock.DebugId + " G=" + thisTp.ChildPointer.LogicalDirection ; }
//------------------------------------------------------------------- // // Private Methods // //---------------------------------------------------------------------- #region Private Methods //------------------------------------------------------------------- // Initilization //--------------------------------------------------------------------- private void _Initialize() { Debug.Assert(_parent != null); // Create Start Block/Container/Position _doclistHead = new ChildDocumentBlock(this, new NullTextContainer()); // Create End Block/Container/Position _doclistTail = new ChildDocumentBlock(this, new NullTextContainer()); // Link Start and End container together _doclistHead.InsertNextBlock(_doclistTail); // Now initialize the child doc block list ChildDocumentBlock currentBlock = _doclistHead; foreach (DocumentReference docRef in _parent.References) { currentBlock.InsertNextBlock(new ChildDocumentBlock(this, docRef)); currentBlock = currentBlock.NextBlock; } //if we have at least one document, start and end pointers should be set to valid child blocks not to the placeholders if (_parent.References.Count != 0) { _start = new DocumentSequenceTextPointer(_doclistHead.NextBlock, _doclistHead.NextBlock.ChildContainer.Start); _end = new DocumentSequenceTextPointer(_doclistTail.PreviousBlock, _doclistTail.PreviousBlock.ChildContainer.End); } else { _start = new DocumentSequenceTextPointer(_doclistHead, _doclistHead.ChildContainer.Start); _end = new DocumentSequenceTextPointer(_doclistTail, _doclistTail.ChildContainer.End); } // Listen to collection changes _parent.References.CollectionChanged += new NotifyCollectionChangedEventHandler(_OnContentChanged); // Listen to Highlights changes so that it can notify sub-TextContainer this.Highlights.Changed += new HighlightChangedEventHandler(_OnHighlightChanged); }
//Searches for the specified pattern and updates start *or* end pointers depending on search direction //At the end of the operation, start or end should be pointing to the beginning/end of the page //of occurance of pattern respectively internal static TextRange Find ( ITextPointer start, ITextPointer end, string findPattern, CultureInfo cultureInfo, bool matchCase, bool matchWholeWord, bool matchLast, bool matchDiacritics, bool matchKashida, bool matchAlefHamza) { Debug.Assert(start != null); Debug.Assert(end != null); Debug.Assert( ((start is DocumentSequenceTextPointer) && (end is DocumentSequenceTextPointer)) || ((start is FixedTextPointer) && (end is FixedTextPointer)) ); Debug.Assert(findPattern != null); if (findPattern.Length == 0) { return null; } IDocumentPaginatorSource paginatorSource = start.TextContainer.Parent as IDocumentPaginatorSource; DynamicDocumentPaginator paginator = paginatorSource.DocumentPaginator as DynamicDocumentPaginator; Debug.Assert(paginator != null); int pageNumber = -1; int endPageNumber = -1; if (matchLast) { endPageNumber = paginator.GetPageNumber( (ContentPosition) start); pageNumber = paginator.GetPageNumber( (ContentPosition) end); } else { endPageNumber = paginator.GetPageNumber( (ContentPosition) end); pageNumber = paginator.GetPageNumber( (ContentPosition) start); } TextRange result = null; CompareInfo compareInfo = cultureInfo.CompareInfo; bool replaceAlefWithAlefHamza = false; CompareOptions compareOptions = _InitializeSearch(cultureInfo, matchCase, matchAlefHamza, matchDiacritics, ref findPattern, out replaceAlefWithAlefHamza); //Translate the page number int translatedPageNumber = pageNumber; //If this is a DocumentSequence, we need to pass translated page number to the below call FixedDocumentSequence documentSequence = paginatorSource as FixedDocumentSequence; DynamicDocumentPaginator childPaginator = null; if (documentSequence != null) { documentSequence.TranslatePageNumber(pageNumber, out childPaginator, out translatedPageNumber); } if (pageNumber - endPageNumber != 0) { ITextPointer firstSearchPageStart = null; ITextPointer firstSearchPageEnd = null; _GetFirstPageSearchPointers(start, end, translatedPageNumber, matchLast, out firstSearchPageStart, out firstSearchPageEnd); Debug.Assert(firstSearchPageStart != null); Debug.Assert(firstSearchPageEnd != null); //Need to search the first page using TextFindEngine to start exactly from the requested search location to avoid false positives result = TextFindEngine.InternalFind( firstSearchPageStart, firstSearchPageEnd, findPattern, cultureInfo, matchCase, matchWholeWord, matchLast, matchDiacritics, matchKashida, matchAlefHamza); if (result == null) { //Start from the next page and check all pages until the end pageNumber = matchLast ? pageNumber-1 : pageNumber+1; int increment = matchLast ? -1 : 1; for (; matchLast ? pageNumber >= endPageNumber : pageNumber <= endPageNumber; pageNumber+=increment) { FixedDocument fixedDoc = null; translatedPageNumber = pageNumber; childPaginator = null; if (documentSequence != null) { documentSequence.TranslatePageNumber(pageNumber, out childPaginator, out translatedPageNumber); fixedDoc = (FixedDocument) childPaginator.Source; } else { fixedDoc = paginatorSource as FixedDocument; } Debug.Assert(fixedDoc != null); String pageString = _GetPageString(fixedDoc, translatedPageNumber, replaceAlefWithAlefHamza); if (pageString == null) { //This is not a page-per-stream //Default back to slow search return TextFindEngine.InternalFind( start, end, findPattern, cultureInfo, matchCase, matchWholeWord, matchLast, matchDiacritics, matchKashida, matchAlefHamza); } if ( _FoundOnPage(pageString, findPattern, cultureInfo, compareOptions) ) { //Update end or start pointer depending on search direction if (documentSequence != null) { ChildDocumentBlock childBlock = documentSequence.TextContainer.FindChildBlock(fixedDoc.DocumentReference); if (matchLast) { end = new DocumentSequenceTextPointer(childBlock, new FixedTextPointer(false, LogicalDirection.Backward, fixedDoc.FixedContainer.FixedTextBuilder.GetPageEndFlowPosition(translatedPageNumber))); start = new DocumentSequenceTextPointer(childBlock, new FixedTextPointer(false, LogicalDirection.Forward, fixedDoc.FixedContainer.FixedTextBuilder.GetPageStartFlowPosition(translatedPageNumber))); } else { start = new DocumentSequenceTextPointer(childBlock, new FixedTextPointer(false, LogicalDirection.Forward, fixedDoc.FixedContainer.FixedTextBuilder.GetPageStartFlowPosition(translatedPageNumber))); end = new DocumentSequenceTextPointer(childBlock, new FixedTextPointer(false, LogicalDirection.Backward, fixedDoc.FixedContainer.FixedTextBuilder.GetPageEndFlowPosition(translatedPageNumber))); } } else { //We are working on a FixedDocument FixedTextBuilder textBuilder = ((FixedDocument)(paginatorSource)).FixedContainer.FixedTextBuilder; if (matchLast) { end = new FixedTextPointer(false, LogicalDirection.Backward, textBuilder.GetPageEndFlowPosition(pageNumber)); start = new FixedTextPointer(false, LogicalDirection.Forward, textBuilder.GetPageStartFlowPosition(pageNumber)); } else { start = new FixedTextPointer(false, LogicalDirection.Forward, textBuilder.GetPageStartFlowPosition(pageNumber)); end = new FixedTextPointer(false, LogicalDirection.Backward, textBuilder.GetPageEndFlowPosition(pageNumber)); } } result = TextFindEngine.InternalFind( start, end, findPattern, cultureInfo, matchCase, matchWholeWord, matchLast, matchDiacritics, matchKashida, matchAlefHamza); //If the result is null, this means we had a false positive if (result != null) { return result; } } } } } else { //Make sure fast search result and slow search result are consistent FixedDocument fixedDoc = childPaginator != null ? childPaginator.Source as FixedDocument : paginatorSource as FixedDocument; String pageString = _GetPageString(fixedDoc, translatedPageNumber, replaceAlefWithAlefHamza); if (pageString == null || _FoundOnPage(pageString, findPattern, cultureInfo, compareOptions)) { //The search is only limited to the current page result = TextFindEngine.InternalFind( start, end, findPattern, cultureInfo, matchCase, matchWholeWord, matchLast, matchDiacritics, matchKashida, matchAlefHamza); } } return result; }
//------------------------------------------------------------------- // ContentChange //---------------------------------------------------------------------- private void _OnContentChanged(object sender, NotifyCollectionChangedEventArgs args) { #if DEBUG this._generation++; #endif if (args.Action == NotifyCollectionChangedAction.Add) { if (args.NewItems.Count != 1) { throw new NotSupportedException(SR.Get(SRID.RangeActionsNotSupported)); } else { object item = args.NewItems[0]; int startingIndex = args.NewStartingIndex; if (startingIndex != _parent.References.Count - 1) { throw new NotSupportedException(SR.Get(SRID.UnexpectedCollectionChangeAction, args.Action)); } ChildDocumentBlock newBlock = new ChildDocumentBlock(this, (DocumentReference)item); ChildDocumentBlock insertAfter = _doclistTail.PreviousBlock; insertAfter.InsertNextBlock(newBlock); DocumentSequenceTextPointer changeStart = new DocumentSequenceTextPointer(insertAfter, insertAfter.End); //Update end pointer _end = new DocumentSequenceTextPointer(newBlock, newBlock.ChildContainer.End); if (newBlock.NextBlock == _doclistTail && newBlock.PreviousBlock == _doclistHead) { //Update start pointer for the first block _start = new DocumentSequenceTextPointer(newBlock, newBlock.ChildContainer.Start); } // Record Change Notifications ITextContainer container = newBlock.ChildContainer; int symbolCount = 1; // takes too long to calculate for large documents, and no one will use this info // this does not affect state, only fires event handlers AddChange(changeStart, symbolCount, PrecursorTextChangeType.ContentAdded); } } else { throw new NotSupportedException(SR.Get(SRID.UnexpectedCollectionChangeAction, args.Action)); } }
/// <summary> /// <see cref="ITextPointer.HasEqualScope"/> /// </summary> public static bool HasEqualScope(DocumentSequenceTextPointer thisTp, ITextPointer position) { DocumentSequenceTextPointer tp = thisTp.AggregatedContainer.VerifyPosition(position); if (thisTp.ChildPointer.TextContainer == tp.ChildPointer.TextContainer) { return thisTp.ChildPointer.HasEqualScope(tp.ChildPointer); } // The TextOM speced behavior is if both scopes are null, return true. return thisTp.ChildPointer.ParentType == typeof(FixedDocument) && tp.ChildPointer.ParentType == typeof(FixedDocument); }
private static object xGapAwareGetEmbeddedElement(DocumentSequenceTextPointer thisTp, LogicalDirection direction) { DocumentSequenceTextPointer tp = xGetClingDSTP(thisTp, direction); return tp.ChildPointer.GetAdjacentElement(direction); }
private static bool xUnseparated(DocumentSequenceTextPointer tp1, DocumentSequenceTextPointer tp2) { // tp1 is before tp2, check both are at edge of documents //check nothing of any length between them if (tp1.ChildPointer.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.None || tp2.ChildPointer.GetPointerContext(LogicalDirection.Backward) != TextPointerContext.None) { return false; } ChildDocumentBlock block = tp1.ChildBlock.NextBlock; while (block != tp2.ChildBlock) { if (block.ChildContainer.Start.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.None) { return false; } block = block.NextBlock; } return true; }
private static void _GetFirstPageSearchPointers ( ITextPointer start, ITextPointer end, int pageNumber, bool matchLast, out ITextPointer firstSearchPageStart, out ITextPointer firstSearchPageEnd) { if (matchLast) { //The page in question is the last page //Need to search between the start of the last page and the end pointer DocumentSequenceTextPointer endAsDSTP = end as DocumentSequenceTextPointer; if (endAsDSTP != null) { FlowPosition pageStartFlowPosition = ((FixedTextContainer)(endAsDSTP.ChildBlock.ChildContainer)).FixedTextBuilder.GetPageStartFlowPosition(pageNumber); firstSearchPageStart = new DocumentSequenceTextPointer(endAsDSTP.ChildBlock, new FixedTextPointer(false, LogicalDirection.Forward,pageStartFlowPosition)); } else { FixedTextPointer endAsFTP = end as FixedTextPointer; Debug.Assert(endAsFTP != null); firstSearchPageStart = new FixedTextPointer(false, LogicalDirection.Forward, endAsFTP.FixedTextContainer.FixedTextBuilder.GetPageStartFlowPosition(pageNumber)); } firstSearchPageEnd = end; } else { //The page in question is the first page //Need to search between the start pointer and the end of the first page DocumentSequenceTextPointer startAsDSTP = start as DocumentSequenceTextPointer; if (startAsDSTP != null) { FlowPosition pageEndFlowPosition = ((FixedTextContainer)startAsDSTP.ChildBlock.ChildContainer).FixedTextBuilder.GetPageEndFlowPosition(pageNumber); firstSearchPageEnd = new DocumentSequenceTextPointer( startAsDSTP.ChildBlock, new FixedTextPointer(false, LogicalDirection.Backward, pageEndFlowPosition)); } else { FixedTextPointer startAsFTP = start as FixedTextPointer; Debug.Assert(startAsFTP != null); firstSearchPageEnd = new FixedTextPointer(false, LogicalDirection.Backward, startAsFTP.FixedTextContainer.FixedTextBuilder.GetPageEndFlowPosition(pageNumber)); } firstSearchPageStart = start; } }
// Intelligent compare routine that understands block gap // Since there it is assumed that there is an invisible Gap // object between adjancent two blocks, there is no position // overlap. private static int xGapAwareCompareTo(DocumentSequenceTextPointer thisTp, DocumentSequenceTextPointer tp) { Debug.Assert(tp != null); if ((object)thisTp == (object)tp) { return 0; } ChildDocumentBlock thisBlock = thisTp.ChildBlock; ChildDocumentBlock tpBlock = tp.ChildBlock; int comp = thisTp.AggregatedContainer.GetChildBlockDistance(thisBlock, tpBlock); if (comp == 0) { Debug.Assert(thisTp.ChildBlock.ChildContainer == tp.ChildBlock.ChildContainer); return thisTp.ChildPointer.CompareTo(tp.ChildPointer); } else if (comp < 0) { // thisBlock is after tpBlock return xUnseparated(tp, thisTp) ? 0 : 1; } else { // thisBlock is before tpBlock return xUnseparated(thisTp, tp) ? 0 : -1; } }