Esempio n. 1
0
        public static void InitCache(
            IOpenTypeFont font,
            OpenTypeTags tableTag,
            GlyphInfoList glyphInfo,
            OpenTypeLayoutWorkspace workspace
            )
        {
            Debug.Assert(tableTag == OpenTypeTags.GSUB || tableTag == OpenTypeTags.GPOS);

            byte[] cacheArray = font.GetTableCache(tableTag);

            unsafe
            {
                if (cacheArray == null)
                {
                    workspace.TableCacheData = null;
                }
                else
                {
                    workspace.TableCacheData = cacheArray;

                    workspace.AllocateCachePointers(glyphInfo.Length);
                    RenewPointers(glyphInfo, workspace, 0, glyphInfo.Length);
                }
            }
        }
Esempio n. 2
0
        private static unsafe void RenewPointers(
            GlyphInfoList glyphInfo,
            OpenTypeLayoutWorkspace workspace,
            int firstGlyph,
            int afterLastGlyph
            )
        {
            fixed(byte *pCache = &workspace.TableCacheData[0])
            {
                // If there is no chache, just exit
                if (pCache == null)
                {
                    return;
                }

                ushort[] cachePointers = workspace.CachePointers;

                for (int i = firstGlyph; i < afterLastGlyph; i++)
                {
                    ushort glyph = glyphInfo.Glyphs[i];

                    // If glyph is not there, we will point to the constant 0xFFFF in the cache
                    int listOffset = 2;

                    //Find glyph entry in the cache
                    int     glyphCount = *((ushort *)pCache + 3);
                    ushort *pGlyphs = (ushort *)pCache + 4;
                    int     low = 0, high = glyphCount;

                    while (low < high)
                    {
                        int    mid      = (low + high) >> 1;
                        ushort midGlyph = pGlyphs[mid * 2];

                        if (glyph < midGlyph)
                        {
                            high = mid;
                            continue;
                        }
                        if (glyph > midGlyph)
                        {
                            low = mid + 1;
                            continue;
                        }

                        // Found it!
                        listOffset = pGlyphs[mid * 2 + 1];
                        break;
                    }

                    // Whether we found glyph in the cache or not,
                    // Pointer will be set to the list, but it may be empty.
                    cachePointers[i] = *((ushort *)(pCache + listOffset));
                }
            }
        }
Esempio n. 3
0
        /// <summary>
        /// ShaperBuffers - constructor
        /// </summary>
        /// <SecurityNote>
        ///     Critical: This code accepts checked pointers and extracts
        ///         unsafe pointers.
        /// </SecurityNote>
        public ShaperBuffers(ushort charCount, ushort glyphCount)
        {
            // the charCount is used to provide an initial size for the
            // various buffers used by the shaper(s).  These may
            // grow over the shaper's life
            _glyphInfoList   = new GlyphInfoList((glyphCount > charCount ? glyphCount : charCount), 16, false);
            _charMap         = new UshortList(charCount, 16);
            _layoutWorkspace = new OpenTypeLayoutWorkspace();

            _charMap.SetRange(0, charCount);
            if (glyphCount > 0)
            {
                _glyphInfoList.SetRange(0, glyphCount);
            }
        }
Esempio n. 4
0
        private static unsafe ushort GetCacheLookupCount(OpenTypeLayoutWorkspace workspace)
        {
            // If there is no chache, just exit
            if (workspace.TableCacheData == null)
            {
                return(0);
            }

            fixed(byte *pCacheByte = &workspace.TableCacheData[0])
            {
                ushort *pCache = (ushort *)pCacheByte;

                return(pCache[2]);
            }
        }
