Example #1
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 #2
0
        private static void AppendLangSys(
                            uint                scriptTag,
                            uint                langSysTag,
                            LangSysTable        langSysTable,
                            FeatureList         featureList,
                            FontTable           table,
                            uint[]              featureTagsList,
                            uint[]              lookupBits,
                            ref WritingSystem[] complexLanguages,
                            ref int             complexLanguageCount
                     )
        {
            ushort featureCount  = langSysTable.FeatureCount(table);

            bool complexFeatureFound = false;

            //

            for(ushort i = 0; !complexFeatureFound && i < featureCount; i++)
            {
                ushort featureIndex = langSysTable.GetFeatureIndex(table, i);

                uint featureTag = featureList.FeatureTag(table,featureIndex);
                bool tagFound = false;

                for(int j = 0; !complexFeatureFound && j < featureTagsList.Length; j++)
                {
                    if (featureTagsList[j] == featureTag)
                    {
                        tagFound = true;
                        break;
                    }
                }

                if (tagFound)
                {
                    // We should check if any of lookups is complex
                    FeatureTable featureTable = featureList.FeatureTable(table, featureIndex);
                    ushort featureLookupCount = featureTable.LookupCount(table);

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

                        if ((lookupBits[lookupIndex>>5] & (1 << (lookupIndex%32))) != 0)
                        {
                            complexFeatureFound = true;
                            break;
                        }
                    }
                }
            }

            if (complexFeatureFound)
            {
                if (complexLanguages.Length == complexLanguageCount)
                {
                    WritingSystem[] newComplexLanguages =
                                        new WritingSystem[complexLanguages.Length * 3 /2];

                    for(int i = 0; i < complexLanguages.Length; i++)
                    {
                        newComplexLanguages[i] = complexLanguages[i];
                    }

                    complexLanguages = newComplexLanguages;
                }

                complexLanguages[complexLanguageCount].scriptTag = scriptTag;
                complexLanguages[complexLanguageCount].langSysTag = langSysTag;
                complexLanguageCount++;
            }

        }
