// Copies a run of text into a ContentContainer.
        // Returns the next node to examine.
        private TextTreeNode CopyTextNode(TextTreeTextNode textNode, TextTreeNode haltNode, out ContentContainer container)
        {
            SplayTreeNode node;

            char[] text;
            int    count;
            int    symbolOffset;

            Invariant.Assert(textNode != haltNode, "Expect at least one node to copy!");

            symbolOffset = textNode.GetSymbolOffset(this.TextContainer.Generation);

            // Get a count of all the characters we're about to copy.
            count = 0;
            node  = textNode;

            do
            {
                count += textNode.SymbolCount;

                node     = textNode.GetNextNode();
                textNode = node as TextTreeTextNode;
            }while (textNode != null && textNode != haltNode);

            // Allocate storage.
            text = new char[count];

            // Copy the text.
            TextTreeText.ReadText(this.TextContainer.RootTextBlock, symbolOffset, count, text, 0 /*startIndex*/);

            container = new TextContentContainer(text);

            return((TextTreeNode)node);
        }
 // Token: 0x06003D19 RID: 15641 RVA: 0x0011BD4A File Offset: 0x00119F4A
 internal TextTreeFixupNode(TextTreeNode previousNode, ElementEdge previousEdge, TextTreeNode nextNode, ElementEdge nextEdge, TextTreeNode firstContainedNode, TextTreeNode lastContainedNode)
 {
     this._previousNode       = previousNode;
     this._previousEdge       = previousEdge;
     this._nextNode           = nextNode;
     this._nextEdge           = nextEdge;
     this._firstContainedNode = firstContainedNode;
     this._lastContainedNode  = lastContainedNode;
 }
 // Creates a new TextTreeFixupNode instance.
 // This ctor should only be called when extracting a single TextTreeTextElementNode.
 // previousNode/Edge should point to the node TextPositions will
 // move to after synchronizing against the deleted content.
 // first/lastContainedNode point to the first and last contained nodes
 // of an extracted element node.  Positions may move into these nodes.
 internal TextTreeFixupNode(TextTreeNode previousNode, ElementEdge previousEdge, TextTreeNode nextNode, ElementEdge nextEdge,
                            TextTreeNode firstContainedNode, TextTreeNode lastContainedNode)
 {
     _previousNode = previousNode;
     _previousEdge = previousEdge;
     _nextNode = nextNode;
     _nextEdge = nextEdge;
     _firstContainedNode = firstContainedNode;
     _lastContainedNode = lastContainedNode;
 }
        // Token: 0x06003D0D RID: 15629 RVA: 0x0011B8BC File Offset: 0x00119ABC
        internal TextTreeDeleteContentUndoUnit(TextContainer tree, TextPointer start, TextPointer end) : base(tree, start.GetSymbolOffset())
        {
            start.DebugAssertGeneration();
            end.DebugAssertGeneration();
            Invariant.Assert(start.GetScopingNode() == end.GetScopingNode(), "start/end have different scope!");
            TextTreeNode adjacentNode  = start.GetAdjacentNode(LogicalDirection.Forward);
            TextTreeNode adjacentNode2 = end.GetAdjacentNode(LogicalDirection.Forward);

            this._content = this.CopyContent(adjacentNode, adjacentNode2);
        }
Exemple #5
0
        // Dumps a node and all contained nodes "flat" -- in notation similar to xaml.
        internal static void DumpFlat(TextTreeNode node)
        {
            Debug.Write("<" + GetFlatPrefix(node) + node.DebugId);

            if (node.ContainedNode != null)
            {
                Debug.Write(">");
                DumpNodeFlatRecursive(node.GetFirstContainedNode());
                Debug.WriteLine("</" + GetFlatPrefix(node) + node.DebugId + ">");
            }
            else
            {
                Debug.WriteLine("/>");
            }
        }
