Example #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);
                }
            }
        }
Example #2
0
        ///<summary>
        ///
        ///</summary>
        internal static OpenTypeLayoutResult CreateLayoutCache(
            IOpenTypeFont font,                 // In: Font access interface
            int maxCacheSize                    // In: Maximum cache size allowed
            )
        {
            OpenTypeLayoutCache.CreateCache(font, maxCacheSize);

            return(OpenTypeLayoutResult.Success);
        }
Example #3
0
 /// <summary>
 /// 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
 /// </summary>
 ///<param name="font">In: Font access interface</param>
 ///<param name="tableTag">In: Font table tag</param>
 ///<param name="scriptTag">In: Script tag</param>
 ///<param name="langSysTag">In: Language System tag</param>
 ///<returns>Success if workspace is initialized succesfully, specific error if failed</returns>
 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);
 }
Example #4
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="Font">Font</param>
        /// <param name="ScriptTag">Script to search in</param>
        /// <param name="LangSysTag">LangGys to search for</param>
        /// <returns>TagInfoFlags, if script not present == None</returns>
        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);
        }
Example #5
0
        internal static void CreateCache(IOpenTypeFont font, int maxCacheSize)
        {
            if (maxCacheSize > ushort.MaxValue)
            {
                // Data structures do not support cache sizes more than 64K.
                maxCacheSize = ushort.MaxValue;
            }

            int tableCacheSize;
            int totalSize = 0;

            CreateTableCache(font, OpenTypeTags.GSUB, maxCacheSize - totalSize, out tableCacheSize);
            totalSize += tableCacheSize;
            Debug.Assert(totalSize <= maxCacheSize);

            CreateTableCache(font, OpenTypeTags.GPOS, maxCacheSize - totalSize, out tableCacheSize);
            totalSize += tableCacheSize;
            Debug.Assert(totalSize <= maxCacheSize);
        }
Example #6
0
        private static void CreateTableCache(IOpenTypeFont font, OpenTypeTags tableTag, int maxCacheSize, out int tableCacheSize)
        {
            // Initialize all computed values
            tableCacheSize = 0;
            int cacheSize       = 0;
            int recordCount     = 0;
            int glyphCount      = 0;
            int lastLookupAdded = -1;

            GlyphLookupRecord[] records = null;

            try
            {
                ComputeTableCache(
                    font,
                    tableTag,
                    maxCacheSize,
                    ref cacheSize,
                    ref records,
                    ref recordCount,
                    ref glyphCount,
                    ref lastLookupAdded
                    );
            }
            catch (FileFormatException)
            {
                cacheSize = 0;
            }

            if (cacheSize > 0)
            {
                tableCacheSize = FillTableCache(
                    font,
                    tableTag,
                    cacheSize,
                    records,
                    recordCount,
                    glyphCount,
                    lastLookupAdded
                    );
            }
        }
Example #7
0
        internal static OpenTypeLayoutResult CreateLayoutCache ( 
            IOpenTypeFont       font,           // In: Font access interface
            int                 maxCacheSize    // In: Maximum cache size allowed 
        )
        {
            OpenTypeLayoutCache.CreateCache(font, maxCacheSize);
 
            return OpenTypeLayoutResult.Success;
        } 
Example #8
0
        public unsafe bool Apply(
                            IOpenTypeFont   Font,
                            FontTable       Table,
                            int             CharCount,
                            UshortList      Charmap,        // Character to glyph map
                            GlyphInfoList   GlyphInfo,      // List of GlyphInfo
                            ushort          LookupFlags,    // Lookup flags for glyph lookups
                            int             FirstGlyph,     // where to apply it
                            int             AfterLastGlyph, // how long is a context we can use
                            out int         NextGlyph       // Next glyph to process
                          )
        {
            Invariant.Assert(FirstGlyph>=0);
            Invariant.Assert(AfterLastGlyph<=GlyphInfo.Length);

            NextGlyph = FirstGlyph + 1; //In case we don't match;
            
            if (Format(Table) != 1) return false; // Unknown format
                
            int glyphCount=GlyphInfo.Length;
            ushort glyphId = GlyphInfo.Glyphs[FirstGlyph];
            int CoverageIndex = Coverage(Table).GetGlyphIndex(Table,glyphId);
            if (CoverageIndex==-1) return false;

            int curGlyph;
            ushort ligatureGlyph=0;
            bool match = false;
            ushort compCount=0;

            LigatureSetTable ligatureSet = LigatureSet(Table,(ushort)CoverageIndex);
            ushort ligaCount = ligatureSet.LigatureCount(Table);
            for(ushort liga=0; liga<ligaCount; liga++)
            {
                LigatureTable ligature = ligatureSet.Ligature(Table,liga);
                compCount = ligature.ComponentCount(Table);
                if (compCount == 0)
                {
                    throw new FileFormatException();
                }
                
                curGlyph=FirstGlyph;
                ushort comp=1;
                for(comp=1;comp<compCount;comp++)
                {
                    curGlyph = LayoutEngine.GetNextGlyphInLookup(Font,GlyphInfo,curGlyph+1,LookupFlags,LayoutEngine.LookForward);
                    if (curGlyph>=AfterLastGlyph) break;
                    
                    if (GlyphInfo.Glyphs[curGlyph]!=ligature.Component(Table,comp)) break;
                }
                
                if (comp==compCount) //liga matched
                {
                    match=true;
                    ligatureGlyph = ligature.LigatureGlyph(Table);
                    break; //Liga found
                }
            }
            //If no ligature found, match will remain false after last iteration
            
            if (match) 
            {
                //Fix character and glyph Mapping
            
                //PERF: localize ligature character range
                    
                //Calculate Ligature CharCount
                int totalLigaCharCount=0;
                int firstLigaChar=int.MaxValue;
                curGlyph=FirstGlyph;
                for(ushort comp=0;comp<compCount;comp++)
                {
                    Invariant.Assert(curGlyph<AfterLastGlyph);
                    
                    int curFirstChar = GlyphInfo.FirstChars[curGlyph];
                    int curLigaCount = GlyphInfo.LigatureCounts[curGlyph];
                    
                    totalLigaCharCount += curLigaCount;
                    if (curFirstChar<firstLigaChar) firstLigaChar=curFirstChar;
                    
                    curGlyph = LayoutEngine.GetNextGlyphInLookup(Font,GlyphInfo,curGlyph+1,LookupFlags,LayoutEngine.LookForward);
                }
                    
                curGlyph=FirstGlyph;
                int prevGlyph=FirstGlyph;
                ushort shift=0;
                for(ushort comp=1;comp<=compCount;comp++)
                {
                    prevGlyph=curGlyph;
                    
                    if (comp<compCount)
                    {
                        curGlyph = LayoutEngine.
                                        GetNextGlyphInLookup(Font,GlyphInfo,
                                                             curGlyph+1,
                                                             LookupFlags,
                                                             LayoutEngine.LookForward);
                    }
                    else curGlyph = GlyphInfo.Length; // to the end from last component
                    
                    // Set charmap for ligature component
                    for(int curChar=0; curChar<CharCount; curChar++)
                    {
                        if (Charmap[curChar]==prevGlyph)
                        {
                            Charmap[curChar] = (ushort)FirstGlyph;
                        }
                    }

                    //Shift glyphInfo
                    if (shift>0)
                    {
                        for(int glyph=prevGlyph+1; glyph<curGlyph; glyph++)
                        {
                            GlyphInfo.Glyphs[glyph-shift]         = GlyphInfo.Glyphs[glyph];
                            GlyphInfo.GlyphFlags[glyph-shift]     = GlyphInfo.GlyphFlags[glyph];
                            GlyphInfo.FirstChars[glyph-shift]     = GlyphInfo.FirstChars[glyph];
                            GlyphInfo.LigatureCounts[glyph-shift] = GlyphInfo.LigatureCounts[glyph];
                        }
                    
                        if (curGlyph-prevGlyph>1) //do fixing only if have glyphs in between
                        {
                            for(int curChar=0; curChar<CharCount; curChar++)
                            {
                                ushort curCharmap = Charmap[curChar];
                                if (curCharmap>prevGlyph && curCharmap<curGlyph)
                                {
                                    Charmap[curChar] -= shift;
                                }
                            }
                        }
                    }
                                        
                    ++shift;
                }
                
                //Place new glyph into position of first ligature glyph
                GlyphInfo.Glyphs[FirstGlyph]         = ligatureGlyph;
                GlyphInfo.GlyphFlags[FirstGlyph]     = (ushort)(GlyphFlags.Unresolved | GlyphFlags.Substituted);
                GlyphInfo.FirstChars[FirstGlyph]     = (ushort)firstLigaChar;
                GlyphInfo.LigatureCounts[FirstGlyph] = (ushort)totalLigaCharCount;
                
                //remove empty space
                if (compCount > 1)
                {
                    GlyphInfo.Remove(GlyphInfo.Length-compCount+1,compCount-1);
                }
                
                NextGlyph=prevGlyph-(compCount-1)+1;
            }
            
            return match;
        }
Example #9
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;
        }
Example #10
0
        private static int FillTableCache(
            IOpenTypeFont font,
            OpenTypeTags tableTag,
            int cacheSize,
            GlyphLookupRecord[] records,
            int recordCount,
            int glyphCount,
            int lastLookupAdded
            )
        {
            // Fill the cache.

            // We are using basically the same code to fill the cache
            // that had been used to calculate the size. So pList pointer
            // moving through cache memory should not overrun allocated space.
            // Asserts are set to chek that at every place where we write to cache
            // and at the end where we check that we filled exactly the same amount.

            unsafe
            {
                byte[] cache = font.AllocateTableCache(tableTag, cacheSize);
                if (cache == null)
                {
                    // We failed to allocate cache of requested size,
                    // exit without created cache.
                    return(0);
                }

                fixed(byte *pCacheByte = &cache[0])
                {
                    ushort *pCache = (ushort *)pCacheByte;

                    pCache[0] = (ushort)cacheSize;              // Cache size
                    pCache[1] = 0xFFFF;                         // 0xFFFF constants
                    pCache[2] = (ushort)(lastLookupAdded + 1);  // Number of lookups that fit into the cache
                    pCache[3] = (ushort)glyphCount;             // Glyph count

                    ushort *pGlyphs   = pCache + 4;
                    ushort *pList     = pGlyphs + glyphCount * 2;
                    ushort *pPrevList = null;

                    int    prevListIndex = -1, prevListLength = 0;
                    int    curListIndex = 0, curListLength = 1;
                    ushort curGlyph = records[0].Glyph;

                    for (int i = 1; i < recordCount; i++)
                    {
                        if (records[i].Glyph != curGlyph)
                        {
                            // We've found another list. Compare it with previous
                            if (prevListLength != curListLength || // Fast check to avoid full comparison
                                !CompareGlyphRecordLists(records,
                                                         recordCount,
                                                         prevListIndex,
                                                         curListIndex)
                                )
                            {
                                // New list. Remember position in pPrevList and write list down
                                pPrevList = pList;

                                for (int j = curListIndex; j < i; j++)
                                {
                                    Debug.Assert((pList - pCache) * sizeof(ushort) < cacheSize);
                                    *pList = records[j].Lookup;
                                    pList++;
                                }

                                Debug.Assert((pList - pCache) * sizeof(ushort) < cacheSize);
                                *pList = 0xFFFF;
                                pList++;
                            }
                            // Now pPrevList points at the first element of the correct list.

                            *pGlyphs = curGlyph;                                        // Write down glyph id
                            pGlyphs++;
                            *pGlyphs = (ushort)((pPrevList - pCache) * sizeof(ushort)); // Write down list offset
                            pGlyphs++;

                            prevListIndex  = curListIndex;
                            prevListLength = curListLength;

                            curGlyph      = records[i].Glyph;
                            curListIndex  = i;
                            curListLength = 1;
                        }
                    }

                    // And we need to check the last list we missed in the loop
                    if (prevListLength != curListLength || // Fast check to avoid full comparison
                        !CompareGlyphRecordLists(records,
                                                 recordCount,
                                                 prevListIndex,
                                                 curListIndex)
                        )
                    {
                        // New list. Remember position in pPrevList and write list down
                        pPrevList = pList;

                        for (int j = curListIndex; j < recordCount; j++)
                        {
                            Debug.Assert((pList - pCache) * sizeof(ushort) < cacheSize);
                            *pList = records[j].Lookup;
                            pList++;
                        }

                        Debug.Assert((pList - pCache) * sizeof(ushort) < cacheSize);
                        *pList = 0xFFFF;
                        pList++;
                    }
                    // Now pPrevList points at the first element of the correct list.

                    *pGlyphs = curGlyph;                                        // Write down glyph id
                    pGlyphs++;
                    *pGlyphs = (ushort)((pPrevList - pCache) * sizeof(ushort)); // Write down list offset
                    pGlyphs++;

                    // We are done with the cache
                    Debug.Assert((pList - pCache) * sizeof(ushort) == cacheSize);                               // We exactly filled up the cache
                    Debug.Assert((pGlyphs - pCache) * sizeof(ushort) == (4 + glyphCount * 2) * sizeof(ushort)); // Glyphs ended where lists start.
                }
            }

            return(cacheSize);
        }