Example #3
0
        internal static void GetComplexLanguageList(
                                                OpenTypeTags            tableTag,
                                                FontTable               table,
                                                uint[]                  featureTagsList,
                                                uint[]                  glyphBits,
                                                ushort                  minGlyphId,
                                                ushort                  maxGlyphId,
                                                out WritingSystem[]     complexLanguages,
                                                out int                 complexLanguageCount
                                             )
        {
            ScriptList  scriptList  = new ScriptList(0);
            FeatureList featureList = new FeatureList(0);
            LookupList  lookupList  = new LookupList(0);

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

            switch (tableTag)
            {
                case OpenTypeTags.GSUB:
                    GSUBHeader gsubHeader = new GSUBHeader(0);
                    scriptList  = gsubHeader.GetScriptList(table);
                    featureList = gsubHeader.GetFeatureList(table);
                    lookupList  = gsubHeader.GetLookupList(table);
                    break;

                case OpenTypeTags.GPOS:
                    GPOSHeader gposHeader = new GPOSHeader(0);
                    scriptList  = gposHeader.GetScriptList(table);
                    featureList = gposHeader.GetFeatureList(table);
                    lookupList  = gposHeader.GetLookupList(table);
                    break;
            }

            int scriptCount  = scriptList.GetScriptCount(table);
            int featureCount = featureList.FeatureCount(table);
            int lookupCount  = lookupList.LookupCount(table);

            // We will mark lookups that should be tested.
            // At the end, we will have only complex ones marked
            uint[] lookupBits = new uint[(lookupCount+31)>>5];

            for(int i = 0; i < (lookupCount+31)>>5; i++)
            {
                lookupBits[i] = 0;
            }

            // Iterate through list of featuers in the table
            for(ushort featureIndex = 0; featureIndex < featureCount; featureIndex++)
            {
                uint featureTag = (uint)featureList.FeatureTag(table, featureIndex);
                bool tagFound   = false;

                //Search for tag in the list of features in question
                for(int j = 0; j < featureTagsList.Length; j++)
                {
                    if (featureTagsList[j] == featureTag)
                    {
                        tagFound = true;
                        break;
                    }
                }

                if (tagFound)
                {
                    // We should mark all lookup mapped to this feature
                    FeatureTable featureTable = featureList.FeatureTable(table, featureIndex);
                    ushort featureLookupCount = featureTable.LookupCount(table);

                    for(ushort j = 0; j < featureLookupCount; j++)
                    {
                        ushort lookupIndex = featureTable.LookupIndex(table, j);
                        
                        if (lookupIndex >= lookupCount)
                        {
                            //This should be invalid font. Lookup associated with the feature is not in lookup array.
                            throw new FileFormatException();
                        }

                        lookupBits[lookupIndex>>5] |= (uint)(1 << (lookupIndex%32));
                    }
                }
            }

            //
            //




            //Now test all marked lookups
            for(ushort lookupIndex = 0; lookupIndex < lookupCount; lookupIndex++)
            {
                if ((lookupBits[lookupIndex>>5] & (1 << (lookupIndex%32))) == 0)
                {
                    continue;
                }

                LookupTable lookup = lookupList.Lookup(table,lookupIndex);

                ushort lookupType    = lookup.LookupType();
                ushort subtableCount = lookup.SubTableCount();

                bool lookupIsCovered = false;

                ushort originalLookupType = lookupType; // We need it to recover,
                                                        // if extension lookup updated lookupFormat
                for(ushort subtableIndex = 0;
                    !lookupIsCovered && 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);
                                    lookupIsCovered = singleSub.IsLookupCovered(table,glyphBits,minGlyphId,maxGlyphId);
                                    break;

                                case 2: //MultipleSubst
                                    MultipleSubstitutionSubtable multipleSub =
                                        new MultipleSubstitutionSubtable(subtableOffset);
                                    lookupIsCovered = multipleSub.IsLookupCovered(table,glyphBits,minGlyphId,maxGlyphId);
                                    break;

                                case 3: //AlternateSubst
                                    AlternateSubstitutionSubtable alternateSub =
                                        new AlternateSubstitutionSubtable(subtableOffset);
                                    lookupIsCovered = alternateSub.IsLookupCovered(table,glyphBits,minGlyphId,maxGlyphId);
                                    break;

                                case 4: //Ligature subst
                                    LigatureSubstitutionSubtable ligaSub =
                                        new LigatureSubstitutionSubtable(subtableOffset);
                                    lookupIsCovered = ligaSub.IsLookupCovered(table,glyphBits,minGlyphId,maxGlyphId);
                                    break;

                                case 5: //ContextualSubst
                                    ContextSubtable contextSub =
                                        new ContextSubtable(subtableOffset);
                                    lookupIsCovered = contextSub.IsLookupCovered(table,glyphBits,minGlyphId,maxGlyphId);
                                    break;

                                case 6: //ChainingSubst
                                    ChainingSubtable chainingSub =
                                                        new ChainingSubtable(subtableOffset);
                                    lookupIsCovered = chainingSub.IsLookupCovered(table,glyphBits,minGlyphId,maxGlyphId);
                                    break;

                                case 7: //Extension lookup
                                    Debug.Assert(false,"Ext.Lookup processed earlier!");
                                    break;

                                case 8: //ReverseCahiningSubst
                                    ReverseChainingSubtable reverseChainingSub =
                                        new ReverseChainingSubtable(subtableOffset);
                                    lookupIsCovered = reverseChainingSub.IsLookupCovered(table,glyphBits,minGlyphId,maxGlyphId);
                                    break;

                                default:
                                    // Unknown format
                                    lookupIsCovered = true;
                                    break;
                            }

                            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);
                                    lookupIsCovered = singlePos.IsLookupCovered(table,glyphBits,minGlyphId,maxGlyphId);
                                    break;

                                case 2: //PairPos
                                    PairPositioningSubtable pairPos =
                                        new PairPositioningSubtable(subtableOffset);
                                    lookupIsCovered = pairPos.IsLookupCovered(table,glyphBits,minGlyphId,maxGlyphId);
                                    break;

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

                                    lookupIsCovered = cursivePositioningSubtable.IsLookupCovered(table,glyphBits,minGlyphId,maxGlyphId);

                                    break;

                                case 4: //MarkToBasePos
                                    MarkToBasePositioningSubtable markToBasePos =
                                        new MarkToBasePositioningSubtable(subtableOffset);
                                    lookupIsCovered = markToBasePos.IsLookupCovered(table,glyphBits,minGlyphId,maxGlyphId);
                                    break;


                                case 5: //MarkToLigaturePos
                                    // Under construction
                                    MarkToLigaturePositioningSubtable markToLigaPos =
                                       new MarkToLigaturePositioningSubtable(subtableOffset);
                                    lookupIsCovered = markToLigaPos.IsLookupCovered(table,glyphBits,minGlyphId,maxGlyphId);
                                    break;

                                case 6: //MarkToMarkPos
                                    MarkToMarkPositioningSubtable markToMarkPos =
                                        new MarkToMarkPositioningSubtable(subtableOffset);
                                    lookupIsCovered = markToMarkPos.IsLookupCovered(table,glyphBits,minGlyphId,maxGlyphId);
                                    break;

                                case 7: // Contextual
                                    ContextSubtable contextSub =
                                        new ContextSubtable(subtableOffset);
                                    lookupIsCovered = contextSub.IsLookupCovered(table,glyphBits,minGlyphId,maxGlyphId);
                                    break;

                                case 8: // Chaining
                                    ChainingSubtable chainingSub =
                                        new ChainingSubtable(subtableOffset);
                                    lookupIsCovered = chainingSub.IsLookupCovered(table,glyphBits,minGlyphId,maxGlyphId);
                                    break;

                                case 9: //Extension lookup
                                    Debug.Assert(false,"Ext.Lookup processed earlier!");
                                    break;

                                default:
                                    // Unknown format
                                    lookupIsCovered = true;
                                    break;
                            }

                            break;
                        }

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

                if (!lookupIsCovered)
                {
                    // Clean the flag
                    lookupBits[lookupIndex>>5] &= ~(uint)(1 << (lookupIndex%32));
                }
            }


            // Check if we have any lookup left
            bool complexLookupFound = false;

            for(int i = 0; i < (lookupCount+31)>>5; i++)
            {
                if (lookupBits[i] != 0)
                {
                    complexLookupFound = true;
                    break;
                }
            }

            if (!complexLookupFound)
            {
                // There are no complex lookups
                complexLanguages = null;
                complexLanguageCount = 0;
                return;
            }

            // Now go through all langauages and fill the list
            complexLanguages = new WritingSystem[10];
            complexLanguageCount = 0;

            for(ushort scriptIndex = 0; scriptIndex < scriptCount; scriptIndex++)
            {
                ScriptTable  scriptTable = scriptList.GetScriptTable(table, scriptIndex);
                uint scriptTag = scriptList.GetScriptTag(table, scriptIndex);

                ushort langSysCount = scriptTable.GetLangSysCount(table);

                if (scriptTable.IsDefaultLangSysExists(table))
                {
                    AppendLangSys(scriptTag, (uint)OpenTypeTags.dflt,
                                  scriptTable.GetDefaultLangSysTable(table),
                                  featureList,
                                  table,
                                  featureTagsList,
                                  lookupBits,
                                  ref complexLanguages,
                                  ref complexLanguageCount
                                 );
                }

                for(ushort langSysIndex = 0; langSysIndex < langSysCount; langSysIndex++)
                {
                    uint langSysTag = scriptTable.GetLangSysTag(table, langSysIndex);

                    AppendLangSys(scriptTag, langSysTag,
                                  scriptTable.GetLangSysTable(table, langSysIndex),
                                  featureList,
                                  table,
                                  featureTagsList,
                                  lookupBits,
                                  ref complexLanguages,
                                  ref complexLanguageCount
                                 );
                }
            }
        }
Example #4
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;
            } 
        }