TextElement.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 / System / Windows / Documents / TextElement.cs / 2 / TextElement.cs

                            //---------------------------------------------------------------------------- 
//
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//
// Description: Base class for content in text based FrameworkElement. 
//
// History: 
//  07/2003    : [....] - Created 
//  02/18/2004: [....] - new TOM method implementation for TextContainer rewrite.
//  10/28/2004 : [....] - ContentElements refactoring. 
//
//---------------------------------------------------------------------------

// Enable presharp pragma warning suppress directives. 
#pragma warning disable 1634, 1691
 
using System.ComponentModel; 
using System.Collections;
using System.Windows.Controls; 
using System.Windows.Media;
using System.Windows.Markup;
using MS.Internal;
using MS.Internal.PresentationFramework; 
using MS.Internal.Text;
using MS.Internal.PtsHost.UnsafeNativeMethods; // PTS restrictions 
 
namespace System.Windows.Documents
{ 
    /// 
    /// TextElement is an  base class for content in text based FrameworkElement
    /// controls such as Text, FlowDocument, or RichTextBox.  TextElements span
    /// other content, applying property values or providing structural information. 
    /// 
    ///  
    ///  
    public abstract class TextElement : FrameworkContentElement, IAddChild
    { 
        //-----------------------------------------------------
        //
        //  Constructors
        // 
        //-----------------------------------------------------
 
        #region Constructors 