Esempio n. 5
0
        public static unsafe void FindNextLookup(
            OpenTypeLayoutWorkspace workspace,
            GlyphInfoList glyphInfo,
            ushort firstLookupIndex,
            out ushort lookupIndex,
            out int firstGlyph
            )
        {
            if (firstLookupIndex >= GetCacheLookupCount(workspace))
            {
                // For lookups that did not fit into cache, just say we should always try it
                lookupIndex = firstLookupIndex;
                firstGlyph  = 0;
                return;
            }

            ushort[] cachePointers = workspace.CachePointers;
            int      glyphCount    = glyphInfo.Length;

            lookupIndex = 0xffff;
            firstGlyph  = 0;

            for (int i = 0; i < glyphCount; i++)
            {
                // Sync up inside the list up to the minimal lookup requested
                // No additional boundary checks are necessary, because every list terminates with 0xffff
                while (cachePointers[i] < firstLookupIndex)
                {
                    cachePointers[i]++;
                }
                //Now we know that our index is higher or equal than firstLookup index

                if (cachePointers[i] < lookupIndex)
                {
                    // We now have new minimum
                    lookupIndex = cachePointers[i];
                    firstGlyph  = i;
                }
            }

            if (lookupIndex == 0xffff)
            {
                // We can't just say we are done, there may be lookups that did not fit into cache
                lookupIndex = GetCacheLookupCount(workspace);
                firstGlyph  = 0;
            }
        }
Esempio n. 6
0
        /// <summary> 
        /// ShaperBuffers - constructor 
        /// </summary>
        /// <SecurityNote> 
        ///     Critical: This code accepts checked pointers and extracts
        ///         unsafe pointers.
        /// </SecurityNote>
        public ShaperBuffers(ushort charCount, ushort glyphCount) 
        {
 
            // the charCount is used to provide an initial size for the 
            // various buffers used by the shaper(s).  These may
            // grow over the shaper's life 
            _glyphInfoList = new GlyphInfoList((glyphCount > charCount ? glyphCount : charCount), 16, false);
            _charMap = new UshortList(charCount, 16);
            _layoutWorkspace = new OpenTypeLayoutWorkspace();
 
            _charMap.SetRange(0,charCount);
            if (glyphCount > 0) 
            { 
                _glyphInfoList.SetRange(0,glyphCount);
            } 

        }
Esempio n. 7
0
        public static void OnGlyphsChanged(
            OpenTypeLayoutWorkspace workspace,
            GlyphInfoList glyphInfo,
            int oldLength,
            int firstGlyphChanged,
            int afterLastGlyphChanged
            )
        {
            unsafe
            {
                if (workspace.TableCacheData == null)
                {
                    return;
                }
            }

            workspace.UpdateCachePointers(oldLength, glyphInfo.Length, firstGlyphChanged, afterLastGlyphChanged);
            RenewPointers(glyphInfo, workspace, firstGlyphChanged, afterLastGlyphChanged);
        }
Esempio n. 8
0
        public static unsafe bool FindNextGlyphInLookup(
            OpenTypeLayoutWorkspace workspace,
            ushort lookupIndex,
            bool isLookupReversal,
            ref int firstGlyph,
            ref int afterLastGlyph
            )
        {
            if (lookupIndex >= GetCacheLookupCount(workspace))
            {
                return(true);
            }

            ushort[] cachePointers = workspace.CachePointers;

            if (!isLookupReversal)
            {
                for (int i = firstGlyph; i < afterLastGlyph; i++)
                {
                    if (cachePointers[i] == lookupIndex)
                    {
                        firstGlyph = i;
                        return(true);
                    }
                }

                return(false);
            }
            else
            {
                for (int i = afterLastGlyph - 1; i >= firstGlyph; i--)
                {
                    if (cachePointers[i] == lookupIndex)
                    {
                        afterLastGlyph = i + 1;
                        return(true);
                    }
                }

                return(false);
            }
        }
