FormattedTextSymbols.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 / FormattedTextSymbols.cs / 1305600 / FormattedTextSymbols.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: 
//  Formatting a single style, single reading direction text symbols
// 
// History:
//  08/16/2004 : wchao - Created it
//
//--------------------------------------------------------------------------- 

using System; 
using System.Security; 
using System.Windows;
using System.Windows.Media; 
using System.Windows.Media.TextFormatting;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics; 
using MS.Internal;
using MS.Internal.Text.TextInterface; 
using MS.Internal.Shaping; 
using System.Globalization;
using MS.Internal.FontCache; 


namespace MS.Internal.TextFormatting
{ 
    /// 
    /// Formatted form of TextSymbols 
    ///  
    internal sealed class FormattedTextSymbols
    { 
        private Glyphs[]    _glyphs;
        private bool        _rightToLeft;
        private TextFormattingMode _textFormattingMode;
        private bool _isSideways; 

        ///  
        /// Construct a formatted run 
        /// 
        ///  
        /// Critical - this method has unsafe blocks, calls Critical methods (Instance, etc.)
        /// Safe     - it doesn't expose any critical data
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        public FormattedTextSymbols(
            GlyphingCache glyphingCache, 
            TextRun       textSymbols, 
            bool          rightToLeft,
            double        scalingFactor, 
            TextFormattingMode textFormattingMode,
            bool isSideways
            )
        { 

            _textFormattingMode = textFormattingMode; 
            _isSideways = isSideways; 
            ITextSymbols  symbols = textSymbols as ITextSymbols;
 
            Debug.Assert(symbols != null);

            // break down a single text run into pieces
            IList shapeables = symbols.GetTextShapeableSymbols( 
                glyphingCache,
                textSymbols.CharacterBufferReference, 
                textSymbols.Length, 
                rightToLeft,  // This is a bool indicating the RTL
                              // based on the bidi level of text (if applicable). 
                              // For FormattedTextSymbols it is equal to paragraph flow direction.

                rightToLeft,  // This is the flow direction of the paragraph as
                              // specified by the user. DWrite needs the paragraph 
                              // flow direction of the paragraph
                              // while WPF algorithms need the RTL of the text based on 
                              // Bidi if possible. 

                null, // cultureInfo 
                null,  // textModifierScope
                _textFormattingMode,
                _isSideways
                ); 

            Debug.Assert(shapeables != null && shapeables.Count > 0); 
 
            _rightToLeft = rightToLeft;
            _glyphs = new Glyphs[shapeables.Count]; 

            CharacterBuffer charBuffer = textSymbols.CharacterBufferReference.CharacterBuffer;
            int offsetToFirstChar = textSymbols.CharacterBufferReference.OffsetToFirstChar;
 
            int i = 0;
            int ich = 0; 
 
            while (i < shapeables.Count)
            { 
                TextShapeableSymbols current = shapeables[i] as TextShapeableSymbols;
                Debug.Assert(current != null);

                int cch = current.Length; 
                int j;
 
                // make a separate character buffer for glyphrun persistence 
                char[] charArray = new char[cch];
                for (j = 0; j < cch; j++) 
                    charArray[j] = charBuffer[offsetToFirstChar + ich + j];

                if (current.IsShapingRequired)
                { 
                    ushort[] clusterMap;
                    ushort[] glyphIndices; 
                    int[] glyphAdvances; 
                    GlyphOffset[] glyphOffsets;
 

                    //

 

 
 
                    unsafe
                    { 
                        fixed (char* fixedCharArray = &charArray[0])
                        {
                            MS.Internal.Text.TextInterface.TextAnalyzer textAnalyzer = MS.Internal.FontCache.DWriteFactory.Instance.CreateTextAnalyzer();
 
                            GlyphTypeface glyphTypeface = current.GlyphTypeFace;
                            DWriteFontFeature[][] fontFeatures; 
                            uint[] fontFeatureRanges; 
                            uint unsignedCch = checked((uint)cch);
                            LSRun.CompileFeatureSet(current.Properties.TypographyProperties, unsignedCch, out fontFeatures, out fontFeatureRanges); 


                            textAnalyzer.GetGlyphsAndTheirPlacements(
                                (ushort*)fixedCharArray, 
                                unsignedCch,
                                glyphTypeface.FontDWrite, 
                                glyphTypeface.BlankGlyphIndex, 
                                false,   // no sideway support yet
                                /************************************************************************************************/ 
                                //
                                rightToLeft,
                                current.Properties.CultureInfo,
                                /************************************************************************************************/ 
                                fontFeatures,
                                fontFeatureRanges, 
                                current.Properties.FontRenderingEmSize, 
                                scalingFactor,
                                Util.PixelsPerDip, 
                                _textFormattingMode,
                                current.ItemProps,
                                out clusterMap,
                                out glyphIndices, 
                                out glyphAdvances,
                                out glyphOffsets 
                                ); 
                        }
                        _glyphs[i] = new Glyphs( 
                           current,
                           charArray,
                           glyphAdvances,
                           clusterMap, 
                           glyphIndices,
                           glyphOffsets, 
                           scalingFactor 
                           );
                    } 

                }
                else
                { 
                    // shaping not required,
                    // bypass glyphing process altogether 
                    int[] nominalAdvances = new int[charArray.Length]; 

                    unsafe 
                    {
                        fixed (char* fixedCharArray = &charArray[0])
                        fixed (int* fixedNominalAdvances = &nominalAdvances[0])
                        { 
                            current.GetAdvanceWidthsUnshaped(
                                fixedCharArray, 
                                cch, 
                                scalingFactor, // format resolution specified per em,
                                fixedNominalAdvances 
                                );
                        }
                    }
 
                    _glyphs[i] = new Glyphs(
                        current, 
                        charArray, 
                        nominalAdvances,
                        scalingFactor 
                        );
                }

                i++; 
                ich += cch;
            } 
        } 

 
        /// 
        /// Total formatted width
        /// 
        public double Width 
        {
            get 
            { 
                Debug.Assert(_glyphs != null);
 
                double width = 0;
                foreach (Glyphs glyphs in _glyphs)
                {
                    width += glyphs.Width; 
                }
                return width; 
            } 
        }
 

