Ejemplo n.º 1
0
        /************************
         * public methods
         */

        public bool Validate(Validator v, OTFontVal fontOwner)
        {
            bool bRet = true;

            v.Info(T.T_NULL, I.CFF_I_Version, m_tag, major + "." + minor);
            v.Info(I.CFF_I_NotValidated, m_tag);

            return(bRet);
        }
Ejemplo n.º 2
0
        /************************
         * public methods
         */

        public bool Validate(Validator v, OTFontVal fontOwner)
        {
            bool bRet = true;

            v.Info(T.T_NULL, I.CFF_I_Version, m_tag, major + "." + minor);
            v.Info(I.CFF_I_NotValidated, m_tag);
            
            return bRet;
        }
Ejemplo n.º 3
0
            public bool Validate(Validator v, string sIdentity, OTTable table)
            {
                bool bRet = true;

                bRet &= ((val_GDEF)table).ValidateNoOverlap(m_offsetMarkGlyphSetsDefTable, CalcLength(), v, sIdentity, table.GetTag());

                if (MarkSetTableFormat != 1)
                {
                    v.Error(T.T_NULL, E.GDEF_E_MarkSetTableFormat, table.m_tag,
                            sIdentity + ": MarkSetTableFormat=" + MarkSetTableFormat.ToString());
                    bRet = false;
                }

                if (m_offsetMarkGlyphSetsDefTable + CalcLength() > m_bufTable.GetLength())
                {
                    v.Error(T.T_NULL, E.GDEF_E_MarkGlyphSetsDefTable_PastEOT, table.m_tag, sIdentity);
                    bRet = false;
                }

                v.Info(T.T_NULL, I.GDEF_I_MarkSetCount, table.m_tag, sIdentity + ": MarkSetCount=" + MarkSetCount);
                // TODO: check Coverage [MarkSetCount] array?

                if (bRet)
                {
                    v.Pass(T.T_NULL, P.GDEF_P_MarkGlyphSetsDefTable, table.m_tag, sIdentity);
                }

                return bRet;
            }
Ejemplo n.º 4
0
        /************************
         * public methods
         */


        public bool Validate(Validator v, OTFontVal fontOwner)
        {
            bool bRet = true;

            v.Info(I.fpgm_I_NotValidated, m_tag);

            return(bRet);
        }
Ejemplo n.º 5
0
        /************************
         * public methods
         */


        public bool Validate(Validator v, OTFontVal fontOwner)
        {
            bool bRet = true;

            v.Info(I.fpgm_I_NotValidated, m_tag);
            
            return bRet;
        }
Ejemplo n.º 6
0
        private bool ValidateGlyfEntryEmpty(Validator validator,
                                            OTFont fontOwner)
        {
            int cntInfo  = 0;
            int numEntry = this.NumEntry(fontOwner);

            if (numEntry == Table_loca.ValueInvalid)
            {
                if (validator != null)
                {
                    validator.Warning(T.T_NULL, W._TEST_W_OtherErrorsInTable,
                                      m_tag,
                                      "Unable to determine the number of entries in the 'loca' table");
                }
                return(false);
            }

            int offsGlyfCur, offsGlyfNext;

            for (int iEntry = 0; iEntry < numEntry - 1; iEntry++)
            {
                if ((!this.GetGlyfOffset(iEntry, out offsGlyfCur, validator, fontOwner)) ||
                    (!this.GetGlyfOffset(iEntry + 1, out offsGlyfNext, validator, fontOwner)))
                {
                    cntInfo++;
                    continue;
                }
                if (offsGlyfNext == offsGlyfCur)
                {
                    cntInfo++;
                }
            }
            if (validator != null)
            {
                if (cntInfo == 0)
                {
                    validator.Pass(P.loca_P_GlyfEntryEmpty, m_tag);
                }
                else
                {
                    validator.Info(T.T_NULL, I.loca_I_GlyfEntryEmpty,
                                   m_tag,
                                   "Number of glyphs that are empty = " + cntInfo);
                }
            }
            return(cntInfo == 0);
        }
Ejemplo n.º 7
0
        /************************
         * public methods
         */


        public bool Validate(Validator v, OTFontVal fontOwner)
        {
            string sDetails = "";

            string [] Apple_Tables = 
                {
                    "acnt", "avar", "bdat", "bhed", "bloc", "bsln", "cmap", "cvar", "cvt ",
                    "EBSC", "fdsc", "feat", "fmtx", "fpgm", "gasp", "glyf", "gvar", "hdmx",
                    "head", "hhea", "hmtx", "hsty", "just", "kern", "lcar", "loca", "maxp",
                    "mort", "morx", "name", "opbd", "OS/2", "post", "prep", "prop", "trak",
                    "vhea", "vmtx", "Zapf"
                };

            string [] VOLT_only_Tables = 
                {
                    "TSIV"
                };

            string [] VOLT_VTT_shared_Tables = 
                {
                    "TSIS", "TSIP", "TSID"
                };

            string [] VTT_only_Tables =
                {
                    "TSI0", "TSI1", "TSI2", "TSI3", "TSI4", "TSI5" ,"TSIJ", "TSIB"
                };

            bool bIdentified = false;

            for (int i=0; i<Apple_Tables.Length; i++)
            {
                if (Apple_Tables[i] == (string)m_tag)
                {
                    sDetails = "This table type is defined in the Apple TrueType spec.";
                    bIdentified = true;
                }
            }

            if (!bIdentified)
            {
                for (int i=0; i<VOLT_only_Tables.Length; i++)
                {
                    if (VOLT_only_Tables[i] == (string)m_tag)
                    {
                        sDetails = "This table type is used by the VOLT tool.";
                        bIdentified = true;
                    }
                }
            }

            if (!bIdentified)
            {
                for (int i=0; i<VOLT_VTT_shared_Tables.Length; i++)
                {
                    if (VOLT_VTT_shared_Tables[i] == (string)m_tag)
                    {
                        sDetails = "This table type is used by the VOLT tool and the VTT tool.";
                        bIdentified = true;
                    }
                }
            }

            if (!bIdentified)
            {
                for (int i=0; i<VTT_only_Tables.Length; i++)
                {
                    if (VTT_only_Tables[i] == (string)m_tag)
                    {
                        sDetails = "This table type is used by the VTT tool.";
                        bIdentified = true;
                    }
                }
            }

            v.Info(T.T_NULL, I._Table_I_Non_OT_Table, m_tag, sDetails);

            // Since there is no way to do any validation on unknown tables
            // always return true

            return true;
        }
Ejemplo n.º 8
0
        public bool Validate(Validator validator, OTFontVal fontOwner)
        {
            bool bRet = true;

            if (!validator.PerformTest(T.glyf_ValidateAll))
            {
                return(true);
            }

            if (fontOwner.GetFile().IsCollection())
            {
                if (fontOwner.GetFontIndexInFile() > 0)
                {
                    // checksum not matching data is covered by check elsewhere. Assume they match.
                    DirectoryEntry de_glyf = fontOwner.GetDirectoryEntry("glyf");
                    for (uint i = 0; i < fontOwner.GetFontIndexInFile(); i++)
                    {
                        if (fontOwner.GetFile().GetFont(i).GetDirectoryEntry("glyf").checkSum
                            == de_glyf.checkSum)
                        {
                            validator.Info(T.T_NULL, I.glyf_I_IDENTICAL_GLYF_TABLES_IN_TTC, m_tag);
                            return(true);
                        }
                    }
                }
            }

            this.m_diaValidate = validator.DIA;
            this.m_cnts        = new int[this.m_namesInfoCnt.Length];
            for (int iCnt = 0; iCnt < this.m_cnts.Length; iCnt++)
            {
                this.m_cnts[iCnt] = 0;
            }

            I_IOGlyphsFile i_IOGlyphs = new I_IOGlyphsFile();

            if (!i_IOGlyphs.Initialize(fontOwner, validator))
            {
                return(false); // the error is already reported
            }

            DIAction diaFilter =
                DIActionBuilder.DIA(this, "DIAFunc_Filter");
            FManager fm       = new FManager(i_IOGlyphs, null, null);
            int      numGlyph = fm.FNumGlyph;
            int      indGlyph;

            for (indGlyph = 0; indGlyph < numGlyph; indGlyph++)
            {
                try
                {
                    if ((indGlyph % 100) == 0)
                    {
                        validator.OnTableProgress("Validating glyph with index " + indGlyph + " (out of " + numGlyph + " glyphs)");
                    }
                    Glyph glyph = fm.GGet(indGlyph);
                    glyph.GValidate();
                    bRet &= fm.GErrGetInformed(indGlyph, diaFilter);
                    fm.ClearManagementStructs();
                }
                catch
                {
                    validator.Error(T.T_NULL, E.glyf_E_ExceptionUnhandeled, (OTTag)"glyf",
                                    "Glyph index " + indGlyph);
                }
                if (validator.CancelFlag)
                {
                    break;
                }
            }
            i_IOGlyphs.Clear();
            fm.ClearDestroy();
            fm = null;

/*
 *          I_ProgressUpdater i_ProgressUpdater=new ValidationCancel(validator);
 *
 *          FManager fm=new FManager(i_IOGlyphs, null, null);
 *          DIAction diaFilter=
 *              DIActionBuilder.DIA(this,"DIAFunc_Filter");
 *
 *          fm.GErrActionAdd(diaFilter,
 *              FManager.TypeActionOnErr.onAdd);
 *
 *
 *          fm.FValidate(GConsts.IND_UNINITIALIZED,
 *              GConsts.IND_UNINITIALIZED);
 *
 *          i_IOGlyphs.Clear();
 *          i_ProgressUpdater.Clear();
 *          fm.ClearDestroy();
 *          fm=null;
 */
            for (int iCnt = 0; iCnt < this.m_cnts.Length; iCnt++)
            {
                if (this.m_cnts[iCnt] > 0)
                {
                    bool   isGErr         = this.m_namesInfoCnt[iCnt].StartsWith("GERR_");
                    string nameFileErr    = isGErr? GErrConsts.FILE_RES_GERR_STRINGS: GErrConsts.FILE_RES_OTFFERR_STRINGS;
                    string nameAsmFileErr = isGErr? GErrConsts.ASM_RES_GERR_STRINGS: GErrConsts.ASM_RES_OTFFERR_STRINGS;
                    string strDetails     = "Number of glyphs with the warning = " + this.m_cnts[iCnt];
                    if (validator.CancelFlag)
                    {
                        strDetails += " (Validation cancelled)";
                    }
                    ValInfoBasic info = new ValInfoBasic(
                        ValInfoBasic.ValInfoType.Warning,
                        this.m_namesInfoCnt[iCnt],
                        strDetails,
                        nameFileErr,
                        nameAsmFileErr,
                        "glyf",
                        null);
                    validator.DIA(info);
                }
            }

            this.m_cnts = null;
            return(bRet);
        }
Ejemplo n.º 9
0
        /************************
         * public methods
         */


        public bool Validate(Validator v, OTFontVal fontOwner)
        {
            bool bRet = true;

            if (v.PerformTest(T.hhea_version))
            {
                if (TableVersionNumber.GetUint() == 0x00010000)
                {
                    v.Pass(T.hhea_version, P.hhea_P_version, m_tag);
                }
                else
                {
                    v.Error(T.hhea_version, E.hhea_E_version, m_tag, "0x" + TableVersionNumber.GetUint().ToString("x8"));
                    bRet = false;
                }
            }

            if (v.PerformTest(T.hhea_AscenderPositive))
            {
                if (Ascender <= 0)
                {
                    string s = "Ascender = " + Ascender;
                    v.Error(T.hhea_AscenderPositive, E.hhea_E_AscenderPositive, m_tag, s);
                    bRet = false;
                }
                else
                {
                    v.Pass(T.hhea_AscenderPositive, P.hhea_P_AscenderPositive, m_tag);
                }
            }

            if (v.PerformTest(T.hhea_DescenderNegative))
            {
                if (Descender >= 0)
                {
                    string s = "Descender = " + Descender;
                    v.Error(T.hhea_DescenderNegative, E.hhea_E_DescenderNegative, m_tag, s);
                    bRet = false;
                }
                else
                {
                    v.Pass(T.hhea_DescenderNegative, P.hhea_P_DescenderNegative, m_tag);
                }
            }

            Table_head headTable = (Table_head)fontOwner.GetTable("head");

            if (headTable != null)
            {
                if (v.PerformTest(T.hhea_Ascender_yMax))
                {
                    if (Ascender > headTable.yMax)
                    {
                        string s = "Ascender = " + Ascender + ", head.yMax = " + headTable.yMax;
                        v.Info(T.hhea_Ascender_yMax, I.hhea_I_Ascender_yMax, m_tag, s);
                        // bRet = false;
                    }
                    else
                    {
                        v.Pass(T.hhea_Ascender_yMax, P.hhea_P_Ascender_yMax, m_tag);
                    }
                }

                if (v.PerformTest(T.hhea_Descender_yMin))
                {
                    if (Descender < headTable.yMin)
                    {
                        string s = "Descender = " + Descender + ", head.yMin = " + headTable.yMin;
                        v.Info(T.hhea_Descender_yMin, I.hhea_I_Descender_yMin, m_tag, s);
                        // bRet = false;
                    }
                    else
                    {
                        v.Pass(T.hhea_Descender_yMin, P.hhea_P_Descender_yMin, m_tag);
                    }
                }
            }
            else
            {
                v.Error(T.hhea_Ascender_yMax, E._TEST_E_TableMissing, m_tag, "head");
                bRet = false;
            }

            if (v.PerformTest(T.hhea_LineGapPositive))
            {
                if (LineGap < 0)
                {
                    string s = "LineGap = " + LineGap;
                    v.Warning(T.hhea_LineGapPositive, W.hhea_W_LineGapPositive, m_tag, s);
                    //bRet = false;
                }
                else
                {
                    v.Pass(T.hhea_LineGapPositive, P.hhea_P_LineGapPositive, m_tag);
                }
            }

            Table_OS2 OS2Table = (Table_OS2)fontOwner.GetTable("OS/2");

            if (OS2Table != null)
            {
                if (v.PerformTest(T.hhea_Ascender_usWinAscent))
                {
                    if (OS2Table.usWinAscent != Ascender)
                    {
                        string s = "hhea.Ascender = " + Ascender + ", OS/2.usWinAscent = " + OS2Table.usWinAscent;
                        v.Warning(T.hhea_Ascender_usWinAscent, W.hhea_W_Ascender_usWinAscent, m_tag, s);
                    }
                    else
                    {
                        v.Pass(T.hhea_Ascender_usWinAscent, P.hhea_P_Ascender_usWinAscent, m_tag);
                    }
                }

                if (v.PerformTest(T.hhea_Descender_usWinDescent))
                {
                    if (OS2Table.usWinDescent != (Descender * -1))
                    {
                        string s = "hhea.Descender = " + Descender + ", OS/2.usWinDescent = " + OS2Table.usWinDescent;
                        v.Warning(T.hhea_Descender_usWinDescent, W.hhea_W_Descender_usWinDescent, m_tag, s);
                    }
                    else
                    {
                        v.Pass(T.hhea_Descender_usWinDescent, P.hhea_P_Descender_usWinDescent, m_tag);
                    }
                }

                // Microsoft is recommending that Ascender, Descender and LineGap be in line with OS2.winAscent, OS2.winDescent
                // and formulated value for LineGap to make sure font displays the same on Apple as it does no Windows.
                if (v.PerformTest(T.hhea_LineGap_minGap))
                {
                    int sMinGap = (OS2Table.usWinAscent + OS2Table.usWinDescent) - (Ascender - Descender);
                    if (LineGap < sMinGap)
                    {
                        string s = "LineGap = " + LineGap + ", recommended = " + sMinGap;
                        v.Warning(T.hhea_LineGap_minGap, W.hhea_W_LineGap_minGap, m_tag, s);
                        //bRet = false;
                    }
                    else
                    {
                        v.Pass(T.hhea_LineGap_minGap, P.hhea_P_LineGap_minGap, m_tag);
                    }
                }
                else
                {
                    v.Error(T.hhea_LineGap_minGap, E._TEST_E_TableMissing, m_tag, "OS/2");
                }
            }
            else
            {
                v.Error(T.hhea_Ascender_usWinAscent, E._TEST_E_TableMissing, m_tag, "OS/2");
                v.Error(T.hhea_Descender_usWinDescent, E._TEST_E_TableMissing, m_tag, "OS/2");
                v.Error(T.hhea_LineGap_minGap, E._TEST_E_TableMissing, m_tag, "OS/2");
                bRet = false;
            }

            if (v.PerformTest(T.hhea_MinMax))
            {
                if (fontOwner.ContainsTrueTypeOutlines())
                {
                    Table_hmtx hmtxTable = (Table_hmtx)fontOwner.GetTable("hmtx");
                    Table_glyf glyfTable = (Table_glyf)fontOwner.GetTable("glyf");
                    Table_maxp maxpTable = (Table_maxp)fontOwner.GetTable("maxp");
                    if (hmtxTable == null)
                    {
                        v.Error(T.hhea_MinMax, E._TEST_E_TableMissing, m_tag, "hmtx");
                        bRet = false;
                    }
                    else if (glyfTable == null)
                    {
                        v.Error(T.hhea_MinMax, E._TEST_E_TableMissing, m_tag, "glyf");
                        bRet = false;
                    }
                    else if (maxpTable == null)
                    {
                        v.Error(T.hhea_MinMax, E._TEST_E_TableMissing, m_tag, "maxp");
                        bRet = false;
                    }
                    else
                    {
                        ushort numGlyphs = fontOwner.GetMaxpNumGlyphs();

                        ushort awMax  = 0;
                        short  minLSB = 32767;
                        short  minRSB = 32767;
                        short  xmaxEx = -32768;

                        Table_hmtx.longHorMetric hm = null;

                        for (uint iGlyph = 0; iGlyph < numGlyphs; iGlyph++)
                        {
                            hm = hmtxTable.GetOrMakeHMetric(iGlyph, fontOwner);
                            if (hm == null)
                            {
                                break;
                            }

                            if (awMax < hm.advanceWidth)
                            {
                                awMax = hm.advanceWidth;

                                // We want to give the user feedback to know what glyph id
                                // has the bad width assigned
                                if (awMax > advanceWidthMax)
                                {
                                    string s = "glyph ID = " + iGlyph + ", advance width = " + awMax;
                                    v.Error(T.hhea_MinMax, E.hhea_E_advanceWidthMax, m_tag, s);
                                    bRet = false;
                                }
                            }

                            Table_glyf.header gh = glyfTable.GetGlyphHeader(iGlyph, fontOwner);
                            // calculate for all non-zero contours...this includes composites
                            if (gh != null &&
                                gh.numberOfContours != 0)
                            {
                                if (minLSB > hm.lsb)
                                {
                                    minLSB = hm.lsb;
                                }

                                short rsb = (short)(hm.advanceWidth - hm.lsb - (gh.xMax - gh.xMin));
                                if (minRSB > rsb)
                                {
                                    minRSB = rsb;
                                }

                                short extent = (short)(hm.lsb + (gh.xMax - gh.xMin));
                                if (xmaxEx < extent)
                                {
                                    xmaxEx = extent;
                                }
                            }
                        }


                        if (hm != null)
                        {
                            if (advanceWidthMax == awMax)
                            {
                                v.Pass(T.hhea_MinMax, P.hhea_P_advanceWidthMax, m_tag);
                            }
                            else
                            {
                                string s = "actual = " + advanceWidthMax + ", calc = " + awMax;
                                v.Error(T.hhea_MinMax, E.hhea_E_advanceWidthMax, m_tag, s);
                                bRet = false;
                            }

                            if (minLeftSideBearing == minLSB)
                            {
                                v.Pass(T.hhea_MinMax, P.hhea_P_minLeftSideBearing, m_tag);
                            }
                            else
                            {
                                string s = "actual = " + minLeftSideBearing + ", calc = " + minLSB;
                                v.Error(T.hhea_MinMax, E.hhea_E_minLeftSideBearing, m_tag, s);
                                bRet = false;
                            }

                            if (minRightSideBearing == minRSB)
                            {
                                v.Pass(T.hhea_MinMax, P.hhea_P_minRightSideBearing, m_tag);
                            }
                            else
                            {
                                string s = "actual = " + minRightSideBearing + ", calc = " + minRSB;
                                v.Error(T.hhea_MinMax, E.hhea_E_minRightSideBearing, m_tag, s);
                                bRet = false;
                            }

                            if (xMaxExtent == xmaxEx)
                            {
                                v.Pass(T.hhea_MinMax, P.hhea_P_xMaxExtent, m_tag);
                            }
                            else
                            {
                                string s = "actual = " + xMaxExtent + ", calc = " + xmaxEx;
                                v.Error(T.hhea_MinMax, E.hhea_E_xMaxExtent, m_tag, s);
                                bRet = false;
                            }
                        }
                        else
                        {
                            v.Warning(T.hhea_MinMax, W.hhea_W_hmtx_invalid, m_tag, "unable to parse hmtx table");
                        }
                    }
                }
                else
                {
                    v.Info(T.hhea_MinMax, I._TEST_I_NotForCFF, m_tag, "test = hhea_MinMax");
                }
            }

            if (v.PerformTest(T.hhea_reserved))
            {
                if (reserved1 != 0)
                {
                    v.Error(T.hhea_reserved, E.hhea_E_reserved1, m_tag, reserved1.ToString());
                    bRet = false;
                }
                else if (reserved2 != 0)
                {
                    v.Error(T.hhea_reserved, E.hhea_E_reserved2, m_tag, reserved2.ToString());
                    bRet = false;
                }
                else if (reserved3 != 0)
                {
                    v.Error(T.hhea_reserved, E.hhea_E_reserved3, m_tag, reserved3.ToString());
                    bRet = false;
                }
                else if (reserved4 != 0)
                {
                    v.Error(T.hhea_reserved, E.hhea_E_reserved4, m_tag, reserved4.ToString());
                    bRet = false;
                }
                else
                {
                    v.Pass(T.hhea_reserved, P.hhea_P_reserved, m_tag);
                }
            }

            if (v.PerformTest(T.hhea_metricDataFormat))
            {
                if (metricDataFormat == 0)
                {
                    v.Pass(T.hhea_metricDataFormat, P.hhea_P_metricDataFormat, m_tag);
                }
                else
                {
                    v.Error(T.hhea_metricDataFormat, E.hhea_E_metricDataFormat, m_tag, metricDataFormat.ToString());
                    bRet = false;
                }
            }

            if (v.PerformTest(T.hhea_numberOfHMetrics))
            {
                Table_hmtx hmtxTable = (Table_hmtx)fontOwner.GetTable("hmtx");
                Table_maxp maxpTable = (Table_maxp)fontOwner.GetTable("maxp");
                if (hmtxTable == null)
                {
                    v.Error(T.hhea_numberOfHMetrics, E._TEST_E_TableMissing, m_tag, "hmtx");
                    bRet = false;
                }
                else if (maxpTable == null)
                {
                    v.Error(T.hhea_numberOfHMetrics, E._TEST_E_TableMissing, m_tag, "maxp");
                    bRet = false;
                }
                else
                {
                    ushort numGlyphs = fontOwner.GetMaxpNumGlyphs();
                    if (numberOfHMetrics * 4 + (numGlyphs - numberOfHMetrics) * 2 == hmtxTable.GetLength())
                    {
                        v.Pass(T.hhea_numberOfHMetrics, P.hhea_P_numberOfHMetrics, m_tag);
                    }
                    else
                    {
                        v.Error(T.hhea_numberOfHMetrics, E.hhea_E_numberOfHMetrics, m_tag);
                        bRet = false;
                    }
                }
            }

            if (v.PerformTest(T.hhea_caretSlope))
            {
                bool bSlopeOk = true;

                Table_post postTable = (Table_post)fontOwner.GetTable("post");

                if (postTable != null)
                {
                    uint   ia           = postTable.italicAngle.GetUint();
                    double dItalicAngle = postTable.italicAngle.GetDouble();

                    if (ia == 0)
                    {
                        if (caretSlopeRun != 0)
                        {
                            v.Error(T.hhea_caretSlope, E.hhea_E_caretSlopeRunNonZero_italicAngle, m_tag);
                            bSlopeOk = false;
                            bRet     = false;
                        }
                    }
                    else
                    {
                        if (caretSlopeRun == 0)
                        {
                            v.Error(T.hhea_caretSlope, E.hhea_E_caretSlopeRunZero_italicAngle, m_tag);
                            bSlopeOk = false;
                            bRet     = false;
                        }
                        else
                        {
                            double dActualAngle = 90.0 + postTable.italicAngle.GetDouble();
                            double dhheaAngle   = (Math.Atan2(caretSlopeRise, caretSlopeRun)) * (180.0 / Math.PI);
                            if (Math.Abs(dActualAngle - dhheaAngle) >= 1.0)
                            {
                                string sDetails = "caretSlope Rise:Run = " + caretSlopeRise + ":" + caretSlopeRun +
                                                  " (" + (dhheaAngle - 90.0) + " degrees)" +
                                                  ", post.italicAngle = 0x" + ia.ToString("x8") +
                                                  " (" + postTable.italicAngle.GetDouble() + " degrees)";
                                v.Error(T.hhea_caretSlope, E.hhea_E_caretSlopeAngle_italicAngle, m_tag, sDetails);
                                bSlopeOk = false;
                                bRet     = false;
                            }
                        }
                    }
                }
                else
                {
                    v.Error(T.hhea_caretSlope, E._TEST_E_TableMissing, m_tag, "post table missing, can't compare caret slope to italicAngle");
                    bSlopeOk = false;
                    bRet     = false;
                }


                if (bSlopeOk)
                {
                    v.Pass(T.hhea_caretSlope, P.hhea_P_caretSlopeAngle_italicAngle, m_tag);
                }
            }

            return(bRet);
        }
Ejemplo n.º 10
0
        /************************
         * public methods
         */


        public bool Validate(Validator v, OTFontVal fontOwner)
        {
            bool bRet = true;


            if (v.PerformTest(T.head_TableLength))
            {
                if (m_bufTable.GetLength() == 54)
                {
                    v.Pass(T.head_TableLength, P.head_P_TableLength, m_tag);
                }
                else
                {
                    v.Error(T.head_TableLength, E.head_E_TableLength, m_tag, m_bufTable.GetLength().ToString());
                    bRet = false;
                }
            }

            if (v.PerformTest(T.head_TableVersion))
            {
                if (TableVersionNumber.GetUint() == 0x00010000)
                {
                    v.Pass(T.head_TableVersion, P.head_P_TableVersion, m_tag);
                }
                else
                {
                    v.Error(T.head_TableVersion, E.head_E_TableVersion, m_tag, "0x"+TableVersionNumber.GetUint().ToString("x8"));
                    bRet = false;
                }
            }

            if (v.PerformTest(T.head_fontRevision))
            {
                string sVersion = fontOwner.GetFontVersion();
                if (sVersion != null)
                {
                    if (sVersion.Length >= 11
                        && sVersion.StartsWith("Version ")
                        && Char.IsDigit(sVersion, 8))
                    {
                        string sVersionNum = sVersion.Substring(8);
                        bool bFoundDecPt = false;
                        int nLastDigitPos = 0;
                        for (int i=0; i<sVersionNum.Length; i++)
                        {
                            if (Char.IsDigit(sVersionNum, i))
                            {
                                nLastDigitPos = i;
                            }
                            else if (sVersionNum[i] == '.')
                            {
                                if (!bFoundDecPt)
                                {
                                    bFoundDecPt = true;
                                }
                                else
                                {
                                    break;
                                }
                            }
                            else
                            {
                                break;
                            }
                        }
                        double fVersion = Double.Parse(sVersionNum.Substring(0, nLastDigitPos+1));
                        double fRevision = fontRevision.GetDouble();

                        if (Math.Round(fVersion, 3) == Math.Round(fRevision, 3))
                        {
                            v.Pass(T.head_fontRevision, P.head_P_fontRevision, m_tag, fRevision.ToString("f3"));
                        }
                        else
                        {
                            string s = "revision: " + fRevision.ToString("f3") + ", version: " + sVersionNum;
                            v.Warning(T.head_fontRevision, W.head_W_fontRevision, m_tag, s);
                        }
                    }
                }
            }
            
            if (v.PerformTest(T.head_ChecksumAdjustment))
            {
                if (checkSumAdjustment == 0xb1b0afba - fontOwner.CalcChecksum())
                {
                    v.Pass(T.head_ChecksumAdjustment, P.head_P_FontChecksum, m_tag, "0x"+checkSumAdjustment.ToString("x8"));
                }
                else
                {
                    v.Error(T.head_ChecksumAdjustment, E.head_E_FontChecksum, m_tag, "0x"+checkSumAdjustment.ToString("x8"));
                    bRet = false;
                }
            }
            
            if (v.PerformTest(T.head_MagicNumber))
            {
                if (magicNumber == 0x5f0f3cf5)
                {
                    v.Pass(T.head_MagicNumber, P.head_P_MagicNumber, m_tag);
                }
                else
                {
                    v.Error(T.head_MagicNumber, E.head_E_MagicNumber, m_tag, "0x"+magicNumber.ToString("x8"));
                    bRet = false;
                }
            }
            
            if (v.PerformTest(T.head_FlagTests))
            {
                ushort val = flags;
                // bit 0 indicates baseline for font at y=0
                
                // bit 1 indicates left sidebearing point at x=0

                // bit 2 indicates instructions may depend on point size

                // bit 3 indicates forcing ppem to integer values instead of fractional values

                // bit 4 indicates non-linear scaling - if set allows presence of LTSH and/or hdmx tables
                Table_hdmx hdmxTable = (Table_hdmx)fontOwner.GetTable("hdmx");
                Table_LTSH LTSHTable = (Table_LTSH)fontOwner.GetTable("LTSH");
                if ((val & 0x0010) == 0)
                {
                    if (hdmxTable == null)
                    {
                        v.Pass(T.head_FlagTests, P.head_P_flags_bit4_0_hdmx, m_tag);
                    }
                    else
                    {
                        v.Error(T.head_FlagTests, E.head_E_flags_bit4_0_hdmx, m_tag);
                    }

                    if (LTSHTable == null)
                    {
                        v.Pass(T.head_FlagTests, P.head_P_flags_bit4_0_LTSH, m_tag);
                    }
                    else
                    {
                        v.Error(T.head_FlagTests, E.head_E_flags_bit4_0_LTSH, m_tag);
                    }
                }
                else
                {
                    if (hdmxTable != null)
                    {
                        v.Pass(T.head_FlagTests, P.head_P_flags_bit4_1_hdmx, m_tag);
                    }
                    else
                    {
                        v.Warning(T.head_FlagTests, W.head_W_flags_bit4_1_hdmx, m_tag);
                    }

                    if (LTSHTable != null)
                    {
                        v.Pass(T.head_FlagTests, P.head_P_flags_bit4_1_LTSH, m_tag);
                    }
                    else
                    {
                        v.Warning(T.head_FlagTests, W.head_W_flags_bit4_1_LTSH, m_tag);
                    }
                }

                // bits 5 - 10 are used by apple and ignored by windows

                // bit 11 indicates font data is 'lossless' as a result of having been compressed/decompressed

                // bit 12 indicates a converted font

                // bit 13 indicates optimized for cleartype

                // bit 14 reserved
                if ((val & 0x4000) == 0)
                {
                    v.Pass(T.head_FlagTests, P.head_P_flags_bit14, m_tag);
                }
                else
                {
                    v.Error(T.head_FlagTests, E.head_E_flags_bit14, m_tag, val.ToString());
                    bRet = false;
                }
                    
                // bit 15 reserved
                if ((val & 0x8000) == 0)
                {
                    v.Pass(T.head_FlagTests, P.head_P_flags_bit15, m_tag);
                }
                else
                {
                    v.Error(T.head_FlagTests, E.head_E_flags_bit15, m_tag, val.ToString());
                    bRet = false;
                }
            }
            
            if (v.PerformTest(T.head_UnitsPerEmValues))
            {
                ushort val = unitsPerEm;

                bool bInRange = false;

                if (val < 16) // opentype spec says min value is 16
                {
                    v.Error(T.head_UnitsPerEmValues, E.head_E_unitsPerEm_LT16, m_tag, val.ToString());
                    bRet = false;
                }
                else if (val < 64) // apple spec says min value is 64
                {
                    v.Warning(T.head_UnitsPerEmValues, W.head_W_unitsPerEM_LT64, m_tag, val.ToString());
                }
                else if (val > 16384)
                {
                    v.Error(T.head_UnitsPerEmValues, E.head_E_unitsPerEM_GT16384, m_tag, val.ToString());
                    bRet = false;
                }
                else
                {
                    bInRange = true;
                }

                // apple spec says unitsPerEm must be power of two
                // but don't check if it's a CFF font
                if (!fontOwner.ContainsPostScriptOutlines())
                {
                    bool bPowerOfTwo = false;
                    for (int i=0; i<16; i++)
                    {
                        ushort nPow2 = (ushort)(1<<i);
                        if (val == nPow2)
                        {
                            bPowerOfTwo = true;
                            break;
                        }
                    }
                    if (bPowerOfTwo)
                    {
                        if (bInRange)
                        {
                            v.Pass(T.head_UnitsPerEmValues, P.head_P_unitsPerEm, m_tag, val.ToString());
                        }
                    }
                    else
                    {
                        v.Warning(T.head_UnitsPerEmValues, W.head_W_unitsPerEm_Pow2, m_tag, val.ToString());
                    }
                }
            }
            
            if (v.PerformTest(T.head_Dates))
            {
                DateTime dtBeforeTrueType = new DateTime(1985, 1, 1);

                if ((created >> 32) == 0)
                {
                    DateTime dtCreated = this.GetCreatedDateTime();
                    if (created == 0)
                    {
                        v.Warning(T.head_Dates, W.head_W_created_0, m_tag);
                    }
                    else if (dtCreated < dtBeforeTrueType || dtCreated > DateTime.Now)
                    {
                        string sDetails = "created = " + created + " (" + dtCreated.ToString("f", null) + ")";
                        v.Warning(T.head_Dates, W.head_W_created_unlikely, m_tag, sDetails);
                    }
                    else
                    {
                        v.Pass(T.head_Dates, P.head_P_created_0, m_tag);
                    }
                }
                else
                {
                    string sDetails = "created = 0x" + created.ToString("x16");
                    v.Error(T.head_Dates, E.head_E_created_invalid, m_tag, sDetails);
                    bRet = false;
                }

                if ((modified >> 32) == 0)
                {
                    DateTime dtModified = this.GetModifiedDateTime();
                    if (modified == 0)
                    {
                        v.Warning(T.head_Dates, W.head_W_modified_0, m_tag);
                    }
                    else if (dtModified < dtBeforeTrueType || dtModified > DateTime.Now)
                    {
                        string sDetails = "modified = " + modified + " (" + dtModified.ToString("f", null) + ")";
                        v.Warning(T.head_Dates, W.head_W_modified_unlikely, m_tag, sDetails);
                    }
                    else
                    {
                        v.Pass(T.head_Dates, P.head_P_modified_0, m_tag);
                    }
                }
                else
                {
                    string sDetails = "modified = 0x" + modified.ToString("x16");
                    v.Error(T.head_Dates, E.head_E_modified_invalid, m_tag, sDetails);
                    bRet = false;
                }
            }
            
            if (v.PerformTest(T.head_MinMaxValues))
            {
                if (fontOwner.ContainsTrueTypeOutlines())
                {
                    if (xMin > xMax)
                    {
                        v.Error(T.head_MinMaxValues, E.head_E_xMin_GT_xMax, m_tag);
                        bRet = false;
                    }

                    if (yMin > yMax)
                    {
                        v.Error(T.head_MinMaxValues, E.head_E_yMin_GT_yMax, m_tag);
                        bRet = false;
                    }

                    short xMinExpected = 32767;
                    short xMaxExpected = -32768;
                    short yMinExpected = 32767;
                    short yMaxExpected = -32768;

                    Table_glyf glyfTable = (Table_glyf)fontOwner.GetTable("glyf");
                    if (glyfTable != null)
                    {
                        Table_maxp maxp = (Table_maxp)fontOwner.GetTable("maxp");
                        if (maxp != null)
                        {
                            for (uint i=0; i<fontOwner.GetMaxpNumGlyphs(); i++)
                            {
                                Table_glyf.header h = glyfTable.GetGlyphHeader(i, fontOwner);
                                if (h != null)
                                {
                                    if (xMinExpected > h.xMin) xMinExpected = h.xMin;
                                    if (xMaxExpected < h.xMax) xMaxExpected = h.xMax;
                                    if (yMinExpected > h.yMin) yMinExpected = h.yMin;
                                    if (yMaxExpected < h.yMax) yMaxExpected = h.yMax;
                                }
                            }

                            if (xMin == xMinExpected)
                            {
                                String s = "xMin = " + xMin;
                                v.Pass(T.head_MinMaxValues, P.head_P_xMin_glyf, m_tag, s);
                            }
                            else
                            {
                                string s = "actual: " + xMin + ", expected: " + xMinExpected;
                                v.Error(T.head_MinMaxValues, E.head_E_xMin_glyf, m_tag, s);
                                bRet = false;
                            }

                            if (yMin == yMinExpected)
                            {
                                String s = "yMin = " + yMin;
                                v.Pass(T.head_MinMaxValues, P.head_P_yMin_glyf, m_tag, s);
                            }
                            else
                            {
                                string s = "actual: " + yMin + ", expected: " + yMinExpected;
                                v.Error(T.head_MinMaxValues, E.head_E_yMin_glyf, m_tag, s);
                                bRet = false;
                            }

                            if (xMax == xMaxExpected)
                            {
                                String s = "xMax = " + xMax;
                                v.Pass(T.head_MinMaxValues, P.head_P_xMax_glyf, m_tag, s);
                            }
                            else
                            {
                                string s = "actual: " + xMax + ", expected: " + xMaxExpected;
                                v.Error(T.head_MinMaxValues, E.head_E_xMax_glyf, m_tag, s);
                                bRet = false;
                            }

                            if (yMax == yMaxExpected)
                            {
                                String s = "yMax = " + yMax;
                                v.Pass(T.head_MinMaxValues, P.head_P_yMax_glyf, m_tag, s);
                            }
                            else
                            {
                                string s = "actual: " + yMax + ", expected: " + yMaxExpected;
                                v.Error(T.head_MinMaxValues, E.head_E_yMax_glyf, m_tag, s);
                                bRet = false;
                            }
                        }
                        else
                        {
                            v.Error(T.head_MinMaxValues, E._TEST_E_TableMissing, m_tag, "maxp");
                        }
                    }
                    else
                    {
                        v.Error(T.head_MinMaxValues, E._TEST_E_TableMissing, m_tag, "glyf");
                    }
                }
                else
                {
                    v.Info(T.head_MinMaxValues, I._TEST_I_NotForCFF, m_tag, "test = head_MinMaxValues");
                }
            }
            
            if (v.PerformTest(T.head_MacStyleBits))
            {
                bool bMacBold = ((macStyle & 0x0001) != 0);
                bool bMacItal = ((macStyle & 0x0002) != 0);

                // subfamily (style) string

                Table_name nameTable = (Table_name)fontOwner.GetTable("name");
                string sStyle = null;
                string sStyleLower = null;
                if (nameTable != null)
                {
                    sStyle = nameTable.GetStyleString();
                    if (sStyle != null)
                    {
                        sStyleLower = sStyle.ToLower();
                    }
                }
                if (sStyleLower != null)
                {
                    if (bMacBold && sStyleLower.IndexOf("bold") == -1)
                    {
                        v.Error(T.head_MacStyleBits, E.head_E_macStyleBold_subfamily, m_tag, "macStyle bold bit is set, but subfamily is " + sStyle);
                        bRet = false;
                    }
                    else if (!bMacBold && sStyleLower.IndexOf("bold") != -1)
                    {
                        v.Error(T.head_MacStyleBits, E.head_E_macStyleBold_subfamily, m_tag, "macStyle bold bit is clear, but subfamily is " + sStyle);
                        bRet = false;
                    }
                    else
                    {
                        v.Pass(T.head_MacStyleBits, P.head_P_macStyleBold_subfamily, m_tag);
                    }

                    if (bMacItal && sStyleLower.IndexOf("italic") == -1 && sStyleLower.IndexOf("oblique") == -1)
                    {
                        v.Error(T.head_MacStyleBits, E.head_E_macStyleItal_subfamily, m_tag, "macStyle italic bit is set, but subfamily is " + sStyle);
                        bRet = false;
                    }
                    else if (!bMacItal && (sStyleLower.IndexOf("italic") != -1 || sStyleLower.IndexOf("oblique") != -1))
                    {
                        v.Error(T.head_MacStyleBits, E.head_E_macStyleItal_subfamily, m_tag, "macStyle italic bit is clear, but subfamily is " + sStyle);
                        bRet = false;
                    }
                    else
                    {
                        v.Pass(T.head_MacStyleBits, P.head_P_macStyleItal_subfamily, m_tag);
                    }
                }

                Table_OS2 OS2Table = (Table_OS2)fontOwner.GetTable("OS/2");
                if (OS2Table != null)
                {
                    // fsSelection

                    bool bOS2Bold = ((OS2Table.fsSelection & 0x0020) != 0);
                    bool bOS2Ital = ((OS2Table.fsSelection & 0x0001) != 0);

                    if (bMacBold == bOS2Bold)
                    {
                        v.Pass(T.head_MacStyleBits, P.head_P_macStyleBold_OS2, m_tag);
                    }
                    else if (bMacBold)
                    {
                        v.Error(T.head_MacStyleBits, E.head_E_macStyleBold1_OS2, m_tag);
                        bRet = false;
                    }
                    else
                    {
                        v.Error(T.head_MacStyleBits, E.head_E_macStyleBold0_OS2, m_tag);
                        bRet = false;
                    }

                    if (bMacItal == bOS2Ital)
                    {
                        v.Pass(T.head_MacStyleBits, P.head_P_macStyleItal_OS2, m_tag);
                    }
                    else if (bMacItal)
                    {
                        v.Error(T.head_MacStyleBits, E.head_E_macStyleItal1_OS2, m_tag);
                        bRet = false;
                    }
                    else
                    {
                        v.Error(T.head_MacStyleBits, E.head_E_macStyleItal0_OS2, m_tag);
                        bRet = false;
                    }
                }

                Table_post postTable = (Table_post)fontOwner.GetTable("post");

                if (postTable != null)
                {
                    bool bPostItal = (postTable.italicAngle.GetUint() != 0);


                    if (bMacItal == bPostItal)
                    {
                        v.Pass(T.head_MacStyleBits, P.head_P_macStyleItal_post, m_tag);
                    }
                    else if (bMacItal)
                    {
                        v.Error(T.head_MacStyleBits, E.head_E_macStyleItal1_post, m_tag);
                        bRet = false;
                    }
                    else
                    {
                        v.Error(T.head_MacStyleBits, E.head_E_macStyleItal0_post, m_tag);
                        bRet = false;
                    }
                }
            }
            
            if (v.PerformTest(T.head_LowestRecSize))
            {
                if (lowestRecPPEM == 0)
                {
                    v.Error(T.head_LowestRecSize, E.head_E_lowestRecPPEM_zero, m_tag);
                    bRet = false;
                }
                else if (lowestRecPPEM >= 1 && lowestRecPPEM <= 6)
                {
                    v.Warning(T.head_LowestRecSize, W.head_W_lowestRecPPEM_small, m_tag, "lowestRecPPEM = " + lowestRecPPEM.ToString());
                }
                else if (lowestRecPPEM >= 36)
                {
                    v.Warning(T.head_LowestRecSize, W.head_W_lowestRecPPEM_large, m_tag, "lowestRecPPEM = " + lowestRecPPEM.ToString());
                }
                else
                {
                    v.Pass(T.head_LowestRecSize, P.head_P_lowestRecPPEM, m_tag);
                }
            }
            
            if (v.PerformTest(T.head_FontDirectionHint))
            {
                if (fontDirectionHint >= -2 && fontDirectionHint <= 2)
                {
                    v.Pass(T.head_FontDirectionHint, P.head_P_fontDirectionHint, m_tag, fontDirectionHint.ToString());
                }
                else
                {
                    v.Error(T.head_FontDirectionHint, E.head_E_fontDirectionHint, m_tag, fontDirectionHint.ToString());
                    bRet = false;
                }
            }
            
            if (v.PerformTest(T.head_IndexToLocFormat))
            {
                if (fontOwner.ContainsPostScriptOutlines())
                {
                    v.Pass(T.head_IndexToLocFormat, P.head_P_indexToLocFormat_ignore, m_tag, "indexToLocFormat = " + indexToLocFormat);
                }
                else
                {
                    if (indexToLocFormat == 0 || indexToLocFormat == 1)
                    {
                        v.Pass(T.head_IndexToLocFormat, P.head_P_indexToLocFormat_range, m_tag, indexToLocFormat.ToString());
                    }
                    else
                    {
                        v.Error(T.head_IndexToLocFormat, E.head_E_indexToLocFormat_range, m_tag, indexToLocFormat.ToString());
                        bRet = false;
                    }

                    if (indexToLocFormat == 0 || indexToLocFormat == 1)
                    {
                        Table_loca locaTable = (Table_loca)fontOwner.GetTable("loca");
                        if (locaTable != null)
                        {
                            Table_maxp maxpTable = (Table_maxp)fontOwner.GetTable("maxp");
                            if (maxpTable != null)
                            {
                                uint locaTableElementSize = 0;
                                if (indexToLocFormat == 0)
                                    locaTableElementSize = 2;
                                else if (indexToLocFormat == 1)
                                    locaTableElementSize = 4;

                                uint CalcLocaLength = (uint)(maxpTable.NumGlyphs + 1) * locaTableElementSize;
                                if (CalcLocaLength == locaTable.GetLength())
                                {
                                    v.Pass(T.head_IndexToLocFormat, P.head_P_indexToLocFormat_match, m_tag, indexToLocFormat.ToString());
                                }
                                else
                                {
                                    v.Error(T.head_IndexToLocFormat, E.head_E_indexToLocFormat_match, m_tag, indexToLocFormat.ToString());
                                    bRet = false;
                                }
                            }
                            else
                            {
                                v.Error(T.head_IndexToLocFormat, E._TEST_E_TableMissing, m_tag, "maxp");
                            }
                        }
                        else
                        {
                            v.Error(T.head_IndexToLocFormat, E._TEST_E_TableMissing, m_tag, "loca");
                        }
                    }
                }
            }
            
            if (v.PerformTest(T.head_GlyphDataFormat))
            {
                if (glyphDataFormat == 0)
                {
                    v.Pass(T.head_GlyphDataFormat, P.head_P_glyphDataFormat, m_tag);
                }
                else
                {
                    v.Error(T.head_GlyphDataFormat, E.head_E_glyphDataFormat, m_tag);
                    bRet = false;
                }
            }

            return bRet;
        }
