def setupTable_head(self): """ Make the head table. **This should not be called externally.** Subclasses may override or supplement this method to handle the table creation in a different way if desired. """ self.otf["head"] = head = newTable("head") font = self.ufo head.checkSumAdjustment = 0 head.tableVersion = 1.0 head.magicNumber = 0x5F0F3CF5 # version numbers # limit minor version to 3 digits as recommended in OpenType spec: # https://www.microsoft.com/typography/otspec/recom.htm versionMajor = getAttrWithFallback(font.info, "versionMajor") versionMinor = getAttrWithFallback(font.info, "versionMinor") fullFontRevision = float("%d.%03d" % (versionMajor, versionMinor)) head.fontRevision = round(fullFontRevision, 3) if head.fontRevision != fullFontRevision: print("Minor version in %s has too many digits and won't fit into " "the head table's fontRevision field; rounded to %s." % (fullFontRevision, head.fontRevision)) # upm head.unitsPerEm = getAttrWithFallback(font.info, "unitsPerEm") # times head.created = dateStringToTimeValue(getAttrWithFallback(font.info, "openTypeHeadCreated")) - mac_epoch_diff head.modified = dateStringToTimeValue(dateStringForNow()) - mac_epoch_diff # bounding box xMin, yMin, xMax, yMax = self.fontBoundingBox head.xMin = xMin head.yMin = yMin head.xMax = xMax head.yMax = yMax # style mapping styleMapStyleName = getAttrWithFallback(font.info, "styleMapStyleName") macStyle = [] if styleMapStyleName == "bold": macStyle = [0] elif styleMapStyleName == "bold italic": macStyle = [0, 1] elif styleMapStyleName == "italic": macStyle = [1] head.macStyle = intListToNum(macStyle, 0, 16) # misc head.flags = intListToNum(getAttrWithFallback(font.info, "openTypeHeadFlags"), 0, 16) head.lowestRecPPEM = _roundInt(getAttrWithFallback(font.info, "openTypeHeadLowestRecPPEM")) head.fontDirectionHint = 2 head.indexToLocFormat = 0 head.glyphDataFormat = 0
def test_calcCodePageRanges(emptyufo, unicodes, expected): font = emptyufo for i, c in enumerate(unicodes): font.newGlyph("glyph%d" % i).unicode = ord(c) compiler = OutlineOTFCompiler(font) compiler.compile() assert compiler.otf["OS/2"].ulCodePageRange1 == intListToNum(expected, start=0, length=32) assert compiler.otf["OS/2"].ulCodePageRange2 == intListToNum(expected, start=32, length=32)
def setupTable_gasp(self): self.otf["gasp"] = gasp = newTable("gasp") gasp_ranges = dict() for record in self.ufo.info.openTypeGaspRangeRecords: rangeMaxPPEM = record["rangeMaxPPEM"] behavior_bits = record["rangeGaspBehavior"] rangeGaspBehavior = intListToNum(behavior_bits, 0, 4) gasp_ranges[rangeMaxPPEM] = rangeGaspBehavior gasp.gaspRange = gasp_ranges
def setupTable_OS2(self): """ Make the OS/2 table. **This should not be called externally.** Subclasses may override or supplement this method to handle the table creation in a different way if desired. """ self.otf["OS/2"] = os2 = newTable("OS/2") font = self.ufo os2.version = 0x0004 # average glyph width widths = [ glyph.width for glyph in self.allGlyphs.values() if glyph.width > 0 ] os2.xAvgCharWidth = _roundInt(sum(widths) / len(widths)) # weight and width classes os2.usWeightClass = getAttrWithFallback(font.info, "openTypeOS2WeightClass") os2.usWidthClass = getAttrWithFallback(font.info, "openTypeOS2WidthClass") # embedding os2.fsType = intListToNum( getAttrWithFallback(font.info, "openTypeOS2Type"), 0, 16) # subscript, superscript, strikeout values, taken from AFDKO: # FDK/Tools/Programs/makeotf/makeotf_lib/source/hotconv/hot.c unitsPerEm = getAttrWithFallback(font.info, "unitsPerEm") italicAngle = getAttrWithFallback(font.info, "italicAngle") xHeight = getAttrWithFallback(font.info, "xHeight") def adjustOffset(offset, angle): """Adjust Y offset based on italic angle, to get X offset.""" return offset * math.tan(math.radians(-angle)) if angle else 0 v = getAttrWithFallback(font.info, "openTypeOS2SubscriptXSize") if v is None: v = unitsPerEm * 0.65 os2.ySubscriptXSize = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2SubscriptYSize") if v is None: v = unitsPerEm * 0.6 os2.ySubscriptYSize = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2SubscriptYOffset") if v is None: v = unitsPerEm * 0.075 os2.ySubscriptYOffset = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2SubscriptXOffset") if v is None: v = adjustOffset(-os2.ySubscriptYOffset, italicAngle) os2.ySubscriptXOffset = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2SuperscriptXSize") if v is None: v = os2.ySubscriptXSize os2.ySuperscriptXSize = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2SuperscriptYSize") if v is None: v = os2.ySubscriptYSize os2.ySuperscriptYSize = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2SuperscriptYOffset") if v is None: v = unitsPerEm * 0.35 os2.ySuperscriptYOffset = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2SuperscriptXOffset") if v is None: v = adjustOffset(os2.ySuperscriptYOffset, italicAngle) os2.ySuperscriptXOffset = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2StrikeoutSize") if v is None: v = getAttrWithFallback(font.info, "postscriptUnderlineThickness") os2.yStrikeoutSize = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2StrikeoutPosition") if v is None: v = xHeight * 0.6 if xHeight else unitsPerEm * 0.22 os2.yStrikeoutPosition = _roundInt(v) # family class ibmFontClass, ibmFontSubclass = getAttrWithFallback( font.info, "openTypeOS2FamilyClass") os2.sFamilyClass = (ibmFontClass << 8) + ibmFontSubclass # panose data = getAttrWithFallback(font.info, "openTypeOS2Panose") panose = Panose() panose.bFamilyType = data[0] panose.bSerifStyle = data[1] panose.bWeight = data[2] panose.bProportion = data[3] panose.bContrast = data[4] panose.bStrokeVariation = data[5] panose.bArmStyle = data[6] panose.bLetterForm = data[7] panose.bMidline = data[8] panose.bXHeight = data[9] os2.panose = panose # Unicode ranges uniRanges = getAttrWithFallback(font.info, "openTypeOS2UnicodeRanges") os2.ulUnicodeRange1 = intListToNum(uniRanges, 0, 32) os2.ulUnicodeRange2 = intListToNum(uniRanges, 32, 32) os2.ulUnicodeRange3 = intListToNum(uniRanges, 64, 32) os2.ulUnicodeRange4 = intListToNum(uniRanges, 96, 32) # codepage ranges codepageRanges = getAttrWithFallback(font.info, "openTypeOS2CodePageRanges") os2.ulCodePageRange1 = intListToNum(codepageRanges, 0, 32) os2.ulCodePageRange2 = intListToNum(codepageRanges, 32, 32) # vendor id os2.achVendID = tounicode(getAttrWithFallback(font.info, "openTypeOS2VendorID"), encoding="ascii", errors="ignore") # vertical metrics os2.sxHeight = _roundInt(getAttrWithFallback(font.info, "xHeight")) os2.sCapHeight = _roundInt(getAttrWithFallback(font.info, "capHeight")) os2.sTypoAscender = _roundInt( getAttrWithFallback(font.info, "openTypeOS2TypoAscender")) os2.sTypoDescender = _roundInt( getAttrWithFallback(font.info, "openTypeOS2TypoDescender")) os2.sTypoLineGap = _roundInt( getAttrWithFallback(font.info, "openTypeOS2TypoLineGap")) os2.usWinAscent = _roundInt( getAttrWithFallback(font.info, "openTypeOS2WinAscent")) os2.usWinDescent = _roundInt( getAttrWithFallback(font.info, "openTypeOS2WinDescent")) # style mapping selection = list(getAttrWithFallback(font.info, "openTypeOS2Selection")) styleMapStyleName = getAttrWithFallback(font.info, "styleMapStyleName") if styleMapStyleName == "regular": selection.append(6) elif styleMapStyleName == "bold": selection.append(5) elif styleMapStyleName == "italic": selection.append(0) elif styleMapStyleName == "bold italic": selection += [0, 5] os2.fsSelection = intListToNum(selection, 0, 16) # characetr indexes unicodes = [ i for i in self.unicodeToGlyphNameMapping.keys() if i is not None ] if unicodes: minIndex = min(unicodes) maxIndex = max(unicodes) else: # the font may have *no* unicode values (it really happens!) so # there needs to be a fallback. use 0xFFFF, as AFDKO does: # FDK/Tools/Programs/makeotf/makeotf_lib/source/hotconv/map.c minIndex = 0xFFFF maxIndex = 0xFFFF if maxIndex > 0xFFFF: # the spec says that 0xFFFF should be used # as the max if the max exceeds 0xFFFF maxIndex = 0xFFFF os2.fsFirstCharIndex = minIndex os2.fsLastCharIndex = maxIndex os2.usBreakChar = 32 os2.usDefaultChar = 0 # maximum contextual lookup length os2.usMaxContex = 0
def setupTable_OS2(self): """ Make the OS/2 table. **This should not be called externally.** Subclasses may override or supplement this method to handle the table creation in a different way if desired. """ self.otf["OS/2"] = os2 = newTable("OS/2") font = self.ufo os2.version = 0x0004 # average glyph width widths = [glyph.width for glyph in self.allGlyphs.values() if glyph.width > 0] os2.xAvgCharWidth = _roundInt(sum(widths) / len(widths)) # weight and width classes os2.usWeightClass = getAttrWithFallback(font.info, "openTypeOS2WeightClass") os2.usWidthClass = getAttrWithFallback(font.info, "openTypeOS2WidthClass") # embedding os2.fsType = intListToNum(getAttrWithFallback(font.info, "openTypeOS2Type"), 0, 16) # subscript v = getAttrWithFallback(font.info, "openTypeOS2SubscriptXSize") if v is None: v = 0 os2.ySubscriptXSize = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2SubscriptYSize") if v is None: v = 0 os2.ySubscriptYSize = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2SubscriptXOffset") if v is None: v = 0 os2.ySubscriptXOffset = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2SubscriptYOffset") if v is None: v = 0 os2.ySubscriptYOffset = _roundInt(v) # superscript v = getAttrWithFallback(font.info, "openTypeOS2SuperscriptXSize") if v is None: v = 0 os2.ySuperscriptXSize = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2SuperscriptYSize") if v is None: v = 0 os2.ySuperscriptYSize = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2SuperscriptXOffset") if v is None: v = 0 os2.ySuperscriptXOffset = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2SuperscriptYOffset") if v is None: v = 0 os2.ySuperscriptYOffset = _roundInt(v) # strikeout v = getAttrWithFallback(font.info, "openTypeOS2StrikeoutSize") if v is None: v = 0 os2.yStrikeoutSize = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2StrikeoutPosition") if v is None: v = 0 os2.yStrikeoutPosition = _roundInt(v) # family class ibmFontClass, ibmFontSubclass = getAttrWithFallback( font.info, "openTypeOS2FamilyClass") os2.sFamilyClass = (ibmFontClass << 8) + ibmFontSubclass # panose data = getAttrWithFallback(font.info, "openTypeOS2Panose") panose = Panose() panose.bFamilyType = data[0] panose.bSerifStyle = data[1] panose.bWeight = data[2] panose.bProportion = data[3] panose.bContrast = data[4] panose.bStrokeVariation = data[5] panose.bArmStyle = data[6] panose.bLetterForm = data[7] panose.bMidline = data[8] panose.bXHeight = data[9] os2.panose = panose # Unicode ranges uniRanges = getAttrWithFallback(font.info, "openTypeOS2UnicodeRanges") os2.ulUnicodeRange1 = intListToNum(uniRanges, 0, 32) os2.ulUnicodeRange2 = intListToNum(uniRanges, 32, 32) os2.ulUnicodeRange3 = intListToNum(uniRanges, 64, 32) os2.ulUnicodeRange4 = intListToNum(uniRanges, 96, 32) # codepage ranges codepageRanges = getAttrWithFallback(font.info, "openTypeOS2CodePageRanges") os2.ulCodePageRange1 = intListToNum(codepageRanges, 0, 32) os2.ulCodePageRange2 = intListToNum(codepageRanges, 32, 32) # vendor id os2.achVendID = tounicode( getAttrWithFallback(font.info, "openTypeOS2VendorID"), encoding="ascii", errors="ignore") # vertical metrics os2.sxHeight = _roundInt(getAttrWithFallback(font.info, "xHeight")) os2.sCapHeight = _roundInt(getAttrWithFallback(font.info, "capHeight")) os2.sTypoAscender = _roundInt(getAttrWithFallback(font.info, "openTypeOS2TypoAscender")) os2.sTypoDescender = _roundInt(getAttrWithFallback(font.info, "openTypeOS2TypoDescender")) os2.sTypoLineGap = _roundInt(getAttrWithFallback(font.info, "openTypeOS2TypoLineGap")) os2.usWinAscent = _roundInt(getAttrWithFallback(font.info, "openTypeOS2WinAscent")) os2.usWinDescent = _roundInt(getAttrWithFallback(font.info, "openTypeOS2WinDescent")) # style mapping selection = list(getAttrWithFallback(font.info, "openTypeOS2Selection")) styleMapStyleName = getAttrWithFallback(font.info, "styleMapStyleName") if styleMapStyleName == "regular": selection.append(6) elif styleMapStyleName == "bold": selection.append(5) elif styleMapStyleName == "italic": selection.append(0) elif styleMapStyleName == "bold italic": selection += [0, 5] os2.fsSelection = intListToNum(selection, 0, 16) # characetr indexes unicodes = [i for i in self.unicodeToGlyphNameMapping.keys() if i is not None] if unicodes: minIndex = min(unicodes) maxIndex = max(unicodes) else: # the font may have *no* unicode values # (it really happens!) so there needs # to be a fallback. use space for this. minIndex = 0x0020 maxIndex = 0x0020 if maxIndex > 0xFFFF: # the spec says that 0xFFFF should be used # as the max if the max exceeds 0xFFFF maxIndex = 0xFFFF os2.fsFirstCharIndex = minIndex os2.fsLastCharIndex = maxIndex os2.usBreakChar = 32 os2.usDefaultChar = 0 # maximum contextual lookup length os2.usMaxContex = 0