Example #11
0
        public unsafe bool Apply( 
            IOpenTypeFont           Font,           // Font access interface 
            OpenTypeTags            TableTag,       // Layout table tag (GSUB or GPOS)
            FontTable               Table,          // Layout table (GSUB or GPOS) 
            LayoutMetrics           Metrics,        // LayoutMetrics
            int                     CharCount,      // Characters count (i.e. Charmap.Length);
            UshortList              Charmap,        // Char to glyph mapping
            GlyphInfoList           GlyphInfo,      // List of GlyphInfo structs 
            int*                    Advances,       // Glyph adv.widths
            LayoutOffset*           Offsets,        // Glyph offsets 
            ushort                  LookupFlags,    // Lookup table flags 
            int                     FirstGlyph,     // where to apply it
            int                     AfterLastGlyph, // how long is a context we can use 
            uint                    Parameter,      // lookup parameter
            int                     nestingLevel,   // Contextual lookup nesting level
            out int                 NextGlyph       // out: next glyph index
            ) 
        {
            Invariant.Assert(Format(Table)==3); 
 
            NextGlyph = FirstGlyph + 1; //in case we don't match
 
            int glyphCount = GlyphInfo.Length;
            int glyphIndex;

            ushort backtrackGlyphCount = BacktrackGlyphCount(Table); 
            ushort inputGlyphCount     = InputGlyphCount(Table);
            ushort lookaheadGlyphCount = LookaheadGlyphCount(Table); 
 
            if (FirstGlyph < backtrackGlyphCount ||
                (FirstGlyph + inputGlyphCount) > AfterLastGlyph) 
            {
                return false;
            }
 
            bool match = true;
 
            //Check backtrack sequence 
            glyphIndex = FirstGlyph;
            for(ushort backtrackIndex = 0; 
                backtrackIndex < backtrackGlyphCount && match;
                backtrackIndex++)
            {
                 glyphIndex = LayoutEngine.GetNextGlyphInLookup(Font, GlyphInfo, 
                                                                glyphIndex-1,
                                                                LookupFlags, 
                                                                LayoutEngine.LookBackward 
                                                               );
 
                if (glyphIndex<0 ||
                    BacktrackCoverage(Table,backtrackIndex)
                            .GetGlyphIndex(Table,GlyphInfo.Glyphs[glyphIndex])<0)
                { 
                    match=false;
                } 
            } 

            if (!match) return false; 

            glyphIndex = FirstGlyph;
            for(ushort inputIndex = 0;
                inputIndex < inputGlyphCount && match; 
                inputIndex++)
            { 
                if (glyphIndex>=AfterLastGlyph || 
                    InputCoverage(Table,inputIndex)
                    .GetGlyphIndex(Table,GlyphInfo.Glyphs[glyphIndex])<0) 
                {
                    match=false;
                }
                else 
                {
                    glyphIndex = LayoutEngine.GetNextGlyphInLookup(Font, GlyphInfo, 
                        glyphIndex + 1, 
                        LookupFlags,
                        LayoutEngine.LookForward 
                        );
                }
            }
 
            if (!match) return false;
 
            int afterInputGlyph = glyphIndex; // remember where we were after input seqence 

            for(ushort lookaheadIndex = 0; 
                lookaheadIndex < lookaheadGlyphCount && match;
                lookaheadIndex++)
            {
                if (glyphIndex>=GlyphInfo.Length || 
                    LookaheadCoverage(Table,lookaheadIndex)
                    .GetGlyphIndex(Table,GlyphInfo.Glyphs[glyphIndex])<0) 
                { 
                    match=false;
                } 
                else
                {
                    glyphIndex = LayoutEngine.
                                    GetNextGlyphInLookup(Font, GlyphInfo, 
                                                         glyphIndex + 1,
                                                         LookupFlags, 
                                                         LayoutEngine.LookForward); 
                }
            } 

            if (match)
            {
                ContextualLookups(Table).ApplyContextualLookups( 
                                                Font,
                                                TableTag, 
                                                Table, 
                                                Metrics,
                                                CharCount, 
                                                Charmap,
                                                GlyphInfo,
                                                Advances,
                                                Offsets, 
                                                LookupFlags,
                                                FirstGlyph, 
                                                afterInputGlyph, //As AfterLastGlyph 
                                                Parameter,
                                                nestingLevel, 
                                                out NextGlyph
                                            );
            }
 
            return match;
        } 
Example #12
0
            public unsafe bool Apply(
                IOpenTypeFont           Font,           // Font access interface 
                OpenTypeTags            TableTag,       // Layout table tag (GSUB or GPOS) 
                FontTable               Table,          // Layout table (GSUB or GPOS)
                LayoutMetrics           Metrics,        // LayoutMetrics 
                ClassDefTable           inputClassDef,
                ClassDefTable           backtrackClassDef,
                ClassDefTable           lookaheadClassDef,
                int                     CharCount,      // Characters count (i.e. Charmap.Length); 
                UshortList              Charmap,        // Char to glyph mapping
                GlyphInfoList           GlyphInfo,      // List of GlyphInfo structs 
                int*                    Advances,       // Glyph adv.widths 
                LayoutOffset*           Offsets,        // Glyph offsets
                ushort                  LookupFlags,    // Lookup table flags 
                int                     FirstGlyph,     // where to apply it
                int                     AfterLastGlyph, // how long is a context we can use
                uint                    Parameter,      // lookup parameter
                int                     nestingLevel,   // Contextual lookup nesting level 
                out int                 NextGlyph       // out: next glyph index
                ) 
            { 
                bool match = true;
                NextGlyph = FirstGlyph + 1; //In case we don't match 

                //We are moving through table. We can pick glyph count or glyph class id.
                int curOffset = offset;
                int glyphIndex; 

                // 
                //Check backtrack sequence 
                //
                int backtrackGlyphCount = GlyphCount(Table,curOffset); 
                curOffset += sizeCount;

                glyphIndex = FirstGlyph;
                for(ushort backtrackIndex = 0; 
                    backtrackIndex < backtrackGlyphCount && match;
                    backtrackIndex++) 
                { 
                    glyphIndex = LayoutEngine.GetNextGlyphInLookup(Font, GlyphInfo,
                        glyphIndex-1, 
                        LookupFlags,
                        LayoutEngine.LookBackward
                        );
 
                    if (glyphIndex<0)
                    { 
                        match = false; 
                    }
                    else 
                    {
                        ushort classId = ClassId(Table,curOffset);
                        curOffset+=sizeClassId;
 
                        ushort glyphClass = backtrackClassDef.
                                        GetClass(Table,GlyphInfo.Glyphs[glyphIndex]); 
 
                        match = (glyphClass == classId);
                    } 
                }

                if (!match) return false;
 
                //
                // Check input sequence 
                // 
                int inputGlyphCount = GlyphCount(Table,curOffset);
                curOffset += sizeCount; 

                glyphIndex = FirstGlyph;
                for(ushort inputIndex = 1; //go from second glyph in the input
                    inputIndex < inputGlyphCount && match; 
                    inputIndex++)
                { 
                    glyphIndex = LayoutEngine.GetNextGlyphInLookup(Font, GlyphInfo, 
                        glyphIndex+1,
                        LookupFlags, 
                        LayoutEngine.LookForward
                        );

                    if (glyphIndex >= AfterLastGlyph) 
                    {
                        match = false; 
                    } 
                    else
                    { 
                        ushort classId = ClassId(Table,curOffset);
                        curOffset+=sizeClassId;

                        ushort glyphClass = inputClassDef. 
                            GetClass(Table,GlyphInfo.Glyphs[glyphIndex]);
 
                        match = (glyphClass == classId); 
                    }
                } 

                if (!match) return false;

                int afterInputGlyph = glyphIndex + 1; // remember where we were after input seqence 

                // 
                // Check lookahead sequence 
                //
                int lookaheadGlyphCount = GlyphCount(Table,curOffset); 
                curOffset += sizeCount;

                // Lokahead sequence starting right after input,
                // no need to change current glyphIndex 
                for(ushort lookaheadIndex = 0;
                    lookaheadIndex < lookaheadGlyphCount && match; 
                    lookaheadIndex++) 
                {
                    glyphIndex = LayoutEngine.GetNextGlyphInLookup(Font, GlyphInfo, 
                        glyphIndex+1,
                        LookupFlags,
                        LayoutEngine.LookForward
                        ); 

                    if (glyphIndex >= GlyphInfo.Length) 
                    { 
                        match = false;
                    } 
                    else
                    {
                        ushort classId = ClassId(Table,curOffset);
                        curOffset+=sizeClassId; 

                        ushort glyphClass = lookaheadClassDef. 
                            GetClass(Table,GlyphInfo.Glyphs[glyphIndex]); 

                        match = (glyphClass == classId); 
                    }
                }

                if (match) 
                {
                    ContextualLookups(Table,curOffset).ApplyContextualLookups( 
                        Font, 
                        TableTag,
                        Table, 
                        Metrics,
                        CharCount,
                        Charmap,
                        GlyphInfo, 
                        Advances,
                        Offsets, 
                        LookupFlags, 
                        FirstGlyph,
                        afterInputGlyph, //As AfterLastGlyph 
                        Parameter,
                        nestingLevel,
                        out NextGlyph
                    ); 
                }
 
                return match; 
            }
