Example #1
0
def makeLookupFlag(name=None, markAttachment=None, markFilteringSet=None):
    value = 0 if name is None else LOOKUP_FLAGS[name]

    if markAttachment is not None:
        assert isinstance(markAttachment, ast.GlyphClassDefinition)
        markAttachment = ast.GlyphClassName(markAttachment)

    if markFilteringSet is not None:
        assert isinstance(markFilteringSet, ast.GlyphClassDefinition)
        markFilteringSet = ast.GlyphClassName(markFilteringSet)

    return ast.LookupFlagStatement(value,
                                   markAttachment=markAttachment,
                                   markFilteringSet=markFilteringSet)
Example #2
0
def asFeaAST(self, inFeature=False):
    if self.name and not inFeature:
        f = feaast.LookupBlock(name=self.name)
    elif self.name:
        f = feaast.LookupBlock(name=self.name)
    else:
        f = feaast.Block()
    arranged = arrange(self)

    if arranged and inFeature:
        f = feaast.Block()
        for a in arranged:
            f.statements.append(asFeaAST(a, inFeature))
        return f

    if hasattr(self, "flags"):
        flags = feaast.LookupFlagStatement(self.flags)
        if self.flags & 0x10 and hasattr(self,
                                         "markFilteringSetAsClass"):  # XXX
            # We only need the name, not the contents
            mfs = feaast.GlyphClassDefinition(self.markFilteringSetAsClass,
                                              feaast.GlyphClass([]))
            flags.markFilteringSet = feaast.GlyphClassName(mfs)
        if self.flags & 0xFF00 and hasattr(self,
                                           "markAttachmentSetAsClass"):  # XXX
            mfs = feaast.GlyphClassDefinition(self.markAttachmentSetAsClass,
                                              feaast.GlyphClass([]))
            flags.markAttachment = feaast.GlyphClassName(mfs)

        f.statements.append(flags)

    for x in self.comments:
        f.statements.append(feaast.Comment(x))

    f.statements.append(feaast.Comment(";"))
    lastaddress = self.address
    if lastaddress:
        f.statements.append(
            feaast.Comment("# Original source: %s " %
                           (" ".join([str(x) for x in lastaddress]))))
    for x in self.rules:
        if x.address and x.address != lastaddress:
            f.statements.append(
                feaast.Comment("# Original source: %s " % x.address))
            lastaddress = x.address
        f.statements.append(x.asFeaAST())
    return f
Example #3
0
    def parse_glyphclass_(self, accept_glyphname):
        if (accept_glyphname and
                self.next_token_type_ in (Lexer.NAME, Lexer.CID)):
            glyph = self.expect_glyph_()
            return ast.GlyphName(self.cur_token_location_, glyph)
        if self.next_token_type_ is Lexer.GLYPHCLASS:
            self.advance_lexer_()
            gc = self.glyphclasses_.resolve(self.cur_token_)
            if gc is None:
                raise FeatureLibError(
                    "Unknown glyph class @%s" % self.cur_token_,
                    self.cur_token_location_)
            if isinstance(gc, ast.MarkClass):
                return ast.MarkClassName(self.cur_token_location_, gc)
            else:
                return ast.GlyphClassName(self.cur_token_location_, gc)

        self.expect_symbol_("[")
        glyphs = set()
        location = self.cur_token_location_
        while self.next_token_ != "]":
            if self.next_token_type_ is Lexer.NAME:
                glyph = self.expect_glyph_()
                if self.next_token_ == "-":
                    range_location = self.cur_token_location_
                    range_start = glyph
                    self.expect_symbol_("-")
                    range_end = self.expect_glyph_()
                    glyphs.update(self.make_glyph_range_(range_location,
                                                         range_start,
                                                         range_end))
                else:
                    glyphs.add(glyph)
            elif self.next_token_type_ is Lexer.CID:
                glyph = self.expect_glyph_()
                if self.next_token_ == "-":
                    range_location = self.cur_token_location_
                    range_start = self.cur_token_
                    self.expect_symbol_("-")
                    range_end = self.expect_cid_()
                    glyphs.update(self.make_cid_range_(range_location,
                                                       range_start, range_end))
                else:
                    glyphs.add("cid%05d" % self.cur_token_)
            elif self.next_token_type_ is Lexer.GLYPHCLASS:
                self.advance_lexer_()
                gc = self.glyphclasses_.resolve(self.cur_token_)
                if gc is None:
                    raise FeatureLibError(
                        "Unknown glyph class @%s" % self.cur_token_,
                        self.cur_token_location_)
                glyphs.update(gc.glyphSet())
            else:
                raise FeatureLibError(
                    "Expected glyph name, glyph range, "
                    "or glyph class reference",
                    self.next_token_location_)
        self.expect_symbol_("]")
        return ast.GlyphClass(location, glyphs)
Example #4
0
 def parse_class_name_(self):
     name = self.expect_class_name_()
     gc = self.glyphclasses_.resolve(name)
     if gc is None:
         raise FeatureLibError("Unknown glyph class @%s" % name,
                               self.cur_token_location_)
     if isinstance(gc, ast.MarkClass):
         return ast.MarkClassName(self.cur_token_location_, gc)
     else:
         return ast.GlyphClassName(self.cur_token_location_, gc)
