TextFormatterImp.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / MS / Internal / TextFormatting / TextFormatterImp.cs / 1600529 / TextFormatterImp.cs

                            //+------------------------------------------------------------------------ 
//
//  Microsoft Windows Client Platform
//  Copyright (C) Microsoft Corporation
// 
//  File:      TextFormatterImp.cs
// 
//  Contents:  Text formatter implementation 
//
//  Created:   2-25-2003 Worachai Chaoweeraprasit (wchao) 
//
//-----------------------------------------------------------------------

 
using System;
using System.Security; 
using System.Windows; 
using System.Windows.Media;
using System.Windows.Threading; 
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Media.TextFormatting; 
using MS.Utility;
 
using SR=MS.Internal.PresentationCore.SR; 
using SRID=MS.Internal.PresentationCore.SRID;
using MS.Internal.Shaping; 
using MS.Internal.Text.TextInterface;
using MS.Internal.FontCache;

#if !OPTIMALBREAK_API 
using MS.Internal.PresentationCore;
#endif 
 

namespace MS.Internal.TextFormatting 
{
    /// 
    /// Implementation of TextFormatter
    ///  
    internal sealed class TextFormatterImp : TextFormatter
    { 
        private FrugalStructList  _contextList;               // LS context free list 
        private bool                                    _multipleContextProhibited; // prohibit multiple contexts within the same formatter
        private GlyphingCache                           _glyphingCache;             // Glyphing cache for font linking process 
        private TextFormattingMode                      _textFormattingMode;
        private TextAnalyzer                            _textAnalyzer;              // TextAnalyzer used for shaping process

        private const int MaxGlyphingCacheCapacity = 16; 

        ///  
        /// Construct an instance of TextFormatter implementation 
        /// 
        internal TextFormatterImp(TextFormattingMode textFormattingMode) 
            : this(null, textFormattingMode)
        { }

        ///  
        /// Construct an instance of TextFormatter implementation
        ///  
        internal TextFormatterImp() : this(null, TextFormattingMode.Ideal) 
        {}
 
        /// 
        /// Construct an instance of TextFormatter implementation with the specified context
        /// 
        ///  
        /// 
        /// TextFormatter created via this special ctor takes a specified context and uses it as the only known 
        /// context within its entire lifetime. It prohibits reentering of TextFormatter during formatting as only 
        /// one context is allowed. This restriction is critical to the optimal break algorithm supported by the current
        /// version of PTLS. 
        /// 
        internal TextFormatterImp(TextFormatterContext soleContext, TextFormattingMode textFormattingMode)
        {
            _textFormattingMode = textFormattingMode; 

            if (soleContext != null) 
                _contextList.Add(soleContext); 

            _multipleContextProhibited = (_contextList.Count != 0); 
        }


        ///  
        /// Finalizing text formatter
        ///  
        ~TextFormatterImp() 
        {
            CleanupInternal(); 
        }


        ///  
        /// Release all unmanaged LS contexts
        ///  
        public override void Dispose() 
        {
            CleanupInternal(); 
            base.Dispose();
            GC.SuppressFinalize(this);
        }
 

        ///  
        /// Release all unmanaged LS contexts 
        /// 
        private void CleanupInternal() 
        {
            for (int i = 0; i < _contextList.Count; i++)
            {
                _contextList[i].Destroy(); 
            }
            _contextList.Clear(); 
        } 

 
        /// 
        /// Client to format a text line that fills a paragraph in the document.
        /// 
        /// an object representing text layout clients text source for TextFormatter. 
        /// character index to specify where in the source text the line starts
        /// width of paragraph in which the line fills 
        /// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation. 
        /// LineBreak property of the previous text line, or null if this is the first line in the paragraph
        /// object representing a line of text that client interacts with.  
        public override TextLine FormatLine(
            TextSource                  textSource,
            int                         firstCharIndex,
            double                      paragraphWidth, 
            TextParagraphProperties     paragraphProperties,
            TextLineBreak               previousLineBreak 
            ) 
        {
            return FormatLineInternal( 
                textSource,
                firstCharIndex,
                0,   // lineLength
                paragraphWidth, 
                paragraphProperties,
                previousLineBreak, 
                new TextRunCache()  // local cache, only live within this call 
                );
        } 



        ///  
        /// Client to format a text line that fills a paragraph in the document.
        ///  
        /// an object representing text layout clients text source for TextFormatter. 
        /// character index to specify where in the source text the line starts
        /// width of paragraph in which the line fills 
        /// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation.
        /// LineBreak property of the previous text line, or null if this is the first line in the paragraph
        /// an object representing content cache of the client.
        /// object representing a line of text that client interacts with.  
        public override TextLine FormatLine(
            TextSource                  textSource, 
            int                         firstCharIndex, 
            double                      paragraphWidth,
            TextParagraphProperties     paragraphProperties, 
            TextLineBreak               previousLineBreak,
            TextRunCache                textRunCache
            )
        { 
            return FormatLineInternal(
                textSource, 
                firstCharIndex, 
                0,   // lineLength
                paragraphWidth, 
                paragraphProperties,
                previousLineBreak,
                textRunCache
                ); 
        }
 
 