Exemple #6
0
        // Dumps a node and all contained nodes "flat" -- in notation similar to xaml.
        internal static void DumpFlat(TextTreeNode node)
        {
            Debug.Write("<" + GetFlatPrefix(node) + node.DebugId);

            if (node.ContainedNode != null)
            {
                Debug.Write(">");
                DumpNodeFlatRecursive(node.GetFirstContainedNode());
                Debug.WriteLine("</" + GetFlatPrefix(node) + node.DebugId + ">");
            }
            else
            {
                Debug.WriteLine("/>");
            }
        }
        //------------------------------------------------------
        //
        //  Private Methods
        //
        //------------------------------------------------------

        #region Private Methods

        // Walks the tree from node to the end of its sibling list,
        // copying content along the way,
        // halting when/if haltNode is encountered. haltNode may be
        // null, in which case we walk to the end of the sibling list.
        //
        // Returns a ContentContainer holding a deep copy of all content
        // walked.
        //
        // This method is called recursively when TextElement nodes
        // are encountered.
        private ContentContainer CopyContent(TextTreeNode node, TextTreeNode haltNode)
        {
            ContentContainer        firstContainer;
            ContentContainer        container;
            ContentContainer        nextContainer;
            TextTreeTextNode        textNode;
            TextTreeObjectNode      objectNode;
            TextTreeTextElementNode elementNode;

            firstContainer = null;
            container      = null;

            while (node != haltNode && node != null)
            {
                textNode = node as TextTreeTextNode;
                if (textNode != null)
                {
                    node = CopyTextNode(textNode, haltNode, out nextContainer);
                }
                else
                {
                    objectNode = node as TextTreeObjectNode;
                    if (objectNode != null)
                    {
                        node = CopyObjectNode(objectNode, out nextContainer);
                    }
                    else
                    {
                        Invariant.Assert(node is TextTreeTextElementNode, "Unexpected TextTreeNode type!");
                        elementNode = (TextTreeTextElementNode)node;

                        node = CopyElementNode(elementNode, out nextContainer);
                    }
                }

                if (container == null)
                {
                    firstContainer = nextContainer;
                }
                else
                {
                    container.NextContainer = nextContainer;
                }
                container = nextContainer;
            }

            return(firstContainer);
        }
        // Token: 0x06003D13 RID: 15635 RVA: 0x0011BAC8 File Offset: 0x00119CC8
        private TextTreeNode CopyTextNode(TextTreeTextNode textNode, TextTreeNode haltNode, out TextTreeDeleteContentUndoUnit.ContentContainer container)
        {
            Invariant.Assert(textNode != haltNode, "Expect at least one node to copy!");
            int           symbolOffset = textNode.GetSymbolOffset(base.TextContainer.Generation);
            int           num          = 0;
            SplayTreeNode nextNode;

            do
            {
                num     += textNode.SymbolCount;
                nextNode = textNode.GetNextNode();
                textNode = (nextNode as TextTreeTextNode);
            }while (textNode != null && textNode != haltNode);
            char[] array = new char[num];
            TextTreeText.ReadText(base.TextContainer.RootTextBlock, symbolOffset, num, array, 0);
            container = new TextTreeDeleteContentUndoUnit.TextContentContainer(array);
            return((TextTreeNode)nextNode);
        }
 // Token: 0x06003D12 RID: 15634 RVA: 0x0011BA44 File Offset: 0x00119C44
 private TextTreeDeleteContentUndoUnit.ContentContainer CopyContent(TextTreeNode node, TextTreeNode haltNode)
 {
     TextTreeDeleteContentUndoUnit.ContentContainer result           = null;
     TextTreeDeleteContentUndoUnit.ContentContainer contentContainer = null;
     while (node != haltNode && node != null)
     {
         TextTreeTextNode textTreeTextNode = node as TextTreeTextNode;
         TextTreeDeleteContentUndoUnit.ContentContainer contentContainer2;
         if (textTreeTextNode != null)
         {
             node = this.CopyTextNode(textTreeTextNode, haltNode, out contentContainer2);
         }
         else
         {
             TextTreeObjectNode textTreeObjectNode = node as TextTreeObjectNode;
             if (textTreeObjectNode != null)
             {
                 node = this.CopyObjectNode(textTreeObjectNode, out contentContainer2);
             }
             else
             {
                 Invariant.Assert(node is TextTreeTextElementNode, "Unexpected TextTreeNode type!");
                 TextTreeTextElementNode elementNode = (TextTreeTextElementNode)node;
                 node = this.CopyElementNode(elementNode, out contentContainer2);
             }
         }
         if (contentContainer == null)
         {
             result = contentContainer2;
         }
         else
         {
             contentContainer.NextContainer = contentContainer2;
         }
         contentContainer = contentContainer2;
     }
     return(result);
 }
        //------------------------------------------------------
        //
        //  Constructors
        //
        //------------------------------------------------------

        #region Constructors

        // Creates a new TextTreeFixupNode instance.
        // previousNode/Edge should point to the node TextPositions will
        // move to after synchronizing against the deleted content.
        internal TextTreeFixupNode(TextTreeNode previousNode, ElementEdge previousEdge, TextTreeNode nextNode, ElementEdge nextEdge) :
                    this(previousNode, previousEdge, nextNode, nextEdge, null, null)
        {
        }
        // Copies a run of text into a ContentContainer.
        // Returns the next node to examine.
        private TextTreeNode CopyTextNode(TextTreeTextNode textNode, TextTreeNode haltNode, out ContentContainer container)
        {
            SplayTreeNode node;
            char[] text;
            int count;
            int symbolOffset;

            Invariant.Assert(textNode != haltNode, "Expect at least one node to copy!");

            symbolOffset = textNode.GetSymbolOffset(this.TextContainer.Generation);

            // Get a count of all the characters we're about to copy.
            count = 0;
            node = textNode;

            do
            {
                count += textNode.SymbolCount;

                node = textNode.GetNextNode();
                textNode = node as TextTreeTextNode;
            }
            while (textNode != null && textNode != haltNode);

            // Allocate storage.
            text = new char[count];

            // Copy the text.
            TextTreeText.ReadText(this.TextContainer.RootTextBlock, symbolOffset, count, text, 0 /*startIndex*/);

            container = new TextContentContainer(text);

            return (TextTreeNode)node;
        }
