Пример #1
0
        // Returns a copy of a sibling tree.  node is expected to be the first sibling.
        private TextTreeNode DeepCopyContainedNodes(TextTreeNode node)
        { 
            TextTreeNode rootClone;
            TextTreeNode previousClone; 
            TextTreeNode clone; 
            TextTreeTextElementNode elementNode;
 
            rootClone = null;
            previousClone = null;

            do 
            {
                elementNode = node as TextTreeTextElementNode; 
                if (elementNode != null) 
                {
                    clone = DeepCopy(elementNode); 
                }
                else
                {
                    clone = node.Clone(); 
                }
 
                // clone will be null in one case: if we're trying to clone an 
                // empty TextNode.  We can skip empty TextNodes (symbol count == 0)
                // because we know the clones have no TextPointer references, so 
                // an empty node serves no purpose.
                Invariant.Assert(clone != null || node is TextTreeTextNode && node.SymbolCount == 0);
                if (clone != null)
                { 
                    clone.ParentNode = previousClone;
                    if (previousClone != null) 
                    { 
                        previousClone.RightChildNode = clone;
                    } 
                    else
                    {
                        Invariant.Assert(clone.Role == SplayTreeNodeRole.LocalRoot);
                        // Remember the first clone created. 
                        rootClone = clone;
                    } 
 
                    previousClone = clone;
                } 

                node = (TextTreeNode)node.GetNextNode();
            }
            while (node != null); 

            return rootClone; 
        } 
Пример #2
0
        // Sums the reference counts for a node and all following or contained nodes.
        private void GetReferenceCounts(TextTreeNode node, ref bool leftEdgeReferenceCount, ref bool rightEdgeReferenceCount) 
        { 
            do
            { 
                // We can combine BeforeStart/BeforeEnd and AfterStart/AfterEnd because
                // they include all positions with equal gravity.
                leftEdgeReferenceCount |= node.BeforeStartReferenceCount || node.BeforeEndReferenceCount;
                rightEdgeReferenceCount |= node.AfterStartReferenceCount || node.AfterEndReferenceCount; 

                if (node.ContainedNode != null) 
                { 
                    GetReferenceCounts((TextTreeNode)node.ContainedNode.GetMinSibling(), ref leftEdgeReferenceCount, ref rightEdgeReferenceCount);
                } 

                node = (TextTreeNode)node.GetNextNode();
            }
            while (node != null); 
        }
Пример #3
0
        // 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;
        }
Пример #4
0
        internal static TextPointerContext GetPointerContextForward(TextTreeNode node, ElementEdge edge)
        {
            TextTreeNode nextNode;
            TextTreeNode firstContainedNode;
            TextPointerContext symbolType;

            switch (edge)
            {
                case ElementEdge.BeforeStart:
                    symbolType = node.GetPointerContext(LogicalDirection.Forward);
                    break;

                case ElementEdge.AfterStart:
                    if (node.ContainedNode != null)
                    {
                        firstContainedNode = (TextTreeNode)node.GetFirstContainedNode();
                        symbolType = firstContainedNode.GetPointerContext(LogicalDirection.Forward);
                    }
                    else
                    {
                        goto case ElementEdge.BeforeEnd;
                    }
                    break;

                case ElementEdge.BeforeEnd:
                    // The root node is special, there's no ElementStart/End, so test for null parent.
                    Invariant.Assert(node.ParentNode != null || node is TextTreeRootNode, "Inconsistent node.ParentNode");
                    symbolType = (node.ParentNode != null) ? TextPointerContext.ElementEnd : TextPointerContext.None;
                    break;

                case ElementEdge.AfterEnd:
                    nextNode = (TextTreeNode)node.GetNextNode();
                    if (nextNode != null)
                    {
                        symbolType = nextNode.GetPointerContext(LogicalDirection.Forward);
                    }
                    else
                    {
                        // The root node is special, there's no ElementStart/End, so test for null parent.
                        Invariant.Assert(node.GetContainingNode() != null, "Bad position!"); // Illegal to be at root AfterEnd.
                        symbolType = (node.GetContainingNode() is TextTreeRootNode) ? TextPointerContext.None : TextPointerContext.ElementEnd;
                    }
                    break;

                default:
                    Invariant.Assert(false, "Unreachable code.");
                    symbolType = TextPointerContext.Text;
                    break;
            }

            return symbolType;
        }
