Ejemplo n.º 1
0
    def parse_lookupflag_(self):
        assert self.is_cur_keyword_("lookupflag")
        location = self.cur_token_location_

        # format B: "lookupflag 6;"
        if self.next_token_type_ == Lexer.NUMBER:
            value = self.expect_number_()
            self.expect_symbol_(";")
            return ast.LookupFlagStatement(location, value, None, None)

        # format A: "lookupflag RightToLeft MarkAttachmentType @M;"
        value, markAttachment, markFilteringSet = 0, None, None
        flags = {
            "RightToLeft": 1,
            "IgnoreBaseGlyphs": 2,
            "IgnoreLigatures": 4,
            "IgnoreMarks": 8
        }
        seen = set()
        while self.next_token_ != ";":
            if self.next_token_ in seen:
                raise FeatureLibError(
                    "%s can be specified only once" % self.next_token_,
                    self.next_token_location_)
            seen.add(self.next_token_)
            if self.next_token_ == "MarkAttachmentType":
                self.expect_keyword_("MarkAttachmentType")
                markAttachment = self.parse_class_name_()
            elif self.next_token_ == "UseMarkFilteringSet":
                self.expect_keyword_("UseMarkFilteringSet")
                markFilteringSet = self.parse_class_name_()
            elif self.next_token_ in flags:
                value = value | flags[self.expect_name_()]
            else:
                raise FeatureLibError(
                    '"%s" is not a recognized lookupflag' % self.next_token_,
                    self.next_token_location_)
        self.expect_symbol_(";")
        return ast.LookupFlagStatement(location, value, markAttachment,
                                       markFilteringSet)
Ejemplo n.º 2
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)
Ejemplo n.º 3
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
Ejemplo n.º 4
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
Ejemplo n.º 5
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)
Ejemplo n.º 6
0
    def _lookupDefinition(self, lookup):
        mark_attachement = None
        mark_filtering = None

        flags = 0
        if lookup.direction == "RTL":
            flags |= 1
        if not lookup.process_base:
            flags |= 2
        # FIXME: Does VOLT support this?
        # if not lookup.process_ligatures:
        #     flags |= 4
        if not lookup.process_marks:
            flags |= 8
        elif isinstance(lookup.process_marks, str):
            mark_attachement = self._groupName(lookup.process_marks)
        elif lookup.mark_glyph_set is not None:
            mark_filtering = self._groupName(lookup.mark_glyph_set)

        lookupflags = None
        if flags or mark_attachement is not None or mark_filtering is not None:
            lookupflags = ast.LookupFlagStatement(flags, mark_attachement,
                                                  mark_filtering)
        if "\\" in lookup.name:
            # Merge sub lookups as subtables (lookups named “base\sub”),
            # makeotf/feaLib will issue a warning and ignore the subtable
            # statement if it is not a pairpos lookup, though.
            name = lookup.name.split("\\")[0]
            if name.lower() not in self._lookups:
                fealookup = ast.LookupBlock(self._lookupName(name))
                if lookupflags is not None:
                    fealookup.statements.append(lookupflags)
                fealookup.statements.append(ast.Comment("# " + lookup.name))
            else:
                fealookup = self._lookups[name.lower()]
                fealookup.statements.append(ast.SubtableStatement())
                fealookup.statements.append(ast.Comment("# " + lookup.name))
            self._lookups[name.lower()] = fealookup
        else:
            fealookup = ast.LookupBlock(self._lookupName(lookup.name))
            if lookupflags is not None:
                fealookup.statements.append(lookupflags)
            self._lookups[lookup.name.lower()] = fealookup

        if lookup.comments is not None:
            fealookup.statements.append(ast.Comment("# " + lookup.comments))

        contexts = []
        if lookup.context:
            for context in lookup.context:
                prefix = self._context(context.left)
                suffix = self._context(context.right)
                ignore = context.ex_or_in == "EXCEPT_CONTEXT"
                contexts.append([prefix, suffix, ignore, False])
                # It seems that VOLT will create contextual substitution using
                # only the input if there is no other contexts in this lookup.
                if ignore and len(lookup.context) == 1:
                    contexts.append([[], [], False, True])
        else:
            contexts.append([[], [], False, False])

        targetlookup = None
        for prefix, suffix, ignore, chain in contexts:
            if lookup.sub is not None:
                self._gsubLookup(lookup, prefix, suffix, ignore, chain,
                                 fealookup)

            if lookup.pos is not None:
                if self._settings.get("COMPILER_USEEXTENSIONLOOKUPS"):
                    fealookup.use_extension = True
                if prefix or suffix or chain or ignore:
                    if not ignore and targetlookup is None:
                        targetname = self._lookupName(lookup.name + " target")
                        targetlookup = ast.LookupBlock(targetname)
                        fealookup.targets = getattr(fealookup, "targets", [])
                        fealookup.targets.append(targetlookup)
                        self._gposLookup(lookup, targetlookup)
                    self._gposContextLookup(lookup, prefix, suffix, ignore,
                                            fealookup, targetlookup)
                else:
                    self._gposLookup(lookup, fealookup)