TextShapeableCharacters.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 / TextShapeableCharacters.cs / 1599983 / TextShapeableCharacters.cs

                            //------------------------------------------------------------------------ 
//
//  Microsoft Windows Client Platform
//  Copyright (C) Microsoft Corporation
// 
//  File:      TextShapeableCharacters.cs
// 
//  Contents:  Implementation of text shapeable symbols for characters 
//
//  Spec:      http://team/sites/Avalon/Specs/Text%20Formatting%20API.doc 
//
//  Created:   1-2-2004 Worachai Chaoweeraprasit (wchao)
//  History:  1-19-2004 garyyyang: Change the class to internal
// 
//-----------------------------------------------------------------------
 
 
using System;
using System.Diagnostics; 
using System.Globalization;
using System.Collections;
using System.Collections.Generic;
using System.Security; 
using System.Windows;
using System.Windows.Markup;    // for XmlLanguage 
using System.Windows.Media; 
using MS.Internal;
using MS.Internal.FontCache; 
using MS.Internal.TextFormatting;
using MS.Internal.Shaping;
using MS.Internal.Text.TextInterface;
 
namespace System.Windows.Media.TextFormatting
{ 
    ///  
    /// A specialized TextShapeableSymbols implemented by TextFormatter to represent
    /// a collection of glyphs from a physical typeface. 
    /// 
    internal sealed class TextShapeableCharacters : TextShapeableSymbols
    {
        private CharacterBufferRange    _characterBufferRange; 
        private TextFormattingMode      _textFormattingMode;
        private bool                    _isSideways; 
        private TextRunProperties       _properties; 
        private double                  _emSize;    // after-scaled
 
        private ItemProps               _textItem;
        private ShapeTypeface           _shapeTypeface;
        private bool                    _nullShape;
 
        #region Constructors
 
        ///  
        /// Construct a shapeable characters object
        ///  
        /// 
        /// The shapeTypeface parameter can be null if and only if CheckFastPathNominalGlyphs
        /// has previously returned true.
        ///  
        internal TextShapeableCharacters(
            CharacterBufferRange    characterRange, 
            TextRunProperties       properties, 
            double                  emSize,
            ItemProps               textItem, 
            ShapeTypeface           shapeTypeface,
            bool                    nullShape,
            TextFormattingMode      textFormattingMode,
            bool isSideways 
            )
        { 
            _isSideways = isSideways; 
            _textFormattingMode = textFormattingMode;
            _characterBufferRange = characterRange; 
            _properties = properties;
            _emSize = emSize;
            _textItem = textItem;
            _shapeTypeface = shapeTypeface; 
            _nullShape = nullShape;
        } 
 
        #endregion
 
        #region TextRun implementation

        /// 
        /// Character reference 
        /// 
        public sealed override CharacterBufferReference CharacterBufferReference 
        { 
            get
            { 
                return _characterBufferRange.CharacterBufferReference;
            }
        }
 

        ///  
        /// Character length of the run 
        /// 
        public sealed override int Length 
        {
            get
            {
                return _characterBufferRange.Length; 
            }
        } 
 

        ///  
        /// A set of properties shared by every characters in the run
        /// 
        public sealed override TextRunProperties Properties
        { 
            get
            { 
                return _properties; 
            }
        } 

        #endregion

 
        #region TextShapeableSymbols implementation
 
