// Token: 0x060035C1 RID: 13761 RVA: 0x000F43D0 File Offset: 0x000F25D0 internal int GetSymbolOffset(uint treeGeneration) { int num = 0; SplayTreeNode splayTreeNode = this; while (splayTreeNode.Generation != treeGeneration || splayTreeNode.SymbolOffsetCache < 0) { splayTreeNode.Splay(); num += splayTreeNode.LeftSymbolCount; num++; splayTreeNode = splayTreeNode.ParentNode; } num += splayTreeNode.SymbolOffsetCache; this.Generation = treeGeneration; this.SymbolOffsetCache = num; return(num); }
// Dumps a node and all following nodes "flat" -- in notation similar to xaml. internal static void DumpNodeFlatRecursive(SplayTreeNode node) { for (; node != null; node = node.GetNextNode()) { Debug.Write("<" + GetFlatPrefix(node) + node.DebugId); if (node.ContainedNode != null) { Debug.Write(">"); DumpNodeFlatRecursive(node.GetFirstContainedNode()); Debug.Write("</" + GetFlatPrefix(node) + node.DebugId + ">"); } else { Debug.Write("/>"); } } }
// Removes a run of nodes from a tree. internal static void Remove(TextTreeTextBlock firstNode, TextTreeTextBlock lastNode) { SplayTreeNode leftTree; SplayTreeNode rightTree; SplayTreeNode rootNode; SplayTreeNode containerNode; // // Break the tree into three subtrees. // leftTree = firstNode.GetPreviousNode(); if (leftTree != null) { // Splitting moves leftTree to local root. leftTree.Split(); containerNode = leftTree.ParentNode; leftTree.ParentNode = null; // We'll fixup leftTree.ParentNode.ContainedNode below. // Join requires that leftTree has a null ParentNode. } else { // There are no preceeding nodes. containerNode = firstNode.GetContainingNode(); } rightTree = lastNode.Split(); // // Recombine the two outer trees. // rootNode = SplayTreeNode.Join(leftTree, rightTree); if (containerNode != null) { containerNode.ContainedNode = rootNode; } if (rootNode != null) { rootNode.ParentNode = containerNode; } }
// Token: 0x060035C6 RID: 13766 RVA: 0x000F460C File Offset: 0x000F280C internal static void Join(SplayTreeNode root, SplayTreeNode leftSubTree, SplayTreeNode rightSubTree) { root.LeftChildNode = leftSubTree; root.RightChildNode = rightSubTree; Invariant.Assert(root.Role == SplayTreeNodeRole.LocalRoot); if (leftSubTree != null) { leftSubTree.ParentNode = root; root.LeftSymbolCount = leftSubTree.LeftSymbolCount + leftSubTree.SymbolCount; root.LeftCharCount = leftSubTree.LeftCharCount + leftSubTree.IMECharCount; } else { root.LeftSymbolCount = 0; root.LeftCharCount = 0; } if (rightSubTree != null) { rightSubTree.ParentNode = root; } }
// 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: 0x060035C2 RID: 13762 RVA: 0x000F442C File Offset: 0x000F262C internal int GetIMECharOffset() { int num = 0; SplayTreeNode splayTreeNode = this; for (;;) { splayTreeNode.Splay(); num += splayTreeNode.LeftCharCount; splayTreeNode = splayTreeNode.ParentNode; if (splayTreeNode == null) { break; } TextTreeTextElementNode textTreeTextElementNode = splayTreeNode as TextTreeTextElementNode; if (textTreeTextElementNode != null) { num += textTreeTextElementNode.IMELeftEdgeCharCount; } } return(num); }
// Token: 0x060035C0 RID: 13760 RVA: 0x000F4378 File Offset: 0x000F2578 internal SplayTreeNode GetNextNode() { SplayTreeNode splayTreeNode = this.RightChildNode; if (splayTreeNode != null) { for (;;) { SplayTreeNode leftChildNode = splayTreeNode.LeftChildNode; if (leftChildNode == null) { break; } splayTreeNode = leftChildNode; } } else { SplayTreeNodeRole role = this.Role; splayTreeNode = this.ParentNode; while (role != SplayTreeNodeRole.LocalRoot) { if (role == SplayTreeNodeRole.LeftChild) { goto IL_41; } role = splayTreeNode.Role; splayTreeNode = splayTreeNode.ParentNode; } splayTreeNode = null; } IL_41: if (splayTreeNode != null) { splayTreeNode.Splay(); } return(splayTreeNode); }
// Combines two trees. Every node in leftSubTree will precede every node // in rightSubTree. // leftSubTree and/or rightSubTree may be null, returns null if both // trees are null. internal static SplayTreeNode Join(SplayTreeNode leftSubTree, SplayTreeNode rightSubTree) { SplayTreeNode maxNode; Invariant.Assert(leftSubTree == null || leftSubTree.ParentNode == null); Invariant.Assert(rightSubTree == null || rightSubTree.ParentNode == null); if (leftSubTree != null) { // Get max of leftSubTree, and splay it. maxNode = leftSubTree.GetMaxSibling(); maxNode.Splay(); Invariant.Assert(maxNode.Role == SplayTreeNodeRole.LocalRoot); Invariant.Assert(maxNode.RightChildNode == null); // Then merge the two trees. // No change to any LeftSymbolCounts. maxNode.RightChildNode = rightSubTree; if (rightSubTree != null) { rightSubTree.ParentNode = maxNode; } } else if (rightSubTree != null) { maxNode = rightSubTree; Invariant.Assert(maxNode.Role == SplayTreeNodeRole.LocalRoot); } else { maxNode = null; } return(maxNode); }
// Returns true if this node is the left/right/contained node of parentNode. internal bool IsChildOfNode(SplayTreeNode parentNode) { return (parentNode.LeftChildNode == this || parentNode.RightChildNode == this || parentNode.ContainedNode == this); }
// Combines two trees. Every node in leftSubTree will precede every node // in rightSubTree. // leftSubTree and/or rightSubTree may be null, returns null if both // trees are null. internal static SplayTreeNode Join(SplayTreeNode leftSubTree, SplayTreeNode rightSubTree) { SplayTreeNode maxNode; Invariant.Assert(leftSubTree == null || leftSubTree.ParentNode == null); Invariant.Assert(rightSubTree == null || rightSubTree.ParentNode == null); if (leftSubTree != null) { // Get max of leftSubTree, and splay it. maxNode = leftSubTree.GetMaxSibling(); maxNode.Splay(); Invariant.Assert(maxNode.Role == SplayTreeNodeRole.LocalRoot); Invariant.Assert(maxNode.RightChildNode == null); // Then merge the two trees. // No change to any LeftSymbolCounts. maxNode.RightChildNode = rightSubTree; if (rightSubTree != null) { rightSubTree.ParentNode = maxNode; } } else if (rightSubTree != null) { maxNode = rightSubTree; Invariant.Assert(maxNode.Role == SplayTreeNodeRole.LocalRoot); } else { maxNode = null; } return maxNode; }
// Parents leftSubTree and rightSubTree to root. Either leftSubTree and/or // rightSubTree may be null. internal static void Join(SplayTreeNode root, SplayTreeNode leftSubTree, SplayTreeNode rightSubTree) { root.LeftChildNode = leftSubTree; root.RightChildNode = rightSubTree; Invariant.Assert(root.Role == SplayTreeNodeRole.LocalRoot); if (leftSubTree != null) { leftSubTree.ParentNode = root; root.LeftSymbolCount = leftSubTree.LeftSymbolCount + leftSubTree.SymbolCount; root.LeftCharCount = leftSubTree.LeftCharCount + leftSubTree.IMECharCount; } else { root.LeftSymbolCount = 0; root.LeftCharCount = 0; } if (rightSubTree != null) { rightSubTree.ParentNode = root; } }
// Inserts a node before or after an existing node. // The new node becomes the local root. internal void InsertAtNode(SplayTreeNode location, bool insertBefore) { SplayTreeNode leftSubTree; SplayTreeNode rightSubTree; SplayTreeNode containingNode; Invariant.Assert(this.ParentNode == null, "Can't insert child node!"); Invariant.Assert(this.LeftChildNode == null, "Can't insert node with left children!"); Invariant.Assert(this.RightChildNode == null, "Can't insert node with right children!"); leftSubTree = insertBefore ? location.GetPreviousNode() : location; if (leftSubTree != null) { rightSubTree = leftSubTree.Split(); containingNode = leftSubTree.ParentNode; } else { rightSubTree = location; location.Splay(); Invariant.Assert(location.Role == SplayTreeNodeRole.LocalRoot, "location should be local root!"); containingNode = location.ParentNode; } // Merge everything into a new tree. Join(this, leftSubTree, rightSubTree); // Hook up the new tree to the containing node. this.ParentNode = containingNode; if (containingNode != null) { containingNode.ContainedNode = this; } }
// Removes nodes from a sibling tree. containingNode must scope start/end. // Returns the combined symbol count of all the removed nodes. private int DeleteContentFromSiblingTree(SplayTreeNode containingNode, TextPointer startPosition, TextPointer endPosition, bool newFirstIMEVisibleNode, out int charCount) { SplayTreeNode leftSubTree; SplayTreeNode middleSubTree; SplayTreeNode rightSubTree; SplayTreeNode rootNode; TextTreeNode previousNode; ElementEdge previousEdge; TextTreeNode nextNode; ElementEdge nextEdge; int symbolCount; int symbolOffset; // Early out in the no-op case. CutContent can't handle an empty content span. if (startPosition.CompareTo(endPosition) == 0) { if (newFirstIMEVisibleNode) { UpdateContainerSymbolCount(containingNode, /* symbolCount */ 0, /* charCount */ -1); } charCount = 0; return 0; } // Get the symbol offset now before the CutContent call invalidates startPosition. symbolOffset = startPosition.GetSymbolOffset(); // Do the cut. middleSubTree is what we want to remove. symbolCount = CutContent(startPosition, endPosition, out charCount, out leftSubTree, out middleSubTree, out rightSubTree); // We need to remember the original previous/next node for the span // we're about to drop, so any orphaned positions can find their way // back. if (middleSubTree != null) { if (leftSubTree != null) { previousNode = (TextTreeNode)leftSubTree.GetMaxSibling(); previousEdge = ElementEdge.AfterEnd; } else { previousNode = (TextTreeNode)containingNode; previousEdge = ElementEdge.AfterStart; } if (rightSubTree != null) { nextNode = (TextTreeNode)rightSubTree.GetMinSibling(); nextEdge = ElementEdge.BeforeStart; } else { nextNode = (TextTreeNode)containingNode; nextEdge = ElementEdge.BeforeEnd; } // Increment previous/nextNode reference counts. This may involve // splitting a text node, so we use refs. AdjustRefCountsForContentDelete(ref previousNode, previousEdge, ref nextNode, nextEdge, (TextTreeNode)middleSubTree); // Make sure left/rightSubTree stay local roots, we might // have inserted new elements in the AdjustRefCountsForContentDelete call. if (leftSubTree != null) { leftSubTree.Splay(); } if (rightSubTree != null) { rightSubTree.Splay(); } // Similarly, middleSubtree might not be a local root any more, // so splay it too. middleSubTree.Splay(); // Note TextContainer now has no references to middleSubTree, if there are // no orphaned positions this allocation won't be kept around. Invariant.Assert(middleSubTree.ParentNode == null, "Assigning fixup node to parented child!"); middleSubTree.ParentNode = new TextTreeFixupNode(previousNode, previousEdge, nextNode, nextEdge); } // Put left/right sub trees back into the TextContainer. rootNode = TextTreeNode.Join(leftSubTree, rightSubTree); containingNode.ContainedNode = rootNode; if (rootNode != null) { rootNode.ParentNode = containingNode; } if (symbolCount > 0) { int nextNodeCharDelta = 0; if (newFirstIMEVisibleNode) { // The following node is the new first ime visible sibling. // It just moved, and loses an edge character. nextNodeCharDelta = -1; } UpdateContainerSymbolCount(containingNode, -symbolCount, -charCount + nextNodeCharDelta); TextTreeText.RemoveText(_rootNode.RootTextBlock, symbolOffset, symbolCount); NextGeneration(true /* deletedContent */); // Notify the TextElement of a content change. Note that any full TextElements // between startPosition and endPosition will be handled by CutTopLevelLogicalNodes, // which will move them from this tree to their own private trees without changing // their contents. Invariant.Assert(startPosition.Parent == endPosition.Parent); TextElement textElement = startPosition.Parent as TextElement; if (textElement != null) { textElement.OnTextUpdated(); } } return symbolCount; }
// Debug only. Walks a node and all its children to get a brute force // symbol count. private static int GetNodeSymbolCountSlow(SplayTreeNode node) { SplayTreeNode child; int count; if (node is TextTreeRootNode || node is TextTreeTextElementNode) { count = 2; for (child = node.GetFirstContainedNode(); child != null; child = child.GetNextNode()) { count += GetNodeSymbolCountSlow(child); } } else { Invariant.Assert(node.ContainedNode == null, "Expected leaf node!"); count = node.SymbolCount; } return count; }
// 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); } }
//----------------------------------------------------- // // Private Methods // //------------------------------------------------------ #region Private Methods // Scans all the immediate contained nodes of a TextElementNode, and // calls AddLogicalChild methods if supported to alert the children // about a new parent. private void ReparentLogicalChildren(SplayTreeNode containerNode, DependencyObject newParentLogicalNode, DependencyObject oldParentLogicalNode) { ReparentLogicalChildren(containerNode.GetFirstContainedNode(), null, newParentLogicalNode, oldParentLogicalNode); }
// Scans all the immediate contained nodes of a TextElementNode, and // calls AddLogicalChild methods if supported to alert the children // about a new parent. private void ReparentLogicalChildren(SplayTreeNode firstChildNode, SplayTreeNode lastChildNode, DependencyObject newParentLogicalNode, DependencyObject oldParentLogicalNode) { SplayTreeNode node; DependencyObject logicalTreeNode; TextTreeTextElementNode elementNode; TextTreeObjectNode uiElementNode; Invariant.Assert(!(newParentLogicalNode == null && oldParentLogicalNode == null), "Both new and old parents should not be null"); for (node = firstChildNode; node != null; node = node.GetNextNode()) { logicalTreeNode = null; elementNode = node as TextTreeTextElementNode; if (elementNode != null) { logicalTreeNode = elementNode.TextElement; } else { uiElementNode = node as TextTreeObjectNode; if (uiElementNode != null) { logicalTreeNode = uiElementNode.EmbeddedElement; } } TextElement textElement = logicalTreeNode as TextElement; if (textElement != null) { textElement.BeforeLogicalTreeChange(); } try { if (oldParentLogicalNode != null) { LogicalTreeHelper.RemoveLogicalChild(oldParentLogicalNode, logicalTreeNode); } if (newParentLogicalNode != null) { LogicalTreeHelper.AddLogicalChild(newParentLogicalNode, logicalTreeNode); } } finally { if (textElement != null) { textElement.AfterLogicalTreeChange(); } } if (node == lastChildNode) break; } }
// Updates the SymbolCount for node's container nodes -- all the way to the TextTree root. private void UpdateContainerSymbolCount(SplayTreeNode containingNode, int symbolCount, int charCount) { do { containingNode.Splay(); containingNode.SymbolCount += symbolCount; containingNode.IMECharCount += charCount; containingNode = containingNode.ParentNode; } while (containingNode != null); }
// Removes an element node from its sibling tree. // // If deep == true, then this method also removes any contained nodes // and returns a deep copy of them. // // If deep == false, any contained nodes are inserted into the original // node's sibling tree. private void ExtractElementFromSiblingTree(SplayTreeNode containingNode, TextTreeTextElementNode elementNode, bool deep) { TextTreeNode previousNode; ElementEdge previousEdge; TextTreeNode nextNode; ElementEdge nextEdge; SplayTreeNode childNode; SplayTreeNode minChildNode; SplayTreeNode maxChildNode; SplayTreeNode localRootNode; TextTreeNode firstContainedNode; TextTreeNode lastContainedNode; // Remember the nodes surrounding the one we're going to remove. previousNode = (TextTreeNode)elementNode.GetPreviousNode(); previousEdge = ElementEdge.AfterEnd; if (previousNode == null) { previousNode = (TextTreeNode)containingNode; previousEdge = ElementEdge.AfterStart; } nextNode = (TextTreeNode)elementNode.GetNextNode(); nextEdge = ElementEdge.BeforeStart; if (nextNode == null) { nextNode = (TextTreeNode)containingNode; nextEdge = ElementEdge.BeforeEnd; } // Remove the element node. elementNode.Remove(); Invariant.Assert(elementNode.Role == SplayTreeNodeRole.LocalRoot); if (deep) { // Increment previous/nextNode reference counts. This may involve // splitting a text node, so we use refs. AdjustRefCountsForContentDelete(ref previousNode, previousEdge, ref nextNode, nextEdge, elementNode); // Reparent the removed node with a FixupNode, so that any orphaned // positions can find their way back to the tree. // We have to do this after the AdjustRefCountsForContentDelete call, because the fixup // node doesn't act like a regular node. elementNode.ParentNode = new TextTreeFixupNode(previousNode, previousEdge, nextNode, nextEdge); DeepCopy(elementNode); } else { // Reparent contained nodes to elementNode's parent. childNode = elementNode.ContainedNode; elementNode.ContainedNode = null; if (childNode != null) { childNode.ParentNode = null; firstContainedNode = (TextTreeNode)childNode.GetMinSibling(); lastContainedNode = (TextTreeNode)childNode.GetMaxSibling(); } else { firstContainedNode = null; lastContainedNode = null; } // Increment previous/nextNode reference counts. This may involve // splitting a text node, so we use refs. AdjustRefCountsForShallowDelete(ref previousNode, previousEdge, ref nextNode, nextEdge, ref firstContainedNode, ref lastContainedNode, elementNode); // Reparent the removed node with a FixupNode, so that any orphaned // positions can find their way back to the tree. // We have to do this after the AdjustRefCountsForContentDelete call, because the fixup // node doesn't act like a regular node. elementNode.ParentNode = new TextTreeFixupNode(previousNode, previousEdge, nextNode, nextEdge, firstContainedNode, lastContainedNode); if (childNode != null) { // Get previous/next nodes into roots of individual trees. // Then merge them with the element's children. // We need to splay childNode because it may no longer be a local root. // The addrefs in AdjustRefCountsForShallowDelete may have created new nodes // and shuffled the tree. childNode.Splay(); localRootNode = childNode; if (previousNode != containingNode) { previousNode.Split(); Invariant.Assert(previousNode.Role == SplayTreeNodeRole.LocalRoot); Invariant.Assert(previousNode.RightChildNode == null); minChildNode = childNode.GetMinSibling(); minChildNode.Splay(); previousNode.RightChildNode = minChildNode; minChildNode.ParentNode = previousNode; localRootNode = previousNode; } if (nextNode != containingNode) { nextNode.Splay(); Invariant.Assert(nextNode.Role == SplayTreeNodeRole.LocalRoot); Invariant.Assert(nextNode.LeftChildNode == null); maxChildNode = childNode.GetMaxSibling(); maxChildNode.Splay(); nextNode.LeftChildNode = maxChildNode; nextNode.LeftSymbolCount += maxChildNode.LeftSymbolCount + maxChildNode.SymbolCount; nextNode.LeftCharCount += maxChildNode.LeftCharCount + maxChildNode.IMECharCount; maxChildNode.ParentNode = nextNode; localRootNode = nextNode; } containingNode.ContainedNode = localRootNode; if (localRootNode != null) { localRootNode.ParentNode = containingNode; } } } }
// Splits a sibling tree into three sub trees -- a tree with content before startPosition, // a tree with content between startPosition/endPosition, and a tree with content following endPosition. // Any of the subtrees may be null on exit, if they contain no content (eg, if // startPosition == endPosition, middleSubTree will be null on exit, and so forth). // // All returned roots have null ParentNode pointers -- the caller MUST // reparent all of them, even if deleting content, to ensure orphaned // TextPositions can find their way back to the original tree. // // Returns the symbol count of middleSubTree -- all the content between startPosition and endPosition. private int CutContent(TextPointer startPosition, TextPointer endPosition, out int charCount, out SplayTreeNode leftSubTree, out SplayTreeNode middleSubTree, out SplayTreeNode rightSubTree) { SplayTreeNode childNode; int symbolCount; Invariant.Assert(startPosition.GetScopingNode() == endPosition.GetScopingNode(), "startPosition/endPosition not in same sibling tree!"); Invariant.Assert(startPosition.CompareTo(endPosition) != 0, "CutContent doesn't expect empty span!"); // Get the root of all nodes to the left of the split. switch (startPosition.Edge) { case ElementEdge.BeforeStart: leftSubTree = startPosition.Node.GetPreviousNode(); break; case ElementEdge.AfterStart: leftSubTree = null; break; case ElementEdge.BeforeEnd: default: Invariant.Assert(false, "Unexpected edge!"); // Should have gone to simple insert case. leftSubTree = null; break; case ElementEdge.AfterEnd: leftSubTree = startPosition.Node; break; } // Get the root of all nodes to the right of the split. switch (endPosition.Edge) { case ElementEdge.BeforeStart: rightSubTree = endPosition.Node; break; case ElementEdge.AfterStart: default: Invariant.Assert(false, "Unexpected edge! (2)"); // Should have gone to simple insert case. rightSubTree = null; break; case ElementEdge.BeforeEnd: rightSubTree = null; break; case ElementEdge.AfterEnd: rightSubTree = endPosition.Node.GetNextNode(); break; } // Get the root of all nodes covered by startPosition/endPosition. if (rightSubTree == null) { if (leftSubTree == null) { middleSubTree = startPosition.GetScopingNode().ContainedNode; } else { middleSubTree = leftSubTree.GetNextNode(); } } else { middleSubTree = rightSubTree.GetPreviousNode(); if (middleSubTree == leftSubTree) { middleSubTree = null; } } // Split the tree into three sub trees matching the roots we've found. if (leftSubTree != null) { leftSubTree.Split(); Invariant.Assert(leftSubTree.Role == SplayTreeNodeRole.LocalRoot); leftSubTree.ParentNode.ContainedNode = null; leftSubTree.ParentNode = null; } symbolCount = 0; charCount = 0; if (middleSubTree != null) { if (rightSubTree != null) { // Split will move middleSubTree up to the root. middleSubTree.Split(); } else { // Make sure middleSubTree is a root. middleSubTree.Splay(); } Invariant.Assert(middleSubTree.Role == SplayTreeNodeRole.LocalRoot, "middleSubTree is not a local root!"); if (middleSubTree.ParentNode != null) { middleSubTree.ParentNode.ContainedNode = null; middleSubTree.ParentNode = null; } // Calc the symbol count of the middle tree. for (childNode = middleSubTree; childNode != null; childNode = childNode.RightChildNode) { symbolCount += childNode.LeftSymbolCount + childNode.SymbolCount; charCount += childNode.LeftCharCount + childNode.IMECharCount; } } if (rightSubTree != null) { // Make sure rightSubTree is a root before returning. // We haven't done anything yet to ensure this. rightSubTree.Splay(); } Invariant.Assert(leftSubTree == null || leftSubTree.Role == SplayTreeNodeRole.LocalRoot); Invariant.Assert(middleSubTree == null || middleSubTree.Role == SplayTreeNodeRole.LocalRoot); Invariant.Assert(rightSubTree == null || rightSubTree.Role == SplayTreeNodeRole.LocalRoot); return symbolCount; }
internal void GetNodeAndEdgeAtOffset(int offset, out SplayTreeNode node, out ElementEdge edge) { GetNodeAndEdgeAtOffset(offset, true /* splitNode */, out node, out edge); }
// Returns a string identifying the type of a given node. private static string GetFlatPrefix(SplayTreeNode node) { string prefix; if (node is TextTreeTextNode) { prefix = "t"; } else if (node is TextTreeObjectNode) { prefix = "o"; } else if (node is TextTreeTextElementNode) { prefix = "e"; } else if (node is TextTreeRootNode) { prefix = "r"; } else { prefix = "?"; } return prefix; }
// 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; }
// Token: 0x060035CC RID: 13772 RVA: 0x000F4833 File Offset: 0x000F2A33 internal bool IsChildOfNode(SplayTreeNode parentNode) { return(parentNode.LeftChildNode == this || parentNode.RightChildNode == this || parentNode.ContainedNode == this); }
//------------------------------------------------------ // // Private Methods // //------------------------------------------------------ #region Private Methods // Recursive worker to DumpNode. internal static void DumpNodeRecursive(SplayTreeNode node, int depth) { SplayTreeNode containedNode; string indent; indent = new string(' ', depth*2); Debug.Write("<"); Debug.Write(node); if (node.ContainedNode == null) { Debug.WriteLine("/>"); } else { Debug.WriteLine(">"); } containedNode = node.ContainedNode; if (containedNode != null) { Debug.Write(indent + "C "); DumpNodeRecursive(containedNode, depth + 1); } if (node.LeftChildNode != null) { Debug.Write(indent + "L "); DumpNodeRecursive(node.LeftChildNode, depth + 1); } if (node.RightChildNode != null) { Debug.Write(indent + "R "); DumpNodeRecursive(node.RightChildNode, depth + 1); } if (containedNode != null) { if (node is TextTreeRootNode) { Debug.WriteLine(indent + "</RootNode>"); } else if (node is TextTreeTextElementNode) { Debug.WriteLine(indent + "</TextElementNode>"); } else { Debug.WriteLine(indent + "</UnknownNode>"); } } }
// This test is so slow we can't afford to run it even with Invariant.Strict. // It grinds execution to a halt. private static void DebugWalkTree(SplayTreeNode node) { SplayTreeNode previousNode; SplayTreeNode previousPreviousNode; previousNode = null; previousPreviousNode = null; for (; node != null; node = node.GetNextNode()) { if (node.SymbolCount == 0 && previousNode != null && previousNode.SymbolCount == 0 && previousPreviousNode != null && previousPreviousNode.SymbolCount == 0) { Invariant.Assert(false, "Found three consecuative zero length nodes!"); } previousPreviousNode = previousNode; previousNode = node; if (node.ContainedNode != null) { DebugWalkTree(node.ContainedNode.GetMinSibling()); } } }