예제 #1
0
        // Finds a node/edge pair matching a given symbol offset in the tree.
        // If the pair matches a character within a text node, the text node is split. 
        internal void GetNodeAndEdgeAtOffset(int offset, bool splitNode, out SplayTreeNode node, out ElementEdge edge)
        { 
            int nodeOffset; 
            int siblingTreeOffset;
            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(offset >= 1 && offset <= this.InternalSymbolCount - 1, "Bogus symbol offset!");
 
            // 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;
            nodeOffset = 0; 
 
            // Each iteration walks through one tree.
            while (true) 
            {
                // While we're at it, fix up the node's SymbolOffsetCache,
                // since we're doing the work already.
                Invariant.Assert(node.Generation != _rootNode.Generation || 
                             node.SymbolOffsetCache == -1 ||
                             node.SymbolOffsetCache == nodeOffset, "Bad node offset cache!"); 
 
                node.Generation = _rootNode.Generation;
                node.SymbolOffsetCache = nodeOffset; 

                if (offset == nodeOffset)
                {
                    edge = ElementEdge.BeforeStart; 
                    checkZeroWidthNode = true;
                    break; 
                } 
                if (node is TextTreeRootNode || node is TextTreeTextElementNode)
                { 
                    if (offset == nodeOffset + 1)
                    {
                        edge = ElementEdge.AfterStart;
                        break; 
                    }
                    if (offset == nodeOffset + node.SymbolCount - 1) 
                    { 
                        edge = ElementEdge.BeforeEnd;
                        break; 
                    }
                }
                if (offset == nodeOffset + node.SymbolCount)
                { 
                    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.... 
                    if (splitNode)
                    { 
                        node = ((TextTreeTextNode)node).Split(offset - nodeOffset, ElementEdge.AfterEnd);
                    }
                    edge = ElementEdge.BeforeStart;
                    break; 
                }
 
                // Need to look into one of the child nodes. 
                node = node.ContainedNode;
                nodeOffset += 1; // Skip over the parent element start edge. 

                // Walk down the sibling tree.
                node = node.GetSiblingAtOffset(offset - nodeOffset, out siblingTreeOffset);
                nodeOffset += siblingTreeOffset; 
            }
 
            // If we're on a zero-width TextTreeTextNode we need some special handling. 
            if (checkZeroWidthNode)
            { 
                node = AdjustForZeroWidthNode(node, edge);
            }
        }