Пример #1
0
        // Increments the reference count of TextPositions referencing a
        // particular edge of this node.
        //
        // If this node is a TextTreeTextNode, the increment may split the node
        // and the return value is guaranteed to be the node containing the referenced
        // edge (which may be a new node).  Otherwise this method always returns
        // the original node.
        internal virtual TextTreeNode IncrementReferenceCount(ElementEdge edge, int delta)
        {
            Invariant.Assert(delta >= 0);

            if (delta > 0)
            {
                switch (edge)
                {
                case ElementEdge.BeforeStart:
                    this.BeforeStartReferenceCount = true;
                    break;

                case ElementEdge.AfterStart:
                    this.AfterStartReferenceCount = true;
                    break;

                case ElementEdge.BeforeEnd:
                    this.BeforeEndReferenceCount = true;
                    break;

                case ElementEdge.AfterEnd:
                    this.AfterEndReferenceCount = true;
                    break;

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

            return(this);
        }
Пример #2
0
        internal int GetOffsetFromEdge(ElementEdge edge)
        {
            int offset;

            switch (edge)
            {
            case ElementEdge.BeforeStart:
                offset = 0;
                break;

            case ElementEdge.AfterStart:
                offset = 1;
                break;

            case ElementEdge.BeforeEnd:
                offset = this.SymbolCount - 1;
                break;

            case ElementEdge.AfterEnd:
                offset = this.SymbolCount;
                break;

            default:
                offset = 0;
                Invariant.Assert(false, "Bad ElementEdge value!");
                break;
            }

            return(offset);
        }
Пример #3
0
        // Token: 0x06003E0B RID: 15883 RVA: 0x0011D230 File Offset: 0x0011B430
        internal TextTreeTextNode Split(int localOffset, ElementEdge edge)
        {
            Invariant.Assert(this._symbolCount > 0, "Splitting a zero-width TextNode!");
            Invariant.Assert(localOffset >= 0 && localOffset <= this._symbolCount, "Bad localOffset!");
            Invariant.Assert(edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd, "Bad edge parameter!");
            TextTreeTextNode textTreeTextNode = new TextTreeTextNode();

            textTreeTextNode._generation = this._generation;
            base.Splay();
            ElementEdge      edge2;
            TextTreeTextNode result;

            if (this._positionRefCount > 0 && this._referencedEdge == ElementEdge.BeforeStart)
            {
                textTreeTextNode._symbolOffsetCache = ((this._symbolOffsetCache == -1) ? -1 : (this._symbolOffsetCache + localOffset));
                textTreeTextNode._symbolCount       = this._symbolCount - localOffset;
                this._symbolCount = localOffset;
                edge2             = ElementEdge.AfterEnd;
                result            = ((edge == ElementEdge.BeforeStart) ? this : textTreeTextNode);
            }
            else
            {
                textTreeTextNode._symbolOffsetCache = this._symbolOffsetCache;
                textTreeTextNode._symbolCount       = localOffset;
                this._symbolOffsetCache             = ((this._symbolOffsetCache == -1) ? -1 : (this._symbolOffsetCache + localOffset));
                this._symbolCount -= localOffset;
                edge2              = ElementEdge.BeforeStart;
                result             = ((edge == ElementEdge.BeforeStart) ? textTreeTextNode : this);
            }
            Invariant.Assert(this._symbolCount >= 0);
            Invariant.Assert(textTreeTextNode._symbolCount >= 0);
            textTreeTextNode.InsertAtNode(this, edge2);
            return(result);
        }
 // Token: 0x06003EF0 RID: 16112 RVA: 0x0011F3A4 File Offset: 0x0011D5A4
 internal static void VerifyElementEdge(ElementEdge edge, string param)
 {
     if (edge != ElementEdge.BeforeStart && edge != ElementEdge.AfterStart && edge != ElementEdge.BeforeEnd && edge != ElementEdge.AfterEnd)
     {
         throw new InvalidEnumArgumentException(param, (int)edge, typeof(ElementEdge));
     }
 }
Пример #5
0
        // Token: 0x06003D4E RID: 15694 RVA: 0x0011C0B8 File Offset: 0x0011A2B8
        internal int GetOffsetFromEdge(ElementEdge edge)
        {
            switch (edge)
            {
            case ElementEdge.BeforeStart:
                return(0);

            case ElementEdge.AfterStart:
                return(1);

            case ElementEdge.BeforeStart | ElementEdge.AfterStart:
                break;

            case ElementEdge.BeforeEnd:
                return(this.SymbolCount - 1);

            default:
                if (edge == ElementEdge.AfterEnd)
                {
                    return(this.SymbolCount);
                }
                break;
            }
            int result = 0;

            Invariant.Assert(false, "Bad ElementEdge value!");
            return(result);
        }
Пример #6
0
        /// <summary>
        /// <see cref="ITextPointer.MoveToElementEdge"/>
        /// </summary>
        void ITextPointer.MoveToElementEdge(ElementEdge edge)
        {
            ValidationHelper.VerifyElementEdge(edge, "edge");
            Debug.Assert(!_isFrozen, "Can't reposition a frozen pointer!");

            FixedElement e = _flowPosition.GetScopingElement();

            if (!e.IsTextElement)
            {
                throw new InvalidOperationException(SR.Get(SRID.NoElementObject));
            }

            switch (edge)
            {
            case ElementEdge.BeforeStart:
                _flowPosition = (FlowPosition)e.Start.FlowPosition.Clone();
                _flowPosition.Move(-1);
                break;

            case ElementEdge.AfterStart:
                _flowPosition = (FlowPosition)e.Start.FlowPosition.Clone();
                break;

            case ElementEdge.BeforeEnd:
                _flowPosition = (FlowPosition)e.End.FlowPosition.Clone();
                break;

            case ElementEdge.AfterEnd:
                _flowPosition = (FlowPosition)e.End.FlowPosition.Clone();
                _flowPosition.Move(1);
                break;
            }
        }
        // Token: 0x060035C3 RID: 13763 RVA: 0x000F446C File Offset: 0x000F266C
        internal void InsertAtNode(SplayTreeNode positionNode, ElementEdge edge)
        {
            if (edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd)
            {
                this.InsertAtNode(positionNode, edge == ElementEdge.BeforeStart);
                return;
            }
            SplayTreeNode splayTreeNode;
            bool          insertBefore;

            if (edge == ElementEdge.AfterStart)
            {
                splayTreeNode = positionNode.GetFirstContainedNode();
                insertBefore  = true;
            }
            else
            {
                splayTreeNode = positionNode.GetLastContainedNode();
                insertBefore  = false;
            }
            if (splayTreeNode == null)
            {
                positionNode.ContainedNode = this;
                this.ParentNode            = positionNode;
                Invariant.Assert(this.LeftChildNode == null);
                Invariant.Assert(this.RightChildNode == null);
                Invariant.Assert(this.LeftSymbolCount == 0);
                return;
            }
            this.InsertAtNode(splayTreeNode, insertBefore);
        }
Пример #8
0
        // Decrements the reference count of TextPositions referencing this
        // node.
        //
        // Be careful!  If this node is a TextTreeTextNode, the decrement may
        // cause a merge, and this node may be removed from the tree.
        internal virtual void DecrementReferenceCount(ElementEdge edge)
        {
#if INT_EDGE_REF_COUNT
            switch (edge)
            {
            case ElementEdge.BeforeStart:
                this.BeforeStartReferenceCount--;
                Invariant.Assert(this.BeforeStartReferenceCount >= 0, "Bad BeforeStart ref count!");
                break;

            case ElementEdge.AfterStart:
                this.AfterStartReferenceCount--;
                Invariant.Assert(this.AfterStartReferenceCount >= 0, "Bad AfterStart ref count!");
                break;

            case ElementEdge.BeforeEnd:
                this.BeforeEndReferenceCount--;
                Invariant.Assert(this.BeforeEndReferenceCount >= 0, "Bad BeforeEnd ref count!");
                break;

            case ElementEdge.AfterEnd:
                this.AfterEndReferenceCount--;
                Invariant.Assert(this.AfterEndReferenceCount >= 0, "Bad AfterEnd ref count!");
                break;

            default:
                Invariant.Assert(false, "Bad ElementEdge value!");
                break;
            }
#endif // INT_EDGE_REF_COUNT
        }
 // 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;
 }
Пример #11
0
 // Token: 0x06003E0A RID: 15882 RVA: 0x0011D1DC File Offset: 0x0011B3DC
 internal override void DecrementReferenceCount(ElementEdge edge)
 {
     Invariant.Assert(edge == this._referencedEdge, "Bad edge decrement!");
     this._positionRefCount--;
     Invariant.Assert(this._positionRefCount >= 0, "Bogus PositionRefCount! ");
     if (this._positionRefCount == 0)
     {
         this.Merge();
     }
 }
Пример #12
0
        // Increments a count of the number of TextPositions and TextNavigators
        // referencing this node.  Called when positions are created or moved.
        // Returns the actual node referenced -- a new node will be created if
        // there are already references to this node's other edge.
        internal override TextTreeNode IncrementReferenceCount(ElementEdge edge, int delta)
        {
            TextTreeTextNode node;
            TextTreeTextNode mergeNode;

            Invariant.Assert(delta >= 0);
            Invariant.Assert(edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd, "Bad edge ref to TextTreeTextNode!");

            if (delta == 0)
            {
                return(this);
            }

            if (_positionRefCount > 0 && edge != _referencedEdge)
            {
                // We need to split off a node to cover the new edge.
                node = Split(edge == ElementEdge.BeforeStart ? 0 : _symbolCount, edge);

                node._referencedEdge    = edge;
                node._positionRefCount += delta;

                // It's possible we need to merge a neighbor node.
                // This happens when someone calls TextContainer.GetNodeAndEdgeAtOffset,
                // which splits a text node into two non-empty nodes.  We can't merge
                // immediately, because we don't know which of the two nodes will
                // get an additional ref.
                // If the unreferenced node of the pair gets the new reference,
                // there no possibility for a merge.  Otherwise, we have to split
                // again on the already referenced node and end up here.
                if (edge == ElementEdge.BeforeStart)
                {
                    // If node B has no references it can merge with node A.
                    // <A ""/><B "x"/><newNode ""/><this "x".>
                    mergeNode = node.GetPreviousNode() as TextTreeTextNode;
                }
                else
                {
                    // If node A has no references it can merge with node B.
                    // <this "x"/><newNode ""/><A "x"/><B ""/>
                    mergeNode = node.GetNextNode() as TextTreeTextNode;
                }
                if (mergeNode != null && mergeNode._positionRefCount == 0)
                {
                    mergeNode.Merge();
                }
            }
            else
            {
                node               = this;
                _referencedEdge    = edge;
                _positionRefCount += delta;
            }

            return(node);
        }
Пример #13
0
        // Decrements a count of the number of TextPositions and TextNavigators
        // referencing this node.
        // This method attempts to merge adjacent TextTreeTextNodes when the ref count
        // transitions from 1 to 0.
        //
        // Be careful!  This can modify the tree, removing
        // TextTreeTextNodes.
        internal override void DecrementReferenceCount(ElementEdge edge)
        {
            Invariant.Assert(edge == _referencedEdge, "Bad edge decrement!");

            _positionRefCount--;
            Invariant.Assert(_positionRefCount >= 0, "Bogus PositionRefCount! ");

            // If the ref count drops to zero, we may be able to merge this node with an adjacent one.
            if (_positionRefCount == 0)
            {
                Merge();
            }
        }
Пример #14
0
        // Token: 0x06007252 RID: 29266 RVA: 0x0020AF8C File Offset: 0x0020918C
        internal static int GetCPFromEmbeddedObject(UIElement embeddedObject, ElementEdge edge)
        {
            Invariant.Assert(edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd, "Cannot retrieve CP from the content of embedded object.");
            int result = -1;

            if (embeddedObject is FrameworkElement)
            {
                FrameworkElement frameworkElement = (FrameworkElement)embeddedObject;
                if (frameworkElement.Parent is TextElement)
                {
                    TextElement textElement = (TextElement)frameworkElement.Parent;
                    result = ((edge == ElementEdge.BeforeStart) ? textElement.ContentStartOffset : textElement.ContentEndOffset);
                }
            }
            return(result);
        }
Пример #15
0
        /// <summary>
        /// Gets CP (character position) representing EmbeddedObject within TextContainer.
        /// If object does not belong to the TextContainer, this method returns -1.
        /// </summary>
        internal static int GetCPFromEmbeddedObject(UIElement embeddedObject, ElementEdge edge)
        {
            Invariant.Assert(edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd, "Cannot retrieve CP from the content of embedded object.");
            int cp = -1;

            if (embeddedObject is FrameworkElement)
            {
                FrameworkElement fe = (FrameworkElement)embeddedObject;
                //likely the embedded element is hosted by some TextElement, like InlineUIContainer or BlockUIContainer
                if (fe.Parent is TextElement)
                {
                    TextElement uiContainer = (TextElement)fe.Parent;
                    cp = (edge == ElementEdge.BeforeStart) ? uiContainer.ContentStartOffset : uiContainer.ContentEndOffset;
                }
            }
            return(cp);
        }
Пример #16
0
        // Inserts a node at a specified position.
        internal void InsertAtNode(SplayTreeNode positionNode, ElementEdge edge)
        {
            SplayTreeNode locationNode;
            bool          insertBefore;

            if (edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd)
            {
                // Insert to this node's tree.
                InsertAtNode(positionNode, edge == ElementEdge.BeforeStart /* insertBefore */);
            }
            else
            {
                // Insert to this node's contained tree.

                if (edge == ElementEdge.AfterStart)
                {
                    locationNode = positionNode.GetFirstContainedNode();
                    insertBefore = true;
                }
                else // ElementEdge == BeforeEnd
                {
                    locationNode = positionNode.GetLastContainedNode();
                    insertBefore = false;
                }

                if (locationNode == null)
                {
                    // Inserting the first contained node.
                    positionNode.ContainedNode = this;
                    this.ParentNode            = positionNode;
                    Invariant.Assert(this.LeftChildNode == null);
                    Invariant.Assert(this.RightChildNode == null);
                    Invariant.Assert(this.LeftSymbolCount == 0);
                }
                else
                {
                    InsertAtNode(locationNode, insertBefore);
                }
            }
        }
        // Token: 0x06002EC8 RID: 11976 RVA: 0x000D3320 File Offset: 0x000D1520
        void ITextPointer.MoveToElementEdge(ElementEdge edge)
        {
            ValidationHelper.VerifyElementEdge(edge, "edge");
            FixedElement scopingElement = this._flowPosition.GetScopingElement();

            if (!scopingElement.IsTextElement)
            {
                throw new InvalidOperationException(SR.Get("NoElementObject"));
            }
            switch (edge)
            {
            case ElementEdge.BeforeStart:
                this._flowPosition = (FlowPosition)scopingElement.Start.FlowPosition.Clone();
                this._flowPosition.Move(-1);
                return;

            case ElementEdge.AfterStart:
                this._flowPosition = (FlowPosition)scopingElement.Start.FlowPosition.Clone();
                return;

            case ElementEdge.BeforeStart | ElementEdge.AfterStart:
                break;

            case ElementEdge.BeforeEnd:
                this._flowPosition = (FlowPosition)scopingElement.End.FlowPosition.Clone();
                return;

            default:
                if (edge != ElementEdge.AfterEnd)
                {
                    return;
                }
                this._flowPosition = (FlowPosition)scopingElement.End.FlowPosition.Clone();
                this._flowPosition.Move(1);
                break;
            }
        }
Пример #18
0
        // Token: 0x06003E09 RID: 15881 RVA: 0x0011D124 File Offset: 0x0011B324
        internal override TextTreeNode IncrementReferenceCount(ElementEdge edge, int delta)
        {
            Invariant.Assert(delta >= 0);
            Invariant.Assert(edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd, "Bad edge ref to TextTreeTextNode!");
            if (delta == 0)
            {
                return(this);
            }
            TextTreeTextNode textTreeTextNode;

            if (this._positionRefCount > 0 && edge != this._referencedEdge)
            {
                textTreeTextNode = this.Split((edge == ElementEdge.BeforeStart) ? 0 : this._symbolCount, edge);
                textTreeTextNode._referencedEdge    = edge;
                textTreeTextNode._positionRefCount += delta;
                TextTreeTextNode textTreeTextNode2;
                if (edge == ElementEdge.BeforeStart)
                {
                    textTreeTextNode2 = (textTreeTextNode.GetPreviousNode() as TextTreeTextNode);
                }
                else
                {
                    textTreeTextNode2 = (textTreeTextNode.GetNextNode() as TextTreeTextNode);
                }
                if (textTreeTextNode2 != null && textTreeTextNode2._positionRefCount == 0)
                {
                    textTreeTextNode2.Merge();
                }
            }
            else
            {
                textTreeTextNode        = this;
                this._referencedEdge    = edge;
                this._positionRefCount += delta;
            }
            return(textTreeTextNode);
        }
Пример #19
0
        internal int GetOffsetFromEdge(ElementEdge edge)
        { 
            int offset;

            switch (edge)
            { 
                case ElementEdge.BeforeStart:
                    offset = 0; 
                    break; 

                case ElementEdge.AfterStart: 
                    offset = 1;
                    break;

                case ElementEdge.BeforeEnd: 
                    offset = this.SymbolCount - 1;
                    break; 
 
                case ElementEdge.AfterEnd:
                    offset = this.SymbolCount; 
                    break;

                default:
                    offset = 0; 
                    Invariant.Assert(false, "Bad ElementEdge value!");
                    break; 
            } 

            return offset; 
        }
Пример #20
0
        // Increments the reference count of TextPositions referencing a
        // particular edge of this node. 
        // 
        // If this node is a TextTreeTextNode, the increment may split the node
        // and the return value is guaranteed to be the node containing the referenced 
        // edge (which may be a new node).  Otherwise this method always returns
        // the original node.
        internal virtual TextTreeNode IncrementReferenceCount(ElementEdge edge, int delta)
        { 
            Invariant.Assert(delta >= 0);
 
            if (delta > 0) 
            {
                switch (edge) 
                {
                    case ElementEdge.BeforeStart:
                        this.BeforeStartReferenceCount = true;
                        break; 

                    case ElementEdge.AfterStart: 
                        this.AfterStartReferenceCount = true; 
                        break;
 
                    case ElementEdge.BeforeEnd:
                        this.BeforeEndReferenceCount = true;
                        break;
 
                    case ElementEdge.AfterEnd:
                        this.AfterEndReferenceCount = true; 
                        break; 

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

            return this; 
        } 
Пример #21
0
 // Increments the reference count of TextPositions referencing a 
 // particular edge of this node. 
 //
 // If this node is a TextTreeTextNode, the increment may split the node 
 // and the return value is guaranteed to be the node containing the referenced
 // edge (which may be a new node).  Otherwise this method always returns
 // the original node.
 internal TextTreeNode IncrementReferenceCount(ElementEdge edge) 
 {
     return IncrementReferenceCount(edge, +1); 
 } 
Пример #22
0
 // Token: 0x06002BFD RID: 11261 RVA: 0x000C7FA9 File Offset: 0x000C61A9
 void ITextPointer.MoveToElementEdge(ElementEdge edge)
 {
     this.ChildPointer.MoveToElementEdge(edge);
 }
        //------------------------------------------------------
        //
        //  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)
        {
        }
Пример #24
0
 /// <summary>
 /// Repositions this TextNavigator at an element edge of its scoping
 /// text element.
 /// </summary>
 /// <param name="edge">
 /// The specific edge to move to.
 /// </param>
 void ITextPointer.MoveToElementEdge(ElementEdge edge)
 {
     Debug.Assert(!_isFrozen, "Can't reposition a frozen pointer!");
     Debug.Assert(false, "No scoping element!");
 }
Пример #25
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); 
            }
        } 
