TextFormatterImp.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 / Core / MS / Internal / TextFormatting / TextFormatterImp.cs / 2 / TextFormatterImp.cs

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

 
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; 

#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 double                                  _toIdeal;                   // scaling factor from client's real space to LS ideal resolution 
        private double                                  _toReal;                    // scaling factor from LS ideal resolution to client's real space 
        private bool                                    _multipleContextProhibited; // prohibit multiple contexts within the same formatter
        private GlyphingCache                           _glyphingCache;             // Glyphing cache for font linking process 

        private const int MaxGlyphingCacheCapacity = 16;

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

        /// 
        /// 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)
        { 
            _toIdeal = Constants.DefaultRealToIdeal;
            _toReal = Constants.DefaultIdealToReal; 
 
            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 
            ) 
        {
            if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose)) 
            {
                EventTrace.EventProvider.TraceEvent(
                    EventTrace.GuidFromId(EventTraceGuidId.GENERICSTRINGGUID),
                    EventType.StartEvent, 
                    "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 
                );

            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; 
            }

            if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose))
            { 
                EventTrace.EventProvider.TraceEvent(
                    EventTrace.GuidFromId(EventTraceGuidId.GENERICSTRINGGUID), 
                    EventType.EndEvent, 
                    "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
                );

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



        ///  
        /// 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
                );
 
            //
            // 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
            ) 
        {
            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
                ); 
        } 

 

        /// 
        /// 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));
 
            double realInfiniteWidth = IdealToReal(Constants.InfiniteWidth); 

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

            double realMaxFontRenderingEmSize = 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 > realInfiniteWidth)
                throw new ArgumentOutOfRangeException("paragraphProperties.Indent", SR.Get(SRID.ParameterCannotBeGreaterThan, realInfiniteWidth)); 
 
            if (paragraphProperties.LineHeight > realInfiniteWidth)
                throw new ArgumentOutOfRangeException("paragraphProperties.LineHeight", SR.Get(SRID.ParameterCannotBeGreaterThan, realInfiniteWidth)); 

            if (   paragraphProperties.DefaultIncrementalTab < 0
                || paragraphProperties.DefaultIncrementalTab > realInfiniteWidth)
            { 
                throw new ArgumentOutOfRangeException("paragraphProperties.DefaultIncrementalTab", SR.Get(SRID.ParameterMustBeBetween, 0, 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("First", SR.Get(SRID.ParameterMustBeBetween, cpFirst, cpFirst + cchLength)); 
            }
 
            if (characterHit.TrailingLength < 0) 
            {
                throw new ArgumentOutOfRangeException("Length", 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); 
        }
 
 

        ///  
        /// Scale LS ideal resolution value to real value
        /// 
        internal double IdealToReal(int i)
        { 
            return i * _toReal;
        } 
 
        /// 
        /// Scale real value to LS ideal resolution 
        /// 
        internal int RealToIdeal(double i)
        {
            return (int) Math.Round(i * _toIdeal); 
        }
 
        ///  
        /// 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 int RealToIdealFloor(double i)
        { 
            return (int) Math.Floor(i * _toIdeal);
        }

        ///  
        /// Ideal to real value scaling factor
        ///  
        internal double ToReal 
        {
            get { return _toReal; } 
        }


        ///  
        /// Real to ideal value scaling factor
        ///  
        internal double ToIdeal 
        {
            get { return _toIdeal; } 
        }


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

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