LineServicesRun.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Core / CSharp / MS / Internal / TextFormatting / LineServicesRun.cs / 1 / LineServicesRun.cs

                            //------------------------------------------------------------------------ 
//
//  Microsoft Windows Client Platform
//  Copyright (C) Microsoft Corporation, 2001
// 
//  File:      LSRun.cs
// 
//  Contents:  Text run in a full text line 
//
//  Created:   9-6-2001 Worachai Chaoweeraprasit (wchao) 
//
//-----------------------------------------------------------------------

using System; 
using System.Collections;
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Runtime.InteropServices;
using System.Windows; 
using System.Windows.Media;
using System.Windows.Media.TextFormatting;
using System.Globalization;
 
using System.Security;
using System.Security.Permissions; 
using MS.Internal.Shaping; 
using MS.Internal.FontCache;
using MS.Utility; 

using SR=MS.Internal.PresentationCore.SR;
using SRID=MS.Internal.PresentationCore.SRID;
 
namespace MS.Internal.TextFormatting
{ 
    ///  
    /// Run represented by a plsrun value dispatched to LS during FetchRun
    ///  
    internal sealed class LSRun
    {
        private TextRunInfo             _runInfo;                   // TextRun Info of the text
        private Plsrun                  _type;                      // Plsrun used as run type 
        private int                     _offsetToFirstCp;           // dcp from line's cpFirst
        private int                     _textRunLength;             // textrun length 
        private CharacterBufferRange    _charBufferRange;           // character buffer range 
        private int                     _baselineOffset;            // distance from top to baseline
        private int                     _height;                    // height 
        private int                     _baselineMoveOffset;        // run is moved by this offset from baseline
        private int                     _emSize;                    // run ideal EM size
        private TextShapeableSymbols    _shapeable;                 // shapeable run
        private ushort                  _charFlags;                 // character attribute flags 
        private byte                    _bidiLevel;                 // resolved bidi level
        private IList       _textEffects;               // TextEffects that should be applied for this run 
 

        ///  
        /// Construct an lsrun
        /// 
        internal LSRun(
            TextRunInfo             runInfo, 
            IList       textEffects,
            Plsrun                  type, 
            int                     offsetToFirstCp, 
            int                     textRunLength,
            int                     emSize, 
            ushort                  charFlags,
            CharacterBufferRange    charBufferRange,
            TextShapeableSymbols    shapeable,
            double                  realToIdeal, 
            byte                    bidiLevel
            ) : 
            this( 
                runInfo,
                textEffects, 
                type,
                offsetToFirstCp,
                textRunLength,
                emSize, 
                charFlags,
                charBufferRange, 
                (shapeable != null ? (int)Math.Round(shapeable.Baseline * realToIdeal) : 0), 
                (shapeable != null ? (int)Math.Round(shapeable.Height * realToIdeal) : 0),
                shapeable, 
                bidiLevel
                )
        {}
 

        ///  
        /// Construct an lsrun 
        /// 
        private LSRun( 
            TextRunInfo             runInfo,
            IList       textEffects,
            Plsrun                  type,
            int                     offsetToFirstCp, 
            int                     textRunLength,
            int                     emSize, 
            ushort                  charFlags, 
            CharacterBufferRange    charBufferRange,
            int                     baselineOffset, 
            int                     height,
            TextShapeableSymbols    shapeable,
            byte                    bidiLevel
            ) 
        {
            _runInfo = runInfo; 
            _type = type; 
            _offsetToFirstCp = offsetToFirstCp;
            _textRunLength = textRunLength; 
            _emSize = emSize;
            _charFlags = charFlags;
            _charBufferRange = charBufferRange;
            _baselineOffset = baselineOffset; 
            _height = height;
            _bidiLevel = bidiLevel; 
            _shapeable = shapeable; 
            _textEffects = textEffects;
        } 


        /// 
        /// Construct an lsrun for a constant control char 
        /// 
        internal LSRun( 
            Plsrun      type, 
            IntPtr      controlChar
            ) : 
            this(
                null,   // text run info
                type,
                controlChar, 
                0,      // textRunLength
                -1,     // offsetToFirstChar 
                0 
                )
        {} 


        /// 
        /// Construct an lsrun 
        /// 
        /// TextRunInfo 
        /// plsrun type 
        /// control character
        /// text run length 
        /// character offset to the first cp
        /// bidi level of this run
        /// 
        ///     Critical: This has an unsafe code block 
        ///     TreatAsSafe: This code is ok to call since it does not expose the critical pointer
        ///   
        [SecurityCritical, SecurityTreatAsSafe] 
        internal LSRun(
            TextRunInfo             runInfo, 
            Plsrun                  type,
            IntPtr                  controlChar,
            int                     textRunLength,
            int                     offsetToFirstCp, 
            byte                    bidiLevel
            ) 
        { 
            unsafe
            { 
                _runInfo = runInfo;
                _type = type;
                _charBufferRange = new CharacterBufferRange((char*)controlChar, 1);
                _textRunLength = textRunLength; 
                _offsetToFirstCp = offsetToFirstCp;
                _bidiLevel = bidiLevel; 
            } 
        }
 

        internal void Truncate(int newLength)
        {
            _charBufferRange = new CharacterBufferRange( 
                _charBufferRange.CharacterBufferReference,
                newLength 
                ); 

            _textRunLength = newLength; 
        }


        ///  
        /// A Boolean value indicates whether hit-testing is allowed within the run
        ///  
        internal bool IsHitTestable 
        {
            get 
            {
                return _type == Plsrun.Text;
            }
        } 

        ///  
        /// A Boolean value indicates whether this run contains visible content. 
        /// 
        internal bool IsVisible 
        {
            get
            {
                return (_type == Plsrun.Text || _type == Plsrun.InlineObject); 
            }
        } 
 
        /// 
        /// A Boolean value indicates whether this run is End-Of-Line marker. 
        /// 
        internal bool IsNewline
        {
            get 
            {
                return (_type == Plsrun.LineBreak || _type == Plsrun.ParaBreak); 
            } 
        }
 
        /// 
        /// A Boolean value indicates whether additional info is required for caret positioning
        /// 
        internal bool NeedsCaretInfo 
        {
            get 
            { 
                return _shapeable != null && _shapeable.NeedsCaretInfo;
            } 
        }


        ///  
        /// A Boolean value indicates whether run has extended character
        ///  
        internal bool HasExtendedCharacter 
        {
            get 
            {
                return _shapeable != null && _shapeable.HasExtendedCharacter;
            }
        } 

 
        ///  
        /// Draw glyphrun
        ///  
        /// The drawing context to draw into 
        /// 
        /// The foreground brush of the glyphrun. Pass in "null" to draw the
        /// glyph run with the foreground in TextRunProperties. 
        /// 
        /// The GlyphRun to be drawn  
        /// bounding rectangle of drawn glyphrun 
        /// 
        /// TextEffect drawing code may use a different foreground brush for the text. 
        /// 
        internal Rect DrawGlyphRun(
            DrawingContext  drawingContext,
            Brush           foregroundBrush, 
            GlyphRun        glyphRun
            ) 
        { 
            Debug.Assert(_shapeable != null);
 
            Rect inkBoundingBox = glyphRun.ComputeInkBoundingBox();

            if (!inkBoundingBox.IsEmpty)
            { 
                // glyph run's ink bounding box is relative to its origin
                inkBoundingBox.X += glyphRun.BaselineOrigin.X; 
                inkBoundingBox.Y += glyphRun.BaselineOrigin.Y; 
            }
 
            if (drawingContext != null)
            {
                int pushCount = 0;              // the number of push we do
                try 
                {
                    if (_textEffects != null) 
                    { 
                        // we need to push in the same order as they are set
                        for (int i = 0; i < _textEffects.Count; i++) 
                        {
                            // get the text effect by its index
                            TextEffect textEffect = _textEffects[i];
 
                            if (textEffect.Transform != null && textEffect.Transform != Transform.Identity)
                            { 
                                drawingContext.PushTransform(textEffect.Transform); 
                                pushCount++;
                            } 

                            if (textEffect.Clip != null)
                            {
                                drawingContext.PushClip(textEffect.Clip); 
                                pushCount++;
                            } 
 
                            if (textEffect.Foreground != null)
                            { 
                                // remember the out-most non-null brush
                                // this brush will be used to draw the glyph run
                                foregroundBrush = textEffect.Foreground;
                            } 
                        }
                    } 
 
                    _shapeable.Draw(drawingContext, foregroundBrush, glyphRun);
                } 
                finally
                {
                    for (int i = 0; i < pushCount; i++)
                    { 
                        drawingContext.Pop();
                    } 
                } 
            }
 
            return inkBoundingBox;
        }

 
        /// 
        /// Map a UV real coordinate to an XY real coordinate 
        ///  
        /// line drawing origin XY
        /// vector to line origin UV 
        /// real distance in text flow direction
        /// real distance in paragraph flow direction
        /// ideal to real scaling factor
        /// container line 
        internal static Point UVToXY(
            Point                       origin, 
            Point                       vectorToOrigin, 
            double                      u,
            double                      v, 
            double                      toReal,
            TextMetrics.FullTextLine    line
            )
        { 
            Point xy;
            origin.Y += vectorToOrigin.Y; 
 
            if (line.RightToLeft)
            { 
                xy = new Point(line.ParagraphWidth * toReal - vectorToOrigin.X - u + origin.X, v + origin.Y);
            }
            else
            { 
                xy = new Point(u + vectorToOrigin.X + origin.X, v + origin.Y);
            } 
 
            return xy;
        } 



        ///  
        /// Map a UV ideal coordinate to an XY real coordinate
        ///  
        /// line drawing origin 
        /// vector to line origin UV
        /// ideal distance in text flow direction 
        /// ideal distance in paragraph flow direction
        /// ideal to real scaling factor
        /// container line
        internal static Point UVToXY( 
            Point           origin,
            Point           vectorToOrigin, 
            int             u, 
            int             v,
            double          toReal, 
            TextMetrics.FullTextLine    line
            )
        {
            Point xy; 
            origin.Y += vectorToOrigin.Y;
 
            if (line.RightToLeft) 
            {
                xy = new Point((line.ParagraphWidth - u) * toReal - vectorToOrigin.X + origin.X, v * toReal + origin.Y); 
            }
            else
            {
                xy = new Point(u * toReal + vectorToOrigin.X + origin.X, v * toReal + origin.Y); 
            }
 
            return xy; 
        }
 



        ///  
        /// Create a rectangle of the two specified UV coordinates
        ///  
        /// line drawing origin 
        /// logical top-left point
        /// logical bottom-right point 
        /// ideal to real scaling factor
        /// container line
        internal static Rect RectUV(
            Point           origin, 
            LSPOINT         topLeft,
            LSPOINT         bottomRight, 
            double          toReal, 
            TextMetrics.FullTextLine    line
            ) 
        {
            int dx = topLeft.x - bottomRight.x;
            if(dx == 1 || dx == -1)
            { 
                // in certain situation LS can be off by 1
                bottomRight.x = topLeft.x; 
            } 

            Rect rect = new Rect( 
                new Point(topLeft.x * toReal, topLeft.y * toReal),
                new Point(bottomRight.x * toReal, bottomRight.y * toReal)
                );
 
            if(DoubleUtil.AreClose(rect.TopLeft.X, rect.BottomRight.X))
            { 
                rect.Width = 0; 
            }
 
            if(DoubleUtil.AreClose(rect.TopLeft.Y, rect.BottomRight.Y))
            {
                rect.Height = 0;
            } 

            return rect; 
        } 

 

        /// 
        /// Move text run's baseline by the specified value
        ///  
        /// offset to be moved away from baseline
        internal void Move(int baselineMoveOffset) 
        { 
            _baselineMoveOffset += baselineMoveOffset;
        } 


        internal byte BidiLevel
        { 
            get { return _bidiLevel; }
        } 
 
        internal bool IsSymbol
        { 
            get
            {
                TextShapeableCharacters shapeable = _shapeable as TextShapeableCharacters;
                return shapeable != null && shapeable.IsSymbol; 
            }
        } 
 
        internal int OffsetToFirstCp
        { 
            get { return _offsetToFirstCp; }
        }