Exemple #12
0
        // Returns the symbol offset within the TextContainer of this Position.
        internal static int GetSymbolOffset(TextContainer tree, TextTreeNode node, ElementEdge edge)
        {
            int offset;

            switch (edge)
            {
                case ElementEdge.BeforeStart:
                    offset = node.GetSymbolOffset(tree.Generation);
                    break;

                case ElementEdge.AfterStart:
                    offset = node.GetSymbolOffset(tree.Generation) + 1;
                    break;

                case ElementEdge.BeforeEnd:
                    offset = node.GetSymbolOffset(tree.Generation) + node.SymbolCount - 1;
                    break;

                case ElementEdge.AfterEnd:
                    offset = node.GetSymbolOffset(tree.Generation) + node.SymbolCount;
                    break;

                default:
                    Invariant.Assert(false, "Unknown value for position edge");
                    offset = 0;
                    break;
            }

            return offset;
        }
Exemple #13
0
        // Fires Change events for IMELeftEdgeCharCount deltas to a node after it
        // moves out of position such that it is no longer the leftmost child 
        // of its parent.
        private void RaiseEventForFormerFirstIMEVisibleNode(TextTreeNode node)
        {
            TextPointer startEdgePosition = new TextPointer(this, node, ElementEdge.BeforeStart); 

            // Next node was the old first node.  Its IMECharCount 
            // just bumped up, report that. 
            AddChange(startEdgePosition, /* symbolCount */ 0, /* IMECharCount */ 1, PrecursorTextChangeType.ContentAdded);
        } 
Exemple #14
0
        internal static TextTreeNode GetAdjacentNode(TextTreeNode node, ElementEdge edge, LogicalDirection direction)
        {
            TextTreeNode adjacentNode;

            adjacentNode = GetAdjacentSiblingNode(node, edge, direction);

            if (adjacentNode == null)
            {
                // We're the first or last child, try the parent.
                if (edge == ElementEdge.AfterStart || edge == ElementEdge.BeforeEnd)
                {
                    adjacentNode = node;
                }
                else
                {
                    adjacentNode = (TextTreeNode)node.GetContainingNode();
                }
            }

            return adjacentNode;
        }