Example #13
0
        public unsafe bool Apply(
            IOpenTypeFont   Font,
            FontTable       Table,
            LayoutMetrics   Metrics,        // LayoutMetrics 
            GlyphInfoList   GlyphInfo,      // List of GlyphInfo structs
            ushort          LookupFlags,    // Lookup flags for glyph lookups 
            int*            Advances,       // Glyph adv.widths 
            LayoutOffset*   Offsets,        // Glyph offsets
            int             FirstGlyph,     // where to apply lookup 
            int             AfterLastGlyph, // how long is a context we can use
            out int         NextGlyph       // Next glyph to process
            )
        { 
            Invariant.Assert(FirstGlyph>=0);
            Invariant.Assert(AfterLastGlyph<=GlyphInfo.Length); 
 
            NextGlyph = FirstGlyph+1; //Always move to the next glyph, whether matched or not
 
            if (Format(Table) != 1) return false; //unknown format

            int glyphCount=GlyphInfo.Length;
 
            int mark1Glyph=FirstGlyph;
 
            //Lookup works with marks only 
            if ((GlyphInfo.GlyphFlags[mark1Glyph]&(ushort)GlyphFlags.GlyphTypeMask)!=(ushort)GlyphFlags.Mark) return false;
 
            int mark1CoverageIndex = Mark1Coverage(Table).GetGlyphIndex(Table,GlyphInfo.Glyphs[mark1Glyph]);
            if (mark1CoverageIndex==-1) return false;

            //Find preceeding mark according mark from specified class 
            int mark2Glyph = LayoutEngine.GetNextGlyphInLookup(Font,
                GlyphInfo, 
                FirstGlyph-1, 
                (ushort)(LookupFlags & 0xFF00), //Clear Ignore... flags
                LayoutEngine.LookBackward); 
            if (mark2Glyph<0) return false;

            int mark2CoverageIndex = Mark2Coverage(Table).GetGlyphIndex(Table,GlyphInfo.Glyphs[mark2Glyph]);
            if (mark2CoverageIndex==-1) return false; 

            ushort classCount = Mark1ClassCount(Table); 
            MarkArray mark1Array = Mark1Array(Table); 

            ushort mark1Class = mark1Array.Class(Table,(ushort)mark1CoverageIndex); 
            if (mark1Class>=classCount) return false; //Invalid mark class

            AnchorTable mark1Anchor = mark1Array.MarkAnchor(Table,(ushort)mark1CoverageIndex);
            if (mark1Anchor.IsNull()) 
            {
                return false; 
            } 

            AnchorTable mark2Anchor = Marks2(Table).Anchor(Table,(ushort)mark2CoverageIndex,classCount,mark1Class); 
            if (mark2Anchor.IsNull())
            {
                return false;
            } 

            Positioning.AlignAnchors(Font,Table,Metrics,GlyphInfo,Advances,Offsets, 
                mark2Glyph,mark1Glyph,mark2Anchor,mark1Anchor,false); 
            return true;
        } 
Example #14
0
        public unsafe bool Apply(
            IOpenTypeFont Font,
            FontTable Table,
            int CharCount,
            UshortList Charmap,             // Character to glyph map
            GlyphInfoList GlyphInfo,        // List of GlyphInfo
            ushort LookupFlags,             // Lookup flags for glyph lookups
            int FirstGlyph,                 // where to apply it
            int AfterLastGlyph,             // how long is a context we can use
            out int NextGlyph               // Next glyph to process
            )
        {
            NextGlyph = FirstGlyph + 1; // in case we don't match

            if (Format(Table) != 1)
            {
                return(false);                    //unknown format
            }
            int oldGlyphCount = GlyphInfo.Length;

            ushort glyphId       = GlyphInfo.Glyphs[FirstGlyph];
            int    coverageIndex = Coverage(Table).GetGlyphIndex(Table, glyphId);

            if (coverageIndex == -1)
            {
                return(false);
            }

            MultipleSubstitutionSequenceTable sequence = Sequence(Table, coverageIndex);

            ushort sequenceLength = sequence.GlyphCount(Table);
            int    lengthDelta    = sequenceLength - 1;

            if (sequenceLength == 0)
            {
                // This is illegal, because mapping will be broken -
                // corresponding char will be lost. Just leave it as it is.
                // (char will be attached to the following glyph).
                GlyphInfo.Remove(FirstGlyph, 1);
            }
            else
            {
                ushort firstChar     = GlyphInfo.FirstChars[FirstGlyph];
                ushort ligatureCount = GlyphInfo.LigatureCounts[FirstGlyph];

                if (lengthDelta > 0)
                {
                    GlyphInfo.Insert(FirstGlyph, lengthDelta);
                }

                //put glyphs in place
                for (ushort gl = 0; gl < sequenceLength; gl++)
                {
                    GlyphInfo.Glyphs[FirstGlyph + gl]     = sequence.Glyph(Table, gl);
                    GlyphInfo.GlyphFlags[FirstGlyph + gl] =
                        (ushort)(GlyphFlags.Unresolved | GlyphFlags.Substituted);
                    GlyphInfo.FirstChars[FirstGlyph + gl]     = firstChar;
                    GlyphInfo.LigatureCounts[FirstGlyph + gl] = ligatureCount;
                }
            }

            // Fix char mapping - very simple for now.
            // Works only for arabic base+mark -> base and marks decomposition
            // Needs work for full mapping
            for (int ch = 0; ch < CharCount; ch++)
            {
                if (Charmap[ch] > FirstGlyph)
                {
                    Charmap[ch] = (ushort)(Charmap[ch] + lengthDelta);
                }
            }

            NextGlyph = FirstGlyph + lengthDelta + 1;

            return(true);
        }
Example #15
0
        public unsafe bool Apply(
            IOpenTypeFont Font,
            FontTable Table,
            int CharCount,
            UshortList Charmap,                             // Character to glyph map
            GlyphInfoList GlyphInfo,                        // List of GlyphInfo
            ushort LookupFlags,                             // Lookup flags for glyph lookups
            int FirstGlyph,                                 // where to apply it
            int AfterLastGlyph,                             // how long is a context we can use
            out int NextGlyph                               // Next glyph to process
            )
        {
            Invariant.Assert(FirstGlyph >= 0);
            Invariant.Assert(AfterLastGlyph <= GlyphInfo.Length);

            NextGlyph = FirstGlyph + 1; //In case we don't match;

            if (Format(Table) != 1)
            {
                return(false);                    // Unknown format
            }
            int    glyphCount    = GlyphInfo.Length;
            ushort glyphId       = GlyphInfo.Glyphs[FirstGlyph];
            int    CoverageIndex = Coverage(Table).GetGlyphIndex(Table, glyphId);

            if (CoverageIndex == -1)
            {
                return(false);
            }

            int    curGlyph;
            ushort ligatureGlyph = 0;
            bool   match         = false;
            ushort compCount     = 0;

            LigatureSetTable ligatureSet = LigatureSet(Table, (ushort)CoverageIndex);
            ushort           ligaCount   = ligatureSet.LigatureCount(Table);

            for (ushort liga = 0; liga < ligaCount; liga++)
            {
                LigatureTable ligature = ligatureSet.Ligature(Table, liga);
                compCount = ligature.ComponentCount(Table);
                if (compCount == 0)
                {
                    throw new FileFormatException();
                }

                curGlyph = FirstGlyph;
                ushort comp = 1;
                for (comp = 1; comp < compCount; comp++)
                {
                    curGlyph = LayoutEngine.GetNextGlyphInLookup(Font, GlyphInfo, curGlyph + 1, LookupFlags, LayoutEngine.LookForward);
                    if (curGlyph >= AfterLastGlyph)
                    {
                        break;
                    }

                    if (GlyphInfo.Glyphs[curGlyph] != ligature.Component(Table, comp))
                    {
                        break;
                    }
                }

                if (comp == compCount) //liga matched
                {
                    match         = true;
                    ligatureGlyph = ligature.LigatureGlyph(Table);
                    break; //Liga found
                }
            }
            //If no ligature found, match will remain false after last iteration

            if (match)
            {
                //Fix character and glyph Mapping

                //PERF: localize ligature character range

                //Calculate Ligature CharCount
                int totalLigaCharCount = 0;
                int firstLigaChar      = int.MaxValue;
                curGlyph = FirstGlyph;
                for (ushort comp = 0; comp < compCount; comp++)
                {
                    Invariant.Assert(curGlyph < AfterLastGlyph);

                    int curFirstChar = GlyphInfo.FirstChars[curGlyph];
                    int curLigaCount = GlyphInfo.LigatureCounts[curGlyph];

                    totalLigaCharCount += curLigaCount;
                    if (curFirstChar < firstLigaChar)
                    {
                        firstLigaChar = curFirstChar;
                    }

                    curGlyph = LayoutEngine.GetNextGlyphInLookup(Font, GlyphInfo, curGlyph + 1, LookupFlags, LayoutEngine.LookForward);
                }

                curGlyph = FirstGlyph;
                int    prevGlyph = FirstGlyph;
                ushort shift     = 0;
                for (ushort comp = 1; comp <= compCount; comp++)
                {
                    prevGlyph = curGlyph;

                    if (comp < compCount)
                    {
                        curGlyph = LayoutEngine.
                                   GetNextGlyphInLookup(Font, GlyphInfo,
                                                        curGlyph + 1,
                                                        LookupFlags,
                                                        LayoutEngine.LookForward);
                    }
                    else
                    {
                        curGlyph = GlyphInfo.Length;  // to the end from last component
                    }
                    // Set charmap for ligature component
                    for (int curChar = 0; curChar < CharCount; curChar++)
                    {
                        if (Charmap[curChar] == prevGlyph)
                        {
                            Charmap[curChar] = (ushort)FirstGlyph;
                        }
                    }

                    //Shift glyphInfo
                    if (shift > 0)
                    {
                        for (int glyph = prevGlyph + 1; glyph < curGlyph; glyph++)
                        {
                            GlyphInfo.Glyphs[glyph - shift]         = GlyphInfo.Glyphs[glyph];
                            GlyphInfo.GlyphFlags[glyph - shift]     = GlyphInfo.GlyphFlags[glyph];
                            GlyphInfo.FirstChars[glyph - shift]     = GlyphInfo.FirstChars[glyph];
                            GlyphInfo.LigatureCounts[glyph - shift] = GlyphInfo.LigatureCounts[glyph];
                        }

                        if (curGlyph - prevGlyph > 1) //do fixing only if have glyphs in between
                        {
                            for (int curChar = 0; curChar < CharCount; curChar++)
                            {
                                ushort curCharmap = Charmap[curChar];
                                if (curCharmap > prevGlyph && curCharmap < curGlyph)
                                {
                                    Charmap[curChar] -= shift;
                                }
                            }
                        }
                    }

                    ++shift;
                }

                //Place new glyph into position of first ligature glyph
                GlyphInfo.Glyphs[FirstGlyph]         = ligatureGlyph;
                GlyphInfo.GlyphFlags[FirstGlyph]     = (ushort)(GlyphFlags.Unresolved | GlyphFlags.Substituted);
                GlyphInfo.FirstChars[FirstGlyph]     = (ushort)firstLigaChar;
                GlyphInfo.LigatureCounts[FirstGlyph] = (ushort)totalLigaCharCount;

                //remove empty space
                if (compCount > 1)
                {
                    GlyphInfo.Remove(GlyphInfo.Length - compCount + 1, compCount - 1);
                }

                NextGlyph = prevGlyph - (compCount - 1) + 1;
            }

            return(match);
        }