        ///  
        /// Client to reconstruct a previously formatted text line
        /// 
        /// an object representing text layout clients text source for TextFormatter.
        /// character index to specify where in the source text the line starts 
        /// character length of the line
        /// width of paragraph in which the line fills 
        /// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation. 
        /// LineBreak property of the previous text line, or null if this is the first line in the paragraph
        /// an object representing content cache of the client. 
        /// object representing a line of text that client interacts with. 
#if OPTIMALBREAK_API
        public override TextLine RecreateLine(
#else 
        internal override TextLine RecreateLine(
#endif 
            TextSource                  textSource, 
            int                         firstCharIndex,
            int                         lineLength, 
            double                      paragraphWidth,
            TextParagraphProperties     paragraphProperties,
            TextLineBreak               previousLineBreak,
            TextRunCache                textRunCache 
            )
        { 
            return FormatLineInternal( 
                textSource,
                firstCharIndex, 
                lineLength,
                paragraphWidth,
                paragraphProperties,
                previousLineBreak, 
                textRunCache
                ); 
        } 

 

        /// 
        /// Format and produce a text line either with or without previously known
        /// line break point. 
        /// 
        private TextLine FormatLineInternal( 
            TextSource                  textSource, 
            int                         firstCharIndex,
            int                         lineLength, 
            double                      paragraphWidth,
            TextParagraphProperties     paragraphProperties,
            TextLineBreak               previousLineBreak,
            TextRunCache                textRunCache 
            )
        { 
            EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordText, EventTrace.Level.Verbose, EventTrace.Event.WClientStringBegin, "TextFormatterImp.FormatLineInternal Start"); 

            // prepare formatting settings 
            FormatSettings settings = PrepareFormatSettings(
                textSource,
                firstCharIndex,
                paragraphWidth, 
                paragraphProperties,
                previousLineBreak, 
                textRunCache, 
                (lineLength != 0),  // Do optimal break if break is given
                true,    // isSingleLineFormatting 
                _textFormattingMode
                );

            TextLine textLine = null; 

            if (    !settings.Pap.AlwaysCollapsible 
                &&  previousLineBreak == null 
                &&  lineLength <= 0
                ) 
            {
                // simple text line.
                textLine = SimpleTextLine.Create(
                    settings, 
                    firstCharIndex,
                    RealToIdealFloor(paragraphWidth) 
                    ) as TextLine; 
            }
 
            if (textLine == null)
            {
                // content is complex, creating complex line
                textLine = new TextMetrics.FullTextLine( 
                    settings,
                    firstCharIndex, 
                    lineLength, 
                    RealToIdealFloor(paragraphWidth),
                    LineFlags.None 
                    ) as TextLine;
            }

            EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordText, EventTrace.Level.Verbose, EventTrace.Event.WClientStringEnd, "TextFormatterImp.FormatLineInternal End"); 

            return textLine; 
        } 

 

        /// 
        /// Client to ask for the possible smallest and largest paragraph width that can fully contain the passing text content
        ///  
        /// an object representing text layout clients text source for TextFormatter.
        /// character index to specify where in the source text the line starts 
        /// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation. 
        /// min max paragraph width
        public override MinMaxParagraphWidth FormatMinMaxParagraphWidth( 
            TextSource                  textSource,
            int                         firstCharIndex,
            TextParagraphProperties     paragraphProperties
            ) 
        {
            return FormatMinMaxParagraphWidth( 
                textSource, 
                firstCharIndex,
                paragraphProperties, 
                new TextRunCache()  // local cache, only live within this call
                );
        }
 

 
        ///  
        /// Client to ask for the possible smallest and largest paragraph width that can fully contain the passing text content
        ///  
        /// an object representing text layout clients text source for TextFormatter.
        /// character index to specify where in the source text the line starts
        /// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation.
        /// an object representing content cache of the client. 
        /// min max paragraph width
        public override MinMaxParagraphWidth FormatMinMaxParagraphWidth( 
            TextSource                  textSource, 
            int                         firstCharIndex,
            TextParagraphProperties     paragraphProperties, 
            TextRunCache                textRunCache
            )
        {
            // prepare formatting settings 
            FormatSettings settings = PrepareFormatSettings(
                textSource, 
                firstCharIndex, 
                0,      // infinite paragraphWidth
                paragraphProperties, 
                null,   // always format the whole paragraph - no previousLineBreak
                textRunCache,
                false,  // optimalBreak
                true,   // isSingleLineFormatting 
                _textFormattingMode
                ); 
 
            // create specialized line specifically for min/max calculation
            TextMetrics.FullTextLine line = new TextMetrics.FullTextLine( 
                settings,
                firstCharIndex,
                0,  // lineLength
                0,  // paragraph width has no significant meaning in min/max calculation 
                (LineFlags.KeepState | LineFlags.MinMax)
                ); 
 
            // line width in this case is the width of a line when the entire paragraph is laid out
            // as a single long line. 
            MinMaxParagraphWidth minMax = new MinMaxParagraphWidth(line.MinWidth, line.Width);
            line.Dispose();
            return minMax;
        } 

        internal TextFormattingMode TextFormattingMode 
        { 
            get
            { 
                return _textFormattingMode;
            }
        }
 
