Example #1
0
    def makeMissingRequiredGlyphs(self):
        """
        Add space and .notdef to the font if they are not present.

        **This should not be called externally.** Subclasses
        may override this method to handle the glyph creation
        in a different way if desired.
        """
        glyphs = {}
        font = self.ufo
        unitsPerEm = _roundInt(getAttrWithFallback(font.info, "unitsPerEm"))
        ascender = _roundInt(getAttrWithFallback(font.info, "ascender"))
        descender = _roundInt(getAttrWithFallback(font.info, "descender"))
        defaultWidth = _roundInt(unitsPerEm * 0.5)
        if ".notdef" not in self.ufo:
            glyphs[".notdef"] = StubGlyph(name=".notdef",
                                          width=defaultWidth,
                                          unitsPerEm=unitsPerEm,
                                          ascender=ascender,
                                          descender=descender)
        if "space" not in self.ufo:
            glyphs["space"] = StubGlyph(name="space",
                                        width=defaultWidth,
                                        unitsPerEm=unitsPerEm,
                                        ascender=ascender,
                                        descender=descender,
                                        unicodes=[32])
        return glyphs
Example #2
0
    def setupTable_post(self):
        """
        Make the post 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["post"] = post = newTable("post")
        font = self.ufo
        post.formatType = 3.0
        # italic angle
        italicAngle = getAttrWithFallback(font.info, "italicAngle")
        post.italicAngle = italicAngle
        # underline
        underlinePosition = getAttrWithFallback(font.info, "postscriptUnderlinePosition")
        if underlinePosition is None:
            underlinePosition = 0
        post.underlinePosition = _roundInt(underlinePosition)
        underlineThickness = getAttrWithFallback(font.info, "postscriptUnderlineThickness")
        if underlineThickness is None:
            underlineThickness = 0
        post.underlineThickness = _roundInt(underlineThickness)
        # determine if the font has a fixed width
        widths = set([glyph.width for glyph in self.allGlyphs.values()])
        post.isFixedPitch = getAttrWithFallback(font.info, "postscriptIsFixedPitch")
        # misc
        post.minMemType42 = 0
        post.maxMemType42 = 0
        post.minMemType1 = 0
        post.maxMemType1 = 0
Example #3
0
    def writeFeatures_hhea(self):
        """
        Write the hhea to a string and return it.

        This gets the values for the file using the fallback
        system as described below:

        ===========  ===
        Ascender     openTypeHheaAscender
        Descender    openTypeHheaDescender
        LineGap      openTypeHheaLineGap
        CaretOffset  openTypeHheaCaretOffset
        ===========  ===

        **This should not be called externally.** Subclasses
        may override this method to handle the string creation
        in a different way if desired.
        """
        ascender = getAttrWithFallback(self.font.info, "openTypeHheaAscender")
        descender = getAttrWithFallback(self.font.info,
                                        "openTypeHheaDescender")
        lineGap = getAttrWithFallback(self.font.info, "openTypeHheaLineGap")
        caret = getAttrWithFallback(self.font.info, "openTypeHheaCaretOffset")
        writer = FeatureTableWriter("hhea")
        writer.addLineWithKeyValue("Ascender", _roundInt(ascender))
        writer.addLineWithKeyValue("Descender", _roundInt(descender))
        writer.addLineWithKeyValue("LineGap", _roundInt(lineGap))
        writer.addLineWithKeyValue("CaretOffset", _roundInt(caret))
        return writer.write()
Example #4
0
    def writeFeatures_hhea(self):
        """
        Write the hhea to a string and return it.

        This gets the values for the file using the fallback
        system as described below:

        ===========  ===
        Ascender     openTypeHheaAscender
        Descender    openTypeHheaDescender
        LineGap      openTypeHheaLineGap
        CaretOffset  openTypeHheaCaretOffset
        ===========  ===

        **This should not be called externally.** Subclasses
        may override this method to handle the string creation
        in a different way if desired.
        """
        ascender = getAttrWithFallback(self.font.info, "openTypeHheaAscender")
        descender = getAttrWithFallback(self.font.info, "openTypeHheaDescender")
        lineGap = getAttrWithFallback(self.font.info, "openTypeHheaLineGap")
        caret = getAttrWithFallback(self.font.info, "openTypeHheaCaretOffset")
        writer = FeatureTableWriter("hhea")
        writer.addLineWithKeyValue("Ascender", _roundInt(ascender))
        writer.addLineWithKeyValue("Descender", _roundInt(descender))
        writer.addLineWithKeyValue("LineGap", _roundInt(lineGap))
        writer.addLineWithKeyValue("CaretOffset", _roundInt(caret))
        return writer.write()
Example #5
0
    def setupTable_post(self):
        """
        Make the post 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["post"] = post = newTable("post")
        font = self.ufo
        post.formatType = 3.0
        # italic angle
        italicAngle = getAttrWithFallback(font.info, "italicAngle")
        post.italicAngle = italicAngle
        # underline
        underlinePosition = getAttrWithFallback(font.info,
                                                "postscriptUnderlinePosition")
        if underlinePosition is None:
            underlinePosition = 0
        post.underlinePosition = _roundInt(underlinePosition)
        underlineThickness = getAttrWithFallback(
            font.info, "postscriptUnderlineThickness")
        if underlineThickness is None:
            underlineThickness = 0
        post.underlineThickness = _roundInt(underlineThickness)
        # determine if the font has a fixed width
        post.isFixedPitch = getAttrWithFallback(font.info,
                                                "postscriptIsFixedPitch")
        # misc
        post.minMemType42 = 0
        post.maxMemType42 = 0
        post.minMemType1 = 0
        post.maxMemType1 = 0