Ejemplo n.º 11
0
        /************************
         * public methods
         */


        public bool Validate(Validator v, OTFontVal fontOwner)
        {
            bool bRet = true;


            if (v.PerformTest(T.head_TableLength))
            {
                if (m_bufTable.GetLength() == 54)
                {
                    v.Pass(T.head_TableLength, P.head_P_TableLength, m_tag);
                }
                else
                {
                    v.Error(T.head_TableLength, E.head_E_TableLength, m_tag, m_bufTable.GetLength().ToString());
                    bRet = false;
                }
            }

            if (v.PerformTest(T.head_TableVersion))
            {
                if (TableVersionNumber.GetUint() == 0x00010000)
                {
                    v.Pass(T.head_TableVersion, P.head_P_TableVersion, m_tag);
                }
                else
                {
                    v.Error(T.head_TableVersion, E.head_E_TableVersion, m_tag, "0x" + TableVersionNumber.GetUint().ToString("x8"));
                    bRet = false;
                }
            }

            if (v.PerformTest(T.head_fontRevision))
            {
                string sVersion = fontOwner.GetFontVersion();
                if (sVersion != null)
                {
                    if (sVersion.Length >= 11 &&
                        sVersion.StartsWith("Version ") &&
                        Char.IsDigit(sVersion, 8))
                    {
                        string sVersionNum   = sVersion.Substring(8);
                        bool   bFoundDecPt   = false;
                        int    nLastDigitPos = 0;
                        for (int i = 0; i < sVersionNum.Length; i++)
                        {
                            if (Char.IsDigit(sVersionNum, i))
                            {
                                nLastDigitPos = i;
                            }
                            else if (sVersionNum[i] == '.')
                            {
                                if (!bFoundDecPt)
                                {
                                    bFoundDecPt = true;
                                }
                                else
                                {
                                    break;
                                }
                            }
                            else
                            {
                                break;
                            }
                        }
                        double fVersion  = Double.Parse(sVersionNum.Substring(0, nLastDigitPos + 1));
                        double fRevision = fontRevision.GetDouble();

                        if (Math.Round(fVersion, 3) == Math.Round(fRevision, 3))
                        {
                            v.Pass(T.head_fontRevision, P.head_P_fontRevision, m_tag, fRevision.ToString("f3"));
                        }
                        else
                        {
                            string s = "revision: " + fRevision.ToString("f3") + ", version: " + sVersionNum;
                            v.Warning(T.head_fontRevision, W.head_W_fontRevision, m_tag, s);
                        }
                    }
                }
            }

            if (v.PerformTest(T.head_ChecksumAdjustment))
            {
                if (checkSumAdjustment == 0xb1b0afba - fontOwner.CalcChecksum())
                {
                    v.Pass(T.head_ChecksumAdjustment, P.head_P_FontChecksum, m_tag, "0x" + checkSumAdjustment.ToString("x8"));
                }
                else
                {
                    v.Error(T.head_ChecksumAdjustment, E.head_E_FontChecksum, m_tag, "0x" + checkSumAdjustment.ToString("x8"));
                    bRet = false;
                }
            }

            if (v.PerformTest(T.head_MagicNumber))
            {
                if (magicNumber == 0x5f0f3cf5)
                {
                    v.Pass(T.head_MagicNumber, P.head_P_MagicNumber, m_tag);
                }
                else
                {
                    v.Error(T.head_MagicNumber, E.head_E_MagicNumber, m_tag, "0x" + magicNumber.ToString("x8"));
                    bRet = false;
                }
            }

            if (v.PerformTest(T.head_FlagTests))
            {
                ushort val = flags;
                // bit 0 indicates baseline for font at y=0

                // bit 1 indicates left sidebearing point at x=0

                // bit 2 indicates instructions may depend on point size

                // bit 3 indicates forcing ppem to integer values instead of fractional values

                // bit 4 indicates non-linear scaling - if set allows presence of LTSH and/or hdmx tables
                Table_hdmx hdmxTable = (Table_hdmx)fontOwner.GetTable("hdmx");
                Table_LTSH LTSHTable = (Table_LTSH)fontOwner.GetTable("LTSH");
                if ((val & 0x0010) == 0)
                {
                    if (hdmxTable == null)
                    {
                        v.Pass(T.head_FlagTests, P.head_P_flags_bit4_0_hdmx, m_tag);
                    }
                    else
                    {
                        v.Error(T.head_FlagTests, E.head_E_flags_bit4_0_hdmx, m_tag);
                    }

                    if (LTSHTable == null)
                    {
                        v.Pass(T.head_FlagTests, P.head_P_flags_bit4_0_LTSH, m_tag);
                    }
                    else
                    {
                        v.Error(T.head_FlagTests, E.head_E_flags_bit4_0_LTSH, m_tag);
                    }
                }
                else
                {
                    if (hdmxTable != null)
                    {
                        v.Pass(T.head_FlagTests, P.head_P_flags_bit4_1_hdmx, m_tag);
                    }
                    else
                    {
                        v.Warning(T.head_FlagTests, W.head_W_flags_bit4_1_hdmx, m_tag);
                    }

                    if (LTSHTable != null)
                    {
                        v.Pass(T.head_FlagTests, P.head_P_flags_bit4_1_LTSH, m_tag);
                    }
                    else
                    {
                        v.Warning(T.head_FlagTests, W.head_W_flags_bit4_1_LTSH, m_tag);
                    }
                }

                // bits 5 - 10 are used by apple and ignored by windows

                // bit 11 indicates font data is 'lossless' as a result of having been compressed/decompressed

                // bit 12 indicates a converted font

                // bit 13 indicates optimized for cleartype

                // bit 14 reserved
                if ((val & 0x4000) == 0)
                {
                    v.Pass(T.head_FlagTests, P.head_P_flags_bit14, m_tag);
                }
                else
                {
                    v.Error(T.head_FlagTests, E.head_E_flags_bit14, m_tag, val.ToString());
                    bRet = false;
                }

                // bit 15 reserved
                if ((val & 0x8000) == 0)
                {
                    v.Pass(T.head_FlagTests, P.head_P_flags_bit15, m_tag);
                }
                else
                {
                    v.Error(T.head_FlagTests, E.head_E_flags_bit15, m_tag, val.ToString());
                    bRet = false;
                }
            }

            if (v.PerformTest(T.head_UnitsPerEmValues))
            {
                ushort val = unitsPerEm;

                bool bInRange = false;

                if (val < 16) // opentype spec says min value is 16
                {
                    v.Error(T.head_UnitsPerEmValues, E.head_E_unitsPerEm_LT16, m_tag, val.ToString());
                    bRet = false;
                }
                else if (val < 64) // apple spec says min value is 64
                {
                    v.Warning(T.head_UnitsPerEmValues, W.head_W_unitsPerEM_LT64, m_tag, val.ToString());
                }
                else if (val > 16384)
                {
                    v.Error(T.head_UnitsPerEmValues, E.head_E_unitsPerEM_GT16384, m_tag, val.ToString());
                    bRet = false;
                }
                else
                {
                    bInRange = true;
                }

                // apple spec says unitsPerEm must be power of two
                // but don't check if it's a CFF font
                if (!fontOwner.ContainsPostScriptOutlines())
                {
                    bool bPowerOfTwo = false;
                    for (int i = 0; i < 16; i++)
                    {
                        ushort nPow2 = (ushort)(1 << i);
                        if (val == nPow2)
                        {
                            bPowerOfTwo = true;
                            break;
                        }
                    }
                    if (bPowerOfTwo)
                    {
                        if (bInRange)
                        {
                            v.Pass(T.head_UnitsPerEmValues, P.head_P_unitsPerEm, m_tag, val.ToString());
                        }
                    }
                    else
                    {
                        v.Warning(T.head_UnitsPerEmValues, W.head_W_unitsPerEm_Pow2, m_tag, val.ToString());
                    }
                }
            }

            if (v.PerformTest(T.head_Dates))
            {
                DateTime dtBeforeTrueType = new DateTime(1985, 1, 1);

                if ((created >> 32) == 0)
                {
                    DateTime dtCreated = this.GetCreatedDateTime();
                    string   sDetails  = "created = " + created + " (" + dtCreated.ToString("f", null) + ")";
                    if (created == 0)
                    {
                        v.Warning(T.head_Dates, W.head_W_created_0, m_tag);
                    }
                    else if (dtCreated < dtBeforeTrueType || dtCreated > DateTime.Now)
                    {
                        v.Warning(T.head_Dates, W.head_W_created_unlikely, m_tag, sDetails);
                    }
                    else
                    {
                        v.Pass(T.head_Dates, P.head_P_created_0, m_tag, sDetails);
                    }
                }
                else
                {
                    string sDetails = "created = 0x" + created.ToString("x16");
                    v.Error(T.head_Dates, E.head_E_created_invalid, m_tag, sDetails);
                    bRet = false;
                }

                if ((modified >> 32) == 0)
                {
                    DateTime dtModified = this.GetModifiedDateTime();
                    string   sDetails   = "modified = " + modified + " (" + dtModified.ToString("f", null) + ")";
                    if (modified == 0)
                    {
                        v.Warning(T.head_Dates, W.head_W_modified_0, m_tag);
                    }
                    else if (dtModified < dtBeforeTrueType || dtModified > DateTime.Now)
                    {
                        v.Warning(T.head_Dates, W.head_W_modified_unlikely, m_tag, sDetails);
                    }
                    else
                    {
                        v.Pass(T.head_Dates, P.head_P_modified_0, m_tag, sDetails);
                    }
                }
                else
                {
                    string sDetails = "modified = 0x" + modified.ToString("x16");
                    v.Error(T.head_Dates, E.head_E_modified_invalid, m_tag, sDetails);
                    bRet = false;
                }
            }

            if (v.PerformTest(T.head_MinMaxValues))
            {
                if (fontOwner.ContainsTrueTypeOutlines())
                {
                    if (xMin > xMax)
                    {
                        v.Error(T.head_MinMaxValues, E.head_E_xMin_GT_xMax, m_tag);
                        bRet = false;
                    }

                    if (yMin > yMax)
                    {
                        v.Error(T.head_MinMaxValues, E.head_E_yMin_GT_yMax, m_tag);
                        bRet = false;
                    }

                    short xMinExpected = 32767;
                    short xMaxExpected = -32768;
                    short yMinExpected = 32767;
                    short yMaxExpected = -32768;

                    Table_glyf glyfTable = (Table_glyf)fontOwner.GetTable("glyf");
                    if (glyfTable != null)
                    {
                        Table_maxp maxp = (Table_maxp)fontOwner.GetTable("maxp");
                        if (maxp != null)
                        {
                            for (uint i = 0; i < fontOwner.GetMaxpNumGlyphs(); i++)
                            {
                                Table_glyf.header h = glyfTable.GetGlyphHeader(i, fontOwner);
                                if (h != null)
                                {
                                    if (xMinExpected > h.xMin)
                                    {
                                        xMinExpected = h.xMin;
                                    }
                                    if (xMaxExpected < h.xMax)
                                    {
                                        xMaxExpected = h.xMax;
                                    }
                                    if (yMinExpected > h.yMin)
                                    {
                                        yMinExpected = h.yMin;
                                    }
                                    if (yMaxExpected < h.yMax)
                                    {
                                        yMaxExpected = h.yMax;
                                    }
                                }
                            }

                            if (xMin == xMinExpected)
                            {
                                String s = "xMin = " + xMin;
                                v.Pass(T.head_MinMaxValues, P.head_P_xMin_glyf, m_tag, s);
                            }
                            else
                            {
                                string s = "actual: " + xMin + ", expected: " + xMinExpected;
                                v.Error(T.head_MinMaxValues, E.head_E_xMin_glyf, m_tag, s);
                                bRet = false;
                            }

                            if (yMin == yMinExpected)
                            {
                                String s = "yMin = " + yMin;
                                v.Pass(T.head_MinMaxValues, P.head_P_yMin_glyf, m_tag, s);
                            }
                            else
                            {
                                string s = "actual: " + yMin + ", expected: " + yMinExpected;
                                v.Error(T.head_MinMaxValues, E.head_E_yMin_glyf, m_tag, s);
                                bRet = false;
                            }

                            if (xMax == xMaxExpected)
                            {
                                String s = "xMax = " + xMax;
                                v.Pass(T.head_MinMaxValues, P.head_P_xMax_glyf, m_tag, s);
                            }
                            else
                            {
                                string s = "actual: " + xMax + ", expected: " + xMaxExpected;
                                v.Error(T.head_MinMaxValues, E.head_E_xMax_glyf, m_tag, s);
                                bRet = false;
                            }

                            if (yMax == yMaxExpected)
                            {
                                String s = "yMax = " + yMax;
                                v.Pass(T.head_MinMaxValues, P.head_P_yMax_glyf, m_tag, s);
                            }
                            else
                            {
                                string s = "actual: " + yMax + ", expected: " + yMaxExpected;
                                v.Error(T.head_MinMaxValues, E.head_E_yMax_glyf, m_tag, s);
                                bRet = false;
                            }
                        }
                        else
                        {
                            v.Error(T.head_MinMaxValues, E._TEST_E_TableMissing, m_tag, "maxp");
                        }
                    }
                    else
                    {
                        v.Error(T.head_MinMaxValues, E._TEST_E_TableMissing, m_tag, "glyf");
                    }
                }
                else
                {
                    v.Info(T.head_MinMaxValues, I._TEST_I_NotForCFF, m_tag, "test = head_MinMaxValues");
                }
            }

            if (v.PerformTest(T.head_MacStyleBits))
            {
                bool bMacBold = ((macStyle & 0x0001) != 0);
                bool bMacItal = ((macStyle & 0x0002) != 0);

                // subfamily (style) string

                Table_name nameTable   = (Table_name)fontOwner.GetTable("name");
                string     sStyle      = null;
                string     sStyleLower = null;
                if (nameTable != null)
                {
                    sStyle = nameTable.GetStyleString();
                    if (sStyle != null)
                    {
                        sStyleLower = sStyle.ToLower();
                    }
                }
                if (sStyleLower != null)
                {
                    if (bMacBold && sStyleLower.IndexOf("bold") == -1)
                    {
                        v.Error(T.head_MacStyleBits, E.head_E_macStyleBold_subfamily, m_tag, "macStyle bold bit is set, but subfamily is " + sStyle);
                        bRet = false;
                    }
                    else if (!bMacBold && sStyleLower.IndexOf("bold") != -1)
                    {
                        v.Error(T.head_MacStyleBits, E.head_E_macStyleBold_subfamily, m_tag, "macStyle bold bit is clear, but subfamily is " + sStyle);
                        bRet = false;
                    }
                    else
                    {
                        v.Pass(T.head_MacStyleBits, P.head_P_macStyleBold_subfamily, m_tag);
                    }

                    if (bMacItal && sStyleLower.IndexOf("italic") == -1 && sStyleLower.IndexOf("oblique") == -1)
                    {
                        v.Error(T.head_MacStyleBits, E.head_E_macStyleItal_subfamily, m_tag, "macStyle italic bit is set, but subfamily is " + sStyle);
                        bRet = false;
                    }
                    else if (!bMacItal && (sStyleLower.IndexOf("italic") != -1 || sStyleLower.IndexOf("oblique") != -1))
                    {
                        v.Error(T.head_MacStyleBits, E.head_E_macStyleItal_subfamily, m_tag, "macStyle italic bit is clear, but subfamily is " + sStyle);
                        bRet = false;
                    }
                    else
                    {
                        v.Pass(T.head_MacStyleBits, P.head_P_macStyleItal_subfamily, m_tag);
                    }
                }

                Table_OS2 OS2Table = (Table_OS2)fontOwner.GetTable("OS/2");
                if (OS2Table != null)
                {
                    // fsSelection

                    bool bOS2Bold = ((OS2Table.fsSelection & 0x0020) != 0);
                    bool bOS2Ital = ((OS2Table.fsSelection & 0x0001) != 0);

                    if (bMacBold == bOS2Bold)
                    {
                        v.Pass(T.head_MacStyleBits, P.head_P_macStyleBold_OS2, m_tag);
                    }
                    else if (bMacBold)
                    {
                        v.Error(T.head_MacStyleBits, E.head_E_macStyleBold1_OS2, m_tag);
                        bRet = false;
                    }
                    else
                    {
                        v.Error(T.head_MacStyleBits, E.head_E_macStyleBold0_OS2, m_tag);
                        bRet = false;
                    }

                    if (bMacItal == bOS2Ital)
                    {
                        v.Pass(T.head_MacStyleBits, P.head_P_macStyleItal_OS2, m_tag);
                    }
                    else if (bMacItal)
                    {
                        v.Error(T.head_MacStyleBits, E.head_E_macStyleItal1_OS2, m_tag);
                        bRet = false;
                    }
                    else
                    {
                        v.Error(T.head_MacStyleBits, E.head_E_macStyleItal0_OS2, m_tag);
                        bRet = false;
                    }
                }

                Table_post postTable = (Table_post)fontOwner.GetTable("post");

                if (postTable != null)
                {
                    bool bPostItal = (postTable.italicAngle.GetUint() != 0);


                    if (bMacItal == bPostItal)
                    {
                        v.Pass(T.head_MacStyleBits, P.head_P_macStyleItal_post, m_tag);
                    }
                    else if (bMacItal)
                    {
                        v.Error(T.head_MacStyleBits, E.head_E_macStyleItal1_post, m_tag);
                        bRet = false;
                    }
                    else
                    {
                        v.Error(T.head_MacStyleBits, E.head_E_macStyleItal0_post, m_tag);
                        bRet = false;
                    }
                }
            }

            if (v.PerformTest(T.head_LowestRecSize))
            {
                if (lowestRecPPEM == 0)
                {
                    v.Error(T.head_LowestRecSize, E.head_E_lowestRecPPEM_zero, m_tag);
                    bRet = false;
                }
                else if (lowestRecPPEM >= 1 && lowestRecPPEM <= 6)
                {
                    v.Warning(T.head_LowestRecSize, W.head_W_lowestRecPPEM_small, m_tag, "lowestRecPPEM = " + lowestRecPPEM.ToString());
                }
                else if (lowestRecPPEM >= 36)
                {
                    v.Warning(T.head_LowestRecSize, W.head_W_lowestRecPPEM_large, m_tag, "lowestRecPPEM = " + lowestRecPPEM.ToString());
                }
                else
                {
                    v.Pass(T.head_LowestRecSize, P.head_P_lowestRecPPEM, m_tag);
                }
            }

            if (v.PerformTest(T.head_FontDirectionHint))
            {
                if (fontDirectionHint >= -2 && fontDirectionHint <= 2)
                {
                    v.Pass(T.head_FontDirectionHint, P.head_P_fontDirectionHint, m_tag, fontDirectionHint.ToString());
                }
                else
                {
                    v.Error(T.head_FontDirectionHint, E.head_E_fontDirectionHint, m_tag, fontDirectionHint.ToString());
                    bRet = false;
                }
            }

            if (v.PerformTest(T.head_IndexToLocFormat))
            {
                if (fontOwner.ContainsPostScriptOutlines())
                {
                    v.Pass(T.head_IndexToLocFormat, P.head_P_indexToLocFormat_ignore, m_tag, "indexToLocFormat = " + indexToLocFormat);
                }
                else
                {
                    if (indexToLocFormat == 0 || indexToLocFormat == 1)
                    {
                        v.Pass(T.head_IndexToLocFormat, P.head_P_indexToLocFormat_range, m_tag, indexToLocFormat.ToString());
                    }
                    else
                    {
                        v.Error(T.head_IndexToLocFormat, E.head_E_indexToLocFormat_range, m_tag, indexToLocFormat.ToString());
                        bRet = false;
                    }

                    if (indexToLocFormat == 0 || indexToLocFormat == 1)
                    {
                        Table_loca locaTable = (Table_loca)fontOwner.GetTable("loca");
                        if (locaTable != null)
                        {
                            Table_maxp maxpTable = (Table_maxp)fontOwner.GetTable("maxp");
                            if (maxpTable != null)
                            {
                                uint locaTableElementSize = 0;
                                if (indexToLocFormat == 0)
                                {
                                    locaTableElementSize = 2;
                                }
                                else if (indexToLocFormat == 1)
                                {
                                    locaTableElementSize = 4;
                                }

                                uint CalcLocaLength = (uint)(maxpTable.NumGlyphs + 1) * locaTableElementSize;
                                if (CalcLocaLength == locaTable.GetLength())
                                {
                                    v.Pass(T.head_IndexToLocFormat, P.head_P_indexToLocFormat_match, m_tag, indexToLocFormat.ToString());
                                }
                                else
                                {
                                    v.Error(T.head_IndexToLocFormat, E.head_E_indexToLocFormat_match, m_tag, indexToLocFormat.ToString());
                                    bRet = false;
                                }
                            }
                            else
                            {
                                v.Error(T.head_IndexToLocFormat, E._TEST_E_TableMissing, m_tag, "maxp");
                            }
                        }
                        else
                        {
                            v.Error(T.head_IndexToLocFormat, E._TEST_E_TableMissing, m_tag, "loca");
                        }
                    }
                }
            }

            if (v.PerformTest(T.head_GlyphDataFormat))
            {
                if (glyphDataFormat == 0)
                {
                    v.Pass(T.head_GlyphDataFormat, P.head_P_glyphDataFormat, m_tag);
                }
                else
                {
                    v.Error(T.head_GlyphDataFormat, E.head_E_glyphDataFormat, m_tag);
                    bRet = false;
                }
            }

            return(bRet);
        }
Ejemplo n.º 12
0
        /************************
         * public methods
         */


        public bool Validate(Validator v, OTFontVal fontOwner)
        {
            string sDetails = "";

            string [] Apple_Tables =
            {
                "acnt", "avar", "bdat", "bhed", "bloc", "bsln", "cmap", "cvar", "cvt ",
                "EBSC", "fdsc", "feat", "fmtx", "fpgm", "gasp", "glyf", "gvar", "hdmx",
                "head", "hhea", "hmtx", "hsty", "just", "kern", "lcar", "loca", "maxp",
                "mort", "morx", "name", "opbd", "OS/2", "post", "prep", "prop", "trak",
                "vhea", "vmtx", "Zapf"
            };

            string [] VOLT_only_Tables =
            {
                "TSIV"
            };

            string [] VOLT_VTT_shared_Tables =
            {
                "TSIS", "TSIP", "TSID"
            };

            string [] VTT_only_Tables =
            {
                "TSI0", "TSI1", "TSI2", "TSI3", "TSI4", "TSI5", "TSIJ", "TSIB"
            };

            bool bIdentified = false;

            for (int i = 0; i < Apple_Tables.Length; i++)
            {
                if (Apple_Tables[i] == (string)m_tag)
                {
                    sDetails    = "This table type is defined in the Apple TrueType spec.";
                    bIdentified = true;
                }
            }

            if (!bIdentified)
            {
                for (int i = 0; i < VOLT_only_Tables.Length; i++)
                {
                    if (VOLT_only_Tables[i] == (string)m_tag)
                    {
                        sDetails    = "This table type is used by the VOLT tool.";
                        bIdentified = true;
                    }
                }
            }

            if (!bIdentified)
            {
                for (int i = 0; i < VOLT_VTT_shared_Tables.Length; i++)
                {
                    if (VOLT_VTT_shared_Tables[i] == (string)m_tag)
                    {
                        sDetails    = "This table type is used by the VOLT tool and the VTT tool.";
                        bIdentified = true;
                    }
                }
            }

            if (!bIdentified)
            {
                for (int i = 0; i < VTT_only_Tables.Length; i++)
                {
                    if (VTT_only_Tables[i] == (string)m_tag)
                    {
                        sDetails    = "This table type is used by the VTT tool.";
                        bIdentified = true;
                    }
                }
            }

            v.Info(T.T_NULL, I._Table_I_Non_OT_Table, m_tag, sDetails);

            // Since there is no way to do any validation on unknown tables
            // always return true

            return(true);
        }
Ejemplo n.º 13
0
        /*****************
        * protected methods
        */

        /*****************
         * public methods
         */

        //meant to avoid code repetition (is called from OTFontVal too)
        public bool ValidateTable(OTTable table, Validator v, DirectoryEntry de, OTFontVal fontOwner)
        {
            String tname = GetTableManager().GetUnaliasedTableName(de.tag);
            bool bRet = true;

            // verify the checksum value from the directory entry matches the checksum for the table
            if (!(tname == "DSIG" && IsCollection()))
            {
                uint calcChecksum = 0;
                if (table != null)
                {
                    calcChecksum = table.CalcChecksum();
                }

                if (de.checkSum != calcChecksum)
                {
                    string s = "table '" + de.tag + "', calc: 0x" + calcChecksum.ToString("x8") + ", font: 0x" + de.checkSum.ToString("x8");
                    v.Error(T.T_NULL, E._DE_E_ChecksumError, de.tag, s);
                    bRet = false;
                }
            }

            // verify that table has pad bytes set to zero
            if (table != null)
            {
                uint nBytes = GetNumPadBytesAfterTable(table);

                bool bPadBytesZero = true;

                if (nBytes != 0)
                {
                    long PadFilePos = table.GetBuffer().GetFilePos() + table.GetBuffer().GetLength();
                    byte[] padbuf = ReadBytes(PadFilePos, nBytes);
                    for (int iByte = 0; iByte < padbuf.Length; iByte++)
                    {
                        if (padbuf[iByte] != 0)
                        {
                            bPadBytesZero = false;
                            break;
                        }
                    }

                }

                if (bPadBytesZero == false)
                {
                    v.Warning(T.T_NULL, W._DE_W_PadBytesNotZero, de.tag, "after " + de.tag + " table");
                }
            }

            // ask the table object to validate its data
            if (!(tname == "DSIG" && IsCollection())) v.OnTableValidationEvent(de, true);
            if (table != null)
            {
                if (v.TestTable(de.tag)) // don't test deselected tables
                {
                    try
                    {
                        ITableValidate valtable = (ITableValidate)table;
                        bRet &= valtable.Validate(v, fontOwner);
                    }
                    catch (InvalidCastException e)
                    {
                        v.ApplicationError(T.T_NULL, E._Table_E_Exception, table.m_tag, e.ToString());
                        bRet = false;
                    }
                }
                else
                {
                    v.Info(I._Table_I_NotSelected, de.tag);
                }
            }
            else
            {
                if (de.length == 0)
                {
                    // check if it's a known OT table type since zero length private tables seem allowable
                    if (TableManager.IsKnownOTTableType(de.tag))
                    {
                        v.Error(T.T_NULL, E._Table_E_Invalid, de.tag, "The directory entry length is zero");
                        bRet = false;
                    }
                }
                else if (de.offset == 0)
                {
                    v.Error(T.T_NULL, E._Table_E_Invalid, de.tag, "The directory entry offset is zero");
                    bRet = false;
                }
                else if (de.offset > GetFileLength())
                {
                    v.Error(T.T_NULL, E._Table_E_Invalid, de.tag, "The table offset points past end of file");
                    bRet = false;
                }
                else if (de.offset + de.length > GetFileLength())
                {
                    v.Error(T.T_NULL, E._Table_E_Invalid, de.tag, "The table extends past end of file");
                    bRet = false;
                }
                else
                {
                    v.Error(E._Table_E_Invalid, de.tag);
                    bRet = false;
                }
            }
            if (!(tname == "DSIG" && IsCollection())) v.OnTableValidationEvent(de, false);

            return bRet;

        }