        /// 
        /// Client to cache information about a paragraph to be used during optimal paragraph line formatting 
        ///  
        /// an object representing text layout clients text source for TextFormatter.
        /// character index to specify where in the source text the line starts 
        /// width of paragraph in which the line fills
        /// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation.
        /// text formatting state at the point where the previous line in the paragraph
        /// was broken by the text formatting process, as specified by the TextLine.LineBreak property for the previous 
        /// line; this parameter can be null, and will always be null for the first line in a paragraph.
        /// an object representing content cache of the client. 
        /// object representing a line of text that client interacts with.  
#if OPTIMALBREAK_API
        public override TextParagraphCache CreateParagraphCache( 
#else
        internal override TextParagraphCache CreateParagraphCache(
#endif
            TextSource                  textSource, 
            int                         firstCharIndex,
            double                      paragraphWidth, 
            TextParagraphProperties     paragraphProperties, 
            TextLineBreak               previousLineBreak,
            TextRunCache                textRunCache 
            )
        {
            // prepare formatting settings
            FormatSettings settings = PrepareFormatSettings( 
                textSource,
                firstCharIndex, 
                paragraphWidth, 
                paragraphProperties,
                previousLineBreak, 
                textRunCache,
                true,   // optimalBreak
                false,  // !isSingleLineFormatting
                _textFormattingMode 
                );
 
            // 
            // Optimal paragraph formatting session specific check
            // 
            if (!settings.Pap.Wrap && settings.Pap.OptimalBreak)
            {
                // Optimal paragraph must wrap.
                throw new ArgumentException(SR.Get(SRID.OptimalParagraphMustWrap)); 
            }
 
            // create paragraph content cache object 
            return new TextParagraphCache(
                settings, 
                firstCharIndex,
                RealToIdeal(paragraphWidth)
                );
        } 

 
 
        /// 
        /// Validate all the relevant text formatting initial settings and package them 
        /// 
        private FormatSettings PrepareFormatSettings(
            TextSource                  textSource,
            int                         firstCharIndex, 
            double                      paragraphWidth,
            TextParagraphProperties     paragraphProperties, 
            TextLineBreak               previousLineBreak, 
            TextRunCache                textRunCache,
            bool                        useOptimalBreak, 
            bool                        isSingleLineFormatting,
            TextFormattingMode              textFormattingMode
            )
        { 
            VerifyTextFormattingArguments(
                textSource, 
                firstCharIndex, 
                paragraphWidth,
                paragraphProperties, 
                textRunCache
                );

            if (textRunCache.Imp == null) 
            {
                // No run cache object available, create one 
                textRunCache.Imp = new TextRunCacheImp(); 
            }
 
            // initialize formatting settings
            return new FormatSettings(
                this,
                textSource, 
                textRunCache.Imp,
                new ParaProp(this, paragraphProperties, useOptimalBreak), 
                previousLineBreak, 
                isSingleLineFormatting,
                textFormattingMode, 
                false
                );
        }
 

 
        ///  
        /// Verify all text formatting arguments
        ///  
        private void VerifyTextFormattingArguments(
            TextSource                  textSource,
            int                         firstCharIndex,
            double                      paragraphWidth, 
            TextParagraphProperties     paragraphProperties,
            TextRunCache                textRunCache 
            ) 
        {
            if (textSource == null) 
                throw new ArgumentNullException("textSource");

            if (textRunCache == null)
                throw new ArgumentNullException("textRunCache"); 

            if (paragraphProperties == null) 
                throw new ArgumentNullException("paragraphProperties"); 

            if (paragraphProperties.DefaultTextRunProperties == null) 
                throw new ArgumentNullException("paragraphProperties.DefaultTextRunProperties");

            if (paragraphProperties.DefaultTextRunProperties.Typeface == null)
                throw new ArgumentNullException("paragraphProperties.DefaultTextRunProperties.Typeface"); 

            if (DoubleUtil.IsNaN(paragraphWidth)) 
                throw new ArgumentOutOfRangeException("paragraphWidth", SR.Get(SRID.ParameterValueCannotBeNaN)); 

            if (double.IsInfinity(paragraphWidth)) 
                throw new ArgumentOutOfRangeException("paragraphWidth", SR.Get(SRID.ParameterValueCannotBeInfinity));

            if (    paragraphWidth < 0
                || paragraphWidth > Constants.RealInfiniteWidth) 
            {
                throw new ArgumentOutOfRangeException("paragraphWidth", SR.Get(SRID.ParameterMustBeBetween, 0, Constants.RealInfiniteWidth)); 
            } 

            double realMaxFontRenderingEmSize = Constants.RealInfiniteWidth / Constants.GreatestMutiplierOfEm; 

            if (    paragraphProperties.DefaultTextRunProperties.FontRenderingEmSize < 0
                ||  paragraphProperties.DefaultTextRunProperties.FontRenderingEmSize > realMaxFontRenderingEmSize)
            { 
                throw new ArgumentOutOfRangeException("paragraphProperties.DefaultTextRunProperties.FontRenderingEmSize", SR.Get(SRID.ParameterMustBeBetween, 0, realMaxFontRenderingEmSize));
            } 
 
            if (paragraphProperties.Indent > Constants.RealInfiniteWidth)
                throw new ArgumentOutOfRangeException("paragraphProperties.Indent", SR.Get(SRID.ParameterCannotBeGreaterThan, Constants.RealInfiniteWidth)); 

            if (paragraphProperties.LineHeight > Constants.RealInfiniteWidth)
                throw new ArgumentOutOfRangeException("paragraphProperties.LineHeight", SR.Get(SRID.ParameterCannotBeGreaterThan, Constants.RealInfiniteWidth));
 
            if (   paragraphProperties.DefaultIncrementalTab < 0
                || paragraphProperties.DefaultIncrementalTab > Constants.RealInfiniteWidth) 
            { 
                throw new ArgumentOutOfRangeException("paragraphProperties.DefaultIncrementalTab", SR.Get(SRID.ParameterMustBeBetween, 0, Constants.RealInfiniteWidth));
            } 
        }


        ///  
        /// Validate the input character hit
        ///  
        internal static void VerifyCaretCharacterHit( 
            CharacterHit    characterHit,
            int             cpFirst, 
            int             cchLength
            )
        {
            if (    characterHit.FirstCharacterIndex < cpFirst 
                ||  characterHit.FirstCharacterIndex > cpFirst + cchLength)
            { 
                throw new ArgumentOutOfRangeException("cpFirst", SR.Get(SRID.ParameterMustBeBetween, cpFirst, cpFirst + cchLength)); 
            }
 
            if (characterHit.TrailingLength < 0)
            {
                throw new ArgumentOutOfRangeException("cchLength", SR.Get(SRID.ParameterCannotBeNegative));
            } 
        }
 
 

        ///  
        /// Acquire a free TextFormatter context for complex line operation
        /// 
        /// object that becomes the owner of LS context once acquired
        /// matching PLOC 
        /// Active LS context
        ///  
        /// Critical - this sets the owner of the context 
        /// Safe     - this doesn't expose critical info
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal TextFormatterContext AcquireContext(
            object      owner,
            IntPtr      ploc 
            )
        { 
            Invariant.Assert(owner != null); 

            TextFormatterContext context = null; 

            int c;
            int contextCount = _contextList.Count;
 
            for (c = 0; c < contextCount; c++)
            { 
                context = (TextFormatterContext)_contextList[c]; 

                if (ploc == IntPtr.Zero) 
                {
                    if(context.Owner == null)
                        break;
                } 
                else if (ploc == context.Ploc.Value)
                { 
                    // LS requires that we use the exact same context for line 
                    // destruction or hittesting (part of the reason is that LS
                    // actually caches some run info in the context). So here 
                    // we use the actual PLSC as the context signature so we
                    // locate the one we want.

                    Debug.Assert(context.Owner == null); 
                    break;
                } 
            } 

            if (c == contextCount) 
            {
                if (contextCount == 0 || !_multipleContextProhibited)
                {
                    //  no free one exists, create a new one 
                    context = new TextFormatterContext();
                    _contextList.Add(context); 
                } 
                else
                { 
                    // This instance of TextFormatter only allows a single context, reentering the
                    // same TextFormatter in this case is not allowed.
                    //
                    // This requirement is currently enforced only during optimal break computation. 
                    // Client implementing nesting of optimal break content inside another must create
                    // a separate TextFormatter instance for each content in different nesting level. 
                    throw new InvalidOperationException(SR.Get(SRID.TextFormatterReentranceProhibited)); 
                }
            } 

            Debug.Assert(context != null);

            context.Owner = owner; 
            return context;
        } 
 

        ///  
        /// Create an anti-inversion transform from the inversion flags.
        /// The result is used to correct glyph bitmap on an output to
        /// a drawing surface with the specified inversions applied on.
        ///  
        internal static MatrixTransform CreateAntiInversionTransform(
            InvertAxes  inversion, 
            double      paragraphWidth, 
            double      lineHeight
            ) 
        {
            if (inversion == InvertAxes.None)
            {
                // avoid creating unncessary pressure on GC when anti-transform is not needed. 
                return null;
            } 
 
            double m11 = 1;
            double m22 = 1; 
            double offsetX = 0;
            double offsetY = 0;

            if ((inversion & InvertAxes.Horizontal) != 0) 
            {
                m11 = -m11; 
                offsetX = paragraphWidth; 
            }
 
            if ((inversion & InvertAxes.Vertical) != 0)
            {
                m22 = -m22;
                offsetY = lineHeight; 
            }
 
            return new MatrixTransform(m11, 0, 0, m22, offsetX, offsetY); 
        }
 
        /// 
        /// Compare text formatter real values - since values are rounded in Display mode, comparison
        /// must also round and only return true if one rounded value is greater than the other.
        ///  
        /// First value to compare.
        /// Second value to compare. 
        /// Text formatting mode. 
        /// 1 if x greater than y, -1 if x less than y, 0 if x == y
        internal static int CompareReal(double x, double y, TextFormattingMode mode) 
        {
            double xDisplay = x;
            double yDisplay = y;
 
            if (mode == TextFormattingMode.Display)
            { 
                xDisplay = RoundDipForDisplayMode(x); 
                yDisplay = RoundDipForDisplayMode(y);
            } 

            if (xDisplay > yDisplay)
            {
                return 1; 
            }
 
            if (xDisplay < yDisplay) 
            {
                return -1; 
            }

            return 0;
        } 

        internal static double RoundDip(double value, TextFormattingMode textFormattingMode) 
        { 
            if (TextFormattingMode.Display == textFormattingMode)
            { 
                return RoundDipForDisplayMode(value);
            }
            else
            { 
                return value;
            } 
        } 

        internal static double RoundDipForDisplayMode(double value) 
        {
            return RoundDipForDisplayMode(value, MidpointRounding.ToEven);
        }
 
        private static double RoundDipForDisplayMode(double value, MidpointRounding midpointRounding)
        { 
            return Math.Round(value * Util.PixelsPerDip, midpointRounding) / Util.PixelsPerDip; 
        }
 
        /// 
        /// The default behavior of Math.Round() leads to undesirable behavior
        /// When used for display mode justified text, where we can find
        /// characters belonging to the same word jumping sideways. 
        /// A word can break among several GlyphRuns. So we need consistent
        /// rounding of the width of the GlyphRuns. If the width of one GlyphRun 
        /// rounds up and the next GlyphRun rounds down then we see characters 
        /// overlapping and so on.
        /// It is too late to change the behavior of our rounding universally 
        /// so we are making the change targeted to Display mode + Justified text
        /// 
        /// 
        ///  
        internal static double RoundDipForDisplayModeJustifiedText(double value)
        { 
            return RoundDipForDisplayMode(value, MidpointRounding.AwayFromZero); 
        }
 
        /// 
        /// Scale LS ideal resolution value to real value
        /// 
        internal static double IdealToRealWithNoRounding(double i) 
        {
            return i * Constants.DefaultIdealToReal; 
        } 

        ///  
        /// Scale LS ideal resolution value to real value
        /// 
        internal double IdealToReal(double i)
        { 
            double value = IdealToRealWithNoRounding(i);
            if (_textFormattingMode == TextFormattingMode.Display) 
            { 
                value = RoundDipForDisplayMode(value);
            } 

            if (i > 0)
            {
                // Non-zero values should not be converted to 0 accidentally through rounding, ensure that at least the min value is returned. 
                value = Math.Max(value, Constants.DefaultIdealToReal);
            } 
 
            return value;
        } 

        /// 
        /// Scale real value to LS ideal resolution
        ///  
        internal static int RealToIdeal(double i)
        { 
            int value = (int)Math.Round(i * ToIdeal); 
            if (i > 0)
            { 
                // Non-zero values should not be converted to 0 accidentally through rounding, ensure that at least the min value is returned.
                value = Math.Max(value, 1);
            }
            return value; 
        }
 
        ///  
        /// Scale the real value to LS ideal resolution
        /// Use the floor value of the scale value 
        /// 
        /// 
        /// Using Math.Round may result in a line larger than
        /// the actual given paragraph width. For example, 
        /// round tripping 100.112 with factor 300 becomes 100.1133...
        /// Using floor to ensure we never go beyond paragraph width 
        ///  
        internal static int RealToIdealFloor(double i)
        { 
            int value = (int)Math.Floor(i * ToIdeal);
            if (i > 0)
            {
                // Non-zero values should not be converted to 0 accidentally through rounding, ensure that at least the min value is returned. 
                value = Math.Max(value, 1);
            } 
            return value; 
        }
 
        /// 
        /// Real to ideal value scaling factor
        /// 
        internal static double ToIdeal 
        {
            get { return Constants.DefaultRealToIdeal; } 
        } 

        ///  
        /// Return the GlyphingCache associated with this TextFormatterImp object.
        /// GlyphingCache stores the mapping from Unicode scalar value to the physical font that is
        /// used to display it.
        ///  
        internal GlyphingCache GlyphingCache
        { 
            get 
            {
                if (_glyphingCache == null) 
                {
                    _glyphingCache = new GlyphingCache(MaxGlyphingCacheCapacity);
                }
 
                return _glyphingCache;
            } 
        } 

        internal TextAnalyzer TextAnalyzer 
        {
            /// 
            /// Return the TextAnalyzer associated with this TextFormatterImp object.
            /// TextAnalyzer is used in shaping process. 
            /// 
            ///  
            /// Critical - Uses security critical DWriteFactory.Instance. 
            /// Safe     - Does not expose the Factory instance.
            ///  
            [SecuritySafeCritical]
            get
            {
                if (_textAnalyzer == null) 
                {
                    _textAnalyzer = DWriteFactory.Instance.CreateTextAnalyzer(); 
                } 

                return _textAnalyzer; 
            }
        }
    }
} 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//+------------------------------------------------------------------------ 
//
//  Microsoft Windows Client Platform
//  Copyright (C) Microsoft Corporation
// 
//  File:      TextFormatterImp.cs
// 
//  Contents:  Text formatter implementation 
//
//  Created:   2-25-2003 Worachai Chaoweeraprasit (wchao) 
//
//-----------------------------------------------------------------------

 
using System;
using System.Security; 
using System.Windows; 
using System.Windows.Media;
using System.Windows.Threading; 
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Media.TextFormatting; 
using MS.Utility;
 