Exemple #15
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;
        }
Exemple #16
0
        // Inc/decs the position ref counts on TextTreeTextNodes as the navigator
        // is repositioned.
        // If the new ref is to a TextTreeTextNode, the node may be split.
        // Returns the actual node referenced, which will always be newNode,
        // unless newNode is a TextTreeTextNode that gets split.  The caller
        // should use the returned node to position navigators.
        private TextTreeNode AdjustRefCounts(TextTreeNode newNode, ElementEdge newNodeEdge, TextTreeNode oldNode, ElementEdge oldNodeEdge)
        {
            TextTreeNode node;

            // This test should walk the tree upwards to catch all errors...probably not worth the slowdown though.
            Invariant.Assert(oldNode.ParentNode == null || oldNode.IsChildOfNode(oldNode.ParentNode), "Trying to add ref a dead node!");
            Invariant.Assert(newNode.ParentNode == null || newNode.IsChildOfNode(newNode.ParentNode), "Trying to add ref a dead node!");

            node = newNode;

            if (newNode != oldNode || newNodeEdge != oldNodeEdge)
            {
                node = newNode.IncrementReferenceCount(newNodeEdge);
                oldNode.DecrementReferenceCount(oldNodeEdge);
            }

            return node;
        }
Exemple #17
0
        // Called by the TextPointer ctor.  Initializes this instance.
        private void Initialize(TextContainer tree, TextTreeNode node, ElementEdge edge, LogicalDirection gravity, uint generation,
            bool caretUnitBoundaryCache, bool isCaretUnitBoundaryCacheValid, uint layoutGeneration)
        {
            _tree = tree;

            // Fixup of the target node based on gravity.
            // Positions always cling to a node edge that matches their gravity,
            // so that insert ops never affect the position.
            RepositionForGravity(ref node, ref edge, gravity);

            SetNodeAndEdge(node.IncrementReferenceCount(edge), edge);
            _generation = generation;

            this.CaretUnitBoundaryCache = caretUnitBoundaryCache;
            this.IsCaretUnitBoundaryCacheValid = isCaretUnitBoundaryCacheValid;
            _layoutGeneration = layoutGeneration;

            VerifyFlags();
            tree.AssertTree();
            AssertState();
        }
Exemple #18
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;
        }
Exemple #19
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;
        }
Exemple #20
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);
        }
Exemple #21
0
 // Dumps a node and all its children.
 internal static void Dump(TextTreeNode node)
 {
     DumpNodeRecursive(node, 0);
 }
Exemple #22
0
        internal bool GetPreviousNodeAndEdge(out TextTreeNode node, out ElementEdge edge)
        {
            DebugAssertGeneration();

            return GetPreviousNodeAndEdge(_node, this.Edge, _tree.PlainTextOnly, out node, out edge);
        }
Exemple #23
0
        // Positions this navigator at a node/edge pair.
        // Node/edge are adjusted based on the current gravity.
        private void MoveToNode(TextContainer tree, TextTreeNode node, ElementEdge edge)
        {
            RepositionForGravity(ref node, ref edge, GetGravityInternal());

            _tree = tree;
            SetNodeAndEdge(AdjustRefCounts(node, edge, _node, this.Edge), edge);
            _generation = tree.PositionGeneration;
        }
Exemple #24
0
        // Fires Change events for IMELeftEdgeCharCount deltas to a node after it
        // moves into position such that it is the leftmost child
        // of its parent. 
        private void RaiseEventForNewFirstIMEVisibleNode(TextTreeNode node)
        { 
            TextPointer startEdgePosition = new TextPointer(this, node, ElementEdge.BeforeStart); 

            // node was the old second node.  Its IMECharCount 
            // just dropped down, report that.
            AddChange(startEdgePosition, /* symbolCount */ 0, /* IMECharCount */ 1, PrecursorTextChangeType.ContentRemoved);
        }