        static TextElement() 
        {
            // For attached properties metadata specific to the type needs to be set using OverrideMetadata
            // instead of passing it during property registration. Otherwise all types will get it.
            PropertyChangedCallback typographyChanged = new PropertyChangedCallback(OnTypographyChanged); 

            // Registering typography properties metadata 
            Typography.StandardLigaturesProperty.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged)); 
            Typography.ContextualLigaturesProperty.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged));
            Typography.DiscretionaryLigaturesProperty.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged)); 
            Typography.HistoricalLigaturesProperty.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged));
            Typography.AnnotationAlternatesProperty.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged));
            Typography.ContextualAlternatesProperty.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged));
            Typography.HistoricalFormsProperty.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged)); 
            Typography.KerningProperty.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged));
            Typography.CapitalSpacingProperty.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged)); 
            Typography.CaseSensitiveFormsProperty.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged)); 
            Typography.StylisticSet1Property.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged));
            Typography.StylisticSet2Property.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged)); 
            Typography.StylisticSet3Property.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged));
            Typography.StylisticSet4Property.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged));
            Typography.StylisticSet5Property.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged));
            Typography.StylisticSet6Property.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged)); 
            Typography.StylisticSet7Property.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged));
            Typography.StylisticSet8Property.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged)); 
            Typography.StylisticSet9Property.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged)); 
            Typography.StylisticSet10Property.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged));
            Typography.StylisticSet11Property.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged)); 
            Typography.StylisticSet12Property.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged));
            Typography.StylisticSet13Property.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged));
            Typography.StylisticSet14Property.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged));
            Typography.StylisticSet15Property.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged)); 
            Typography.StylisticSet16Property.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged));
            Typography.StylisticSet17Property.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged)); 
            Typography.StylisticSet18Property.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged)); 
            Typography.StylisticSet19Property.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged));
            Typography.StylisticSet20Property.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged)); 
            Typography.FractionProperty.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged));
            Typography.SlashedZeroProperty.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged));
            Typography.MathematicalGreekProperty.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged));
            Typography.EastAsianExpertFormsProperty.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged)); 
            Typography.VariantsProperty.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged));
            Typography.CapitalsProperty.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged)); 
            Typography.NumeralStyleProperty.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged)); 
            Typography.NumeralAlignmentProperty.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged));
            Typography.EastAsianWidthsProperty.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged)); 
            Typography.EastAsianLanguageProperty.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged));
            Typography.StandardSwashesProperty.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged));
            Typography.ContextualSwashesProperty.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged));
            Typography.StylisticAlternatesProperty.OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged)); 
        }
 
        ///  
        /// Internal constructor to prevent publicly derived classes.
        ///  
        internal TextElement() : base()
        {
        }
 
        #endregion Constructors
 
        //------------------------------------------------------ 
        //
        //  Public Methods 
        //
        //-----------------------------------------------------

        #region Public Methods 

        ///  
        /// Extracts this TextElement from its current position, if any, and 
        /// inserts it at a specified location.
        ///  
        /// 
        /// New start position.
        /// 
        ///  
        /// New end position.
        ///  
        ///  
        /// Throws an ArgumentException if start and end are not
        /// positioned within the same document, or if start is positioned 
        /// after end, or if start == null but end != null.
        /// 
        /// 
        /// This method extracts the TextElement from its current position, 
        /// leaving behind any contained content, before inserting the TextElement
        /// at a new location. 
        /// 
        /// If start is null, end must also be null, and the TextElement will
        /// not be inserted into a new document. 
        /// 
        internal void Reposition(TextPointer start, TextPointer end)
        {
            TextContainer tree; 

            if (start != null) 
            { 
                ValidationHelper.VerifyPositionPair(start, end);
            } 
            else if (end != null)
            {
                throw new ArgumentException(SR.Get(SRID.TextElement_UnmatchedEndPointer));
            } 

            if (start != null) 
            { 
                // start/end must be equally scoped.  But we want to discount
                // this TextElement when considering scoping -- it will be 
                // extracted before the final insert.

                SplayTreeNode startNode = start.GetScopingNode();
                // Suppress presharp 6506: Parameter 'end' to this public method must be validated. 
                // We already validated it indirectly above, when calling ValidationHelper.VerifyPositionPair.
                #pragma warning suppress 6506 
                SplayTreeNode endNode = end.GetScopingNode(); 

                if (startNode == _textElementNode) 
                {
                    startNode = _textElementNode.GetContainingNode();
                }
                if (endNode == _textElementNode) 
                {
                    endNode = _textElementNode.GetContainingNode(); 
                } 

                if (startNode != endNode) 
                {
                    throw new ArgumentException(SR.Get(SRID.InDifferentScope, "start", "end"));
                }
            } 

            if (this.IsInTree) 
            { 
                tree = EnsureTextContainer();
 
                if (start == null)
                {
                    //
                    // Case 0: Extract this element from its tree. 
                    //
 
                    tree.BeginChange(); 
                    try
                    { 
                        tree.ExtractElementInternal(this);
                    }
                    finally
                    { 
                        tree.EndChange();
                    } 
                } 
                else
                { 
                    // Presharp doesn't understand that by design TextPointer.TextContainer can never be null.
                    #pragma warning suppress 6506
                    if (tree == start.TextContainer)
                    { 
                        //
                        // Case 1: extract and insert this TextElement within the same tree. 
                        // 

                        tree.BeginChange(); 
                        try
                        {
                            tree.ExtractElementInternal(this);
                            tree.InsertElementInternal(start, end, this); 
                        }
                        finally 
                        { 
                            tree.EndChange();
                        } 
                    }
                    else
                    {
                        // 
                        // Case 2: extract and insert this TextElement from one tree to another tree.
                        // 
 
                        tree.BeginChange();
                        try 
                        {
                            tree.ExtractElementInternal(this);
                        }
                        finally 
                        {
                            tree.EndChange(); 
                        } 

                        // Presharp doesn't understand that by design TextPointer.TextContainer can never be null. 
                        #pragma warning suppress 56506
                        start.TextContainer.BeginChange();
                        try
                        { 
                            start.TextContainer.InsertElementInternal(start, end, this);
                        } 
                        finally 
                        {
                            start.TextContainer.EndChange(); 
                        }
                    }
                }
            } 
            else if (start != null)
            { 
                // 
                // Case 3: insert this TextElement to a new tree (this is no current tree).
                // 

                start.TextContainer.BeginChange();
                try
                { 
                    start.TextContainer.InsertElementInternal(start, end, this);
                } 
                finally 
                {
                    start.TextContainer.EndChange(); 
                }
            }
        }
 
        /// 
        /// Extracts this TextElement and its content from its current 
        /// position, if any, and inserts it at a specified location. 
        /// 
        ///  
        /// New position.
        /// 
        /// 
        /// This method extracts the TextElement from its current position, 
        /// including any contained content, before inserting the TextElement
        /// at a new location. 
        /// 
        /// If textPosition is null, the TextElement will not be inserted into
        /// a new document. 
        /// 
        internal void RepositionWithContent(TextPointer textPosition)
        {
            TextContainer tree; 

            if (textPosition == null) 
            { 
                if (this.IsInTree)
                { 
                    tree = EnsureTextContainer();

                    // Presharp doesn't understand that by design EnsureTextContainer can never return null.
                    #pragma warning suppress 6506 
                    tree.BeginChange();
                    try 
                    { 
                        tree.DeleteContentInternal(this.ElementStart, this.ElementEnd);
                    } 
                    finally
                    {
                        tree.EndChange();
                    } 
                }
            } 
            else 
            {
                tree = textPosition.TextContainer; 

                // Presharp doesn't understand that by design TextPointer.TextContainer can never be null.
                #pragma warning suppress 56506
                tree.BeginChange(); 
                try
                { 
                    tree.InsertElementInternal(textPosition, textPosition, this); 
                }
                finally 
                {
                    tree.EndChange();
                }
            } 
        }
 
        #endregion Public Methods 

        //------------------------------------------------------ 
        //
        //  Public Properties
        //
        //------------------------------------------------------ 

        #region Public Properties 
 
        internal static readonly UncommonField ContainerTextElementField = new UncommonField();
 
        /// 
        /// A TextRange spanning the content of this element.
        /// 
        internal TextRange TextRange 
        {
            get 
            { 
                VerifyAccess();
 
                TextContainer tree = EnsureTextContainer();

                TextPointer contentStart = new TextPointer(tree, _textElementNode, ElementEdge.AfterStart, LogicalDirection.Backward);
                contentStart.Freeze(); 

                TextPointer contentEnd = new TextPointer(tree, _textElementNode, ElementEdge.BeforeEnd, LogicalDirection.Forward); 
                contentEnd.Freeze(); 

                return new TextRange(contentStart, contentEnd); 
            }
        }

        ///  
        /// A TextPointer located just before the start edge of this TextElement.
        ///  
        ///  
        /// The TextPointer returned always has its IsFrozen property set true
        /// and LogicalDirection set Forward. 
        /// 
        public TextPointer ElementStart
        {
            get 
            {
                TextContainer tree; 
                TextPointer elementStart; 

                tree = EnsureTextContainer(); 

                elementStart = new TextPointer(tree, _textElementNode, ElementEdge.BeforeStart, LogicalDirection.Forward);
                elementStart.Freeze();
 
                return elementStart;
            } 
        } 

        internal StaticTextPointer StaticElementStart 
        {
            get
            {
                TextContainer tree = EnsureTextContainer(); 

                return new StaticTextPointer(tree, _textElementNode, 0); 
            } 
        }
 
        /// 
        /// A TextPointer located just past the start edge of this TextElement.
        /// 
        ///  
        /// The TextPointer returned always has its IsFrozen property set true
        /// and LogicalDirection set Backward. 
        ///  
        public TextPointer ContentStart
        { 
            get
            {
                TextContainer tree;
                TextPointer contentStart; 

                tree = EnsureTextContainer(); 
 
                contentStart = new TextPointer(tree, _textElementNode, ElementEdge.AfterStart, LogicalDirection.Backward);
                contentStart.Freeze(); 

                return contentStart;
            }
        } 

        internal StaticTextPointer StaticContentStart 
        { 
            get
            { 
                TextContainer tree = EnsureTextContainer();

                return new StaticTextPointer(tree, _textElementNode, 1);
            } 
        }
 
        ///  
        /// A TextPointer located just before the end edge of this TextElement.
        ///  
        /// 
        /// The TextPointer returned always has its IsFrozen property set true
        /// and LogicalDirection set Forward.
        ///  
        public TextPointer ContentEnd
        { 
            get 
            {
                TextContainer tree; 
                TextPointer contentEnd;

                tree = EnsureTextContainer();
 
                contentEnd = new TextPointer(tree, _textElementNode, ElementEdge.BeforeEnd, LogicalDirection.Forward);
                contentEnd.Freeze(); 
 
                return contentEnd;
            } 
        }

        internal StaticTextPointer StaticContentEnd
        { 
            get
            { 
                TextContainer tree = EnsureTextContainer(); 

                return new StaticTextPointer(tree, _textElementNode, _textElementNode.SymbolCount - 1); 
            }
        }

        // Returns true if a position belongs to inner part of this TextElement (ContentStart and ContentEnd including). 
        internal bool Contains(TextPointer position)
        { 
            TextContainer tree = EnsureTextContainer(); 
            ValidationHelper.VerifyPosition(tree, position);
            return this.ContentStart.CompareTo(position) <= 0 && this.ContentEnd.CompareTo(position) >= 0; 
        }

        /// 
        /// A TextPointer located just after the end edge of this TextElement. 
        /// 
        ///  
        /// The TextPointer returned always has its IsFrozen property set true 
        /// and LogicalDirection set Backward.
        ///  
        public TextPointer ElementEnd
        {
            get
            { 
                TextContainer tree;
                TextPointer elementEnd; 
 
                tree = EnsureTextContainer();
 
                elementEnd = new TextPointer(tree, _textElementNode, ElementEdge.AfterEnd, LogicalDirection.Backward);
                elementEnd.Freeze();

                return elementEnd; 
            }
        } 
 
        internal StaticTextPointer StaticElementEnd
        { 
            get
            {
                TextContainer tree = EnsureTextContainer();
 
                return new StaticTextPointer(tree, _textElementNode, _textElementNode.SymbolCount);
            } 
        } 

        #region DependencyProperties 

        /// 
        /// DependencyProperty for  property.
        ///  
        [CommonDependencyProperty]
        public static readonly DependencyProperty FontFamilyProperty = 
                DependencyProperty.RegisterAttached( 
                        "FontFamily",
                        typeof(FontFamily), 
                        typeof(TextElement),
                        new FrameworkPropertyMetadata(
                                SystemFonts.MessageFontFamily,
                                FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits), 
                        new ValidateValueCallback(IsValidFontFamily));
 
        ///  
        /// The FontFamily property specifies the name of font family.
        ///  
        [Localizability(
            LocalizationCategory.Font,
            Modifiability = Modifiability.Unmodifiable
        )] 
        public FontFamily FontFamily
        { 
            get { return (FontFamily) GetValue(FontFamilyProperty); } 
            set { SetValue(FontFamilyProperty, value); }
        } 

        /// 
        /// DependencyProperty setter for  property.
        ///  
        /// The element to which to write the attached property.
        /// The property value to set 
        public static void SetFontFamily(DependencyObject element, FontFamily value) 
        {
            if (element == null) 
            {
                throw new ArgumentNullException("element");
            }
 
            element.SetValue(FontFamilyProperty, value);
        } 
 
        /// 
        /// DependencyProperty getter for  property. 
        /// 
        /// The element from which to read the attached property.
        public static FontFamily GetFontFamily(DependencyObject element)
        { 
            if (element == null)
            { 
                throw new ArgumentNullException("element"); 
            }
 
            return (FontFamily)element.GetValue(FontFamilyProperty);
        }

        ///  
        /// DependencyProperty for  property.
        ///  
        [CommonDependencyProperty] 
        public static readonly DependencyProperty FontStyleProperty =
                DependencyProperty.RegisterAttached( 
                        "FontStyle",
                        typeof(FontStyle),
                        typeof(TextElement),
                        new FrameworkPropertyMetadata( 
                                SystemFonts.MessageFontStyle,
                                FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits)); 
 
        /// 
        /// The FontStyle property requests normal, italic, and oblique faces within a font family. 
        /// 
        public FontStyle FontStyle
        {
            get { return (FontStyle) GetValue(FontStyleProperty); } 
            set { SetValue(FontStyleProperty, value); }
        } 
 
        /// 
        /// DependencyProperty setter for  property. 
        /// 
        /// The element to which to write the attached property.
        /// The property value to set
        public static void SetFontStyle(DependencyObject element, FontStyle value) 
        {
            if (element == null) 
            { 
                throw new ArgumentNullException("element");
            } 

            element.SetValue(FontStyleProperty, value);
        }
 
        /// 
        /// DependencyProperty getter for  property. 
        ///  
        /// The element from which to read the attached property.
        public static FontStyle GetFontStyle(DependencyObject element) 
        {
            if (element == null)
            {
                throw new ArgumentNullException("element"); 
            }
 
            return (FontStyle)element.GetValue(FontStyleProperty); 
        }
 
        /// 
        /// DependencyProperty for  property.
        /// 
        [CommonDependencyProperty] 
        public static readonly DependencyProperty FontWeightProperty =
                DependencyProperty.RegisterAttached( 
                        "FontWeight", 
                        typeof(FontWeight),
                        typeof(TextElement), 
                        new FrameworkPropertyMetadata(
                                SystemFonts.MessageFontWeight,
                                FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits));
 
        /// 
        /// The FontWeight property specifies the weight of the font. 
        ///  
        public FontWeight FontWeight
        { 
            get { return (FontWeight) GetValue(FontWeightProperty); }
            set { SetValue(FontWeightProperty, value); }
        }
 
        /// 
        /// DependencyProperty setter for  property. 
        ///  
        /// The element to which to write the attached property.
        /// The property value to set 
        public static void SetFontWeight(DependencyObject element, FontWeight value)
        {
            if (element == null)
            { 
                throw new ArgumentNullException("element");
            } 
 
            element.SetValue(FontWeightProperty, value);
        } 

        /// 
        /// DependencyProperty getter for  property.
        ///  
        /// The element from which to read the attached property.
        public static FontWeight GetFontWeight(DependencyObject element) 
        { 
            if (element == null)
            { 
                throw new ArgumentNullException("element");
            }

            return (FontWeight)element.GetValue(FontWeightProperty); 
        }
 
        ///  
        /// DependencyProperty for  property.
        ///  
        [CommonDependencyProperty]
        public static readonly DependencyProperty FontStretchProperty =
                DependencyProperty.RegisterAttached(
                        "FontStretch", 
                        typeof(FontStretch),
                        typeof(TextElement), 
                        new FrameworkPropertyMetadata( 
                                FontStretches.Normal,
                                FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits)); 

        /// 
        /// The FontStretch property selects a normal, condensed, or extended face from a font family.
        ///  
        public FontStretch FontStretch
        { 
            get { return (FontStretch) GetValue(FontStretchProperty); } 
            set { SetValue(FontStretchProperty, value); }
        } 

        /// 
        /// DependencyProperty setter for  property.
        ///  
        /// The element to which to write the attached property.
        /// The property value to set 
        public static void SetFontStretch(DependencyObject element, FontStretch value) 
        {
            if (element == null) 
            {
                throw new ArgumentNullException("element");
            }
 
            element.SetValue(FontStretchProperty, value);
        } 
 
        /// 
        /// DependencyProperty getter for  property. 
        /// 
        /// The element from which to read the attached property.
        public static FontStretch GetFontStretch(DependencyObject element)
        { 
            if (element == null)
            { 
                throw new ArgumentNullException("element"); 
            }
 
            return (FontStretch)element.GetValue(FontStretchProperty);
        }

        ///  
        /// DependencyProperty for  property.
        ///  
        [CommonDependencyProperty] 
        public static readonly DependencyProperty FontSizeProperty =
                DependencyProperty.RegisterAttached( 
                        "FontSize",
                        typeof(double),
                        typeof(TextElement),
                        new FrameworkPropertyMetadata( 
                                SystemFonts.MessageFontSize,
                                FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits), 
                        new ValidateValueCallback(IsValidFontSize)); 

        ///  
        /// The FontSize property specifies the size of the font.
        /// 
        [TypeConverter(typeof(FontSizeConverter))]
        [Localizability(LocalizationCategory.None)] 
        public double FontSize
        { 
            get { return (double) GetValue(FontSizeProperty); } 
            set { SetValue(FontSizeProperty, value); }
        } 

        /// 
        /// DependencyProperty setter for  property.
        ///  
        /// The element to which to write the attached property.
        /// The property value to set 
        public static void SetFontSize(DependencyObject element, double value) 
        {
            if (element == null) 
            {
                throw new ArgumentNullException("element");
            }
 
            element.SetValue(FontSizeProperty, value);
        } 
 
        /// 
        /// DependencyProperty getter for  property. 
        /// 
        /// The element from which to read the attached property.
        [TypeConverter(typeof(FontSizeConverter))]
        public static double GetFontSize(DependencyObject element) 
        {
            if (element == null) 
            { 
                throw new ArgumentNullException("element");
            } 

            return (double)element.GetValue(FontSizeProperty);
        }
 
        /// 
        /// DependencyProperty for  property. 
        ///  
        [CommonDependencyProperty]
        public static readonly DependencyProperty ForegroundProperty = 
                DependencyProperty.RegisterAttached(
                        "Foreground",
                        typeof(Brush),
                        typeof(TextElement), 
                        new FrameworkPropertyMetadata(
                                Brushes.Black, 
                                FrameworkPropertyMetadataOptions.AffectsRender | 
                                FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender |
                                FrameworkPropertyMetadataOptions.Inherits)); 

        /// 
        /// The Foreground property specifies the foreground brush of an element's text content.
        ///  
        public Brush Foreground
        { 
            get { return (Brush) GetValue(ForegroundProperty); } 
            set { SetValue(ForegroundProperty, value); }
        } 

        /// 
        /// DependencyProperty setter for  property.
        ///  
        /// The element to which to write the attached property.
        /// The property value to set 
        public static void SetForeground(DependencyObject element, Brush value) 
        {
            if (element == null) 
            {
                throw new ArgumentNullException("element");
            }
 
            element.SetValue(ForegroundProperty, value);
        } 
 
        /// 
        /// DependencyProperty getter for  property. 
        /// 
        /// The element from which to read the attached property.
        public static Brush GetForeground(DependencyObject element)
        { 
            if (element == null)
            { 
                throw new ArgumentNullException("element"); 
            }
 
            return (Brush)element.GetValue(ForegroundProperty);
        }

        ///  
        /// DependencyProperty for  property.
        ///  
        [CommonDependencyProperty] 
        public static readonly DependencyProperty BackgroundProperty =
                DependencyProperty.Register("Background", 
                        typeof(Brush),
                        typeof(TextElement),
                        new FrameworkPropertyMetadata((Brush)null,
                                FrameworkPropertyMetadataOptions.AffectsRender)); 

        ///  
        /// The Background property defines the brush used to fill the content area. 
        /// 
        public Brush Background 
        {
            get { return (Brush) GetValue(BackgroundProperty); }
            set { SetValue(BackgroundProperty, value); }
        } 

        ///  
        /// DependencyProperty for  property. 
        /// It doesn't affect layout
        ///  
        public static readonly DependencyProperty TextEffectsProperty =
                DependencyProperty.Register(
                        "TextEffects",
                        typeof(TextEffectCollection), 
                        typeof(TextElement),
                        new FrameworkPropertyMetadata( 
                                new FreezableDefaultValueFactory(TextEffectCollection.Empty), 
                                FrameworkPropertyMetadataOptions.AffectsRender));
 
        /// 
        /// The TextEffects property specifies effects that are added to the text of an element.
        /// 
        public TextEffectCollection TextEffects 
        {
            get { return (TextEffectCollection) GetValue(TextEffectsProperty); } 
            set { SetValue(TextEffectsProperty, value); } 
        }
 
        /// 
        /// Class providing access to all text typography properties
        /// 
        public Typography Typography 
        {
            get 
            { 
                return new Typography(this);
            } 
        }

        #endregion DependencyProperties
 
        #region IAddChild
 
        /// 
        /// Called to add the object as a child.
        /// 
        ///
        /// A Block to add as a child.
        ///
        ///  
        /// o must derive from either UIElement or TextElement, or an
        /// ArgumentException will be thrown by this method. 
        ///  
        void IAddChild.AddChild(object value)
        { 
            Type valueType = value.GetType();

            TextElement te = value as TextElement;
 
            if (te != null)
            { 
                TextSchema.ValidateChild(/*parent:*/this, /*child:*/te, true /* throwIfIllegalChild */, true /* throwIfIllegalHyperlinkDescendent */); 
                Append(te);
            } 
            else
            {
                UIElement uie = value as UIElement;
                if (uie != null) 
                {
                    InlineUIContainer inlineContainer = this as InlineUIContainer; 
                    if (inlineContainer != null) 
                    {
                        if (inlineContainer.Child != null) 
                        {
                            throw new ArgumentException(SR.Get(SRID.TextSchema_ThisInlineUIContainerHasAChildUIElementAlready, this.GetType().Name, ((InlineUIContainer)this).Child.GetType().Name, value.GetType().Name));
                        }
 
                        inlineContainer.Child = uie;
                    } 
                    else 
                    {
                        BlockUIContainer blockContainer = this as BlockUIContainer; 
                        if (blockContainer != null)
                        {
                            if (blockContainer.Child != null)
                            { 
                                throw new ArgumentException(SR.Get(SRID.TextSchema_ThisBlockUIContainerHasAChildUIElementAlready, this.GetType().Name, ((BlockUIContainer)this).Child.GetType().Name, value.GetType().Name));
                            } 
 
                            blockContainer.Child = uie;
                        } 
                        else
                        {
                            if (TextSchema.IsValidChild(/*parent:*/this, /*childType:*/typeof(InlineUIContainer)))
                            { 
                                // Create implicit InlineUIContainer wrapper for this UIElement
                                InlineUIContainer implicitInlineUIContainer = Inline.CreateImplicitInlineUIContainer(this); 
                                Append(implicitInlineUIContainer); 
                                implicitInlineUIContainer.Child = uie;
                            } 
                            else
                            {
                                throw new ArgumentException(SR.Get(SRID.TextSchema_ChildTypeIsInvalid, this.GetType().Name, value.GetType().Name));
                            } 
                        }
                    } 
                } 
                else
                { 
                    throw new ArgumentException(SR.Get(SRID.TextSchema_ChildTypeIsInvalid, this.GetType().Name, value.GetType().Name));
                }
            }
        } 

        /// 
        /// Called when text appears under the tag in markup 
        ///
        /// 
        /// Text to Add to this TextElement
        ///
        /// 
        void IAddChild.AddText(string text) 
        {
            if (text == null) 
            { 
                throw new ArgumentNullException("text");
            } 

            // Check if text run is allowed in this element,
            // and create implicit Run if possible.
            if (TextSchema.IsValidChild(/*parent:*/this, /*childType:*/typeof(string))) 
            {
                Append(text); 
            } 
            else
            { 
                // Implicit Run creation
                if (TextSchema.IsValidChild(/*parent:*/this, /*childType:*/typeof(Run)))
                {
 
                    // NOTE: Do not use new Run(text) constructor to avoid TextContainer creation
                    // which would hit parser perf 
                    Run implicitRun = Inline.CreateImplicitRun(this); 

                    Append(implicitRun); 

                    implicitRun.Text = text;
                }
                else 
                {
                    // Otherwise text is not allowed. Throw if it is not a whitespace 
                    if (text.Trim().Length > 0) 
                    {
                        throw new InvalidOperationException(SR.Get(SRID.TextSchema_TextIsNotAllowed, this.GetType().Name)); 
                    }

                    // As to whitespace - it can be simply ignored
                } 
            }
        } 
 
        #endregion IAddChild
 
        #region LogicalTree

        /// 
        /// Returns enumerator to logical children. 
        /// 
        protected internal override IEnumerator LogicalChildren 
        { 
            get
            { 
                return this.IsEmpty
                    ? new RangeContentEnumerator(null, null)
                    : new RangeContentEnumerator(this.ContentStart, this.ContentEnd);
            } 
        }
 
        #endregion LogicalTree 

        #endregion Public Properties 

        //-----------------------------------------------------
        //
        //  Protected Methods 
        //
        //------------------------------------------------------ 
 
        #region Protected Methods
 
        /// 
        /// Notification that a specified property has been invalidated
        /// 
        /// EventArgs that contains the property, metadata, old value, and new value for this change 
        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
        { 
            // Always call base.OnPropertyChanged, otherwise Property Engine will not work. 
            base.OnPropertyChanged(e);
 
            // Note whether or not this change due to a SetValue/ClearValue call.
            bool localValueChanged = e.NewValueSource == BaseValueSourceInternal.Local || e.OldValueSource == BaseValueSourceInternal.Local;

            if (localValueChanged || e.IsAValueChange || e.IsASubPropertyChange) 
            {
                if (this.IsInTree) // No work to do if no one's listening. 
                { 
                    // If the modified property affects layout we have some additional
                    // bookkeeping to take care of. 
                    FrameworkPropertyMetadata fmetadata = e.Metadata as FrameworkPropertyMetadata;
                    if (fmetadata != null)
                    {
                        bool affectsMeasureOrArrange = fmetadata.AffectsMeasure || fmetadata.AffectsArrange || fmetadata.AffectsParentMeasure || fmetadata.AffectsParentArrange; 
                        bool affectsRender = (fmetadata.AffectsRender &&
                            (e.IsAValueChange || !fmetadata.SubPropertiesDoNotAffectRender)); 
                        if (affectsMeasureOrArrange || affectsRender) 
                        {
                            TextContainer textContainer = EnsureTextContainer(); 

                            textContainer.BeginChange();
                            try
                            { 
                                if (localValueChanged)
                                { 
                                    TextTreeUndo.CreatePropertyUndoUnit(this, e); 
                                }
 
                                if (e.IsAValueChange || e.IsASubPropertyChange)
                                {
                                    NotifyTypographicPropertyChanged(affectsMeasureOrArrange, localValueChanged, e.Property);
                                } 
                            }
                            finally 
                            { 
                                textContainer.EndChange();
                            } 
                        }
                    }
                }
            } 
        }
 
        // Notify our TextContainer that a typographic property has changed 
        // value on this TextElement.
        // This has the side effect of invalidating layout. 
        internal void NotifyTypographicPropertyChanged(bool affectsMeasureOrArrange, bool localValueChanged, DependencyProperty property)
        {
            if (!this.IsInTree) // No work to do if no one's listening.
            { 
                return;
            } 
 
            TextContainer tree;
            TextPointer beforeStart; 

            tree = EnsureTextContainer();

            // Take note that something layout related has changed. 
            tree.NextLayoutGeneration();
 
            // Notify any external listeners. 
            if (tree.HasListeners)
            { 
                // Get the position before the start of this element.
                beforeStart = new TextPointer(tree, _textElementNode, ElementEdge.BeforeStart, LogicalDirection.Forward);
                beforeStart.Freeze();
 
                // Raise ContentAffected event that spans entire TextElement (from BeforeStart to AfterEnd).
                tree.BeginChange(); 
                try 
                {
                    tree.BeforeAddChange(); 
                    if (localValueChanged)
                    {
                        tree.AddLocalValueChange();
                    } 
                    tree.AddChange(beforeStart, _textElementNode.SymbolCount, _textElementNode.IMECharCount,
                        PrecursorTextChangeType.PropertyModified, property, !affectsMeasureOrArrange); 
                } 
                finally
                { 
                    tree.EndChange();
                }
            }
        } 

        #endregion Protected Events 
 
        //-----------------------------------------------------
        // 
        //  Internal Methods
        //
        //-----------------------------------------------------
 
        #region Internal Methods
 
        internal static TypographyProperties GetTypographyProperties(DependencyObject element) 
        {
            TypographyProperties group = new TypographyProperties(); 

            group.SetStandardLigatures((bool) element.GetValue(Typography.StandardLigaturesProperty));
            group.SetContextualLigatures((bool) element.GetValue(Typography.ContextualLigaturesProperty));
            group.SetDiscretionaryLigatures((bool) element.GetValue(Typography.DiscretionaryLigaturesProperty)); 
            group.SetHistoricalLigatures((bool) element.GetValue(Typography.HistoricalLigaturesProperty));
            group.SetAnnotationAlternates((int) element.GetValue(Typography.AnnotationAlternatesProperty)); 
            group.SetContextualAlternates((bool) element.GetValue(Typography.ContextualAlternatesProperty)); 
            group.SetHistoricalForms((bool) element.GetValue(Typography.HistoricalFormsProperty));
            group.SetKerning((bool) element.GetValue(Typography.KerningProperty)); 
            group.SetCapitalSpacing((bool) element.GetValue(Typography.CapitalSpacingProperty));
            group.SetCaseSensitiveForms((bool) element.GetValue(Typography.CaseSensitiveFormsProperty));
            group.SetStylisticSet1((bool) element.GetValue(Typography.StylisticSet1Property));
            group.SetStylisticSet2((bool) element.GetValue(Typography.StylisticSet2Property)); 
            group.SetStylisticSet3((bool) element.GetValue(Typography.StylisticSet3Property));
            group.SetStylisticSet4((bool) element.GetValue(Typography.StylisticSet4Property)); 
            group.SetStylisticSet5((bool) element.GetValue(Typography.StylisticSet5Property)); 
            group.SetStylisticSet6((bool) element.GetValue(Typography.StylisticSet6Property));
            group.SetStylisticSet7((bool) element.GetValue(Typography.StylisticSet7Property)); 
            group.SetStylisticSet8((bool) element.GetValue(Typography.StylisticSet8Property));
            group.SetStylisticSet9((bool) element.GetValue(Typography.StylisticSet9Property));
            group.SetStylisticSet10((bool) element.GetValue(Typography.StylisticSet10Property));
            group.SetStylisticSet11((bool) element.GetValue(Typography.StylisticSet11Property)); 
            group.SetStylisticSet12((bool) element.GetValue(Typography.StylisticSet12Property));
            group.SetStylisticSet13((bool) element.GetValue(Typography.StylisticSet13Property)); 
            group.SetStylisticSet14((bool) element.GetValue(Typography.StylisticSet14Property)); 
            group.SetStylisticSet15((bool) element.GetValue(Typography.StylisticSet15Property));
            group.SetStylisticSet16((bool) element.GetValue(Typography.StylisticSet16Property)); 
            group.SetStylisticSet17((bool) element.GetValue(Typography.StylisticSet17Property));
            group.SetStylisticSet18((bool) element.GetValue(Typography.StylisticSet18Property));
            group.SetStylisticSet19((bool) element.GetValue(Typography.StylisticSet19Property));
            group.SetStylisticSet20((bool) element.GetValue(Typography.StylisticSet20Property)); 
            group.SetFraction((FontFraction) element.GetValue(Typography.FractionProperty));
            group.SetSlashedZero((bool) element.GetValue(Typography.SlashedZeroProperty)); 
            group.SetMathematicalGreek((bool) element.GetValue(Typography.MathematicalGreekProperty)); 
            group.SetEastAsianExpertForms((bool) element.GetValue(Typography.EastAsianExpertFormsProperty));
            group.SetVariants((FontVariants) element.GetValue(Typography.VariantsProperty)); 
            group.SetCapitals((FontCapitals) element.GetValue(Typography.CapitalsProperty));
            group.SetNumeralStyle((FontNumeralStyle) element.GetValue(Typography.NumeralStyleProperty));
            group.SetNumeralAlignment((FontNumeralAlignment) element.GetValue(Typography.NumeralAlignmentProperty));
            group.SetEastAsianWidths((FontEastAsianWidths) element.GetValue(Typography.EastAsianWidthsProperty)); 
            group.SetEastAsianLanguage((FontEastAsianLanguage) element.GetValue(Typography.EastAsianLanguageProperty));
            group.SetStandardSwashes((int) element.GetValue(Typography.StandardSwashesProperty)); 
            group.SetContextualSwashes((int) element.GetValue(Typography.ContextualSwashesProperty)); 
            group.SetStylisticAlternates((int) element.GetValue(Typography.StylisticAlternatesProperty));
 
            return group;
        }

        // ........................................................................ 
        //
        // Helpers for Text Flow Initialization 
        // 
        // ........................................................................
 
        // Recursively calls EndInit for this element and for all its descendants
        internal void DeepEndInit()
        {
            if (!this.IsInitialized) 
            {
                if (!this.IsEmpty) 
                { 
                    IEnumerator children = this.LogicalChildren;
 
                    while (children.MoveNext())
                    {
                        // child.Current could be FrameworkElement, FrameworkContentElement,
                        //  or anything else.  Only recursively call self for FE & FCE. 
                        TextElement child = children.Current as TextElement;
                        if (child != null) 
                        { 
                            child.DeepEndInit();
                        } 
                    }
                }

                // Mark the end of the initialization phase 
                this.EndInit();
                Invariant.Assert(this.IsInitialized); 
            } 
        }
 
        // Returns the common TextElement ancestor of two TextElements.
        internal static TextElement GetCommonAncestor(TextElement element1, TextElement element2)
        {
            if (element1 != element2) 
            {
                int depth1 = 0; 
                int depth2 = 0; 
                TextElement element;
 
                // Calculate the depths of each TextElement within the tree.
                for (element = element1; element.Parent is TextElement; element = (TextElement)element.Parent)
                {
                    depth1++; 
                }
                for (element = element2; element.Parent is TextElement; element = (TextElement)element.Parent) 
                { 
                    depth2++;
                } 

                // Then walk up until we reach an equal depth.

                while (depth1 > depth2 && element1 != element2) 
                {
                    element1 = (TextElement)element1.Parent; 
                    depth1--; 
                }
 
                while (depth2 > depth1 && element1 != element2)
                {
                    element2 = (TextElement)element2.Parent;
                    depth2--; 
                }
 
                // Then, if necessary, keep going up to the root looking for a match. 
                while (element1 != element2)
                { 
                    element1 = element1.Parent as TextElement;
                    element2 = element2.Parent as TextElement;
                }
            } 

            Invariant.Assert(element1 == element2); 
            return element1; 
        }
 
        #endregion Internal Methods

        //-----------------------------------------------------
        // 
        //  Internal Properties
        // 
        //------------------------------------------------------ 

        #region Internal Properties 

        //-----------------------------------------------------
        // The TextContainer containing this TextElement.
        //------------------------------------------------------ 
        internal TextContainer TextContainer
        { 
            get 
            {
                return EnsureTextContainer(); 
            }
        }

        //------------------------------------------------------ 
        // Emptiness of an element
        //----------------------------------------------------- 
        internal bool IsEmpty 
        {
            get 
            {
                if (_textElementNode == null)
                    return true;
 
                return (_textElementNode.ContainedNode == null);
            } 
        } 

        //------------------------------------------------------ 
        // True if this TextElement is contained within a TextContainer.
        //-----------------------------------------------------
        internal bool IsInTree
        { 
            get
            { 
                return _textElementNode != null; 
            }
        } 

        //-----------------------------------------------------
        // Symbol offset of this.ElementStart.
        //----------------------------------------------------- 
        internal int ElementStartOffset
        { 
            get 
            {
                Invariant.Assert(this.IsInTree, "TextElement is not in any TextContainer, caller should ensure this."); 
                return _textElementNode.GetSymbolOffset(EnsureTextContainer().Generation) - 1;
            }
        }
 
        //------------------------------------------------------
        // Symbol offset of this.ContentStart. 
        //----------------------------------------------------- 
        internal int ContentStartOffset
        { 
            get
            {
                Invariant.Assert(this.IsInTree, "TextElement is not in any TextContainer, caller should ensure this.");
                return _textElementNode.GetSymbolOffset(EnsureTextContainer().Generation); 
            }
        } 
 
        //------------------------------------------------------
        // Symbol offset of this.ContentEnd. 
        //------------------------------------------------------
        internal int ContentEndOffset
        {
            get 
            {
                Invariant.Assert(this.IsInTree, "TextElement is not in any TextContainer, caller should ensure this."); 
                return _textElementNode.GetSymbolOffset(EnsureTextContainer().Generation) + _textElementNode.SymbolCount - 2; 
            }
        } 

        //-----------------------------------------------------
        // Symbol offset of this.ElementEnd.
        //------------------------------------------------------ 
        internal int ElementEndOffset
        { 
            get 
            {
                Invariant.Assert(this.IsInTree, "TextElement is not in any TextContainer, caller should ensure this."); 
                return _textElementNode.GetSymbolOffset(EnsureTextContainer().Generation) + _textElementNode.SymbolCount - 1;
            }
        }
 
        //-----------------------------------------------------
        // Symbol count of this TextElement, including start/end 
        // edges. 
        //-----------------------------------------------------
        internal int SymbolCount 
        {
            get
            {
                return this.IsInTree ? _textElementNode.SymbolCount : 2; 
            }
        } 
 
        //-----------------------------------------------------
        // The node in a TextContainer representing this TextElement. 
        //------------------------------------------------------
        internal TextTreeTextElementNode TextElementNode
        {
            get 
            {
                return _textElementNode; 
            } 

            set 
            {
                _textElementNode = value;
            }
        } 

        //------------------------------------------------------------------- 
        // Typography properties group 
        //--------------------------------------------------------------------
        internal TypographyProperties TypographyPropertiesGroup 
        {
            get
            {
                if (_typographyPropertiesGroup == null) 
                {
                    _typographyPropertiesGroup = GetTypographyProperties(this); 
                } 
                return _typographyPropertiesGroup;
            } 
        }

        private static void OnTypographyChanged(DependencyObject element, DependencyPropertyChangedEventArgs e)
        { 
            ((TextElement) element)._typographyPropertiesGroup = null;
        } 
 
        //------------------------------------------------------
        // Derived classes override this method if they want 
        // their left edges to be visible to IMEs.  This is the
        // case for structural elements like Paragraph but not
        // for formatting elements like Inline.
        //----------------------------------------------------- 
        internal virtual bool IsIMEStructuralElement
        { 
            get 
            {
                return false; 
            }
        }

        //------------------------------------------------------ 
        // Plain text character count of this element's edges.
        // Used by the IME to convert Paragraph, TableCell, etc. 
        // into unicode placeholders. 
        //-----------------------------------------------------
        internal int IMELeftEdgeCharCount 
        {
            get
            {
                int leftEdgeCharCount = 0; 

                if (this.IsIMEStructuralElement) 
                { 
                    if (!this.IsInTree)
                    { 
                        // IMELeftEdgeCharCount depends on context, has no meaning outside a tree.
                        leftEdgeCharCount = -1;
                    }
                    else 
                    {
                        // The first sibling is always invisible to the IME. 
                        // This ensures we don't get into trouble creating implicit 
                        // content on IME SetText calls.
                        leftEdgeCharCount = this.TextElementNode.IsFirstSibling ? 0 : 1; 
                    }
                }

                return leftEdgeCharCount; 
            }
        } 
 
        //-----------------------------------------------------
        // Returns true if this node is the leftmost sibling of its parent 
        // and visible to the IMEs (ie, is a Block).
        //
        // This is interesting because when we do want to expose
        // element edges to the IMEs (Blocks, TableCell, etc.) we 
        // have one exception: the first sibling.  Edges of first
        // siblings must be hidden because the TextEditor will 
        // implicitly create first siblings when the IMEs, for example, 
        // insert raw text into a TableCell that lacks a Paragraph.
        // The IMEs can't handle the implicit edge creation, so we 
        // hide those edges.
        //-----------------------------------------------------
        internal virtual bool IsFirstIMEVisibleSibling
        { 
            get
            { 
                bool isFirstIMEVisibleSibling = false; 

                if (this.IsIMEStructuralElement) 
                {
                    isFirstIMEVisibleSibling = (this.TextElementNode == null) ? true : this.TextElementNode.IsFirstSibling;
                }
 
                return isFirstIMEVisibleSibling;
            } 
        } 

        //------------------------------------------------------ 
        // Returns a TextElement immediately following this one
        // on the same level of siblings.
        //-----------------------------------------------------
        internal TextElement NextElement 
        {
            get 
            { 
                if (!this.IsInTree)
                { 
                    return null;
                }

                TextTreeTextElementNode node = _textElementNode.GetNextNode() as TextTreeTextElementNode; 
                return (node != null) ? node.TextElement : null;
            } 
        } 

        //------------------------------------------------------ 
        // Returns a TextElement immediately preceding this one
        // on the same level of siblings.
        //------------------------------------------------------
        internal TextElement PreviousElement 
        {
            get 
            { 
                if (!this.IsInTree)
                { 
                    return null;
                }

                TextTreeTextElementNode node = _textElementNode.GetPreviousNode() as TextTreeTextElementNode; 
                return (node != null) ? node.TextElement : null;
            } 
        } 

        //----------------------------------------------------- 
        // Returns the first TextElement contained by this
        // TextElement.
        //------------------------------------------------------
        internal TextElement FirstChildElement 
        {
            get 
            { 
                if (!this.IsInTree)
                { 
                    return null;
                }

                TextTreeTextElementNode node = _textElementNode.GetFirstContainedNode() as TextTreeTextElementNode; 
                return (node != null) ? node.TextElement : null;
            } 
        } 

        //----------------------------------------------------- 
        // Returns the last TextElement contained by this
        // TextElement.
        //-----------------------------------------------------
        internal TextElement LastChildElement 
        {
            get 
            { 
                if (!this.IsInTree)
                { 
                    return null;
                }

                TextTreeTextElementNode node = _textElementNode.GetLastContainedNode() as TextTreeTextElementNode; 
                return (node != null) ? node.TextElement : null;
            } 
        } 

        #endregion Internal Properties 

        //-----------------------------------------------------
        //
        //  Private Methods 
        //
        //------------------------------------------------------ 
 
        #region Private Methods
 
        /// 
        /// Inserts a string at the end of the content spanned by this TextElement.
        /// 
        ///  
        /// string to insert.
        ///  
        private void Append(string textData) 
        {
            TextContainer tree; 

            if (textData == null)
            {
                throw new ArgumentNullException("textData"); 
            }
 
            tree = EnsureTextContainer(); 

            tree.BeginChange(); 
            try
            {
                //
 
                tree.InsertTextInternal(new TextPointer(tree, _textElementNode, ElementEdge.BeforeEnd), textData);
            } 
            finally 
            {
                tree.EndChange(); 
            }
        }

        ///  
        /// Inserts a TextElement at the end of the content spanned by this
        /// TextElement. 
        ///  
        /// 
        /// TextElement to insert. 
        /// 
        /// 
        /// This method will remove element from TextContainer it was previously
        /// positioned within.  Any content spanned by element will also 
        /// be moved.
        ///  
        private void Append(TextElement element) 
        {
            TextContainer tree; 
            TextPointer position;

            if (element == null)
            { 
                throw new ArgumentNullException("element");
            } 
 
            tree = EnsureTextContainer();
 
            tree.BeginChange();
            try
            {
                // 

                position = new TextPointer(tree, _textElementNode, ElementEdge.BeforeEnd); 
                tree.InsertElementInternal(position, position, element); 
            }
            finally 
            {
                tree.EndChange();
            }
        } 

        // Demand creates a TextContainer if no tree is associated with this instance. 
        // Otherwise returns the exisiting tree, and clears the tree's DeadPositionList. 
        private TextContainer EnsureTextContainer()
        { 
            TextContainer tree;
            TextPointer start;

            if (this.IsInTree) 
            {
                tree = _textElementNode.GetTextTree(); 
                tree.EmptyDeadPositionList(); 
            }
            else 
            {
                tree = new TextContainer(null, false /* plainTextOnly */);
                start = tree.Start;
 
                tree.BeginChange();
                try 
                { 
                    tree.InsertElementInternal(start, start, this);
                } 
                finally
                {
                    // No event will be raised, since we know there are no listeners yet!
                    tree.EndChange(); 
                }
 
                Invariant.Assert(this.IsInTree); 
            }
 
            return tree;
        }

        private static bool IsValidFontFamily(object o) 
        {
            FontFamily value = o as FontFamily; 
            return (value != null); 
        }
 
        /// 
        /// 
        /// 
        private static bool IsValidFontSize(object value) 
        {
            double fontSize = (double) value; 
            double minFontSize = TextDpi.MinWidth; 
            double maxFontSize = Math.Min(1000000, PTS.MaxFontSize);
 
            if (Double.IsNaN(fontSize))
            {
                return false;
            } 
            if (fontSize < minFontSize)
            { 
                return false; 
            }
            if (fontSize > maxFontSize) 
            {
                return false;
            }
            return true; 
        }
 
        #endregion Private methods 

        //----------------------------------------------------- 
        //
        //  Private Fields
        //
        //------------------------------------------------------ 

        #region Private Fields 
 
        // The node in a TextContainer representing this TextElement.
        private TextTreeTextElementNode _textElementNode; 

        //--------------------------------------------------------------------
        // Typography Group Property
        //------------------------------------------------------------------- 
        private TypographyProperties _typographyPropertiesGroup = Typography.Default;
 
        #endregion Private Fields 
    }
} 

// 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