Ejemplo n.º 14
0
        /************************
         * public methods
         */


        public bool Validate(Validator v, OTFontVal fontOwner)
        {
            bool bRet = true;

            if (v.PerformTest(T.maxp_TableVersion))
            {
                uint val = TableVersionNumber.GetUint();

                Table_CFF  CFFTable  = (Table_CFF)  fontOwner.GetTable("CFF ");
                Table_glyf glyfTable = (Table_glyf) fontOwner.GetTable("glyf");

                if (val == 0x00005000)
                {
                    if (CFFTable != null && glyfTable == null)
                    {
                        v.Pass(T.maxp_TableVersion, P.maxp_P_VERSION_0_5, m_tag);
                    }
                    else if (CFFTable == null)
                    {
                        v.Error(T.maxp_TableVersion, E.maxp_E_VERSION_0_5_NOCFF, m_tag);
                        bRet = false;
                    }
                    else if (glyfTable != null)
                    {
                        v.Error(T.maxp_TableVersion, E.maxp_E_VERSION_0_5_glyf, m_tag);
                        bRet = false;
                    }
                }
                else if (val == 0x00010000)
                {
                    if (CFFTable == null && glyfTable != null)
                    {
                        v.Pass(T.maxp_TableVersion, P.maxp_P_VERSION_1_0, m_tag);
                    }
                    else if (glyfTable == null)
                    {
                        v.Error(T.maxp_TableVersion, E.maxp_E_VERSION_1_0_NOglyf, m_tag);
                        bRet = false;
                    }
                    else if (CFFTable != null)
                    {
                        v.Error(T.maxp_TableVersion, E.maxp_E_VERSION_1_0_CFF, m_tag);
                        bRet = false;
                    }
                }
                else
                {
                    v.Error(T.maxp_TableVersion, E.maxp_E_VERSION_INVALID, m_tag, "0x"+val.ToString("x8"));
                    bRet = false;
                }
            }

            if (v.PerformTest(T.maxp_TableLength))
            {
                uint val = TableVersionNumber.GetUint();

                if (val == 0x00005000)
                {
                    if (m_bufTable.GetLength() == 6)
                    {
                        v.Pass(T.maxp_TableLength, P.maxp_P_LENGTH_0_5, m_tag);
                    }
                    else
                    {
                        v.Error(T.maxp_TableLength, E.maxp_E_LENGTH_0_5, m_tag, m_bufTable.GetLength().ToString());
                        bRet = false;
                    }
                }
                else if (val == 0x00010000)
                {
                    if (m_bufTable.GetLength() == 32)
                    {
                        v.Pass(T.maxp_TableLength, P.maxp_P_LENGTH_1_0, m_tag);
                    }
                    else
                    {
                        v.Error(T.maxp_TableLength, E.maxp_E_LENGTH_1_0, m_tag, m_bufTable.GetLength().ToString());
                        bRet = false;
                    }
                }
            }

            if (v.PerformTest(T.maxp_NumGlyphsMatchLoca))
            {
                if (TableVersionNumber.GetUint() == 0x00010000)
                {
                    Table_loca locaTable = (Table_loca)fontOwner.GetTable("loca");
                    if (locaTable != null)
                    {
                        // locaTable.NumEntry returns (-1) on failure
                        if (locaTable.NumEntry(fontOwner) == NumGlyphs+1)
                        {
                            v.Pass(T.maxp_NumGlyphsMatchLoca, P.maxp_P_NumGlyphsMatchLoca, m_tag, "numGlyphs = " + NumGlyphs);
                        }
                        else
                        {
                            v.Error(T.maxp_NumGlyphsMatchLoca, E.maxp_E_NumGlyphsMatchLoca, m_tag, "numGlyphs = " + NumGlyphs);
                            bRet = false;
                        }
                    }
                    else
                    {
                        v.Error(T.maxp_NumGlyphsMatchLoca, E._TEST_E_TableMissing, m_tag, "loca");
						bRet = false;
                    }
                }
                else
                {
                    v.Info(T.maxp_NumGlyphsMatchLoca, I._TEST_I_TableVersion, m_tag, "test = maxp_NumGlyphsMatchLoca");
                }
            }

            if (v.PerformTest(T.maxp_GlyphStats))
            {
                if (TableVersionNumber.GetUint() == 0x00010000)
                {
                    Table_glyf glyfTable = (Table_glyf) fontOwner.GetTable("glyf");

                    if (glyfTable == null)
                    {
                        v.Error(T.maxp_GlyphStats, E._TEST_E_TableMissing, m_tag, "glyf");
						bRet = false;
                    }
                    else
                    {

                        bool bGlyphStatsOk = true;

                        if (ComputeMaxpStats(glyfTable, fontOwner))
                        {

                            if (maxPoints != maxPointsCalc)
                            {
                                String sDetails = "maxPoints = " + maxPoints + ", calculated = " + maxPointsCalc;
                                v.Error(T.maxp_GlyphStats, E.maxp_E_Calculation, m_tag, sDetails);
                                bRet = false;
                                bGlyphStatsOk = false;
                            }

                            if (maxContours != maxContoursCalc)
                            {
                                String sDetails = "maxContours = " + maxContours + ", calculated = " + maxContoursCalc;
                                v.Error(T.maxp_GlyphStats, E.maxp_E_Calculation, m_tag, sDetails);
                                bRet = false;
                                bGlyphStatsOk = false;
                            }

                            if (maxCompositePoints != maxCompositePointsCalc)
                            {
                                String sDetails = "maxCompositePoints = " + maxCompositePoints + ", calculated = " + maxCompositePointsCalc;
                                v.Error(T.maxp_GlyphStats, E.maxp_E_Calculation, m_tag, sDetails);
                                bRet = false;
                                bGlyphStatsOk = false;
                            }

                            if (maxCompositeContours != maxCompositeContoursCalc)
                            {
                                String sDetails = "maxCompositeContours = " + maxCompositeContours + ", calculated = " + maxCompositeContoursCalc;
                                v.Error(T.maxp_GlyphStats, E.maxp_E_Calculation, m_tag, sDetails);
                                bRet = false;
                                bGlyphStatsOk = false;
                            }

                            // Bug 2168.
                            // Case 1: Same as max size from glyf table. Info.
                            // Case 2: Same as max size from glyf table + 
                            //         size(fpgm) + size(prep). Info message.
                            // Case 3: Smaller than max size from glyf table. 
                            //         Error
                            // Case 4: Neither 1 nor 2. Warning.
                            DirectoryEntry dePrep = 
                                fontOwner.GetDirectoryEntry("prep" );
                            uint prepLength = 0;
                            if ( null != dePrep ) {
                                prepLength = dePrep.length;
                            }
                            DirectoryEntry deFpgm = 
                                fontOwner.GetDirectoryEntry("fpgm" );
                            uint fpgmLength = 0;
                            if ( null != deFpgm ) {
                                fpgmLength = deFpgm.length;
                            }

                            if ( maxSizeOfInstructions == 
                                 maxSizeOfInstructionsCalc ) {
                                // Case 1:
                                String sDetails = "maxSizeOfInstructions=" +
                                    maxSizeOfInstructions + ", computed " +
                                    "from the glyf table";
                                v.Info( T.maxp_GlyphStats,
                                        I.maxp_I_Calculation_Method1,
                                        m_tag, sDetails);
                            }
                            else if ( maxSizeOfInstructions ==  
                                      ( maxSizeOfInstructionsCalc + 
                                        prepLength + fpgmLength ) ) {
                                // Case 2:
                                String sDetails = 
                                    "maxp maxSizeOfInstructions is " + 
                                    maxSizeOfInstructions + ", which is " +
                                    "glyf maxSizeOfInstructions (" + 
                                    maxSizeOfInstructionsCalc + 
                                    ") + prep size (" + prepLength + 
                                    ") + fpgm size (" + fpgmLength + ")";
                                v.Info( T.maxp_GlyphStats, 
                                        I.maxp_I_Calculation_Method2, 
                                        m_tag, sDetails);
                            }
                            else if ( maxSizeOfInstructions < 
                                      maxSizeOfInstructionsCalc ) {
                                // Case 3
                                String sDetails = 
                                    "maxp maxSizeOfInstructions is " + 
                                    maxSizeOfInstructions + 
                                    ", which is smaller than the " + 
                                    "size of instuctions (" + 
                                    maxSizeOfInstructionsCalc + ") found" +
                                    " for some glyph in the glyf table.";
                                v.Error( T.maxp_GlyphStats, 
                                         E.maxp_E_Calculation, m_tag, 
                                         sDetails);
                                bRet = false;
                            }
                            else {
                                // Case 4
                                String sDetails = 
                                    "glyf maxSizeOfInstructions=" + 
                                    maxSizeOfInstructionsCalc + 
                                    ", prep size=" + prepLength + 
                                    ", fpgm size=" + fpgmLength + 
                                    ", whereas maxp maxSizeOfInstruction " +
                                    "is " + maxSizeOfInstructions;
                                v.Warning(T.maxp_GlyphStats, 
                                          W.maxp_W_Calculation_Unclear, 
                                          m_tag, 
                                          sDetails);
                                bGlyphStatsOk = false;
                            }

                            if (maxComponentElements != maxComponentElementsCalc)
                            {
                                String sDetails = "maxComponentElements = " + maxComponentElements + ", calculated = " + maxComponentElementsCalc;
                                v.Error(T.maxp_GlyphStats, E.maxp_E_Calculation, m_tag, sDetails);
                                bRet = false;
                                bGlyphStatsOk = false;
                            }

                            if (maxComponentDepth != maxComponentDepthCalc)
                            {
                                String sDetails = "maxComponentDepth = " + maxComponentDepth + ", calculated = " + maxComponentDepthCalc;
                                v.Error(T.maxp_GlyphStats, E.maxp_E_Calculation, m_tag, sDetails);
                                bRet = false;
                                bGlyphStatsOk = false;
                            }

                            if (bGlyphStatsOk)
                            {
                                v.Pass(T.maxp_GlyphStats, P.maxp_P_Calculation, m_tag);
                            }
                        }
                        else
                        {
                            v.Warning(T.maxp_GlyphStats, W._TEST_W_ErrorInAnotherTable, m_tag, "Errors in the glyf table are preventing validation of maxPoints, maxContours, maxCompositePoints, maxCompositeContours, maxSizeofInstructions, maxComponentElements, and maxComponentDepth");
                        }
                    }
                }
                else
                {
                    v.Info(T.maxp_GlyphStats, I._TEST_I_TableVersion, m_tag, "test = maxp_GlyphStats");
                }
            }

            return bRet;
        }
Ejemplo n.º 15
0
 private bool CheckNames( Validator v,
                          OTFontVal fontOwner,
                          PostNames pn,
                          uint iGlyph,
                          uint index )
 {
     bool bNamesOk = true;
     string sName = GetNameString(index-258);
     System.Globalization.NumberStyles hexStyle = 
         System.Globalization.NumberStyles.HexNumber;
     if (Is_uniXXXX(sName))
     {
         char c = (char)Int16.Parse(sName.Substring(3, 4), hexStyle );
         if (fontOwner.FastMapUnicodeToGlyphID(c) != iGlyph)
         {
             char cMapped = fontOwner.MapGlyphIDToUnicode(iGlyph,(char)0);
             string s = "glyph = " + iGlyph +
                 ", char = U+" + 
                 ((uint)cMapped).ToString("X4")
                 + ", name = " + sName;
             v.Info(T.post_v2_names, 
                    I.post_I_names_uni_unexpected, 
                    m_tag, s);
             bNamesOk = false;
         }
     }
     else if (Is_uXXXXX(sName))
     {
         uint c = (uint)Int32.Parse(sName.Substring(1), hexStyle );
         if (c < 0xffff)
         {
             if (fontOwner.FastMapUnicodeToGlyphID((char)c) != iGlyph)
             {
                 char cMapped = fontOwner.MapGlyphIDToUnicode(iGlyph, 
                                                              (char)0);
                 string s = "glyph = " + iGlyph + ", char = U+" +
                     ((uint)cMapped).ToString("X4") + ", name = " + sName;
                 v.Info(T.post_v2_names, I.post_I_names_uni_unexpected, 
                        m_tag, s);
                 bNamesOk = false;
             }
         }
         else
         {
             if (fontOwner.FastMapUnicode32ToGlyphID(c) != iGlyph)
             {
                 uint cMapped = 
                     fontOwner.MapGlyphIDToUnicode32(iGlyph, 0);
                 string s = "glyph = " + iGlyph + ", char = U+" + 
                     ((uint)cMapped).ToString("X5") + ", name = " + sName;
                 v.Info(T.post_v2_names, I.post_I_names_uni_unexpected, 
                        m_tag, s);
                 bNamesOk = false;
             }
         }
     }
     else
     {
         // check the Adobe Glyph Names
         
         char c = (char)fontOwner.MapGlyphIDToUnicode(iGlyph, (char)0);
         if (c != 0xffff)
         {
             string sAdobeName = pn.GetAdobeGlyphName(c);
             if (sAdobeName == null)
             {
                 string s = "glyph = " + iGlyph + ", char = U+" + 
                     ((uint)c).ToString("X4") + ", name = " + sName;
                 v.Info(T.post_v2_names, I.post_I_names_noAdobe, m_tag,s);
                 bNamesOk = false;
             }
             else if (sName != sAdobeName)
             {
                 string s = "glyph = " + iGlyph + ", char = U+" + 
                     ((uint)c).ToString("X4") + ", name = " + sName;
                 v.Info(T.post_v2_names, I.post_I_names_nomatch, m_tag,s);
                 bNamesOk = false;
             }
         }
     }
     return bNamesOk;
 }
Ejemplo n.º 16
0
        /************************
         * public methods
         */


        public bool Validate(Validator v, OTFontVal fontOwner)
        {
            bool bRet = true;

            if (v.PerformTest(T.post_TableLength))
            {
                bool bLenOk = true;

                if (Version.GetUint() == 0x00010000 ||
                    Version.GetUint() == 0x00030000)
                {
                    if (GetLength() != 32)
                    {
                        v.Error(T.post_TableLength, E.post_E_TableLenNot32, m_tag);
                        bLenOk = false;
                        bRet = false;
                    }
                }
                if (Version.GetUint() == 0x00020000)
                {
                    if (GetLength() < 34)
                    {
                        v.Error(T.post_TableLength, E.post_E_InvalidTableLen, m_tag);
                        bLenOk = false;
                        bRet = false;
                    }
                }

                if (bLenOk)
                {
                    v.Pass(T.post_TableLength, P.post_P_TableLength, m_tag);
                }
            }

            if (v.PerformTest(T.post_Version))
            {
                uint ver = Version.GetUint();
                if (ver == 0x00025000)
                {
                    v.Warning(T.post_Version, W.post_W_Version_2_5, m_tag);
                }
                else if (ver == 0x00010000 || ver == 0x00020000 || ver == 0x00030000)
                {
                    v.Pass(T.post_Version, P.post_P_Version, m_tag);
                }
                else
                {
                    v.Error(T.post_Version, E.post_E_Version, m_tag, "0x"+ver.ToString("x8"));
                }
            }

            if (v.PerformTest(T.post_italicAngle))
            {
                bool bItalOk = true;

                uint ia = italicAngle.GetUint();
                double dItalicAngle = italicAngle.GetDouble();

                if (dItalicAngle < -30.0 || dItalicAngle > 360.0 || (dItalicAngle > 0.0 && dItalicAngle < 330.0 ))
                {
                    v.Warning(T.post_italicAngle, W.post_W_italicAngle_unlikely, m_tag, "0x"+ia.ToString("x8"));
                    bItalOk = false;
                }

                Table_head headTable = (Table_head)fontOwner.GetTable("head");
                if (headTable != null)
                {
                    if ((headTable.macStyle & 0x0002) != 0)
                    {
                        if (ia == 0)
                        {
                            v.Error(T.post_italicAngle, E.post_E_italicAngleZero_macStyle, m_tag);
                            bItalOk = false;
                            bRet = false;
                        }
                    }
                    else
                    {
                        if (ia != 0)
                        {
                            v.Error(T.post_italicAngle, E.post_E_italicAngleNonzero_macStyle, m_tag);
                            bItalOk = false;
                            bRet = false;
                        }
                    }
                }
                else
                {
                    v.Error(T.post_italicAngle, E._TEST_E_TableMissing, m_tag, "head table missing, can't compare italicAngle to head.macStyle");
                    bItalOk = false;
                }

                Table_hhea hheaTable = (Table_hhea)fontOwner.GetTable("hhea");
                if (hheaTable != null)
                {
                    if (ia == 0)
                    {
                        if (hheaTable.caretSlopeRun != 0)
                        {
                            v.Error(T.post_italicAngle, E.post_E_italicAngleZero_caretSlopeRun, m_tag);
                            bItalOk = false;
                            bRet = false;
                        }
                    }
                    else
                    {
                        if (hheaTable.caretSlopeRun == 0)
                        {
                            v.Error(T.post_italicAngle, E.post_E_italicAngleNonzero_caretSlopeRun, m_tag);
                            bItalOk = false;
                            bRet = false;
                        }
                        else
                        {
                            double dActualAngle = 90.0 + italicAngle.GetDouble();
                            double dhheaAngle = (Math.Atan2(hheaTable.caretSlopeRise, hheaTable.caretSlopeRun)) * (180.0 / Math.PI);
                            if (Math.Abs(dActualAngle-dhheaAngle) >= 1.0)
                            {
                                string sDetails = "italicAngle = 0x" + ia.ToString("x8") + 
                                    " (" + italicAngle.GetDouble() + " degrees)" +
                                    ",caretSlope Rise:Run = " + hheaTable.caretSlopeRise + ":" + hheaTable.caretSlopeRun +
                                    " (" + (dhheaAngle-90.0) + " degrees)";
                                v.Error(T.post_italicAngle, E.post_E_italicAngleNonzero_hheaAngle, m_tag, sDetails);
                                bItalOk = false;
                                bRet = false;
                            }
                        }
                    }
                }
                else
                {
                    v.Error(T.post_italicAngle, E._TEST_E_TableMissing, m_tag, "hhea table missing, can't compare italicAngle to hhea.caretSlopeRun");
                    bItalOk = false;
					bRet = false;
                }

                if (bItalOk)
                {
                    v.Pass(T.post_italicAngle, P.post_P_italicAngle, m_tag);
                }
            }

            if (v.PerformTest(T.post_underlinePosition))
            {
                Table_hhea hheaTable = (Table_hhea)fontOwner.GetTable("hhea");
                if (hheaTable != null)
                {
                    if (underlinePosition >= hheaTable.Descender)
                    {
                        v.Pass(T.post_underlinePosition, P.post_P_underlinePosition, m_tag);
                    }
                    else
                    {
                        v.Warning(T.post_underlinePosition, W.post_W_underlinePos_LT_descender, m_tag);
                        //bRet = false;
                    }
                }
                else
                {
                    v.Error(T.post_underlinePosition, E._TEST_E_TableMissing, m_tag, "hhea table missing, can't compare underlinePosition to hhea.Descender");
                }
            }

            if (v.PerformTest(T.post_underlineThickness))
            {
                Table_head headTable = (Table_head)fontOwner.GetTable("head");
                if (headTable != null)
                {
                    if (underlineThickness >= 0 && underlineThickness < headTable.unitsPerEm / 2 )
                    {
                        v.Pass(T.post_underlineThickness, P.post_P_underlineThickness, m_tag);
                    }
                    else
                    {
                        v.Warning(T.post_underlineThickness, W.post_W_underlineThickness, m_tag, underlineThickness.ToString());
                    }
                }
                else
                {
                    v.Error(T.post_underlineThickness, E._TEST_E_TableMissing, m_tag, "head table missing, can't compare underlineThickness to head.unitsPerEm");
					bRet = false;
                }
            }

            if (v.PerformTest(T.post_isFixedPitch))
            {
                bool bFixedPitchOk = true;

                Table_hmtx hmtxTable = (Table_hmtx)fontOwner.GetTable("hmtx");
                if (hmtxTable != null)
                {
                    uint numberOfHMetrics = 0;

                    Table_hhea hheaTable = (Table_hhea)fontOwner.GetTable("hhea");
                    if (hheaTable != null)
                    {
                        numberOfHMetrics = hheaTable.numberOfHMetrics;
                    }
                    else
                    {
                        v.Error(T.post_isFixedPitch, E._TEST_E_TableMissing, m_tag, "hhea table missing, can't compare isFixedPitch to horizontal metrics");
						bRet = false;
                    }

                    bool bHmtxMono = hmtxTable.IsMonospace(fontOwner);

                    if (isFixedPitch == 0 && bHmtxMono)
                    {
                        v.Error(T.post_isFixedPitch, E.post_E_isFixedPitchZero_hmtx, m_tag);
                        bFixedPitchOk = false;
                        bRet = false;
                    }
                    else if (isFixedPitch != 0 && !bHmtxMono)
                    {
                        v.Error(T.post_isFixedPitch, E.post_E_isFixedPitchNonzero_hmtx, m_tag);
                        bFixedPitchOk = false;
                        bRet = false;
                    }
                }
                else
                {
                    v.Error(T.post_isFixedPitch, E._TEST_E_TableMissing, m_tag, "hmtx table missing, can't compare isFixedPitch to horizontal metrics");
					bRet = false;
                }

                Table_OS2 OS2Table = (Table_OS2)fontOwner.GetTable("OS/2");
                if (OS2Table != null)
                {
                    if (OS2Table.panose_byte1 == 2) // PANOSE family kind == LatinText
                    {
                        if (isFixedPitch == 0 && OS2Table.panose_byte4 == 9) // PANOSE proportion == monospaced
                        {
                            v.Error(T.post_isFixedPitch, E.post_E_isFixedPitchZero_OS_2, m_tag);
                            bFixedPitchOk = false;
                            bRet = false;
                        }
                        else if (isFixedPitch != 0 && OS2Table.panose_byte4 != 9)
                        {
                            v.Error(T.post_isFixedPitch, E.post_E_isFixedPitchNonzero_OS_2, m_tag);
                            bFixedPitchOk = false;
                            bRet = false;
                        }
                    }
                }
                else
                {
                    v.Error(T.post_isFixedPitch, E._TEST_E_TableMissing,
                            m_tag, "OS/2 table is missing, can't compare isFixedPitch to OS/2 PANOSE");
					bRet = false;
                }

                if (bFixedPitchOk && hmtxTable != null && OS2Table != null)
                {
                    v.Pass(T.post_isFixedPitch, P.post_P_isFixedPitch, m_tag, "matches the hmtx and OS/2 tables");
                }
                else if (bFixedPitchOk && hmtxTable == null && OS2Table != null)
                {
                    v.Pass(T.post_isFixedPitch, P.post_P_isFixedPitch, m_tag, "matches the OS/2 table");
                }
                else if (bFixedPitchOk && hmtxTable != null && OS2Table == null)
                {
                    v.Pass(T.post_isFixedPitch, P.post_P_isFixedPitch, m_tag, "matches the hmtx table");
                }
            }

            if (v.PerformTest(T.post_v2_numberOfGlyphs))
            {
                if (Version.GetUint() == 0x00020000)
                {
                    Table_maxp maxpTable = (Table_maxp)fontOwner.GetTable("maxp");
                    if (maxpTable == null)
                    {
                        v.Error(T.post_v2_numberOfGlyphs, E._TEST_E_TableMissing, m_tag, "maxp table is missing");
						bRet = false;
                    }
                    else
                    {
                        if (numberOfGlyphs == fontOwner.GetMaxpNumGlyphs())
                        {
                            v.Pass(T.post_v2_numberOfGlyphs, P.post_P_v2_numberOfGlyphs, m_tag);
                        }
                        else
                        {
                            v.Error(T.post_v2_numberOfGlyphs, E.post_E_v2_numberOfGlyphs,
                                    m_tag, "numberOfGlyphs = " + numberOfGlyphs + 
                                    ", maxp.numGlyphs = " + fontOwner.GetMaxpNumGlyphs());
                            bRet = false;
                        }
                    }
                }
                else
                {
                    v.Info(T.post_v2_numberOfGlyphs, I.post_I_v2_numberOfGlyphs_notv2, m_tag);
                }
            }

            if (v.PerformTest(T.post_v2_glyphNameIndex))
            {
                if (Version.GetUint() == 0x00020000 && GetLength() >= 34)
                {
                    bool bIndexOk = true;

                    for (uint i=0; i<numberOfGlyphs; i++)
                    {
                        if ((uint)FieldOffsetsVer2.glyphNameIndex + i*2 + 2 <= m_bufTable.GetLength())
                        {
                            ushort index = GetGlyphNameIndex((ushort)i);
                            if (index-258 >= m_nameOffsets.Length)
                            {
                                string s = "glyphNameIndex[" + i + "] = " + 
                                    index + ", # names = " + m_nameOffsets.Length;
                                v.Error(T.post_v2_glyphNameIndex, E.post_E_glyphNameIndex_range, m_tag, s);
                                bIndexOk = false;
                                bRet = false;
                            }
                        }
                        else
                        {
                            v.Warning(T.post_v2_glyphNameIndex, 
                                      W._TEST_W_OtherErrorsInTable, m_tag, 
                                      "unable to validate any more glyph indexes, index  " + 
                                      i + " is past end of table");
                            bIndexOk = false;
                            break;
                        }
                    }

                    if (bIndexOk)
                    {
                        v.Pass(T.post_v2_glyphNameIndex, P.post_P_glyphNameIndex, m_tag);
                    }
                }
                else
                {
                    v.Info(T.post_v2_glyphNameIndex, I.post_I_v2_glyphNameIndex_notv2, m_tag);
                }
            }

            if (v.PerformTest(T.post_v2_names))
            {
                if (Version.GetUint() == 0x00020000)
                {

                    PostNames pn = new PostNames();

                    bool bNamesOk = true;

                    byte [] buf = new byte[2];

                    for (uint iGlyph=0; iGlyph<numberOfGlyphs; iGlyph++)
                    {
                        if ((uint)FieldOffsetsVer2.glyphNameIndex + iGlyph*2 + 2
                            <= m_bufTable.GetLength())
                        {
                            uint index = GetGlyphNameIndex((ushort)iGlyph);
                            if (index >= 258 && index-258 < m_nameOffsets.Length)
                            {
                                if (m_nameOffsets[index-258] >= GetLength())
                                {
                                    string s = "name index = " + index;
                                    v.Error(T.post_v2_names, 
                                            E.post_E_v2_NameOffsetInvalid, 
                                            m_tag, s);
                                    bNamesOk = false;
                                    bRet = false;
                                }
                                else
                                {
                                    uint length = 
                                        m_bufTable.GetByte(m_nameOffsets[index-258]);
                                    if (m_nameOffsets[index-258] + length < GetLength())
                                    {
                                        bNamesOk = CheckNames( v, fontOwner, pn, iGlyph, index );
                                    }
                                    else
                                    {
                                        string s = "name index = " + index;
                                        v.Error(T.post_v2_names, E.post_E_v2_NameLengthInvalid, m_tag, s);
                                        bNamesOk = false;
                                        bRet = false;
                                    }
                                }
                            }
                        }
                        else
                        {
                            v.Warning(T.post_v2_names, W._TEST_W_OtherErrorsInTable, m_tag, 
                                      "unable to validate any more names, index " + 
                                      iGlyph + " is past end of table");
                            bNamesOk = false;
                            break;
                        }
                    }

                    if (bNamesOk)
                    {
                        v.Pass(T.post_v2_names, P.post_P_names, m_tag);
                    }
                }
                else
                {
                    v.Info(T.post_v2_names, I.post_I_v2_names_notv2, m_tag);
                }
            }

            return bRet;
        }
Ejemplo n.º 17
0
        /************************
         * public methods
         */


        public bool Validate(Validator v, OTFontVal fontOwner)
        {
            bool bRet = true;

            if (fontOwner.GetFile().IsCollection())
            {
                if (fontOwner.GetFontIndexInFile() > 0)
                {
                    // checksum not matching data is covered by check elsewhere. Assume they match.
                    DirectoryEntry de_EBDT = fontOwner.GetDirectoryEntry("EBDT");
                    for (uint i = 0; i < fontOwner.GetFontIndexInFile(); i++)
                    {
                        if (fontOwner.GetFile().GetFont(i).GetDirectoryEntry("EBDT").checkSum
                            == de_EBDT.checkSum)
                        {
                            v.Info(T.T_NULL, I.glyf_I_IDENTICAL_GLYF_TABLES_IN_TTC, m_tag);
                            return(true);
                        }
                    }
                }
            }

            m_nCachedMaxpNumGlyphs = fontOwner.GetMaxpNumGlyphs();


            if (v.PerformTest(T.EBDT_version))
            {
                if (version.GetUint() == 0x00020000 || version.GetUint() == 0x00030000)
                {
                    v.Pass(T.EBDT_version, P.EBDT_P_version, m_tag);
                }
                else
                {
                    v.Error(T.EBDT_version, E.EBDT_E_version, m_tag, "version = 0x" + version.GetUint().ToString("x8") + ", unable to continue validation");
                    return(false);
                }
            }
            //TODO: check tag for EBDT v3, CBDT v2, bdat

            if (v.PerformTest(T.EBDT_TableDependency))
            {
                Table_EBLC EBLCTable = (Table_EBLC)fontOwner.GetTable("EBLC");
                if (EBLCTable != null)
                {
                    v.Pass(T.EBDT_TableDependency, P.EBDT_P_TableDependency, m_tag);
                }
                else
                {
                    v.Error(T.EBDT_TableDependency, E.EBDT_E_TableDependency, m_tag);
                    bRet = false;
                }
            }

            // T.EBDT_GlyphImageData depends on T.EBDT_TableDependency passing.
            if (v.PerformTest(T.EBDT_GlyphImageData))
            {
                bool bGlyphImageDataOk = true;

                Table_EBLC EBLCTable = (Table_EBLC)fontOwner.GetTable("EBLC");
                if (EBLCTable == null)
                {
                    return(bRet); //failed the last test, not going on.
                }
                // for each bitmap size
                for (uint i = 0; i < EBLCTable.numSizes; i++)
                {
                    Table_EBLC.bitmapSizeTable bst = EBLCTable.GetBitmapSizeTable(i);
                    string sSize = "bitmapsize[" + i + "], ppemX=" + bst.ppemX + ", ppemY=" + bst.ppemY;

                    if (true)
                    {
                        for (uint j = 0; j < bst.numberOfIndexSubTables; j++)
                        {
                            Table_EBLC.indexSubTable      ist    = null;
                            Table_EBLC.indexSubTableArray ista_j = EBLCTable.GetIndexSubTableArray(bst, j);
                            if (ista_j != null)
                            {
                                ist = bst.GetIndexSubTable(ista_j);
                            }

                            if (ist != null)
                            {
                                string sID = sSize + ", indexSubTable[" + j + "](index fmt " + ist.header.indexFormat +
                                             ", image fmt " + ist.header.imageFormat + ")";

                                switch (ist.header.imageFormat)
                                {
                                case 1:
                                    if (!Validate_Format1(v, sID, ist))
                                    {
                                        bGlyphImageDataOk = false;
                                        bRet = false;
                                    }
                                    break;

                                case 2:
                                    if (!Validate_Format2(v, sID, ist))
                                    {
                                        bGlyphImageDataOk = false;
                                        bRet = false;
                                    }
                                    break;

                                case 3:
                                    if (!Validate_Format3(v, sID, ist))
                                    {
                                        bGlyphImageDataOk = false;
                                        bRet = false;
                                    }
                                    break;

                                case 4:
                                    if (!Validate_Format4(v, sID, ist))
                                    {
                                        bGlyphImageDataOk = false;
                                        bRet = false;
                                    }
                                    break;

                                case 5:
                                    if (!Validate_Format5(v, sID, ist))
                                    {
                                        bGlyphImageDataOk = false;
                                        bRet = false;
                                    }
                                    break;

                                case 6:
                                    if (!Validate_Format6(v, sID, ist))
                                    {
                                        bGlyphImageDataOk = false;
                                        bRet = false;
                                    }
                                    break;

                                case 7:
                                    if (!Validate_Format7(v, sID, ist))
                                    {
                                        bGlyphImageDataOk = false;
                                        bRet = false;
                                    }
                                    break;

                                case 8:
                                    if (!Validate_Format8(v, sID, ist))
                                    {
                                        bGlyphImageDataOk = false;
                                        bRet = false;
                                    }
                                    break;

                                case 9:
                                    if (!Validate_Format9(v, sID, ist))
                                    {
                                        bGlyphImageDataOk = false;
                                        bRet = false;
                                    }
                                    break;

                                case 17:
                                    if (version.GetUint() != 0x00030000)
                                    {
                                        bGlyphImageDataOk = false;
                                        bRet = false;
                                    }
                                    // TODO: adding 3 checks
                                    break;

                                case 18:
                                    if (version.GetUint() != 0x00030000)
                                    {
                                        bGlyphImageDataOk = false;
                                        bRet = false;
                                    }
                                    // TODO: adding 3 checks
                                    break;

                                case 19:
                                    if (version.GetUint() != 0x00030000)
                                    {
                                        bGlyphImageDataOk = false;
                                        bRet = false;
                                    }
                                    // TODO: adding 3 checks
                                    break;

                                default:
                                    // TODO: emit Unknown
                                    break;
                                }
                            }
                        }
                    }
                }

                if (bGlyphImageDataOk)
                {
                    v.Pass(T.EBDT_GlyphImageData, P.EBDT_P_GlyphImageData, m_tag);
                }
            }

            return(bRet);
        }
Ejemplo n.º 18
0
        bool VerifyUnicodeRanges( Validator  v,
            uint        ulUnicodeRange,
            uint        ulUnicodeRangeBit,
            uint        nCharsInRange,
            string      sRangeNames)
        {
            bool bRet = true;
            if(nCharsInRange != 0)
            {
                if((ulUnicodeRange & ulUnicodeRangeBit) == 0)
                {
                    v.Info(T.T_NULL, I.OS_2_I_RangeBitNotSet, m_tag, nCharsInRange + " characters are present in the ranges: " + sRangeNames);
                }
            }
            else
            {
                if((ulUnicodeRange & ulUnicodeRangeBit) != 0)
                {
                    v.Error(T.T_NULL, E.OS_2_E_RangeBitSet, m_tag, "No characters are present in the ranges: " + sRangeNames);
                    bRet = false;
                }
            }

            return bRet;
        }