Exemple #25
0
        // Repositions the TextPointer and clears any relevant caches.
        private void SetNodeAndEdge(TextTreeNode node, ElementEdge edge)
        {
            Invariant.Assert(edge == ElementEdge.BeforeStart ||
                             edge == ElementEdge.AfterStart ||
                             edge == ElementEdge.BeforeEnd ||
                             edge == ElementEdge.AfterEnd);

            _node = node;
            _flags = (_flags & ~(uint)Flags.EdgeMask) | (uint)edge;
            VerifyFlags();

            // Always clear the caret unit boundary cache when we move to a new position.
            this.IsCaretUnitBoundaryCacheValid = false;
        }
Exemple #26
0
        internal static TextTreeNode GetScopingNode(TextTreeNode node, ElementEdge edge)
        {
            TextTreeNode scopingNode;

            switch (edge)
            {
                case ElementEdge.BeforeStart:
                case ElementEdge.AfterEnd:
                    scopingNode = (TextTreeNode)node.GetContainingNode();
                    break;

                case ElementEdge.AfterStart:
                case ElementEdge.BeforeEnd:
                default:
                    scopingNode = node;
                    break;
            }

            return scopingNode;
        }
Exemple #27
0
        // Finds a node/edge pair matching a given char offset in the tree.
        // If the pair matches a character within a text node, the text node is split. 
        internal void GetNodeAndEdgeAtCharOffset(int charOffset, out TextTreeNode node, out ElementEdge edge) 
        {
            int nodeCharOffset; 
            int siblingTreeCharOffset;
            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(charOffset >= 0 && charOffset <= this.IMECharCount, "Bogus char offset!"); 

            if (this.IMECharCount == 0) 
            {
                node = null;
                edge = ElementEdge.BeforeStart;
                return; 
            }
 
            // 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;
            nodeCharOffset = 0; 
 
            // Each iteration walks through one tree.
            while (true) 
            {
                int leftEdgeCharCount = 0;
                TextTreeTextElementNode textElementNode = node as TextTreeTextElementNode;
 
                if (textElementNode != null)
                { 
                    leftEdgeCharCount = textElementNode.IMELeftEdgeCharCount; 
                    if (leftEdgeCharCount > 0)
                    { 
                        if (charOffset == nodeCharOffset)
                        {
                            edge = ElementEdge.BeforeStart;
                            break; 
                        }
                        if (charOffset == nodeCharOffset + leftEdgeCharCount) 
                        { 
                            edge = ElementEdge.AfterStart;
                            break; 
                        }
                    }
                }
                else if (node is TextTreeTextNode || node is TextTreeObjectNode) 
                {
                    if (charOffset == nodeCharOffset) 
                    { 
                        edge = ElementEdge.BeforeStart;
                        checkZeroWidthNode = true; 
                        break;
                    }
                    if (charOffset == nodeCharOffset + node.IMECharCount)
                    { 
                        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....
                    node = ((TextTreeTextNode)node).Split(charOffset - nodeCharOffset, ElementEdge.AfterEnd); 
                    edge = ElementEdge.BeforeStart;
                    break;
                }
 
                // Need to look into one of the child nodes.
                node = (TextTreeNode)node.ContainedNode; 
                nodeCharOffset += leftEdgeCharCount; // Skip over the parent element start edge. 

                // Walk down the sibling tree. 
                node = (TextTreeNode)node.GetSiblingAtCharOffset(charOffset - nodeCharOffset, out siblingTreeCharOffset);
                nodeCharOffset += siblingTreeCharOffset;
            }
 
            // If we're on a zero-width TextTreeTextNode we need some special handling.
            if (checkZeroWidthNode) 
            { 
                node = (TextTreeNode)AdjustForZeroWidthNode(node, edge);
            } 
        }
Exemple #28
0
 // Dumps a node and all its children.
 internal static void Dump(TextTreeNode node)
 {
     DumpNodeRecursive(node, 0);
 }
Exemple #29
0
        // 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; 
        }
