// Helper for DeleteContentInternal. // If startPosition is placed at the very front of its parent's sibling list, // returns the next sibling following endPositoin (the new head of the sibling // list). The new head node is interesting because its IMELeftEdgeCharCount may // change because of its new position. private TextTreeTextElementNode GetNextIMEVisibleNode(TextPointer startPosition, TextPointer endPosition) { TextTreeTextElementNode nextIMEVisibleNode = null; TextElement adjacentElement = startPosition.GetAdjacentElement(LogicalDirection.Forward) as TextElement; if (adjacentElement != null && adjacentElement.IsFirstIMEVisibleSibling) { nextIMEVisibleNode = (TextTreeTextElementNode)endPosition.GetAdjacentSiblingNode(LogicalDirection.Forward); } return nextIMEVisibleNode; }
// Does a deep extract of all top-level TextElements between two positions. // Returns the combined symbol count of all extracted elements. // Each extracted element (and its children) are moved into a private tree. // This insures that outside references to the TextElement can still use // the TextElements freely, inserting or removing content, etc. // // Also calls AddLogicalChild on any top-level UIElements encountered. private int CutTopLevelLogicalNodes(TextTreeNode containingNode, TextPointer startPosition, TextPointer endPosition, out int charCount) { SplayTreeNode node; SplayTreeNode nextNode; SplayTreeNode stopNode; TextTreeTextElementNode elementNode; TextTreeObjectNode uiElementNode; char[] elementText; int symbolCount; TextContainer tree; TextPointer newTreeStart; DependencyObject logicalParent; object currentLogicalChild; Invariant.Assert(startPosition.GetScopingNode() == endPosition.GetScopingNode(), "startPosition/endPosition not in same sibling tree!"); node = startPosition.GetAdjacentSiblingNode(LogicalDirection.Forward); stopNode = endPosition.GetAdjacentSiblingNode(LogicalDirection.Forward); symbolCount = 0; charCount = 0; logicalParent = containingNode.GetLogicalTreeNode(); while (node != stopNode) { currentLogicalChild = null; // Get the next node now, before we extract any TextElementNodes. nextNode = node.GetNextNode(); elementNode = node as TextTreeTextElementNode; if (elementNode != null) { // Grab the IMECharCount before we modify the node. // This value depends on the node's current context. int imeCharCountInOriginalContainer = elementNode.IMECharCount; // Cut and record the matching symbols. elementText = TextTreeText.CutText(_rootNode.RootTextBlock, elementNode.GetSymbolOffset(this.Generation), elementNode.SymbolCount); // Rip the element out of its sibling tree. // textElementNode.TextElement's TextElementNode will be updated // with a deep copy of all contained nodes. We need a deep copy // to ensure the new element/tree has no TextPointer references. ExtractElementFromSiblingTree(containingNode, elementNode, true /* deep */); // Assert that the TextElement now points to a new TextElementNode, not the original one. Invariant.Assert(elementNode.TextElement.TextElementNode != elementNode); // We want to start referring to the copied node, update elementNode. elementNode = elementNode.TextElement.TextElementNode; UpdateContainerSymbolCount(containingNode, -elementNode.SymbolCount, -imeCharCountInOriginalContainer); NextGeneration(true /* deletedContent */); // Stick it in a private tree so it's safe for the outside world to play with. tree = new TextContainer(null, false /* plainTextOnly */); newTreeStart = tree.Start; tree.InsertElementToSiblingTree(newTreeStart, newTreeStart, elementNode); Invariant.Assert(elementText.Length == elementNode.SymbolCount); tree.UpdateContainerSymbolCount(elementNode.GetContainingNode(), elementNode.SymbolCount, elementNode.IMECharCount); tree.DemandCreateText(); TextTreeText.InsertText(tree.RootTextBlock, 1 /* symbolOffset */, elementText); tree.NextGeneration(false /* deletedContent */); currentLogicalChild = elementNode.TextElement; // Keep a running total of how many symbols we've removed. symbolCount += elementNode.SymbolCount; charCount += imeCharCountInOriginalContainer; } else { uiElementNode = node as TextTreeObjectNode; if (uiElementNode != null) { currentLogicalChild = uiElementNode.EmbeddedElement; } } // Remove the child from the logical tree LogicalTreeHelper.RemoveLogicalChild(logicalParent, currentLogicalChild); node = nextNode; } if (symbolCount > 0) { startPosition.SyncToTreeGeneration(); endPosition.SyncToTreeGeneration(); } return symbolCount; }