TextContainerHelper.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Framework / MS / Internal / documents / TextContainerHelper.cs / 1 / TextContainerHelper.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: Helper services for TextContainer. 
// 
// History:
//  07/26/2004 : [....] - Created. 
//
//---------------------------------------------------------------------------

using System; 
using System.Collections.Generic;
using System.Collections.ObjectModel; 
using System.Windows; 
using System.Windows.Automation.Peers;            // AutomationPeer
using System.Windows.Controls; 
using System.Windows.Documents;
using System.Windows.Media;
using MS.Internal.Text;
 
namespace MS.Internal.Documents
{ 
    internal sealed class TextContentRange 
    {
        internal TextContentRange() 
        {
        }
        internal TextContentRange(int cpFirst, int cpLast, ITextContainer textContainer)
        { 
            Invariant.Assert(cpFirst <= cpLast);
            Invariant.Assert(cpFirst >= 0); 
            Invariant.Assert(textContainer != null); 
            Invariant.Assert(cpLast <= textContainer.SymbolCount);
            _cpFirst = cpFirst; 
            _cpLast = cpLast;
            _size = 0;
            _ranges = null;
            _textContainer = textContainer; 
        }
        internal void Merge(TextContentRange other) 
        { 
            Invariant.Assert(other != null);
 
            // Skip merge operation if we're merging an empty text content range.
            if(other._textContainer == null)
            {
                return; 
            }
 
            if (_textContainer == null) 
            {
                _cpFirst = other._cpFirst; 
                _cpLast = other._cpLast;
                _textContainer = other._textContainer;
                _size = other._size;
                if (_size != 0) 
                {
                    Invariant.Assert(other._ranges != null); 
                    Invariant.Assert(other._ranges.Length >= (other._size * 2)); 
                    _ranges = new int[_size * 2];
                    for (int i = 0; i < _ranges.Length; i++) 
                    {
                        _ranges[i] = other._ranges[i];
                    }
                } 
            }
            else 
            { 
                Invariant.Assert(_textContainer == other._textContainer);
                if (other.IsSimple) 
                {
                    Merge(other._cpFirst, other._cpLast);
                }
                else 
                {
                    for (int i = 0; i < other._size; i++) 
                    { 
                        Merge(other._ranges[i * 2], other._ranges[i * 2 + 1]);
                    } 
                }
            }
            Normalize();
        } 
        internal ReadOnlyCollection GetTextSegments()
        { 
            List segments; 
            if (_textContainer == null)
            { 
                segments = new List();
            }
            else
            { 
                if (IsSimple)
                { 
                    segments = new List(1); 
                    segments.Add(new TextSegment(
                        _textContainer.CreatePointerAtOffset(_cpFirst, LogicalDirection.Forward), 
                        _textContainer.CreatePointerAtOffset(_cpLast, LogicalDirection.Backward),
                        true));
                }
                else 
                {
                    segments = new List(_size); 
                    for (int i = 0; i < _size; i++) 
                    {
                        segments.Add(new TextSegment( 
                            _textContainer.CreatePointerAtOffset(_ranges[i * 2], LogicalDirection.Forward),
                            _textContainer.CreatePointerAtOffset(_ranges[i * 2 + 1], LogicalDirection.Backward),
                            true));
                    } 
                }
            } 
            return new ReadOnlyCollection(segments); 
        }
        internal bool Contains(ITextPointer position, bool strict) 
        {
            bool contains = false;
            int cpPos = position.Offset;
            if (IsSimple) 
            {
                if (cpPos >= _cpFirst && cpPos <= _cpLast) 
                { 
                    contains = true;
                    if (strict && (_cpFirst != _cpLast)) 
                    {
                        if (cpPos == _cpFirst && position.LogicalDirection == LogicalDirection.Backward ||
                            cpPos == _cpLast && position.LogicalDirection == LogicalDirection.Forward)
                        { 
                            contains = false;
                        } 
                    } 
                }
            } 
            else
            {
                for (int i = 0; i < _size; i++)
                { 
                    if (cpPos >= _ranges[i * 2] && cpPos <= _ranges[i * 2 + 1])
                    { 
                        contains = true; 
                        if (strict)
                        { 
                            if (cpPos == _ranges[i * 2] && position.LogicalDirection == LogicalDirection.Backward ||
                                cpPos == _ranges[i * 2 + 1] && position.LogicalDirection == LogicalDirection.Forward)
                            {
                                contains = false; 
                            }
                        } 
                        break; 
                    }
                } 
            }
            return contains;
        }
        internal ITextPointer StartPosition 
        {
            get 
            { 
                ITextPointer startPosition = null;
                if (_textContainer != null) 
                {
                    startPosition = _textContainer.CreatePointerAtOffset(IsSimple ? _cpFirst : _ranges[0], LogicalDirection.Forward);
                }
                return startPosition; 
            }
        } 
        internal ITextPointer EndPosition 
        {
            get 
            {
                ITextPointer endPosition = null;
                if (_textContainer != null)
                { 
                    endPosition = _textContainer.CreatePointerAtOffset(IsSimple ? _cpLast : _ranges[(_size - 1) * 2 + 1], LogicalDirection.Backward);
                } 
                return endPosition; 
            }
        } 
        private void Merge(int cpFirst, int cpLast)
        {
            if (IsSimple)
            { 
                if (cpFirst > _cpLast || cpLast < _cpFirst)
                { 
                    _size = 2; 
                    _ranges = new int[8]; // 4 entries
                    if (cpFirst > _cpLast) 
                    {
                        _ranges[0] = _cpFirst;
                        _ranges[1] = _cpLast;
                        _ranges[2] = cpFirst; 
                        _ranges[3] = cpLast;
                    } 
                    else 
                    {
                        _ranges[0] = cpFirst; 
                        _ranges[1] = cpLast;
                        _ranges[2] = _cpFirst;
                        _ranges[3] = _cpLast;
                    } 
                }
                else 
                { 
                    _cpFirst = Math.Min(_cpFirst, cpFirst);
                    _cpLast = Math.Max(_cpLast, cpLast); 
                }
            }
            else
            { 
                int i = 0;
                while (i < _size) 
                { 
                    if (cpLast < _ranges[i * 2])
                    { 
                        // Insert before the current position
                        EnsureSize();
                        for (int j = _size * 2 - 1; j >= i * 2; j--)
                        { 
                            _ranges[j + 2] = _ranges[j];
                        } 
                        _ranges[i * 2] = cpFirst; 
                        _ranges[i * 2 + 1] = cpLast;
                        ++_size; 
                        break;
                    }
                    else if (cpFirst <= _ranges[i * 2 + 1])
                    { 
                        // Merge with the current position
                        _ranges[i * 2] = Math.Min(_ranges[i * 2], cpFirst); 
                        _ranges[i * 2 + 1] = Math.Max(_ranges[i * 2 + 1], cpLast); 
                        while (MergeWithNext(i)) { }
                        break; 
                    }
                    ++i;
                }
                if (i >= _size) 
                {
                    // Insert at the last position 
                    EnsureSize(); 
                    _ranges[_size * 2] = cpFirst;
                    _ranges[_size * 2 + 1] = cpLast; 
                    ++_size;
                }
            }
        } 
        private bool MergeWithNext(int pos)
        { 
            if (pos < _size - 1) 
            {
                if (_ranges[pos * 2 + 1] >= _ranges[(pos + 1) * 2]) 
                {
                    _ranges[pos * 2 + 1] = Math.Max(_ranges[pos * 2 + 1], _ranges[(pos + 1) * 2 + 1]);
                    for (int i = (pos + 1) * 2; i < (_size - 1) * 2; i++)
                    { 
                        _ranges[i] = _ranges[i + 2];
                    } 
                    --_size; 
                    return true;
                } 
            }
            return false;
        }
        private void EnsureSize() 
        {
            Invariant.Assert(_size > 0); 
            Invariant.Assert(_ranges != null); 
            if (_ranges.Length < (_size + 1) * 2)
            { 
                int[] ranges = new int[_ranges.Length * 2];
                for (int i = 0; i < _size * 2; i++)
                {
                    ranges[i] = _ranges[i]; 
                }
                _ranges = ranges; 
            } 
        }
        private void Normalize() 
        {
            if (_size == 1)
            {
                _cpFirst = _ranges[0]; 
                _cpLast = _ranges[1];
                _size = 0; 
                _ranges = null; 
            }
        } 
        private bool IsSimple { get { return (_size == 0); } }
        private int _cpFirst;
        private int _cpLast;
        private int _size; 
        private int[] _ranges;
        private ITextContainer _textContainer; 
    } 