Exemple #30
0
        // Increments the position reference counts on nodes immediately
        // preceding and following a delete operation.
        //
        // Whenever we delete a span of content, we have to worry about any 
        // positions still referencing the deleted content.  They have enough
        // information to find their way back to the surrounding nodes, but 
        // we need to increment the ref count on those nodes now so that they'll 
        // still be around when the positions need them.
        // 
        // Because incrementing a ref count on a text node edge may involve
        // splitting the text node, this method takes refs to nodes and will
        // update the refs if a node is split.
        // 
        // Called by DeleteContentFromSiblingTree and ExtractElementInternal.
        private void AdjustRefCountsForContentDelete(ref TextTreeNode previousNode, ElementEdge previousEdge, 
                                                     ref TextTreeNode nextNode, ElementEdge nextEdge, 
                                                     TextTreeNode middleSubTree)
        { 
            bool leftEdgeReferenceCount;
            bool rightEdgeReferenceCount;

            leftEdgeReferenceCount = false; 
            rightEdgeReferenceCount = false;
 
            // Get the count of all positions referencing text node edges across the deleted content. 
            GetReferenceCounts((TextTreeNode)middleSubTree.GetMinSibling(), ref leftEdgeReferenceCount, ref rightEdgeReferenceCount);
 
            previousNode = previousNode.IncrementReferenceCount(previousEdge, rightEdgeReferenceCount);
            nextNode = nextNode.IncrementReferenceCount(nextEdge, leftEdgeReferenceCount);
        }
Exemple #31
0
 // Returns the TextTreeTextNode in the direction indicated bordering
 // a TextPointer, or null if no such node exists.
 internal static TextTreeTextNode GetAdjacentTextNodeSibling(TextTreeNode node, ElementEdge edge, LogicalDirection direction)
 {
     return GetAdjacentSiblingNode(node, edge, direction) as TextTreeTextNode;
 }
        //------------------------------------------------------
        //
        //  Private Methods
        //
        //------------------------------------------------------

        #region Private Methods

        // Walks the tree from node to the end of its sibling list,
        // copying content along the way,
        // halting when/if haltNode is encountered. haltNode may be
        // null, in which case we walk to the end of the sibling list.
        //
        // Returns a ContentContainer holding a deep copy of all content
        // walked.
        //
        // This method is called recursively when TextElement nodes
        // are encountered.
        private ContentContainer CopyContent(TextTreeNode node, TextTreeNode haltNode)
        {
            ContentContainer firstContainer;
            ContentContainer container;
            ContentContainer nextContainer;
            TextTreeTextNode textNode;
            TextTreeObjectNode objectNode;
            TextTreeTextElementNode elementNode;

            firstContainer = null;
            container = null;

            while (node != haltNode && node != null)
            {
                textNode = node as TextTreeTextNode;
                if (textNode != null)
                {
                    node = CopyTextNode(textNode, haltNode, out nextContainer);
                }
                else
                {
                    objectNode = node as TextTreeObjectNode;
                    if (objectNode != null)
                    {
                        node = CopyObjectNode(objectNode, out nextContainer);
                    }
                    else
                    {
                        Invariant.Assert(node is TextTreeTextElementNode, "Unexpected TextTreeNode type!");
                        elementNode = (TextTreeTextElementNode)node;

                        node = CopyElementNode(elementNode, out nextContainer);
                    }
                }

                if (container == null)
                {
                    firstContainer = nextContainer;
                }
                else
                {
                    container.NextContainer = nextContainer;
                }
                container = nextContainer;
            }

            return firstContainer;
        }
