Merge remote-tracking branch 'origin/main' into variable-colr
This commit is contained in:
commit
fcd2a67f52
3
.github/workflows/publish.yml
vendored
3
.github/workflows/publish.yml
vendored
@ -9,6 +9,9 @@ on:
|
||||
tags:
|
||||
- '*.*.*' # e.g. 1.0.0 or 20.15.10
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
|
3
.github/workflows/test.yml
vendored
3
.github/workflows/test.yml
vendored
@ -6,6 +6,9 @@ on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
|
@ -764,7 +764,7 @@ class Builder(object):
|
||||
gdef.Version = 0x00010002 if gdef.MarkGlyphSetsDef else 0x00010000
|
||||
if self.varstorebuilder:
|
||||
store = self.varstorebuilder.finish()
|
||||
if store.VarData:
|
||||
if store:
|
||||
gdef.Version = 0x00010003
|
||||
gdef.VarStore = store
|
||||
varidx_map = store.optimize()
|
||||
|
@ -73,6 +73,7 @@ class Parser(object):
|
||||
self.next_token_location_ = None
|
||||
lexerClass = IncludingLexer if followIncludes else NonIncludingLexer
|
||||
self.lexer_ = lexerClass(featurefile, includeDir=includeDir)
|
||||
self.missing = {}
|
||||
self.advance_lexer_(comments=True)
|
||||
|
||||
def parse(self):
|
||||
@ -125,6 +126,16 @@ class Parser(object):
|
||||
),
|
||||
self.cur_token_location_,
|
||||
)
|
||||
# Report any missing glyphs at the end of parsing
|
||||
if self.missing:
|
||||
error = [
|
||||
" %s (first found at %s)" % (name, loc)
|
||||
for name, loc in self.missing.items()
|
||||
]
|
||||
raise FeatureLibError(
|
||||
"The following glyph names are referenced but are missing from the "
|
||||
"glyph set:\n" + ("\n".join(error)), None
|
||||
)
|
||||
return self.doc_
|
||||
|
||||
def parse_anchor_(self):
|
||||
@ -2073,19 +2084,18 @@ class Parser(object):
|
||||
raise FeatureLibError("Expected a glyph name or CID", self.cur_token_location_)
|
||||
|
||||
def check_glyph_name_in_glyph_set(self, *names):
|
||||
"""Raises if glyph name (just `start`) or glyph names of a
|
||||
range (`start` and `end`) are not in the glyph set.
|
||||
"""Adds a glyph name (just `start`) or glyph names of a
|
||||
range (`start` and `end`) which are not in the glyph set
|
||||
to the "missing list" for future error reporting.
|
||||
|
||||
If no glyph set is present, does nothing.
|
||||
"""
|
||||
if self.glyphNames_:
|
||||
missing = [name for name in names if name not in self.glyphNames_]
|
||||
if missing:
|
||||
raise FeatureLibError(
|
||||
"The following glyph names are referenced but are missing from the "
|
||||
f"glyph set: {', '.join(missing)}",
|
||||
self.cur_token_location_,
|
||||
)
|
||||
for name in names:
|
||||
if name in self.glyphNames_:
|
||||
continue
|
||||
if name not in self.missing:
|
||||
self.missing[name] = self.cur_token_location_
|
||||
|
||||
def expect_markClass_reference_(self):
|
||||
name = self.expect_class_name_()
|
||||
|
@ -534,7 +534,9 @@ class OTTableWriter(object):
|
||||
https://github.com/harfbuzz/uharfbuzz/blob/main/src/uharfbuzz/_harfbuzz.pyx#L1149
|
||||
"""
|
||||
internedTables = {}
|
||||
self._doneWriting(internedTables, shareExtension=True)
|
||||
# TODO: Restore shareExtension=True after we fix
|
||||
# https://github.com/fonttools/fonttools/issues/2661
|
||||
self._doneWriting(internedTables, shareExtension=False)
|
||||
tables = []
|
||||
obj_list = []
|
||||
done = {}
|
||||
|
@ -488,7 +488,7 @@ def _get_advance_metrics(font, masterModel, master_ttfs,
|
||||
vOrigMap[glyphName] = storeBuilder.storeDeltas(deltas, round=noRound)
|
||||
|
||||
indirectStore = storeBuilder.finish()
|
||||
mapping2 = indirectStore.optimize()
|
||||
mapping2 = indirectStore.optimize(use_NO_VARIATION_INDEX=False)
|
||||
advMapping = [mapping2[advMapping[g]] for g in glyphOrder]
|
||||
advanceMapping = builder.buildVarIdxMap(advMapping, glyphOrder)
|
||||
|
||||
@ -608,7 +608,7 @@ def _add_BASE(font, masterModel, master_ttfs, axisTags):
|
||||
merger.mergeTables(font, master_ttfs, ['BASE'])
|
||||
store = merger.store_builder.finish()
|
||||
|
||||
if not store.VarData:
|
||||
if not store:
|
||||
return
|
||||
base = font['BASE'].table
|
||||
assert base.Version == 0x00010000
|
||||
@ -623,7 +623,7 @@ def _merge_OTL(font, model, master_fonts, axisTags):
|
||||
|
||||
merger.mergeTables(font, master_fonts, ['GSUB', 'GDEF', 'GPOS'])
|
||||
store = merger.store_builder.finish()
|
||||
if not store.VarData:
|
||||
if not store:
|
||||
return
|
||||
try:
|
||||
GDEF = font['GDEF'].table
|
||||
|
@ -633,6 +633,7 @@ def instantiateItemVariationStore(itemVarStore, fvarAxes, axisLimits):
|
||||
for major, deltas in enumerate(defaultDeltaArray)
|
||||
for minor, delta in enumerate(deltas)
|
||||
}
|
||||
defaultDeltas[itemVarStore.NO_VARIATION_INDEX] = 0
|
||||
return defaultDeltas
|
||||
|
||||
|
||||
|
@ -7,6 +7,10 @@ from functools import partial
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
NO_VARIATION_INDEX = 0xFFFFFFFF
|
||||
ot.VarStore.NO_VARIATION_INDEX = NO_VARIATION_INDEX
|
||||
|
||||
|
||||
def _getLocationKey(loc):
|
||||
return tuple(sorted(loc.items(), key=lambda kv: kv[0]))
|
||||
|
||||
@ -135,6 +139,11 @@ def VarRegion_get_support(self, fvar_axes):
|
||||
|
||||
ot.VarRegion.get_support = VarRegion_get_support
|
||||
|
||||
def VarStore___bool__(self):
|
||||
return bool(self.VarData)
|
||||
|
||||
ot.VarStore.__bool__ = VarStore___bool__
|
||||
|
||||
class VarStoreInstancer(object):
|
||||
|
||||
def __init__(self, varstore, fvar_axes, location={}):
|
||||
@ -169,6 +178,7 @@ class VarStoreInstancer(object):
|
||||
|
||||
def __getitem__(self, varidx):
|
||||
major, minor = varidx >> 16, varidx & 0xFFFF
|
||||
if varidx == NO_VARIATION_INDEX: return 0.
|
||||
varData = self._varData
|
||||
scalars = [self._getScalar(ri) for ri in varData[major].VarRegionIndex]
|
||||
deltas = varData[major].Item[minor]
|
||||
@ -431,7 +441,7 @@ class _EncodingDict(dict):
|
||||
return chars
|
||||
|
||||
|
||||
def VarStore_optimize(self):
|
||||
def VarStore_optimize(self, use_NO_VARIATION_INDEX=True):
|
||||
"""Optimize storage. Returns mapping from old VarIdxes to new ones."""
|
||||
|
||||
# TODO
|
||||
@ -455,6 +465,10 @@ def VarStore_optimize(self):
|
||||
row[regionIdx] += v
|
||||
row = tuple(row)
|
||||
|
||||
if use_NO_VARIATION_INDEX and not any(row):
|
||||
front_mapping[(major<<16)+minor] = None
|
||||
continue
|
||||
|
||||
encodings.add_row(row)
|
||||
front_mapping[(major<<16)+minor] = row
|
||||
|
||||
@ -537,9 +551,9 @@ def VarStore_optimize(self):
|
||||
back_mapping[item] = (major<<16)+minor
|
||||
|
||||
# Compile final mapping.
|
||||
varidx_map = {}
|
||||
varidx_map = {NO_VARIATION_INDEX:NO_VARIATION_INDEX}
|
||||
for k,v in front_mapping.items():
|
||||
varidx_map[k] = back_mapping[v]
|
||||
varidx_map[k] = back_mapping[v] if v is not None else NO_VARIATION_INDEX
|
||||
|
||||
# Remove unused regions.
|
||||
self.prune_regions()
|
||||
|
@ -316,7 +316,7 @@ class ParserTest(unittest.TestCase):
|
||||
def test_strict_glyph_name_check(self):
|
||||
self.parse("@bad = [a b ccc];", glyphNames=("a", "b", "ccc"))
|
||||
|
||||
with self.assertRaisesRegex(FeatureLibError, "missing from the glyph set: ccc"):
|
||||
with self.assertRaisesRegex(FeatureLibError, "(?s)missing from the glyph set:.*ccc"):
|
||||
self.parse("@bad = [a b ccc];", glyphNames=("a", "b"))
|
||||
|
||||
def test_glyphclass(self):
|
||||
|
@ -360,7 +360,7 @@ class InstantiateHVARTest(object):
|
||||
assert support == pytest.approx(expectedRegion[axisTag])
|
||||
|
||||
assert len(varStore.VarData) == 1
|
||||
assert varStore.VarData[0].ItemCount == 2
|
||||
assert varStore.VarData[0].ItemCount == 1
|
||||
|
||||
assert hvar.AdvWidthMap is not None
|
||||
advWithMap = hvar.AdvWidthMap.mapping
|
||||
@ -368,9 +368,7 @@ class InstantiateHVARTest(object):
|
||||
assert advWithMap[".notdef"] == advWithMap["space"]
|
||||
varIdx = advWithMap[".notdef"]
|
||||
# these glyphs have no metrics variations in the test font
|
||||
assert varStore.VarData[varIdx >> 16].Item[varIdx & 0xFFFF] == (
|
||||
[0] * varStore.VarData[0].VarRegionCount
|
||||
)
|
||||
assert varIdx == varStore.NO_VARIATION_INDEX
|
||||
|
||||
varIdx = advWithMap["hyphen"]
|
||||
assert varStore.VarData[varIdx >> 16].Item[varIdx & 0xFFFF] == expectedDeltas
|
||||
@ -458,6 +456,8 @@ class InstantiateItemVariationStoreTest(object):
|
||||
|
||||
defaultDeltaArray = []
|
||||
for varidx, delta in sorted(defaultDeltas.items()):
|
||||
if varidx == varStore.NO_VARIATION_INDEX:
|
||||
continue
|
||||
major, minor = varidx >> 16, varidx & 0xFFFF
|
||||
if major == len(defaultDeltaArray):
|
||||
defaultDeltaArray.append([])
|
||||
|
@ -13,7 +13,7 @@ from fontTools.ttLib.tables.otTables import VarStore
|
||||
(
|
||||
[{}, {"a": 1}],
|
||||
[
|
||||
[10, 20],
|
||||
[10, 10], # Test NO_VARIATION_INDEX
|
||||
[100, 2000],
|
||||
[100, 22000],
|
||||
],
|
||||
|
Loading…
x
Reference in New Issue
Block a user