Пример #26
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);
            } 
        }
Пример #27
0
        // This method is called by GetNodeAndEdgeAtOffset to adjust a node
        // matching a symbol offset. 
        //
        // When text positions reference both sides of a text run 
        // we always split the run into a zero-width TextTreeTextNode 
        // followed by a non-zero-width node.  We do this so that
        // later we can safely split the non-zero node without disturbing 
        // existing text positions.
        //
        // Here, we have to be very careful never to reference a node
        // edge between the zero-width node and the non-zero width node. 
        //
        // A: <TextTreeTextNode SymbolCount=0/><TextTreeTextNode SymbolCount=1+/> 
        // B: <TextTreeTextNode SymbolCount=1+/><TextTreeTextNode SymbolCount=0/> 
        //
        // In case A, if we're searching for the first character in the second 
        // node, we want to return the first (zero-width) node.  A TextPointer
        // could be at node1/BeforeBegin but node2/BeforeBegin is invalid.
        //
        // In case B, if we're searching for the last character in the first 
        // node, we want to return the second (zero-width) node. A TextPointer
        // could be at node2/AfterEnd but not node1/AfterEnd is invalid. 
        private SplayTreeNode AdjustForZeroWidthNode(SplayTreeNode node, ElementEdge edge) 
        {
            TextTreeTextNode textNode; 
            SplayTreeNode nextNode;
            SplayTreeNode previousNode;

            textNode = node as TextTreeTextNode; 

            if (textNode == null) 
            { 
                Invariant.Assert(node.SymbolCount > 0, "Only TextTreeTextNodes may have zero symbol counts!");
                return node; 
            }

            if (textNode.SymbolCount == 0)
            { 
                // There are only ever at most two consectuative zero-width
                // text nodes (one for each possible position gravity).  Make sure 
                // we chose the following one.  This ensures consistency with 
                // the typical non-zero width case -- we return the node whose
                // start edge is closest to a character offset. 
                nextNode = textNode.GetNextNode();
                if (nextNode != null)
                {
                    if (Invariant.Strict) 
                    {
                        if (nextNode.SymbolCount == 0) 
                        { 
                            // Node and previousNode are logically one text run.
                            // <TextTreeTextNode SymbolCount=1+/><node SymbolCount=0/><TextTreeTextNode SymbolCount=0/><TextTreeTextNode SymbolCount=1+/> 
                            Invariant.Assert(nextNode is TextTreeTextNode);
                            Invariant.Assert(!textNode.BeforeStartReferenceCount);
                            Invariant.Assert(!((TextTreeTextNode)nextNode).AfterEndReferenceCount);
                            Invariant.Assert(textNode.GetPreviousNode() == null || textNode.GetPreviousNode().SymbolCount > 0, "Found three consecutive zero-width text nodes! (1)"); 
                            Invariant.Assert(nextNode.GetNextNode() == null || nextNode.GetNextNode().SymbolCount > 0, "Found three consecutive zero-width text nodes! (2)");
                        } 
                    } 

                    if (!textNode.BeforeStartReferenceCount) 
                    {
                        // Node and previousNode are logically one text run.
                        // <TextTreeTextNode SymbolCount=1+/><node SymbolCount=0/><AnyNode/>
                        node = nextNode; 
                    }
                } 
            } 
            else if (edge == ElementEdge.BeforeStart)
            { 
                if (textNode.AfterEndReferenceCount)
                {
                    // <TextTreeTextNode SymbolCount=0/><node SymbolCount=1+/>
                    // Case A.  Check for previous zero-width node. 
                    previousNode = textNode.GetPreviousNode();
                    if (previousNode != null && previousNode.SymbolCount == 0 && !((TextTreeNode)previousNode).AfterEndReferenceCount) 
                    { 
                        Invariant.Assert(previousNode is TextTreeTextNode);
                        node = previousNode; 
                    }
                }
            }
            else // edge == ElementEdge.AfterEnd 
            {
                if (textNode.BeforeStartReferenceCount) 
                { 
                    // B: <node SymbolCount=1+/><TextTreeTextNode SymbolCount=0/>
                    // Case B.  Check for following zero-width node. 
                    nextNode = textNode.GetNextNode();
                    if (nextNode != null && nextNode.SymbolCount == 0 && !((TextTreeNode)nextNode).BeforeStartReferenceCount)
                    {
                        Invariant.Assert(nextNode is TextTreeTextNode); 
                        node = nextNode;
                    } 
                } 
            }
 
            return node;
        }