Example #6
0
    def setupFile_menuName(self, path):
        """
        Make the menu name source file. This gets the values for
        the file using the fallback system as described below:

        ====  ===
        [PS]  postscriptFontName
        f=    openTypeNamePreferredFamilyName
        s=    openTypeNamePreferredSubfamilyName
        l=    styleMapFamilyName
        m=1,  openTypeNameCompatibleFullName
        ====  ===

        **This should not be called externally.** Subclasses
        may override this method to handle the file creation
        in a different way if desired.
        """
        psName = getAttrWithFallback(self.font.info, "postscriptFontName")
        lines = ["[%s]" % psName]
        # family name
        familyName = getAttrWithFallback(self.font.info,
                                         "openTypeNamePreferredFamilyName")
        encodedFamilyName = winStr(familyName)
        lines.append("f=%s" % encodedFamilyName)
        if encodedFamilyName != familyName:
            lines.append("f=1,%s" % macStr(familyName))
        # style name
        styleName = getAttrWithFallback(self.font.info,
                                        "openTypeNamePreferredSubfamilyName")
        encodedStyleName = winStr(styleName)
        lines.append("s=%s" % encodedStyleName)
        if encodedStyleName != styleName:
            lines.append("s=1,%s" % macStr(styleName))
        # compatible name
        winCompatible = getAttrWithFallback(self.font.info,
                                            "styleMapFamilyName")
        ## the second qualification here is in place for Mac Office <= 2004.
        ## in that app the menu name is pulled from name ID 18. the font
        ## may have standard naming data that combines to a length longer
        ## than the app can handle (see Adobe Tech Note #5088). the designer
        ## may have created a specific openTypeNameCompatibleFullName to
        ## get around this problem. sigh, old app bugs live long lives.
        if winCompatible != familyName or self.font.info.openTypeNameCompatibleFullName is not None:
            # windows
            l = "l=%s" % normalizeStringForPostscript(winCompatible)
            lines.append(l)
            # mac
            macCompatible = getAttrWithFallback(
                self.font.info, "openTypeNameCompatibleFullName")
            l = "m=1,%s" % macStr(macCompatible)
            lines.append(l)
        text = "\n".join(lines) + "\n"
        f = open(path, "wb")
        f.write(text)
        f.close()
Example #7
0
    def setupFile_menuName(self, path):
        """
        Make the menu name source file. This gets the values for
        the file using the fallback system as described below:

        ====  ===
        [PS]  postscriptFontName
        f=    openTypeNamePreferredFamilyName
        s=    openTypeNamePreferredSubfamilyName
        l=    styleMapFamilyName
        m=1,  openTypeNameCompatibleFullName
        ====  ===

        **This should not be called externally.** Subclasses
        may override this method to handle the file creation
        in a different way if desired.
        """
        psName = getAttrWithFallback(self.font.info,"postscriptFontName")
        lines = [
            "[%s]" % psName
        ]
        # family name
        familyName = getAttrWithFallback(self.font.info,"openTypeNamePreferredFamilyName")
        encodedFamilyName = winStr(familyName)
        lines.append("f=%s" % encodedFamilyName)
        if encodedFamilyName != familyName:
            lines.append("f=1,%s" % macStr(familyName))
        # style name
        styleName = getAttrWithFallback(self.font.info,"openTypeNamePreferredSubfamilyName")
        encodedStyleName = winStr(styleName)
        lines.append("s=%s" % encodedStyleName)
        if encodedStyleName != styleName:
            lines.append("s=1,%s" % macStr(styleName))
        # compatible name
        winCompatible = getAttrWithFallback(self.font.info,"styleMapFamilyName")
        ## the second qualification here is in place for Mac Office <= 2004.
        ## in that app the menu name is pulled from name ID 18. the font
        ## may have standard naming data that combines to a length longer
        ## than the app can handle (see Adobe Tech Note #5088). the designer
        ## may have created a specific openTypeNameCompatibleFullName to
        ## get around this problem. sigh, old app bugs live long lives.
        if winCompatible != familyName or self.font.info.openTypeNameCompatibleFullName is not None:
            # windows
            l = "l=%s" % normalizeStringForPostscript(winCompatible)
            lines.append(l)
            # mac
            macCompatible = getAttrWithFallback(self.font.info,"openTypeNameCompatibleFullName")
            l = "m=1,%s" % macStr(macCompatible)
            lines.append(l)
        text = "\n".join(lines) + "\n"
        f = open(path, "wb")
        f.write(text)
        f.close()
Example #8
0
    def setupFile_fontInfo(self, path):
        """
        Make the font info source file. This gets the values for
        the file using the fallback system as described below:

        ==========================  ===
        IsItalicStyle               styleMapStyleName
        IsBoldStyle                 styleMapStyleName
        PreferOS/2TypoMetrics       openTypeOS2Selection
        IsOS/2WidthWeigthSlopeOnly  openTypeOS2Selection
        IsOS/2OBLIQUE               openTypeOS2Selection
        ==========================  ===

        **This should not be called externally.** Subclasses
        may override this method to handle the file creation
        in a different way if desired.
        """
        lines = []
        # style mapping
        styleMapStyleName = getAttrWithFallback(self.font.info,
                                                "styleMapStyleName")
        if styleMapStyleName in ("italic", "bold italic"):
            lines.append("IsItalicStyle true")
        else:
            lines.append("IsItalicStyle false")
        if styleMapStyleName in ("bold", "bold italic"):
            lines.append("IsBoldStyle true")
        else:
            lines.append("IsBoldStyle false")
        # fsSelection bits
        selection = getAttrWithFallback(self.font.info, "openTypeOS2Selection")
        if 7 in selection:
            lines.append("PreferOS/2TypoMetrics true")
        else:
            lines.append("PreferOS/2TypoMetrics false")
        if 8 in selection:
            lines.append("IsOS/2WidthWeigthSlopeOnly true")
        else:
            lines.append("IsOS/2WidthWeigthSlopeOnly false")
        if 9 in selection:
            lines.append("IsOS/2OBLIQUE true")
        else:
            lines.append("IsOS/2OBLIQUE false")
        # write the file
        if lines:
            f = open(path, "wb")
            f.write("\n".join(lines))
            f.close()