using SR=MS.Internal.PresentationCore.SR; 
using SRID=MS.Internal.PresentationCore.SRID;
using MS.Internal.Shaping; 
using MS.Internal.Text.TextInterface;
using MS.Internal.FontCache;

#if !OPTIMALBREAK_API 
using MS.Internal.PresentationCore;
#endif 
 

namespace MS.Internal.TextFormatting 
{
    /// 
    /// Implementation of TextFormatter
    ///  
    internal sealed class TextFormatterImp : TextFormatter
    { 
        private FrugalStructList  _contextList;               // LS context free list 
        private bool                                    _multipleContextProhibited; // prohibit multiple contexts within the same formatter
        private GlyphingCache                           _glyphingCache;             // Glyphing cache for font linking process 
        private TextFormattingMode                      _textFormattingMode;
        private TextAnalyzer                            _textAnalyzer;              // TextAnalyzer used for shaping process

        private const int MaxGlyphingCacheCapacity = 16; 

        ///  
        /// Construct an instance of TextFormatter implementation 
        /// 
        internal TextFormatterImp(TextFormattingMode textFormattingMode) 
            : this(null, textFormattingMode)
        { }

        ///  
        /// Construct an instance of TextFormatter implementation
        ///  
        internal TextFormatterImp() : this(null, TextFormattingMode.Ideal) 
        {}
 