Esempio n. 9
0
        /// <summary>
        /// Position glyphs according to features defined in the font.
        /// </summary>
        /// <param name="Font">In: Font access interface</param>
        /// <param name="workspace">In: Workspace for layout engine</param>
        /// <param name="ScriptTag">In: Script tag</param>
        /// <param name="LangSysTag">In: LangSys tag</param>
        /// <param name="Metrics">In: LayoutMetrics</param>
        /// <param name="FeatureSet">In: List of features to apply</param>
        /// <param name="featureCount">In: Actual number of features in <paramref name="FeatureSet"/></param>
        /// <param name="featureSetOffset">In: offset of input characters inside FeatureSet</param>
        /// <param name="CharCount">In: Characters count (i.e. <paramref name="Charmap"/>.Length);</param>
        /// <param name="Charmap">In: Char to glyph mapping</param>
        /// <param name="Glyphs">In/out: List of GlyphInfo structs</param>
        /// <param name="Advances">In/out: Glyphs adv.widths</param>
        /// <param name="Offsets">In/out: Glyph offsets</param>
        /// <returns>Substitution result</returns>
        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);
        }
Esempio n. 10
0
/* This is unused code, but will be used later so it is just commented out for now.
 *
 *      /// <summary>
 *      /// Enumerates scripts in a font
 *      /// </summary>
 *      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 = Array.Empty<TagInfo>();
 *                  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; i<GsubScriptCount; i++)
 *              {
 *                  Scripts[i].Tag      = GsubScriptList.GetScriptTag(GsubTable,i);
 *                  Scripts[i].TagFlags = TagInfoFlags.Substitution;
 *              }
 *
 *              //Check GPOS for tags that is not in GSUB
 *              GposNewTags=0;
 *
 *              for(i=0;i<GposScriptCount;i++)
 *              {
 *                  uint GposTag = GsubScriptList.GetScriptTag(GposTable,i);
 *                  if (TagInfo.IsNewTag(Scripts,GposTag)) GposNewTags++;
 *              }
 *
 *              //append new tags to ScriptTags if any exists
 *              if (GposNewTags>0)
 *              {
 *                  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<GposScriptCount;i++)
 *                  {
 *                      uint GposTag = GsubScriptList.GetScriptTag(GposTable,i);
 *                      if (TagInfo.IsNewTag(Scripts,GposTag))
 *                      {
 *                          Scripts[CurrentScriptIndex].Tag=GposTag;
 *                          Scripts[CurrentScriptIndex].TagFlags
 *                              = TagInfoFlags.Positioning;
 ++CurrentScriptIndex;
 *                      }
 *                      else
 *                      {
 *                          int ScriptIndex = TagInfo.GetTagIndex(Scripts,GposTag);
 *                          Scripts[ScriptIndex].TagFlags |= TagInfoFlags.Positioning;
 *                      }
 *                  }
 *
 *                  Debug.Assert(CurrentScriptIndex==Scripts.Length);
 *              }
 *          }
 *          catch (FileFormatException)
 *          {
 *              return OpenTypeLayoutResult.BadFontTable;
 *          }
 *
 *          return OpenTypeLayoutResult.Success;
 *      }
 *
 *
 *      ///<summary>
 *      /// Enumerates language systems for script
 *      /// </summary>
 *      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; i<GsubLangSysCount; i++)
 *              {
 *                  LangSystems[CurrentLangSysIndex].Tag = GsubScript.GetLangSysTag(GsubTable,i);
 *                  LangSystems[CurrentLangSysIndex].TagFlags = TagInfoFlags.Substitution;
 ++CurrentLangSysIndex;
 *              }
 *
 *              //Check GPOS for tags that is not in GSUB
 *              GposNewTags=0;
 *
 *              if (!GposScript.IsNull)
 *              {
 *                  if (GposScript.IsDefaultLangSysExists(GposTable) &&
 *                      TagInfo.IsNewTag(LangSystems,(uint)OpenTypeTags.dflt))
 *                  {
 ++GposNewTags;
 *                  }
 *
 *                  for(i=0;i<GposLangSysCount;i++)
 *                  {
 *                      uint GposTag = GsubScript.GetLangSysTag(GposTable,i);
 *                      if (TagInfo.IsNewTag(LangSystems,GposTag))
 *                      {
 ++GposNewTags;
 *                      }
 *                  }
 *              }
 *
 *              Debug.Assert(CurrentLangSysIndex==LangSystems.Length);
 *
 *              //append new tags to ScriptTags if any exists
 *              if (GposNewTags>0)
 *              {
 *                  //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<GposLangSysCount;i++)
 *                  {
 *                      uint GposTag = GposScript.GetLangSysTag(GposTable,i);
 *
 *                      if (TagInfo.IsNewTag(LangSystems,GposTag))
 *                      {
 *                          LangSystems[CurrentLangSysIndex].Tag = GposTag;
 *                          LangSystems[CurrentLangSysIndex].TagFlags = TagInfoFlags.Positioning;
 ++CurrentLangSysIndex;
 *                      }
 *                      else
 *                      {
 *                          int LangSysIndex = TagInfo.GetTagIndex(LangSystems,GposTag);
 *                          LangSystems[LangSysIndex].TagFlags |= TagInfoFlags.Positioning;
 *                      }
 *                  }
 *
 *                  Debug.Assert(CurrentLangSysIndex==LangSystems.Length);
 *              }
 *          }
 *          catch (FileFormatException)
 *          {
 *              return OpenTypeLayoutResult.BadFontTable;
 *          }
 *
 *          return OpenTypeLayoutResult.Success;
 *      }
 *
 *
 *      /// <summary>
 *      /// Enumerates features in a language system
 *      /// </summary>
 *      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; i<GsubFeatureCount; i++)
 *              {
 *                  ushort FeatureIndex = GsubLangSys.GetFeatureIndex(GsubTable,i);
 *                  Features[CurrentFeatureIndex].Tag = GsubFeatureList.FeatureTag(GsubTable,FeatureIndex);
 *                  Features[CurrentFeatureIndex].TagFlags = TagInfoFlags.Substitution;
 ++CurrentFeatureIndex;
 *              }
 *
 *              Debug.Assert(CurrentFeatureIndex==Features.Length);
 *
 *              //Check GPOS for tags that is not in GSUB
 *              GposNewTags=0;
 *              if (!GposLangSys.IsNull)
 *              {
 *                  for(i=0;i<GposFeatureCount;i++)
 *                  {
 *                      ushort FeatureIndex = GposLangSys.GetFeatureIndex(GposTable,i);
 *                      uint GposTag = GposFeatureList.FeatureTag(GposTable,FeatureIndex);
 *                      if (TagInfo.IsNewTag(Features,GposTag))
 *                      {
 ++GposNewTags;
 *                      }
 *                  }
 *              }
 *
 *              //append new tags to ScriptTags if any exists
 *              if (GposNewTags>0)
 *              {
 *                  //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<GposFeatureCount;i++)
 *                  {
 *                      ushort FeatureIndex = GposLangSys.GetFeatureIndex(GposTable,i);
 *                      uint GposTag = GposFeatureList.FeatureTag(GposTable,FeatureIndex);
 *
 *                      if (TagInfo.IsNewTag(Features,GposTag))
 *                      {
 *                          Features[CurrentFeatureIndex].Tag = GposTag;
 *                          Features[CurrentFeatureIndex].TagFlags = TagInfoFlags.Positioning;
 ++CurrentFeatureIndex;
 *                      }
 *                      else
 *                      {
 *                          int Index = TagInfo.GetTagIndex(Features,GposTag);
 *                          Features[Index].TagFlags |= TagInfoFlags.Positioning;
 *                      }
 *                  }
 *
 *                  Debug.Assert(CurrentFeatureIndex==Features.Length);
 *              }
 *
 *
 *          }
 *          catch (FileFormatException)
 *          {
 *              return OpenTypeLayoutResult.BadFontTable;
 *          }
 *
 *          return OpenTypeLayoutResult.Success;
 *      }
 */

        /// <summary>
        /// Substitutes glyphs according to features defined in the font.
        /// </summary>
        /// <param name="Font">In: Font access interface</param>
        /// <param name="workspace">In: Workspace for layout engine</param>
        /// <param name="ScriptTag">In: Script tag</param>
        /// <param name="LangSysTag">In: LangSys tag</param>
        /// <param name="FeatureSet">In: List of features to apply</param>
        /// <param name="featureCount">In: Actual number of features in <paramref name="FeatureSet"/></param>
        /// <param name="featureSetOffset">In: offset of input characters inside FeatureSet</param>
        /// <param name="CharCount">In: Characters count (i.e. <paramref name="Charmap"/>.Length);</param>
        /// <param name="Charmap">In/out: Char to glyph mapping</param>
        /// <param name="Glyphs">In/out: List of GlyphInfo structs</param>
        /// <returns>Substitution result</returns>
        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);
        }
