예제 #1
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);
            } 
        }