示例#1
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);
        }
        //If it is OK, return > 0
        //If it is faulty, return < 0
        //If it has postscript outlines (can't rasterize for now, but it is ok) , return 0
        protected int TestFontRasterization()
        {
            //Any font with postscript outlines instead of truetype outlines has a CFF, table
            //So, if the file has a CFF table, we return 0 promptly
            //
            // FreeType is CFF capable.
            Type freeType = Type.GetType("Compat.OTFontFile.Rasterizer.FreeType.Library");

            if (freeType == null)
            {
                freeType = Type.GetType("SharpFont.Library");
            }
            if (IsPostScript() && freeType == null)
            {
                m_sDevMetricsDataError = "Font has PostScript outlines, rasterization not yet implemented";
                return(0);
            }

            // We do a sanity check here to make sure font meets minimal requirements before we will do
            // rasterization testing
            string s = "Unable to get data from rasterizer. ";

            DirectoryEntry de_head   = GetDirectoryEntry("head");
            Table_head     headTable = (Table_head)GetTable("head");

            if ((de_head != null && headTable == null) ||
                headTable == null)
            {
                m_sDevMetricsDataError = s + "'head' table is not present.";
                return(-1);
            }
            if (headTable.GetLength() != 54)
            {
                m_sDevMetricsDataError = s + "'head' table length is invalid.";
                return(-1);
            }

            if (headTable.magicNumber != 0x5f0f3cf5)
            {
                m_sDevMetricsDataError = s + "'head' table magic number is not correct.";
                return(-1);
            }

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

            if (maxpTable == null)
            {
                m_sDevMetricsDataError = s + "'maxp' table is not present.";
                return(-1);
            }
            uint val = maxpTable.TableVersionNumber.GetUint();

            if ((val == 0x00005000 && maxpTable.GetLength() != 6) ||
                (val == 0x00010000 && maxpTable.GetLength() != 32))
            {
                m_sDevMetricsDataError = s + "'maxp' table length is invalid.";
                return(-1);
            }

            DirectoryEntry de_cvt   = GetDirectoryEntry("cvt ");
            Table_cvt      cvtTable = (Table_cvt)GetTable("cvt ");

            if (de_cvt != null && cvtTable == null)
            {
                m_sDevMetricsDataError = s + "'cvt ' table is not valid.";
                return(-1);
            }

            DirectoryEntry de_glyf   = GetDirectoryEntry("glyf");
            Table_glyf     glyfTable = (Table_glyf)GetTable("glyf");

            if ((de_glyf != null && glyfTable == null) ||
                glyfTable == null)
            {
                m_sDevMetricsDataError = s + "'glyf' table is not valid.";
                return(-1);
            }

            Table_hhea hheaTable = (Table_hhea)GetTable("hhea");

            if (hheaTable == null)
            {
                m_sDevMetricsDataError = s + "'hhea' table is not present.";
                return(-1);
            }

            return(1);
        }
示例#3
0
        /************************
         * public methods
         */


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                    bool bHmtxMono = hmtxTable.IsMonospace(fontOwner);

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

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

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

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

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

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

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

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

                    bool bNamesOk = true;

                    byte [] buf = new byte[2];

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

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

            return(bRet);
        }