        ///  
        /// Compute a shaped glyph run object from specified glyph-based info
        ///  
        internal sealed override GlyphRun ComputeShapedGlyphRun(
            Point                    origin,
            char[]                   characterString,
            ushort[]                 clusterMap, 
            ushort[]                 glyphIndices,
            IList            glyphAdvances, 
            IList             glyphOffsets, 
            bool                     rightToLeft,
            bool                     sideways 
            )
        {
            Invariant.Assert(_shapeTypeface != null);
            Invariant.Assert(glyphIndices   != null); 
            // Device fonts are only used through the LS non-glyphed code path. Only when a DigitCulture is set
            // will a potential device font be ignored and come through shaping. 
            Invariant.Assert(_shapeTypeface.DeviceFont == null  || _textItem.DigitCulture != null); 

            bool[] caretStops = null; 

            if (    clusterMap != null
                &&  (HasExtendedCharacter || NeedsCaretInfo)
                ) 
            {
                caretStops = new bool[clusterMap.Length + 1]; 
 
                // caret stops at cluster boundaries, the first and the last entries are always set
                caretStops[0] = true; 
                caretStops[clusterMap.Length] = true;

                ushort lastGlyph = clusterMap[0];
 
                for (int i = 1; i < clusterMap.Length; i++)
                { 
                    ushort glyph = clusterMap[i]; 

                    if (glyph != lastGlyph) 
                    {
                        caretStops[i] = true;
                        lastGlyph = glyph;
                    } 
                }
            } 
 
            return GlyphRun.TryCreate(
                _shapeTypeface.GlyphTypeface, 
                (rightToLeft ? 1 : 0),
                sideways,
                _emSize,
                glyphIndices, 
                origin,
                glyphAdvances, 
                glyphOffsets, 
                characterString,
                null, 
                clusterMap,
                caretStops,
                XmlLanguage.GetLanguage(CultureMapper.GetSpecificCulture(_properties.CultureInfo).IetfLanguageTag),
                _textFormattingMode 
                );
        } 
 
        private GlyphTypeface GetGlyphTypeface(out bool nullFont)
        { 
            GlyphTypeface glyphTypeface;

            if (_shapeTypeface == null)
            { 
                // We're in the optimized path where the GlyphTypeface depends only
                // on the Typeface, not on the particular input characters. 
                Typeface typeface = _properties.Typeface; 

                // Get the GlyphTypeface. 
                glyphTypeface = typeface.TryGetGlyphTypeface();

                // If Typeface does not specify *any* valid font family, then we use
                // the GlyphTypeface for Arial but only to display missing glyphs. 
                nullFont = typeface.NullFont;
            } 
            else 
            {
                // Font linking has mapped the input to a specific GlyphTypeface. 
                glyphTypeface = _shapeTypeface.GlyphTypeface;

                // If font linking could not find *any* physical font family, then we
                // use the GlyphTypeface for Arial but only to display missing glyphs. 
                nullFont = _nullShape;
            } 
 
            Invariant.Assert(glyphTypeface != null);
            return glyphTypeface; 
        }

        /// 
        /// Compute unshaped glyph run object from the specified character-based info 
        /// 
        internal sealed override GlyphRun ComputeUnshapedGlyphRun( 
            Point         origin, 
            char[]        characterString,
            IList characterAdvances 
            )
        {
            bool nullFont;
            GlyphTypeface glyphTypeface = GetGlyphTypeface(out nullFont); 
            Invariant.Assert(glyphTypeface != null);
 
            return glyphTypeface.ComputeUnshapedGlyphRun( 
                origin,
                new CharacterBufferRange( 
                    characterString,
                    0,  // offsetToFirstChar
                    characterString.Length
                    ), 
                characterAdvances,
                _emSize, 
                _properties.FontHintingEmSize, 
                nullFont,
                CultureMapper.GetSpecificCulture(_properties.CultureInfo), 
                (_shapeTypeface == null  ||  _shapeTypeface.DeviceFont == null) ? null : _shapeTypeface.DeviceFont.Name,
                _textFormattingMode
            );
        } 

 
        ///  
        /// Draw glyph run to the drawing surface
        ///  
        internal sealed override void Draw(
            DrawingContext      drawingContext,
            Brush               foregroundBrush,
            GlyphRun            glyphRun 
            )
        { 
            if (drawingContext == null) 
                throw new ArgumentNullException("drawingContext");
 
            glyphRun.EmitBackground(drawingContext, _properties.BackgroundBrush);

            drawingContext.DrawGlyphRun(
                foregroundBrush != null ? foregroundBrush : _properties.ForegroundBrush, 
                glyphRun
                ); 
        } 

        internal override double EmSize 
        {
            get
            {
                return _emSize; 
            }
        } 
 
        internal override MS.Internal.Text.TextInterface.ItemProps ItemProps
        { 
            get
            {
                return _textItem;
            } 
        }
 