Пример #28
0
 /// <summary> 
 /// Gets CP (character position) representing EmbeddedObject within TextContainer.
 /// If object does not belong to the TextContainer, this method returns -1.
 /// </summary>
 internal static int GetCPFromEmbeddedObject(UIElement embeddedObject, ElementEdge edge) 
 {
     Invariant.Assert(edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd, "Cannot retrieve CP from the content of embedded object."); 
     int cp = -1; 
     if (embeddedObject is FrameworkElement)
     { 
         FrameworkElement fe = (FrameworkElement)embeddedObject;
         //likely the embedded element is hosted by some TextElement, like InlineUIContainer or BlockUIContainer
         if (fe.Parent is TextElement)
         { 
             TextElement uiContainer = (TextElement)fe.Parent;
             cp = (edge == ElementEdge.BeforeStart) ? uiContainer.ContentStartOffset : uiContainer.ContentEndOffset; 
         } 
     }
     return cp; 
 }
Пример #29
0
        /// <summary>
        /// Gets CP (character position) representing DependencyObject within given TextContainer. 
        /// If object does not belong to the TextContainer, this method returns
        /// distance to the end of TextContainer. 
        /// Only TextElement or host of TextContainer can be passed here. 
        /// </summary>
        internal static int GetCPFromElement(ITextContainer textContainer, DependencyObject element, ElementEdge edge) 
        {
            int cp;
            TextElement textElement;
 
            textElement = element as TextElement;
            if (textElement != null) 
            { 
                if (!textElement.IsInTree || textElement.TextContainer != textContainer)
                { 
                    // Element is not in the tree. Use TextContainer.End instead.
                    // This situation may happen, if element got removed, but StructuralCache
                    // still have a reference to it and it is trying to do incremental update.
                    cp = textContainer.SymbolCount; 
                }
                else 
                { 
                    // Get TextPointer from appropriate edge.
                    switch (edge) 
                    {
                        case ElementEdge.BeforeStart:
                            cp = textElement.ElementStartOffset;
                            break; 
                        case ElementEdge.AfterStart:
                            cp = textElement.ContentStartOffset; 
                            break; 
                        case ElementEdge.BeforeEnd:
                            cp = textElement.ContentEndOffset; 
                            break;
                        case ElementEdge.AfterEnd:
                            cp = textElement.ElementEndOffset;
                            break; 
                        default:
                            Invariant.Assert(false, "Unknown ElementEdge."); 
                            cp = 0; 
                            break;
                    } 
                }
            }
            else
            { 
                // The element is the owner of TextContainer,
                // return the beginning or the end of the content. 
                Invariant.Assert(element is TextBlock || element is FlowDocument || element is TextBox, 
                    "Cannot retrive length for EmbeddedObject.");
                cp = (edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterStart) ? 0 : textContainer.SymbolCount; 
            }
            return cp;
        }