    ///  
    /// Helper services for TextContainer.
    /// 
    internal static class TextContainerHelper
    { 
        //-------------------------------------------------------------------
        // 
        //  Internal Methods 
        //
        //------------------------------------------------------------------- 

        #region Internal Methods

        ///  
        /// Retrieves a collection of AutomationPeers that fall within the range.
        /// Children that overlap with the range but are not entirely enclosed by 
        /// it will also be included in the collection. 
        /// 
        internal static List GetAutomationPeersFromRange(ITextPointer start, ITextPointer end, ITextPointer ownerContentStart) 
        {
            bool positionMoved;
            AutomationPeer peer = null;
            object element; 
            List peers = new List();
            start = start.CreatePointer(); 
 
            while (start.CompareTo(end) < 0)
            { 
                // Indicate that 'start' position is not moved yet.
                positionMoved = false;

                if (start.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementStart) 
                {
                    // Get adjacent element and try to retrive AutomationPeer for it. 
                    element = start.GetAdjacentElement(LogicalDirection.Forward); 
                    if (element is ContentElement)
                    { 
                        peer = ContentElementAutomationPeer.CreatePeerForElement((ContentElement)element);
                        // If AutomationPeer has been retrieved, add it to the collection.
                        // And skip entire element.
                        if (peer != null) 
                        {
                            if (ownerContentStart == null || IsImmediateAutomationChild(start, ownerContentStart)) 
                            { 
                                peers.Add(peer);
                            } 
                            start.MoveToNextContextPosition(LogicalDirection.Forward);
                            start.MoveToElementEdge(ElementEdge.AfterEnd);
                            positionMoved = true;
                        } 
                    }
                } 
                else if (start.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.EmbeddedElement) 
                {
                    // Get adjacent element and try to retrive AutomationPeer for it. 
                    element = start.GetAdjacentElement(LogicalDirection.Forward);
                    if (element is UIElement)
                    {
                        if (ownerContentStart == null || IsImmediateAutomationChild(start, ownerContentStart)) 
                        {
                            peer = UIElementAutomationPeer.CreatePeerForElement((UIElement)element); 
                            // If AutomationPeer has been retrieved, add it to the collection. 
                            if (peer != null)
                            { 
                                peers.Add(peer);
                            }
                            else
                            { 
                                iterate((Visual)element, peers);
                            } 
                        } 
                    }
                    else if (element is ContentElement) 
                    {
                        peer = ContentElementAutomationPeer.CreatePeerForElement((ContentElement)element);
                        // If AutomationPeer has been retrieved, add it to the collection.
                        if (peer != null) 
                        {
                            if (ownerContentStart == null || IsImmediateAutomationChild(start, ownerContentStart)) 
                            { 
                                peers.Add(peer);
                            } 
                        }
                    }
                }
                // Move to the next content position, if position has not been moved already. 
                if (!positionMoved)
                { 
                    if (!start.MoveToNextContextPosition(LogicalDirection.Forward)) 
                    {
                        break; 
                    }
                }
            }
 
            return peers;
        } 
 