Example #5
0
def asFeaAST(self):
    if self.name:
        f = feaast.LookupBlock(name=self.name)
    else:
        f = feaast.Block()

    if hasattr(self, "flags"):
        flags = feaast.LookupFlagStatement(self.flags)
        if self.flags & 0x10 and hasattr(self,
                                         "markFilteringSetAsClass"):  # XXX
            # We only need the name, not the contents
            mfs = feaast.GlyphClassDefinition(self.markFilteringSetAsClass,
                                              feaast.GlyphClass([]))
            flags.markFilteringSet = feaast.GlyphClassName(mfs)
        if self.flags & 0xFF00 and hasattr(self,
                                           "markAttachmentSetAsClass"):  # XXX
            mfs = feaast.GlyphClassDefinition(self.markAttachmentSetAsClass,
                                              feaast.GlyphClass([]))
            flags.markAttachment = feaast.GlyphClassName(mfs)

        f.statements.append(flags)

    for x in self.comments:
        f.statements.append(feaast.Comment(x))

    f.statements.append(feaast.Comment(";"))
    lastaddress = self.address
    if lastaddress:
        f.statements.append(
            feaast.Comment("# Original source: %s " %
                           (" ".join([str(x) for x in lastaddress]))))
    for x in self.rules:
        if x.address and x.address != lastaddress:
            f.statements.append(
                feaast.Comment("# Original source: %s " % x.address))
            lastaddress = x.address
        if hasattr(x, "note"):
            f.statements.append(
                feaast.Comment("\n".join(
                    [f"# {n}" for n in x.note.split("\n")])))
        f.statements.append(x.asFeaAST())
    return f
Example #6
0
def makeQuranSajdaLine(font):
    pos = font["uni06D7"].getBounds(font).yMax
    thickness = font.info.postscriptUnderlineThickness
    minwidth = 100

    _, gdefclasses = findGDEF(font)
    # collect glyphs grouped by their widths rounded by 100 units, we will use
    # them to decide the widths of over/underline glyphs we will draw
    widths = {}
    for glyph in font:
        u = glyph.unicode
        if ((u is None ) or (0x0600 <= u <= 0x06FF) or u == ord(" ")) \
        and glyph.width > 0:
            width = round(glyph.width / minwidth) * minwidth
            width = width > minwidth and width or minwidth
            if not width in widths:
                widths[width] = []
            widths[width].append(glyph.name)

    base = 'uni0305'
    drawOverline(font, base, 0x0305, pos, thickness, 500)

    mark = ast.FeatureBlock("mark")
    overset = ast.GlyphClassDefinition("OverSet", ast.GlyphClass([base]))
    lookupflag = ast.LookupFlagStatement(
        markFilteringSet=ast.GlyphClassName(overset))
    mark.statements.extend([overset, lookupflag])

    for width in sorted(widths.keys()):
        # for each width group we create an over/underline glyph with the same
        # width, and add a contextual substitution lookup to use it when an
        # over/underline follows any glyph in this group
        replace = f"uni0305.{width}"
        drawOverline(font, replace, None, pos, thickness, width)
        sub = ast.SingleSubstStatement([ast.GlyphName(base)],
                                       [ast.GlyphName(replace)],
                                       [ast.GlyphClass(widths[width])], [],
                                       False)
        gdefclasses.markGlyphs.append(replace)
        mark.statements.append(sub)

    font.features.text.statements.append(mark)
Example #7
0
 def _groupName(self, group):
     try:
         name = group.group
     except AttributeError:
         name = group
     return ast.GlyphClassName(self._glyphclasses[name.lower()])
Example #8
0
    def _buildFeatureFile(self, tables):
        doc = ast.FeatureFile()
        statements = doc.statements

        if self._glyphclasses:
            statements.append(ast.Comment("# Glyph classes"))
            statements.extend(self._glyphclasses.values())

        if self._markclasses:
            statements.append(ast.Comment("\n# Mark classes"))
            statements.extend(c[1] for c in sorted(self._markclasses.items()))

        if self._lookups:
            statements.append(ast.Comment("\n# Lookups"))
            for lookup in self._lookups.values():
                statements.extend(getattr(lookup, "targets", []))
                statements.append(lookup)

        # Prune features
        features = self._features.copy()
        for ftag in features:
            scripts = features[ftag]
            for stag in scripts:
                langs = scripts[stag]
                for ltag in langs:
                    langs[ltag] = [
                        l for l in langs[ltag] if l.lower() in self._lookups
                    ]
                scripts[stag] = {t: l for t, l in langs.items() if l}
            features[ftag] = {t: s for t, s in scripts.items() if s}
        features = {t: f for t, f in features.items() if f}

        if features:
            statements.append(ast.Comment("# Features"))
            for ftag, scripts in features.items():
                feature = ast.FeatureBlock(ftag)
                stags = sorted(scripts, key=lambda k: 0 if k == "DFLT" else 1)
                for stag in stags:
                    feature.statements.append(ast.ScriptStatement(stag))
                    ltags = sorted(scripts[stag],
                                   key=lambda k: 0 if k == "dflt" else 1)
                    for ltag in ltags:
                        include_default = True if ltag == "dflt" else False
                        feature.statements.append(
                            ast.LanguageStatement(
                                ltag, include_default=include_default))
                        for name in scripts[stag][ltag]:
                            lookup = self._lookups[name.lower()]
                            lookupref = ast.LookupReferenceStatement(lookup)
                            feature.statements.append(lookupref)
                statements.append(feature)

        if self._gdef and "GDEF" in tables:
            classes = []
            for name in ("BASE", "MARK", "LIGATURE", "COMPONENT"):
                if name in self._gdef:
                    classname = "GDEF_" + name.lower()
                    glyphclass = ast.GlyphClassDefinition(
                        classname, self._gdef[name])
                    statements.append(glyphclass)
                    classes.append(ast.GlyphClassName(glyphclass))
                else:
                    classes.append(None)

            gdef = ast.TableBlock("GDEF")
            gdef.statements.append(ast.GlyphClassDefStatement(*classes))
            statements.append(gdef)

        return doc