        ///  
        /// Get advance widths of unshaped characters
        ///  
        /// 
        ///    Critical: This code deals with pointers and calls SC methods like GetAdvanceWidthsUnshaped
        /// 
        [SecurityCritical] 
        internal sealed override unsafe void GetAdvanceWidthsUnshaped(
            char*         characterString, 
            int           characterLength, 
            double        scalingFactor,
            int*          advanceWidthsUnshaped 
            )
        {
            if (!IsShapingRequired)
            { 
                if (    (_shapeTypeface            != null)
                    &&  (_shapeTypeface.DeviceFont != null)) 
                { 
                    // Use device font to compute advance widths
                    _shapeTypeface.DeviceFont.GetAdvanceWidths( 
                        characterString,
                        characterLength,
                        _emSize * scalingFactor,
                        advanceWidthsUnshaped 
                    );
                } 
                else 
                {
                    bool nullFont; 
                    GlyphTypeface glyphTypeface = GetGlyphTypeface(out nullFont);
                    Invariant.Assert(glyphTypeface != null);

                    glyphTypeface.GetAdvanceWidthsUnshaped( 
                        characterString,
                        characterLength, 
                        _emSize, 
                        scalingFactor,
                        advanceWidthsUnshaped, 
                        nullFont,
                        _textFormattingMode,
                        _isSideways
                        ); 
                }
            } 
            else 
            {
                GlyphTypeface glyphTypeface = _shapeTypeface.GlyphTypeface; 

                Invariant.Assert(glyphTypeface != null);
                Invariant.Assert(characterLength > 0);
 
                CharacterBufferRange newBuffer = new CharacterBufferRange(characterString, characterLength);
                MS.Internal.Text.TextInterface.GlyphMetrics[] glyphMetrics = BufferCache.GetGlyphMetrics(characterLength); 
 
                glyphTypeface.GetGlyphMetricsOptimized(newBuffer,
                                                       _emSize, 
                                                       _textFormattingMode,
                                                       _isSideways,
                                                       glyphMetrics
                                                       ); 

                double designToEm = _emSize * scalingFactor / glyphTypeface.DesignEmHeight; 
 
                for (int i = 0; i < characterLength; i++)
                { 
                    advanceWidthsUnshaped[i] = (int)Math.Round(glyphMetrics[i].AdvanceWidth * designToEm);
                }

                BufferCache.ReleaseGlyphMetrics(glyphMetrics); 
            }
        } 
 
        /// 
        /// This is needed to decide whether we should pass a max cluster size to LS. 
        /// We pass a max cluster size to LS to perform line breaking correctly.
        /// Passing a max cluster size larger than necessary will have impact on perf.
        /// 
        internal sealed override bool NeedsMaxClusterSize 
        {
            get 
            { 
                //  We will need to pass a max cluster size to LS if:
                //  1) the script is not Latin (hence more likely to formed into ligature) 
                //  2) or the run contains combining mark or extended characters
                if (!_textItem.IsLatin ||
                    _textItem.HasCombiningMark ||
                    _textItem.HasExtendedCharacter 
                    )
                { 
                    return true; 
                }
 
                return false;
            }
        }
 
        /// 
        /// Return value indicates whether two runs can shape together 
        ///  
        internal sealed override bool CanShapeTogether(
            TextShapeableSymbols   shapeable 
            )
        {
            TextShapeableCharacters charShape = shapeable as TextShapeableCharacters;
 
            if (charShape == null)
                return false; 
 
            return
                    _shapeTypeface.Equals(charShape._shapeTypeface) 
                // Extended characters need to be shaped by surrogate shaper. They cannot be shaped together with non-exteneded characters.
                && (_textItem.HasExtendedCharacter) == (charShape._textItem.HasExtendedCharacter)
                && _emSize == charShape._emSize
                && ( 
                    _properties.CultureInfo == null ?
                        charShape._properties.CultureInfo == null 
                      : _properties.CultureInfo.Equals(charShape._properties.CultureInfo) 
                    )
                && _nullShape == charShape._nullShape 
                && (_textItem.CanShapeTogether(charShape._textItem));
        }

 
        /// 
        /// Indicate whether run cannot be treated as simple characters because shaping is required. 
        /// 
        /// The following cases use simple rendering without shaping:
        ///   o  No _shapeTypeface. This happens in very simple rendering cases. 
        ///   o  Non-Unicode (i.e. symbol) fonts.
        ///   o  When using a device font.
        ///
        /// Note that the presence of a device font in _shapeTypeface.DeviceFont implies use of 
        /// a device font in all cases except where digit substitution applies. This special
        /// case occurs because the cached result per codepoint of TypefaceMap must include the device font 
        /// for non-western digits in order to support device font rendering of the non-Western 
        /// digit Unicode codepoints. The device font is not used however when the non-Western digits
        /// are displayed as a result of digit substitution from backing store Western digits. 
        /// 
        internal sealed override bool IsShapingRequired
        {
            get 
            {
                return 
                        (_shapeTypeface != null)                 // Can't use shaping without a shape typeface 
                    &&  (    (_shapeTypeface.DeviceFont == null) // Can't use shaping when rendering with a device font
                         ||  (_textItem.DigitCulture != null))   //   -- unless substituting digits 
                    &&  (!IsSymbol);                             // Can't use shaping for symbol (non-Unicode) fonts
            }
        }
 