Пример #30
0
        /// <summary> 
        /// Gets TextContentRange for a TextElement's edge.
        /// </summary> 
        internal static TextContentRange GetTextContentRangeForTextElementEdge(TextElement textElement, ElementEdge edge) 
        {
            Invariant.Assert(edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd); 

            ITextContainer textContainer = textElement.TextContainer;
            int cpFirst, cpLast;
            if (edge == ElementEdge.AfterEnd) 
            {
                cpFirst = textElement.ContentEndOffset; 
                cpLast = textElement.ElementEndOffset; 
            }
            else 
            {
                cpFirst = textElement.ElementStartOffset;
                cpLast = textElement.ContentStartOffset;
            } 
            return new TextContentRange(cpFirst, cpLast, textContainer);
        } 
        /// <summary>
        /// <see cref="ITextPointer.MoveToElementEdge"/>
        /// </summary>
        void ITextPointer.MoveToElementEdge(ElementEdge edge)
        {
            Debug.Assert(!_isFrozen, "Can't reposition a frozen pointer!");

            this.ChildPointer.MoveToElementEdge(edge);
        }
Пример #32
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();
        }
Пример #33
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;
        }
Пример #34
0
        /// <summary>
        /// <see cref="ITextPointer.MoveToElementEdge"/>
        /// </summary>
        void ITextPointer.MoveToElementEdge(ElementEdge edge)
        {
            Debug.Assert(!_isFrozen, "Can't reposition a frozen pointer!");

            this.ChildPointer.MoveToElementEdge(edge);
        }