Example #9
0
    def setupFile_fontInfo(self, path):
        """
        Make the font info source file. This gets the values for
        the file using the fallback system as described below:

        ==========================  ===
        IsItalicStyle               styleMapStyleName
        IsBoldStyle                 styleMapStyleName
        PreferOS/2TypoMetrics       openTypeOS2Selection
        IsOS/2WidthWeigthSlopeOnly  openTypeOS2Selection
        IsOS/2OBLIQUE               openTypeOS2Selection
        ==========================  ===

        **This should not be called externally.** Subclasses
        may override this method to handle the file creation
        in a different way if desired.
        """
        lines = []
        # style mapping
        styleMapStyleName = getAttrWithFallback(self.font.info,"styleMapStyleName")
        if styleMapStyleName in ("italic", "bold italic"):
            lines.append("IsItalicStyle true")
        else:
            lines.append("IsItalicStyle false")
        if styleMapStyleName in ("bold", "bold italic"):
            lines.append("IsBoldStyle true")
        else:
            lines.append("IsBoldStyle false")
        # fsSelection bits
        selection = getAttrWithFallback(self.font.info,"openTypeOS2Selection")
        if 7 in selection:
            lines.append("PreferOS/2TypoMetrics true")
        else:
            lines.append("PreferOS/2TypoMetrics false")
        if 8 in selection:
            lines.append("IsOS/2WidthWeigthSlopeOnly true")
        else:
            lines.append("IsOS/2WidthWeigthSlopeOnly false")
        if 9 in selection:
            lines.append("IsOS/2OBLIQUE true")
        else:
            lines.append("IsOS/2OBLIQUE false")
        # write the file
        if lines:
            f = open(path, "wb")
            f.write("\n".join(lines))
            f.close()
Example #10
0
    def makeMissingRequiredGlyphs(self):
        """
        Add space and .notdef to the font if they are not present.

        **This should not be called externally.** Subclasses
        may override this method to handle the glyph creation
        in a different way if desired.
        """
        glyphs = {}
        font = self.ufo
        unitsPerEm = _roundInt(getAttrWithFallback(font.info, "unitsPerEm"))
        ascender = _roundInt(getAttrWithFallback(font.info, "ascender"))
        descender = _roundInt(getAttrWithFallback(font.info, "descender"))
        defaultWidth = _roundInt(unitsPerEm * 0.5)
        if ".notdef" not in self.ufo:
            glyphs[".notdef"] = StubGlyph(name=".notdef", width=defaultWidth, unitsPerEm=unitsPerEm, ascender=ascender, descender=descender)
        if "space" not in self.ufo:
            glyphs["space"] = StubGlyph(name="space", width=defaultWidth, unitsPerEm=unitsPerEm, ascender=ascender, descender=descender, unicodes=[32])
        return glyphs
Example #11
0
    def writeFeatures_head(self):
        """
        Write the head to a string and return it.

        This gets the values for the file using the fallback
        system as described below:

        =====  ===
        X.XXX  versionMajor.versionMinor
        =====  ===

        **This should not be called externally.** Subclasses
        may override this method to handle the string creation
        in a different way if desired.
        """
        versionMajor = getAttrWithFallback(self.font.info, "versionMajor")
        versionMinor = getAttrWithFallback(self.font.info, "versionMinor")
        value = "%d.%s" % (versionMajor, str(versionMinor).zfill(3))
        writer = FeatureTableWriter("head")
        writer.addLineWithKeyValue("FontRevision", value)
        return writer.write()
Example #12
0
    def writeFeatures_head(self):
        """
        Write the head to a string and return it.

        This gets the values for the file using the fallback
        system as described below:

        =====  ===
        X.XXX  versionMajor.versionMinor
        =====  ===

        **This should not be called externally.** Subclasses
        may override this method to handle the string creation
        in a different way if desired.
        """
        versionMajor = getAttrWithFallback(self.font.info, "versionMajor")
        versionMinor = getAttrWithFallback(self.font.info, "versionMinor")
        value = "%d.%s" % (versionMajor, str(versionMinor).zfill(3))
        writer = FeatureTableWriter("head")
        writer.addLineWithKeyValue("FontRevision", value)
        return writer.write()
Example #13
0
    def writeFeatures_name(self):
        """
        Write the name to a string and return it.

        This gets the values for the file using the fallback
        system as described below:

        =========  ===
        nameid 0   copyright
        nameid 7   trademark
        nameid 8   openTypeNameManufacturer
        nameid 9   openTypeNameDesigner
        nameid 10  openTypeNameDescription
        nameid 11  openTypeNameManufacturerURL
        nameid 12  openTypeNameDesignerURL
        nameid 13  openTypeNameLicense
        nameid 14  openTypeNameLicenseURL
        nameid 19  openTypeNameSampleText
        =========  ===

        **This should not be called externally.** Subclasses
        may override this method to handle the string creation
        in a different way if desired.
        """
        idToAttr = [
            (0  , "copyright"),
            (7  , "trademark"),
            (8  , "openTypeNameManufacturer"),
            (9  , "openTypeNameDesigner"),
            (10 , "openTypeNameDescription"),
            (11 , "openTypeNameManufacturerURL"),
            (12 , "openTypeNameDesignerURL"),
            (13 , "openTypeNameLicense"),
            (14 , "openTypeNameLicenseURL"),
            (19 , "openTypeNameSampleText")
        ]
        multilineNameTableEntries = {}
        lines = []
        for id, attr in idToAttr:
            value = getAttrWithFallback(self.font.info, attr)
            if value is None:
                continue
            s = 'nameid %d "%s";' % (id, winStr(value))
            lines.append(s)
            s = 'nameid %d 1 "%s";' % (id, macStr(value))
            lines.append(s)
        if not lines:
            return ""
        writer = FeatureTableWriter("name")
        for line in lines:
            writer.addLine(line)
        return writer.write()
