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