Esempio n. 11
0
        private static void GetNextEnabledGlyphRange(
            Feature[]               FeatureSet,     // In: List of features to apply
            int                     featureCount,   // In: Actual nubmer of features in FeatureSet
            int                     featureSetOffset, // In: offset of input chars inside feature set
            FontTable               Table,          // Layout table (GSUB or GPOS)
            OpenTypeLayoutWorkspace workspace,      // workspace with compiled feature set
            LangSysTable            LangSys,        // Language system
            FeatureList             Features,       // List of Features in layout table
            ushort                  lookupIndex,    // List of lokups definitions in layout table
            int                     CharCount,      // Characters count (i.e. Charmap.Length);
            UshortList              Charmap,        // Character to glyph mapping

            int                     StartChar,
            int                     StartGlyph,
            int                     GlyphRunLength,

            out int                 FirstChar,      // First char in enabled range
            out int                 AfterLastChar,  // next char after enabled range
            out int                 FirstGlyph,     // First char in enabled range
            out int                 AfterLastGlyph, // next char after enabled range
            out uint                Parameter       // applied feature parameter
            )
        {
            FirstChar       = int.MaxValue;
            AfterLastChar   = int.MaxValue;
            FirstGlyph      = StartGlyph;
            AfterLastGlyph  = GlyphRunLength;
            Parameter       = 0;

            if (workspace.IsRequiredFeatureFlagSet(lookupIndex))
            {
                FirstChar       = StartChar;
                AfterLastChar   = CharCount;
                FirstGlyph      = StartGlyph;
                AfterLastGlyph  = GlyphRunLength;

                return;
            }

            for(int feature=0; feature < featureCount; feature++)
            {
                if (!workspace.IsFeatureFlagSet(lookupIndex,feature))
                {
                    continue;
                }

                Feature featureDescription = FeatureSet[feature];

                // Shift values from the feature by specified offset and
                // work with these values from here
                int featureStart = featureDescription.StartIndex - featureSetOffset;
                if (featureStart < 0)
                {
                    featureStart = 0;
                }

                int featureAfterEnd = featureDescription.StartIndex + featureDescription.Length
                                            - featureSetOffset;
                if (featureAfterEnd > CharCount)
                {
                    featureAfterEnd = CharCount;
                }

                //If feature is disabled there should not be any flag set
                Debug.Assert(featureDescription.Parameter != 0);

                if (featureAfterEnd <= StartChar)
                {
                    continue;
                }

                if (featureStart < FirstChar ||
                    (
                      featureStart == FirstChar &&
                      featureAfterEnd >= AfterLastChar
                    )
                   )
                {
                    FirstChar     = featureStart;
                    AfterLastChar = featureAfterEnd;
                    Parameter     = featureDescription.Parameter;
                    continue;
                }
            }

            //No ranges found
            if (FirstChar == int.MaxValue)
            {
                FirstGlyph      = GlyphRunLength;
                AfterLastGlyph  = GlyphRunLength;
            }
            else
            {
                if (StartGlyph > Charmap[FirstChar])
                    FirstGlyph = StartGlyph;
                else
                    FirstGlyph = Charmap[FirstChar];

                if (AfterLastChar < CharCount)
                    AfterLastGlyph = Charmap[AfterLastChar];
                else
                    AfterLastGlyph = GlyphRunLength;
            }

        }
