// 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("/>"); } } }
// 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("/>"); } } }
// 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; } }
// 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; }
// 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()); } } }