Merge pull request #1148 from anthrotype/pair-pos-conflict-warning
emit warning if enum pos rules overridden by preceding single pair
This commit is contained in:
commit
60bc2b722b
@ -9,6 +9,10 @@ from fontTools.otlLib import builder as otl
|
|||||||
from fontTools.ttLib import newTable, getTableModule
|
from fontTools.ttLib import newTable, getTableModule
|
||||||
from fontTools.ttLib.tables import otBase, otTables
|
from fontTools.ttLib.tables import otBase, otTables
|
||||||
import itertools
|
import itertools
|
||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def addOpenTypeFeatures(font, featurefile):
|
def addOpenTypeFeatures(font, featurefile):
|
||||||
@ -1424,11 +1428,15 @@ class PairPosBuilder(LookupBuilder):
|
|||||||
key = (glyph1, glyph2)
|
key = (glyph1, glyph2)
|
||||||
oldValue = self.glyphPairs.get(key, None)
|
oldValue = self.glyphPairs.get(key, None)
|
||||||
if oldValue is not None:
|
if oldValue is not None:
|
||||||
|
# the Feature File spec explicitly allows specific pairs generated
|
||||||
|
# by an 'enum' rule to be overridden by preceding single pairs;
|
||||||
|
# we emit a warning and use the previously defined value
|
||||||
otherLoc = self.locations[key]
|
otherLoc = self.locations[key]
|
||||||
raise FeatureLibError(
|
log.warning(
|
||||||
'Already defined position for pair %s %s at %s:%d:%d'
|
'Already defined position for pair %s %s at %s:%d:%d; '
|
||||||
% (glyph1, glyph2, otherLoc[0], otherLoc[1], otherLoc[2]),
|
'choosing the first value',
|
||||||
location)
|
glyph1, glyph2, otherLoc[0], otherLoc[1], otherLoc[2])
|
||||||
|
else:
|
||||||
val1, _ = makeOpenTypeValueRecord(value1, pairPosContext=True)
|
val1, _ = makeOpenTypeValueRecord(value1, pairPosContext=True)
|
||||||
val2, _ = makeOpenTypeValueRecord(value2, pairPosContext=True)
|
val2, _ = makeOpenTypeValueRecord(value2, pairPosContext=True)
|
||||||
self.glyphPairs[key] = (val1, val2)
|
self.glyphPairs[key] = (val1, val2)
|
||||||
|
@ -467,7 +467,7 @@ class CapturingLogHandler(logging.Handler):
|
|||||||
import re
|
import re
|
||||||
pattern = re.compile(regexp)
|
pattern = re.compile(regexp)
|
||||||
for r in self.records:
|
for r in self.records:
|
||||||
if pattern.search(r.msg):
|
if pattern.search(r.getMessage()):
|
||||||
return True
|
return True
|
||||||
assert 0, "Pattern '%s' not found in logger records" % regexp
|
assert 0, "Pattern '%s' not found in logger records" % regexp
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
from __future__ import print_function, division, absolute_import
|
from __future__ import print_function, division, absolute_import
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
from fontTools.misc.py23 import *
|
from fontTools.misc.py23 import *
|
||||||
|
from fontTools.misc.loggingTools import CapturingLogHandler
|
||||||
from fontTools.feaLib.builder import Builder, addOpenTypeFeatures, \
|
from fontTools.feaLib.builder import Builder, addOpenTypeFeatures, \
|
||||||
addOpenTypeFeaturesFromString
|
addOpenTypeFeaturesFromString
|
||||||
from fontTools.feaLib.error import FeatureLibError
|
from fontTools.feaLib.error import FeatureLibError
|
||||||
@ -13,6 +14,7 @@ import os
|
|||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
|
import logging
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
|
||||||
@ -196,16 +198,29 @@ class BuilderTest(unittest.TestCase):
|
|||||||
" sub f_f_i by f f i;"
|
" sub f_f_i by f f i;"
|
||||||
"} test;")
|
"} test;")
|
||||||
|
|
||||||
def test_pairPos_redefinition(self):
|
def test_pairPos_redefinition_warning(self):
|
||||||
self.assertRaisesRegex(
|
# https://github.com/fonttools/fonttools/issues/1147
|
||||||
FeatureLibError,
|
logger = logging.getLogger("fontTools.feaLib.builder")
|
||||||
r"Already defined position for pair A B "
|
with CapturingLogHandler(logger, "WARNING") as captor:
|
||||||
"at .*:2:[0-9]+", # :2: = line 2
|
# the pair "yacute semicolon" is redefined in the enum pos
|
||||||
self.build,
|
font = self.build(
|
||||||
"feature test {\n"
|
"@Y_LC = [y yacute ydieresis];"
|
||||||
" pos A B 123;\n" # line 2
|
"@SMALL_PUNC = [comma semicolon period];"
|
||||||
" pos A B 456;\n"
|
"feature kern {"
|
||||||
"} test;\n")
|
" pos yacute semicolon -70;"
|
||||||
|
" enum pos @Y_LC semicolon -80;"
|
||||||
|
" pos @Y_LC @SMALL_PUNC -100;"
|
||||||
|
"} kern;")
|
||||||
|
|
||||||
|
captor.assertRegex("Already defined position for pair yacute semicolon")
|
||||||
|
|
||||||
|
# the first definition prevails: yacute semicolon -70
|
||||||
|
st = font["GPOS"].table.LookupList.Lookup[0].SubTable[0]
|
||||||
|
self.assertEqual(st.Coverage.glyphs[2], "yacute")
|
||||||
|
self.assertEqual(st.PairSet[2].PairValueRecord[0].SecondGlyph,
|
||||||
|
"semicolon")
|
||||||
|
self.assertEqual(vars(st.PairSet[2].PairValueRecord[0].Value1),
|
||||||
|
{"XAdvance": -70})
|
||||||
|
|
||||||
def test_singleSubst_multipleSubstitutionsForSameGlyph(self):
|
def test_singleSubst_multipleSubstitutionsForSameGlyph(self):
|
||||||
self.assertRaisesRegex(
|
self.assertRaisesRegex(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user