Пример #35
0
        // Inserts a node at a specified position.
        internal void InsertAtNode(SplayTreeNode positionNode, ElementEdge edge) 
        {
            SplayTreeNode locationNode; 
            bool insertBefore; 

            if (edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd) 
            {
                // Insert to this node's tree.
                InsertAtNode(positionNode, edge == ElementEdge.BeforeStart /* insertBefore */);
            } 
            else
            { 
                // Insert to this node's contained tree. 

                if (edge == ElementEdge.AfterStart) 
                {
                    locationNode = positionNode.GetFirstContainedNode();
                    insertBefore = true;
                } 
                else // ElementEdge == BeforeEnd
                { 
                    locationNode = positionNode.GetLastContainedNode(); 
                    insertBefore = false;
                } 

                if (locationNode == null)
                {
                    // Inserting the first contained node. 
                    positionNode.ContainedNode = this;
                    this.ParentNode = positionNode; 
                    Invariant.Assert(this.LeftChildNode == null); 
                    Invariant.Assert(this.RightChildNode == null);
                    Invariant.Assert(this.LeftSymbolCount == 0); 
                }
                else
                {
                    InsertAtNode(locationNode, insertBefore); 
                }
            } 
        } 
Пример #36
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;
        }
Пример #37
0
 // Token: 0x06003220 RID: 12832 RVA: 0x00002137 File Offset: 0x00000337
 void ITextPointer.MoveToElementEdge(ElementEdge edge)
 {
 }