        ///  
        /// A Boolean value indicates whether additional info is required for caret positioning 
        /// 
        internal sealed override bool NeedsCaretInfo 
        {
            get
            {
                return (_textItem.HasCombiningMark) 
                    || (_textItem.NeedsCaretInfo);
            } 
        } 

 
        /// 
        /// A Boolean value indicates whether run has extended character
        /// 
        internal sealed override bool HasExtendedCharacter 
        {
            get 
            { 
                return _textItem.HasExtendedCharacter;
            } 
        }


        ///  
        /// Run height
        ///  
        internal sealed override double Height 
        {
            get 
            {
                return _properties.Typeface.LineSpacing(_properties.FontRenderingEmSize, 1, Util.PixelsPerDip, _textFormattingMode);
            }
        } 

 
        ///  
        /// Distance from top to baseline
        ///  
        internal sealed override double Baseline
        {
            get
            { 
                return _properties.Typeface.Baseline(_properties.FontRenderingEmSize, 1, Util.PixelsPerDip, _textFormattingMode);
            } 
        } 

 
        /// 
        /// Distance from baseline to underline position relative to TextRunProperties.FontRenderingEmSize
        /// 
        internal sealed override double UnderlinePosition 
        {
            get 
            { 
                return _properties.Typeface.UnderlinePosition;
            } 
        }


        ///  
        /// Underline thickness relative to TextRunProperties.FontRenderingEmSize
        ///  
        internal sealed override double UnderlineThickness 
        {
            get 
            {
                return _properties.Typeface.UnderlineThickness;
            }
        } 

 
        ///  
        /// Distance from baseline to strike-through position relative to TextRunProperties.FontRenderingEmSize
        ///  
        internal sealed override double StrikethroughPosition
        {
            get
            { 
                return _properties.Typeface.StrikethroughPosition;
            } 
        } 

 
        /// 
        /// strike-through thickness relative to TextRunProperties.FontRenderingEmSize
        /// 
        internal sealed override double StrikethroughThickness 
        {
            get 
            { 
                return _properties.Typeface.StrikethroughThickness;
            } 
        }

        #endregion
 

        ///  
        /// Whether all characters in this run are non-Unicode character (symbol) 
        /// 
        internal bool IsSymbol 
        {
            get
            {
                if (_shapeTypeface != null) 
                    return _shapeTypeface.GlyphTypeface.Symbol;
 
                return _properties.Typeface.Symbol; 
            }
        } 

        internal override GlyphTypeface GlyphTypeFace
        {
            get 
            {
                if (_shapeTypeface != null) 
                    return _shapeTypeface.GlyphTypeface; 

                return _properties.Typeface.TryGetGlyphTypeface(); 
            }
        }

        ///  
        /// Returns maximum possible cluster size for the run.  Normally, this
        /// is 8 characters, but Indic scripts require this to be 15. 
        ///  
        internal const ushort DefaultMaxClusterSize = 8;
        private  const ushort IndicMaxClusterSize = 15; 
        internal sealed override ushort MaxClusterSize
        {
            get
            { 
                if (_textItem.IsIndic)
                { 
                    return IndicMaxClusterSize; 
                }
 
                return DefaultMaxClusterSize;
            }

        } 
    }
} 
 