Ejemplo n.º 19
0
        /************************
         * public methods
         */

        public bool Validate(Validator v, OTFontVal fontOwner)
        {
            bool bRet = true;

            v.Info(T.T_NULL, I.CFF_I_Version, m_tag, major + "." + minor);

            if ( major == 1 && minor == 0 && hdrSize == 4 )
            {
                v.Pass(T.CFF_Header, P.CFF_P_Header, m_tag);
            }
            else
            {
                v.Error(T.CFF_Header, E.CFF_E_Header, m_tag,
                        "major=" + major + ", minor=" + minor + ", hdrSize=" + hdrSize + ", offSize=" + offSize);
            }

            try
            {
                v.Pass(T.CFF_MAININDEX_Enumeration, P.CFF_P_MAININDEX_Enumeration, m_tag,
                       "Name=" + Name.count + ", TopDICT=" + TopDICT.count + ", String=" + String.count + ", GlobalSubr=" + GlobalSubr.count);
            }
            catch (Exception e)
            {
                v.Error(T.CFF_MAININDEX_Enumeration, E.CFF_E_MAININDEX_Enumeration, m_tag,
                        e.Message);

                return false;
            }

            if ( Name.count == TopDICT.count && TopDICT.count == 1)
            {
                v.Pass(T.CFF_NameDICTSize, P.CFF_P_NameDICTSize, m_tag);
            }
            else
            {
                v.Error(T.CFF_NameDICTSize, E.CFF_E_NameDICTSize, m_tag,
                        "Name=" + Name.count + ", TopDICT=" + TopDICT.count);
            }

            if (Name.GetOffset(0) != 1)
                v.Warning( T.CFF_INDEXFirstOffset, W.CFF_W_INDEXFirstOffset, m_tag, "Name=" + Name.GetOffset(0) );
            if (TopDICT.GetOffset(0) != 1)
                v.Warning( T.CFF_INDEXFirstOffset, W.CFF_W_INDEXFirstOffset, m_tag, "TopDICT=" + TopDICT.GetOffset(0) );
            if (String.GetOffset(0) != 1)
                v.Warning( T.CFF_INDEXFirstOffset, W.CFF_W_INDEXFirstOffset, m_tag, "String=" + String.GetOffset(0) );
            if (GlobalSubr.GetOffset(0) != 1)
                v.Warning( T.CFF_INDEXFirstOffset, W.CFF_W_INDEXFirstOffset, m_tag, "GlobalSubr=" + GlobalSubr.GetOffset(0) );

            var overlap = new DataOverlapDetector();

            if ( !overlap.CheckForNoOverlap(0, hdrSize) )
                v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "hdrSize");
            if ( !overlap.CheckForNoOverlap(Name.begin, Name.size) )
                v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "Name");
            if ( !overlap.CheckForNoOverlap(TopDICT.begin, TopDICT.size) )
                v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "TopDICT");
            if ( !overlap.CheckForNoOverlap(String.begin, String.size) )
                v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "String");
            if ( !overlap.CheckForNoOverlap(GlobalSubr.begin, GlobalSubr.size) )
                v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "GlobalSubr");

            try
            {
                for(uint i = 0; i< Name.count; i++)
                {
                    var name = Name.GetString(i);
                }

                v.Pass(T.CFF_Non_ASCII_String_or_Name, P.CFF_P_Non_ASCII_String_or_Name, m_tag, "Name INDEX");
            }
            catch (DecoderFallbackException)
            {
                v.Error(T.CFF_Non_ASCII_String_or_Name, E.CFF_E_Non_ASCII_String_or_Name, m_tag, "Name INDEX");
            }

            try{
                for(uint i = 0; i< String.count; i++)
                {
                    var a = String.GetString(i);
                }

                v.Pass(T.CFF_Non_ASCII_String_or_Name, P.CFF_P_Non_ASCII_String_or_Name, m_tag, "String INDEX");
            }
            catch (DecoderFallbackException)
            {
                v.Error(T.CFF_Non_ASCII_String_or_Name, E.CFF_E_Non_ASCII_String_or_Name, m_tag, "String INDEX");
            }

            for(uint iDICT = 0; iDICT < TopDICT.count; iDICT++)
            {
                Table_CFF.DICTData curTopDICT = null;
                try
                {
                    curTopDICT = GetTopDICT(iDICT);

                    v.Pass(T.CFF_DICTUnwind, P.CFF_P_DICTUnwind, m_tag, curTopDICT.FullName);

                    if ( !overlap.CheckForNoOverlap((uint)curTopDICT.offsetPrivate, (uint)curTopDICT.sizePrivate) )
                        v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "TopDICTPriv");
                }
                catch (Exception e)
                {
                    v.Error(T.CFF_DICTUnwind, E.CFF_E_DICTUnwind, m_tag, "TopDICT: " + e.Message);
                }

                Table_CFF.DICTData topPrivateDict = null;
                try
                {
                    topPrivateDict = GetPrivate(curTopDICT);
                    v.Pass(T.CFF_PrivDICTUnwind, P.CFF_P_PrivDICTUnwind, m_tag, "topPrivateDict");
                }
                catch (Exception e)
                {
                    v.Error(T.CFF_PrivDICTUnwind, E.CFF_E_PrivDICTUnwind, m_tag, "topPrivateDict: " + e.Message);
                }

                if (topPrivateDict != null && topPrivateDict.Subrs != 0)
                {
                    try
                    {
                        Table_CFF.INDEXData topPrivSubrs = GetINDEX(curTopDICT.offsetPrivate + topPrivateDict.Subrs);
                        v.Pass(T.CFF_INDEXCount, P.CFF_P_INDEXCount, m_tag, "topPrivSubrs: " + topPrivSubrs.count);

                        if (topPrivSubrs.GetOffset(0) != 1)
                            v.Warning( T.CFF_INDEXFirstOffset, W.CFF_W_INDEXFirstOffset, m_tag, "topPrivSubrs=" + topPrivSubrs.GetOffset(0) );

                        if ( !overlap.CheckForNoOverlap(topPrivSubrs.begin, topPrivSubrs.size) )
                            v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "topPrivSubrs");
                    }
                    catch (Exception e)
                    {
                        v.Error(T.CFF_INDEXCount, E.CFF_E_INDEXCount, m_tag, "topPrivSubrs: " + e.Message);
                    }
                }

                Table_CFF.INDEXData CharStrings = null;
                try
                {
                    CharStrings = GetINDEX(curTopDICT.offsetCharStrings);
                    v.Pass(T.CFF_INDEXCount, P.CFF_P_INDEXCount, m_tag, "CharStrings: " + CharStrings.count);

                    if (CharStrings.GetOffset(0) != 1)
                        v.Warning( T.CFF_INDEXFirstOffset, W.CFF_W_INDEXFirstOffset, m_tag, "CharStrings=" + CharStrings.GetOffset(0) );

                    if ( !overlap.CheckForNoOverlap(CharStrings.begin, CharStrings.size) )
                        v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "CharStrings");
                }
                catch (Exception e)
                {
                    v.Error(T.CFF_INDEXCount, E.CFF_E_INDEXCount, m_tag, "CharStrings: " + e.Message);
                }

                if ( CharStrings.count == fontOwner.GetMaxpNumGlyphs() )
                {
                    v.Pass(T.CFF_CharStringsCount, P.CFF_P_CharStringsCount, m_tag);
                }
                else
                {
                    v.Error(T.CFF_CharStringsCount, E.CFF_E_CharStringsCount, m_tag,
                            CharStrings.count.ToString() + "!=" + fontOwner.GetMaxpNumGlyphs());
                }

                if (curTopDICT.ROS != null)
                {
                    v.Info(T.CFF_CIDROS, I.CFF_I_CIDROS, m_tag, curTopDICT.ROS);
                }

                if (curTopDICT.offsetFDArray > 0)
                {
                    Table_CFF.INDEXData FDArray = null;
                    try {
                        FDArray = GetINDEX(curTopDICT.offsetFDArray);
                        v.Pass(T.CFF_INDEXCount, P.CFF_P_INDEXCount, m_tag, "FDArray: " + FDArray.count);

                        if (FDArray.GetOffset(0) != 1)
                            v.Warning( T.CFF_INDEXFirstOffset, W.CFF_W_INDEXFirstOffset, m_tag, "FDArray=" + FDArray.GetOffset(0) );

                        if ( !overlap.CheckForNoOverlap(FDArray.begin, FDArray.size) )
                            v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "FDArray");
                    }
                    catch (Exception e)
                    {
                        v.Error(T.CFF_INDEXCount, E.CFF_E_INDEXCount, m_tag, "FDArray: " + e.Message);
                    }

                    for(uint i = 0; i< FDArray.count; i++)
                    {
                        Table_CFF.DICTData FDict = null;
                        try
                        {
                            FDict = GetDICT(FDArray.GetData(i));

                            v.Pass(T.CFF_DICTUnwind, P.CFF_P_DICTUnwind, m_tag, "CID FontDict #" + i + ": " +  FDict.FontName);

                            if ( !overlap.CheckForNoOverlap((uint)FDict.offsetPrivate, (uint)FDict.sizePrivate) )
                                v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "FDictPriv#" + i);
                        }
                        catch (Exception e)
                        {
                            v.Error(T.CFF_DICTUnwind, E.CFF_E_DICTUnwind, m_tag, "CID FontDict #" + i + ": " + e.Message);
                        }

                        Table_CFF.DICTData FDictPrivate = null;
                        try
                        {
                            FDictPrivate = GetPrivate(FDict);
                            v.Pass(T.CFF_PrivDICTUnwind, P.CFF_P_PrivDICTUnwind, m_tag,  "CID FontDict Private DICT#" + i);
                        }
                        catch (Exception e)
                        {
                            v.Error(T.CFF_PrivDICTUnwind, E.CFF_E_PrivDICTUnwind, m_tag, "CID FontDict Private DICT#" + i + ": " + e.Message);
                        }

                        if (FDictPrivate != null && FDictPrivate.Subrs != 0)
                        {
                            Table_CFF.INDEXData PrivSubrs = null;
                            try
                            {
                                PrivSubrs = GetINDEX(FDict.offsetPrivate + FDictPrivate.Subrs);
                                v.Pass(T.CFF_INDEXCount, P.CFF_P_INDEXCount, m_tag, "PrivSubrs#" + i + ": " + PrivSubrs.count);

                                if (PrivSubrs.GetOffset(0) != 1)
                                    v.Warning( T.CFF_INDEXFirstOffset, W.CFF_W_INDEXFirstOffset, m_tag,
                                               "PrivSubrs#" + i + "=" + PrivSubrs.GetOffset(0) );

                                if ( !overlap.CheckForNoOverlap(PrivSubrs.begin, PrivSubrs.size) )
                                    v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "PrivSubrs#" + i);
    ;
                            }
                            catch (Exception e)
                            {
                                v.Error(T.CFF_INDEXCount, E.CFF_E_INDEXCount, m_tag, "PrivSubrs#" + i + ": " + e.Message);
                            }
                        }
                    }
                }
                string result = "Tested Region: " + overlap.Occupied + " of " + GetLength() + ", not testing" +
                    ( curTopDICT.offsetCharset == 0 ? "" : " Charset: " + curTopDICT.offsetCharset) +
                    ( curTopDICT.offsetEncoding == 0 ? "" : " Encoding: " + curTopDICT.offsetEncoding) +
                    ( curTopDICT.offsetFDSelect == 0 ? "" : " FDSelect: " + curTopDICT.offsetFDSelect ) ;
                v.Info(T.CFF_TestCoverage, I.CFF_I_NotValidated, m_tag, result);
            }

            return bRet;
        }
Ejemplo n.º 20
0
        /************************
         * public methods
         */
        
        
        public bool Validate(Validator v, OTFontVal fontOwner)
        {
            bool bRet = true;

            if (v.PerformTest(T.OS_2_Version))
            {
                if (version == 0 || version == 1 || version == 2)
                {
                    v.Warning(T.OS_2_Version, W.OS_2_W_Version_old, m_tag, version.ToString());
                }
                else if (version == 3)
                {
                    v.Pass(T.OS_2_Version, P.OS_2_P_Version, m_tag, version.ToString());
                }
                else
                {
                    v.Error(T.OS_2_Version, E.OS_2_E_Version, m_tag, version.ToString());
                    bRet = false;
                }
            }

            if (v.PerformTest(T.OS_2_TableLength))
            {
                uint len = GetLength();
                if ((version == 0 && len == 78)
                    || (version == 1 && len == 86)
                    || (version == 2 && len == 96)
                    || (version == 3 && len == 96))
                {
                    v.Pass(T.OS_2_TableLength, P.OS_2_P_TableLength, m_tag);
                }
                else
                {
                    v.Error(T.OS_2_TableLength, E.OS_2_E_TableLength, m_tag);
                    bRet = false;
                }
            }

            if (!bRet)
            {
                v.Warning(T.T_NULL, W._TEST_W_OtherErrorsInTable, m_tag, "OS/2 table appears to be corrupt.  No further tests will be performed.");
                return bRet;
            }

            if (v.PerformTest(T.OS_2_xAvgCharWidth))
            {
                if (fontOwner.GetTable("maxp") == null)
                {
                    v.Warning(T.OS_2_xAvgCharWidth, W._TEST_W_ErrorInAnotherTable, m_tag, "maxp table inaccessible, can't check Avg Char Width");
                }
                else
                {
                    if (fontOwner.ContainsTrueTypeOutlines())
                    {
                        Table_hmtx hmtxTable = (Table_hmtx)fontOwner.GetTable("hmtx");
                        val_loca locaTable = (val_loca)fontOwner.GetTable("loca");
                        val_maxp maxpTable = (val_maxp)fontOwner.GetTable("maxp");
                        if (hmtxTable == null)
                        {
                            v.Error(T.OS_2_xAvgCharWidth, E._TEST_E_TableMissing, m_tag, "hmtx");
                            bRet = false;
                        }
                        else if (locaTable == null)
                        {
                            v.Error(T.OS_2_xAvgCharWidth, E._TEST_E_TableMissing, m_tag, "loca");
                            bRet = false;
                        }
                        else if (maxpTable == null)
                        {
                            v.Error(T.OS_2_xAvgCharWidth, E._TEST_E_TableMissing, m_tag, "maxp");
                            bRet = false;
                        }
                        else
                        {

                            if (   version == 3
                                || fontOwner.ContainsMsSymbolEncodedCmap())
                            {
                                int nTotalWidth = 0;
                                int nTotalGlyphs = 0;
                                for (uint iGlyph=0; iGlyph<fontOwner.GetMaxpNumGlyphs(); iGlyph++)
                                {
                                    Table_hmtx.longHorMetric hm = hmtxTable.GetOrMakeHMetric(iGlyph, fontOwner);
                                    if (hm != null)
                                    {
                                        nTotalWidth += hm.advanceWidth;
                                        // only average non-zero width glyphs
                                        if (hm.advanceWidth > 0)
                                        {
                                            nTotalGlyphs ++;
                                        }
                                    }
                                }

                                short CalcAvgWidth = 0;
                                if (nTotalGlyphs > 0)
                                    CalcAvgWidth = (short)(nTotalWidth / nTotalGlyphs);

                                if (xAvgCharWidth == CalcAvgWidth)
                                {
                                    v.Pass(T.OS_2_xAvgCharWidth, P.OS_2_P_xAvgCharWidth, m_tag);
                                }
                                else
                                {
                                    string s = "actual = " + xAvgCharWidth + ", calc = " + CalcAvgWidth;
                                    v.Error(T.OS_2_xAvgCharWidth, E.OS_2_E_xAvgCharWidth, m_tag, s);
                                    bRet = false;
                                }
                            }
                            else
                            {
                                // do weighed average
                                ushort [] weightLC = { 
                                                       64, 14, 27, 35, 100, 20, 14, 42, 63,  3,  6, 35, 20,
                                                       56, 56, 17,  4,  49, 56, 71, 31, 10,  18, 3, 18, 2
                                                     };
                                ushort weightSpace = 166;

                                try
                                {

                                    uint iSpaceGlyph = fontOwner.FastMapUnicodeToGlyphID(' ');
                                    if (iSpaceGlyph >= fontOwner.GetMaxpNumGlyphs())
                                    {
                                        throw new ApplicationException("error in cmap table");
                                    }
                                    Table_hmtx.longHorMetric hmSpace = hmtxTable.GetOrMakeHMetric(iSpaceGlyph, fontOwner);

                                    if (hmSpace != null)
                                    {

                                        int nTotalWeight = hmSpace.advanceWidth * weightSpace;
                                        int nLowerCase = 0;
                                        for (char c = 'a'; c <= 'z'; c++)
                                        {
                                            uint iGlyph = fontOwner.FastMapUnicodeToGlyphID(c);
                                            if (iGlyph > 0
                                                && iGlyph < fontOwner.GetMaxpNumGlyphs())
                                            {
                                                nLowerCase ++;

                                                Table_hmtx.longHorMetric hm = hmtxTable.GetOrMakeHMetric(iGlyph, fontOwner);
                                                nTotalWeight += hm.advanceWidth * weightLC[c-'a'];
                                            }
                                        }

                                        short CalcAvgWidth = 0;
                                        
                                        if (nLowerCase == 26)
                                        {
                                            CalcAvgWidth = (short)(nTotalWeight / 1000);
                                        }
                                        else
                                        {
                                            int nTotalWidth = 0;
                                            int nTotalGlyphs = 0;
                                            for (uint iGlyph=0; iGlyph<fontOwner.GetMaxpNumGlyphs(); iGlyph++)
                                            {
                                                Table_hmtx.longHorMetric hm = hmtxTable.GetOrMakeHMetric(iGlyph, fontOwner);
                                                nTotalWidth += hm.advanceWidth;
                                                nTotalGlyphs ++;
                                            }

                                            CalcAvgWidth = (short)(nTotalWidth / nTotalGlyphs);
                                        }

                                        if (xAvgCharWidth == CalcAvgWidth)
                                        {
                                            v.Pass(T.OS_2_xAvgCharWidth, P.OS_2_P_xAvgCharWidth, m_tag);
                                        }
                                        else
                                        {
                                            string s = "actual = " + xAvgCharWidth + ", calc = " + CalcAvgWidth;
                                            v.Error(T.OS_2_xAvgCharWidth, E.OS_2_E_xAvgCharWidth, m_tag, s);
                                            bRet = false;
                                        }
                                    }
                                    else
                                    {
                                        v.Warning(T.OS_2_xAvgCharWidth, W.OS_2_W_hmtx_invalid, m_tag, "unable to parse hmtx table");
                                    }
                                }
                                catch (ApplicationException e)
                                {
                                    v.Warning(T.OS_2_xAvgCharWidth, W._TEST_W_ErrorInAnotherTable, m_tag, "xAvgCharWidth cannot be validated due to " + e.Message);
                                }
                            }
                        }

                    }
                    else
                    {
                        // not a TT outline font - should embedded bitmap only font be handled here?
                        v.Info(T.OS_2_xAvgCharWidth, I._TEST_I_NotForCFF, m_tag, "test = OS/2_xAvgCharWidth");
                    }

                }
            }

            if (v.PerformTest(T.OS_2_WeightClass))
            {
                if (usWeightClass >= 100 &&
                    usWeightClass <= 900 &&
                    usWeightClass% 100 == 0)
                {
                    bool bWeightClassOk = true;

                    // compare to the PANOSE weight value
                    if (panose_byte1 == 2 || panose_byte1 == 3 || panose_byte1 == 4) // latin text, hand writing, or decorative
                    {
                        if (panose_byte3 > 1)
                        {
                            // convert PANOSE weight value from a range of [2..11] to a range of [100..900] (reasonably close anyway, given integer math)
                            int nConvertedPANOSE = (panose_byte3-2)*89+100;
                            int nDifference = Math.Abs(usWeightClass - nConvertedPANOSE);
                            if (nDifference < 200)
                            {
                                v.Pass(T.OS_2_WeightClass, P.OS_2_P_WeightClass_PANOSE, m_tag);
                            }
                            else
                            {
                                v.Warning(T.OS_2_WeightClass, W.OS_2_W_WeightClass_PANOSE, m_tag, "usWeightClass = " + usWeightClass + ", PANOSE weight = " + panose_byte3);
                                bWeightClassOk = false;
                            }
                        }
                    }

                    if (bWeightClassOk)
                    {
                        v.Pass(T.OS_2_WeightClass, P.OS_2_P_WeightClass, m_tag, usWeightClass.ToString());
                    }
                }
                else
                {
                    v.Error(T.OS_2_WeightClass, E.OS_2_E_WeightClass, m_tag, usWeightClass.ToString());
                    bRet = false;
                }
            }

            if (v.PerformTest(T.OS_2_WidthClass))
            {
                if (usWidthClass >=1 && usWidthClass <= 9)
                {
                    v.Pass(T.OS_2_WidthClass, P.OS_2_P_WidthClass, m_tag, usWidthClass.ToString());
                }
                else
                {
                    v.Error(T.OS_2_WidthClass, E.OS_2_E_WidthClass, m_tag, usWidthClass.ToString());
                    bRet = false;
                }
            }

            if (v.PerformTest(T.OS_2_fsType))
            {
                bool bPass = true;

                if ((fsType & 0xfcf1) != 0)
                {
                    v.Error(T.OS_2_fsType, E.OS_2_E_fsTypeReserved, m_tag, "0x"+fsType.ToString("x4"));
                    bRet = false;
                    bPass = false;
                }
                else
                {
                    int nExclusiveBits = 0;
                    if ((fsType & 0x0002) !=0) //Restricted License Embedding
                    {
                        nExclusiveBits++;
                    }
                    if ((fsType & 0x0004) != 0) // Preview and Print embedding
                    {
                        nExclusiveBits++;
                    }
                    if ((fsType & 0x0008) != 0) // Editable embedding
                    {
                        nExclusiveBits++;
                    }

                    if (nExclusiveBits > 1)
                    {
                        string sDetails = "0x"+fsType.ToString("x4");
                        if ((fsType & 0x0002) !=0)
                        {
                            sDetails += ", Restricted License Embedding";
                        }
                        if ((fsType & 0x0004) != 0)
                        {
                            sDetails += ", Preview and Print embedding";
                        }
                        if ((fsType & 0x0008) != 0)
                        {
                            sDetails += ", Editable embedding";
                        }

                        v.Error(T.OS_2_fsType, E.OS_2_E_fsTypeExclusiveBits, m_tag, sDetails);
                        bRet = false;
                        bPass = false;
                    }
                }

                if (bPass)
                {
                    string sDetails = "0x"+fsType.ToString("x4");
                    if (fsType == 0)
                    {
                        sDetails += ", Installable Embedding";
                    }
                    if ((fsType & 0x0002) !=0)
                    {
                        sDetails += ", Restricted License Embedding";
                    }
                    if ((fsType & 0x0004) != 0)
                    {
                        sDetails += ", Preview and Print embedding";
                    }
                    if ((fsType & 0x0008) != 0)
                    {
                        sDetails += ", Editable embedding";
                    }
                    if ((fsType & 0x0100) != 0)
                    {
                        sDetails += ", No subsetting";
                    }
                    if ((fsType & 0x0200) != 0)
                    {
                        sDetails += ", Bitmap embedding only";
                    }

                    v.Pass(T.OS_2_fsType, P.OS_2_P_fsType, m_tag, sDetails);
                }
            }

            if (v.PerformTest(T.OS_2_SubscriptSuperscript))
            {
                Table_head headTable = (Table_head)fontOwner.GetTable("head");
                if (headTable != null)
                {
                    ushort unitsPerEm = headTable.unitsPerEm;
                    ushort SmallestScript = (ushort)(unitsPerEm / 10);
                    bool bNoWarnOrErr = true;


                    if (ySubscriptXSize < SmallestScript ||
                        ySubscriptXSize > unitsPerEm )
                    {
                        v.Warning(T.OS_2_SubscriptSuperscript, W.OS_2_W_ySubscriptXSize_unlikely, m_tag, ySubscriptXSize.ToString());
                        bNoWarnOrErr = false;
                    }
                    if (ySubscriptYSize < SmallestScript ||
                        ySubscriptYSize > unitsPerEm )
                    {
                        v.Warning(T.OS_2_SubscriptSuperscript, W.OS_2_W_ySubscriptYSize_unlikely, m_tag, ySubscriptYSize.ToString());
                        bNoWarnOrErr = false;
                    }
                    if (ySubscriptYOffset < 0 )
                    {
                        v.Warning(T.OS_2_SubscriptSuperscript, W.OS_2_W_ySubscriptYOffset_LTZero, m_tag, ySubscriptYOffset.ToString());
                        bNoWarnOrErr = false;
                    }
                    if (ySuperscriptXSize < SmallestScript ||
                        ySuperscriptXSize > unitsPerEm )
                    {
                        v.Warning(T.OS_2_SubscriptSuperscript, W.OS_2_W_ySuperscriptXSize_unlikely, m_tag, ySuperscriptXSize.ToString());
                        bNoWarnOrErr = false;
                    }
                    if (ySuperscriptYSize < SmallestScript ||
                        ySuperscriptYSize > unitsPerEm )
                    {
                        v.Warning(T.OS_2_SubscriptSuperscript, W.OS_2_W_ySuperscriptYSize_unlikely, m_tag, ySuperscriptYSize.ToString());
                        bNoWarnOrErr = false;
                    }
                    if (ySuperscriptYOffset < 0 )
                    {
                        v.Warning(T.OS_2_SubscriptSuperscript, W.OS_2_W_ySuperscriptYOffset_unlikely, m_tag, ySuperscriptYOffset.ToString());
                        bNoWarnOrErr = false;
                    }

                    if (bNoWarnOrErr)
                    {
                        v.Pass(T.OS_2_SubscriptSuperscript, P.OS_2_P_SuperscriptSubscript, m_tag);
                    }
                }
                else
                {
                    v.Error(T.OS_2_SubscriptSuperscript, E._TEST_E_TableMissing, m_tag, "head");
                    bRet = false;
                }
            }

            if (v.PerformTest(T.OS_2_Strikeout))
            {
                Table_head headTable = (Table_head)fontOwner.GetTable("head");
                if (headTable != null)
                {
                    ushort unitsPerEm = headTable.unitsPerEm;
                    bool bNoWarnings = true;

                    if (yStrikeoutSize < 0 || yStrikeoutSize > unitsPerEm / 2 )
                    {
                        v.Warning(T.OS_2_Strikeout, W.OS_2_W_yStrikeoutSize_unlikely, m_tag, yStrikeoutSize.ToString());
                        bNoWarnings = false;
                    }
                    if (yStrikeoutPosition <= 0 )
                    {
                        v.Warning(T.OS_2_Strikeout, W.OS_2_W_yStrikeoutPosition_unlikely, m_tag, yStrikeoutPosition.ToString());
                        bNoWarnings = false;
                    }

                    if (bNoWarnings)
                    {
                        v.Pass(T.OS_2_Strikeout, P.OS_2_P_Strikeout, m_tag);
                    }
                }
                else
                {
                    v.Error(T.OS_2_Strikeout, E._TEST_E_TableMissing, m_tag, "head");
                    bRet = false;
                }
            }

            if (v.PerformTest(T.OS_2_FamilyClass))
            {
                bool bIDsOk = true;
                byte ClassID = (byte)(sFamilyClass >> 8);
                byte SubclassID = (byte)(sFamilyClass);

                if (ClassID == 6 || ClassID == 11 || ClassID == 13 || ClassID == 14 )
                {
                    v.Error(T.OS_2_FamilyClass, E.OS_2_E_sFamilyClass_classID_reserved, m_tag, ClassID.ToString());
                    bIDsOk = false;
                    bRet = false;
                }
                if (ClassID > 14 )
                {
                    v.Error(T.OS_2_FamilyClass, E.OS_2_E_sFamilyClass_ClassID_undefined, m_tag, ClassID.ToString());
                    bIDsOk = false;
                    bRet = false;
                }
                if (SubclassID > 15 )
                {
                    v.Error(T.OS_2_FamilyClass, E.OS_2_E_sFamilyClass_subclassID_undefined, m_tag, ClassID.ToString());
                    bIDsOk = false;
                    bRet = false;
                }
                if (bIDsOk)
                {
                    v.Pass(T.OS_2_FamilyClass, P.OS_2_P_sFamilyClass, m_tag);
                }
            }

            if (v.PerformTest(T.OS_2_Panose))
            {
                bool bPanoseOk = true;

                if (panose_byte1 < 5) // panose kind valid, but not latin symbol
                {
                    if (fontOwner.ContainsSymbolsOnly())
                    {
                        v.Error(T.OS_2_Panose, E.OS_2_E_Panose_FamilyTypeNotSymbol, m_tag, "PANOSE byte 1 = " + panose_byte1.ToString());
                        bPanoseOk = false;
                        bRet = false;
                    }
                }
                else if (panose_byte1 == 5) // panose family kind == latin symbol
                {
                    if (!fontOwner.ContainsSymbolsOnly())
                    {
                        v.Error(T.OS_2_Panose, E.OS_2_E_Panose_FamilyTypeSymbol, m_tag, "PANOSE byte 1 = " + panose_byte1.ToString());
                        bPanoseOk = false;
                        bRet = false;
                    }
                }
                else if ( panose_byte1 > 5 ) // family kind is invalid
                {
                    v.Error(T.OS_2_Panose, E.OS_2_E_Panose_bFamilyType, m_tag, panose_byte1.ToString());
                    bPanoseOk = false;
                    bRet = false;
                }




                if (panose_byte1 == 2) // family kind == latin text
                {
                    if ( panose_byte2 > 15 )
                    {
                        v.Error(T.OS_2_Panose, E.OS_2_E_Panose_bSerifStyle, m_tag, panose_byte2.ToString());
                        bPanoseOk = false;
                        bRet = false;
                    }
                }

                if ( panose_byte3 > 11 ) // byte3 always means weight
                {
                    v.Error(T.OS_2_Panose, E.OS_2_E_Panose_bWeight, m_tag, panose_byte3.ToString());
                    bPanoseOk = false;
                    bRet = false;
                }

                if (panose_byte1 == 5) // panose family kind == latin symbol
                {
                    if (panose_byte3 != 1) // weight must be 1 for symbols
                    {
                        v.Error(T.OS_2_Panose, E.OS_2_E_Panose_SymbolWeight, m_tag, panose_byte3.ToString());
                        bPanoseOk = false;
                        bRet = false;
                    }

                    if (panose_byte5 != 1) // aspect ratio & contrast must be 1 for symbols
                    {
                        v.Error(T.OS_2_Panose, E.OS_2_E_Panose_SymbolAspectRatio, m_tag, panose_byte5.ToString());
                        bPanoseOk = false;
                        bRet = false;
                    }
                }


                if (panose_byte1 == 2) // family kind == latin text
                {
                    // the following tests are only valid when family kind is latin text

                    if ( panose_byte4 > 9 )
                    {
                        v.Error(T.OS_2_Panose, E.OS_2_E_Panose_bProportion, m_tag, panose_byte4.ToString());
                        bPanoseOk = false;
                        bRet = false;
                    }

                    if ( panose_byte5 > 9 )
                    {
                        v.Error(T.OS_2_Panose, E.OS_2_E_Panose_bContrast, m_tag, panose_byte5.ToString());
                        bPanoseOk = false;
                        bRet = false;
                    }

                    if ( panose_byte6 > 10 )
                    {
                        v.Error(T.OS_2_Panose, E.OS_2_E_Panose_bStrokeVariation, m_tag, panose_byte6.ToString());
                        bPanoseOk = false;
                        bRet = false;
                    }

                    if ( panose_byte7 > 11 )
                    {
                        v.Error(T.OS_2_Panose, E.OS_2_E_Panose_bArmStyle, m_tag, panose_byte7.ToString());
                        bPanoseOk = false;
                        bRet = false;
                    }

                    if ( panose_byte8 > 15 )
                    {
                        v.Error(T.OS_2_Panose, E.OS_2_E_Panose_bLetterform, m_tag, panose_byte8.ToString());
                        bPanoseOk = false;
                        bRet = false;
                    }

                    if ( panose_byte9 > 13 )
                    {
                        v.Error(T.OS_2_Panose, E.OS_2_E_Panose_bMidline, m_tag, panose_byte9.ToString());
                        bPanoseOk = false;
                        bRet = false;
                    }

                    if ( panose_byte10 > 7 )
                    {
                        v.Error(T.OS_2_Panose, E.OS_2_E_Panose_bXHeight, m_tag, panose_byte10.ToString());
                        bPanoseOk = false;
                        bRet = false;
                    }
                }

                if (panose_byte1  == 0 && 
                    panose_byte2  == 0 &&
                    panose_byte3  == 0 &&
                    panose_byte4  == 0 &&
                    panose_byte5  == 0 &&
                    panose_byte6  == 0 &&
                    panose_byte7  == 0 &&
                    panose_byte8  == 0 &&
                    panose_byte9  == 0 &&
                    panose_byte10 == 0 )
                {
                    v.Warning(T.OS_2_Panose, W.OS_2_W_Panose_undefined, m_tag);
                    bPanoseOk = false;
                }

                if (bPanoseOk)
                {
                    v.Pass(T.OS_2_Panose, P.OS_2_P_Panose, m_tag);
                }
            }

            if (v.PerformTest(T.OS_2_UnicodeRanges))
            {
                bRet &= CheckUnicodeRanges(v, fontOwner);
            }

            if (v.PerformTest(T.OS_2_fsSelection))
            {
                bool bSelOk = true;

                Table_name nameTable = (Table_name)fontOwner.GetTable("name");
                string sStyle = null;
                string sStyleLower = null;
                if (nameTable != null)
                {
                    sStyle = nameTable.GetStyleString();
                    if (sStyle != null)
                    {
                        sStyleLower = sStyle.ToLower();
                    }
                }

                // reserved bits
                if ( (fsSelection & 0xFF80 ) != 0 )
                {
                    // we need to look for Win 3.1 font pages
                    // Fonts with these
                    const ushort HEBREW_FONT_PAGE = 0xB100;
                    const ushort SIMP_ARABIC_FONT_PAGE = 0xB200;
                    const ushort TRAD_ARABIC_FONT_PAGE = 0xB300;
                    const ushort OEM_ARABIC_FONT_PAGE = 0xB400;
                    const ushort SIMP_FARSI_FONT_PAGE = 0xBA00;
                    const ushort TRAD_FARSI_FONT_PAGE = 0xBB00;
                    const ushort THAI_FONT_PAGE = 0xDE00;

                    String sDetails = "Bit(s) ";
                    bool bFoundFirstBadBit = false;

                    if (version == 0)
                    {
                        switch (fsSelection & 0xFF00)
                        {
                            case HEBREW_FONT_PAGE:
                                sDetails = "Hebrew Windows 3.1 font page";
                                break;
                            case SIMP_ARABIC_FONT_PAGE:
                                sDetails = "Simplified Arabic Windows 3.1 font page";
                                break;
                            case TRAD_ARABIC_FONT_PAGE:
                                sDetails = "Traditional Arabic Windows 3.1 font page";
                                break;
                            case OEM_ARABIC_FONT_PAGE:
                                sDetails = "OEM Arabic Windows 3.1 font page";
                                break;
                            case SIMP_FARSI_FONT_PAGE:
                                sDetails = "Simplified Farsi Windows 3.1 font page";
                                break;
                            case TRAD_FARSI_FONT_PAGE:
                                sDetails = "Traditional Farsi Windows 3.1 font page";
                                break;
                            case THAI_FONT_PAGE:
                                sDetails = "Thai Windows 3.1 font page";
                                break;
                            default:
                                for (int i=0; i<16; i++)
                                {
                                    int nBitValue = 1<<i;
                                    if ((nBitValue & 0xFF80) != 0)
                                    {
                                        if ((fsSelection & nBitValue) != 0)
                                        {
                                            if (bFoundFirstBadBit)
                                            {
                                                sDetails += ", " + i;
                                            }
                                            else
                                            {
                                                sDetails += i.ToString();
                                                bFoundFirstBadBit = true;
                                            }
                                        }
                                    }
                                }
                                break;
                            
                        }
                    }
                    else
                    {
                        for (int i=0; i<16; i++)
                        {
                            int nBitValue = 1<<i;
                            if ((nBitValue & 0xFF80) != 0)
                            {
                                if ((fsSelection & nBitValue) != 0)
                                {
                                    if (bFoundFirstBadBit)
                                    {
                                        sDetails += ", " + i;
                                    }
                                    else
                                    {
                                        sDetails += i.ToString();
                                        bFoundFirstBadBit = true;
                                    }
                                }
                            }
                        }
                    }

                    v.Error(T.OS_2_fsSelection, E.OS_2_E_fsSelection_undefbits, m_tag, sDetails);
                    bSelOk = false;
                    bRet = false;
                }

                // compare to head.macStyle italic and bold bits
                Table_head headTable = (Table_head)fontOwner.GetTable("head");
                if (headTable != null)
                {
                    bool bItalic = ((fsSelection & 0x01) != 0 );
                    bool bBold   = ((fsSelection & 0x20) != 0 );

                    bool bMacBold = ((headTable.macStyle & 0x0001) != 0);
                    bool bMacItal = ((headTable.macStyle & 0x0002) != 0);

                    if (bItalic != bMacItal)
                    {
                        string sDetails = null;
                        if (bItalic) sDetails = "fsSelection italic bit is set, but macstyle italic bit is clear";
                        else sDetails =  "fsSelection italic bit is clear, but macstyle italic bit is set";

                        v.Error(T.OS_2_fsSelection, E.OS_2_E_fsSelection_macStyle_italic, m_tag, sDetails);
                        bSelOk = false;
                        bRet = false;
                    }

                    if (bBold != bMacBold)
                    {
                        string sDetails = null;
                        if (bBold) sDetails = "fsSelection bold bit is set, but macstyle bold bit is clear";
                        else sDetails =  "fsSelection bold bit is clear, but macstyle bold bit is set";

                        v.Error(T.OS_2_fsSelection, E.OS_2_E_fsSelection_macStyle_bold, m_tag, sDetails);
                        bSelOk = false;
                        bRet = false;
                    }
                }

                if ((fsSelection & 0x01) != 0 ) // italic bit
                {
                    // compare to name subfamily
                    if (sStyleLower != null)
                    {
                        if (sStyleLower.IndexOf("italic") == -1 && sStyleLower.IndexOf("oblique") == -1)
                        {
                            v.Error(T.OS_2_fsSelection, E.OS_2_E_fsSelection_subfamily, m_tag, "fsSelection italic bit is set, but subfamily is " + sStyle);
                            bSelOk = false;
                            bRet = false;
                        }
                    }
                }

                if ((fsSelection & 0x20) != 0 ) // bold bit
                {
                    // compare to name subfamily
                    if (sStyleLower != null)
                    {
                        if (sStyleLower.IndexOf("bold") == -1)
                        {
                            v.Error(T.OS_2_fsSelection, E.OS_2_E_fsSelection_subfamily, m_tag, "fsSelection bold bit is set, but subfamily is " + sStyle);
                            bSelOk = false;
                            bRet = false;
                        }
                    }

                    if (usWeightClass <= 500)
                    {
                        v.Warning(T.OS_2_fsSelection, W.OS_2_W_fsSelection_weight, m_tag, "usWeightClass = " + usWeightClass);
                        bSelOk = false;
                    }
                }

                if ((fsSelection & 0x40) != 0 ) // regular bit
                {
                    if ((fsSelection & 0x20) != 0 )
                    {
                        v.Error(T.OS_2_fsSelection, E.OS_2_E_reg_bold, m_tag);
                        bSelOk = false;
                        bRet = false;
                    }
                    if ((fsSelection & 0x01) != 0) 
                    {
                        v.Error(T.OS_2_fsSelection, E.OS_2_E_reg_ital, m_tag);
                        bSelOk = false;
                        bRet = false;
                    }

                    if (sStyleLower != null)
                    {
                        // compare to name subfamily
                        if (sStyleLower.CompareTo("regular") != 0)
                        {
                            v.Error(T.OS_2_fsSelection, E.OS_2_E_fsSelection_subfamily, m_tag, "fsSelection regular bit is set, but subfamily is " + sStyle);
                            bSelOk = false;
                            bRet = false;
                        }
                    }                    
                }

                if (bSelOk)
                {
                    v.Pass(T.OS_2_fsSelection, P.OS_2_P_fsSelection, m_tag);
                }
            }

            if (v.PerformTest(T.OS_2_CharIndexes))
            {
                Table_cmap cmapTable = (Table_cmap)fontOwner.GetTable("cmap");

                if (cmapTable != null)
                {
                    ushort charFirst = 0xffff;
                    ushort charLast  = 0;

                    Table_cmap.EncodingTableEntry eteUni = cmapTable.GetEncodingTableEntry(3,1);
                    if (eteUni == null)
                    {
                        // presumably a symbol font
                        eteUni = cmapTable.GetEncodingTableEntry(3,0);
                    }

                    if (eteUni != null)
                    {
                        Table_cmap.Subtable st = cmapTable.GetSubtable(eteUni);
                        if (st != null)
                        {
                            bool bCmapOk = true;
                            byte[] charbuf = new byte[2];
                            // find the first char
                            for (ushort c=0; c<0xffff; c++)
                            {
                                charbuf[0] = (byte)c;
                                charbuf[1] = (byte)(c>>8);
                                uint glyphID;
                                try
                                {
                                    glyphID = st.MapCharToGlyph(charbuf, 0);
                                }
                                catch
                                {
                                    bCmapOk = false;
                                    break;
                                }
                                if (glyphID != 0)
                                {
                                    charFirst = c;
                                    break;
                                }
                            }
                            // find the last char (start at fffd: fffe and ffff aren't legal characters)
                            if (bCmapOk)
                            {
                                for (ushort c=0xfffd; c>0; c--)
                                {
                                    charbuf[0] = (byte)c;
                                    charbuf[1] = (byte)(c>>8);
                                    uint glyphID;
                                    try
                                    {
                                        glyphID = st.MapCharToGlyph(charbuf, 0);
                                    }
                                    catch
                                    {
                                        bCmapOk = false;
                                        break;
                                    }

                                    if (glyphID != 0)
                                    {
                                        charLast = c;
                                        break;
                                    }
                                }
                            }

                            if (!bCmapOk)
                            {
                                v.Warning(T.OS_2_CharIndexes, W._TEST_W_ErrorInAnotherTable, m_tag, "usFirstCharIndex and usLastCharIndex cannot be validated due to errors in the cmap table");
                            }
                            else if (usFirstCharIndex == charFirst && usLastCharIndex == charLast)
                            {
                                v.Pass(T.OS_2_CharIndexes, P.OS_2_P_CharIndexes, m_tag, "first = 0x" + usFirstCharIndex.ToString("x4") + ", last = 0x" + usLastCharIndex.ToString("x4"));
                            }
                            else
                            {
                                if (usFirstCharIndex != charFirst)
                                {
                                    String sDetails = "actual = 0x" + usFirstCharIndex.ToString("x4") + ", calculated = 0x" + charFirst.ToString("x4");
                                    v.Error(T.OS_2_CharIndexes, E.OS_2_E_usFirstCharIndex, m_tag, sDetails);
                                    bRet = false;
                                }
                        
                                if (usLastCharIndex != charLast)
                                {
                                    String sDetails = "actual = 0x" + usLastCharIndex.ToString("x4") + ", calculated = 0x" + charLast.ToString("x4");
                                    v.Error(T.OS_2_CharIndexes, E.OS_2_E_usLastCharIndex, m_tag, sDetails);
                                    bRet = false;
                                }
                            }
                        }
                        else
                        {
                            v.Warning(T.OS_2_CharIndexes, W._TEST_W_ErrorInAnotherTable, m_tag, "usFirstCharIndex and usLastCharIndex cannot be validated due to errors in the cmap table");
                        }
                    }

                }
                else
                {
                    v.Error(T.OS_2_CharIndexes, E._TEST_E_TableMissing, m_tag, "cmap");
                    bRet = false;
                }
            }

            if (v.PerformTest(T.OS_2_TypoMetrics))
            {
                bool bOk = true;

                if (sTypoAscender <= 0)
                {
                    v.Error(T.OS_2_TypoMetrics, E.OS_2_E_sTypoAscender_notpositive, m_tag, sTypoAscender.ToString());
                    bOk = false;
                    bRet = false;
                }

                if (sTypoDescender > 0)
                {
                    v.Error(T.OS_2_TypoMetrics, E.OS_2_E_sTypoDescender_positive, m_tag, sTypoDescender.ToString());
                    bOk = false;
                    bRet = false;
                }

                Table_head headTable = (Table_head)fontOwner.GetTable("head");
                if (headTable != null)
                {
                    if (sTypoAscender - sTypoDescender > headTable.unitsPerEm)
                    {
                        string sDetails = "sTypoAscender = " + sTypoAscender + ", sTypoDescender = " + sTypoDescender;
                        v.Warning(T.OS_2_TypoMetrics, W.OS_2_W_sTypoAscenderDescender_difference, m_tag, sDetails);
                        bOk = false;
                    }
                }
                else
                {
                    v.Error(T.OS_2_TypoMetrics, E._TEST_E_TableMissing, m_tag, "head");
                    bRet = false;
                }

                if (bOk)
                {
                    string sDetails = "sTypoAscender = " + sTypoAscender + ", sTypoDescender = " + sTypoDescender;
                    v.Pass(T.OS_2_TypoMetrics, P.OS_2_P_sTypoAscenderDescender, m_tag, sDetails);
                }
            }

            if (v.PerformTest(T.OS_2_CodePageRanges))
            {
                if (version >= 1)
                {
                    bRet &= CheckCodePageRanges(v, fontOwner);
                }
            }

            if (v.PerformTest(T.OS_2_sxHeight))
            {
                if (version >= 2)
                {
                    if (sxHeight == 0)
                    {
                        if (fontOwner.FastMapUnicodeToGlyphID((char)0x0078) != 0)
                        {
                            v.Error(T.OS_2_sxHeight, E.OS_2_E_sxHeight, m_tag);
                            bRet = false;
                        }
                        else
                        {
                            v.Pass(T.OS_2_sxHeight, P.OS_2_P_sxHeight_zero, m_tag, sxHeight.ToString());
                        }
                    }
                    else
                    {
                        v.Pass(T.OS_2_sxHeight, P.OS_2_P_sxHeight_nonzero, m_tag, sxHeight.ToString());
                    }
                }
            }

            if (v.PerformTest(T.OS_2_sCapHeight))
            {
                if (version >= 2)
                {
                    if (sCapHeight == 0)
                    {
                        if (fontOwner.FastMapUnicodeToGlyphID((char)0x0048) != 0)
                        {
                            v.Error(T.OS_2_sCapHeight, E.OS_2_E_sCapHeight, m_tag);
                            bRet = false;
                        }
                        else
                        {
                            v.Pass(T.OS_2_sCapHeight, P.OS_2_P_sCapHeight_zero, m_tag, sCapHeight.ToString());
                        }
                    }
                    else
                    {
                        v.Pass(T.OS_2_sCapHeight, P.OS_2_P_sCapHeight_nonzero, m_tag, sCapHeight.ToString());
                    }
                }
            }

            if (v.PerformTest(T.OS_2_usDefaultChar))
            {
                if (version >= 2)
                {
                    if (usDefaultChar == 0)
                    {
                        v.Pass(T.OS_2_usDefaultChar, P.OS_2_P_usDefaultChar_zero, m_tag);
                    }
                    else if (fontOwner.FastMapUnicodeToGlyphID((char)usDefaultChar) != 0)
                    {
                        v.Pass(T.OS_2_usDefaultChar, P.OS_2_P_usDefaultChar_nonzero, m_tag, "0x" + usDefaultChar.ToString("x4"));
                    }
                    else
                    {
                        v.Error(T.OS_2_usDefaultChar, E.OS_2_E_usDefaultChar_notmapped, m_tag, "0x" + usDefaultChar.ToString("x4"));
                        bRet = false;
                    }
                }
            }

            if (v.PerformTest(T.OS_2_usBreakChar))
            {
                if (version >= 2)
                {
                    if (fontOwner.FastMapUnicodeToGlyphID((char)usBreakChar) != 0)
                    {
                        v.Pass(T.OS_2_usBreakChar, P.OS_2_P_usBreakChar_mapped, m_tag);
                    }
                    else
                    {
                        v.Error(T.OS_2_usBreakChar, E.OS_2_E_usBreakChar_notmapped, m_tag, "0x" + usBreakChar.ToString("x4"));
                        bRet = false;
                    }
                }
            }

            if (v.PerformTest(T.OS_2_usMaxContext))
            {
                if (version >= 2)
                {
                    ushort GPOSMaxContext = 0;
                    Table_GPOS GPOSTable = (Table_GPOS)fontOwner.GetTable("GPOS");
                    if (GPOSTable != null)
                    {
                        GPOSMaxContext = GPOSTable.GetMaxContext();
                    }

                    ushort GSUBMaxContext = 0;
                    Table_GSUB GSUBTable = (Table_GSUB)fontOwner.GetTable("GSUB");
                    if (GSUBTable != null)
                    {
                        GSUBMaxContext = GSUBTable.GetMaxContext();
                    }

                    ushort CalcMaxContext = Math.Max(GPOSMaxContext, GSUBMaxContext);

                    if (usMaxContext == CalcMaxContext)
                    {
                        v.Pass(T.OS_2_usMaxContext, P.OS_2_P_usMaxContext, m_tag, usMaxContext.ToString());
                    }
                    else
                    {
                        v.Error(T.OS_2_usMaxContext, E.OS_2_E_usMaxContext, m_tag, "calc = " + CalcMaxContext + ", actual = " + usMaxContext);
                        bRet = false;
                    }
                }
            }

            return bRet;
        }