Example #14
0
    def setupTable_hhea(self):
        """
        Make the hhea 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["hhea"] = hhea = newTable("hhea")
        font = self.ufo
        hhea.tableVersion = 1.0
        # vertical metrics
        hhea.ascent = _roundInt(getAttrWithFallback(font.info, "openTypeHheaAscender"))
        hhea.descent = _roundInt(getAttrWithFallback(font.info, "openTypeHheaDescender"))
        hhea.lineGap = _roundInt(getAttrWithFallback(font.info, "openTypeHheaLineGap"))
        # horizontal metrics
        widths = []
        lefts = []
        rights = []
        extents = []
        for glyph in self.allGlyphs.values():
            left = glyph.leftMargin
            right = glyph.rightMargin
            if left is None:
                left = 0
            if right is None:
                right = 0
            widths.append(glyph.width)
            lefts.append(left)
            rights.append(right)
            # robofab
            if hasattr(glyph, "box"):
                bounds = glyph.box
            # others
            else:
                bounds = glyph.bounds
            if bounds is not None:
                xMin, yMin, xMax, yMax = bounds
            else:
                xMin = 0
                xMax = 0
            extent = left + (xMax - xMin) # equation from spec for calculating xMaxExtent: Max(lsb + (xMax - xMin))
            extents.append(extent)
        hhea.advanceWidthMax = _roundInt(max(widths))
        hhea.minLeftSideBearing = _roundInt(min(lefts))
        hhea.minRightSideBearing = _roundInt(min(rights))
        hhea.xMaxExtent = _roundInt(max(extents))
        # misc
        hhea.caretSlopeRise = getAttrWithFallback(font.info, "openTypeHheaCaretSlopeRise")
        hhea.caretSlopeRun = getAttrWithFallback(font.info, "openTypeHheaCaretSlopeRun")
        hhea.caretOffset = _roundInt(getAttrWithFallback(font.info, "openTypeHheaCaretOffset"))
        hhea.reserved0 = 0
        hhea.reserved1 = 0
        hhea.reserved2 = 0
        hhea.reserved3 = 0
        hhea.metricDataFormat = 0
        # glyph count
        hhea.numberOfHMetrics = len(self.allGlyphs)
Example #15
0
    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
        versionMajor = getAttrWithFallback(font.info, "versionMajor")
        versionMinor = getAttrWithFallback(font.info, "versionMinor") * .001
        head.fontRevision = versionMajor + versionMinor
        head.magicNumber = 0x5F0F3CF5
        # 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
Example #16
0
    def getCharStringForGlyph(self, glyph, private, globalSubrs):
        """
        Get a Type2CharString for the *glyph*

        **This should not be called externally.** Subclasses
        may override this method to handle the charstring creation
        in a different way if desired.
        """
        width = glyph.width
        # subtract the nominal width
        postscriptNominalWidthX = getAttrWithFallback(self.ufo.info, "postscriptNominalWidthX")
        if postscriptNominalWidthX:
            width = width - postscriptNominalWidthX
        # round
        width = _roundInt(width)
        pen = T2CharStringPen(width, self.allGlyphs)
        glyph.draw(pen)
        charString = pen.getCharString(private, globalSubrs)
        return charString
Example #17
0
    def getCharStringForGlyph(self, glyph, private, globalSubrs):
        """
        Get a Type2CharString for the *glyph*

        **This should not be called externally.** Subclasses
        may override this method to handle the charstring creation
        in a different way if desired.
        """
        width = glyph.width
        # subtract the nominal width
        postscriptNominalWidthX = getAttrWithFallback(
            self.ufo.info, "postscriptNominalWidthX")
        if postscriptNominalWidthX:
            width = width - postscriptNominalWidthX
        # round
        width = _roundInt(width)
        pen = T2CharStringPen(width, self.allGlyphs)
        glyph.draw(pen)
        charString = pen.getCharString(private, globalSubrs)
        return charString
Example #18
0
    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
        versionMajor = getAttrWithFallback(font.info, "versionMajor")
        versionMinor = getAttrWithFallback(font.info, "versionMinor") * .001
        head.fontRevision = versionMajor + versionMinor
        head.magicNumber = 0x5F0F3CF5
        # 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
Example #19
0
    def setupTable_CFF(self):
        """
        Make the CFF 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["CFF "] = cff = newTable("CFF ")
        cff = cff.cff
        # set up the basics
        cff.major = 1
        cff.minor = 0
        cff.hdrSize = 4
        cff.offSize = 4
        cff.fontNames = []
        strings = IndexedStrings()
        cff.strings = strings
        private = PrivateDict(strings=strings)
        private.rawDict.update(private.defaults)
        globalSubrs = GlobalSubrsIndex(private=private)
        topDict = TopDict(GlobalSubrs=globalSubrs, strings=strings)
        topDict.Private = private
        charStrings = topDict.CharStrings = CharStrings(
            file=None,
            charset=None,
            globalSubrs=globalSubrs,
            private=private,
            fdSelect=None,
            fdArray=None)
        charStrings.charStringsAreIndexed = True
        topDict.charset = []
        charStringsIndex = charStrings.charStringsIndex = SubrsIndex(
            private=private, globalSubrs=globalSubrs)
        cff.topDictIndex = topDictIndex = TopDictIndex()
        topDictIndex.append(topDict)
        topDictIndex.strings = strings
        cff.GlobalSubrs = globalSubrs
        # populate naming data
        info = self.ufo.info
        psName = getAttrWithFallback(info, "postscriptFontName")
        cff.fontNames.append(psName)
        topDict = cff.topDictIndex[0]
        topDict.version = "%d.%d" % (getAttrWithFallback(
            info, "versionMajor"), getAttrWithFallback(info, "versionMinor"))
        trademark = getAttrWithFallback(info, "trademark")
        if trademark:
            trademark = normalizeStringForPostscript(
                trademark.replace(u"\u00A9", "Copyright"))
        if trademark != self.ufo.info.trademark:
            self.log.append(
                "[Warning] The trademark was normalized for storage in the CFF table and consequently some characters were dropped: '%s'"
                % trademark)
        if trademark is None:
            trademark = ""
        topDict.Notice = trademark
        copyright = getAttrWithFallback(info, "copyright")
        if copyright:
            copyright = normalizeStringForPostscript(
                copyright.replace(u"\u00A9", "Copyright"))
        if copyright != self.ufo.info.copyright:
            self.log.append(
                "[Warning] The copyright was normalized for storage in the CFF table and consequently some characters were dropped: '%s'"
                % copyright)
        if copyright is None:
            copyright = ""
        topDict.Copyright = copyright
        topDict.FullName = getAttrWithFallback(info, "postscriptFullName")
        topDict.FamilyName = getAttrWithFallback(
            info, "openTypeNamePreferredFamilyName")
        topDict.Weight = getAttrWithFallback(info, "postscriptWeightName")
        topDict.FontName = getAttrWithFallback(info, "postscriptFontName")
        # populate various numbers
        topDict.isFixedPitch = getAttrWithFallback(info,
                                                   "postscriptIsFixedPitch")
        topDict.ItalicAngle = getAttrWithFallback(info, "italicAngle")
        underlinePosition = getAttrWithFallback(info,
                                                "postscriptUnderlinePosition")
        if underlinePosition is None:
            underlinePosition = 0
        topDict.UnderlinePosition = _roundInt(underlinePosition)
        underlineThickness = getAttrWithFallback(
            info, "postscriptUnderlineThickness")
        if underlineThickness is None:
            underlineThickness = 0
        topDict.UnderlineThickness = _roundInt(underlineThickness)
        # populate font matrix
        unitsPerEm = _roundInt(getAttrWithFallback(info, "unitsPerEm"))
        topDict.FontMatrix = [1.0 / unitsPerEm, 0, 0, 1.0 / unitsPerEm, 0, 0]
        # populate the width values
        defaultWidthX = _roundInt(
            getAttrWithFallback(info, "postscriptDefaultWidthX"))
        if defaultWidthX:
            private.rawDict["defaultWidthX"] = defaultWidthX
        nominalWidthX = _roundInt(
            getAttrWithFallback(info, "postscriptNominalWidthX"))
        if nominalWidthX:
            private.rawDict["nominalWidthX"] = nominalWidthX
        # populate hint data
        blueFuzz = _roundInt(getAttrWithFallback(info, "postscriptBlueFuzz"))
        blueShift = _roundInt(getAttrWithFallback(info, "postscriptBlueShift"))
        blueScale = getAttrWithFallback(info, "postscriptBlueScale")
        forceBold = getAttrWithFallback(info, "postscriptForceBold")
        blueValues = getAttrWithFallback(info, "postscriptBlueValues")
        if isinstance(blueValues, list):
            blueValues = [_roundInt(i) for i in blueValues]
        otherBlues = getAttrWithFallback(info, "postscriptOtherBlues")
        if isinstance(otherBlues, list):
            otherBlues = [_roundInt(i) for i in otherBlues]
        familyBlues = getAttrWithFallback(info, "postscriptFamilyBlues")
        if isinstance(familyBlues, list):
            familyBlues = [_roundInt(i) for i in familyBlues]
        familyOtherBlues = getAttrWithFallback(info,
                                               "postscriptFamilyOtherBlues")
        if isinstance(familyOtherBlues, list):
            familyOtherBlues = [_roundInt(i) for i in familyOtherBlues]
        stemSnapH = getAttrWithFallback(info, "postscriptStemSnapH")
        if isinstance(stemSnapH, list):
            stemSnapH = [_roundInt(i) for i in stemSnapH]
        stemSnapV = getAttrWithFallback(info, "postscriptStemSnapV")
        if isinstance(stemSnapV, list):
            stemSnapV = [_roundInt(i) for i in stemSnapV]
        # only write the blues data if some blues are defined.
        if (blueValues or otherBlues):
            private.rawDict["BlueFuzz"] = blueFuzz
            private.rawDict["BlueShift"] = blueShift
            private.rawDict["BlueScale"] = blueScale
            private.rawDict["ForceBold"] = forceBold
            private.rawDict["BlueValues"] = blueValues
            private.rawDict["OtherBlues"] = otherBlues
            private.rawDict["FamilyBlues"] = familyBlues
            private.rawDict["FamilyOtherBlues"] = familyOtherBlues
        # only write the stems if both are defined.
        if (stemSnapH and stemSnapV):
            private.rawDict["StemSnapH"] = stemSnapH
            private.rawDict["StdHW"] = stemSnapH[0]
            private.rawDict["StemSnapV"] = stemSnapV
            private.rawDict["StdVW"] = stemSnapV[0]
        # populate glyphs
        for glyphName in self.glyphOrder:
            glyph = self.allGlyphs[glyphName]
            unicodes = glyph.unicodes
            charString = self.getCharStringForGlyph(glyph, private,
                                                    globalSubrs)
            # add to the font
            exists = charStrings.has_key(glyphName)
            if exists:
                # XXX a glyph already has this name. should we choke?
                glyphID = charStrings.charStrings[glyphName]
                charStringsIndex.items[glyphID] = charString
            else:
                charStringsIndex.append(charString)
                glyphID = len(topDict.charset)
                charStrings.charStrings[glyphName] = glyphID
                topDict.charset.append(glyphName)
        topDict.FontBBox = self.fontBoundingBox
        # write the glyph order
        self.otf.setGlyphOrder(self.glyphOrder)