        /// 
        /// Construct an instance of TextFormatter implementation with the specified context
        /// 
        ///  
        /// 
        /// TextFormatter created via this special ctor takes a specified context and uses it as the only known 
        /// context within its entire lifetime. It prohibits reentering of TextFormatter during formatting as only 
        /// one context is allowed. This restriction is critical to the optimal break algorithm supported by the current
        /// version of PTLS. 
        /// 
        internal TextFormatterImp(TextFormatterContext soleContext, TextFormattingMode textFormattingMode)
        {
            _textFormattingMode = textFormattingMode; 

            if (soleContext != null) 
                _contextList.Add(soleContext); 

            _multipleContextProhibited = (_contextList.Count != 0); 
        }


        ///  
        /// Finalizing text formatter
        ///  
        ~TextFormatterImp() 
        {
            CleanupInternal(); 
        }


        ///  
        /// Release all unmanaged LS contexts
        ///  
        public override void Dispose() 
        {
            CleanupInternal(); 
            base.Dispose();
            GC.SuppressFinalize(this);
        }
 

        ///  
        /// Release all unmanaged LS contexts 
        /// 
        private void CleanupInternal() 
        {
            for (int i = 0; i < _contextList.Count; i++)
            {
                _contextList[i].Destroy(); 
            }
            _contextList.Clear(); 
        } 

 
        /// 
        /// Client to format a text line that fills a paragraph in the document.
        /// 
        /// an object representing text layout clients text source for TextFormatter. 
        /// character index to specify where in the source text the line starts
        /// width of paragraph in which the line fills 
        /// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation. 
        /// LineBreak property of the previous text line, or null if this is the first line in the paragraph
        /// object representing a line of text that client interacts with.  
        public override TextLine FormatLine(
            TextSource                  textSource,
            int                         firstCharIndex,
            double                      paragraphWidth, 
            TextParagraphProperties     paragraphProperties,
            TextLineBreak               previousLineBreak 
            ) 
        {
            return FormatLineInternal( 
                textSource,
                firstCharIndex,
                0,   // lineLength
                paragraphWidth, 
                paragraphProperties,
                previousLineBreak, 
                new TextRunCache()  // local cache, only live within this call 
                );
        } 



        ///  
        /// Client to format a text line that fills a paragraph in the document.
        ///  
        /// an object representing text layout clients text source for TextFormatter. 
        /// character index to specify where in the source text the line starts
        /// width of paragraph in which the line fills 
        /// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation.
        /// LineBreak property of the previous text line, or null if this is the first line in the paragraph
        /// an object representing content cache of the client.
        /// object representing a line of text that client interacts with.  
        public override TextLine FormatLine(
            TextSource                  textSource, 
            int                         firstCharIndex, 
            double                      paragraphWidth,
            TextParagraphProperties     paragraphProperties, 
            TextLineBreak               previousLineBreak,
            TextRunCache                textRunCache
            )
        { 
            return FormatLineInternal(
                textSource, 
                firstCharIndex, 
                0,   // lineLength
                paragraphWidth, 
                paragraphProperties,
                previousLineBreak,
                textRunCache
                ); 
        }
 
 