// 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:      TextShapeableCharacters.cs
// 
//  Contents:  Implementation of text shapeable symbols for characters 
//
//  Spec:      http://team/sites/Avalon/Specs/Text%20Formatting%20API.doc 
//
//  Created:   1-2-2004 Worachai Chaoweeraprasit (wchao)
//  History:  1-19-2004 garyyyang: Change the class to internal
// 
//-----------------------------------------------------------------------
 
 
using System;
using System.Diagnostics; 
using System.Globalization;
using System.Collections;
using System.Collections.Generic;
using System.Security; 
using System.Windows;
using System.Windows.Markup;    // for XmlLanguage 
using System.Windows.Media; 
using MS.Internal;
using MS.Internal.FontCache; 
using MS.Internal.TextFormatting;
using MS.Internal.Shaping;
using MS.Internal.Text.TextInterface;
 
namespace System.Windows.Media.TextFormatting
{ 
    ///  
    /// A specialized TextShapeableSymbols implemented by TextFormatter to represent
    /// a collection of glyphs from a physical typeface. 
    /// 
    internal sealed class TextShapeableCharacters : TextShapeableSymbols
    {
        private CharacterBufferRange    _characterBufferRange; 
        private TextFormattingMode      _textFormattingMode;
        private bool                    _isSideways; 
        private TextRunProperties       _properties; 
        private double                  _emSize;    // after-scaled
 
        private ItemProps               _textItem;
        private ShapeTypeface           _shapeTypeface;
        private bool                    _nullShape;
 
        #region Constructors
 
        ///  
        /// Construct a shapeable characters object
        ///  
        /// 
        /// The shapeTypeface parameter can be null if and only if CheckFastPathNominalGlyphs
        /// has previously returned true.
        ///  
        internal TextShapeableCharacters(
            CharacterBufferRange    characterRange, 
            TextRunProperties       properties, 
            double                  emSize,
            ItemProps               textItem, 
            ShapeTypeface           shapeTypeface,
            bool                    nullShape,
            TextFormattingMode      textFormattingMode,
            bool isSideways 
            )
        { 
            _isSideways = isSideways; 
            _textFormattingMode = textFormattingMode;
            _characterBufferRange = characterRange; 
            _properties = properties;
            _emSize = emSize;
            _textItem = textItem;
            _shapeTypeface = shapeTypeface; 
            _nullShape = nullShape;
        } 
 
        #endregion
 
        #region TextRun implementation

        /// 
        /// Character reference 
        /// 
        public sealed override CharacterBufferReference CharacterBufferReference 
        { 
            get
            { 
                return _characterBufferRange.CharacterBufferReference;
            }
        }
 

        ///  
        /// Character length of the run 
        /// 
        public sealed override int Length 
        {
            get
            {
                return _characterBufferRange.Length; 
            }
        } 
 

        ///  
        /// A set of properties shared by every characters in the run
        /// 
        public sealed override TextRunProperties Properties
        { 
            get
            { 
                return _properties; 
            }
        } 

        #endregion

 
        #region TextShapeableSymbols implementation
 