Example #20
0
    def writeFeatures_OS2(self):
        """
        Write the OS/2 to a string and return it.

        This gets the values for the file using the fallback
        system as described below:

        =============  ===
        FSType         openTypeOS2Type
        Panose         openTypeOS2Panose
        UnicodeRange   openTypeOS2UnicodeRanges
        CodePageRange  openTypeOS2CodePageRanges
        TypoAscender   openTypeOS2TypoAscender
        TypoDescender  openTypeOS2TypoDescender
        TypoLineGap    openTypeOS2TypoLineGap
        winAscent      openTypeOS2WinAscent
        winDescent     openTypeOS2WinDescent
        XHeight        xHeight
        CapHeight      capHeight
        WeightClass    openTypeOS2WeightClass
        WidthClass     openTypeOS2WidthClass
        Vendor         openTypeOS2VendorID
        =============  ===

        **This should not be called externally.** Subclasses
        may override this method to handle the string creation
        in a different way if desired.
        """
        codePageBitTranslation = {
            0  : "1252",
            1  : "1250",
            2  : "1251",
            3  : "1253",
            4  : "1254",
            5  : "1255",
            6  : "1256",
            7  : "1257",
            8  : "1258",
            16 : "874",
            17 : "932",
            18 : "936",
            19 : "949",
            20 : "950",
            21 : "1361",
            48 : "869",
            49 : "866",
            50 : "865",
            51 : "864",
            52 : "863",
            53 : "862",
            54 : "861",
            55 : "860",
            56 : "857",
            57 : "855",
            58 : "852",
            59 : "775",
            60 : "737",
            61 : "708",
            62 : "850",
            63 : "437"
        }
        # writer
        writer = FeatureTableWriter("OS/2")
        # type
        writer.addLineWithKeyValue("FSType", intListToNum(getAttrWithFallback(self.font.info, "openTypeOS2Type"), 0, 16))
        # panose
        panose = [str(i) for i in getAttrWithFallback(self.font.info, "openTypeOS2Panose")]
        writer.addLineWithKeyValue("Panose", " ".join(panose))
        # unicode ranges
        unicodeRange = [str(i) for i in getAttrWithFallback(self.font.info, "openTypeOS2UnicodeRanges")]
        if unicodeRange:
            writer.addLineWithKeyValue("UnicodeRange", " ".join(unicodeRange))
        # code page ranges
        codePageRange = [codePageBitTranslation[i] for i in getAttrWithFallback(self.font.info, "openTypeOS2CodePageRanges") if i in codePageBitTranslation]
        if codePageRange:
            writer.addLineWithKeyValue("CodePageRange", " ".join(codePageRange))
        # vertical metrics
        writer.addLineWithKeyValue("TypoAscender", _roundInt(getAttrWithFallback(self.font.info, "openTypeOS2TypoAscender")))
        writer.addLineWithKeyValue("TypoDescender", _roundInt(getAttrWithFallback(self.font.info, "openTypeOS2TypoDescender")))
        writer.addLineWithKeyValue("TypoLineGap", _roundInt(getAttrWithFallback(self.font.info, "openTypeOS2TypoLineGap")))
        writer.addLineWithKeyValue("winAscent", _roundInt(getAttrWithFallback(self.font.info, "openTypeOS2WinAscent")))
        writer.addLineWithKeyValue("winDescent", abs(_roundInt(getAttrWithFallback(self.font.info, "openTypeOS2WinDescent"))))
        writer.addLineWithKeyValue("XHeight", _roundInt(getAttrWithFallback(self.font.info, "xHeight")))
        writer.addLineWithKeyValue("CapHeight", _roundInt(getAttrWithFallback(self.font.info, "capHeight")))
        writer.addLineWithKeyValue("WeightClass", getAttrWithFallback(self.font.info, "openTypeOS2WeightClass"))
        writer.addLineWithKeyValue("WidthClass", getAttrWithFallback(self.font.info, "openTypeOS2WidthClass"))
        writer.addLineWithKeyValue("Vendor", '"%s"' % getAttrWithFallback(self.font.info, "openTypeOS2VendorID"))
        return writer.write()
