G_P_O_S_.py revision a36fd88a20e9441bef930a870b7e4ce7c9ef597c
1import otCommon 2 3 4class table_G_P_O_S_(otCommon.base_GPOS_GSUB): 5 6 def getLookupTypeClass(self, lookupType): 7 return lookupTypeClasses[lookupType] 8 9 10class SinglePos: 11 12 def decompile(self, reader, otFont): 13 self.format = reader.readUShort() 14 if self.format == 1: 15 self.decompileFormat1(reader, otFont) 16 elif self.format == 2: 17 self.decompileFormat2(reader, otFont) 18 else: 19 from fontTools import ttLib 20 raise ttLib.TTLibError, "unknown SinglePos format: %d" % self.format 21 22 def decompileFormat1(self, reader, otFont): 23 coverage = reader.readTable(otCommon.CoverageTable, otFont) 24 valueFactory = ValueRecordFactory(reader.readUShort()) 25 self.coverage = coverage.getGlyphNames() 26 self.value = valueFactory.readValueRecord(reader, otFont) 27 28 def decompileFormat2(self, reader, otFont): 29 coverage = reader.readTable(otCommon.CoverageTable, otFont) 30 valueFactory = ValueRecordFactory(reader.readUShort()) 31 valueCount = reader.readUShort() 32 glyphNames = coverage.getGlyphNames() 33 self.pos = pos = {} 34 for i in range(valueCount): 35 pos[glyphNames[i]] = valueFactory.readValueRecord(reader, otFont) 36 37 def compile(self, writer, otFont): 38 xxx 39 40 def toXML(self, xmlWriter, otFont): 41 xmlWriter.comment("NotImplemented") 42 xmlWriter.newline() 43 44 def fromXML(self, (name, attrs, content), otFont): 45 raise NotImplementedError 46 47 48class PairPos: 49 50 def decompile(self, reader, otFont): 51 self.format = reader.readUShort() 52 if self.format == 1: 53 self.decompileFormat1(reader, otFont) 54 elif self.format == 2: 55 self.decompileFormat2(reader, otFont) 56 else: 57 from fontTools import ttLib 58 raise ttLib.TTLibError, "unknown PairPos format: %d" % self.format 59 60 def decompileFormat1(self, reader, otFont): 61 coverage = reader.readTable(otCommon.CoverageTable, otFont) 62 glyphNames = coverage.glyphNames 63 valueFactory1 = ValueRecordFactory(reader.readUShort()) 64 valueFactory2 = ValueRecordFactory(reader.readUShort()) 65 self.pairs = pairs = {} 66 for i in range(reader.readUShort()): 67 firstGlyphName = glyphNames[i] 68 set = reader.readTable(PairSet, otFont, valueFactory1, valueFactory2) 69 pairs[firstGlyphName] = set.getValues() 70 71 def decompileFormat2(self, reader, otFont): 72 coverage = reader.readTable(otCommon.CoverageTable, otFont) 73 glyphNames = coverage.glyphNames 74 valueFactory1 = ValueRecordFactory(reader.readUShort()) 75 valueFactory2 = ValueRecordFactory(reader.readUShort()) 76 self.classDef1 = reader.readTable(otCommon.ClassDefinitionTable, otFont) 77 self.classDef2 = reader.readTable(otCommon.ClassDefinitionTable, otFont) 78 class1Count = reader.readUShort() 79 class2Count = reader.readUShort() 80 self.pairs = pairs = {} # sparse matrix 81 for i in range(class1Count): 82 row = {} 83 for j in range(class2Count): 84 value1 = valueFactory1.readValueRecord(reader, otFont) 85 value2 = valueFactory2.readValueRecord(reader, otFont) 86 if value1 or value2: 87 row[j] = (value1, value2) 88 if row: 89 pairs[i] = row 90 91 def compile(self, writer, otFont): 92 if self.format == 1: 93 self.compileFormat1(writer, otFont) 94 elif self.format == 2: 95 self.compileFormat2(writer, otFont) 96 else: 97 from fontTools import ttLib 98 raise ttLib.TTLibError, "unknown PairPos format: %d" % self.format 99 100 def compileFormat1(self, writer, otFont): 101 pairs = self.pairs 102 glyphNames = pairs.keys() 103 coverage = otCommon.CoverageTable() 104 glyphNames = coverage.setGlyphNames(glyphNames, otFont) 105 writer.writeTable(coverage, otFont) 106 # dumb approach: just take the first pair and grab the value. 107 dummy, sample1, sample2 = pairs[pairs.keys()[0]][0] 108 valueFormat1 = valueFormat2 = 0 109 if sample1: 110 valueFormat1 = sample1.getFormat() 111 if sample2: 112 valueFormat2 = sample2.getFormat() 113 writer.writeUShort(valueFormat1) 114 writer.writeUShort(valueFormat2) 115 116 valueFactory1 = ValueRecordFactory(valueFormat1) 117 valueFactory2 = ValueRecordFactory(valueFormat2) 118 119 writer.writeUShort(len(pairs)) 120 for glyphName in glyphNames: 121 set = PairSet(valueFactory1, valueFactory2) 122 set.setValues(pairs[glyphName]) 123 writer.writeTable(set, otFont) 124 125 def compileFormat2(self, writer, otFont): 126 xxx 127 128 def toXML(self, xmlWriter, otFont): 129 if self.format == 1: 130 self.toXMLFormat1(xmlWriter, otFont) 131 elif self.format == 2: 132 self.toXMLFormat2(xmlWriter, otFont) 133 else: 134 from fontTools import ttLib 135 raise ttLib.TTLibError, "unknown PairPos format: %d" % self.format 136 137 def toXMLFormat1(self, xmlWriter, otFont): 138 pairs = self.pairs.items() 139 pairs.sort() 140 for firstGlyph, secondGlyphs in pairs: 141 for secondGlyph, value1, value2 in secondGlyphs: 142 xmlWriter.begintag("Pair", pair=firstGlyph+","+secondGlyph) 143 if value1: 144 value1.toXML(xmlWriter, otFont) 145 else: 146 xmlWriter.simpletag("Value") 147 if value2: 148 value2.toXML(xmlWriter, otFont) 149 #else: # the second value can be omitted 150 # xmlWriter.simpletag("Value") 151 xmlWriter.endtag("Pair") 152 xmlWriter.newline() 153 154 def toXMLFormat2(self, xmlWriter, otFont): 155 xmlWriter.comment("NotImplemented") 156 xmlWriter.newline() 157 158 def fromXML(self, (name, attrs, content), otFont): 159 raise NotImplementedError 160 161 162class PairSet: 163 164 def __init__(self, valueFactory1=None, valueFactory2=None): 165 self.valueFactory1 = valueFactory1 166 self.valueFactory2 = valueFactory2 167 168 def getValues(self): 169 return self.values 170 171 def setValues(self, values): 172 self.values = values 173 174 def decompile(self, reader, otFont): 175 pairValueCount = reader.readUShort() 176 self.values = values = [] 177 for j in range(pairValueCount): 178 secondGlyphID = reader.readUShort() 179 secondGlyphName = otFont.getGlyphName(secondGlyphID) 180 value1 = self.valueFactory1.readValueRecord(reader, otFont) 181 value2 = self.valueFactory2.readValueRecord(reader, otFont) 182 values.append((secondGlyphName, value1, value2)) 183 184 def compile(self, writer, otFont): 185 values = self.values 186 writer.writeUShort(len(values)) 187 for secondGlyphName, value1, value2 in values: 188 writer.writeUShort(otFont.getGlyphID(secondGlyphName)) 189 self.valueFactory1.writeValuerecord(value1, writer, otFont) 190 self.valueFactory2.writeValuerecord(value2, writer, otFont) 191 192 193# 194# ------------------ 195# 196 197class CursivePos: 198 199 def decompile(self, reader, otFont): 200 xxx 201 202 def compile(self, writer, otFont): 203 xxx 204 205 def toXML(self, xmlWriter, otFont): 206 xmlWriter.comment("NotImplemented") 207 xmlWriter.newline() 208 209 210class MarkBasePos: 211 212 def decompile(self, reader, otFont): 213 xxx 214 215 def compile(self, writer, otFont): 216 xxx 217 218 def toXML(self, xmlWriter, otFont): 219 xmlWriter.comment("NotImplemented") 220 xmlWriter.newline() 221 222 223class MarkLigPos: 224 225 def decompile(self, reader, otFont): 226 xxx 227 228 def compile(self, writer, otFont): 229 xxx 230 231 def toXML(self, xmlWriter, otFont): 232 xmlWriter.comment("NotImplemented") 233 xmlWriter.newline() 234 235 236class MarkMarkPos: 237 238 def decompile(self, reader, otFont): 239 xxx 240 241 def compile(self, writer, otFont): 242 xxx 243 244 def toXML(self, xmlWriter, otFont): 245 xmlWriter.comment("NotImplemented") 246 xmlWriter.newline() 247 248 249class ContextPos: 250 251 def decompile(self, reader, otFont): 252 xxx 253 254 def compile(self, writer, otFont): 255 xxx 256 257 def toXML(self, xmlWriter, otFont): 258 xmlWriter.comment("NotImplemented") 259 xmlWriter.newline() 260 261 262class ChainContextPos: 263 264 def decompile(self, reader, otFont): 265 xxx 266 267 def compile(self, writer, otFont): 268 xxx 269 270 def toXML(self, xmlWriter, otFont): 271 xmlWriter.comment("NotImplemented") 272 xmlWriter.newline() 273 274 275valueRecordFormat = [ 276# Mask Name isDevice struct format char 277 (0x0001, "XPlacement", 0, "h"), 278 (0x0002, "YPlacement", 0, "h"), 279 (0x0004, "XAdvance", 0, "h"), 280 (0x0008, "YAdvance", 0, "h"), 281 (0x0010, "XPlaDevice", 1, "H"), 282 (0x0020, "YPlaDevice", 1, "H"), 283 (0x0040, "XAdvDevice", 1, "H"), 284 (0x0080, "YAdvDevice", 1, "H"), 285# reserved: 286 (0x0100, "Reserved1", 0, "H"), 287 (0x0200, "Reserved2", 0, "H"), 288 (0x0400, "Reserved3", 0, "H"), 289 (0x0800, "Reserved4", 0, "H"), 290 (0x1000, "Reserved5", 0, "H"), 291 (0x2000, "Reserved6", 0, "H"), 292 (0x4000, "Reserved7", 0, "H"), 293 (0x8000, "Reserved8", 0, "H"), 294] 295 296valueRecordFormatDict = {} 297for mask, name, isDevice, format in valueRecordFormat: 298 valueRecordFormatDict[name] = mask, isDevice, format 299 300 301class ValueRecordFactory: 302 303 def __init__(self, valueFormat): 304 format = ">" 305 names = [] 306 for mask, name, isDevice, formatChar in valueRecordFormat: 307 if valueFormat & mask: 308 names.append((name, isDevice)) 309 format = format + formatChar 310 self.names, self.format = names, format 311 self.size = 2 * len(names) 312 313 def readValueRecord(self, reader, otFont): 314 names = self.names 315 if not names: 316 return None 317 values = reader.readStruct(self.format, self.size) 318 values = map(int, values) 319 valueRecord = ValueRecord() 320 items = map(None, names, values) 321 for (name, isDevice), value in items: 322 if isDevice: 323 if value: 324 device = otCommon.DeviceTable() 325 device.decompile(reader.getSubString(value), otFont) 326 else: 327 device = None 328 setattr(valueRecord, name, device) 329 else: 330 setattr(valueRecord, name, value) 331 return valueRecord 332 333 def writeValuerecord(self, valueRecord, writer, otFont): 334 values = [] 335 for (name, isDevice) in self.names: 336 if isDevice: 337 raise NotImplementedError 338 else: 339 values.append(valueRecord.__dict__.get(name, 0)) 340 writer.writeStruct(self.format, tuple(values)) 341 342 343class ValueRecord: 344 # see ValueRecordFactory 345 346 def getFormat(self): 347 format = 0 348 for name in self.__dict__.keys(): 349 format = format | valueRecordFormatDict[name][0] 350 return format 351 352 def toXML(self, xmlWriter, otFont): 353 simpleItems = [] 354 for mask, name, isDevice, format in valueRecordFormat[:4]: # "simple" values 355 if hasattr(self, name): 356 simpleItems.append((name, getattr(self, name))) 357 deviceItems = [] 358 for mask, name, isDevice, format in valueRecordFormat[4:8]: # device records 359 if hasattr(self, name): 360 deviceItems.append((name, getattr(self, name))) 361 if deviceItems: 362 xmlWriter.begintag("Value", simpleItems) 363 xmlWriter.newline() 364 for name, deviceRecord in deviceItems: 365 xxx 366 xmlWriter.endtag("Value") 367 else: 368 xmlWriter.simpletag("Value", simpleItems) 369 370 def __repr__(self): 371 return "<ValueRecord>" 372 373 374lookupTypeClasses = { 375 1: SinglePos, 376 2: PairPos, 377 3: CursivePos, 378 4: MarkBasePos, 379 5: MarkLigPos, 380 6: MarkMarkPos, 381 7: ContextPos, 382 8: ChainContextPos, 383} 384 385