        /// 
        /// Draw all formatted glyphruns
        ///  
        /// drawing bounding box
        public Rect Draw( 
            DrawingContext drawingContext, 
            Point          currentOrigin
            ) 
        {
            Rect inkBoundingBox = Rect.Empty;

            Debug.Assert(_glyphs != null); 

            foreach (Glyphs glyphs in _glyphs) 
            { 
                GlyphRun glyphRun = glyphs.CreateGlyphRun(currentOrigin, _rightToLeft);
                Rect boundingBox; 

                if (glyphRun != null)
                {
                    boundingBox = glyphRun.ComputeInkBoundingBox(); 

                    if (drawingContext != null) 
                    { 
                        // Emit glyph run background.
                        glyphRun.EmitBackground(drawingContext, glyphs.BackgroundBrush); 

                        drawingContext.PushGuidelineY1(currentOrigin.Y);
                        try
                        { 
                            drawingContext.DrawGlyphRun(glyphs.ForegroundBrush, glyphRun);
                        } 
                        finally 
                        {
                            drawingContext.Pop(); 
                        }
                    }
                }
                else 
                {
                    boundingBox = Rect.Empty; 
                } 

                if (!boundingBox.IsEmpty) 
                {
                    // glyph run's ink bounding box is relative to its origin
                    boundingBox.X += glyphRun.BaselineOrigin.X;
                    boundingBox.Y += glyphRun.BaselineOrigin.Y; 
                }
 
                // accumulate overall ink bounding box 
                inkBoundingBox.Union(boundingBox);
 
                if (_rightToLeft)
                {
                    currentOrigin.X -= glyphs.Width;
                } 
                else
                { 
                    currentOrigin.X += glyphs.Width; 
                }
            } 

            return inkBoundingBox;
        }
 