Пример #38
0
        // Splits this node into two adjacent nodes.
        // Returns the node which contains the original requested edge
        // (e.g., if edge == ElementEdge.BeforeStart, this method returns the
        // preceding node, if edge == ElementEdge.AfterEnd, it returns the
        // following node).
        internal TextTreeTextNode Split(int localOffset, ElementEdge edge)
        {
            TextTreeTextNode newNode;
            TextTreeTextNode edgeNode;
            ElementEdge      newNodeEdge;

            Invariant.Assert(_symbolCount > 0, "Splitting a zero-width TextNode!");
            Invariant.Assert(localOffset >= 0 && localOffset <= _symbolCount, "Bad localOffset!");
            Invariant.Assert(edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd, "Bad edge parameter!");

#if DEBUG
            if (localOffset == 0)
            {
                TextTreeNode previousNode;

                Invariant.Assert(edge == ElementEdge.BeforeStart, "Unexpected edge!");
                Invariant.Assert(edge != _referencedEdge, "Splitting at referenced edge!");

                previousNode = (TextTreeNode)GetPreviousNode();
                Invariant.Assert(previousNode == null || previousNode.SymbolCount > 0 || previousNode.AfterEndReferenceCount,
                                 "Found preceding zero-width text node inside Split!");
            }
            else if (localOffset == _symbolCount)
            {
                TextTreeNode nextNode;

                Invariant.Assert(edge == ElementEdge.AfterEnd, "Unexpected edge!");
                Invariant.Assert(edge != _referencedEdge, "Splitting at referenced edge!");

                nextNode = (TextTreeNode)GetNextNode();
                Invariant.Assert(nextNode == null || nextNode.SymbolCount > 0 || nextNode.BeforeStartReferenceCount,
                                 "Found following zero-width text node inside Split! (2)");
            }
#endif // DEBUG

            newNode             = new TextTreeTextNode();
            newNode._generation = _generation;

            // Splay this node to the root so we don't corrupt any LeftSymbolCounts
            // of ancestor nodes when we fixup _symbolCount below.
            Splay();

            if (_positionRefCount > 0 && _referencedEdge == ElementEdge.BeforeStart)
            {
                // New node is the following node.
                newNode._symbolOffsetCache = (_symbolOffsetCache == -1) ? -1 : _symbolOffsetCache + localOffset;
                newNode._symbolCount       = _symbolCount - localOffset;

                _symbolCount = localOffset;

                newNodeEdge = ElementEdge.AfterEnd;

                edgeNode = (edge == ElementEdge.BeforeStart) ? this : newNode;
            }
            else
            {
                // New node is the preceding node.
                newNode._symbolOffsetCache = _symbolOffsetCache;
                newNode._symbolCount       = localOffset;

                _symbolOffsetCache = (_symbolOffsetCache == -1) ? -1 : _symbolOffsetCache + localOffset;
                _symbolCount      -= localOffset;

                newNodeEdge = ElementEdge.BeforeStart;

                edgeNode = (edge == ElementEdge.BeforeStart) ? newNode : this;
            }

            Invariant.Assert(_symbolCount >= 0);
            Invariant.Assert(newNode._symbolCount >= 0);

            newNode.InsertAtNode(this, newNodeEdge);

            return(edgeNode);
        }
Пример #39
0
 internal virtual TextTreeNode IncrementReferenceCount(ElementEdge edge, bool delta)
 {
     return(IncrementReferenceCount(edge, delta ? 1 : 0));
 }
Пример #40
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)
        {
        }
Пример #41
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);
            }
        }
Пример #42
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;
        }
Пример #43
0
        // Splits this node into two adjacent nodes. 
        // Returns the node which contains the original requested edge
        // (e.g., if edge == ElementEdge.BeforeStart, this method returns the
        // preceding node, if edge == ElementEdge.AfterEnd, it returns the
        // following node). 
        internal TextTreeTextNode Split(int localOffset, ElementEdge edge)
        { 
            TextTreeTextNode newNode; 
            TextTreeTextNode edgeNode;
            ElementEdge newNodeEdge; 

            Invariant.Assert(_symbolCount > 0, "Splitting a zero-width TextNode!");
            Invariant.Assert(localOffset >= 0 && localOffset <= _symbolCount, "Bad localOffset!");
            Invariant.Assert(edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd, "Bad edge parameter!"); 

#if DEBUG 
            if (localOffset == 0) 
            {
                TextTreeNode previousNode; 

                Invariant.Assert(edge == ElementEdge.BeforeStart, "Unexpected edge!");
                Invariant.Assert(edge != _referencedEdge, "Splitting at referenced edge!");
 
                previousNode = (TextTreeNode)GetPreviousNode();
                Invariant.Assert(previousNode == null || previousNode.SymbolCount > 0 || previousNode.AfterEndReferenceCount, 
                             "Found preceding zero-width text node inside Split!"); 
            }
            else if (localOffset == _symbolCount) 
            {
                TextTreeNode nextNode;

                Invariant.Assert(edge == ElementEdge.AfterEnd, "Unexpected edge!"); 
                Invariant.Assert(edge != _referencedEdge, "Splitting at referenced edge!");
 
                nextNode = (TextTreeNode)GetNextNode(); 
                Invariant.Assert(nextNode == null || nextNode.SymbolCount > 0 || nextNode.BeforeStartReferenceCount,
                             "Found following zero-width text node inside Split! (2)"); 
            }
#endif // DEBUG

            newNode = new TextTreeTextNode(); 
            newNode._generation = _generation;
 
            // Splay this node to the root so we don't corrupt any LeftSymbolCounts 
            // of ancestor nodes when we fixup _symbolCount below.
            Splay(); 

            if (_positionRefCount > 0 && _referencedEdge == ElementEdge.BeforeStart)
            {
                // New node is the following node. 
                newNode._symbolOffsetCache = (_symbolOffsetCache == -1) ? -1 : _symbolOffsetCache + localOffset;
                newNode._symbolCount = _symbolCount - localOffset; 
 
                _symbolCount = localOffset;
 
                newNodeEdge = ElementEdge.AfterEnd;

                edgeNode = (edge == ElementEdge.BeforeStart) ? this : newNode;
            } 
            else
            { 
                // New node is the preceding node. 
                newNode._symbolOffsetCache = _symbolOffsetCache;
                newNode._symbolCount = localOffset; 

                _symbolOffsetCache = (_symbolOffsetCache == -1) ? -1 : _symbolOffsetCache + localOffset;
                _symbolCount -= localOffset;
 
                newNodeEdge = ElementEdge.BeforeStart;
 
                edgeNode = (edge == ElementEdge.BeforeStart) ? newNode : this; 
            }
 
            Invariant.Assert(_symbolCount >= 0);
            Invariant.Assert(newNode._symbolCount >= 0);

            newNode.InsertAtNode(this, newNodeEdge); 

            return edgeNode; 
        } 
        /// <summary>
        /// <see cref="ITextPointer.MoveToElementEdge"/>
        /// </summary>
        void ITextPointer.MoveToElementEdge(ElementEdge edge)
        {
            Debug.Assert(!_isFrozen, "Can't reposition a frozen pointer!");

            Debug.Assert(false, "No scoping element!");
        }
