Beispiel #1
0
    def _write(self):
        lookups = self._makeKerningLookups()
        if not lookups:
            self.log.debug("kerning lookups empty; skipped")
            return False

        features = self._makeFeatureBlocks(lookups)
        if not features:
            self.log.debug("kerning features empty; skipped")
            return False

        # extend feature file with the new generated statements
        statements = self.context.feaFile.statements

        # first add the glyph class definitions
        side1Classes = self.context.kerning.side1Classes
        side2Classes = self.context.kerning.side2Classes
        for classes in (side1Classes, side2Classes):
            statements.extend([c for _, c in sorted(classes.items())])

        # add empty line to separate classes from following statements
        if statements:
            statements.append(ast.Comment(""))

        # finally add the lookup and feature blocks
        for _, lookup in sorted(lookups.items()):
            statements.append(lookup)
        if "kern" in features:
            statements.append(features["kern"])
        if "dist" in features:
            statements.append(features["dist"])
        return True
Beispiel #2
0
    def _write(self):
        self._pruneUnusedAnchors()

        newClassDefs = self._makeMarkClassDefinitions()
        self._setBaseAnchorMarkClasses()

        features = self._makeFeatures()
        if not features:
            return False

        feaFile = self.context.feaFile
        feaFile.statements.extend(newClassDefs)
        # add empty line to separate classes from following statements
        feaFile.statements.append(ast.Comment(""))
        for _, feature in sorted(features.items()):
            feaFile.statements.append(feature)
        return True
Beispiel #3
0
    def _insert(
        self,
        feaFile,
        classDefs=None,
        anchorDefs=None,
        markClassDefs=None,
        lookups=None,
        features=None,
    ):
        """
        Insert feature, its classDefs or markClassDefs and lookups at insert
        marker comment.

        If the insert marker is at the top of a feature block, the feature is
        inserted before that block, and after if the insert marker is at the
        bottom.
        """

        statements = feaFile.statements
        inserted = {}

        # First handle those with a known location, i.e. insert markers
        insertComments = self.context.insertComments
        indices = []
        for ix, feature in enumerate(features):
            if insertComments and feature.name in insertComments:
                block, comment = insertComments[feature.name]
                markerIndex = block.statements.index(comment)

                onlyCommentsBefore = all(
                    isinstance(s, ast.Comment) for s in block.statements[:markerIndex]
                )
                onlyCommentsAfter = all(
                    isinstance(s, ast.Comment) for s in block.statements[markerIndex:]
                )

                # Remove insert marker(s) from feature block.
                del block.statements[markerIndex]

                # insertFeatureMarker is in a block with only comments.
                # Replace that block with new feature block.
                if onlyCommentsBefore and onlyCommentsAfter:
                    index = statements.index(block)
                    statements.remove(block)

                # insertFeatureMarker is at the top of a feature block
                # or only preceded by other comments.
                elif onlyCommentsBefore:
                    index = statements.index(block)

                # insertFeatureMarker is at the bottom of a feature block
                # or only followed by other comments
                elif onlyCommentsAfter:
                    index = statements.index(block) + 1

                # insertFeatureMarker is in the middle of a feature block
                # preceded and followed by statements that are not comments
                #
                # Glyphs3 can insert a feature block when rules are before
                # and after the insert marker.
                # See
                # https://github.com/googlefonts/ufo2ft/issues/351#issuecomment-765294436
                # This is currently not supported.
                else:
                    raise InvalidFeaturesData(
                        "Insert marker has rules before and after, feature "
                        f"{block.name} cannot be inserted. This is not supported."
                    )

                statements.insert(index, feature)
                indices.append(index)
                inserted[id(feature)] = True

                # Now walk feature list backwards and insert any dependent features
                for i in range(ix - 1, -1, -1):
                    if id(features[i]) in inserted:
                        break
                    # Insert this before the current one i.e. at same array index
                    statements.insert(index, features[i])
                    # All the indices recorded previously have now shifted up by one
                    indices = [index] + [j + 1 for j in indices]
                    inserted[id(features[i])] = True

        # Finally, deal with any remaining features
        for feature in features:
            if id(feature) in inserted:
                continue
            index = len(statements)
            statements.insert(index, feature)
            indices.append(index)

        # Write classDefs, anchorsDefs, markClassDefs, lookups at earliest
        # opportunity.
        others = []
        minindex = min(indices)
        for defs in [classDefs, anchorDefs, markClassDefs]:
            if defs:
                others.extend(defs)
                others.append(ast.Comment(""))
        # Insert lookups
        if lookups:
            if minindex > 0 and not others:
                others.append(ast.Comment(""))
            others.extend(lookups)
        if others:
            feaFile.statements = statements = (
                statements[:minindex] + others + statements[minindex:]
            )
    def _insert(
        self,
        feaFile,
        classDefs=None,
        anchorDefs=None,
        markClassDefs=None,
        lookups=None,
        features=None,
    ):
        """
        Insert feature, its classDefs or markClassDefs and lookups at insert
        marker comment.

        If the insert marker is at the top of a feature block, the feature is
        inserted before that block, and after if the insert marker is at the
        bottom.
        """

        statements = feaFile.statements

        # Collect insert markers in blocks
        insertComments = self.context.insertComments

        wroteOthers = False
        for feature in features:
            if insertComments and feature.name in insertComments:
                block, comment = insertComments[feature.name]
                markerIndex = block.statements.index(comment)

                onlyCommentsBefore = all(
                    isinstance(s, ast.Comment)
                    for s in block.statements[:markerIndex])
                onlyCommentsAfter = all(
                    isinstance(s, ast.Comment)
                    for s in block.statements[markerIndex:])

                # Remove insert marker(s) from feature block.
                del block.statements[markerIndex]

                # insertFeatureMarker is in a block with only comments.
                # Replace that block with new feature block.
                if onlyCommentsBefore and onlyCommentsAfter:
                    index = statements.index(block)
                    statements.remove(block)

                # insertFeatureMarker is at the top of a feature block
                # or only preceded by other comments.
                elif onlyCommentsBefore:
                    index = statements.index(block)

                # insertFeatureMarker is at the bottom of a feature block
                # or only followed by other comments
                elif onlyCommentsAfter:
                    index = statements.index(block) + 1

                # insertFeatureMarker is in the middle of a feature block
                # preceded and followed by statements that are not comments
                #
                # Glyphs3 can insert a feature block when rules are before
                # and after the insert marker.
                # See
                # https://github.com/googlefonts/ufo2ft/issues/351#issuecomment-765294436
                # This is currently not supported.
                else:
                    raise InvalidFeaturesData(
                        "Insert marker has rules before and after, feature "
                        f"{block.name} cannot be inserted. This is not supported."
                    )

            else:
                index = len(statements)

            # Write classDefs, anchorsDefs, markClassDefs, lookups on the first
            # iteration.
            if not wroteOthers:
                others = []
                # Insert classDefs, anchorsDefs, markClassDefs
                for defs in [classDefs, anchorDefs, markClassDefs]:
                    if defs:
                        others.extend(defs)
                        others.append(ast.Comment(""))
                # Insert lookups
                if lookups:
                    if index > 0 and not others:
                        others.append(ast.Comment(""))
                    others.extend(lookups)
                if others:
                    feaFile.statements = statements = (statements[:index] +
                                                       others +
                                                       statements[index:])
                    index = index + len(others)
                wroteOthers = True

            statements.insert(index, feature)