1999-12-16 21:34:53 +00:00
|
|
|
import DefaultTable
|
2013-09-17 16:59:39 -04:00
|
|
|
from fontTools.misc import sstruct
|
1999-12-16 21:34:53 +00:00
|
|
|
from fontTools.misc.textTools import safeEval, num2binary, binary2num
|
2002-05-10 19:03:34 +00:00
|
|
|
from types import TupleType
|
|
|
|
|
1999-12-16 21:34:53 +00:00
|
|
|
|
|
|
|
# panose classification
|
|
|
|
|
|
|
|
panoseFormat = """
|
2000-06-08 18:38:43 +00:00
|
|
|
bFamilyType: B
|
|
|
|
bSerifStyle: B
|
|
|
|
bWeight: B
|
|
|
|
bProportion: B
|
|
|
|
bContrast: B
|
|
|
|
bStrokeVariation: B
|
|
|
|
bArmStyle: B
|
|
|
|
bLetterForm: B
|
|
|
|
bMidline: B
|
|
|
|
bXHeight: B
|
1999-12-16 21:34:53 +00:00
|
|
|
"""
|
|
|
|
|
|
|
|
class Panose:
|
|
|
|
|
|
|
|
def toXML(self, writer, ttFont):
|
|
|
|
formatstring, names, fixes = sstruct.getformat(panoseFormat)
|
|
|
|
for name in names:
|
|
|
|
writer.simpletag(name, value=getattr(self, name))
|
|
|
|
writer.newline()
|
|
|
|
|
|
|
|
def fromXML(self, (name, attrs, content), ttFont):
|
|
|
|
setattr(self, name, safeEval(attrs["value"]))
|
|
|
|
|
|
|
|
|
|
|
|
# 'sfnt' OS/2 and Windows Metrics table - 'OS/2'
|
|
|
|
|
|
|
|
OS2_format_0 = """
|
2000-06-08 18:38:43 +00:00
|
|
|
> # big endian
|
|
|
|
version: H # version
|
|
|
|
xAvgCharWidth: h # average character width
|
|
|
|
usWeightClass: H # degree of thickness of strokes
|
|
|
|
usWidthClass: H # aspect ratio
|
|
|
|
fsType: h # type flags
|
|
|
|
ySubscriptXSize: h # subscript horizontal font size
|
|
|
|
ySubscriptYSize: h # subscript vertical font size
|
|
|
|
ySubscriptXOffset: h # subscript x offset
|
|
|
|
ySubscriptYOffset: h # subscript y offset
|
|
|
|
ySuperscriptXSize: h # superscript horizontal font size
|
|
|
|
ySuperscriptYSize: h # superscript vertical font size
|
|
|
|
ySuperscriptXOffset: h # superscript x offset
|
|
|
|
ySuperscriptYOffset: h # superscript y offset
|
|
|
|
yStrikeoutSize: h # strikeout size
|
|
|
|
yStrikeoutPosition: h # strikeout position
|
|
|
|
sFamilyClass: h # font family class and subclass
|
|
|
|
panose: 10s # panose classification number
|
2006-01-12 14:04:40 +00:00
|
|
|
ulUnicodeRange1: L # character range
|
|
|
|
ulUnicodeRange2: L # character range
|
|
|
|
ulUnicodeRange3: L # character range
|
|
|
|
ulUnicodeRange4: L # character range
|
2000-06-08 18:38:43 +00:00
|
|
|
achVendID: 4s # font vendor identification
|
|
|
|
fsSelection: H # font selection flags
|
|
|
|
fsFirstCharIndex: H # first unicode character index
|
|
|
|
fsLastCharIndex: H # last unicode character index
|
2001-08-15 07:01:44 +00:00
|
|
|
sTypoAscender: h # typographic ascender
|
|
|
|
sTypoDescender: h # typographic descender
|
|
|
|
sTypoLineGap: h # typographic line gap
|
2000-06-08 18:38:43 +00:00
|
|
|
usWinAscent: H # Windows ascender
|
|
|
|
usWinDescent: H # Windows descender
|
1999-12-16 21:34:53 +00:00
|
|
|
"""
|
|
|
|
|
|
|
|
OS2_format_1_addition = """
|
2006-01-12 14:04:40 +00:00
|
|
|
ulCodePageRange1: L
|
|
|
|
ulCodePageRange2: L
|
1999-12-16 21:34:53 +00:00
|
|
|
"""
|
|
|
|
|
|
|
|
OS2_format_2_addition = OS2_format_1_addition + """
|
2000-06-08 18:38:43 +00:00
|
|
|
sxHeight: h
|
|
|
|
sCapHeight: h
|
|
|
|
usDefaultChar: H
|
|
|
|
usBreakChar: H
|
|
|
|
usMaxContex: H
|
1999-12-16 21:34:53 +00:00
|
|
|
"""
|
|
|
|
|
2013-11-18 21:53:25 +01:00
|
|
|
OS2_format_5_addition = OS2_format_2_addition + """
|
|
|
|
usLowerOpticalPointSize: H
|
|
|
|
usUpperOpticalPointSize: H
|
|
|
|
"""
|
|
|
|
|
1999-12-16 21:34:53 +00:00
|
|
|
bigendian = " > # big endian\n"
|
|
|
|
|
|
|
|
OS2_format_1 = OS2_format_0 + OS2_format_1_addition
|
|
|
|
OS2_format_2 = OS2_format_0 + OS2_format_2_addition
|
2013-11-18 21:53:25 +01:00
|
|
|
OS2_format_5 = OS2_format_0 + OS2_format_5_addition
|
1999-12-16 21:34:53 +00:00
|
|
|
OS2_format_1_addition = bigendian + OS2_format_1_addition
|
|
|
|
OS2_format_2_addition = bigendian + OS2_format_2_addition
|
2013-11-18 21:53:25 +01:00
|
|
|
OS2_format_5_addition = bigendian + OS2_format_5_addition
|
1999-12-16 21:34:53 +00:00
|
|
|
|
|
|
|
|
|
|
|
class table_O_S_2f_2(DefaultTable.DefaultTable):
|
|
|
|
|
|
|
|
"""the OS/2 table"""
|
|
|
|
|
|
|
|
def decompile(self, data, ttFont):
|
|
|
|
dummy, data = sstruct.unpack2(OS2_format_0, data, self)
|
2011-02-13 06:25:21 +00:00
|
|
|
# workarounds for buggy fonts (Apple, mona)
|
|
|
|
if not data:
|
2000-10-13 13:51:33 +00:00
|
|
|
self.version = 0
|
2011-02-13 06:25:21 +00:00
|
|
|
elif len(data) == sstruct.calcsize(OS2_format_1_addition):
|
|
|
|
self.version = 1
|
|
|
|
elif len(data) == sstruct.calcsize(OS2_format_2_addition):
|
|
|
|
if self.version not in (2, 3, 4):
|
|
|
|
self.version = 1
|
2013-11-18 21:53:25 +01:00
|
|
|
elif len(data) == sstruct.calcsize(OS2_format_5_addition):
|
2013-11-25 07:23:51 -05:00
|
|
|
assert self.version == 5
|
2011-02-13 06:25:21 +00:00
|
|
|
else:
|
|
|
|
from fontTools import ttLib
|
|
|
|
raise ttLib.TTLibError, "unknown format for OS/2 table (incorrect length): version %s" % (self.version, len(data))
|
1999-12-16 21:34:53 +00:00
|
|
|
if self.version == 1:
|
2003-01-03 20:52:42 +00:00
|
|
|
sstruct.unpack2(OS2_format_1_addition, data, self)
|
2007-10-22 09:31:02 +00:00
|
|
|
elif self.version in (2, 3, 4):
|
2003-01-03 20:52:42 +00:00
|
|
|
sstruct.unpack2(OS2_format_2_addition, data, self)
|
2013-11-18 21:53:25 +01:00
|
|
|
elif self.version == 5:
|
|
|
|
sstruct.unpack2(OS2_format_5_addition, data, self)
|
2013-11-25 07:21:10 -05:00
|
|
|
self.usLowerOpticalPointSize /= 20.
|
|
|
|
self.usUpperOpticalPointSize /= 20.
|
1999-12-16 21:34:53 +00:00
|
|
|
elif self.version <> 0:
|
|
|
|
from fontTools import ttLib
|
|
|
|
raise ttLib.TTLibError, "unknown format for OS/2 table: version %s" % self.version
|
|
|
|
self.panose = sstruct.unpack(panoseFormat, self.panose, Panose())
|
|
|
|
|
|
|
|
def compile(self, ttFont):
|
|
|
|
panose = self.panose
|
|
|
|
self.panose = sstruct.pack(panoseFormat, self.panose)
|
|
|
|
if self.version == 0:
|
|
|
|
data = sstruct.pack(OS2_format_0, self)
|
|
|
|
elif self.version == 1:
|
|
|
|
data = sstruct.pack(OS2_format_1, self)
|
2007-10-22 09:31:02 +00:00
|
|
|
elif self.version in (2, 3, 4):
|
1999-12-16 21:34:53 +00:00
|
|
|
data = sstruct.pack(OS2_format_2, self)
|
2013-11-18 21:53:25 +01:00
|
|
|
elif self.version == 5:
|
2013-11-25 07:21:10 -05:00
|
|
|
lower = self.usLowerOpticalPointSize
|
|
|
|
upper = self.usUpperOpticalPointSize
|
|
|
|
self.usLowerOpticalPointSize = int(round(self.usLowerOpticalPointSize * 20))
|
|
|
|
self.usUpperOpticalPointSize = int(round(self.usUpperOpticalPointSize * 20))
|
2013-11-18 21:53:25 +01:00
|
|
|
data = sstruct.pack(OS2_format_5, self)
|
2013-11-25 07:21:10 -05:00
|
|
|
self.usLowerOpticalPointSize = lower
|
|
|
|
self.usUpperOpticalPointSize = upper
|
1999-12-16 21:34:53 +00:00
|
|
|
else:
|
|
|
|
from fontTools import ttLib
|
|
|
|
raise ttLib.TTLibError, "unknown format for OS/2 table: version %s" % self.version
|
|
|
|
self.panose = panose
|
|
|
|
return data
|
|
|
|
|
|
|
|
def toXML(self, writer, ttFont):
|
|
|
|
if self.version == 1:
|
|
|
|
format = OS2_format_1
|
2007-10-22 09:31:02 +00:00
|
|
|
elif self.version in (2, 3, 4):
|
1999-12-16 21:34:53 +00:00
|
|
|
format = OS2_format_2
|
2013-11-18 21:53:25 +01:00
|
|
|
elif self.version == 5:
|
|
|
|
format = OS2_format_5
|
1999-12-16 21:34:53 +00:00
|
|
|
else:
|
|
|
|
format = OS2_format_0
|
|
|
|
formatstring, names, fixes = sstruct.getformat(format)
|
|
|
|
for name in names:
|
|
|
|
value = getattr(self, name)
|
|
|
|
if type(value) == type(0L):
|
|
|
|
value = int(value)
|
|
|
|
if name=="panose":
|
|
|
|
writer.begintag("panose")
|
|
|
|
writer.newline()
|
|
|
|
value.toXML(writer, ttFont)
|
|
|
|
writer.endtag("panose")
|
|
|
|
elif name in ("ulUnicodeRange1", "ulUnicodeRange2",
|
|
|
|
"ulUnicodeRange3", "ulUnicodeRange4",
|
|
|
|
"ulCodePageRange1", "ulCodePageRange2"):
|
|
|
|
writer.simpletag(name, value=num2binary(value))
|
|
|
|
elif name in ("fsType", "fsSelection"):
|
|
|
|
writer.simpletag(name, value=num2binary(value, 16))
|
|
|
|
elif name == "achVendID":
|
|
|
|
writer.simpletag(name, value=repr(value)[1:-1])
|
|
|
|
else:
|
|
|
|
writer.simpletag(name, value=value)
|
|
|
|
writer.newline()
|
|
|
|
|
|
|
|
def fromXML(self, (name, attrs, content), ttFont):
|
|
|
|
if name == "panose":
|
|
|
|
self.panose = panose = Panose()
|
|
|
|
for element in content:
|
2002-05-10 19:03:34 +00:00
|
|
|
if type(element) == TupleType:
|
1999-12-16 21:34:53 +00:00
|
|
|
panose.fromXML(element, ttFont)
|
|
|
|
elif name in ("ulUnicodeRange1", "ulUnicodeRange2",
|
|
|
|
"ulUnicodeRange3", "ulUnicodeRange4",
|
|
|
|
"ulCodePageRange1", "ulCodePageRange2",
|
|
|
|
"fsType", "fsSelection"):
|
|
|
|
setattr(self, name, binary2num(attrs["value"]))
|
|
|
|
elif name == "achVendID":
|
|
|
|
setattr(self, name, safeEval("'''" + attrs["value"] + "'''"))
|
|
|
|
else:
|
|
|
|
setattr(self, name, safeEval(attrs["value"]))
|
|
|
|
|
|
|
|
|