Esempio n. 12
0
        private static void CompileFeatureSet(
            Feature[]               FeatureSet,     // In: List of features to apply
            int                     featureCount,   // In: Actual number of features in FeatureSet
            int                     featureSetOffset, //In: Offset of character input sequence inside feature set
            int                     charCount,      // In: number of characters in the input string
            FontTable               Table,          // In: Layout table (GSUB or GPOS)
            LangSysTable            LangSys,        // In: Language system
            FeatureList             Features,       // In: List of Features in layout table
            int                     lookupCount,    // In: number of lookup in layout table
            OpenTypeLayoutWorkspace workspace       // In: workspace with compiled feature set
            )
        {
            workspace.InitLookupUsageFlags(lookupCount, featureCount);

            //Set lookup uasge flags for required feature
            FeatureTable requiredFeatureTable = LangSys.RequiredFeature(Table, Features);
            if (!requiredFeatureTable.IsNull)
            {
                int featureLookupCount = requiredFeatureTable.LookupCount(Table);
                for(ushort lookup = 0; lookup < featureLookupCount; lookup++)
                {
                    workspace.SetRequiredFeatureFlag(requiredFeatureTable.LookupIndex(Table,lookup));
                }
            }

            //Set lookup usage flags for each feature in the FeatureSet
            for(int feature = 0; feature < featureCount; feature++)
            {
                Feature featureDescription = FeatureSet[feature];

                //Filter out features which:
                // Not enabled or applied completely before or after input characters
                if (featureDescription.Parameter == 0 ||
                    featureDescription.StartIndex >= (featureSetOffset + charCount) ||
                    (featureDescription.StartIndex+featureDescription.Length) <= featureSetOffset
                   )
                {
                    continue;
                }

                FeatureTable featureTable = LangSys.FindFeature( Table,
                                                                 Features,
                                                                 featureDescription.Tag);
                if (featureTable.IsNull)
                {
                    continue;
                }

                int featureLookupCount = featureTable.LookupCount(Table);
                for(ushort lookup = 0; lookup < featureLookupCount; lookup++)
                {
                    workspace.SetFeatureFlag(featureTable.LookupIndex(Table,lookup), feature);
                }
            }
        }
