OpenTypeLayout.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / MS / Internal / Shaping / OpenTypeLayout.cs / 1305600 / OpenTypeLayout.cs

                            //+------------------------------------------------------------------------ 
//
//  Microsoft Windows Client Platform
//  Copyright (C) Microsoft Corporation, 2002
// 
//  File:      OpenTypeLayout.cs
// 
//  Contents:  OpentTypeLayout interfaces 
//
//  contact:   sergeym 
//
//  History:   2002-03-02   Created (sergeym)
//
//----------------------------------------------------------------------- 

using System; 
using System.Security; 
using System.Security.Permissions;
using System.IO; 
using System.Diagnostics;

using MS.Internal.FontCache;
 
namespace MS.Internal.Shaping
{ 
    internal struct LayoutOffset 
    {
        public LayoutOffset(int dx, int dy) { this.dx=dx; this.dy=dy; } 
        public int dx;
        public int dy;
    }
 
    /// 
    /// Tags used in OpenTypeLayout 
    ///  
    internal enum OpenTypeTags :uint
    { 
        Null = 0x00000000,

        GSUB = 0x47535542,
        GPOS = 0x47504F53, 
        GDEF = 0x47444546,
        BASE = 0x42415345, 
        name = 0x6e616D65, 
        post = 0x706F7374,
        dflt = 0x64666c74, 
        head = 0x68656164,

        //GSUB feature tags
        locl = 0x6c6f636c, 
        ccmp = 0x63636d70,
        rlig = 0x726c6967, 
        liga = 0x6c696761, 
        clig = 0x636c6967,
        pwid = 0x70776964, 
        init = 0x696e6974,
        medi = 0x6d656469,
        fina = 0x66696e61,
        isol = 0x69736f6c, 
        calt = 0x63616c74,
        //Indic subst 
        nukt = 0x6e756b74, 
        akhn = 0x616b686e,
        rphf = 0x72706866, 
        blwf = 0x626c7766,
        half = 0x68616c66,
        vatu = 0x76617475,
        pres = 0x70726573, 
        abvs = 0x61627673,
        blws = 0x626c7773, 
        psts = 0x70737473, 
        haln = 0x68616c6e,
 
        //GPOS feature tags
        kern = 0x6b65726e,
        mark = 0x6d61726b,
        mkmk = 0x6d6b6d6b, 
        curs = 0x63757273,
        //Indic pos 
        abvm = 0x6162766d, 
        blwm = 0x626c776d,
        dist = 0x64697374, 

        //script tags
        latn = 0x6c61746e
    } 