Example #16
0
        internal static int GetNextGlyphInLookup(
            IOpenTypeFont   Font,           //
            GlyphInfoList   GlyphInfo,      // Glyph run
            int             FirstGlyph,     // Current glyph index
            ushort          LookupFlags,    // Lookup flags to use
            int             Direction     // Search direction (forward/back)
            )
        {
            FontTable gdefTable;
            ClassDefTable markAttachClassDef;

             //assign them only to avoid error: using unassigned variable
            gdefTable = null;
            markAttachClassDef = ClassDefTable.InvalidClassDef;

            if (LookupFlags==0) return FirstGlyph;

            //we will mark classes only if mark filter is set
            if ((LookupFlags&(ushort)LookupFlagMarkAttachmentTypeMask)!=0)
            {
                gdefTable = Font.GetFontTable(OpenTypeTags.GDEF);

                if (gdefTable.IsPresent)
                {
                    markAttachClassDef = (new GDEFHeader(0)).GetMarkAttachClassDef(gdefTable);
                }
            }

            UshortList glyphFlags = GlyphInfo.GlyphFlags;
            ushort attachClass = (ushort)((LookupFlags&LookupFlagMarkAttachmentTypeMask)>>8);

            int glyph;

            int glyphRunLength    = GlyphInfo.Length;
            for(glyph=FirstGlyph; glyph<glyphRunLength && glyph>=0; glyph+=Direction)
            {
                if (
                    (LookupFlags&LookupFlagIgnoreBases)!=0 &&
                    (glyphFlags[glyph]&(ushort)GlyphFlags.GlyphTypeMask)==(ushort)GlyphFlags.Base
                    ) continue;

                if (
                    (LookupFlags&LookupFlagIgnoreMarks)!=0 &&
                    (glyphFlags[glyph]&(ushort)GlyphFlags.GlyphTypeMask)==(ushort)GlyphFlags.Mark
                   ) continue;

                if (
                    (LookupFlags&LookupFlagIgnoreLigatures)!=0 &&
                    (glyphFlags[glyph]&(ushort)GlyphFlags.GlyphTypeMask)==(ushort)GlyphFlags.Ligature
                   ) continue;

                if (attachClass!=0 &&
                    (glyphFlags[glyph]&(ushort)GlyphFlags.GlyphTypeMask)==(ushort)GlyphFlags.Mark &&
                     !markAttachClassDef.IsInvalid &&
                     attachClass!=markAttachClassDef.GetClass(gdefTable,GlyphInfo.Glyphs[glyph])
                   ) continue;

                return glyph;
            }

            return glyph;
        }
Example #17
0
        private static void UpdateGlyphFlags(
                                                IOpenTypeFont   Font,
                                                GlyphInfoList   GlyphInfo,
                                                int             FirstGlyph,
                                                int             AfterLastGlyph,
                                                bool            DoAll,
                                                GlyphFlags      FlagToSet
                                            )
        {
            Debug.Assert( FlagToSet==GlyphFlags.NotChanged ||
                            FlagToSet==GlyphFlags.Substituted ||
                            FlagToSet==GlyphFlags.Positioned);

            ushort typemask = (ushort)GlyphFlags.GlyphTypeMask;

            FontTable gdefTable = Font.GetFontTable(OpenTypeTags.GDEF);

            if (!gdefTable.IsPresent)
            {
                //GDEF(i.e. class def in it) is not present.
                //Assign unassigned to all glyphs
                for(int i=FirstGlyph;i<AfterLastGlyph;i++)
                {
                    ushort flags = (ushort)(
                        (GlyphInfo.GlyphFlags[i] & (ushort)~typemask) |
                        (ushort)GlyphFlags.Unassigned |
                        (ushort)FlagToSet);
                }
                return;
            }

            GDEFHeader gdefHeader = new GDEFHeader(0);
            ClassDefTable GlyphClassDef = gdefHeader.GetGlyphClassDef(gdefTable);

            for(int i=FirstGlyph;i<AfterLastGlyph;i++)
            {
                ushort flags = (ushort)(GlyphInfo.GlyphFlags[i] | (ushort)FlagToSet);

                if ((flags & typemask) == (ushort)GlyphFlags.Unresolved ||
                                                FlagToSet!=GlyphFlags.NotChanged)
                {
                    ushort glyph = GlyphInfo.Glyphs[i];

                    flags &= (ushort)~typemask;

                    int glyphClass = GlyphClassDef.GetClass(gdefTable,glyph);

                    GlyphInfo.GlyphFlags[i] = (ushort)(flags|
                                                        ((glyphClass==-1)?
                                                          (ushort)GlyphFlags.Unassigned:
                                                          (ushort)glyphClass
                                                        )
                                                      );
                }
            }
        }
Example #18
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);
                    }
                }
            }
        }
Example #19
0
        internal static bool ApplyLookup(
            IOpenTypeFont           Font,           // Font access interface
            OpenTypeTags            TableTag,       // Layout table tag (GSUB or GPOS)
            FontTable               Table,          // Layout table (GSUB or GPOS)
            LayoutMetrics           Metrics,        // LayoutMetrics
            LookupTable             Lookup,         // List definition structure
            int                     CharCount,      // Characters count (i.e. Charmap.Length);
            UshortList              Charmap,        // Char to glyph mapping
            GlyphInfoList           GlyphInfo,      // List of GlyphInfo structs
            int*                    Advances,       // Glyph adv.widths
            LayoutOffset*           Offsets,        // Glyph offsets
            int                     FirstGlyph,     // where to apply it
            int                     AfterLastGlyph, // how long is a context we can use
            uint                    Parameter,      // lookup parameter
            int                     nestingLevel,   // Contextual lookup nesting level
            out int                 NextGlyph       // out: next glyph index
            )
        {
            Debug.Assert(TableTag==OpenTypeTags.GSUB || TableTag==OpenTypeTags.GPOS);
            Debug.Assert(FirstGlyph<AfterLastGlyph);
            Debug.Assert(AfterLastGlyph<=GlyphInfo.Length);

            ushort lookupType = Lookup.LookupType();
            ushort lookupFlags = Lookup.LookupFlags();
            ushort subtableCount = Lookup.SubTableCount();

            bool match=false;
            NextGlyph=FirstGlyph+1; //Just to avoid compiler error

            // Find first glyph
            if (!IsLookupReversal(TableTag,lookupType))
            {
                FirstGlyph=LayoutEngine.GetNextGlyphInLookup(Font,GlyphInfo,FirstGlyph,
                                                                lookupFlags,LayoutEngine.LookForward);
            }
            else
            {
                AfterLastGlyph = LayoutEngine.GetNextGlyphInLookup(Font,GlyphInfo,AfterLastGlyph-1,
                                                                      lookupFlags,LayoutEngine.LookBackward) + 1;
            }
            if (FirstGlyph>=AfterLastGlyph) return match;

            ushort originalLookupType = lookupType; // We need it to recover, if extension lookup updated lookupFormat

            for(ushort subtableIndex=0; !match && subtableIndex < subtableCount; subtableIndex++)
            {
                lookupType = originalLookupType;
                int subtableOffset = Lookup.SubtableOffset(Table, subtableIndex);

                switch (TableTag)
                {
                    case OpenTypeTags.GSUB:
                    {
                        if (lookupType == 7)
                        {
                            ExtensionLookupTable extension =
                                    new ExtensionLookupTable(subtableOffset);

                            lookupType = extension.LookupType(Table);
                            subtableOffset = extension.LookupSubtableOffset(Table);
                        }

                        switch (lookupType)
                        {
                            case 1: //SingleSubst
                                SingleSubstitutionSubtable singleSub =
                                    new SingleSubstitutionSubtable(subtableOffset);
                                match = singleSub.Apply( Table,
                                                         GlyphInfo,
                                                         FirstGlyph,
                                                         out NextGlyph
                                                       );
                                break;

                            case 2: //MultipleSubst
                                MultipleSubstitutionSubtable multipleSub =
                                    new MultipleSubstitutionSubtable(subtableOffset);
                                match = multipleSub.Apply(  Font,
                                                            Table,
                                                            CharCount,
                                                            Charmap,
                                                            GlyphInfo,
                                                            lookupFlags,
                                                            FirstGlyph,
                                                            AfterLastGlyph,
                                                            out NextGlyph
                                                         );
                                break;

                            case 3: //AlternateSubst
                                AlternateSubstitutionSubtable alternateSub =
                                    new AlternateSubstitutionSubtable(subtableOffset);
                                match = alternateSub.Apply( Table,
                                                            GlyphInfo,
                                                            Parameter,
                                                            FirstGlyph,
                                                            out NextGlyph
                                                          );
                                break;

                            case 4: //Ligature subst
                                LigatureSubstitutionSubtable ligaSub =
                                    new LigatureSubstitutionSubtable(subtableOffset);
                                match = ligaSub.Apply( Font,
                                                       Table,
                                                       CharCount,
                                                       Charmap,
                                                       GlyphInfo,
                                                       lookupFlags,
                                                       FirstGlyph,
                                                       AfterLastGlyph,
                                                       out NextGlyph
                                                     );
                                break;

                            case 5: //ContextualSubst
                                ContextSubtable contextSub =
                                    new ContextSubtable(subtableOffset);
                                match = contextSub.Apply( Font,
                                                          TableTag,
                                                          Table,
                                                          Metrics,
                                                          CharCount,
                                                          Charmap,
                                                          GlyphInfo,
                                                          Advances,
                                                          Offsets,
                                                          lookupFlags,
                                                          FirstGlyph,
                                                          AfterLastGlyph,
                                                          Parameter,
                                                          nestingLevel,
                                                          out NextGlyph
                                                        );
                                break;

                            case 6: //ChainingSubst
                                ChainingSubtable chainingSub =
                                                    new ChainingSubtable(subtableOffset);
                                match = chainingSub.Apply(  Font,
                                                            TableTag,
                                                            Table,
                                                            Metrics,
                                                            CharCount,
                                                            Charmap,
                                                            GlyphInfo,
                                                            Advances,
                                                            Offsets,
                                                            lookupFlags,
                                                            FirstGlyph,
                                                            AfterLastGlyph,
                                                            Parameter,
                                                            nestingLevel,
                                                            out NextGlyph
                                                          );
                                break;

                            case 7: //Extension lookup
                                // Ext.Lookup processed earlier. It can't contain another ext.lookups in it.
                                // Just skip it (do nothing);

                                NextGlyph = FirstGlyph + 1;
                                break;

                            case 8: //ReverseCahiningSubst
                                ReverseChainingSubtable reverseChainingSub =
                                    new ReverseChainingSubtable(subtableOffset);
                                match = reverseChainingSub.Apply(
                                                                    Font,
                                                                    TableTag,
                                                                    Table,
                                                                    Metrics,
                                                                    CharCount,
                                                                    Charmap,
                                                                    GlyphInfo,
                                                                    Advances,
                                                                    Offsets,
                                                                    lookupFlags,
                                                                    FirstGlyph,
                                                                    AfterLastGlyph,
                                                                    Parameter,
                                                                    out NextGlyph
                                                                 );
                                break;

                            default:
                                // Unknown format
                                NextGlyph = FirstGlyph+1;
                                break;
                        }

                        if (match)
                        {
                            if (!IsLookupReversal(TableTag,lookupType))
                            {
                                UpdateGlyphFlags(Font,GlyphInfo,FirstGlyph,NextGlyph,true,GlyphFlags.Substituted);
                            }
                            else
                            {
                                UpdateGlyphFlags(Font,GlyphInfo,NextGlyph,AfterLastGlyph,true,GlyphFlags.Substituted);
                            }
                        }

                        break;
                    }

                    case OpenTypeTags.GPOS:
                    {
                        if (lookupType == 9)
                        {
                            ExtensionLookupTable extension =
                                    new ExtensionLookupTable(subtableOffset);

                            lookupType = extension.LookupType(Table);
                            subtableOffset = extension.LookupSubtableOffset(Table);

                        }

                        switch (lookupType)
                        {
                            case 1: //SinglePos
                                SinglePositioningSubtable singlePos =
                                    new SinglePositioningSubtable(subtableOffset);
                                match = singlePos.Apply(Table,
                                                        Metrics,
                                                        GlyphInfo,
                                                        Advances,
                                                        Offsets,
                                                        FirstGlyph,
                                                        AfterLastGlyph,
                                                        out NextGlyph
                                                       );
                                break;

                            case 2: //PairPos
                                PairPositioningSubtable pairPos =
                                    new PairPositioningSubtable(subtableOffset);
                                match = pairPos.Apply(  Font,
                                                        Table,
                                                        Metrics,        // LayoutMetrics
                                                        GlyphInfo,      // List of GlyphInfo structs
                                                        lookupFlags,    // Lookup flags for glyph lookups
                                                        Advances,       // Glyph adv.widths
                                                        Offsets,        // Glyph offsets
                                                        FirstGlyph,     // where to apply lookup
                                                        AfterLastGlyph, // how long is a context we can use
                                                        out NextGlyph   // Next glyph to process
                                                     );
                                break;

                            case 3: // CursivePos
                                // Under construction
                                CursivePositioningSubtable cursivePositioningSubtable =
                                    new CursivePositioningSubtable(subtableOffset);

                                cursivePositioningSubtable.Apply(   Font,
                                                                    Table,
                                                                    Metrics,        // LayoutMetrics
                                                                    GlyphInfo,      // List of GlyphInfo structs
                                                                    lookupFlags,    // Lookup flags for glyph lookups
                                                                    Advances,       // Glyph adv.widths
                                                                    Offsets,        // Glyph offsets
                                                                    FirstGlyph,     // where to apply lookup
                                                                    AfterLastGlyph, // how long is a context we can use
                                                                    out NextGlyph   // Next glyph to process
                                                                );

                                break;

                            case 4: //MarkToBasePos
                                MarkToBasePositioningSubtable markToBasePos =
                                    new MarkToBasePositioningSubtable(subtableOffset);
                                match = markToBasePos.Apply(Font,
                                                            Table,
                                                            Metrics,        // LayoutMetrics
                                                            GlyphInfo,      // List of GlyphInfo structs
                                                            lookupFlags,    // Lookup flags for glyph lookups
                                                            Advances,       // Glyph adv.widths
                                                            Offsets,        // Glyph offsets
                                                            FirstGlyph,     // where to apply lookup
                                                            AfterLastGlyph, // how long is a context we can use
                                                            out NextGlyph   // Next glyph to process
                                                           );
                                break;


                            case 5: //MarkToLigaturePos
                                // Under construction
                                MarkToLigaturePositioningSubtable markToLigaPos =
                                   new MarkToLigaturePositioningSubtable(subtableOffset);
                                match = markToLigaPos.Apply(
                                                            Font,
                                                            Table,
                                                            Metrics,        // LayoutMetrics
                                                            GlyphInfo,      // List of GlyphInfo structs
                                                            lookupFlags,    // Lookup flags for glyph lookups
                                                            CharCount,      // Characters count (i.e. Charmap.Length);
                                                            Charmap,        // Char to glyph mapping
                                                            Advances,       // Glyph adv.widths
                                                            Offsets,        // Glyph offsets
                                                            FirstGlyph,     // where to apply lookup
                                                            AfterLastGlyph, // how long is a context we can use
                                                            out NextGlyph   // Next glyph to process
                                                           );
                                break;

                            case 6: //MarkToMarkPos
                                MarkToMarkPositioningSubtable markToMarkPos =
                                    new MarkToMarkPositioningSubtable(subtableOffset);
                                match = markToMarkPos.Apply(
                                                            Font,
                                                            Table,
                                                            Metrics,        // LayoutMetrics
                                                            GlyphInfo,      // List of GlyphInfo structs
                                                            lookupFlags,    // Lookup flags for glyph lookups
                                                            Advances,       // Glyph adv.widths
                                                            Offsets,        // Glyph offsets
                                                            FirstGlyph,     // where to apply lookup
                                                            AfterLastGlyph, // how long is a context we can use
                                                            out NextGlyph   // Next glyph to process
                                                           );
                                break;

                            case 7: // Contextual
                                ContextSubtable contextSub =
                                    new ContextSubtable(subtableOffset);
                                match = contextSub.Apply( Font,
                                                          TableTag,
                                                          Table,
                                                          Metrics,
                                                          CharCount,
                                                          Charmap,
                                                          GlyphInfo,
                                                          Advances,
                                                          Offsets,
                                                          lookupFlags,
                                                          FirstGlyph,
                                                          AfterLastGlyph,
                                                          Parameter,
                                                          nestingLevel,
                                                          out NextGlyph
                                                        );
                                break;

                            case 8: // Chaining
                                ChainingSubtable chainingSub =
                                    new ChainingSubtable(subtableOffset);
                                match = chainingSub.Apply( Font,
                                                           TableTag,
                                                           Table,
                                                           Metrics,
                                                           CharCount,
                                                           Charmap,
                                                           GlyphInfo,
                                                           Advances,
                                                           Offsets,
                                                           lookupFlags,
                                                           FirstGlyph,
                                                           AfterLastGlyph,
                                                           Parameter,
                                                           nestingLevel,
                                                           out NextGlyph
                                                         );
                                break;

                            case 9: //Extension lookup
                                // Ext.Lookup processed earlier. It can't contain another ext.lookups in it.
                                // Just skip it (do nothing);

                                NextGlyph = FirstGlyph + 1;
                                break;

                            default:
                                // Unknown format
                                NextGlyph = FirstGlyph + 1;
                                break;
                        }

                        if (match)
                        {
                            UpdateGlyphFlags(Font,GlyphInfo,FirstGlyph,NextGlyph,false,GlyphFlags.Positioned);
                        }

                        break;
                    }
                    default:
                        Debug.Assert(false,"Unknown OpenType layout table!");
                        break;
                }
            }

            return match;
        }