        internal int Length 
        {
            get { return _textRunLength; } 
        } 

        internal TextModifierScope TextModifierScope 
        {
            get { return _runInfo.TextModifierScope; }
        }
 
        internal Plsrun Type
        { 
            get { return _type; } 
        }
 
        internal ushort CharacterAttributeFlags
        {
            get { return _charFlags; }
        } 

        internal CharacterBuffer CharacterBuffer 
        { 
            get { return _charBufferRange.CharacterBuffer; }
        } 

        internal int StringLength
        {
            get { return _charBufferRange.Length; } 
        }
 
        internal int OffsetToFirstChar 
        {
            get { return _charBufferRange.OffsetToFirstChar; } 
        }

        internal TextRun TextRun
        { 
            get { return _runInfo.TextRun; }
        } 
 
        internal TextShapeableSymbols Shapeable
        { 
            get { return _shapeable; }
        }

        internal int BaselineOffset 
        {
            get { return _baselineOffset; } 
            set { _baselineOffset = value; } 
        }
 
        internal int Height
        {
            get { return _height; }
            set { _height = value; } 
        }
 
        internal int Descent 
        {
            get { return Height - BaselineOffset; } 
        }

        internal TextRunProperties RunProp
        { 
            get
            { 
                return _runInfo.Properties; 
            }
        } 

        internal CultureInfo TextCulture
        {
            get 
            {
                return CultureMapper.GetSpecificCulture(RunProp != null ? RunProp.CultureInfo : null); 
            } 
        }
 
        internal int EmSize
        {
            get { return _emSize; }
        } 

        internal int BaselineMoveOffset 
        { 
            get { return _baselineMoveOffset; }
        } 

        /// 
        /// required set of features that will be added to every feature set
        /// It will be used if nothing is set in typogrpahy porperties 
        /// 
        private static readonly Feature[] RequiredFeatures = 
        { 
            new Feature(0,ushort.MaxValue,(uint)OpenTypeTags.locl,1),
            new Feature(0,ushort.MaxValue,(uint)OpenTypeTags.ccmp,1), 
            new Feature(0,ushort.MaxValue,(uint)OpenTypeTags.rlig,1),
            new Feature(0,ushort.MaxValue,(uint)OpenTypeTags.mark,1),
            new Feature(0,ushort.MaxValue,(uint)OpenTypeTags.mkmk,1)
        }; 

        ///  
        /// Set of features corresponding to TextRunTypographyProperties.DefaultProperties 
        ///
 
        private static readonly Feature[] DefaultFeatures =
        {
            new Feature(0,ushort.MaxValue,(uint)OpenTypeTags.locl,1),
            new Feature(0,ushort.MaxValue,(uint)OpenTypeTags.ccmp,1), 
            new Feature(0,ushort.MaxValue,(uint)OpenTypeTags.rlig,1),
            new Feature(0,ushort.MaxValue,(uint)OpenTypeTags.kern,1), 
            new Feature(0,ushort.MaxValue,(uint)OpenTypeTags.mark,1), 
            new Feature(0,ushort.MaxValue,(uint)OpenTypeTags.mkmk,1),
            new Feature(0,ushort.MaxValue,(uint)OpenTypeTags.liga,1), 
            new Feature(0,ushort.MaxValue,(uint)OpenTypeTags.calt,1),
            new Feature(0,ushort.MaxValue,(uint)OpenTypeTags.clig,1)
        };
 
        private enum CustomOpenTypeFeatures
        { 
            AlternativeFractions                     , 
            PetiteCapitalsFrom----s               ,
            SmallCapitalsFrom----s                , 
            ContextualAlternates                     ,
            CaseSensitiveForms                       ,
            ContextualLigatures                      ,
            CapitalSpacing                           , 
            ContextualSwash                          ,
            CursivePositioning                       , 
            DiscretionaryLigatures                   , 
            ExpertForms                              ,
            Fractions                                , 
            FullWidth                                ,
            HalfForms                                ,
            HalantForms                              ,
            AlternateHalfWidth                       , 
            HistoricalForms                          ,
            HorizontalKanaAlternates                 , 
            HistoricalLigatures                      , 
            HojoKanjiForms                           ,
            HalfWidth                                , 
            JIS78Forms                               ,
            JIS83Forms                               ,
            JIS90Forms                               ,
            JIS04Forms                               , 
            Kerning                                  ,
            StandardLigatures                        , 
            LiningFigures                            , 
            MathematicalGreek                        ,
            AlternateAnnotationForms                 , 
            NLCKanjiForms                            ,
            OldStyleFigures                          ,
            Ordinals                                 ,
            ProportionalAlternateWidth               , 
            PetiteCapitals                           ,
            ProportionalFigures                      , 
            ProportionalWidths                       , 
            QuarterWidths                            ,
            RubyNotationForms                        , 
            StylisticAlternates                      ,
            ScientificInferiors                      ,
            SmallCapitals                            ,
            SimplifiedForms                          , 
            StylisticSet1                            ,
            StylisticSet2                            , 
            StylisticSet3                            , 
            StylisticSet4                            ,
            StylisticSet5                            , 
            StylisticSet6                            ,
            StylisticSet7                            ,
            StylisticSet8                            ,
            StylisticSet9                            , 
            StylisticSet10                           ,
            StylisticSet11                           , 
            StylisticSet12                           , 
            StylisticSet13                           ,
            StylisticSet14                           , 
            StylisticSet15                           ,
            StylisticSet16                           ,
            StylisticSet17                           ,
            StylisticSet18                           , 
            StylisticSet19                           ,
            StylisticSet20                           , 
            Subscript                                , 
            Superscript                              ,
            Swash                                    , 
            Titling                                  ,
            TraditionalNameForms                     ,
            TabularFigures                           ,
            TraditionalForms                         , 
            ThirdWidths                              ,
            Unicase                                  , 
            SlashedZero                              , 
            Count
        } 

        private static FeatureTags[] CustomOpenTypeFeatureTags = new FeatureTags[(int)CustomOpenTypeFeatures.Count]
        {
            FeatureTags.AlternativeFractions                     , 
            FeatureTags.PetiteCapitalsFrom----s               ,
            FeatureTags.SmallCapitalsFrom----s                , 
            FeatureTags.ContextualAlternates                     , 
            FeatureTags.CaseSensitiveForms                       ,
            FeatureTags.ContextualLigatures                      , 
            FeatureTags.CapitalSpacing                           ,
            FeatureTags.ContextualSwash                          ,
            FeatureTags.CursivePositioning                       ,
            FeatureTags.DiscretionaryLigatures                   , 
            FeatureTags.ExpertForms                              ,
            FeatureTags.Fractions                                , 
            FeatureTags.FullWidth                                , 
            FeatureTags.HalfForms                                ,
            FeatureTags.HalantForms                              , 
            FeatureTags.AlternateHalfWidth                       ,
            FeatureTags.HistoricalForms                          ,
            FeatureTags.HorizontalKanaAlternates                 ,
            FeatureTags.HistoricalLigatures                      , 
            FeatureTags.HojoKanjiForms                           ,
            FeatureTags.HalfWidth                                , 
            FeatureTags.JIS78Forms                               , 
            FeatureTags.JIS83Forms                               ,
            FeatureTags.JIS90Forms                               , 
            FeatureTags.JIS04Forms                               ,
            FeatureTags.Kerning                                  ,
            FeatureTags.StandardLigatures                        ,
            FeatureTags.LiningFigures                            , 
            FeatureTags.MathematicalGreek                        ,
            FeatureTags.AlternateAnnotationForms                 , 
            FeatureTags.NLCKanjiForms                            , 
            FeatureTags.OldStyleFigures                          ,
            FeatureTags.Ordinals                                 , 
            FeatureTags.ProportionalAlternateWidth               ,
            FeatureTags.PetiteCapitals                           ,
            FeatureTags.ProportionalFigures                      ,
            FeatureTags.ProportionalWidths                       , 
            FeatureTags.QuarterWidths                            ,
            FeatureTags.RubyNotationForms                        , 
            FeatureTags.StylisticAlternates                      , 
            FeatureTags.ScientificInferiors                      ,
            FeatureTags.SmallCapitals                            , 
            FeatureTags.SimplifiedForms                          ,
            FeatureTags.StylisticSet1                            ,
            FeatureTags.StylisticSet2                            ,
            FeatureTags.StylisticSet3                            , 
            FeatureTags.StylisticSet4                            ,
            FeatureTags.StylisticSet5                            , 
            FeatureTags.StylisticSet6                            , 
            FeatureTags.StylisticSet7                            ,
            FeatureTags.StylisticSet8                            , 
            FeatureTags.StylisticSet9                            ,
            FeatureTags.StylisticSet10                           ,
            FeatureTags.StylisticSet11                           ,
            FeatureTags.StylisticSet12                           , 
            FeatureTags.StylisticSet13                           ,
            FeatureTags.StylisticSet14                           , 
            FeatureTags.StylisticSet15                           , 
            FeatureTags.StylisticSet16                           ,
            FeatureTags.StylisticSet17                           , 
            FeatureTags.StylisticSet18                           ,
            FeatureTags.StylisticSet19                           ,
            FeatureTags.StylisticSet20                           ,
            FeatureTags.Subscript                                , 
            FeatureTags.Superscript                              ,
            FeatureTags.Swash                                    , 
            FeatureTags.Titling                                  , 
            FeatureTags.TraditionalNameForms                     ,
            FeatureTags.TabularFigures                           , 
            FeatureTags.TraditionalForms                         ,
            FeatureTags.ThirdWidths                              ,
            FeatureTags.Unicase                                  ,
            FeatureTags.SlashedZero 
        };
 
        private const ushort FeatureNotEnabled = 0xffff; 