Ejemplo n.º 21
0
        /************************
         * public methods
         */


        public bool Validate(Validator v, OTFontVal fontOwner)
        {
            bool bRet = true;

            if (v.PerformTest(T.name_FormatSelector))
            {
                if (FormatSelector == 0)
                {
                    v.Pass(T.name_FormatSelector, P.name_P_FormatSelector, m_tag);
                }
                else
                {
                    v.Error(T.name_FormatSelector, E.name_E_FormatSelector, m_tag, FormatSelector.ToString());
                    bRet = false;
                }
            }

            if (v.PerformTest(T.name_StringsWithinTable))
            {
                bool bStringsWithinTable = true;

                uint tableLength = GetLength();
                for (uint i=0; i<NumberNameRecords; i++)
                {
                    NameRecord nr = GetNameRecord(i);
                    if (nr != null)
                    {
                        if (nr.StringOffset + nr.StringLength > tableLength)
                        {
                            v.Error(T.name_StringsWithinTable, E.name_E_StringsWithinTable, m_tag, "string# " + i);
                            bStringsWithinTable = false;
                            bRet = false;
                        }
                    }
                    else
                    {
                        v.Warning(T.name_StringsWithinTable, W._TEST_W_OtherErrorsInTable, m_tag);
                        bStringsWithinTable = false;
                        break;
                    }
                }
                if (bStringsWithinTable)
                {
                    v.Pass(T.name_StringsWithinTable, P.name_P_StringsWithinTable, m_tag);
                }
            }

            if (v.PerformTest(T.name_NameRecordsSorted))
            {
                bool bSortedOrder = true;

                if (NumberNameRecords > 1)
                {
                    NameRecord CurrNR = GetNameRecord(0);
                    NameRecord NextNR = null;
                    for (uint i=0; i<NumberNameRecords-1; i++)
                    {
                        NextNR = GetNameRecord(i+1);

                        if (CurrNR == null || NextNR == null)
                        {
                            bSortedOrder = false;
                            break;
                        }

                        if (CurrNR.PlatformID > NextNR.PlatformID)
                        {
                            bSortedOrder = false;
                            break;
                        }
                        else if (CurrNR.PlatformID == NextNR.PlatformID)
                        {
                            if (CurrNR.EncodingID > NextNR.EncodingID)
                            {
                                bSortedOrder = false;
                                break;
                            }
                            else if (CurrNR.EncodingID == NextNR.EncodingID)
                            {
                                if (CurrNR.LanguageID > NextNR.LanguageID)
                                {
                                    bSortedOrder = false;
                                    break;
                                }
                                else if (CurrNR.LanguageID == NextNR.LanguageID)
                                {
                                    if (CurrNR.NameID > NextNR.NameID)
                                    {
                                        bSortedOrder = false;
                                        break;
                                    }
                                }
                            }
                        }

                        CurrNR = NextNR;
                    }
                }

                if (bSortedOrder)
                {
                    v.Pass(T.name_NameRecordsSorted, P.name_P_NameRecordsSorted, m_tag);
                }
                else
                {
                    v.Error(T.name_NameRecordsSorted, E.name_E_NameRecordsSorted, m_tag);
                    bRet = false;
                }
            }

            if (v.PerformTest(T.name_ReservedNameIDs))
            {
                bool bReservedOk = true;

                for (uint i=0; i<NumberNameRecords; i++)
                {
                    NameRecord nr = GetNameRecord(i);

                    if (nr != null)
                    {
                        if (nr.NameID >= 21 && nr.NameID <= 255)
                        {
                            string s = "platID = " + nr.PlatformID 
                                + ", encID = " + nr.EncodingID
                                + ", langID = " + nr.LanguageID
                                + ", nameID = " + nr.NameID;
                            v.Error(T.name_ReservedNameIDs, E.name_E_ReservedNameID, m_tag, s);
                            bReservedOk = false;
                            break;
                        }
                    }
                    else
                    {
                        v.Warning(T.name_ReservedNameIDs, W._TEST_W_OtherErrorsInTable, m_tag);
                        bReservedOk = false;
                        break;
                    }
                }

                if (bReservedOk)
                {
                    v.Pass(T.name_ReservedNameIDs, P.name_P_ReservedNameID, m_tag);
                }
            }

            if (v.PerformTest(T.name_BothPlatforms))
            {
                bool bMac = false;
                bool bMS = false;


                for (uint i=0; i<NumberNameRecords; i++)
                {
                    NameRecord nr = GetNameRecord(i);
                    if (nr != null)
                    {

                        if (nr.PlatformID == 1)
                        {
                            bMac = true;
                        }
                        else if (nr.PlatformID == 3)
                        {
                            bMS = true;
                        }
                    }
                }

                if (bMac && bMS)
                {
                    v.Pass(T.name_BothPlatforms, P.name_P_BothPlatforms, m_tag);
                }
                else if (!bMac)
                {
                    v.Error(T.name_BothPlatforms, E.name_E_NoMacPlatform, m_tag);
					bRet = false;
                }
                else if (!bMS)
                {
                    v.Error(T.name_BothPlatforms, E.name_E_NoMSPlatform, m_tag);
					bRet = false;
                }
            }

            if (v.PerformTest(T.name_VersionString))
            {
                bool bFound = false;
                string sVersion = "";

                for (uint i=0; i<NumberNameRecords; i++)
                {
                    NameRecord nr = GetNameRecord(i);
                    if (nr != null)
                    {
                        if (nr.PlatformID    == 3       // ms
                            && (nr.EncodingID == 1 /* unicode */ || nr.EncodingID == 0 /*symbol*/)
                            && nr.NameID     == 5)      // version string
                        {
                            bFound = true;

                            bool bVerStringValid = false;
                            byte [] buf = GetEncodedString(nr);

							string s = "";

                            if (buf != null)
                            {
                                sVersion = "";
                                for (int j=0; j<buf.Length/2; j++)
                                {
                                    char c = (char)(ushort)(buf[j*2]<<8 | buf[j*2+1]);
                                    sVersion += c;
                                }

                                if (sVersion.Length >= 11
                                    && sVersion.StartsWith("Version ")
                                    && Char.IsDigit(sVersion, 8))
                                {
                                    int j = 9;
                            
                                    // advance past the digits in the major number
                                    while (j < sVersion.Length)
                                    {
                                        if (Char.IsDigit(sVersion, j))
                                        {
                                            j++;
                                        }
                                        else
                                        {
                                            break;
                                        }
                                    }

                                    // if major number is followed by a period
                                    if (sVersion[j] == '.')
                                    {
                                        // advance past the period
                                        j++;

                                        // check for a digit
                                        if (Char.IsDigit(sVersion, j))
                                        {
                                            bVerStringValid = true;
                                        }
                                    }
                                }
                            }
                        
							s = "platID = " + nr.PlatformID 
								+ ", encID = " + nr.EncodingID
								+ ", langID = " + nr.LanguageID
								+ ", \"" + sVersion + "\"";

							if (bVerStringValid)
							{
								v.Pass(T.name_VersionString, P.name_P_VersionStringFormat, m_tag, s);
							}
							else
                            {
                                v.Error(T.name_VersionString, E.name_E_VersionStringFormat, m_tag, s);
                                bRet = false;
                            }

                            // compare to mac version string if present
                            string sMacVer = GetString(1, 0, 0xffff, 5);
                            if (sMacVer != null)
                            {
                                if (sVersion.CompareTo(sMacVer) != 0)
                                {
                                    v.Warning(T.name_VersionString, W.name_W_VersionMismatch_MS_MAC, m_tag);
                                }
                            }

							// compare to 3,10 version string if present
							string s310Ver = GetString(3, 10, nr.LanguageID, 5);
							if (s310Ver != null)
							{
								if (sVersion.CompareTo(s310Ver) != 0)
								{
									string s310 = "platID = 3, encID = 10, langID = " + nr.LanguageID
										+ ", \"" + s310Ver + "\"";
									v.Warning(T.name_VersionString, W.name_W_VersionMismatch_3_1_3_10, m_tag, s + " / " + s310);
								}
							}
                        }
                    }
                }

                if (!bFound)
                {
                    v.Error(T.name_VersionString, E.name_E_VersionStringNotFound, m_tag);
                    bRet = false;
                }
            }

            if (v.PerformTest(T.name_PlatformSpecificEncoding))
            {
                bool bIDsOk = true;

                for (uint i=0; i<NumberNameRecords; i++)
                {
                    NameRecord nr = GetNameRecord(i);
                    if (nr != null)
                    {
                        if (nr.PlatformID == 0) // unicode
                        {
                            if (nr.EncodingID > 3)
                            {
                                string s = "platID = " + nr.PlatformID 
                                    + ", encID = " + nr.EncodingID
                                    + ", langID = " + nr.LanguageID
                                    + ", nameID = " + nr.NameID;
                                v.Error(T.name_PlatformSpecificEncoding, E.name_E_PlatformSpecificEncoding, m_tag, s);
                                bIDsOk = false;
                                bRet = false;
                            }
                        }
                        else if (nr.PlatformID == 1) // mac
                        {
                            if (nr.EncodingID > 32)
                            {
                                string s = "platID = " + nr.PlatformID 
                                    + ", encID = " + nr.EncodingID
                                    + ", langID = " + nr.LanguageID
                                    + ", nameID = " + nr.NameID;
                                v.Error(T.name_PlatformSpecificEncoding, E.name_E_PlatformSpecificEncoding, m_tag, s);
                                bIDsOk = false;
                                bRet = false;
                            }
                        }
                        else if (nr.PlatformID == 2) // iso
                        {
                            if (nr.EncodingID > 2)
                            {
                                string s = "platID = " + nr.PlatformID 
                                    + ", encID = " + nr.EncodingID
                                    + ", langID = " + nr.LanguageID
                                    + ", nameID = " + nr.NameID;
                                v.Error(T.name_PlatformSpecificEncoding, E.name_E_PlatformSpecificEncoding, m_tag, s);
                                bIDsOk = false;
                                bRet = false;
                            }
                        }
                        else if (nr.PlatformID == 3) // MS
                        {
                            if (nr.EncodingID > 10)
                            {
                                string s = "platID = " + nr.PlatformID 
                                    + ", encID = " + nr.EncodingID
                                    + ", langID = " + nr.LanguageID
                                    + ", nameID = " + nr.NameID;
                                v.Error(T.name_PlatformSpecificEncoding, E.name_E_PlatformSpecificEncoding, m_tag, s);
                                bIDsOk = false;
                                bRet = false;
                            }
                        }
                        /*
                        else if (nr.PlatformID == 4) // Custom
                        {
                        }
                        */

                    }
                    else
                    {
                        v.Warning(T.name_PlatformSpecificEncoding, W._TEST_W_OtherErrorsInTable, m_tag);
                        bIDsOk = false;
                        break;
                    }
                }

                if (bIDsOk)
                {
                    v.Pass(T.name_PlatformSpecificEncoding, P.name_P_PlatformSpecificEncoding, m_tag);
                }
            }

            if (v.PerformTest(T.name_MSLanguageIDs))
            {
                bool bFound = false;
                bool bIDsOk = true;

                ushort [] MSLangIDs = // taken from Q224804
                    {
                        0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409,
                        0x040a, 0x040b, 0x040c, 0x040D, 0x040e, 0x040F, 0x0410, 0x0411, 0x0412,
                        0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041a, 0x041b,
                        0x041c, 0x041D, 0x041E, 0x041f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424,
                        0x0425, 0x0426, 0x0427, 0x0429, 0x042a, 0x042b, 0x042c, 0x042D, 0x042e,
                        0x042f, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
                        0x0438, 0x0439, 0x043b, 0x043d, 0x043e, 0x043f, 0x0441, 0x0443, 0x0444,
                        0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d,
                        0x044e, 0x044f, 0x0457, 0x0459, 0x0461, 0x0801, 0x0804, 0x0807, 0x0809,
                        0x080a, 0x080c, 0x0810, 0x0812, 0x0813, 0x0814, 0x0816, 0x0818, 0x0819,
                        0x081a, 0x081d, 0x0820, 0x0827, 0x082c, 0x083e, 0x0843, 0x0860, 0x0861,
                        0x0C01, 0x0C04, 0x0c07, 0x0c09, 0x0c0a, 0x0c0c, 0x0c1a, 0x1001, 0x1004,
                        0x1007, 0x1009, 0x100a, 0x100c, 0x1401, 0x1404, 0x1407, 0x1409, 0x140a,
                        0x140c, 0x1801, 0x1809, 0x180a, 0x180c, 0x1C01, 0x1c09, 0x1c0a, 0x2001,
                        0x2009, 0x200a, 0x2401, 0x2409, 0x240a, 0x2801, 0x2809, 0x280a, 0x2C01,
                        0x2c09, 0x2c0a, 0x3001, 0x3009, 0x300a, 0x3401, 0x3409, 0x340a, 0x3801,
                        0x380a, 0x3C01, 0x3c0a, 0x4001, 0x400a, 0x440a, 0x480a, 0x4c0a, 0x500a
                    };

                for (uint i=0; i<NumberNameRecords; i++)
                {
                    NameRecord nr = GetNameRecord(i);
                    if (nr != null)
                    {
                        if (nr.PlatformID == 3 && nr.EncodingID == 1)
                        {
                            bFound = true;

                            bool bValidID = false;
                            for (uint j=0; j<MSLangIDs.Length; j++)
                            {
                                if (nr.LanguageID == MSLangIDs[j])
                                {
                                    bValidID = true;
                                    break;
                                }
                            }

                            if (!bValidID)
                            {
                                string s = "platID = " + nr.PlatformID 
                                    + ", encID = " + nr.EncodingID
                                    + ", langID = 0x" + nr.LanguageID.ToString("x4")
                                    + ", nameID = " + nr.NameID;
                                v.Error(T.name_MSLanguageIDs, E.name_E_MSLanguageID, m_tag, s);
                                bIDsOk = false;
                                bRet = false;
                            }
                        }
                    }
                }

                if (bFound && bIDsOk)
                {
                    v.Pass(T.name_MSLanguageIDs, P.name_P_MSLanguageID, m_tag);
                }
            }

            if (v.PerformTest(T.name_unicode_length))
            {
                bool bLengthsOk = true;

                for (uint i=0; i<NumberNameRecords; i++)
                {
                    NameRecord nr = GetNameRecord(i);
                    if (nr != null)
                    {
                        if (nr.PlatformID == 0 || nr.PlatformID == 2 || // unicode or iso platform
                            (nr.PlatformID == 3 && nr.EncodingID == 1)) // microsoft platform, unicode encoding
                        {
                            if ((nr.StringLength & 1) == 1)
                            {
                                string s = "platID = " + nr.PlatformID 
                                    + ", encID = " + nr.EncodingID
                                    + ", langID = " + nr.LanguageID
                                    + ", nameID = " + nr.NameID
                                    + ", length = " + nr.StringLength;
                                v.Error(T.name_unicode_length, E.name_E_UnicodeLength, m_tag, s);
                                bLengthsOk = false;
                                bRet = false;
                            }
                        }
                    }
                    else
                    {
                        v.Warning(T.name_unicode_length, W._TEST_W_OtherErrorsInTable, m_tag);
                        bLengthsOk = false;
                        break;
                    }
                }

                if (bLengthsOk)
                {
                    v.Pass(T.name_unicode_length, P.name_P_UnicodeLength, m_tag);
                }
            }

            if (v.PerformTest(T.name_Postscript))
            {
                bool bPostscriptOk = true;

                string sPostscriptMac = GetString(1, 0, 0, 6);
                if (sPostscriptMac != null)
                {
                    if (sPostscriptMac.Length > 63)
                    {
                        v.Error(T.name_Postscript, E.name_E_Postscript_length, m_tag, "name string (1, 0, 0, 6) is " + sPostscriptMac.Length + " characters long");
                        bRet = false;
                        bPostscriptOk = false;
                    }

                    for (int i=0; i<sPostscriptMac.Length; i++)
                    {
                        char c = sPostscriptMac[i];
                        if (c < 33 || c > 126 || c=='[' || c==']' || c=='(' || c==')' || c=='{' || c=='}' || c=='<' || c=='>' || c=='/' || c=='%')
                        {
                            v.Error(T.name_Postscript, E.name_E_Postscript_chars, m_tag, "name string (1, 0, 0, 6) contains an illegal character at index " + i);
                            bRet = false;
                            bPostscriptOk = false;
                        }
                    }
                }

                ushort nEncoding = 1;
                if (fontOwner.ContainsMsSymbolEncodedCmap())
                {
                    nEncoding = 0;
                }

                string sPostscriptMS = GetString(3, nEncoding, 0x409, 6); // ms
                if (sPostscriptMS != null)
                {
                    if (sPostscriptMS.Length > 63)
                    {
                        v.Error(T.name_Postscript, E.name_E_Postscript_length, m_tag, "name string (3, " + nEncoding + ", 0x409, 6) is " + sPostscriptMS.Length + " characters long");
                        bRet = false;
                        bPostscriptOk = false;
                    }

                    for (int i=0; i<sPostscriptMS.Length; i++)
                    {
                        char c = sPostscriptMS[i];
                        if (c < 33 || c > 126 || c=='[' || c==']' || c=='(' || c==')' || c=='{' || c=='}' || c=='<' || c=='>' || c=='/' || c=='%')
                        {
                            v.Error(T.name_Postscript, E.name_E_Postscript_chars, m_tag, "name string (3, " + nEncoding + ", 0x409, 6) contains an illegal character at index " + i);
                            bRet = false;
                            bPostscriptOk = false;
                        }
                    }
                }

                if (sPostscriptMac==null && sPostscriptMS!=null)
                {
                    v.Error(T.name_Postscript, E.name_E_Postscript_missing, m_tag, "Mac Postscript string is missing, but MS Postscript string is present");
                    bRet = false;
                    bPostscriptOk = false;
                }
                else if (sPostscriptMac!=null && sPostscriptMS==null)
                {
                    v.Error(T.name_Postscript, E.name_E_Postscript_missing, m_tag, "MS Postscript string is missing, but Mac Postscript string is present");
                    bRet = false;
                    bPostscriptOk = false;
                }
                if (sPostscriptMac!=null && sPostscriptMS!=null)
                {
                    if (sPostscriptMac != sPostscriptMS)
                    {
                        v.Error(T.name_Postscript, E.name_E_Postscript_unequal, m_tag, "mac postscript = " + sPostscriptMac + ", MS postscript = " + sPostscriptMS );
                        bRet = false;
                        bPostscriptOk = false;
                    }
                }


                if (sPostscriptMac!=null && sPostscriptMS!=null && bPostscriptOk)
                {
                    v.Pass(T.name_Postscript, P.name_P_Postscript, m_tag);
                }
            }

            if (v.PerformTest(T.name_Subfamily))
            {
                string sStyle = GetStyleString();
                if (sStyle != null)
                {
                    Table_OS2 OS2Table = (Table_OS2)fontOwner.GetTable("OS/2");
                    if (OS2Table != null)
                    {
                        bool bStyleOk = true;
                        string sStyleDetails = "";
                        string s = sStyle.ToLower();

                        bool bItalic = ((OS2Table.fsSelection & 0x01) != 0 );
                        bool bBold   = ((OS2Table.fsSelection & 0x20) != 0 );

                        if (bItalic)                            
                        {
                            if (s.IndexOf("italic") == -1 && s.IndexOf("oblique") == -1)
                            {
                                bStyleOk = false;
                                sStyleDetails = "OS/2.fsSelection italic bit is set, but subfamily string = '" + sStyle + "'";
                            }
                        }
                        else
                        {
                            if (s.IndexOf("italic") != -1 || s.IndexOf("oblique") != -1)
                            {
                                bStyleOk = false;
                                sStyleDetails = "OS/2.fsSelection italic bit is clear, but subfamily string = '" + sStyle + "'";
                            }
                        }

                        if (bBold)                            
                        {
                            if (s.IndexOf("bold") == -1)
                            {
                                bStyleOk = false;
                                sStyleDetails = "OS/2.fsSelection bold bit is set, but subfamily string = '" + sStyle + "'";
                            }
                        }
                        else
                        {
                            if (s.IndexOf("bold") != -1)
                            {
                                bStyleOk = false;
                                sStyleDetails = "OS/2.fsSelection bold bit is clear, but subfamily string = '" + sStyle + "'";
                            }
                        }

                        if (bStyleOk)
                        {
                            v.Pass(T.name_Subfamily, P.name_P_subfamily, m_tag);
                        }
                        else
                        {
                            v.Warning(T.name_Subfamily, W.name_W_subfamily_style, m_tag, sStyleDetails);
                        }
                    }
                }
            }


            if (v.PerformTest(T.name_NoFormat14))
            {
                bool bStringOK = true;
                for (uint i=0; i<NumberNameRecords; i++)
                {
                    NameRecord nr = GetNameRecord(i);
                    if (nr != null &&
                        nr.NameID == 19 &&
                        nr.PlatformID == 0 &&
                        nr.EncodingID == 5 )
                    {
                        string sDetails = 
                            "name string(" + nr.PlatformID 
                            + ", " + nr.EncodingID
                            + ", 0x" + nr.LanguageID.ToString("x4")
                            + ", " + nr.NameID + 
                            ", offset=0x" + 
                            nr.StringOffset.ToString("x4") + ")";
                        v.Error( T.name_NoFormat14, 
                                 E.name_E_NoFormat14,
                                 m_tag,
                                 sDetails );
						bRet = false;
                        bStringOK = false;
                    }
                }
                if ( bStringOK )
                {
                    string sDetails = "PlatformID=0, EncodingID=5 is for " +
                        "Variation Sequences (Format 14)";
                    v.Pass(T.name_NoFormat14, P.name_P_NoFormat14, m_tag, 
                           sDetails );
                }

            }

            if (v.PerformTest(T.name_SampleString))
            {
                Table_cmap cmapTable = (Table_cmap)fontOwner.GetTable("cmap");
                if (cmapTable != null)
                {
                    for (uint i=0; i<NumberNameRecords; i++)
                    {
                        NameRecord nr = GetNameRecord(i);
                        if (nr != null)
                        {
                            if (nr.NameID == 19)
                            {
                                if ( nr.PlatformID == 0 &&
                                     nr.EncodingID == 5 ) 
                                {
                                    // Unicode platform encoding ID 5 can be 
                                    // used for encodings in the 'cmap' table 
                                    // but not for strings in the 'name' table. 
                                    // It has already been flagged as an error,
                                    // so we will just skip it here.
                                    break;
                                }
                                Table_cmap.Subtable CmapSubTable = cmapTable.GetSubtable(nr.PlatformID, nr.EncodingID);
                                if (CmapSubTable != null)
                                {
                                    bool bStringOk = true;

                                    byte[] strbuf = GetEncodedString(nr);
                            
                                    for (uint j=0; j<strbuf.Length;)
                                    {

                                        if (CmapSubTable.MapCharToGlyph(strbuf, j, true) == 0)
                                        {
                                            string sDetails = "name string(" + nr.PlatformID 
                                                + ", " + nr.EncodingID
                                                + ", 0x" + nr.LanguageID.ToString("x4")
                                                + ", " + nr.NameID
                                                + "), character at index " + j + " is not mapped";
                                            v.Error(T.name_SampleString, E.name_E_sample, m_tag, sDetails);
                                            bStringOk = false;
                                            bRet = false;
                                            break;
                                        }

                                        j += CmapSubTable.BytesInChar(strbuf, j);
                                    }

                                    if (bStringOk)
                                    {
                                        string sDetails = "name string(" + nr.PlatformID 
                                            + ", " + nr.EncodingID
                                            + ", 0x" + nr.LanguageID.ToString("x4")
                                            + ", " + nr.NameID
                                            + ")";
                                        v.Pass(T.name_SampleString, P.name_P_sample, m_tag, sDetails);
                                    }
                                }
                            }
                        }
                    }
                }
            }

			if (v.PerformTest(T.name_PreferredFamily))
			{
				bool bFound = false;

				for (uint i=0; i<NumberNameRecords; i++)
				{
					NameRecord nr = GetNameRecord(i);
					if (nr != null)
					{
						if (nr.NameID == 16)
						{
							string sPrefFam = this.GetString(nr.PlatformID, nr.EncodingID, nr.LanguageID, 16);

							string s = "platID = " + nr.PlatformID 
									+ ", encID = " + nr.EncodingID
									+ ", langID = " + nr.LanguageID
									+ ", nameID = " + nr.NameID
									+ ", \"" + sPrefFam + "\"";
							v.Info(T.name_PreferredFamily, I.name_I_Preferred_family_present, m_tag, s);

							bFound = true;
						}
					}
				}

				if (!bFound)
				{
					v.Info(T.name_PreferredFamily, I.name_I_Preferred_family_not_present, m_tag);
				}
			}

			if (v.PerformTest(T.name_PreferredSubfamily))
			{
				bool bFound = false;

				for (uint i=0; i<NumberNameRecords; i++)
				{
					NameRecord nr = GetNameRecord(i);
					if (nr != null)
					{
						if (nr.NameID == 17)
						{
							string sPrefSubfam = this.GetString(nr.PlatformID, nr.EncodingID, nr.LanguageID, 17);

							string s = "platID = " + nr.PlatformID 
								+ ", encID = " + nr.EncodingID
								+ ", langID = " + nr.LanguageID
								+ ", nameID = " + nr.NameID
								+ ", \"" + sPrefSubfam + "\"";
							v.Info(T.name_PreferredSubfamily, I.name_I_Preferred_subfamily_present, m_tag, s);

							bFound = true;
						}
					}
				}

				if (!bFound)
				{
					v.Info(T.name_PreferredSubfamily, I.name_I_Preferred_subfamily_not_present, m_tag);
				}
			}

            if (v.PerformTest(T.name_CopyrightConsistent))
            {
                bool bCopyrightOk = true;

                // get mac roman English Copyright string if present
                string sMac = GetString(1, 0, 0, 0);

                // get windows 3,0 English Copyright string if present
                string sWin3_0 = GetString(3, 0, 1033, 0);

                // get windows 3,1 English Copyright string if present
                string sWin3_1 = GetString(3, 1, 1033, 0);

                // get windows 3,10 English Copyright string if present
                string sWin3_10 = GetString(3, 10, 1033, 0);

                // compare strings

                if (sMac != null)
                {
                    if (sWin3_0 != null)
                    {
                        if (sWin3_0.CompareTo(sMac) != 0)
                        {
                            string sDetails = "(1,0,0,0)='" + sMac + "', (3,0,1033,0)='" + sWin3_0 + "'";
                            v.Warning(T.name_CopyrightConsistent, W.name_W_CopyrightInconsistent, m_tag, sDetails);
                            bCopyrightOk = false;
                        }
                    }

                    if (sWin3_1 != null)
                    {
                        if (sWin3_1.CompareTo(sMac) != 0)
                        {
                            string sDetails = "(1,0,0,0)='" + sMac + "', (3,1,1033,0)='" + sWin3_1 + "'";
                            v.Warning(T.name_CopyrightConsistent, W.name_W_CopyrightInconsistent, m_tag, sDetails);
                            bCopyrightOk = false;
                        }
                    }

                    if (sWin3_10 != null)
                    {
                        if (sWin3_10.CompareTo(sMac) != 0)
                        {
                            string sDetails = "(1,0,0,0)='" + sMac + "', (3,10,1033,0)='" + sWin3_10 + "'";
                            v.Warning(T.name_CopyrightConsistent, W.name_W_CopyrightInconsistent, m_tag, sDetails);
                            bCopyrightOk = false;
                        }
                    }
                }

                if (sWin3_0 != null)
                {
                    if (sWin3_1 != null)
                    {
                        if (sWin3_1.CompareTo(sWin3_0) != 0)
                        {
                            string sDetails = "(3,0,1033,0)='" + sWin3_0 + "', (3,1,1033,0)='" + sWin3_1 + "'";
                            v.Warning(T.name_CopyrightConsistent, W.name_W_CopyrightInconsistent, m_tag, sDetails);
                            bCopyrightOk = false;
                        }
                    }

                    if (sWin3_10 != null)
                    {
                        if (sWin3_10.CompareTo(sWin3_0) != 0)
                        {
                            string sDetails = "(3,0,1033,0)='" + sWin3_0 + "', (3,10,1033,0)='" + sWin3_10 + "'";
                            v.Warning(T.name_CopyrightConsistent, W.name_W_CopyrightInconsistent, m_tag, sDetails);
                            bCopyrightOk = false;
                        }
                    }
                }

                if (sWin3_1 != null)
                {
                    if (sWin3_10 != null)
                    {
                        if (sWin3_10.CompareTo(sWin3_1) != 0)
                        {
                            string sDetails = "(3,1,1033,0)='" + sWin3_1 + "', (3,10,1033,0)='" + sWin3_10 + "'";
                            v.Warning(T.name_CopyrightConsistent, W.name_W_CopyrightInconsistent, m_tag, sDetails);
                            bCopyrightOk = false;
                        }
                    }
                }

                if (bCopyrightOk)
                {
                    v.Pass(T.name_CopyrightConsistent, P.name_P_CopyrightConsistent, m_tag);
                }
                else
                {
                    //bRet = false;
                }


            }

            if (v.PerformTest(T.name_TrademarkConsistent))
            {
                bool bTrademarkOk = true;

                // get mac roman English Trademark string if present
                string sMac = GetString(1, 0, 0, 7);

                // get windows 3,0 English Trademark string if present
                string sWin3_0 = GetString(3, 0, 1033, 7);

                // get windows 3,1 English Trademark string if present
                string sWin3_1 = GetString(3, 1, 1033, 7);

                // get windows 3,10 English Trademark string if present
                string sWin3_10 = GetString(3, 10, 1033, 7);

                // compare strings

                if (sMac != null)
                {
                    if (sWin3_0 != null)
                    {
                        if (sWin3_0.CompareTo(sMac) != 0)
                        {
                            string sDetails = "(1,0,0,7)='" + sMac + "', (3,0,1033,7)='" + sWin3_0 + "'";
                            v.Warning(T.name_TrademarkConsistent, W.name_W_TrademarkInconsistent, m_tag, sDetails);
                            bTrademarkOk = false;
                        }
                    }

                    if (sWin3_1 != null)
                    {
                        if (sWin3_1.CompareTo(sMac) != 0)
                        {
                            string sDetails = "(1,0,0,7)='" + sMac + "', (3,1,1033,7)='" + sWin3_1 + "'";
                            v.Warning(T.name_TrademarkConsistent, W.name_W_TrademarkInconsistent, m_tag, sDetails);
                            bTrademarkOk = false;
                        }
                    }

                    if (sWin3_10 != null)
                    {
                        if (sWin3_10.CompareTo(sMac) != 0)
                        {
                            string sDetails = "(1,0,0,7)='" + sMac + "', (3,10,1033,7)='" + sWin3_10 + "'";
                            v.Warning(T.name_TrademarkConsistent, W.name_W_TrademarkInconsistent, m_tag, sDetails);
                            bTrademarkOk = false;
                        }
                    }
                }

                if (sWin3_0 != null)
                {
                    if (sWin3_1 != null)
                    {
                        if (sWin3_1.CompareTo(sWin3_0) != 0)
                        {
                            string sDetails = "(3,0,1033,7)='" + sWin3_0 + "', (3,1,1033,7)='" + sWin3_1 + "'";
                            v.Warning(T.name_TrademarkConsistent, W.name_W_TrademarkInconsistent, m_tag, sDetails);
                            bTrademarkOk = false;
                        }
                    }

                    if (sWin3_10 != null)
                    {
                        if (sWin3_10.CompareTo(sWin3_0) != 0)
                        {
                            string sDetails = "(3,0,1033,7)='" + sWin3_0 + "', (3,10,1033,7)='" + sWin3_10 + "'";
                            v.Warning(T.name_TrademarkConsistent, W.name_W_TrademarkInconsistent, m_tag, sDetails);
                            bTrademarkOk = false;
                        }
                    }
                }

                if (sWin3_1 != null)
                {
                    if (sWin3_10 != null)
                    {
                        if (sWin3_10.CompareTo(sWin3_1) != 0)
                        {
                            string sDetails = "(3,1,1033,7)='" + sWin3_1 + "', (3,10,1033,7)='" + sWin3_10 + "'";
                            v.Warning(T.name_TrademarkConsistent, W.name_W_TrademarkInconsistent, m_tag, sDetails);
                            bTrademarkOk = false;
                        }
                    }
                }

                if (bTrademarkOk)
                {
                    v.Pass(T.name_TrademarkConsistent, P.name_P_TrademarkConsistent, m_tag);
                }
                else
                {
                    //bRet = false;
                }
            }

            if (v.PerformTest(T.name_DescriptionConsistent))
            {
                bool bDescriptionOk = true;

                // get mac roman English Description string if present
                string sMac = GetString(1, 0, 0, 10);

                // get windows 3,0 English Description string if present
                string sWin3_0 = GetString(3, 0, 1033, 10);

                // get windows 3,1 English Description string if present
                string sWin3_1 = GetString(3, 1, 1033, 10);

                // get windows 3,10 English Description string if present
                string sWin3_10 = GetString(3, 10, 1033, 10);

                // compare strings

                if (sMac != null)
                {
                    if (sWin3_0 != null)
                    {
                        if (sWin3_0.CompareTo(sMac) != 0)
                        {
                            string sDetails = "(1,0,0,10)='" + sMac + "', (3,0,1033,10)='" + sWin3_0 + "'";
                            v.Warning(T.name_DescriptionConsistent, W.name_W_DescriptionInconsistent, m_tag, sDetails);
                            bDescriptionOk = false;
                        }
                    }

                    if (sWin3_1 != null)
                    {
                        if (sWin3_1.CompareTo(sMac) != 0)
                        {
                            string sDetails = "(1,0,0,10)='" + sMac + "', (3,1,1033,10)='" + sWin3_1 + "'";
                            v.Warning(T.name_DescriptionConsistent, W.name_W_DescriptionInconsistent, m_tag, sDetails);
                            bDescriptionOk = false;
                        }
                    }

                    if (sWin3_10 != null)
                    {
                        if (sWin3_10.CompareTo(sMac) != 0)
                        {
                            string sDetails = "(1,0,0,10)='" + sMac + "', (3,10,1033,10)='" + sWin3_10 + "'";
                            v.Warning(T.name_DescriptionConsistent, W.name_W_DescriptionInconsistent, m_tag, sDetails);
                            bDescriptionOk = false;
                        }
                    }
                }

                if (sWin3_0 != null)
                {
                    if (sWin3_1 != null)
                    {
                        if (sWin3_1.CompareTo(sWin3_0) != 0)
                        {
                            string sDetails = "(3,0,1033,10)='" + sWin3_0 + "', (3,1,1033,10)='" + sWin3_1 + "'";
                            v.Warning(T.name_DescriptionConsistent, W.name_W_DescriptionInconsistent, m_tag, sDetails);
                            bDescriptionOk = false;
                        }
                    }

                    if (sWin3_10 != null)
                    {
                        if (sWin3_10.CompareTo(sWin3_0) != 0)
                        {
                            string sDetails = "(3,0,1033,10)='" + sWin3_0 + "', (3,10,1033,10)='" + sWin3_10 + "'";
                            v.Warning(T.name_DescriptionConsistent, W.name_W_DescriptionInconsistent, m_tag, sDetails);
                            bDescriptionOk = false;
                        }
                    }
                }

                if (sWin3_1 != null)
                {
                    if (sWin3_10 != null)
                    {
                        if (sWin3_10.CompareTo(sWin3_1) != 0)
                        {
                            string sDetails = "(3,1,1033,10)='" + sWin3_1 + "', (3,10,1033,10)='" + sWin3_10 + "'";
                            v.Warning(T.name_DescriptionConsistent, W.name_W_DescriptionInconsistent, m_tag, sDetails);
                            bDescriptionOk = false;
                        }
                    }
                }

                if (bDescriptionOk)
                {
                    v.Pass(T.name_DescriptionConsistent, P.name_P_DescriptionConsistent, m_tag);
                }
                else
                {
                    //bRet = false;
                }

            }


            return bRet;
        }