Example #20
0
        public unsafe bool Apply( 
            IOpenTypeFont           Font,           // Font access interface
            OpenTypeTags            TableTag,       // Layout table tag (GSUB or GPOS) 
            FontTable               Table,          // Layout table (GSUB or GPOS)
            LayoutMetrics           Metrics,        // LayoutMetrics
            int                     CharCount,      // Characters count (i.e. Charmap.Length);
            UshortList              Charmap,        // Char to glyph mapping 
            GlyphInfoList           GlyphInfo,      // List of GlyphInfo structs
            int*                    Advances,       // Glyph adv.widths 
            LayoutOffset*           Offsets,        // Glyph offsets 
            ushort                  LookupFlags,    // Lookup table flags
            int                     FirstGlyph,     // where to apply it 
            int                     AfterLastGlyph, // how long is a context we can use
            uint                    Parameter,      // lookup parameter
            int                     nestingLevel,   // Contextual lookup nesting level
            out int                 NextGlyph       // out: next glyph index 
            )
        { 
            Invariant.Assert(Format(Table)==1); 

            NextGlyph = FirstGlyph + 1; //in case we don't match 

            int glyphCount = GlyphInfo.Length;

            int     glyphIndex = FirstGlyph; 
            ushort  glyphId = GlyphInfo.Glyphs[glyphIndex];
 
            int coverageIndex = Coverage(Table).GetGlyphIndex(Table,glyphId); 
            if (coverageIndex < 0) return false;
 
            SubRuleSet subRuleSet= RuleSet(Table, coverageIndex);

            ushort ruleCount = subRuleSet.RuleCount(Table);
 
            bool match = false;
            for(ushort i=0; !match && i<ruleCount; i++) 
            { 
                match = subRuleSet.Rule(Table,i).Apply(Font, TableTag, Table, Metrics,
                                                        CharCount, Charmap, 
                                                        GlyphInfo, Advances, Offsets,
                                                        LookupFlags, FirstGlyph, AfterLastGlyph,
                                                        Parameter,
                                                        nestingLevel, 
                                                        out NextGlyph
                                                        ); 
            } 

            return match; 
        }
Example #21
0
        public unsafe void ApplyContextualLookups( 
            IOpenTypeFont           Font,           // Font access interface
            OpenTypeTags            TableTag,       // Layout table tag (GSUB or GPOS) 
            FontTable               Table,          // Layout table (GSUB or GPOS)
            LayoutMetrics           Metrics,        // LayoutMetrics
            int                     CharCount,      // Characters count (i.e. Charmap.Length);
            UshortList              Charmap,        // Char to glyph mapping 
            GlyphInfoList           GlyphInfo,      // List of GlyphInfo structs
            int*                    Advances,       // Glyph adv.widths 
            LayoutOffset*           Offsets,        // Glyph offsets 
            ushort                  LookupFlags,    // Lookup table flags
            int                     FirstGlyph,     // where to apply it 
            int                     AfterLastGlyph, // how long is a context we can use
            uint                    Parameter,      // lookup parameter
            int                     nestingLevel,   // Contextual lookup nesting level
            out int                 nextGlyph       // out: next glyph index 
            )
        { 
            // Limit nesting level for contextual lookups to 
            // prevent infinite loops from corrupt fonts
            if (nestingLevel >=  MaximumContextualLookupNestingLevel) 
            {
                nextGlyph = AfterLastGlyph;
                return;
            } 

            LookupList lookupList; 
            if (TableTag == OpenTypeTags.GSUB) 
            {
                lookupList = (new GSUBHeader(0)).GetLookupList(Table); 
            }
            else
            {
                lookupList = (new GPOSHeader(0)).GetLookupList(Table); 
            }
 
            int prevLookupIndex   = -1; 
            int prevSequenceIndex = -1;
 
            while (true)
            {
                ushort lookupIndex = ushort.MaxValue;
                ushort sequenceIndex = ushort.MaxValue; 

                for(ushort i = 0; i < recordCount; i++) 
                { 
                    ushort recordLookupIndex   = LookupIndex(Table,i);
                    ushort recordSequenceIndex = SequenceIndex(Table,i); 

                    if (recordLookupIndex < prevLookupIndex ||
                        (recordLookupIndex == prevLookupIndex &&
                         recordSequenceIndex <= prevSequenceIndex 
                        )
                       ) 
                    { 
                        // This record we already should have been processed
                        continue; 
                    }

                    // Among not proccessed record, find next one
                    if ( recordLookupIndex < lookupIndex || 
                         (recordLookupIndex == lookupIndex &&
                          recordSequenceIndex < sequenceIndex 
                         ) 
                       )
                    { 
                        lookupIndex = recordLookupIndex;
                        sequenceIndex = recordSequenceIndex;
                    }
                } 

                if (lookupIndex == ushort.MaxValue) 
                { 
                    // All records processed (or we had duplicate records, which we skipped automatically)
                    break; 
                }

                //remember for the next iteration
                prevLookupIndex   = lookupIndex; 
                prevSequenceIndex = sequenceIndex;
 
                // Now find actual glyph where to apply lookup (may depend on lookup flags) 

                int recordFirstGlyph = FirstGlyph; 
                for (int i = 0; i < sequenceIndex && recordFirstGlyph < AfterLastGlyph; i++)
                {
                    recordFirstGlyph = LayoutEngine.GetNextGlyphInLookup(Font, GlyphInfo,
                                                                         recordFirstGlyph + 1, 
                                                                         LookupFlags,
                                                                         LayoutEngine.LookForward 
                                                                        ); 
                }
 
                if (recordFirstGlyph >= AfterLastGlyph)
                {
                    // Requested position is outside of input sequence, do nothing.
                    continue; 
                }
 
                // And finally apply lookup 

                int prevLength = GlyphInfo.Length; 
                int dummyNextGlyph;
                LayoutEngine.ApplyLookup(
                                            Font,
                                            TableTag, 
                                            Table,
                                            Metrics, 
                                            lookupList.Lookup(Table, lookupIndex), 
                                            CharCount,
                                            Charmap, 
                                            GlyphInfo,
                                            Advances,
                                            Offsets,
 
                                            recordFirstGlyph,
                                            AfterLastGlyph, 
                                            Parameter, 
                                            nestingLevel + 1,
                                            out dummyNextGlyph // we don't need it here 
                                          );
                //We need to adjust afterLastGlyph, in case non-single substitution happened
                AfterLastGlyph += GlyphInfo.Length - prevLength;
            } 

            nextGlyph = AfterLastGlyph; 
 
        }