        /// 
        /// Is AutometionPeer represented by 'elementStart' is immediate child of AutomationPeer 
        /// represented by 'ownerContentStart'.
        /// 
        internal static bool IsImmediateAutomationChild(ITextPointer elementStart, ITextPointer ownerContentStart)
        { 
            Invariant.Assert(elementStart.CompareTo(ownerContentStart) >= 0);
            bool immediateChild = true; 
            // Walk element tree up looking for AutomationPeers. 
            ITextPointer position = elementStart.CreatePointer();
            while (typeof(TextElement).IsAssignableFrom(position.ParentType)) 
            {
                position.MoveToElementEdge(ElementEdge.BeforeStart);
                if (position.CompareTo(ownerContentStart) <= 0)
                { 
                    break;
                } 
                AutomationPeer peer = null; 
                object element = position.GetAdjacentElement(LogicalDirection.Forward);
                if (element is UIElement) 
                {
                    peer = UIElementAutomationPeer.CreatePeerForElement((UIElement)element);
                }
                else if (element is ContentElement) 
                {
                    peer = ContentElementAutomationPeer.CreatePeerForElement((ContentElement)element); 
                } 
                if (peer != null)
                { 
                    immediateChild = false;
                    break;
                }
            } 
            return immediateChild;
        } 
 