Example #21
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
        os2.sFamilyClass = 0 # XXX not sure how to create the appropriate value
        # 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 = str(getAttrWithFallback(font.info, "openTypeOS2VendorID").decode("ascii", "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
Example #22
0
    def writeFeatures_OS2(self):
        """
        Write the OS/2 to a string and return it.

        This gets the values for the file using the fallback
        system as described below:

        =============  ===
        FSType         openTypeOS2Type
        Panose         openTypeOS2Panose
        UnicodeRange   openTypeOS2UnicodeRanges
        CodePageRange  openTypeOS2CodePageRanges
        TypoAscender   openTypeOS2TypoAscender
        TypoDescender  openTypeOS2TypoDescender
        TypoLineGap    openTypeOS2TypoLineGap
        winAscent      openTypeOS2WinAscent
        winDescent     openTypeOS2WinDescent
        XHeight        xHeight
        CapHeight      capHeight
        WeightClass    openTypeOS2WeightClass
        WidthClass     openTypeOS2WidthClass
        Vendor         openTypeOS2VendorID
        =============  ===

        **This should not be called externally.** Subclasses
        may override this method to handle the string creation
        in a different way if desired.
        """
        codePageBitTranslation = {
            0: "1252",
            1: "1250",
            2: "1251",
            3: "1253",
            4: "1254",
            5: "1255",
            6: "1256",
            7: "1257",
            8: "1258",
            16: "874",
            17: "932",
            18: "936",
            19: "949",
            20: "950",
            21: "1361",
            48: "869",
            49: "866",
            50: "865",
            51: "864",
            52: "863",
            53: "862",
            54: "861",
            55: "860",
            56: "857",
            57: "855",
            58: "852",
            59: "775",
            60: "737",
            61: "708",
            62: "850",
            63: "437"
        }
        # writer
        writer = FeatureTableWriter("OS/2")
        # type
        writer.addLineWithKeyValue(
            "FSType",
            intListToNum(
                getAttrWithFallback(self.font.info, "openTypeOS2Type"), 0, 16))
        # panose
        panose = [
            str(i)
            for i in getAttrWithFallback(self.font.info, "openTypeOS2Panose")
        ]
        writer.addLineWithKeyValue("Panose", " ".join(panose))
        # unicode ranges
        unicodeRange = [
            str(i) for i in getAttrWithFallback(self.font.info,
                                                "openTypeOS2UnicodeRanges")
        ]
        if unicodeRange:
            writer.addLineWithKeyValue("UnicodeRange", " ".join(unicodeRange))
        # code page ranges
        codePageRange = [
            codePageBitTranslation[i] for i in getAttrWithFallback(
                self.font.info, "openTypeOS2CodePageRanges")
            if i in codePageBitTranslation
        ]
        if codePageRange:
            writer.addLineWithKeyValue("CodePageRange",
                                       " ".join(codePageRange))
        # vertical metrics
        writer.addLineWithKeyValue(
            "TypoAscender",
            _roundInt(
                getAttrWithFallback(self.font.info,
                                    "openTypeOS2TypoAscender")))
        writer.addLineWithKeyValue(
            "TypoDescender",
            _roundInt(
                getAttrWithFallback(self.font.info,
                                    "openTypeOS2TypoDescender")))
        writer.addLineWithKeyValue(
            "TypoLineGap",
            _roundInt(
                getAttrWithFallback(self.font.info, "openTypeOS2TypoLineGap")))
        writer.addLineWithKeyValue(
            "winAscent",
            _roundInt(
                getAttrWithFallback(self.font.info, "openTypeOS2WinAscent")))
        writer.addLineWithKeyValue(
            "winDescent",
            abs(
                _roundInt(
                    getAttrWithFallback(self.font.info,
                                        "openTypeOS2WinDescent"))))
        writer.addLineWithKeyValue(
            "XHeight", _roundInt(getAttrWithFallback(self.font.info,
                                                     "xHeight")))
        writer.addLineWithKeyValue(
            "CapHeight",
            _roundInt(getAttrWithFallback(self.font.info, "capHeight")))
        writer.addLineWithKeyValue(
            "WeightClass",
            getAttrWithFallback(self.font.info, "openTypeOS2WeightClass"))
        writer.addLineWithKeyValue(
            "WidthClass",
            getAttrWithFallback(self.font.info, "openTypeOS2WidthClass"))
        writer.addLineWithKeyValue(
            "Vendor", '"%s"' %
            getAttrWithFallback(self.font.info, "openTypeOS2VendorID"))
        return writer.write()