Example #22
0
        public unsafe bool Apply(
            IOpenTypeFont   Font, 
            FontTable       Table,
            LayoutMetrics   Metrics,        // LayoutMetrics 
            GlyphInfoList   GlyphInfo,      // List of GlyphInfo structs 
            ushort          LookupFlags,    // Lookup flags for glyph lookups
            int*            Advances,       // Glyph adv.widths 
            LayoutOffset*   Offsets,        // Glyph offsets
            int             FirstGlyph,     // where to apply lookup
            int             AfterLastGlyph, // how long is a context we can use
            out int         NextGlyph       // Next glyph to process 
            )
        { 
            Invariant.Assert(FirstGlyph>=0); 
            Invariant.Assert(AfterLastGlyph<=GlyphInfo.Length);
 
            NextGlyph = FirstGlyph+1;

            if (Format(Table) != 1) return false; // Unknown format
 
            bool RTL = (LookupFlags & LayoutEngine.LookupFlagRightToLeft) != 0;
            ushort cursiveBit = (ushort)GlyphFlags.CursiveConnected; 
 
            //
 



            int glyphIndex, prevGlyphIndex, 
                coverageIndex, prevCoverageIndex;
 
            glyphIndex = LayoutEngine.GetNextGlyphInLookup(Font,GlyphInfo, 
                                                               FirstGlyph,LookupFlags,
                                                               LayoutEngine.LookForward 
                                                           );

            //clear "CursiveConected" bit,
            //we will set it only if there is a connection to previous glyph 
            if (RTL)
            { 
                GlyphInfo.GlyphFlags[glyphIndex] &= (ushort)~cursiveBit; 
            }
 
            if ( glyphIndex >= AfterLastGlyph )
            {
                return false;
            } 

            prevGlyphIndex = LayoutEngine.GetNextGlyphInLookup(Font,GlyphInfo, 
                                                               FirstGlyph-1,LookupFlags, 
                                                               LayoutEngine.LookBackward
                                                              ); 
            if ( prevGlyphIndex < 0 )
            {
                return false;
            } 

            CoverageTable coverage = Coverage(Table); 
 
            coverageIndex = coverage.GetGlyphIndex(Table,GlyphInfo.Glyphs[glyphIndex]);
            if (coverageIndex == -1) 
            {
                return false;
            }
 
            prevCoverageIndex = coverage.
                                   GetGlyphIndex(Table,GlyphInfo.Glyphs[prevGlyphIndex]); 
            if (prevCoverageIndex == -1) 
            {
                return false; 
            }

            AnchorTable prevExitAnchor, entryAnchor;
 
            prevExitAnchor = ExitAnchor(Table, prevCoverageIndex);
            if (prevExitAnchor.IsNull()) 
            { 
                return false;
            } 

            entryAnchor = EntryAnchor(Table,coverageIndex);
            if (entryAnchor.IsNull())
            { 
                return false;
            } 
 
            Positioning.AlignAnchors(Font, Table, Metrics,
                                     GlyphInfo, Advances, Offsets, 
                                     prevGlyphIndex, glyphIndex,
                                     prevExitAnchor, entryAnchor, true);

            if (RTL) 
            {
                UshortList glyphFlags = GlyphInfo.GlyphFlags; 
 
                int index;
 
                //set "cursive" bit for everything up to prevGlyphIndex
                for(index = glyphIndex; index>prevGlyphIndex; index--)
                {
                    glyphFlags[index] |= cursiveBit; 
                }
 
                //fix cursive dependencies 
                int yCorrection = Offsets[glyphIndex].dy;
                for(index = glyphIndex; 
                    (glyphFlags[index] & cursiveBit) != 0 ;
                    index--
                   )
                { 
                    Offsets[index].dy -= yCorrection;
                } 
                Invariant.Assert(glyphIndex>=0); //First glyph should not have bit set 
                Offsets[index].dy  -= yCorrection;
            } 

            return true;
        }
Example #23
0
        public unsafe bool Apply( 
            IOpenTypeFont           Font,           // Font access interface 
            OpenTypeTags            TableTag,       // Layout table tag (GSUB or GPOS)
            FontTable               Table,          // Layout table (GSUB or GPOS) 
            LayoutMetrics           Metrics,        // LayoutMetrics
            int                     CharCount,      // Characters count (i.e. Charmap.Length);
            UshortList              Charmap,        // Char to glyph mapping
            GlyphInfoList           GlyphInfo,      // List of GlyphInfo structs 
            int*                    Advances,       // Glyph adv.widths
            LayoutOffset*           Offsets,        // Glyph offsets 
            ushort                  LookupFlags,    // Lookup table flags 
            int                     FirstGlyph,     // where to apply it
            int                     AfterLastGlyph, // how long is a context we can use 
            uint                    Parameter,      // lookup parameter
            int                     nestingLevel,   // Contextual lookup nesting level
            out int                 NextGlyph       // out: next glyph index
            ) 
        {
            Invariant.Assert(Format(Table)==2); 
 
            NextGlyph = FirstGlyph + 1; //in case we don't match
 
            int glyphCount = GlyphInfo.Length;

            int     glyphIndex = FirstGlyph;
            ushort  glyphId = GlyphInfo.Glyphs[glyphIndex]; 

            if (Coverage(Table).GetGlyphIndex(Table,glyphId) < 0) return false; 
 
            ClassDefTable inputClassDef = InputClassDef(Table),
                          backtrackClassDef =  BacktrackClassDef(Table), 
                          lookaheadClassDef = LookaheadClassDef(Table);

            ushort GlyphClass = inputClassDef.GetClass(Table,glyphId);
            if (GlyphClass >= ClassSetCount(Table)) return false; //!!! Bad font table 

            SubClassSet subClassSet = ClassSet(Table,GlyphClass); 
            if (subClassSet.IsNull) return false;   // There are no rules for this class 

            ushort ruleCount = subClassSet.RuleCount(Table); 

            bool match = false;
            for(ushort i=0; !match && i<ruleCount; i++)
            { 
                match = subClassSet.Rule(Table,i).Apply(Font, TableTag, Table, Metrics,
                                                        inputClassDef,backtrackClassDef,lookaheadClassDef, 
                                                        CharCount, Charmap, 
                                                        GlyphInfo, Advances, Offsets,
                                                        LookupFlags, FirstGlyph, AfterLastGlyph, 
                                                        Parameter,
                                                        nestingLevel,
                                                        out NextGlyph
                                                       ); 
            }
 
            return match; 
        }
Example #24
0
        public unsafe bool Apply( 
            IOpenTypeFont   Font, 
            FontTable       Table,
            LayoutMetrics   Metrics,        // LayoutMetrics 
            GlyphInfoList   GlyphInfo,      // List of GlyphInfo structs
            ushort          LookupFlags,    // Lookup flags for glyph lookups
            int             CharCount,      // Characters count (i.e. Charmap.Length);
            UshortList      Charmap,        // Char to glyph mapping 
            int*            Advances,       // Glyph adv.widths
            LayoutOffset*   Offsets,        // Glyph offsets 
            int             FirstGlyph,     // where to apply lookup 
            int             AfterLastGlyph, // how long is a context we can use
            out int         NextGlyph       // Next glyph to process 
            )
        {
            Invariant.Assert(FirstGlyph>=0);
            Invariant.Assert(AfterLastGlyph<=GlyphInfo.Length); 

            NextGlyph = FirstGlyph+1; //Always move to the next glyph, whether matched or not 
 
            if (Format(Table) != 1) return false; //unknown format
 
            int glyphCount=GlyphInfo.Length;
            int markGlyph=FirstGlyph;

            //Lookup works with marks only 
            if ((GlyphInfo.GlyphFlags[markGlyph]&(ushort)GlyphFlags.GlyphTypeMask)!=(ushort)GlyphFlags.Mark) return false;
 
            int markCoverageIndex = MarkCoverage(Table).GetGlyphIndex(Table,GlyphInfo.Glyphs[markGlyph]); 
            if (markCoverageIndex==-1) return false;
 
            int baseGlyph;
            ushort component;

            FindBaseLigature(CharCount, Charmap,GlyphInfo,markGlyph, 
                                                out component, out baseGlyph);
            if (baseGlyph<0) return false; 
 
            int baseCoverageIndex = LigatureCoverage(Table).
                                        GetGlyphIndex(Table,GlyphInfo.Glyphs[baseGlyph]); 
            if (baseCoverageIndex == -1) return false;

            ushort classCount = ClassCount(Table);
            MarkArray marks = Marks(Table); 

            ushort markClass = marks.Class(Table,(ushort)markCoverageIndex); 
            if (markClass>=classCount) return false; //Invalid mark class 

            AnchorTable baseAnchor = Ligatures(Table,baseCoverageIndex, classCount). 
                                            LigatureAnchor(Table,component,markClass);
            if (baseAnchor.IsNull())
            {
                return false; 
            }
 
            AnchorTable markAnchor = marks.MarkAnchor(Table,(ushort)markCoverageIndex); 
            if (markAnchor.IsNull())
            { 
                return false;
            }

            Positioning.AlignAnchors(Font,Table,Metrics,GlyphInfo,Advances,Offsets, 
                baseGlyph,markGlyph,baseAnchor,markAnchor,false);
 
            return true; 
        }
Example #25
0
 /// <summary> 
 /// 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
 /// </summary>
 ///<param name="font">In: Font access interface</param> 
 ///<param name="tableTag">In: Font table tag</param>
 ///<param name="scriptTag">In: Script tag</param> 
 ///<param name="langSysTag">In: Language System tag</param> 
 ///<returns>Success if workspace is initialized succesfully, specific error if failed</returns>
 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; 
 }
Example #26
0
        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;
            } 
        }