Пример #45
0
        // Token: 0x06007249 RID: 29257 RVA: 0x0020AD70 File Offset: 0x00208F70
        internal static TextContentRange GetTextContentRangeForTextElementEdge(TextElement textElement, ElementEdge edge)
        {
            Invariant.Assert(edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd);
            ITextContainer textContainer = textElement.TextContainer;
            int            cpFirst;
            int            cpLast;

            if (edge == ElementEdge.AfterEnd)
            {
                cpFirst = textElement.ContentEndOffset;
                cpLast  = textElement.ElementEndOffset;
            }
            else
            {
                cpFirst = textElement.ElementStartOffset;
                cpLast  = textElement.ContentStartOffset;
            }
            return(new TextContentRange(cpFirst, cpLast, textContainer));
        }
Пример #46
0
 internal virtual TextTreeNode IncrementReferenceCount(ElementEdge edge, bool delta) 
 {
     return IncrementReferenceCount(edge, delta ? 1 : 0);
 }
Пример #47
0
        // Token: 0x06007250 RID: 29264 RVA: 0x0020AEA4 File Offset: 0x002090A4
        internal static int GetCPFromElement(ITextContainer textContainer, DependencyObject element, ElementEdge edge)
        {
            TextElement textElement = element as TextElement;
            int         result;

            if (textElement != null)
            {
                if (!textElement.IsInTree || textElement.TextContainer != textContainer)
                {
                    result = textContainer.SymbolCount;
                }
                else
                {
                    switch (edge)
                    {
                    case ElementEdge.BeforeStart:
                        return(textElement.ElementStartOffset);

                    case ElementEdge.AfterStart:
                        return(textElement.ContentStartOffset);

                    case ElementEdge.BeforeStart | ElementEdge.AfterStart:
                        break;

                    case ElementEdge.BeforeEnd:
                        return(textElement.ContentEndOffset);

                    default:
                        if (edge == ElementEdge.AfterEnd)
                        {
                            return(textElement.ElementEndOffset);
                        }
                        break;
                    }
                    Invariant.Assert(false, "Unknown ElementEdge.");
                    result = 0;
                }
            }
            else
            {
                Invariant.Assert(element is TextBlock || element is FlowDocument || element is TextBox, "Cannot retrive length for EmbeddedObject.");
                result = ((edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterStart) ? 0 : textContainer.SymbolCount);
            }
            return(result);
        }
Пример #48
0
        // Decrements the reference count of TextPositions referencing this 
        // node.
        //
        // Be careful!  If this node is a TextTreeTextNode, the decrement may
        // cause a merge, and this node may be removed from the tree. 
        internal virtual void DecrementReferenceCount(ElementEdge edge)
        { 
#if INT_EDGE_REF_COUNT 
            switch (edge)
            { 
                case ElementEdge.BeforeStart:
                    this.BeforeStartReferenceCount--;
                    Invariant.Assert(this.BeforeStartReferenceCount >= 0, "Bad BeforeStart ref count!");
                    break; 

                case ElementEdge.AfterStart: 
                    this.AfterStartReferenceCount--; 
                    Invariant.Assert(this.AfterStartReferenceCount >= 0, "Bad AfterStart ref count!");
                    break; 

                case ElementEdge.BeforeEnd:
                    this.BeforeEndReferenceCount--;
                    Invariant.Assert(this.BeforeEndReferenceCount >= 0, "Bad BeforeEnd ref count!"); 
                    break;
 
                case ElementEdge.AfterEnd: 
                    this.AfterEndReferenceCount--;
                    Invariant.Assert(this.AfterEndReferenceCount >= 0, "Bad AfterEnd ref count!"); 
                    break;

                default:
                    Invariant.Assert(false, "Bad ElementEdge value!"); 
                    break;
            } 
#endif // INT_EDGE_REF_COUNT 
        }
Пример #49
0
 internal void GetNodeAndEdgeAtOffset(int offset, out SplayTreeNode node, out ElementEdge edge) 
 {
     GetNodeAndEdgeAtOffset(offset, true /* splitNode */, out node, out edge); 
 }
Пример #50
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;
        }
Пример #51
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;
        }
Пример #52
0
 // Throws an ArgumentException if edge is not a valid enum.
 internal static void VerifyElementEdge(ElementEdge edge, string param)
 {
     if (edge != ElementEdge.BeforeStart &&
         edge != ElementEdge.AfterStart  &&
         edge != ElementEdge.BeforeEnd   &&
         edge != ElementEdge.AfterEnd)
     {
         throw new InvalidEnumArgumentException(param, (int)edge, typeof(ElementEdge));
     }
 }