Example #23
0
    def writeFeatures_name(self):
        """
        Write the name to a string and return it.

        This gets the values for the file using the fallback
        system as described below:

        =========  ===
        nameid 0   copyright
        nameid 7   trademark
        nameid 8   openTypeNameManufacturer
        nameid 9   openTypeNameDesigner
        nameid 10  openTypeNameDescription
        nameid 11  openTypeNameManufacturerURL
        nameid 12  openTypeNameDesignerURL
        nameid 13  openTypeNameLicense
        nameid 14  openTypeNameLicenseURL
        nameid 19  openTypeNameSampleText
        =========  ===

        **This should not be called externally.** Subclasses
        may override this method to handle the string creation
        in a different way if desired.
        """
        idToAttr = [(0, "copyright"), (7, "trademark"),
                    (8, "openTypeNameManufacturer"), (9,
                                                      "openTypeNameDesigner"),
                    (10, "openTypeNameDescription"),
                    (11, "openTypeNameManufacturerURL"),
                    (12, "openTypeNameDesignerURL"),
                    (13, "openTypeNameLicense"),
                    (14, "openTypeNameLicenseURL"),
                    (19, "openTypeNameSampleText")]
        multilineNameTableEntries = {}
        lines = []
        for id, attr in idToAttr:
            value = getAttrWithFallback(self.font.info, attr)
            if value is None:
                continue
            s = 'nameid %d "%s";' % (id, winStr(value))
            lines.append(s)
            s = 'nameid %d 1 "%s";' % (id, macStr(value))
            lines.append(s)
        if self.font.info.openTypeNameRecords is not None:
            for record in self.font.info.openTypeNameRecords:
                nameID = record["nameID"]
                if nameID >= 1 and nameID <= 6:
                    continue
                platformID = record["platformID"]
                encodingID = record["encodingID"]
                languageID = record["languageID"]
                string = record["string"]
                if platformID == 0:
                    string = macStr(string)
                else:
                    string = winStr(string)
                s = 'nameid %d %d %d %d "%s";' % (
                    nameID, platformID, encodingID, languageID, string)
                lines.append(s)
        if not lines:
            return ""
        writer = FeatureTableWriter("name")
        for line in lines:
            writer.addLine(line)
        return writer.write()