Exemple #33
0
        // Increments the position reference counts on nodes immediately 
        // preceding and following a delete operation on a single TextElementNode.
        // This is similar to AdjustRefCountsForContentDelete, except that 
        // in this case we deleting a single node, and positions at the
        // BeforeStart/AfterEnd edges may move into contained content, which
        // is still live in the tree.
        // 
        // Whenever we delete a span of content, we have to worry about any
        // positions still referencing the deleted content.  They have enough 
        // information to find their way back to the surrounding nodes, but 
        // we need to increment the ref count on those nodes now so that they'll
        // still be around when the positions need them. 
        //
        // Because incrementing a ref count on a text node edge may involve
        // splitting the text node, this method takes refs to nodes and will
        // update the refs if a node is split. 
        //
        // Called by ExtractElementFromSiblingTree. 
        private void AdjustRefCountsForShallowDelete(ref TextTreeNode previousNode, ElementEdge previousEdge, 
                                                     ref TextTreeNode nextNode,ElementEdge nextEdge,
                                                     ref TextTreeNode firstContainedNode, ref TextTreeNode lastContainedNode, 
                                                     TextTreeTextElementNode extractedElementNode)
        {
            previousNode = previousNode.IncrementReferenceCount(previousEdge, extractedElementNode.AfterStartReferenceCount);
 
            nextNode = nextNode.IncrementReferenceCount(nextEdge, extractedElementNode.BeforeEndReferenceCount);
 
            if (firstContainedNode != null) 
            {
                firstContainedNode = firstContainedNode.IncrementReferenceCount(ElementEdge.BeforeStart, extractedElementNode.BeforeStartReferenceCount); 
            }
            else
            {
                nextNode = nextNode.IncrementReferenceCount(nextEdge, extractedElementNode.BeforeStartReferenceCount); 
            }
 
            if (lastContainedNode != null) 
            {
                lastContainedNode = lastContainedNode.IncrementReferenceCount(ElementEdge.AfterEnd, extractedElementNode.AfterEndReferenceCount); 
            }
            else
            {
                previousNode = previousNode.IncrementReferenceCount(previousEdge, extractedElementNode.AfterEndReferenceCount); 
            }
        } 
Exemple #34
0
        //------------------------------------------------------
        //
        //  Constructors
        //
        //------------------------------------------------------

        #region Constructors

        // Creates a new TextTreeFixupNode instance.
        // previousNode/Edge should point to the node TextPositions will
        // move to after synchronizing against the deleted content.
        internal TextTreeFixupNode(TextTreeNode previousNode, ElementEdge previousEdge, TextTreeNode nextNode, ElementEdge nextEdge) :
            this(previousNode, previousEdge, nextNode, nextEdge, null, null)
        {
        }
Exemple #35
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; 
        } 
Exemple #36
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;
        }
Exemple #37
0
        private void AssertTreeRecursive(TextTreeNode containingNode)
        {
            TextTreeNode node; 

            if (containingNode.ContainedNode == null) 
            { 
                Invariant.Assert(containingNode.ParentNode == null || containingNode.ParentNode.ContainedNode == containingNode);
                return; 
            }

            Invariant.Assert(containingNode.ContainedNode.ParentNode == containingNode);
 
            for (node = (TextTreeNode)containingNode.ContainedNode.GetMinSibling(); node != null; node = (TextTreeNode)node.GetNextNode())
            { 
                if (node != containingNode.ContainedNode) 
                {
                    Invariant.Assert(node.ParentNode.LeftChildNode == node || node.ParentNode.RightChildNode == node); 
                }
                Invariant.Assert(node.SymbolCount >= 0);
                if (node.SymbolCount == 0)
                { 
                    Invariant.Assert(node is TextTreeTextNode);
                    Invariant.Assert(node.BeforeStartReferenceCount > 0 || node.AfterEndReferenceCount > 0); 
                } 

                if (node.ContainedNode != null) 
                {
                    AssertTreeRecursive((TextTreeNode)node.ContainedNode);
                }
            } 
        }
Exemple #38
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); 
        }
Exemple #39
0
 // Creates a new TextPointer instance.
 internal TextPointer(TextContainer tree, TextTreeNode node, ElementEdge edge, LogicalDirection direction)
 {
     Initialize(tree, node, edge, direction, tree.PositionGeneration, false, false, tree.LayoutGeneration);
 }