        /// 
        /// Returns the common ancestor of two positions. This ancestor needs to have 
        /// AutomationPeer associated with it.
        /// 
        internal static AutomationPeer GetEnclosingAutomationPeer(ITextPointer start, ITextPointer end, out ITextPointer elementStart, out ITextPointer elementEnd)
        { 
            object element;
            AutomationPeer peer; 
            ITextPointer position; 
            List ancestorsStart, ancestorsEnd;
            List positionsStart, positionsEnd; 

            // Get instances of parent objects for start position. The only valid type for
            // scoping elements inside ITextContainer is TextElement.
            ancestorsStart = new List(); 
            positionsStart = new List();
            position = start.CreatePointer(); 
            while (typeof(TextElement).IsAssignableFrom(position.ParentType)) 
            {
                position.MoveToElementEdge(ElementEdge.BeforeStart); 
                element = position.GetAdjacentElement(LogicalDirection.Forward);
                if (element != null)
                {
                    ancestorsStart.Insert(0, element); 
                    positionsStart.Insert(0, position.CreatePointer(LogicalDirection.Forward));
                } 
            } 

            // Get instances of parent objects for end position. The only valid type for 
            // scoping elements inside ITextContainer is TextElement.
            ancestorsEnd = new List();
            positionsEnd = new List();
            position = end.CreatePointer(); 
            while (typeof(TextElement).IsAssignableFrom(position.ParentType))
            { 
                position.MoveToElementEdge(ElementEdge.AfterEnd); 
                element = position.GetAdjacentElement(LogicalDirection.Backward);
                if (element != null) 
                {
                    ancestorsEnd.Insert(0, element);
                    positionsEnd.Insert(0, position.CreatePointer(LogicalDirection.Backward));
                } 
            }
 
            // Find common ancestor. If any of ancestors collection is empty, there 
            // is no common ancestor.
            peer = null; 
            elementStart = elementEnd = null;
            int depth = Math.Min(ancestorsStart.Count, ancestorsEnd.Count);
            while (depth > 0)
            { 
                if (ancestorsStart[depth - 1] == ancestorsEnd[depth - 1])
                { 
                    element = ancestorsStart[depth - 1]; 
                    if (element is UIElement)
                    { 
                        peer = UIElementAutomationPeer.CreatePeerForElement((UIElement)element);
                    }
                    else if (element is ContentElement)
                    { 
                        peer = ContentElementAutomationPeer.CreatePeerForElement((ContentElement)element);
                    } 
                    if (peer != null) 
                    {
                        elementStart = positionsStart[depth - 1]; 
                        elementEnd = positionsEnd[depth - 1];
                        break;
                    }
                } 
                depth--;
            } 
 
            return peer;
        } 

        /// 
        /// Gets TextContentRange for a TextElement (including element's edges).
        ///  
        internal static TextContentRange GetTextContentRangeForTextElement(TextElement textElement)
        { 
            ITextContainer textContainer = textElement.TextContainer; 
            int cpFirst = textElement.ElementStartOffset;
            int cpLast = textElement.ElementEndOffset; 
            return new TextContentRange(cpFirst, cpLast, textContainer);
        }