Ejemplo n.º 22
0
        /************************
         * public methods
         */


        public bool Validate(Validator v, OTFontVal fontOwner)
        {
            bool bRet = true;

            if (v.PerformTest(T.hhea_version))
            {
                if (TableVersionNumber.GetUint() == 0x00010000)
                {
                    v.Pass(T.hhea_version, P.hhea_P_version, m_tag);
                }
                else
                {
                    v.Error(T.hhea_version, E.hhea_E_version, m_tag, "0x"+TableVersionNumber.GetUint().ToString("x8"));
                    bRet = false;
                }
            }

            if (v.PerformTest(T.hhea_AscenderPositive))
            {
                if (Ascender <= 0)
                {
                    string s = "Ascender = " + Ascender;
                    v.Error(T.hhea_AscenderPositive, E.hhea_E_AscenderPositive, m_tag, s);
                    bRet = false;
                }
                else
                {
                    v.Pass(T.hhea_AscenderPositive, P.hhea_P_AscenderPositive, m_tag);
                }
            }

            if (v.PerformTest(T.hhea_DescenderNegative))
            {
                if (Descender >= 0)
                {
                    string s = "Descender = " + Descender;
                    v.Error(T.hhea_DescenderNegative, E.hhea_E_DescenderNegative, m_tag, s);
                    bRet = false;
                }
                else
                {
                    v.Pass(T.hhea_DescenderNegative, P.hhea_P_DescenderNegative, m_tag);
                }
            }

            Table_head headTable = (Table_head)fontOwner.GetTable("head");

            if (headTable != null)
            {
                if (v.PerformTest(T.hhea_Ascender_yMax))
                {
                    if (Ascender > headTable.yMax)
                    {
                        string s = "Ascender = " + Ascender + ", head.yMax = " + headTable.yMax;
                        v.Info(T.hhea_Ascender_yMax, I.hhea_I_Ascender_yMax, m_tag, s);
                        // bRet = false;
                    }
                    else
                    {
                        v.Pass(T.hhea_Ascender_yMax, P.hhea_P_Ascender_yMax, m_tag);
                    }
                }

                if (v.PerformTest(T.hhea_Descender_yMin))
                {
                    if (Descender < headTable.yMin)
                    {
                        string s = "Descender = " + Descender + ", head.yMin = " + headTable.yMin;
                        v.Info(T.hhea_Descender_yMin, I.hhea_I_Descender_yMin, m_tag, s);
                        // bRet = false;
                    }
                    else
                    {
                        v.Pass(T.hhea_Descender_yMin, P.hhea_P_Descender_yMin, m_tag);
                    }
                }
            }
            else
            {
                v.Error(T.hhea_Ascender_yMax, E._TEST_E_TableMissing, m_tag, "head");
				bRet = false;
            }

            if (v.PerformTest(T.hhea_LineGapPositive))
            {
                if (LineGap < 0)
                {
                    string s = "LineGap = " + LineGap;
                    v.Warning(T.hhea_LineGapPositive, W.hhea_W_LineGapPositive, m_tag, s);
                    //bRet = false;
                }
                else
                {
                    v.Pass(T.hhea_LineGapPositive, P.hhea_P_LineGapPositive, m_tag);
                }
            }

            Table_OS2 OS2Table = (Table_OS2)fontOwner.GetTable("OS/2");
            if (OS2Table != null)
            {

                if (v.PerformTest(T.hhea_Ascender_usWinAscent))
                {
                    if (OS2Table.usWinAscent != Ascender)
                    {
                        string s = "hhea.Ascender = " + Ascender + ", OS/2.usWinAscent = " + OS2Table.usWinAscent;
                        v.Warning(T.hhea_Ascender_usWinAscent, W.hhea_W_Ascender_usWinAscent, m_tag, s);
                    }
                    else
                    {
                        v.Pass(T.hhea_Ascender_usWinAscent, P.hhea_P_Ascender_usWinAscent, m_tag);
                    }
                }

                if (v.PerformTest(T.hhea_Descender_usWinDescent))
                {
                    if (OS2Table.usWinDescent != (Descender * -1))
                    {
                        string s = "hhea.Descender = " + Descender + ", OS/2.usWinDescent = " + OS2Table.usWinDescent;
                        v.Warning(T.hhea_Descender_usWinDescent, W.hhea_W_Descender_usWinDescent, m_tag, s);
                    }
                    else
                    {
                        v.Pass(T.hhea_Descender_usWinDescent, P.hhea_P_Descender_usWinDescent, m_tag);
                    }
                }

                // Microsoft is recommending that Ascender, Descender and LineGap be in line with OS2.winAscent, OS2.winDescent
                // and formulated value for LineGap to make sure font displays the same on Apple as it does no Windows. 
                if (v.PerformTest(T.hhea_LineGap_minGap))
                {
                    int sMinGap = (OS2Table.usWinAscent + OS2Table.usWinDescent) - (Ascender - Descender);
                    if (LineGap < sMinGap)
                    {
                        string s = "LineGap = " + LineGap + ", recommended = " + sMinGap;
                        v.Warning(T.hhea_LineGap_minGap, W.hhea_W_LineGap_minGap, m_tag, s);
                        //bRet = false;
                    }
                    else
                    {
                        v.Pass(T.hhea_LineGap_minGap, P.hhea_P_LineGap_minGap, m_tag);
                    }
                }
                else
                {
                    v.Error(T.hhea_LineGap_minGap, E._TEST_E_TableMissing, m_tag, "OS/2");
                }

            }
            else
            {
                v.Error(T.hhea_Ascender_usWinAscent, E._TEST_E_TableMissing, m_tag, "OS/2");
                v.Error(T.hhea_Descender_usWinDescent, E._TEST_E_TableMissing, m_tag, "OS/2");
                v.Error(T.hhea_LineGap_minGap, E._TEST_E_TableMissing, m_tag, "OS/2");
				bRet = false;
            }

            if (v.PerformTest(T.hhea_MinMax))
            {
                if (fontOwner.ContainsTrueTypeOutlines())
                {
                    Table_hmtx hmtxTable = (Table_hmtx)fontOwner.GetTable("hmtx");
                    Table_glyf glyfTable = (Table_glyf)fontOwner.GetTable("glyf");
                    Table_maxp maxpTable = (Table_maxp)fontOwner.GetTable("maxp");
                    if (hmtxTable == null)
                    {
                        v.Error(T.hhea_MinMax, E._TEST_E_TableMissing, m_tag, "hmtx");
						bRet = false;
                    }
                    else if (glyfTable == null)
                    {
                        v.Error(T.hhea_MinMax, E._TEST_E_TableMissing, m_tag, "glyf");
						bRet = false;
                    }
                    else if (maxpTable == null)
                    {
                        v.Error(T.hhea_MinMax, E._TEST_E_TableMissing, m_tag, "maxp");
						bRet = false;
                    }
                    else
                    {
                        ushort numGlyphs = fontOwner.GetMaxpNumGlyphs();

                        ushort awMax = 0;
                        short minLSB = 32767;
                        short minRSB = 32767;
                        short xmaxEx = -32768;

                        Table_hmtx.longHorMetric hm = null;

                        for (uint iGlyph = 0; iGlyph < numGlyphs; iGlyph++)
                        {
                            hm = hmtxTable.GetOrMakeHMetric(iGlyph, fontOwner);
                            if (hm == null)
                            {
                                break;
                            }

                            if (awMax  < hm.advanceWidth)
                            {
                                awMax  = hm.advanceWidth;

                                // We want to give the user feedback to know what glyph id
                                // has the bad width assigned
                                if (awMax > advanceWidthMax)
                                {
                                    string s = "glyph ID = " + iGlyph + ", advance width = " + awMax;
                                    v.Error(T.hhea_MinMax, E.hhea_E_advanceWidthMax, m_tag, s);
									bRet = false;
                                }
                            }

                            Table_glyf.header gh = glyfTable.GetGlyphHeader(iGlyph, fontOwner);
                            // calculate for all non-zero contours...this includes composites
                            if (gh != null
                                && gh.numberOfContours != 0)
                            {
                                if (minLSB > hm.lsb) minLSB = hm.lsb;

                                short rsb = (short)(hm.advanceWidth - hm.lsb - (gh.xMax - gh.xMin));
                                if (minRSB > rsb) minRSB = rsb;

                                short extent = (short)(hm.lsb + (gh.xMax - gh.xMin));
                                if (xmaxEx < extent) xmaxEx = extent;
                            }
                        }


                        if (hm != null)
                        {
                            if (advanceWidthMax == awMax)
                            {
                                v.Pass(T.hhea_MinMax, P.hhea_P_advanceWidthMax, m_tag);
                            }
                            else
                            {
                                string s = "actual = " + advanceWidthMax + ", calc = " + awMax;
                                v.Error(T.hhea_MinMax, E.hhea_E_advanceWidthMax, m_tag, s);
                                bRet = false;
                            }

                            if (minLeftSideBearing == minLSB)
                            {
                                v.Pass(T.hhea_MinMax, P.hhea_P_minLeftSideBearing, m_tag);
                            }
                            else
                            {
                                string s = "actual = " + minLeftSideBearing + ", calc = " + minLSB;
                                v.Error(T.hhea_MinMax, E.hhea_E_minLeftSideBearing, m_tag, s);
                                bRet = false;
                            }

                            if (minRightSideBearing == minRSB)
                            {
                                v.Pass(T.hhea_MinMax, P.hhea_P_minRightSideBearing, m_tag);
                            }
                            else
                            {
                                string s = "actual = " + minRightSideBearing + ", calc = " + minRSB;
                                v.Error(T.hhea_MinMax, E.hhea_E_minRightSideBearing, m_tag, s);
                                bRet = false;
                            }

                            if (xMaxExtent == xmaxEx)
                            {
                                v.Pass(T.hhea_MinMax, P.hhea_P_xMaxExtent, m_tag);
                            }
                            else
                            {
                                string s = "actual = " + xMaxExtent + ", calc = " + xmaxEx;
                                v.Error(T.hhea_MinMax, E.hhea_E_xMaxExtent, m_tag, s);
                                bRet = false;
                            }
                        }
                        else
                        {
                            v.Warning(T.hhea_MinMax, W.hhea_W_hmtx_invalid, m_tag, "unable to parse hmtx table");
                        }
                    }
                }
                else
                {
                    v.Info(T.hhea_MinMax, I._TEST_I_NotForCFF, m_tag, "test = hhea_MinMax");
                }
            }

            if (v.PerformTest(T.hhea_reserved))
            {
                if (reserved1 != 0)
                {
                    v.Error(T.hhea_reserved, E.hhea_E_reserved1, m_tag, reserved1.ToString());
                    bRet = false;
                }
                else if (reserved2 != 0)
                {
                    v.Error(T.hhea_reserved, E.hhea_E_reserved2, m_tag, reserved2.ToString());
                    bRet = false;
                }
                else if (reserved3 != 0)
                {
                    v.Error(T.hhea_reserved, E.hhea_E_reserved3, m_tag, reserved3.ToString());
                    bRet = false;
                }
                else if (reserved4 != 0)
                {
                    v.Error(T.hhea_reserved, E.hhea_E_reserved4, m_tag, reserved4.ToString());
                    bRet = false;
                }
                else
                {
                    v.Pass(T.hhea_reserved, P.hhea_P_reserved, m_tag);
                }
            }

            if (v.PerformTest(T.hhea_metricDataFormat))
            {
                if (metricDataFormat == 0)
                {
                    v.Pass(T.hhea_metricDataFormat, P.hhea_P_metricDataFormat, m_tag);
                }
                else
                {
                    v.Error(T.hhea_metricDataFormat, E.hhea_E_metricDataFormat, m_tag, metricDataFormat.ToString());
                    bRet = false;
                }
            }

            if (v.PerformTest(T.hhea_numberOfHMetrics))
            {
                Table_hmtx hmtxTable = (Table_hmtx)fontOwner.GetTable("hmtx");
                Table_maxp maxpTable = (Table_maxp)fontOwner.GetTable("maxp");
                if (hmtxTable == null)
                {
                    v.Error(T.hhea_numberOfHMetrics, E._TEST_E_TableMissing, m_tag, "hmtx");
					bRet = false;
                }
                else if (maxpTable == null)
                {
                    v.Error(T.hhea_numberOfHMetrics, E._TEST_E_TableMissing, m_tag, "maxp");
					bRet = false;
                }
                else
                {
                    ushort numGlyphs = fontOwner.GetMaxpNumGlyphs();
                    if (numberOfHMetrics*4 + (numGlyphs-numberOfHMetrics)*2 == hmtxTable.GetLength())
                    {
                        v.Pass(T.hhea_numberOfHMetrics, P.hhea_P_numberOfHMetrics, m_tag);
                    }
                    else
                    {
                        v.Error(T.hhea_numberOfHMetrics, E.hhea_E_numberOfHMetrics, m_tag);
                        bRet = false;
                    }
                }

            }

            if (v.PerformTest(T.hhea_caretSlope))
            {
                bool bSlopeOk = true;

                Table_post postTable = (Table_post)fontOwner.GetTable("post");

                if (postTable != null)
                {
                    uint ia = postTable.italicAngle.GetUint();
                    double dItalicAngle = postTable.italicAngle.GetDouble();

                    if (ia == 0)
                    {
                        if (caretSlopeRun != 0)
                        {
                            v.Error(T.hhea_caretSlope, E.hhea_E_caretSlopeRunNonZero_italicAngle, m_tag);
                            bSlopeOk = false;
                            bRet = false;
                        }
                    }
                    else
                    {
                        if (caretSlopeRun == 0)
                        {
                            v.Error(T.hhea_caretSlope, E.hhea_E_caretSlopeRunZero_italicAngle, m_tag);
                            bSlopeOk = false;
                            bRet = false;
                        }
                        else
                        {
                            double dActualAngle = 90.0 + postTable.italicAngle.GetDouble();
                            double dhheaAngle = (Math.Atan2(caretSlopeRise, caretSlopeRun)) * (180.0 / Math.PI);
                            if (Math.Abs(dActualAngle-dhheaAngle) >= 1.0)
                            {
                                string sDetails = "caretSlope Rise:Run = " + caretSlopeRise + ":" + caretSlopeRun +
                                    " (" + (dhheaAngle-90.0) + " degrees)" +
                                    ", post.italicAngle = 0x" + ia.ToString("x8") +
                                    " (" + postTable.italicAngle.GetDouble() + " degrees)";
                                v.Error(T.hhea_caretSlope, E.hhea_E_caretSlopeAngle_italicAngle, m_tag, sDetails);
                                bSlopeOk = false;
                                bRet = false;
                            }
                        }
                    }
                }
                else
                {
                    v.Error(T.hhea_caretSlope, E._TEST_E_TableMissing, m_tag, "post table missing, can't compare caret slope to italicAngle");
                    bSlopeOk = false;
					bRet = false;
                }


                if (bSlopeOk)
                {
                    v.Pass(T.hhea_caretSlope, P.hhea_P_caretSlopeAngle_italicAngle, m_tag);
                }
            }

            return bRet;
        }
Ejemplo n.º 23
0
            public bool Validate(Validator v, string sIdentity, OTTable table)
            {
                bool bRet = true;

                bRet &= ((val_GDEF)table).ValidateNoOverlap(m_offsetMarkGlyphSetsDefTable, CalcLength(), v, sIdentity, table.GetTag());

                if (MarkSetTableFormat != 1)
                {
                    v.Error(T.T_NULL, E.GDEF_E_MarkSetTableFormat, table.m_tag,
                            sIdentity + ": MarkSetTableFormat=" + MarkSetTableFormat.ToString());
                    bRet = false;
                }

                if (m_offsetMarkGlyphSetsDefTable + CalcLength() > m_bufTable.GetLength())
                {
                    v.Error(T.T_NULL, E.GDEF_E_MarkGlyphSetsDefTable_PastEOT, table.m_tag, sIdentity);
                    bRet = false;
                }

                v.Info(T.T_NULL, I.GDEF_I_MarkSetCount, table.m_tag, sIdentity + ": MarkSetCount=" + MarkSetCount);
                // TODO: check Coverage [MarkSetCount] array?

                if (bRet)
                {
                    v.Pass(T.T_NULL, P.GDEF_P_MarkGlyphSetsDefTable, table.m_tag, sIdentity);
                }

                return bRet;
            }
Ejemplo n.º 24
0
        /*****************
         * protected methods
         */

        /*****************
         * public methods
         */

        //meant to avoid code repetition (is called from OTFontVal too)
        public bool ValidateTable(OTTable table, Validator v, DirectoryEntry de, OTFontVal fontOwner)
        {
            String tname = GetTableManager().GetUnaliasedTableName(de.tag);
            bool   bRet  = true;

            // verify the checksum value from the directory entry matches the checksum for the table
            if (!(tname == "DSIG" && IsCollection()))
            {
                uint calcChecksum = 0;
                if (table != null)
                {
                    calcChecksum = table.CalcChecksum();
                }

                if (de.checkSum != calcChecksum)
                {
                    string s = "table '" + de.tag + "', calc: 0x" + calcChecksum.ToString("x8") + ", font: 0x" + de.checkSum.ToString("x8");
                    v.Error(T.T_NULL, E._DE_E_ChecksumError, de.tag, s);
                    bRet = false;
                }
            }

            // verify that table has pad bytes set to zero
            if (table != null)
            {
                uint nBytes = 0;
                try {
                    nBytes = GetNumPadBytesAfterTable(table);
                }
                catch (Exception e)
                {
                    v.ApplicationError(T.T_NULL, E._Table_E_Exception, de.tag, "GetNumPadBytesAfterTable: " + e.Message);
                    bRet = false;
                }

                bool bPadBytesZero = true;

                if (nBytes != 0)
                {
                    long   PadFilePos = table.GetBuffer().GetFilePos() + table.GetBuffer().GetLength();
                    byte[] padbuf     = ReadBytes(PadFilePos, nBytes);
                    for (int iByte = 0; iByte < padbuf.Length; iByte++)
                    {
                        if (padbuf[iByte] != 0)
                        {
                            bPadBytesZero = false;
                            break;
                        }
                    }
                }

                if (bPadBytesZero == false)
                {
                    v.Warning(T.T_NULL, W._DE_W_PadBytesNotZero, de.tag, "after " + de.tag + " table");
                }
            }

            // ask the table object to validate its data
            if (!(tname == "DSIG" && IsCollection()))
            {
                v.OnTableValidationEvent(de, true);
            }
            if (table != null)
            {
                if (v.TestTable(de.tag)) // don't test deselected tables
                {
                    try
                    {
                        ITableValidate valtable = (ITableValidate)table;
                        bRet &= valtable.Validate(v, fontOwner);
                    }
                    catch (InvalidCastException e)
                    {
                        v.ApplicationError(T.T_NULL, E._Table_E_Exception, table.m_tag, e.ToString());
                        bRet = false;
                    }
                }
                else
                {
                    v.Info(I._Table_I_NotSelected, de.tag);
                }
            }
            else
            {
                if (de.length == 0)
                {
                    // check if it's a known OT table type since zero length private tables seem allowable
                    if (TableManager.IsKnownOTTableType(de.tag))
                    {
                        v.Error(T.T_NULL, E._Table_E_Invalid, de.tag, "The directory entry length is zero");
                        bRet = false;
                    }
                }
                else if (de.offset == 0)
                {
                    v.Error(T.T_NULL, E._Table_E_Invalid, de.tag, "The directory entry offset is zero");
                    bRet = false;
                }
                else if (de.offset > GetFileLength())
                {
                    v.Error(T.T_NULL, E._Table_E_Invalid, de.tag, "The table offset points past end of file");
                    bRet = false;
                }
                else if (de.offset + de.length > GetFileLength())
                {
                    v.Error(T.T_NULL, E._Table_E_Invalid, de.tag, "The table extends past end of file");
                    bRet = false;
                }
                else
                {
                    v.Error(E._Table_E_Invalid, de.tag);
                    bRet = false;
                }
            }
            if (!(tname == "DSIG" && IsCollection()))
            {
                v.OnTableValidationEvent(de, false);
            }

            return(bRet);
        }
Ejemplo n.º 25
0
        /************************
         * public methods
         */


        public bool Validate(Validator v, OTFontVal fontOwner)
        {
            bool bRet = true;

            if (v.PerformTest(T.maxp_TableVersion))
            {
                uint val = TableVersionNumber.GetUint();

                Table_CFF  CFFTable  = (Table_CFF)fontOwner.GetTable("CFF ");
                Table_glyf glyfTable = (Table_glyf)fontOwner.GetTable("glyf");

                if (val == 0x00005000)
                {
                    if (CFFTable != null && glyfTable == null)
                    {
                        v.Pass(T.maxp_TableVersion, P.maxp_P_VERSION_0_5, m_tag);
                    }
                    else if (CFFTable == null)
                    {
                        v.Error(T.maxp_TableVersion, E.maxp_E_VERSION_0_5_NOCFF, m_tag);
                        bRet = false;
                    }
                    else if (glyfTable != null)
                    {
                        v.Error(T.maxp_TableVersion, E.maxp_E_VERSION_0_5_glyf, m_tag);
                        bRet = false;
                    }
                }
                else if (val == 0x00010000)
                {
                    if (CFFTable == null && glyfTable != null)
                    {
                        v.Pass(T.maxp_TableVersion, P.maxp_P_VERSION_1_0, m_tag);
                    }
                    else if (glyfTable == null)
                    {
                        v.Error(T.maxp_TableVersion, E.maxp_E_VERSION_1_0_NOglyf, m_tag);
                        bRet = false;
                    }
                    else if (CFFTable != null)
                    {
                        v.Error(T.maxp_TableVersion, E.maxp_E_VERSION_1_0_CFF, m_tag);
                        bRet = false;
                    }
                }
                else
                {
                    v.Error(T.maxp_TableVersion, E.maxp_E_VERSION_INVALID, m_tag, "0x" + val.ToString("x8"));
                    bRet = false;
                }
            }

            if (v.PerformTest(T.maxp_TableLength))
            {
                uint val = TableVersionNumber.GetUint();

                if (val == 0x00005000)
                {
                    if (m_bufTable.GetLength() == 6)
                    {
                        v.Pass(T.maxp_TableLength, P.maxp_P_LENGTH_0_5, m_tag);
                    }
                    else
                    {
                        v.Error(T.maxp_TableLength, E.maxp_E_LENGTH_0_5, m_tag, m_bufTable.GetLength().ToString());
                        bRet = false;
                    }
                }
                else if (val == 0x00010000)
                {
                    if (m_bufTable.GetLength() == 32)
                    {
                        v.Pass(T.maxp_TableLength, P.maxp_P_LENGTH_1_0, m_tag);
                    }
                    else
                    {
                        v.Error(T.maxp_TableLength, E.maxp_E_LENGTH_1_0, m_tag, m_bufTable.GetLength().ToString());
                        bRet = false;
                    }
                }
            }

            if (v.PerformTest(T.maxp_NumGlyphsMatchLoca))
            {
                if (TableVersionNumber.GetUint() == 0x00010000)
                {
                    Table_loca locaTable = (Table_loca)fontOwner.GetTable("loca");
                    if (locaTable != null)
                    {
                        // locaTable.NumEntry returns (-1) on failure
                        if (locaTable.NumEntry(fontOwner) == NumGlyphs + 1)
                        {
                            v.Pass(T.maxp_NumGlyphsMatchLoca, P.maxp_P_NumGlyphsMatchLoca, m_tag, "numGlyphs = " + NumGlyphs);
                        }
                        else
                        {
                            v.Error(T.maxp_NumGlyphsMatchLoca, E.maxp_E_NumGlyphsMatchLoca, m_tag, "numGlyphs = " + NumGlyphs);
                            bRet = false;
                        }
                    }
                    else
                    {
                        v.Error(T.maxp_NumGlyphsMatchLoca, E._TEST_E_TableMissing, m_tag, "loca");
                        bRet = false;
                    }
                }
                else
                {
                    v.Info(T.maxp_NumGlyphsMatchLoca, I._TEST_I_TableVersion, m_tag, "test = maxp_NumGlyphsMatchLoca");
                }
            }

            if (v.PerformTest(T.maxp_GlyphStats))
            {
                if (TableVersionNumber.GetUint() == 0x00010000)
                {
                    Table_glyf glyfTable = (Table_glyf)fontOwner.GetTable("glyf");

                    if (glyfTable == null)
                    {
                        v.Error(T.maxp_GlyphStats, E._TEST_E_TableMissing, m_tag, "glyf");
                        bRet = false;
                    }
                    else
                    {
                        bool bGlyphStatsOk = true;

                        if (ComputeMaxpStats(glyfTable, fontOwner))
                        {
                            if (maxPoints != maxPointsCalc)
                            {
                                String sDetails = "maxPoints = " + maxPoints + ", calculated = " + maxPointsCalc;
                                v.Error(T.maxp_GlyphStats, E.maxp_E_Calculation, m_tag, sDetails);
                                bRet          = false;
                                bGlyphStatsOk = false;
                            }

                            if (maxContours != maxContoursCalc)
                            {
                                String sDetails = "maxContours = " + maxContours + ", calculated = " + maxContoursCalc;
                                v.Error(T.maxp_GlyphStats, E.maxp_E_Calculation, m_tag, sDetails);
                                bRet          = false;
                                bGlyphStatsOk = false;
                            }

                            if (maxCompositePoints != maxCompositePointsCalc)
                            {
                                String sDetails = "maxCompositePoints = " + maxCompositePoints + ", calculated = " + maxCompositePointsCalc;
                                v.Error(T.maxp_GlyphStats, E.maxp_E_Calculation, m_tag, sDetails);
                                bRet          = false;
                                bGlyphStatsOk = false;
                            }

                            if (maxCompositeContours != maxCompositeContoursCalc)
                            {
                                String sDetails = "maxCompositeContours = " + maxCompositeContours + ", calculated = " + maxCompositeContoursCalc;
                                v.Error(T.maxp_GlyphStats, E.maxp_E_Calculation, m_tag, sDetails);
                                bRet          = false;
                                bGlyphStatsOk = false;
                            }

                            // Bug 2168.
                            // Case 1: Same as max size from glyf table. Info.
                            // Case 2: Same as max size from glyf table +
                            //         size(fpgm) + size(prep). Info message.
                            // Case 3: Smaller than max size from glyf table.
                            //         Error
                            // Case 4: Neither 1 nor 2. Warning.
                            DirectoryEntry dePrep =
                                fontOwner.GetDirectoryEntry("prep");
                            uint prepLength = 0;
                            if (null != dePrep)
                            {
                                prepLength = dePrep.length;
                            }
                            DirectoryEntry deFpgm =
                                fontOwner.GetDirectoryEntry("fpgm");
                            uint fpgmLength = 0;
                            if (null != deFpgm)
                            {
                                fpgmLength = deFpgm.length;
                            }

                            if (maxSizeOfInstructions ==
                                maxSizeOfInstructionsCalc)
                            {
                                // Case 1:
                                String sDetails = "maxSizeOfInstructions=" +
                                                  maxSizeOfInstructions + ", computed " +
                                                  "from the glyf table";
                                v.Info(T.maxp_GlyphStats,
                                       I.maxp_I_Calculation_Method1,
                                       m_tag, sDetails);
                            }
                            else if (maxSizeOfInstructions ==
                                     (maxSizeOfInstructionsCalc +
                                      prepLength + fpgmLength))
                            {
                                // Case 2:
                                String sDetails =
                                    "maxp maxSizeOfInstructions is " +
                                    maxSizeOfInstructions + ", which is " +
                                    "glyf maxSizeOfInstructions (" +
                                    maxSizeOfInstructionsCalc +
                                    ") + prep size (" + prepLength +
                                    ") + fpgm size (" + fpgmLength + ")";
                                v.Info(T.maxp_GlyphStats,
                                       I.maxp_I_Calculation_Method2,
                                       m_tag, sDetails);
                            }
                            else if (maxSizeOfInstructions <
                                     maxSizeOfInstructionsCalc)
                            {
                                // Case 3
                                String sDetails =
                                    "maxp maxSizeOfInstructions is " +
                                    maxSizeOfInstructions +
                                    ", which is smaller than the " +
                                    "size of instuctions (" +
                                    maxSizeOfInstructionsCalc + ") found" +
                                    " for some glyph in the glyf table.";
                                v.Error(T.maxp_GlyphStats,
                                        E.maxp_E_Calculation, m_tag,
                                        sDetails);
                                bRet = false;
                            }
                            else
                            {
                                // Case 4
                                String sDetails =
                                    "glyf maxSizeOfInstructions=" +
                                    maxSizeOfInstructionsCalc +
                                    ", prep size=" + prepLength +
                                    ", fpgm size=" + fpgmLength +
                                    ", whereas maxp maxSizeOfInstruction " +
                                    "is " + maxSizeOfInstructions;
                                v.Warning(T.maxp_GlyphStats,
                                          W.maxp_W_Calculation_Unclear,
                                          m_tag,
                                          sDetails);
                                bGlyphStatsOk = false;
                            }

                            if (maxComponentElements != maxComponentElementsCalc)
                            {
                                String sDetails = "maxComponentElements = " + maxComponentElements + ", calculated = " + maxComponentElementsCalc;
                                v.Error(T.maxp_GlyphStats, E.maxp_E_Calculation, m_tag, sDetails);
                                bRet          = false;
                                bGlyphStatsOk = false;
                            }

                            if (maxComponentDepth != maxComponentDepthCalc)
                            {
                                String sDetails = "maxComponentDepth = " + maxComponentDepth + ", calculated = " + maxComponentDepthCalc;
                                v.Error(T.maxp_GlyphStats, E.maxp_E_Calculation, m_tag, sDetails);
                                bRet          = false;
                                bGlyphStatsOk = false;
                            }

                            if (bGlyphStatsOk)
                            {
                                v.Pass(T.maxp_GlyphStats, P.maxp_P_Calculation, m_tag);
                            }
                        }
                        else
                        {
                            v.Warning(T.maxp_GlyphStats, W._TEST_W_ErrorInAnotherTable, m_tag, "Errors in the glyf table are preventing validation of maxPoints, maxContours, maxCompositePoints, maxCompositeContours, maxSizeofInstructions, maxComponentElements, and maxComponentDepth");
                        }
                    }
                }
                else
                {
                    v.Info(T.maxp_GlyphStats, I._TEST_I_TableVersion, m_tag, "test = maxp_GlyphStats");
                }
            }

            return(bRet);
        }
