Home | History | Annotate | Download | only in tables
      1 from __future__ import print_function, division, absolute_import
      2 from fontTools.misc.py23 import *
      3 from fontTools.misc import sstruct
      4 from fontTools.misc.textTools import safeEval, num2binary, binary2num
      5 from fontTools.misc.timeTools import timestampFromString, timestampToString, timestampNow
      6 from fontTools.misc.timeTools import epoch_diff as mac_epoch_diff # For backward compat
      7 from . import DefaultTable
      8 import logging
      9 
     10 
     11 log = logging.getLogger(__name__)
     12 
     13 headFormat = """
     14 		>	# big endian
     15 		tableVersion:       16.16F
     16 		fontRevision:       16.16F
     17 		checkSumAdjustment: I
     18 		magicNumber:        I
     19 		flags:              H
     20 		unitsPerEm:         H
     21 		created:            Q
     22 		modified:           Q
     23 		xMin:               h
     24 		yMin:               h
     25 		xMax:               h
     26 		yMax:               h
     27 		macStyle:           H
     28 		lowestRecPPEM:      H
     29 		fontDirectionHint:  h
     30 		indexToLocFormat:   h
     31 		glyphDataFormat:    h
     32 """
     33 
     34 class table__h_e_a_d(DefaultTable.DefaultTable):
     35 
     36 	dependencies = ['maxp', 'loca', 'CFF ']
     37 
     38 	def decompile(self, data, ttFont):
     39 		dummy, rest = sstruct.unpack2(headFormat, data, self)
     40 		if rest:
     41 			# this is quite illegal, but there seem to be fonts out there that do this
     42 			log.warning("extra bytes at the end of 'head' table")
     43 			assert rest == "\0\0"
     44 
     45 		# For timestamp fields, ignore the top four bytes.  Some fonts have
     46 		# bogus values there.  Since till 2038 those bytes only can be zero,
     47 		# ignore them.
     48 		#
     49 		# https://github.com/fonttools/fonttools/issues/99#issuecomment-66776810
     50 		for stamp in 'created', 'modified':
     51 			value = getattr(self, stamp)
     52 			if value > 0xFFFFFFFF:
     53 				log.warning("'%s' timestamp out of range; ignoring top bytes", stamp)
     54 				value &= 0xFFFFFFFF
     55 				setattr(self, stamp, value)
     56 			if value < 0x7C259DC0: # January 1, 1970 00:00:00
     57 				log.warning("'%s' timestamp seems very low; regarding as unix timestamp", stamp)
     58 				value += 0x7C259DC0
     59 				setattr(self, stamp, value)
     60 
     61 	def compile(self, ttFont):
     62 		if ttFont.recalcBBoxes:
     63 			# For TT-flavored fonts, xMin, yMin, xMax and yMax are set in table__m_a_x_p.recalc().
     64 			if 'CFF ' in ttFont:
     65 				topDict = ttFont['CFF '].cff.topDictIndex[0]
     66 				self.xMin, self.yMin, self.xMax, self.yMax = topDict.FontBBox
     67 		if ttFont.recalcTimestamp:
     68 			self.modified = timestampNow()
     69 		data = sstruct.pack(headFormat, self)
     70 		return data
     71 
     72 	def toXML(self, writer, ttFont):
     73 		writer.comment("Most of this table will be recalculated by the compiler")
     74 		writer.newline()
     75 		formatstring, names, fixes = sstruct.getformat(headFormat)
     76 		for name in names:
     77 			value = getattr(self, name)
     78 			if name in ("created", "modified"):
     79 				value = timestampToString(value)
     80 			if name in ("magicNumber", "checkSumAdjustment"):
     81 				if value < 0:
     82 					value = value + 0x100000000
     83 				value = hex(value)
     84 				if value[-1:] == "L":
     85 					value = value[:-1]
     86 			elif name in ("macStyle", "flags"):
     87 				value = num2binary(value, 16)
     88 			writer.simpletag(name, value=value)
     89 			writer.newline()
     90 
     91 	def fromXML(self, name, attrs, content, ttFont):
     92 		value = attrs["value"]
     93 		if name in ("created", "modified"):
     94 			value = timestampFromString(value)
     95 		elif name in ("macStyle", "flags"):
     96 			value = binary2num(value)
     97 		else:
     98 			value = safeEval(value)
     99 		setattr(self, name, value)
    100