// Increments the reference count of TextPositions referencing a // particular edge of this node. // // If this node is a TextTreeTextNode, the increment may split the node // and the return value is guaranteed to be the node containing the referenced // edge (which may be a new node). Otherwise this method always returns // the original node. internal virtual TextTreeNode IncrementReferenceCount(ElementEdge edge, int delta) { Invariant.Assert(delta >= 0); if (delta > 0) { switch (edge) { case ElementEdge.BeforeStart: this.BeforeStartReferenceCount = true; break; case ElementEdge.AfterStart: this.AfterStartReferenceCount = true; break; case ElementEdge.BeforeEnd: this.BeforeEndReferenceCount = true; break; case ElementEdge.AfterEnd: this.AfterEndReferenceCount = true; break; default: Invariant.Assert(false, "Bad ElementEdge value!"); break; } } return(this); }
internal int GetOffsetFromEdge(ElementEdge edge) { int offset; switch (edge) { case ElementEdge.BeforeStart: offset = 0; break; case ElementEdge.AfterStart: offset = 1; break; case ElementEdge.BeforeEnd: offset = this.SymbolCount - 1; break; case ElementEdge.AfterEnd: offset = this.SymbolCount; break; default: offset = 0; Invariant.Assert(false, "Bad ElementEdge value!"); break; } return(offset); }
// Token: 0x06003E0B RID: 15883 RVA: 0x0011D230 File Offset: 0x0011B430 internal TextTreeTextNode Split(int localOffset, ElementEdge edge) { Invariant.Assert(this._symbolCount > 0, "Splitting a zero-width TextNode!"); Invariant.Assert(localOffset >= 0 && localOffset <= this._symbolCount, "Bad localOffset!"); Invariant.Assert(edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd, "Bad edge parameter!"); TextTreeTextNode textTreeTextNode = new TextTreeTextNode(); textTreeTextNode._generation = this._generation; base.Splay(); ElementEdge edge2; TextTreeTextNode result; if (this._positionRefCount > 0 && this._referencedEdge == ElementEdge.BeforeStart) { textTreeTextNode._symbolOffsetCache = ((this._symbolOffsetCache == -1) ? -1 : (this._symbolOffsetCache + localOffset)); textTreeTextNode._symbolCount = this._symbolCount - localOffset; this._symbolCount = localOffset; edge2 = ElementEdge.AfterEnd; result = ((edge == ElementEdge.BeforeStart) ? this : textTreeTextNode); } else { textTreeTextNode._symbolOffsetCache = this._symbolOffsetCache; textTreeTextNode._symbolCount = localOffset; this._symbolOffsetCache = ((this._symbolOffsetCache == -1) ? -1 : (this._symbolOffsetCache + localOffset)); this._symbolCount -= localOffset; edge2 = ElementEdge.BeforeStart; result = ((edge == ElementEdge.BeforeStart) ? textTreeTextNode : this); } Invariant.Assert(this._symbolCount >= 0); Invariant.Assert(textTreeTextNode._symbolCount >= 0); textTreeTextNode.InsertAtNode(this, edge2); return(result); }
// Token: 0x06003EF0 RID: 16112 RVA: 0x0011F3A4 File Offset: 0x0011D5A4 internal static void VerifyElementEdge(ElementEdge edge, string param) { if (edge != ElementEdge.BeforeStart && edge != ElementEdge.AfterStart && edge != ElementEdge.BeforeEnd && edge != ElementEdge.AfterEnd) { throw new InvalidEnumArgumentException(param, (int)edge, typeof(ElementEdge)); } }
// Token: 0x06003D4E RID: 15694 RVA: 0x0011C0B8 File Offset: 0x0011A2B8 internal int GetOffsetFromEdge(ElementEdge edge) { switch (edge) { case ElementEdge.BeforeStart: return(0); case ElementEdge.AfterStart: return(1); case ElementEdge.BeforeStart | ElementEdge.AfterStart: break; case ElementEdge.BeforeEnd: return(this.SymbolCount - 1); default: if (edge == ElementEdge.AfterEnd) { return(this.SymbolCount); } break; } int result = 0; Invariant.Assert(false, "Bad ElementEdge value!"); return(result); }
/// <summary> /// <see cref="ITextPointer.MoveToElementEdge"/> /// </summary> void ITextPointer.MoveToElementEdge(ElementEdge edge) { ValidationHelper.VerifyElementEdge(edge, "edge"); Debug.Assert(!_isFrozen, "Can't reposition a frozen pointer!"); FixedElement e = _flowPosition.GetScopingElement(); if (!e.IsTextElement) { throw new InvalidOperationException(SR.Get(SRID.NoElementObject)); } switch (edge) { case ElementEdge.BeforeStart: _flowPosition = (FlowPosition)e.Start.FlowPosition.Clone(); _flowPosition.Move(-1); break; case ElementEdge.AfterStart: _flowPosition = (FlowPosition)e.Start.FlowPosition.Clone(); break; case ElementEdge.BeforeEnd: _flowPosition = (FlowPosition)e.End.FlowPosition.Clone(); break; case ElementEdge.AfterEnd: _flowPosition = (FlowPosition)e.End.FlowPosition.Clone(); _flowPosition.Move(1); break; } }
// Token: 0x060035C3 RID: 13763 RVA: 0x000F446C File Offset: 0x000F266C internal void InsertAtNode(SplayTreeNode positionNode, ElementEdge edge) { if (edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd) { this.InsertAtNode(positionNode, edge == ElementEdge.BeforeStart); return; } SplayTreeNode splayTreeNode; bool insertBefore; if (edge == ElementEdge.AfterStart) { splayTreeNode = positionNode.GetFirstContainedNode(); insertBefore = true; } else { splayTreeNode = positionNode.GetLastContainedNode(); insertBefore = false; } if (splayTreeNode == null) { positionNode.ContainedNode = this; this.ParentNode = positionNode; Invariant.Assert(this.LeftChildNode == null); Invariant.Assert(this.RightChildNode == null); Invariant.Assert(this.LeftSymbolCount == 0); return; } this.InsertAtNode(splayTreeNode, insertBefore); }
// Decrements the reference count of TextPositions referencing this // node. // // Be careful! If this node is a TextTreeTextNode, the decrement may // cause a merge, and this node may be removed from the tree. internal virtual void DecrementReferenceCount(ElementEdge edge) { #if INT_EDGE_REF_COUNT switch (edge) { case ElementEdge.BeforeStart: this.BeforeStartReferenceCount--; Invariant.Assert(this.BeforeStartReferenceCount >= 0, "Bad BeforeStart ref count!"); break; case ElementEdge.AfterStart: this.AfterStartReferenceCount--; Invariant.Assert(this.AfterStartReferenceCount >= 0, "Bad AfterStart ref count!"); break; case ElementEdge.BeforeEnd: this.BeforeEndReferenceCount--; Invariant.Assert(this.BeforeEndReferenceCount >= 0, "Bad BeforeEnd ref count!"); break; case ElementEdge.AfterEnd: this.AfterEndReferenceCount--; Invariant.Assert(this.AfterEndReferenceCount >= 0, "Bad AfterEnd ref count!"); break; default: Invariant.Assert(false, "Bad ElementEdge value!"); break; } #endif // INT_EDGE_REF_COUNT }
// Token: 0x06003D19 RID: 15641 RVA: 0x0011BD4A File Offset: 0x00119F4A internal TextTreeFixupNode(TextTreeNode previousNode, ElementEdge previousEdge, TextTreeNode nextNode, ElementEdge nextEdge, TextTreeNode firstContainedNode, TextTreeNode lastContainedNode) { this._previousNode = previousNode; this._previousEdge = previousEdge; this._nextNode = nextNode; this._nextEdge = nextEdge; this._firstContainedNode = firstContainedNode; this._lastContainedNode = lastContainedNode; }
// Creates a new TextTreeFixupNode instance. // This ctor should only be called when extracting a single TextTreeTextElementNode. // previousNode/Edge should point to the node TextPositions will // move to after synchronizing against the deleted content. // first/lastContainedNode point to the first and last contained nodes // of an extracted element node. Positions may move into these nodes. internal TextTreeFixupNode(TextTreeNode previousNode, ElementEdge previousEdge, TextTreeNode nextNode, ElementEdge nextEdge, TextTreeNode firstContainedNode, TextTreeNode lastContainedNode) { _previousNode = previousNode; _previousEdge = previousEdge; _nextNode = nextNode; _nextEdge = nextEdge; _firstContainedNode = firstContainedNode; _lastContainedNode = lastContainedNode; }
// Token: 0x06003E0A RID: 15882 RVA: 0x0011D1DC File Offset: 0x0011B3DC internal override void DecrementReferenceCount(ElementEdge edge) { Invariant.Assert(edge == this._referencedEdge, "Bad edge decrement!"); this._positionRefCount--; Invariant.Assert(this._positionRefCount >= 0, "Bogus PositionRefCount! "); if (this._positionRefCount == 0) { this.Merge(); } }
// Increments a count of the number of TextPositions and TextNavigators // referencing this node. Called when positions are created or moved. // Returns the actual node referenced -- a new node will be created if // there are already references to this node's other edge. internal override TextTreeNode IncrementReferenceCount(ElementEdge edge, int delta) { TextTreeTextNode node; TextTreeTextNode mergeNode; Invariant.Assert(delta >= 0); Invariant.Assert(edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd, "Bad edge ref to TextTreeTextNode!"); if (delta == 0) { return(this); } if (_positionRefCount > 0 && edge != _referencedEdge) { // We need to split off a node to cover the new edge. node = Split(edge == ElementEdge.BeforeStart ? 0 : _symbolCount, edge); node._referencedEdge = edge; node._positionRefCount += delta; // It's possible we need to merge a neighbor node. // This happens when someone calls TextContainer.GetNodeAndEdgeAtOffset, // which splits a text node into two non-empty nodes. We can't merge // immediately, because we don't know which of the two nodes will // get an additional ref. // If the unreferenced node of the pair gets the new reference, // there no possibility for a merge. Otherwise, we have to split // again on the already referenced node and end up here. if (edge == ElementEdge.BeforeStart) { // If node B has no references it can merge with node A. // <A ""/><B "x"/><newNode ""/><this "x".> mergeNode = node.GetPreviousNode() as TextTreeTextNode; } else { // If node A has no references it can merge with node B. // <this "x"/><newNode ""/><A "x"/><B ""/> mergeNode = node.GetNextNode() as TextTreeTextNode; } if (mergeNode != null && mergeNode._positionRefCount == 0) { mergeNode.Merge(); } } else { node = this; _referencedEdge = edge; _positionRefCount += delta; } return(node); }
// Decrements a count of the number of TextPositions and TextNavigators // referencing this node. // This method attempts to merge adjacent TextTreeTextNodes when the ref count // transitions from 1 to 0. // // Be careful! This can modify the tree, removing // TextTreeTextNodes. internal override void DecrementReferenceCount(ElementEdge edge) { Invariant.Assert(edge == _referencedEdge, "Bad edge decrement!"); _positionRefCount--; Invariant.Assert(_positionRefCount >= 0, "Bogus PositionRefCount! "); // If the ref count drops to zero, we may be able to merge this node with an adjacent one. if (_positionRefCount == 0) { Merge(); } }
// Token: 0x06007252 RID: 29266 RVA: 0x0020AF8C File Offset: 0x0020918C internal static int GetCPFromEmbeddedObject(UIElement embeddedObject, ElementEdge edge) { Invariant.Assert(edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd, "Cannot retrieve CP from the content of embedded object."); int result = -1; if (embeddedObject is FrameworkElement) { FrameworkElement frameworkElement = (FrameworkElement)embeddedObject; if (frameworkElement.Parent is TextElement) { TextElement textElement = (TextElement)frameworkElement.Parent; result = ((edge == ElementEdge.BeforeStart) ? textElement.ContentStartOffset : textElement.ContentEndOffset); } } return(result); }
/// <summary> /// Gets CP (character position) representing EmbeddedObject within TextContainer. /// If object does not belong to the TextContainer, this method returns -1. /// </summary> internal static int GetCPFromEmbeddedObject(UIElement embeddedObject, ElementEdge edge) { Invariant.Assert(edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd, "Cannot retrieve CP from the content of embedded object."); int cp = -1; if (embeddedObject is FrameworkElement) { FrameworkElement fe = (FrameworkElement)embeddedObject; //likely the embedded element is hosted by some TextElement, like InlineUIContainer or BlockUIContainer if (fe.Parent is TextElement) { TextElement uiContainer = (TextElement)fe.Parent; cp = (edge == ElementEdge.BeforeStart) ? uiContainer.ContentStartOffset : uiContainer.ContentEndOffset; } } return(cp); }
// Inserts a node at a specified position. internal void InsertAtNode(SplayTreeNode positionNode, ElementEdge edge) { SplayTreeNode locationNode; bool insertBefore; if (edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd) { // Insert to this node's tree. InsertAtNode(positionNode, edge == ElementEdge.BeforeStart /* insertBefore */); } else { // Insert to this node's contained tree. if (edge == ElementEdge.AfterStart) { locationNode = positionNode.GetFirstContainedNode(); insertBefore = true; } else // ElementEdge == BeforeEnd { locationNode = positionNode.GetLastContainedNode(); insertBefore = false; } if (locationNode == null) { // Inserting the first contained node. positionNode.ContainedNode = this; this.ParentNode = positionNode; Invariant.Assert(this.LeftChildNode == null); Invariant.Assert(this.RightChildNode == null); Invariant.Assert(this.LeftSymbolCount == 0); } else { InsertAtNode(locationNode, insertBefore); } } }
// Token: 0x06002EC8 RID: 11976 RVA: 0x000D3320 File Offset: 0x000D1520 void ITextPointer.MoveToElementEdge(ElementEdge edge) { ValidationHelper.VerifyElementEdge(edge, "edge"); FixedElement scopingElement = this._flowPosition.GetScopingElement(); if (!scopingElement.IsTextElement) { throw new InvalidOperationException(SR.Get("NoElementObject")); } switch (edge) { case ElementEdge.BeforeStart: this._flowPosition = (FlowPosition)scopingElement.Start.FlowPosition.Clone(); this._flowPosition.Move(-1); return; case ElementEdge.AfterStart: this._flowPosition = (FlowPosition)scopingElement.Start.FlowPosition.Clone(); return; case ElementEdge.BeforeStart | ElementEdge.AfterStart: break; case ElementEdge.BeforeEnd: this._flowPosition = (FlowPosition)scopingElement.End.FlowPosition.Clone(); return; default: if (edge != ElementEdge.AfterEnd) { return; } this._flowPosition = (FlowPosition)scopingElement.End.FlowPosition.Clone(); this._flowPosition.Move(1); break; } }
// Token: 0x06003E09 RID: 15881 RVA: 0x0011D124 File Offset: 0x0011B324 internal override TextTreeNode IncrementReferenceCount(ElementEdge edge, int delta) { Invariant.Assert(delta >= 0); Invariant.Assert(edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd, "Bad edge ref to TextTreeTextNode!"); if (delta == 0) { return(this); } TextTreeTextNode textTreeTextNode; if (this._positionRefCount > 0 && edge != this._referencedEdge) { textTreeTextNode = this.Split((edge == ElementEdge.BeforeStart) ? 0 : this._symbolCount, edge); textTreeTextNode._referencedEdge = edge; textTreeTextNode._positionRefCount += delta; TextTreeTextNode textTreeTextNode2; if (edge == ElementEdge.BeforeStart) { textTreeTextNode2 = (textTreeTextNode.GetPreviousNode() as TextTreeTextNode); } else { textTreeTextNode2 = (textTreeTextNode.GetNextNode() as TextTreeTextNode); } if (textTreeTextNode2 != null && textTreeTextNode2._positionRefCount == 0) { textTreeTextNode2.Merge(); } } else { textTreeTextNode = this; this._referencedEdge = edge; this._positionRefCount += delta; } return(textTreeTextNode); }
internal int GetOffsetFromEdge(ElementEdge edge) { int offset; switch (edge) { case ElementEdge.BeforeStart: offset = 0; break; case ElementEdge.AfterStart: offset = 1; break; case ElementEdge.BeforeEnd: offset = this.SymbolCount - 1; break; case ElementEdge.AfterEnd: offset = this.SymbolCount; break; default: offset = 0; Invariant.Assert(false, "Bad ElementEdge value!"); break; } return offset; }
// Increments the reference count of TextPositions referencing a // particular edge of this node. // // If this node is a TextTreeTextNode, the increment may split the node // and the return value is guaranteed to be the node containing the referenced // edge (which may be a new node). Otherwise this method always returns // the original node. internal virtual TextTreeNode IncrementReferenceCount(ElementEdge edge, int delta) { Invariant.Assert(delta >= 0); if (delta > 0) { switch (edge) { case ElementEdge.BeforeStart: this.BeforeStartReferenceCount = true; break; case ElementEdge.AfterStart: this.AfterStartReferenceCount = true; break; case ElementEdge.BeforeEnd: this.BeforeEndReferenceCount = true; break; case ElementEdge.AfterEnd: this.AfterEndReferenceCount = true; break; default: Invariant.Assert(false, "Bad ElementEdge value!"); break; } } return this; }
// Increments the reference count of TextPositions referencing a // particular edge of this node. // // If this node is a TextTreeTextNode, the increment may split the node // and the return value is guaranteed to be the node containing the referenced // edge (which may be a new node). Otherwise this method always returns // the original node. internal TextTreeNode IncrementReferenceCount(ElementEdge edge) { return IncrementReferenceCount(edge, +1); }
// Token: 0x06002BFD RID: 11261 RVA: 0x000C7FA9 File Offset: 0x000C61A9 void ITextPointer.MoveToElementEdge(ElementEdge edge) { this.ChildPointer.MoveToElementEdge(edge); }
//------------------------------------------------------ // // Constructors // //------------------------------------------------------ #region Constructors // Creates a new TextTreeFixupNode instance. // previousNode/Edge should point to the node TextPositions will // move to after synchronizing against the deleted content. internal TextTreeFixupNode(TextTreeNode previousNode, ElementEdge previousEdge, TextTreeNode nextNode, ElementEdge nextEdge) : this(previousNode, previousEdge, nextNode, nextEdge, null, null) { }
/// <summary> /// Repositions this TextNavigator at an element edge of its scoping /// text element. /// </summary> /// <param name="edge"> /// The specific edge to move to. /// </param> void ITextPointer.MoveToElementEdge(ElementEdge edge) { Debug.Assert(!_isFrozen, "Can't reposition a frozen pointer!"); Debug.Assert(false, "No scoping element!"); }
// Increments the position reference counts on nodes immediately // preceding and following a delete operation on a single TextElementNode. // This is similar to AdjustRefCountsForContentDelete, except that // in this case we deleting a single node, and positions at the // BeforeStart/AfterEnd edges may move into contained content, which // is still live in the tree. // // Whenever we delete a span of content, we have to worry about any // positions still referencing the deleted content. They have enough // information to find their way back to the surrounding nodes, but // we need to increment the ref count on those nodes now so that they'll // still be around when the positions need them. // // Because incrementing a ref count on a text node edge may involve // splitting the text node, this method takes refs to nodes and will // update the refs if a node is split. // // Called by ExtractElementFromSiblingTree. private void AdjustRefCountsForShallowDelete(ref TextTreeNode previousNode, ElementEdge previousEdge, ref TextTreeNode nextNode,ElementEdge nextEdge, ref TextTreeNode firstContainedNode, ref TextTreeNode lastContainedNode, TextTreeTextElementNode extractedElementNode) { previousNode = previousNode.IncrementReferenceCount(previousEdge, extractedElementNode.AfterStartReferenceCount); nextNode = nextNode.IncrementReferenceCount(nextEdge, extractedElementNode.BeforeEndReferenceCount); if (firstContainedNode != null) { firstContainedNode = firstContainedNode.IncrementReferenceCount(ElementEdge.BeforeStart, extractedElementNode.BeforeStartReferenceCount); } else { nextNode = nextNode.IncrementReferenceCount(nextEdge, extractedElementNode.BeforeStartReferenceCount); } if (lastContainedNode != null) { lastContainedNode = lastContainedNode.IncrementReferenceCount(ElementEdge.AfterEnd, extractedElementNode.AfterEndReferenceCount); } else { previousNode = previousNode.IncrementReferenceCount(previousEdge, extractedElementNode.AfterEndReferenceCount); } }
// Finds a node/edge pair matching a given char offset in the tree. // If the pair matches a character within a text node, the text node is split. internal void GetNodeAndEdgeAtCharOffset(int charOffset, out TextTreeNode node, out ElementEdge edge) { int nodeCharOffset; int siblingTreeCharOffset; bool checkZeroWidthNode; // Offset zero/SymbolCount-1 are before/after the root node, which // is an illegal position -- you can't add or remove content there // and it's never exposed publicly. Invariant.Assert(charOffset >= 0 && charOffset <= this.IMECharCount, "Bogus char offset!"); if (this.IMECharCount == 0) { node = null; edge = ElementEdge.BeforeStart; return; } // If this flag is set true on exit, we need to consider the case // where we've found a "zero-width" (SymbolCount == 0) text node. // Zero width nodes needs special handling, since they are logically // part of a following or preceding node. checkZeroWidthNode = false; // Find the node. node = _rootNode; nodeCharOffset = 0; // Each iteration walks through one tree. while (true) { int leftEdgeCharCount = 0; TextTreeTextElementNode textElementNode = node as TextTreeTextElementNode; if (textElementNode != null) { leftEdgeCharCount = textElementNode.IMELeftEdgeCharCount; if (leftEdgeCharCount > 0) { if (charOffset == nodeCharOffset) { edge = ElementEdge.BeforeStart; break; } if (charOffset == nodeCharOffset + leftEdgeCharCount) { edge = ElementEdge.AfterStart; break; } } } else if (node is TextTreeTextNode || node is TextTreeObjectNode) { if (charOffset == nodeCharOffset) { edge = ElementEdge.BeforeStart; checkZeroWidthNode = true; break; } if (charOffset == nodeCharOffset + node.IMECharCount) { edge = ElementEdge.AfterEnd; checkZeroWidthNode = true; break; } } // No child node? That means we're inside a TextTreeTextNode. if (node.ContainedNode == null) { Invariant.Assert(node is TextTreeTextNode); // Need to split the TextTreeTextNode. // Here we want a character buried inside a single node, split // the node open.... node = ((TextTreeTextNode)node).Split(charOffset - nodeCharOffset, ElementEdge.AfterEnd); edge = ElementEdge.BeforeStart; break; } // Need to look into one of the child nodes. node = (TextTreeNode)node.ContainedNode; nodeCharOffset += leftEdgeCharCount; // Skip over the parent element start edge. // Walk down the sibling tree. node = (TextTreeNode)node.GetSiblingAtCharOffset(charOffset - nodeCharOffset, out siblingTreeCharOffset); nodeCharOffset += siblingTreeCharOffset; } // If we're on a zero-width TextTreeTextNode we need some special handling. if (checkZeroWidthNode) { node = (TextTreeNode)AdjustForZeroWidthNode(node, edge); } }
// This method is called by GetNodeAndEdgeAtOffset to adjust a node // matching a symbol offset. // // When text positions reference both sides of a text run // we always split the run into a zero-width TextTreeTextNode // followed by a non-zero-width node. We do this so that // later we can safely split the non-zero node without disturbing // existing text positions. // // Here, we have to be very careful never to reference a node // edge between the zero-width node and the non-zero width node. // // A: <TextTreeTextNode SymbolCount=0/><TextTreeTextNode SymbolCount=1+/> // B: <TextTreeTextNode SymbolCount=1+/><TextTreeTextNode SymbolCount=0/> // // In case A, if we're searching for the first character in the second // node, we want to return the first (zero-width) node. A TextPointer // could be at node1/BeforeBegin but node2/BeforeBegin is invalid. // // In case B, if we're searching for the last character in the first // node, we want to return the second (zero-width) node. A TextPointer // could be at node2/AfterEnd but not node1/AfterEnd is invalid. private SplayTreeNode AdjustForZeroWidthNode(SplayTreeNode node, ElementEdge edge) { TextTreeTextNode textNode; SplayTreeNode nextNode; SplayTreeNode previousNode; textNode = node as TextTreeTextNode; if (textNode == null) { Invariant.Assert(node.SymbolCount > 0, "Only TextTreeTextNodes may have zero symbol counts!"); return node; } if (textNode.SymbolCount == 0) { // There are only ever at most two consectuative zero-width // text nodes (one for each possible position gravity). Make sure // we chose the following one. This ensures consistency with // the typical non-zero width case -- we return the node whose // start edge is closest to a character offset. nextNode = textNode.GetNextNode(); if (nextNode != null) { if (Invariant.Strict) { if (nextNode.SymbolCount == 0) { // Node and previousNode are logically one text run. // <TextTreeTextNode SymbolCount=1+/><node SymbolCount=0/><TextTreeTextNode SymbolCount=0/><TextTreeTextNode SymbolCount=1+/> Invariant.Assert(nextNode is TextTreeTextNode); Invariant.Assert(!textNode.BeforeStartReferenceCount); Invariant.Assert(!((TextTreeTextNode)nextNode).AfterEndReferenceCount); Invariant.Assert(textNode.GetPreviousNode() == null || textNode.GetPreviousNode().SymbolCount > 0, "Found three consecutive zero-width text nodes! (1)"); Invariant.Assert(nextNode.GetNextNode() == null || nextNode.GetNextNode().SymbolCount > 0, "Found three consecutive zero-width text nodes! (2)"); } } if (!textNode.BeforeStartReferenceCount) { // Node and previousNode are logically one text run. // <TextTreeTextNode SymbolCount=1+/><node SymbolCount=0/><AnyNode/> node = nextNode; } } } else if (edge == ElementEdge.BeforeStart) { if (textNode.AfterEndReferenceCount) { // <TextTreeTextNode SymbolCount=0/><node SymbolCount=1+/> // Case A. Check for previous zero-width node. previousNode = textNode.GetPreviousNode(); if (previousNode != null && previousNode.SymbolCount == 0 && !((TextTreeNode)previousNode).AfterEndReferenceCount) { Invariant.Assert(previousNode is TextTreeTextNode); node = previousNode; } } } else // edge == ElementEdge.AfterEnd { if (textNode.BeforeStartReferenceCount) { // B: <node SymbolCount=1+/><TextTreeTextNode SymbolCount=0/> // Case B. Check for following zero-width node. nextNode = textNode.GetNextNode(); if (nextNode != null && nextNode.SymbolCount == 0 && !((TextTreeNode)nextNode).BeforeStartReferenceCount) { Invariant.Assert(nextNode is TextTreeTextNode); node = nextNode; } } } return node; }
/// <summary> /// Gets CP (character position) representing EmbeddedObject within TextContainer. /// If object does not belong to the TextContainer, this method returns -1. /// </summary> internal static int GetCPFromEmbeddedObject(UIElement embeddedObject, ElementEdge edge) { Invariant.Assert(edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd, "Cannot retrieve CP from the content of embedded object."); int cp = -1; if (embeddedObject is FrameworkElement) { FrameworkElement fe = (FrameworkElement)embeddedObject; //likely the embedded element is hosted by some TextElement, like InlineUIContainer or BlockUIContainer if (fe.Parent is TextElement) { TextElement uiContainer = (TextElement)fe.Parent; cp = (edge == ElementEdge.BeforeStart) ? uiContainer.ContentStartOffset : uiContainer.ContentEndOffset; } } return cp; }
/// <summary> /// Gets CP (character position) representing DependencyObject within given TextContainer. /// If object does not belong to the TextContainer, this method returns /// distance to the end of TextContainer. /// Only TextElement or host of TextContainer can be passed here. /// </summary> internal static int GetCPFromElement(ITextContainer textContainer, DependencyObject element, ElementEdge edge) { int cp; TextElement textElement; textElement = element as TextElement; if (textElement != null) { if (!textElement.IsInTree || textElement.TextContainer != textContainer) { // Element is not in the tree. Use TextContainer.End instead. // This situation may happen, if element got removed, but StructuralCache // still have a reference to it and it is trying to do incremental update. cp = textContainer.SymbolCount; } else { // Get TextPointer from appropriate edge. switch (edge) { case ElementEdge.BeforeStart: cp = textElement.ElementStartOffset; break; case ElementEdge.AfterStart: cp = textElement.ContentStartOffset; break; case ElementEdge.BeforeEnd: cp = textElement.ContentEndOffset; break; case ElementEdge.AfterEnd: cp = textElement.ElementEndOffset; break; default: Invariant.Assert(false, "Unknown ElementEdge."); cp = 0; break; } } } else { // The element is the owner of TextContainer, // return the beginning or the end of the content. Invariant.Assert(element is TextBlock || element is FlowDocument || element is TextBox, "Cannot retrive length for EmbeddedObject."); cp = (edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterStart) ? 0 : textContainer.SymbolCount; } return cp; }
/// <summary> /// Gets TextContentRange for a TextElement's edge. /// </summary> internal static TextContentRange GetTextContentRangeForTextElementEdge(TextElement textElement, ElementEdge edge) { Invariant.Assert(edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd); ITextContainer textContainer = textElement.TextContainer; int cpFirst, cpLast; if (edge == ElementEdge.AfterEnd) { cpFirst = textElement.ContentEndOffset; cpLast = textElement.ElementEndOffset; } else { cpFirst = textElement.ElementStartOffset; cpLast = textElement.ContentStartOffset; } return new TextContentRange(cpFirst, cpLast, textContainer); }
/// <summary> /// <see cref="ITextPointer.MoveToElementEdge"/> /// </summary> void ITextPointer.MoveToElementEdge(ElementEdge edge) { Debug.Assert(!_isFrozen, "Can't reposition a frozen pointer!"); this.ChildPointer.MoveToElementEdge(edge); }
// Called by the TextPointer ctor. Initializes this instance. private void Initialize(TextContainer tree, TextTreeNode node, ElementEdge edge, LogicalDirection gravity, uint generation, bool caretUnitBoundaryCache, bool isCaretUnitBoundaryCacheValid, uint layoutGeneration) { _tree = tree; // Fixup of the target node based on gravity. // Positions always cling to a node edge that matches their gravity, // so that insert ops never affect the position. RepositionForGravity(ref node, ref edge, gravity); SetNodeAndEdge(node.IncrementReferenceCount(edge), edge); _generation = generation; this.CaretUnitBoundaryCache = caretUnitBoundaryCache; this.IsCaretUnitBoundaryCacheValid = isCaretUnitBoundaryCacheValid; _layoutGeneration = layoutGeneration; VerifyFlags(); tree.AssertTree(); AssertState(); }
internal static TextTreeNode GetAdjacentNode(TextTreeNode node, ElementEdge edge, LogicalDirection direction) { TextTreeNode adjacentNode; adjacentNode = GetAdjacentSiblingNode(node, edge, direction); if (adjacentNode == null) { // We're the first or last child, try the parent. if (edge == ElementEdge.AfterStart || edge == ElementEdge.BeforeEnd) { adjacentNode = node; } else { adjacentNode = (TextTreeNode)node.GetContainingNode(); } } return adjacentNode; }
// Positions this navigator at a node/edge pair. // Node/edge are adjusted based on the current gravity. private void MoveToNode(TextContainer tree, TextTreeNode node, ElementEdge edge) { RepositionForGravity(ref node, ref edge, GetGravityInternal()); _tree = tree; SetNodeAndEdge(AdjustRefCounts(node, edge, _node, this.Edge), edge); _generation = tree.PositionGeneration; }
// Token: 0x06003220 RID: 12832 RVA: 0x00002137 File Offset: 0x00000337 void ITextPointer.MoveToElementEdge(ElementEdge edge) { }
// Splits this node into two adjacent nodes. // Returns the node which contains the original requested edge // (e.g., if edge == ElementEdge.BeforeStart, this method returns the // preceding node, if edge == ElementEdge.AfterEnd, it returns the // following node). internal TextTreeTextNode Split(int localOffset, ElementEdge edge) { TextTreeTextNode newNode; TextTreeTextNode edgeNode; ElementEdge newNodeEdge; Invariant.Assert(_symbolCount > 0, "Splitting a zero-width TextNode!"); Invariant.Assert(localOffset >= 0 && localOffset <= _symbolCount, "Bad localOffset!"); Invariant.Assert(edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd, "Bad edge parameter!"); #if DEBUG if (localOffset == 0) { TextTreeNode previousNode; Invariant.Assert(edge == ElementEdge.BeforeStart, "Unexpected edge!"); Invariant.Assert(edge != _referencedEdge, "Splitting at referenced edge!"); previousNode = (TextTreeNode)GetPreviousNode(); Invariant.Assert(previousNode == null || previousNode.SymbolCount > 0 || previousNode.AfterEndReferenceCount, "Found preceding zero-width text node inside Split!"); } else if (localOffset == _symbolCount) { TextTreeNode nextNode; Invariant.Assert(edge == ElementEdge.AfterEnd, "Unexpected edge!"); Invariant.Assert(edge != _referencedEdge, "Splitting at referenced edge!"); nextNode = (TextTreeNode)GetNextNode(); Invariant.Assert(nextNode == null || nextNode.SymbolCount > 0 || nextNode.BeforeStartReferenceCount, "Found following zero-width text node inside Split! (2)"); } #endif // DEBUG newNode = new TextTreeTextNode(); newNode._generation = _generation; // Splay this node to the root so we don't corrupt any LeftSymbolCounts // of ancestor nodes when we fixup _symbolCount below. Splay(); if (_positionRefCount > 0 && _referencedEdge == ElementEdge.BeforeStart) { // New node is the following node. newNode._symbolOffsetCache = (_symbolOffsetCache == -1) ? -1 : _symbolOffsetCache + localOffset; newNode._symbolCount = _symbolCount - localOffset; _symbolCount = localOffset; newNodeEdge = ElementEdge.AfterEnd; edgeNode = (edge == ElementEdge.BeforeStart) ? this : newNode; } else { // New node is the preceding node. newNode._symbolOffsetCache = _symbolOffsetCache; newNode._symbolCount = localOffset; _symbolOffsetCache = (_symbolOffsetCache == -1) ? -1 : _symbolOffsetCache + localOffset; _symbolCount -= localOffset; newNodeEdge = ElementEdge.BeforeStart; edgeNode = (edge == ElementEdge.BeforeStart) ? newNode : this; } Invariant.Assert(_symbolCount >= 0); Invariant.Assert(newNode._symbolCount >= 0); newNode.InsertAtNode(this, newNodeEdge); return(edgeNode); }
internal virtual TextTreeNode IncrementReferenceCount(ElementEdge edge, bool delta) { return(IncrementReferenceCount(edge, delta ? 1 : 0)); }
// Finds a node/edge pair matching a given symbol offset in the tree. // If the pair matches a character within a text node, the text node is split. internal void GetNodeAndEdgeAtOffset(int offset, bool splitNode, out SplayTreeNode node, out ElementEdge edge) { int nodeOffset; int siblingTreeOffset; bool checkZeroWidthNode; // Offset zero/SymbolCount-1 are before/after the root node, which // is an illegal position -- you can't add or remove content there // and it's never exposed publicly. Invariant.Assert(offset >= 1 && offset <= this.InternalSymbolCount - 1, "Bogus symbol offset!"); // If this flag is set true on exit, we need to consider the case // where we've found a "zero-width" (SymbolCount == 0) text node. // Zero width nodes needs special handling, since they are logically // part of a following or preceding node. checkZeroWidthNode = false; // Find the node. node = _rootNode; nodeOffset = 0; // Each iteration walks through one tree. while (true) { // While we're at it, fix up the node's SymbolOffsetCache, // since we're doing the work already. Invariant.Assert(node.Generation != _rootNode.Generation || node.SymbolOffsetCache == -1 || node.SymbolOffsetCache == nodeOffset, "Bad node offset cache!"); node.Generation = _rootNode.Generation; node.SymbolOffsetCache = nodeOffset; if (offset == nodeOffset) { edge = ElementEdge.BeforeStart; checkZeroWidthNode = true; break; } if (node is TextTreeRootNode || node is TextTreeTextElementNode) { if (offset == nodeOffset + 1) { edge = ElementEdge.AfterStart; break; } if (offset == nodeOffset + node.SymbolCount - 1) { edge = ElementEdge.BeforeEnd; break; } } if (offset == nodeOffset + node.SymbolCount) { edge = ElementEdge.AfterEnd; checkZeroWidthNode = true; break; } // No child node? That means we're inside a TextTreeTextNode. if (node.ContainedNode == null) { Invariant.Assert(node is TextTreeTextNode); // Need to split the TextTreeTextNode. // Here we want a character buried inside a single node, split // the node open.... if (splitNode) { node = ((TextTreeTextNode)node).Split(offset - nodeOffset, ElementEdge.AfterEnd); } edge = ElementEdge.BeforeStart; break; } // Need to look into one of the child nodes. node = node.ContainedNode; nodeOffset += 1; // Skip over the parent element start edge. // Walk down the sibling tree. node = node.GetSiblingAtOffset(offset - nodeOffset, out siblingTreeOffset); nodeOffset += siblingTreeOffset; } // If we're on a zero-width TextTreeTextNode we need some special handling. if (checkZeroWidthNode) { node = AdjustForZeroWidthNode(node, edge); } }
// For any logical position (location between two symbols) there are two // possible node/edge pairs. This method choses the pair that fits a // specified gravity, such that future inserts won't require that a text // position be moved, based on its gravity, at the node/edge pair. private static void RepositionForGravity(ref TextTreeNode node, ref ElementEdge edge, LogicalDirection gravity) { SplayTreeNode newNode; ElementEdge newEdge; newNode = node; newEdge = edge; switch (edge) { case ElementEdge.BeforeStart: if (gravity == LogicalDirection.Backward) { newNode = node.GetPreviousNode(); newEdge = ElementEdge.AfterEnd; if (newNode == null) { newNode = node.GetContainingNode(); newEdge = ElementEdge.AfterStart; } } break; case ElementEdge.AfterStart: if (gravity == LogicalDirection.Forward) { newNode = node.GetFirstContainedNode(); newEdge = ElementEdge.BeforeStart; if (newNode == null) { newNode = node; newEdge = ElementEdge.BeforeEnd; } } break; case ElementEdge.BeforeEnd: if (gravity == LogicalDirection.Backward) { newNode = node.GetLastContainedNode(); newEdge = ElementEdge.AfterEnd; if (newNode == null) { newNode = node; newEdge = ElementEdge.AfterStart; } } break; case ElementEdge.AfterEnd: if (gravity == LogicalDirection.Forward) { newNode = node.GetNextNode(); newEdge = ElementEdge.BeforeStart; if (newNode == null) { newNode = node.GetContainingNode(); newEdge = ElementEdge.BeforeEnd; } } break; } node = (TextTreeNode)newNode; edge = newEdge; }
// Splits this node into two adjacent nodes. // Returns the node which contains the original requested edge // (e.g., if edge == ElementEdge.BeforeStart, this method returns the // preceding node, if edge == ElementEdge.AfterEnd, it returns the // following node). internal TextTreeTextNode Split(int localOffset, ElementEdge edge) { TextTreeTextNode newNode; TextTreeTextNode edgeNode; ElementEdge newNodeEdge; Invariant.Assert(_symbolCount > 0, "Splitting a zero-width TextNode!"); Invariant.Assert(localOffset >= 0 && localOffset <= _symbolCount, "Bad localOffset!"); Invariant.Assert(edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd, "Bad edge parameter!"); #if DEBUG if (localOffset == 0) { TextTreeNode previousNode; Invariant.Assert(edge == ElementEdge.BeforeStart, "Unexpected edge!"); Invariant.Assert(edge != _referencedEdge, "Splitting at referenced edge!"); previousNode = (TextTreeNode)GetPreviousNode(); Invariant.Assert(previousNode == null || previousNode.SymbolCount > 0 || previousNode.AfterEndReferenceCount, "Found preceding zero-width text node inside Split!"); } else if (localOffset == _symbolCount) { TextTreeNode nextNode; Invariant.Assert(edge == ElementEdge.AfterEnd, "Unexpected edge!"); Invariant.Assert(edge != _referencedEdge, "Splitting at referenced edge!"); nextNode = (TextTreeNode)GetNextNode(); Invariant.Assert(nextNode == null || nextNode.SymbolCount > 0 || nextNode.BeforeStartReferenceCount, "Found following zero-width text node inside Split! (2)"); } #endif // DEBUG newNode = new TextTreeTextNode(); newNode._generation = _generation; // Splay this node to the root so we don't corrupt any LeftSymbolCounts // of ancestor nodes when we fixup _symbolCount below. Splay(); if (_positionRefCount > 0 && _referencedEdge == ElementEdge.BeforeStart) { // New node is the following node. newNode._symbolOffsetCache = (_symbolOffsetCache == -1) ? -1 : _symbolOffsetCache + localOffset; newNode._symbolCount = _symbolCount - localOffset; _symbolCount = localOffset; newNodeEdge = ElementEdge.AfterEnd; edgeNode = (edge == ElementEdge.BeforeStart) ? this : newNode; } else { // New node is the preceding node. newNode._symbolOffsetCache = _symbolOffsetCache; newNode._symbolCount = localOffset; _symbolOffsetCache = (_symbolOffsetCache == -1) ? -1 : _symbolOffsetCache + localOffset; _symbolCount -= localOffset; newNodeEdge = ElementEdge.BeforeStart; edgeNode = (edge == ElementEdge.BeforeStart) ? newNode : this; } Invariant.Assert(_symbolCount >= 0); Invariant.Assert(newNode._symbolCount >= 0); newNode.InsertAtNode(this, newNodeEdge); return edgeNode; }
/// <summary> /// <see cref="ITextPointer.MoveToElementEdge"/> /// </summary> void ITextPointer.MoveToElementEdge(ElementEdge edge) { Debug.Assert(!_isFrozen, "Can't reposition a frozen pointer!"); Debug.Assert(false, "No scoping element!"); }
// Token: 0x06007249 RID: 29257 RVA: 0x0020AD70 File Offset: 0x00208F70 internal static TextContentRange GetTextContentRangeForTextElementEdge(TextElement textElement, ElementEdge edge) { Invariant.Assert(edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd); ITextContainer textContainer = textElement.TextContainer; int cpFirst; int cpLast; if (edge == ElementEdge.AfterEnd) { cpFirst = textElement.ContentEndOffset; cpLast = textElement.ElementEndOffset; } else { cpFirst = textElement.ElementStartOffset; cpLast = textElement.ContentStartOffset; } return(new TextContentRange(cpFirst, cpLast, textContainer)); }
internal virtual TextTreeNode IncrementReferenceCount(ElementEdge edge, bool delta) { return IncrementReferenceCount(edge, delta ? 1 : 0); }
// Token: 0x06007250 RID: 29264 RVA: 0x0020AEA4 File Offset: 0x002090A4 internal static int GetCPFromElement(ITextContainer textContainer, DependencyObject element, ElementEdge edge) { TextElement textElement = element as TextElement; int result; if (textElement != null) { if (!textElement.IsInTree || textElement.TextContainer != textContainer) { result = textContainer.SymbolCount; } else { switch (edge) { case ElementEdge.BeforeStart: return(textElement.ElementStartOffset); case ElementEdge.AfterStart: return(textElement.ContentStartOffset); case ElementEdge.BeforeStart | ElementEdge.AfterStart: break; case ElementEdge.BeforeEnd: return(textElement.ContentEndOffset); default: if (edge == ElementEdge.AfterEnd) { return(textElement.ElementEndOffset); } break; } Invariant.Assert(false, "Unknown ElementEdge."); result = 0; } } else { Invariant.Assert(element is TextBlock || element is FlowDocument || element is TextBox, "Cannot retrive length for EmbeddedObject."); result = ((edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterStart) ? 0 : textContainer.SymbolCount); } return(result); }
internal void GetNodeAndEdgeAtOffset(int offset, out SplayTreeNode node, out ElementEdge edge) { GetNodeAndEdgeAtOffset(offset, true /* splitNode */, out node, out edge); }
// Inc/decs the position ref counts on TextTreeTextNodes as the navigator // is repositioned. // If the new ref is to a TextTreeTextNode, the node may be split. // Returns the actual node referenced, which will always be newNode, // unless newNode is a TextTreeTextNode that gets split. The caller // should use the returned node to position navigators. private TextTreeNode AdjustRefCounts(TextTreeNode newNode, ElementEdge newNodeEdge, TextTreeNode oldNode, ElementEdge oldNodeEdge) { TextTreeNode node; // This test should walk the tree upwards to catch all errors...probably not worth the slowdown though. Invariant.Assert(oldNode.ParentNode == null || oldNode.IsChildOfNode(oldNode.ParentNode), "Trying to add ref a dead node!"); Invariant.Assert(newNode.ParentNode == null || newNode.IsChildOfNode(newNode.ParentNode), "Trying to add ref a dead node!"); node = newNode; if (newNode != oldNode || newNodeEdge != oldNodeEdge) { node = newNode.IncrementReferenceCount(newNodeEdge); oldNode.DecrementReferenceCount(oldNodeEdge); } return node; }
// Repositions the TextPointer and clears any relevant caches. private void SetNodeAndEdge(TextTreeNode node, ElementEdge edge) { Invariant.Assert(edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterStart || edge == ElementEdge.BeforeEnd || edge == ElementEdge.AfterEnd); _node = node; _flags = (_flags & ~(uint)Flags.EdgeMask) | (uint)edge; VerifyFlags(); // Always clear the caret unit boundary cache when we move to a new position. this.IsCaretUnitBoundaryCacheValid = false; }
// Throws an ArgumentException if edge is not a valid enum. internal static void VerifyElementEdge(ElementEdge edge, string param) { if (edge != ElementEdge.BeforeStart && edge != ElementEdge.AfterStart && edge != ElementEdge.BeforeEnd && edge != ElementEdge.AfterEnd) { throw new InvalidEnumArgumentException(param, (int)edge, typeof(ElementEdge)); } }
// Increments the reference count of TextPositions referencing a // particular edge of this node. // // If this node is a TextTreeTextNode, the increment may split the node // and the return value is guaranteed to be the node containing the referenced // edge (which may be a new node). Otherwise this method always returns // the original node. internal TextTreeNode IncrementReferenceCount(ElementEdge edge) { return(IncrementReferenceCount(edge, +1)); }
// Increments the position reference counts on nodes immediately // preceding and following a delete operation. // // Whenever we delete a span of content, we have to worry about any // positions still referencing the deleted content. They have enough // information to find their way back to the surrounding nodes, but // we need to increment the ref count on those nodes now so that they'll // still be around when the positions need them. // // Because incrementing a ref count on a text node edge may involve // splitting the text node, this method takes refs to nodes and will // update the refs if a node is split. // // Called by DeleteContentFromSiblingTree and ExtractElementInternal. private void AdjustRefCountsForContentDelete(ref TextTreeNode previousNode, ElementEdge previousEdge, ref TextTreeNode nextNode, ElementEdge nextEdge, TextTreeNode middleSubTree) { bool leftEdgeReferenceCount; bool rightEdgeReferenceCount; leftEdgeReferenceCount = false; rightEdgeReferenceCount = false; // Get the count of all positions referencing text node edges across the deleted content. GetReferenceCounts((TextTreeNode)middleSubTree.GetMinSibling(), ref leftEdgeReferenceCount, ref rightEdgeReferenceCount); previousNode = previousNode.IncrementReferenceCount(previousEdge, rightEdgeReferenceCount); nextNode = nextNode.IncrementReferenceCount(nextEdge, leftEdgeReferenceCount); }
// Increments a count of the number of TextPositions and TextNavigators // referencing this node. Called when positions are created or moved. // Returns the actual node referenced -- a new node will be created if // there are already references to this node's other edge. internal override TextTreeNode IncrementReferenceCount(ElementEdge edge, int delta) { TextTreeTextNode node; TextTreeTextNode mergeNode; Invariant.Assert(delta >= 0); Invariant.Assert(edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd, "Bad edge ref to TextTreeTextNode!"); if (delta == 0) { return this; } if (_positionRefCount > 0 && edge != _referencedEdge) { // We need to split off a node to cover the new edge. node = Split(edge == ElementEdge.BeforeStart ? 0 : _symbolCount, edge); node._referencedEdge = edge; node._positionRefCount += delta; // It's possible we need to merge a neighbor node. // This happens when someone calls TextContainer.GetNodeAndEdgeAtOffset, // which splits a text node into two non-empty nodes. We can't merge // immediately, because we don't know which of the two nodes will // get an additional ref. // If the unreferenced node of the pair gets the new reference, // there no possibility for a merge. Otherwise, we have to split // again on the already referenced node and end up here. if (edge == ElementEdge.BeforeStart) { // If node B has no references it can merge with node A. // <A ""/><B "x"/><newNode ""/><this "x".> mergeNode = node.GetPreviousNode() as TextTreeTextNode; } else { // If node A has no references it can merge with node B. // <this "x"/><newNode ""/><A "x"/><B ""/> mergeNode = node.GetNextNode() as TextTreeTextNode; } if (mergeNode != null && mergeNode._positionRefCount == 0) { mergeNode.Merge(); } } else { node = this; _referencedEdge = edge; _positionRefCount += delta; } return node; }
// Token: 0x06003D4A RID: 15690 RVA: 0x00002137 File Offset: 0x00000337 internal virtual void DecrementReferenceCount(ElementEdge edge) { }
/// <summary> /// Gets CP (character position) representing DependencyObject within given TextContainer. /// If object does not belong to the TextContainer, this method returns /// distance to the end of TextContainer. /// Only TextElement or host of TextContainer can be passed here. /// </summary> internal static int GetCPFromElement(ITextContainer textContainer, DependencyObject element, ElementEdge edge) { int cp; TextElement textElement; textElement = element as TextElement; if (textElement != null) { if (!textElement.IsInTree || textElement.TextContainer != textContainer) { // Element is not in the tree. Use TextContainer.End instead. // This situation may happen, if element got removed, but StructuralCache // still have a reference to it and it is trying to do incremental update. cp = textContainer.SymbolCount; } else { // Get TextPointer from appropriate edge. switch (edge) { case ElementEdge.BeforeStart: cp = textElement.ElementStartOffset; break; case ElementEdge.AfterStart: cp = textElement.ContentStartOffset; break; case ElementEdge.BeforeEnd: cp = textElement.ContentEndOffset; break; case ElementEdge.AfterEnd: cp = textElement.ElementEndOffset; break; default: Invariant.Assert(false, "Unknown ElementEdge."); cp = 0; break; } } } else { // The element is the owner of TextContainer, // return the beginning or the end of the content. Invariant.Assert(element is TextBlock || element is FlowDocument || element is TextBox, "Cannot retrive length for EmbeddedObject."); cp = (edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterStart) ? 0 : textContainer.SymbolCount; } return(cp); }