Esempio n. 13
0
        public static void ApplyFeatures(
            IOpenTypeFont           Font,
            OpenTypeLayoutWorkspace workspace,
            OpenTypeTags            TableTag,
            FontTable               Table,
            LayoutMetrics           Metrics,
            LangSysTable            LangSys,
            FeatureList             Features,
            LookupList              Lookups,
            Feature[]               FeatureSet,
            int                     featureCount,
            int                     featureSetOffset,
            int                     CharCount,
            UshortList              Charmap,
            GlyphInfoList           GlyphInfo,
            int*                    Advances,
            LayoutOffset*           Offsets
            )
        {
            UpdateGlyphFlags(Font, GlyphInfo, 0, GlyphInfo.Length, false, GlyphFlags.NotChanged);

            // if client did not supply us with workspace
            // we will create our own (temporarily)
            if (workspace == null)
            {
                workspace = new OpenTypeLayoutWorkspace();
            }

            ushort lookupCount=Lookups.LookupCount(Table);

            //Compile feature set
            CompileFeatureSet(
                                FeatureSet,
                                featureCount,
                                featureSetOffset,
                                CharCount,
                                Table,
                                LangSys,
                                Features,
                                lookupCount,
                                workspace
                             );

            OpenTypeLayoutCache.InitCache(Font, TableTag, GlyphInfo, workspace);

            for(ushort lookupIndex = 0; lookupIndex < lookupCount; lookupIndex++)
            {
                if (!workspace.IsAggregatedFlagSet(lookupIndex))
                {
                    continue;
                }

                int  firstChar=0,
                     afterLastChar=0,
                     firstGlyph=0,
                     afterLastGlyph=0;

                OpenTypeLayoutCache.FindNextLookup(workspace, 
                                                   GlyphInfo, 
                                                   lookupIndex, 
                                                   out lookupIndex, 
                                                   out firstGlyph);

                // We need to check this again, because FindNextLookup will change lookupIndex
                if (lookupIndex >= lookupCount)
                {
                    break;
                }

                if (!workspace.IsAggregatedFlagSet(lookupIndex))
                {
                    continue;
                }

                LookupTable lookup = Lookups.Lookup(Table, lookupIndex);

                uint parameter=0;
                bool isLookupReversal = IsLookupReversal(TableTag, lookup.LookupType());

                while(firstGlyph < GlyphInfo.Length) // While we have ranges to work on
                {
                    if (!OpenTypeLayoutCache.FindNextGlyphInLookup(workspace, lookupIndex, isLookupReversal, ref firstGlyph, ref afterLastGlyph))
                    {
                        firstGlyph = afterLastGlyph;
                    }

                    if (firstGlyph < afterLastGlyph) // Apply lookup while in one range
                    {
                        int nextGlyph;
                        int oldLength = GlyphInfo.Length;
                        int glyphsAfterLastChar = oldLength - afterLastGlyph;

                        bool match = ApplyLookup(
                                            Font,           // In: Font access interface
                                            TableTag,       // Layout table tag (GSUB or GPOS)
                                            Table,          // Layout table (GSUB or GPOS)
                                            Metrics,        // In: LayoutMetrics
                                            lookup,         // Lookup definition structure
                                            CharCount,
                                            Charmap,        // In: Char to glyph mapping
                                            GlyphInfo,      // In/out: List of GlyphInfo structs
                                            Advances,       // In/out: Glyph adv.widths
                                            Offsets,        // In/out: Glyph offsets

                                            firstGlyph,     // where to apply it
                                            afterLastGlyph, // how long is a context we can use
                                            parameter,      // lookup parameter
                                            0,              // Nesting level for contextual lookups
                                            out nextGlyph   // out: next glyph index
                                                            // !!!: for reversal lookup, should
                                                            //      return new afterLastGlyph
                                            );

                        if (match)
                        {
                            //Adjust range end if length changed,
                            // for reversal changes happens beyond afterLast, no change needed
                            if (!isLookupReversal)
                            {
                                OpenTypeLayoutCache.OnGlyphsChanged(workspace, GlyphInfo, oldLength, firstGlyph, nextGlyph);

                                afterLastGlyph = GlyphInfo.Length - glyphsAfterLastChar;
                                firstGlyph = nextGlyph;
                            }
                            else
                            {
                                OpenTypeLayoutCache.OnGlyphsChanged(workspace, GlyphInfo, oldLength, nextGlyph, afterLastGlyph);

                                afterLastGlyph = nextGlyph;
                            }
                        }
                        else
                        {
                            if (isLookupReversal)
                                afterLastGlyph = nextGlyph;
                            else
                                firstGlyph = nextGlyph;
                        }
                    }
                    else // End of range. Get next
                    {
                        GetNextEnabledGlyphRange(
                            FeatureSet,
                            featureCount,
                            featureSetOffset,
                            Table,
                            workspace,
                            LangSys,
                            Features,
                            lookupIndex,
                            CharCount,
                            Charmap,

                            afterLastChar,
                            afterLastGlyph,
                            GlyphInfo.Length,

                            out firstChar,
                            out afterLastChar,
                            out firstGlyph,
                            out afterLastGlyph,
                            out parameter);
                    }
                }
            }
        }
Esempio n. 14
0
        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;
        }
Esempio n. 15
0
        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;
        }