Example #27
0
        private static void ComputeTableCache(
            IOpenTypeFont font,
            OpenTypeTags tableTag,
            int maxCacheSize,
            ref int cacheSize,
            ref GlyphLookupRecord[] records,
            ref int recordCount,
            ref int glyphCount,
            ref int lastLookupAdded
            )
        {
            FontTable table = font.GetFontTable(tableTag);

            if (!table.IsPresent)
            {
                return;
            }

            FeatureList featureList;
            LookupList  lookupList;

            Debug.Assert(tableTag == OpenTypeTags.GSUB || tableTag == OpenTypeTags.GPOS);

            switch (tableTag)
            {
            case OpenTypeTags.GSUB:
            {
                GSUBHeader header = new GSUBHeader();
                featureList = header.GetFeatureList(table);
                lookupList  = header.GetLookupList(table);
                break;
            }

            case OpenTypeTags.GPOS:
            {
                GPOSHeader header = new GPOSHeader();
                featureList = header.GetFeatureList(table);
                lookupList  = header.GetLookupList(table);
                break;
            }

            default:
            {
                Debug.Assert(false);
                featureList = new FeatureList(0);
                lookupList  = new LookupList(0);
                break;
            }
            }

            // Estimate number of records that can fit into cache using ratio of approximately
            // 4 bytes of cache per actual record. Most of fonts will fit into this value, except
            // some tiny caches and big EA font that can have ratio of around 5 (theoretical maximum is 8).
            //
            // If actual ratio for particluar font will be larger than 4, we will remove records
            // from the end to fit into cache.
            //
            // If ratio is less than 4 we actually can fit more lookups, but for the speed and because most fonts
            // will fit into cache completely anyway we do not do anything about this here.
            int maxRecordCount = maxCacheSize / 4;

            // For now, we will just allocate array of maximum size.
            // Given heuristics above, it wont be greater than max cache size.
            //
            records = new GlyphLookupRecord[maxRecordCount];

            //
            // Now iterate through lookups and subtables, filling in lookup-glyph pairs list
            //
            int lookupCount = lookupList.LookupCount(table);
            int recordCountAfterLastLookup = 0;

            //
            // Not all lookups can be invoked from feature directly,
            // they are actions from contextual lookups.
            // We are not interested in those, because they will
            // never work from high level, so do not bother adding them to the cache.
            //
            // Filling array of lookup usage bits, to skip those not mapped to any lookup
            //
            BitArray lookupUsage = new BitArray(lookupCount);

            for (ushort feature = 0; feature < featureList.FeatureCount(table); feature++)
            {
                FeatureTable featureTable = featureList.FeatureTable(table, feature);

                for (ushort lookup = 0; lookup < featureTable.LookupCount(table); lookup++)
                {
                    ushort lookupIndex = featureTable.LookupIndex(table, lookup);

                    if (lookupIndex >= lookupCount)
                    {
                        // This must be an invalid font. Just igonoring this lookup here.
                        continue;
                    }

                    lookupUsage[lookupIndex] = true;
                }
            }
            // Done with lookup usage bits

            for (ushort lookupIndex = 0; lookupIndex < lookupCount; lookupIndex++)
            {
                if (!lookupUsage[lookupIndex])
                {
                    continue;
                }

                int  firstLookupRecord = recordCount;
                int  maxLookupGlyph    = -1;
                bool cacheIsFull       = false;

                LookupTable lookup        = lookupList.Lookup(table, lookupIndex);
                ushort      lookupType    = lookup.LookupType();
                ushort      subtableCount = lookup.SubTableCount();

                for (ushort subtableIndex = 0; subtableIndex < subtableCount; subtableIndex++)
                {
                    int subtableOffset = lookup.SubtableOffset(table, subtableIndex);

                    CoverageTable coverage = GetSubtablePrincipalCoverage(table, tableTag, lookupType, subtableOffset);

                    if (coverage.IsInvalid)
                    {
                        continue;
                    }

                    cacheIsFull = !AppendCoverageGlyphRecords(table, lookupIndex, coverage, records, ref recordCount, ref maxLookupGlyph);

                    if (cacheIsFull)
                    {
                        break;
                    }
                }

                if (cacheIsFull)
                {
                    break;
                }

                lastLookupAdded            = lookupIndex;
                recordCountAfterLastLookup = recordCount;
            }

            // We may hit storage overflow in the middle of lookup. Throw this partial lookup away
            recordCount = recordCountAfterLastLookup;

            if (lastLookupAdded == -1)
            {
                // We did not succeed adding even single lookup.
                return;
            }

            // We now have glyph records for (may be not all) lookups in the table.
            // Cache structures should be sorted by glyph, then by lookup index.
            Array.Sort(records, 0, recordCount);

            cacheSize  = -1;
            glyphCount = -1;

            // It may happen, that records do not fit into cache, even using our heuristics.
            // We will remove lookups one by one from the end until it fits.
            while (recordCount > 0)
            {
                CalculateCacheSize(records, recordCount, out cacheSize, out glyphCount);

                if (cacheSize <= maxCacheSize)
                {
                    // Fine, we now fit into max cache size
                    break;
                }
                else
                {
                    // Find last lookup index
                    int lastLookup = -1;
                    for (int i = 0; i < recordCount; i++)
                    {
                        int lookup = records[i].Lookup;

                        if (lastLookup < lookup)
                        {
                            lastLookup = lookup;
                        }
                    }

                    Debug.Assert(lastLookup >= 0); // There are lookups, so there was an index

                    // Remove it
                    int currentRecord = 0;
                    for (int i = 0; i < recordCount; i++)
                    {
                        if (records[i].Lookup == lastLookup)
                        {
                            continue;
                        }

                        if (currentRecord == i)
                        {
                            continue;
                        }

                        records[currentRecord] = records[i];
                        currentRecord++;
                    }

                    recordCount = currentRecord;

                    // Do not forget update lastLookupAdded variable
                    lastLookupAdded = lastLookup - 1;
                }
            }

            if (recordCount == 0)
            {
                // We can't fit even single lookup into the cache
                return;
            }

            Debug.Assert(cacheSize > 0);  // We've calcucalted them at least ones, and
            Debug.Assert(glyphCount > 0); // if there is no records, we already should've exited
        }
Example #28
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);
        }
Example #29
0
        /// <summary>
        ///  Align to anchors between two glyphs (e.g. mark and base)
        ///  by changing adv.width and offsets for both of them 
        /// </summary>
        /// <param name="Font"></param> 
        /// <param name="Table"></param> 
        /// <param name="Metrics"></param>
        /// <param name="GlyphInfo"></param> 
        /// <param name="Advances"></param>
        /// <param name="Offsets"></param>
        /// <param name="StaticGlyph"></param>
        /// <param name="MobileGlyph"></param> 
        /// <param name="StaticAnchor"></param>
        /// <param name="MobileAnchor"></param> 
        /// <param name="UseAdvances"></param> 
        /// <returns></returns>
        public static unsafe void AlignAnchors( 
                                        IOpenTypeFont   Font,
                                        FontTable          Table,
                                        LayoutMetrics   Metrics,
                                        GlyphInfoList   GlyphInfo, 
                                        int*            Advances,
                                        LayoutOffset*   Offsets, 
                                        int             StaticGlyph, 
                                        int             MobileGlyph,
                                        AnchorTable     StaticAnchor, 
                                        AnchorTable     MobileAnchor,
                                        bool            UseAdvances
                                      )
        { 
            Invariant.Assert(StaticGlyph>=0 && StaticGlyph<GlyphInfo.Length);
            Invariant.Assert(MobileGlyph>=0 && MobileGlyph<GlyphInfo.Length); 
            Invariant.Assert(!StaticAnchor.IsNull()); 
            Invariant.Assert(!MobileAnchor.IsNull());
 
            LayoutOffset ContourPoint = new LayoutOffset();
            if (StaticAnchor.NeedContourPoint(Table))
            {
                ContourPoint = Font.GetGlyphPointCoord(GlyphInfo.Glyphs[MobileGlyph], 
                                                       StaticAnchor.ContourPointIndex(Table));
            } 
            LayoutOffset StaticAnchorPoint = StaticAnchor.AnchorCoordinates(Table,Metrics,ContourPoint); 

            if (MobileAnchor.NeedContourPoint(Table)) 
            {
                ContourPoint = Font.GetGlyphPointCoord(GlyphInfo.Glyphs[MobileGlyph],
                                                                  MobileAnchor.ContourPointIndex(Table));
            } 
            LayoutOffset MobileAnchorPoint = MobileAnchor.AnchorCoordinates(Table,Metrics,ContourPoint);
 
            int AdvanceInBetween=0; 
            if (StaticGlyph<MobileGlyph)
                for(int i=StaticGlyph+1;i<MobileGlyph;i++) AdvanceInBetween+=Advances[i]; 
            else
                for(int i=MobileGlyph+1;i<StaticGlyph;i++) AdvanceInBetween+=Advances[i];

            if (Metrics.Direction==TextFlowDirection.LTR || 
                Metrics.Direction==TextFlowDirection.RTL)
            { 
                Offsets[MobileGlyph].dy = Offsets[StaticGlyph].dy + StaticAnchorPoint.dy 
                                                                  - MobileAnchorPoint.dy;
 
                if ((Metrics.Direction==TextFlowDirection.LTR)==(StaticGlyph<MobileGlyph))
                {
                    // static glyph is on the left(phisically, not logically) to the mobile glyph
                    int dx = Offsets[StaticGlyph].dx - Advances[StaticGlyph] +  StaticAnchorPoint.dx 
                                        - AdvanceInBetween - MobileAnchorPoint.dx;
 
                    if (UseAdvances) 
                    {
                        Advances[StaticGlyph] += dx; 
                    }
                    else
                    {
                        Offsets[MobileGlyph].dx = dx; 
                    }
                } 
                else 
                {
                    // static glyph is on the right(phisically, not logically) to the mobile glyph 
                    int dx = Offsets[StaticGlyph].dx + Advances[MobileGlyph] +  StaticAnchorPoint.dx
                        + AdvanceInBetween - MobileAnchorPoint.dx;

                    if (UseAdvances) 
                    {
                        Advances[MobileGlyph] -= dx; 
                    } 
                    else
                    { 
                        Offsets[MobileGlyph].dx = dx;
                    }
                }
            } 
            else
            { 
                 //TTB, BTT: //Under construction 
            }
 
        }
Example #30
0
        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; 
        }
Example #31
0
        ///<summary>
        /// Internal method to test layout tables if they are uitable for fast path.
        /// Returns list of script-langauge pairs that are not optimizable.
        ///</summary>
        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);
            }
        }
Example #32
0
        public unsafe bool Apply(
                            IOpenTypeFont   Font,
                            FontTable       Table, 
                            LayoutMetrics   Metrics,        // LayoutMetrics
                            GlyphInfoList   GlyphInfo,      // List of GlyphInfo structs 
                            ushort          LookupFlags,    // Lookup flags for glyph lookups 
                            int*            Advances,       // Glyph adv.widths
                            LayoutOffset*   Offsets,        // Glyph offsets 
                            int             FirstGlyph,     // where to apply lookup
                            int             AfterLastGlyph, // how long is a context we can use
                            out int         NextGlyph       // Next glyph to process
                         ) 
        {
            Invariant.Assert(FirstGlyph>=0); 
            Invariant.Assert(AfterLastGlyph<=GlyphInfo.Length); 

            NextGlyph = FirstGlyph+1; //Always move to the next glyph, whether matched or not 

            int glyphCount=GlyphInfo.Length;
            ushort firstGlyphId = GlyphInfo.Glyphs[FirstGlyph];
 
            int secondGlyph = LayoutEngine.GetNextGlyphInLookup(Font,GlyphInfo,FirstGlyph+1,LookupFlags,LayoutEngine.LookForward);
            if (secondGlyph>=AfterLastGlyph) return false; 
 
            ushort secondGlyphId = GlyphInfo.Glyphs[secondGlyph];
 
            ValueRecordTable firstValueRecord, secondValueRecord;

            switch (Format(Table))
            { 
                case 1:
                { 
                    int coverageIndex = Coverage(Table).GetGlyphIndex(Table,firstGlyphId); 
                    if (coverageIndex==-1) return false;
 
                    PairSetTable pairSet = Format1PairSet(Table,(ushort)coverageIndex);

                    int pairValueIndex = pairSet.FindPairValue(Table, secondGlyphId);
                    if (pairValueIndex == -1) return false; 

                    firstValueRecord  = pairSet.FirstValueRecord(Table,(ushort)pairValueIndex,FirstValueFormat(Table)); 
                    secondValueRecord = pairSet.SecondValueRecord(Table,(ushort)pairValueIndex,SecondValueFormat(Table)); 

                    break; 
                }
                case 2:
                {
                    int coverageIndex = Coverage(Table).GetGlyphIndex(Table,firstGlyphId); 
                    if (coverageIndex == -1) return false;
 
                    ushort firstClassIndex = Format2Class1Table(Table).GetClass(Table,firstGlyphId); 
                    if (firstClassIndex >= Format2Class1Count(Table)) return false; //this is invalid font;
                    ushort secondClassIndex = Format2Class2Table(Table).GetClass(Table,secondGlyphId); 
                    if (secondClassIndex >= Format2Class2Count(Table)) return false; //this is invalid font;

                    ushort class2Count = Format2Class2Count(Table);
                    firstValueRecord = Format2FirstValueRecord(Table, 
                                                               class2Count,
                                                               firstClassIndex, 
                                                               secondClassIndex 
                                                              );
                    secondValueRecord = Format2SecondValueRecord(Table, 
                                                                 class2Count,
                                                                 firstClassIndex,
                                                                 secondClassIndex
                                                                ); 
                    break;
                } 
                default: 
                    return false;
            } 

            //Now adjust positions
            firstValueRecord.AdjustPos (Table, Metrics, ref Offsets[FirstGlyph],  ref Advances[FirstGlyph]);
            secondValueRecord.AdjustPos(Table, Metrics, ref Offsets[secondGlyph], ref Advances[secondGlyph]); 

            return true; 
        } 