        ///  
        /// Gets TextContentRange for a TextElement's edge.
        ///  
        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);
        } 
 
        /// 
        /// Retrieves ITextPointer representing content start of given element. 
        /// 
        internal static ITextPointer GetContentStart(ITextContainer textContainer, DependencyObject element)
        {
            ITextPointer textPointer; 
            // If the element is a TextElement, return the beginning of its content.
            // Otherwise assume that element is the host of text content and return 
            // the beginning of TextContainer. 
            if (element is TextElement)
            { 
                textPointer = ((TextElement)element).ContentStart;
            }
            else
            { 
                Invariant.Assert(element is TextBlock || element is FlowDocument || element is TextBox,
                    "Cannot retrive ContentStart position for EmbeddedObject."); 
                textPointer = textContainer.CreatePointerAtOffset(0, LogicalDirection.Forward); // Start 
            }
            return textPointer; 
        }

        /// 
        /// Retrieves the length (in CPs) of given element including edges. 
        /// 
        internal static int GetElementLength(ITextContainer textContainer, DependencyObject element) 
        { 
            int length;
            // For TextElement return its length including edges. 
            // Otherwise assume that this is host of TextContainer and return the
            // length of TextContainer.
            if (element is TextElement)
            { 
                length = ((TextElement)element).SymbolCount;
            } 
            else 
            {
                Invariant.Assert(element is TextBlock || element is FlowDocument || element is TextBox, 
                    "Cannot retrive length for EmbeddedObject.");
                length = textContainer.SymbolCount;
            }
            return length; 
        }
 
        ///  
        /// Length (in CPs) of embedded object.
        ///  
        internal static int EmbeddedObjectLength { get { return 1; } }

        /// 
        /// Gets dynamic TextPointer form character position. 
        /// 
        internal static ITextPointer GetTextPointerFromCP(ITextContainer textContainer, int cp, LogicalDirection direction) 
        { 
            return textContainer.CreatePointerAtOffset(cp, direction);
        } 

        /// 
        /// Gets static TextPointer form character position.
        ///  
        internal static StaticTextPointer GetStaticTextPointerFromCP(ITextContainer textContainer, int cp)
        { 
            return textContainer.CreateStaticPointerAtOffset(cp); 
        }
 
        /// 
        /// Retrieves TextPointer representing embedded object.
        /// 
        internal static ITextPointer GetTextPointerForEmbeddedObject(FrameworkElement embeddedObject) 
        {
            // Likely the embedded element is hosted by some TextElement, like InlineUIContainer or BlockUIContainer 
            ITextPointer position; 
            TextElement uiContainer = embeddedObject.Parent as TextElement;
            if (uiContainer != null) 
            {
                position = uiContainer.ContentStart;
            }
            else 
            {
                Invariant.Assert(false, "Embedded object needs to have InlineUIContainer or BlockUIContainer as parent."); 
                position = null; 
            }
            return position; 
        }

        /// 
        /// 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. 
        /// 
        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;
        }
 
        /// 
        /// Returns the number of TextContainer symbols covered by a DependencyObject. 
        /// This includes the element edges if element is a TextElement. 
        /// 
        internal static int GetCchFromElement(ITextContainer textContainer, DependencyObject element) 
        {
            int cch;
            TextElement textElement;
 
            textElement = element as TextElement;
            if (textElement != null) 
            { 
                cch = textElement.SymbolCount;
            } 
            else
            {
                cch = textContainer.SymbolCount;
            } 

            return cch; 
        } 

        ///  
        /// Gets CP (character position) representing EmbeddedObject within TextContainer.
        /// If object does not belong to the TextContainer, this method returns -1.
        /// 
        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; 
        }

        /// 
        /// Element edge character length 
        /// 
        internal static int ElementEdgeCharacterLength = 1; 
 
        #endregion Internal Methods
 
        //--------------------------------------------------------------------
        //
        //  Private Methods
        // 
        //-------------------------------------------------------------------
 
        #region Private Methods 

        private static void iterate(Visual parent, List peers) 
        {
            AutomationPeer peer = null;
            int count = parent.InternalVisualChildrenCount;
            for (int i = 0; i < count; i++) 
            {
                Visual child = parent.InternalGetVisualChild(i); 
                if (child != null 
                    && child.CheckFlagsAnd(VisualFlags.IsUIElement)
                    && (peer = UIElementAutomationPeer.CreatePeerForElement((UIElement)child)) != null) 
                {
                    peers.Add(peer);
                }
                else 
                {
                    iterate(child, peers); 
                } 
            }
        } 

        #endregion Private Methods

 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK