GetTable() public method

public GetTable ( OTFontFile.OTTag tag ) : OTFontFile.OTTable
tag OTFontFile.OTTag
return OTFontFile.OTTable
Esempio n. 1
0
        /************************
         * public methods
         */


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

            Table_maxp maxpTable = (Table_maxp)fontOwner.GetTable("maxp");
            if (maxpTable == null)
            {
                v.Error(T.T_NULL, E._TEST_E_TableMissing, m_tag, "Unable to test this table, maxp table is invalid or missing");
                return false;
            }
            
            if (v.PerformTest(T.vmtx_TableLength))
            {
                uint CalcTableLength = GetNumOfLongVerMetrics(fontOwner)*4 
                    + (fontOwner.GetMaxpNumGlyphs() - GetNumOfLongVerMetrics(fontOwner))*2;
                if (CalcTableLength == GetLength())
                {
                    v.Pass(T.vmtx_TableLength, P.vmtx_P_TableLength, m_tag);
                }
                else
                {
                    v.Error(T.vmtx_TableLength, E.vmtx_E_TableLength, m_tag);
                    bRet = false;
                }
            }

            return bRet;
        }
Esempio n. 2
0
        /************************
         * public methods
         */


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

            if (v.PerformTest(T.PCLT_TableLength))
            {
                if (GetLength() == 54)
                {
                    v.Pass(T.PCLT_TableLength, P.PCLT_P_TableLength, m_tag);
                }
                else
                {
                    v.Error(T.PCLT_TableLength, E.PCLT_E_TableLength, m_tag, GetLength().ToString());
                    bRet = false;
                }
            }

            if (v.PerformTest(T.PCLT_Version))
            {
                if (Version.GetUint() == 0x00010000)
                {
                    v.Pass(T.PCLT_Version, P.PCLT_P_Version, m_tag);
                }
                else
                {
                    v.Error(T.PCLT_Version, E.PCLT_E_Version, m_tag, "0x"+Version.GetUint().ToString("x8"));
                    bRet = false;
                }
            }

            if (v.PerformTest(T.PCLT_Pitch))
            {
                Table_hmtx hmtxTable = (Table_hmtx)fontOwner.GetTable("hmtx");
                Table_maxp maxpTable = (Table_maxp)fontOwner.GetTable("maxp");
                if (hmtxTable == null)
                {
                    v.Error(T.PCLT_Pitch, E._TEST_E_TableMissing, m_tag, "hmtx");
                    bRet = false;
                }
                else if (maxpTable == null)
                {
                    v.Error(T.PCLT_Pitch, E._TEST_E_TableMissing, m_tag, "maxp");
                    bRet = false;
                }
                else
                {
                    uint iSpaceGlyph = fontOwner.FastMapUnicodeToGlyphID(' ');

                    if (iSpaceGlyph < fontOwner.GetMaxpNumGlyphs())
                    {
                        Table_hmtx.longHorMetric hmSpace = hmtxTable.GetOrMakeHMetric(iSpaceGlyph, fontOwner);
                        if (hmSpace != null)
                        {
                            if (Pitch == hmSpace.advanceWidth)
                            {
                                v.Pass(T.PCLT_Pitch, P.PCLT_P_Pitch, m_tag);
                            }
                            else
                            {
                                string s = "actual = " + Pitch + ", expected = " + hmSpace.advanceWidth;
                                v.Error(T.PCLT_Pitch, E.PCLT_E_Pitch, m_tag, s);
                                bRet = false;
                            }
                        }
                    }
                    else
                    {
                        // JJF Figure out what to do
                        v.Warning(T.PCLT_Pitch, W._TEST_W_ErrorInAnotherTable, m_tag, "can't validate Pitch field, error getting the space glyph");
                        bRet = false;
                    }
                }
            }

            if (v.PerformTest(T.PCLT_Style))
            {
                ushort Posture   = (ushort)(Style      & 0x0003);
                ushort Width     = (ushort)((Style>>2) & 0x0007);
                ushort Structure = (ushort)((Style>>5) & 0x001f);
                ushort Reserved  = (ushort)(Style>>10);

                bool bBitsOk = true;

                if (Posture == 3)
                {
                    v.Error(T.PCLT_Style, E.PCLT_E_Style_Posture, m_tag, "0x"+Style.ToString("x4"));
                    bBitsOk = false;
                    bRet = false;
                }
                if (Width == 5)
                {
                    v.Error(T.PCLT_Style, E.PCLT_E_Style_Width, m_tag, "0x"+Style.ToString("x4"));
                    bBitsOk = false;
                    bRet = false;
                }
                if (Structure > 17)
                {
                    v.Error(T.PCLT_Style, E.PCLT_E_Style_Structure, m_tag, "0x"+Style.ToString("x4"));
                    bBitsOk = false;
                    bRet = false;
                }
                if (Reserved != 0)
                {
                    v.Error(T.PCLT_Style, E.PCLT_E_Style_Reserved, m_tag, "0x"+Style.ToString("x4"));
                    bBitsOk = false;
                    bRet = false;
                }

                if (bBitsOk)
                {
                    v.Pass(T.PCLT_Style, P.PCLT_P_Style, m_tag);
                }

            }

            if (v.PerformTest(T.PCLT_StrokeWeight))
            {
                if (StrokeWeight >= -7 && StrokeWeight <= 7)
                {
                    v.Pass(T.PCLT_StrokeWeight, P.PCLT_P_StrokeWeight, m_tag, StrokeWeight.ToString());
                }
                else
                {
                    v.Error(T.PCLT_StrokeWeight, E.PCLT_E_StrokeWeight, m_tag, StrokeWeight.ToString());
                    bRet = false;
                }
            }

            if (v.PerformTest(T.PCLT_WidthType))
            {
                if (WidthType >= -5 && WidthType <= 5)
                {
                    v.Pass(T.PCLT_WidthType, P.PCLT_P_WidthType, m_tag, WidthType.ToString());
                }
                else
                {
                    v.Error(T.PCLT_WidthType, E.PCLT_E_WidthType, m_tag, WidthType.ToString());
                    bRet = false;
                }
            }

            if (v.PerformTest(T.PCLT_SerifStyle))
            {
                uint bot6 = (uint)SerifStyle & 0x3f;
                uint top2 = (uint)SerifStyle>>6;

                bool bBitsOk = true;

                if (bot6 > 12)
                {
                    v.Error(T.PCLT_SerifStyle, E.PCLT_E_Bottom6, m_tag, "0x"+SerifStyle.ToString("x2"));
                    bBitsOk = false;
                    bRet = false;
                }                
                if (top2 == 0 || top2 == 3)
                {
                    v.Error(T.PCLT_SerifStyle, E.PCLT_E_Top2, m_tag);
                    bBitsOk = false;
                    bRet = false;
                }

                if (bBitsOk)
                {
                    v.Pass(T.PCLT_SerifStyle, P.PCLT_P_SerifStyle, m_tag);
                }
            }

            if (v.PerformTest(T.PCLT_Reserved))
            {
                if (Reserved == 0)
                {
                    v.Pass(T.PCLT_Reserved, P.PCLT_P_Reserved, m_tag);
                }
                else
                {
                    v.Error(T.PCLT_Reserved, E.PCLT_E_Reserved, m_tag, Reserved.ToString());
                    bRet = false;
                }
            }

            return bRet;
        }
Esempio n. 3
0
        /************************
         * public methods
         */


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

            if (v.PerformTest(T.EBSC_version))
            {
                if (version.GetUint() == 0x00020000)
                {
                    v.Pass(T.EBSC_version, P.EBSC_P_version, m_tag);
                }
                else
                {
                    v.Error(T.EBSC_version, E.EBSC_E_version, m_tag, "version = 0x" + version.GetUint().ToString("x8") + ", unable to continue validation");
                    return false;
                }
            }

            if (v.PerformTest(T.EBSC_TableLength))
            {
                uint CalcLength = 8 + (numSizes * 28);
                if (CalcLength == GetLength())
                {
                    v.Pass(T.EBSC_TableLength, P.EBSC_P_TableLength, m_tag);
                }
                else
                {
                    string s = "actual length = " + GetLength() + ", calculated = " + CalcLength;
                    v.Error(T.EBSC_TableLength, E.EBSC_E_TableLength, m_tag, s);
                    bRet = false;
                }
            }

            if (v.PerformTest(T.EBSC_TableDependency))
            {
                Table_EBLC EBLCTable = (Table_EBLC)fontOwner.GetTable("EBLC");
                Table_EBDT EBDTTable = (Table_EBDT)fontOwner.GetTable("EBDT");
                if (   EBLCTable != null
                    && EBDTTable != null)
                {
                    v.Pass(T.EBSC_TableDependency, P.EBSC_P_TableDependency, m_tag);
                }
                else
                {
                    string s = "Missing: ";
                    if (EBLCTable == null)
                    {
                        s = s + "EBLC";
                    }
                    if (EBDTTable == null)
                    {
                        if (EBLCTable == null)
                            s = s + ", EBDT";
                        else
                            s = s + "EBDT";
                    }

                    v.Error(T.EBSC_TableDependency, E.EBSC_E_TableDependency, m_tag, s);
                    bRet = false;
                }
            }

            if (v.PerformTest("EBSC_StrikeSizes"))
            {
                Table_EBLC EBLCTable = (Table_EBLC)fontOwner.GetTable("EBLC");
                if (EBLCTable != null)
                {
                    string s = "Missing strike: ";
                    bool bPass = true;

                    for (uint i = 0; i < numSizes; i++)
                    {
                        bitmapScaleTable bitmapScale = GetBitmapScaleTable(i);

                        if (bitmapScale != null)
                        {
                            bool bFound = false;

                            for (uint n = 0; n < EBLCTable.numSizes; n++)
                            {
                                Table_EBLC.bitmapSizeTable bitmapSize = EBLCTable.GetBitmapSizeTable(n);
                                if (bitmapSize != null)
                                {
                                    if (   bitmapScale.substitutePpemX == bitmapSize.ppemX
                                        && bitmapScale.substitutePpemY == bitmapSize.ppemY)
                                    {
                                        bFound = true;
                                        break;
                                    }
                                }

                            }

                            if (!bFound)
                            {
                                string size = "(PpemX:" + bitmapScale.substitutePpemX + ", PpemY:" + bitmapScale.substitutePpemY + ") ";
                                s = s + size;
                                bPass = false;
                            }
                        }
                    }

                    if (bPass)
                    {
                        v.Pass(T.EBSC_StrikeSizes, P.EBSC_P_StrikeSize, m_tag);
                    }
                    else
                    {
                        v.Error(T.EBSC_StrikeSizes, E.EBSC_E_StrikeSize, m_tag, s);
                    }
                }
                else
                {
                    v.Error(T.EBSC_StrikeSizes, E.EBSC_E_StrikeSizeNoEBLC, m_tag);
                }
            }


            return bRet;
        }
Esempio n. 4
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;
        }
Esempio n. 5
0
        /************************
         * public methods
         */


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

            if (v.PerformTest(T.EBSC_version))
            {
                if (version.GetUint() == 0x00020000)
                {
                    v.Pass(T.EBSC_version, P.EBSC_P_version, m_tag);
                }
                else
                {
                    v.Error(T.EBSC_version, E.EBSC_E_version, m_tag, "version = 0x" + version.GetUint().ToString("x8") + ", unable to continue validation");
                    return(false);
                }
            }

            if (v.PerformTest(T.EBSC_TableLength))
            {
                uint CalcLength = 8 + (numSizes * 28);
                if (CalcLength == GetLength())
                {
                    v.Pass(T.EBSC_TableLength, P.EBSC_P_TableLength, m_tag);
                }
                else
                {
                    string s = "actual length = " + GetLength() + ", calculated = " + CalcLength;
                    v.Error(T.EBSC_TableLength, E.EBSC_E_TableLength, m_tag, s);
                    bRet = false;
                }
            }

            if (v.PerformTest(T.EBSC_TableDependency))
            {
                Table_EBLC EBLCTable = (Table_EBLC)fontOwner.GetTable("EBLC");
                Table_EBDT EBDTTable = (Table_EBDT)fontOwner.GetTable("EBDT");
                if (EBLCTable != null &&
                    EBDTTable != null)
                {
                    v.Pass(T.EBSC_TableDependency, P.EBSC_P_TableDependency, m_tag);
                }
                else
                {
                    string s = "Missing: ";
                    if (EBLCTable == null)
                    {
                        s = s + "EBLC";
                    }
                    if (EBDTTable == null)
                    {
                        if (EBLCTable == null)
                        {
                            s = s + ", EBDT";
                        }
                        else
                        {
                            s = s + "EBDT";
                        }
                    }

                    v.Error(T.EBSC_TableDependency, E.EBSC_E_TableDependency, m_tag, s);
                    bRet = false;
                }
            }

            if (v.PerformTest("EBSC_StrikeSizes"))
            {
                Table_EBLC EBLCTable = (Table_EBLC)fontOwner.GetTable("EBLC");
                if (EBLCTable != null)
                {
                    string s     = "Missing strike: ";
                    bool   bPass = true;

                    for (uint i = 0; i < numSizes; i++)
                    {
                        bitmapScaleTable bitmapScale = GetBitmapScaleTable(i);

                        if (bitmapScale != null)
                        {
                            bool bFound = false;

                            for (uint n = 0; n < EBLCTable.numSizes; n++)
                            {
                                Table_EBLC.bitmapSizeTable bitmapSize = EBLCTable.GetBitmapSizeTable(n);
                                if (bitmapSize != null)
                                {
                                    if (bitmapScale.substitutePpemX == bitmapSize.ppemX &&
                                        bitmapScale.substitutePpemY == bitmapSize.ppemY)
                                    {
                                        bFound = true;
                                        break;
                                    }
                                }
                            }

                            if (!bFound)
                            {
                                string size = "(PpemX:" + bitmapScale.substitutePpemX + ", PpemY:" + bitmapScale.substitutePpemY + ") ";
                                s     = s + size;
                                bPass = false;
                            }
                        }
                    }

                    if (bPass)
                    {
                        v.Pass(T.EBSC_StrikeSizes, P.EBSC_P_StrikeSize, m_tag);
                    }
                    else
                    {
                        v.Error(T.EBSC_StrikeSizes, E.EBSC_E_StrikeSize, m_tag, s);
                    }
                }
                else
                {
                    v.Error(T.EBSC_StrikeSizes, E.EBSC_E_StrikeSizeNoEBLC, m_tag);
                }
            }


            return(bRet);
        }
Esempio n. 6
0
        /************************
         * public methods
         */


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

            if (v.PerformTest(T.LTSH_version))
            {
                if (version == 0)
                {
                    v.Pass(T.LTSH_version, P.LTSH_P_version, m_tag);
                }
                else
                {
                    v.Error(T.LTSH_version, E.LTSH_E_version, m_tag, version.ToString());
                    bRet = false;
                }
            }

            Table_maxp maxpTable = (Table_maxp)fontOwner.GetTable("maxp");

            if (maxpTable == null)
            {
                v.Error(T.T_NULL, E._TEST_E_TableMissing, m_tag, "Unable to test this table, maxp table is invalid or missing");
                return(false);
            }

            if (v.PerformTest(T.LTSH_numGlyphs))
            {
                if (numGlyphs == fontOwner.GetMaxpNumGlyphs())
                {
                    v.Pass(T.LTSH_numGlyphs, P.LTSH_P_numGlyphs, m_tag);
                }
                else
                {
                    string s = "LTSH.numGlyphs = " + numGlyphs + ", maxp.numGlyphs = " + fontOwner.GetMaxpNumGlyphs();
                    v.Error(T.LTSH_numGlyphs, E.LTSH_E_numGlyphs, m_tag, s);
                    bRet = false;
                }
            }

            if (v.PerformTest(T.LTSH_TableLength))
            {
                uint CalcLength = (uint)FieldOffsets.yPels + numGlyphs;
                if (GetLength() == CalcLength)
                {
                    v.Pass(T.LTSH_TableLength, P.LTSH_P_TableLength, m_tag);
                }
                else
                {
                    string s = "calc length = " + CalcLength + ", actual length = " + GetLength();
                    v.Error(T.LTSH_TableLength, E.LTSH_E_TableLength, m_tag, s);
                    bRet = false;
                }
            }

            if (v.PerformTest(T.LTSH_yPels))
            {
                bool bYPelsOk = true;
                RasterInterf.DevMetricsData dmd = null;
                try
                {
                    Version ver = fontOwner.GetFile().GetRasterizer().FTVersion;

                    if (ver.CompareTo(new Version(2, 6, 1)) < 0)
                    {
                        v.Warning(T.LTSH_yPels, W.LTSH_W_Need_Newer_FreeType, m_tag,
                                  "Using FreeType Version " + ver + " may not get correct results for LTSH");
                    }

                    dmd = fontOwner.GetCalculatedDevMetrics();
                }
                catch (Exception e)
                {
                    v.ApplicationError(T.LTSH_yPels, E._Table_E_Exception, m_tag, e.Message);
                    bRet = false;
                }

                if (dmd != null)
                {
                    for (uint iGlyphIndex = 0; iGlyphIndex < numGlyphs; iGlyphIndex++)
                    {
                        if (iGlyphIndex >= fontOwner.GetMaxpNumGlyphs())
                        {
                            // JJF. Figure out what to do
                            v.Warning(T.LTSH_yPels, W._TEST_W_OtherErrorsInTable, m_tag, "can't test all yPel values, LTSH.numGlyphs does not equal maxp.numGlyphs");
                            bRet     = false;
                            bYPelsOk = false;
                            break;
                        }

                        if (GetYPel(iGlyphIndex) != dmd.ltshData.yPels[iGlyphIndex])
                        {
                            String sDetails = "glyph# = " + iGlyphIndex + ", value = " + GetYPel(iGlyphIndex) + ", calculated value = " + dmd.ltshData.yPels[iGlyphIndex];
                            v.Error(T.LTSH_yPels, E.LTSH_E_yPels, m_tag, sDetails);
                            bRet     = false;
                            bYPelsOk = false;
                        }

                        /*
                         * else
                         * {
                         *  String sDetails = "glyph# = " + iGlyphIndex + ", value = " + GetYPel(iGlyphIndex);
                         *  v.DebugMsg("yPel value OK! " + sDetails, m_tag);
                         * }
                         */

                        if (GetYPel(iGlyphIndex) == 0)
                        {
                            String sDetails = "glyph# = " + iGlyphIndex;
                            v.Warning(T.LTSH_yPels, W.LTSH_W_yPels_zero, m_tag, sDetails);
                        }
                    }

                    if (bYPelsOk)
                    {
                        v.Pass(T.LTSH_yPels, P.LTSH_P_yPels, m_tag);
                    }
                }
                else
                {
                    // if user didn't cancel, then check for error message
                    if (!v.CancelFlag)
                    {
                        String sDetails = null;
                        try
                        {
                            sDetails = fontOwner.GetDevMetricsDataError();
                        }
                        catch (Exception e)
                        {
                            v.ApplicationError(T.LTSH_yPels, E._Table_E_Exception, m_tag, e.Message);
                        }
                        Debug.Assert(sDetails != null);
                        v.Error(T.LTSH_yPels, E.LTSH_E_Rasterizer, m_tag, sDetails);
                        bRet = false;
                    }
                }
            }

            return(bRet);
        }
Esempio n. 7
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);
        }
Esempio n. 8
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;
        }
Esempio n. 9
0
        /************************
         * public methods
         */


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

            if (v.PerformTest(T.kern_TableVersion))
            {
                if (version == 0)
                {
                    v.Pass(T.kern_TableVersion, P.kern_P_TableVersion, m_tag);
                }
                else
                {
                    v.Error(T.kern_TableVersion, E.kern_E_TableVersion, m_tag, "version = " + version.ToString() + ", unrecognized version #, no further tests can be performed");
                    return false;
                }
            }



            if (v.PerformTest(T.kern_NumSubtables))
            {
                if (nTables != 0)
                {
                    v.Pass(T.kern_NumSubtables, P.kern_P_NumSubTables, m_tag, nTables.ToString());
                }
                else
                {
                    v.Error(T.kern_NumSubtables, E.kern_E_NumSubTables, m_tag);
                    bRet = false;
                }
            }


            if (v.PerformTest(T.kern_SubtableFormats))
            {
                bool bFormatsOk = true;

                for (uint i=0; i<nTables; i++)
                {
                    SubTableHeader sth = GetSubTableHeader(i);
                    if (sth != null)
                    {
                        if (sth.GetFormat() != 0 && sth.GetFormat() != 2)
                        {
                            v.Error(T.kern_SubtableFormats, E.kern_E_SubtableFormats, m_tag, "subtable #" + i + ", format " + sth.GetFormat());
                            bFormatsOk = false;
                            bRet = false;
                        }
                    }
                    else
                    {
                        v.Error(T.kern_SubtableFormats, E.kern_E_SubTableExtendsPastEOT, m_tag, "subtable #" + i );
                        bFormatsOk = false;
                        bRet = false;
                        break;
                    }
                }
                if (bFormatsOk)
                {
                    v.Pass(T.kern_SubtableFormats, P.kern_P_SubtableFormats, m_tag);
                }
            }

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

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

                for (uint i=0; i<nTables; i++)
                {
                    SubTable st = this.GetSubTable(i);
                    if (st.length != st.CalculatedLength())
                    {
                        v.Error(T.kern_SubtableLength, E.kern_E_SubtableLength, m_tag, "subtable #" + i + ", length = " + st.length + ", calculated length = " + st.CalculatedLength());
                        bLengthsOk = false;
                        bRet = false;
                    }
                }
                if (bLengthsOk)
                {
                    v.Pass(T.kern_SubtableLength, P.kern_P_SubtableLengths, m_tag);
                }
            }

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

                for (uint i=0; i<nTables; i++)
                {
                    SubTable st = this.GetSubTable(i);
                    if ((st.coverage & 0xf0)  != 0)
                    {
                        bReservedOk = false;
                        v.Error(T.kern_CoverageReservedBits, E.kern_E_ReservedCoverageBits, m_tag, "subtable #" + i);
                        bRet = false;
                        break;
                    }
                }
                if (bReservedOk)
                {
                    v.Pass(T.kern_CoverageReservedBits, P.kern_P_ReservedCoverageBits, m_tag);
                }
            }

            if (v.PerformTest(T.kern_Format0_SearchFields))
            {
                bool bBinaryFieldsOk = true;

                for (uint i=0; i<nTables; i++)
                {
                    SubTable st = this.GetSubTable(i);
                    if (st.version == 0)
                    {
                        SubTableFormat0 stf0 = (SubTableFormat0)st;
                        ushort nPairs = stf0.nPairs;
                        ushort sizeofEntry = 6;

                        if (nPairs != 0)
                        {
                            ushort CalculatedSearchRange   = (ushort)(util.MaxPower2LE(nPairs) * sizeofEntry);
                            ushort CalculatedEntrySelector = util.Log2(util.MaxPower2LE(nPairs));
                            ushort CalculatedRangeShift    = (ushort)((nPairs - util.MaxPower2LE(nPairs))* sizeofEntry);

                            if (stf0.searchRange != CalculatedSearchRange)
                            {
                                string s =  "subtable #" + i 
                                    + ", calc = " + CalculatedSearchRange 
                                    + ", actual = " + stf0.searchRange;
                                v.Error(T.kern_Format0_SearchFields, E.kern_E_Format0_searchRange, m_tag, s);
                                bBinaryFieldsOk = false;
                                bRet = false;
                            }
                            if (stf0.entrySelector != CalculatedEntrySelector)
                            {
                                string s =  "subtable #" + i 
                                    + ", calc = " +  CalculatedEntrySelector
                                    + ", actual = " + stf0.entrySelector;
                                v.Error(T.kern_Format0_SearchFields, E.kern_E_Format0_entrySelector, m_tag, s);
                                bBinaryFieldsOk = false;
                                bRet = false;
                            }
                            if (stf0.rangeShift != CalculatedRangeShift)
                            {
                                string s =  "subtable #" + i 
                                    + ", calc = " +  CalculatedRangeShift
                                    + ", actual = " + stf0.rangeShift;
                                v.Error(T.kern_Format0_SearchFields, E.kern_E_Format0_rangeShift, m_tag, s);
                                bBinaryFieldsOk = false;
                                bRet = false;
                            }
                        }
                        else
                        {
                            // cannot validate fields since they are undefined when nPairs is zero
                            v.Warning(T.kern_Format0_SearchFields, W.kern_W_Format0_SearchFields, m_tag, "subtable #" + i + ", nPairs = " + stf0.nPairs);
                            bBinaryFieldsOk = false;
                        }
                    }
                }

                if (bBinaryFieldsOk)
                {
                    v.Pass(T.kern_Format0_SearchFields, P.kern_P_Format0_SearchFields, m_tag);
                }
            }

            if (v.PerformTest(T.kern_Format0_GlyphIDs))
            {
                for (uint i=0; i<nTables; i++)
                {
                    SubTable st = this.GetSubTable(i);
                    if (st.version == 0)
                    {
                        bool bGlyphIDsOk = true;

                        SubTableFormat0 stf0 = (SubTableFormat0)st;

                        for (int iPair=0; iPair<stf0.nPairs; iPair++)
                        {
                            ushort left=0, right=0;
                            short kernvalue=0;

                            stf0.GetKerningPairAndValue(iPair, ref left, ref right, ref kernvalue);

                            ushort numGlyphs = fontOwner.GetMaxpNumGlyphs();
                            if (left >= numGlyphs)
                            {
                                v.Error(T.kern_Format0_GlyphIDs, E.kern_E_Format0_GlyphIDs, m_tag, "kern pair[" + iPair + "]: left = " + left);
                                bGlyphIDsOk = false;
                                bRet = false;
                            }
                            if (right >= numGlyphs)
                            {
                                v.Error(T.kern_Format0_GlyphIDs, E.kern_E_Format0_GlyphIDs, m_tag, "kern pair[" + iPair + "]: right = " + right);
                                bGlyphIDsOk = false;
                                bRet = false;
                            }
                        }

                        if (bGlyphIDsOk)
                        {
                            v.Pass(T.kern_Format0_GlyphIDs, P.kern_P_Format0_GlyphIDs, m_tag);
                        }
                    }
                }

            }

            if (v.PerformTest(T.kern_Format0_Values))
            {
                for (uint i=0; i<nTables; i++)
                {
                    SubTable st = this.GetSubTable(i);
                    if (st.version == 0)
                    {
                        SubTableFormat0 stf0 = (SubTableFormat0)st;

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

                            bool bValuesOk = true;

                            for (int iPair=0; iPair<stf0.nPairs; iPair++)
                            {
                                ushort left=0, right=0;
                                short kernvalue=0;

                                stf0.GetKerningPairAndValue(iPair, ref left, ref right, ref kernvalue);
                                short absKernValue = Math.Abs(kernvalue);

                                Table_hmtx.longHorMetric lhmLeft = hmtxTable.GetOrMakeHMetric(left, fontOwner);
                                Table_hmtx.longHorMetric lhmRight = hmtxTable.GetOrMakeHMetric(right, fontOwner);
                            
                                if (absKernValue > lhmLeft.advanceWidth && absKernValue > lhmRight.advanceWidth)
                                {
                                    v.Error(T.kern_Format0_Values, E.kern_E_Format0_Values, m_tag, "kern pair[" + iPair + "]: left id = " + left + ", right id = " + right + ", value = " + kernvalue);
                                    bValuesOk=false;
                                    bRet = false;
                                }
                            }

                            if (bValuesOk)
                            {
                                v.Pass(T.kern_Format0_Values, P.kern_P_Format0_Values, m_tag);
                            }
                        }
                    }
                }

            }

            if (v.PerformTest("kern_Format0_IDsInCmap"))
            {
                for (uint i=0; i<nTables; i++)
                {
                    SubTable st = this.GetSubTable(i);
                    if (st.version == 0)
                    {
                        SubTableFormat0 stf0 = (SubTableFormat0)st;

                        Table_cmap cmapTable = (Table_cmap)fontOwner.GetTable("cmap");
                        if (cmapTable != null)
                        {
                            Table_cmap.Subtable cmapSubtable = cmapTable.GetSubtable(3,10);
                            if (cmapSubtable == null)
                            {
                                cmapSubtable = cmapTable.GetSubtable(3,1);
                            }
                            if (cmapSubtable == null)
                            {
                                Table_cmap.EncodingTableEntry ete = cmapTable .GetEncodingTableEntry(0);
                                cmapSubtable = cmapTable.GetSubtable(ete);
                            }

                            if (cmapSubtable != null)
                            {
                                uint [] map = cmapSubtable.GetMap();

                                bool bAllIDsInCmap = true;

                                for (int iPair=0; iPair<stf0.nPairs; iPair++)
                                {
                                    ushort left=0, right=0;
                                    short kernvalue=0;

                                    stf0.GetKerningPairAndValue(iPair, ref left, ref right, ref kernvalue);
                                    
                                    bool bFoundLeft = false;
                                    bool bFoundRight = false;

                                    for (int j=0; j<map.Length; j++)
                                    {
                                        if (left == map[j])
                                        {
                                            bFoundLeft = true;
                                            break;
                                        }
                                    }

                                    for (int j=0; j<map.Length; j++)
                                    {
                                        if (right == map[j])
                                        {
                                            bFoundRight = true;
                                            break;
                                        }
                                    }

                                    if (bFoundLeft==false)
                                    {
                                        v.Error(T.kern_Format0_IDsInCmap, E.kern_E_Format0_GlyphIdInCmap, m_tag, "kern pair[" + iPair + "]: left id = " + left);
                                        bAllIDsInCmap = false;
                                        bRet = false;
                                    }
                                    if (bFoundRight==false)
                                    {
                                        v.Error(T.kern_Format0_IDsInCmap, E.kern_E_Format0_GlyphIdInCmap, m_tag, "kern pair[" + iPair + "]: right id = " + right);
                                        bAllIDsInCmap = false;
                                        bRet = false;
                                    }
                                }

                                if (bAllIDsInCmap)
                                {
                                    v.Pass(T.kern_Format0_IDsInCmap, P.kern_P_Format0_GlyphIdInCmap, m_tag);
                                }
                            }

                        }
                    }
                }
            }

            return bRet;
        }
Esempio n. 10
0
        /************************
         * public methods
         */


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

            if (v.PerformTest(T.LTSH_version))
            {
                if (version == 0)
                {
                    v.Pass(T.LTSH_version, P.LTSH_P_version, m_tag);
                }
                else
                {
                    v.Error(T.LTSH_version, E.LTSH_E_version, m_tag, version.ToString());
                    bRet = false;
                }
            }

            Table_maxp maxpTable = (Table_maxp)fontOwner.GetTable("maxp");
            if (maxpTable == null)
            {
                v.Error(T.T_NULL, E._TEST_E_TableMissing, m_tag, "Unable to test this table, maxp table is invalid or missing");
                return false;
            }
            
            if (v.PerformTest(T.LTSH_numGlyphs))
            {
                if (numGlyphs == fontOwner.GetMaxpNumGlyphs())
                {
                    v.Pass(T.LTSH_numGlyphs, P.LTSH_P_numGlyphs, m_tag);
                }
                else
                {
                    string s = "LTSH.numGlyphs = " + numGlyphs + ", maxp.numGlyphs = " + fontOwner.GetMaxpNumGlyphs();
                    v.Error(T.LTSH_numGlyphs, E.LTSH_E_numGlyphs, m_tag, s);
                    bRet = false;
                }
            }

            if (v.PerformTest(T.LTSH_TableLength))
            {
                uint CalcLength = (uint)FieldOffsets.yPels + numGlyphs;
                if (GetLength() == CalcLength)
                {
                    v.Pass(T.LTSH_TableLength, P.LTSH_P_TableLength, m_tag);
                }
                else
                {
                    string s = "calc length = " + CalcLength + ", actual length = " + GetLength();
                    v.Error(T.LTSH_TableLength, E.LTSH_E_TableLength, m_tag, s);
                    bRet = false;
                }
            }

            if (v.PerformTest(T.LTSH_yPels))
            {
                bool bYPelsOk = true;
                RasterInterf.DevMetricsData dmd = null;
                try
                {
                    Version ver = fontOwner.GetFile().GetRasterizer().FTVersion;

                    if ( ver.CompareTo(new Version(2,6,1)) < 0 )
                        v.Warning(T.LTSH_yPels, W.LTSH_W_Need_Newer_FreeType, m_tag,
                                  "Using FreeType Version " + ver + " may not get correct results for LTSH");

                    dmd = fontOwner.GetCalculatedDevMetrics();
                }
                catch (Exception e)
                {
                    v.ApplicationError(T.LTSH_yPels, E._Table_E_Exception, m_tag, e.Message);
                    bRet = false;
                }

                if (dmd != null)
                {
                    for( uint iGlyphIndex = 0; iGlyphIndex < numGlyphs; iGlyphIndex++ )
                    {
                        if (iGlyphIndex >= fontOwner.GetMaxpNumGlyphs())
                        {
                            // JJF. Figure out what to do
                            v.Warning(T.LTSH_yPels, W._TEST_W_OtherErrorsInTable, m_tag, "can't test all yPel values, LTSH.numGlyphs does not equal maxp.numGlyphs");
                            bRet = false;
                            bYPelsOk = false;
                            break;
                        }

                        if( GetYPel(iGlyphIndex) != dmd.ltshData.yPels[iGlyphIndex] )
                        {
                            String sDetails = "glyph# = " + iGlyphIndex + ", value = " + GetYPel(iGlyphIndex) + ", calculated value = " + dmd.ltshData.yPels[iGlyphIndex];
                            v.Error(T.LTSH_yPels, E.LTSH_E_yPels, m_tag, sDetails);
                            bRet = false;
                            bYPelsOk = false;
                        }
                        /*
                        else
                        {
                            String sDetails = "glyph# = " + iGlyphIndex + ", value = " + GetYPel(iGlyphIndex);
                            v.DebugMsg("yPel value OK! " + sDetails, m_tag);
                        }
                        */

                        if (GetYPel(iGlyphIndex) == 0)
                        {
                            String sDetails = "glyph# = " + iGlyphIndex;
                            v.Warning(T.LTSH_yPels, W.LTSH_W_yPels_zero, m_tag, sDetails);
                        }
                    }

                    if (bYPelsOk)
                    {
                        v.Pass(T.LTSH_yPels, P.LTSH_P_yPels, m_tag);
                    }
                }
                else
                {
                    // if user didn't cancel, then check for error message
                    if (!v.CancelFlag)
                    {
                        String sDetails = null;
                        try
                        {
                            sDetails = fontOwner.GetDevMetricsDataError();
                        }
                        catch (Exception e)
                        {
                            v.ApplicationError(T.LTSH_yPels, E._Table_E_Exception, m_tag, e.Message);
                        }
                        Debug.Assert(sDetails != null);
                        v.Error(T.LTSH_yPels, E.LTSH_E_Rasterizer, m_tag, sDetails);
                        bRet = false;
                    }                    
                }
            }

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


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

            Table_hhea hheaTable = (Table_hhea)fontOwner.GetTable("hhea");
            if (hheaTable == null)
            {
                v.Error(T.T_NULL, E._TEST_E_TableMissing, m_tag, "Unable to test this table, hhea table is invalid or missing");
                return false;
            }

            Table_maxp maxpTable = (Table_maxp)fontOwner.GetTable("maxp");
            if (maxpTable == null)
            {
                v.Error(T.T_NULL, E._TEST_E_TableMissing, m_tag, "Unable to test this table, maxp table is invalid or missing");
                return false;
            }
            
            if (v.PerformTest(T.hmtx_TableSize))
            {
                uint nhm = GetNumberOfHMetrics(fontOwner);
                uint nlsb = GetNumLeftSideBearingEntries(fontOwner);
                uint CalcTableLength = nhm*4 + nlsb*2;

                if (CalcTableLength == GetLength())
                {
                    v.Pass(T.hmtx_TableSize, P.hmtx_P_TableSize, m_tag);
                }
                else
                {
                    v.Error(T.hmtx_TableSize, E.hmtx_E_TableSize, m_tag);
                    bRet = false;
                }
            }

            if (v.PerformTest(T.hmtx_CheckMetrics))
            {
                bool bMetricsOk = true;

                for (uint iGlyph=0; iGlyph<fontOwner.GetMaxpNumGlyphs(); iGlyph++)
                {
                    longHorMetric hm = this.GetOrMakeHMetric(iGlyph, fontOwner);

                    if (hm != null)
                    {
                        if (hm.lsb > hm.advanceWidth)
                        {
                            v.Warning(T.hmtx_CheckMetrics, W.hmtx_W_CheckMetrics_lsb_gt_adv, m_tag, "glyph# " + iGlyph);
                            bMetricsOk = false;
                        }
                    }
                    else
                    {
                        // unable to fetch this horizontal metric
                        // (probably bad hheaTable.numberOfHMetrics or bad table length)
                        bMetricsOk = false;
                    }
                }

                if (bMetricsOk)
                {
                    v.Pass(T.hmtx_CheckMetrics, P.hmtx_P_CheckMetrics, m_tag);
                }
            }

            return bRet;
        }
Esempio n. 12
0
        /************************
         * public methods
         */


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

            m_nCachedMaxpNumGlyphs = fontOwner.GetMaxpNumGlyphs();


            if (v.PerformTest(T.EBDT_version))
            {
                if (version.GetUint() == 0x00020000)
                {
                    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);
                }
            }

            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;
                }
            }

            if (v.PerformTest(T.EBDT_GlyphImageData))
            {
                bool bGlyphImageDataOk = true;

                Table_EBLC EBLCTable = (Table_EBLC)fontOwner.GetTable("EBLC");

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

                    Table_EBLC.indexSubTableArray[] ista = EBLCTable.GetIndexSubTableArray(bst);

                    if (ista != null)
                    {
                        for (uint j = 0; j < bst.numberOfIndexSubTables; j++)
                        {
                            Table_EBLC.indexSubTable ist = null;
                            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;

                                default:
                                    break;
                                }
                            }
                        }
                    }
                }

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

            return(bRet);
        }
Esempio n. 13
0
        /************************
         * public methods
         */


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

            Table_EBDT EBDTTable = (Table_EBDT)fontOwner.GetTable("EBDT");


            if (v.PerformTest(T.EBLC_version))
            {
                // TODO warning on 0x00030000 + EBLC and 0x00020000 + CBLC
                if (version.GetUint() == 0x00020000 || version.GetUint() == 0x00030000)
                {
                    v.Pass(T.EBLC_version, P.EBLC_P_version, m_tag);
                }
                else
                {
                    v.Error(T.EBLC_version, E.EBLC_E_version, m_tag, "version = 0x" + version.GetUint().ToString("x8") + ", unable to continue validation");
                    return(false);
                }
            }
            // TODO: check tag and warn EBLC v3, CBLC v2, bloc

            if (v.PerformTest(T.EBLC_numSizes))
            {
                if (numSizes < (m_bufTable.GetLength() / 48))
                {
                    v.Pass(T.EBLC_numSizes, P.EBLC_P_numSizes, m_tag);
                }
                else
                {
                    v.Error(T.EBLC_numSizes, E.EBLC_E_numSizes, m_tag, "0x" + numSizes.ToString("x8"));
                    bNumSizesOkay = false;
                    bRet          = false;
                }
            }

            if (v.PerformTest(T.EBLC_TableDependency))
            {
                if (EBDTTable != null)
                {
                    v.Pass(T.EBLC_TableDependency, P.EBLC_P_TableDependency, m_tag);
                }
                else
                {
                    v.Error(T.EBLC_TableDependency, E.EBLC_E_TableDependency, m_tag);
                    bRet = false;
                }
            }

            if (v.PerformTest(T.EBLC_indexSubTableArrayOffset) && bNumSizesOkay == true)
            {
                bool bOffsetsOk = true;
                bool bIndicesOk = true;

                uint SmallestPossibleOffset = 8 + numSizes * 48; // sizeof header + sizeof bitmapSizeTAbles
                for (uint i = 0; i < numSizes; i++)
                {
                    bitmapSizeTable bst = GetBitmapSizeTable(i);

                    // start must be less than or equal to end
                    if (bst.startGlyphIndex > bst.endGlyphIndex)
                    {
                        string s = "index = " + i + ", start index = " + bst.startGlyphIndex + ", stop index = " + bst.endGlyphIndex;
                        v.Error(T.EBLC_SizeTableIndexOrder, E.EBLC_E_BitmapSizeTableIndexOrder, m_tag, s);
                        bIndicesOk = false;
                        bRet       = false;
                    }

                    if (bst.indexSubTableArrayOffset < SmallestPossibleOffset ||
                        bst.indexSubTableArrayOffset + bst.indexTablesSize > GetLength())
                    {
                        string s = "index = " + i + ", indexSubTableArrayOffset = " + bst.indexSubTableArrayOffset
                                   + ", indexTablesSize = " + bst.indexTablesSize;
                        v.Error(T.EBLC_indexSubTableArrayOffset, E.EBLC_E_indexSubTableArrayOffset, m_tag, s);
                        bOffsetsOk = false;
                        bRet       = false;
                    }
                    else
                    {
                        indexSubTableArray[] ista = GetIndexSubTableArray(bst);

                        for (uint j = 0; j < bst.numberOfIndexSubTables; j++)
                        {
                            // first must be less than or equal to last
                            if (ista[j].firstGlyphIndex > ista[j].lastGlyphIndex)
                            {
                            }

                            // subtable indices must be within size table range
                            if (ista[j].firstGlyphIndex <bst.startGlyphIndex ||
                                                         ista[j].lastGlyphIndex> bst.endGlyphIndex)
                            {
                            }
                        }
                    }
                }

                if (bOffsetsOk)
                {
                    v.Pass(T.EBLC_indexSubTableArrayOffset, P.EBLC_P_indexSubTableArrayOffset, m_tag);
                }

                if (bIndicesOk)
                {
                    v.Pass(T.EBLC_SizeTableIndexOrder, P.EBLC_P_BitmapSizeTableIndexOrder, m_tag);
                }
            }

            if (v.PerformTest(T.EBLC_bitDepth) && bNumSizesOkay == true)
            {
                bool bBitDepthOk = true;

                for (uint i = 0; i < numSizes; i++)
                {
                    bitmapSizeTable bst = GetBitmapSizeTable(i);
                    if (bst.bitDepth != 1 && bst.bitDepth != 2 && bst.bitDepth != 4 && bst.bitDepth != 8 &&
                        !(version.GetUint() == 0x00030000 && bst.bitDepth == 32))
                    {
                        string s = "index = " + i + ", bitDepth = " + bst.bitDepth;
                        v.Error(T.EBLC_bitDepth, E.EBLC_E_bitDepth, m_tag, s);
                        bBitDepthOk = false;
                        bRet        = false;
                    }
                }

                if (bBitDepthOk)
                {
                    v.Pass(T.EBLC_bitDepth, P.EBLC_P_bitDepth, m_tag);
                }
            }

            if (v.PerformTest(T.EBLC_indexSubTables) && bNumSizesOkay == true)
            {
                for (uint i = 0; i < numSizes; i++)
                {
                    bitmapSizeTable bst   = GetBitmapSizeTable(i);
                    string          sSize = "bitmapsize[" + i + "], ppemX=" + bst.ppemX + ", ppemY=" + bst.ppemY;

                    indexSubTableArray[] ista = GetIndexSubTableArray(bst);

                    for (uint j = 0; j < bst.numberOfIndexSubTables; j++)
                    {
                        indexSubTable ist = bst.GetIndexSubTable(ista[j]);
                        string        sID = sSize + ", indexSubTable[" + j + "](fmt " + ist.header.indexFormat + ")";

                        if (!Validate_indexSubTable(v, ist, ista[j], sID, fontOwner))
                        {
                            bRet = false;
                        }
                    }
                }
            }

            return(bRet);
        }
Esempio n. 14
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;
        }
Esempio n. 15
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;
        }
Esempio n. 16
0
        bool Validate_indexSubTable_format5(Validator v, indexSubTable5 ist5, indexSubTableArray ista, string sID, OTFontVal fontOwner)
        {
            bool bOk = true;

            Table_EBDT EBDTTable = (Table_EBDT)fontOwner.GetTable("EBDT");

            // header has already been validated


            // validate the image size

            if (ist5.numGlyphs*ist5.imageSize > EBDTTable.GetLength())
            {
                string sDetails = "images extend past end of EBDT table: " + sID + ", imageSize = " + ist5.imageSize 
                    + ", EBDT length = " + EBDTTable.GetLength();
                v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails);
                bOk = false;
            }


            // validate the bigGlyphMetrics

            val_EBDT.bigGlyphMetrics_val bgm = val_EBDT.bigGlyphMetrics_val.CreateFromBigGlyphMetrics(ist5.bigMetrics);
            bgm.Validate(v, sID, this);


            // validate numGlyphs

            uint nGlyphsInRange = (uint)ista.lastGlyphIndex - ista.firstGlyphIndex + 1;
            if (ist5.numGlyphs > nGlyphsInRange)
            {
                string sDetails = "numGlyphs is invalid: " + sID + 
                    ", numGlyphs = " + ist5.numGlyphs + 
                    ", indexSubTableArray.firstGlyphIndex = " + ista.firstGlyphIndex +
                    ", indexSubTableArray.lastGlyphIndex = " + ista.lastGlyphIndex;
                v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails);
                bOk = false;
            }

            
            // validate glyphCodeArray

            for (ushort i=0; i<ist5.numGlyphs; i++)
            {
                ushort idGlyph = ist5.GetGlyphCode(i);
                if (idGlyph < ista.firstGlyphIndex || idGlyph > ista.lastGlyphIndex)
                {
                    string sDetails = "invalid glyph id: " + sID + 
                        ", glyphCodeArray[" + i + "] = " + idGlyph +
                        ", indexSubTableArray.firstGlyphIndex = " + ista.firstGlyphIndex +
                        ", indexSubTableArray.lastGlyphIndex = " + ista.lastGlyphIndex;
                    v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails);
                    bOk = false;
                }
            }

            return bOk;
        }
Esempio n. 17
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);
        }
Esempio n. 18
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_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);
        }
Esempio n. 19
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;
                    }
                }
                // TODO: Version.GetUint() === 0x00025000, GetLength()

                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);
        }
Esempio n. 20
0
        /************************
         * public methods
         */


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

            m_nCachedMaxpNumGlyphs = fontOwner.GetMaxpNumGlyphs();


            if (v.PerformTest(T.EBDT_version))
            {
                if (version.GetUint() == 0x00020000)
                {
                    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;
                }
            }

            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;
                }
            }

            if (v.PerformTest(T.EBDT_GlyphImageData))
            {
                bool bGlyphImageDataOk = true;

                Table_EBLC EBLCTable = (Table_EBLC)fontOwner.GetTable("EBLC");
                
                // 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;

                    Table_EBLC.indexSubTableArray[] ista = EBLCTable.GetIndexSubTableArray(bst);

                    if (ista != null)
                    {
                        for (uint j=0; j < bst.numberOfIndexSubTables; j++)
                        {
                            Table_EBLC.indexSubTable ist = null;
                            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;

                                    default:
                                        break;
                                }
                            }
                        }
                    }
                }

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

            return bRet;
        }
Esempio n. 21
0
        bool Validate_indexSubHeader(Validator v, indexSubHeader iSH, string sID, OTFontVal fontOwner)
        {
            bool bOk = true;

            Table_EBDT EBDTTable = (Table_EBDT)fontOwner.GetTable("EBDT");

            if (iSH.indexFormat < 1 || iSH.indexFormat > 5)
            {
                string sDetails = "invalid indexFormat: " + sID + ", indexFormat = " + iSH.indexFormat;
                v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails);
                bOk = false;
            }

            if (iSH.imageFormat < 1 || iSH.imageFormat > 9 || iSH.imageFormat == 3)
            {
                string sDetails = "invalid imageFormat: " + sID + ", imageFormat = " + iSH.imageFormat;
                v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails);
                bOk = false;
            }

            bool bInconsistentFormats = false;
            if (iSH.indexFormat == 1 || iSH.indexFormat == 3 || iSH.indexFormat == 4)
            {
                if (iSH.imageFormat == 5)
                {
                    bInconsistentFormats = true;
                }
            }
            else
            {
                if (iSH.imageFormat != 5)
                {
                    bInconsistentFormats = true;
                }
            }
            if (bInconsistentFormats)
            {
                string sDetails = "inconsistent formats: " + sID + ", indexFormat = " + iSH.indexFormat + ", imageFormat = " + iSH.imageFormat;
                v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails);
                bOk = false;
            }

            if (EBDTTable != null)
            {
                if (iSH.imageDataOffset > EBDTTable.GetLength())
                {
                    string sDetails = "invalid imageDataOffset: " + sID + ", imageDataOffset = " + iSH.imageDataOffset;
                    v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails);
                    bOk = false;
                }
            }

            return bOk;
        }
Esempio n. 22
0
        /************************
         * public methods
         */


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

            if (v.PerformTest(T.PCLT_TableLength))
            {
                if (GetLength() == 54)
                {
                    v.Pass(T.PCLT_TableLength, P.PCLT_P_TableLength, m_tag);
                }
                else
                {
                    v.Error(T.PCLT_TableLength, E.PCLT_E_TableLength, m_tag, GetLength().ToString());
                    bRet = false;
                }
            }

            if (v.PerformTest(T.PCLT_Version))
            {
                if (Version.GetUint() == 0x00010000)
                {
                    v.Pass(T.PCLT_Version, P.PCLT_P_Version, m_tag);
                }
                else
                {
                    v.Error(T.PCLT_Version, E.PCLT_E_Version, m_tag, "0x" + Version.GetUint().ToString("x8"));
                    bRet = false;
                }
            }

            if (v.PerformTest(T.PCLT_Pitch))
            {
                Table_hmtx hmtxTable = (Table_hmtx)fontOwner.GetTable("hmtx");
                Table_maxp maxpTable = (Table_maxp)fontOwner.GetTable("maxp");
                if (hmtxTable == null)
                {
                    v.Error(T.PCLT_Pitch, E._TEST_E_TableMissing, m_tag, "hmtx");
                    bRet = false;
                }
                else if (maxpTable == null)
                {
                    v.Error(T.PCLT_Pitch, E._TEST_E_TableMissing, m_tag, "maxp");
                    bRet = false;
                }
                else
                {
                    uint iSpaceGlyph = fontOwner.FastMapUnicodeToGlyphID(' ');

                    if (iSpaceGlyph < fontOwner.GetMaxpNumGlyphs())
                    {
                        Table_hmtx.longHorMetric hmSpace = hmtxTable.GetOrMakeHMetric(iSpaceGlyph, fontOwner);
                        if (hmSpace != null)
                        {
                            if (Pitch == hmSpace.advanceWidth)
                            {
                                v.Pass(T.PCLT_Pitch, P.PCLT_P_Pitch, m_tag);
                            }
                            else
                            {
                                string s = "actual = " + Pitch + ", expected = " + hmSpace.advanceWidth;
                                v.Error(T.PCLT_Pitch, E.PCLT_E_Pitch, m_tag, s);
                                bRet = false;
                            }
                        }
                    }
                    else
                    {
                        // JJF Figure out what to do
                        v.Warning(T.PCLT_Pitch, W._TEST_W_ErrorInAnotherTable, m_tag, "can't validate Pitch field, error getting the space glyph");
                        bRet = false;
                    }
                }
            }

            if (v.PerformTest(T.PCLT_Style))
            {
                ushort Posture   = (ushort)(Style & 0x0003);
                ushort Width     = (ushort)((Style >> 2) & 0x0007);
                ushort Structure = (ushort)((Style >> 5) & 0x001f);
                ushort Reserved  = (ushort)(Style >> 10);

                bool bBitsOk = true;

                if (Posture == 3)
                {
                    v.Error(T.PCLT_Style, E.PCLT_E_Style_Posture, m_tag, "0x" + Style.ToString("x4"));
                    bBitsOk = false;
                    bRet    = false;
                }
                if (Width == 5)
                {
                    v.Error(T.PCLT_Style, E.PCLT_E_Style_Width, m_tag, "0x" + Style.ToString("x4"));
                    bBitsOk = false;
                    bRet    = false;
                }
                if (Structure > 17)
                {
                    v.Error(T.PCLT_Style, E.PCLT_E_Style_Structure, m_tag, "0x" + Style.ToString("x4"));
                    bBitsOk = false;
                    bRet    = false;
                }
                if (Reserved != 0)
                {
                    v.Error(T.PCLT_Style, E.PCLT_E_Style_Reserved, m_tag, "0x" + Style.ToString("x4"));
                    bBitsOk = false;
                    bRet    = false;
                }

                if (bBitsOk)
                {
                    v.Pass(T.PCLT_Style, P.PCLT_P_Style, m_tag);
                }
            }

            if (v.PerformTest(T.PCLT_StrokeWeight))
            {
                if (StrokeWeight >= -7 && StrokeWeight <= 7)
                {
                    v.Pass(T.PCLT_StrokeWeight, P.PCLT_P_StrokeWeight, m_tag, StrokeWeight.ToString());
                }
                else
                {
                    v.Error(T.PCLT_StrokeWeight, E.PCLT_E_StrokeWeight, m_tag, StrokeWeight.ToString());
                    bRet = false;
                }
            }

            if (v.PerformTest(T.PCLT_WidthType))
            {
                if (WidthType >= -5 && WidthType <= 5)
                {
                    v.Pass(T.PCLT_WidthType, P.PCLT_P_WidthType, m_tag, WidthType.ToString());
                }
                else
                {
                    v.Error(T.PCLT_WidthType, E.PCLT_E_WidthType, m_tag, WidthType.ToString());
                    bRet = false;
                }
            }

            if (v.PerformTest(T.PCLT_SerifStyle))
            {
                uint bot6 = (uint)SerifStyle & 0x3f;
                uint top2 = (uint)SerifStyle >> 6;

                bool bBitsOk = true;

                if (bot6 > 12)
                {
                    v.Error(T.PCLT_SerifStyle, E.PCLT_E_Bottom6, m_tag, "0x" + SerifStyle.ToString("x2"));
                    bBitsOk = false;
                    bRet    = false;
                }
                if (top2 == 0 || top2 == 3)
                {
                    v.Error(T.PCLT_SerifStyle, E.PCLT_E_Top2, m_tag);
                    bBitsOk = false;
                    bRet    = false;
                }

                if (bBitsOk)
                {
                    v.Pass(T.PCLT_SerifStyle, P.PCLT_P_SerifStyle, m_tag);
                }
            }

            if (v.PerformTest(T.PCLT_Reserved))
            {
                if (Reserved == 0)
                {
                    v.Pass(T.PCLT_Reserved, P.PCLT_P_Reserved, m_tag);
                }
                else
                {
                    v.Error(T.PCLT_Reserved, E.PCLT_E_Reserved, m_tag, Reserved.ToString());
                    bRet = false;
                }
            }

            return(bRet);
        }
Esempio n. 23
0
        /************************
         * public methods
         */


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

            Table_EBDT EBDTTable = (Table_EBDT)fontOwner.GetTable("EBDT");

            
            if (v.PerformTest(T.EBLC_version))
            {
                if (version.GetUint() == 0x00020000)
                {
                    v.Pass(T.EBLC_version, P.EBLC_P_version, m_tag);
                }
                else
                {
                    v.Error(T.EBLC_version, E.EBLC_E_version, m_tag, "version = 0x" + version.GetUint().ToString("x8") + ", unable to continue validation");
                    return false;
                }
            }

            if (v.PerformTest(T.EBLC_numSizes))
            {
                if (numSizes < (m_bufTable.GetLength() / 48))
                {
                    v.Pass(T.EBLC_numSizes, P.EBLC_P_numSizes, m_tag);
                }
                else
                {
                    v.Error(T.EBLC_numSizes, E.EBLC_E_numSizes, m_tag, "0x" + numSizes.ToString("x8"));
                    bNumSizesOkay = false;
                    bRet = false;
                }
            }

            if (v.PerformTest(T.EBLC_TableDependency))
            {
                if (EBDTTable != null)
                {
                    v.Pass(T.EBLC_TableDependency, P.EBLC_P_TableDependency, m_tag);
                }
                else
                {
                    v.Error(T.EBLC_TableDependency, E.EBLC_E_TableDependency, m_tag);
                    bRet = false;
                }
            }

            if (v.PerformTest(T.EBLC_indexSubTableArrayOffset) && bNumSizesOkay == true)
            {
                bool bOffsetsOk = true;
                bool bIndicesOk = true;

                uint SmallestPossibleOffset = 8 + numSizes*48; // sizeof header + sizeof bitmapSizeTAbles
                for (uint i=0; i<numSizes; i++)
                {
                    bitmapSizeTable bst = GetBitmapSizeTable(i);

                    // start must be less than or equal to end
                    if ( bst.startGlyphIndex > bst.endGlyphIndex)
                    {
                        string s = "index = " + i + ", start index = " + bst.startGlyphIndex + ", stop index = " + bst.endGlyphIndex;
                        v.Error(T.EBLC_SizeTableIndexOrder, E.EBLC_E_BitmapSizeTableIndexOrder, m_tag, s);
                        bIndicesOk = false;
                        bRet = false;
                    }

                    if (   bst.indexSubTableArrayOffset < SmallestPossibleOffset
                        || bst.indexSubTableArrayOffset + bst.indexTablesSize > GetLength())
                    {
                        string s = "index = " + i + ", indexSubTableArrayOffset = " + bst.indexSubTableArrayOffset 
                            + ", indexTablesSize = " + bst.indexTablesSize;
                        v.Error(T.EBLC_indexSubTableArrayOffset, E.EBLC_E_indexSubTableArrayOffset, m_tag, s);
                        bOffsetsOk = false;
                        bRet = false;
                    }
                    else
                    {
                        indexSubTableArray[] ista = GetIndexSubTableArray(bst);

                        for (uint j=0; j < bst.numberOfIndexSubTables; j++)
                        {
                            // first must be less than or equal to last
                            if ( ista[j].firstGlyphIndex > ista[j].lastGlyphIndex)
                            {
                            }

                            // subtable indices must be within size table range
                            if (   ista[j].firstGlyphIndex < bst.startGlyphIndex
                                || ista[j].lastGlyphIndex > bst.endGlyphIndex)
                            {
                            }
                        }
                    }
                }

                if (bOffsetsOk)
                {
                    v.Pass(T.EBLC_indexSubTableArrayOffset, P.EBLC_P_indexSubTableArrayOffset, m_tag);
                }

                if (bIndicesOk)
                {
                    v.Pass(T.EBLC_SizeTableIndexOrder, P.EBLC_P_BitmapSizeTableIndexOrder, m_tag);
                }
            }

            if (v.PerformTest(T.EBLC_bitDepth) && bNumSizesOkay == true)
            {
                bool bBitDepthOk = true;

                for (uint i=0; i<numSizes; i++)
                {
                    bitmapSizeTable bst = GetBitmapSizeTable(i);
                    if (bst.bitDepth != 1 && bst.bitDepth != 2 && bst.bitDepth != 4 && bst.bitDepth != 8)
                    {
                        string s = "index = " + i + ", bitDepth = " + bst.bitDepth;
                        v.Error(T.EBLC_bitDepth, E.EBLC_E_bitDepth, m_tag, s);
                        bBitDepthOk = false;
                        bRet = false;
                    }
                }

                if (bBitDepthOk)
                {
                    v.Pass(T.EBLC_bitDepth, P.EBLC_P_bitDepth, m_tag);
                }
            }

            if (v.PerformTest(T.EBLC_indexSubTables) && bNumSizesOkay == true)
            {

                for (uint i=0; i<numSizes; i++)
                {
                    bitmapSizeTable bst = GetBitmapSizeTable(i);
                    string sSize = "bitmapsize[" + i + "], ppemX=" + bst.ppemX + ", ppemY=" + bst.ppemY;

                    indexSubTableArray[] ista = GetIndexSubTableArray(bst);

                    for (uint j=0; j < bst.numberOfIndexSubTables; j++)
                    {
                        indexSubTable ist = bst.GetIndexSubTable(ista[j]);
                        string sID = sSize + ", indexSubTable[" + j + "](fmt " + ist.header.indexFormat + ")";

                        if (!Validate_indexSubTable(v, ist, ista[j], sID, fontOwner))
                        {
                            bRet = false;
                        }
                    }
                }
            }

            return bRet;
        }
Esempio n. 24
0
        /************************
         * public methods
         */


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

            if (v.PerformTest(T.kern_TableVersion))
            {
                if (version == 0)
                {
                    v.Pass(T.kern_TableVersion, P.kern_P_TableVersion, m_tag);
                }
                else
                {
                    v.Error(T.kern_TableVersion, E.kern_E_TableVersion, m_tag, "version = " + version.ToString() + ", unrecognized version #, no further tests can be performed");
                    return(false);
                }
            }



            if (v.PerformTest(T.kern_NumSubtables))
            {
                if (nTables != 0)
                {
                    v.Pass(T.kern_NumSubtables, P.kern_P_NumSubTables, m_tag, nTables.ToString());
                }
                else
                {
                    v.Error(T.kern_NumSubtables, E.kern_E_NumSubTables, m_tag);
                    bRet = false;
                }
            }


            if (v.PerformTest(T.kern_SubtableFormats))
            {
                bool bFormatsOk = true;

                for (uint i = 0; i < nTables; i++)
                {
                    SubTableHeader sth = GetSubTableHeader(i);
                    if (sth != null)
                    {
                        if (sth.GetFormat() != 0 && sth.GetFormat() != 2)
                        {
                            v.Error(T.kern_SubtableFormats, E.kern_E_SubtableFormats, m_tag, "subtable #" + i + ", format " + sth.GetFormat());
                            bFormatsOk = false;
                            bRet       = false;
                        }
                    }
                    else
                    {
                        v.Error(T.kern_SubtableFormats, E.kern_E_SubTableExtendsPastEOT, m_tag, "subtable #" + i);
                        bFormatsOk = false;
                        bRet       = false;
                        break;
                    }
                }
                if (bFormatsOk)
                {
                    v.Pass(T.kern_SubtableFormats, P.kern_P_SubtableFormats, m_tag);
                }
            }

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

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

                for (uint i = 0; i < nTables; i++)
                {
                    SubTable st = this.GetSubTable(i);
                    if (st.length != st.CalculatedLength())
                    {
                        v.Error(T.kern_SubtableLength, E.kern_E_SubtableLength, m_tag, "subtable #" + i + ", length = " + st.length + ", calculated length = " + st.CalculatedLength());
                        bLengthsOk = false;
                        bRet       = false;
                    }
                }
                if (bLengthsOk)
                {
                    v.Pass(T.kern_SubtableLength, P.kern_P_SubtableLengths, m_tag);
                }
            }

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

                for (uint i = 0; i < nTables; i++)
                {
                    SubTable st = this.GetSubTable(i);
                    if ((st.coverage & 0xf0) != 0)
                    {
                        bReservedOk = false;
                        v.Error(T.kern_CoverageReservedBits, E.kern_E_ReservedCoverageBits, m_tag, "subtable #" + i);
                        bRet = false;
                        break;
                    }
                }
                if (bReservedOk)
                {
                    v.Pass(T.kern_CoverageReservedBits, P.kern_P_ReservedCoverageBits, m_tag);
                }
            }

            if (v.PerformTest(T.kern_Format0_SearchFields))
            {
                bool bBinaryFieldsOk = true;

                for (uint i = 0; i < nTables; i++)
                {
                    SubTable st = this.GetSubTable(i);
                    if (st.version == 0)
                    {
                        SubTableFormat0 stf0        = (SubTableFormat0)st;
                        ushort          nPairs      = stf0.nPairs;
                        ushort          sizeofEntry = 6;

                        if (nPairs != 0)
                        {
                            ushort CalculatedSearchRange   = (ushort)(util.MaxPower2LE(nPairs) * sizeofEntry);
                            ushort CalculatedEntrySelector = util.Log2(util.MaxPower2LE(nPairs));
                            ushort CalculatedRangeShift    = (ushort)((nPairs - util.MaxPower2LE(nPairs)) * sizeofEntry);

                            if (stf0.searchRange != CalculatedSearchRange)
                            {
                                string s = "subtable #" + i
                                           + ", calc = " + CalculatedSearchRange
                                           + ", actual = " + stf0.searchRange;
                                v.Error(T.kern_Format0_SearchFields, E.kern_E_Format0_searchRange, m_tag, s);
                                bBinaryFieldsOk = false;
                                bRet            = false;
                            }
                            if (stf0.entrySelector != CalculatedEntrySelector)
                            {
                                string s = "subtable #" + i
                                           + ", calc = " + CalculatedEntrySelector
                                           + ", actual = " + stf0.entrySelector;
                                v.Error(T.kern_Format0_SearchFields, E.kern_E_Format0_entrySelector, m_tag, s);
                                bBinaryFieldsOk = false;
                                bRet            = false;
                            }
                            if (stf0.rangeShift != CalculatedRangeShift)
                            {
                                string s = "subtable #" + i
                                           + ", calc = " + CalculatedRangeShift
                                           + ", actual = " + stf0.rangeShift;
                                v.Error(T.kern_Format0_SearchFields, E.kern_E_Format0_rangeShift, m_tag, s);
                                bBinaryFieldsOk = false;
                                bRet            = false;
                            }
                        }
                        else
                        {
                            // cannot validate fields since they are undefined when nPairs is zero
                            v.Warning(T.kern_Format0_SearchFields, W.kern_W_Format0_SearchFields, m_tag, "subtable #" + i + ", nPairs = " + stf0.nPairs);
                            bBinaryFieldsOk = false;
                        }
                    }
                }

                if (bBinaryFieldsOk)
                {
                    v.Pass(T.kern_Format0_SearchFields, P.kern_P_Format0_SearchFields, m_tag);
                }
            }

            if (v.PerformTest(T.kern_Format0_GlyphIDs))
            {
                for (uint i = 0; i < nTables; i++)
                {
                    SubTable st = this.GetSubTable(i);
                    if (st.version == 0)
                    {
                        bool bGlyphIDsOk = true;

                        SubTableFormat0 stf0 = (SubTableFormat0)st;

                        for (int iPair = 0; iPair < stf0.nPairs; iPair++)
                        {
                            ushort left = 0, right = 0;
                            short  kernvalue = 0;

                            stf0.GetKerningPairAndValue(iPair, ref left, ref right, ref kernvalue);

                            ushort numGlyphs = fontOwner.GetMaxpNumGlyphs();
                            if (left >= numGlyphs)
                            {
                                v.Error(T.kern_Format0_GlyphIDs, E.kern_E_Format0_GlyphIDs, m_tag, "kern pair[" + iPair + "]: left = " + left);
                                bGlyphIDsOk = false;
                                bRet        = false;
                            }
                            if (right >= numGlyphs)
                            {
                                v.Error(T.kern_Format0_GlyphIDs, E.kern_E_Format0_GlyphIDs, m_tag, "kern pair[" + iPair + "]: right = " + right);
                                bGlyphIDsOk = false;
                                bRet        = false;
                            }
                        }

                        if (bGlyphIDsOk)
                        {
                            v.Pass(T.kern_Format0_GlyphIDs, P.kern_P_Format0_GlyphIDs, m_tag);
                        }
                    }
                }
            }

            if (v.PerformTest(T.kern_Format0_Values))
            {
                for (uint i = 0; i < nTables; i++)
                {
                    SubTable st = this.GetSubTable(i);
                    if (st.version == 0)
                    {
                        SubTableFormat0 stf0 = (SubTableFormat0)st;

                        Table_hmtx hmtxTable = (Table_hmtx)fontOwner.GetTable("hmtx");
                        if (hmtxTable != null)
                        {
                            bool bValuesOk = true;

                            for (int iPair = 0; iPair < stf0.nPairs; iPair++)
                            {
                                ushort left = 0, right = 0;
                                short  kernvalue = 0;

                                stf0.GetKerningPairAndValue(iPair, ref left, ref right, ref kernvalue);
                                short absKernValue = Math.Abs(kernvalue);

                                Table_hmtx.longHorMetric lhmLeft  = null;
                                Table_hmtx.longHorMetric lhmRight = null;
                                try {
                                    lhmLeft  = hmtxTable.GetOrMakeHMetric(left, fontOwner);
                                    lhmRight = hmtxTable.GetOrMakeHMetric(right, fontOwner);
                                }
                                catch (Exception e)
                                {
                                    v.ApplicationError(T.kern_Format0_Values, E._Table_E_Exception, m_tag, "GetOrMakeHMetric:" + e.Message);
                                    bValuesOk = false;
                                    bRet      = false;
                                    break;
                                }

                                if (lhmLeft == null || lhmRight == null)
                                {
                                    v.ApplicationError(T.kern_Format0_Values, E._Table_E_Exception, m_tag, "hmtx Left or Right null");
                                    bValuesOk = false;
                                    bRet      = false;
                                    break;
                                }

                                if (absKernValue > lhmLeft.advanceWidth && absKernValue > lhmRight.advanceWidth)
                                {
                                    v.Error(T.kern_Format0_Values, E.kern_E_Format0_Values, m_tag, "kern pair[" + iPair + "]: left id = " + left + ", right id = " + right + ", value = " + kernvalue);
                                    bValuesOk = false;
                                    bRet      = false;
                                }
                            }

                            if (bValuesOk)
                            {
                                v.Pass(T.kern_Format0_Values, P.kern_P_Format0_Values, m_tag);
                            }
                        }
                    }
                }
            }

            if (v.PerformTest("kern_Format0_IDsInCmap"))
            {
                for (uint i = 0; i < nTables; i++)
                {
                    SubTable st = this.GetSubTable(i);
                    if (st.version == 0)
                    {
                        SubTableFormat0 stf0 = (SubTableFormat0)st;

                        Table_cmap cmapTable = (Table_cmap)fontOwner.GetTable("cmap");
                        if (cmapTable != null)
                        {
                            Table_cmap.Subtable cmapSubtable = cmapTable.GetSubtable(3, 10);
                            if (cmapSubtable == null)
                            {
                                cmapSubtable = cmapTable.GetSubtable(3, 1);
                            }
                            if (cmapSubtable == null)
                            {
                                Table_cmap.EncodingTableEntry ete = cmapTable.GetEncodingTableEntry(0);
                                cmapSubtable = cmapTable.GetSubtable(ete);
                            }

                            if (cmapSubtable != null)
                            {
                                uint [] map = cmapSubtable.GetMap();

                                bool bAllIDsInCmap = true;

                                for (int iPair = 0; iPair < stf0.nPairs; iPair++)
                                {
                                    ushort left = 0, right = 0;
                                    short  kernvalue = 0;

                                    stf0.GetKerningPairAndValue(iPair, ref left, ref right, ref kernvalue);

                                    bool bFoundLeft  = false;
                                    bool bFoundRight = false;

                                    for (int j = 0; j < map.Length; j++)
                                    {
                                        if (left == map[j])
                                        {
                                            bFoundLeft = true;
                                            break;
                                        }
                                    }

                                    for (int j = 0; j < map.Length; j++)
                                    {
                                        if (right == map[j])
                                        {
                                            bFoundRight = true;
                                            break;
                                        }
                                    }

                                    if (bFoundLeft == false)
                                    {
                                        v.Error(T.kern_Format0_IDsInCmap, E.kern_E_Format0_GlyphIdInCmap, m_tag, "kern pair[" + iPair + "]: left id = " + left);
                                        bAllIDsInCmap = false;
                                        bRet          = false;
                                    }
                                    if (bFoundRight == false)
                                    {
                                        v.Error(T.kern_Format0_IDsInCmap, E.kern_E_Format0_GlyphIdInCmap, m_tag, "kern pair[" + iPair + "]: right id = " + right);
                                        bAllIDsInCmap = false;
                                        bRet          = false;
                                    }
                                }

                                if (bAllIDsInCmap)
                                {
                                    v.Pass(T.kern_Format0_IDsInCmap, P.kern_P_Format0_GlyphIdInCmap, m_tag);
                                }
                            }
                        }
                    }
                }
            }

            return(bRet);
        }
Esempio n. 25
0
        bool Validate_indexSubTable_format2(Validator v, indexSubTable2 ist2, indexSubTableArray ista, string sID, OTFontVal fontOwner)
        {
            bool bOk = true;

            Table_EBDT EBDTTable = (Table_EBDT)fontOwner.GetTable("EBDT");

            // header has already been validated


            // validate the image size

            uint nGlyphsInRange = (uint)ista.lastGlyphIndex - ista.firstGlyphIndex + 1;
            if (nGlyphsInRange*ist2.imageSize > EBDTTable.GetLength())
            {
                string sDetails = "images extend past end of EBDT table: " + sID + ", imageSize = " + ist2.imageSize 
                    + ", EBDT length = " + EBDTTable.GetLength();
                v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails);
                bOk = false;
            }

            // validate the bigGlyphMetrics
            val_EBDT.bigGlyphMetrics_val bgm = val_EBDT.bigGlyphMetrics_val.CreateFromBigGlyphMetrics(ist2.bigMetrics);
            bgm.Validate(v, sID, this);

            return bOk;
        }
Esempio n. 26
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;
        }
Esempio n. 27
0
        bool Validate_indexSubTable_format3(Validator v, indexSubTable3 ist3, indexSubTableArray ista, string sID, OTFontVal fontOwner)
        {
            bool bOk = true;

            Table_EBDT EBDTTable = (Table_EBDT)fontOwner.GetTable("EBDT");

            // header has already been validated


            // validate the array of offsets

            int nArrSize = ista.lastGlyphIndex - ista.firstGlyphIndex + 1;
            uint nEBDTLength = EBDTTable.GetLength();
            for (ushort i=0; i<nArrSize; i++)
            {
                uint offsetImage = ist3.GetOffset(i) + ist3.header.imageDataOffset;
                if (offsetImage > nEBDTLength)
                {
                    string sDetails = "invalid offset: " + sID + ", offset[" + i + "] = " + offsetImage +
                        ", EBDT length = " + nEBDTLength;
                    v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails);
                    bOk = false;
                }
            }

            return bOk;
        }
Esempio n. 28
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;
        }
Esempio n. 29
0
        bool Validate_indexSubTable_format4(Validator v, indexSubTable4 ist4, indexSubTableArray ista, string sID, OTFontVal fontOwner)
        {
            bool bOk = true;

            Table_EBDT EBDTTable = (Table_EBDT)fontOwner.GetTable("EBDT");

            // header has already been validated


            // validate numGlyphs

            uint nGlyphsInRange = (uint)ista.lastGlyphIndex - ista.firstGlyphIndex + 1;
            if (ist4.numGlyphs > nGlyphsInRange)
            {
                string sDetails = "numGlyphs is invalid: " + sID + 
                        ", numGlyphs = " + ist4.numGlyphs + 
                        ", indexSubTableArray.firstGlyphIndex = " + ista.firstGlyphIndex +
                        ", indexSubTableArray.lastGlyphIndex = " + ista.lastGlyphIndex;
                v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails);
                bOk = false;
            }


            // validate code offset pairs
            uint nEBDTLength = EBDTTable.GetLength();
            for (ushort idGlyph=0; idGlyph<ist4.numGlyphs; idGlyph++)
            {
                indexSubTable4.codeOffsetPair cop = ist4.GetCodeOffsetPair(idGlyph);

                // glyph code
                if (cop.glyphCode < ista.firstGlyphIndex || cop.glyphCode > ista.lastGlyphIndex)
                {
                    string sDetails = "glyph code is invalid: " + sID + 
                        ", codeOffsetPair[" + idGlyph + "]" + 
                        ", indexSubTableArray.firstGlyphIndex = " + ista.firstGlyphIndex +
                        ", indexSubTableArray.lastGlyphIndex = " + ista.lastGlyphIndex;
                    v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails);
                    bOk = false;
                }

                // offset
                if (cop.offset > nEBDTLength)
                {
                    string sDetails = "invalid offset: " + sID + 
                        ", codeOffsetPair[" + idGlyph + "].offset = " + cop.offset +
                        ", EBDT length = " + nEBDTLength;
                    v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails);
                    bOk = false;
                }
            }
            
            return bOk;
        }
Esempio n. 30
0
        public bool Validate(Validator v, OTFontVal fontOwner)
        {
            bool bRet = true;

            if (v.PerformTest(T.cmap_Version))
            {
                if (TableVersionNumber == 0)
                {
                    v.Pass(T.cmap_Version, P.cmap_P_version, m_tag);
                }
                else
                {
                    v.Error(T.cmap_Version, E.cmap_E_version, m_tag,
                            TableVersionNumber.ToString());
                    bRet = false;
                }
            }

            // Check that the number of encoding records seems to 
            // agree with the numTables field, and that each offset
            // is greater than 0 and less than the length of the cmap 
            // table.

            bool bOffsetsOk = true;
            if (v.PerformTest(T.cmap_SubtableOffset))
            {
                
                for (uint i=0; i<NumberOfEncodingTables; i++)
                {
                    EncodingTableEntry ete = GetEncodingTableEntry(i);
                    if (ete != null)
                    {
                        if (ete.offset == 0)
                        {
                            v.Error(T.cmap_SubtableOffset, 
                                    E.cmap_E_SubtableOffset_zero, m_tag, 
                                    "encoding table entry index = " + 
                                    i.ToString() + ", platformID = " + 
                                    ete.platformID + ", encodingID = " +
                                    ete.encodingID);
                            bRet = false;
                            bOffsetsOk = false;
                        }

                        if (ete.offset > m_bufTable.GetLength())
                        {
                            v.Error(T.cmap_SubtableOffset,
                                    E.cmap_E_SubtableOffset_eot, m_tag, 
                                    "encoding table entry index = " +
                                    i.ToString() + ", platformID = " +
                                    ete.platformID +
                                    ", encodingID = " + ete.encodingID);
                            bRet = false;
                            bOffsetsOk = false;
                        }
                    }
                    else
                    {
                        v.Warning(T.cmap_SubtableOffset, 
                                  W._TEST_W_OtherErrorsInTable, m_tag, 
                                  "cmap table appears to be corrupt. " + 
                                  " No further tests will be performed.");
                        return bRet; 
                    }
                }
                
                if (bOffsetsOk)
                {
                    v.Pass(T.cmap_SubtableOffset, P.cmap_P_SubtableOffset,
                           m_tag);
                }
            }

            // Check that each subtable can be retrieved from the font
            // and that its offset + length lies within the cmap.

            bool bLengthsOk = true;
            if (v.PerformTest(T.cmap_SubtableLength))
            {
                
                for (uint i=0; i<NumberOfEncodingTables; i++)
                {
                    EncodingTableEntry ete = GetEncodingTableEntry(i);
                    Subtable st = GetSubtable(ete);

                    if (st != null)
                    {
                        if (st.length == 0)
                        {
                            v.Error(T.cmap_SubtableLength,
                                    E.cmap_E_SubtableLength_zero, m_tag, 
                                    i.ToString());
                            bRet = false;
                            bLengthsOk = false;
                        }

                        if (ete.offset + st.length > m_bufTable.GetLength())
                        {
                            v.Error(T.cmap_SubtableLength,
                                    E.cmap_E_SubtableLength_eot, m_tag, 
                                    i.ToString());
                            bRet = false;
                            bLengthsOk = false;
                        }
                    }
                    else
                    {
                        string sDetails = "PlatID = " + ete.platformID +
                            ", EncID = " + ete.encodingID;
                        v.Warning(T.cmap_SubtableLength, 
                                  W._TEST_W_OtherErrorsInTable, m_tag,
                                  "unable to validate the length of subtable - "
                                  + sDetails);
                        bLengthsOk = false;
                    }
                }
                
                if (bLengthsOk)
                {
                    v.Pass(T.cmap_SubtableLength, P.cmap_P_SubtableLength,
                           m_tag);
                }
            }

            // Assuming previous tests ok, check that sort order is by
            // 1. increasing platformID
            // 2. increasing encodingID
            // 3. increasing language

            if (v.PerformTest(T.cmap_SubtableSortOrder))
            {
                if (bOffsetsOk && bLengthsOk)
                {
                    bool bOrderOk = true;

                    if (NumberOfEncodingTables > 1)
                    {
                        EncodingTableEntry etePrev = GetEncodingTableEntry(0);

                        for (uint i=1; i<NumberOfEncodingTables; i++)
                        {
                            EncodingTableEntry ete = GetEncodingTableEntry(i);

                            if (etePrev.platformID == ete.platformID)
                            {
                                if (etePrev.encodingID == ete.encodingID)
                                {
                                    Subtable stPrev = GetSubtable(etePrev);
                                    Subtable st = GetSubtable(ete);

                                    if (stPrev.language > st.language)
                                    {
                                        bOrderOk = false;
                                    }
                                }
                                else if (etePrev.encodingID > ete.encodingID)
                                {
                                    bOrderOk = false;
                                }
                            }
                            else if (etePrev.platformID > ete.platformID)
                            {
                                bOrderOk = false;
                            }

                            etePrev = ete;
                        }
                    }

                    if (bOrderOk)
                    {
                        v.Pass(T.cmap_SubtableSortOrder,
                               P.cmap_P_SubtableSortOrder, m_tag);
                    }
                    else
                    {
                        v.Error(T.cmap_SubtableSortOrder,
                                E.cmap_E_SubtableSortOrder, m_tag);
                        bRet = false;
                    }
                }
                else
                {
                    v.Warning(T.cmap_SubtableSortOrder,
                              W._TEST_W_OtherErrorsInTable, m_tag,
                              "unable to validate sort order");
                }
            }

            // Check that no encoding record has the same 
            //      (platformID,encodingID,language)
            // as the previous one.

            if (v.PerformTest(T.cmap_DuplicateSubtables))
            {
                if (bOffsetsOk && bLengthsOk)
                {
                    bool bNoDuplicates = true;

                    if (NumberOfEncodingTables > 1)
                    {
                        EncodingTableEntry etePrev = GetEncodingTableEntry(0);

                        for (uint i=1; i<NumberOfEncodingTables; i++)
                        {
                            EncodingTableEntry ete = GetEncodingTableEntry(i);

                            if (etePrev.platformID == ete.platformID)
                            {
                                if (etePrev.encodingID == ete.encodingID)
                                {
                                    Subtable stPrev = GetSubtable(etePrev);
                                    Subtable st = GetSubtable(ete);

                                    if (stPrev.language == st.language)
                                    {
                                        bNoDuplicates = false;
                                    }
                                }
                            }

                            etePrev = ete;
                        }
                    }

                    if (bNoDuplicates)
                    {
                        v.Pass(T.cmap_DuplicateSubtables,
                               P.cmap_P_DuplicateSubtables, m_tag);
                    }
                    else
                    {
                        v.Error(T.cmap_DuplicateSubtables,
                                E.cmap_E_DuplicateSubtables, m_tag);
                        bRet = false;
                    }
                }
                else
                {
                    string unable = "unable to validate that there are " + 
                        "no duplicate subtables";
                    v.Warning(T.cmap_DuplicateSubtables,
                              W._TEST_W_OtherErrorsInTable, m_tag,
                              unable );
                }
            }

            // Check that no subtable overlaps and subtable following it,
            // in other words, check for the beginning of one subtable 
            // falling within the bounds of a subtable that follows it.

            if (v.PerformTest(T.cmap_SubtableOverlap))
            {
                if (bOffsetsOk && bLengthsOk)
                {
                    bool bNoOverlap = true;

                    if (NumberOfEncodingTables > 1)
                    {
                        for (uint i=0; i<NumberOfEncodingTables; i++)
                        {
                            EncodingTableEntry ete1 = GetEncodingTableEntry(i);
                            Subtable st1 = GetSubtable(ete1);

                            for (uint j=i+1; j<NumberOfEncodingTables; j++)
                            {
                                EncodingTableEntry ete2 = 
                                    GetEncodingTableEntry(j);
                                Subtable st2 = GetSubtable(ete2);

                                if ( (ete1.offset > ete2.offset && 
                                      ete1.offset < ete2.offset + st2.length) ||
                                    (ete2.offset > ete1.offset &&
                                     ete2.offset < ete1.offset + st1.length) )
                                {
                                    v.Error(T.cmap_SubtableOverlap, 
                                            E.cmap_E_SubtableOverlap, m_tag,
                                            i.ToString() + " " + j.ToString());
                                    bRet = false;
                                    bNoOverlap = true;
                                }
                            }
                        }
                    }

                    if (bNoOverlap)
                    {
                        v.Pass(T.cmap_SubtableOverlap, 
                               P.cmap_P_SubtableOverlap, m_tag);
                    }
                }
                else
                {
                    v.Warning(T.cmap_SubtableOverlap, 
                              W._TEST_W_OtherErrorsInTable, m_tag,
                              "unable to validate that no subtables overlap");
                }
            }

            // Check that all subtable formats (First USHORT in the subtable)
            // is an even number between 0 and 14, inclusive.

            if (v.PerformTest(T.cmap_ValidFormat))
            {
                bool bAllFormatsValid = true;
                for (uint i=0; i<NumberOfEncodingTables; i++)
                {
                    EncodingTableEntry ete = GetEncodingTableEntry(i);
                    if (ete.offset < m_bufTable.GetLength()-1)
                    {
                        // the format of the subtable is the first uint16
                        ushort format = m_bufTable.GetUshort(ete.offset);

                        if (format > HIGHEST_FORMAT || ((format&1)==1))
                        {
                            string sDetails = "PlatID = " + ete.platformID +
                                ", EncID = " + ete.encodingID + ", Fmt = " + 
                                format;
                            v.Error(T.cmap_ValidFormat, 
                                    E.cmap_E_SubtableValidFormat, m_tag, 
                                    sDetails);
                            bRet = false;
                            bAllFormatsValid = false;
                        }
                    }
                    else
                    {
                        string sDetails = "PlatID = " + ete.platformID + 
                            ", EncID = " + ete.encodingID;
                        string unable = 
                            "unable to validate format number for subtable - ";
                        v.Warning(T.cmap_ValidFormat, 
                                  W._TEST_W_OtherErrorsInTable, m_tag, 
                                  unable + sDetails);
                        bAllFormatsValid = false;
                    }
                }

                if (bAllFormatsValid)
                {
                    v.Pass(T.cmap_ValidFormat, 
                           P.cmap_P_SubtableValidFormat, m_tag);
                }
            }

            // Assuming maxp is present, get the number of glyphs from maxp, 
            // and for each subtable, run its validate routine.

            if (v.PerformTest(T.cmap_SubtableInternalFormat))
            {
                if (fontOwner.GetTable("maxp") == null)
                {
                    string cant = 
                        "can't check subtable internal formats - " + 
                        "maxp table inaccessible";
                    v.Warning(T.cmap_SubtableInternalFormat, 
                              W._TEST_W_ErrorInAnotherTable, m_tag,
                              cant );
                }
                else
                {
                    for (uint i=0; i<NumberOfEncodingTables; i++)
                    {
                        bool bInternalFormatOk = true;
                        EncodingTableEntry ete = GetEncodingTableEntry(i);
                        Subtable st = GetSubtable(ete);
                        if (st != null)
                        {
                            ushort numGlyphs = fontOwner.GetMaxpNumGlyphs();
                            string sIdentity = "PlatID = " + ete.platformID +
                                ", EncID = " + ete.encodingID + ", Fmt = " + 
                                st.format;
                            
                            ISubtableValidate valSubtable =
                                (ISubtableValidate)st;
                            bInternalFormatOk = valSubtable.Validate(v, this,
                                                                     numGlyphs,
                                                                     sIdentity);
                            bRet &= bInternalFormatOk;
                            if (bInternalFormatOk)
                            {
                                v.Pass(T.cmap_SubtableInternalFormat,
                                       P.cmap_P_InternalFormat, m_tag, 
                                       sIdentity);
                            }
                        }
                        else
                        {
                            string sDetails = "PlatID = " + ete.platformID +
                                ", EncID = " + ete.encodingID;
                            v.Warning(T.cmap_SubtableInternalFormat,
                                      W._TEST_W_OtherErrorsInTable, m_tag, 
                                      "unable to validate internal format " +
                                      "for subtable - "
                                      + sDetails);
                        }
                    }
                }
            }

            // Pass if there is at least one subtable with platformID == 1 and
            // one subtable with platformID == 3.
            // Warn if either is missing.

            if (v.PerformTest(T.cmap_AppleMSSupport))
            {
                bool bFoundApple = false;
                bool bFoundMS    = false;

                for (uint i=0; i<NumberOfEncodingTables; i++)
                {
                    EncodingTableEntry ete = GetEncodingTableEntry(i);
                    if (ete.platformID == 1)
                    {
                        bFoundApple = true;
                    }
                    else if (ete.platformID == 3)
                    {
                        bFoundMS = true;
                    }
                }

                if (bFoundApple && bFoundMS)
                {
                    v.Pass(T.cmap_AppleMSSupport, P.cmap_P_AppleMSSupport,
                           m_tag);
                }
                else if (!bFoundApple)
                {
                    v.Warning(T.cmap_AppleMSSupport, W.cmap_W_AppleMSSupport_A,
                              m_tag);
                }
                else if (!bFoundMS)
                {
                    v.Warning(T.cmap_AppleMSSupport, W.cmap_W_AppleMSSupport_M,
                              m_tag);
                }
            }

            // Find encoding table with platformID==1, encodingID==0 
            // i.e., Macintosh. Make sure that the Apple Logo, code point 240,
            // is mapped to glyphID 0, a legal requirement for Microsoft fonts
            // developed for use on Apple platforms.

            if (v.PerformTest(T.cmap_AppleLogo))
            {
                EncodingTableEntry ete = GetEncodingTableEntry(1,0);
                if (ete != null)
                {
                    Subtable st = GetSubtable(ete);
                    if (st != null)
                    {
                        byte[] charbuf = new byte[2];
                        charbuf[0] = 240;
                        charbuf[1] = 0;
                        uint glyph = st.MapCharToGlyph(charbuf, 0);
                        if (glyph == 0)
                        {
                            v.Pass(T.cmap_AppleLogo, P.cmap_P_AppleLogo, m_tag);
                        }
                        else
                        {
                            v.Warning(T.cmap_AppleLogo, W.cmap_W_AppleLogo,
                                      m_tag);
                        }
                    }
                    else
                    {
                        string sDetails = "PlatID = " + ete.platformID +
                            ", EncID = " + ete.encodingID;
                        string unable = 
                            "unable to validate apple logo for subtable - ";
                        v.Warning(T.cmap_AppleLogo, 
                                  W._TEST_W_OtherErrorsInTable, m_tag,
                                  unable + sDetails);
                    }
                }
                else
                {
                    v.Warning(T.cmap_AppleLogo, W.cmap_W_AppleLogo_NoMap, 
                              m_tag);
                }
            }

            // Euro symbol.
            // Unless there is a Microsoft Symbol encoding cmap (3,0):
            // * Make sure that any apple cmap(1,0) contains a glyph U+00db
            // * Make sure that any Microsoft Unicode cmap (3,1) contains
            //   a glyph U+20AC.

            if (v.PerformTest(T.cmap_EuroGlyph))
            {
                EncodingTableEntry eteSym = GetEncodingTableEntry(3,0);
                if (eteSym == null)
                {
                    EncodingTableEntry eteMac = GetEncodingTableEntry(1,0);
                    if (eteMac != null)
                    {
                        Subtable st = GetSubtable(eteMac);
                        if (st != null)
                        {
                            byte[] charbuf = new byte[2];
                            charbuf[0] = 0xdb;
                            charbuf[1] = 0;
                            uint glyph = st.MapCharToGlyph(charbuf, 0);
                            if (glyph != 0)
                            {
                                v.Pass(T.cmap_EuroGlyph,
                                       P.cmap_P_EuroGlyph_Mac, m_tag);
                            }
                            else
                            {
                                v.Warning(T.cmap_EuroGlyph,
                                          W.cmap_W_EuroGlyph_Mac, m_tag);
                            }
                        }
                        else
                        {
                            string sDetails = "PlatID = " + eteMac.platformID +
                                ", EncID = " + eteMac.encodingID;
                            string unable = 
                                "unable to validate if euro glyph " + 
                                "is present for subtable - ";
                            v.Warning(T.cmap_EuroGlyph,
                                      W._TEST_W_OtherErrorsInTable, m_tag,
                                      unable + sDetails);
                        }
                    }

                    EncodingTableEntry eteUni = GetEncodingTableEntry(3,1);
                    if (eteUni != null)
                    {
                        Subtable st = GetSubtable(eteUni);
                        if (st != null)
                        {
                            byte[] charbuf = new byte[2];
                            charbuf[0] = 0xac;
                            charbuf[1] = 0x20;
                            uint glyph = st.MapCharToGlyph(charbuf, 0);
                            if (glyph != 0)
                            {
                                v.Pass(T.cmap_EuroGlyph,
                                       P.cmap_P_EuroGlyph_Uni, m_tag);
                            }
                            else
                            {
                                v.Warning(T.cmap_EuroGlyph,
                                          W.cmap_W_EuroGlyph_Uni, m_tag);
                            }
                        }
                        else
                        {
                            string sDetails = "PlatID = " + eteMac.platformID +
                                ", EncID = " + eteMac.encodingID;
                            string unable = "unable to validate if euro glyph" +
                                " is present for subtable - ";
                            v.Warning(T.cmap_EuroGlyph,
                                      W._TEST_W_OtherErrorsInTable, m_tag, 
                                      unable + sDetails);
                        }
                    }
                }
            }

            // Make sure that no glyphs, other than "fi" and "fl" ligatures,
            // are mapped from the "private use area", that is, 
            // 0xE000 - 0xF8FF. The above ligatures may only be a the 
            // prescribed places. 
            //
            // Checks that 0xf001 and 0xfb01 map to the same place, and
            // Checks that 0xf002 and 0xfb02 map to the same place.
            //
            // Only warn if a problem.

            if (v.PerformTest(T.cmap_PrivateUse))
            {
                EncodingTableEntry eteUni = GetEncodingTableEntry(3,1);
                if (eteUni != null)
                {
                    Subtable st = GetSubtable(eteUni);
                    if (st != null)
                    {
                        bool bFoundGlyph = false;
                        bool bFoundLigChar = false;
                        byte[] charbuf = new byte[2];

                        for (char c='\xe000'; c<'\xf8ff'; c++)
                        {
                            uint glyph = fontOwner.FastMapUnicodeToGlyphID(c);
                            if (glyph != 0)
                            {
                                if (c == '\xf001')
                                {
                                    // check to see if this is the 'fi' ligature
                                    uint glyph2 = fontOwner.
                                        FastMapUnicodeToGlyphID('\xfb01');
                                    if (glyph == glyph2)
                                    {
                                        bFoundLigChar = true;
                                    }
                                    else
                                    {
                                        bFoundGlyph = true;
                                        break;
                                    }
                                }
                                else if (c == '\xf002')
                                {
                                    // check to see if this is the 'fl' ligature
                                    uint glyph2 = fontOwner.
                                        FastMapUnicodeToGlyphID('\xfb02');
                                    if (glyph == glyph2)
                                    {
                                        bFoundLigChar = true;
                                    }
                                    else
                                    {
                                        bFoundGlyph = true;
                                        break;
                                    }
                                }
                                else
                                {
                                    bFoundGlyph = true;
                                    break;
                                }
                            }
                        }
                        if (bFoundGlyph)
                        {
                            v.Warning(T.cmap_PrivateUse, 
                                      W.cmap_W_UnicodePrivateUse, m_tag);
                        }
                        else if (bFoundLigChar)
                        {
                            v.Pass(T.cmap_PrivateUse, 
                                   P.cmap_P_UnicodePrivateUse_lig, m_tag);
                        }
                        else
                        {
                            v.Pass(T.cmap_PrivateUse, 
                                   P.cmap_P_UnicodePrivateUse, m_tag);
                        }
                    }
                    else
                    {
                        string sDetails = "PlatID = " + eteUni.platformID + 
                            ", EncID = " + eteUni.encodingID;
                        v.Warning(T.cmap_PrivateUse,
                                  W._TEST_W_OtherErrorsInTable, m_tag, 
                                  "unable to validate Private Use Area " + 
                                  "for subtable - "
                                  + sDetails);
                    }
                }
            }

            // Check that subtable language field is zero if not mac platform

            if (v.PerformTest(T.cmap_NonMacSubtableLanguage))
            {
                bool bOk = true;
                for (uint i=0; i<NumberOfEncodingTables; i++)
                {
                    EncodingTableEntry ete = GetEncodingTableEntry(i);
                    Subtable st = GetSubtable(ete);
                    if (st != null)
                    {
                        if (ete.platformID != 1) // not mac
                        {
                            if (st.language != 0)
                            {
                                string sDetails = "PlatID = " +
                                    ete.platformID + ", EncID = " +
                                    ete.encodingID +
                                    ", Language = " + st.language;
                                v.Error(T.cmap_SubtableLanguage, 
                                        E.cmap_E_NonMacSubtableLanguage,
                                        m_tag, sDetails);
                                bOk = false;
                            }
                        }
                    }
                }
                if (bOk)
                {
                    v.Pass(T.cmap_SubtableLanguage,
                           P.cmap_P_NonMacSubtableLanguage, m_tag);
                }
            }

            return bRet;
        }
Esempio n. 31
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);
        }