-
Notifications
You must be signed in to change notification settings - Fork 510
Description
Apologies for a semi-off-topic issue.
Microsoft recently opensourced Font Validator (FontVal) under the super-liberal MIT license. Somewhat unfortunately, Font Validator is written in C#, but it seems to me that, generally speaking, that code is relatively self-contained, and seems to be cleanly written. Do you think it would be feasible to port it to Python (to make "PyFontVal" — which shouldn't really become part of fontTools, much more likely a wholly-separate package)? Given that C# is more strongly typed than Python, it should be possible, at least theoretically.
I've just looked at one function, val_JSTF.cs, and tried to automatically convert a bit of it to Python using the VaryCode converter, which, after the free registration, limits the conversion to 2048 characters.
Here's the input:
using System;
using OTFontFile;
using OTFontFile.OTL;
namespace OTFontFileVal
{
/// <summary>
/// Summary description for val_JSTF.
/// </summary>
public class val_JSTF : Table_JSTF, ITableValidate
{
public val_JSTF(OTTag tag, MBOBuffer buf) : base(tag, buf)
{
m_DataOverlapDetector = new DataOverlapDetector();
}
public bool Validate(Validator v, OTFontVal fontOwner)
{
bool bRet = true;
// check the version
if (v.PerformTest(T.JSTF_Version))
{
if (Version.GetUint() == 0x00010000)
{
v.Pass(T.JSTF_Version, P.JSTF_P_Version, m_tag);
}
else
{
v.Error(T.JSTF_Version, E.JSTF_E_Version, m_tag, "0x" + Version.GetUint().ToString("x8"));
bRet = false;
}
}
// check the JstfScriptRecord array length
if (v.PerformTest(T.JSTF_JstfScriptRecord_length))
{
if ((uint)FieldOffsets.JstfScriptRecords + JstfScriptCount*6 > m_bufTable.GetLength())
{
v.Error(T.JSTF_JstfScriptRecord_length, E.JSTF_E_Array_pastEOT, m_tag, "JstfScriptRecord array");
bRet = false;
}
}
// check that the JstfScriptRecord array is in alphabetical order
if (v.PerformTest(T.JSTF_JstfScriptRecord_order))
{
if (JstfScriptCount > 1)
{
for (uint i=0; i<JstfScriptCount-1; i++)
{
JstfScriptRecord jsrCurr = GetJstfScriptRecord_val(i);
JstfScriptRecord jsrNext = GetJstfScriptRecord_val(i+1);
if (jsrCurr.JstfScriptTag >= jsrNext.JstfScriptTag)
{
v.Error(T.JSTF_JstfScriptRecord_order, E.JSTF_E_Array_order, m_tag, "JstfScriptRecord array");
bRet = false;
break;
}
}
}
}
// check each JstfScriptRecord
if (v.PerformTest(T.JSTF_JstfScriptRecords))
{
for (uint i=0; i<JstfScriptCount; i++)
{
JstfScriptRecord_val jsr = GetJstfScriptRecord_val(i);
// check the tag
if (!jsr.JstfScriptTag.IsValid())
{
v.Error(T.JSTF_JstfScriptRecords, E.JSTF_E_tag, m_tag, "JstfScriptRecord[" + i + "]");
bRet = false;
}
// check the offset
if (jsr.JstfScriptOffset > m_bufTable.GetLength())
{
v.Error(T.JSTF_JstfScriptRecords, E.JSTF_E_Offset_PastEOT, m_tag, "JstfScriptRecord[" + i + "]");
bRet = false;
}
// validate the JstfScript table
JstfScript_val js = jsr.GetJstfScriptTable_val();
...and here is the generated Python code:
from System import *
from OTFontFile import *
from OTFontFile.OTL import *
class val_JSTF(Table_JSTF, ITableValidate):
""" <summary>
Summary description for val_JSTF.
</summary>
"""
def __init__(self, tag, buf):
self._m_DataOverlapDetector = DataOverlapDetector()
def Validate(self, v, fontOwner):
bRet = True
# check the version
if v.PerformTest(T.JSTF_Version):
if Version.GetUint() == 0x00010000:
v.Pass(T.JSTF_Version, P.JSTF_P_Version, m_tag)
else:
v.Error(T.JSTF_Version, E.JSTF_E_Version, m_tag, "0x" + Version.GetUint().ToString("x8"))
bRet = False
# check the JstfScriptRecord array length
if v.PerformTest(T.JSTF_JstfScriptRecord_length):
if FieldOffsets.JstfScriptRecords + JstfScriptCount * 6 > m_bufTable.GetLength():
v.Error(T.JSTF_JstfScriptRecord_length, E.JSTF_E_Array_pastEOT, m_tag, "JstfScriptRecord array")
bRet = False
# check that the JstfScriptRecord array is in alphabetical order
if v.PerformTest(T.JSTF_JstfScriptRecord_order):
if JstfScriptCount > 1:
i = 0
while i < JstfScriptCount - 1:
jsrCurr = self.GetJstfScriptRecord_val(i)
jsrNext = self.GetJstfScriptRecord_val(i + 1)
if jsrCurr.JstfScriptTag >= jsrNext.JstfScriptTag:
v.Error(T.JSTF_JstfScriptRecord_order, E.JSTF_E_Array_order, m_tag, "JstfScriptRecord array")
bRet = False
break
i += 1
# check each JstfScriptRecord
if v.PerformTest(T.JSTF_JstfScriptRecords):
i = 0
while i < JstfScriptCount:
jsr = self.GetJstfScriptRecord_val(i)
# check the tag
if not jsr.JstfScriptTag.IsValid():
v.Error(T.JSTF_JstfScriptRecords, E.JSTF_E_tag, m_tag, "JstfScriptRecord[" + i + "]")
bRet = False
# check the offset
if jsr.JstfScriptOffset > m_bufTable.GetLength():
v.Error(T.JSTF_JstfScriptRecords, E.JSTF_E_Offset_PastEOT, m_tag, "JstfScriptRecord[" + i + "]")
bRet = False
# validate the JstfScript table
js = jsr.GetJstfScriptTable_val()
...At least it does not look bad. Perhaps, after a conversion and some refactoring, this could be used as a basis for a more-generic font validation library which could integrate fontTools, the "PyFontVal" port and a somewhat refactored AFDKO CompareFamily.py ?