        ///  
        /// All glyph properties used during GlyphRun construction 
        /// 
        ///  
        /// We should be able to get rid off this type and just store GlyphRuns
        /// once GlyphRun gets refactor'd so that it contains no drawing time
        /// positioning data inside.
        ///  
        private sealed class Glyphs
        { 
            private TextShapeableSymbols     _shapeable; 
            private char[]                   _charArray;
            private ushort[]                 _clusterMap; 
            private ushort[]                 _glyphIndices;
            private double[]                 _glyphAdvances;
            private IList             _glyphOffsets;
            private double                   _width; 

 
            ///  
            /// Construct a nominal description of glyph data
            ///  
            internal Glyphs(
                TextShapeableSymbols    shapeable,
                char[]                  charArray,
                int[]                  nominalAdvances, 
                double                  scalingFactor
                ) : 
                this( 
                    shapeable,
                    charArray, 
                    nominalAdvances,
                    null,   // clusterMap
                    null,   // glyphIndices
                    null,   // glyphOffsets 
                    scalingFactor
                    ) 
            {} 

 
            /// 
            /// Construct a full description of glyph data
            /// 
            internal Glyphs( 
                TextShapeableSymbols     shapeable,
                char[]                   charArray, 
                int[]                   glyphAdvances, 
                ushort[]                 clusterMap,
                ushort[]                 glyphIndices, 
                GlyphOffset[]            glyphOffsets,
                double                   scalingFactor
                )
            { 
                _shapeable = shapeable;
                _charArray = charArray; 
 
                // create double array for glyph run creation, because Shaping is all done in
                // ideal units. FormattedTextSymbol is used to draw text collapsing symbols 
                // which usually contains very few glyphs. Using double[] and Point[] directly
                // is more efficient.
                _glyphAdvances = new double[glyphAdvances.Length];
 
                double ToReal = 1.0 / scalingFactor;
 
                for (int i = 0; i < glyphAdvances.Length; i++) 
                {
                    _glyphAdvances[i] = glyphAdvances[i] * ToReal; 
                    _width += _glyphAdvances[i];

                }
 
                if (glyphIndices != null)
                { 
                    _clusterMap = clusterMap; 

                    if (glyphOffsets != null) 
                    {
                        _glyphOffsets  = new PartialArray(new Point[glyphOffsets.Length]);

                        for (int i = 0; i < glyphOffsets.Length; i++) 
                        {
                            _glyphOffsets[i] = new Point( 
                                glyphOffsets[i].du * ToReal, 
                                glyphOffsets[i].dv * ToReal
                                ); 
                        }
                    }

                    Debug.Assert(glyphAdvances.Length <= glyphIndices.Length); 

                    if (glyphAdvances.Length != glyphIndices.Length) 
                    { 
                        _glyphIndices = new ushort[glyphAdvances.Length];
 
                        for (int i = 0; i < glyphAdvances.Length; i++)
                        {
                            _glyphIndices[i] = glyphIndices[i];
                        } 
                    }
                    else 
                    { 
                        _glyphIndices = glyphIndices;
                    } 
                }
            }

 
            /// 
            /// Total formatted width 
            ///  
            public double Width
            { 
                get { return _width; }
            }

 
            /// 
            /// Construct a GlyphRun object given the specified drawing origin 
            ///  
            internal GlyphRun CreateGlyphRun(
                Point       currentOrigin, 
                bool        rightToLeft
                )
            {
                if (!_shapeable.IsShapingRequired) 
                {
                    return _shapeable.ComputeUnshapedGlyphRun( 
                        currentOrigin, 
                        _charArray,
                        _glyphAdvances 
                        );
                }

                return _shapeable.ComputeShapedGlyphRun( 
                    currentOrigin,
                    _charArray, 
                    _clusterMap, 
                    _glyphIndices,
                    _glyphAdvances, 
                    _glyphOffsets,
                    rightToLeft,
                    false   // sideways not yet supported
                    ); 
            }
 
            public Brush ForegroundBrush 
            {
                get { return _shapeable.Properties.ForegroundBrush; } 
            }