        ///  
        /// Compute a shaped glyph run object from specified glyph-based info
        ///  
        internal sealed override GlyphRun ComputeShapedGlyphRun(
            Point                    origin,
            char[]                   characterString,
            ushort[]                 clusterMap, 
            ushort[]                 glyphIndices,
            IList            glyphAdvances, 
            IList             glyphOffsets, 
            bool                     rightToLeft,
            bool                     sideways 
            )
        {
            Invariant.Assert(_shapeTypeface != null);
            Invariant.Assert(glyphIndices   != null); 
            // Device fonts are only used through the LS non-glyphed code path. Only when a DigitCulture is set
            // will a potential device font be ignored and come through shaping. 
            Invariant.Assert(_shapeTypeface.DeviceFont == null  || _textItem.DigitCulture != null); 

            bool[] caretStops = null; 

            if (    clusterMap != null
                &&  (HasExtendedCharacter || NeedsCaretInfo)
                ) 
            {
                caretStops = new bool[clusterMap.Length + 1]; 
 
                // caret stops at cluster boundaries, the first and the last entries are always set
                caretStops[0] = true; 
                caretStops[clusterMap.Length] = true;

                ushort lastGlyph = clusterMap[0];
 
                for (int i = 1; i < clusterMap.Length; i++)
                { 
                    ushort glyph = clusterMap[i]; 

                    if (glyph != lastGlyph) 
                    {
                        caretStops[i] = true;
                        lastGlyph = glyph;
                    } 
                }
            } 
 
            return GlyphRun.TryCreate(
                _shapeTypeface.GlyphTypeface, 
                (rightToLeft ? 1 : 0),
                sideways,
                _emSize,
                glyphIndices, 
                origin,
                glyphAdvances, 
                glyphOffsets, 
                characterString,
                null, 
                clusterMap,
                caretStops,
                XmlLanguage.GetLanguage(CultureMapper.GetSpecificCulture(_properties.CultureInfo).IetfLanguageTag),
                _textFormattingMode 
                );
        } 
 
        private GlyphTypeface GetGlyphTypeface(out bool nullFont)
        { 
            GlyphTypeface glyphTypeface;

            if (_shapeTypeface == null)
            { 
                // We're in the optimized path where the GlyphTypeface depends only
                // on the Typeface, not on the particular input characters. 
                Typeface typeface = _properties.Typeface; 

                // Get the GlyphTypeface. 
                glyphTypeface = typeface.TryGetGlyphTypeface();

                // If Typeface does not specify *any* valid font family, then we use
                // the GlyphTypeface for Arial but only to display missing glyphs. 
                nullFont = typeface.NullFont;
            } 
            else 
            {
                // Font linking has mapped the input to a specific GlyphTypeface. 
                glyphTypeface = _shapeTypeface.GlyphTypeface;

                // If font linking could not find *any* physical font family, then we
                // use the GlyphTypeface for Arial but only to display missing glyphs. 
                nullFont = _nullShape;
            } 
 
            Invariant.Assert(glyphTypeface != null);
            return glyphTypeface; 
        }

        /// 
        /// Compute unshaped glyph run object from the specified character-based info 
        /// 
        internal sealed override GlyphRun ComputeUnshapedGlyphRun( 
            Point         origin, 
            char[]        characterString,
            IList characterAdvances 
            )
        {
            bool nullFont;
            GlyphTypeface glyphTypeface = GetGlyphTypeface(out nullFont); 
            Invariant.Assert(glyphTypeface != null);
 
            return glyphTypeface.ComputeUnshapedGlyphRun( 
                origin,
                new CharacterBufferRange( 
                    characterString,
                    0,  // offsetToFirstChar
                    characterString.Length
                    ), 
                characterAdvances,
                _emSize, 
                _properties.FontHintingEmSize, 
                nullFont,
                CultureMapper.GetSpecificCulture(_properties.CultureInfo), 
                (_shapeTypeface == null  ||  _shapeTypeface.DeviceFont == null) ? null : _shapeTypeface.DeviceFont.Name,
                _textFormattingMode
            );
        } 

 
        ///  
        /// Draw glyph run to the drawing surface
        ///  
        internal sealed override void Draw(
            DrawingContext      drawingContext,
            Brush               foregroundBrush,
            GlyphRun            glyphRun 
            )
        { 
            if (drawingContext == null) 
                throw new ArgumentNullException("drawingContext");
 
            glyphRun.EmitBackground(drawingContext, _properties.BackgroundBrush);

            drawingContext.DrawGlyphRun(
                foregroundBrush != null ? foregroundBrush : _properties.ForegroundBrush, 
                glyphRun
                ); 
        } 

        internal override double EmSize 
        {
            get
            {
                return _emSize; 
            }
        } 
 
        internal override MS.Internal.Text.TextInterface.ItemProps ItemProps
        { 
            get
            {
                return _textItem;
            } 
        }
 