Пример #53
0
        /// <summary>
        /// <see cref="ITextPointer.MoveToElementEdge"/>
        /// </summary>
        void ITextPointer.MoveToElementEdge(ElementEdge edge)
        {
            ValidationHelper.VerifyElementEdge(edge, "edge");
            Debug.Assert(!_isFrozen, "Can't reposition a frozen pointer!");

            FixedElement e = _flowPosition.GetScopingElement();
            if (!e.IsTextElement)
            {
                throw new InvalidOperationException(SR.Get(SRID.NoElementObject));
            }

            switch (edge)
            {
                case ElementEdge.BeforeStart:
                    _flowPosition = (FlowPosition)e.Start.FlowPosition.Clone();
                    _flowPosition.Move(-1);
                    break;

                case ElementEdge.AfterStart:
                    _flowPosition = (FlowPosition)e.Start.FlowPosition.Clone();
                    break;

                case ElementEdge.BeforeEnd:
                    _flowPosition = (FlowPosition)e.End.FlowPosition.Clone();
                    break;

                case ElementEdge.AfterEnd:
                    _flowPosition = (FlowPosition)e.End.FlowPosition.Clone();
                    _flowPosition.Move(1);
                    break;
            }
        }
Пример #54
0
 // Increments the reference count of TextPositions referencing a
 // particular edge of this node.
 //
 // If this node is a TextTreeTextNode, the increment may split the node
 // and the return value is guaranteed to be the node containing the referenced
 // edge (which may be a new node).  Otherwise this method always returns
 // the original node.
 internal TextTreeNode IncrementReferenceCount(ElementEdge edge)
 {
     return(IncrementReferenceCount(edge, +1));
 }
Пример #55
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);
        }
Пример #56
0
        // Increments a count of the number of TextPositions and TextNavigators 
        // referencing this node.  Called when positions are created or moved.
        // Returns the actual node referenced -- a new node will be created if
        // there are already references to this node's other edge.
        internal override TextTreeNode IncrementReferenceCount(ElementEdge edge, int delta) 
        {
            TextTreeTextNode node; 
            TextTreeTextNode mergeNode; 

            Invariant.Assert(delta >= 0); 
            Invariant.Assert(edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd, "Bad edge ref to TextTreeTextNode!");

            if (delta == 0)
            { 
                return this;
            } 
 
            if (_positionRefCount > 0 && edge != _referencedEdge)
            { 
                // We need to split off a node to cover the new edge.
                node = Split(edge == ElementEdge.BeforeStart ? 0 : _symbolCount, edge);

                node._referencedEdge = edge; 
                node._positionRefCount += delta;
 
                // It's possible we need to merge a neighbor node. 
                // This happens when someone calls TextContainer.GetNodeAndEdgeAtOffset,
                // which splits a text node into two non-empty nodes.  We can't merge 
                // immediately, because we don't know which of the two nodes will
                // get an additional ref.
                // If the unreferenced node of the pair gets the new reference,
                // there no possibility for a merge.  Otherwise, we have to split 
                // again on the already referenced node and end up here.
                if (edge == ElementEdge.BeforeStart) 
                { 
                    // If node B has no references it can merge with node A.
                    // <A ""/><B "x"/><newNode ""/><this "x".> 
                    mergeNode = node.GetPreviousNode() as TextTreeTextNode;
                }
                else
                { 
                    // If node A has no references it can merge with node B.
                    // <this "x"/><newNode ""/><A "x"/><B ""/> 
                    mergeNode = node.GetNextNode() as TextTreeTextNode; 
                }
                if (mergeNode != null && mergeNode._positionRefCount == 0) 
                {
                    mergeNode.Merge();
                }
            } 
            else
            { 
                node = this; 
                _referencedEdge = edge;
                _positionRefCount += delta; 
            }

            return node;
        } 
Пример #57
0
 // Token: 0x06003D4A RID: 15690 RVA: 0x00002137 File Offset: 0x00000337
 internal virtual void DecrementReferenceCount(ElementEdge edge)
 {
 }
Пример #58
0
        // Decrements a count of the number of TextPositions and TextNavigators 
        // referencing this node. 
        // This method attempts to merge adjacent TextTreeTextNodes when the ref count
        // transitions from 1 to 0. 
        //
        // Be careful!  This can modify the tree, removing
        // TextTreeTextNodes.
        internal override void DecrementReferenceCount(ElementEdge edge) 
        {
            Invariant.Assert(edge == _referencedEdge, "Bad edge decrement!"); 
 
            _positionRefCount--;
            Invariant.Assert(_positionRefCount >= 0, "Bogus PositionRefCount! "); 

            // If the ref count drops to zero, we may be able to merge this node with an adjacent one.
            if (_positionRefCount == 0)
            { 
                Merge();
            } 
        } 
Пример #59
0
        /// <summary>
        /// Gets CP (character position) representing DependencyObject within given TextContainer.
        /// If object does not belong to the TextContainer, this method returns
        /// distance to the end of TextContainer.
        /// Only TextElement or host of TextContainer can be passed here.
        /// </summary>
        internal static int GetCPFromElement(ITextContainer textContainer, DependencyObject element, ElementEdge edge)
        {
            int         cp;
            TextElement textElement;

            textElement = element as TextElement;
            if (textElement != null)
            {
                if (!textElement.IsInTree || textElement.TextContainer != textContainer)
                {
                    // Element is not in the tree. Use TextContainer.End instead.
                    // This situation may happen, if element got removed, but StructuralCache
                    // still have a reference to it and it is trying to do incremental update.
                    cp = textContainer.SymbolCount;
                }
                else
                {
                    // Get TextPointer from appropriate edge.
                    switch (edge)
                    {
                    case ElementEdge.BeforeStart:
                        cp = textElement.ElementStartOffset;
                        break;

                    case ElementEdge.AfterStart:
                        cp = textElement.ContentStartOffset;
                        break;

                    case ElementEdge.BeforeEnd:
                        cp = textElement.ContentEndOffset;
                        break;

                    case ElementEdge.AfterEnd:
                        cp = textElement.ElementEndOffset;
                        break;

                    default:
                        Invariant.Assert(false, "Unknown ElementEdge.");
                        cp = 0;
                        break;
                    }
                }
            }
            else
            {
                // The element is the owner of TextContainer,
                // return the beginning or the end of the content.
                Invariant.Assert(element is TextBlock || element is FlowDocument || element is TextBox,
                                 "Cannot retrive length for EmbeddedObject.");
                cp = (edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterStart) ? 0 : textContainer.SymbolCount;
            }
            return(cp);
        }