            public Brush BackgroundBrush
            { 
                get { return _shapeable.Properties.BackgroundBrush; }
            } 
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: 
//  Formatting a single style, single reading direction text symbols
// 
// History:
//  08/16/2004 : wchao - Created it
//
//--------------------------------------------------------------------------- 

using System; 
using System.Security; 
using System.Windows;
using System.Windows.Media; 
using System.Windows.Media.TextFormatting;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics; 
using MS.Internal;
using MS.Internal.Text.TextInterface; 
using MS.Internal.Shaping; 
using System.Globalization;
using MS.Internal.FontCache; 


namespace MS.Internal.TextFormatting
{ 
    /// 
    /// Formatted form of TextSymbols 
    ///  
    internal sealed class FormattedTextSymbols
    { 
        private Glyphs[]    _glyphs;
        private bool        _rightToLeft;
        private TextFormattingMode _textFormattingMode;
        private bool _isSideways; 

        ///  
        /// Construct a formatted run 
        /// 
        ///  
        /// Critical - this method has unsafe blocks, calls Critical methods (Instance, etc.)
        /// Safe     - it doesn't expose any critical data
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        public FormattedTextSymbols(
            GlyphingCache glyphingCache, 
            TextRun       textSymbols, 
            bool          rightToLeft,
            double        scalingFactor, 
            TextFormattingMode textFormattingMode,
            bool isSideways
            )
        { 

            _textFormattingMode = textFormattingMode; 
            _isSideways = isSideways; 
            ITextSymbols  symbols = textSymbols as ITextSymbols;
 
            Debug.Assert(symbols != null);

            // break down a single text run into pieces
            IList shapeables = symbols.GetTextShapeableSymbols( 
                glyphingCache,
                textSymbols.CharacterBufferReference, 
                textSymbols.Length, 
                rightToLeft,  // This is a bool indicating the RTL
                              // based on the bidi level of text (if applicable). 
                              // For FormattedTextSymbols it is equal to paragraph flow direction.

                rightToLeft,  // This is the flow direction of the paragraph as
                              // specified by the user. DWrite needs the paragraph 
                              // flow direction of the paragraph
                              // while WPF algorithms need the RTL of the text based on 
                              // Bidi if possible. 

                null, // cultureInfo 
                null,  // textModifierScope
                _textFormattingMode,
                _isSideways
                ); 

            Debug.Assert(shapeables != null && shapeables.Count > 0); 
 
            _rightToLeft = rightToLeft;
            _glyphs = new Glyphs[shapeables.Count]; 

            CharacterBuffer charBuffer = textSymbols.CharacterBufferReference.CharacterBuffer;
            int offsetToFirstChar = textSymbols.CharacterBufferReference.OffsetToFirstChar;
 
            int i = 0;
            int ich = 0; 
 
            while (i < shapeables.Count)
            { 
                TextShapeableSymbols current = shapeables[i] as TextShapeableSymbols;
                Debug.Assert(current != null);

                int cch = current.Length; 
                int j;
 
                // make a separate character buffer for glyphrun persistence 
                char[] charArray = new char[cch];
                for (j = 0; j < cch; j++) 
                    charArray[j] = charBuffer[offsetToFirstChar + ich + j];

                if (current.IsShapingRequired)
                { 
                    ushort[] clusterMap;
                    ushort[] glyphIndices; 
                    int[] glyphAdvances; 
                    GlyphOffset[] glyphOffsets;
 

                    //

 

 
 
                    unsafe
                    { 
                        fixed (char* fixedCharArray = &charArray[0])
                        {
                            MS.Internal.Text.TextInterface.TextAnalyzer textAnalyzer = MS.Internal.FontCache.DWriteFactory.Instance.CreateTextAnalyzer();
 
                            GlyphTypeface glyphTypeface = current.GlyphTypeFace;
                            DWriteFontFeature[][] fontFeatures; 
                            uint[] fontFeatureRanges; 
                            uint unsignedCch = checked((uint)cch);
                            LSRun.CompileFeatureSet(current.Properties.TypographyProperties, unsignedCch, out fontFeatures, out fontFeatureRanges); 


                            textAnalyzer.GetGlyphsAndTheirPlacements(
                                (ushort*)fixedCharArray, 
                                unsignedCch,
                                glyphTypeface.FontDWrite, 
                                glyphTypeface.BlankGlyphIndex, 
                                false,   // no sideway support yet
                                /************************************************************************************************/ 
                                //
                                rightToLeft,
                                current.Properties.CultureInfo,
                                /************************************************************************************************/ 
                                fontFeatures,
                                fontFeatureRanges, 
                                current.Properties.FontRenderingEmSize, 
                                scalingFactor,
                                Util.PixelsPerDip, 
                                _textFormattingMode,
                                current.ItemProps,
                                out clusterMap,
                                out glyphIndices, 
                                out glyphAdvances,
                                out glyphOffsets 
                                ); 
                        }
                        _glyphs[i] = new Glyphs( 
                           current,
                           charArray,
                           glyphAdvances,
                           clusterMap, 
                           glyphIndices,
                           glyphOffsets, 
                           scalingFactor 
                           );
                    } 

                }
                else
                { 
                    // shaping not required,
                    // bypass glyphing process altogether 
                    int[] nominalAdvances = new int[charArray.Length]; 

                    unsafe 
                    {
                        fixed (char* fixedCharArray = &charArray[0])
                        fixed (int* fixedNominalAdvances = &nominalAdvances[0])
                        { 
                            current.GetAdvanceWidthsUnshaped(
                                fixedCharArray, 
                                cch, 
                                scalingFactor, // format resolution specified per em,
                                fixedNominalAdvances 
                                );
                        }
                    }
 
                    _glyphs[i] = new Glyphs(
                        current, 
                        charArray, 
                        nominalAdvances,
                        scalingFactor 
                        );
                }

                i++; 
                ich += cch;
            } 
        } 

 
        /// 
        /// Total formatted width
        /// 
        public double Width 
        {
            get 
            { 
                Debug.Assert(_glyphs != null);
 
                double width = 0;
                foreach (Glyphs glyphs in _glyphs)
                {
                    width += glyphs.Width; 
                }
                return width; 
            } 
        }
 

