Пример #1
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;
        }
Пример #2
0
        // Finds the previous run, returned as a node/edge pair.
        // Returns false if there is no preceding run, in which case node/edge will match the input position.
        // The returned node/edge pair respects the input positon's gravity.
        internal static bool GetPreviousNodeAndEdge(TextTreeNode sourceNode, ElementEdge sourceEdge, bool plainTextOnly, out TextTreeNode node, out ElementEdge edge)
        {
            SplayTreeNode currentNode;
            SplayTreeNode newNode;
            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.GetPreviousNode();
                        if (newNode != null)
                        {
                            // Move to next node/last child;
                            if (newNode is TextTreeTextElementNode)
                            {
                                // Move to previous node last child/previous node
                                edge = ElementEdge.BeforeEnd;
                            }
                            else
                            {
                                // Move to previous previous node/previous node.
                                startedAdjacentToTextNode = newNode is TextTreeTextNode;
                                endedAdjacentToTextNode = startedAdjacentToTextNode && newNode.GetPreviousNode() is TextTreeTextNode;
                            }
                        }
                        else
                        {
                            containingNode = currentNode.GetContainingNode();

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

                    case ElementEdge.AfterStart:
                        newNode = currentNode.GetPreviousNode();
                        if (newNode != null)
                        {
                            endedAdjacentToTextNode = newNode is TextTreeTextNode;

                            // Move to previous node;
                            edge = ElementEdge.AfterEnd;
                        }
                        else
                        {
                            // Move to inner edge of parent.
                            newNode = currentNode.GetContainingNode();
                        }
                        break;

                    case ElementEdge.BeforeEnd:
                        newNode = currentNode.GetLastContainedNode();
                        if (newNode != null)
                        {
                            // Move to penultimate child/last child or inner edge of last child.
                            if (newNode is TextTreeTextElementNode)
                            {
                                edge = ElementEdge.BeforeEnd;
                            }
                            else
                            {
                                startedAdjacentToTextNode = newNode is TextTreeTextNode;
                                endedAdjacentToTextNode = startedAdjacentToTextNode && newNode.GetPreviousNode() is TextTreeTextNode;
                                edge = ElementEdge.BeforeStart;
                            }
                        }
                        else if (currentNode is TextTreeTextElementNode)
                        {
                            // Move to next node.
                            newNode = currentNode;
                            edge = ElementEdge.BeforeStart;
                        }
                        else
                        {
                            Invariant.Assert(currentNode is TextTreeRootNode, "currentNode is expected to be a TextTreeRootNode");
                            // This is the root node, leave newNode null.
                        }
                        break;

                    case ElementEdge.AfterEnd:
                        newNode = currentNode.GetLastContainedNode();
                        if (newNode != null)
                        {
                            // Move to inner edge/last child.
                        }
                        else if (currentNode is TextTreeTextElementNode)
                        {
                            // Move to opposite edge.
                            newNode = currentNode;
                            edge = ElementEdge.AfterStart;
                        }
                        else
                        {
                            // Move to previous node.
                            startedAdjacentToTextNode = currentNode is TextTreeTextNode;
                            edge = ElementEdge.AfterStart;
                            goto case ElementEdge.AfterStart;
                        }
                        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 start.
                if (startedAdjacentToTextNode && endedAdjacentToTextNode && plainTextOnly)
                {
                    newNode = newNode.GetContainingNode();
                    Invariant.Assert(newNode is TextTreeRootNode);

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

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

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

            return (newNode != null);
        }
Пример #3
0
        // Returns the symbol type preceding thisPosition.
        internal static TextPointerContext GetPointerContextBackward(TextTreeNode node, ElementEdge edge)
        {
            TextPointerContext symbolType;
            TextTreeNode previousNode;
            TextTreeNode lastChildNode;

            switch (edge)
            {
                case ElementEdge.BeforeStart:
                    previousNode = (TextTreeNode)node.GetPreviousNode();
                    if (previousNode != null)
                    {
                        symbolType = previousNode.GetPointerContext(LogicalDirection.Backward);
                    }
                    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 BeforeStart.
                        symbolType = (node.GetContainingNode() is TextTreeRootNode) ? TextPointerContext.None : TextPointerContext.ElementStart;
                    }
                    break;

                case ElementEdge.AfterStart:
                    // 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.ElementStart : TextPointerContext.None;
                    break;

                case ElementEdge.BeforeEnd:
                    lastChildNode = (TextTreeNode)node.GetLastContainedNode();
                    if (lastChildNode != null)
                    {
                        symbolType = lastChildNode.GetPointerContext(LogicalDirection.Backward);
                    }
                    else
                    {
                        goto case ElementEdge.AfterStart;
                    }
                    break;

                case ElementEdge.AfterEnd:
                    symbolType = node.GetPointerContext(LogicalDirection.Backward);
                    break;

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

            return symbolType;
        }
Пример #4
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;
        }