//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); }
/************************ * 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); }
/************************ * 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); }
static byte[] get_TTF_digest(OTFile f) { OTFont fn = f.GetFont(0); Table_DSIG tDSIG = (Table_DSIG)fn.GetTable("DSIG"); DirectoryEntry deDSIG = null; // sort table by offset Dictionary <uint, int> offsetlookup = new Dictionary <uint, int>(); var list = new List <uint>(); for (ushort i = 0; i < fn.GetNumTables(); i++) { DirectoryEntry de = fn.GetDirectoryEntry(i); offsetlookup.Add(de.offset, i); list.Add(de.offset); if ((string)de.tag == "DSIG") { deDSIG = de; } } list.Sort(); // New offset table var old_ot = fn.GetOffsetTable(); OffsetTable ot = new OffsetTable(old_ot.sfntVersion, (ushort)(old_ot.numTables - 1)); for (ushort i = 0; i < fn.GetNumTables(); i++) { DirectoryEntry oldde = fn.GetDirectoryEntry(i); if ((string)oldde.tag != "DSIG") { DirectoryEntry de = new DirectoryEntry(oldde); de.offset -= 16; // one less entry if (de.offset > deDSIG.offset) { de.offset -= tDSIG.GetBuffer().GetPaddedLength(); } ot.DirectoryEntries.Add(de); } } hash.TransformBlock(ot.m_buf.GetBuffer(), 0, (int)ot.m_buf.GetLength(), ot.m_buf.GetBuffer(), 0); for (int i = 0; i < ot.DirectoryEntries.Count; i++) { DirectoryEntry de = (DirectoryEntry)ot.DirectoryEntries[i]; hash.TransformBlock(de.m_buf.GetBuffer(), 0, (int)de.m_buf.GetLength(), de.m_buf.GetBuffer(), 0); } Table_head headTable = (Table_head)fn.GetTable("head"); // calculate the checksum uint sum = 0; sum += ot.CalcOffsetTableChecksum(); sum += ot.CalcDirectoryEntriesChecksum(); foreach (var key in list) { OTTable table = fn.GetTable((ushort)offsetlookup[key]); if ((string)table.GetTag() != "DSIG") { sum += table.CalcChecksum(); } } Table_head.head_cache headCache = (Table_head.head_cache)headTable.GetCache(); // set the checkSumAdujustment field headCache.checkSumAdjustment = 0xb1b0afba - sum; Table_head newHead = (Table_head)headCache.GenerateTable(); foreach (var key in list) { OTTable table = fn.GetTable((ushort)offsetlookup[key]); if ((string)table.GetTag() == "head") { table = newHead; } if ((string)table.GetTag() != "DSIG") { hash.TransformBlock(table.m_bufTable.GetBuffer(), 0, (int)table.GetBuffer().GetPaddedLength(), table.m_bufTable.GetBuffer(), 0); } } byte[] usFlag = { 0, 1 }; hash.TransformFinalBlock(usFlag, 0, 2); return(hash.Hash); }