Ejemplo n.º 26
0
        /************************
         * public methods
         */


        public bool Validate(Validator v, OTFontVal fontOwner)
        {
            bool bRet = true;

            if (v.PerformTest(T.name_FormatSelector))
            {
                if (FormatSelector == 0)
                {
                    v.Pass(T.name_FormatSelector, P.name_P_FormatSelector, m_tag);
                }
                else
                {
                    v.Error(T.name_FormatSelector, E.name_E_FormatSelector, m_tag, FormatSelector.ToString());
                    bRet = false;
                }
            }

            if (v.PerformTest(T.name_StringsWithinTable))
            {
                bool bStringsWithinTable = true;

                uint tableLength = GetLength();
                for (uint i = 0; i < NumberNameRecords; i++)
                {
                    NameRecord nr = GetNameRecord(i);
                    if (nr != null)
                    {
                        if (nr.StringOffset + nr.StringLength > tableLength)
                        {
                            v.Error(T.name_StringsWithinTable, E.name_E_StringsWithinTable, m_tag, "string# " + i);
                            bStringsWithinTable = false;
                            bRet = false;
                        }
                    }
                    else
                    {
                        v.Warning(T.name_StringsWithinTable, W._TEST_W_OtherErrorsInTable, m_tag);
                        bStringsWithinTable = false;
                        break;
                    }
                }
                if (bStringsWithinTable)
                {
                    v.Pass(T.name_StringsWithinTable, P.name_P_StringsWithinTable, m_tag);
                }
            }

            if (v.PerformTest(T.name_NameRecordsSorted))
            {
                bool bSortedOrder = true;

                if (NumberNameRecords > 1)
                {
                    NameRecord CurrNR = GetNameRecord(0);
                    NameRecord NextNR = null;
                    for (uint i = 0; i < NumberNameRecords - 1; i++)
                    {
                        NextNR = GetNameRecord(i + 1);

                        if (CurrNR == null || NextNR == null)
                        {
                            bSortedOrder = false;
                            break;
                        }

                        if (CurrNR.PlatformID > NextNR.PlatformID)
                        {
                            bSortedOrder = false;
                            break;
                        }
                        else if (CurrNR.PlatformID == NextNR.PlatformID)
                        {
                            if (CurrNR.EncodingID > NextNR.EncodingID)
                            {
                                bSortedOrder = false;
                                break;
                            }
                            else if (CurrNR.EncodingID == NextNR.EncodingID)
                            {
                                if (CurrNR.LanguageID > NextNR.LanguageID)
                                {
                                    bSortedOrder = false;
                                    break;
                                }
                                else if (CurrNR.LanguageID == NextNR.LanguageID)
                                {
                                    if (CurrNR.NameID > NextNR.NameID)
                                    {
                                        bSortedOrder = false;
                                        break;
                                    }
                                }
                            }
                        }

                        CurrNR = NextNR;
                    }
                }

                if (bSortedOrder)
                {
                    v.Pass(T.name_NameRecordsSorted, P.name_P_NameRecordsSorted, m_tag);
                }
                else
                {
                    v.Error(T.name_NameRecordsSorted, E.name_E_NameRecordsSorted, m_tag);
                    bRet = false;
                }
            }

            if (v.PerformTest(T.name_ReservedNameIDs))
            {
                bool bReservedOk = true;

                for (uint i = 0; i < NumberNameRecords; i++)
                {
                    NameRecord nr = GetNameRecord(i);

                    if (nr != null)
                    {
                        if (nr.NameID >= 26 && nr.NameID <= 255)
                        {
                            string s = "platID = " + nr.PlatformID
                                       + ", encID = " + nr.EncodingID
                                       + ", langID = " + nr.LanguageID
                                       + ", nameID = " + nr.NameID;
                            v.Error(T.name_ReservedNameIDs, E.name_E_ReservedNameID, m_tag, s);
                            bReservedOk = false;
                            break;
                        }
                    }
                    else
                    {
                        v.Warning(T.name_ReservedNameIDs, W._TEST_W_OtherErrorsInTable, m_tag);
                        bReservedOk = false;
                        break;
                    }
                }

                if (bReservedOk)
                {
                    v.Pass(T.name_ReservedNameIDs, P.name_P_ReservedNameID, m_tag);
                }
            }

            if (v.PerformTest(T.name_BothPlatforms))
            {
                bool bMac = false;
                bool bMS  = false;


                for (uint i = 0; i < NumberNameRecords; i++)
                {
                    NameRecord nr = GetNameRecord(i);
                    if (nr != null)
                    {
                        if (nr.PlatformID == 1)
                        {
                            bMac = true;
                        }
                        else if (nr.PlatformID == 3)
                        {
                            bMS = true;
                        }
                    }
                }

                if (bMac && bMS)
                {
                    v.Pass(T.name_BothPlatforms, P.name_P_BothPlatforms, m_tag);
                }
                else if (!bMac)
                {
                    v.Error(T.name_BothPlatforms, E.name_E_NoMacPlatform, m_tag);
                    bRet = false;
                }
                else if (!bMS)
                {
                    v.Error(T.name_BothPlatforms, E.name_E_NoMSPlatform, m_tag);
                    bRet = false;
                }
            }

            if (v.PerformTest(T.name_VersionString))
            {
                bool   bFound   = false;
                string sVersion = "";

                for (uint i = 0; i < NumberNameRecords; i++)
                {
                    NameRecord nr = GetNameRecord(i);
                    if (nr != null)
                    {
                        if (nr.PlatformID == 3 &&       // ms
                            (nr.EncodingID == 1 /* unicode */ || nr.EncodingID == 0 /*symbol*/) &&
                            nr.NameID == 5)             // version string
                        {
                            bFound = true;

                            bool    bVerStringValid = false;
                            byte [] buf             = GetEncodedString(nr);

                            string s = "";

                            if (buf != null)
                            {
                                sVersion = "";
                                for (int j = 0; j < buf.Length / 2; j++)
                                {
                                    char c = (char)(ushort)(buf[j * 2] << 8 | buf[j * 2 + 1]);
                                    sVersion += c;
                                }

                                if (sVersion.Length >= 11 &&
                                    sVersion.StartsWith("Version ") &&
                                    Char.IsDigit(sVersion, 8))
                                {
                                    int j = 9;

                                    // advance past the digits in the major number
                                    while (j < sVersion.Length)
                                    {
                                        if (Char.IsDigit(sVersion, j))
                                        {
                                            j++;
                                        }
                                        else
                                        {
                                            break;
                                        }
                                    }

                                    // if major number is followed by a period
                                    if (sVersion[j] == '.')
                                    {
                                        // advance past the period
                                        j++;

                                        // check for a digit
                                        if (Char.IsDigit(sVersion, j))
                                        {
                                            bVerStringValid = true;
                                        }
                                    }
                                }
                            }

                            s = "platID = " + nr.PlatformID
                                + ", encID = " + nr.EncodingID
                                + ", langID = " + nr.LanguageID
                                + ", \"" + sVersion + "\"";

                            if (bVerStringValid)
                            {
                                v.Pass(T.name_VersionString, P.name_P_VersionStringFormat, m_tag, s);
                            }
                            else
                            {
                                v.Error(T.name_VersionString, E.name_E_VersionStringFormat, m_tag, s);
                                bRet = false;
                            }

                            // compare to mac version string if present
                            string sMacVer = GetString(1, 0, 0xffff, 5);
                            if (sMacVer != null)
                            {
                                if (sVersion.CompareTo(sMacVer) != 0)
                                {
                                    v.Warning(T.name_VersionString, W.name_W_VersionMismatch_MS_MAC, m_tag);
                                }
                            }

                            // compare to 3,10 version string if present
                            string s310Ver = GetString(3, 10, nr.LanguageID, 5);
                            if (s310Ver != null)
                            {
                                if (sVersion.CompareTo(s310Ver) != 0)
                                {
                                    string s310 = "platID = 3, encID = 10, langID = " + nr.LanguageID
                                                  + ", \"" + s310Ver + "\"";
                                    v.Warning(T.name_VersionString, W.name_W_VersionMismatch_3_1_3_10, m_tag, s + " / " + s310);
                                }
                            }
                        }
                    }
                }

                if (!bFound)
                {
                    v.Error(T.name_VersionString, E.name_E_VersionStringNotFound, m_tag);
                    bRet = false;
                }
            }

            if (v.PerformTest(T.name_PlatformSpecificEncoding))
            {
                bool bIDsOk = true;

                for (uint i = 0; i < NumberNameRecords; i++)
                {
                    NameRecord nr = GetNameRecord(i);
                    if (nr != null)
                    {
                        if (nr.PlatformID == 0) // unicode
                        {
                            if (nr.EncodingID > 7)
                            {
                                string s = "platID = " + nr.PlatformID
                                           + ", encID = " + nr.EncodingID
                                           + ", langID = " + nr.LanguageID
                                           + ", nameID = " + nr.NameID;
                                v.Error(T.name_PlatformSpecificEncoding, E.name_E_PlatformSpecificEncoding, m_tag, s);
                                bIDsOk = false;
                                bRet   = false;
                            }
                        }
                        else if (nr.PlatformID == 1) // mac
                        {
                            if (nr.EncodingID > 32)
                            {
                                string s = "platID = " + nr.PlatformID
                                           + ", encID = " + nr.EncodingID
                                           + ", langID = " + nr.LanguageID
                                           + ", nameID = " + nr.NameID;
                                v.Error(T.name_PlatformSpecificEncoding, E.name_E_PlatformSpecificEncoding, m_tag, s);
                                bIDsOk = false;
                                bRet   = false;
                            }
                        }
                        else if (nr.PlatformID == 2) // iso
                        {
                            if (nr.EncodingID > 2)
                            {
                                string s = "platID = " + nr.PlatformID
                                           + ", encID = " + nr.EncodingID
                                           + ", langID = " + nr.LanguageID
                                           + ", nameID = " + nr.NameID;
                                v.Error(T.name_PlatformSpecificEncoding, E.name_E_PlatformSpecificEncoding, m_tag, s);
                                bIDsOk = false;
                                bRet   = false;
                            }
                        }
                        else if (nr.PlatformID == 3) // MS
                        {
                            if (nr.EncodingID > 10)
                            {
                                string s = "platID = " + nr.PlatformID
                                           + ", encID = " + nr.EncodingID
                                           + ", langID = " + nr.LanguageID
                                           + ", nameID = " + nr.NameID;
                                v.Error(T.name_PlatformSpecificEncoding, E.name_E_PlatformSpecificEncoding, m_tag, s);
                                bIDsOk = false;
                                bRet   = false;
                            }
                        }

                        /*
                         * else if (nr.PlatformID == 4) // Custom
                         * {
                         * }
                         */
                    }
                    else
                    {
                        v.Warning(T.name_PlatformSpecificEncoding, W._TEST_W_OtherErrorsInTable, m_tag);
                        bIDsOk = false;
                        break;
                    }
                }

                if (bIDsOk)
                {
                    v.Pass(T.name_PlatformSpecificEncoding, P.name_P_PlatformSpecificEncoding, m_tag);
                }
            }

            if (v.PerformTest(T.name_MSLanguageIDs))
            {
                bool bFound = false;
                bool bIDsOk = true;

                ushort [] MSLangIDs = // taken from Q224804
                {
                    0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409,
                    0x040a, 0x040b, 0x040c, 0x040D, 0x040e, 0x040F, 0x0410, 0x0411, 0x0412,
                    0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041a, 0x041b,
                    0x041c, 0x041D, 0x041E, 0x041f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424,
                    0x0425, 0x0426, 0x0427, 0x0429, 0x042a, 0x042b, 0x042c, 0x042D, 0x042e,
                    0x042f, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
                    0x0438, 0x0439, 0x043b, 0x043d, 0x043e, 0x043f, 0x0441, 0x0443, 0x0444,
                    0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d,
                    0x044e, 0x044f, 0x0457, 0x0459, 0x0461, 0x0801, 0x0804, 0x0807, 0x0809,
                    0x080a, 0x080c, 0x0810, 0x0812, 0x0813, 0x0814, 0x0816, 0x0818, 0x0819,
                    0x081a, 0x081d, 0x0820, 0x0827, 0x082c, 0x083e, 0x0843, 0x0860, 0x0861,
                    0x0C01, 0x0C04, 0x0c07, 0x0c09, 0x0c0a, 0x0c0c, 0x0c1a, 0x1001, 0x1004,
                    0x1007, 0x1009, 0x100a, 0x100c, 0x1401, 0x1404, 0x1407, 0x1409, 0x140a,
                    0x140c, 0x1801, 0x1809, 0x180a, 0x180c, 0x1C01, 0x1c09, 0x1c0a, 0x2001,
                    0x2009, 0x200a, 0x2401, 0x2409, 0x240a, 0x2801, 0x2809, 0x280a, 0x2C01,
                    0x2c09, 0x2c0a, 0x3001, 0x3009, 0x300a, 0x3401, 0x3409, 0x340a, 0x3801,
                    0x380a, 0x3C01, 0x3c0a, 0x4001, 0x400a, 0x440a, 0x480a, 0x4c0a, 0x500a
                };

                for (uint i = 0; i < NumberNameRecords; i++)
                {
                    NameRecord nr = GetNameRecord(i);
                    if (nr != null)
                    {
                        if (nr.PlatformID == 3 && nr.EncodingID == 1)
                        {
                            bFound = true;

                            bool bValidID = false;
                            for (uint j = 0; j < MSLangIDs.Length; j++)
                            {
                                if (nr.LanguageID == MSLangIDs[j])
                                {
                                    bValidID = true;
                                    break;
                                }
                            }

                            if (!bValidID)
                            {
                                string s = "platID = " + nr.PlatformID
                                           + ", encID = " + nr.EncodingID
                                           + ", langID = 0x" + nr.LanguageID.ToString("x4")
                                           + ", nameID = " + nr.NameID;
                                v.Error(T.name_MSLanguageIDs, E.name_E_MSLanguageID, m_tag, s);
                                bIDsOk = false;
                                bRet   = false;
                            }
                        }
                    }
                }

                if (bFound && bIDsOk)
                {
                    v.Pass(T.name_MSLanguageIDs, P.name_P_MSLanguageID, m_tag);
                }
            }

            if (v.PerformTest(T.name_unicode_length))
            {
                bool bLengthsOk = true;

                for (uint i = 0; i < NumberNameRecords; i++)
                {
                    NameRecord nr = GetNameRecord(i);
                    if (nr != null)
                    {
                        if (nr.PlatformID == 0 || nr.PlatformID == 2 || // unicode or iso platform
                            (nr.PlatformID == 3 && nr.EncodingID == 1)) // microsoft platform, unicode encoding
                        {
                            if ((nr.StringLength & 1) == 1)
                            {
                                string s = "platID = " + nr.PlatformID
                                           + ", encID = " + nr.EncodingID
                                           + ", langID = " + nr.LanguageID
                                           + ", nameID = " + nr.NameID
                                           + ", length = " + nr.StringLength;
                                v.Error(T.name_unicode_length, E.name_E_UnicodeLength, m_tag, s);
                                bLengthsOk = false;
                                bRet       = false;
                            }
                        }
                    }
                    else
                    {
                        v.Warning(T.name_unicode_length, W._TEST_W_OtherErrorsInTable, m_tag);
                        bLengthsOk = false;
                        break;
                    }
                }

                if (bLengthsOk)
                {
                    v.Pass(T.name_unicode_length, P.name_P_UnicodeLength, m_tag);
                }
            }

            if (v.PerformTest(T.name_Postscript))
            {
                bool bPostscriptOk = true;

                string sPostscriptMac = GetString(1, 0, 0, 6);
                if (sPostscriptMac != null)
                {
                    if (sPostscriptMac.Length > 63)
                    {
                        v.Error(T.name_Postscript, E.name_E_Postscript_length, m_tag, "name string (1, 0, 0, 6) is " + sPostscriptMac.Length + " characters long");
                        bRet          = false;
                        bPostscriptOk = false;
                    }

                    for (int i = 0; i < sPostscriptMac.Length; i++)
                    {
                        char c = sPostscriptMac[i];
                        if (c < 33 || c > 126 || c == '[' || c == ']' || c == '(' || c == ')' || c == '{' || c == '}' || c == '<' || c == '>' || c == '/' || c == '%')
                        {
                            v.Error(T.name_Postscript, E.name_E_Postscript_chars, m_tag, "name string (1, 0, 0, 6) contains an illegal character at index " + i);
                            bRet          = false;
                            bPostscriptOk = false;
                        }
                    }
                }

                ushort nEncoding = 1;
                if (fontOwner.ContainsMsSymbolEncodedCmap())
                {
                    nEncoding = 0;
                }

                string sPostscriptMS = GetString(3, nEncoding, 0x409, 6); // ms
                if (sPostscriptMS != null)
                {
                    if (sPostscriptMS.Length > 63)
                    {
                        v.Error(T.name_Postscript, E.name_E_Postscript_length, m_tag, "name string (3, " + nEncoding + ", 0x409, 6) is " + sPostscriptMS.Length + " characters long");
                        bRet          = false;
                        bPostscriptOk = false;
                    }

                    for (int i = 0; i < sPostscriptMS.Length; i++)
                    {
                        char c = sPostscriptMS[i];
                        if (c < 33 || c > 126 || c == '[' || c == ']' || c == '(' || c == ')' || c == '{' || c == '}' || c == '<' || c == '>' || c == '/' || c == '%')
                        {
                            v.Error(T.name_Postscript, E.name_E_Postscript_chars, m_tag, "name string (3, " + nEncoding + ", 0x409, 6) contains an illegal character at index " + i);
                            bRet          = false;
                            bPostscriptOk = false;
                        }
                    }
                }

                if (sPostscriptMac == null && sPostscriptMS != null)
                {
                    v.Error(T.name_Postscript, E.name_E_Postscript_missing, m_tag, "Mac Postscript string is missing, but MS Postscript string is present");
                    bRet          = false;
                    bPostscriptOk = false;
                }
                else if (sPostscriptMac != null && sPostscriptMS == null)
                {
                    v.Error(T.name_Postscript, E.name_E_Postscript_missing, m_tag, "MS Postscript string is missing, but Mac Postscript string is present");
                    bRet          = false;
                    bPostscriptOk = false;
                }
                if (sPostscriptMac != null && sPostscriptMS != null)
                {
                    if (sPostscriptMac != sPostscriptMS)
                    {
                        v.Error(T.name_Postscript, E.name_E_Postscript_unequal, m_tag, "mac postscript = " + sPostscriptMac + ", MS postscript = " + sPostscriptMS);
                        bRet          = false;
                        bPostscriptOk = false;
                    }
                }


                if (sPostscriptMac != null && sPostscriptMS != null && bPostscriptOk)
                {
                    v.Pass(T.name_Postscript, P.name_P_Postscript, m_tag);
                }
            }

            if (v.PerformTest(T.name_Subfamily))
            {
                string sStyle = GetStyleString();
                if (sStyle != null)
                {
                    Table_OS2 OS2Table = (Table_OS2)fontOwner.GetTable("OS/2");
                    if (OS2Table != null)
                    {
                        bool   bStyleOk      = true;
                        string sStyleDetails = "";
                        string s             = sStyle.ToLower();

                        bool bItalic = ((OS2Table.fsSelection & 0x01) != 0);
                        bool bBold   = ((OS2Table.fsSelection & 0x20) != 0);

                        if (bItalic)
                        {
                            if (s.IndexOf("italic") == -1 && s.IndexOf("oblique") == -1)
                            {
                                bStyleOk      = false;
                                sStyleDetails = "OS/2.fsSelection italic bit is set, but subfamily string = '" + sStyle + "'";
                            }
                        }
                        else
                        {
                            if (s.IndexOf("italic") != -1 || s.IndexOf("oblique") != -1)
                            {
                                bStyleOk      = false;
                                sStyleDetails = "OS/2.fsSelection italic bit is clear, but subfamily string = '" + sStyle + "'";
                            }
                        }

                        if (bBold)
                        {
                            if (s.IndexOf("bold") == -1)
                            {
                                bStyleOk      = false;
                                sStyleDetails = "OS/2.fsSelection bold bit is set, but subfamily string = '" + sStyle + "'";
                            }
                        }
                        else
                        {
                            if (s.IndexOf("bold") != -1)
                            {
                                bStyleOk      = false;
                                sStyleDetails = "OS/2.fsSelection bold bit is clear, but subfamily string = '" + sStyle + "'";
                            }
                        }

                        if (bStyleOk)
                        {
                            v.Pass(T.name_Subfamily, P.name_P_subfamily, m_tag);
                        }
                        else
                        {
                            v.Warning(T.name_Subfamily, W.name_W_subfamily_style, m_tag, sStyleDetails);
                        }
                    }
                }
            }


            if (v.PerformTest(T.name_NoFormat14))
            {
                bool bStringOK = true;
                for (uint i = 0; i < NumberNameRecords; i++)
                {
                    NameRecord nr = GetNameRecord(i);
                    if (nr != null &&
                        nr.NameID == 19 &&
                        nr.PlatformID == 0 &&
                        nr.EncodingID == 5)
                    {
                        string sDetails =
                            "name string(" + nr.PlatformID
                            + ", " + nr.EncodingID
                            + ", 0x" + nr.LanguageID.ToString("x4")
                            + ", " + nr.NameID +
                            ", offset=0x" +
                            nr.StringOffset.ToString("x4") + ")";
                        v.Error(T.name_NoFormat14,
                                E.name_E_NoFormat14,
                                m_tag,
                                sDetails);
                        bRet      = false;
                        bStringOK = false;
                    }
                }
                if (bStringOK)
                {
                    string sDetails = "PlatformID=0, EncodingID=5 is for " +
                                      "Variation Sequences (Format 14)";
                    v.Pass(T.name_NoFormat14, P.name_P_NoFormat14, m_tag,
                           sDetails);
                }
            }

            if (v.PerformTest(T.name_SampleString))
            {
                Table_cmap cmapTable = (Table_cmap)fontOwner.GetTable("cmap");
                if (cmapTable != null)
                {
                    for (uint i = 0; i < NumberNameRecords; i++)
                    {
                        NameRecord nr = GetNameRecord(i);
                        if (nr != null)
                        {
                            if (nr.NameID == 19)
                            {
                                if (nr.PlatformID == 0 &&
                                    nr.EncodingID == 5)
                                {
                                    // Unicode platform encoding ID 5 can be
                                    // used for encodings in the 'cmap' table
                                    // but not for strings in the 'name' table.
                                    // It has already been flagged as an error,
                                    // so we will just skip it here.
                                    break;
                                }
                                Table_cmap.Subtable CmapSubTable = cmapTable.GetSubtable(nr.PlatformID, nr.EncodingID);
                                if (CmapSubTable != null)
                                {
                                    bool bStringOk = true;

                                    byte[] strbuf = GetEncodedString(nr);

                                    for (uint j = 0; j < strbuf.Length;)
                                    {
                                        if (CmapSubTable.MapCharToGlyph(strbuf, j, true) == 0)
                                        {
                                            string sDetails = "name string(" + nr.PlatformID
                                                              + ", " + nr.EncodingID
                                                              + ", 0x" + nr.LanguageID.ToString("x4")
                                                              + ", " + nr.NameID
                                                              + "), character at index " + j + " is not mapped";
                                            v.Error(T.name_SampleString, E.name_E_sample, m_tag, sDetails);
                                            bStringOk = false;
                                            bRet      = false;
                                            break;
                                        }

                                        j += CmapSubTable.BytesInChar(strbuf, j);
                                    }

                                    if (bStringOk)
                                    {
                                        string sDetails = "name string(" + nr.PlatformID
                                                          + ", " + nr.EncodingID
                                                          + ", 0x" + nr.LanguageID.ToString("x4")
                                                          + ", " + nr.NameID
                                                          + ")";
                                        v.Pass(T.name_SampleString, P.name_P_sample, m_tag, sDetails);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            if (v.PerformTest(T.name_NameID1to6))
            {
                for (uint id = 1; id <= 6; id++)
                {
                    bool bFound = false;

                    for (uint i = 0; i < NumberNameRecords; i++)
                    {
                        NameRecord nr = GetNameRecord(i);
                        if (nr != null)
                        {
                            if (nr.NameID == id)
                            {
                                bFound = true;
                                break;
                            }
                        }
                    }

                    if (!bFound)
                    {
                        v.Warning(T.name_NameID1to6, W.name_W_ID_1to6_Required_For_Common_OSes, m_tag,
                                  "Missing Name ID " + id);
                    }
                }
            }

            if (v.PerformTest(T.name_PreferredFamily))
            {
                bool bFound = false;

                for (uint i = 0; i < NumberNameRecords; i++)
                {
                    NameRecord nr = GetNameRecord(i);
                    if (nr != null)
                    {
                        if (nr.NameID == 16)
                        {
                            string sPrefFam = this.GetString(nr.PlatformID, nr.EncodingID, nr.LanguageID, 16);

                            string s = "platID = " + nr.PlatformID
                                       + ", encID = " + nr.EncodingID
                                       + ", langID = " + nr.LanguageID
                                       + ", nameID = " + nr.NameID
                                       + ", \"" + sPrefFam + "\"";
                            v.Info(T.name_PreferredFamily, I.name_I_Preferred_family_present, m_tag, s);

                            bFound = true;
                        }
                    }
                }

                if (!bFound)
                {
                    v.Info(T.name_PreferredFamily, I.name_I_Preferred_family_not_present, m_tag);
                }
            }

            if (v.PerformTest(T.name_PreferredSubfamily))
            {
                bool bFound = false;

                for (uint i = 0; i < NumberNameRecords; i++)
                {
                    NameRecord nr = GetNameRecord(i);
                    if (nr != null)
                    {
                        if (nr.NameID == 17)
                        {
                            string sPrefSubfam = this.GetString(nr.PlatformID, nr.EncodingID, nr.LanguageID, 17);

                            string s = "platID = " + nr.PlatformID
                                       + ", encID = " + nr.EncodingID
                                       + ", langID = " + nr.LanguageID
                                       + ", nameID = " + nr.NameID
                                       + ", \"" + sPrefSubfam + "\"";
                            v.Info(T.name_PreferredSubfamily, I.name_I_Preferred_subfamily_present, m_tag, s);

                            bFound = true;
                        }
                    }
                }

                if (!bFound)
                {
                    v.Info(T.name_PreferredSubfamily, I.name_I_Preferred_subfamily_not_present, m_tag);
                }
            }

            if (v.PerformTest(T.name_CopyrightConsistent))
            {
                bool bCopyrightOk = true;

                // get mac roman English Copyright string if present
                string sMac = GetString(1, 0, 0, 0);

                // get windows 3,0 English Copyright string if present
                string sWin3_0 = GetString(3, 0, 1033, 0);

                // get windows 3,1 English Copyright string if present
                string sWin3_1 = GetString(3, 1, 1033, 0);

                // get windows 3,10 English Copyright string if present
                string sWin3_10 = GetString(3, 10, 1033, 0);

                // compare strings

                if (sMac != null)
                {
                    if (sWin3_0 != null)
                    {
                        if (sWin3_0.CompareTo(sMac) != 0)
                        {
                            string sDetails = "(1,0,0,0)='" + sMac + "', (3,0,1033,0)='" + sWin3_0 + "'";
                            v.Warning(T.name_CopyrightConsistent, W.name_W_CopyrightInconsistent, m_tag, sDetails);
                            bCopyrightOk = false;
                        }
                    }

                    if (sWin3_1 != null)
                    {
                        if (sWin3_1.CompareTo(sMac) != 0)
                        {
                            string sDetails = "(1,0,0,0)='" + sMac + "', (3,1,1033,0)='" + sWin3_1 + "'";
                            v.Warning(T.name_CopyrightConsistent, W.name_W_CopyrightInconsistent, m_tag, sDetails);
                            bCopyrightOk = false;
                        }
                    }

                    if (sWin3_10 != null)
                    {
                        if (sWin3_10.CompareTo(sMac) != 0)
                        {
                            string sDetails = "(1,0,0,0)='" + sMac + "', (3,10,1033,0)='" + sWin3_10 + "'";
                            v.Warning(T.name_CopyrightConsistent, W.name_W_CopyrightInconsistent, m_tag, sDetails);
                            bCopyrightOk = false;
                        }
                    }
                }

                if (sWin3_0 != null)
                {
                    if (sWin3_1 != null)
                    {
                        if (sWin3_1.CompareTo(sWin3_0) != 0)
                        {
                            string sDetails = "(3,0,1033,0)='" + sWin3_0 + "', (3,1,1033,0)='" + sWin3_1 + "'";
                            v.Warning(T.name_CopyrightConsistent, W.name_W_CopyrightInconsistent, m_tag, sDetails);
                            bCopyrightOk = false;
                        }
                    }

                    if (sWin3_10 != null)
                    {
                        if (sWin3_10.CompareTo(sWin3_0) != 0)
                        {
                            string sDetails = "(3,0,1033,0)='" + sWin3_0 + "', (3,10,1033,0)='" + sWin3_10 + "'";
                            v.Warning(T.name_CopyrightConsistent, W.name_W_CopyrightInconsistent, m_tag, sDetails);
                            bCopyrightOk = false;
                        }
                    }
                }

                if (sWin3_1 != null)
                {
                    if (sWin3_10 != null)
                    {
                        if (sWin3_10.CompareTo(sWin3_1) != 0)
                        {
                            string sDetails = "(3,1,1033,0)='" + sWin3_1 + "', (3,10,1033,0)='" + sWin3_10 + "'";
                            v.Warning(T.name_CopyrightConsistent, W.name_W_CopyrightInconsistent, m_tag, sDetails);
                            bCopyrightOk = false;
                        }
                    }
                }

                if (bCopyrightOk)
                {
                    v.Pass(T.name_CopyrightConsistent, P.name_P_CopyrightConsistent, m_tag);
                }
                else
                {
                    //bRet = false;
                }
            }

            if (v.PerformTest(T.name_TrademarkConsistent))
            {
                bool bTrademarkOk = true;

                // get mac roman English Trademark string if present
                string sMac = GetString(1, 0, 0, 7);

                // get windows 3,0 English Trademark string if present
                string sWin3_0 = GetString(3, 0, 1033, 7);

                // get windows 3,1 English Trademark string if present
                string sWin3_1 = GetString(3, 1, 1033, 7);

                // get windows 3,10 English Trademark string if present
                string sWin3_10 = GetString(3, 10, 1033, 7);

                // compare strings

                if (sMac != null)
                {
                    if (sWin3_0 != null)
                    {
                        if (sWin3_0.CompareTo(sMac) != 0)
                        {
                            string sDetails = "(1,0,0,7)='" + sMac + "', (3,0,1033,7)='" + sWin3_0 + "'";
                            v.Warning(T.name_TrademarkConsistent, W.name_W_TrademarkInconsistent, m_tag, sDetails);
                            bTrademarkOk = false;
                        }
                    }

                    if (sWin3_1 != null)
                    {
                        if (sWin3_1.CompareTo(sMac) != 0)
                        {
                            string sDetails = "(1,0,0,7)='" + sMac + "', (3,1,1033,7)='" + sWin3_1 + "'";
                            v.Warning(T.name_TrademarkConsistent, W.name_W_TrademarkInconsistent, m_tag, sDetails);
                            bTrademarkOk = false;
                        }
                    }

                    if (sWin3_10 != null)
                    {
                        if (sWin3_10.CompareTo(sMac) != 0)
                        {
                            string sDetails = "(1,0,0,7)='" + sMac + "', (3,10,1033,7)='" + sWin3_10 + "'";
                            v.Warning(T.name_TrademarkConsistent, W.name_W_TrademarkInconsistent, m_tag, sDetails);
                            bTrademarkOk = false;
                        }
                    }
                }

                if (sWin3_0 != null)
                {
                    if (sWin3_1 != null)
                    {
                        if (sWin3_1.CompareTo(sWin3_0) != 0)
                        {
                            string sDetails = "(3,0,1033,7)='" + sWin3_0 + "', (3,1,1033,7)='" + sWin3_1 + "'";
                            v.Warning(T.name_TrademarkConsistent, W.name_W_TrademarkInconsistent, m_tag, sDetails);
                            bTrademarkOk = false;
                        }
                    }

                    if (sWin3_10 != null)
                    {
                        if (sWin3_10.CompareTo(sWin3_0) != 0)
                        {
                            string sDetails = "(3,0,1033,7)='" + sWin3_0 + "', (3,10,1033,7)='" + sWin3_10 + "'";
                            v.Warning(T.name_TrademarkConsistent, W.name_W_TrademarkInconsistent, m_tag, sDetails);
                            bTrademarkOk = false;
                        }
                    }
                }

                if (sWin3_1 != null)
                {
                    if (sWin3_10 != null)
                    {
                        if (sWin3_10.CompareTo(sWin3_1) != 0)
                        {
                            string sDetails = "(3,1,1033,7)='" + sWin3_1 + "', (3,10,1033,7)='" + sWin3_10 + "'";
                            v.Warning(T.name_TrademarkConsistent, W.name_W_TrademarkInconsistent, m_tag, sDetails);
                            bTrademarkOk = false;
                        }
                    }
                }

                if (bTrademarkOk)
                {
                    v.Pass(T.name_TrademarkConsistent, P.name_P_TrademarkConsistent, m_tag);
                }
                else
                {
                    //bRet = false;
                }
            }

            if (v.PerformTest(T.name_DescriptionConsistent))
            {
                bool bDescriptionOk = true;

                // get mac roman English Description string if present
                string sMac = GetString(1, 0, 0, 10);

                // get windows 3,0 English Description string if present
                string sWin3_0 = GetString(3, 0, 1033, 10);

                // get windows 3,1 English Description string if present
                string sWin3_1 = GetString(3, 1, 1033, 10);

                // get windows 3,10 English Description string if present
                string sWin3_10 = GetString(3, 10, 1033, 10);

                // compare strings

                if (sMac != null)
                {
                    if (sWin3_0 != null)
                    {
                        if (sWin3_0.CompareTo(sMac) != 0)
                        {
                            string sDetails = "(1,0,0,10)='" + sMac + "', (3,0,1033,10)='" + sWin3_0 + "'";
                            v.Warning(T.name_DescriptionConsistent, W.name_W_DescriptionInconsistent, m_tag, sDetails);
                            bDescriptionOk = false;
                        }
                    }

                    if (sWin3_1 != null)
                    {
                        if (sWin3_1.CompareTo(sMac) != 0)
                        {
                            string sDetails = "(1,0,0,10)='" + sMac + "', (3,1,1033,10)='" + sWin3_1 + "'";
                            v.Warning(T.name_DescriptionConsistent, W.name_W_DescriptionInconsistent, m_tag, sDetails);
                            bDescriptionOk = false;
                        }
                    }

                    if (sWin3_10 != null)
                    {
                        if (sWin3_10.CompareTo(sMac) != 0)
                        {
                            string sDetails = "(1,0,0,10)='" + sMac + "', (3,10,1033,10)='" + sWin3_10 + "'";
                            v.Warning(T.name_DescriptionConsistent, W.name_W_DescriptionInconsistent, m_tag, sDetails);
                            bDescriptionOk = false;
                        }
                    }
                }

                if (sWin3_0 != null)
                {
                    if (sWin3_1 != null)
                    {
                        if (sWin3_1.CompareTo(sWin3_0) != 0)
                        {
                            string sDetails = "(3,0,1033,10)='" + sWin3_0 + "', (3,1,1033,10)='" + sWin3_1 + "'";
                            v.Warning(T.name_DescriptionConsistent, W.name_W_DescriptionInconsistent, m_tag, sDetails);
                            bDescriptionOk = false;
                        }
                    }

                    if (sWin3_10 != null)
                    {
                        if (sWin3_10.CompareTo(sWin3_0) != 0)
                        {
                            string sDetails = "(3,0,1033,10)='" + sWin3_0 + "', (3,10,1033,10)='" + sWin3_10 + "'";
                            v.Warning(T.name_DescriptionConsistent, W.name_W_DescriptionInconsistent, m_tag, sDetails);
                            bDescriptionOk = false;
                        }
                    }
                }

                if (sWin3_1 != null)
                {
                    if (sWin3_10 != null)
                    {
                        if (sWin3_10.CompareTo(sWin3_1) != 0)
                        {
                            string sDetails = "(3,1,1033,10)='" + sWin3_1 + "', (3,10,1033,10)='" + sWin3_10 + "'";
                            v.Warning(T.name_DescriptionConsistent, W.name_W_DescriptionInconsistent, m_tag, sDetails);
                            bDescriptionOk = false;
                        }
                    }
                }

                if (bDescriptionOk)
                {
                    v.Pass(T.name_DescriptionConsistent, P.name_P_DescriptionConsistent, m_tag);
                }
                else
                {
                    //bRet = false;
                }
            }


            return(bRet);
        }
Ejemplo n.º 27
0
        private bool CheckNames(Validator v,
                                OTFontVal fontOwner,
                                PostNames pn,
                                uint iGlyph,
                                uint index)
        {
            bool   bNamesOk = true;
            string sName    = GetNameString(index - 258);

            System.Globalization.NumberStyles hexStyle =
                System.Globalization.NumberStyles.HexNumber;
            if (Is_uniXXXX(sName))
            {
                char c = (char)Int16.Parse(sName.Substring(3, 4), hexStyle);
                if (fontOwner.FastMapUnicodeToGlyphID(c) != iGlyph)
                {
                    char   cMapped = fontOwner.MapGlyphIDToUnicode(iGlyph, (char)0);
                    string s       = "glyph = " + iGlyph +
                                     ", char = U+" +
                                     ((uint)cMapped).ToString("X4")
                                     + ", name = " + sName;
                    v.Info(T.post_v2_names,
                           I.post_I_names_uni_unexpected,
                           m_tag, s);
                    bNamesOk = false;
                }
            }
            else if (Is_uXXXXX(sName))
            {
                uint c = (uint)Int32.Parse(sName.Substring(1), hexStyle);
                if (c < 0xffff)
                {
                    if (fontOwner.FastMapUnicodeToGlyphID((char)c) != iGlyph)
                    {
                        char cMapped = fontOwner.MapGlyphIDToUnicode(iGlyph,
                                                                     (char)0);
                        string s = "glyph = " + iGlyph + ", char = U+" +
                                   ((uint)cMapped).ToString("X4") + ", name = " + sName;
                        v.Info(T.post_v2_names, I.post_I_names_uni_unexpected,
                               m_tag, s);
                        bNamesOk = false;
                    }
                }
                else
                {
                    if (fontOwner.FastMapUnicode32ToGlyphID(c) != iGlyph)
                    {
                        uint cMapped =
                            fontOwner.MapGlyphIDToUnicode32(iGlyph, 0);
                        string s = "glyph = " + iGlyph + ", char = U+" +
                                   ((uint)cMapped).ToString("X5") + ", name = " + sName;
                        v.Info(T.post_v2_names, I.post_I_names_uni_unexpected,
                               m_tag, s);
                        bNamesOk = false;
                    }
                }
            }
            else
            {
                // check the Adobe Glyph Names

                char c = (char)fontOwner.MapGlyphIDToUnicode(iGlyph, (char)0);
                if (c != 0xffff)
                {
                    string sAdobeName = pn.GetAdobeGlyphName(c);
                    if (sAdobeName == null)
                    {
                        string s = "glyph = " + iGlyph + ", char = U+" +
                                   ((uint)c).ToString("X4") + ", name = " + sName;
                        v.Info(T.post_v2_names, I.post_I_names_noAdobe, m_tag, s);
                        bNamesOk = false;
                    }
                    else if (sName != sAdobeName)
                    {
                        string s = "glyph = " + iGlyph + ", char = U+" +
                                   ((uint)c).ToString("X4") + ", name = " + sName;
                        v.Info(T.post_v2_names, I.post_I_names_nomatch, m_tag, s);
                        bNamesOk = false;
                    }
                }
            }
            return(bNamesOk);
        }
Ejemplo n.º 28
0
        /*****************
         * public methods
         */


        public bool Validate()
        {
            bool bRet = true;
            int  canrast;

            Validator v = GetFile().GetValidator();

            if (v.PerformTest(T._OFFSET_sfntVersion))
            {
                uint sfnt = m_OffsetTable.sfntVersion.GetUint();
                if (!OTFile.IsValidSfntVersion(sfnt))
                {
                    v.Error(T._OFFSET_sfntVersion, E._OFFSET_E_InvalidSFNT, null, "0x" + sfnt.ToString("x8"));
                    bRet = false;
                }
            }

            if (v.PerformTest(T._OFFSET_numTables))
            {
                if (m_OffsetTable.numTables == 0)
                {
                    v.Error(T._OFFSET_numTables, E._OFFSET_E_numTables, null);
                    bRet = false;
                }
                else
                {
                    v.Pass(T._OFFSET_numTables, P._OFFSET_P_numTables, null, m_OffsetTable.numTables.ToString());
                }
            }

            if (v.PerformTest(T._OFFSET_BinarySearchFields))
            {
                ushort numTables               = m_OffsetTable.numTables;
                ushort CalculatedSearchRange   = (ushort)(util.MaxPower2LE(numTables) * 16);
                ushort CalculatedEntrySelector = util.Log2(util.MaxPower2LE(numTables));
                ushort CalculatedRangeShift    = (ushort)(numTables * 16 - CalculatedSearchRange);

                bool bBinaryFieldsOk = true;

                if (m_OffsetTable.searchRange != CalculatedSearchRange)
                {
                    v.Error(T._OFFSET_BinarySearchFields, E._OFFSET_E_searchRange, null, m_OffsetTable.searchRange.ToString());
                    bBinaryFieldsOk = false;
                    bRet            = false;
                }
                if (m_OffsetTable.entrySelector != CalculatedEntrySelector)
                {
                    v.Error(T._OFFSET_BinarySearchFields, E._OFFSET_E_entrySelector, null, m_OffsetTable.entrySelector.ToString());
                    bBinaryFieldsOk = false;
                    bRet            = false;
                }
                if (m_OffsetTable.rangeShift != CalculatedRangeShift)
                {
                    v.Error(T._OFFSET_BinarySearchFields, E._OFFSET_E_rangeShift, null, m_OffsetTable.rangeShift.ToString());
                    bBinaryFieldsOk = false;
                    bRet            = false;
                }

                if (bBinaryFieldsOk)
                {
                    v.Pass(T._OFFSET_BinarySearchFields, P._OFFSET_P_BinarySearchTables, null);
                }
            }

            bRet &= CheckDirectoryEntriesNonZero(v);

            bRet &= CheckTablesInFileAndNotOverlapping(v);

            bRet &= CheckNoDuplicateTags(v);

            if (v.PerformTest(T._DE_TagsAscendingOrder))
            {
                bRet &= CheckTagsAscending(v);
            }

            if (v.PerformTest(T._DE_TagNames))
            {
                bRet &= CheckTagNames(v);
            }

            if (v.PerformTest(T._DE_TableAlignment))
            {
                bRet &= CheckTableAlignment(v);
            }

            if (v.PerformTest(T._FONT_RequiredTables))
            {
                bRet &= CheckForRequiredTables(v);
            }

            if (v.PerformTest(T._FONT_RecommendedTables))
            {
                bRet &= CheckForRecommendedTables(v);
            }

            if (v.PerformTest(T._FONT_UnnecessaryTables))
            {
                bRet &= CheckForNoUnnecessaryTables(v);
            }

            if (v.PerformTest(T._FONT_OptimalTableOrder))
            {
                bRet &= CheckForOptimalTableOrder(v);
            }


            // Validate each table

            if (m_OffsetTable != null)
            {
                for (int i = 0; i < m_OffsetTable.DirectoryEntries.Count; i++)
                {
                    // check to see if user canceled validation
                    if (v.CancelFlag)
                    {
                        break;
                    }

                    // get the table
                    DirectoryEntry de    = (DirectoryEntry)m_OffsetTable.DirectoryEntries[i];
                    OTTable        table = GetFile().GetTableManager().GetTable(this, de);

                    // Will it really happen?
                    if (GetFile().GetTableManager().GetUnaliasedTableName(de.tag) == "DSIG" && GetFile().IsCollection())
                    {
                        continue;
                    }

                    if (GetFile().GetTableManager().GetUnaliasedTableName(de.tag) == "glyf" &&
                        Is_TTC_LaterIdenticalTable("glyf"))
                    {
                        v.Info(T.T_NULL, I.glyf_I_IDENTICAL_GLYF_TABLES_IN_TTC, de.tag, "glyf");
                        continue;
                    }

                    if (GetFile().GetTableManager().GetUnaliasedTableName(de.tag) == "EBDT" &&
                        Is_TTC_LaterIdenticalTable("EBDT"))
                    {
                        v.Info(T.T_NULL, I.glyf_I_IDENTICAL_GLYF_TABLES_IN_TTC, de.tag, "EBDT");
                        continue;
                    }

                    // Call the function that validates a single table
                    bRet &= this.GetFile().ValidateTable(table, v, de, this);
                }
            }

            canrast = TestFontRasterization();
            ushort numGlyphs = GetMaxpNumGlyphs();

            // rasterization test - BW

            v.OnRastTestValidationEvent_BW(true);
            if (v.PeformRastTest_BW() && Is_TTC_LaterIdenticalTable("glyf"))
            {
                v.Info(T.T_NULL, I.glyf_I_IDENTICAL_GLYF_TABLES_IN_TTC, null, "B/W Rasterization");
            }
            else
            if (v.PeformRastTest_BW())
            {
                if (canrast > 0)
                {
                    try
                    {
                        // fetch the rasterizer object and initialize it with this font
                        RasterInterf ri = GetFile().GetRasterizer();
                        ri.RasterNewSfnt(GetFile().GetFileStream(), GetFontIndexInFile());


                        // call the rasterizer
                        RasterInterf.UpdateProgressDelegate upg  = new RasterInterf.UpdateProgressDelegate(v.OnTableProgress);
                        RasterInterf.RastTestErrorDelegate  rted = new RasterInterf.RastTestErrorDelegate(v.OnRastTestError);
                        int               x          = v.GetRastTestXRes();
                        int               y          = v.GetRastTestYRes();
                        int []            pointsizes = v.GetRastTestPointSizes();
                        RastTestTransform rtt        = v.GetRastTestTransform();
                        bRet &= ri.RastTest(
                            x, y, pointsizes,
                            rtt.stretchX, rtt.stretchY, rtt.rotation, rtt.skew, rtt.matrix,
                            true, false, false, 0,
                            rted, upg, numGlyphs);
                        if (ri.GetRastErrorCount() == 0)
                        {
                            v.Pass(T.T_NULL, P._rast_P_rasterization, null);
                        }
                    }
                    catch (Exception e)
                    {
                        v.ApplicationError(T.T_NULL, E._rast_A_ExceptionUnhandled, null, e.Message + e.StackTrace);
                    }
                }
                else if (canrast == 0)
                {
                    v.Info(T.T_NULL, I._rast_I_rasterization, null, GetDevMetricsDataError());
                }
                else
                {
                    v.Error(T.T_NULL, E._rast_E_rasterization, null, GetDevMetricsDataError());
                    bRet = false;
                }
            }
            else
            {
                v.Info(I._TEST_I_RastTestNotSelected, null);
            }
            v.OnRastTestValidationEvent_BW(false);


            // rasterization test - Grayscale

            v.OnRastTestValidationEvent_Grayscale(true);
            if (v.PeformRastTest_Grayscale() && Is_TTC_LaterIdenticalTable("glyf"))
            {
                v.Info(T.T_NULL, I.glyf_I_IDENTICAL_GLYF_TABLES_IN_TTC, null, "Grayscale Rasterization");
            }
            else
            if (v.PeformRastTest_Grayscale())
            {
                if (canrast > 0)
                {
                    try
                    {
                        // fetch the rasterizer object and initialize it with this font
                        RasterInterf ri = GetFile().GetRasterizer();
                        ri.RasterNewSfnt(GetFile().GetFileStream(), GetFontIndexInFile());


                        // call the rasterizer
                        RasterInterf.UpdateProgressDelegate upg  = new RasterInterf.UpdateProgressDelegate(v.OnTableProgress);
                        RasterInterf.RastTestErrorDelegate  rted = new RasterInterf.RastTestErrorDelegate(v.OnRastTestError);
                        int               x          = v.GetRastTestXRes();
                        int               y          = v.GetRastTestYRes();
                        int []            pointsizes = v.GetRastTestPointSizes();
                        RastTestTransform rtt        = v.GetRastTestTransform();
                        bRet &= ri.RastTest(
                            x, y, pointsizes,
                            rtt.stretchX, rtt.stretchY, rtt.rotation, rtt.skew, rtt.matrix,
                            false, true, false, 0,
                            rted, upg, numGlyphs);
                        if (ri.GetRastErrorCount() == 0)
                        {
                            v.Pass(T.T_NULL, P._rast_P_rasterization, null);
                        }
                    }
                    catch (Exception e)
                    {
                        v.ApplicationError(T.T_NULL, E._rast_A_ExceptionUnhandled, null, e.Message + e.StackTrace);
                    }
                }
                else if (canrast == 0)
                {
                    v.Info(T.T_NULL, I._rast_I_rasterization, null, GetDevMetricsDataError());
                }
                else
                {
                    v.Error(T.T_NULL, E._rast_E_rasterization, null, GetDevMetricsDataError());
                    bRet = false;
                }
            }
            else
            {
                v.Info(I._TEST_I_RastTestNotSelected, null);
            }
            v.OnRastTestValidationEvent_Grayscale(false);



            // rasterization test - Cleartype

            v.OnRastTestValidationEvent_Cleartype(true);
            if (v.PeformRastTest_Cleartype() && Is_TTC_LaterIdenticalTable("glyf"))
            {
                v.Info(T.T_NULL, I.glyf_I_IDENTICAL_GLYF_TABLES_IN_TTC, null, "Cleartype Rasterization");
            }
            else
            if (v.PeformRastTest_Cleartype())
            {
                if (canrast > 0)
                {
                    try
                    {
                        uint CTFlags = v.GetCleartypeFlags();

                        // fetch the rasterizer object and initialize it with this font
                        RasterInterf ri = GetFile().GetRasterizer();
                        ri.RasterNewSfnt(GetFile().GetFileStream(), GetFontIndexInFile());


                        // call the rasterizer
                        RasterInterf.UpdateProgressDelegate upg  = new RasterInterf.UpdateProgressDelegate(v.OnTableProgress);
                        RasterInterf.RastTestErrorDelegate  rted = new RasterInterf.RastTestErrorDelegate(v.OnRastTestError);
                        int               x          = v.GetRastTestXRes();
                        int               y          = v.GetRastTestYRes();
                        int []            pointsizes = v.GetRastTestPointSizes();
                        RastTestTransform rtt        = v.GetRastTestTransform();
                        bRet &= ri.RastTest(
                            x, y, pointsizes,
                            rtt.stretchX, rtt.stretchY, rtt.rotation, rtt.skew, rtt.matrix,
                            false, false, true, CTFlags,
                            rted, upg, numGlyphs);
                        if (ri.GetRastErrorCount() == 0)
                        {
                            v.Pass(T.T_NULL, P._rast_P_rasterization, null);
                        }
                    }
                    catch (Exception e)
                    {
                        v.ApplicationError(T.T_NULL, E._rast_A_ExceptionUnhandled, null, e.Message + e.StackTrace);
                    }
                }
                else if (canrast == 0)
                {
                    v.Info(T.T_NULL, I._rast_I_rasterization, null, GetDevMetricsDataError());
                }
                else
                {
                    v.Error(T.T_NULL, E._rast_E_rasterization, null, GetDevMetricsDataError());
                    bRet = false;
                }
            }
            else
            {
                v.Info(I._TEST_I_RastTestNotSelected, null);
            }
            v.OnRastTestValidationEvent_Cleartype(false);

            return(bRet);
        }
Ejemplo n.º 29
0
        /************************
         * public methods
         */

        public bool Validate(Validator v, OTFontVal fontOwner)
        {
            bool bRet = true;

            v.Info(T.T_NULL, I.CFF_I_Version, m_tag, major + "." + minor);

            if (major == 1 && minor == 0 && hdrSize == 4)
            {
                v.Pass(T.CFF_Header, P.CFF_P_Header, m_tag);
            }
            else
            {
                v.Error(T.CFF_Header, E.CFF_E_Header, m_tag,
                        "major=" + major + ", minor=" + minor + ", hdrSize=" + hdrSize + ", offSize=" + offSize);
            }

            try
            {
                v.Pass(T.CFF_MAININDEX_Enumeration, P.CFF_P_MAININDEX_Enumeration, m_tag,
                       "Name=" + Name.count + ", TopDICT=" + TopDICT.count + ", String=" + String.count + ", GlobalSubr=" + GlobalSubr.count);
            }
            catch (Exception e)
            {
                v.Error(T.CFF_MAININDEX_Enumeration, E.CFF_E_MAININDEX_Enumeration, m_tag,
                        e.Message);

                return(false);
            }

            if (Name.count == TopDICT.count && TopDICT.count == 1)
            {
                v.Pass(T.CFF_NameDICTSize, P.CFF_P_NameDICTSize, m_tag);
            }
            else
            {
                v.Error(T.CFF_NameDICTSize, E.CFF_E_NameDICTSize, m_tag,
                        "Name=" + Name.count + ", TopDICT=" + TopDICT.count);
            }

            if (Name.GetOffset(0) != 1)
            {
                v.Warning(T.CFF_INDEXFirstOffset, W.CFF_W_INDEXFirstOffset, m_tag, "Name=" + Name.GetOffset(0));
            }
            if (TopDICT.GetOffset(0) != 1)
            {
                v.Warning(T.CFF_INDEXFirstOffset, W.CFF_W_INDEXFirstOffset, m_tag, "TopDICT=" + TopDICT.GetOffset(0));
            }
            if (String.GetOffset(0) != 1)
            {
                v.Warning(T.CFF_INDEXFirstOffset, W.CFF_W_INDEXFirstOffset, m_tag, "String=" + String.GetOffset(0));
            }
            if (GlobalSubr.GetOffset(0) != 1)
            {
                v.Warning(T.CFF_INDEXFirstOffset, W.CFF_W_INDEXFirstOffset, m_tag, "GlobalSubr=" + GlobalSubr.GetOffset(0));
            }

            var overlap = new DataOverlapDetector();

            if (!overlap.CheckForNoOverlap(0, hdrSize))
            {
                v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "hdrSize");
            }
            if (!overlap.CheckForNoOverlap(Name.begin, Name.size))
            {
                v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "Name");
            }
            if (!overlap.CheckForNoOverlap(TopDICT.begin, TopDICT.size))
            {
                v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "TopDICT");
            }
            if (!overlap.CheckForNoOverlap(String.begin, String.size))
            {
                v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "String");
            }
            if (!overlap.CheckForNoOverlap(GlobalSubr.begin, GlobalSubr.size))
            {
                v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "GlobalSubr");
            }

            try
            {
                for (uint i = 0; i < Name.count; i++)
                {
                    var name = Name.GetString(i);
                }

                v.Pass(T.CFF_Non_ASCII_String_or_Name, P.CFF_P_Non_ASCII_String_or_Name, m_tag, "Name INDEX");
            }
            catch (DecoderFallbackException)
            {
                v.Error(T.CFF_Non_ASCII_String_or_Name, E.CFF_E_Non_ASCII_String_or_Name, m_tag, "Name INDEX");
            }

            try{
                for (uint i = 0; i < String.count; i++)
                {
                    var a = String.GetString(i);
                }

                v.Pass(T.CFF_Non_ASCII_String_or_Name, P.CFF_P_Non_ASCII_String_or_Name, m_tag, "String INDEX");
            }
            catch (DecoderFallbackException)
            {
                v.Error(T.CFF_Non_ASCII_String_or_Name, E.CFF_E_Non_ASCII_String_or_Name, m_tag, "String INDEX");
            }

            for (uint iDICT = 0; iDICT < TopDICT.count; iDICT++)
            {
                Table_CFF.DICTData curTopDICT = null;
                try
                {
                    curTopDICT = GetTopDICT(iDICT);

                    v.Pass(T.CFF_DICTUnwind, P.CFF_P_DICTUnwind, m_tag, curTopDICT.FullName);

                    if (!overlap.CheckForNoOverlap((uint)curTopDICT.offsetPrivate, (uint)curTopDICT.sizePrivate))
                    {
                        v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "TopDICTPriv");
                    }
                }
                catch (Exception e)
                {
                    v.Error(T.CFF_DICTUnwind, E.CFF_E_DICTUnwind, m_tag, "TopDICT: " + e.Message);
                }

                Table_CFF.DICTData topPrivateDict = null;
                try
                {
                    topPrivateDict = GetPrivate(curTopDICT);
                    v.Pass(T.CFF_PrivDICTUnwind, P.CFF_P_PrivDICTUnwind, m_tag, "topPrivateDict");
                }
                catch (Exception e)
                {
                    v.Error(T.CFF_PrivDICTUnwind, E.CFF_E_PrivDICTUnwind, m_tag, "topPrivateDict: " + e.Message);
                }

                if (topPrivateDict != null && topPrivateDict.Subrs != 0)
                {
                    try
                    {
                        Table_CFF.INDEXData topPrivSubrs = GetINDEX(curTopDICT.offsetPrivate + topPrivateDict.Subrs);
                        v.Pass(T.CFF_INDEXCount, P.CFF_P_INDEXCount, m_tag, "topPrivSubrs: " + topPrivSubrs.count);

                        if (topPrivSubrs.GetOffset(0) != 1)
                        {
                            v.Warning(T.CFF_INDEXFirstOffset, W.CFF_W_INDEXFirstOffset, m_tag, "topPrivSubrs=" + topPrivSubrs.GetOffset(0));
                        }

                        if (!overlap.CheckForNoOverlap(topPrivSubrs.begin, topPrivSubrs.size))
                        {
                            v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "topPrivSubrs");
                        }
                    }
                    catch (Exception e)
                    {
                        v.Error(T.CFF_INDEXCount, E.CFF_E_INDEXCount, m_tag, "topPrivSubrs: " + e.Message);
                    }
                }

                Table_CFF.INDEXData CharStrings = null;
                try
                {
                    CharStrings = GetINDEX(curTopDICT.offsetCharStrings);
                    v.Pass(T.CFF_INDEXCount, P.CFF_P_INDEXCount, m_tag, "CharStrings: " + CharStrings.count);

                    if (CharStrings.GetOffset(0) != 1)
                    {
                        v.Warning(T.CFF_INDEXFirstOffset, W.CFF_W_INDEXFirstOffset, m_tag, "CharStrings=" + CharStrings.GetOffset(0));
                    }

                    if (!overlap.CheckForNoOverlap(CharStrings.begin, CharStrings.size))
                    {
                        v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "CharStrings");
                    }
                }
                catch (Exception e)
                {
                    v.Error(T.CFF_INDEXCount, E.CFF_E_INDEXCount, m_tag, "CharStrings: " + e.Message);
                }

                if (CharStrings.count == fontOwner.GetMaxpNumGlyphs())
                {
                    v.Pass(T.CFF_CharStringsCount, P.CFF_P_CharStringsCount, m_tag);
                }
                else
                {
                    v.Error(T.CFF_CharStringsCount, E.CFF_E_CharStringsCount, m_tag,
                            CharStrings.count.ToString() + "!=" + fontOwner.GetMaxpNumGlyphs());
                }

                if (curTopDICT.ROS != null)
                {
                    v.Info(T.CFF_CIDROS, I.CFF_I_CIDROS, m_tag, curTopDICT.ROS);
                }

                if (curTopDICT.offsetFDArray > 0)
                {
                    Table_CFF.INDEXData FDArray = null;
                    try {
                        FDArray = GetINDEX(curTopDICT.offsetFDArray);
                        v.Pass(T.CFF_INDEXCount, P.CFF_P_INDEXCount, m_tag, "FDArray: " + FDArray.count);

                        if (FDArray.GetOffset(0) != 1)
                        {
                            v.Warning(T.CFF_INDEXFirstOffset, W.CFF_W_INDEXFirstOffset, m_tag, "FDArray=" + FDArray.GetOffset(0));
                        }

                        if (!overlap.CheckForNoOverlap(FDArray.begin, FDArray.size))
                        {
                            v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "FDArray");
                        }
                    }
                    catch (Exception e)
                    {
                        v.Error(T.CFF_INDEXCount, E.CFF_E_INDEXCount, m_tag, "FDArray: " + e.Message);
                    }

                    for (uint i = 0; i < FDArray.count; i++)
                    {
                        Table_CFF.DICTData FDict = null;
                        try
                        {
                            FDict = GetDICT(FDArray.GetData(i));

                            v.Pass(T.CFF_DICTUnwind, P.CFF_P_DICTUnwind, m_tag, "CID FontDict #" + i + ": " + FDict.FontName);

                            if (!overlap.CheckForNoOverlap((uint)FDict.offsetPrivate, (uint)FDict.sizePrivate))
                            {
                                v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "FDictPriv#" + i);
                            }
                        }
                        catch (Exception e)
                        {
                            v.Error(T.CFF_DICTUnwind, E.CFF_E_DICTUnwind, m_tag, "CID FontDict #" + i + ": " + e.Message);
                        }

                        Table_CFF.DICTData FDictPrivate = null;
                        try
                        {
                            FDictPrivate = GetPrivate(FDict);
                            v.Pass(T.CFF_PrivDICTUnwind, P.CFF_P_PrivDICTUnwind, m_tag, "CID FontDict Private DICT#" + i);
                        }
                        catch (Exception e)
                        {
                            v.Error(T.CFF_PrivDICTUnwind, E.CFF_E_PrivDICTUnwind, m_tag, "CID FontDict Private DICT#" + i + ": " + e.Message);
                        }

                        if (FDictPrivate != null && FDictPrivate.Subrs != 0)
                        {
                            Table_CFF.INDEXData PrivSubrs = null;
                            try
                            {
                                PrivSubrs = GetINDEX(FDict.offsetPrivate + FDictPrivate.Subrs);
                                v.Pass(T.CFF_INDEXCount, P.CFF_P_INDEXCount, m_tag, "PrivSubrs#" + i + ": " + PrivSubrs.count);

                                if (PrivSubrs.GetOffset(0) != 1)
                                {
                                    v.Warning(T.CFF_INDEXFirstOffset, W.CFF_W_INDEXFirstOffset, m_tag,
                                              "PrivSubrs#" + i + "=" + PrivSubrs.GetOffset(0));
                                }

                                if (!overlap.CheckForNoOverlap(PrivSubrs.begin, PrivSubrs.size))
                                {
                                    v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "PrivSubrs#" + i);
                                }
                                ;
                            }
                            catch (Exception e)
                            {
                                v.Error(T.CFF_INDEXCount, E.CFF_E_INDEXCount, m_tag, "PrivSubrs#" + i + ": " + e.Message);
                            }
                        }
                    }
                }
                string result = "Tested Region: " + overlap.Occupied + " of " + GetLength() + ", not testing" +
                                (curTopDICT.offsetCharset == 0 ? "" : " Charset: " + curTopDICT.offsetCharset) +
                                (curTopDICT.offsetEncoding == 0 ? "" : " Encoding: " + curTopDICT.offsetEncoding) +
                                (curTopDICT.offsetFDSelect == 0 ? "" : " FDSelect: " + curTopDICT.offsetFDSelect);
                v.Info(T.CFF_TestCoverage, I.CFF_I_NotValidated, m_tag, result);
            }

            return(bRet);
        }
