This file is indexed.

/usr/lib/python3/dist-packages/ufo2ft/featureCompiler.py is in python3-ufo2ft 1.1.0-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
from __future__ import \
    print_function, division, absolute_import, unicode_literals
import logging
import os
from inspect import isclass
from tempfile import NamedTemporaryFile

from fontTools import feaLib
from fontTools.feaLib.builder import addOpenTypeFeaturesFromString
from fontTools import mtiLib
from fontTools.misc.py23 import UnicodeIO, tobytes

from ufo2ft.featureWriters import DEFAULT_FEATURE_WRITERS
from ufo2ft.maxContextCalc import maxCtxFont

logger = logging.getLogger(__name__)


class FeatureCompiler(object):
    """Generates OpenType feature tables for a UFO.

    *featureWriters* argument is a list that can contain either subclasses
    of BaseFeatureWriter or pre-initialized instances (or a mix of the two).
    Classes are initialized without arguments so will use default options.

    Features will be written by each feature writer in the given order.
    The default value is [KernFeatureWriter, MarkFeatureWriter].

    If mtiFeatures is passed to the constructor, it should be a dictionary
    mapping feature table tags to MTI feature declarations for that table.
    These are passed to mtiLib for compilation.
    """

    def __init__(self, font, outline,
                 featureWriters=None,
                 mtiFeatures=None):
        self.font = font
        self.outline = outline
        if featureWriters is None:
            featureWriters = DEFAULT_FEATURE_WRITERS
        self.featureWriters = []
        for writer in featureWriters:
            if isclass(writer):
                writer = writer()
            self.featureWriters.append(writer)
        self.mtiFeatures = mtiFeatures

    def compile(self):
        """Compile the features.

        Starts by generating feature syntax for the kern, mark, and mkmk
        features. If they already exist, they will not be overwritten.
        """

        self.setupFile_features()
        self.setupFile_featureTables()
        self.postProcess()

    def setupFile_features(self):
        """
        Make the features source file. If any tables
        or the kern feature are defined in the font's
        features, they will not be overwritten.

        **This should not be called externally.** Subclasses
        may override this method to handle the file creation
        in a different way if desired.
        """

        if self.mtiFeatures is not None:
            return

        existingFeatures = self._findLayoutFeatures()

        # build features as necessary
        autoFeatures = []
        # the current MarkFeatureWriter writes both mark and mkmk features
        # with shared markClass definitions; to prevent duplicate glyphs in
        # markClass, here we write the features only if none of them is alread
        # present.
        # TODO: Support updating pre-existing markClass definitions to allow
        # writing either mark or mkmk features indipendently from each other
        # https://github.com/googlei18n/fontmake/issues/319
        font = self.font
        for fw in self.featureWriters:
            if (fw.mode == "append" or (
                    fw.mode == "skip" and
                    all(fea not in existingFeatures for fea in fw.features))):
                autoFeatures.append(fw.write(font))

        # write the features
        self.features = "\n\n".join([font.features.text or ""] + autoFeatures)

    def _findLayoutFeatures(self):
        """Returns what OpenType layout feature tags are present in the UFO."""
        featxt = self.font.features.text
        if not featxt:
            return set()
        buf = UnicodeIO(featxt)
        # the path is only used by the lexer to resolve 'include' statements
        if self.font.path is not None:
            buf.name = os.path.join(self.font.path, "features.fea")
        glyphMap = self.outline.getReverseGlyphMap()
        parser = feaLib.parser.Parser(buf, glyphMap)
        doc = parser.parse()
        return {f.name for f in doc.statements
                if isinstance(f, feaLib.ast.FeatureBlock)}

    def setupFile_featureTables(self):
        """
        Compile and return OpenType feature tables from the source.
        Raises a FeaLibError if the feature compilation was unsuccessful.

        **This should not be called externally.** Subclasses
        may override this method to handle the table compilation
        in a different way if desired.
        """

        if self.mtiFeatures is not None:
            for tag, features in self.mtiFeatures.items():
                table = mtiLib.build(features.splitlines(), self.outline)
                assert table.tableTag == tag
                self.outline[tag] = table

        elif self.features.strip():
            # the path to features.fea is only used by the lexer to resolve
            # the relative "include" statements
            if self.font.path is not None:
                feapath = os.path.join(self.font.path, "features.fea")
            else:
                # in-memory UFO has no path, can't do 'include' either
                feapath = None

            # save generated features to a temp file if things go wrong...
            data = tobytes(self.features, encoding="utf-8")
            with NamedTemporaryFile(delete=False) as tmp:
                tmp.write(data)

            # if compilation succedes or fails for unrelated reasons, clean
            # up the temporary file
            try:
                addOpenTypeFeaturesFromString(self.outline, self.features,
                                              filename=feapath)
            except feaLib.error.FeatureLibError:
                logger.error("Compilation failed! Inspect temporary file: %r",
                             tmp.name)
                raise
            except:
                os.remove(tmp.name)
                raise
            else:
                os.remove(tmp.name)

    def postProcess(self):
        """Make post-compilation calculations.

        **This should not be called externally.** Subclasses
        may override this method if desired.
        """

        # only after compiling features can usMaxContext be calculated
        self.outline['OS/2'].usMaxContext = maxCtxFont(self.outline)