Пример #5
0
        // Finds the next run, returned as a node/edge pair.
        // Returns false if there is no following run, in which case node/edge will match the input position.
        // The returned node/edge pair respects the input position's gravity.
        internal static bool GetNextNodeAndEdge(TextTreeNode sourceNode, ElementEdge sourceEdge, bool plainTextOnly, out TextTreeNode node, out ElementEdge edge)
        {
            SplayTreeNode currentNode;
            SplayTreeNode newNode;
            SplayTreeNode nextNode;
            SplayTreeNode containingNode;
            bool startedAdjacentToTextNode;
            bool endedAdjacentToTextNode;

            node = sourceNode;
            edge = sourceEdge;

            newNode = node;
            currentNode = node;

            // If we started next to a TextTreeTextNode, and the next node
            // is also a TextTreeTextNode, then skip past the second node
            // as well -- multiple text nodes count as a single Move run.
            do
            {
                startedAdjacentToTextNode = false;
                endedAdjacentToTextNode = false;

                switch (edge)
                {
                    case ElementEdge.BeforeStart:
                        newNode = currentNode.GetFirstContainedNode();
                        if (newNode != null)
                        {
                            // Move to inner edge/first child.
                        }
                        else if (currentNode is TextTreeTextElementNode)
                        {
                            // Move to inner edge.
                            newNode = currentNode;
                            edge = ElementEdge.BeforeEnd;
                        }
                        else
                        {
                            // Move to next node.
                            startedAdjacentToTextNode = currentNode is TextTreeTextNode;
                            edge = ElementEdge.BeforeEnd;
                            goto case ElementEdge.BeforeEnd;
                        }
                        break;

                    case ElementEdge.AfterStart:
                        newNode = currentNode.GetFirstContainedNode();
                        if (newNode != null)
                        {
                            // Move to first child/second child or first child/first child child
                            if (newNode is TextTreeTextElementNode)
                            {
                                edge = ElementEdge.AfterStart;
                            }
                            else
                            {
                                startedAdjacentToTextNode = newNode is TextTreeTextNode;
                                endedAdjacentToTextNode = newNode.GetNextNode() is TextTreeTextNode;
                                edge = ElementEdge.AfterEnd;
                            }
                        }
                        else if (currentNode is TextTreeTextElementNode)
                        {
                            // Move to next node.
                            newNode = currentNode;
                            edge = ElementEdge.AfterEnd;
                        }
                        else
                        {
                            Invariant.Assert(currentNode is TextTreeRootNode, "currentNode is expected to be TextTreeRootNode");
                            // This is the root node, leave newNode null.
                        }
                        break;

                    case ElementEdge.BeforeEnd:
                        newNode = currentNode.GetNextNode();
                        if (newNode != null)
                        {
                            // Move to next node;
                            endedAdjacentToTextNode = newNode is TextTreeTextNode;
                            edge = ElementEdge.BeforeStart;
                        }
                        else
                        {
                            // Move to inner edge of parent.
                            newNode = currentNode.GetContainingNode();
                        }
                        break;

                    case ElementEdge.AfterEnd:
                        nextNode = currentNode.GetNextNode();
                        startedAdjacentToTextNode = nextNode is TextTreeTextNode;

                        newNode = nextNode;
                        if (newNode != null)
                        {
                            // Move to next node/first child;
                            if (newNode is TextTreeTextElementNode)
                            {
                                edge = ElementEdge.AfterStart;
                            }
                            else
                            {
                                // Move to next node/next next node.
                                endedAdjacentToTextNode = newNode.GetNextNode() is TextTreeTextNode;
                            }
                        }
                        else
                        {
                            containingNode = currentNode.GetContainingNode();

                            if (!(containingNode is TextTreeRootNode))
                            {
                                // Move to parent.
                                newNode = containingNode;
                            }
                        }
                        break;

                    default:
                        Invariant.Assert(false, "Unknown ElementEdge value");
                        break;
                }

                currentNode = newNode;

                // Multiple text nodes count as a single Move run.
                // Instead of iterating through N text nodes, exploit
                // the fact (when we can) that text nodes are only ever contained in
                // runs with no other content.  Jump straight to the end.
                if (startedAdjacentToTextNode && endedAdjacentToTextNode && plainTextOnly)
                {
                    newNode = newNode.GetContainingNode();
                    Invariant.Assert(newNode is TextTreeRootNode);

                    if (edge == ElementEdge.BeforeStart)
                    {
                        edge = ElementEdge.BeforeEnd;
                    }
                    else
                    {
                        newNode = newNode.GetLastContainedNode();
                        Invariant.Assert(newNode != null);
                        Invariant.Assert(edge == ElementEdge.AfterEnd);
                    }

                    break;
                }
            }
            while (startedAdjacentToTextNode && endedAdjacentToTextNode);

            if (newNode != null)
            {
                node = (TextTreeNode)newNode;
            }

            return (newNode != null);
        }
Пример #6
0
        internal static TextTreeNode GetAdjacentSiblingNode(TextTreeNode node, ElementEdge edge, LogicalDirection direction)
        {
            SplayTreeNode sibling;

            if (direction == LogicalDirection.Forward)
            {
                switch (edge)
                {
                    case ElementEdge.BeforeStart:
                        sibling = node;
                        break;

                    case ElementEdge.AfterStart:
                        sibling = node.GetFirstContainedNode();
                        break;

                    case ElementEdge.BeforeEnd:
                    default:
                        sibling = null;
                        break;

                    case ElementEdge.AfterEnd:
                        sibling = node.GetNextNode();
                        break;
                }
            }
            else // direction == LogicalDirection.Backward
            {
                switch (edge)
                {
                    case ElementEdge.BeforeStart:
                        sibling = node.GetPreviousNode();
                        break;

                    case ElementEdge.AfterStart:
                    default:
                        sibling = null;
                        break;

                    case ElementEdge.BeforeEnd:
                        sibling = node.GetLastContainedNode();
                        break;

                    case ElementEdge.AfterEnd:
                        sibling = node;
                        break;
                }
            }

            return (TextTreeNode)sibling;
        }