Example #24
0
    def setupTable_CFF(self):
        """
        Make the CFF 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["CFF "] = cff = newTable("CFF ")
        cff = cff.cff
        # set up the basics
        cff.major = 1
        cff.minor = 0
        cff.hdrSize = 4
        cff.offSize = 4
        cff.fontNames = []
        strings = IndexedStrings()
        cff.strings = strings
        private = PrivateDict(strings=strings)
        private.rawDict.update(private.defaults)
        globalSubrs = GlobalSubrsIndex(private=private)
        topDict = TopDict(GlobalSubrs=globalSubrs, strings=strings)
        topDict.Private = private
        charStrings = topDict.CharStrings = CharStrings(file=None, charset=None,
            globalSubrs=globalSubrs, private=private, fdSelect=None, fdArray=None)
        charStrings.charStringsAreIndexed = True
        topDict.charset = []
        charStringsIndex = charStrings.charStringsIndex = SubrsIndex(private=private, globalSubrs=globalSubrs)
        cff.topDictIndex = topDictIndex = TopDictIndex()
        topDictIndex.append(topDict)
        topDictIndex.strings = strings
        cff.GlobalSubrs = globalSubrs
        # populate naming data
        info = self.ufo.info
        psName = getAttrWithFallback(info, "postscriptFontName")
        cff.fontNames.append(psName)
        topDict = cff.topDictIndex[0]
        topDict.version = "%d.%d" % (getAttrWithFallback(info, "versionMajor"), getAttrWithFallback(info, "versionMinor"))
        trademark = getAttrWithFallback(info, "trademark")
        if trademark:
            trademark = normalizeStringForPostscript(trademark.replace(u"\u00A9", "Copyright"))
        if trademark != self.ufo.info.trademark:
            self.log.append("[Warning] The trademark was normalized for storage in the CFF table and consequently some characters were dropped: '%s'" % trademark)
        if trademark is None:
            trademark = ""
        topDict.Notice = trademark
        copyright = getAttrWithFallback(info, "copyright")
        if copyright:
            copyright = normalizeStringForPostscript(copyright.replace(u"\u00A9", "Copyright"))
        if copyright != self.ufo.info.copyright:
            self.log.append("[Warning] The copyright was normalized for storage in the CFF table and consequently some characters were dropped: '%s'" % copyright)
        if copyright is None:
            copyright = ""
        topDict.Copyright = copyright
        topDict.FullName = getAttrWithFallback(info, "postscriptFullName")
        topDict.FamilyName = getAttrWithFallback(info, "openTypeNamePreferredFamilyName")
        topDict.Weight = getAttrWithFallback(info, "postscriptWeightName")
        topDict.FontName = getAttrWithFallback(info, "postscriptFontName")
        # populate various numbers
        topDict.isFixedPitch = getAttrWithFallback(info, "postscriptIsFixedPitch")
        topDict.ItalicAngle = getAttrWithFallback(info, "italicAngle")
        underlinePosition = getAttrWithFallback(info, "postscriptUnderlinePosition")
        if underlinePosition is None:
            underlinePosition = 0
        topDict.UnderlinePosition = _roundInt(underlinePosition)
        underlineThickness = getAttrWithFallback(info, "postscriptUnderlineThickness")
        if underlineThickness is None:
            underlineThickness = 0
        topDict.UnderlineThickness = _roundInt(underlineThickness)
        # populate font matrix
        unitsPerEm = _roundInt(getAttrWithFallback(info, "unitsPerEm"))
        topDict.FontMatrix = [1.0 / unitsPerEm, 0, 0, 1.0 / unitsPerEm, 0, 0]
        # populate the width values
        defaultWidthX = _roundInt(getAttrWithFallback(info, "postscriptDefaultWidthX"))
        if defaultWidthX:
            private.rawDict["defaultWidthX"] = defaultWidthX
        nominalWidthX = _roundInt(getAttrWithFallback(info, "postscriptNominalWidthX"))
        if nominalWidthX:
            private.rawDict["nominalWidthX"] = nominalWidthX
        # populate hint data
        blueFuzz = _roundInt(getAttrWithFallback(info, "postscriptBlueFuzz"))
        blueShift = _roundInt(getAttrWithFallback(info, "postscriptBlueShift"))
        blueScale = getAttrWithFallback(info, "postscriptBlueScale")
        forceBold = getAttrWithFallback(info, "postscriptForceBold")
        blueValues = getAttrWithFallback(info, "postscriptBlueValues")
        if isinstance(blueValues, list):
            blueValues = [_roundInt(i) for i in blueValues]
        otherBlues = getAttrWithFallback(info, "postscriptOtherBlues")
        if isinstance(otherBlues, list):
            otherBlues = [_roundInt(i) for i in otherBlues]
        familyBlues = getAttrWithFallback(info, "postscriptFamilyBlues")
        if isinstance(familyBlues, list):
            familyBlues = [_roundInt(i) for i in familyBlues]
        familyOtherBlues = getAttrWithFallback(info, "postscriptFamilyOtherBlues")
        if isinstance(familyOtherBlues, list):
            familyOtherBlues = [_roundInt(i) for i in familyOtherBlues]
        stemSnapH = getAttrWithFallback(info, "postscriptStemSnapH")
        if isinstance(stemSnapH, list):
            stemSnapH = [_roundInt(i) for i in stemSnapH]
        stemSnapV = getAttrWithFallback(info, "postscriptStemSnapV")
        if isinstance(stemSnapV, list):
            stemSnapV = [_roundInt(i) for i in stemSnapV]
        # only write the blues data if some blues are defined.
        if (blueValues or otherBlues):
            private.rawDict["BlueFuzz"] = blueFuzz
            private.rawDict["BlueShift"] = blueShift
            private.rawDict["BlueScale"] = blueScale
            private.rawDict["ForceBold"] = forceBold
            private.rawDict["BlueValues"] = blueValues
            private.rawDict["OtherBlues"] = otherBlues
            private.rawDict["FamilyBlues"] = familyBlues
            private.rawDict["FamilyOtherBlues"] = familyOtherBlues
        # only write the stems if both are defined.
        if (stemSnapH and stemSnapV):
            private.rawDict["StemSnapH"] = stemSnapH
            private.rawDict["StdHW"] = stemSnapH[0]
            private.rawDict["StemSnapV"] = stemSnapV
            private.rawDict["StdVW"] = stemSnapV[0]
        # populate glyphs
        for glyphName in self.glyphOrder:
            glyph = self.allGlyphs[glyphName]
            unicodes = glyph.unicodes
            charString = self.getCharStringForGlyph(glyph, private, globalSubrs)
            # add to the font
            exists = charStrings.has_key(glyphName)
            if exists:
                # XXX a glyph already has this name. should we choke?
                glyphID = charStrings.charStrings[glyphName]
                charStringsIndex.items[glyphID] = charString
            else:
                charStringsIndex.append(charString)
                glyphID = len(topDict.charset)
                charStrings.charStrings[glyphName] = glyphID
                topDict.charset.append(glyphName)
        topDict.FontBBox = self.fontBoundingBox
        # write the glyph order
        self.otf.setGlyphOrder(self.glyphOrder)
Example #25
0
    def setupTable_hhea(self):
        """
        Make the hhea 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["hhea"] = hhea = newTable("hhea")
        font = self.ufo
        hhea.tableVersion = 1.0
        # vertical metrics
        hhea.ascent = _roundInt(
            getAttrWithFallback(font.info, "openTypeHheaAscender"))
        hhea.descent = _roundInt(
            getAttrWithFallback(font.info, "openTypeHheaDescender"))
        hhea.lineGap = _roundInt(
            getAttrWithFallback(font.info, "openTypeHheaLineGap"))
        # horizontal metrics
        widths = []
        lefts = []
        rights = []
        extents = []
        for glyph in self.allGlyphs.values():
            left = glyph.leftMargin
            right = glyph.rightMargin
            if left is None:
                left = 0
            if right is None:
                right = 0
            widths.append(glyph.width)
            lefts.append(left)
            rights.append(right)
            # robofab
            if hasattr(glyph, "box"):
                bounds = glyph.box
            # others
            else:
                bounds = glyph.bounds
            if bounds is not None:
                xMin, yMin, xMax, yMax = bounds
            else:
                xMin = 0
                xMax = 0
            extent = left + (
                xMax - xMin
            )  # equation from spec for calculating xMaxExtent: Max(lsb + (xMax - xMin))
            extents.append(extent)
        hhea.advanceWidthMax = _roundInt(max(widths))
        hhea.minLeftSideBearing = _roundInt(min(lefts))
        hhea.minRightSideBearing = _roundInt(min(rights))
        hhea.xMaxExtent = _roundInt(max(extents))
        # misc
        hhea.caretSlopeRise = getAttrWithFallback(
            font.info, "openTypeHheaCaretSlopeRise")
        hhea.caretSlopeRun = getAttrWithFallback(font.info,
                                                 "openTypeHheaCaretSlopeRun")
        hhea.caretOffset = _roundInt(
            getAttrWithFallback(font.info, "openTypeHheaCaretOffset"))
        hhea.reserved0 = 0
        hhea.reserved1 = 0
        hhea.reserved2 = 0
        hhea.reserved3 = 0
        hhea.metricDataFormat = 0
        # glyph count
        hhea.numberOfHMetrics = len(self.allGlyphs)
Example #26
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
        os2.sFamilyClass = 0  # XXX not sure how to create the appropriate value
        # 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 = str(
            getAttrWithFallback(font.info, "openTypeOS2VendorID").decode(
                "ascii", "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