        ///  
        /// Client to reconstruct a previously formatted text line
        /// 
        /// an object representing text layout clients text source for TextFormatter.
        /// character index to specify where in the source text the line starts 
        /// character length of the line
        /// width of paragraph in which the line fills 
        /// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation. 
        /// LineBreak property of the previous text line, or null if this is the first line in the paragraph
        /// an object representing content cache of the client. 
        /// object representing a line of text that client interacts with. 
#if OPTIMALBREAK_API
        public override TextLine RecreateLine(
#else 
        internal override TextLine RecreateLine(
#endif 
            TextSource                  textSource, 
            int                         firstCharIndex,
            int                         lineLength, 
            double                      paragraphWidth,
            TextParagraphProperties     paragraphProperties,
            TextLineBreak               previousLineBreak,
            TextRunCache                textRunCache 
            )
        { 
            return FormatLineInternal( 
                textSource,
                firstCharIndex, 
                lineLength,
                paragraphWidth,
                paragraphProperties,
                previousLineBreak, 
                textRunCache
                ); 
        } 

 

        /// 
        /// Format and produce a text line either with or without previously known
        /// line break point. 
        /// 
        private TextLine FormatLineInternal( 
            TextSource                  textSource, 
            int                         firstCharIndex,
            int                         lineLength, 
            double                      paragraphWidth,
            TextParagraphProperties     paragraphProperties,
            TextLineBreak               previousLineBreak,
            TextRunCache                textRunCache 
            )
        { 
            EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordText, EventTrace.Level.Verbose, EventTrace.Event.WClientStringBegin, "TextFormatterImp.FormatLineInternal Start"); 

            // prepare formatting settings 
            FormatSettings settings = PrepareFormatSettings(
                textSource,
                firstCharIndex,
                paragraphWidth, 
                paragraphProperties,
                previousLineBreak, 
                textRunCache, 
                (lineLength != 0),  // Do optimal break if break is given
                true,    // isSingleLineFormatting 
                _textFormattingMode
                );

            TextLine textLine = null; 

            if (    !settings.Pap.AlwaysCollapsible 
                &&  previousLineBreak == null 
                &&  lineLength <= 0
                ) 
            {
                // simple text line.
                textLine = SimpleTextLine.Create(
                    settings, 
                    firstCharIndex,
                    RealToIdealFloor(paragraphWidth) 
                    ) as TextLine; 
            }
 
            if (textLine == null)
            {
                // content is complex, creating complex line
                textLine = new TextMetrics.FullTextLine( 
                    settings,
                    firstCharIndex, 
                    lineLength, 
                    RealToIdealFloor(paragraphWidth),
                    LineFlags.None 
                    ) as TextLine;
            }

            EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordText, EventTrace.Level.Verbose, EventTrace.Event.WClientStringEnd, "TextFormatterImp.FormatLineInternal End"); 

            return textLine; 
        } 

 

        /// 
        /// Client to ask for the possible smallest and largest paragraph width that can fully contain the passing text content
        ///  
        /// an object representing text layout clients text source for TextFormatter.
        /// character index to specify where in the source text the line starts 
        /// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation. 
        /// min max paragraph width
        public override MinMaxParagraphWidth FormatMinMaxParagraphWidth( 
            TextSource                  textSource,
            int                         firstCharIndex,
            TextParagraphProperties     paragraphProperties
            ) 
        {
            return FormatMinMaxParagraphWidth( 
                textSource, 
                firstCharIndex,
                paragraphProperties, 
                new TextRunCache()  // local cache, only live within this call
                );
        }
 

 
        ///  
        /// Client to ask for the possible smallest and largest paragraph width that can fully contain the passing text content
        ///  
        /// an object representing text layout clients text source for TextFormatter.
        /// character index to specify where in the source text the line starts
        /// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation.
        /// an object representing content cache of the client. 
        /// min max paragraph width
        public override MinMaxParagraphWidth FormatMinMaxParagraphWidth( 
            TextSource                  textSource, 
            int                         firstCharIndex,
            TextParagraphProperties     paragraphProperties, 
            TextRunCache                textRunCache
            )
        {
            // prepare formatting settings 
            FormatSettings settings = PrepareFormatSettings(
                textSource, 
                firstCharIndex, 
                0,      // infinite paragraphWidth
                paragraphProperties, 
                null,   // always format the whole paragraph - no previousLineBreak
                textRunCache,
                false,  // optimalBreak
                true,   // isSingleLineFormatting 
                _textFormattingMode
                ); 
 
            // create specialized line specifically for min/max calculation
            TextMetrics.FullTextLine line = new TextMetrics.FullTextLine( 
                settings,
                firstCharIndex,
                0,  // lineLength
                0,  // paragraph width has no significant meaning in min/max calculation 
                (LineFlags.KeepState | LineFlags.MinMax)
                ); 
 
            // line width in this case is the width of a line when the entire paragraph is laid out
            // as a single long line. 
            MinMaxParagraphWidth minMax = new MinMaxParagraphWidth(line.MinWidth, line.Width);
            line.Dispose();
            return minMax;
        } 

        internal TextFormattingMode TextFormattingMode 
        { 
            get
            { 
                return _textFormattingMode;
            }
        }
 
