diff options
author | Haibo Huang <hhb@google.com> | 2019-06-20 15:45:36 -0700 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2019-06-20 15:45:36 -0700 |
commit | 55de623ce0b138e0e8065c62c436339b8c3f395d (patch) | |
tree | 828083704fd779faf5667257b07d7983dab580c1 | |
parent | 901dd4f8265046e6cb7f5295b93b6a8c8db419cd (diff) | |
parent | 38c89b946c6cd100175a41bb29130e0f80227c04 (diff) | |
download | fonttools-55de623ce0b138e0e8065c62c436339b8c3f395d.tar.gz |
Upgrade fonttools to 3.43.1 am: 9b4ad0c3d9
am: 38c89b946c
Change-Id: I5ab01c1ea4b725ac943c4cc847c4a685ed66c8c4
45 files changed, 5003 insertions, 516 deletions
diff --git a/Lib/fontTools/__init__.py b/Lib/fontTools/__init__.py index 6a066d73..d6919b28 100644 --- a/Lib/fontTools/__init__.py +++ b/Lib/fontTools/__init__.py @@ -5,6 +5,6 @@ from fontTools.misc.loggingTools import configLogger log = logging.getLogger(__name__) -version = __version__ = "3.42.0" +version = __version__ = "3.43.1" __all__ = ["version", "log", "configLogger"] diff --git a/Lib/fontTools/misc/loggingTools.py b/Lib/fontTools/misc/loggingTools.py index aacc0858..b4b9a9b0 100644 --- a/Lib/fontTools/misc/loggingTools.py +++ b/Lib/fontTools/misc/loggingTools.py @@ -250,8 +250,8 @@ class Timer(object): upon exiting the with-statement. >>> import logging - >>> log = logging.getLogger("fontTools") - >>> configLogger(level="DEBUG", format="%(message)s", stream=sys.stdout) + >>> log = logging.getLogger("my-fancy-timer-logger") + >>> configLogger(logger=log, level="DEBUG", format="%(message)s", stream=sys.stdout) >>> with Timer(log, 'do something'): ... time.sleep(0.01) Took ... to do something @@ -530,67 +530,6 @@ def deprecateFunction(msg, category=UserWarning): return decorator -class LastResortLogger(logging.Logger): - """ Adds support for 'lastResort' handler introduced in Python 3.2. - It allows to print messages to sys.stderr even when no explicit handler - was configured. - To enable it, you can do: - - import logging - logging.lastResort = StderrHandler(logging.WARNING) - logging.setLoggerClass(LastResortLogger) - """ - - def callHandlers(self, record): - # this is the same as Python 3.5's logging.Logger.callHandlers - c = self - found = 0 - while c: - for hdlr in c.handlers: - found = found + 1 - if record.levelno >= hdlr.level: - hdlr.handle(record) - if not c.propagate: - c = None # break out - else: - c = c.parent - if found == 0: - if logging.lastResort: - if record.levelno >= logging.lastResort.level: - logging.lastResort.handle(record) - elif ( - logging.raiseExceptions - and not self.manager.emittedNoHandlerWarning - ): - sys.stderr.write( - "No handlers could be found for logger" - ' "%s"\n' % self.name - ) - self.manager.emittedNoHandlerWarning = True - - -class StderrHandler(logging.StreamHandler): - """ This class is like a StreamHandler using sys.stderr, but always uses - whateve sys.stderr is currently set to rather than the value of - sys.stderr at handler construction time. - """ - - def __init__(self, level=logging.NOTSET): - """ - Initialize the handler. - """ - logging.Handler.__init__(self, level) - - @property - def stream(self): - # the try/execept avoids failures during interpreter shutdown, when - # globals are set to None - try: - return sys.stderr - except AttributeError: - return __import__("sys").stderr - - if __name__ == "__main__": import doctest sys.exit(doctest.testmod(optionflags=doctest.ELLIPSIS).failed) diff --git a/Lib/fontTools/otlLib/builder.py b/Lib/fontTools/otlLib/builder.py index f8b3ce3b..a087b2d3 100644 --- a/Lib/fontTools/otlLib/builder.py +++ b/Lib/fontTools/otlLib/builder.py @@ -1,4 +1,5 @@ from __future__ import print_function, division, absolute_import +from collections import namedtuple from fontTools import ttLib from fontTools.ttLib.tables import otTables as ot from fontTools.ttLib.tables.otBase import ValueRecord, valueRecordFormatDict @@ -488,17 +489,25 @@ def _getSinglePosValueKey(valueRecord): return tuple(result) +_DeviceTuple = namedtuple("_DeviceTuple", "DeltaFormat StartSize EndSize DeltaValue") + + def _makeDeviceTuple(device): """otTables.Device --> tuple, for making device tables unique""" - return (device.DeltaFormat, device.StartSize, device.EndSize, - tuple(device.DeltaValue)) + return _DeviceTuple( + device.DeltaFormat, + device.StartSize, + device.EndSize, + () if device.DeltaFormat & 0x8000 else tuple(device.DeltaValue) + ) + def _getSinglePosValueSize(valueKey): """Returns how many ushorts this valueKey (short form of ValueRecord) takes up""" count = 0 - for k in valueKey[1:]: - if hasattr(k[1], '__len__') and len(k[1]): - count += len(k[1][3]) + 3 + for _, v in valueKey[1:]: + if isinstance(v, _DeviceTuple): + count += len(v.DeltaValue) + 3 else: count += 1 return count diff --git a/Lib/fontTools/subset/__init__.py b/Lib/fontTools/subset/__init__.py index 8cf82c12..6863bb6f 100644 --- a/Lib/fontTools/subset/__init__.py +++ b/Lib/fontTools/subset/__init__.py @@ -1987,7 +1987,8 @@ def closure_glyphs(self, s): @_add_method(ttLib.getTableClass('MATH')) def closure_glyphs(self, s): - self.table.MathVariants.closure_glyphs(s) + if self.table.MathVariants: + self.table.MathVariants.closure_glyphs(s) @_add_method(otTables.MathItalicsCorrectionInfo) def subset_glyphs(self, s): @@ -2039,8 +2040,10 @@ def subset_glyphs(self, s): @_add_method(ttLib.getTableClass('MATH')) def subset_glyphs(self, s): s.glyphs = s.glyphs_mathed - self.table.MathGlyphInfo.subset_glyphs(s) - self.table.MathVariants.subset_glyphs(s) + if self.table.MathGlyphInfo: + self.table.MathGlyphInfo.subset_glyphs(s) + if self.table.MathVariants: + self.table.MathVariants.subset_glyphs(s) return True @_add_method(ttLib.getTableModule('glyf').Glyph) diff --git a/Lib/fontTools/ttLib/woff2.py b/Lib/fontTools/ttLib/woff2.py index c0c0e704..56b119a7 100644 --- a/Lib/fontTools/ttLib/woff2.py +++ b/Lib/fontTools/ttLib/woff2.py @@ -16,7 +16,7 @@ from fontTools.ttLib.tables import ttProgram import logging -log = logging.getLogger(__name__) +log = logging.getLogger("fontTools.ttLib.woff2") haveBrotli = False try: @@ -82,7 +82,7 @@ class WOFF2Reader(SFNTReader): """Fetch the raw table data. Reconstruct transformed tables.""" entry = self.tables[Tag(tag)] if not hasattr(entry, 'data'): - if tag in woff2TransformedTableTags: + if entry.transformed: entry.data = self.reconstructTable(tag) else: entry.data = entry.loadData(self.transformBuffer) @@ -90,8 +90,6 @@ class WOFF2Reader(SFNTReader): def reconstructTable(self, tag): """Reconstruct table named 'tag' from transformed data.""" - if tag not in woff2TransformedTableTags: - raise TTLibError("transform for table '%s' is unknown" % tag) entry = self.tables[Tag(tag)] rawData = entry.loadData(self.transformBuffer) if tag == 'glyf': @@ -100,8 +98,10 @@ class WOFF2Reader(SFNTReader): data = self._reconstructGlyf(rawData, padding) elif tag == 'loca': data = self._reconstructLoca() + elif tag == 'hmtx': + data = self._reconstructHmtx(rawData) else: - raise NotImplementedError + raise TTLibError("transform for table '%s' is unknown" % tag) return data def _reconstructGlyf(self, data, padding=None): @@ -130,6 +130,34 @@ class WOFF2Reader(SFNTReader): % (self.tables['loca'].origLength, len(data))) return data + def _reconstructHmtx(self, data): + """ Return reconstructed hmtx table data. """ + # Before reconstructing 'hmtx' table we need to parse other tables: + # 'glyf' is required for reconstructing the sidebearings from the glyphs' + # bounding box; 'hhea' is needed for the numberOfHMetrics field. + if "glyf" in self.flavorData.transformedTables: + # transformed 'glyf' table is self-contained, thus 'loca' not needed + tableDependencies = ("maxp", "hhea", "glyf") + else: + # decompiling untransformed 'glyf' requires 'loca', which requires 'head' + tableDependencies = ("maxp", "head", "hhea", "loca", "glyf") + for tag in tableDependencies: + self._decompileTable(tag) + hmtxTable = self.ttFont["hmtx"] = WOFF2HmtxTable() + hmtxTable.reconstruct(data, self.ttFont) + data = hmtxTable.compile(self.ttFont) + return data + + def _decompileTable(self, tag): + """Decompile table data and store it inside self.ttFont.""" + data = self[tag] + if self.ttFont.isLoaded(tag): + return self.ttFont[tag] + tableClass = getTableClass(tag) + table = tableClass(tag) + self.ttFont.tables[tag] = table + table.decompile(data, self.ttFont) + class WOFF2Writer(SFNTWriter): @@ -146,7 +174,7 @@ class WOFF2Writer(SFNTWriter): self.file = file self.numTables = numTables self.sfntVersion = Tag(sfntVersion) - self.flavorData = flavorData or WOFF2FlavorData() + self.flavorData = WOFF2FlavorData(data=flavorData) self.directoryFormat = woff2DirectoryFormat self.directorySize = woff2DirectorySize @@ -199,7 +227,7 @@ class WOFF2Writer(SFNTWriter): # See: # https://github.com/khaledhosny/ots/issues/60 # https://github.com/google/woff2/issues/15 - if isTrueType: + if isTrueType and "glyf" in self.flavorData.transformedTables: self._normaliseGlyfAndLoca(padding=4) self._setHeadTransformFlag() @@ -234,13 +262,7 @@ class WOFF2Writer(SFNTWriter): if self.sfntVersion == "OTTO": return - # make up glyph names required to decompile glyf table - self._decompileTable('maxp') - numGlyphs = self.ttFont['maxp'].numGlyphs - glyphOrder = ['.notdef'] + ["glyph%.5d" % i for i in range(1, numGlyphs)] - self.ttFont.setGlyphOrder(glyphOrder) - - for tag in ('head', 'loca', 'glyf'): + for tag in ('maxp', 'head', 'loca', 'glyf'): self._decompileTable(tag) self.ttFont['glyf'].padding = padding for tag in ('glyf', 'loca'): @@ -265,6 +287,8 @@ class WOFF2Writer(SFNTWriter): tableClass = WOFF2LocaTable elif tag == 'glyf': tableClass = WOFF2GlyfTable + elif tag == 'hmtx': + tableClass = WOFF2HmtxTable else: tableClass = getTableClass(tag) table = tableClass(tag) @@ -293,11 +317,17 @@ class WOFF2Writer(SFNTWriter): def _transformTables(self): """Return transformed font data.""" + transformedTables = self.flavorData.transformedTables for tag, entry in self.tables.items(): - if tag in woff2TransformedTableTags: + data = None + if tag in transformedTables: data = self.transformTable(tag) - else: + if data is not None: + entry.transformed = True + if data is None: + # pass-through the table data without transformation data = entry.data + entry.transformed = False entry.offset = self.nextTableOffset entry.saveData(self.transformBuffer, data) self.nextTableOffset += entry.length @@ -306,9 +336,9 @@ class WOFF2Writer(SFNTWriter): return fontData def transformTable(self, tag): - """Return transformed table data.""" - if tag not in woff2TransformedTableTags: - raise TTLibError("Transform for table '%s' is unknown" % tag) + """Return transformed table data, or None if some pre-conditions aren't + met -- in which case, the non-transformed table data will be used. + """ if tag == "loca": data = b"" elif tag == "glyf": @@ -316,8 +346,15 @@ class WOFF2Writer(SFNTWriter): self._decompileTable(tag) glyfTable = self.ttFont['glyf'] data = glyfTable.transform(self.ttFont) + elif tag == "hmtx": + if "glyf" not in self.tables: + return + for tag in ("maxp", "head", "hhea", "loca", "glyf", "hmtx"): + self._decompileTable(tag) + hmtxTable = self.ttFont["hmtx"] + data = hmtxTable.transform(self.ttFont) # can be None else: - raise NotImplementedError + raise TTLibError("Transform for table '%s' is unknown" % tag) return data def _calcMasterChecksum(self): @@ -533,11 +570,9 @@ class WOFF2DirectoryEntry(DirectoryEntry): # otherwise, tag is derived from a fixed 'Known Tags' table self.tag = woff2KnownTags[self.flags & 0x3F] self.tag = Tag(self.tag) - if self.flags & 0xC0 != 0: - raise TTLibError('bits 6-7 are reserved and must be 0') self.origLength, data = unpackBase128(data) self.length = self.origLength - if self.tag in woff2TransformedTableTags: + if self.transformed: self.length, data = unpackBase128(data) if self.tag == 'loca' and self.length != 0: raise TTLibError( @@ -550,10 +585,44 @@ class WOFF2DirectoryEntry(DirectoryEntry): if (self.flags & 0x3F) == 0x3F: data += struct.pack('>4s', self.tag.tobytes()) data += packBase128(self.origLength) - if self.tag in woff2TransformedTableTags: + if self.transformed: data += packBase128(self.length) return data + @property + def transformVersion(self): + """Return bits 6-7 of table entry's flags, which indicate the preprocessing + transformation version number (between 0 and 3). + """ + return self.flags >> 6 + + @transformVersion.setter + def transformVersion(self, value): + assert 0 <= value <= 3 + self.flags |= value << 6 + + @property + def transformed(self): + """Return True if the table has any transformation, else return False.""" + # For all tables in a font, except for 'glyf' and 'loca', the transformation + # version 0 indicates the null transform (where the original table data is + # passed directly to the Brotli compressor). For 'glyf' and 'loca' tables, + # transformation version 3 indicates the null transform + if self.tag in {"glyf", "loca"}: + return self.transformVersion != 3 + else: + return self.transformVersion != 0 + + @transformed.setter + def transformed(self, booleanValue): + # here we assume that a non-null transform means version 0 for 'glyf' and + # 'loca' and 1 for every other table (e.g. hmtx); but that may change as + # new transformation formats are introduced in the future (if ever). + if self.tag in {"glyf", "loca"}: + self.transformVersion = 3 if not booleanValue else 0 + else: + self.transformVersion = int(booleanValue) + class WOFF2LocaTable(getTableClass('loca')): """Same as parent class. The only difference is that it attempts to preserve @@ -652,19 +721,7 @@ class WOFF2GlyfTable(getTableClass('glyf')): def transform(self, ttFont): """ Return transformed 'glyf' data """ self.numGlyphs = len(self.glyphs) - if not hasattr(self, "glyphOrder"): - try: - self.glyphOrder = ttFont.getGlyphOrder() - except: - self.glyphOrder = None - if self.glyphOrder is None: - self.glyphOrder = [".notdef"] - self.glyphOrder.extend(["glyph%.5d" % i for i in range(1, self.numGlyphs)]) - if len(self.glyphOrder) != self.numGlyphs: - raise TTLibError( - "incorrect glyphOrder: expected %d glyphs, found %d" % - (len(self.glyphOrder), self.numGlyphs)) - + assert len(self.glyphOrder) == self.numGlyphs if 'maxp' in ttFont: ttFont['maxp'].numGlyphs = self.numGlyphs self.indexFormat = ttFont['head'].indexToLocFormat @@ -909,13 +966,206 @@ class WOFF2GlyfTable(getTableClass('glyf')): self.glyphStream += triplets.tostring() +class WOFF2HmtxTable(getTableClass("hmtx")): + + def __init__(self, tag=None): + self.tableTag = Tag(tag or 'hmtx') + + def reconstruct(self, data, ttFont): + flags, = struct.unpack(">B", data[:1]) + data = data[1:] + if flags & 0b11111100 != 0: + raise TTLibError("Bits 2-7 of '%s' flags are reserved" % self.tableTag) + + # When bit 0 is _not_ set, the lsb[] array is present + hasLsbArray = flags & 1 == 0 + # When bit 1 is _not_ set, the leftSideBearing[] array is present + hasLeftSideBearingArray = flags & 2 == 0 + if hasLsbArray and hasLeftSideBearingArray: + raise TTLibError( + "either bits 0 or 1 (or both) must set in transformed '%s' flags" + % self.tableTag + ) + + glyfTable = ttFont["glyf"] + headerTable = ttFont["hhea"] + glyphOrder = glyfTable.glyphOrder + numGlyphs = len(glyphOrder) + numberOfHMetrics = min(int(headerTable.numberOfHMetrics), numGlyphs) + + assert len(data) >= 2 * numberOfHMetrics + advanceWidthArray = array.array("H", data[:2 * numberOfHMetrics]) + if sys.byteorder != "big": + advanceWidthArray.byteswap() + data = data[2 * numberOfHMetrics:] + + if hasLsbArray: + assert len(data) >= 2 * numberOfHMetrics + lsbArray = array.array("h", data[:2 * numberOfHMetrics]) + if sys.byteorder != "big": + lsbArray.byteswap() + data = data[2 * numberOfHMetrics:] + else: + # compute (proportional) glyphs' lsb from their xMin + lsbArray = array.array("h") + for i, glyphName in enumerate(glyphOrder): + if i >= numberOfHMetrics: + break + glyph = glyfTable[glyphName] + xMin = getattr(glyph, "xMin", 0) + lsbArray.append(xMin) + + numberOfSideBearings = numGlyphs - numberOfHMetrics + if hasLeftSideBearingArray: + assert len(data) >= 2 * numberOfSideBearings + leftSideBearingArray = array.array("h", data[:2 * numberOfSideBearings]) + if sys.byteorder != "big": + leftSideBearingArray.byteswap() + data = data[2 * numberOfSideBearings:] + else: + # compute (monospaced) glyphs' leftSideBearing from their xMin + leftSideBearingArray = array.array("h") + for i, glyphName in enumerate(glyphOrder): + if i < numberOfHMetrics: + continue + glyph = glyfTable[glyphName] + xMin = getattr(glyph, "xMin", 0) + leftSideBearingArray.append(xMin) + + if data: + raise TTLibError("too much '%s' table data" % self.tableTag) + + self.metrics = {} + for i in range(numberOfHMetrics): + glyphName = glyphOrder[i] + advanceWidth, lsb = advanceWidthArray[i], lsbArray[i] + self.metrics[glyphName] = (advanceWidth, lsb) + lastAdvance = advanceWidthArray[-1] + for i in range(numberOfSideBearings): + glyphName = glyphOrder[i + numberOfHMetrics] + self.metrics[glyphName] = (lastAdvance, leftSideBearingArray[i]) + + def transform(self, ttFont): + glyphOrder = ttFont.getGlyphOrder() + glyf = ttFont["glyf"] + hhea = ttFont["hhea"] + numberOfHMetrics = hhea.numberOfHMetrics + + # check if any of the proportional glyphs has left sidebearings that + # differ from their xMin bounding box values. + hasLsbArray = False + for i in range(numberOfHMetrics): + glyphName = glyphOrder[i] + lsb = self.metrics[glyphName][1] + if lsb != getattr(glyf[glyphName], "xMin", 0): + hasLsbArray = True + break + + # do the same for the monospaced glyphs (if any) at the end of hmtx table + hasLeftSideBearingArray = False + for i in range(numberOfHMetrics, len(glyphOrder)): + glyphName = glyphOrder[i] + lsb = self.metrics[glyphName][1] + if lsb != getattr(glyf[glyphName], "xMin", 0): + hasLeftSideBearingArray = True + break + + # if we need to encode both sidebearings arrays, then no transformation is + # applicable, and we must use the untransformed hmtx data + if hasLsbArray and hasLeftSideBearingArray: + return + + # set bit 0 and 1 when the respective arrays are _not_ present + flags = 0 + if not hasLsbArray: + flags |= 1 << 0 + if not hasLeftSideBearingArray: + flags |= 1 << 1 + + data = struct.pack(">B", flags) + + advanceWidthArray = array.array( + "H", + [ + self.metrics[glyphName][0] + for i, glyphName in enumerate(glyphOrder) + if i < numberOfHMetrics + ] + ) + if sys.byteorder != "big": + advanceWidthArray.byteswap() + data += advanceWidthArray.tostring() + + if hasLsbArray: + lsbArray = array.array( + "h", + [ + self.metrics[glyphName][1] + for i, glyphName in enumerate(glyphOrder) + if i < numberOfHMetrics + ] + ) + if sys.byteorder != "big": + lsbArray.byteswap() + data += lsbArray.tostring() + + if hasLeftSideBearingArray: + leftSideBearingArray = array.array( + "h", + [ + self.metrics[glyphOrder[i]][1] + for i in range(numberOfHMetrics, len(glyphOrder)) + ] + ) + if sys.byteorder != "big": + leftSideBearingArray.byteswap() + data += leftSideBearingArray.tostring() + + return data + + class WOFF2FlavorData(WOFFFlavorData): Flavor = 'woff2' - def __init__(self, reader=None): + def __init__(self, reader=None, data=None, transformedTables=None): + """Data class that holds the WOFF2 header major/minor version, any + metadata or private data (as bytes strings), and the set of + table tags that have transformations applied (if reader is not None), + or will have once the WOFF2 font is compiled. + + Args: + reader: an SFNTReader (or subclass) object to read flavor data from. + data: another WOFFFlavorData object to initialise data from. + transformedTables: set of strings containing table tags to be transformed. + + Raises: + ImportError if the brotli module is not installed. + + NOTE: The 'reader' argument, on the one hand, and the 'data' and + 'transformedTables' arguments, on the other hand, are mutually exclusive. + """ if not haveBrotli: raise ImportError("No module named brotli") + + if reader is not None: + if data is not None: + raise TypeError( + "'reader' and 'data' arguments are mutually exclusive" + ) + if transformedTables is not None: + raise TypeError( + "'reader' and 'transformedTables' arguments are mutually exclusive" + ) + + if transformedTables is not None and ( + "glyf" in transformedTables and "loca" not in transformedTables + or "loca" in transformedTables and "glyf" not in transformedTables + ): + raise ValueError( + "'glyf' and 'loca' must be transformed (or not) together" + ) + self.majorVersion = None self.minorVersion = None self.metaData = None @@ -927,14 +1177,31 @@ class WOFF2FlavorData(WOFFFlavorData): reader.file.seek(reader.metaOffset) rawData = reader.file.read(reader.metaLength) assert len(rawData) == reader.metaLength - data = brotli.decompress(rawData) - assert len(data) == reader.metaOrigLength - self.metaData = data + metaData = brotli.decompress(rawData) + assert len(metaData) == reader.metaOrigLength + self.metaData = metaData if reader.privLength: reader.file.seek(reader.privOffset) - data = reader.file.read(reader.privLength) - assert len(data) == reader.privLength - self.privData = data + privData = reader.file.read(reader.privLength) + assert len(privData) == reader.privLength + self.privData = privData + transformedTables = [ + tag + for tag, entry in reader.tables.items() + if entry.transformed + ] + elif data: + self.majorVersion = data.majorVersion + self.majorVersion = data.minorVersion + self.metaData = data.metaData + self.privData = data.privData + if transformedTables is None and hasattr(data, "transformedTables"): + transformedTables = data.transformedTables + + if transformedTables is None: + transformedTables = woff2TransformedTableTags + + self.transformedTables = set(transformedTables) def unpackBase128(data): @@ -1091,6 +1358,166 @@ def pack255UShort(value): return struct.pack(">BH", 253, value) +def compress(input_file, output_file, transform_tables=None): + """Compress OpenType font to WOFF2. + + Args: + input_file: a file path, file or file-like object (open in binary mode) + containing an OpenType font (either CFF- or TrueType-flavored). + output_file: a file path, file or file-like object where to save the + compressed WOFF2 font. + transform_tables: Optional[Iterable[str]]: a set of table tags for which + to enable preprocessing transformations. By default, only 'glyf' + and 'loca' tables are transformed. An empty set means disable all + transformations. + """ + log.info("Processing %s => %s" % (input_file, output_file)) + + font = TTFont(input_file, recalcBBoxes=False, recalcTimestamp=False) + font.flavor = "woff2" + + if transform_tables is not None: + font.flavorData = WOFF2FlavorData( + data=font.flavorData, transformedTables=transform_tables + ) + + font.save(output_file, reorderTables=False) + + +def decompress(input_file, output_file): + """Decompress WOFF2 font to OpenType font. + + Args: + input_file: a file path, file or file-like object (open in binary mode) + containing a compressed WOFF2 font. + output_file: a file path, file or file-like object where to save the + decompressed OpenType font. + """ + log.info("Processing %s => %s" % (input_file, output_file)) + + font = TTFont(input_file, recalcBBoxes=False, recalcTimestamp=False) + font.flavor = None + font.flavorData = None + font.save(output_file, reorderTables=True) + + +def main(args=None): + import argparse + from fontTools import configLogger + from fontTools.ttx import makeOutputFileName + + class _NoGlyfTransformAction(argparse.Action): + def __call__(self, parser, namespace, values, option_string=None): + namespace.transform_tables.difference_update({"glyf", "loca"}) + + class _HmtxTransformAction(argparse.Action): + def __call__(self, parser, namespace, values, option_string=None): + namespace.transform_tables.add("hmtx") + + parser = argparse.ArgumentParser( + prog="fonttools ttLib.woff2", + description="Compress and decompress WOFF2 fonts", + ) + + parser_group = parser.add_subparsers(title="sub-commands") + parser_compress = parser_group.add_parser("compress") + parser_decompress = parser_group.add_parser("decompress") + + for subparser in (parser_compress, parser_decompress): + group = subparser.add_mutually_exclusive_group(required=False) + group.add_argument( + "-v", + "--verbose", + action="store_true", + help="print more messages to console", + ) + group.add_argument( + "-q", + "--quiet", + action="store_true", + help="do not print messages to console", + ) + + parser_compress.add_argument( + "input_file", + metavar="INPUT", + help="the input OpenType font (.ttf or .otf)", + ) + parser_decompress.add_argument( + "input_file", + metavar="INPUT", + help="the input WOFF2 font", + ) + + parser_compress.add_argument( + "-o", + "--output-file", + metavar="OUTPUT", + help="the output WOFF2 font", + ) + parser_decompress.add_argument( + "-o", + "--output-file", + metavar="OUTPUT", + help="the output OpenType font", + ) + + transform_group = parser_compress.add_argument_group() + transform_group.add_argument( + "--no-glyf-transform", + dest="transform_tables", + nargs=0, + action=_NoGlyfTransformAction, + help="Do not transform glyf (and loca) tables", + ) + transform_group.add_argument( + "--hmtx-transform", + dest="transform_tables", + nargs=0, + action=_HmtxTransformAction, + help="Enable optional transformation for 'hmtx' table", + ) + + parser_compress.set_defaults( + subcommand=compress, + transform_tables={"glyf", "loca"}, + ) + parser_decompress.set_defaults(subcommand=decompress) + + options = vars(parser.parse_args(args)) + + subcommand = options.pop("subcommand", None) + if not subcommand: + parser.print_help() + return + + quiet = options.pop("quiet") + verbose = options.pop("verbose") + configLogger( + level=("ERROR" if quiet else "DEBUG" if verbose else "INFO"), + ) + + if not options["output_file"]: + if subcommand is compress: + extension = ".woff2" + elif subcommand is decompress: + # choose .ttf/.otf file extension depending on sfntVersion + with open(options["input_file"], "rb") as f: + f.seek(4) # skip 'wOF2' signature + sfntVersion = f.read(4) + assert len(sfntVersion) == 4, "not enough data" + extension = ".otf" if sfntVersion == b"OTTO" else ".ttf" + else: + raise AssertionError(subcommand) + options["output_file"] = makeOutputFileName( + options["input_file"], outputDir=None, extension=extension + ) + + try: + subcommand(**options) + except TTLibError as e: + parser.error(e) + + if __name__ == "__main__": - import doctest - sys.exit(doctest.testmod().failed) + sys.exit(main()) diff --git a/Lib/fontTools/unicodedata/Blocks.py b/Lib/fontTools/unicodedata/Blocks.py index 692fca89..132b0954 100644 --- a/Lib/fontTools/unicodedata/Blocks.py +++ b/Lib/fontTools/unicodedata/Blocks.py @@ -4,9 +4,9 @@ # Source: https://unicode.org/Public/UNIDATA/Blocks.txt # License: http://unicode.org/copyright.html#License # -# Blocks-11.0.0.txt -# Date: 2017-10-16, 24:39:00 GMT [KW] -# © 2017 Unicode®, Inc. +# Blocks-12.1.0.txt +# Date: 2019-03-08, 23:59:00 GMT [KW] +# © 2019 Unicode®, Inc. # For terms of use, see http://www.unicode.org/terms_of_use.html # # Unicode Character Database @@ -237,7 +237,8 @@ RANGES = [ 0x10E80, # .. 0x10EFF ; No_Block 0x10F00, # .. 0x10F2F ; Old Sogdian 0x10F30, # .. 0x10F6F ; Sogdian - 0x10F70, # .. 0x10FFF ; No_Block + 0x10F70, # .. 0x10FDF ; No_Block + 0x10FE0, # .. 0x10FFF ; Elymaic 0x11000, # .. 0x1107F ; Brahmi 0x11080, # .. 0x110CF ; Kaithi 0x110D0, # .. 0x110FF ; Sora Sompeng @@ -264,7 +265,8 @@ RANGES = [ 0x11800, # .. 0x1184F ; Dogra 0x11850, # .. 0x1189F ; No_Block 0x118A0, # .. 0x118FF ; Warang Citi - 0x11900, # .. 0x119FF ; No_Block + 0x11900, # .. 0x1199F ; No_Block + 0x119A0, # .. 0x119FF ; Nandinagari 0x11A00, # .. 0x11A4F ; Zanabazar Square 0x11A50, # .. 0x11AAF ; Soyombo 0x11AB0, # .. 0x11ABF ; No_Block @@ -277,13 +279,15 @@ RANGES = [ 0x11D60, # .. 0x11DAF ; Gunjala Gondi 0x11DB0, # .. 0x11EDF ; No_Block 0x11EE0, # .. 0x11EFF ; Makasar - 0x11F00, # .. 0x11FFF ; No_Block + 0x11F00, # .. 0x11FBF ; No_Block + 0x11FC0, # .. 0x11FFF ; Tamil Supplement 0x12000, # .. 0x123FF ; Cuneiform 0x12400, # .. 0x1247F ; Cuneiform Numbers and Punctuation 0x12480, # .. 0x1254F ; Early Dynastic Cuneiform 0x12550, # .. 0x12FFF ; No_Block 0x13000, # .. 0x1342F ; Egyptian Hieroglyphs - 0x13430, # .. 0x143FF ; No_Block + 0x13430, # .. 0x1343F ; Egyptian Hieroglyph Format Controls + 0x13440, # .. 0x143FF ; No_Block 0x14400, # .. 0x1467F ; Anatolian Hieroglyphs 0x14680, # .. 0x167FF ; No_Block 0x16800, # .. 0x16A3F ; Bamum Supplement @@ -302,7 +306,7 @@ RANGES = [ 0x18B00, # .. 0x1AFFF ; No_Block 0x1B000, # .. 0x1B0FF ; Kana Supplement 0x1B100, # .. 0x1B12F ; Kana Extended-A - 0x1B130, # .. 0x1B16F ; No_Block + 0x1B130, # .. 0x1B16F ; Small Kana Extension 0x1B170, # .. 0x1B2FF ; Nushu 0x1B300, # .. 0x1BBFF ; No_Block 0x1BC00, # .. 0x1BC9F ; Duployan @@ -320,13 +324,19 @@ RANGES = [ 0x1D800, # .. 0x1DAAF ; Sutton SignWriting 0x1DAB0, # .. 0x1DFFF ; No_Block 0x1E000, # .. 0x1E02F ; Glagolitic Supplement - 0x1E030, # .. 0x1E7FF ; No_Block + 0x1E030, # .. 0x1E0FF ; No_Block + 0x1E100, # .. 0x1E14F ; Nyiakeng Puachue Hmong + 0x1E150, # .. 0x1E2BF ; No_Block + 0x1E2C0, # .. 0x1E2FF ; Wancho + 0x1E300, # .. 0x1E7FF ; No_Block 0x1E800, # .. 0x1E8DF ; Mende Kikakui 0x1E8E0, # .. 0x1E8FF ; No_Block 0x1E900, # .. 0x1E95F ; Adlam 0x1E960, # .. 0x1EC6F ; No_Block 0x1EC70, # .. 0x1ECBF ; Indic Siyaq Numbers - 0x1ECC0, # .. 0x1EDFF ; No_Block + 0x1ECC0, # .. 0x1ECFF ; No_Block + 0x1ED00, # .. 0x1ED4F ; Ottoman Siyaq Numbers + 0x1ED50, # .. 0x1EDFF ; No_Block 0x1EE00, # .. 0x1EEFF ; Arabic Mathematical Alphabetic Symbols 0x1EF00, # .. 0x1EFFF ; No_Block 0x1F000, # .. 0x1F02F ; Mahjong Tiles @@ -343,7 +353,8 @@ RANGES = [ 0x1F800, # .. 0x1F8FF ; Supplemental Arrows-C 0x1F900, # .. 0x1F9FF ; Supplemental Symbols and Pictographs 0x1FA00, # .. 0x1FA6F ; Chess Symbols - 0x1FA70, # .. 0x1FFFF ; No_Block + 0x1FA70, # .. 0x1FAFF ; Symbols and Pictographs Extended-A + 0x1FB00, # .. 0x1FFFF ; No_Block 0x20000, # .. 0x2A6DF ; CJK Unified Ideographs Extension B 0x2A6E0, # .. 0x2A6FF ; No_Block 0x2A700, # .. 0x2B73F ; CJK Unified Ideographs Extension C @@ -582,7 +593,8 @@ VALUES = [ 'No_Block', # 10E80..10EFF 'Old Sogdian', # 10F00..10F2F 'Sogdian', # 10F30..10F6F - 'No_Block', # 10F70..10FFF + 'No_Block', # 10F70..10FDF + 'Elymaic', # 10FE0..10FFF 'Brahmi', # 11000..1107F 'Kaithi', # 11080..110CF 'Sora Sompeng', # 110D0..110FF @@ -609,7 +621,8 @@ VALUES = [ 'Dogra', # 11800..1184F 'No_Block', # 11850..1189F 'Warang Citi', # 118A0..118FF - 'No_Block', # 11900..119FF + 'No_Block', # 11900..1199F + 'Nandinagari', # 119A0..119FF 'Zanabazar Square', # 11A00..11A4F 'Soyombo', # 11A50..11AAF 'No_Block', # 11AB0..11ABF @@ -622,13 +635,15 @@ VALUES = [ 'Gunjala Gondi', # 11D60..11DAF 'No_Block', # 11DB0..11EDF 'Makasar', # 11EE0..11EFF - 'No_Block', # 11F00..11FFF + 'No_Block', # 11F00..11FBF + 'Tamil Supplement', # 11FC0..11FFF 'Cuneiform', # 12000..123FF 'Cuneiform Numbers and Punctuation', # 12400..1247F 'Early Dynastic Cuneiform', # 12480..1254F 'No_Block', # 12550..12FFF 'Egyptian Hieroglyphs', # 13000..1342F - 'No_Block', # 13430..143FF + 'Egyptian Hieroglyph Format Controls', # 13430..1343F + 'No_Block', # 13440..143FF 'Anatolian Hieroglyphs', # 14400..1467F 'No_Block', # 14680..167FF 'Bamum Supplement', # 16800..16A3F @@ -647,7 +662,7 @@ VALUES = [ 'No_Block', # 18B00..1AFFF 'Kana Supplement', # 1B000..1B0FF 'Kana Extended-A', # 1B100..1B12F - 'No_Block', # 1B130..1B16F + 'Small Kana Extension', # 1B130..1B16F 'Nushu', # 1B170..1B2FF 'No_Block', # 1B300..1BBFF 'Duployan', # 1BC00..1BC9F @@ -665,13 +680,19 @@ VALUES = [ 'Sutton SignWriting', # 1D800..1DAAF 'No_Block', # 1DAB0..1DFFF 'Glagolitic Supplement', # 1E000..1E02F - 'No_Block', # 1E030..1E7FF + 'No_Block', # 1E030..1E0FF + 'Nyiakeng Puachue Hmong', # 1E100..1E14F + 'No_Block', # 1E150..1E2BF + 'Wancho', # 1E2C0..1E2FF + 'No_Block', # 1E300..1E7FF 'Mende Kikakui', # 1E800..1E8DF 'No_Block', # 1E8E0..1E8FF 'Adlam', # 1E900..1E95F 'No_Block', # 1E960..1EC6F 'Indic Siyaq Numbers', # 1EC70..1ECBF - 'No_Block', # 1ECC0..1EDFF + 'No_Block', # 1ECC0..1ECFF + 'Ottoman Siyaq Numbers', # 1ED00..1ED4F + 'No_Block', # 1ED50..1EDFF 'Arabic Mathematical Alphabetic Symbols', # 1EE00..1EEFF 'No_Block', # 1EF00..1EFFF 'Mahjong Tiles', # 1F000..1F02F @@ -688,7 +709,8 @@ VALUES = [ 'Supplemental Arrows-C', # 1F800..1F8FF 'Supplemental Symbols and Pictographs', # 1F900..1F9FF 'Chess Symbols', # 1FA00..1FA6F - 'No_Block', # 1FA70..1FFFF + 'Symbols and Pictographs Extended-A', # 1FA70..1FAFF + 'No_Block', # 1FB00..1FFFF 'CJK Unified Ideographs Extension B', # 20000..2A6DF 'No_Block', # 2A6E0..2A6FF 'CJK Unified Ideographs Extension C', # 2A700..2B73F diff --git a/Lib/fontTools/unicodedata/ScriptExtensions.py b/Lib/fontTools/unicodedata/ScriptExtensions.py index bfcdbec3..d7d2e3c8 100644 --- a/Lib/fontTools/unicodedata/ScriptExtensions.py +++ b/Lib/fontTools/unicodedata/ScriptExtensions.py @@ -4,9 +4,9 @@ # Source: https://unicode.org/Public/UNIDATA/ScriptExtensions.txt # License: http://unicode.org/copyright.html#License # -# ScriptExtensions-11.0.0.txt -# Date: 2018-02-04, 20:04:00 GMT -# © 2018 Unicode®, Inc. +# ScriptExtensions-12.1.0.txt +# Date: 2019-04-01, 09:10:42 GMT +# © 2019 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. # For terms of use, see http://www.unicode.org/terms_of_use.html # @@ -75,8 +75,8 @@ RANGES = [ 0x0951, # .. 0x0951 ; {'Beng', 'Deva', 'Gran', 'Gujr', 'Guru', 'Knda', 'Latn', 'Mlym', 'Orya', 'Shrd', 'Taml', 'Telu', 'Tirh'} 0x0952, # .. 0x0952 ; {'Beng', 'Deva', 'Gran', 'Gujr', 'Guru', 'Knda', 'Latn', 'Mlym', 'Orya', 'Taml', 'Telu', 'Tirh'} 0x0953, # .. 0x0963 ; None - 0x0964, # .. 0x0964 ; {'Beng', 'Deva', 'Dogr', 'Gong', 'Gran', 'Gujr', 'Guru', 'Knda', 'Mahj', 'Mlym', 'Orya', 'Sind', 'Sinh', 'Sylo', 'Takr', 'Taml', 'Telu', 'Tirh'} - 0x0965, # .. 0x0965 ; {'Beng', 'Deva', 'Dogr', 'Gong', 'Gran', 'Gujr', 'Guru', 'Knda', 'Limb', 'Mahj', 'Mlym', 'Orya', 'Sind', 'Sinh', 'Sylo', 'Takr', 'Taml', 'Telu', 'Tirh'} + 0x0964, # .. 0x0964 ; {'Beng', 'Deva', 'Dogr', 'Gong', 'Gonm', 'Gran', 'Gujr', 'Guru', 'Knda', 'Mahj', 'Mlym', 'Nand', 'Orya', 'Sind', 'Sinh', 'Sylo', 'Takr', 'Taml', 'Telu', 'Tirh'} + 0x0965, # .. 0x0965 ; {'Beng', 'Deva', 'Dogr', 'Gong', 'Gonm', 'Gran', 'Gujr', 'Guru', 'Knda', 'Limb', 'Mahj', 'Mlym', 'Nand', 'Orya', 'Sind', 'Sinh', 'Sylo', 'Takr', 'Taml', 'Telu', 'Tirh'} 0x0966, # .. 0x096F ; {'Deva', 'Dogr', 'Kthi', 'Mahj'} 0x0970, # .. 0x09E5 ; None 0x09E6, # .. 0x09EF ; {'Beng', 'Cakm', 'Sylo'} @@ -86,7 +86,9 @@ RANGES = [ 0x0AE6, # .. 0x0AEF ; {'Gujr', 'Khoj'} 0x0AF0, # .. 0x0BE5 ; None 0x0BE6, # .. 0x0BF3 ; {'Gran', 'Taml'} - 0x0BF4, # .. 0x103F ; None + 0x0BF4, # .. 0x0CE5 ; None + 0x0CE6, # .. 0x0CEF ; {'Knda', 'Nand'} + 0x0CF0, # .. 0x103F ; None 0x1040, # .. 0x1049 ; {'Cakm', 'Mymr', 'Tale'} 0x104A, # .. 0x10FA ; None 0x10FB, # .. 0x10FB ; {'Geor', 'Latn'} @@ -112,19 +114,24 @@ RANGES = [ 0x1CDE, # .. 0x1CDF ; {'Deva'} 0x1CE0, # .. 0x1CE0 ; {'Deva', 'Shrd'} 0x1CE1, # .. 0x1CE1 ; {'Beng', 'Deva'} - 0x1CE2, # .. 0x1CE9 ; {'Deva'} + 0x1CE2, # .. 0x1CE8 ; {'Deva'} + 0x1CE9, # .. 0x1CE9 ; {'Deva', 'Nand'} 0x1CEA, # .. 0x1CEA ; {'Beng', 'Deva'} 0x1CEB, # .. 0x1CEC ; {'Deva'} 0x1CED, # .. 0x1CED ; {'Beng', 'Deva'} 0x1CEE, # .. 0x1CF1 ; {'Deva'} - 0x1CF2, # .. 0x1CF3 ; {'Deva', 'Gran'} + 0x1CF2, # .. 0x1CF2 ; {'Beng', 'Deva', 'Gran', 'Knda', 'Nand', 'Orya', 'Telu', 'Tirh'} + 0x1CF3, # .. 0x1CF3 ; {'Deva', 'Gran'} 0x1CF4, # .. 0x1CF4 ; {'Deva', 'Gran', 'Knda'} 0x1CF5, # .. 0x1CF6 ; {'Beng', 'Deva'} 0x1CF7, # .. 0x1CF7 ; {'Beng'} 0x1CF8, # .. 0x1CF9 ; {'Deva', 'Gran'} - 0x1CFA, # .. 0x1DBF ; None + 0x1CFA, # .. 0x1CFA ; {'Nand'} + 0x1CFB, # .. 0x1DBF ; None 0x1DC0, # .. 0x1DC1 ; {'Grek'} - 0x1DC2, # .. 0x20EF ; None + 0x1DC2, # .. 0x202E ; None + 0x202F, # .. 0x202F ; {'Latn', 'Mong'} + 0x2030, # .. 0x20EF ; None 0x20F0, # .. 0x20F0 ; {'Deva', 'Gran', 'Latn'} 0x20F1, # .. 0x2E42 ; None 0x2E43, # .. 0x2E43 ; {'Cyrl', 'Glag'} @@ -166,7 +173,9 @@ RANGES = [ 0x3280, # .. 0x32B0 ; {'Hani'} 0x32B1, # .. 0x32BF ; None 0x32C0, # .. 0x32CB ; {'Hani'} - 0x32CC, # .. 0x3357 ; None + 0x32CC, # .. 0x32FE ; None + 0x32FF, # .. 0x32FF ; {'Hani'} + 0x3300, # .. 0x3357 ; None 0x3358, # .. 0x3370 ; {'Hani'} 0x3371, # .. 0x337A ; None 0x337B, # .. 0x337F ; {'Hani'} @@ -175,8 +184,8 @@ RANGES = [ 0x33FF, # .. 0xA66E ; None 0xA66F, # .. 0xA66F ; {'Cyrl', 'Glag'} 0xA670, # .. 0xA82F ; None - 0xA830, # .. 0xA832 ; {'Deva', 'Dogr', 'Gujr', 'Guru', 'Khoj', 'Knda', 'Kthi', 'Mahj', 'Mlym', 'Modi', 'Sind', 'Takr', 'Tirh'} - 0xA833, # .. 0xA835 ; {'Deva', 'Dogr', 'Gujr', 'Guru', 'Khoj', 'Knda', 'Kthi', 'Mahj', 'Modi', 'Sind', 'Takr', 'Tirh'} + 0xA830, # .. 0xA832 ; {'Deva', 'Dogr', 'Gujr', 'Guru', 'Khoj', 'Knda', 'Kthi', 'Mahj', 'Mlym', 'Modi', 'Nand', 'Sind', 'Takr', 'Tirh'} + 0xA833, # .. 0xA835 ; {'Deva', 'Dogr', 'Gujr', 'Guru', 'Khoj', 'Knda', 'Kthi', 'Mahj', 'Modi', 'Nand', 'Sind', 'Takr', 'Tirh'} 0xA836, # .. 0xA839 ; {'Deva', 'Dogr', 'Gujr', 'Guru', 'Khoj', 'Kthi', 'Mahj', 'Modi', 'Sind', 'Takr', 'Tirh'} 0xA83A, # .. 0xA8F0 ; None 0xA8F1, # .. 0xA8F1 ; {'Beng', 'Deva'} @@ -212,7 +221,11 @@ RANGES = [ 0x11303, # .. 0x11303 ; {'Gran', 'Taml'} 0x11304, # .. 0x1133A ; None 0x1133B, # .. 0x1133C ; {'Gran', 'Taml'} - 0x1133D, # .. 0x1BC9F ; None + 0x1133D, # .. 0x11FCF ; None + 0x11FD0, # .. 0x11FD1 ; {'Gran', 'Taml'} + 0x11FD2, # .. 0x11FD2 ; None + 0x11FD3, # .. 0x11FD3 ; {'Gran', 'Taml'} + 0x11FD4, # .. 0x1BC9F ; None 0x1BCA0, # .. 0x1BCA3 ; {'Dupl'} 0x1BCA4, # .. 0x1D35F ; None 0x1D360, # .. 0x1D371 ; {'Hani'} @@ -256,8 +269,8 @@ VALUES = [ {'Beng', 'Deva', 'Gran', 'Gujr', 'Guru', 'Knda', 'Latn', 'Mlym', 'Orya', 'Shrd', 'Taml', 'Telu', 'Tirh'}, # 0951..0951 {'Beng', 'Deva', 'Gran', 'Gujr', 'Guru', 'Knda', 'Latn', 'Mlym', 'Orya', 'Taml', 'Telu', 'Tirh'}, # 0952..0952 None, # 0953..0963 - {'Beng', 'Deva', 'Dogr', 'Gong', 'Gran', 'Gujr', 'Guru', 'Knda', 'Mahj', 'Mlym', 'Orya', 'Sind', 'Sinh', 'Sylo', 'Takr', 'Taml', 'Telu', 'Tirh'}, # 0964..0964 - {'Beng', 'Deva', 'Dogr', 'Gong', 'Gran', 'Gujr', 'Guru', 'Knda', 'Limb', 'Mahj', 'Mlym', 'Orya', 'Sind', 'Sinh', 'Sylo', 'Takr', 'Taml', 'Telu', 'Tirh'}, # 0965..0965 + {'Beng', 'Deva', 'Dogr', 'Gong', 'Gonm', 'Gran', 'Gujr', 'Guru', 'Knda', 'Mahj', 'Mlym', 'Nand', 'Orya', 'Sind', 'Sinh', 'Sylo', 'Takr', 'Taml', 'Telu', 'Tirh'}, # 0964..0964 + {'Beng', 'Deva', 'Dogr', 'Gong', 'Gonm', 'Gran', 'Gujr', 'Guru', 'Knda', 'Limb', 'Mahj', 'Mlym', 'Nand', 'Orya', 'Sind', 'Sinh', 'Sylo', 'Takr', 'Taml', 'Telu', 'Tirh'}, # 0965..0965 {'Deva', 'Dogr', 'Kthi', 'Mahj'}, # 0966..096F None, # 0970..09E5 {'Beng', 'Cakm', 'Sylo'}, # 09E6..09EF @@ -267,7 +280,9 @@ VALUES = [ {'Gujr', 'Khoj'}, # 0AE6..0AEF None, # 0AF0..0BE5 {'Gran', 'Taml'}, # 0BE6..0BF3 - None, # 0BF4..103F + None, # 0BF4..0CE5 + {'Knda', 'Nand'}, # 0CE6..0CEF + None, # 0CF0..103F {'Cakm', 'Mymr', 'Tale'}, # 1040..1049 None, # 104A..10FA {'Geor', 'Latn'}, # 10FB..10FB @@ -293,19 +308,24 @@ VALUES = [ {'Deva'}, # 1CDE..1CDF {'Deva', 'Shrd'}, # 1CE0..1CE0 {'Beng', 'Deva'}, # 1CE1..1CE1 - {'Deva'}, # 1CE2..1CE9 + {'Deva'}, # 1CE2..1CE8 + {'Deva', 'Nand'}, # 1CE9..1CE9 {'Beng', 'Deva'}, # 1CEA..1CEA {'Deva'}, # 1CEB..1CEC {'Beng', 'Deva'}, # 1CED..1CED {'Deva'}, # 1CEE..1CF1 - {'Deva', 'Gran'}, # 1CF2..1CF3 + {'Beng', 'Deva', 'Gran', 'Knda', 'Nand', 'Orya', 'Telu', 'Tirh'}, # 1CF2..1CF2 + {'Deva', 'Gran'}, # 1CF3..1CF3 {'Deva', 'Gran', 'Knda'}, # 1CF4..1CF4 {'Beng', 'Deva'}, # 1CF5..1CF6 {'Beng'}, # 1CF7..1CF7 {'Deva', 'Gran'}, # 1CF8..1CF9 - None, # 1CFA..1DBF + {'Nand'}, # 1CFA..1CFA + None, # 1CFB..1DBF {'Grek'}, # 1DC0..1DC1 - None, # 1DC2..20EF + None, # 1DC2..202E + {'Latn', 'Mong'}, # 202F..202F + None, # 2030..20EF {'Deva', 'Gran', 'Latn'}, # 20F0..20F0 None, # 20F1..2E42 {'Cyrl', 'Glag'}, # 2E43..2E43 @@ -347,7 +367,9 @@ VALUES = [ {'Hani'}, # 3280..32B0 None, # 32B1..32BF {'Hani'}, # 32C0..32CB - None, # 32CC..3357 + None, # 32CC..32FE + {'Hani'}, # 32FF..32FF + None, # 3300..3357 {'Hani'}, # 3358..3370 None, # 3371..337A {'Hani'}, # 337B..337F @@ -356,8 +378,8 @@ VALUES = [ None, # 33FF..A66E {'Cyrl', 'Glag'}, # A66F..A66F None, # A670..A82F - {'Deva', 'Dogr', 'Gujr', 'Guru', 'Khoj', 'Knda', 'Kthi', 'Mahj', 'Mlym', 'Modi', 'Sind', 'Takr', 'Tirh'}, # A830..A832 - {'Deva', 'Dogr', 'Gujr', 'Guru', 'Khoj', 'Knda', 'Kthi', 'Mahj', 'Modi', 'Sind', 'Takr', 'Tirh'}, # A833..A835 + {'Deva', 'Dogr', 'Gujr', 'Guru', 'Khoj', 'Knda', 'Kthi', 'Mahj', 'Mlym', 'Modi', 'Nand', 'Sind', 'Takr', 'Tirh'}, # A830..A832 + {'Deva', 'Dogr', 'Gujr', 'Guru', 'Khoj', 'Knda', 'Kthi', 'Mahj', 'Modi', 'Nand', 'Sind', 'Takr', 'Tirh'}, # A833..A835 {'Deva', 'Dogr', 'Gujr', 'Guru', 'Khoj', 'Kthi', 'Mahj', 'Modi', 'Sind', 'Takr', 'Tirh'}, # A836..A839 None, # A83A..A8F0 {'Beng', 'Deva'}, # A8F1..A8F1 @@ -393,7 +415,11 @@ VALUES = [ {'Gran', 'Taml'}, # 11303..11303 None, # 11304..1133A {'Gran', 'Taml'}, # 1133B..1133C - None, # 1133D..1BC9F + None, # 1133D..11FCF + {'Gran', 'Taml'}, # 11FD0..11FD1 + None, # 11FD2..11FD2 + {'Gran', 'Taml'}, # 11FD3..11FD3 + None, # 11FD4..1BC9F {'Dupl'}, # 1BCA0..1BCA3 None, # 1BCA4..1D35F {'Hani'}, # 1D360..1D371 diff --git a/Lib/fontTools/unicodedata/Scripts.py b/Lib/fontTools/unicodedata/Scripts.py index 30cd8f5e..dc8c1e2b 100644 --- a/Lib/fontTools/unicodedata/Scripts.py +++ b/Lib/fontTools/unicodedata/Scripts.py @@ -4,9 +4,9 @@ # Source: https://unicode.org/Public/UNIDATA/Scripts.txt # License: http://unicode.org/copyright.html#License # -# Scripts-11.0.0.txt -# Date: 2018-02-21, 05:34:31 GMT -# © 2018 Unicode®, Inc. +# Scripts-12.1.0.txt +# Date: 2019-04-01, 09:10:42 GMT +# © 2019 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. # For terms of use, see http://www.unicode.org/terms_of_use.html # @@ -128,8 +128,8 @@ RANGES = [ 0x08E2, # .. 0x08E2 ; Common 0x08E3, # .. 0x08FF ; Arabic 0x0900, # .. 0x0950 ; Devanagari - 0x0951, # .. 0x0952 ; Inherited - 0x0953, # .. 0x0963 ; Devanagari + 0x0951, # .. 0x0954 ; Inherited + 0x0955, # .. 0x0963 ; Devanagari 0x0964, # .. 0x0965 ; Common 0x0966, # .. 0x097F ; Devanagari 0x0980, # .. 0x0983 ; Bengali @@ -301,8 +301,8 @@ RANGES = [ 0x0C60, # .. 0x0C63 ; Telugu 0x0C64, # .. 0x0C65 ; Unknown 0x0C66, # .. 0x0C6F ; Telugu - 0x0C70, # .. 0x0C77 ; Unknown - 0x0C78, # .. 0x0C7F ; Telugu + 0x0C70, # .. 0x0C76 ; Unknown + 0x0C77, # .. 0x0C7F ; Telugu 0x0C80, # .. 0x0C8C ; Kannada 0x0C8D, # .. 0x0C8D ; Unknown 0x0C8E, # .. 0x0C90 ; Kannada @@ -377,28 +377,14 @@ RANGES = [ 0x0E81, # .. 0x0E82 ; Lao 0x0E83, # .. 0x0E83 ; Unknown 0x0E84, # .. 0x0E84 ; Lao - 0x0E85, # .. 0x0E86 ; Unknown - 0x0E87, # .. 0x0E88 ; Lao - 0x0E89, # .. 0x0E89 ; Unknown - 0x0E8A, # .. 0x0E8A ; Lao - 0x0E8B, # .. 0x0E8C ; Unknown - 0x0E8D, # .. 0x0E8D ; Lao - 0x0E8E, # .. 0x0E93 ; Unknown - 0x0E94, # .. 0x0E97 ; Lao - 0x0E98, # .. 0x0E98 ; Unknown - 0x0E99, # .. 0x0E9F ; Lao - 0x0EA0, # .. 0x0EA0 ; Unknown - 0x0EA1, # .. 0x0EA3 ; Lao + 0x0E85, # .. 0x0E85 ; Unknown + 0x0E86, # .. 0x0E8A ; Lao + 0x0E8B, # .. 0x0E8B ; Unknown + 0x0E8C, # .. 0x0EA3 ; Lao 0x0EA4, # .. 0x0EA4 ; Unknown 0x0EA5, # .. 0x0EA5 ; Lao 0x0EA6, # .. 0x0EA6 ; Unknown - 0x0EA7, # .. 0x0EA7 ; Lao - 0x0EA8, # .. 0x0EA9 ; Unknown - 0x0EAA, # .. 0x0EAB ; Lao - 0x0EAC, # .. 0x0EAC ; Unknown - 0x0EAD, # .. 0x0EB9 ; Lao - 0x0EBA, # .. 0x0EBA ; Unknown - 0x0EBB, # .. 0x0EBD ; Lao + 0x0EA7, # .. 0x0EBD ; Lao 0x0EBE, # .. 0x0EBF ; Unknown 0x0EC0, # .. 0x0EC4 ; Lao 0x0EC5, # .. 0x0EC5 ; Unknown @@ -585,7 +571,8 @@ RANGES = [ 0x1CF4, # .. 0x1CF4 ; Inherited 0x1CF5, # .. 0x1CF7 ; Common 0x1CF8, # .. 0x1CF9 ; Inherited - 0x1CFA, # .. 0x1CFF ; Unknown + 0x1CFA, # .. 0x1CFA ; Common + 0x1CFB, # .. 0x1CFF ; Unknown 0x1D00, # .. 0x1D25 ; Latin 0x1D26, # .. 0x1D2A ; Greek 0x1D2B, # .. 0x1D2B ; Cyrillic @@ -672,10 +659,7 @@ RANGES = [ 0x2B74, # .. 0x2B75 ; Unknown 0x2B76, # .. 0x2B95 ; Common 0x2B96, # .. 0x2B97 ; Unknown - 0x2B98, # .. 0x2BC8 ; Common - 0x2BC9, # .. 0x2BC9 ; Unknown - 0x2BCA, # .. 0x2BFE ; Common - 0x2BFF, # .. 0x2BFF ; Unknown + 0x2B98, # .. 0x2BFF ; Common 0x2C00, # .. 0x2C2E ; Glagolitic 0x2C2F, # .. 0x2C2F ; Unknown 0x2C30, # .. 0x2C5E ; Glagolitic @@ -714,8 +698,8 @@ RANGES = [ 0x2DD8, # .. 0x2DDE ; Ethiopic 0x2DDF, # .. 0x2DDF ; Unknown 0x2DE0, # .. 0x2DFF ; Cyrillic - 0x2E00, # .. 0x2E4E ; Common - 0x2E4F, # .. 0x2E7F ; Unknown + 0x2E00, # .. 0x2E4F ; Common + 0x2E50, # .. 0x2E7F ; Unknown 0x2E80, # .. 0x2E99 ; Han 0x2E9A, # .. 0x2E9A ; Unknown 0x2E9B, # .. 0x2EF3 ; Han @@ -762,7 +746,7 @@ RANGES = [ 0x3260, # .. 0x327E ; Hangul 0x327F, # .. 0x32CF ; Common 0x32D0, # .. 0x32FE ; Katakana - 0x32FF, # .. 0x32FF ; Unknown + 0x32FF, # .. 0x32FF ; Common 0x3300, # .. 0x3357 ; Katakana 0x3358, # .. 0x33FF ; Common 0x3400, # .. 0x4DB5 ; Han @@ -783,8 +767,10 @@ RANGES = [ 0xA700, # .. 0xA721 ; Common 0xA722, # .. 0xA787 ; Latin 0xA788, # .. 0xA78A ; Common - 0xA78B, # .. 0xA7B9 ; Latin - 0xA7BA, # .. 0xA7F6 ; Unknown + 0xA78B, # .. 0xA7BF ; Latin + 0xA7C0, # .. 0xA7C1 ; Unknown + 0xA7C2, # .. 0xA7C6 ; Latin + 0xA7C7, # .. 0xA7F6 ; Unknown 0xA7F7, # .. 0xA7FF ; Latin 0xA800, # .. 0xA82B ; Syloti_Nagri 0xA82C, # .. 0xA82F ; Unknown @@ -840,7 +826,8 @@ RANGES = [ 0xAB5B, # .. 0xAB5B ; Common 0xAB5C, # .. 0xAB64 ; Latin 0xAB65, # .. 0xAB65 ; Greek - 0xAB66, # .. 0xAB6F ; Unknown + 0xAB66, # .. 0xAB67 ; Latin + 0xAB68, # .. 0xAB6F ; Unknown 0xAB70, # .. 0xABBF ; Cherokee 0xABC0, # .. 0xABED ; Meetei_Mayek 0xABEE, # .. 0xABEF ; Unknown @@ -1086,7 +1073,9 @@ RANGES = [ 0x10F00, # .. 0x10F27 ; Old_Sogdian 0x10F28, # .. 0x10F2F ; Unknown 0x10F30, # .. 0x10F59 ; Sogdian - 0x10F5A, # .. 0x10FFF ; Unknown + 0x10F5A, # .. 0x10FDF ; Unknown + 0x10FE0, # .. 0x10FF6 ; Elymaic + 0x10FF7, # .. 0x10FFF ; Unknown 0x11000, # .. 0x1104D ; Brahmi 0x1104E, # .. 0x11051 ; Unknown 0x11052, # .. 0x1106F ; Brahmi @@ -1165,8 +1154,8 @@ RANGES = [ 0x1145A, # .. 0x1145A ; Unknown 0x1145B, # .. 0x1145B ; Newa 0x1145C, # .. 0x1145C ; Unknown - 0x1145D, # .. 0x1145E ; Newa - 0x1145F, # .. 0x1147F ; Unknown + 0x1145D, # .. 0x1145F ; Newa + 0x11460, # .. 0x1147F ; Unknown 0x11480, # .. 0x114C7 ; Tirhuta 0x114C8, # .. 0x114CF ; Unknown 0x114D0, # .. 0x114D9 ; Tirhuta @@ -1181,8 +1170,8 @@ RANGES = [ 0x1165A, # .. 0x1165F ; Unknown 0x11660, # .. 0x1166C ; Mongolian 0x1166D, # .. 0x1167F ; Unknown - 0x11680, # .. 0x116B7 ; Takri - 0x116B8, # .. 0x116BF ; Unknown + 0x11680, # .. 0x116B8 ; Takri + 0x116B9, # .. 0x116BF ; Unknown 0x116C0, # .. 0x116C9 ; Takri 0x116CA, # .. 0x116FF ; Unknown 0x11700, # .. 0x1171A ; Ahom @@ -1196,12 +1185,16 @@ RANGES = [ 0x118A0, # .. 0x118F2 ; Warang_Citi 0x118F3, # .. 0x118FE ; Unknown 0x118FF, # .. 0x118FF ; Warang_Citi - 0x11900, # .. 0x119FF ; Unknown + 0x11900, # .. 0x1199F ; Unknown + 0x119A0, # .. 0x119A7 ; Nandinagari + 0x119A8, # .. 0x119A9 ; Unknown + 0x119AA, # .. 0x119D7 ; Nandinagari + 0x119D8, # .. 0x119D9 ; Unknown + 0x119DA, # .. 0x119E4 ; Nandinagari + 0x119E5, # .. 0x119FF ; Unknown 0x11A00, # .. 0x11A47 ; Zanabazar_Square 0x11A48, # .. 0x11A4F ; Unknown - 0x11A50, # .. 0x11A83 ; Soyombo - 0x11A84, # .. 0x11A85 ; Unknown - 0x11A86, # .. 0x11AA2 ; Soyombo + 0x11A50, # .. 0x11AA2 ; Soyombo 0x11AA3, # .. 0x11ABF ; Unknown 0x11AC0, # .. 0x11AF8 ; Pau_Cin_Hau 0x11AF9, # .. 0x11BFF ; Unknown @@ -1246,7 +1239,10 @@ RANGES = [ 0x11DA0, # .. 0x11DA9 ; Gunjala_Gondi 0x11DAA, # .. 0x11EDF ; Unknown 0x11EE0, # .. 0x11EF8 ; Makasar - 0x11EF9, # .. 0x11FFF ; Unknown + 0x11EF9, # .. 0x11FBF ; Unknown + 0x11FC0, # .. 0x11FF1 ; Tamil + 0x11FF2, # .. 0x11FFE ; Unknown + 0x11FFF, # .. 0x11FFF ; Tamil 0x12000, # .. 0x12399 ; Cuneiform 0x1239A, # .. 0x123FF ; Unknown 0x12400, # .. 0x1246E ; Cuneiform @@ -1256,7 +1252,9 @@ RANGES = [ 0x12480, # .. 0x12543 ; Cuneiform 0x12544, # .. 0x12FFF ; Unknown 0x13000, # .. 0x1342E ; Egyptian_Hieroglyphs - 0x1342F, # .. 0x143FF ; Unknown + 0x1342F, # .. 0x1342F ; Unknown + 0x13430, # .. 0x13438 ; Egyptian_Hieroglyphs + 0x13439, # .. 0x143FF ; Unknown 0x14400, # .. 0x14646 ; Anatolian_Hieroglyphs 0x14647, # .. 0x167FF ; Unknown 0x16800, # .. 0x16A38 ; Bamum @@ -1283,22 +1281,27 @@ RANGES = [ 0x16B90, # .. 0x16E3F ; Unknown 0x16E40, # .. 0x16E9A ; Medefaidrin 0x16E9B, # .. 0x16EFF ; Unknown - 0x16F00, # .. 0x16F44 ; Miao - 0x16F45, # .. 0x16F4F ; Unknown - 0x16F50, # .. 0x16F7E ; Miao - 0x16F7F, # .. 0x16F8E ; Unknown + 0x16F00, # .. 0x16F4A ; Miao + 0x16F4B, # .. 0x16F4E ; Unknown + 0x16F4F, # .. 0x16F87 ; Miao + 0x16F88, # .. 0x16F8E ; Unknown 0x16F8F, # .. 0x16F9F ; Miao 0x16FA0, # .. 0x16FDF ; Unknown 0x16FE0, # .. 0x16FE0 ; Tangut 0x16FE1, # .. 0x16FE1 ; Nushu - 0x16FE2, # .. 0x16FFF ; Unknown - 0x17000, # .. 0x187F1 ; Tangut - 0x187F2, # .. 0x187FF ; Unknown + 0x16FE2, # .. 0x16FE3 ; Common + 0x16FE4, # .. 0x16FFF ; Unknown + 0x17000, # .. 0x187F7 ; Tangut + 0x187F8, # .. 0x187FF ; Unknown 0x18800, # .. 0x18AF2 ; Tangut 0x18AF3, # .. 0x1AFFF ; Unknown 0x1B000, # .. 0x1B000 ; Katakana 0x1B001, # .. 0x1B11E ; Hiragana - 0x1B11F, # .. 0x1B16F ; Unknown + 0x1B11F, # .. 0x1B14F ; Unknown + 0x1B150, # .. 0x1B152 ; Hiragana + 0x1B153, # .. 0x1B163 ; Unknown + 0x1B164, # .. 0x1B167 ; Katakana + 0x1B168, # .. 0x1B16F ; Unknown 0x1B170, # .. 0x1B2FB ; Nushu 0x1B2FC, # .. 0x1BBFF ; Unknown 0x1BC00, # .. 0x1BC6A ; Duployan @@ -1390,19 +1393,33 @@ RANGES = [ 0x1E023, # .. 0x1E024 ; Glagolitic 0x1E025, # .. 0x1E025 ; Unknown 0x1E026, # .. 0x1E02A ; Glagolitic - 0x1E02B, # .. 0x1E7FF ; Unknown + 0x1E02B, # .. 0x1E0FF ; Unknown + 0x1E100, # .. 0x1E12C ; Nyiakeng_Puachue_Hmong + 0x1E12D, # .. 0x1E12F ; Unknown + 0x1E130, # .. 0x1E13D ; Nyiakeng_Puachue_Hmong + 0x1E13E, # .. 0x1E13F ; Unknown + 0x1E140, # .. 0x1E149 ; Nyiakeng_Puachue_Hmong + 0x1E14A, # .. 0x1E14D ; Unknown + 0x1E14E, # .. 0x1E14F ; Nyiakeng_Puachue_Hmong + 0x1E150, # .. 0x1E2BF ; Unknown + 0x1E2C0, # .. 0x1E2F9 ; Wancho + 0x1E2FA, # .. 0x1E2FE ; Unknown + 0x1E2FF, # .. 0x1E2FF ; Wancho + 0x1E300, # .. 0x1E7FF ; Unknown 0x1E800, # .. 0x1E8C4 ; Mende_Kikakui 0x1E8C5, # .. 0x1E8C6 ; Unknown 0x1E8C7, # .. 0x1E8D6 ; Mende_Kikakui 0x1E8D7, # .. 0x1E8FF ; Unknown - 0x1E900, # .. 0x1E94A ; Adlam - 0x1E94B, # .. 0x1E94F ; Unknown + 0x1E900, # .. 0x1E94B ; Adlam + 0x1E94C, # .. 0x1E94F ; Unknown 0x1E950, # .. 0x1E959 ; Adlam 0x1E95A, # .. 0x1E95D ; Unknown 0x1E95E, # .. 0x1E95F ; Adlam 0x1E960, # .. 0x1EC70 ; Unknown 0x1EC71, # .. 0x1ECB4 ; Common - 0x1ECB5, # .. 0x1EDFF ; Unknown + 0x1ECB5, # .. 0x1ED00 ; Unknown + 0x1ED01, # .. 0x1ED3D ; Common + 0x1ED3E, # .. 0x1EDFF ; Unknown 0x1EE00, # .. 0x1EE03 ; Arabic 0x1EE04, # .. 0x1EE04 ; Unknown 0x1EE05, # .. 0x1EE1F ; Arabic @@ -1485,8 +1502,8 @@ RANGES = [ 0x1F0F6, # .. 0x1F0FF ; Unknown 0x1F100, # .. 0x1F10C ; Common 0x1F10D, # .. 0x1F10F ; Unknown - 0x1F110, # .. 0x1F16B ; Common - 0x1F16C, # .. 0x1F16F ; Unknown + 0x1F110, # .. 0x1F16C ; Common + 0x1F16D, # .. 0x1F16F ; Unknown 0x1F170, # .. 0x1F1AC ; Common 0x1F1AD, # .. 0x1F1E5 ; Unknown 0x1F1E6, # .. 0x1F1FF ; Common @@ -1501,16 +1518,18 @@ RANGES = [ 0x1F252, # .. 0x1F25F ; Unknown 0x1F260, # .. 0x1F265 ; Common 0x1F266, # .. 0x1F2FF ; Unknown - 0x1F300, # .. 0x1F6D4 ; Common - 0x1F6D5, # .. 0x1F6DF ; Unknown + 0x1F300, # .. 0x1F6D5 ; Common + 0x1F6D6, # .. 0x1F6DF ; Unknown 0x1F6E0, # .. 0x1F6EC ; Common 0x1F6ED, # .. 0x1F6EF ; Unknown - 0x1F6F0, # .. 0x1F6F9 ; Common - 0x1F6FA, # .. 0x1F6FF ; Unknown + 0x1F6F0, # .. 0x1F6FA ; Common + 0x1F6FB, # .. 0x1F6FF ; Unknown 0x1F700, # .. 0x1F773 ; Common 0x1F774, # .. 0x1F77F ; Unknown 0x1F780, # .. 0x1F7D8 ; Common - 0x1F7D9, # .. 0x1F7FF ; Unknown + 0x1F7D9, # .. 0x1F7DF ; Unknown + 0x1F7E0, # .. 0x1F7EB ; Common + 0x1F7EC, # .. 0x1F7FF ; Unknown 0x1F800, # .. 0x1F80B ; Common 0x1F80C, # .. 0x1F80F ; Unknown 0x1F810, # .. 0x1F847 ; Common @@ -1522,25 +1541,29 @@ RANGES = [ 0x1F890, # .. 0x1F8AD ; Common 0x1F8AE, # .. 0x1F8FF ; Unknown 0x1F900, # .. 0x1F90B ; Common - 0x1F90C, # .. 0x1F90F ; Unknown - 0x1F910, # .. 0x1F93E ; Common - 0x1F93F, # .. 0x1F93F ; Unknown - 0x1F940, # .. 0x1F970 ; Common - 0x1F971, # .. 0x1F972 ; Unknown + 0x1F90C, # .. 0x1F90C ; Unknown + 0x1F90D, # .. 0x1F971 ; Common + 0x1F972, # .. 0x1F972 ; Unknown 0x1F973, # .. 0x1F976 ; Common 0x1F977, # .. 0x1F979 ; Unknown - 0x1F97A, # .. 0x1F97A ; Common - 0x1F97B, # .. 0x1F97B ; Unknown - 0x1F97C, # .. 0x1F9A2 ; Common - 0x1F9A3, # .. 0x1F9AF ; Unknown - 0x1F9B0, # .. 0x1F9B9 ; Common - 0x1F9BA, # .. 0x1F9BF ; Unknown - 0x1F9C0, # .. 0x1F9C2 ; Common - 0x1F9C3, # .. 0x1F9CF ; Unknown - 0x1F9D0, # .. 0x1F9FF ; Common - 0x1FA00, # .. 0x1FA5F ; Unknown + 0x1F97A, # .. 0x1F9A2 ; Common + 0x1F9A3, # .. 0x1F9A4 ; Unknown + 0x1F9A5, # .. 0x1F9AA ; Common + 0x1F9AB, # .. 0x1F9AD ; Unknown + 0x1F9AE, # .. 0x1F9CA ; Common + 0x1F9CB, # .. 0x1F9CC ; Unknown + 0x1F9CD, # .. 0x1FA53 ; Common + 0x1FA54, # .. 0x1FA5F ; Unknown 0x1FA60, # .. 0x1FA6D ; Common - 0x1FA6E, # .. 0x1FFFF ; Unknown + 0x1FA6E, # .. 0x1FA6F ; Unknown + 0x1FA70, # .. 0x1FA73 ; Common + 0x1FA74, # .. 0x1FA77 ; Unknown + 0x1FA78, # .. 0x1FA7A ; Common + 0x1FA7B, # .. 0x1FA7F ; Unknown + 0x1FA80, # .. 0x1FA82 ; Common + 0x1FA83, # .. 0x1FA8F ; Unknown + 0x1FA90, # .. 0x1FA95 ; Common + 0x1FA96, # .. 0x1FFFF ; Unknown 0x20000, # .. 0x2A6D6 ; Han 0x2A6D7, # .. 0x2A6FF ; Unknown 0x2A700, # .. 0x2B734 ; Han @@ -1669,8 +1692,8 @@ VALUES = [ 'Zyyy', # 08E2..08E2 ; Common 'Arab', # 08E3..08FF ; Arabic 'Deva', # 0900..0950 ; Devanagari - 'Zinh', # 0951..0952 ; Inherited - 'Deva', # 0953..0963 ; Devanagari + 'Zinh', # 0951..0954 ; Inherited + 'Deva', # 0955..0963 ; Devanagari 'Zyyy', # 0964..0965 ; Common 'Deva', # 0966..097F ; Devanagari 'Beng', # 0980..0983 ; Bengali @@ -1842,8 +1865,8 @@ VALUES = [ 'Telu', # 0C60..0C63 ; Telugu 'Zzzz', # 0C64..0C65 ; Unknown 'Telu', # 0C66..0C6F ; Telugu - 'Zzzz', # 0C70..0C77 ; Unknown - 'Telu', # 0C78..0C7F ; Telugu + 'Zzzz', # 0C70..0C76 ; Unknown + 'Telu', # 0C77..0C7F ; Telugu 'Knda', # 0C80..0C8C ; Kannada 'Zzzz', # 0C8D..0C8D ; Unknown 'Knda', # 0C8E..0C90 ; Kannada @@ -1918,28 +1941,14 @@ VALUES = [ 'Laoo', # 0E81..0E82 ; Lao 'Zzzz', # 0E83..0E83 ; Unknown 'Laoo', # 0E84..0E84 ; Lao - 'Zzzz', # 0E85..0E86 ; Unknown - 'Laoo', # 0E87..0E88 ; Lao - 'Zzzz', # 0E89..0E89 ; Unknown - 'Laoo', # 0E8A..0E8A ; Lao - 'Zzzz', # 0E8B..0E8C ; Unknown - 'Laoo', # 0E8D..0E8D ; Lao - 'Zzzz', # 0E8E..0E93 ; Unknown - 'Laoo', # 0E94..0E97 ; Lao - 'Zzzz', # 0E98..0E98 ; Unknown - 'Laoo', # 0E99..0E9F ; Lao - 'Zzzz', # 0EA0..0EA0 ; Unknown - 'Laoo', # 0EA1..0EA3 ; Lao + 'Zzzz', # 0E85..0E85 ; Unknown + 'Laoo', # 0E86..0E8A ; Lao + 'Zzzz', # 0E8B..0E8B ; Unknown + 'Laoo', # 0E8C..0EA3 ; Lao 'Zzzz', # 0EA4..0EA4 ; Unknown 'Laoo', # 0EA5..0EA5 ; Lao 'Zzzz', # 0EA6..0EA6 ; Unknown - 'Laoo', # 0EA7..0EA7 ; Lao - 'Zzzz', # 0EA8..0EA9 ; Unknown - 'Laoo', # 0EAA..0EAB ; Lao - 'Zzzz', # 0EAC..0EAC ; Unknown - 'Laoo', # 0EAD..0EB9 ; Lao - 'Zzzz', # 0EBA..0EBA ; Unknown - 'Laoo', # 0EBB..0EBD ; Lao + 'Laoo', # 0EA7..0EBD ; Lao 'Zzzz', # 0EBE..0EBF ; Unknown 'Laoo', # 0EC0..0EC4 ; Lao 'Zzzz', # 0EC5..0EC5 ; Unknown @@ -2126,7 +2135,8 @@ VALUES = [ 'Zinh', # 1CF4..1CF4 ; Inherited 'Zyyy', # 1CF5..1CF7 ; Common 'Zinh', # 1CF8..1CF9 ; Inherited - 'Zzzz', # 1CFA..1CFF ; Unknown + 'Zyyy', # 1CFA..1CFA ; Common + 'Zzzz', # 1CFB..1CFF ; Unknown 'Latn', # 1D00..1D25 ; Latin 'Grek', # 1D26..1D2A ; Greek 'Cyrl', # 1D2B..1D2B ; Cyrillic @@ -2213,10 +2223,7 @@ VALUES = [ 'Zzzz', # 2B74..2B75 ; Unknown 'Zyyy', # 2B76..2B95 ; Common 'Zzzz', # 2B96..2B97 ; Unknown - 'Zyyy', # 2B98..2BC8 ; Common - 'Zzzz', # 2BC9..2BC9 ; Unknown - 'Zyyy', # 2BCA..2BFE ; Common - 'Zzzz', # 2BFF..2BFF ; Unknown + 'Zyyy', # 2B98..2BFF ; Common 'Glag', # 2C00..2C2E ; Glagolitic 'Zzzz', # 2C2F..2C2F ; Unknown 'Glag', # 2C30..2C5E ; Glagolitic @@ -2255,8 +2262,8 @@ VALUES = [ 'Ethi', # 2DD8..2DDE ; Ethiopic 'Zzzz', # 2DDF..2DDF ; Unknown 'Cyrl', # 2DE0..2DFF ; Cyrillic - 'Zyyy', # 2E00..2E4E ; Common - 'Zzzz', # 2E4F..2E7F ; Unknown + 'Zyyy', # 2E00..2E4F ; Common + 'Zzzz', # 2E50..2E7F ; Unknown 'Hani', # 2E80..2E99 ; Han 'Zzzz', # 2E9A..2E9A ; Unknown 'Hani', # 2E9B..2EF3 ; Han @@ -2303,7 +2310,7 @@ VALUES = [ 'Hang', # 3260..327E ; Hangul 'Zyyy', # 327F..32CF ; Common 'Kana', # 32D0..32FE ; Katakana - 'Zzzz', # 32FF..32FF ; Unknown + 'Zyyy', # 32FF..32FF ; Common 'Kana', # 3300..3357 ; Katakana 'Zyyy', # 3358..33FF ; Common 'Hani', # 3400..4DB5 ; Han @@ -2324,8 +2331,10 @@ VALUES = [ 'Zyyy', # A700..A721 ; Common 'Latn', # A722..A787 ; Latin 'Zyyy', # A788..A78A ; Common - 'Latn', # A78B..A7B9 ; Latin - 'Zzzz', # A7BA..A7F6 ; Unknown + 'Latn', # A78B..A7BF ; Latin + 'Zzzz', # A7C0..A7C1 ; Unknown + 'Latn', # A7C2..A7C6 ; Latin + 'Zzzz', # A7C7..A7F6 ; Unknown 'Latn', # A7F7..A7FF ; Latin 'Sylo', # A800..A82B ; Syloti_Nagri 'Zzzz', # A82C..A82F ; Unknown @@ -2381,7 +2390,8 @@ VALUES = [ 'Zyyy', # AB5B..AB5B ; Common 'Latn', # AB5C..AB64 ; Latin 'Grek', # AB65..AB65 ; Greek - 'Zzzz', # AB66..AB6F ; Unknown + 'Latn', # AB66..AB67 ; Latin + 'Zzzz', # AB68..AB6F ; Unknown 'Cher', # AB70..ABBF ; Cherokee 'Mtei', # ABC0..ABED ; Meetei_Mayek 'Zzzz', # ABEE..ABEF ; Unknown @@ -2627,7 +2637,9 @@ VALUES = [ 'Sogo', # 10F00..10F27 ; Old_Sogdian 'Zzzz', # 10F28..10F2F ; Unknown 'Sogd', # 10F30..10F59 ; Sogdian - 'Zzzz', # 10F5A..10FFF ; Unknown + 'Zzzz', # 10F5A..10FDF ; Unknown + 'Elym', # 10FE0..10FF6 ; Elymaic + 'Zzzz', # 10FF7..10FFF ; Unknown 'Brah', # 11000..1104D ; Brahmi 'Zzzz', # 1104E..11051 ; Unknown 'Brah', # 11052..1106F ; Brahmi @@ -2706,8 +2718,8 @@ VALUES = [ 'Zzzz', # 1145A..1145A ; Unknown 'Newa', # 1145B..1145B ; Newa 'Zzzz', # 1145C..1145C ; Unknown - 'Newa', # 1145D..1145E ; Newa - 'Zzzz', # 1145F..1147F ; Unknown + 'Newa', # 1145D..1145F ; Newa + 'Zzzz', # 11460..1147F ; Unknown 'Tirh', # 11480..114C7 ; Tirhuta 'Zzzz', # 114C8..114CF ; Unknown 'Tirh', # 114D0..114D9 ; Tirhuta @@ -2722,8 +2734,8 @@ VALUES = [ 'Zzzz', # 1165A..1165F ; Unknown 'Mong', # 11660..1166C ; Mongolian 'Zzzz', # 1166D..1167F ; Unknown - 'Takr', # 11680..116B7 ; Takri - 'Zzzz', # 116B8..116BF ; Unknown + 'Takr', # 11680..116B8 ; Takri + 'Zzzz', # 116B9..116BF ; Unknown 'Takr', # 116C0..116C9 ; Takri 'Zzzz', # 116CA..116FF ; Unknown 'Ahom', # 11700..1171A ; Ahom @@ -2737,12 +2749,16 @@ VALUES = [ 'Wara', # 118A0..118F2 ; Warang_Citi 'Zzzz', # 118F3..118FE ; Unknown 'Wara', # 118FF..118FF ; Warang_Citi - 'Zzzz', # 11900..119FF ; Unknown + 'Zzzz', # 11900..1199F ; Unknown + 'Nand', # 119A0..119A7 ; Nandinagari + 'Zzzz', # 119A8..119A9 ; Unknown + 'Nand', # 119AA..119D7 ; Nandinagari + 'Zzzz', # 119D8..119D9 ; Unknown + 'Nand', # 119DA..119E4 ; Nandinagari + 'Zzzz', # 119E5..119FF ; Unknown 'Zanb', # 11A00..11A47 ; Zanabazar_Square 'Zzzz', # 11A48..11A4F ; Unknown - 'Soyo', # 11A50..11A83 ; Soyombo - 'Zzzz', # 11A84..11A85 ; Unknown - 'Soyo', # 11A86..11AA2 ; Soyombo + 'Soyo', # 11A50..11AA2 ; Soyombo 'Zzzz', # 11AA3..11ABF ; Unknown 'Pauc', # 11AC0..11AF8 ; Pau_Cin_Hau 'Zzzz', # 11AF9..11BFF ; Unknown @@ -2787,7 +2803,10 @@ VALUES = [ 'Gong', # 11DA0..11DA9 ; Gunjala_Gondi 'Zzzz', # 11DAA..11EDF ; Unknown 'Maka', # 11EE0..11EF8 ; Makasar - 'Zzzz', # 11EF9..11FFF ; Unknown + 'Zzzz', # 11EF9..11FBF ; Unknown + 'Taml', # 11FC0..11FF1 ; Tamil + 'Zzzz', # 11FF2..11FFE ; Unknown + 'Taml', # 11FFF..11FFF ; Tamil 'Xsux', # 12000..12399 ; Cuneiform 'Zzzz', # 1239A..123FF ; Unknown 'Xsux', # 12400..1246E ; Cuneiform @@ -2797,7 +2816,9 @@ VALUES = [ 'Xsux', # 12480..12543 ; Cuneiform 'Zzzz', # 12544..12FFF ; Unknown 'Egyp', # 13000..1342E ; Egyptian_Hieroglyphs - 'Zzzz', # 1342F..143FF ; Unknown + 'Zzzz', # 1342F..1342F ; Unknown + 'Egyp', # 13430..13438 ; Egyptian_Hieroglyphs + 'Zzzz', # 13439..143FF ; Unknown 'Hluw', # 14400..14646 ; Anatolian_Hieroglyphs 'Zzzz', # 14647..167FF ; Unknown 'Bamu', # 16800..16A38 ; Bamum @@ -2824,22 +2845,27 @@ VALUES = [ 'Zzzz', # 16B90..16E3F ; Unknown 'Medf', # 16E40..16E9A ; Medefaidrin 'Zzzz', # 16E9B..16EFF ; Unknown - 'Plrd', # 16F00..16F44 ; Miao - 'Zzzz', # 16F45..16F4F ; Unknown - 'Plrd', # 16F50..16F7E ; Miao - 'Zzzz', # 16F7F..16F8E ; Unknown + 'Plrd', # 16F00..16F4A ; Miao + 'Zzzz', # 16F4B..16F4E ; Unknown + 'Plrd', # 16F4F..16F87 ; Miao + 'Zzzz', # 16F88..16F8E ; Unknown 'Plrd', # 16F8F..16F9F ; Miao 'Zzzz', # 16FA0..16FDF ; Unknown 'Tang', # 16FE0..16FE0 ; Tangut 'Nshu', # 16FE1..16FE1 ; Nushu - 'Zzzz', # 16FE2..16FFF ; Unknown - 'Tang', # 17000..187F1 ; Tangut - 'Zzzz', # 187F2..187FF ; Unknown + 'Zyyy', # 16FE2..16FE3 ; Common + 'Zzzz', # 16FE4..16FFF ; Unknown + 'Tang', # 17000..187F7 ; Tangut + 'Zzzz', # 187F8..187FF ; Unknown 'Tang', # 18800..18AF2 ; Tangut 'Zzzz', # 18AF3..1AFFF ; Unknown 'Kana', # 1B000..1B000 ; Katakana 'Hira', # 1B001..1B11E ; Hiragana - 'Zzzz', # 1B11F..1B16F ; Unknown + 'Zzzz', # 1B11F..1B14F ; Unknown + 'Hira', # 1B150..1B152 ; Hiragana + 'Zzzz', # 1B153..1B163 ; Unknown + 'Kana', # 1B164..1B167 ; Katakana + 'Zzzz', # 1B168..1B16F ; Unknown 'Nshu', # 1B170..1B2FB ; Nushu 'Zzzz', # 1B2FC..1BBFF ; Unknown 'Dupl', # 1BC00..1BC6A ; Duployan @@ -2931,19 +2957,33 @@ VALUES = [ 'Glag', # 1E023..1E024 ; Glagolitic 'Zzzz', # 1E025..1E025 ; Unknown 'Glag', # 1E026..1E02A ; Glagolitic - 'Zzzz', # 1E02B..1E7FF ; Unknown + 'Zzzz', # 1E02B..1E0FF ; Unknown + 'Hmnp', # 1E100..1E12C ; Nyiakeng_Puachue_Hmong + 'Zzzz', # 1E12D..1E12F ; Unknown + 'Hmnp', # 1E130..1E13D ; Nyiakeng_Puachue_Hmong + 'Zzzz', # 1E13E..1E13F ; Unknown + 'Hmnp', # 1E140..1E149 ; Nyiakeng_Puachue_Hmong + 'Zzzz', # 1E14A..1E14D ; Unknown + 'Hmnp', # 1E14E..1E14F ; Nyiakeng_Puachue_Hmong + 'Zzzz', # 1E150..1E2BF ; Unknown + 'Wcho', # 1E2C0..1E2F9 ; Wancho + 'Zzzz', # 1E2FA..1E2FE ; Unknown + 'Wcho', # 1E2FF..1E2FF ; Wancho + 'Zzzz', # 1E300..1E7FF ; Unknown 'Mend', # 1E800..1E8C4 ; Mende_Kikakui 'Zzzz', # 1E8C5..1E8C6 ; Unknown 'Mend', # 1E8C7..1E8D6 ; Mende_Kikakui 'Zzzz', # 1E8D7..1E8FF ; Unknown - 'Adlm', # 1E900..1E94A ; Adlam - 'Zzzz', # 1E94B..1E94F ; Unknown + 'Adlm', # 1E900..1E94B ; Adlam + 'Zzzz', # 1E94C..1E94F ; Unknown 'Adlm', # 1E950..1E959 ; Adlam 'Zzzz', # 1E95A..1E95D ; Unknown 'Adlm', # 1E95E..1E95F ; Adlam 'Zzzz', # 1E960..1EC70 ; Unknown 'Zyyy', # 1EC71..1ECB4 ; Common - 'Zzzz', # 1ECB5..1EDFF ; Unknown + 'Zzzz', # 1ECB5..1ED00 ; Unknown + 'Zyyy', # 1ED01..1ED3D ; Common + 'Zzzz', # 1ED3E..1EDFF ; Unknown 'Arab', # 1EE00..1EE03 ; Arabic 'Zzzz', # 1EE04..1EE04 ; Unknown 'Arab', # 1EE05..1EE1F ; Arabic @@ -3026,8 +3066,8 @@ VALUES = [ 'Zzzz', # 1F0F6..1F0FF ; Unknown 'Zyyy', # 1F100..1F10C ; Common 'Zzzz', # 1F10D..1F10F ; Unknown - 'Zyyy', # 1F110..1F16B ; Common - 'Zzzz', # 1F16C..1F16F ; Unknown + 'Zyyy', # 1F110..1F16C ; Common + 'Zzzz', # 1F16D..1F16F ; Unknown 'Zyyy', # 1F170..1F1AC ; Common 'Zzzz', # 1F1AD..1F1E5 ; Unknown 'Zyyy', # 1F1E6..1F1FF ; Common @@ -3042,16 +3082,18 @@ VALUES = [ 'Zzzz', # 1F252..1F25F ; Unknown 'Zyyy', # 1F260..1F265 ; Common 'Zzzz', # 1F266..1F2FF ; Unknown - 'Zyyy', # 1F300..1F6D4 ; Common - 'Zzzz', # 1F6D5..1F6DF ; Unknown + 'Zyyy', # 1F300..1F6D5 ; Common + 'Zzzz', # 1F6D6..1F6DF ; Unknown 'Zyyy', # 1F6E0..1F6EC ; Common 'Zzzz', # 1F6ED..1F6EF ; Unknown - 'Zyyy', # 1F6F0..1F6F9 ; Common - 'Zzzz', # 1F6FA..1F6FF ; Unknown + 'Zyyy', # 1F6F0..1F6FA ; Common + 'Zzzz', # 1F6FB..1F6FF ; Unknown 'Zyyy', # 1F700..1F773 ; Common 'Zzzz', # 1F774..1F77F ; Unknown 'Zyyy', # 1F780..1F7D8 ; Common - 'Zzzz', # 1F7D9..1F7FF ; Unknown + 'Zzzz', # 1F7D9..1F7DF ; Unknown + 'Zyyy', # 1F7E0..1F7EB ; Common + 'Zzzz', # 1F7EC..1F7FF ; Unknown 'Zyyy', # 1F800..1F80B ; Common 'Zzzz', # 1F80C..1F80F ; Unknown 'Zyyy', # 1F810..1F847 ; Common @@ -3063,25 +3105,29 @@ VALUES = [ 'Zyyy', # 1F890..1F8AD ; Common 'Zzzz', # 1F8AE..1F8FF ; Unknown 'Zyyy', # 1F900..1F90B ; Common - 'Zzzz', # 1F90C..1F90F ; Unknown - 'Zyyy', # 1F910..1F93E ; Common - 'Zzzz', # 1F93F..1F93F ; Unknown - 'Zyyy', # 1F940..1F970 ; Common - 'Zzzz', # 1F971..1F972 ; Unknown + 'Zzzz', # 1F90C..1F90C ; Unknown + 'Zyyy', # 1F90D..1F971 ; Common + 'Zzzz', # 1F972..1F972 ; Unknown 'Zyyy', # 1F973..1F976 ; Common 'Zzzz', # 1F977..1F979 ; Unknown - 'Zyyy', # 1F97A..1F97A ; Common - 'Zzzz', # 1F97B..1F97B ; Unknown - 'Zyyy', # 1F97C..1F9A2 ; Common - 'Zzzz', # 1F9A3..1F9AF ; Unknown - 'Zyyy', # 1F9B0..1F9B9 ; Common - 'Zzzz', # 1F9BA..1F9BF ; Unknown - 'Zyyy', # 1F9C0..1F9C2 ; Common - 'Zzzz', # 1F9C3..1F9CF ; Unknown - 'Zyyy', # 1F9D0..1F9FF ; Common - 'Zzzz', # 1FA00..1FA5F ; Unknown + 'Zyyy', # 1F97A..1F9A2 ; Common + 'Zzzz', # 1F9A3..1F9A4 ; Unknown + 'Zyyy', # 1F9A5..1F9AA ; Common + 'Zzzz', # 1F9AB..1F9AD ; Unknown + 'Zyyy', # 1F9AE..1F9CA ; Common + 'Zzzz', # 1F9CB..1F9CC ; Unknown + 'Zyyy', # 1F9CD..1FA53 ; Common + 'Zzzz', # 1FA54..1FA5F ; Unknown 'Zyyy', # 1FA60..1FA6D ; Common - 'Zzzz', # 1FA6E..1FFFF ; Unknown + 'Zzzz', # 1FA6E..1FA6F ; Unknown + 'Zyyy', # 1FA70..1FA73 ; Common + 'Zzzz', # 1FA74..1FA77 ; Unknown + 'Zyyy', # 1FA78..1FA7A ; Common + 'Zzzz', # 1FA7B..1FA7F ; Unknown + 'Zyyy', # 1FA80..1FA82 ; Common + 'Zzzz', # 1FA83..1FA8F ; Unknown + 'Zyyy', # 1FA90..1FA95 ; Common + 'Zzzz', # 1FA96..1FFFF ; Unknown 'Hani', # 20000..2A6D6 ; Han 'Zzzz', # 2A6D7..2A6FF ; Unknown 'Hani', # 2A700..2B734 ; Han @@ -3135,6 +3181,7 @@ NAMES = { 'Dupl': 'Duployan', 'Egyp': 'Egyptian_Hieroglyphs', 'Elba': 'Elbasan', + 'Elym': 'Elymaic', 'Ethi': 'Ethiopic', 'Geor': 'Georgian', 'Glag': 'Glagolitic', @@ -3153,6 +3200,7 @@ NAMES = { 'Hira': 'Hiragana', 'Hluw': 'Anatolian_Hieroglyphs', 'Hmng': 'Pahawh_Hmong', + 'Hmnp': 'Nyiakeng_Puachue_Hmong', 'Hrkt': 'Katakana_Or_Hiragana', 'Hung': 'Old_Hungarian', 'Ital': 'Old_Italic', @@ -3190,6 +3238,7 @@ NAMES = { 'Mtei': 'Meetei_Mayek', 'Mult': 'Multani', 'Mymr': 'Myanmar', + 'Nand': 'Nandinagari', 'Narb': 'Old_North_Arabian', 'Nbat': 'Nabataean', 'Newa': 'Newa', @@ -3246,6 +3295,7 @@ NAMES = { 'Ugar': 'Ugaritic', 'Vaii': 'Vai', 'Wara': 'Warang_Citi', + 'Wcho': 'Wancho', 'Xpeo': 'Old_Persian', 'Xsux': 'Cuneiform', 'Yiii': 'Yi', diff --git a/Lib/fontTools/varLib/cff.py b/Lib/fontTools/varLib/cff.py index a8da2145..bcafdeee 100755 --- a/Lib/fontTools/varLib/cff.py +++ b/Lib/fontTools/varLib/cff.py @@ -161,7 +161,7 @@ def merge_PrivateDicts(top_dicts, vsindex_dict, var_model, fd_map): For each key, step through each relevant source font Private dict, and build a list of values to blend. The 'relevant' source fonts are selected by first getting the right - submodel using model_keys[vsindex]. The indices of the + submodel using vsindex_dict[vsindex]. The indices of the subModel.locations are mapped to source font list indices by assuming the latter order is the same as the order of the var_model.locations. I can then get the index of each subModel @@ -180,7 +180,7 @@ def merge_PrivateDicts(top_dicts, vsindex_dict, var_model, fd_map): # At the moment, no PrivateDict has a vsindex key, but let's support # how it should work. See comment at end of # merge_charstrings() - still need to optimize use of vsindex. - sub_model, model_keys = vsindex_dict[vsindex] + sub_model, _ = vsindex_dict[vsindex] master_indices = [] for loc in sub_model.locations[1:]: i = var_model.locations.index(loc) - 1 @@ -270,7 +270,9 @@ def getfd_map(varFont, fonts_list): num_regions = len(region_fonts) topDict = default_font['CFF '].cff.topDictIndex[0] if not hasattr(topDict, 'FDSelect'): - fd_map[0] = [0]*num_regions + # All glyphs reference only one FontDict. + # Map the FD index for regions to index 0. + fd_map[0] = {ri:0 for ri in range(num_regions)} return fd_map gname_mapping = {} @@ -317,6 +319,19 @@ def _get_cs(charstrings, glyphName): return None return charstrings[glyphName] +def _add_new_vsindex(model, key, masterSupports, vsindex_dict, + vsindex_by_key, varDataList): + varTupleIndexes = [] + for support in model.supports[1:]: + if support not in masterSupports: + masterSupports.append(support) + varTupleIndexes.append(masterSupports.index(support)) + var_data = varLib.builder.buildVarData(varTupleIndexes, None, False) + vsindex = len(vsindex_dict) + vsindex_by_key[key] = vsindex + vsindex_dict[vsindex] = (model, [key]) + varDataList.append(var_data) + return vsindex def merge_charstrings(glyphOrder, num_masters, top_dicts, masterModel): @@ -365,24 +380,24 @@ def merge_charstrings(glyphOrder, num_masters, top_dicts, masterModel): # If the charstring required a new model, create # a VarData table to go with, and set vsindex. + key = tuple(v is not None for v in all_cs) try: - key = tuple(v is not None for v in all_cs) vsindex = vsindex_by_key[key] except KeyError: - varTupleIndexes = [] - for support in model.supports[1:]: - if support not in masterSupports: - masterSupports.append(support) - varTupleIndexes.append(masterSupports.index(support)) - var_data = varLib.builder.buildVarData(varTupleIndexes, None, False) - vsindex = len(vsindex_dict) - vsindex_by_key[key] = vsindex - vsindex_dict[vsindex] = (model, [key]) - varDataList.append(var_data) + vsindex = _add_new_vsindex(model, key, masterSupports, vsindex_dict, + vsindex_by_key, varDataList) # We do not need to check for an existing new_cs.private.vsindex, # as we know it doesn't exist yet. if vsindex != 0: new_cs.program[:0] = [vsindex, 'vsindex'] + + # If there is no variation in any of the charstrings, then vsindex_dict + # never gets built. This could still be needed if there is variation + # in the PrivatDict, so we will build the default data for vsindex = 0. + if not vsindex_dict: + key = (True,) * num_masters + _add_new_vsindex(model, key, masterSupports, vsindex_dict, + vsindex_by_key, varDataList) cvData = CVarData(varDataList=varDataList, masterSupports=masterSupports, vsindex_dict=vsindex_dict) # XXX To do: optimize use of vsindex between the PrivateDicts and diff --git a/Lib/fontTools/varLib/featureVars.py b/Lib/fontTools/varLib/featureVars.py index de2808db..4caf30a2 100644 --- a/Lib/fontTools/varLib/featureVars.py +++ b/Lib/fontTools/varLib/featureVars.py @@ -342,7 +342,7 @@ def buildGSUB(): langrec = ot.LangSysRecord() langrec.LangSys = ot.LangSys() langrec.LangSys.ReqFeatureIndex = 0xFFFF - langrec.LangSys.FeatureIndex = [0] + langrec.LangSys.FeatureIndex = [] srec.Script.DefaultLangSys = langrec.LangSys gsub.ScriptList.ScriptRecord.append(srec) diff --git a/Lib/fontTools/varLib/merger.py b/Lib/fontTools/varLib/merger.py index b4b17059..cd16ace4 100644 --- a/Lib/fontTools/varLib/merger.py +++ b/Lib/fontTools/varLib/merger.py @@ -2,6 +2,8 @@ Merge OpenType Layout tables (GDEF / GPOS / GSUB). """ from __future__ import print_function, division, absolute_import +import copy +from operator import ior from fontTools.misc.py23 import * from fontTools.misc.fixedTools import otRound from fontTools.misc import classifyTools @@ -12,6 +14,7 @@ from fontTools.varLib import builder, models, varStore from fontTools.varLib.models import nonNone, allNone, allEqual, allEqualTo from fontTools.varLib.varStore import VarStoreInstancer from functools import reduce +from fontTools.otlLib.builder import buildSinglePos class Merger(object): @@ -455,7 +458,7 @@ def _PairPosFormat2_align_matrices(self, lst, font, transparent=False): exemplarGlyph = next(iter(classSet)) klass = classDef2.get(exemplarGlyph, 0) rec2 = oldClass2Records[klass] - class2Records.append(rec2) + class2Records.append(copy.deepcopy(rec2)) class1Records.append(rec1new) new_matrices.append(class1Records) matrices = new_matrices @@ -726,6 +729,30 @@ def _Lookup_PairPos_subtables_canonicalize(lst, font): return lst +def _Lookup_SinglePos_subtables_flatten(lst, font, min_inclusive_rec_format): + glyphs, _ = _merge_GlyphOrders(font, + [v.Coverage.glyphs for v in lst], None) + num_glyphs = len(glyphs) + new = ot.SinglePos() + new.Format = 2 + new.ValueFormat = min_inclusive_rec_format + new.Coverage = ot.Coverage() + new.Coverage.glyphs = glyphs + new.ValueCount = num_glyphs + new.Value = [None] * num_glyphs + for singlePos in lst: + if singlePos.Format == 1: + val_rec = singlePos.Value + for gname in singlePos.Coverage.glyphs: + i = glyphs.index(gname) + new.Value[i] = copy.deepcopy(val_rec) + elif singlePos.Format == 2: + for j, gname in enumerate(singlePos.Coverage.glyphs): + val_rec = singlePos.Value[j] + i = glyphs.index(gname) + new.Value[i] = copy.deepcopy(val_rec) + return [new] + @AligningMerger.merger(ot.Lookup) def merge(merger, self, lst): subtables = merger.lookup_subtables = [l.SubTable for l in lst] @@ -745,12 +772,28 @@ def merge(merger, self, lst): isPairPos = self.SubTable and isinstance(self.SubTable[0], ot.PairPos) if isPairPos: - # AFDKO and feaLib sometimes generate two Format1 subtables instead of one. # Merge those before continuing. # https://github.com/fonttools/fonttools/issues/719 self.SubTable = _Lookup_PairPos_subtables_canonicalize(self.SubTable, merger.font) subtables = merger.lookup_subtables = [_Lookup_PairPos_subtables_canonicalize(st, merger.font) for st in subtables] + else: + isSinglePos = self.SubTable and isinstance(self.SubTable[0], ot.SinglePos) + if isSinglePos: + numSubtables = [len(st) for st in subtables] + if not all([nums == numSubtables[0] for nums in numSubtables]): + # Flatten list of SinglePos subtables to single Format 2 subtable, + # with all value records set to the rec format type. + # We use buildSinglePos() to optimize the lookup after merging. + valueFormatList = [t.ValueFormat for st in subtables for t in st] + # Find the minimum value record that can accomodate all the singlePos subtables. + mirf = reduce(ior, valueFormatList) + self.SubTable = _Lookup_SinglePos_subtables_flatten(self.SubTable, merger.font, mirf) + subtables = merger.lookup_subtables = [ + _Lookup_SinglePos_subtables_flatten(st, merger.font, mirf) for st in subtables] + flattened = True + else: + flattened = False merger.mergeLists(self.SubTable, subtables) self.SubTableCount = len(self.SubTable) @@ -768,6 +811,16 @@ def merge(merger, self, lst): self.SubTable.pop(-1) self.SubTableCount -= 1 + elif isSinglePos and flattened: + singlePosTable = self.SubTable[0] + glyphs = singlePosTable.Coverage.glyphs + # We know that singlePosTable is Format 2, as this is set + # in _Lookup_SinglePos_subtables_flatten. + singlePosMapping = { + gname: valRecord + for gname, valRecord in zip(glyphs, singlePosTable.Value) + } + self.SubTable = buildSinglePos(singlePosMapping, merger.font.getReverseGlyphMap()) merger.mergeObjects(self, lst, exclude=['SubTable', 'SubTableCount']) del merger.lookup_subtables diff --git a/Lib/fonttools.egg-info/PKG-INFO b/Lib/fonttools.egg-info/PKG-INFO index b302ec90..74bb40d0 100644 --- a/Lib/fonttools.egg-info/PKG-INFO +++ b/Lib/fonttools.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: fonttools -Version: 3.42.0 +Version: 3.43.1 Summary: Tools to manipulate font files Home-page: http://github.com/fonttools/fonttools Author: Just van Rossum @@ -415,6 +415,37 @@ Description: |Travis Build Status| |Appveyor Build status| |Coverage Status| |Py Changelog ~~~~~~~~~ + 3.43.1 (released 2019-06-19) + ---------------------------- + + - [subset] Fixed regression when passing ``--flavor=woff2`` option with an input font + that was already compressed as WOFF 1.0 (#1650). + + 3.43.0 (released 2019-06-18) + ---------------------------- + + - [woff2] Added support for compressing/decompressing WOFF2 fonts with non-transformed + ``glyf`` and ``loca`` tables, as well as with transformed ``hmtx`` table. + Removed ``Snippets/woff2_compress.py`` and ``Snippets/woff2_decompress.py`` scripts, + and replaced them with a new console entry point ``fonttools ttLib.woff2`` + that provides two sub-commands ``compress`` and ``decompress``. + - [varLib.cff] Fixed bug when merging CFF2 ``PrivateDicts``. The ``PrivateDict`` + data from the first region font was incorrecty used for all subsequent fonts. + The bug would only affect variable CFF2 fonts with hinting (#1643, #1644). + Also, fixed a merging bug when VF masters have no blends or marking glyphs (#1632, + #1642). + - [loggingTools] Removed unused backport of ``LastResortLogger`` class. + - [subset] Gracefully handle partial MATH table (#1635). + - [featureVars] Avoid duplicate references to ``rvrn`` feature record in + ``DefaultLangSys`` tables when calling ``addFeatureVariations`` on a font that + does not already have a ``GSUB`` table (aa8a5bc6). + - [varLib] Fixed merging of class-based kerning. Before, the process could introduce + rogue kerning values and variations for random classes against class zero (everything + not otherwise classed). + - [varLib] Fixed merging GPOS tables from master fonts with different number of + ``SinglePos`` subtables (#1621, #1641). + - [unicodedata] Updated Blocks, Scripts and ScriptExtensions to Unicode 12.1. + 3.42.0 (released 2019-05-28) ---------------------------- @@ -1756,13 +1787,13 @@ Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Text Processing :: Fonts Classifier: Topic :: Multimedia :: Graphics Classifier: Topic :: Multimedia :: Graphics :: Graphics Conversion -Provides-Extra: all -Provides-Extra: symfont -Provides-Extra: graphite -Provides-Extra: unicode -Provides-Extra: interpolatable Provides-Extra: lxml +Provides-Extra: interpolatable +Provides-Extra: unicode +Provides-Extra: type1 +Provides-Extra: all Provides-Extra: ufo +Provides-Extra: graphite Provides-Extra: woff Provides-Extra: plot -Provides-Extra: type1 +Provides-Extra: symfont diff --git a/Lib/fonttools.egg-info/SOURCES.txt b/Lib/fonttools.egg-info/SOURCES.txt index 4ff321a1..063c93c2 100644 --- a/Lib/fonttools.egg-info/SOURCES.txt +++ b/Lib/fonttools.egg-info/SOURCES.txt @@ -328,8 +328,6 @@ Snippets/otf2ttf.py Snippets/rename-fonts.py Snippets/subset-fpgm.py Snippets/svg2glif.py -Snippets/woff2_compress.py -Snippets/woff2_decompress.py Tests/agl_test.py Tests/merge_test.py Tests/unicodedata_test.py @@ -648,6 +646,7 @@ Tests/pens/reverseContourPen_test.py Tests/pens/t2CharStringPen_test.py Tests/pens/ttGlyphPen_test.py Tests/subset/subset_test.py +Tests/subset/data/Lobster.subset.otf Tests/subset/data/Lobster.subset.ttx Tests/subset/data/NotdefWidthCID-Regular.ttx Tests/subset/data/TestANKR.ttx @@ -682,6 +681,7 @@ Tests/subset/data/expect_keep_gvar_notdef_outline.ttx Tests/subset/data/expect_keep_math.ttx Tests/subset/data/expect_lcar_0.ttx Tests/subset/data/expect_lcar_1.ttx +Tests/subset/data/expect_math_partial.ttx Tests/subset/data/expect_no_hinting_CFF.ttx Tests/subset/data/expect_no_hinting_TTF.ttx Tests/subset/data/expect_no_hinting_desubroutinize_CFF.ttx @@ -698,6 +698,7 @@ Tests/subset/data/test_cntrmask_CFF.desub.ttx Tests/subset/data/test_cntrmask_CFF.ttx Tests/subset/data/test_hinted_subrs_CFF.desub.ttx Tests/subset/data/test_hinted_subrs_CFF.ttx +Tests/subset/data/test_math_partial.ttx Tests/svgLib/path/__init__.py Tests/svgLib/path/parser_test.py Tests/svgLib/path/path_test.py @@ -1442,13 +1443,21 @@ Tests/varLib/data/FeatureVars.designspace Tests/varLib/data/InterpolateLayout.designspace Tests/varLib/data/InterpolateLayout2.designspace Tests/varLib/data/InterpolateLayout3.designspace +Tests/varLib/data/KerningMerging.designspace Tests/varLib/data/SparseMasters.designspace Tests/varLib/data/TestCFF2.designspace +Tests/varLib/data/TestNonMarkingCFF2.designspace Tests/varLib/data/TestSparseCFF2VF.designspace Tests/varLib/data/TestVVAR.designspace +Tests/varLib/data/test_vpal.designspace Tests/varLib/data/master_cff2/TestCFF2_Black.ttx Tests/varLib/data/master_cff2/TestCFF2_ExtraLight.ttx Tests/varLib/data/master_cff2/TestCFF2_Regular.ttx +Tests/varLib/data/master_kerning_merging/0.ttx +Tests/varLib/data/master_kerning_merging/1.ttx +Tests/varLib/data/master_kerning_merging/2.ttx +Tests/varLib/data/master_non_marking_cff2/TestNonMarkingCFF2_ExtraLight.ttx +Tests/varLib/data/master_non_marking_cff2/TestNonMarkingCFF2_Regular.ttx Tests/varLib/data/master_sparse_cff2/MasterSet_Kanji-w0.00.ttx Tests/varLib/data/master_sparse_cff2/MasterSet_Kanji-w1000.00.ttx Tests/varLib/data/master_sparse_cff2/MasterSet_Kanji-w439.00.ttx @@ -1747,6 +1756,8 @@ Tests/varLib/data/master_ufo/TestFamily4-Regular.ufo/glyphs.public.background/co Tests/varLib/data/master_ufo/TestFamily4-Regular.ufo/glyphs.public.background/dieresiscomb.glif Tests/varLib/data/master_ufo/TestFamily4-Regular.ufo/glyphs.public.background/n.glif Tests/varLib/data/master_ufo/TestFamily4-Regular.ufo/glyphs.public.background/o.glif +Tests/varLib/data/master_vpal_test/master_vpal_test_0.ttx +Tests/varLib/data/master_vpal_test/master_vpal_test_1.ttx Tests/varLib/data/master_vvar_cff2/TestVVAR.0.ttx Tests/varLib/data/master_vvar_cff2/TestVVAR.1.ttx Tests/varLib/data/test_results/Build.ttx @@ -1785,7 +1796,9 @@ Tests/varLib/data/test_results/Mutator.ttx Tests/varLib/data/test_results/Mutator_Getvar-instance.ttx Tests/varLib/data/test_results/Mutator_IUP-instance.ttx Tests/varLib/data/test_results/SparseMasters.ttx +Tests/varLib/data/test_results/TestNonMarkingCFF2.ttx Tests/varLib/data/test_results/TestSparseCFF2VF.ttx Tests/varLib/data/test_results/TestVVAR.ttx +Tests/varLib/data/test_results/test_vpal.ttx Tests/voltLib/lexer_test.py Tests/voltLib/parser_test.py
\ No newline at end of file @@ -7,12 +7,12 @@ third_party { } url { type: ARCHIVE - value: "https://github.com/fonttools/fonttools/releases/download/3.42.0/fonttools-3.42.0.zip" + value: "https://github.com/fonttools/fonttools/releases/download/3.43.1/fonttools-3.43.1.zip" } - version: "3.42.0" + version: "3.43.1" last_upgrade_date { year: 2019 - month: 5 - day: 31 + month: 6 + day: 19 } } @@ -1,3 +1,34 @@ +3.43.1 (released 2019-06-19) +---------------------------- + +- [subset] Fixed regression when passing ``--flavor=woff2`` option with an input font + that was already compressed as WOFF 1.0 (#1650). + +3.43.0 (released 2019-06-18) +---------------------------- + +- [woff2] Added support for compressing/decompressing WOFF2 fonts with non-transformed + ``glyf`` and ``loca`` tables, as well as with transformed ``hmtx`` table. + Removed ``Snippets/woff2_compress.py`` and ``Snippets/woff2_decompress.py`` scripts, + and replaced them with a new console entry point ``fonttools ttLib.woff2`` + that provides two sub-commands ``compress`` and ``decompress``. +- [varLib.cff] Fixed bug when merging CFF2 ``PrivateDicts``. The ``PrivateDict`` + data from the first region font was incorrecty used for all subsequent fonts. + The bug would only affect variable CFF2 fonts with hinting (#1643, #1644). + Also, fixed a merging bug when VF masters have no blends or marking glyphs (#1632, + #1642). +- [loggingTools] Removed unused backport of ``LastResortLogger`` class. +- [subset] Gracefully handle partial MATH table (#1635). +- [featureVars] Avoid duplicate references to ``rvrn`` feature record in + ``DefaultLangSys`` tables when calling ``addFeatureVariations`` on a font that + does not already have a ``GSUB`` table (aa8a5bc6). +- [varLib] Fixed merging of class-based kerning. Before, the process could introduce + rogue kerning values and variations for random classes against class zero (everything + not otherwise classed). +- [varLib] Fixed merging GPOS tables from master fonts with different number of + ``SinglePos`` subtables (#1621, #1641). +- [unicodedata] Updated Blocks, Scripts and ScriptExtensions to Unicode 12.1. + 3.42.0 (released 2019-05-28) ---------------------------- @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: fonttools -Version: 3.42.0 +Version: 3.43.1 Summary: Tools to manipulate font files Home-page: http://github.com/fonttools/fonttools Author: Just van Rossum @@ -415,6 +415,37 @@ Description: |Travis Build Status| |Appveyor Build status| |Coverage Status| |Py Changelog ~~~~~~~~~ + 3.43.1 (released 2019-06-19) + ---------------------------- + + - [subset] Fixed regression when passing ``--flavor=woff2`` option with an input font + that was already compressed as WOFF 1.0 (#1650). + + 3.43.0 (released 2019-06-18) + ---------------------------- + + - [woff2] Added support for compressing/decompressing WOFF2 fonts with non-transformed + ``glyf`` and ``loca`` tables, as well as with transformed ``hmtx`` table. + Removed ``Snippets/woff2_compress.py`` and ``Snippets/woff2_decompress.py`` scripts, + and replaced them with a new console entry point ``fonttools ttLib.woff2`` + that provides two sub-commands ``compress`` and ``decompress``. + - [varLib.cff] Fixed bug when merging CFF2 ``PrivateDicts``. The ``PrivateDict`` + data from the first region font was incorrecty used for all subsequent fonts. + The bug would only affect variable CFF2 fonts with hinting (#1643, #1644). + Also, fixed a merging bug when VF masters have no blends or marking glyphs (#1632, + #1642). + - [loggingTools] Removed unused backport of ``LastResortLogger`` class. + - [subset] Gracefully handle partial MATH table (#1635). + - [featureVars] Avoid duplicate references to ``rvrn`` feature record in + ``DefaultLangSys`` tables when calling ``addFeatureVariations`` on a font that + does not already have a ``GSUB`` table (aa8a5bc6). + - [varLib] Fixed merging of class-based kerning. Before, the process could introduce + rogue kerning values and variations for random classes against class zero (everything + not otherwise classed). + - [varLib] Fixed merging GPOS tables from master fonts with different number of + ``SinglePos`` subtables (#1621, #1641). + - [unicodedata] Updated Blocks, Scripts and ScriptExtensions to Unicode 12.1. + 3.42.0 (released 2019-05-28) ---------------------------- @@ -1756,13 +1787,13 @@ Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Text Processing :: Fonts Classifier: Topic :: Multimedia :: Graphics Classifier: Topic :: Multimedia :: Graphics :: Graphics Conversion -Provides-Extra: all -Provides-Extra: symfont -Provides-Extra: graphite -Provides-Extra: unicode -Provides-Extra: interpolatable Provides-Extra: lxml +Provides-Extra: interpolatable +Provides-Extra: unicode +Provides-Extra: type1 +Provides-Extra: all Provides-Extra: ufo +Provides-Extra: graphite Provides-Extra: woff Provides-Extra: plot -Provides-Extra: type1 +Provides-Extra: symfont diff --git a/Snippets/woff2_compress.py b/Snippets/woff2_compress.py deleted file mode 100755 index 689ebdcc..00000000 --- a/Snippets/woff2_compress.py +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env python - -from __future__ import print_function, division, absolute_import -from fontTools.misc.py23 import * -from fontTools.ttLib import TTFont -from fontTools.ttx import makeOutputFileName -import sys -import os - - -def main(args=None): - if args is None: - args = sys.argv[1:] - if len(args) < 1: - print("One argument, the input filename, must be provided.", file=sys.stderr) - return 1 - - filename = args[0] - outfilename = makeOutputFileName(filename, outputDir=None, extension='.woff2') - - print("Processing %s => %s" % (filename, outfilename)) - - font = TTFont(filename, recalcBBoxes=False, recalcTimestamp=False) - font.flavor = "woff2" - font.save(outfilename, reorderTables=False) - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/Snippets/woff2_decompress.py b/Snippets/woff2_decompress.py deleted file mode 100755 index e7c1beaa..00000000 --- a/Snippets/woff2_decompress.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python - -from __future__ import print_function, division, absolute_import -from fontTools.misc.py23 import * -from fontTools.ttLib import TTFont -from fontTools.ttx import makeOutputFileName -import sys -import os - - -def make_output_name(filename): - with open(filename, "rb") as f: - f.seek(4) - sfntVersion = f.read(4) - assert len(sfntVersion) == 4, "not enough data" - ext = '.ttf' if sfntVersion == b"\x00\x01\x00\x00" else ".otf" - outfilename = makeOutputFileName(filename, outputDir=None, extension=ext) - return outfilename - - -def main(args=None): - if args is None: - args = sys.argv[1:] - if len(args) < 1: - print("One argument, the input filename, must be provided.", file=sys.stderr) - return 1 - - filename = args[0] - outfilename = make_output_name(filename) - - print("Processing %s => %s" % (filename, outfilename)) - - font = TTFont(filename, recalcBBoxes=False, recalcTimestamp=False) - font.flavor = None - font.save(outfilename, reorderTables=True) - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/Tests/feaLib/builder_test.py b/Tests/feaLib/builder_test.py index eb800782..3d852afd 100644 --- a/Tests/feaLib/builder_test.py +++ b/Tests/feaLib/builder_test.py @@ -513,10 +513,9 @@ class BuilderTest(unittest.TestCase): addOpenTypeFeatures(font, tree) assert "GSUB" in font - @unittest.skipIf(sys.version_info[0:2] < (3, 4), - "assertLogs() was introduced in 3.4") def test_unsupported_subtable_break(self): - with self.assertLogs(level='WARNING') as logs: + logger = logging.getLogger("fontTools.feaLib.builder") + with CapturingLogHandler(logger, level='WARNING') as captor: self.build( "feature test {" " pos a 10;" @@ -524,9 +523,10 @@ class BuilderTest(unittest.TestCase): " pos b 10;" "} test;" ) - self.assertEqual(logs.output, - ['WARNING:fontTools.feaLib.builder:<features>:1:32: ' - 'unsupported "subtable" statement for lookup type']) + + captor.assertRegex( + '<features>:1:32: unsupported "subtable" statement for lookup type' + ) def test_skip_featureNames_if_no_name_table(self): features = ( diff --git a/Tests/misc/loggingTools_test.py b/Tests/misc/loggingTools_test.py index 18b71b19..fd64b8b3 100644 --- a/Tests/misc/loggingTools_test.py +++ b/Tests/misc/loggingTools_test.py @@ -6,15 +6,11 @@ from fontTools.misc.loggingTools import ( configLogger, ChannelsFilter, LogMixin, - StderrHandler, - LastResortLogger, - _resetExistingLoggers, ) import logging import textwrap import time import re -import sys import pytest @@ -179,32 +175,3 @@ def test_LogMixin(): assert isinstance(b.log, logging.Logger) assert a.log.name == "loggingTools_test.A" assert b.log.name == "loggingTools_test.B" - - -@pytest.mark.skipif(sys.version_info[:2] > (2, 7), reason="only for python2.7") -@pytest.mark.parametrize( - "reset", [True, False], ids=["reset", "no-reset"] -) -def test_LastResortLogger(reset, capsys, caplog): - current = logging.getLoggerClass() - msg = "The quick brown fox jumps over the lazy dog" - try: - if reset: - _resetExistingLoggers() - else: - caplog.set_level(logging.ERROR, logger="myCustomLogger") - logging.lastResort = StderrHandler(logging.WARNING) - logging.setLoggerClass(LastResortLogger) - logger = logging.getLogger("myCustomLogger") - logger.error(msg) - finally: - del logging.lastResort - logging.setLoggerClass(current) - - captured = capsys.readouterr() - if reset: - assert msg in captured.err - msg not in caplog.text - else: - msg in caplog.text - msg not in captured.err diff --git a/Tests/subset/data/Lobster.subset.otf b/Tests/subset/data/Lobster.subset.otf Binary files differnew file mode 100644 index 00000000..81475427 --- /dev/null +++ b/Tests/subset/data/Lobster.subset.otf diff --git a/Tests/subset/data/expect_math_partial.ttx b/Tests/subset/data/expect_math_partial.ttx new file mode 100644 index 00000000..34136e96 --- /dev/null +++ b/Tests/subset/data/expect_math_partial.ttx @@ -0,0 +1,168 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ttFont sfntVersion="OTTO" ttLibVersion="3.41"> + + <MATH> + <Version value="0x00010000"/> + <MathConstants> + <ScriptPercentScaleDown value="75"/> + <ScriptScriptPercentScaleDown value="60"/> + <DelimitedSubFormulaMinHeight value="1500"/> + <DisplayOperatorMinHeight value="1450"/> + <MathLeading> + <Value value="150"/> + </MathLeading> + <AxisHeight> + <Value value="250"/> + </AxisHeight> + <AccentBaseHeight> + <Value value="450"/> + </AccentBaseHeight> + <FlattenedAccentBaseHeight> + <Value value="662"/> + </FlattenedAccentBaseHeight> + <SubscriptShiftDown> + <Value value="250"/> + </SubscriptShiftDown> + <SubscriptTopMax> + <Value value="400"/> + </SubscriptTopMax> + <SubscriptBaselineDropMin> + <Value value="50"/> + </SubscriptBaselineDropMin> + <SuperscriptShiftUp> + <Value value="400"/> + </SuperscriptShiftUp> + <SuperscriptShiftUpCramped> + <Value value="275"/> + </SuperscriptShiftUpCramped> + <SuperscriptBottomMin> + <Value value="125"/> + </SuperscriptBottomMin> + <SuperscriptBaselineDropMax> + <Value value="375"/> + </SuperscriptBaselineDropMax> + <SubSuperscriptGapMin> + <Value value="264"/> + </SubSuperscriptGapMin> + <SuperscriptBottomMaxWithSubscript> + <Value value="400"/> + </SuperscriptBottomMaxWithSubscript> + <SpaceAfterScript> + <Value value="41"/> + </SpaceAfterScript> + <UpperLimitGapMin> + <Value value="150"/> + </UpperLimitGapMin> + <UpperLimitBaselineRiseMin> + <Value value="300"/> + </UpperLimitBaselineRiseMin> + <LowerLimitGapMin> + <Value value="150"/> + </LowerLimitGapMin> + <LowerLimitBaselineDropMin> + <Value value="600"/> + </LowerLimitBaselineDropMin> + <StackTopShiftUp> + <Value value="480"/> + </StackTopShiftUp> + <StackTopDisplayStyleShiftUp> + <Value value="580"/> + </StackTopDisplayStyleShiftUp> + <StackBottomShiftDown> + <Value value="800"/> + </StackBottomShiftDown> + <StackBottomDisplayStyleShiftDown> + <Value value="900"/> + </StackBottomDisplayStyleShiftDown> + <StackGapMin> + <Value value="198"/> + </StackGapMin> + <StackDisplayStyleGapMin> + <Value value="462"/> + </StackDisplayStyleGapMin> + <StretchStackTopShiftUp> + <Value value="300"/> + </StretchStackTopShiftUp> + <StretchStackBottomShiftDown> + <Value value="600"/> + </StretchStackBottomShiftDown> + <StretchStackGapAboveMin> + <Value value="150"/> + </StretchStackGapAboveMin> + <StretchStackGapBelowMin> + <Value value="150"/> + </StretchStackGapBelowMin> + <FractionNumeratorShiftUp> + <Value value="480"/> + </FractionNumeratorShiftUp> + <FractionNumeratorDisplayStyleShiftUp> + <Value value="580"/> + </FractionNumeratorDisplayStyleShiftUp> + <FractionDenominatorShiftDown> + <Value value="480"/> + </FractionDenominatorShiftDown> + <FractionDenominatorDisplayStyleShiftDown> + <Value value="700"/> + </FractionDenominatorDisplayStyleShiftDown> + <FractionNumeratorGapMin> + <Value value="66"/> + </FractionNumeratorGapMin> + <FractionNumDisplayStyleGapMin> + <Value value="198"/> + </FractionNumDisplayStyleGapMin> + <FractionRuleThickness> + <Value value="66"/> + </FractionRuleThickness> + <FractionDenominatorGapMin> + <Value value="66"/> + </FractionDenominatorGapMin> + <FractionDenomDisplayStyleGapMin> + <Value value="198"/> + </FractionDenomDisplayStyleGapMin> + <SkewedFractionHorizontalGap> + <Value value="300"/> + </SkewedFractionHorizontalGap> + <SkewedFractionVerticalGap> + <Value value="66"/> + </SkewedFractionVerticalGap> + <OverbarVerticalGap> + <Value value="198"/> + </OverbarVerticalGap> + <OverbarRuleThickness> + <Value value="66"/> + </OverbarRuleThickness> + <OverbarExtraAscender> + <Value value="66"/> + </OverbarExtraAscender> + <UnderbarVerticalGap> + <Value value="198"/> + </UnderbarVerticalGap> + <UnderbarRuleThickness> + <Value value="66"/> + </UnderbarRuleThickness> + <UnderbarExtraDescender> + <Value value="66"/> + </UnderbarExtraDescender> + <RadicalVerticalGap> + <Value value="82"/> + </RadicalVerticalGap> + <RadicalDisplayStyleVerticalGap> + <Value value="186"/> + </RadicalDisplayStyleVerticalGap> + <RadicalRuleThickness> + <Value value="66"/> + </RadicalRuleThickness> + <RadicalExtraAscender> + <Value value="66"/> + </RadicalExtraAscender> + <RadicalKernBeforeDegree> + <Value value="277"/> + </RadicalKernBeforeDegree> + <RadicalKernAfterDegree> + <Value value="-555"/> + </RadicalKernAfterDegree> + <RadicalDegreeBottomRaisePercent value="70"/> + </MathConstants> + </MATH> + +</ttFont> diff --git a/Tests/subset/data/test_math_partial.ttx b/Tests/subset/data/test_math_partial.ttx new file mode 100644 index 00000000..c0a70da0 --- /dev/null +++ b/Tests/subset/data/test_math_partial.ttx @@ -0,0 +1,391 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ttFont sfntVersion="OTTO" ttLibVersion="3.41"> + + <GlyphOrder> + <!-- The 'id' attribute is only for humans; it is ignored when parsed. --> + <GlyphID id="0" name=".notdef"/> + <GlyphID id="1" name="A"/> + </GlyphOrder> + + <head> + <!-- Most of this table will be recalculated by the compiler --> + <tableVersion value="1.0"/> + <fontRevision value="1.10799"/> + <checkSumAdjustment value="0x266835f6"/> + <magicNumber value="0x5f0f3cf5"/> + <flags value="00000000 00001011"/> + <unitsPerEm value="1000"/> + <created value="Sun Jan 10 17:35:12 2016"/> + <modified value="Sat Jun 8 23:59:34 2019"/> + <xMin value="-761"/> + <yMin value="-509"/> + <xMax value="3000"/> + <yMax value="2566"/> + <macStyle value="00000000 00000000"/> + <lowestRecPPEM value="8"/> + <fontDirectionHint value="2"/> + <indexToLocFormat value="0"/> + <glyphDataFormat value="0"/> + </head> + + <hhea> + <tableVersion value="0x00010000"/> + <ascent value="750"/> + <descent value="-250"/> + <lineGap value="0"/> + <advanceWidthMax value="3000"/> + <minLeftSideBearing value="-761"/> + <minRightSideBearing value="-365"/> + <xMaxExtent value="3000"/> + <caretSlopeRise value="1"/> + <caretSlopeRun value="0"/> + <caretOffset value="0"/> + <reserved0 value="0"/> + <reserved1 value="0"/> + <reserved2 value="0"/> + <reserved3 value="0"/> + <metricDataFormat value="0"/> + <numberOfHMetrics value="2"/> + </hhea> + + <maxp> + <tableVersion value="0x5000"/> + <numGlyphs value="2"/> + </maxp> + + <OS_2> + <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex' + will be recalculated by the compiler --> + <version value="4"/> + <xAvgCharWidth value="666"/> + <usWeightClass value="400"/> + <usWidthClass value="5"/> + <fsType value="00000000 00000000"/> + <ySubscriptXSize value="500"/> + <ySubscriptYSize value="500"/> + <ySubscriptXOffset value="0"/> + <ySubscriptYOffset value="250"/> + <ySuperscriptXSize value="500"/> + <ySuperscriptYSize value="500"/> + <ySuperscriptXOffset value="0"/> + <ySuperscriptYOffset value="500"/> + <yStrikeoutSize value="50"/> + <yStrikeoutPosition value="306"/> + <sFamilyClass value="0"/> + <panose> + <bFamilyType value="2"/> + <bSerifStyle value="0"/> + <bWeight value="5"/> + <bProportion value="3"/> + <bContrast value="0"/> + <bStrokeVariation value="0"/> + <bArmStyle value="0"/> + <bLetterForm value="0"/> + <bMidline value="0"/> + <bXHeight value="0"/> + </panose> + <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/> + <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/> + <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/> + <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/> + <achVendID value="STIX"/> + <fsSelection value="00000000 11000000"/> + <usFirstCharIndex value="65"/> + <usLastCharIndex value="65"/> + <sTypoAscender value="750"/> + <sTypoDescender value="-250"/> + <sTypoLineGap value="0"/> + <usWinAscent value="2598"/> + <usWinDescent value="918"/> + <ulCodePageRange1 value="01100000 00000000 00000000 10011111"/> + <ulCodePageRange2 value="11011111 11010111 00000000 00000000"/> + <sxHeight value="450"/> + <sCapHeight value="662"/> + <usDefaultChar value="0"/> + <usBreakChar value="32"/> + <usMaxContext value="2"/> + </OS_2> + + <name> + <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409"> + XITS Math + </namerecord> + <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409"> + Regular + </namerecord> + </name> + + <cmap> + <tableVersion version="0"/> + <cmap_format_4 platformID="0" platEncID="3" language="0"> + <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A --> + </cmap_format_4> + <cmap_format_12 platformID="0" platEncID="4" format="12" reserved="0" length="28" language="0" nGroups="1"> + <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A --> + </cmap_format_12> + <cmap_format_4 platformID="3" platEncID="1" language="0"> + <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A --> + </cmap_format_4> + <cmap_format_12 platformID="3" platEncID="10" format="12" reserved="0" length="28" language="0" nGroups="1"> + <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A --> + </cmap_format_12> + </cmap> + + <post> + <formatType value="3.0"/> + <italicAngle value="0.0"/> + <underlinePosition value="-75"/> + <underlineThickness value="50"/> + <isFixedPitch value="0"/> + <minMemType42 value="0"/> + <maxMemType42 value="0"/> + <minMemType1 value="0"/> + <maxMemType1 value="0"/> + </post> + + <CFF> + <major value="1"/> + <minor value="0"/> + <CFFFont name="XITSMath"> + <version value="1.108"/> + <Notice value="Copyright (c) 2001-2011 by the STI Pub Companies, consisting of the American Chemical Society, the American Institute of Physics, the American Mathematical Society, the American Physical Society, Elsevier, Inc., and The Institute of Electrical and Electronic Engineers, Inc. Portions copyright (c) 1998-2003 by MicroPress, Inc. Portions copyright (c) 1990 by Elsevier, Inc. Portions copyright (c) 2009-2012 by Khaled Hosny. All rights reserved. "/> + <FullName value="XITS Math"/> + <FamilyName value="XITS Math"/> + <Weight value="Regular"/> + <isFixedPitch value="0"/> + <ItalicAngle value="0"/> + <UnderlinePosition value="-50"/> + <UnderlineThickness value="50"/> + <PaintType value="0"/> + <CharstringType value="2"/> + <FontMatrix value="0.001 0 0 0.001 0 0"/> + <FontBBox value="-761 -509 3000 2566"/> + <StrokeWidth value="0"/> + <!-- charset is dumped separately as the 'GlyphOrder' element --> + <Encoding name="StandardEncoding"/> + <Private> + <BlueValues value="-14 0 450 460 662 676"/> + <BlueScale value="0.039625"/> + <BlueShift value="6"/> + <BlueFuzz value="1"/> + <StdHW value="66"/> + <StdVW value="66"/> + <StemSnapH value="23 28 31 34 38 43 50 54 63 66"/> + <StemSnapV value="39 43 48 52 56 59 66 73 79 83"/> + <ForceBold value="0"/> + <LanguageGroup value="0"/> + <ExpansionFactor value="0.06"/> + <initialRandomSeed value="0"/> + <defaultWidthX value="685"/> + <nominalWidthX value="601"/> + <Subrs> + <!-- The 'index' attribute is only for humans; it is ignored when parsed. --> + <CharString index="0"> + 19 vlineto + -52 6 -14 21 -28 65 rrcurveto + -246 563 -20 0 -206 -488 rlineto + -59 -140 -9 -21 -58 -6 rrcurveto + -19 199 19 vlineto + -48 -22 10 31 hvcurveto + 0 12 4 17 5 13 rrcurveto + 46 114 262 0 41 -94 rlineto + 12 -28 7 -27 0 -15 0 -9 -6 -11 -8 -4 -12 -7 -7 -2 -36 0 rrcurveto + -19 vlineto + return + </CharString> + <CharString index="1"> + -231 0 115 275 rlineto + return + </CharString> + </Subrs> + </Private> + <CharStrings> + <CharString name=".notdef"> + -351 endchar + </CharString> + <CharString name="A"> + 121 0 20 196 41 397 20 hstem + 707 hmoveto + -107 callsubr + -5 257 rmoveto + -106 callsubr + endchar + </CharString> + </CharStrings> + </CFFFont> + + <GlobalSubrs> + <!-- The 'index' attribute is only for humans; it is ignored when parsed. --> + </GlobalSubrs> + </CFF> + + <MATH> + <Version value="0x00010000"/> + <MathConstants> + <ScriptPercentScaleDown value="75"/> + <ScriptScriptPercentScaleDown value="60"/> + <DelimitedSubFormulaMinHeight value="1500"/> + <DisplayOperatorMinHeight value="1450"/> + <MathLeading> + <Value value="150"/> + </MathLeading> + <AxisHeight> + <Value value="250"/> + </AxisHeight> + <AccentBaseHeight> + <Value value="450"/> + </AccentBaseHeight> + <FlattenedAccentBaseHeight> + <Value value="662"/> + </FlattenedAccentBaseHeight> + <SubscriptShiftDown> + <Value value="250"/> + </SubscriptShiftDown> + <SubscriptTopMax> + <Value value="400"/> + </SubscriptTopMax> + <SubscriptBaselineDropMin> + <Value value="50"/> + </SubscriptBaselineDropMin> + <SuperscriptShiftUp> + <Value value="400"/> + </SuperscriptShiftUp> + <SuperscriptShiftUpCramped> + <Value value="275"/> + </SuperscriptShiftUpCramped> + <SuperscriptBottomMin> + <Value value="125"/> + </SuperscriptBottomMin> + <SuperscriptBaselineDropMax> + <Value value="375"/> + </SuperscriptBaselineDropMax> + <SubSuperscriptGapMin> + <Value value="264"/> + </SubSuperscriptGapMin> + <SuperscriptBottomMaxWithSubscript> + <Value value="400"/> + </SuperscriptBottomMaxWithSubscript> + <SpaceAfterScript> + <Value value="41"/> + </SpaceAfterScript> + <UpperLimitGapMin> + <Value value="150"/> + </UpperLimitGapMin> + <UpperLimitBaselineRiseMin> + <Value value="300"/> + </UpperLimitBaselineRiseMin> + <LowerLimitGapMin> + <Value value="150"/> + </LowerLimitGapMin> + <LowerLimitBaselineDropMin> + <Value value="600"/> + </LowerLimitBaselineDropMin> + <StackTopShiftUp> + <Value value="480"/> + </StackTopShiftUp> + <StackTopDisplayStyleShiftUp> + <Value value="580"/> + </StackTopDisplayStyleShiftUp> + <StackBottomShiftDown> + <Value value="800"/> + </StackBottomShiftDown> + <StackBottomDisplayStyleShiftDown> + <Value value="900"/> + </StackBottomDisplayStyleShiftDown> + <StackGapMin> + <Value value="198"/> + </StackGapMin> + <StackDisplayStyleGapMin> + <Value value="462"/> + </StackDisplayStyleGapMin> + <StretchStackTopShiftUp> + <Value value="300"/> + </StretchStackTopShiftUp> + <StretchStackBottomShiftDown> + <Value value="600"/> + </StretchStackBottomShiftDown> + <StretchStackGapAboveMin> + <Value value="150"/> + </StretchStackGapAboveMin> + <StretchStackGapBelowMin> + <Value value="150"/> + </StretchStackGapBelowMin> + <FractionNumeratorShiftUp> + <Value value="480"/> + </FractionNumeratorShiftUp> + <FractionNumeratorDisplayStyleShiftUp> + <Value value="580"/> + </FractionNumeratorDisplayStyleShiftUp> + <FractionDenominatorShiftDown> + <Value value="480"/> + </FractionDenominatorShiftDown> + <FractionDenominatorDisplayStyleShiftDown> + <Value value="700"/> + </FractionDenominatorDisplayStyleShiftDown> + <FractionNumeratorGapMin> + <Value value="66"/> + </FractionNumeratorGapMin> + <FractionNumDisplayStyleGapMin> + <Value value="198"/> + </FractionNumDisplayStyleGapMin> + <FractionRuleThickness> + <Value value="66"/> + </FractionRuleThickness> + <FractionDenominatorGapMin> + <Value value="66"/> + </FractionDenominatorGapMin> + <FractionDenomDisplayStyleGapMin> + <Value value="198"/> + </FractionDenomDisplayStyleGapMin> + <SkewedFractionHorizontalGap> + <Value value="300"/> + </SkewedFractionHorizontalGap> + <SkewedFractionVerticalGap> + <Value value="66"/> + </SkewedFractionVerticalGap> + <OverbarVerticalGap> + <Value value="198"/> + </OverbarVerticalGap> + <OverbarRuleThickness> + <Value value="66"/> + </OverbarRuleThickness> + <OverbarExtraAscender> + <Value value="66"/> + </OverbarExtraAscender> + <UnderbarVerticalGap> + <Value value="198"/> + </UnderbarVerticalGap> + <UnderbarRuleThickness> + <Value value="66"/> + </UnderbarRuleThickness> + <UnderbarExtraDescender> + <Value value="66"/> + </UnderbarExtraDescender> + <RadicalVerticalGap> + <Value value="82"/> + </RadicalVerticalGap> + <RadicalDisplayStyleVerticalGap> + <Value value="186"/> + </RadicalDisplayStyleVerticalGap> + <RadicalRuleThickness> + <Value value="66"/> + </RadicalRuleThickness> + <RadicalExtraAscender> + <Value value="66"/> + </RadicalExtraAscender> + <RadicalKernBeforeDegree> + <Value value="277"/> + </RadicalKernBeforeDegree> + <RadicalKernAfterDegree> + <Value value="-555"/> + </RadicalKernAfterDegree> + <RadicalDegreeBottomRaisePercent value="70"/> + </MathConstants> + </MATH> + + <hmtx> + <mtx name=".notdef" width="250" lsb="0"/> + <mtx name="A" width="722" lsb="15"/> + </hmtx> + +</ttFont> diff --git a/Tests/subset/subset_test.py b/Tests/subset/subset_test.py index 956197a3..2bdfd9b5 100644 --- a/Tests/subset/subset_test.py +++ b/Tests/subset/subset_test.py @@ -237,6 +237,13 @@ class SubsetTest(unittest.TestCase): subsetfont = TTFont(subsetpath) self.expect_ttx(subsetfont, self.getpath("expect_keep_math.ttx"), ["GlyphOrder", "CFF ", "MATH", "hmtx"]) + def test_subset_math_partial(self): + _, fontpath = self.compile_font(self.getpath("test_math_partial.ttx"), ".ttf") + subsetpath = self.temp_path(".ttf") + subset.main([fontpath, "--text=A", "--output-file=%s" % subsetpath]) + subsetfont = TTFont(subsetpath) + self.expect_ttx(subsetfont, self.getpath("expect_math_partial.ttx"), ["MATH"]) + def test_subset_opbd_remove(self): # In the test font, only the glyphs 'A' and 'zero' have an entry in # the Optical Bounds table. When subsetting, we do not request any @@ -671,6 +678,48 @@ class SubsetTest(unittest.TestCase): subsetfont = TTFont(subsetpath) self.expect_ttx(subsetfont, self.getpath("expect_HVVAR_retain_gids.ttx"), ["GlyphOrder", "HVAR", "VVAR", "avar", "fvar"]) + def test_subset_flavor(self): + _, fontpath = self.compile_font(self.getpath("TestTTF-Regular.ttx"), ".ttf") + font = TTFont(fontpath) + + woff_path = self.temp_path(".woff") + subset.main( + [ + fontpath, + "*", + "--flavor=woff", + "--output-file=%s" % woff_path, + ] + ) + woff = TTFont(woff_path) + + self.assertEqual(woff.flavor, "woff") + + woff2_path = self.temp_path(".woff2") + subset.main( + [ + woff_path, + "*", + "--flavor=woff2", + "--output-file=%s" % woff2_path, + ] + ) + woff2 = TTFont(woff2_path) + + self.assertEqual(woff2.flavor, "woff2") + + ttf_path = self.temp_path(".ttf") + subset.main( + [ + woff2_path, + "*", + "--output-file=%s" % ttf_path, + ] + ) + ttf = TTFont(ttf_path) + + self.assertEqual(ttf.flavor, None) + if __name__ == "__main__": sys.exit(unittest.main()) diff --git a/Tests/ttLib/woff2_test.py b/Tests/ttLib/woff2_test.py index 55c4b778..4a474aed 100644 --- a/Tests/ttLib/woff2_test.py +++ b/Tests/ttLib/woff2_test.py @@ -1,19 +1,24 @@ from __future__ import print_function, division, absolute_import, unicode_literals from fontTools.misc.py23 import * from fontTools import ttLib +from fontTools.ttLib import woff2 from fontTools.ttLib.woff2 import ( WOFF2Reader, woff2DirectorySize, woff2DirectoryFormat, woff2FlagsSize, woff2UnknownTagSize, woff2Base128MaxSize, WOFF2DirectoryEntry, getKnownTagIndex, packBase128, base128Size, woff2UnknownTagIndex, WOFF2FlavorData, woff2TransformedTableTags, WOFF2GlyfTable, WOFF2LocaTable, - WOFF2Writer, unpackBase128, unpack255UShort, pack255UShort) + WOFF2HmtxTable, WOFF2Writer, unpackBase128, unpack255UShort, pack255UShort) import unittest from fontTools.misc import sstruct +from fontTools import fontBuilder +from fontTools.pens.ttGlyphPen import TTGlyphPen import struct import os import random import copy from collections import OrderedDict +from functools import partial +import pytest haveBrotli = False try: @@ -122,7 +127,7 @@ class WOFF2ReaderTest(unittest.TestCase): def test_reconstruct_unknown(self): reader = WOFF2Reader(self.file) with self.assertRaisesRegex(ttLib.TTLibError, 'transform for table .* unknown'): - reader.reconstructTable('ZZZZ') + reader.reconstructTable('head') class WOFF2ReaderTTFTest(WOFF2ReaderTest): @@ -145,6 +150,7 @@ class WOFF2ReaderTTFTest(WOFF2ReaderTest): def test_reconstruct_loca(self): woff2Reader = WOFF2Reader(self.file) reconstructedData = woff2Reader['loca'] + self.font.getTableData("glyf") # 'glyf' needs to be compiled before 'loca' self.assertEqual(self.font.getTableData('loca'), reconstructedData) self.assertTrue(hasattr(woff2Reader.tables['glyf'], 'data')) @@ -242,10 +248,6 @@ class WOFF2DirectoryEntryTest(unittest.TestCase): with self.assertRaisesRegex(ttLib.TTLibError, "can't read table 'tag'"): self.entry.fromString(bytes(incompleteData)) - def test_table_reserved_flags(self): - with self.assertRaisesRegex(ttLib.TTLibError, "bits 6-7 are reserved"): - self.entry.fromString(bytechr(0xC0)) - def test_loca_zero_transformLength(self): data = bytechr(getKnownTagIndex('loca')) # flags data += packBase128(random.randint(1, 100)) # origLength @@ -291,6 +293,35 @@ class WOFF2DirectoryEntryTest(unittest.TestCase): data = self.entry.toString() self.assertEqual(len(data), expectedSize) + def test_glyf_loca_transform_flags(self): + for tag in ("glyf", "loca"): + entry = WOFF2DirectoryEntry() + entry.tag = Tag(tag) + entry.flags = getKnownTagIndex(entry.tag) + + self.assertEqual(entry.transformVersion, 0) + self.assertTrue(entry.transformed) + + entry.transformed = False + + self.assertEqual(entry.transformVersion, 3) + self.assertEqual(entry.flags & 0b11000000, (3 << 6)) + self.assertFalse(entry.transformed) + + def test_other_transform_flags(self): + entry = WOFF2DirectoryEntry() + entry.tag = Tag('ZZZZ') + entry.flags = woff2UnknownTagIndex + + self.assertEqual(entry.transformVersion, 0) + self.assertFalse(entry.transformed) + + entry.transformed = True + + self.assertEqual(entry.transformVersion, 1) + self.assertEqual(entry.flags & 0b11000000, (1 << 6)) + self.assertTrue(entry.transformed) + class DummyReader(WOFF2Reader): @@ -299,6 +330,7 @@ class DummyReader(WOFF2Reader): for attr in ('majorVersion', 'minorVersion', 'metaOffset', 'metaLength', 'metaOrigLength', 'privLength', 'privOffset'): setattr(self, attr, 0) + self.tables = {} class WOFF2FlavorDataTest(unittest.TestCase): @@ -353,6 +385,27 @@ class WOFF2FlavorDataTest(unittest.TestCase): self.assertEqual(flavorData.majorVersion, 1) self.assertEqual(flavorData.minorVersion, 1) + def test_mutually_exclusive_args(self): + msg = "arguments are mutually exclusive" + reader = DummyReader(self.file) + with self.assertRaisesRegex(TypeError, msg): + WOFF2FlavorData(reader, transformedTables={"hmtx"}) + with self.assertRaisesRegex(TypeError, msg): + WOFF2FlavorData(reader, data=WOFF2FlavorData()) + + def test_transformedTables_default(self): + flavorData = WOFF2FlavorData() + self.assertEqual(flavorData.transformedTables, set(woff2TransformedTableTags)) + + def test_transformedTables_invalid(self): + msg = r"'glyf' and 'loca' must be transformed \(or not\) together" + + with self.assertRaisesRegex(ValueError, msg): + WOFF2FlavorData(transformedTables={"glyf"}) + + with self.assertRaisesRegex(ValueError, msg): + WOFF2FlavorData(transformedTables={"loca"}) + class WOFF2WriterTest(unittest.TestCase): @@ -360,7 +413,7 @@ class WOFF2WriterTest(unittest.TestCase): def setUpClass(cls): cls.font = ttLib.TTFont(recalcBBoxes=False, recalcTimestamp=False, flavor="woff2") cls.font.importXML(OTX) - cls.tags = [t for t in cls.font.keys() if t != 'GlyphOrder'] + cls.tags = sorted(t for t in cls.font.keys() if t != 'GlyphOrder') cls.numTables = len(cls.tags) cls.file = BytesIO(CFF_WOFF2.getvalue()) cls.file.seek(0, 2) @@ -511,6 +564,30 @@ class WOFF2WriterTest(unittest.TestCase): flavorData.majorVersion, flavorData.minorVersion = (10, 11) self.assertEqual((10, 11), self.writer._getVersion()) + def test_hmtx_trasform(self): + tableTransforms = {"glyf", "loca", "hmtx"} + + writer = WOFF2Writer(BytesIO(), self.numTables, self.font.sfntVersion) + writer.flavorData = WOFF2FlavorData(transformedTables=tableTransforms) + + for tag in self.tags: + writer[tag] = self.font.getTableData(tag) + writer.close() + + # enabling hmtx transform has no effect when font has no glyf table + self.assertEqual(writer.file.getvalue(), CFF_WOFF2.getvalue()) + + def test_no_transforms(self): + writer = WOFF2Writer(BytesIO(), self.numTables, self.font.sfntVersion) + writer.flavorData = WOFF2FlavorData(transformedTables=()) + + for tag in self.tags: + writer[tag] = self.font.getTableData(tag) + writer.close() + + # transforms settings have no effect when font is CFF-flavored, since + # all the current transforms only apply to TrueType-flavored fonts. + self.assertEqual(writer.file.getvalue(), CFF_WOFF2.getvalue()) class WOFF2WriterTTFTest(WOFF2WriterTest): @@ -518,7 +595,7 @@ class WOFF2WriterTTFTest(WOFF2WriterTest): def setUpClass(cls): cls.font = ttLib.TTFont(recalcBBoxes=False, recalcTimestamp=False, flavor="woff2") cls.font.importXML(TTX) - cls.tags = [t for t in cls.font.keys() if t != 'GlyphOrder'] + cls.tags = sorted(t for t in cls.font.keys() if t != 'GlyphOrder') cls.numTables = len(cls.tags) cls.file = BytesIO(TT_WOFF2.getvalue()) cls.file.seek(0, 2) @@ -539,6 +616,35 @@ class WOFF2WriterTTFTest(WOFF2WriterTest): for tag in normTables: self.assertEqual(self.writer.tables[tag].data, normTables[tag]) + def test_hmtx_trasform(self): + tableTransforms = {"glyf", "loca", "hmtx"} + + writer = WOFF2Writer(BytesIO(), self.numTables, self.font.sfntVersion) + writer.flavorData = WOFF2FlavorData(transformedTables=tableTransforms) + + for tag in self.tags: + writer[tag] = self.font.getTableData(tag) + writer.close() + + length = len(writer.file.getvalue()) + + # enabling optional hmtx transform shaves off a few bytes + self.assertLess(length, len(TT_WOFF2.getvalue())) + + def test_no_transforms(self): + writer = WOFF2Writer(BytesIO(), self.numTables, self.font.sfntVersion) + writer.flavorData = WOFF2FlavorData(transformedTables=()) + + for tag in self.tags: + writer[tag] = self.font.getTableData(tag) + writer.close() + + self.assertNotEqual(writer.file.getvalue(), TT_WOFF2.getvalue()) + + writer.file.seek(0) + reader = WOFF2Reader(writer.file) + self.assertEqual(len(reader.flavorData.transformedTables), 0) + class WOFF2LocaTableTest(unittest.TestCase): @@ -708,28 +814,6 @@ class WOFF2GlyfTableTest(unittest.TestCase): data = glyfTable.transform(self.font) self.assertEqual(self.transformedGlyfData, data) - def test_transform_glyf_incorrect_glyphOrder(self): - glyfTable = self.font['glyf'] - badGlyphOrder = self.font.getGlyphOrder()[:-1] - del glyfTable.glyphOrder - self.font.setGlyphOrder(badGlyphOrder) - with self.assertRaisesRegex(ttLib.TTLibError, "incorrect glyphOrder"): - glyfTable.transform(self.font) - glyfTable.glyphOrder = badGlyphOrder - with self.assertRaisesRegex(ttLib.TTLibError, "incorrect glyphOrder"): - glyfTable.transform(self.font) - - def test_transform_glyf_missing_glyphOrder(self): - glyfTable = self.font['glyf'] - del glyfTable.glyphOrder - del self.font.glyphOrder - numGlyphs = self.font['maxp'].numGlyphs - del self.font['maxp'] - glyfTable.transform(self.font) - expected = [".notdef"] - expected.extend(["glyph%.5d" % i for i in range(1, numGlyphs)]) - self.assertEqual(expected, glyfTable.glyphOrder) - def test_roundtrip_glyf_reconstruct_and_transform(self): glyfTable = WOFF2GlyfTable() glyfTable.reconstruct(self.transformedGlyfData, self.font) @@ -747,6 +831,489 @@ class WOFF2GlyfTableTest(unittest.TestCase): self.assertEqual(normGlyfData, reconstructedData) +@pytest.fixture(scope="module") +def fontfile(): + + class Glyph(object): + def __init__(self, empty=False, **kwargs): + if not empty: + self.draw = partial(self.drawRect, **kwargs) + else: + self.draw = lambda pen: None + + @staticmethod + def drawRect(pen, xMin, xMax): + pen.moveTo((xMin, 0)) + pen.lineTo((xMin, 1000)) + pen.lineTo((xMax, 1000)) + pen.lineTo((xMax, 0)) + pen.closePath() + + class CompositeGlyph(object): + def __init__(self, components): + self.components = components + + def draw(self, pen): + for baseGlyph, (offsetX, offsetY) in self.components: + pen.addComponent(baseGlyph, (1, 0, 0, 1, offsetX, offsetY)) + + fb = fontBuilder.FontBuilder(unitsPerEm=1000, isTTF=True) + fb.setupGlyphOrder( + [".notdef", "space", "A", "acutecomb", "Aacute", "zero", "one", "two"] + ) + fb.setupCharacterMap( + { + 0x20: "space", + 0x41: "A", + 0x0301: "acutecomb", + 0xC1: "Aacute", + 0x30: "zero", + 0x31: "one", + 0x32: "two", + } + ) + fb.setupHorizontalMetrics( + { + ".notdef": (500, 50), + "space": (600, 0), + "A": (550, 40), + "acutecomb": (0, -40), + "Aacute": (550, 40), + "zero": (500, 30), + "one": (500, 50), + "two": (500, 40), + } + ) + fb.setupHorizontalHeader(ascent=1000, descent=-200) + + srcGlyphs = { + ".notdef": Glyph(xMin=50, xMax=450), + "space": Glyph(empty=True), + "A": Glyph(xMin=40, xMax=510), + "acutecomb": Glyph(xMin=-40, xMax=60), + "Aacute": CompositeGlyph([("A", (0, 0)), ("acutecomb", (200, 0))]), + "zero": Glyph(xMin=30, xMax=470), + "one": Glyph(xMin=50, xMax=450), + "two": Glyph(xMin=40, xMax=460), + } + pen = TTGlyphPen(srcGlyphs) + glyphSet = {} + for glyphName, glyph in srcGlyphs.items(): + glyph.draw(pen) + glyphSet[glyphName] = pen.glyph() + fb.setupGlyf(glyphSet) + + fb.setupNameTable( + { + "familyName": "TestWOFF2", + "styleName": "Regular", + "uniqueFontIdentifier": "TestWOFF2 Regular; Version 1.000; ABCD", + "fullName": "TestWOFF2 Regular", + "version": "Version 1.000", + "psName": "TestWOFF2-Regular", + } + ) + fb.setupOS2() + fb.setupPost() + + buf = BytesIO() + fb.save(buf) + buf.seek(0) + + assert fb.font["maxp"].numGlyphs == 8 + assert fb.font["hhea"].numberOfHMetrics == 6 + for glyphName in fb.font.getGlyphOrder(): + xMin = getattr(fb.font["glyf"][glyphName], "xMin", 0) + assert xMin == fb.font["hmtx"][glyphName][1] + + return buf + + +@pytest.fixture +def ttFont(fontfile): + return ttLib.TTFont(fontfile, recalcBBoxes=False, recalcTimestamp=False) + + +class WOFF2HmtxTableTest(object): + def test_transform_no_sidebearings(self, ttFont): + hmtxTable = WOFF2HmtxTable() + hmtxTable.metrics = ttFont["hmtx"].metrics + + data = hmtxTable.transform(ttFont) + + assert data == ( + b"\x03" # 00000011 | bits 0 and 1 are set (no sidebearings arrays) + + # advanceWidthArray + b'\x01\xf4' # .notdef: 500 + b'\x02X' # space: 600 + b'\x02&' # A: 550 + b'\x00\x00' # acutecomb: 0 + b'\x02&' # Aacute: 550 + b'\x01\xf4' # zero: 500 + ) + + def test_transform_proportional_sidebearings(self, ttFont): + hmtxTable = WOFF2HmtxTable() + metrics = ttFont["hmtx"].metrics + # force one of the proportional glyphs to have its left sidebearing be + # different from its xMin (40) + metrics["A"] = (550, 39) + hmtxTable.metrics = metrics + + assert ttFont["glyf"]["A"].xMin != metrics["A"][1] + + data = hmtxTable.transform(ttFont) + + assert data == ( + b"\x02" # 00000010 | bits 0 unset: explicit proportional sidebearings + + # advanceWidthArray + b'\x01\xf4' # .notdef: 500 + b'\x02X' # space: 600 + b'\x02&' # A: 550 + b'\x00\x00' # acutecomb: 0 + b'\x02&' # Aacute: 550 + b'\x01\xf4' # zero: 500 + + # lsbArray + b'\x002' # .notdef: 50 + b'\x00\x00' # space: 0 + b"\x00'" # A: 39 (xMin: 40) + b'\xff\xd8' # acutecomb: -40 + b'\x00(' # Aacute: 40 + b'\x00\x1e' # zero: 30 + ) + + def test_transform_monospaced_sidebearings(self, ttFont): + hmtxTable = WOFF2HmtxTable() + metrics = ttFont["hmtx"].metrics + hmtxTable.metrics = metrics + + # force one of the monospaced glyphs at the end of hmtx table to have + # its xMin different from its left sidebearing (50) + ttFont["glyf"]["one"].xMin = metrics["one"][1] + 1 + + data = hmtxTable.transform(ttFont) + + assert data == ( + b"\x01" # 00000001 | bits 1 unset: explicit monospaced sidebearings + + # advanceWidthArray + b'\x01\xf4' # .notdef: 500 + b'\x02X' # space: 600 + b'\x02&' # A: 550 + b'\x00\x00' # acutecomb: 0 + b'\x02&' # Aacute: 550 + b'\x01\xf4' # zero: 500 + + # leftSideBearingArray + b'\x002' # one: 50 (xMin: 51) + b'\x00(' # two: 40 + ) + + def test_transform_not_applicable(self, ttFont): + hmtxTable = WOFF2HmtxTable() + metrics = ttFont["hmtx"].metrics + # force both a proportional and monospaced glyph to have sidebearings + # different from the respective xMin coordinates + metrics["A"] = (550, 39) + metrics["one"] = (500, 51) + hmtxTable.metrics = metrics + + # 'None' signals to fall back using untransformed hmtx table data + assert hmtxTable.transform(ttFont) is None + + def test_reconstruct_no_sidebearings(self, ttFont): + hmtxTable = WOFF2HmtxTable() + + data = ( + b"\x03" # 00000011 | bits 0 and 1 are set (no sidebearings arrays) + + # advanceWidthArray + b'\x01\xf4' # .notdef: 500 + b'\x02X' # space: 600 + b'\x02&' # A: 550 + b'\x00\x00' # acutecomb: 0 + b'\x02&' # Aacute: 550 + b'\x01\xf4' # zero: 500 + ) + + hmtxTable.reconstruct(data, ttFont) + + assert hmtxTable.metrics == { + ".notdef": (500, 50), + "space": (600, 0), + "A": (550, 40), + "acutecomb": (0, -40), + "Aacute": (550, 40), + "zero": (500, 30), + "one": (500, 50), + "two": (500, 40), + } + + def test_reconstruct_proportional_sidebearings(self, ttFont): + hmtxTable = WOFF2HmtxTable() + + data = ( + b"\x02" # 00000010 | bits 0 unset: explicit proportional sidebearings + + # advanceWidthArray + b'\x01\xf4' # .notdef: 500 + b'\x02X' # space: 600 + b'\x02&' # A: 550 + b'\x00\x00' # acutecomb: 0 + b'\x02&' # Aacute: 550 + b'\x01\xf4' # zero: 500 + + # lsbArray + b'\x002' # .notdef: 50 + b'\x00\x00' # space: 0 + b"\x00'" # A: 39 (xMin: 40) + b'\xff\xd8' # acutecomb: -40 + b'\x00(' # Aacute: 40 + b'\x00\x1e' # zero: 30 + ) + + hmtxTable.reconstruct(data, ttFont) + + assert hmtxTable.metrics == { + ".notdef": (500, 50), + "space": (600, 0), + "A": (550, 39), + "acutecomb": (0, -40), + "Aacute": (550, 40), + "zero": (500, 30), + "one": (500, 50), + "two": (500, 40), + } + + assert ttFont["glyf"]["A"].xMin == 40 + + def test_reconstruct_monospaced_sidebearings(self, ttFont): + hmtxTable = WOFF2HmtxTable() + + data = ( + b"\x01" # 00000001 | bits 1 unset: explicit monospaced sidebearings + + # advanceWidthArray + b'\x01\xf4' # .notdef: 500 + b'\x02X' # space: 600 + b'\x02&' # A: 550 + b'\x00\x00' # acutecomb: 0 + b'\x02&' # Aacute: 550 + b'\x01\xf4' # zero: 500 + + # leftSideBearingArray + b'\x003' # one: 51 (xMin: 50) + b'\x00(' # two: 40 + ) + + hmtxTable.reconstruct(data, ttFont) + + assert hmtxTable.metrics == { + ".notdef": (500, 50), + "space": (600, 0), + "A": (550, 40), + "acutecomb": (0, -40), + "Aacute": (550, 40), + "zero": (500, 30), + "one": (500, 51), + "two": (500, 40), + } + + assert ttFont["glyf"]["one"].xMin == 50 + + def test_reconstruct_flags_reserved_bits(self): + hmtxTable = WOFF2HmtxTable() + + with pytest.raises( + ttLib.TTLibError, match="Bits 2-7 of 'hmtx' flags are reserved" + ): + hmtxTable.reconstruct(b"\xFF", ttFont=None) + + def test_reconstruct_flags_required_bits(self): + hmtxTable = WOFF2HmtxTable() + + with pytest.raises(ttLib.TTLibError, match="either bits 0 or 1 .* must set"): + hmtxTable.reconstruct(b"\x00", ttFont=None) + + def test_reconstruct_too_much_data(self, ttFont): + ttFont["hhea"].numberOfHMetrics = 2 + data = b'\x03\x01\xf4\x02X\x02&' + hmtxTable = WOFF2HmtxTable() + + with pytest.raises(ttLib.TTLibError, match="too much 'hmtx' table data"): + hmtxTable.reconstruct(data, ttFont) + + +class WOFF2RoundtripTest(object): + @staticmethod + def roundtrip(infile): + infile.seek(0) + ttFont = ttLib.TTFont(infile, recalcBBoxes=False, recalcTimestamp=False) + outfile = BytesIO() + ttFont.save(outfile) + return outfile, ttFont + + def test_roundtrip_default_transforms(self, ttFont): + ttFont.flavor = "woff2" + # ttFont.flavorData = None + tmp = BytesIO() + ttFont.save(tmp) + + tmp2, ttFont2 = self.roundtrip(tmp) + + assert tmp.getvalue() == tmp2.getvalue() + assert ttFont2.reader.flavorData.transformedTables == {"glyf", "loca"} + + def test_roundtrip_no_transforms(self, ttFont): + ttFont.flavor = "woff2" + ttFont.flavorData = WOFF2FlavorData(transformedTables=[]) + tmp = BytesIO() + ttFont.save(tmp) + + tmp2, ttFont2 = self.roundtrip(tmp) + + assert tmp.getvalue() == tmp2.getvalue() + assert not ttFont2.reader.flavorData.transformedTables + + def test_roundtrip_all_transforms(self, ttFont): + ttFont.flavor = "woff2" + ttFont.flavorData = WOFF2FlavorData(transformedTables=["glyf", "loca", "hmtx"]) + tmp = BytesIO() + ttFont.save(tmp) + + tmp2, ttFont2 = self.roundtrip(tmp) + + assert tmp.getvalue() == tmp2.getvalue() + assert ttFont2.reader.flavorData.transformedTables == {"glyf", "loca", "hmtx"} + + def test_roundtrip_only_hmtx_no_glyf_transform(self, ttFont): + ttFont.flavor = "woff2" + ttFont.flavorData = WOFF2FlavorData(transformedTables=["hmtx"]) + tmp = BytesIO() + ttFont.save(tmp) + + tmp2, ttFont2 = self.roundtrip(tmp) + + assert tmp.getvalue() == tmp2.getvalue() + assert ttFont2.reader.flavorData.transformedTables == {"hmtx"} + + +class MainTest(object): + + @staticmethod + def make_ttf(tmpdir): + ttFont = ttLib.TTFont(recalcBBoxes=False, recalcTimestamp=False) + ttFont.importXML(TTX) + filename = str(tmpdir / "TestTTF-Regular.ttf") + ttFont.save(filename) + return filename + + def test_compress_ttf(self, tmpdir): + input_file = self.make_ttf(tmpdir) + + assert woff2.main(["compress", input_file]) is None + + assert (tmpdir / "TestTTF-Regular.woff2").check(file=True) + + def test_compress_ttf_no_glyf_transform(self, tmpdir): + input_file = self.make_ttf(tmpdir) + + assert woff2.main(["compress", "--no-glyf-transform", input_file]) is None + + assert (tmpdir / "TestTTF-Regular.woff2").check(file=True) + + def test_compress_ttf_hmtx_transform(self, tmpdir): + input_file = self.make_ttf(tmpdir) + + assert woff2.main(["compress", "--hmtx-transform", input_file]) is None + + assert (tmpdir / "TestTTF-Regular.woff2").check(file=True) + + def test_compress_ttf_no_glyf_transform_hmtx_transform(self, tmpdir): + input_file = self.make_ttf(tmpdir) + + assert woff2.main( + ["compress", "--no-glyf-transform", "--hmtx-transform", input_file] + ) is None + + assert (tmpdir / "TestTTF-Regular.woff2").check(file=True) + + def test_compress_output_file(self, tmpdir): + input_file = self.make_ttf(tmpdir) + output_file = tmpdir / "TestTTF.woff2" + + assert woff2.main( + ["compress", "-o", str(output_file), str(input_file)] + ) is None + + assert output_file.check(file=True) + + def test_compress_otf(self, tmpdir): + ttFont = ttLib.TTFont(recalcBBoxes=False, recalcTimestamp=False) + ttFont.importXML(OTX) + input_file = str(tmpdir / "TestOTF-Regular.otf") + ttFont.save(input_file) + + assert woff2.main(["compress", input_file]) is None + + assert (tmpdir / "TestOTF-Regular.woff2").check(file=True) + + def test_recompress_woff2_keeps_flavorData(self, tmpdir): + woff2_font = ttLib.TTFont(BytesIO(TT_WOFF2.getvalue())) + woff2_font.flavorData.privData = b"FOOBAR" + woff2_file = tmpdir / "TestTTF-Regular.woff2" + woff2_font.save(str(woff2_file)) + + assert woff2_font.flavorData.transformedTables == {"glyf", "loca"} + + woff2.main(["compress", "--hmtx-transform", str(woff2_file)]) + + output_file = tmpdir / "TestTTF-Regular#1.woff2" + assert output_file.check(file=True) + + new_woff2_font = ttLib.TTFont(str(output_file)) + + assert new_woff2_font.flavorData.transformedTables == {"glyf", "loca", "hmtx"} + assert new_woff2_font.flavorData.privData == b"FOOBAR" + + def test_decompress_ttf(self, tmpdir): + input_file = tmpdir / "TestTTF-Regular.woff2" + input_file.write_binary(TT_WOFF2.getvalue()) + + assert woff2.main(["decompress", str(input_file)]) is None + + assert (tmpdir / "TestTTF-Regular.ttf").check(file=True) + + def test_decompress_otf(self, tmpdir): + input_file = tmpdir / "TestTTF-Regular.woff2" + input_file.write_binary(CFF_WOFF2.getvalue()) + + assert woff2.main(["decompress", str(input_file)]) is None + + assert (tmpdir / "TestTTF-Regular.otf").check(file=True) + + def test_decompress_output_file(self, tmpdir): + input_file = tmpdir / "TestTTF-Regular.woff2" + input_file.write_binary(TT_WOFF2.getvalue()) + output_file = tmpdir / "TestTTF.ttf" + + assert woff2.main( + ["decompress", "-o", str(output_file), str(input_file)] + ) is None + + assert output_file.check(file=True) + + def test_no_subcommand_show_help(self, capsys): + with pytest.raises(SystemExit): + woff2.main(["--help"]) + + captured = capsys.readouterr() + assert "usage: fonttools ttLib.woff2" in captured.out + + class Base128Test(unittest.TestCase): def test_unpackBase128(self): diff --git a/Tests/unicodedata_test.py b/Tests/unicodedata_test.py index 190576fd..fde3338f 100644 --- a/Tests/unicodedata_test.py +++ b/Tests/unicodedata_test.py @@ -165,8 +165,8 @@ def test_script_extension(): assert unicodedata.script_extension("\u0660") == {'Arab', 'Thaa'} assert unicodedata.script_extension("\u0964") == { - 'Beng', 'Deva', 'Dogr', 'Gong', 'Gran', 'Gujr', 'Guru', 'Knda', - 'Mahj', 'Mlym', 'Orya', 'Sind', 'Sinh', 'Sylo', 'Takr', 'Taml', + 'Beng', 'Deva', 'Dogr', 'Gong', 'Gonm', 'Gran', 'Gujr', 'Guru', 'Knda', + 'Mahj', 'Mlym', 'Nand', 'Orya', 'Sind', 'Sinh', 'Sylo', 'Takr', 'Taml', 'Telu', 'Tirh'} diff --git a/Tests/varLib/data/KerningMerging.designspace b/Tests/varLib/data/KerningMerging.designspace new file mode 100644 index 00000000..f7ce7ef8 --- /dev/null +++ b/Tests/varLib/data/KerningMerging.designspace @@ -0,0 +1,23 @@ +<?xml version='1.0' encoding='UTF-8'?> +<designspace format="4.0"> + <axes> + <axis tag="wght" name="Weight" minimum="100" maximum="900" default="400"/> + </axes> + <sources> + <source filename="master_kerning_merging/0.ttf"> + <location> + <dimension name="Weight" xvalue="100"/> + </location> + </source> + <source filename="master_kerning_merging/1.ttf"> + <location> + <dimension name="Weight" xvalue="400"/> + </location> + </source> + <source filename="master_kerning_merging/2.ttf"> + <location> + <dimension name="Weight" xvalue="900"/> + </location> + </source> + </sources> +</designspace> diff --git a/Tests/varLib/data/TestNonMarkingCFF2.designspace b/Tests/varLib/data/TestNonMarkingCFF2.designspace new file mode 100644 index 00000000..23c7797d --- /dev/null +++ b/Tests/varLib/data/TestNonMarkingCFF2.designspace @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<designspace format="3"> + <axes> + <axis default="0.0" maximum="1000.0" minimum="0.0" name="weight" tag="wght" /> + </axes> + <sources> + <source filename="master_non_marking_cff2/TestNonMarkingCFF2_ExtraLight.ufo" name="master_0"> + <lib copy="1" /> + <location> + <dimension name="weight" xvalue="0" /> + </location> + </source> + <source filename="master_non_marking_cff2/TestNonMarkingCFF2_Regular.ufo" name="master_1"> + <location> + <dimension name="weight" xvalue="1000" /> + </location> + </source> + </sources> + <instances> + <instance familyname="Test Non Marking CFF2 Roman" postscriptfontname="TestNonMarkingCFF2-ExtraLight" stylename="ExtraLight"> + <location> + <dimension name="weight" xvalue="0" /> + </location> + <kerning /> + <info /> + </instance> + <instance familyname="Test Non Marking CFF2 Roman" postscriptfontname="TestNonMarkingCFF2-Regular" stylename="Regular"> + <location> + <dimension name="weight" xvalue="1000" /> + </location> + <kerning /> + <info /> + </instance> + </instances> +</designspace> diff --git a/Tests/varLib/data/master_kerning_merging/0.ttx b/Tests/varLib/data/master_kerning_merging/0.ttx new file mode 100644 index 00000000..858f9275 --- /dev/null +++ b/Tests/varLib/data/master_kerning_merging/0.ttx @@ -0,0 +1,304 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.41"> + + <GlyphOrder> + <!-- The 'id' attribute is only for humans; it is ignored when parsed. --> + <GlyphID id="0" name=".notdef"/> + <GlyphID id="1" name="A"/> + <GlyphID id="2" name="B"/> + <GlyphID id="3" name="C"/> + <GlyphID id="4" name="D"/> + </GlyphOrder> + + <head> + <!-- Most of this table will be recalculated by the compiler --> + <tableVersion value="1.0"/> + <fontRevision value="0.0"/> + <checkSumAdjustment value="0x341296b2"/> + <magicNumber value="0x5f0f3cf5"/> + <flags value="00000000 00000011"/> + <unitsPerEm value="1000"/> + <created value="Wed Jun 12 15:33:01 2019"/> + <modified value="Wed Jun 12 15:33:01 2019"/> + <xMin value="50"/> + <yMin value="-200"/> + <xMax value="450"/> + <yMax value="800"/> + <macStyle value="00000000 00000000"/> + <lowestRecPPEM value="6"/> + <fontDirectionHint value="2"/> + <indexToLocFormat value="0"/> + <glyphDataFormat value="0"/> + </head> + + <hhea> + <tableVersion value="0x00010000"/> + <ascent value="1000"/> + <descent value="-200"/> + <lineGap value="0"/> + <advanceWidthMax value="500"/> + <minLeftSideBearing value="50"/> + <minRightSideBearing value="50"/> + <xMaxExtent value="450"/> + <caretSlopeRise value="1"/> + <caretSlopeRun value="0"/> + <caretOffset value="0"/> + <reserved0 value="0"/> + <reserved1 value="0"/> + <reserved2 value="0"/> + <reserved3 value="0"/> + <metricDataFormat value="0"/> + <numberOfHMetrics value="1"/> + </hhea> + + <maxp> + <!-- Most of this table will be recalculated by the compiler --> + <tableVersion value="0x10000"/> + <numGlyphs value="5"/> + <maxPoints value="8"/> + <maxContours value="2"/> + <maxCompositePoints value="0"/> + <maxCompositeContours value="0"/> + <maxZones value="1"/> + <maxTwilightPoints value="0"/> + <maxStorage value="0"/> + <maxFunctionDefs value="0"/> + <maxInstructionDefs value="0"/> + <maxStackElements value="0"/> + <maxSizeOfInstructions value="0"/> + <maxComponentElements value="0"/> + <maxComponentDepth value="0"/> + </maxp> + + <OS_2> + <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex' + will be recalculated by the compiler --> + <version value="4"/> + <xAvgCharWidth value="500"/> + <usWeightClass value="400"/> + <usWidthClass value="5"/> + <fsType value="00000000 00000100"/> + <ySubscriptXSize value="650"/> + <ySubscriptYSize value="600"/> + <ySubscriptXOffset value="0"/> + <ySubscriptYOffset value="75"/> + <ySuperscriptXSize value="650"/> + <ySuperscriptYSize value="600"/> + <ySuperscriptXOffset value="0"/> + <ySuperscriptYOffset value="350"/> + <yStrikeoutSize value="50"/> + <yStrikeoutPosition value="300"/> + <sFamilyClass value="0"/> + <panose> + <bFamilyType value="0"/> + <bSerifStyle value="0"/> + <bWeight value="0"/> + <bProportion value="0"/> + <bContrast value="0"/> + <bStrokeVariation value="0"/> + <bArmStyle value="0"/> + <bLetterForm value="0"/> + <bMidline value="0"/> + <bXHeight value="0"/> + </panose> + <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/> + <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/> + <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/> + <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/> + <achVendID value="NONE"/> + <fsSelection value="00000000 01000000"/> + <usFirstCharIndex value="65"/> + <usLastCharIndex value="68"/> + <sTypoAscender value="800"/> + <sTypoDescender value="-200"/> + <sTypoLineGap value="200"/> + <usWinAscent value="1000"/> + <usWinDescent value="200"/> + <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/> + <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/> + <sxHeight value="500"/> + <sCapHeight value="700"/> + <usDefaultChar value="0"/> + <usBreakChar value="32"/> + <usMaxContext value="2"/> + </OS_2> + + <hmtx> + <mtx name=".notdef" width="500" lsb="50"/> + <mtx name="A" width="500" lsb="0"/> + <mtx name="B" width="500" lsb="0"/> + <mtx name="C" width="500" lsb="0"/> + <mtx name="D" width="500" lsb="0"/> + </hmtx> + + <cmap> + <tableVersion version="0"/> + <cmap_format_4 platformID="0" platEncID="3" language="0"> + <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A --> + <map code="0x42" name="B"/><!-- LATIN CAPITAL LETTER B --> + <map code="0x43" name="C"/><!-- LATIN CAPITAL LETTER C --> + <map code="0x44" name="D"/><!-- LATIN CAPITAL LETTER D --> + </cmap_format_4> + <cmap_format_4 platformID="3" platEncID="1" language="0"> + <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A --> + <map code="0x42" name="B"/><!-- LATIN CAPITAL LETTER B --> + <map code="0x43" name="C"/><!-- LATIN CAPITAL LETTER C --> + <map code="0x44" name="D"/><!-- LATIN CAPITAL LETTER D --> + </cmap_format_4> + </cmap> + + <loca> + <!-- The 'loca' table will be calculated by the compiler --> + </loca> + + <glyf> + + <!-- The xMin, yMin, xMax and yMax values + will be recalculated by the compiler. --> + + <TTGlyph name=".notdef" xMin="50" yMin="-200" xMax="450" yMax="800"> + <contour> + <pt x="50" y="-200" on="1"/> + <pt x="450" y="-200" on="1"/> + <pt x="450" y="800" on="1"/> + <pt x="50" y="800" on="1"/> + </contour> + <contour> + <pt x="100" y="-150" on="1"/> + <pt x="100" y="750" on="1"/> + <pt x="400" y="750" on="1"/> + <pt x="400" y="-150" on="1"/> + </contour> + <instructions/> + </TTGlyph> + + <TTGlyph name="A"/><!-- contains no outline data --> + + <TTGlyph name="B"/><!-- contains no outline data --> + + <TTGlyph name="C"/><!-- contains no outline data --> + + <TTGlyph name="D"/><!-- contains no outline data --> + + </glyf> + + <name> + <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409"> + Test Thin + </namerecord> + <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409"> + Regular + </namerecord> + <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409"> + 0.000;NONE;Test-Thin + </namerecord> + <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409"> + Test Thin + </namerecord> + <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409"> + Version 0.000 + </namerecord> + <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409"> + Test-Thin + </namerecord> + <namerecord nameID="16" platformID="3" platEncID="1" langID="0x409"> + Test + </namerecord> + <namerecord nameID="17" platformID="3" platEncID="1" langID="0x409"> + Thin + </namerecord> + </name> + + <post> + <formatType value="2.0"/> + <italicAngle value="0.0"/> + <underlinePosition value="-150"/> + <underlineThickness value="50"/> + <isFixedPitch value="0"/> + <minMemType42 value="0"/> + <maxMemType42 value="0"/> + <minMemType1 value="0"/> + <maxMemType1 value="0"/> + <psNames> + <!-- This file uses unique glyph names based on the information + found in the 'post' table. Since these names might not be unique, + we have to invent artificial names in case of clashes. In order to + be able to retain the original information, we need a name to + ps name mapping for those cases where they differ. That's what + you see below. + --> + </psNames> + <extraNames> + <!-- following are the name that are not taken from the standard Mac glyph order --> + </extraNames> + </post> + + <GPOS> + <Version value="0x00010000"/> + <ScriptList> + <!-- ScriptCount=1 --> + <ScriptRecord index="0"> + <ScriptTag value="DFLT"/> + <Script> + <DefaultLangSys> + <ReqFeatureIndex value="65535"/> + <!-- FeatureCount=1 --> + <FeatureIndex index="0" value="0"/> + </DefaultLangSys> + <!-- LangSysCount=0 --> + </Script> + </ScriptRecord> + </ScriptList> + <FeatureList> + <!-- FeatureCount=1 --> + <FeatureRecord index="0"> + <FeatureTag value="kern"/> + <Feature> + <!-- LookupCount=1 --> + <LookupListIndex index="0" value="0"/> + </Feature> + </FeatureRecord> + </FeatureList> + <LookupList> + <!-- LookupCount=1 --> + <Lookup index="0"> + <LookupType value="2"/> + <LookupFlag value="8"/> + <!-- SubTableCount=1 --> + <PairPos index="0" Format="2"> + <Coverage Format="1"> + <Glyph value="A"/> + <Glyph value="B"/> + </Coverage> + <ValueFormat1 value="4"/> + <ValueFormat2 value="0"/> + <ClassDef1 Format="1"> + <ClassDef glyph="A" class="1"/> + </ClassDef1> + <ClassDef2 Format="1"> + <ClassDef glyph="C" class="1"/> + </ClassDef2> + <!-- Class1Count=2 --> + <!-- Class2Count=2 --> + <Class1Record index="0"> + <Class2Record index="0"> + <Value1 XAdvance="0"/> + </Class2Record> + <Class2Record index="1"> + <Value1 XAdvance="10"/> + </Class2Record> + </Class1Record> + <Class1Record index="1"> + <Class2Record index="0"> + <Value1 XAdvance="0"/> + </Class2Record> + <Class2Record index="1"> + <Value1 XAdvance="10"/> + </Class2Record> + </Class1Record> + </PairPos> + </Lookup> + </LookupList> + </GPOS> + +</ttFont> diff --git a/Tests/varLib/data/master_kerning_merging/1.ttx b/Tests/varLib/data/master_kerning_merging/1.ttx new file mode 100644 index 00000000..d60a7084 --- /dev/null +++ b/Tests/varLib/data/master_kerning_merging/1.ttx @@ -0,0 +1,292 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.41"> + + <GlyphOrder> + <!-- The 'id' attribute is only for humans; it is ignored when parsed. --> + <GlyphID id="0" name=".notdef"/> + <GlyphID id="1" name="A"/> + <GlyphID id="2" name="B"/> + <GlyphID id="3" name="C"/> + <GlyphID id="4" name="D"/> + </GlyphOrder> + + <head> + <!-- Most of this table will be recalculated by the compiler --> + <tableVersion value="1.0"/> + <fontRevision value="0.0"/> + <checkSumAdjustment value="0x340ca516"/> + <magicNumber value="0x5f0f3cf5"/> + <flags value="00000000 00000011"/> + <unitsPerEm value="1000"/> + <created value="Wed Jun 12 15:33:01 2019"/> + <modified value="Wed Jun 12 15:33:01 2019"/> + <xMin value="50"/> + <yMin value="-200"/> + <xMax value="450"/> + <yMax value="800"/> + <macStyle value="00000000 00000000"/> + <lowestRecPPEM value="6"/> + <fontDirectionHint value="2"/> + <indexToLocFormat value="0"/> + <glyphDataFormat value="0"/> + </head> + + <hhea> + <tableVersion value="0x00010000"/> + <ascent value="1000"/> + <descent value="-200"/> + <lineGap value="0"/> + <advanceWidthMax value="500"/> + <minLeftSideBearing value="50"/> + <minRightSideBearing value="50"/> + <xMaxExtent value="450"/> + <caretSlopeRise value="1"/> + <caretSlopeRun value="0"/> + <caretOffset value="0"/> + <reserved0 value="0"/> + <reserved1 value="0"/> + <reserved2 value="0"/> + <reserved3 value="0"/> + <metricDataFormat value="0"/> + <numberOfHMetrics value="1"/> + </hhea> + + <maxp> + <!-- Most of this table will be recalculated by the compiler --> + <tableVersion value="0x10000"/> + <numGlyphs value="5"/> + <maxPoints value="8"/> + <maxContours value="2"/> + <maxCompositePoints value="0"/> + <maxCompositeContours value="0"/> + <maxZones value="1"/> + <maxTwilightPoints value="0"/> + <maxStorage value="0"/> + <maxFunctionDefs value="0"/> + <maxInstructionDefs value="0"/> + <maxStackElements value="0"/> + <maxSizeOfInstructions value="0"/> + <maxComponentElements value="0"/> + <maxComponentDepth value="0"/> + </maxp> + + <OS_2> + <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex' + will be recalculated by the compiler --> + <version value="4"/> + <xAvgCharWidth value="500"/> + <usWeightClass value="400"/> + <usWidthClass value="5"/> + <fsType value="00000000 00000100"/> + <ySubscriptXSize value="650"/> + <ySubscriptYSize value="600"/> + <ySubscriptXOffset value="0"/> + <ySubscriptYOffset value="75"/> + <ySuperscriptXSize value="650"/> + <ySuperscriptYSize value="600"/> + <ySuperscriptXOffset value="0"/> + <ySuperscriptYOffset value="350"/> + <yStrikeoutSize value="50"/> + <yStrikeoutPosition value="300"/> + <sFamilyClass value="0"/> + <panose> + <bFamilyType value="0"/> + <bSerifStyle value="0"/> + <bWeight value="0"/> + <bProportion value="0"/> + <bContrast value="0"/> + <bStrokeVariation value="0"/> + <bArmStyle value="0"/> + <bLetterForm value="0"/> + <bMidline value="0"/> + <bXHeight value="0"/> + </panose> + <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/> + <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/> + <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/> + <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/> + <achVendID value="NONE"/> + <fsSelection value="00000000 01000000"/> + <usFirstCharIndex value="65"/> + <usLastCharIndex value="68"/> + <sTypoAscender value="800"/> + <sTypoDescender value="-200"/> + <sTypoLineGap value="200"/> + <usWinAscent value="1000"/> + <usWinDescent value="200"/> + <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/> + <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/> + <sxHeight value="500"/> + <sCapHeight value="700"/> + <usDefaultChar value="0"/> + <usBreakChar value="32"/> + <usMaxContext value="2"/> + </OS_2> + + <hmtx> + <mtx name=".notdef" width="500" lsb="50"/> + <mtx name="A" width="500" lsb="0"/> + <mtx name="B" width="500" lsb="0"/> + <mtx name="C" width="500" lsb="0"/> + <mtx name="D" width="500" lsb="0"/> + </hmtx> + + <cmap> + <tableVersion version="0"/> + <cmap_format_4 platformID="0" platEncID="3" language="0"> + <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A --> + <map code="0x42" name="B"/><!-- LATIN CAPITAL LETTER B --> + <map code="0x43" name="C"/><!-- LATIN CAPITAL LETTER C --> + <map code="0x44" name="D"/><!-- LATIN CAPITAL LETTER D --> + </cmap_format_4> + <cmap_format_4 platformID="3" platEncID="1" language="0"> + <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A --> + <map code="0x42" name="B"/><!-- LATIN CAPITAL LETTER B --> + <map code="0x43" name="C"/><!-- LATIN CAPITAL LETTER C --> + <map code="0x44" name="D"/><!-- LATIN CAPITAL LETTER D --> + </cmap_format_4> + </cmap> + + <loca> + <!-- The 'loca' table will be calculated by the compiler --> + </loca> + + <glyf> + + <!-- The xMin, yMin, xMax and yMax values + will be recalculated by the compiler. --> + + <TTGlyph name=".notdef" xMin="50" yMin="-200" xMax="450" yMax="800"> + <contour> + <pt x="50" y="-200" on="1"/> + <pt x="450" y="-200" on="1"/> + <pt x="450" y="800" on="1"/> + <pt x="50" y="800" on="1"/> + </contour> + <contour> + <pt x="100" y="-150" on="1"/> + <pt x="100" y="750" on="1"/> + <pt x="400" y="750" on="1"/> + <pt x="400" y="-150" on="1"/> + </contour> + <instructions/> + </TTGlyph> + + <TTGlyph name="A"/><!-- contains no outline data --> + + <TTGlyph name="B"/><!-- contains no outline data --> + + <TTGlyph name="C"/><!-- contains no outline data --> + + <TTGlyph name="D"/><!-- contains no outline data --> + + </glyf> + + <name> + <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409"> + Test + </namerecord> + <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409"> + Regular + </namerecord> + <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409"> + 0.000;NONE;Test-Regular + </namerecord> + <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409"> + Test Regular + </namerecord> + <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409"> + Version 0.000 + </namerecord> + <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409"> + Test-Regular + </namerecord> + </name> + + <post> + <formatType value="2.0"/> + <italicAngle value="0.0"/> + <underlinePosition value="-150"/> + <underlineThickness value="50"/> + <isFixedPitch value="0"/> + <minMemType42 value="0"/> + <maxMemType42 value="0"/> + <minMemType1 value="0"/> + <maxMemType1 value="0"/> + <psNames> + <!-- This file uses unique glyph names based on the information + found in the 'post' table. Since these names might not be unique, + we have to invent artificial names in case of clashes. In order to + be able to retain the original information, we need a name to + ps name mapping for those cases where they differ. That's what + you see below. + --> + </psNames> + <extraNames> + <!-- following are the name that are not taken from the standard Mac glyph order --> + </extraNames> + </post> + + <GPOS> + <Version value="0x00010000"/> + <ScriptList> + <!-- ScriptCount=1 --> + <ScriptRecord index="0"> + <ScriptTag value="DFLT"/> + <Script> + <DefaultLangSys> + <ReqFeatureIndex value="65535"/> + <!-- FeatureCount=1 --> + <FeatureIndex index="0" value="0"/> + </DefaultLangSys> + <!-- LangSysCount=0 --> + </Script> + </ScriptRecord> + </ScriptList> + <FeatureList> + <!-- FeatureCount=1 --> + <FeatureRecord index="0"> + <FeatureTag value="kern"/> + <Feature> + <!-- LookupCount=1 --> + <LookupListIndex index="0" value="0"/> + </Feature> + </FeatureRecord> + </FeatureList> + <LookupList> + <!-- LookupCount=1 --> + <Lookup index="0"> + <LookupType value="2"/> + <LookupFlag value="8"/> + <!-- SubTableCount=1 --> + <PairPos index="0" Format="2"> + <Coverage Format="1"> + <Glyph value="A"/> + </Coverage> + <ValueFormat1 value="4"/> + <ValueFormat2 value="0"/> + <ClassDef1 Format="2"> + </ClassDef1> + <ClassDef2 Format="1"> + <ClassDef glyph="B" class="2"/> + <ClassDef glyph="D" class="1"/> + </ClassDef2> + <!-- Class1Count=1 --> + <!-- Class2Count=3 --> + <Class1Record index="0"> + <Class2Record index="0"> + <Value1 XAdvance="0"/> + </Class2Record> + <Class2Record index="1"> + <Value1 XAdvance="-20"/> + </Class2Record> + <Class2Record index="2"> + <Value1 XAdvance="-20"/> + </Class2Record> + </Class1Record> + </PairPos> + </Lookup> + </LookupList> + </GPOS> + +</ttFont> diff --git a/Tests/varLib/data/master_kerning_merging/2.ttx b/Tests/varLib/data/master_kerning_merging/2.ttx new file mode 100644 index 00000000..e01a7b1f --- /dev/null +++ b/Tests/varLib/data/master_kerning_merging/2.ttx @@ -0,0 +1,304 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.41"> + + <GlyphOrder> + <!-- The 'id' attribute is only for humans; it is ignored when parsed. --> + <GlyphID id="0" name=".notdef"/> + <GlyphID id="1" name="A"/> + <GlyphID id="2" name="B"/> + <GlyphID id="3" name="C"/> + <GlyphID id="4" name="D"/> + </GlyphOrder> + + <head> + <!-- Most of this table will be recalculated by the compiler --> + <tableVersion value="1.0"/> + <fontRevision value="0.0"/> + <checkSumAdjustment value="0x330c9492"/> + <magicNumber value="0x5f0f3cf5"/> + <flags value="00000000 00000011"/> + <unitsPerEm value="1000"/> + <created value="Wed Jun 12 15:33:01 2019"/> + <modified value="Wed Jun 12 15:33:01 2019"/> + <xMin value="50"/> + <yMin value="-200"/> + <xMax value="450"/> + <yMax value="800"/> + <macStyle value="00000000 00000000"/> + <lowestRecPPEM value="6"/> + <fontDirectionHint value="2"/> + <indexToLocFormat value="0"/> + <glyphDataFormat value="0"/> + </head> + + <hhea> + <tableVersion value="0x00010000"/> + <ascent value="1000"/> + <descent value="-200"/> + <lineGap value="0"/> + <advanceWidthMax value="500"/> + <minLeftSideBearing value="50"/> + <minRightSideBearing value="50"/> + <xMaxExtent value="450"/> + <caretSlopeRise value="1"/> + <caretSlopeRun value="0"/> + <caretOffset value="0"/> + <reserved0 value="0"/> + <reserved1 value="0"/> + <reserved2 value="0"/> + <reserved3 value="0"/> + <metricDataFormat value="0"/> + <numberOfHMetrics value="1"/> + </hhea> + + <maxp> + <!-- Most of this table will be recalculated by the compiler --> + <tableVersion value="0x10000"/> + <numGlyphs value="5"/> + <maxPoints value="8"/> + <maxContours value="2"/> + <maxCompositePoints value="0"/> + <maxCompositeContours value="0"/> + <maxZones value="1"/> + <maxTwilightPoints value="0"/> + <maxStorage value="0"/> + <maxFunctionDefs value="0"/> + <maxInstructionDefs value="0"/> + <maxStackElements value="0"/> + <maxSizeOfInstructions value="0"/> + <maxComponentElements value="0"/> + <maxComponentDepth value="0"/> + </maxp> + + <OS_2> + <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex' + will be recalculated by the compiler --> + <version value="4"/> + <xAvgCharWidth value="500"/> + <usWeightClass value="400"/> + <usWidthClass value="5"/> + <fsType value="00000000 00000100"/> + <ySubscriptXSize value="650"/> + <ySubscriptYSize value="600"/> + <ySubscriptXOffset value="0"/> + <ySubscriptYOffset value="75"/> + <ySuperscriptXSize value="650"/> + <ySuperscriptYSize value="600"/> + <ySuperscriptXOffset value="0"/> + <ySuperscriptYOffset value="350"/> + <yStrikeoutSize value="50"/> + <yStrikeoutPosition value="300"/> + <sFamilyClass value="0"/> + <panose> + <bFamilyType value="0"/> + <bSerifStyle value="0"/> + <bWeight value="0"/> + <bProportion value="0"/> + <bContrast value="0"/> + <bStrokeVariation value="0"/> + <bArmStyle value="0"/> + <bLetterForm value="0"/> + <bMidline value="0"/> + <bXHeight value="0"/> + </panose> + <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/> + <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/> + <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/> + <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/> + <achVendID value="NONE"/> + <fsSelection value="00000000 01000000"/> + <usFirstCharIndex value="65"/> + <usLastCharIndex value="68"/> + <sTypoAscender value="800"/> + <sTypoDescender value="-200"/> + <sTypoLineGap value="200"/> + <usWinAscent value="1000"/> + <usWinDescent value="200"/> + <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/> + <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/> + <sxHeight value="500"/> + <sCapHeight value="700"/> + <usDefaultChar value="0"/> + <usBreakChar value="32"/> + <usMaxContext value="2"/> + </OS_2> + + <hmtx> + <mtx name=".notdef" width="500" lsb="50"/> + <mtx name="A" width="500" lsb="0"/> + <mtx name="B" width="500" lsb="0"/> + <mtx name="C" width="500" lsb="0"/> + <mtx name="D" width="500" lsb="0"/> + </hmtx> + + <cmap> + <tableVersion version="0"/> + <cmap_format_4 platformID="0" platEncID="3" language="0"> + <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A --> + <map code="0x42" name="B"/><!-- LATIN CAPITAL LETTER B --> + <map code="0x43" name="C"/><!-- LATIN CAPITAL LETTER C --> + <map code="0x44" name="D"/><!-- LATIN CAPITAL LETTER D --> + </cmap_format_4> + <cmap_format_4 platformID="3" platEncID="1" language="0"> + <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A --> + <map code="0x42" name="B"/><!-- LATIN CAPITAL LETTER B --> + <map code="0x43" name="C"/><!-- LATIN CAPITAL LETTER C --> + <map code="0x44" name="D"/><!-- LATIN CAPITAL LETTER D --> + </cmap_format_4> + </cmap> + + <loca> + <!-- The 'loca' table will be calculated by the compiler --> + </loca> + + <glyf> + + <!-- The xMin, yMin, xMax and yMax values + will be recalculated by the compiler. --> + + <TTGlyph name=".notdef" xMin="50" yMin="-200" xMax="450" yMax="800"> + <contour> + <pt x="50" y="-200" on="1"/> + <pt x="450" y="-200" on="1"/> + <pt x="450" y="800" on="1"/> + <pt x="50" y="800" on="1"/> + </contour> + <contour> + <pt x="100" y="-150" on="1"/> + <pt x="100" y="750" on="1"/> + <pt x="400" y="750" on="1"/> + <pt x="400" y="-150" on="1"/> + </contour> + <instructions/> + </TTGlyph> + + <TTGlyph name="A"/><!-- contains no outline data --> + + <TTGlyph name="B"/><!-- contains no outline data --> + + <TTGlyph name="C"/><!-- contains no outline data --> + + <TTGlyph name="D"/><!-- contains no outline data --> + + </glyf> + + <name> + <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409"> + Test Black + </namerecord> + <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409"> + Regular + </namerecord> + <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409"> + 0.000;NONE;Test-Black + </namerecord> + <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409"> + Test Black + </namerecord> + <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409"> + Version 0.000 + </namerecord> + <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409"> + Test-Black + </namerecord> + <namerecord nameID="16" platformID="3" platEncID="1" langID="0x409"> + Test + </namerecord> + <namerecord nameID="17" platformID="3" platEncID="1" langID="0x409"> + Black + </namerecord> + </name> + + <post> + <formatType value="2.0"/> + <italicAngle value="0.0"/> + <underlinePosition value="-150"/> + <underlineThickness value="50"/> + <isFixedPitch value="0"/> + <minMemType42 value="0"/> + <maxMemType42 value="0"/> + <minMemType1 value="0"/> + <maxMemType1 value="0"/> + <psNames> + <!-- This file uses unique glyph names based on the information + found in the 'post' table. Since these names might not be unique, + we have to invent artificial names in case of clashes. In order to + be able to retain the original information, we need a name to + ps name mapping for those cases where they differ. That's what + you see below. + --> + </psNames> + <extraNames> + <!-- following are the name that are not taken from the standard Mac glyph order --> + </extraNames> + </post> + + <GPOS> + <Version value="0x00010000"/> + <ScriptList> + <!-- ScriptCount=1 --> + <ScriptRecord index="0"> + <ScriptTag value="DFLT"/> + <Script> + <DefaultLangSys> + <ReqFeatureIndex value="65535"/> + <!-- FeatureCount=1 --> + <FeatureIndex index="0" value="0"/> + </DefaultLangSys> + <!-- LangSysCount=0 --> + </Script> + </ScriptRecord> + </ScriptList> + <FeatureList> + <!-- FeatureCount=1 --> + <FeatureRecord index="0"> + <FeatureTag value="kern"/> + <Feature> + <!-- LookupCount=1 --> + <LookupListIndex index="0" value="0"/> + </Feature> + </FeatureRecord> + </FeatureList> + <LookupList> + <!-- LookupCount=1 --> + <Lookup index="0"> + <LookupType value="2"/> + <LookupFlag value="8"/> + <!-- SubTableCount=1 --> + <PairPos index="0" Format="2"> + <Coverage Format="1"> + <Glyph value="A"/> + <Glyph value="B"/> + </Coverage> + <ValueFormat1 value="4"/> + <ValueFormat2 value="0"/> + <ClassDef1 Format="1"> + <ClassDef glyph="A" class="1"/> + </ClassDef1> + <ClassDef2 Format="1"> + <ClassDef glyph="D" class="1"/> + </ClassDef2> + <!-- Class1Count=2 --> + <!-- Class2Count=2 --> + <Class1Record index="0"> + <Class2Record index="0"> + <Value1 XAdvance="0"/> + </Class2Record> + <Class2Record index="1"> + <Value1 XAdvance="40"/> + </Class2Record> + </Class1Record> + <Class1Record index="1"> + <Class2Record index="0"> + <Value1 XAdvance="0"/> + </Class2Record> + <Class2Record index="1"> + <Value1 XAdvance="40"/> + </Class2Record> + </Class1Record> + </PairPos> + </Lookup> + </LookupList> + </GPOS> + +</ttFont> diff --git a/Tests/varLib/data/master_non_marking_cff2/TestNonMarkingCFF2_ExtraLight.ttx b/Tests/varLib/data/master_non_marking_cff2/TestNonMarkingCFF2_ExtraLight.ttx new file mode 100644 index 00000000..9d3b2679 --- /dev/null +++ b/Tests/varLib/data/master_non_marking_cff2/TestNonMarkingCFF2_ExtraLight.ttx @@ -0,0 +1,233 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ttFont sfntVersion="OTTO" ttLibVersion="3.41"> + + <GlyphOrder> + <!-- The 'id' attribute is only for humans; it is ignored when parsed. --> + <GlyphID id="0" name=".notdef"/> + <GlyphID id="1" name="A"/> + </GlyphOrder> + + <head> + <!-- Most of this table will be recalculated by the compiler --> + <tableVersion value="1.0"/> + <fontRevision value="1.01"/> + <checkSumAdjustment value="0xeb345d38"/> + <magicNumber value="0x5f0f3cf5"/> + <flags value="00000000 00000011"/> + <unitsPerEm value="1000"/> + <created value="Thu Nov 29 14:52:09 2018"/> + <modified value="Thu Nov 29 14:52:09 2018"/> + <xMin value="50"/> + <yMin value="-115"/> + <xMax value="550"/> + <yMax value="762"/> + <macStyle value="00000000 00000000"/> + <lowestRecPPEM value="3"/> + <fontDirectionHint value="2"/> + <indexToLocFormat value="0"/> + <glyphDataFormat value="0"/> + </head> + + <hhea> + <tableVersion value="0x00010000"/> + <ascent value="984"/> + <descent value="-273"/> + <lineGap value="0"/> + <advanceWidthMax value="600"/> + <minLeftSideBearing value="50"/> + <minRightSideBearing value="50"/> + <xMaxExtent value="550"/> + <caretSlopeRise value="1"/> + <caretSlopeRun value="0"/> + <caretOffset value="0"/> + <reserved0 value="0"/> + <reserved1 value="0"/> + <reserved2 value="0"/> + <reserved3 value="0"/> + <metricDataFormat value="0"/> + <numberOfHMetrics value="5"/> + </hhea> + + <maxp> + <tableVersion value="0x5000"/> + <numGlyphs value="5"/> + </maxp> + + <OS_2> + <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex' + will be recalculated by the compiler --> + <version value="3"/> + <xAvgCharWidth value="578"/> + <usWeightClass value="200"/> + <usWidthClass value="5"/> + <fsType value="00000000 00000000"/> + <ySubscriptXSize value="650"/> + <ySubscriptYSize value="600"/> + <ySubscriptXOffset value="0"/> + <ySubscriptYOffset value="75"/> + <ySuperscriptXSize value="650"/> + <ySuperscriptYSize value="600"/> + <ySuperscriptXOffset value="0"/> + <ySuperscriptYOffset value="350"/> + <yStrikeoutSize value="50"/> + <yStrikeoutPosition value="286"/> + <sFamilyClass value="0"/> + <panose> + <bFamilyType value="2"/> + <bSerifStyle value="11"/> + <bWeight value="3"/> + <bProportion value="9"/> + <bContrast value="3"/> + <bStrokeVariation value="4"/> + <bArmStyle value="3"/> + <bLetterForm value="2"/> + <bMidline value="2"/> + <bXHeight value="4"/> + </panose> + <ulUnicodeRange1 value="00000000 00000000 00000000 00000000"/> + <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/> + <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/> + <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/> + <achVendID value="ADBO"/> + <fsSelection value="00000000 00000000"/> + <usFirstCharIndex value="36"/> + <usLastCharIndex value="84"/> + <sTypoAscender value="750"/> + <sTypoDescender value="-250"/> + <sTypoLineGap value="0"/> + <usWinAscent value="984"/> + <usWinDescent value="273"/> + <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/> + <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/> + <sxHeight value="478"/> + <sCapHeight value="660"/> + <usDefaultChar value="0"/> + <usBreakChar value="32"/> + <usMaxContext value="1"/> + </OS_2> + + <name> + <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True"> + Source Code Variable + </namerecord> + <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True"> + Regular + </namerecord> + <namerecord nameID="3" platformID="1" platEncID="0" langID="0x0" unicode="True"> + 1.010;ADBO;SourceCode_ExtraLight + </namerecord> + <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True"> + Source Code Variable + </namerecord> + <namerecord nameID="5" platformID="1" platEncID="0" langID="0x0" unicode="True"> + Version 1.010;hotconv 1.0.109;makeotfexe 2.5.65596 + </namerecord> + <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True"> + SourceCode_ExtraLight + </namerecord> + <namerecord nameID="17" platformID="1" platEncID="0" langID="0x0" unicode="True"> + Roman Master 0 + </namerecord> + <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409"> + Source Code Variable + </namerecord> + <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409"> + Regular + </namerecord> + <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409"> + 1.010;ADBO;SourceCode_ExtraLight + </namerecord> + <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409"> + Source Code Variable + </namerecord> + <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409"> + Version 1.010;hotconv 1.0.109;makeotfexe 2.5.65596 + </namerecord> + <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409"> + SourceCode_ExtraLight + </namerecord> + <namerecord nameID="17" platformID="3" platEncID="1" langID="0x409"> + Roman Master 0 + </namerecord> + </name> + + <cmap> + <tableVersion version="0"/> + <cmap_format_4 platformID="0" platEncID="3" language="0"> + <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A --> + </cmap_format_4> + <cmap_format_6 platformID="1" platEncID="0" language="0"> + <map code="0x41" name="A"/> + </cmap_format_6> + <cmap_format_4 platformID="3" platEncID="1" language="0"> + <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A --> + </cmap_format_4> + </cmap> + + <post> + <formatType value="3.0"/> + <italicAngle value="0.0"/> + <underlinePosition value="-75"/> + <underlineThickness value="50"/> + <isFixedPitch value="1"/> + <minMemType42 value="0"/> + <maxMemType42 value="0"/> + <minMemType1 value="0"/> + <maxMemType1 value="0"/> + </post> + + <CFF> + <major value="1"/> + <minor value="0"/> + <CFFFont name="SourceCode_ExtraLight"> + <version value="1.0"/> + <Notice value="Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries."/> + <Copyright value="Copyright 2010 - 2012 Adobe Systems Incorporated. All Rights Reserved."/> + <FamilyName value="Source Code"/> + <isFixedPitch value="1"/> + <ItalicAngle value="0"/> + <UnderlinePosition value="-100"/> + <UnderlineThickness value="50"/> + <PaintType value="0"/> + <CharstringType value="2"/> + <FontMatrix value="0.001 0 0 0.001 0 0"/> + <FontBBox value="50 -115 550 762"/> + <StrokeWidth value="0"/> + <!-- charset is dumped separately as the 'GlyphOrder' element --> + <Encoding name="StandardEncoding"/> + <Private> + <BlueValues value="-12 0 478 490 570 582 640 652 660 672 722 734"/> + <OtherBlues value="-234 -222"/> + <BlueScale value="0.0625"/> + <BlueShift value="7"/> + <BlueFuzz value="0"/> + <StdHW value="28"/> + <StdVW value="34"/> + <ForceBold value="0"/> + <LanguageGroup value="0"/> + <ExpansionFactor value="0.06"/> + <initialRandomSeed value="0"/> + <defaultWidthX value="600"/> + <nominalWidthX value="597"/> + </Private> + <CharStrings> + <CharString name=".notdef"> + endchar + </CharString> + <CharString name="A"> + endchar + </CharString> += </CharStrings> + </CFFFont> + + <GlobalSubrs> + <!-- The 'index' attribute is only for humans; it is ignored when parsed. --> + </GlobalSubrs> + </CFF> + + <hmtx> + <mtx name=".notdef" width="600" lsb="84"/> + <mtx name="A" width="600" lsb="50"/> + </hmtx> + +</ttFont> diff --git a/Tests/varLib/data/master_non_marking_cff2/TestNonMarkingCFF2_Regular.ttx b/Tests/varLib/data/master_non_marking_cff2/TestNonMarkingCFF2_Regular.ttx new file mode 100644 index 00000000..4e6775da --- /dev/null +++ b/Tests/varLib/data/master_non_marking_cff2/TestNonMarkingCFF2_Regular.ttx @@ -0,0 +1,233 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ttFont sfntVersion="OTTO" ttLibVersion="3.41"> + + <GlyphOrder> + <!-- The 'id' attribute is only for humans; it is ignored when parsed. --> + <GlyphID id="0" name=".notdef"/> + <GlyphID id="1" name="A"/> + </GlyphOrder> + + <head> + <!-- Most of this table will be recalculated by the compiler --> + <tableVersion value="1.0"/> + <fontRevision value="1.01"/> + <checkSumAdjustment value="0x60d07155"/> + <magicNumber value="0x5f0f3cf5"/> + <flags value="00000000 00000011"/> + <unitsPerEm value="1000"/> + <created value="Thu Nov 29 14:52:09 2018"/> + <modified value="Thu Nov 29 14:52:09 2018"/> + <xMin value="31"/> + <yMin value="-115"/> + <xMax value="569"/> + <yMax value="751"/> + <macStyle value="00000000 00000000"/> + <lowestRecPPEM value="3"/> + <fontDirectionHint value="2"/> + <indexToLocFormat value="0"/> + <glyphDataFormat value="0"/> + </head> + + <hhea> + <tableVersion value="0x00010000"/> + <ascent value="984"/> + <descent value="-273"/> + <lineGap value="0"/> + <advanceWidthMax value="600"/> + <minLeftSideBearing value="31"/> + <minRightSideBearing value="31"/> + <xMaxExtent value="569"/> + <caretSlopeRise value="1"/> + <caretSlopeRun value="0"/> + <caretOffset value="0"/> + <reserved0 value="0"/> + <reserved1 value="0"/> + <reserved2 value="0"/> + <reserved3 value="0"/> + <metricDataFormat value="0"/> + <numberOfHMetrics value="5"/> + </hhea> + + <maxp> + <tableVersion value="0x5000"/> + <numGlyphs value="5"/> + </maxp> + + <OS_2> + <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex' + will be recalculated by the compiler --> + <version value="3"/> + <xAvgCharWidth value="579"/> + <usWeightClass value="400"/> + <usWidthClass value="5"/> + <fsType value="00000000 00000000"/> + <ySubscriptXSize value="650"/> + <ySubscriptYSize value="600"/> + <ySubscriptXOffset value="0"/> + <ySubscriptYOffset value="75"/> + <ySuperscriptXSize value="650"/> + <ySuperscriptYSize value="600"/> + <ySuperscriptXOffset value="0"/> + <ySuperscriptYOffset value="350"/> + <yStrikeoutSize value="50"/> + <yStrikeoutPosition value="291"/> + <sFamilyClass value="0"/> + <panose> + <bFamilyType value="2"/> + <bSerifStyle value="11"/> + <bWeight value="5"/> + <bProportion value="9"/> + <bContrast value="3"/> + <bStrokeVariation value="4"/> + <bArmStyle value="3"/> + <bLetterForm value="2"/> + <bMidline value="2"/> + <bXHeight value="4"/> + </panose> + <ulUnicodeRange1 value="00000000 00000000 00000000 00000000"/> + <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/> + <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/> + <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/> + <achVendID value="ADBO"/> + <fsSelection value="00000000 01000000"/> + <usFirstCharIndex value="36"/> + <usLastCharIndex value="84"/> + <sTypoAscender value="750"/> + <sTypoDescender value="-250"/> + <sTypoLineGap value="0"/> + <usWinAscent value="984"/> + <usWinDescent value="273"/> + <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/> + <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/> + <sxHeight value="486"/> + <sCapHeight value="660"/> + <usDefaultChar value="0"/> + <usBreakChar value="32"/> + <usMaxContext value="1"/> + </OS_2> + + <name> + <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True"> + Source Code Variable + </namerecord> + <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True"> + Regular + </namerecord> + <namerecord nameID="3" platformID="1" platEncID="0" langID="0x0" unicode="True"> + 1.010;ADBO;SourceCodeVariable-Roman + </namerecord> + <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True"> + Source Code Variable + </namerecord> + <namerecord nameID="5" platformID="1" platEncID="0" langID="0x0" unicode="True"> + Version 1.010;hotconv 1.0.109;makeotfexe 2.5.65596 + </namerecord> + <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True"> + SourceCodeVariable-Roman + </namerecord> + <namerecord nameID="17" platformID="1" platEncID="0" langID="0x0" unicode="True"> + Roman + </namerecord> + <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409"> + Source Code Variable + </namerecord> + <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409"> + Regular + </namerecord> + <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409"> + 1.010;ADBO;SourceCodeVariable-Roman + </namerecord> + <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409"> + Source Code Variable + </namerecord> + <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409"> + Version 1.010;hotconv 1.0.109;makeotfexe 2.5.65596 + </namerecord> + <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409"> + SourceCodeVariable-Roman + </namerecord> + <namerecord nameID="17" platformID="3" platEncID="1" langID="0x409"> + Roman + </namerecord> + </name> + + <cmap> + <tableVersion version="0"/> + <cmap_format_4 platformID="0" platEncID="3" language="0"> + <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A --> + </cmap_format_4> + <cmap_format_6 platformID="1" platEncID="0" language="0"> + <map code="0x41" name="A"/> + </cmap_format_6> + <cmap_format_4 platformID="3" platEncID="1" language="0"> + <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A --> + </cmap_format_4> + </cmap> + + <post> + <formatType value="3.0"/> + <italicAngle value="0.0"/> + <underlinePosition value="-75"/> + <underlineThickness value="50"/> + <isFixedPitch value="1"/> + <minMemType42 value="0"/> + <maxMemType42 value="0"/> + <minMemType1 value="0"/> + <maxMemType1 value="0"/> + </post> + + <CFF> + <major value="1"/> + <minor value="0"/> + <CFFFont name="SourceCodeVariable-Roman"> + <version value="1.0"/> + <Notice value="Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries."/> + <Copyright value="Copyright 2010 - 2012 Adobe Systems Incorporated. All Rights Reserved."/> + <FamilyName value="Source Code"/> + <isFixedPitch value="1"/> + <ItalicAngle value="0"/> + <UnderlinePosition value="-100"/> + <UnderlineThickness value="50"/> + <PaintType value="0"/> + <CharstringType value="2"/> + <FontMatrix value="0.001 0 0 0.001 0 0"/> + <FontBBox value="31 -115 569 751"/> + <StrokeWidth value="0"/> + <!-- charset is dumped separately as the 'GlyphOrder' element --> + <Encoding name="StandardEncoding"/> + <Private> + <BlueValues value="-12 0 486 498 574 586 638 650 656 668 712 724"/> + <OtherBlues value="-217 -205"/> + <BlueScale value="0.0625"/> + <BlueShift value="7"/> + <BlueFuzz value="0"/> + <StdHW value="67"/> + <StdVW value="85"/> + <ForceBold value="0"/> + <LanguageGroup value="0"/> + <ExpansionFactor value="0.06"/> + <initialRandomSeed value="0"/> + <defaultWidthX value="600"/> + <nominalWidthX value="604"/> + </Private> + <CharStrings> + <CharString name=".notdef"> + endchar + </CharString> + <CharString name="A"> + endchar + </CharString> + </CharStrings> + </CFFFont> + + <GlobalSubrs> + <!-- The 'index' attribute is only for humans; it is ignored when parsed. --> + </GlobalSubrs> + </CFF> + + <hmtx> + <mtx name=".notdef" width="600" lsb="62"/> + <mtx name="A" width="600" lsb="31"/> + </hmtx> + +</ttFont> diff --git a/Tests/varLib/data/master_vpal_test/master_vpal_test_0.ttx b/Tests/varLib/data/master_vpal_test/master_vpal_test_0.ttx new file mode 100644 index 00000000..1fbb45d3 --- /dev/null +++ b/Tests/varLib/data/master_vpal_test/master_vpal_test_0.ttx @@ -0,0 +1,485 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ttFont sfntVersion="OTTO" ttLibVersion="3.42"> + + <GlyphOrder> + <!-- The 'id' attribute is only for humans; it is ignored when parsed. --> + <GlyphID id="0" name=".notdef"/> + <GlyphID id="1" name="uni3001"/> + <GlyphID id="2" name="uni30FB"/> + <GlyphID id="3" name="uniFF1A"/> + <GlyphID id="4" name="uniFF2D"/> + <GlyphID id="5" name="uni3073"/> + <GlyphID id="6" name="uni3074"/> + <GlyphID id="7" name="uni307B"/> + </GlyphOrder> + + <head> + <!-- Most of this table will be recalculated by the compiler --> + <tableVersion value="1.0"/> + <fontRevision value="1.004"/> + <checkSumAdjustment value="0x90c6f91d"/> + <magicNumber value="0x5f0f3cf5"/> + <flags value="00000000 00000011"/> + <unitsPerEm value="1000"/> + <created value="Wed Jun 5 14:40:00 2019"/> + <modified value="Tue Jun 11 21:27:36 2019"/> + <xMin value="64"/> + <yMin value="-52"/> + <xMax value="974"/> + <yMax value="798"/> + <macStyle value="00000000 00000000"/> + <lowestRecPPEM value="3"/> + <fontDirectionHint value="2"/> + <indexToLocFormat value="0"/> + <glyphDataFormat value="0"/> + </head> + + <hhea> + <tableVersion value="0x00010000"/> + <ascent value="1160"/> + <descent value="-317"/> + <lineGap value="0"/> + <advanceWidthMax value="1000"/> + <minLeftSideBearing value="64"/> + <minRightSideBearing value="26"/> + <xMaxExtent value="974"/> + <caretSlopeRise value="1"/> + <caretSlopeRun value="0"/> + <caretOffset value="0"/> + <reserved0 value="0"/> + <reserved1 value="0"/> + <reserved2 value="0"/> + <reserved3 value="0"/> + <metricDataFormat value="0"/> + <numberOfHMetrics value="2"/> + </hhea> + + <maxp> + <tableVersion value="0x5000"/> + <numGlyphs value="8"/> + </maxp> + + <OS_2> + <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex' + will be recalculated by the compiler --> + <version value="3"/> + <xAvgCharWidth value="962"/> + <usWeightClass value="250"/> + <usWidthClass value="5"/> + <fsType value="00000000 00000100"/> + <ySubscriptXSize value="650"/> + <ySubscriptYSize value="600"/> + <ySubscriptXOffset value="0"/> + <ySubscriptYOffset value="75"/> + <ySuperscriptXSize value="650"/> + <ySuperscriptYSize value="600"/> + <ySuperscriptXOffset value="0"/> + <ySuperscriptYOffset value="350"/> + <yStrikeoutSize value="50"/> + <yStrikeoutPosition value="228"/> + <sFamilyClass value="0"/> + <panose> + <bFamilyType value="0"/> + <bSerifStyle value="0"/> + <bWeight value="3"/> + <bProportion value="0"/> + <bContrast value="0"/> + <bStrokeVariation value="0"/> + <bArmStyle value="0"/> + <bLetterForm value="0"/> + <bMidline value="0"/> + <bXHeight value="0"/> + </panose> + <ulUnicodeRange1 value="00000000 00000000 00000000 00000000"/> + <ulUnicodeRange2 value="00000000 00000111 00000000 00000000"/> + <ulUnicodeRange3 value="00000000 00000000 00000000 00010000"/> + <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/> + <achVendID value="UKWN"/> + <fsSelection value="00000000 00000000"/> + <usFirstCharIndex value="12289"/> + <usLastCharIndex value="65325"/> + <sTypoAscender value="880"/> + <sTypoDescender value="-120"/> + <sTypoLineGap value="200"/> + <usWinAscent value="1160"/> + <usWinDescent value="317"/> + <ulCodePageRange1 value="00100000 00000010 00000000 10011111"/> + <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/> + <sxHeight value="380"/> + <sCapHeight value="760"/> + <usDefaultChar value="0"/> + <usBreakChar value="32"/> + <usMaxContext value="1"/> + </OS_2> + + <name> + <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409"> + Copyright © 2018 Adobe systems Co., Ltd. All Rights Reserved. + </namerecord> + <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409"> + MasterSet_KanjiFullEX + </namerecord> + <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409"> + Regular + </namerecord> + <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409"> + 1.004;UKWN;MasterSet_KanjiFullEX-w0.00 + </namerecord> + <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409"> + MasterSet_KanjiFullEX + </namerecord> + <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409"> + Version 1.004;hotconv 1.0.109;makeotfexe 2.5.65596 + </namerecord> + <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409"> + MasterSet_KanjiFullEX-w0.00 + </namerecord> + </name> + + <cmap> + <tableVersion version="0"/> + <cmap_format_4 platformID="0" platEncID="3" language="0"> + <map code="0x3001" name="uni3001"/><!-- IDEOGRAPHIC COMMA --> + <map code="0x3073" name="uni3073"/><!-- HIRAGANA LETTER BI --> + <map code="0x3074" name="uni3074"/><!-- HIRAGANA LETTER PI --> + <map code="0x307b" name="uni307B"/><!-- HIRAGANA LETTER HO --> + <map code="0x30fb" name="uni30FB"/><!-- KATAKANA MIDDLE DOT --> + <map code="0xff1a" name="uniFF1A"/><!-- FULLWIDTH COLON --> + <map code="0xff2d" name="uniFF2D"/><!-- FULLWIDTH LATIN CAPITAL LETTER M --> + </cmap_format_4> + <cmap_format_12 platformID="0" platEncID="4" format="12" reserved="0" length="88" language="0" nGroups="6"> + <map code="0x3001" name="uni3001"/><!-- IDEOGRAPHIC COMMA --> + <map code="0x3073" name="uni3073"/><!-- HIRAGANA LETTER BI --> + <map code="0x3074" name="uni3074"/><!-- HIRAGANA LETTER PI --> + <map code="0x307b" name="uni307B"/><!-- HIRAGANA LETTER HO --> + <map code="0x30fb" name="uni30FB"/><!-- KATAKANA MIDDLE DOT --> + <map code="0xff1a" name="uniFF1A"/><!-- FULLWIDTH COLON --> + <map code="0xff2d" name="uniFF2D"/><!-- FULLWIDTH LATIN CAPITAL LETTER M --> + </cmap_format_12> + <cmap_format_4 platformID="3" platEncID="1" language="0"> + <map code="0x3001" name="uni3001"/><!-- IDEOGRAPHIC COMMA --> + <map code="0x3073" name="uni3073"/><!-- HIRAGANA LETTER BI --> + <map code="0x3074" name="uni3074"/><!-- HIRAGANA LETTER PI --> + <map code="0x307b" name="uni307B"/><!-- HIRAGANA LETTER HO --> + <map code="0x30fb" name="uni30FB"/><!-- KATAKANA MIDDLE DOT --> + <map code="0xff1a" name="uniFF1A"/><!-- FULLWIDTH COLON --> + <map code="0xff2d" name="uniFF2D"/><!-- FULLWIDTH LATIN CAPITAL LETTER M --> + </cmap_format_4> + <cmap_format_12 platformID="3" platEncID="10" format="12" reserved="0" length="88" language="0" nGroups="6"> + <map code="0x3001" name="uni3001"/><!-- IDEOGRAPHIC COMMA --> + <map code="0x3073" name="uni3073"/><!-- HIRAGANA LETTER BI --> + <map code="0x3074" name="uni3074"/><!-- HIRAGANA LETTER PI --> + <map code="0x307b" name="uni307B"/><!-- HIRAGANA LETTER HO --> + <map code="0x30fb" name="uni30FB"/><!-- KATAKANA MIDDLE DOT --> + <map code="0xff1a" name="uniFF1A"/><!-- FULLWIDTH COLON --> + <map code="0xff2d" name="uniFF2D"/><!-- FULLWIDTH LATIN CAPITAL LETTER M --> + </cmap_format_12> + </cmap> + + <post> + <formatType value="3.0"/> + <italicAngle value="0.0"/> + <underlinePosition value="-75"/> + <underlineThickness value="50"/> + <isFixedPitch value="0"/> + <minMemType42 value="0"/> + <maxMemType42 value="0"/> + <minMemType1 value="0"/> + <maxMemType1 value="0"/> + </post> + + <CFF> + <major value="1"/> + <minor value="0"/> + <CFFFont name="MasterSet_KanjiFullEX-w0.00"> + <FamilyName value="MasterSet_KanjiFullEX"/> + <isFixedPitch value="0"/> + <ItalicAngle value="0"/> + <UnderlinePosition value="-100"/> + <UnderlineThickness value="50"/> + <PaintType value="0"/> + <CharstringType value="2"/> + <FontMatrix value="0.001 0 0 0.001 0 0"/> + <FontBBox value="64 -52 974 798"/> + <StrokeWidth value="0"/> + <!-- charset is dumped separately as the 'GlyphOrder' element --> + <Encoding name="StandardEncoding"/> + <Private> + <BlueValues value="0 0"/> + <BlueScale value="0.039625"/> + <BlueShift value="7"/> + <BlueFuzz value="1"/> + <ForceBold value="0"/> + <LanguageGroup value="0"/> + <ExpansionFactor value="0.06"/> + <initialRandomSeed value="0"/> + <defaultWidthX value="1000"/> + <nominalWidthX value="532"/> + </Private> + <CharStrings> + <CharString name=".notdef"> + -282 endchar + </CharString> + <CharString name="uni3001"> + 291 -43 rmoveto + 29 24 rlineto + -74 84 -84 83 -73 58 rrcurveto + -25 -24 rlineto + 72 -56 87 -85 68 -84 rrcurveto + endchar + </CharString> + <CharString name="uni3073"> + 706 699 rmoveto + -32 -10 rlineto + 50 -192 56 -132 112 -115 rrcurveto + 24 26 rlineto + -143 124 -45 182 -22 117 rrcurveto + -592 -57 rmoveto + 3 -38 rlineto + 18 2 18 3 17 2 rrcurveto + 43 6 101 12 63 13 rrcurveto + -83 -80 -128 -166 0 -210 rrcurveto + 0 -150 92 -88 154 0 rrcurveto + 294 0 65 313 -48 302 rrcurveto + -29 79 rlineto + 64 -402 -96 -263 -249 0 rrcurveto + -109 0 -110 48 0 166 rrcurveto + 0 219 171 196 58 42 rrcurveto + 14 5 30 6 12 3 rrcurveto + -9 30 rlineto + -52 -21 -170 -26 -83 -3 rrcurveto + -18 -1 -21 0 -12 1 rrcurveto + 677 114 rmoveto + -26 -11 rlineto + 22 -34 33 -63 20 -42 rrcurveto + 30 14 rlineto + -21 41 -37 62 -21 33 rrcurveto + 97 40 rmoveto + -26 -13 rlineto + 24 -33 31 -59 21 -44 rrcurveto + 30 14 rlineto + -23 43 -36 60 -21 32 rrcurveto + endchar + </CharString> + <CharString name="uni3074"> + 706 699 rmoveto + -32 -10 rlineto + 50 -192 56 -132 112 -115 rrcurveto + 24 26 rlineto + -143 124 -45 182 -22 117 rrcurveto + -592 -57 rmoveto + 3 -38 rlineto + 18 2 18 3 17 2 rrcurveto + 43 6 101 12 63 13 rrcurveto + -83 -80 -128 -166 0 -210 rrcurveto + 0 -150 92 -88 154 0 rrcurveto + 294 0 65 313 -48 302 rrcurveto + -29 79 rlineto + 64 -402 -96 -263 -249 0 rrcurveto + -109 0 -110 48 0 166 rrcurveto + 0 219 171 196 58 42 rrcurveto + 14 5 30 6 12 3 rrcurveto + -9 30 rlineto + -52 -21 -170 -26 -83 -3 rrcurveto + -18 -1 -21 0 -12 1 rrcurveto + 681 51 rmoveto + 0 42 33 33 41 0 rrcurveto + 41 0 33 -33 0 -42 rrcurveto + 0 -41 -33 -33 -41 0 rrcurveto + -42 0 -32 33 0 41 rrcurveto + -30 0 rmoveto + 0 -57 46 -47 58 0 rrcurveto + 57 0 48 47 0 57 rrcurveto + 0 58 -48 47 -57 0 rrcurveto + -58 0 -46 -47 0 -58 rrcurveto + endchar + </CharString> + <CharString name="uni307B"> + 703 676 rmoveto + -28 0 rlineto + 0 -63 0 -106 0 -61 rrcurveto + 0 -103 14 -162 0 -52 rrcurveto + 0 -59 -17 -50 -97 0 rrcurveto + -91 0 -58 31 0 63 rrcurveto + 0 53 62 37 87 0 rrcurveto + 125 0 119 -56 94 -98 rrcurveto + 19 31 rlineto + -90 81 -113 69 -154 0 rrcurveto + -130 0 -47 -64 0 -53 rrcurveto + 0 -80 70 -42 105 0 rrcurveto + 85 0 58 36 0 74 rrcurveto + 0 68 -13 166 0 113 rrcurveto + 0 61 0 96 0 70 rrcurveto + -284 -213 rmoveto + 0 -31 rlineto + 168 -10 194 12 125 13 rrcurveto + 0 31 rlineto + -129 -15 -187 -13 -171 13 rrcurveto + 16 230 rmoveto + 0 -30 rlineto + 139 -7 200 11 108 11 rrcurveto + 0 30 rlineto + -111 -15 -197 -11 -139 11 rrcurveto + -207 51 rmoveto + -37 4 rlineto + 0 -11 -1 -14 -3 -19 rrcurveto + -13 -88 -37 -183 0 -143 rrcurveto + 0 -135 16 -105 20 -74 rrcurveto + 28 3 rlineto + -1 7 -2 12 -1 9 rrcurveto + -1 13 2 16 3 14 rrcurveto + 9 43 39 105 22 55 rrcurveto + -20 17 rlineto + -20 -48 -32 -89 -18 -56 rrcurveto + -10 78 -5 58 0 78 rrcurveto + 0 124 26 166 25 119 rrcurveto + 3 18 4 13 4 13 rrcurveto + endchar + </CharString> + <CharString name="uni30FB"> + 500 465 rmoveto + -47 0 -38 -38 0 -47 rrcurveto + 0 -47 38 -38 47 0 rrcurveto + 47 0 38 38 0 47 rrcurveto + 0 47 -38 38 -47 0 rrcurveto + endchar + </CharString> + <CharString name="uniFF1A"> + 500 572 rmoveto + 28 0 28 19 0 37 rrcurveto + 0 37 -28 19 -28 0 rrcurveto + -28 0 -28 -19 0 -37 rrcurveto + 0 -37 28 -19 28 0 rrcurveto + 0 -502 rmoveto + 28 0 28 19 0 37 rrcurveto + 0 37 -28 19 -28 0 rrcurveto + -28 0 -28 -19 0 -37 rrcurveto + 0 -37 28 -19 28 0 rrcurveto + endchar + </CharString> + <CharString name="uniFF2D"> + 180 0 rmoveto + 35 0 rlineto + 0 502 rlineto + 0 57 -1 74 -2 59 rrcurveto + 5 0 rlineto + 67 -160 rlineto + 196 -451 rlineto + 39 0 rlineto + 195 451 rlineto + 69 160 rlineto + 5 0 rlineto + -2 -59 -3 -74 0 -57 rrcurveto + 0 -502 rlineto + 37 0 rlineto + 0 726 rlineto + -59 0 rlineto + -191 -438 rlineto + -23 -54 -20 -55 -24 -55 rrcurveto + -4 0 rlineto + -24 55 -23 55 -23 54 rrcurveto + -190 438 rlineto + -59 0 rlineto + 0 -726 rlineto + endchar + </CharString> + </CharStrings> + </CFFFont> + + <GlobalSubrs> + <!-- The 'index' attribute is only for humans; it is ignored when parsed. --> + </GlobalSubrs> + </CFF> + + <GPOS> + <Version value="0x00010000"/> + <ScriptList> + <!-- ScriptCount=1 --> + <ScriptRecord index="0"> + <ScriptTag value="DFLT"/> + <Script> + <DefaultLangSys> + <ReqFeatureIndex value="65535"/> + <!-- FeatureCount=1 --> + <FeatureIndex index="0" value="0"/> + </DefaultLangSys> + <!-- LangSysCount=0 --> + </Script> + </ScriptRecord> + </ScriptList> + <FeatureList> + <!-- FeatureCount=1 --> + <FeatureRecord index="0"> + <FeatureTag value="vpal"/> + <Feature> + <!-- LookupCount=1 --> + <LookupListIndex index="0" value="0"/> + </Feature> + </FeatureRecord> + </FeatureList> + <LookupList> + <!-- LookupCount=1 --> + <Lookup index="0"> + <LookupType value="1"/> + <LookupFlag value="0"/> + <!-- SubTableCount=5 --> + <SinglePos index="0" Format="2"> + <Coverage Format="1"> + <Glyph value="uni3001"/> + <Glyph value="uniFF1A"/> + </Coverage> + <ValueFormat value="5"/> + <!-- ValueCount=2 --> + <Value index="0" XPlacement="-9" XAdvance="-500"/> + <Value index="1" XPlacement="-250" XAdvance="-500"/> + </SinglePos> + <SinglePos index="1" Format="2"> + <Coverage Format="1"> + <Glyph value="uni30FB"/> + </Coverage> + <ValueFormat value="7"/> + <!-- ValueCount=1 --> + <Value index="0" XPlacement="-250" YPlacement="1" XAdvance="-500"/> + </SinglePos> + <SinglePos index="2" Format="2"> + <Coverage Format="1"> + <Glyph value="uni3073"/> + <Glyph value="uni3074"/> + </Coverage> + <ValueFormat value="4"/> + <!-- ValueCount=2 --> + <Value index="0" XAdvance="-36"/> + <Value index="1" XAdvance="-30"/> + </SinglePos> + <SinglePos index="3" Format="2"> + <Coverage Format="1"> + <Glyph value="uni307B"/> + </Coverage> + <ValueFormat value="1"/> + <!-- ValueCount=1 --> + <Value index="0" XPlacement="11"/> + </SinglePos> + <SinglePos index="4" Format="2"> + <Coverage Format="1"> + <Glyph value="uniFF2D"/> + </Coverage> + <ValueFormat value="5"/> + <!-- ValueCount=1 --> + <Value index="0" XPlacement="12" XAdvance="23"/> + </SinglePos> + </Lookup> + </LookupList> + </GPOS> + + <hmtx> + <mtx name=".notdef" width="250" lsb="0"/> + <mtx name="uni3001" width="1000" lsb="64"/> + <mtx name="uni3073" width="1000" lsb="114"/> + <mtx name="uni3074" width="1000" lsb="114"/> + <mtx name="uni307B" width="1000" lsb="137"/> + <mtx name="uni30FB" width="1000" lsb="415"/> + <mtx name="uniFF1A" width="1000" lsb="444"/> + <mtx name="uniFF2D" width="1000" lsb="180"/> + </hmtx> + +</ttFont> diff --git a/Tests/varLib/data/master_vpal_test/master_vpal_test_1.ttx b/Tests/varLib/data/master_vpal_test/master_vpal_test_1.ttx new file mode 100644 index 00000000..bb439586 --- /dev/null +++ b/Tests/varLib/data/master_vpal_test/master_vpal_test_1.ttx @@ -0,0 +1,473 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ttFont sfntVersion="OTTO" ttLibVersion="3.42"> + + <GlyphOrder> + <!-- The 'id' attribute is only for humans; it is ignored when parsed. --> + <GlyphID id="0" name=".notdef"/> + <GlyphID id="1" name="uni3001"/> + <GlyphID id="2" name="uni30FB"/> + <GlyphID id="3" name="uniFF1A"/> + <GlyphID id="4" name="uniFF2D"/> + <GlyphID id="5" name="uni3073"/> + <GlyphID id="6" name="uni3074"/> + <GlyphID id="7" name="uni307B"/> + </GlyphOrder> + + <head> + <!-- Most of this table will be recalculated by the compiler --> + <tableVersion value="1.0"/> + <fontRevision value="1.004"/> + <checkSumAdjustment value="0xfa2dc49e"/> + <magicNumber value="0x5f0f3cf5"/> + <flags value="00000000 00000011"/> + <unitsPerEm value="1000"/> + <created value="Wed Jun 5 14:40:08 2019"/> + <modified value="Tue Jun 11 21:27:55 2019"/> + <xMin value="33"/> + <yMin value="-87"/> + <xMax value="992"/> + <yMax value="855"/> + <macStyle value="00000000 00000000"/> + <lowestRecPPEM value="3"/> + <fontDirectionHint value="2"/> + <indexToLocFormat value="0"/> + <glyphDataFormat value="0"/> + </head> + + <hhea> + <tableVersion value="0x00010000"/> + <ascent value="1160"/> + <descent value="-317"/> + <lineGap value="0"/> + <advanceWidthMax value="1000"/> + <minLeftSideBearing value="33"/> + <minRightSideBearing value="8"/> + <xMaxExtent value="992"/> + <caretSlopeRise value="1"/> + <caretSlopeRun value="0"/> + <caretOffset value="0"/> + <reserved0 value="0"/> + <reserved1 value="0"/> + <reserved2 value="0"/> + <reserved3 value="0"/> + <metricDataFormat value="0"/> + <numberOfHMetrics value="2"/> + </hhea> + + <maxp> + <tableVersion value="0x5000"/> + <numGlyphs value="8"/> + </maxp> + + <OS_2> + <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex' + will be recalculated by the compiler --> + <version value="3"/> + <xAvgCharWidth value="971"/> + <usWeightClass value="900"/> + <usWidthClass value="5"/> + <fsType value="00000000 00000100"/> + <ySubscriptXSize value="650"/> + <ySubscriptYSize value="600"/> + <ySubscriptXOffset value="0"/> + <ySubscriptYOffset value="75"/> + <ySuperscriptXSize value="650"/> + <ySuperscriptYSize value="600"/> + <ySuperscriptXOffset value="0"/> + <ySuperscriptYOffset value="350"/> + <yStrikeoutSize value="50"/> + <yStrikeoutPosition value="228"/> + <sFamilyClass value="0"/> + <panose> + <bFamilyType value="0"/> + <bSerifStyle value="0"/> + <bWeight value="10"/> + <bProportion value="0"/> + <bContrast value="0"/> + <bStrokeVariation value="0"/> + <bArmStyle value="0"/> + <bLetterForm value="0"/> + <bMidline value="0"/> + <bXHeight value="0"/> + </panose> + <ulUnicodeRange1 value="00000000 00000000 00000000 00000000"/> + <ulUnicodeRange2 value="00000000 00000111 00000000 00000000"/> + <ulUnicodeRange3 value="00000000 00000000 00000000 00010000"/> + <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/> + <achVendID value="UKWN"/> + <fsSelection value="00000000 00000000"/> + <usFirstCharIndex value="12289"/> + <usLastCharIndex value="65325"/> + <sTypoAscender value="880"/> + <sTypoDescender value="-120"/> + <sTypoLineGap value="200"/> + <usWinAscent value="1160"/> + <usWinDescent value="317"/> + <ulCodePageRange1 value="00100000 00000010 00000000 10011111"/> + <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/> + <sxHeight value="380"/> + <sCapHeight value="760"/> + <usDefaultChar value="0"/> + <usBreakChar value="32"/> + <usMaxContext value="1"/> + </OS_2> + + <name> + <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409"> + Copyright © 2018 Adobe systems Co., Ltd. All Rights Reserved. + </namerecord> + <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409"> + MasterSet_KanjiFullEX + </namerecord> + <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409"> + Regular + </namerecord> + <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409"> + 1.004;UKWN;MasterSet_KanjiFullEX-w1000.00 + </namerecord> + <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409"> + MasterSet_KanjiFullEX + </namerecord> + <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409"> + Version 1.004;hotconv 1.0.109;makeotfexe 2.5.65596 + </namerecord> + <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409"> + MasterSet_KanjiFullEX-w1000.00 + </namerecord> + </name> + + <cmap> + <tableVersion version="0"/> + <cmap_format_4 platformID="0" platEncID="3" language="0"> + <map code="0x3001" name="uni3001"/><!-- IDEOGRAPHIC COMMA --> + <map code="0x3073" name="uni3073"/><!-- HIRAGANA LETTER BI --> + <map code="0x3074" name="uni3074"/><!-- HIRAGANA LETTER PI --> + <map code="0x307b" name="uni307B"/><!-- HIRAGANA LETTER HO --> + <map code="0x30fb" name="uni30FB"/><!-- KATAKANA MIDDLE DOT --> + <map code="0xff1a" name="uniFF1A"/><!-- FULLWIDTH COLON --> + <map code="0xff2d" name="uniFF2D"/><!-- FULLWIDTH LATIN CAPITAL LETTER M --> + </cmap_format_4> + <cmap_format_12 platformID="0" platEncID="4" format="12" reserved="0" length="88" language="0" nGroups="6"> + <map code="0x3001" name="uni3001"/><!-- IDEOGRAPHIC COMMA --> + <map code="0x3073" name="uni3073"/><!-- HIRAGANA LETTER BI --> + <map code="0x3074" name="uni3074"/><!-- HIRAGANA LETTER PI --> + <map code="0x307b" name="uni307B"/><!-- HIRAGANA LETTER HO --> + <map code="0x30fb" name="uni30FB"/><!-- KATAKANA MIDDLE DOT --> + <map code="0xff1a" name="uniFF1A"/><!-- FULLWIDTH COLON --> + <map code="0xff2d" name="uniFF2D"/><!-- FULLWIDTH LATIN CAPITAL LETTER M --> + </cmap_format_12> + <cmap_format_4 platformID="3" platEncID="1" language="0"> + <map code="0x3001" name="uni3001"/><!-- IDEOGRAPHIC COMMA --> + <map code="0x3073" name="uni3073"/><!-- HIRAGANA LETTER BI --> + <map code="0x3074" name="uni3074"/><!-- HIRAGANA LETTER PI --> + <map code="0x307b" name="uni307B"/><!-- HIRAGANA LETTER HO --> + <map code="0x30fb" name="uni30FB"/><!-- KATAKANA MIDDLE DOT --> + <map code="0xff1a" name="uniFF1A"/><!-- FULLWIDTH COLON --> + <map code="0xff2d" name="uniFF2D"/><!-- FULLWIDTH LATIN CAPITAL LETTER M --> + </cmap_format_4> + <cmap_format_12 platformID="3" platEncID="10" format="12" reserved="0" length="88" language="0" nGroups="6"> + <map code="0x3001" name="uni3001"/><!-- IDEOGRAPHIC COMMA --> + <map code="0x3073" name="uni3073"/><!-- HIRAGANA LETTER BI --> + <map code="0x3074" name="uni3074"/><!-- HIRAGANA LETTER PI --> + <map code="0x307b" name="uni307B"/><!-- HIRAGANA LETTER HO --> + <map code="0x30fb" name="uni30FB"/><!-- KATAKANA MIDDLE DOT --> + <map code="0xff1a" name="uniFF1A"/><!-- FULLWIDTH COLON --> + <map code="0xff2d" name="uniFF2D"/><!-- FULLWIDTH LATIN CAPITAL LETTER M --> + </cmap_format_12> + </cmap> + + <post> + <formatType value="3.0"/> + <italicAngle value="0.0"/> + <underlinePosition value="-75"/> + <underlineThickness value="50"/> + <isFixedPitch value="0"/> + <minMemType42 value="0"/> + <maxMemType42 value="0"/> + <minMemType1 value="0"/> + <maxMemType1 value="0"/> + </post> + + <CFF> + <major value="1"/> + <minor value="0"/> + <CFFFont name="MasterSet_KanjiFullEX-w1000.00"> + <FamilyName value="MasterSet_KanjiFullEX"/> + <isFixedPitch value="0"/> + <ItalicAngle value="0"/> + <UnderlinePosition value="-100"/> + <UnderlineThickness value="50"/> + <PaintType value="0"/> + <CharstringType value="2"/> + <FontMatrix value="0.001 0 0 0.001 0 0"/> + <FontBBox value="33 -87 992 855"/> + <StrokeWidth value="0"/> + <!-- charset is dumped separately as the 'GlyphOrder' element --> + <Encoding name="StandardEncoding"/> + <Private> + <BlueValues value="0 0"/> + <BlueScale value="0.039625"/> + <BlueShift value="7"/> + <BlueFuzz value="1"/> + <ForceBold value="0"/> + <LanguageGroup value="0"/> + <ExpansionFactor value="0.06"/> + <initialRandomSeed value="0"/> + <defaultWidthX value="1000"/> + <nominalWidthX value="705"/> + </Private> + <CharStrings> + <CharString name=".notdef"> + -455 endchar + </CharString> + <CharString name="uni3001"> + 245 -76 rmoveto + 129 111 rlineto + -44 56 -100 103 -70 58 rrcurveto + -127 -109 rlineto + 69 -61 84 -86 59 -72 rrcurveto + endchar + </CharString> + <CharString name="uni3073"> + 729 763 rmoveto + -152 -42 rlineto + 75 -225 86 -176 109 -123 rrcurveto + 97 140 rlineto + -155 146 -41 152 -19 128 rrcurveto + -677 -48 rmoveto + 11 -156 rlineto + 24 5 15 2 22 3 rrcurveto + 26 3 53 6 31 1 rrcurveto + -96 -130 -50 -109 0 -149 rrcurveto + 0 -190 149 -88 163 0 rrcurveto + 344 0 43 303 -58 260 rrcurveto + -142 223 rlineto + 96 -376 -59 -246 -221 0 rrcurveto + -92 0 -67 46 0 103 rrcurveto + 0 184 125 143 71 54 rrcurveto + 16 10 18 8 15 6 rrcurveto + -46 134 rlineto + -69 -25 -166 -20 -98 -5 rrcurveto + -19 -1 -20 0 -19 1 rrcurveto + 768 103 rmoveto + -88 -27 rlineto + 22 -45 16 -54 15 -49 rrcurveto + 87 28 rlineto + -11 41 -23 62 -18 44 rrcurveto + 110 37 rmoveto + -85 -28 rlineto + 21 -44 19 -57 14 -46 rrcurveto + 88 28 rlineto + -13 40 -22 63 -22 44 rrcurveto + endchar + </CharString> + <CharString name="uni3074"> + 729 763 rmoveto + -152 -42 rlineto + 75 -225 86 -176 109 -123 rrcurveto + 97 140 rlineto + -155 146 -41 152 -19 128 rrcurveto + -677 -48 rmoveto + 11 -156 rlineto + 24 5 15 2 22 3 rrcurveto + 26 3 53 6 31 1 rrcurveto + -96 -130 -50 -109 0 -149 rrcurveto + 0 -190 149 -88 163 0 rrcurveto + 344 0 43 303 -58 260 rrcurveto + -142 223 rlineto + 96 -376 -59 -246 -221 0 rrcurveto + -92 0 -67 46 0 103 rrcurveto + 0 184 125 143 71 54 rrcurveto + 16 10 18 8 15 6 rrcurveto + -46 134 rlineto + -69 -25 -166 -20 -98 -5 rrcurveto + -19 -1 -20 0 -19 1 rrcurveto + 772 16 rmoveto + 0 27 22 22 27 0 rrcurveto + 27 0 22 -22 0 -27 rrcurveto + 0 -27 -22 -22 -27 0 rrcurveto + -27 0 -22 22 0 27 rrcurveto + -70 0 rmoveto + 0 -66 53 -53 66 0 rrcurveto + 66 0 53 53 0 66 rrcurveto + 0 66 -53 53 -66 0 rrcurveto + -66 0 -53 -53 0 -66 rrcurveto + endchar + </CharString> + <CharString name="uni307B"> + 758 687 rmoveto + -141 0 rlineto + 0 -42 0 -111 0 -88 rrcurveto + 0 -104 8 -126 0 -63 rrcurveto + 0 -45 -23 -24 -49 0 rrcurveto + -37 0 -24 16 0 29 rrcurveto + 0 28 23 18 48 0 rrcurveto + 107 0 121 -81 97 -98 rrcurveto + 79 131 rlineto + -51 45 -135 115 -213 0 rrcurveto + -137 0 -76 -72 0 -97 rrcurveto + 0 -116 100 -52 119 0 rrcurveto + 142 0 55 65 0 93 rrcurveto + 0 97 -13 99 0 147 rrcurveto + 0 64 0 96 0 76 rrcurveto + -360 -167 rmoveto + 1 -139 rlineto + 195 -9 191 7 133 16 rrcurveto + 0 139 rlineto + -148 -18 -178 -11 -194 15 rrcurveto + 15 235 rmoveto + 0 -134 rlineto + 197 -9 162 8 126 14 rrcurveto + 0 134 rlineto + -127 -19 -163 -9 -195 15 rrcurveto + -117 26 rmoveto + -168 14 rlineto + -1 -37 -6 -47 -4 -29 rrcurveto + -11 -74 -26 -192 0 -153 rrcurveto + 0 -136 20 -117 21 -68 rrcurveto + 139 10 rlineto + -1 16 0 18 0 11 rrcurveto + 0 10 3 23 3 14 rrcurveto + 12 58 30 101 30 90 rrcurveto + -73 59 rlineto + -13 -30 -14 -23 -12 -29 rrcurveto + -1 4 0 20 0 3 rrcurveto + 0 93 33 237 12 52 rrcurveto + 4 18 14 62 9 22 rrcurveto + endchar + </CharString> + <CharString name="uni30FB"> + 500 520 rmoveto + -77 0 -63 -63 0 -77 rrcurveto + 0 -77 63 -63 77 0 rrcurveto + 77 0 63 63 0 77 rrcurveto + 0 77 -63 63 -77 0 rrcurveto + endchar + </CharString> + <CharString name="uniFF1A"> + 500 500 rmoveto + 60 0 46 46 0 58 rrcurveto + 0 60 -46 46 -60 0 rrcurveto + -60 0 -46 -46 0 -60 rrcurveto + 0 -58 46 -46 60 0 rrcurveto + 0 -470 rmoveto + 60 0 46 46 0 58 rrcurveto + 0 60 -46 46 -60 0 rrcurveto + -60 0 -46 -46 0 -60 rrcurveto + 0 -58 46 -46 60 0 rrcurveto + endchar + </CharString> + <CharString name="uniFF2D"> + 113 0 rmoveto + 160 0 rlineto + 0 255 rlineto + 0 75 -12 113 -9 74 rrcurveto + 4 0 rlineto + 72 -182 rlineto + 121 -272 rlineto + 98 0 rlineto + 120 272 rlineto + 73 182 rlineto + 5 0 rlineto + -10 -74 -12 -113 0 -75 rrcurveto + 0 -255 rlineto + 163 0 rlineto + 0 748 rlineto + -194 0 rlineto + -135 -325 rlineto + -17 -43 -18 -47 -18 -46 rrcurveto + -5 0 rlineto + -16 46 -19 47 -16 43 rrcurveto + -142 325 rlineto + -193 0 rlineto + 0 -748 rlineto + endchar + </CharString> + </CharStrings> + </CFFFont> + + <GlobalSubrs> + <!-- The 'index' attribute is only for humans; it is ignored when parsed. --> + </GlobalSubrs> + </CFF> + + <GPOS> + <Version value="0x00010000"/> + <ScriptList> + <!-- ScriptCount=1 --> + <ScriptRecord index="0"> + <ScriptTag value="DFLT"/> + <Script> + <DefaultLangSys> + <ReqFeatureIndex value="65535"/> + <!-- FeatureCount=1 --> + <FeatureIndex index="0" value="0"/> + </DefaultLangSys> + <!-- LangSysCount=0 --> + </Script> + </ScriptRecord> + </ScriptList> + <FeatureList> + <!-- FeatureCount=1 --> + <FeatureRecord index="0"> + <FeatureTag value="vpal"/> + <Feature> + <!-- LookupCount=1 --> + <LookupListIndex index="0" value="0"/> + </Feature> + </FeatureRecord> + </FeatureList> + <LookupList> + <!-- LookupCount=1 --> + <Lookup index="0"> + <LookupType value="1"/> + <LookupFlag value="0"/> + <!-- SubTableCount=3 --> + <SinglePos index="0" Format="2"> + <Coverage Format="1"> + <Glyph value="uni3001"/> + <Glyph value="uni30FB"/> + <Glyph value="uniFF1A"/> + </Coverage> + <ValueFormat value="5"/> + <!-- ValueCount=3 --> + <Value index="0" XPlacement="-3" XAdvance="-500"/> + <Value index="1" XPlacement="-250" XAdvance="-500"/> + <Value index="2" XPlacement="-250" XAdvance="-500"/> + </SinglePos> + <SinglePos index="1" Format="2"> + <Coverage Format="1"> + <Glyph value="uni3073"/> + <Glyph value="uni3074"/> + </Coverage> + <ValueFormat value="4"/> + <!-- ValueCount=2 --> + <Value index="0" XAdvance="-35"/> + <Value index="1" XAdvance="-30"/> + </SinglePos> + <SinglePos index="2" Format="2"> + <Coverage Format="1"> + <Glyph value="uniFF2D"/> + <Glyph value="uni307B"/> + </Coverage> + <ValueFormat value="1"/> + <!-- ValueCount=2 --> + <Value index="0" XPlacement="1"/> + <Value index="1" XPlacement="10"/> + </SinglePos> + </Lookup> + </LookupList> + </GPOS> + + <hmtx> + <mtx name=".notdef" width="250" lsb="0"/> + <mtx name="uni3001" width="1000" lsb="33"/> + <mtx name="uni3073" width="1000" lsb="52"/> + <mtx name="uni3074" width="1000" lsb="52"/> + <mtx name="uni307B" width="1000" lsb="80"/> + <mtx name="uni30FB" width="1000" lsb="360"/> + <mtx name="uniFF1A" width="1000" lsb="394"/> + <mtx name="uniFF2D" width="1000" lsb="113"/> + </hmtx> + +</ttFont> diff --git a/Tests/varLib/data/test_results/BuildTestCFF2.ttx b/Tests/varLib/data/test_results/BuildTestCFF2.ttx index 37ed3aaf..91b83fc0 100644 --- a/Tests/varLib/data/test_results/BuildTestCFF2.ttx +++ b/Tests/varLib/data/test_results/BuildTestCFF2.ttx @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<ttFont sfntVersion="OTTO" ttLibVersion="3.38"> +<ttFont sfntVersion="OTTO" ttLibVersion="3.42"> <fvar> @@ -67,29 +67,29 @@ <BlueValues> <blend value="-12 0 0"/> <blend value="0 0 0"/> - <blend value="486 -8 -8"/> + <blend value="486 -8 14"/> <blend value="498 0 0"/> - <blend value="574 4 4"/> + <blend value="574 4 -8"/> <blend value="586 0 0"/> - <blend value="638 6 6"/> + <blend value="638 6 -10"/> <blend value="650 0 0"/> - <blend value="656 2 2"/> + <blend value="656 2 -2"/> <blend value="668 0 0"/> - <blend value="712 6 6"/> + <blend value="712 6 -10"/> <blend value="724 0 0"/> </BlueValues> <OtherBlues> - <blend value="-217 -17 -17"/> + <blend value="-217 -17 29"/> <blend value="-205 0 0"/> </OtherBlues> <BlueScale value="0.0625"/> <BlueShift value="7"/> <BlueFuzz value="0"/> <StdHW> - <blend value="67 -39.0 -39.0"/> + <blend value="67 -39.0 67.0"/> </StdHW> <StdVW> - <blend value="85 -51.0 -51.0"/> + <blend value="85 -51.0 87.0"/> </StdVW> </Private> </FontDict> diff --git a/Tests/varLib/data/test_results/FeatureVars.ttx b/Tests/varLib/data/test_results/FeatureVars.ttx index f2f6b05d..93ad795f 100644 --- a/Tests/varLib/data/test_results/FeatureVars.ttx +++ b/Tests/varLib/data/test_results/FeatureVars.ttx @@ -33,9 +33,8 @@ <Script> <DefaultLangSys> <ReqFeatureIndex value="65535"/> - <!-- FeatureCount=2 --> + <!-- FeatureCount=1 --> <FeatureIndex index="0" value="0"/> - <FeatureIndex index="1" value="0"/> </DefaultLangSys> <!-- LangSysCount=0 --> </Script> diff --git a/Tests/varLib/data/test_results/TestNonMarkingCFF2.ttx b/Tests/varLib/data/test_results/TestNonMarkingCFF2.ttx new file mode 100644 index 00000000..5ded5b91 --- /dev/null +++ b/Tests/varLib/data/test_results/TestNonMarkingCFF2.ttx @@ -0,0 +1,76 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ttFont sfntVersion="OTTO" ttLibVersion="3.42"> + + <CFF2> + <major value="2"/> + <minor value="0"/> + <CFFFont name="CFF2Font"> + <FontMatrix value="0.001 0 0 0.001 0 0"/> + <FDArray> + <FontDict index="0"> + <Private> + <BlueValues> + <blend value="-12 0"/> + <blend value="0 0"/> + <blend value="478 8"/> + <blend value="490 0"/> + <blend value="570 -4"/> + <blend value="582 0"/> + <blend value="640 -6"/> + <blend value="652 0"/> + <blend value="660 -2"/> + <blend value="672 0"/> + <blend value="722 -6"/> + <blend value="734 0"/> + </BlueValues> + <OtherBlues> + <blend value="-234 17"/> + <blend value="-222 0"/> + </OtherBlues> + <BlueScale value="0.0625"/> + <BlueShift value="7"/> + <BlueFuzz value="0"/> + <StdHW> + <blend value="28 39.0"/> + </StdHW> + <StdVW> + <blend value="34 51.0"/> + </StdVW> + </Private> + </FontDict> + </FDArray> + <CharStrings> + <CharString name=".notdef"> + </CharString> + <CharString name="A"> + </CharString> + </CharStrings> + <VarStore Format="1"> + <Format value="1"/> + <VarRegionList> + <!-- RegionAxisCount=1 --> + <!-- RegionCount=1 --> + <Region index="0"> + <VarRegionAxis index="0"> + <StartCoord value="0.0"/> + <PeakCoord value="1.0"/> + <EndCoord value="1.0"/> + </VarRegionAxis> + </Region> + </VarRegionList> + <!-- VarDataCount=1 --> + <VarData index="0"> + <!-- ItemCount=0 --> + <NumShorts value="0"/> + <!-- VarRegionCount=1 --> + <VarRegionIndex index="0" value="0"/> + </VarData> + </VarStore> + </CFFFont> + + <GlobalSubrs> + <!-- The 'index' attribute is only for humans; it is ignored when parsed. --> + </GlobalSubrs> + </CFF2> + +</ttFont> diff --git a/Tests/varLib/data/test_results/test_vpal.ttx b/Tests/varLib/data/test_results/test_vpal.ttx new file mode 100644 index 00000000..334ced55 --- /dev/null +++ b/Tests/varLib/data/test_results/test_vpal.ttx @@ -0,0 +1,120 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ttFont sfntVersion="OTTO" ttLibVersion="3.42"> + + <GPOS> + <Version value="0x00010000"/> + <ScriptList> + <!-- ScriptCount=1 --> + <ScriptRecord index="0"> + <ScriptTag value="DFLT"/> + <Script> + <DefaultLangSys> + <ReqFeatureIndex value="65535"/> + <!-- FeatureCount=1 --> + <FeatureIndex index="0" value="0"/> + </DefaultLangSys> + <!-- LangSysCount=0 --> + </Script> + </ScriptRecord> + </ScriptList> + <FeatureList> + <!-- FeatureCount=1 --> + <FeatureRecord index="0"> + <FeatureTag value="vpal"/> + <Feature> + <!-- LookupCount=1 --> + <LookupListIndex index="0" value="0"/> + </Feature> + </FeatureRecord> + </FeatureList> + <LookupList> + <!-- LookupCount=1 --> + <Lookup index="0"> + <LookupType value="1"/> + <LookupFlag value="0"/> + <!-- SubTableCount=6 --> + <SinglePos index="0" Format="2"> + <Coverage Format="1"> + <Glyph value="uniFF1A"/> + <Glyph value="uni3074"/> + </Coverage> + <ValueFormat value="7"/> + <!-- ValueCount=2 --> + <Value index="0" XPlacement="-250" YPlacement="0" XAdvance="-500"/> + <Value index="1" XPlacement="0" YPlacement="0" XAdvance="-30"/> + </SinglePos> + <SinglePos index="1" Format="1"> + <Coverage Format="1"> + <Glyph value="uni3001"/> + </Coverage> + <ValueFormat value="23"/> + <Value XPlacement="-9" YPlacement="0" XAdvance="-500"> + <XPlaDevice> + <StartSize value="0"/> + <EndSize value="4"/> + <DeltaFormat value="32768"/> + </XPlaDevice> + </Value> + </SinglePos> + <SinglePos index="2" Format="1"> + <Coverage Format="1"> + <Glyph value="uni30FB"/> + </Coverage> + <ValueFormat value="39"/> + <Value XPlacement="-250" YPlacement="1" XAdvance="-500"> + <YPlaDevice> + <StartSize value="0"/> + <EndSize value="2"/> + <DeltaFormat value="32768"/> + </YPlaDevice> + </Value> + </SinglePos> + <SinglePos index="3" Format="1"> + <Coverage Format="1"> + <Glyph value="uniFF2D"/> + </Coverage> + <ValueFormat value="87"/> + <Value XPlacement="12" YPlacement="0" XAdvance="23"> + <XPlaDevice> + <StartSize value="0"/> + <EndSize value="1"/> + <DeltaFormat value="32768"/> + </XPlaDevice> + <XAdvDevice> + <StartSize value="0"/> + <EndSize value="0"/> + <DeltaFormat value="32768"/> + </XAdvDevice> + </Value> + </SinglePos> + <SinglePos index="4" Format="1"> + <Coverage Format="1"> + <Glyph value="uni3073"/> + </Coverage> + <ValueFormat value="71"/> + <Value XPlacement="0" YPlacement="0" XAdvance="-36"> + <XAdvDevice> + <StartSize value="0"/> + <EndSize value="3"/> + <DeltaFormat value="32768"/> + </XAdvDevice> + </Value> + </SinglePos> + <SinglePos index="5" Format="1"> + <Coverage Format="1"> + <Glyph value="uni307B"/> + </Coverage> + <ValueFormat value="23"/> + <Value XPlacement="11" YPlacement="0" XAdvance="0"> + <XPlaDevice> + <StartSize value="0"/> + <EndSize value="2"/> + <DeltaFormat value="32768"/> + </XPlaDevice> + </Value> + </SinglePos> + </Lookup> + </LookupList> + </GPOS> + +</ttFont> diff --git a/Tests/varLib/data/test_vpal.designspace b/Tests/varLib/data/test_vpal.designspace new file mode 100644 index 00000000..a736927e --- /dev/null +++ b/Tests/varLib/data/test_vpal.designspace @@ -0,0 +1,35 @@ +<?xml version='1.0' encoding='utf-8'?> +<designspace format="3"> + <axes> + <axis default="0" maximum="1000" minimum="0" name="weight" tag="wght" /> + </axes> + <sources> + <source filename="master_vpal_test/master_vpal_test_0.ufo" stylename="w0.00"> + <info copy="1" /> + <location> + <dimension name="weight" xvalue="0.00" /> + </location> + </source> + <source filename="master_vpal_test/master_vpal_test_1.ufo" stylename="w1000.00"> + <location> + <dimension name="weight" xvalue="1000.00" /> + </location> + </source> + </sources> + <instances> + <instance familyname="SHSansJPVFTest" filename="instances/SHSansJPVFTest-ExtraLight.otf" postscriptfontname="SHSansJPVFTest-ExtraLight" stylename="ExtraLight"> + <location> + <dimension name="weight" xvalue="0" /> + </location> + <kerning /> + <info /> + </instance> + <instance familyname="SHSansJPVFTest" filename="instances/SHSansJPVFTest-Heavy.otf" postscriptfontname="SHSansJPVFTest-Heavy" stylename="Heavy"> + <location> + <dimension name="weight" xvalue="1000" /> + </location> + <kerning /> + <info /> + </instance> + </instances> +</designspace> diff --git a/Tests/varLib/varLib_test.py b/Tests/varLib/varLib_test.py index f3037339..e29befbf 100644 --- a/Tests/varLib/varLib_test.py +++ b/Tests/varLib/varLib_test.py @@ -2,6 +2,7 @@ from __future__ import print_function, division, absolute_import from fontTools.misc.py23 import * from fontTools.ttLib import TTFont, newTable from fontTools.varLib import build +from fontTools.varLib.mutator import instantiateVariableFont from fontTools.varLib import main as varLib_main, load_masters from fontTools.designspaceLib import ( DesignSpaceDocumentError, DesignSpaceDocument, SourceDescriptor, @@ -227,6 +228,28 @@ class BuildTest(unittest.TestCase): expected_ttx_name=test_name ) + def test_varlib_nonmarking_CFF2(self): + ds_path = self.get_test_input('TestNonMarkingCFF2.designspace') + ttx_dir = self.get_test_input("master_non_marking_cff2") + expected_ttx_path = self.get_test_output("TestNonMarkingCFF2.ttx") + + self.temp_dir() + for path in self.get_file_list(ttx_dir, '.ttx', 'TestNonMarkingCFF2_'): + self.compile_font(path, ".otf", self.tempdir) + + ds = DesignSpaceDocument.fromfile(ds_path) + for source in ds.sources: + source.path = os.path.join( + self.tempdir, os.path.basename(source.filename).replace(".ufo", ".otf") + ) + ds.updatePaths() + + varfont, _, _ = build(ds) + varfont = reload_font(varfont) + + tables = ["CFF2"] + self.expect_ttx(varfont, expected_ttx_path, tables) + def test_varlib_build_CFF2(self): ds_path = self.get_test_input('TestCFF2.designspace') ttx_dir = self.get_test_input("master_cff2") @@ -249,7 +272,6 @@ class BuildTest(unittest.TestCase): tables = ["fvar", "CFF2"] self.expect_ttx(varfont, expected_ttx_path, tables) - def test_varlib_build_sparse_CFF2(self): ds_path = self.get_test_input('TestSparseCFF2VF.designspace') ttx_dir = self.get_test_input("master_sparse_cff2") @@ -272,6 +294,27 @@ class BuildTest(unittest.TestCase): tables = ["fvar", "CFF2"] self.expect_ttx(varfont, expected_ttx_path, tables) + def test_varlib_build_vpal(self): + ds_path = self.get_test_input('test_vpal.designspace') + ttx_dir = self.get_test_input("master_vpal_test") + expected_ttx_path = self.get_test_output("test_vpal.ttx") + + self.temp_dir() + for path in self.get_file_list(ttx_dir, '.ttx', 'master_vpal_test_'): + self.compile_font(path, ".otf", self.tempdir) + + ds = DesignSpaceDocument.fromfile(ds_path) + for source in ds.sources: + source.path = os.path.join( + self.tempdir, os.path.basename(source.filename).replace(".ufo", ".otf") + ) + ds.updatePaths() + + varfont, _, _ = build(ds) + varfont = reload_font(varfont) + + tables = ["GPOS"] + self.expect_ttx(varfont, expected_ttx_path, tables) def test_varlib_main_ttf(self): """Mostly for testing varLib.main() @@ -496,6 +539,98 @@ class BuildTest(unittest.TestCase): self.expect_ttx(varfont, expected_ttx_path, tables) self.check_ttx_dump(varfont, expected_ttx_path, tables, suffix) + def test_kerning_merging(self): + """Test the correct merging of class-based pair kerning. + + Problem description at https://github.com/fonttools/fonttools/pull/1638. + Test font and Designspace generated by + https://gist.github.com/madig/183d0440c9f7d05f04bd1280b9664bd1. + """ + ds_path = self.get_test_input("KerningMerging.designspace") + ttx_dir = self.get_test_input("master_kerning_merging") + + ds = DesignSpaceDocument.fromfile(ds_path) + for source in ds.sources: + ttx_dump = TTFont() + ttx_dump.importXML( + os.path.join( + ttx_dir, os.path.basename(source.filename).replace(".ttf", ".ttx") + ) + ) + source.font = reload_font(ttx_dump) + + varfont, _, _ = build(ds) + varfont = reload_font(varfont) + + class_kerning_tables = [ + t + for l in varfont["GPOS"].table.LookupList.Lookup + for t in l.SubTable + if t.Format == 2 + ] + assert len(class_kerning_tables) == 1 + class_kerning_table = class_kerning_tables[0] + + # Test that no class kerned against class zero (containing all glyphs not + # classed) has a `XAdvDevice` table attached, which in the variable font + # context is a "VariationIndex" table and points to kerning deltas in the GDEF + # table. Variation deltas of any kerning class against class zero should + # probably never exist. + for class1_record in class_kerning_table.Class1Record: + class2_zero = class1_record.Class2Record[0] + assert getattr(class2_zero.Value1, "XAdvDevice", None) is None + + # Assert the variable font's kerning table (without deltas) is equal to the + # default font's kerning table. The bug fixed in + # https://github.com/fonttools/fonttools/pull/1638 caused rogue kerning + # values to be written to the variable font. + assert _extract_flat_kerning(varfont, class_kerning_table) == { + ("A", ".notdef"): 0, + ("A", "A"): 0, + ("A", "B"): -20, + ("A", "C"): 0, + ("A", "D"): -20, + ("B", ".notdef"): 0, + ("B", "A"): 0, + ("B", "B"): 0, + ("B", "C"): 0, + ("B", "D"): 0, + } + + instance_thin = instantiateVariableFont(varfont, {"wght": 100}) + instance_thin_kerning_table = ( + instance_thin["GPOS"].table.LookupList.Lookup[0].SubTable[0] + ) + assert _extract_flat_kerning(instance_thin, instance_thin_kerning_table) == { + ("A", ".notdef"): 0, + ("A", "A"): 0, + ("A", "B"): 0, + ("A", "C"): 10, + ("A", "D"): 0, + ("B", ".notdef"): 0, + ("B", "A"): 0, + ("B", "B"): 0, + ("B", "C"): 10, + ("B", "D"): 0, + } + + instance_black = instantiateVariableFont(varfont, {"wght": 900}) + instance_black_kerning_table = ( + instance_black["GPOS"].table.LookupList.Lookup[0].SubTable[0] + ) + assert _extract_flat_kerning(instance_black, instance_black_kerning_table) == { + ("A", ".notdef"): 0, + ("A", "A"): 0, + ("A", "B"): 0, + ("A", "C"): 0, + ("A", "D"): 40, + ("B", ".notdef"): 0, + ("B", "A"): 0, + ("B", "B"): 0, + ("B", "C"): 0, + ("B", "D"): 40, + } + def test_load_masters_layerName_without_required_font(): ds = DesignSpaceDocument() @@ -511,5 +646,20 @@ def test_load_masters_layerName_without_required_font(): load_masters(ds) +def _extract_flat_kerning(font, pairpos_table): + extracted_kerning = {} + for glyph_name_1 in pairpos_table.Coverage.glyphs: + class_def_1 = pairpos_table.ClassDef1.classDefs.get(glyph_name_1, 0) + for glyph_name_2 in font.getGlyphOrder(): + class_def_2 = pairpos_table.ClassDef2.classDefs.get(glyph_name_2, 0) + kern_value = ( + pairpos_table.Class1Record[class_def_1] + .Class2Record[class_def_2] + .Value1.XAdvance + ) + extracted_kerning[(glyph_name_1, glyph_name_2)] = kern_value + return extracted_kerning + + if __name__ == "__main__": sys.exit(unittest.main()) diff --git a/requirements.txt b/requirements.txt index bdfd52ba..8e1fe6ed 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,4 +8,4 @@ scipy==1.3.0; platform_python_implementation != "PyPy" and python_version >= '3. munkres==1.0.12; platform_python_implementation == "PyPy" and python_version < '3.5' # pyup: ignore munkres==1.1.2; platform_python_implementation == "PyPy" and python_version >= '3.5' zopfli==0.1.6 -fs==2.4.5 +fs==2.4.8 @@ -1,5 +1,5 @@ [bumpversion] -current_version = 3.42.0 +current_version = 3.43.1 commit = True tag = False tag_name = {new_version} @@ -352,7 +352,7 @@ def find_data_files(manpath="share/man"): setup( name="fonttools", - version="3.42.0", + version="3.43.1", description="Tools to manipulate font files", author="Just van Rossum", author_email="just@letterror.com", @@ -6,6 +6,7 @@ envlist = py{27,37}-cov, htmlcov deps = cov: coverage>=4.3 pytest + pytest-randomly -rrequirements.txt extras = ufo |