• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from __future__ import print_function, division, absolute_import
2from fontTools.misc.py23 import *
3from fontTools.misc import sstruct
4from fontTools.misc.textTools import safeEval, num2binary, binary2num
5from . import DefaultTable
6from .sbixGlyph import *
7from .sbixStrike import *
8
9
10sbixHeaderFormat = """
11	>
12	version:       H	# Version number (set to 1)
13	flags:         H	# The only two bits used in the flags field are bits 0
14						# and 1. For historical reasons, bit 0 must always be 1.
15						# Bit 1 is a sbixDrawOutlines flag and is interpreted as
16						# follows:
17						#     0: Draw only 'sbix' bitmaps
18						#     1: Draw both 'sbix' bitmaps and outlines, in that
19						#        order
20	numStrikes:    L	# Number of bitmap strikes to follow
21"""
22sbixHeaderFormatSize = sstruct.calcsize(sbixHeaderFormat)
23
24
25sbixStrikeOffsetFormat = """
26	>
27	strikeOffset:  L	# Offset from begining of table to data for the
28						# individual strike
29"""
30sbixStrikeOffsetFormatSize = sstruct.calcsize(sbixStrikeOffsetFormat)
31
32
33class table__s_b_i_x(DefaultTable.DefaultTable):
34
35	def __init__(self, tag=None):
36		DefaultTable.DefaultTable.__init__(self, tag)
37		self.version = 1
38		self.flags = 1
39		self.numStrikes = 0
40		self.strikes = {}
41		self.strikeOffsets = []
42
43	def decompile(self, data, ttFont):
44		# read table header
45		sstruct.unpack(sbixHeaderFormat, data[ : sbixHeaderFormatSize], self)
46		# collect offsets to individual strikes in self.strikeOffsets
47		for i in range(self.numStrikes):
48			current_offset = sbixHeaderFormatSize + i * sbixStrikeOffsetFormatSize
49			offset_entry = sbixStrikeOffset()
50			sstruct.unpack(sbixStrikeOffsetFormat, \
51				data[current_offset:current_offset+sbixStrikeOffsetFormatSize], \
52				offset_entry)
53			self.strikeOffsets.append(offset_entry.strikeOffset)
54
55		# decompile Strikes
56		for i in range(self.numStrikes-1, -1, -1):
57			current_strike = Strike(rawdata=data[self.strikeOffsets[i]:])
58			data = data[:self.strikeOffsets[i]]
59			current_strike.decompile(ttFont)
60			#print "  Strike length: %xh" % len(bitmapSetData)
61			#print "Number of Glyph entries:", len(current_strike.glyphs)
62			if current_strike.ppem in self.strikes:
63				from fontTools import ttLib
64				raise ttLib.TTLibError("Pixel 'ppem' must be unique for each Strike")
65			self.strikes[current_strike.ppem] = current_strike
66
67		# after the glyph data records have been extracted, we don't need the offsets anymore
68		del self.strikeOffsets
69		del self.numStrikes
70
71	def compile(self, ttFont):
72		sbixData = b""
73		self.numStrikes = len(self.strikes)
74		sbixHeader = sstruct.pack(sbixHeaderFormat, self)
75
76		# calculate offset to start of first strike
77		setOffset = sbixHeaderFormatSize + sbixStrikeOffsetFormatSize * self.numStrikes
78
79		for si in sorted(self.strikes.keys()):
80			current_strike = self.strikes[si]
81			current_strike.compile(ttFont)
82			# append offset to this strike to table header
83			current_strike.strikeOffset = setOffset
84			sbixHeader += sstruct.pack(sbixStrikeOffsetFormat, current_strike)
85			setOffset += len(current_strike.data)
86			sbixData += current_strike.data
87
88		return sbixHeader + sbixData
89
90	def toXML(self, xmlWriter, ttFont):
91		xmlWriter.simpletag("version", value=self.version)
92		xmlWriter.newline()
93		xmlWriter.simpletag("flags", value=num2binary(self.flags, 16))
94		xmlWriter.newline()
95		for i in sorted(self.strikes.keys()):
96			self.strikes[i].toXML(xmlWriter, ttFont)
97
98	def fromXML(self, name, attrs, content, ttFont):
99		if name =="version":
100			setattr(self, name, safeEval(attrs["value"]))
101		elif name == "flags":
102			setattr(self, name, binary2num(attrs["value"]))
103		elif name == "strike":
104			current_strike = Strike()
105			for element in content:
106				if isinstance(element, tuple):
107					name, attrs, content = element
108					current_strike.fromXML(name, attrs, content, ttFont)
109			self.strikes[current_strike.ppem] = current_strike
110		else:
111			from fontTools import ttLib
112			raise ttLib.TTLibError("can't handle '%s' element" % name)
113
114
115# Helper classes
116
117class sbixStrikeOffset(object):
118	pass
119