Ejemplo n.º 30
0
        /************************
         * public methods
         */


        public bool Validate(Validator v, OTFontVal fontOwner)
        {
            bool bRet = true;

            if (v.PerformTest(T.post_TableLength))
            {
                bool bLenOk = true;

                if (Version.GetUint() == 0x00010000 ||
                    Version.GetUint() == 0x00030000)
                {
                    if (GetLength() != 32)
                    {
                        v.Error(T.post_TableLength, E.post_E_TableLenNot32, m_tag);
                        bLenOk = false;
                        bRet   = false;
                    }
                }
                if (Version.GetUint() == 0x00020000)
                {
                    if (GetLength() < 34)
                    {
                        v.Error(T.post_TableLength, E.post_E_InvalidTableLen, m_tag);
                        bLenOk = false;
                        bRet   = false;
                    }
                }

                if (bLenOk)
                {
                    v.Pass(T.post_TableLength, P.post_P_TableLength, m_tag);
                }
            }

            if (v.PerformTest(T.post_Version))
            {
                uint ver = Version.GetUint();
                if (ver == 0x00025000)
                {
                    v.Warning(T.post_Version, W.post_W_Version_2_5, m_tag);
                }
                else if (ver == 0x00010000 || ver == 0x00020000)
                {
                    v.Pass(T.post_Version, P.post_P_Version, m_tag);
                }
                else if (ver == 0x00030000)
                {
                    v.Warning(T.post_Version, W.post_W_Version_3_Apple, m_tag);
                }
                else if (ver == 0x00040000)
                {
                    v.Warning(T.post_Version, W.post_W_Version_4_Apple, m_tag);
                }
                else
                {
                    v.Error(T.post_Version, E.post_E_Version, m_tag, "0x" + ver.ToString("x8"));
                }
            }

            if (v.PerformTest(T.post_italicAngle))
            {
                bool bItalOk = true;

                uint   ia           = italicAngle.GetUint();
                double dItalicAngle = italicAngle.GetDouble();

                if (dItalicAngle < -30.0 || dItalicAngle > 360.0 || (dItalicAngle > 0.0 && dItalicAngle < 330.0))
                {
                    v.Warning(T.post_italicAngle, W.post_W_italicAngle_unlikely, m_tag, "0x" + ia.ToString("x8"));
                    bItalOk = false;
                }

                Table_head headTable = (Table_head)fontOwner.GetTable("head");
                if (headTable != null)
                {
                    if ((headTable.macStyle & 0x0002) != 0)
                    {
                        if (ia == 0)
                        {
                            v.Error(T.post_italicAngle, E.post_E_italicAngleZero_macStyle, m_tag);
                            bItalOk = false;
                            bRet    = false;
                        }
                    }
                    else
                    {
                        if (ia != 0)
                        {
                            v.Error(T.post_italicAngle, E.post_E_italicAngleNonzero_macStyle, m_tag);
                            bItalOk = false;
                            bRet    = false;
                        }
                    }
                }
                else
                {
                    v.Error(T.post_italicAngle, E._TEST_E_TableMissing, m_tag, "head table missing, can't compare italicAngle to head.macStyle");
                    bItalOk = false;
                }

                Table_hhea hheaTable = (Table_hhea)fontOwner.GetTable("hhea");
                if (hheaTable != null)
                {
                    if (ia == 0)
                    {
                        if (hheaTable.caretSlopeRun != 0)
                        {
                            v.Error(T.post_italicAngle, E.post_E_italicAngleZero_caretSlopeRun, m_tag);
                            bItalOk = false;
                            bRet    = false;
                        }
                    }
                    else
                    {
                        if (hheaTable.caretSlopeRun == 0)
                        {
                            v.Error(T.post_italicAngle, E.post_E_italicAngleNonzero_caretSlopeRun, m_tag);
                            bItalOk = false;
                            bRet    = false;
                        }
                        else
                        {
                            double dActualAngle = 90.0 + italicAngle.GetDouble();
                            double dhheaAngle   = (Math.Atan2(hheaTable.caretSlopeRise, hheaTable.caretSlopeRun)) * (180.0 / Math.PI);
                            if (Math.Abs(dActualAngle - dhheaAngle) >= 1.0)
                            {
                                string sDetails = "italicAngle = 0x" + ia.ToString("x8") +
                                                  " (" + italicAngle.GetDouble() + " degrees)" +
                                                  ",caretSlope Rise:Run = " + hheaTable.caretSlopeRise + ":" + hheaTable.caretSlopeRun +
                                                  " (" + (dhheaAngle - 90.0) + " degrees)";
                                v.Error(T.post_italicAngle, E.post_E_italicAngleNonzero_hheaAngle, m_tag, sDetails);
                                bItalOk = false;
                                bRet    = false;
                            }
                        }
                    }
                }
                else
                {
                    v.Error(T.post_italicAngle, E._TEST_E_TableMissing, m_tag, "hhea table missing, can't compare italicAngle to hhea.caretSlopeRun");
                    bItalOk = false;
                    bRet    = false;
                }

                if (bItalOk)
                {
                    v.Pass(T.post_italicAngle, P.post_P_italicAngle, m_tag);
                }
            }

            if (v.PerformTest(T.post_underlinePosition))
            {
                Table_hhea hheaTable = (Table_hhea)fontOwner.GetTable("hhea");
                if (hheaTable != null)
                {
                    if (underlinePosition >= hheaTable.Descender)
                    {
                        v.Pass(T.post_underlinePosition, P.post_P_underlinePosition, m_tag);
                    }
                    else
                    {
                        v.Warning(T.post_underlinePosition, W.post_W_underlinePos_LT_descender, m_tag);
                        //bRet = false;
                    }
                }
                else
                {
                    v.Error(T.post_underlinePosition, E._TEST_E_TableMissing, m_tag, "hhea table missing, can't compare underlinePosition to hhea.Descender");
                }
            }

            if (v.PerformTest(T.post_underlineThickness))
            {
                Table_head headTable = (Table_head)fontOwner.GetTable("head");
                if (headTable != null)
                {
                    if (underlineThickness >= 0 && underlineThickness < headTable.unitsPerEm / 2)
                    {
                        v.Pass(T.post_underlineThickness, P.post_P_underlineThickness, m_tag);
                    }
                    else
                    {
                        v.Warning(T.post_underlineThickness, W.post_W_underlineThickness, m_tag, underlineThickness.ToString());
                    }
                }
                else
                {
                    v.Error(T.post_underlineThickness, E._TEST_E_TableMissing, m_tag, "head table missing, can't compare underlineThickness to head.unitsPerEm");
                    bRet = false;
                }
            }

            if (v.PerformTest(T.post_isFixedPitch))
            {
                bool bFixedPitchOk = true;

                Table_hmtx hmtxTable = (Table_hmtx)fontOwner.GetTable("hmtx");
                if (hmtxTable != null)
                {
                    uint numberOfHMetrics = 0;

                    Table_hhea hheaTable = (Table_hhea)fontOwner.GetTable("hhea");
                    if (hheaTable != null)
                    {
                        numberOfHMetrics = hheaTable.numberOfHMetrics;
                    }
                    else
                    {
                        v.Error(T.post_isFixedPitch, E._TEST_E_TableMissing, m_tag, "hhea table missing, can't compare isFixedPitch to horizontal metrics");
                        bRet = false;
                    }

                    bool bHmtxMono = hmtxTable.IsMonospace(fontOwner);

                    if (isFixedPitch == 0 && bHmtxMono)
                    {
                        v.Error(T.post_isFixedPitch, E.post_E_isFixedPitchZero_hmtx, m_tag);
                        bFixedPitchOk = false;
                        bRet          = false;
                    }
                    else if (isFixedPitch != 0 && !bHmtxMono)
                    {
                        v.Error(T.post_isFixedPitch, E.post_E_isFixedPitchNonzero_hmtx, m_tag);
                        bFixedPitchOk = false;
                        bRet          = false;
                    }
                }
                else
                {
                    v.Error(T.post_isFixedPitch, E._TEST_E_TableMissing, m_tag, "hmtx table missing, can't compare isFixedPitch to horizontal metrics");
                    bRet = false;
                }

                Table_OS2 OS2Table = (Table_OS2)fontOwner.GetTable("OS/2");
                if (OS2Table != null)
                {
                    if (OS2Table.panose_byte1 == 2)                          // PANOSE family kind == LatinText
                    {
                        if (isFixedPitch == 0 && OS2Table.panose_byte4 == 9) // PANOSE proportion == monospaced
                        {
                            v.Error(T.post_isFixedPitch, E.post_E_isFixedPitchZero_OS_2, m_tag);
                            bFixedPitchOk = false;
                            bRet          = false;
                        }
                        else if (isFixedPitch != 0 && OS2Table.panose_byte4 != 9)
                        {
                            v.Error(T.post_isFixedPitch, E.post_E_isFixedPitchNonzero_OS_2, m_tag);
                            bFixedPitchOk = false;
                            bRet          = false;
                        }
                    }
                }
                else
                {
                    v.Error(T.post_isFixedPitch, E._TEST_E_TableMissing,
                            m_tag, "OS/2 table is missing, can't compare isFixedPitch to OS/2 PANOSE");
                    bRet = false;
                }

                if (bFixedPitchOk && hmtxTable != null && OS2Table != null)
                {
                    v.Pass(T.post_isFixedPitch, P.post_P_isFixedPitch, m_tag, "matches the hmtx and OS/2 tables");
                }
                else if (bFixedPitchOk && hmtxTable == null && OS2Table != null)
                {
                    v.Pass(T.post_isFixedPitch, P.post_P_isFixedPitch, m_tag, "matches the OS/2 table");
                }
                else if (bFixedPitchOk && hmtxTable != null && OS2Table == null)
                {
                    v.Pass(T.post_isFixedPitch, P.post_P_isFixedPitch, m_tag, "matches the hmtx table");
                }
            }

            if (v.PerformTest(T.post_v2_numberOfGlyphs))
            {
                if (Version.GetUint() == 0x00020000)
                {
                    Table_maxp maxpTable = (Table_maxp)fontOwner.GetTable("maxp");
                    if (maxpTable == null)
                    {
                        v.Error(T.post_v2_numberOfGlyphs, E._TEST_E_TableMissing, m_tag, "maxp table is missing");
                        bRet = false;
                    }
                    else
                    {
                        if (numberOfGlyphs == fontOwner.GetMaxpNumGlyphs())
                        {
                            v.Pass(T.post_v2_numberOfGlyphs, P.post_P_v2_numberOfGlyphs, m_tag);
                        }
                        else
                        {
                            v.Error(T.post_v2_numberOfGlyphs, E.post_E_v2_numberOfGlyphs,
                                    m_tag, "numberOfGlyphs = " + numberOfGlyphs +
                                    ", maxp.numGlyphs = " + fontOwner.GetMaxpNumGlyphs());
                            bRet = false;
                        }
                    }
                }
                else
                {
                    v.Info(T.post_v2_numberOfGlyphs, I.post_I_v2_numberOfGlyphs_notv2, m_tag);
                }
            }

            if (v.PerformTest(T.post_v2_glyphNameIndex))
            {
                if (Version.GetUint() == 0x00020000 && GetLength() >= 34)
                {
                    bool bIndexOk = true;

                    for (uint i = 0; i < numberOfGlyphs; i++)
                    {
                        if ((uint)FieldOffsetsVer2.glyphNameIndex + i * 2 + 2 <= m_bufTable.GetLength())
                        {
                            ushort index = GetGlyphNameIndex((ushort)i);
                            if (index - 258 >= m_nameOffsets.Length)
                            {
                                string s = "glyphNameIndex[" + i + "] = " +
                                           index + ", # names = " + m_nameOffsets.Length;
                                v.Error(T.post_v2_glyphNameIndex, E.post_E_glyphNameIndex_range, m_tag, s);
                                bIndexOk = false;
                                bRet     = false;
                            }
                        }
                        else
                        {
                            v.Warning(T.post_v2_glyphNameIndex,
                                      W._TEST_W_OtherErrorsInTable, m_tag,
                                      "unable to validate any more glyph indexes, index  " +
                                      i + " is past end of table");
                            bIndexOk = false;
                            break;
                        }
                    }

                    if (bIndexOk)
                    {
                        v.Pass(T.post_v2_glyphNameIndex, P.post_P_glyphNameIndex, m_tag);
                    }
                }
                else
                {
                    v.Info(T.post_v2_glyphNameIndex, I.post_I_v2_glyphNameIndex_notv2, m_tag);
                }
            }

            if (v.PerformTest(T.post_v2_names))
            {
                if (Version.GetUint() == 0x00020000)
                {
                    PostNames pn = new PostNames();

                    bool bNamesOk = true;

                    byte [] buf = new byte[2];

                    for (uint iGlyph = 0; iGlyph < numberOfGlyphs; iGlyph++)
                    {
                        if ((uint)FieldOffsetsVer2.glyphNameIndex + iGlyph * 2 + 2
                            <= m_bufTable.GetLength())
                        {
                            uint index = GetGlyphNameIndex((ushort)iGlyph);
                            if (index >= 258 && index - 258 < m_nameOffsets.Length)
                            {
                                if (m_nameOffsets[index - 258] >= GetLength())
                                {
                                    string s = "name index = " + index;
                                    v.Error(T.post_v2_names,
                                            E.post_E_v2_NameOffsetInvalid,
                                            m_tag, s);
                                    bNamesOk = false;
                                    bRet     = false;
                                }
                                else
                                {
                                    uint length =
                                        m_bufTable.GetByte(m_nameOffsets[index - 258]);
                                    if (m_nameOffsets[index - 258] + length < GetLength())
                                    {
                                        bNamesOk = CheckNames(v, fontOwner, pn, iGlyph, index);
                                    }
                                    else
                                    {
                                        string s = "name index = " + index;
                                        v.Error(T.post_v2_names, E.post_E_v2_NameLengthInvalid, m_tag, s);
                                        bNamesOk = false;
                                        bRet     = false;
                                    }
                                }
                            }
                        }
                        else
                        {
                            v.Warning(T.post_v2_names, W._TEST_W_OtherErrorsInTable, m_tag,
                                      "unable to validate any more names, index " +
                                      iGlyph + " is past end of table");
                            bNamesOk = false;
                            break;
                        }
                    }

                    if (bNamesOk)
                    {
                        v.Pass(T.post_v2_names, P.post_P_names, m_tag);
                    }
                }
                else
                {
                    v.Info(T.post_v2_names, I.post_I_v2_names_notv2, m_tag);
                }
            }

            return(bRet);
        }
Ejemplo n.º 31
0
 private bool ValidateGlyfEntryEmpty(Validator validator,
     OTFont fontOwner)
 {
     int cntInfo=0;
     int numEntry=this.NumEntry(fontOwner);
     if (numEntry==Table_loca.ValueInvalid)
     {
         if (validator!=null)
         {
             validator.Warning(T.T_NULL, W._TEST_W_OtherErrorsInTable, 
                 m_tag,
                 "Unable to determine the number of entries in the 'loca' table");
         }
         return false;
     }
     
     int offsGlyfCur, offsGlyfNext;            
     for (int iEntry=0; iEntry<numEntry-1; iEntry++)
     {
         if ((!this.GetGlyfOffset(iEntry, out offsGlyfCur, validator, fontOwner))||
             (!this.GetGlyfOffset(iEntry+1, out offsGlyfNext, validator, fontOwner)))
         {
             cntInfo++;
             continue;
         }
         if (offsGlyfNext==offsGlyfCur)
         {
             cntInfo++;
         }
     }
     if (validator!=null)
     {
         if (cntInfo==0)
         {
             validator.Pass(P.loca_P_GlyfEntryEmpty, m_tag);
         }
         else
         {
             validator.Info(T.T_NULL, I.loca_I_GlyfEntryEmpty, 
                 m_tag,
                 "Number of glyphs that are empty = "+cntInfo);
         }
     }
     return (cntInfo==0);
 }