        ///  
        /// Get advance widths of unshaped characters
        ///  
        /// 
        ///    Critical: This code deals with pointers and calls SC methods like GetAdvanceWidthsUnshaped
        /// 
        [SecurityCritical] 
        internal sealed override unsafe void GetAdvanceWidthsUnshaped(
            char*         characterString, 
            int           characterLength, 
            double        scalingFactor,
            int*          advanceWidthsUnshaped 
            )
        {
            if (!IsShapingRequired)
            { 
                if (    (_shapeTypeface            != null)
                    &&  (_shapeTypeface.DeviceFont != null)) 
                { 
                    // Use device font to compute advance widths
                    _shapeTypeface.DeviceFont.GetAdvanceWidths( 
                        characterString,
                        characterLength,
                        _emSize * scalingFactor,
                        advanceWidthsUnshaped 
                    );
                } 
                else 
                {
                    bool nullFont; 
                    GlyphTypeface glyphTypeface = GetGlyphTypeface(out nullFont);
                    Invariant.Assert(glyphTypeface != null);

                    glyphTypeface.GetAdvanceWidthsUnshaped( 
                        characterString,
                        characterLength, 
                        _emSize, 
                        scalingFactor,
                        advanceWidthsUnshaped, 
                        nullFont,
                        _textFormattingMode,
                        _isSideways
                        ); 
                }
            } 
            else 
            {
                GlyphTypeface glyphTypeface = _shapeTypeface.GlyphTypeface; 

                Invariant.Assert(glyphTypeface != null);
                Invariant.Assert(characterLength > 0);
 
                CharacterBufferRange newBuffer = new CharacterBufferRange(characterString, characterLength);
                MS.Internal.Text.TextInterface.GlyphMetrics[] glyphMetrics = BufferCache.GetGlyphMetrics(characterLength); 
 
                glyphTypeface.GetGlyphMetricsOptimized(newBuffer,
                                                       _emSize, 
                                                       _textFormattingMode,
                                                       _isSideways,
                                                       glyphMetrics
                                                       ); 

                double designToEm = _emSize * scalingFactor / glyphTypeface.DesignEmHeight; 
 
                for (int i = 0; i < characterLength; i++)
                { 
                    advanceWidthsUnshaped[i] = (int)Math.Round(glyphMetrics[i].AdvanceWidth * designToEm);
                }

                BufferCache.ReleaseGlyphMetrics(glyphMetrics); 
            }
        } 
 
        /// 
        /// This is needed to decide whether we should pass a max cluster size to LS. 
        /// We pass a max cluster size to LS to perform line breaking correctly.
        /// Passing a max cluster size larger than necessary will have impact on perf.
        /// 
        internal sealed override bool NeedsMaxClusterSize 
        {
            get 
            { 
                //  We will need to pass a max cluster size to LS if:
                //  1) the script is not Latin (hence more likely to formed into ligature) 
                //  2) or the run contains combining mark or extended characters
                if (!_textItem.IsLatin ||
                    _textItem.HasCombiningMark ||
                    _textItem.HasExtendedCharacter 
                    )
                { 
                    return true; 
                }
 
                return false;
            }
        }
 
        /// 
        /// Return value indicates whether two runs can shape together 
        ///  
        internal sealed override bool CanShapeTogether(
            TextShapeableSymbols   shapeable 
            )
        {
            TextShapeableCharacters charShape = shapeable as TextShapeableCharacters;
 
            if (charShape == null)
                return false; 
 
            return
                    _shapeTypeface.Equals(charShape._shapeTypeface) 
                // Extended characters need to be shaped by surrogate shaper. They cannot be shaped together with non-exteneded characters.
                && (_textItem.HasExtendedCharacter) == (charShape._textItem.HasExtendedCharacter)
                && _emSize == charShape._emSize
                && ( 
                    _properties.CultureInfo == null ?
                        charShape._properties.CultureInfo == null 
                      : _properties.CultureInfo.Equals(charShape._properties.CultureInfo) 
                    )
                && _nullShape == charShape._nullShape 
                && (_textItem.CanShapeTogether(charShape._textItem));
        }

 
        /// 
        /// Indicate whether run cannot be treated as simple characters because shaping is required. 
        /// 
        /// The following cases use simple rendering without shaping:
        ///   o  No _shapeTypeface. This happens in very simple rendering cases. 
        ///   o  Non-Unicode (i.e. symbol) fonts.
        ///   o  When using a device font.
        ///
        /// Note that the presence of a device font in _shapeTypeface.DeviceFont implies use of 
        /// a device font in all cases except where digit substitution applies. This special
        /// case occurs because the cached result per codepoint of TypefaceMap must include the device font 
        /// for non-western digits in order to support device font rendering of the non-Western 
        /// digit Unicode codepoints. The device font is not used however when the non-Western digits
        /// are displayed as a result of digit substitution from backing store Western digits. 
        /// 
        internal sealed override bool IsShapingRequired
        {
            get 
            {
                return 
                        (_shapeTypeface != null)                 // Can't use shaping without a shape typeface 
                    &&  (    (_shapeTypeface.DeviceFont == null) // Can't use shaping when rendering with a device font
                         ||  (_textItem.DigitCulture != null))   //   -- unless substituting digits 
                    &&  (!IsSymbol);                             // Can't use shaping for symbol (non-Unicode) fonts
            }
        }
 