        /// 
        /// Draw all formatted glyphruns
        ///  
        /// drawing bounding box
        public Rect Draw( 
            DrawingContext drawingContext, 
            Point          currentOrigin
            ) 
        {
            Rect inkBoundingBox = Rect.Empty;

            Debug.Assert(_glyphs != null); 

            foreach (Glyphs glyphs in _glyphs) 
            { 
                GlyphRun glyphRun = glyphs.CreateGlyphRun(currentOrigin, _rightToLeft);
                Rect boundingBox; 

                if (glyphRun != null)
                {
                    boundingBox = glyphRun.ComputeInkBoundingBox(); 

                    if (drawingContext != null) 
                    { 
                        // Emit glyph run background.
                        glyphRun.EmitBackground(drawingContext, glyphs.BackgroundBrush); 

                        drawingContext.PushGuidelineY1(currentOrigin.Y);
                        try
                        { 
                            drawingContext.DrawGlyphRun(glyphs.ForegroundBrush, glyphRun);
                        } 
                        finally 
                        {
                            drawingContext.Pop(); 
                        }
                    }
                }
                else 
                {
                    boundingBox = Rect.Empty; 
                } 

                if (!boundingBox.IsEmpty) 
                {
                    // glyph run's ink bounding box is relative to its origin
                    boundingBox.X += glyphRun.BaselineOrigin.X;
                    boundingBox.Y += glyphRun.BaselineOrigin.Y; 
                }
 
                // accumulate overall ink bounding box 
                inkBoundingBox.Union(boundingBox);
 
                if (_rightToLeft)
                {
                    currentOrigin.X -= glyphs.Width;
                } 
                else
                { 
                    currentOrigin.X += glyphs.Width; 
                }
            } 

            return inkBoundingBox;
        }
 