        ///  
        /// Compile feature set from the linked list of LSRuns
        ///
        /// TypographyProperties shoulde be either all null or all not-null.
        /// First is used for internal purposes, also can be used by simple clients. 
        ///
        ///  
        ///  Feature set  
        /// 
        /// Critical - This method uses stackalloc to allocate buffer on stack and uses a pointer to that buffer. 
        ///            It also accesses unmanaged memory.
        /// 
        [SecurityCritical]
        internal static unsafe FeatureSet CompileFeatureSet( 
            LSRun[]     lsruns,
            int*        pcchRuns 
            ) 
        {
            Debug.Assert(lsruns != null && lsruns.Length > 0 && lsruns[0] != null); 

            //
            //  Quick check for null properties
            //  Run properties should be all null or all not null 
            //
            if (lsruns[0].RunProp.TypographyProperties == null) 
            { 
                for(int i = 1; i < lsruns.Length; i++)
                { 
                    if (lsruns[i].RunProp.TypographyProperties != null)
                    {
                        throw new ArgumentException(SR.Get(SRID.CompileFeatureSet_InvalidTypographyProperties));
                    } 
                }
 
                return new FeatureSet((uint)LanguageTags.Default, DefaultFeatures, DefaultFeatures.Length); 
            }
            //End of quick check. We will process custom features now. 

            Feature[] features;
            int featureCount;
 
            // Check if this properties are already cached.
            // This will work only if they already had been cached together, 
            // i.e. all cached features are the same. 
            // ( We do not call Equals on all porperties, because it is considered expensive)
            bool sameFeatures = true; 
            lsruns[0].RunProp.TypographyProperties.GetCachedFeatureSet(out features, out featureCount);

            if (features != null) // otherwise, we will have to go through features anyway
            { 
                for(int i = 1; i < lsruns.Length; i++)
                { 
                    Feature[] currentFeatures; 
                    int       currentFeatureCount;
 
                    lsruns[i].RunProp.TypographyProperties.GetCachedFeatureSet(out currentFeatures, out currentFeatureCount);

                    if (features != currentFeatures ||
                        featureCount != currentFeatureCount /* can this actually be if arrays are the same? I guess not, but just in case */ 
                       )
                    { 
                        sameFeatures = false; 
                        break;
                    } 
                }

                if (sameFeatures)
                { 
                    return new FeatureSet((uint)LanguageTags.Default,features,featureCount);
                } 
            } 

            //Create new set, add required features 
            int initialFeatureCount = RequiredFeatures.Length + 5;
            features = new Feature[initialFeatureCount];
            featureCount = RequiredFeatures.Length;
            Array.Copy(RequiredFeatures,features,RequiredFeatures.Length); 

 
            //Allocate feature index array, initalize all features to not enabled 
            ushort* featureIndex = stackalloc ushort[(int)CustomOpenTypeFeatures.Count];
            for (int i = 0; i < (int)CustomOpenTypeFeatures.Count; i++) 
            {
                featureIndex[i] = FeatureNotEnabled;
            }
 
            int currentStart = 0, currentLength;
 
            for(int i = 0; i < lsruns.Length; i++) 
            {
                TextRunTypographyProperties properties = lsruns[i].RunProp.TypographyProperties; 

                currentLength = pcchRuns[i];

                Debug.Assert(currentStart < ushort.MaxValue); 
                Debug.Assert((currentStart + currentLength) < ushort.MaxValue);
 
 
                //StandardLigatures
                SetFeature(CustomOpenTypeFeatures.StandardLigatures, properties.StandardLigatures?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 

                //Kerning
                SetFeature(CustomOpenTypeFeatures.Kerning, properties.Kerning?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);
 
                //----s
                switch (properties.Capitals) 
                { 
                    case FontCapitals.Normal:
                        DisableFeature(CustomOpenTypeFeatures.SmallCapitals,             featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.SmallCapitalsFrom----s, featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.PetiteCapitals,            featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.PetiteCapitalsFrom----s,featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.Unicase,                   featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.Titling,                   featureIndex);
                        break; 
                    case FontCapitals.SmallCaps: 
                        SetFeature(    CustomOpenTypeFeatures.SmallCapitals,             1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        DisableFeature(CustomOpenTypeFeatures.SmallCapitalsFrom----s, featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.PetiteCapitals,            featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.PetiteCapitalsFrom----s,featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.Unicase,                   featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.Titling,                   featureIndex); 
                        break;
                    case FontCapitals.AllSmallCaps: 
                        SetFeature(    CustomOpenTypeFeatures.SmallCapitals,             1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        SetFeature(    CustomOpenTypeFeatures.SmallCapitalsFrom----s, 1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        DisableFeature(CustomOpenTypeFeatures.PetiteCapitals,            featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.PetiteCapitalsFrom----s,featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.Unicase,                   featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.Titling,                   featureIndex);
                        break; 
                    case FontCapitals.PetiteCaps:
                        DisableFeature(CustomOpenTypeFeatures.SmallCapitals,             featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.SmallCapitalsFrom----s, featureIndex); 
                        SetFeature(    CustomOpenTypeFeatures.PetiteCapitals,            1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        DisableFeature(CustomOpenTypeFeatures.PetiteCapitalsFrom----s,featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.Unicase,                   featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.Titling,                   featureIndex);
                        break;
                    case FontCapitals.AllPetiteCaps: 
                        DisableFeature(CustomOpenTypeFeatures.SmallCapitals,             featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.SmallCapitalsFrom----s, featureIndex); 
                        SetFeature(    CustomOpenTypeFeatures.PetiteCapitals,            1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        SetFeature(    CustomOpenTypeFeatures.PetiteCapitalsFrom----s,1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        DisableFeature(CustomOpenTypeFeatures.Unicase,                   featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.Titling,                   featureIndex);
                        break;
                    case FontCapitals.Unicase:
                        DisableFeature(CustomOpenTypeFeatures.SmallCapitals,             featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.SmallCapitalsFrom----s, featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.PetiteCapitals,            featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.PetiteCapitalsFrom----s,featureIndex); 
                        SetFeature(    CustomOpenTypeFeatures.Unicase,                   1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        DisableFeature(CustomOpenTypeFeatures.Titling,                   featureIndex); 
                        break;
                    case FontCapitals.Titling:
                        DisableFeature(CustomOpenTypeFeatures.SmallCapitals,             featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.SmallCapitalsFrom----s, featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.PetiteCapitals,            featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.PetiteCapitalsFrom----s,featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.Unicase,                   featureIndex); 
                        SetFeature(    CustomOpenTypeFeatures.Titling,                   1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        break; 
                }

                //NumeralStyle
                switch (properties.NumeralStyle) 
                {
                    case FontNumeralStyle.Normal: 
                        DisableFeature(CustomOpenTypeFeatures.LiningFigures,              featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.OldStyleFigures,            featureIndex);
                        break; 
                    case FontNumeralStyle.Lining:
                        SetFeature(    CustomOpenTypeFeatures.LiningFigures,              1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        DisableFeature(CustomOpenTypeFeatures.OldStyleFigures,            featureIndex);
                        break; 
                    case FontNumeralStyle.OldStyle:
                        DisableFeature(CustomOpenTypeFeatures.LiningFigures,              featureIndex); 
                        SetFeature(    CustomOpenTypeFeatures.OldStyleFigures,            1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        break;
                } 


                //NumeralAlignment
                switch (properties.NumeralAlignment) 
                {
                    case FontNumeralAlignment.Normal: 
                        DisableFeature(CustomOpenTypeFeatures.ProportionalFigures,       featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.TabularFigures,            featureIndex);
                        break; 
                    case FontNumeralAlignment.Proportional:
                        SetFeature(    CustomOpenTypeFeatures.ProportionalFigures,       1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        DisableFeature(CustomOpenTypeFeatures.TabularFigures,            featureIndex);
                        break; 
                    case FontNumeralAlignment.Tabular:
                        DisableFeature(CustomOpenTypeFeatures.ProportionalFigures,       featureIndex); 
                        SetFeature(    CustomOpenTypeFeatures.TabularFigures,            1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        break;
                } 

                //Fraction
                switch (properties.Fraction)
                { 
                    case FontFraction.Normal:
                        DisableFeature(CustomOpenTypeFeatures.Fractions,                 featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.AlternativeFractions,      featureIndex); 
                        break;
                    case FontFraction.Stacked: 
                        DisableFeature(CustomOpenTypeFeatures.Fractions,                 featureIndex);
                        SetFeature(    CustomOpenTypeFeatures.AlternativeFractions,      1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        break;
                    case FontFraction.Slashed: 
                        SetFeature(    CustomOpenTypeFeatures.Fractions,                 1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        DisableFeature(CustomOpenTypeFeatures.AlternativeFractions,      featureIndex); 
                        break; 
                }
 
                //DiscretionaryLigatures
                SetFeature(CustomOpenTypeFeatures.DiscretionaryLigatures, properties.DiscretionaryLigatures?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);

                //HistoricalLigatures 
                SetFeature(CustomOpenTypeFeatures.HistoricalLigatures, properties.HistoricalLigatures?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);
 
                //HistoricalForms 
                SetFeature(CustomOpenTypeFeatures.HistoricalForms, properties.HistoricalForms?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);
 
                //FontVariants
                switch (properties.Variants)
                {
                    case FontVariants.Normal: 
                        DisableFeature(CustomOpenTypeFeatures.ScientificInferiors,       featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.Ordinals,                  featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.RubyNotationForms,         featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.Subscript,                 featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.Superscript,               featureIndex); 
                        break;
                    case FontVariants.Inferior:
                        SetFeature(    CustomOpenTypeFeatures.ScientificInferiors,       1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        DisableFeature(CustomOpenTypeFeatures.Ordinals,                  featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.RubyNotationForms,         featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.Subscript,                 featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.Superscript,               featureIndex); 
                        break;
                    case FontVariants.Ordinal: 
                        DisableFeature(CustomOpenTypeFeatures.ScientificInferiors,       featureIndex);
                        SetFeature(    CustomOpenTypeFeatures.Ordinals,                  1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        DisableFeature(CustomOpenTypeFeatures.RubyNotationForms,         featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.Subscript,                 featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.Superscript,               featureIndex);
                        break; 
                    case FontVariants.Ruby: 
                        DisableFeature(CustomOpenTypeFeatures.ScientificInferiors,       featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.Ordinals,                  featureIndex); 
                        SetFeature    (CustomOpenTypeFeatures.RubyNotationForms,         1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        DisableFeature(CustomOpenTypeFeatures.Subscript,                 featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.Superscript,               featureIndex);
                        break; 
                    case FontVariants.Subscript:
                        DisableFeature(CustomOpenTypeFeatures.ScientificInferiors,       featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.Ordinals,                  featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.RubyNotationForms,         featureIndex);
                        SetFeature    (CustomOpenTypeFeatures.Subscript,                 1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        DisableFeature(CustomOpenTypeFeatures.Superscript,               featureIndex);
                        break;
                    case FontVariants.Superscript:
                        DisableFeature(CustomOpenTypeFeatures.ScientificInferiors,       featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.Ordinals,                  featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.RubyNotationForms,         featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.Subscript,                 featureIndex); 
                        SetFeature    (CustomOpenTypeFeatures.Superscript,               1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        break; 
                }

                //ContextualLigatures
                SetFeature(CustomOpenTypeFeatures.ContextualLigatures, properties.ContextualLigatures?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 

                //Contextual alternates 
                SetFeature(CustomOpenTypeFeatures.ContextualAlternates, properties.ContextualAlternates?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 

                //CapitalSpacing 
                SetFeature(CustomOpenTypeFeatures.CapitalSpacing, properties.CapitalSpacing?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);

                //Case sensitive forms
                SetFeature(CustomOpenTypeFeatures.CaseSensitiveForms, properties.CaseSensitiveForms?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 

                //StylisticSet1 
                SetFeature(CustomOpenTypeFeatures.StylisticSet1, properties.StylisticSet1?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                //StylisticSet2
                SetFeature(CustomOpenTypeFeatures.StylisticSet2, properties.StylisticSet2?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                //StylisticSet3
                SetFeature(CustomOpenTypeFeatures.StylisticSet3, properties.StylisticSet3?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                //StylisticSet4
                SetFeature(CustomOpenTypeFeatures.StylisticSet4, properties.StylisticSet4?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                //StylisticSet5
                SetFeature(CustomOpenTypeFeatures.StylisticSet5, properties.StylisticSet5?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                //StylisticSet6 
                SetFeature(CustomOpenTypeFeatures.StylisticSet6, properties.StylisticSet6?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                //StylisticSet7 
                SetFeature(CustomOpenTypeFeatures.StylisticSet7, properties.StylisticSet7?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                //StylisticSet8
                SetFeature(CustomOpenTypeFeatures.StylisticSet8, properties.StylisticSet8?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                //StylisticSet9 
                SetFeature(CustomOpenTypeFeatures.StylisticSet9, properties.StylisticSet9?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                //StylisticSet10 
                SetFeature(CustomOpenTypeFeatures.StylisticSet10, properties.StylisticSet10?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                //StylisticSet11
                SetFeature(CustomOpenTypeFeatures.StylisticSet11, properties.StylisticSet11?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                //StylisticSet12
                SetFeature(CustomOpenTypeFeatures.StylisticSet12, properties.StylisticSet12?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                //StylisticSet13
                SetFeature(CustomOpenTypeFeatures.StylisticSet13, properties.StylisticSet13?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                //StylisticSet14
                SetFeature(CustomOpenTypeFeatures.StylisticSet14, properties.StylisticSet14?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                //StylisticSet15 
                SetFeature(CustomOpenTypeFeatures.StylisticSet15, properties.StylisticSet15?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                //StylisticSet16 
                SetFeature(CustomOpenTypeFeatures.StylisticSet16, properties.StylisticSet16?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                //StylisticSet17
                SetFeature(CustomOpenTypeFeatures.StylisticSet17, properties.StylisticSet17?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                //StylisticSet18 
                SetFeature(CustomOpenTypeFeatures.StylisticSet18, properties.StylisticSet18?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                //StylisticSet19 
                SetFeature(CustomOpenTypeFeatures.StylisticSet19, properties.StylisticSet19?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                //StylisticSet20
                SetFeature(CustomOpenTypeFeatures.StylisticSet20, properties.StylisticSet20?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 

                //SlashedZero
                SetFeature(CustomOpenTypeFeatures.SlashedZero, properties.SlashedZero?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);
 
                //MathematicalGreek
                SetFeature(CustomOpenTypeFeatures.MathematicalGreek, properties.MathematicalGreek?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
 
                //EastAsian expert forms
                SetFeature(CustomOpenTypeFeatures.ExpertForms, properties.EastAsianExpertForms?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 

                //Standard swashes
                SetFeature(CustomOpenTypeFeatures.Swash, properties.StandardSwashes, currentStart, currentLength, featureIndex, ref features, ref featureCount);
 
                //Contextual swashes
                SetFeature(CustomOpenTypeFeatures.ContextualSwash, properties.ContextualSwashes, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
 
                //Stylistic alternates
                SetFeature(CustomOpenTypeFeatures.StylisticAlternates, properties.StylisticAlternates, currentStart, currentLength, featureIndex, ref features, ref featureCount); 

                //Annotation alternates.
                SetFeature(CustomOpenTypeFeatures.AlternateAnnotationForms, properties.AnnotationAlternates, currentStart, currentLength, featureIndex, ref features, ref featureCount);
 
                //EastAsian Widths
                switch (properties.EastAsianWidths) 
                { 
                    case FontEastAsianWidths.Normal:
                        DisableFeature(CustomOpenTypeFeatures.ProportionalWidths,        featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.ProportionalAlternateWidth,featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.FullWidth,                 featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.HalfWidth,                 featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.ThirdWidths,               featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.QuarterWidths,             featureIndex);
                        break; 
                    case FontEastAsianWidths.Proportional: 
                        SetFeature    (CustomOpenTypeFeatures.ProportionalWidths,        1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        SetFeature    (CustomOpenTypeFeatures.ProportionalAlternateWidth,1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        DisableFeature(CustomOpenTypeFeatures.FullWidth,                 featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.HalfWidth,                 featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.ThirdWidths,               featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.QuarterWidths,             featureIndex); 
                        break;
                    case FontEastAsianWidths.Full: 
                        DisableFeature(CustomOpenTypeFeatures.ProportionalWidths,        featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.ProportionalAlternateWidth,featureIndex);
                        SetFeature    (CustomOpenTypeFeatures.FullWidth,                 1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        DisableFeature(CustomOpenTypeFeatures.HalfWidth,                 featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.ThirdWidths,               featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.QuarterWidths,             featureIndex);
                        break; 
                    case FontEastAsianWidths.Half:
                        DisableFeature(CustomOpenTypeFeatures.ProportionalWidths,        featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.ProportionalAlternateWidth,featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.FullWidth,                 featureIndex);
                        SetFeature    (CustomOpenTypeFeatures.HalfWidth,                 1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        DisableFeature(CustomOpenTypeFeatures.ThirdWidths,               featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.QuarterWidths,             featureIndex);
                        break;
                    case FontEastAsianWidths.Third: 
                        DisableFeature(CustomOpenTypeFeatures.ProportionalWidths,        featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.ProportionalAlternateWidth,featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.FullWidth,                 featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.HalfWidth,                 featureIndex);
                        SetFeature    (CustomOpenTypeFeatures.ThirdWidths,               1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        DisableFeature(CustomOpenTypeFeatures.QuarterWidths,             featureIndex);
                        break;
                    case FontEastAsianWidths.Quarter:
                        DisableFeature(CustomOpenTypeFeatures.ProportionalWidths,        featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.ProportionalAlternateWidth,featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.FullWidth,                 featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.HalfWidth,                 featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.ThirdWidths,               featureIndex);
                        SetFeature    (CustomOpenTypeFeatures.QuarterWidths,             1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        break;
                }

                //EastAsian language 
                switch (properties.EastAsianLanguage)
                { 
                    case FontEastAsianLanguage.Normal: 
                        DisableFeature(CustomOpenTypeFeatures.SimplifiedForms,           featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.TraditionalForms,          featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.TraditionalNameForms,      featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.NLCKanjiForms,             featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.HojoKanjiForms,            featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS78Forms,                featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.JIS83Forms,                featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS90Forms,                featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.JIS04Forms,                featureIndex); 
                        break;
                    case FontEastAsianLanguage.Simplified: 
                        SetFeature    (CustomOpenTypeFeatures.SimplifiedForms,           1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        DisableFeature(CustomOpenTypeFeatures.TraditionalForms,          featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.TraditionalNameForms,      featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.NLCKanjiForms,             featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.HojoKanjiForms,            featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS78Forms,                featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.JIS83Forms,                featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.JIS90Forms,                featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS04Forms,                featureIndex); 
                        break;
                    case FontEastAsianLanguage.Traditional:
                        DisableFeature(CustomOpenTypeFeatures.SimplifiedForms,           featureIndex);
                        SetFeature    (CustomOpenTypeFeatures.TraditionalForms,          1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        DisableFeature(CustomOpenTypeFeatures.TraditionalNameForms,      featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.NLCKanjiForms,             featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.HojoKanjiForms,            featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.JIS78Forms,                featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS83Forms,                featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.JIS90Forms,                featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS04Forms,                featureIndex);
                        break;
                    case FontEastAsianLanguage.TraditionalNames: 
                        DisableFeature(CustomOpenTypeFeatures.SimplifiedForms,           featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.TraditionalForms,          featureIndex); 
                        SetFeature    (CustomOpenTypeFeatures.TraditionalNameForms,      1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        DisableFeature(CustomOpenTypeFeatures.NLCKanjiForms,             featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.HojoKanjiForms,            featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.JIS78Forms,                featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS83Forms,                featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS90Forms,                featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS04Forms,                featureIndex); 
                        break;
                    case FontEastAsianLanguage.NlcKanji: 
                        DisableFeature(CustomOpenTypeFeatures.SimplifiedForms,           featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.TraditionalForms,          featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.TraditionalNameForms,      featureIndex); 
                        SetFeature    (CustomOpenTypeFeatures.NLCKanjiForms,             1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        DisableFeature(CustomOpenTypeFeatures.HojoKanjiForms,            featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS78Forms,                featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS83Forms,                featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.JIS90Forms,                featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS04Forms,                featureIndex); 
                        break; 
                    case FontEastAsianLanguage.HojoKanji:
                        DisableFeature(CustomOpenTypeFeatures.SimplifiedForms,           featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.TraditionalForms,          featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.TraditionalNameForms,      featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.NLCKanjiForms,             featureIndex);
                        SetFeature    (CustomOpenTypeFeatures.HojoKanjiForms,            1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        DisableFeature(CustomOpenTypeFeatures.JIS78Forms,                featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS83Forms,                featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.JIS90Forms,                featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.JIS04Forms,                featureIndex);
                        break; 
                    case FontEastAsianLanguage.Jis78:
                        DisableFeature(CustomOpenTypeFeatures.SimplifiedForms,           featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.TraditionalForms,          featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.TraditionalNameForms,      featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.NLCKanjiForms,             featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.HojoKanjiForms,            featureIndex); 
                        SetFeature    (CustomOpenTypeFeatures.JIS78Forms,                1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        DisableFeature(CustomOpenTypeFeatures.JIS83Forms,                featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS90Forms,                featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.JIS04Forms,                featureIndex);
                        break;
                    case FontEastAsianLanguage.Jis83:
                        DisableFeature(CustomOpenTypeFeatures.SimplifiedForms,           featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.TraditionalForms,          featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.TraditionalNameForms,      featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.NLCKanjiForms,             featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.HojoKanjiForms,            featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS78Forms,                featureIndex); 
                        SetFeature    (CustomOpenTypeFeatures.JIS83Forms,                1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        DisableFeature(CustomOpenTypeFeatures.JIS90Forms,                featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS04Forms,                featureIndex);
                        break; 
                    case FontEastAsianLanguage.Jis90:
                        DisableFeature(CustomOpenTypeFeatures.SimplifiedForms,           featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.TraditionalForms,          featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.TraditionalNameForms,      featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.NLCKanjiForms,             featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.HojoKanjiForms,            featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS78Forms,                featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS83Forms,                featureIndex);
                        SetFeature    (CustomOpenTypeFeatures.JIS90Forms,                1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        DisableFeature(CustomOpenTypeFeatures.JIS04Forms,                featureIndex);
                        break; 
                    case FontEastAsianLanguage.Jis04: 
                        DisableFeature(CustomOpenTypeFeatures.SimplifiedForms,           featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.TraditionalForms,          featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.TraditionalNameForms,      featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.NLCKanjiForms,             featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.HojoKanjiForms,            featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS78Forms,                featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.JIS83Forms,                featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS90Forms,                featureIndex); 
                        SetFeature    (CustomOpenTypeFeatures.JIS04Forms,                1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        break;
                } 

                currentStart += currentLength;
            }
 
            // Check if all runs have actually the same features.
            // All feature record should start at 0 and have full length 
            // We skip required features in this check, because they are always the same 
            sameFeatures = true;
            for(int i = RequiredFeatures.Length; i < featureCount; i++) 
            {
                if (features[i].StartIndex != 0 ||
                    features[i].Length != currentStart
                   ) 
                {
                    sameFeatures = false; 
                    break; 
                }
            } 

            if (sameFeatures)
            {
                // Change length for each feature record to 65535, so they do not depend on 
                // particular input length and can be cached
                for(int i = RequiredFeatures.Length; i < featureCount; i++) 
                { 
                    features[i].Length = ushort.MaxValue;
                } 

                // Now cache features inside each run
                for(int i = 0; i < lsruns.Length; i++)
                { 
                    lsruns[i].RunProp.TypographyProperties.SetCachedFeatureSet(features, featureCount);
                } 
            } 

            return new FeatureSet((uint)LanguageTags.Default,features,featureCount); 
        }

        /// 
        ///     Critical: This code dereferences a pointer without validation 
        /// 
        [SecurityCritical] 
        private static unsafe void SetFeature( 
            CustomOpenTypeFeatures      feature,
            int                         parameter, 
            int                         start,
            int                         length,
            ushort*                     featureIndex,
            ref Feature[]               features, 
            ref int                     featureCount
            ) 
        { 
            if (parameter == 0)
            { 
                // Nothing to change, just set featureIndex to not enabled
                featureIndex[(int)feature] = FeatureNotEnabled;
                return;
            } 

            ushort index = featureIndex[(int)feature]; 
            Debug.Assert( // if feature is already enabled, index should be valid and feature record should have the same tag 
                         index == FeatureNotEnabled ||
                         (index < featureCount && features[index].Tag == (uint)CustomOpenTypeFeatureTags[(int)feature]) 
                        );

            // Check if we can just append to existing feature record
            if (index != FeatureNotEnabled && 
                features[index].Parameter == parameter
               ) 
            { 
                features[index].Length += (ushort)length;
                return; 
            }

            //
            // We should add another feature record 
            //
 
            if (featureCount == ushort.MaxValue) 
            {
                throw new OutOfMemoryException(); 
            }

            // reallocate if it is needed
            if (featureCount == features.Length) 
            {
                Feature[] tempFeatures = new Feature[features.Length + 3]; 
                Array.Copy(features, tempFeatures, features.Length); 
                features = tempFeatures;
            } 

            features[featureCount] = new Feature(
                    (ushort)start,
                    (ushort)length, 
                    (uint)CustomOpenTypeFeatureTags[(int)feature],
                    (uint)parameter 
                ); 

            //Set this as current record for the feature 
            featureIndex[(int)feature] = (ushort)featureCount;

            featureCount++;
        } 

        ///  
        /// This is simplified version of SetFeature, 
        /// assuming that parameter is 0
        ///  
        /// 
        ///     Critical: This code dereferences a pointer without validation
        /// 
        [SecurityCritical] 
        private static unsafe void DisableFeature(
            CustomOpenTypeFeatures      feature, 
            ushort*                     featureIndex 
        )
        { 
            // Nothing to change, just set featureIndex to not enabled
            featureIndex[(int)feature] = FeatureNotEnabled;
        }
    } 
}

// 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, 2001
// 
//  File:      LSRun.cs
// 
//  Contents:  Text run in a full text line 
//
//  Created:   9-6-2001 Worachai Chaoweeraprasit (wchao) 
//
//-----------------------------------------------------------------------

using System; 
using System.Collections;
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Runtime.InteropServices;
using System.Windows; 
using System.Windows.Media;
using System.Windows.Media.TextFormatting;
using System.Globalization;
 
using System.Security;
using System.Security.Permissions; 
using MS.Internal.Shaping; 
using MS.Internal.FontCache;
using MS.Utility; 

using SR=MS.Internal.PresentationCore.SR;
using SRID=MS.Internal.PresentationCore.SRID;
 
namespace MS.Internal.TextFormatting
{ 
    ///  
    /// Run represented by a plsrun value dispatched to LS during FetchRun
    ///  
    internal sealed class LSRun
    {
        private TextRunInfo             _runInfo;                   // TextRun Info of the text
        private Plsrun                  _type;                      // Plsrun used as run type 
        private int                     _offsetToFirstCp;           // dcp from line's cpFirst
        private int                     _textRunLength;             // textrun length 
        private CharacterBufferRange    _charBufferRange;           // character buffer range 
        private int                     _baselineOffset;            // distance from top to baseline
        private int                     _height;                    // height 
        private int                     _baselineMoveOffset;        // run is moved by this offset from baseline
        private int                     _emSize;                    // run ideal EM size
        private TextShapeableSymbols    _shapeable;                 // shapeable run
        private ushort                  _charFlags;                 // character attribute flags 
        private byte                    _bidiLevel;                 // resolved bidi level
        private IList       _textEffects;               // TextEffects that should be applied for this run 
 

        ///  
        /// Construct an lsrun
        /// 
        internal LSRun(
            TextRunInfo             runInfo, 
            IList       textEffects,
            Plsrun                  type, 
            int                     offsetToFirstCp, 
            int                     textRunLength,
            int                     emSize, 
            ushort                  charFlags,
            CharacterBufferRange    charBufferRange,
            TextShapeableSymbols    shapeable,
            double                  realToIdeal, 
            byte                    bidiLevel
            ) : 
            this( 
                runInfo,
                textEffects, 
                type,
                offsetToFirstCp,
                textRunLength,
                emSize, 
                charFlags,
                charBufferRange, 
                (shapeable != null ? (int)Math.Round(shapeable.Baseline * realToIdeal) : 0), 
                (shapeable != null ? (int)Math.Round(shapeable.Height * realToIdeal) : 0),
                shapeable, 
                bidiLevel
                )
        {}
 

        ///  
        /// Construct an lsrun 
        /// 
        private LSRun( 
            TextRunInfo             runInfo,
            IList       textEffects,
            Plsrun                  type,
            int                     offsetToFirstCp, 
            int                     textRunLength,
            int                     emSize, 
            ushort                  charFlags, 
            CharacterBufferRange    charBufferRange,
            int                     baselineOffset, 
            int                     height,
            TextShapeableSymbols    shapeable,
            byte                    bidiLevel
            ) 
        {
            _runInfo = runInfo; 
            _type = type; 
            _offsetToFirstCp = offsetToFirstCp;
            _textRunLength = textRunLength; 
            _emSize = emSize;
            _charFlags = charFlags;
            _charBufferRange = charBufferRange;
            _baselineOffset = baselineOffset; 
            _height = height;
            _bidiLevel = bidiLevel; 
            _shapeable = shapeable; 
            _textEffects = textEffects;
        } 


        /// 
        /// Construct an lsrun for a constant control char 
        /// 
        internal LSRun( 
            Plsrun      type, 
            IntPtr      controlChar
            ) : 
            this(
                null,   // text run info
                type,
                controlChar, 
                0,      // textRunLength
                -1,     // offsetToFirstChar 
                0 
                )
        {} 


        /// 
        /// Construct an lsrun 
        /// 
        /// TextRunInfo 
        /// plsrun type 
        /// control character
        /// text run length 
        /// character offset to the first cp
        /// bidi level of this run
        /// 
        ///     Critical: This has an unsafe code block 
        ///     TreatAsSafe: This code is ok to call since it does not expose the critical pointer
        ///   
        [SecurityCritical, SecurityTreatAsSafe] 
        internal LSRun(
            TextRunInfo             runInfo, 
            Plsrun                  type,
            IntPtr                  controlChar,
            int                     textRunLength,
            int                     offsetToFirstCp, 
            byte                    bidiLevel
            ) 
        { 
            unsafe
            { 
                _runInfo = runInfo;
                _type = type;
                _charBufferRange = new CharacterBufferRange((char*)controlChar, 1);
                _textRunLength = textRunLength; 
                _offsetToFirstCp = offsetToFirstCp;
                _bidiLevel = bidiLevel; 
            } 
        }
 

        internal void Truncate(int newLength)
        {
            _charBufferRange = new CharacterBufferRange( 
                _charBufferRange.CharacterBufferReference,
                newLength 
                ); 

            _textRunLength = newLength; 
        }


        ///  
        /// A Boolean value indicates whether hit-testing is allowed within the run
        ///  
        internal bool IsHitTestable 
        {
            get 
            {
                return _type == Plsrun.Text;
            }
        } 

        ///  
        /// A Boolean value indicates whether this run contains visible content. 
        /// 
        internal bool IsVisible 
        {
            get
            {
                return (_type == Plsrun.Text || _type == Plsrun.InlineObject); 
            }
        } 
 
        /// 
        /// A Boolean value indicates whether this run is End-Of-Line marker. 
        /// 
        internal bool IsNewline
        {
            get 
            {
                return (_type == Plsrun.LineBreak || _type == Plsrun.ParaBreak); 
            } 
        }
 
        /// 
        /// A Boolean value indicates whether additional info is required for caret positioning
        /// 
        internal bool NeedsCaretInfo 
        {
            get 
            { 
                return _shapeable != null && _shapeable.NeedsCaretInfo;
            } 
        }


        ///  
        /// A Boolean value indicates whether run has extended character
        ///  
        internal bool HasExtendedCharacter 
        {
            get 
            {
                return _shapeable != null && _shapeable.HasExtendedCharacter;
            }
        } 

 
        ///  
        /// Draw glyphrun
        ///  
        /// The drawing context to draw into 
        /// 
        /// The foreground brush of the glyphrun. Pass in "null" to draw the
        /// glyph run with the foreground in TextRunProperties. 
        /// 
        /// The GlyphRun to be drawn  
        /// bounding rectangle of drawn glyphrun 
        /// 
        /// TextEffect drawing code may use a different foreground brush for the text. 
        /// 
        internal Rect DrawGlyphRun(
            DrawingContext  drawingContext,
            Brush           foregroundBrush, 
            GlyphRun        glyphRun
            ) 
        { 
            Debug.Assert(_shapeable != null);
 
            Rect inkBoundingBox = glyphRun.ComputeInkBoundingBox();

            if (!inkBoundingBox.IsEmpty)
            { 
                // glyph run's ink bounding box is relative to its origin
                inkBoundingBox.X += glyphRun.BaselineOrigin.X; 
                inkBoundingBox.Y += glyphRun.BaselineOrigin.Y; 
            }
 
            if (drawingContext != null)
            {
                int pushCount = 0;              // the number of push we do
                try 
                {
                    if (_textEffects != null) 
                    { 
                        // we need to push in the same order as they are set
                        for (int i = 0; i < _textEffects.Count; i++) 
                        {
                            // get the text effect by its index
                            TextEffect textEffect = _textEffects[i];
 
                            if (textEffect.Transform != null && textEffect.Transform != Transform.Identity)
                            { 
                                drawingContext.PushTransform(textEffect.Transform); 
                                pushCount++;
                            } 

                            if (textEffect.Clip != null)
                            {
                                drawingContext.PushClip(textEffect.Clip); 
                                pushCount++;
                            } 
 
                            if (textEffect.Foreground != null)
                            { 
                                // remember the out-most non-null brush
                                // this brush will be used to draw the glyph run
                                foregroundBrush = textEffect.Foreground;
                            } 
                        }
                    } 
 
                    _shapeable.Draw(drawingContext, foregroundBrush, glyphRun);
                } 
                finally
                {
                    for (int i = 0; i < pushCount; i++)
                    { 
                        drawingContext.Pop();
                    } 
                } 
            }
 
            return inkBoundingBox;
        }

 
        /// 
        /// Map a UV real coordinate to an XY real coordinate 
        ///  
        /// line drawing origin XY
        /// vector to line origin UV 
        /// real distance in text flow direction
        /// real distance in paragraph flow direction
        /// ideal to real scaling factor
        /// container line 
        internal static Point UVToXY(
            Point                       origin, 
            Point                       vectorToOrigin, 
            double                      u,
            double                      v, 
            double                      toReal,
            TextMetrics.FullTextLine    line
            )
        { 
            Point xy;
            origin.Y += vectorToOrigin.Y; 
 
            if (line.RightToLeft)
            { 
                xy = new Point(line.ParagraphWidth * toReal - vectorToOrigin.X - u + origin.X, v + origin.Y);
            }
            else
            { 
                xy = new Point(u + vectorToOrigin.X + origin.X, v + origin.Y);
            } 
 
            return xy;
        } 



        ///  
        /// Map a UV ideal coordinate to an XY real coordinate
        ///  
        /// line drawing origin 
        /// vector to line origin UV
        /// ideal distance in text flow direction 
        /// ideal distance in paragraph flow direction
        /// ideal to real scaling factor
        /// container line
        internal static Point UVToXY( 
            Point           origin,
            Point           vectorToOrigin, 
            int             u, 
            int             v,
            double          toReal, 
            TextMetrics.FullTextLine    line
            )
        {
            Point xy; 
            origin.Y += vectorToOrigin.Y;
 
            if (line.RightToLeft) 
            {
                xy = new Point((line.ParagraphWidth - u) * toReal - vectorToOrigin.X + origin.X, v * toReal + origin.Y); 
            }
            else
            {
                xy = new Point(u * toReal + vectorToOrigin.X + origin.X, v * toReal + origin.Y); 
            }
 
            return xy; 
        }
 



        ///  
        /// Create a rectangle of the two specified UV coordinates
        ///  
        /// line drawing origin 
        /// logical top-left point
        /// logical bottom-right point 
        /// ideal to real scaling factor
        /// container line
        internal static Rect RectUV(
            Point           origin, 
            LSPOINT         topLeft,
            LSPOINT         bottomRight, 
            double          toReal, 
            TextMetrics.FullTextLine    line
            ) 
        {
            int dx = topLeft.x - bottomRight.x;
            if(dx == 1 || dx == -1)
            { 
                // in certain situation LS can be off by 1
                bottomRight.x = topLeft.x; 
            } 

            Rect rect = new Rect( 
                new Point(topLeft.x * toReal, topLeft.y * toReal),
                new Point(bottomRight.x * toReal, bottomRight.y * toReal)
                );
 
            if(DoubleUtil.AreClose(rect.TopLeft.X, rect.BottomRight.X))
            { 
                rect.Width = 0; 
            }
 
            if(DoubleUtil.AreClose(rect.TopLeft.Y, rect.BottomRight.Y))
            {
                rect.Height = 0;
            } 

            return rect; 
        } 

 

        /// 
        /// Move text run's baseline by the specified value
        ///  
        /// offset to be moved away from baseline
        internal void Move(int baselineMoveOffset) 
        { 
            _baselineMoveOffset += baselineMoveOffset;
        } 


        internal byte BidiLevel
        { 
            get { return _bidiLevel; }
        } 
 
        internal bool IsSymbol
        { 
            get
            {
                TextShapeableCharacters shapeable = _shapeable as TextShapeableCharacters;
                return shapeable != null && shapeable.IsSymbol; 
            }
        } 
 
        internal int OffsetToFirstCp
        { 
            get { return _offsetToFirstCp; }
        }

        internal int Length 
        {
            get { return _textRunLength; } 
        } 

        internal TextModifierScope TextModifierScope 
        {
            get { return _runInfo.TextModifierScope; }
        }
 
        internal Plsrun Type
        { 
            get { return _type; } 
        }
 
        internal ushort CharacterAttributeFlags
        {
            get { return _charFlags; }
        } 

        internal CharacterBuffer CharacterBuffer 
        { 
            get { return _charBufferRange.CharacterBuffer; }
        } 

        internal int StringLength
        {
            get { return _charBufferRange.Length; } 
        }
 
        internal int OffsetToFirstChar 
        {
            get { return _charBufferRange.OffsetToFirstChar; } 
        }

        internal TextRun TextRun
        { 
            get { return _runInfo.TextRun; }
        } 
 
        internal TextShapeableSymbols Shapeable
        { 
            get { return _shapeable; }
        }

        internal int BaselineOffset 
        {
            get { return _baselineOffset; } 
            set { _baselineOffset = value; } 
        }
 
        internal int Height
        {
            get { return _height; }
            set { _height = value; } 
        }
 
        internal int Descent 
        {
            get { return Height - BaselineOffset; } 
        }

        internal TextRunProperties RunProp
        { 
            get
            { 
                return _runInfo.Properties; 
            }
        } 

        internal CultureInfo TextCulture
        {
            get 
            {
                return CultureMapper.GetSpecificCulture(RunProp != null ? RunProp.CultureInfo : null); 
            } 
        }
 
        internal int EmSize
        {
            get { return _emSize; }
        } 

        internal int BaselineMoveOffset 
        { 
            get { return _baselineMoveOffset; }
        } 

        /// 
        /// required set of features that will be added to every feature set
        /// It will be used if nothing is set in typogrpahy porperties 
        /// 
        private static readonly Feature[] RequiredFeatures = 
        { 
            new Feature(0,ushort.MaxValue,(uint)OpenTypeTags.locl,1),
            new Feature(0,ushort.MaxValue,(uint)OpenTypeTags.ccmp,1), 
            new Feature(0,ushort.MaxValue,(uint)OpenTypeTags.rlig,1),
            new Feature(0,ushort.MaxValue,(uint)OpenTypeTags.mark,1),
            new Feature(0,ushort.MaxValue,(uint)OpenTypeTags.mkmk,1)
        }; 

        ///  
        /// Set of features corresponding to TextRunTypographyProperties.DefaultProperties 
        ///
 
        private static readonly Feature[] DefaultFeatures =
        {
            new Feature(0,ushort.MaxValue,(uint)OpenTypeTags.locl,1),
            new Feature(0,ushort.MaxValue,(uint)OpenTypeTags.ccmp,1), 
            new Feature(0,ushort.MaxValue,(uint)OpenTypeTags.rlig,1),
            new Feature(0,ushort.MaxValue,(uint)OpenTypeTags.kern,1), 
            new Feature(0,ushort.MaxValue,(uint)OpenTypeTags.mark,1), 
            new Feature(0,ushort.MaxValue,(uint)OpenTypeTags.mkmk,1),
            new Feature(0,ushort.MaxValue,(uint)OpenTypeTags.liga,1), 
            new Feature(0,ushort.MaxValue,(uint)OpenTypeTags.calt,1),
            new Feature(0,ushort.MaxValue,(uint)OpenTypeTags.clig,1)
        };
 
        private enum CustomOpenTypeFeatures
        { 
            AlternativeFractions                     , 
            PetiteCapitalsFrom----s               ,
            SmallCapitalsFrom----s                , 
            ContextualAlternates                     ,
            CaseSensitiveForms                       ,
            ContextualLigatures                      ,
            CapitalSpacing                           , 
            ContextualSwash                          ,
            CursivePositioning                       , 
            DiscretionaryLigatures                   , 
            ExpertForms                              ,
            Fractions                                , 
            FullWidth                                ,
            HalfForms                                ,
            HalantForms                              ,
            AlternateHalfWidth                       , 
            HistoricalForms                          ,
            HorizontalKanaAlternates                 , 
            HistoricalLigatures                      , 
            HojoKanjiForms                           ,
            HalfWidth                                , 
            JIS78Forms                               ,
            JIS83Forms                               ,
            JIS90Forms                               ,
            JIS04Forms                               , 
            Kerning                                  ,
            StandardLigatures                        , 
            LiningFigures                            , 
            MathematicalGreek                        ,
            AlternateAnnotationForms                 , 
            NLCKanjiForms                            ,
            OldStyleFigures                          ,
            Ordinals                                 ,
            ProportionalAlternateWidth               , 
            PetiteCapitals                           ,
            ProportionalFigures                      , 
            ProportionalWidths                       , 
            QuarterWidths                            ,
            RubyNotationForms                        , 
            StylisticAlternates                      ,
            ScientificInferiors                      ,
            SmallCapitals                            ,
            SimplifiedForms                          , 
            StylisticSet1                            ,
            StylisticSet2                            , 
            StylisticSet3                            , 
            StylisticSet4                            ,
            StylisticSet5                            , 
            StylisticSet6                            ,
            StylisticSet7                            ,
            StylisticSet8                            ,
            StylisticSet9                            , 
            StylisticSet10                           ,
            StylisticSet11                           , 
            StylisticSet12                           , 
            StylisticSet13                           ,
            StylisticSet14                           , 
            StylisticSet15                           ,
            StylisticSet16                           ,
            StylisticSet17                           ,
            StylisticSet18                           , 
            StylisticSet19                           ,
            StylisticSet20                           , 
            Subscript                                , 
            Superscript                              ,
            Swash                                    , 
            Titling                                  ,
            TraditionalNameForms                     ,
            TabularFigures                           ,
            TraditionalForms                         , 
            ThirdWidths                              ,
            Unicase                                  , 
            SlashedZero                              , 
            Count
        } 

        private static FeatureTags[] CustomOpenTypeFeatureTags = new FeatureTags[(int)CustomOpenTypeFeatures.Count]
        {
            FeatureTags.AlternativeFractions                     , 
            FeatureTags.PetiteCapitalsFrom----s               ,
            FeatureTags.SmallCapitalsFrom----s                , 
            FeatureTags.ContextualAlternates                     , 
            FeatureTags.CaseSensitiveForms                       ,
            FeatureTags.ContextualLigatures                      , 
            FeatureTags.CapitalSpacing                           ,
            FeatureTags.ContextualSwash                          ,
            FeatureTags.CursivePositioning                       ,
            FeatureTags.DiscretionaryLigatures                   , 
            FeatureTags.ExpertForms                              ,
            FeatureTags.Fractions                                , 
            FeatureTags.FullWidth                                , 
            FeatureTags.HalfForms                                ,
            FeatureTags.HalantForms                              , 
            FeatureTags.AlternateHalfWidth                       ,
            FeatureTags.HistoricalForms                          ,
            FeatureTags.HorizontalKanaAlternates                 ,
            FeatureTags.HistoricalLigatures                      , 
            FeatureTags.HojoKanjiForms                           ,
            FeatureTags.HalfWidth                                , 
            FeatureTags.JIS78Forms                               , 
            FeatureTags.JIS83Forms                               ,
            FeatureTags.JIS90Forms                               , 
            FeatureTags.JIS04Forms                               ,
            FeatureTags.Kerning                                  ,
            FeatureTags.StandardLigatures                        ,
            FeatureTags.LiningFigures                            , 
            FeatureTags.MathematicalGreek                        ,
            FeatureTags.AlternateAnnotationForms                 , 
            FeatureTags.NLCKanjiForms                            , 
            FeatureTags.OldStyleFigures                          ,
            FeatureTags.Ordinals                                 , 
            FeatureTags.ProportionalAlternateWidth               ,
            FeatureTags.PetiteCapitals                           ,
            FeatureTags.ProportionalFigures                      ,
            FeatureTags.ProportionalWidths                       , 
            FeatureTags.QuarterWidths                            ,
            FeatureTags.RubyNotationForms                        , 
            FeatureTags.StylisticAlternates                      , 
            FeatureTags.ScientificInferiors                      ,
            FeatureTags.SmallCapitals                            , 
            FeatureTags.SimplifiedForms                          ,
            FeatureTags.StylisticSet1                            ,
            FeatureTags.StylisticSet2                            ,
            FeatureTags.StylisticSet3                            , 
            FeatureTags.StylisticSet4                            ,
            FeatureTags.StylisticSet5                            , 
            FeatureTags.StylisticSet6                            , 
            FeatureTags.StylisticSet7                            ,
            FeatureTags.StylisticSet8                            , 
            FeatureTags.StylisticSet9                            ,
            FeatureTags.StylisticSet10                           ,
            FeatureTags.StylisticSet11                           ,
            FeatureTags.StylisticSet12                           , 
            FeatureTags.StylisticSet13                           ,
            FeatureTags.StylisticSet14                           , 
            FeatureTags.StylisticSet15                           , 
            FeatureTags.StylisticSet16                           ,
            FeatureTags.StylisticSet17                           , 
            FeatureTags.StylisticSet18                           ,
            FeatureTags.StylisticSet19                           ,
            FeatureTags.StylisticSet20                           ,
            FeatureTags.Subscript                                , 
            FeatureTags.Superscript                              ,
            FeatureTags.Swash                                    , 
            FeatureTags.Titling                                  , 
            FeatureTags.TraditionalNameForms                     ,
            FeatureTags.TabularFigures                           , 
            FeatureTags.TraditionalForms                         ,
            FeatureTags.ThirdWidths                              ,
            FeatureTags.Unicase                                  ,
            FeatureTags.SlashedZero 
        };
 
        private const ushort FeatureNotEnabled = 0xffff; 

        ///  
        /// Compile feature set from the linked list of LSRuns
        ///
        /// TypographyProperties shoulde be either all null or all not-null.
        /// First is used for internal purposes, also can be used by simple clients. 
        ///
        ///  
        ///  Feature set  
        /// 
        /// Critical - This method uses stackalloc to allocate buffer on stack and uses a pointer to that buffer. 
        ///            It also accesses unmanaged memory.
        /// 
        [SecurityCritical]
        internal static unsafe FeatureSet CompileFeatureSet( 
            LSRun[]     lsruns,
            int*        pcchRuns 
            ) 
        {
            Debug.Assert(lsruns != null && lsruns.Length > 0 && lsruns[0] != null); 

            //
            //  Quick check for null properties
            //  Run properties should be all null or all not null 
            //
            if (lsruns[0].RunProp.TypographyProperties == null) 
            { 
                for(int i = 1; i < lsruns.Length; i++)
                { 
                    if (lsruns[i].RunProp.TypographyProperties != null)
                    {
                        throw new ArgumentException(SR.Get(SRID.CompileFeatureSet_InvalidTypographyProperties));
                    } 
                }
 
                return new FeatureSet((uint)LanguageTags.Default, DefaultFeatures, DefaultFeatures.Length); 
            }
            //End of quick check. We will process custom features now. 

            Feature[] features;
            int featureCount;
 
            // Check if this properties are already cached.
            // This will work only if they already had been cached together, 
            // i.e. all cached features are the same. 
            // ( We do not call Equals on all porperties, because it is considered expensive)
            bool sameFeatures = true; 
            lsruns[0].RunProp.TypographyProperties.GetCachedFeatureSet(out features, out featureCount);

            if (features != null) // otherwise, we will have to go through features anyway
            { 
                for(int i = 1; i < lsruns.Length; i++)
                { 
                    Feature[] currentFeatures; 
                    int       currentFeatureCount;
 
                    lsruns[i].RunProp.TypographyProperties.GetCachedFeatureSet(out currentFeatures, out currentFeatureCount);

                    if (features != currentFeatures ||
                        featureCount != currentFeatureCount /* can this actually be if arrays are the same? I guess not, but just in case */ 
                       )
                    { 
                        sameFeatures = false; 
                        break;
                    } 
                }

                if (sameFeatures)
                { 
                    return new FeatureSet((uint)LanguageTags.Default,features,featureCount);
                } 
            } 

            //Create new set, add required features 
            int initialFeatureCount = RequiredFeatures.Length + 5;
            features = new Feature[initialFeatureCount];
            featureCount = RequiredFeatures.Length;
            Array.Copy(RequiredFeatures,features,RequiredFeatures.Length); 

 
            //Allocate feature index array, initalize all features to not enabled 
            ushort* featureIndex = stackalloc ushort[(int)CustomOpenTypeFeatures.Count];
            for (int i = 0; i < (int)CustomOpenTypeFeatures.Count; i++) 
            {
                featureIndex[i] = FeatureNotEnabled;
            }
 
            int currentStart = 0, currentLength;
 
            for(int i = 0; i < lsruns.Length; i++) 
            {
                TextRunTypographyProperties properties = lsruns[i].RunProp.TypographyProperties; 

                currentLength = pcchRuns[i];

                Debug.Assert(currentStart < ushort.MaxValue); 
                Debug.Assert((currentStart + currentLength) < ushort.MaxValue);
 
 
                //StandardLigatures
                SetFeature(CustomOpenTypeFeatures.StandardLigatures, properties.StandardLigatures?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 

                //Kerning
                SetFeature(CustomOpenTypeFeatures.Kerning, properties.Kerning?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);
 
                //----s
                switch (properties.Capitals) 
                { 
                    case FontCapitals.Normal:
                        DisableFeature(CustomOpenTypeFeatures.SmallCapitals,             featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.SmallCapitalsFrom----s, featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.PetiteCapitals,            featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.PetiteCapitalsFrom----s,featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.Unicase,                   featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.Titling,                   featureIndex);
                        break; 
                    case FontCapitals.SmallCaps: 
                        SetFeature(    CustomOpenTypeFeatures.SmallCapitals,             1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        DisableFeature(CustomOpenTypeFeatures.SmallCapitalsFrom----s, featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.PetiteCapitals,            featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.PetiteCapitalsFrom----s,featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.Unicase,                   featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.Titling,                   featureIndex); 
                        break;
                    case FontCapitals.AllSmallCaps: 
                        SetFeature(    CustomOpenTypeFeatures.SmallCapitals,             1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        SetFeature(    CustomOpenTypeFeatures.SmallCapitalsFrom----s, 1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        DisableFeature(CustomOpenTypeFeatures.PetiteCapitals,            featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.PetiteCapitalsFrom----s,featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.Unicase,                   featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.Titling,                   featureIndex);
                        break; 
                    case FontCapitals.PetiteCaps:
                        DisableFeature(CustomOpenTypeFeatures.SmallCapitals,             featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.SmallCapitalsFrom----s, featureIndex); 
                        SetFeature(    CustomOpenTypeFeatures.PetiteCapitals,            1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        DisableFeature(CustomOpenTypeFeatures.PetiteCapitalsFrom----s,featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.Unicase,                   featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.Titling,                   featureIndex);
                        break;
                    case FontCapitals.AllPetiteCaps: 
                        DisableFeature(CustomOpenTypeFeatures.SmallCapitals,             featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.SmallCapitalsFrom----s, featureIndex); 
                        SetFeature(    CustomOpenTypeFeatures.PetiteCapitals,            1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        SetFeature(    CustomOpenTypeFeatures.PetiteCapitalsFrom----s,1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        DisableFeature(CustomOpenTypeFeatures.Unicase,                   featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.Titling,                   featureIndex);
                        break;
                    case FontCapitals.Unicase:
                        DisableFeature(CustomOpenTypeFeatures.SmallCapitals,             featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.SmallCapitalsFrom----s, featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.PetiteCapitals,            featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.PetiteCapitalsFrom----s,featureIndex); 
                        SetFeature(    CustomOpenTypeFeatures.Unicase,                   1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        DisableFeature(CustomOpenTypeFeatures.Titling,                   featureIndex); 
                        break;
                    case FontCapitals.Titling:
                        DisableFeature(CustomOpenTypeFeatures.SmallCapitals,             featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.SmallCapitalsFrom----s, featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.PetiteCapitals,            featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.PetiteCapitalsFrom----s,featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.Unicase,                   featureIndex); 
                        SetFeature(    CustomOpenTypeFeatures.Titling,                   1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        break; 
                }

                //NumeralStyle
                switch (properties.NumeralStyle) 
                {
                    case FontNumeralStyle.Normal: 
                        DisableFeature(CustomOpenTypeFeatures.LiningFigures,              featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.OldStyleFigures,            featureIndex);
                        break; 
                    case FontNumeralStyle.Lining:
                        SetFeature(    CustomOpenTypeFeatures.LiningFigures,              1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        DisableFeature(CustomOpenTypeFeatures.OldStyleFigures,            featureIndex);
                        break; 
                    case FontNumeralStyle.OldStyle:
                        DisableFeature(CustomOpenTypeFeatures.LiningFigures,              featureIndex); 
                        SetFeature(    CustomOpenTypeFeatures.OldStyleFigures,            1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        break;
                } 


                //NumeralAlignment
                switch (properties.NumeralAlignment) 
                {
                    case FontNumeralAlignment.Normal: 
                        DisableFeature(CustomOpenTypeFeatures.ProportionalFigures,       featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.TabularFigures,            featureIndex);
                        break; 
                    case FontNumeralAlignment.Proportional:
                        SetFeature(    CustomOpenTypeFeatures.ProportionalFigures,       1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        DisableFeature(CustomOpenTypeFeatures.TabularFigures,            featureIndex);
                        break; 
                    case FontNumeralAlignment.Tabular:
                        DisableFeature(CustomOpenTypeFeatures.ProportionalFigures,       featureIndex); 
                        SetFeature(    CustomOpenTypeFeatures.TabularFigures,            1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        break;
                } 

                //Fraction
                switch (properties.Fraction)
                { 
                    case FontFraction.Normal:
                        DisableFeature(CustomOpenTypeFeatures.Fractions,                 featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.AlternativeFractions,      featureIndex); 
                        break;
                    case FontFraction.Stacked: 
                        DisableFeature(CustomOpenTypeFeatures.Fractions,                 featureIndex);
                        SetFeature(    CustomOpenTypeFeatures.AlternativeFractions,      1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        break;
                    case FontFraction.Slashed: 
                        SetFeature(    CustomOpenTypeFeatures.Fractions,                 1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        DisableFeature(CustomOpenTypeFeatures.AlternativeFractions,      featureIndex); 
                        break; 
                }
 
                //DiscretionaryLigatures
                SetFeature(CustomOpenTypeFeatures.DiscretionaryLigatures, properties.DiscretionaryLigatures?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);

                //HistoricalLigatures 
                SetFeature(CustomOpenTypeFeatures.HistoricalLigatures, properties.HistoricalLigatures?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);
 
                //HistoricalForms 
                SetFeature(CustomOpenTypeFeatures.HistoricalForms, properties.HistoricalForms?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);
 
                //FontVariants
                switch (properties.Variants)
                {
                    case FontVariants.Normal: 
                        DisableFeature(CustomOpenTypeFeatures.ScientificInferiors,       featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.Ordinals,                  featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.RubyNotationForms,         featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.Subscript,                 featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.Superscript,               featureIndex); 
                        break;
                    case FontVariants.Inferior:
                        SetFeature(    CustomOpenTypeFeatures.ScientificInferiors,       1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        DisableFeature(CustomOpenTypeFeatures.Ordinals,                  featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.RubyNotationForms,         featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.Subscript,                 featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.Superscript,               featureIndex); 
                        break;
                    case FontVariants.Ordinal: 
                        DisableFeature(CustomOpenTypeFeatures.ScientificInferiors,       featureIndex);
                        SetFeature(    CustomOpenTypeFeatures.Ordinals,                  1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        DisableFeature(CustomOpenTypeFeatures.RubyNotationForms,         featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.Subscript,                 featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.Superscript,               featureIndex);
                        break; 
                    case FontVariants.Ruby: 
                        DisableFeature(CustomOpenTypeFeatures.ScientificInferiors,       featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.Ordinals,                  featureIndex); 
                        SetFeature    (CustomOpenTypeFeatures.RubyNotationForms,         1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        DisableFeature(CustomOpenTypeFeatures.Subscript,                 featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.Superscript,               featureIndex);
                        break; 
                    case FontVariants.Subscript:
                        DisableFeature(CustomOpenTypeFeatures.ScientificInferiors,       featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.Ordinals,                  featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.RubyNotationForms,         featureIndex);
                        SetFeature    (CustomOpenTypeFeatures.Subscript,                 1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        DisableFeature(CustomOpenTypeFeatures.Superscript,               featureIndex);
                        break;
                    case FontVariants.Superscript:
                        DisableFeature(CustomOpenTypeFeatures.ScientificInferiors,       featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.Ordinals,                  featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.RubyNotationForms,         featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.Subscript,                 featureIndex); 
                        SetFeature    (CustomOpenTypeFeatures.Superscript,               1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        break; 
                }

                //ContextualLigatures
                SetFeature(CustomOpenTypeFeatures.ContextualLigatures, properties.ContextualLigatures?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 

                //Contextual alternates 
                SetFeature(CustomOpenTypeFeatures.ContextualAlternates, properties.ContextualAlternates?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 

                //CapitalSpacing 
                SetFeature(CustomOpenTypeFeatures.CapitalSpacing, properties.CapitalSpacing?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);

                //Case sensitive forms
                SetFeature(CustomOpenTypeFeatures.CaseSensitiveForms, properties.CaseSensitiveForms?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 

                //StylisticSet1 
                SetFeature(CustomOpenTypeFeatures.StylisticSet1, properties.StylisticSet1?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                //StylisticSet2
                SetFeature(CustomOpenTypeFeatures.StylisticSet2, properties.StylisticSet2?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                //StylisticSet3
                SetFeature(CustomOpenTypeFeatures.StylisticSet3, properties.StylisticSet3?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                //StylisticSet4
                SetFeature(CustomOpenTypeFeatures.StylisticSet4, properties.StylisticSet4?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                //StylisticSet5
                SetFeature(CustomOpenTypeFeatures.StylisticSet5, properties.StylisticSet5?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                //StylisticSet6 
                SetFeature(CustomOpenTypeFeatures.StylisticSet6, properties.StylisticSet6?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                //StylisticSet7 
                SetFeature(CustomOpenTypeFeatures.StylisticSet7, properties.StylisticSet7?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                //StylisticSet8
                SetFeature(CustomOpenTypeFeatures.StylisticSet8, properties.StylisticSet8?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                //StylisticSet9 
                SetFeature(CustomOpenTypeFeatures.StylisticSet9, properties.StylisticSet9?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                //StylisticSet10 
                SetFeature(CustomOpenTypeFeatures.StylisticSet10, properties.StylisticSet10?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                //StylisticSet11
                SetFeature(CustomOpenTypeFeatures.StylisticSet11, properties.StylisticSet11?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                //StylisticSet12
                SetFeature(CustomOpenTypeFeatures.StylisticSet12, properties.StylisticSet12?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                //StylisticSet13
                SetFeature(CustomOpenTypeFeatures.StylisticSet13, properties.StylisticSet13?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                //StylisticSet14
                SetFeature(CustomOpenTypeFeatures.StylisticSet14, properties.StylisticSet14?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                //StylisticSet15 
                SetFeature(CustomOpenTypeFeatures.StylisticSet15, properties.StylisticSet15?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                //StylisticSet16 
                SetFeature(CustomOpenTypeFeatures.StylisticSet16, properties.StylisticSet16?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                //StylisticSet17
                SetFeature(CustomOpenTypeFeatures.StylisticSet17, properties.StylisticSet17?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                //StylisticSet18 
                SetFeature(CustomOpenTypeFeatures.StylisticSet18, properties.StylisticSet18?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                //StylisticSet19 
                SetFeature(CustomOpenTypeFeatures.StylisticSet19, properties.StylisticSet19?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                //StylisticSet20
                SetFeature(CustomOpenTypeFeatures.StylisticSet20, properties.StylisticSet20?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 

                //SlashedZero
                SetFeature(CustomOpenTypeFeatures.SlashedZero, properties.SlashedZero?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount);
 
                //MathematicalGreek
                SetFeature(CustomOpenTypeFeatures.MathematicalGreek, properties.MathematicalGreek?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
 
                //EastAsian expert forms
                SetFeature(CustomOpenTypeFeatures.ExpertForms, properties.EastAsianExpertForms?1:0, currentStart, currentLength, featureIndex, ref features, ref featureCount); 

                //Standard swashes
                SetFeature(CustomOpenTypeFeatures.Swash, properties.StandardSwashes, currentStart, currentLength, featureIndex, ref features, ref featureCount);
 
                //Contextual swashes
                SetFeature(CustomOpenTypeFeatures.ContextualSwash, properties.ContextualSwashes, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
 
                //Stylistic alternates
                SetFeature(CustomOpenTypeFeatures.StylisticAlternates, properties.StylisticAlternates, currentStart, currentLength, featureIndex, ref features, ref featureCount); 

                //Annotation alternates.
                SetFeature(CustomOpenTypeFeatures.AlternateAnnotationForms, properties.AnnotationAlternates, currentStart, currentLength, featureIndex, ref features, ref featureCount);
 
                //EastAsian Widths
                switch (properties.EastAsianWidths) 
                { 
                    case FontEastAsianWidths.Normal:
                        DisableFeature(CustomOpenTypeFeatures.ProportionalWidths,        featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.ProportionalAlternateWidth,featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.FullWidth,                 featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.HalfWidth,                 featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.ThirdWidths,               featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.QuarterWidths,             featureIndex);
                        break; 
                    case FontEastAsianWidths.Proportional: 
                        SetFeature    (CustomOpenTypeFeatures.ProportionalWidths,        1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        SetFeature    (CustomOpenTypeFeatures.ProportionalAlternateWidth,1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        DisableFeature(CustomOpenTypeFeatures.FullWidth,                 featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.HalfWidth,                 featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.ThirdWidths,               featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.QuarterWidths,             featureIndex); 
                        break;
                    case FontEastAsianWidths.Full: 
                        DisableFeature(CustomOpenTypeFeatures.ProportionalWidths,        featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.ProportionalAlternateWidth,featureIndex);
                        SetFeature    (CustomOpenTypeFeatures.FullWidth,                 1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        DisableFeature(CustomOpenTypeFeatures.HalfWidth,                 featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.ThirdWidths,               featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.QuarterWidths,             featureIndex);
                        break; 
                    case FontEastAsianWidths.Half:
                        DisableFeature(CustomOpenTypeFeatures.ProportionalWidths,        featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.ProportionalAlternateWidth,featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.FullWidth,                 featureIndex);
                        SetFeature    (CustomOpenTypeFeatures.HalfWidth,                 1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        DisableFeature(CustomOpenTypeFeatures.ThirdWidths,               featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.QuarterWidths,             featureIndex);
                        break;
                    case FontEastAsianWidths.Third: 
                        DisableFeature(CustomOpenTypeFeatures.ProportionalWidths,        featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.ProportionalAlternateWidth,featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.FullWidth,                 featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.HalfWidth,                 featureIndex);
                        SetFeature    (CustomOpenTypeFeatures.ThirdWidths,               1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        DisableFeature(CustomOpenTypeFeatures.QuarterWidths,             featureIndex);
                        break;
                    case FontEastAsianWidths.Quarter:
                        DisableFeature(CustomOpenTypeFeatures.ProportionalWidths,        featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.ProportionalAlternateWidth,featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.FullWidth,                 featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.HalfWidth,                 featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.ThirdWidths,               featureIndex);
                        SetFeature    (CustomOpenTypeFeatures.QuarterWidths,             1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        break;
                }

                //EastAsian language 
                switch (properties.EastAsianLanguage)
                { 
                    case FontEastAsianLanguage.Normal: 
                        DisableFeature(CustomOpenTypeFeatures.SimplifiedForms,           featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.TraditionalForms,          featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.TraditionalNameForms,      featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.NLCKanjiForms,             featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.HojoKanjiForms,            featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS78Forms,                featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.JIS83Forms,                featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS90Forms,                featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.JIS04Forms,                featureIndex); 
                        break;
                    case FontEastAsianLanguage.Simplified: 
                        SetFeature    (CustomOpenTypeFeatures.SimplifiedForms,           1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        DisableFeature(CustomOpenTypeFeatures.TraditionalForms,          featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.TraditionalNameForms,      featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.NLCKanjiForms,             featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.HojoKanjiForms,            featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS78Forms,                featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.JIS83Forms,                featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.JIS90Forms,                featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS04Forms,                featureIndex); 
                        break;
                    case FontEastAsianLanguage.Traditional:
                        DisableFeature(CustomOpenTypeFeatures.SimplifiedForms,           featureIndex);
                        SetFeature    (CustomOpenTypeFeatures.TraditionalForms,          1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        DisableFeature(CustomOpenTypeFeatures.TraditionalNameForms,      featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.NLCKanjiForms,             featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.HojoKanjiForms,            featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.JIS78Forms,                featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS83Forms,                featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.JIS90Forms,                featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS04Forms,                featureIndex);
                        break;
                    case FontEastAsianLanguage.TraditionalNames: 
                        DisableFeature(CustomOpenTypeFeatures.SimplifiedForms,           featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.TraditionalForms,          featureIndex); 
                        SetFeature    (CustomOpenTypeFeatures.TraditionalNameForms,      1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        DisableFeature(CustomOpenTypeFeatures.NLCKanjiForms,             featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.HojoKanjiForms,            featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.JIS78Forms,                featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS83Forms,                featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS90Forms,                featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS04Forms,                featureIndex); 
                        break;
                    case FontEastAsianLanguage.NlcKanji: 
                        DisableFeature(CustomOpenTypeFeatures.SimplifiedForms,           featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.TraditionalForms,          featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.TraditionalNameForms,      featureIndex); 
                        SetFeature    (CustomOpenTypeFeatures.NLCKanjiForms,             1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        DisableFeature(CustomOpenTypeFeatures.HojoKanjiForms,            featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS78Forms,                featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS83Forms,                featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.JIS90Forms,                featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS04Forms,                featureIndex); 
                        break; 
                    case FontEastAsianLanguage.HojoKanji:
                        DisableFeature(CustomOpenTypeFeatures.SimplifiedForms,           featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.TraditionalForms,          featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.TraditionalNameForms,      featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.NLCKanjiForms,             featureIndex);
                        SetFeature    (CustomOpenTypeFeatures.HojoKanjiForms,            1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        DisableFeature(CustomOpenTypeFeatures.JIS78Forms,                featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS83Forms,                featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.JIS90Forms,                featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.JIS04Forms,                featureIndex);
                        break; 
                    case FontEastAsianLanguage.Jis78:
                        DisableFeature(CustomOpenTypeFeatures.SimplifiedForms,           featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.TraditionalForms,          featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.TraditionalNameForms,      featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.NLCKanjiForms,             featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.HojoKanjiForms,            featureIndex); 
                        SetFeature    (CustomOpenTypeFeatures.JIS78Forms,                1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        DisableFeature(CustomOpenTypeFeatures.JIS83Forms,                featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS90Forms,                featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.JIS04Forms,                featureIndex);
                        break;
                    case FontEastAsianLanguage.Jis83:
                        DisableFeature(CustomOpenTypeFeatures.SimplifiedForms,           featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.TraditionalForms,          featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.TraditionalNameForms,      featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.NLCKanjiForms,             featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.HojoKanjiForms,            featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS78Forms,                featureIndex); 
                        SetFeature    (CustomOpenTypeFeatures.JIS83Forms,                1, currentStart, currentLength, featureIndex, ref features, ref featureCount);
                        DisableFeature(CustomOpenTypeFeatures.JIS90Forms,                featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS04Forms,                featureIndex);
                        break; 
                    case FontEastAsianLanguage.Jis90:
                        DisableFeature(CustomOpenTypeFeatures.SimplifiedForms,           featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.TraditionalForms,          featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.TraditionalNameForms,      featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.NLCKanjiForms,             featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.HojoKanjiForms,            featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS78Forms,                featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS83Forms,                featureIndex);
                        SetFeature    (CustomOpenTypeFeatures.JIS90Forms,                1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        DisableFeature(CustomOpenTypeFeatures.JIS04Forms,                featureIndex);
                        break; 
                    case FontEastAsianLanguage.Jis04: 
                        DisableFeature(CustomOpenTypeFeatures.SimplifiedForms,           featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.TraditionalForms,          featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.TraditionalNameForms,      featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.NLCKanjiForms,             featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.HojoKanjiForms,            featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS78Forms,                featureIndex); 
                        DisableFeature(CustomOpenTypeFeatures.JIS83Forms,                featureIndex);
                        DisableFeature(CustomOpenTypeFeatures.JIS90Forms,                featureIndex); 
                        SetFeature    (CustomOpenTypeFeatures.JIS04Forms,                1, currentStart, currentLength, featureIndex, ref features, ref featureCount); 
                        break;
                } 

                currentStart += currentLength;
            }
 
            // Check if all runs have actually the same features.
            // All feature record should start at 0 and have full length 
            // We skip required features in this check, because they are always the same 
            sameFeatures = true;
            for(int i = RequiredFeatures.Length; i < featureCount; i++) 
            {
                if (features[i].StartIndex != 0 ||
                    features[i].Length != currentStart
                   ) 
                {
                    sameFeatures = false; 
                    break; 
                }
            } 

            if (sameFeatures)
            {
                // Change length for each feature record to 65535, so they do not depend on 
                // particular input length and can be cached
                for(int i = RequiredFeatures.Length; i < featureCount; i++) 
                { 
                    features[i].Length = ushort.MaxValue;
                } 

                // Now cache features inside each run
                for(int i = 0; i < lsruns.Length; i++)
                { 
                    lsruns[i].RunProp.TypographyProperties.SetCachedFeatureSet(features, featureCount);
                } 
            } 

            return new FeatureSet((uint)LanguageTags.Default,features,featureCount); 
        }

        /// 
        ///     Critical: This code dereferences a pointer without validation 
        /// 
        [SecurityCritical] 
        private static unsafe void SetFeature( 
            CustomOpenTypeFeatures      feature,
            int                         parameter, 
            int                         start,
            int                         length,
            ushort*                     featureIndex,
            ref Feature[]               features, 
            ref int                     featureCount
            ) 
        { 
            if (parameter == 0)
            { 
                // Nothing to change, just set featureIndex to not enabled
                featureIndex[(int)feature] = FeatureNotEnabled;
                return;
            } 

            ushort index = featureIndex[(int)feature]; 
            Debug.Assert( // if feature is already enabled, index should be valid and feature record should have the same tag 
                         index == FeatureNotEnabled ||
                         (index < featureCount && features[index].Tag == (uint)CustomOpenTypeFeatureTags[(int)feature]) 
                        );

            // Check if we can just append to existing feature record
            if (index != FeatureNotEnabled && 
                features[index].Parameter == parameter
               ) 
            { 
                features[index].Length += (ushort)length;
                return; 
            }

            //
            // We should add another feature record 
            //
 
            if (featureCount == ushort.MaxValue) 
            {
                throw new OutOfMemoryException(); 
            }

            // reallocate if it is needed
            if (featureCount == features.Length) 
            {
                Feature[] tempFeatures = new Feature[features.Length + 3]; 
                Array.Copy(features, tempFeatures, features.Length); 
                features = tempFeatures;
            } 

            features[featureCount] = new Feature(
                    (ushort)start,
                    (ushort)length, 
                    (uint)CustomOpenTypeFeatureTags[(int)feature],
                    (uint)parameter 
                ); 

            //Set this as current record for the feature 
            featureIndex[(int)feature] = (ushort)featureCount;

            featureCount++;
        } 

        ///  
        /// This is simplified version of SetFeature, 
        /// assuming that parameter is 0
        ///  
        /// 
        ///     Critical: This code dereferences a pointer without validation
        /// 
        [SecurityCritical] 
        private static unsafe void DisableFeature(
            CustomOpenTypeFeatures      feature, 
            ushort*                     featureIndex 
        )
        { 
            // Nothing to change, just set featureIndex to not enabled
            featureIndex[(int)feature] = FeatureNotEnabled;
        }
    } 
}

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