        ///  
        /// A Boolean value indicates whether additional info is required for caret positioning 
        /// 
        internal sealed override bool NeedsCaretInfo 
        {
            get
            {
                return (_textItem.HasCombiningMark) 
                    || (_textItem.NeedsCaretInfo);
            } 
        } 

 
        /// 
        /// A Boolean value indicates whether run has extended character
        /// 
        internal sealed override bool HasExtendedCharacter 
        {
            get 
            { 
                return _textItem.HasExtendedCharacter;
            } 
        }


        ///  
        /// Run height
        ///  
        internal sealed override double Height 
        {
            get 
            {
                return _properties.Typeface.LineSpacing(_properties.FontRenderingEmSize, 1, Util.PixelsPerDip, _textFormattingMode);
            }
        } 

 
        ///  
        /// Distance from top to baseline
        ///  
        internal sealed override double Baseline
        {
            get
            { 
                return _properties.Typeface.Baseline(_properties.FontRenderingEmSize, 1, Util.PixelsPerDip, _textFormattingMode);
            } 
        } 

 
        /// 
        /// Distance from baseline to underline position relative to TextRunProperties.FontRenderingEmSize
        /// 
        internal sealed override double UnderlinePosition 
        {
            get 
            { 
                return _properties.Typeface.UnderlinePosition;
            } 
        }


        ///  
        /// Underline thickness relative to TextRunProperties.FontRenderingEmSize
        ///  
        internal sealed override double UnderlineThickness 
        {
            get 
            {
                return _properties.Typeface.UnderlineThickness;
            }
        } 

 
        ///  
        /// Distance from baseline to strike-through position relative to TextRunProperties.FontRenderingEmSize
        ///  
        internal sealed override double StrikethroughPosition
        {
            get
            { 
                return _properties.Typeface.StrikethroughPosition;
            } 
        } 

 
        /// 
        /// strike-through thickness relative to TextRunProperties.FontRenderingEmSize
        /// 
        internal sealed override double StrikethroughThickness 
        {
            get 
            { 
                return _properties.Typeface.StrikethroughThickness;
            } 
        }

        #endregion
 

        ///  
        /// Whether all characters in this run are non-Unicode character (symbol) 
        /// 
        internal bool IsSymbol 
        {
            get
            {
                if (_shapeTypeface != null) 
                    return _shapeTypeface.GlyphTypeface.Symbol;
 
                return _properties.Typeface.Symbol; 
            }
        } 

        internal override GlyphTypeface GlyphTypeFace
        {
            get 
            {
                if (_shapeTypeface != null) 
                    return _shapeTypeface.GlyphTypeface; 

                return _properties.Typeface.TryGetGlyphTypeface(); 
            }
        }

        ///  
        /// Returns maximum possible cluster size for the run.  Normally, this
        /// is 8 characters, but Indic scripts require this to be 15. 
        ///  
        internal const ushort DefaultMaxClusterSize = 8;
        private  const ushort IndicMaxClusterSize = 15; 
        internal sealed override ushort MaxClusterSize
        {
            get
            { 
                if (_textItem.IsIndic)
                { 
                    return IndicMaxClusterSize; 
                }
 
                return DefaultMaxClusterSize;
            }

        } 
    }
} 
 

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