Example #33
0
            public unsafe bool Apply(
                IOpenTypeFont           Font,           // Font access interface 
                OpenTypeTags            TableTag,       // Layout table tag (GSUB or GPOS) 
                FontTable               Table,          // Layout table (GSUB or GPOS)
                LayoutMetrics           Metrics,        // LayoutMetrics 
                ClassDefTable           ClassDef,
                int                     CharCount,      // Characters count (i.e. Charmap.Length);
                UshortList              Charmap,        // Char to glyph mapping
                GlyphInfoList           GlyphInfo,      // List of GlyphInfo structs 
                int*                    Advances,       // Glyph adv.widths
                LayoutOffset*           Offsets,        // Glyph offsets 
                ushort                  LookupFlags,    // Lookup table flags 
                int                     FirstGlyph,     // where to apply it
                int                     AfterLastGlyph, // how long is a context we can use 
                uint                    Parameter,      // lookup parameter
                int                     nestingLevel,   // Contextual lookup nesting level
                out int                 NextGlyph       // out: next glyph index
                ) 
            {
                NextGlyph = FirstGlyph + 1; //In case we don't match 
 
                //
                // Check input sequence 
                //
                bool match = true;
                int glyphIndex = FirstGlyph;
 
                int inputGlyphCount = GlyphCount(Table);
                for(ushort inputIndex = 1; // go from second glyph in the input 
                    inputIndex < inputGlyphCount && match; 
                    inputIndex++)
                { 
                    glyphIndex = LayoutEngine.GetNextGlyphInLookup(Font, GlyphInfo,
                        glyphIndex+1,
                        LookupFlags,
                        LayoutEngine.LookForward 
                        );
 
                    if (glyphIndex>=AfterLastGlyph) 
                    {
                        match = false; 
                    }
                    else
                    {
                        ushort classId = ClassId(Table,inputIndex); 

                        ushort glyphClass = 
                                  ClassDef.GetClass(Table,GlyphInfo.Glyphs[glyphIndex]); 

                        match = (glyphClass == classId); 
                    }
                }

                if (match) 
                {
                    ContextualLookups(Table).ApplyContextualLookups( 
                        Font, 
                        TableTag,
                        Table, 
                        Metrics,
                        CharCount,
                        Charmap,
                        GlyphInfo, 
                        Advances,
                        Offsets, 
                        LookupFlags, 
                        FirstGlyph,
                        glyphIndex + 1, //As AfterLastGlyph 
                        Parameter,
                        nestingLevel,
                        out NextGlyph
                    ); 
                }
 
                return match; 
            }
Example #34
0
 public unsafe bool Apply(
     IOpenTypeFont           Font,           // Font access interface 
     OpenTypeTags            TableTag,       // Layout table tag (GSUB or GPOS) 
     FontTable               Table,          // Layout table (GSUB or GPOS)
     LayoutMetrics           Metrics,        // LayoutMetrics 
     int                     CharCount,      // Characters count (i.e. Charmap.Length);
     UshortList              Charmap,        // Char to glyph mapping
     GlyphInfoList           GlyphInfo,      // List of GlyphInfo structs
     int*                    Advances,       // Glyph adv.widths 
     LayoutOffset*           Offsets,        // Glyph offsets
     ushort                  LookupFlags,    // Lookup table flags 
     int                     FirstGlyph,     // where to apply it 
     int                     AfterLastGlyph, // how long is a context we can use
     uint                    Parameter,      // lookup parameter 
     int                     nestingLevel,   // Contextual lookup nesting level
     out int                 NextGlyph       // out: next glyph index
     )
 { 
     switch (Format(Table))
     { 
         case 1: 
             GlyphContextSubtable glyphContextSubtable =
                                         new GlyphContextSubtable(offset); 
             return glyphContextSubtable.Apply(
                 Font, TableTag, Table, Metrics,
                 CharCount, Charmap,
                 GlyphInfo, Advances, Offsets, 
                 LookupFlags, FirstGlyph, AfterLastGlyph,
                 Parameter, 
                 nestingLevel, 
                 out NextGlyph
                 ); 
         case 2:
             ClassContextSubtable classContextSubtable =
                                         new ClassContextSubtable(offset);
             return classContextSubtable.Apply( 
                 Font, TableTag, Table, Metrics,
                 CharCount, Charmap, 
                 GlyphInfo, Advances, Offsets, 
                 LookupFlags, FirstGlyph, AfterLastGlyph,
                 Parameter, 
                 nestingLevel,
                 out NextGlyph
                 );
         case 3: 
             CoverageContextSubtable coverageContextSubtable =
                                         new CoverageContextSubtable(offset); 
             return coverageContextSubtable.Apply( 
                 Font, TableTag, Table, Metrics,
                 CharCount, Charmap, 
                 GlyphInfo, Advances, Offsets,
                 LookupFlags, FirstGlyph, AfterLastGlyph,
                 Parameter,
                 nestingLevel, 
                 out NextGlyph
                 ); 
         default: 
             //Unknown format
             NextGlyph = FirstGlyph+1; //don't match 
             return false;
     }
 }
Example #35
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);
        }
Example #36
0
        public unsafe bool Apply(
            IOpenTypeFont           Font,           // Font access interface 
            OpenTypeTags            TableTag,       // Layout table tag (GSUB or GPOS) 
            FontTable               Table,          // Layout table (GSUB or GPOS)
            LayoutMetrics           Metrics,        // LayoutMetrics 
            int                     CharCount,      // Characters count (i.e. Charmap.Length);
            UshortList              Charmap,        // Char to glyph mapping
            GlyphInfoList           GlyphInfo,      // List of GlyphInfo structs
            int*                    Advances,       // Glyph adv.widths 
            LayoutOffset*           Offsets,        // Glyph offsets
            ushort                  LookupFlags,    // Lookup table flags 
            int                     FirstGlyph,     // where to apply it 
            int                     AfterLastGlyph, // how long is a context we can use
            uint                    Parameter,      // lookup parameter 
            out int                 NextGlyph       // out: next glyph index
            )
        {
            //This will be the next glyph, does not matter sequence matched or not 
            NextGlyph = AfterLastGlyph-1;
 
            if (Format(Table)!=1) return false; //Unknown 

            bool match = true; 
            int inputGlyphIndex = AfterLastGlyph - 1;
            int glyphIndex;

            //Check input glyph 
            int coverageIndex = InputCoverage(Table).GetGlyphIndex(Table,GlyphInfo.Glyphs[inputGlyphIndex]);
 
            if (coverageIndex<0) return false; 

            //we reading data sequenctially from table, moving pointer through it 
            int curOffset = offset + offsetBacktrackGlyphCount;

            //
            // Check backtrack sequence 
            //
            ushort backtrackGlyphCount = GlyphCount(Table,curOffset); 
            curOffset += sizeCount; 

            glyphIndex = inputGlyphIndex; 
            for(ushort backtrackIndex = 0;
                backtrackIndex < backtrackGlyphCount && match;
                backtrackIndex++)
            { 
                glyphIndex = LayoutEngine.GetNextGlyphInLookup(Font, GlyphInfo,
                    glyphIndex-1, 
                    LookupFlags, 
                    LayoutEngine.LookBackward
                    ); 

                if (glyphIndex<0)
                {
                    match = false; 
                }
                else 
                { 
                    match = (Coverage(Table,curOffset).GetGlyphIndex(Table,GlyphInfo.Glyphs[glyphIndex]) >= 0);
                    curOffset += sizeOffset; 
                }
            }

            ushort lookaheadGlyphCount = GlyphCount(Table,curOffset); 
            curOffset += sizeCount;
 
            glyphIndex = inputGlyphIndex; 
            for(ushort lookaheadIndex = 0;
                lookaheadIndex < lookaheadGlyphCount && match; 
                lookaheadIndex++)
            {
                glyphIndex = LayoutEngine.GetNextGlyphInLookup(Font, GlyphInfo,
                    glyphIndex+1, 
                    LookupFlags,
                    LayoutEngine.LookForward 
                    ); 

                if (glyphIndex>=GlyphInfo.Length) 
                {
                    match = false;
                }
                else 
                {
                    match = (Coverage(Table,curOffset).GetGlyphIndex(Table,GlyphInfo.Glyphs[glyphIndex]) >= 0); 
                    curOffset += sizeOffset; 
                }
            } 

            if (match)
            {
                curOffset += sizeCount + sizeGlyphId*coverageIndex; 
                GlyphInfo.Glyphs[inputGlyphIndex] = Glyph(Table,curOffset);
                GlyphInfo.GlyphFlags[inputGlyphIndex] = (ushort)(GlyphFlags.Unresolved | GlyphFlags.Substituted); 
            } 

            return match; 
        }
Example #37
0
        public unsafe bool Apply(
            IOpenTypeFont   Font,
            FontTable       Table,
            int             CharCount,
            UshortList      Charmap,        // Character to glyph map
            GlyphInfoList   GlyphInfo,      // List of GlyphInfo
            ushort          LookupFlags,    // Lookup flags for glyph lookups
            int             FirstGlyph,     // where to apply it
            int             AfterLastGlyph, // how long is a context we can use
            out int         NextGlyph       // Next glyph to process
            )
         {
            NextGlyph = FirstGlyph + 1; // in case we don't match
            
            if (Format(Table) != 1) return false; //unknown format
            
            int oldGlyphCount=GlyphInfo.Length;
            
            ushort glyphId = GlyphInfo.Glyphs[FirstGlyph];
            int coverageIndex = Coverage(Table).GetGlyphIndex(Table,glyphId);
            if (coverageIndex==-1) return false;
            
            MultipleSubstitutionSequenceTable sequence = Sequence(Table,coverageIndex);

            ushort sequenceLength = sequence.GlyphCount(Table);
            int lengthDelta = sequenceLength - 1;
            
            if (sequenceLength==0)
            {
                // This is illegal, because mapping will be broken -
                // corresponding char will be lost. Just leave it as it is.
                // (char will be attached to the following glyph).
                GlyphInfo.Remove(FirstGlyph,1);
            }
            else
            {
                ushort firstChar = GlyphInfo.FirstChars[FirstGlyph];
                ushort ligatureCount = GlyphInfo.LigatureCounts[FirstGlyph];

                if (lengthDelta > 0)
                {
                    GlyphInfo.Insert(FirstGlyph,lengthDelta);
                }
                
                //put glyphs in place
                for(ushort gl=0; gl<sequenceLength; gl++)
                {
                    GlyphInfo.Glyphs[FirstGlyph + gl] = sequence.Glyph(Table,gl);
                    GlyphInfo.GlyphFlags[FirstGlyph + gl] =
                                (ushort)(GlyphFlags.Unresolved | GlyphFlags.Substituted);
                    GlyphInfo.FirstChars[FirstGlyph + gl] = firstChar;
                    GlyphInfo.LigatureCounts[FirstGlyph + gl] = ligatureCount;
                }
            }
            
            //Fix char mapping - very simple for now. 
            // Works only for arabic base+mark -> base and marks decomposition
            //
            for(int ch=0;ch<CharCount;ch++)
            {
                if (Charmap[ch]>FirstGlyph) Charmap[ch] = (ushort)(Charmap[ch]+lengthDelta);
            }
            
            NextGlyph = FirstGlyph + lengthDelta + 1;
            
            return true;
         }
Example #38
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;
        }