    ///  
    /// FeatureInfo flags, describing actions implemented in OT feature 
    /// 
    [Flags] 
    internal enum TagInfoFlags : uint
    {
        Substitution    = 0x01, // does glyph substitution
        Positioning     = 0x02, // does glyph positioning 
        Both            = 0x03, // does both substitution and positioning
        None            = 0x00  // neither of them 
    } 

/* Used by commented code below 
    /// 
    /// OpenType feature information. Returned from GetFeatureList method
    /// 
    internal struct TagInfo 
    {
        public uint          Tag; 
        public TagInfoFlags  TagFlags; 

        public static bool IsNewTag(TagInfo[] Tags, uint Tag) 
        {
            for(int i=0; i
    /// Table pointer wrapper. Checking table boundaries
    ///  
    internal unsafe class FontTable
    { 
        ///  
        ///   Critical: This code is unsafe and stores a byte ptr
        ///  
        [SecurityCritical]
        public FontTable(byte[] data)
        {
            m_data = data; 
            if (data != null)
            { 
                m_length = (uint)data.Length; 
            }
            else 
            {
                m_length = 0;
            }
        } 

        public const int InvalidOffset  = int.MaxValue; 
        public const int NullOffset     = 0; 

        ///  
        ///   Critical: This code acceses font table.
        ///   Safe    : This code doesn't expose any value from font table.
        /// 
        public bool IsPresent 
        {
              [SecurityCritical,SecurityTreatAsSafe] 
              get 
           {
                 return (m_data!=null); 
           }
        }

        ///  
        ///   Critical: This code acceses font table data.
        ///  
        [SecurityCritical] 
        public ushort GetUShort(int offset)
        { 
            Invariant.Assert(m_data!= null);

            if ((offset + 1) >= m_length) throw new FileFormatException();
            return (ushort)((m_data[offset]<<8) + m_data[offset+1]); 
        }
        ///  
        ///   Critical: This code acceses font table data. 
        /// 
        [SecurityCritical] 
        public short GetShort(int offset)
        {
            Invariant.Assert(m_data != null);
 
            if ((offset + 1) >= m_length) throw new FileFormatException();
            return (short)((m_data[offset]<<8) + m_data[offset+1]); 
        } 
        /// 
        ///   Critical: This code acceses font table data. 
        /// 
        [SecurityCritical]
        public uint GetUInt(int offset)
        { 
            Invariant.Assert(m_data != null);
 
            if ((offset + 3) >= m_length) throw new FileFormatException(); 
            return (uint)((m_data[offset]<<24) + (m_data[offset+1]<<16) + (m_data[offset+2]<<8) + m_data[offset+3]);
        } 
        /// 
        ///   Critical: This code acceses font table data.
        /// 
        [SecurityCritical] 
        public ushort GetOffset(int offset)
        { 
            Invariant.Assert(m_data != null); 

            if ((offset+1)>=m_length) throw new FileFormatException(); 
            return (ushort)((m_data[offset]<<8) + m_data[offset+1]);
        }

        private byte[] m_data; 

        ///  
        ///     Critical:This code is used to validate length and dereference pointers. 
        /// 
        [SecurityCritical] 
        private uint  m_length;
    }

    ///  
    /// Font file access callbacks
    ///  
    internal interface IOpenTypeFont 
    {
        ///  
        /// Returns array containing font table data
        /// Return empty array if table does not exist.
        /// 
        ///  
        /// Critical - as this accesses FontFaceLayoutInfo.Gdef which exposes font info.
        ///  
        [SecurityCritical] 
        FontTable GetFontTable(OpenTypeTags TableTag);
 
        /// 
        /// Returns glyph coordinate
        /// 
        LayoutOffset GetGlyphPointCoord(ushort Glyph, ushort PointIndex); 

        ///  
        /// Returns cache for layout table. If cache not found, return null Checked pointer 
        /// 
        byte[] GetTableCache(OpenTypeTags tableTag); 

        /// 
        /// Allocate space for layout table cache. If space is not available
        /// client should return null checked pointer. 
        /// Only font cache implementation need to implement this interface.
        /// Normal layout funcitons will not call it. 
        ///  
        byte[] AllocateTableCache(OpenTypeTags tableTag, int size);
    } 

    /// 
    /// Text direction
    ///  
    internal enum TextFlowDirection : ushort
    { 
        LTR, 
        RTL,
        TTB, 
        BTT
    }

    ///  
    /// Layout metrics
    ///  
    internal struct LayoutMetrics 
    {
        public TextFlowDirection Direction; 

        //if DesignEmHeight==0, result requested in design units
        public ushort      DesignEmHeight; // font design units per Em
 
        public ushort      PixelsEmWidth;   // Em width in pixels
        public ushort      PixelsEmHeight;  // Em height in pixels 
 
        public LayoutMetrics(TextFlowDirection Direction,
                             ushort DesignEmHeight, 
                             ushort PixelsEmWidth,
                             ushort PixelsEmHeight)
        {
            this.Direction=Direction; 
            this.DesignEmHeight=DesignEmHeight;
            this.PixelsEmWidth=PixelsEmWidth; 
            this.PixelsEmHeight=PixelsEmHeight; 
        }
    } 

    internal class Feature
    {
        public Feature( 
            ushort  startIndex,
            ushort  length, 
            uint    tag, 
            uint    parameter //0 if disabled
            ) 
        {
            _startIndex = startIndex;
            _length = length;
            _tag = tag; 
            _parameter = parameter;
        } 
 
        public uint Tag
        { 
            get { return _tag; }
            set { _tag = value; }
        }
 
        public uint Parameter
        { 
            get { return _parameter; } 
            set { _parameter = value; }
        } 

        public ushort StartIndex
        {
            get { return _startIndex; } 
            set { _startIndex = value; }
        } 
 
        public ushort Length
        { 
            get { return _length; }
            set { _length = value; }
        }
 
        private ushort  _startIndex;   // first to be applied
        private ushort  _length;       // length to be applied 
        private uint    _tag;          // OpenType feature tag 
        private uint    _parameter;    // feature parameter
    } 

    /// 
    /// OpenTypeLayout class provides access to OpenType Layout services
    ///  
    internal static unsafe class OpenTypeLayout
    { 
        ///  
        /// 
        /// Font 
        /// Script to find
        /// TagInfo, if script not present flags == None
        /// 
        /// Critical - Access protected font information (raw bytes) 
        /// 
        [SecurityCritical] 
        internal static TagInfoFlags FindScript( 
            IOpenTypeFont       Font,     // In: Font access interface
            uint                ScriptTag // In 
            )
        {
            TagInfoFlags flags = TagInfoFlags.None;
 
            try
            { 
                FontTable gsubTable = Font.GetFontTable(OpenTypeTags.GSUB); 
                if (gsubTable.IsPresent)
                { 
                    GSUBHeader gsubHeader = new GSUBHeader(0);
                    if (!gsubHeader.GetScriptList(gsubTable).FindScript(gsubTable,ScriptTag).IsNull)
                    {
                        flags |= TagInfoFlags.Substitution; 
                    }
                } 
            } 
            catch (FileFormatException)
            { 
                return TagInfoFlags.None;
            }

            try 
            {
                FontTable gposTable = Font.GetFontTable(OpenTypeTags.GPOS); 
                if (gposTable.IsPresent) 
                {
                    GPOSHeader gposHeader = new GPOSHeader(0); 
                    if (!gposHeader.GetScriptList(gposTable).FindScript(gposTable,ScriptTag).IsNull)
                    {
                        flags |= TagInfoFlags.Positioning;
                    } 
                }
            } 
            catch (FileFormatException) 
            {
                return TagInfoFlags.None; 
            }

            return flags;
        } 

        ///  
        /// 
        /// 
        /// Font 
        /// Script to search in
        /// LangGys to search for
        /// TagInfoFlags, if script not present == None
        ///  
        /// Critical - access protected font resource (FontTable)
        ///  
        [SecurityCritical] 
        internal static TagInfoFlags FindLangSys(
            IOpenTypeFont       Font, 
            uint                ScriptTag,
            uint                LangSysTag
            )
        { 
            TagInfoFlags flags = TagInfoFlags.None;
 
            try 
            {
                FontTable gsubTable = Font.GetFontTable(OpenTypeTags.GSUB); 
                if (gsubTable.IsPresent)
                {
                    GSUBHeader gsubHeader = new GSUBHeader(0);
                    ScriptTable gsubScript = gsubHeader.GetScriptList(gsubTable).FindScript(gsubTable,ScriptTag); 
                    if (!gsubScript.IsNull && !gsubScript.FindLangSys(gsubTable,LangSysTag).IsNull)
                    { 
                        flags |= TagInfoFlags.Substitution; 
                    }
                } 
            }
            catch (FileFormatException)
            {
                return TagInfoFlags.None; 
            }
 
            try 
            {
                FontTable gposTable = Font.GetFontTable(OpenTypeTags.GPOS); 
                if (gposTable.IsPresent)
                {
                    GPOSHeader gposHeader = new GPOSHeader(0);
                    ScriptTable gposScript = gposHeader.GetScriptList(gposTable).FindScript(gposTable,ScriptTag); 
                    if (!gposScript.IsNull && !gposScript.FindLangSys(gposTable,LangSysTag).IsNull)
                    { 
                        flags |= TagInfoFlags.Positioning; 
                    }
                } 
            }
            catch (FileFormatException)
            {
                return TagInfoFlags.None; 
            }
 
            return flags; 
        }
 
/* This is unused code, but will be used later so it is just commented out for now.

        /// 
        /// Enumerates scripts in a font 
        /// 
        internal static OpenTypeLayoutResult GetScriptList ( 
            IOpenTypeFont       Font,     // In: Font access interface 
            out TagInfo[]       Scripts   // Out: Array of scripts supported
            ) 
        {
            ushort i;
            ushort GposNewTags;
 
            Scripts=null; // Assignment required, because of out attribute.
                          // This value should be owerwritten later. 
 
            try
            { 
                FontTable GsubTable = Font.GetFontTable(OpenTypeTags.GSUB);
                FontTable GposTable = Font.GetFontTable(OpenTypeTags.GPOS);

                GSUBHeader GsubHeader = new GSUBHeader(0); 
                GPOSHeader GposHeader = new GPOSHeader(0);
 
                ScriptList GsubScriptList; 
                ScriptList GposScriptList;
                ushort GsubScriptCount; 
                ushort GposScriptCount;

                if (GsubTable.IsNotPresent && GposTable.IsNotPresent)
                { 
                    Scripts = new TagInfo[0];
                    return OpenTypeLayoutResult.Success; 
                } 

                if (GsubTable.IsPresent) 
                {
                    GsubScriptList  = GsubHeader.GetScriptList(GsubTable);
                    GsubScriptCount = GsubScriptList.GetScriptCount(GsubTable);
                } 
                else
                { 
                    GsubScriptList = new ScriptList(FontTable.InvalidOffset); 
                    GsubScriptCount = 0;
                } 

                if (GposTable.IsPresent)
                {
                    GposScriptList  = GposHeader.GetScriptList(GposTable); 
                    GposScriptCount = GposScriptList.GetScriptCount(GposTable);
                } 
                else 
                {
                    GposScriptList = new ScriptList(FontTable.InvalidOffset); 
                    GposScriptCount = 0;
                }

                //This is true in most cases that there is no new tags in GPOS. 
                //So, we allocate this array then check GPOS for new tags
                Scripts = new TagInfo[GsubScriptCount]; 
 
                for(i=0; i0) 
                { 
                    int CurrentScriptIndex=GposScriptCount;
 
                    //Allocate new array to fit all tags
                    TagInfo[] tmp = Scripts;
                    Scripts = new TagInfo[GsubScriptCount+GposNewTags];
                    Array.Copy(tmp,0,Scripts,0,tmp.Length); 

                    for(i=0;i
        /// Enumerates language systems for script 
        /// 
        internal static OpenTypeLayoutResult  GetLangSysList (
            IOpenTypeFont   Font,       // In: Font access interface
            uint            ScriptTag,  // In: Script tag 
            out TagInfo[]   LangSystems // Out: Array of LangSystems for Script
            ) 
        { 
            ushort i;
            ushort GposNewTags; 

            LangSystems=null; // Assignment required, because of out attribute.
                              // This value should be owerwritten later.
 
            try
            { 
                FontTable GsubTable = Font.GetFontTable(OpenTypeTags.GSUB); 
                FontTable GposTable = Font.GetFontTable(OpenTypeTags.GPOS);
 
                GSUBHeader GsubHeader = new GSUBHeader(0);
                GPOSHeader GposHeader = new GPOSHeader(0);

                ScriptList GsubScriptList; 
                ScriptList GposScriptList;
                ScriptTable GsubScript; 
                ScriptTable GposScript; 
                ushort GsubLangSysCount;
                ushort GposLangSysCount; 

                if (GsubTable.IsNotPresent && GposTable.IsNotPresent)
                {
                    return OpenTypeLayoutResult.ScriptNotFound; 
                }
 
                if (GsubTable.IsPresent) 
                {
                    GsubScriptList = GsubHeader.GetScriptList(GsubTable); 
                    GsubScript = GsubScriptList.FindScript(GsubTable,ScriptTag);
                }
                else
                { 
                    GsubScript = new ScriptTable(FontTable.InvalidOffset);
                } 
 
                if (GposTable.IsPresent)
                { 
                    GposScriptList  = GposHeader.GetScriptList(GposTable);
                    GposScript = GposScriptList.FindScript(GposTable,ScriptTag);
                }
                else 
                {
                    GposScript = new ScriptTable(FontTable.InvalidOffset); 
                } 

                if (GsubScript.IsNull && GposScript.IsNull) 
                {
                    return OpenTypeLayoutResult.ScriptNotFound;
                }
 
                if (!GsubScript.IsNull)
                { 
                    GsubLangSysCount = GsubScript.GetLangSysCount(GsubTable); 
                }
                else 
                {
                    GsubLangSysCount = 0;
                }
 
                if (!GposScript.IsNull)
                { 
                    GposLangSysCount = GposScript.GetLangSysCount(GposTable); 
                }
                else 
                {
                    GposLangSysCount = 0;
                }
 
                //This is true in most cases that there is no new tags in GPOS.
                //So, we allocate this array then check GPOS for new tags 
                ushort CurrentLangSysIndex; 

                if (GsubScript.IsDefaultLangSysExists(GsubTable)) 
                {
                    LangSystems = new TagInfo[GsubLangSysCount+1];
                    LangSystems[0].Tag      = (uint)OpenTypeTags.dflt;
                    LangSystems[0].TagFlags = TagInfoFlags.Substitution; 
                    CurrentLangSysIndex = 1;
                } 
                else 
                {
                    LangSystems = new TagInfo[GsubLangSysCount]; 
                    CurrentLangSysIndex = 0;
                }

                for(i=0; i0)
                { 
                    //Allocate new array to fit all tags
                    TagInfo[] tmp = LangSystems;
                    LangSystems = new TagInfo[GsubLangSysCount+GposNewTags];
                    Array.Copy(tmp,0,LangSystems,0,tmp.Length); 

                    if (GposScript.IsDefaultLangSysExists(GposTable)) 
                    { 
                        if (TagInfo.IsNewTag(LangSystems,(uint)OpenTypeTags.dflt))
                        { 
                            LangSystems[CurrentLangSysIndex].Tag = (uint)OpenTypeTags.dflt;
                            LangSystems[CurrentLangSysIndex].TagFlags = TagInfoFlags.Positioning;
                            ++CurrentLangSysIndex;
                        } 
                        else
                        { 
                            int LangSysIndex = TagInfo.GetTagIndex(LangSystems,(uint)OpenTypeTags.dflt); 
                            LangSystems[LangSysIndex].TagFlags |= TagInfoFlags.Positioning;
                        } 
                    }

                    for(i=0;i
        /// Enumerates features in a language system 
        ///  
        internal static OpenTypeLayoutResult  GetFeatureList (
            IOpenTypeFont   Font,           // In: Font access interface 
            uint            ScriptTag,      // In: Script tag
            uint            LangSysTag,     // In: LangSys tag
            out TagInfo[]   Features        // Out: Array of features
            ) 
        {
            ushort i; 
            ushort GposNewTags; 

            Features=null; // Assignment required, because of out attribute. 
                           // This value should be owerwritten later.

            try
            { 
                FontTable GsubTable = Font.GetFontTable(OpenTypeTags.GSUB);
                FontTable GposTable = Font.GetFontTable(OpenTypeTags.GPOS); 
 
                GSUBHeader GsubHeader = new GSUBHeader(0);
                GPOSHeader GposHeader = new GPOSHeader(0); 

                ScriptList GsubScriptList;
                ScriptList GposScriptList;
                ScriptTable GsubScript; 
                ScriptTable GposScript;
                LangSysTable GsubLangSys; 
                LangSysTable GposLangSys; 
                ushort GsubFeatureCount;
                ushort GposFeatureCount; 
                FeatureList GsubFeatureList;
                FeatureList GposFeatureList;

 
                if (GsubTable.IsNotPresent && GposTable.IsNotPresent)
                { 
                    return OpenTypeLayoutResult.ScriptNotFound; 
                }
 
                if (GsubTable.IsPresent)
                {
                    GsubScriptList  = GsubHeader.GetScriptList(GsubTable);
                    GsubScript      = GsubScriptList.FindScript(GsubTable,ScriptTag); 
                    GsubLangSys     = GsubScript.FindLangSys(GsubTable,LangSysTag);
                    GsubFeatureList = GsubHeader.GetFeatureList(GsubTable); 
                } 
                else
                { 
                    GsubScript = new ScriptTable(FontTable.InvalidOffset);
                    GsubLangSys = new LangSysTable(FontTable.InvalidOffset);
                    GsubFeatureList = new FeatureList(FontTable.InvalidOffset);
                } 

                if (GposTable.IsPresent) 
                { 
                    GposScriptList  = GposHeader.GetScriptList(GposTable);
                    GposScript      = GposScriptList.FindScript(GposTable,ScriptTag); 
                    GposLangSys     = GposScript.FindLangSys(GposTable,LangSysTag);
                    GposFeatureList = GposHeader.GetFeatureList(GposTable);
                }
                else 
                {
                    GposScript = new ScriptTable(FontTable.InvalidOffset); 
                    GposLangSys = new LangSysTable(FontTable.InvalidOffset); 
                    GposFeatureList = new FeatureList(FontTable.InvalidOffset);
                } 

                if (GsubScript.IsNull && GposScript.IsNull)
                {
                    return OpenTypeLayoutResult.ScriptNotFound; 
                }
 
                if (GsubLangSys.IsNull && GposLangSys.IsNull) 
                {
                    return OpenTypeLayoutResult.LangSysNotFound; 
                }

                if (!GsubLangSys.IsNull)
                { 
                    GsubFeatureCount = GsubLangSys.FeatureCount(GsubTable);
                } 
                else 
                {
                    GsubFeatureCount = 0; 
                }

                if (!GposLangSys.IsNull)
                { 
                    GposFeatureCount = GposLangSys.FeatureCount(GposTable);
                } 
                else 
                {
                    GposFeatureCount = 0; 
                }

                Features = new TagInfo[GsubFeatureCount];
                int CurrentFeatureIndex = 0; 

                for(i=0; i0)
                { 
                    //Allocate new array to fit all tags 
                    TagInfo[] tmp = Features;
                    Features = new TagInfo[GsubFeatureCount+GposNewTags]; 
                    Array.Copy(tmp,0,Features,0,tmp.Length);

                    for(i=0;i
        /// Substitutes glyphs according to features defined in the font. 
        /// 
        /// In: Font access interface
        /// In: Workspace for layout engine
        /// In: Script tag 
        /// In: LangSys tag
        /// In: List of features to apply 
        /// In: Actual number of features in  
        /// In: offset of input characters inside FeatureSet
        /// In: Characters count (i.e. .Length); 
        /// In/out: Char to glyph mapping
        /// In/out: List of GlyphInfo structs
        /// Substitution result
        ///  
        /// Critical - access fonttable, which is protected... in addition charcount
        ///            parameters are passed directly to other code, which could result 
        ///            in buffer reads outside of fonttable. 
        /// 
        [SecurityCritical] 
        internal static OpenTypeLayoutResult SubstituteGlyphs(
            IOpenTypeFont           Font,           // In: Font access interface
            OpenTypeLayoutWorkspace workspace,      // In: Workspace for layout engine
            uint                    ScriptTag,      // In: Script tag 
            uint                    LangSysTag,     // In: LangSys tag
            Feature[]               FeatureSet,     // In: List of features to apply 
            int                     featureCount,   // In: Actual number of features in FeatureSet 
            int                     featureSetOffset,
            int                     CharCount,      // In: Characters count (i.e. Charmap.Length); 
            UshortList              Charmap,        // In/out: Char to glyph mapping
            GlyphInfoList           Glyphs          // In/out: List of GlyphInfo structs
            )
        { 
            try
            { 
                FontTable GsubTable = Font.GetFontTable(OpenTypeTags.GSUB); 
                if (!GsubTable.IsPresent) {return OpenTypeLayoutResult.ScriptNotFound;}
 
                GSUBHeader GsubHeader = new GSUBHeader(0);
                ScriptList ScriptList = GsubHeader.GetScriptList(GsubTable);

                ScriptTable Script    = ScriptList.FindScript(GsubTable,ScriptTag); 
                if (Script.IsNull) {return OpenTypeLayoutResult.ScriptNotFound;}
 
                LangSysTable LangSys = Script.FindLangSys(GsubTable,LangSysTag); 
                if (LangSys.IsNull) {return OpenTypeLayoutResult.LangSysNotFound;}
 
                FeatureList FeatureList = GsubHeader.GetFeatureList(GsubTable);
                LookupList LookupList = GsubHeader.GetLookupList(GsubTable);

                LayoutEngine.ApplyFeatures( 
                    Font,
                    workspace, 
                    OpenTypeTags.GSUB, 
                    GsubTable,
                    new LayoutMetrics(), //it is not needed for substitution 
                    LangSys,
                    FeatureList,
                    LookupList,
                    FeatureSet, 
                    featureCount,
                    featureSetOffset, 
                    CharCount, 
                    Charmap,
                    Glyphs, 
                    null,
                    null
                );
            } 
            catch (FileFormatException)
            { 
                return OpenTypeLayoutResult.BadFontTable; 
            }
 
            return OpenTypeLayoutResult.Success;
        }

        ///  
        /// Position glyphs according to features defined in the font.
        ///  
        /// In: Font access interface 
        /// In: Workspace for layout engine
        /// In: Script tag 
        /// In: LangSys tag
        /// In: LayoutMetrics
        /// In: List of features to apply
        /// In: Actual number of features in  
        /// In: offset of input characters inside FeatureSet
        /// In: Characters count (i.e. .Length); 
        /// In: Char to glyph mapping 
        /// In/out: List of GlyphInfo structs
        /// In/out: Glyphs adv.widths 
        /// In/out: Glyph offsets
        /// Substitution result
        /// 
        /// Critical - access fonttable, which is protected... in addition charcount 
        ///            parameters are passed directly to other code, which could result
        ///            in buffer reads outside of fonttable. 
        ///  
        [SecurityCritical]
        internal static OpenTypeLayoutResult PositionGlyphs( 
            IOpenTypeFont           Font,
            OpenTypeLayoutWorkspace workspace,
            uint                    ScriptTag,
            uint                    LangSysTag, 
            LayoutMetrics           Metrics,
            Feature[]               FeatureSet, 
            int                     featureCount, 
            int                     featureSetOffset,
            int                     CharCount, 
            UshortList              Charmap,
            GlyphInfoList           Glyphs,
            int*                    Advances,
            LayoutOffset*           Offsets 
        )
        { 
            try 
            {
                FontTable GposTable = Font.GetFontTable(OpenTypeTags.GPOS); 
                if (!GposTable.IsPresent) {return  OpenTypeLayoutResult.ScriptNotFound;}

                GPOSHeader GposHeader = new GPOSHeader(0);
                ScriptList ScriptList = GposHeader.GetScriptList(GposTable); 

                ScriptTable Script    = ScriptList.FindScript(GposTable,ScriptTag); 
                if (Script.IsNull) {return OpenTypeLayoutResult.ScriptNotFound;} 

                LangSysTable LangSys = Script.FindLangSys(GposTable,LangSysTag); 
                if (LangSys.IsNull) {return OpenTypeLayoutResult.LangSysNotFound;}

                FeatureList FeatureList = GposHeader.GetFeatureList(GposTable);
                LookupList LookupList = GposHeader.GetLookupList(GposTable); 

                LayoutEngine.ApplyFeatures( 
                    Font, 
                    workspace,
                    OpenTypeTags.GPOS, 
                    GposTable,
                    Metrics,
                    LangSys,
                    FeatureList, 
                    LookupList,
                    FeatureSet, 
                    featureCount, 
                    featureSetOffset,
                    CharCount, 
                    Charmap,
                    Glyphs,
                    Advances,
                    Offsets 
                );
            } 
            catch (FileFormatException) 
            {
                return OpenTypeLayoutResult.BadFontTable; 
            }

            return OpenTypeLayoutResult.Success;
        } 

 
        /// 
        ///
        /// 
        /// 
        /// Critical - access fonttable, which is protected... in addition glyph range
        ///            parameters are passed directly to other code, which could result
        ///            in buffer reads outside of fonttable. 
        /// 
        [SecurityCritical] 
        internal static OpenTypeLayoutResult CreateLayoutCache ( 
            IOpenTypeFont       font,           // In: Font access interface
            int                 maxCacheSize    // In: Maximum cache size allowed 
        )
        {
            OpenTypeLayoutCache.CreateCache(font, maxCacheSize);
 
            return OpenTypeLayoutResult.Success;
        } 
 
        ///
        /// Internal method to test layout tables if they are uitable for fast path. 
        /// Returns list of script-langauge pairs that are not optimizable.
        ///
        /// 
        /// Critical - access fonttable, which is protected... in addition glyph range 
        ///            parameters are passed directly to other code, which could result
        ///            in buffer reads outside of fonttable. 
        ///  
        [SecurityCritical]
        internal static OpenTypeLayoutResult GetComplexLanguageList ( 
            IOpenTypeFont       Font,           //In: Font access interface
            uint[]              featureList,     //In: Feature to look in
            uint[]              glyphBits,
            ushort              minGlyphId, 
            ushort              maxGlyphId,
            out WritingSystem[] complexLanguages 
                                                          // Out: List of script/langauge pair 
                                                          //      that are not optimizable
        ) 
        {
            try
            {
                WritingSystem[] gsubComplexLanguages = null; 
                WritingSystem[] gposComplexLanguages = null;
                int gsubComplexLanguagesCount = 0; 
                int gposComplexLanguagesCount = 0; 

                FontTable GsubTable = Font.GetFontTable(OpenTypeTags.GSUB); 
                FontTable GposTable = Font.GetFontTable(OpenTypeTags.GPOS);

                if (GsubTable.IsPresent)
                { 
                    LayoutEngine.GetComplexLanguageList(
                                        OpenTypeTags.GSUB, 
                                        GsubTable, 
                                        featureList,
                                        glyphBits, 
                                        minGlyphId,
                                        maxGlyphId,
                                        out gsubComplexLanguages,
                                        out gsubComplexLanguagesCount 
                                 );
                } 
 
                if (GposTable.IsPresent)
                { 
                    LayoutEngine.GetComplexLanguageList(
                                        OpenTypeTags.GPOS,
                                        GposTable,
                                        featureList, 
                                        glyphBits,
                                        minGlyphId, 
                                        maxGlyphId, 
                                        out gposComplexLanguages,
                                        out gposComplexLanguagesCount 
                                 );
                }

                if (gsubComplexLanguages == null && gposComplexLanguages == null) 
                {
                    complexLanguages = null; 
                    return OpenTypeLayoutResult.Success; 
                }
 
                // Both tables have complex scrips, merge results

                // Count gpos unique Languages
                // and pack them at the same time 
                // so we do not research them again.
                int gposNewLanguages=0, i, j; 
 
                for(i = 0; i < gposComplexLanguagesCount ;i++)
                { 
                    bool foundInGsub = false;

                    for(j = 0; j < gsubComplexLanguagesCount ;j++)
                    { 
                        if (gsubComplexLanguages[j].scriptTag == gposComplexLanguages[i].scriptTag &&
                            gsubComplexLanguages[j].langSysTag == gposComplexLanguages[i].langSysTag 
                           ) 
                        {
                            foundInGsub = true; 
                            break;
                        };
                    }
 
                    if (!foundInGsub)
                    { 
                        if (gposNewLanguages < i) 
                        {
                            gposComplexLanguages[gposNewLanguages] = gposComplexLanguages[i]; 
                        }

                        gposNewLanguages++;
                    } 
                }
 
                //realloc array for merged results, merge both arrays 
                complexLanguages = new WritingSystem[gsubComplexLanguagesCount + gposNewLanguages];
 
                for(i = 0; i < gsubComplexLanguagesCount; i++)
                {
                    complexLanguages[i] = gsubComplexLanguages[i];
                } 

                for(i = 0; i < gposNewLanguages; i++) 
                { 
                    complexLanguages[gsubComplexLanguagesCount + i] = gposComplexLanguages[i];
                } 

                return OpenTypeLayoutResult.Success;

            } 
            catch (FileFormatException)
            { 
                complexLanguages = null; 
                return OpenTypeLayoutResult.BadFontTable;
            } 
        }
    }

    internal struct WritingSystem 
    {
        internal uint scriptTag; 
        internal uint langSysTag; 
    }
 
    /// 
    /// 
    internal enum OpenTypeLayoutResult
    { 
        Success,
        InvalidParameter, 
        TableNotFound, 
        ScriptNotFound,
        LangSysNotFound, 
        BadFontTable,
        UnderConstruction
    }
 
    /// 
    /// Class for internal OpenType use to store per font 
    /// information and temporary buffers. 
    ///
    /// We do not use fontcache now, so this information 
    /// will be recreated every time shaping engine
    /// will be called, so
    ///
 

 
    internal class OpenTypeLayoutWorkspace 
    {
        ///  
        /// Init buffers to initial values.
        /// 
        /// 
        /// Critical:  Calls unsafe code 
        /// Safe:      Does not actually access data through the pointers
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        internal unsafe OpenTypeLayoutWorkspace()
        { 
            _bytesPerLookup     = 0;
            _lookupUsageFlags   = null;
            _cachePointers      = null;
        } 

        ///  
        /// Reset all structures to the new font/OTTable/script/langsys. 
        ///
        /// Client need to call it only once per shaping engine call. 
        /// This is client's responsibility to ensure that workspace is
        /// used for single font/OTTable/script/langsys between Init() calls
        /// 
        ///In: Font access interface 
        ///In: Font table tag
        ///In: Script tag 
        ///In: Language System tag 
        ///Success if workspace is initialized succesfully, specific error if failed
        internal OpenTypeLayoutResult Init( 
            IOpenTypeFont           font,
            OpenTypeTags            tableTag,
            uint                    scriptTag,
            uint                    langSysTag 
            )
        { 
            // Currently all buffers are per call, 
            // no need to do anything.
            return OpenTypeLayoutResult.Success; 
        }

#region Lookup flags
 
        //lookup usage flags access
        private const byte AggregatedFlagMask        = 0x01; 
        private const byte RequiredFeatureFlagMask   = 0x02; 
        private const int  FeatureFlagsStartBit      = 2;
 
        public void InitLookupUsageFlags(int lookupCount, int featureCount)
        {
            _bytesPerLookup = (featureCount + FeatureFlagsStartBit + 7) >> 3;
 
            int requiredLookupUsageArraySize = lookupCount * _bytesPerLookup;
 
            if ( _lookupUsageFlags == null || 
                 _lookupUsageFlags.Length < requiredLookupUsageArraySize)
            { 
                _lookupUsageFlags = new byte[requiredLookupUsageArraySize];
            }

            Array.Clear(_lookupUsageFlags, 0, requiredLookupUsageArraySize); 
        }
 
        public bool IsAggregatedFlagSet(int lookupIndex) 
        {
            return ((_lookupUsageFlags[lookupIndex * _bytesPerLookup] & AggregatedFlagMask) != 0); 
        }

        public bool IsFeatureFlagSet(int lookupIndex, int featureIndex)
        { 
            int flagIndex = featureIndex + FeatureFlagsStartBit;
            int flagByte = (lookupIndex * _bytesPerLookup) + (flagIndex >> 3); 
            byte flagMask = (byte)(1 << (flagIndex %    8)); 

            return ((_lookupUsageFlags[flagByte] & flagMask) != 0); 
        }

        public bool IsRequiredFeatureFlagSet(int lookupIndex)
        { 
            return ((_lookupUsageFlags[lookupIndex * _bytesPerLookup] & RequiredFeatureFlagMask) != 0);
        } 
 
        public void SetFeatureFlag(int lookupIndex, int featureIndex)
        { 
            int startLookupByte = lookupIndex * _bytesPerLookup;
            int flagIndex = featureIndex + FeatureFlagsStartBit;
            int flagByte = startLookupByte + (flagIndex >> 3);
            byte flagMask = (byte)(1 << (flagIndex % 8)); 

            if (flagByte >= _lookupUsageFlags.Length) 
            { 
                //This should be invalid font. Lookup associated with the feature is not in lookup array.
                throw new FileFormatException(); 
            }

            _lookupUsageFlags[flagByte] |= flagMask;
 
            // Also set agregated usage flag
            _lookupUsageFlags[startLookupByte] |= AggregatedFlagMask; 
        } 

        public void SetRequiredFeatureFlag(int lookupIndex) 
        {
            int flagByte = lookupIndex * _bytesPerLookup;

            if (flagByte >= _lookupUsageFlags.Length) 
            {
                //This should be invalid font. Lookup associated with the feature is not in lookup array. 
                throw new FileFormatException(); 
            }
 
            //set RequiredFeature and aggregated flag at the same time
            _lookupUsageFlags[flagByte] |= (AggregatedFlagMask | RequiredFeatureFlagMask);
        }
 
        // Define cache which lookup is enabled by which feature.
        // Buffer grows with number of features applied 
        private int _bytesPerLookup; 
        private byte[] _lookupUsageFlags;
#endregion Lookup flags 

#region Layout cache pointers

        ///  
        /// Allocate enough memory for array of cache pointers, parallel to glyph run.
        /// 
        /// These method should not be used directly, it is only called by OpenTypeLayputCache. 
        ///
        ///  
        ///In: Size of a glyph run
        /// 
        /// Critical:  Calls unsafe code
        /// Safe:      Does not actually access data through the pointers 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        public unsafe void AllocateCachePointers(int glyphRunLength) 
        {
            if (_cachePointers != null && _cachePointers.Length >= glyphRunLength) return; 

            _cachePointers = new ushort[glyphRunLength];
        }
 
        /// 
        /// If glyph run is cahnged, update pointers according to the change. Reallocate array if necessary. 
        /// 
        /// These method should not be used directly, it is only called by OpenTypeLayputCache.
        /// 
        /// 
        ///In: Number of glyphs in the run before change
        ///In: Number of glyphs in the run after change
        ///In: Index of the first changed glyph 
        ///In: Index of the glyph after last changed
        ///  
        /// Critical:  Calls unsafe code 
        /// Safe:      Does not actually access data through the pointers
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        public unsafe void UpdateCachePointers(
                                        int     oldLength,
                                        int     newLength, 
                                        int     firstGlyphChanged,
                                        int     afterLastGlyphChanged 
                                       ) 
        {
            if (oldLength != newLength) 
            {
                int oldAfterLastGlyphChanged = afterLastGlyphChanged - (newLength - oldLength);

                if (_cachePointers.Length < newLength) 
                {
                    ushort[] tmp = new ushort[newLength]; 
 
                    Array.Copy(_cachePointers, tmp, firstGlyphChanged);
                    Array.Copy(_cachePointers, oldAfterLastGlyphChanged, tmp, afterLastGlyphChanged, oldLength - oldAfterLastGlyphChanged); 

                    _cachePointers = tmp;
                }
                else 
                {
                        Array.Copy(_cachePointers, oldAfterLastGlyphChanged, _cachePointers, afterLastGlyphChanged, oldLength - oldAfterLastGlyphChanged); 
                } 
            }
        } 

        /// 
        /// Critical:  Exposes font cache raw pointers
        ///  
        public unsafe ushort[] CachePointers
        { 
            [SecurityCritical] 
            get { return _cachePointers; }
        } 

        /// 
        /// Critical:  Exposes font cache raw pointers
        ///  
        public byte[] TableCacheData
        { 
            [SecurityCritical] 
            get { return _tableCache; }
            [SecurityCritical] 
            set { _tableCache = value; }
        }

        // Array of cache pointers, per glyph 
        /// 
        ///     Critical: This holds font cache raw pointers 
        ///  
        [SecurityCritical]
        private unsafe ushort[]  _cachePointers; 

        // Pointer to the table cache
        /// 
        ///     Critical: This holds font cache raw pointers 
        /// 
        [SecurityCritical] 
        private byte[]      _tableCache; 

#endregion Layout cache pointers 
    }
}

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