        ///  
        /// All glyph properties used during GlyphRun construction 
        /// 
        ///  
        /// We should be able to get rid off this type and just store GlyphRuns
        /// once GlyphRun gets refactor'd so that it contains no drawing time
        /// positioning data inside.
        ///  
        private sealed class Glyphs
        { 
            private TextShapeableSymbols     _shapeable; 
            private char[]                   _charArray;
            private ushort[]                 _clusterMap; 
            private ushort[]                 _glyphIndices;
            private double[]                 _glyphAdvances;
            private IList             _glyphOffsets;
            private double                   _width; 

 
            ///  
            /// Construct a nominal description of glyph data
            ///  
            internal Glyphs(
                TextShapeableSymbols    shapeable,
                char[]                  charArray,
                int[]                  nominalAdvances, 
                double                  scalingFactor
                ) : 
                this( 
                    shapeable,
                    charArray, 
                    nominalAdvances,
                    null,   // clusterMap
                    null,   // glyphIndices
                    null,   // glyphOffsets 
                    scalingFactor
                    ) 
            {} 

 
            /// 
            /// Construct a full description of glyph data
            /// 
            internal Glyphs( 
                TextShapeableSymbols     shapeable,
                char[]                   charArray, 
                int[]                   glyphAdvances, 
                ushort[]                 clusterMap,
                ushort[]                 glyphIndices, 
                GlyphOffset[]            glyphOffsets,
                double                   scalingFactor
                )
            { 
                _shapeable = shapeable;
                _charArray = charArray; 
 
                // create double array for glyph run creation, because Shaping is all done in
                // ideal units. FormattedTextSymbol is used to draw text collapsing symbols 
                // which usually contains very few glyphs. Using double[] and Point[] directly
                // is more efficient.
                _glyphAdvances = new double[glyphAdvances.Length];
 
                double ToReal = 1.0 / scalingFactor;
 
                for (int i = 0; i < glyphAdvances.Length; i++) 
                {
                    _glyphAdvances[i] = glyphAdvances[i] * ToReal; 
                    _width += _glyphAdvances[i];

                }
 
                if (glyphIndices != null)
                { 
                    _clusterMap = clusterMap; 

                    if (glyphOffsets != null) 
                    {
                        _glyphOffsets  = new PartialArray(new Point[glyphOffsets.Length]);

                        for (int i = 0; i < glyphOffsets.Length; i++) 
                        {
                            _glyphOffsets[i] = new Point( 
                                glyphOffsets[i].du * ToReal, 
                                glyphOffsets[i].dv * ToReal
                                ); 
                        }
                    }

                    Debug.Assert(glyphAdvances.Length <= glyphIndices.Length); 

                    if (glyphAdvances.Length != glyphIndices.Length) 
                    { 
                        _glyphIndices = new ushort[glyphAdvances.Length];
 
                        for (int i = 0; i < glyphAdvances.Length; i++)
                        {
                            _glyphIndices[i] = glyphIndices[i];
                        } 
                    }
                    else 
                    { 
                        _glyphIndices = glyphIndices;
                    } 
                }
            }

 
            /// 
            /// Total formatted width 
            ///  
            public double Width
            { 
                get { return _width; }
            }

 
            /// 
            /// Construct a GlyphRun object given the specified drawing origin 
            ///  
            internal GlyphRun CreateGlyphRun(
                Point       currentOrigin, 
                bool        rightToLeft
                )
            {
                if (!_shapeable.IsShapingRequired) 
                {
                    return _shapeable.ComputeUnshapedGlyphRun( 
                        currentOrigin, 
                        _charArray,
                        _glyphAdvances 
                        );
                }

                return _shapeable.ComputeShapedGlyphRun( 
                    currentOrigin,
                    _charArray, 
                    _clusterMap, 
                    _glyphIndices,
                    _glyphAdvances, 
                    _glyphOffsets,
                    rightToLeft,
                    false   // sideways not yet supported
                    ); 
            }
 
            public Brush ForegroundBrush 
            {
                get { return _shapeable.Properties.ForegroundBrush; } 
            }

            public Brush BackgroundBrush
            { 
                get { return _shapeable.Properties.BackgroundBrush; }
            } 
        } 
    }
} 

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