        /// 
        /// Client to cache information about a paragraph to be used during optimal paragraph line formatting 
        ///  
        /// an object representing text layout clients text source for TextFormatter.
        /// character index to specify where in the source text the line starts 
        /// width of paragraph in which the line fills
        /// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation.
        /// text formatting state at the point where the previous line in the paragraph
        /// was broken by the text formatting process, as specified by the TextLine.LineBreak property for the previous 
        /// line; this parameter can be null, and will always be null for the first line in a paragraph.
        /// an object representing content cache of the client. 
        /// object representing a line of text that client interacts with.  
#if OPTIMALBREAK_API
        public override TextParagraphCache CreateParagraphCache( 
#else
        internal override TextParagraphCache CreateParagraphCache(
#endif
            TextSource                  textSource, 
            int                         firstCharIndex,
            double                      paragraphWidth, 
            TextParagraphProperties     paragraphProperties, 
            TextLineBreak               previousLineBreak,
            TextRunCache                textRunCache 
            )
        {
            // prepare formatting settings
            FormatSettings settings = PrepareFormatSettings( 
                textSource,
                firstCharIndex, 
                paragraphWidth, 
                paragraphProperties,
                previousLineBreak, 
                textRunCache,
                true,   // optimalBreak
                false,  // !isSingleLineFormatting
                _textFormattingMode 
                );
 
            // 
            // Optimal paragraph formatting session specific check
            // 
            if (!settings.Pap.Wrap && settings.Pap.OptimalBreak)
            {
                // Optimal paragraph must wrap.
                throw new ArgumentException(SR.Get(SRID.OptimalParagraphMustWrap)); 
            }
 
            // create paragraph content cache object 
            return new TextParagraphCache(
                settings, 
                firstCharIndex,
                RealToIdeal(paragraphWidth)
                );
        } 

 
 
        /// 
        /// Validate all the relevant text formatting initial settings and package them 
        /// 
        private FormatSettings PrepareFormatSettings(
            TextSource                  textSource,
            int                         firstCharIndex, 
            double                      paragraphWidth,
            TextParagraphProperties     paragraphProperties, 
            TextLineBreak               previousLineBreak, 
            TextRunCache                textRunCache,
            bool                        useOptimalBreak, 
            bool                        isSingleLineFormatting,
            TextFormattingMode              textFormattingMode
            )
        { 
            VerifyTextFormattingArguments(
                textSource, 
                firstCharIndex, 
                paragraphWidth,
                paragraphProperties, 
                textRunCache
                );

            if (textRunCache.Imp == null) 
            {
                // No run cache object available, create one 
                textRunCache.Imp = new TextRunCacheImp(); 
            }
 
            // initialize formatting settings
            return new FormatSettings(
                this,
                textSource, 
                textRunCache.Imp,
                new ParaProp(this, paragraphProperties, useOptimalBreak), 
                previousLineBreak, 
                isSingleLineFormatting,
                textFormattingMode, 
                false
                );
        }
 

 
        ///  
        /// Verify all text formatting arguments
        ///  
        private void VerifyTextFormattingArguments(
            TextSource                  textSource,
            int                         firstCharIndex,
            double                      paragraphWidth, 
            TextParagraphProperties     paragraphProperties,
            TextRunCache                textRunCache 
            ) 
        {
            if (textSource == null) 
                throw new ArgumentNullException("textSource");

            if (textRunCache == null)
                throw new ArgumentNullException("textRunCache"); 

            if (paragraphProperties == null) 
                throw new ArgumentNullException("paragraphProperties"); 

            if (paragraphProperties.DefaultTextRunProperties == null) 
                throw new ArgumentNullException("paragraphProperties.DefaultTextRunProperties");

            if (paragraphProperties.DefaultTextRunProperties.Typeface == null)
                throw new ArgumentNullException("paragraphProperties.DefaultTextRunProperties.Typeface"); 

            if (DoubleUtil.IsNaN(paragraphWidth)) 
                throw new ArgumentOutOfRangeException("paragraphWidth", SR.Get(SRID.ParameterValueCannotBeNaN)); 

            if (double.IsInfinity(paragraphWidth)) 
                throw new ArgumentOutOfRangeException("paragraphWidth", SR.Get(SRID.ParameterValueCannotBeInfinity));

            if (    paragraphWidth < 0
                || paragraphWidth > Constants.RealInfiniteWidth) 
            {
                throw new ArgumentOutOfRangeException("paragraphWidth", SR.Get(SRID.ParameterMustBeBetween, 0, Constants.RealInfiniteWidth)); 
            } 

            double realMaxFontRenderingEmSize = Constants.RealInfiniteWidth / Constants.GreatestMutiplierOfEm; 

            if (    paragraphProperties.DefaultTextRunProperties.FontRenderingEmSize < 0
                ||  paragraphProperties.DefaultTextRunProperties.FontRenderingEmSize > realMaxFontRenderingEmSize)
            { 
                throw new ArgumentOutOfRangeException("paragraphProperties.DefaultTextRunProperties.FontRenderingEmSize", SR.Get(SRID.ParameterMustBeBetween, 0, realMaxFontRenderingEmSize));
            } 
 
            if (paragraphProperties.Indent > Constants.RealInfiniteWidth)
                throw new ArgumentOutOfRangeException("paragraphProperties.Indent", SR.Get(SRID.ParameterCannotBeGreaterThan, Constants.RealInfiniteWidth)); 

            if (paragraphProperties.LineHeight > Constants.RealInfiniteWidth)
                throw new ArgumentOutOfRangeException("paragraphProperties.LineHeight", SR.Get(SRID.ParameterCannotBeGreaterThan, Constants.RealInfiniteWidth));
 
            if (   paragraphProperties.DefaultIncrementalTab < 0
                || paragraphProperties.DefaultIncrementalTab > Constants.RealInfiniteWidth) 
            { 
                throw new ArgumentOutOfRangeException("paragraphProperties.DefaultIncrementalTab", SR.Get(SRID.ParameterMustBeBetween, 0, Constants.RealInfiniteWidth));
            } 
        }


        ///  
        /// Validate the input character hit
        ///  
        internal static void VerifyCaretCharacterHit( 
            CharacterHit    characterHit,
            int             cpFirst, 
            int             cchLength
            )
        {
            if (    characterHit.FirstCharacterIndex < cpFirst 
                ||  characterHit.FirstCharacterIndex > cpFirst + cchLength)
            { 
                throw new ArgumentOutOfRangeException("cpFirst", SR.Get(SRID.ParameterMustBeBetween, cpFirst, cpFirst + cchLength)); 
            }
 
            if (characterHit.TrailingLength < 0)
            {
                throw new ArgumentOutOfRangeException("cchLength", SR.Get(SRID.ParameterCannotBeNegative));
            } 
        }
 
 

        ///  
        /// Acquire a free TextFormatter context for complex line operation
        /// 
        /// object that becomes the owner of LS context once acquired
        /// matching PLOC 
        /// Active LS context
        ///  
        /// Critical - this sets the owner of the context 
        /// Safe     - this doesn't expose critical info
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal TextFormatterContext AcquireContext(
            object      owner,
            IntPtr      ploc 
            )
        { 
            Invariant.Assert(owner != null); 

            TextFormatterContext context = null; 

            int c;
            int contextCount = _contextList.Count;
 
            for (c = 0; c < contextCount; c++)
            { 
                context = (TextFormatterContext)_contextList[c]; 

                if (ploc == IntPtr.Zero) 
                {
                    if(context.Owner == null)
                        break;
                } 
                else if (ploc == context.Ploc.Value)
                { 
                    // LS requires that we use the exact same context for line 
                    // destruction or hittesting (part of the reason is that LS
                    // actually caches some run info in the context). So here 
                    // we use the actual PLSC as the context signature so we
                    // locate the one we want.

                    Debug.Assert(context.Owner == null); 
                    break;
                } 
            } 

            if (c == contextCount) 
            {
                if (contextCount == 0 || !_multipleContextProhibited)
                {
                    //  no free one exists, create a new one 
                    context = new TextFormatterContext();
                    _contextList.Add(context); 
                } 
                else
                { 
                    // This instance of TextFormatter only allows a single context, reentering the
                    // same TextFormatter in this case is not allowed.
                    //
                    // This requirement is currently enforced only during optimal break computation. 
                    // Client implementing nesting of optimal break content inside another must create
                    // a separate TextFormatter instance for each content in different nesting level. 
                    throw new InvalidOperationException(SR.Get(SRID.TextFormatterReentranceProhibited)); 
                }
            } 

            Debug.Assert(context != null);

            context.Owner = owner; 
            return context;
        } 
 

        ///  
        /// Create an anti-inversion transform from the inversion flags.
        /// The result is used to correct glyph bitmap on an output to
        /// a drawing surface with the specified inversions applied on.
        ///  
        internal static MatrixTransform CreateAntiInversionTransform(
            InvertAxes  inversion, 
            double      paragraphWidth, 
            double      lineHeight
            ) 
        {
            if (inversion == InvertAxes.None)
            {
                // avoid creating unncessary pressure on GC when anti-transform is not needed. 
                return null;
            } 
 
            double m11 = 1;
            double m22 = 1; 
            double offsetX = 0;
            double offsetY = 0;

            if ((inversion & InvertAxes.Horizontal) != 0) 
            {
                m11 = -m11; 
                offsetX = paragraphWidth; 
            }
 
            if ((inversion & InvertAxes.Vertical) != 0)
            {
                m22 = -m22;
                offsetY = lineHeight; 
            }
 
            return new MatrixTransform(m11, 0, 0, m22, offsetX, offsetY); 
        }
 
        /// 
        /// Compare text formatter real values - since values are rounded in Display mode, comparison
        /// must also round and only return true if one rounded value is greater than the other.
        ///  
        /// First value to compare.
        /// Second value to compare. 
        /// Text formatting mode. 
        /// 1 if x greater than y, -1 if x less than y, 0 if x == y
        internal static int CompareReal(double x, double y, TextFormattingMode mode) 
        {
            double xDisplay = x;
            double yDisplay = y;
 
            if (mode == TextFormattingMode.Display)
            { 
                xDisplay = RoundDipForDisplayMode(x); 
                yDisplay = RoundDipForDisplayMode(y);
            } 

            if (xDisplay > yDisplay)
            {
                return 1; 
            }
 
            if (xDisplay < yDisplay) 
            {
                return -1; 
            }

            return 0;
        } 

        internal static double RoundDip(double value, TextFormattingMode textFormattingMode) 
        { 
            if (TextFormattingMode.Display == textFormattingMode)
            { 
                return RoundDipForDisplayMode(value);
            }
            else
            { 
                return value;
            } 
        } 

        internal static double RoundDipForDisplayMode(double value) 
        {
            return RoundDipForDisplayMode(value, MidpointRounding.ToEven);
        }
 
        private static double RoundDipForDisplayMode(double value, MidpointRounding midpointRounding)
        { 
            return Math.Round(value * Util.PixelsPerDip, midpointRounding) / Util.PixelsPerDip; 
        }
 
        /// 
        /// The default behavior of Math.Round() leads to undesirable behavior
        /// When used for display mode justified text, where we can find
        /// characters belonging to the same word jumping sideways. 
        /// A word can break among several GlyphRuns. So we need consistent
        /// rounding of the width of the GlyphRuns. If the width of one GlyphRun 
        /// rounds up and the next GlyphRun rounds down then we see characters 
        /// overlapping and so on.
        /// It is too late to change the behavior of our rounding universally 
        /// so we are making the change targeted to Display mode + Justified text
        /// 
        /// 
        ///  
        internal static double RoundDipForDisplayModeJustifiedText(double value)
        { 
            return RoundDipForDisplayMode(value, MidpointRounding.AwayFromZero); 
        }
 
        /// 
        /// Scale LS ideal resolution value to real value
        /// 
        internal static double IdealToRealWithNoRounding(double i) 
        {
            return i * Constants.DefaultIdealToReal; 
        } 

        ///  
        /// Scale LS ideal resolution value to real value
        /// 
        internal double IdealToReal(double i)
        { 
            double value = IdealToRealWithNoRounding(i);
            if (_textFormattingMode == TextFormattingMode.Display) 
            { 
                value = RoundDipForDisplayMode(value);
            } 

            if (i > 0)
            {
                // Non-zero values should not be converted to 0 accidentally through rounding, ensure that at least the min value is returned. 
                value = Math.Max(value, Constants.DefaultIdealToReal);
            } 
 
            return value;
        } 

        /// 
        /// Scale real value to LS ideal resolution
        ///  
        internal static int RealToIdeal(double i)
        { 
            int value = (int)Math.Round(i * ToIdeal); 
            if (i > 0)
            { 
                // Non-zero values should not be converted to 0 accidentally through rounding, ensure that at least the min value is returned.
                value = Math.Max(value, 1);
            }
            return value; 
        }
 
        ///  
        /// Scale the real value to LS ideal resolution
        /// Use the floor value of the scale value 
        /// 
        /// 
        /// Using Math.Round may result in a line larger than
        /// the actual given paragraph width. For example, 
        /// round tripping 100.112 with factor 300 becomes 100.1133...
        /// Using floor to ensure we never go beyond paragraph width 
        ///  
        internal static int RealToIdealFloor(double i)
        { 
            int value = (int)Math.Floor(i * ToIdeal);
            if (i > 0)
            {
                // Non-zero values should not be converted to 0 accidentally through rounding, ensure that at least the min value is returned. 
                value = Math.Max(value, 1);
            } 
            return value; 
        }
 
        /// 
        /// Real to ideal value scaling factor
        /// 
        internal static double ToIdeal 
        {
            get { return Constants.DefaultRealToIdeal; } 
        } 

        ///  
        /// Return the GlyphingCache associated with this TextFormatterImp object.
        /// GlyphingCache stores the mapping from Unicode scalar value to the physical font that is
        /// used to display it.
        ///  
        internal GlyphingCache GlyphingCache
        { 
            get 
            {
                if (_glyphingCache == null) 
                {
                    _glyphingCache = new GlyphingCache(MaxGlyphingCacheCapacity);
                }
 
                return _glyphingCache;
            } 
        } 

        internal TextAnalyzer TextAnalyzer 
        {
            /// 
            /// Return the TextAnalyzer associated with this TextFormatterImp object.
            /// TextAnalyzer is used in shaping process. 
            /// 
            ///  
            /// Critical - Uses security critical DWriteFactory.Instance. 
            /// Safe     - Does not expose the Factory instance.
            ///  
            [SecuritySafeCritical]
            get
            {
                if (_textAnalyzer == null) 
                {
                    _textAnalyzer = DWriteFactory.Instance.CreateTextAnalyzer(); 
                } 

                return _textAnalyzer; 
            }
        }
    }
} 


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