Merge pull request #2348 from fonttools/paint-scale-variants

Add PaintScale* and Paint{Rotate,Skew}* variants
This commit is contained in:
Cosimo Lupo 2021-06-28 20:10:25 +01:00 committed by GitHub
commit c8473264eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 312 additions and 71 deletions

View File

@ -1764,36 +1764,128 @@ otData = [
('VarFixed', 'dy', None, None, 'Translation in y direction.'),
]),
# PaintRotate
# PaintScale
('PaintFormat16', [
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 16'),
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintScale table) to Paint subtable.'),
('Fixed', 'scaleX', None, None, ''),
('Fixed', 'scaleY', None, None, ''),
]),
# PaintVarScale
('PaintFormat17', [
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 17'),
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintVarScale table) to Paint subtable.'),
('VarFixed', 'scaleX', None, None, ''),
('VarFixed', 'scaleY', None, None, ''),
]),
# PaintScaleAroundCenter
('PaintFormat18', [
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 18'),
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintScaleAroundCenter table) to Paint subtable.'),
('Fixed', 'scaleX', None, None, ''),
('Fixed', 'scaleY', None, None, ''),
('Fixed', 'centerX', None, None, ''),
('Fixed', 'centerY', None, None, ''),
]),
# PaintVarScaleAroundCenter
('PaintFormat19', [
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 19'),
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintVarScaleAroundCenter table) to Paint subtable.'),
('VarFixed', 'scaleX', None, None, ''),
('VarFixed', 'scaleY', None, None, ''),
('VarFixed', 'centerX', None, None, ''),
('VarFixed', 'centerY', None, None, ''),
]),
# PaintScaleUniform
('PaintFormat20', [
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 20'),
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintScaleUniform table) to Paint subtable.'),
('Fixed', 'scale', None, None, ''),
]),
# PaintVarScaleUniform
('PaintFormat21', [
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 21'),
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintVarScaleUniform table) to Paint subtable.'),
('VarFixed', 'scale', None, None, ''),
]),
# PaintScaleUniformAroundCenter
('PaintFormat22', [
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 22'),
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintScaleUniformAroundCenter table) to Paint subtable.'),
('Fixed', 'scale', None, None, ''),
('Fixed', 'centerX', None, None, ''),
('Fixed', 'centerY', None, None, ''),
]),
# PaintVarScaleUniformAroundCenter
('PaintFormat23', [
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 23'),
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintVarScaleUniformAroundCenter table) to Paint subtable.'),
('VarFixed', 'scale', None, None, ''),
('VarFixed', 'centerX', None, None, ''),
('VarFixed', 'centerY', None, None, ''),
]),
# PaintRotate
('PaintFormat24', [
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 24'),
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintRotate table) to Paint subtable.'),
('Fixed', 'angle', None, None, ''),
]),
# PaintVarRotate
('PaintFormat25', [
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 25'),
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintVarRotate table) to Paint subtable.'),
('VarFixed', 'angle', None, None, ''),
]),
# PaintRotateAroundCenter
('PaintFormat26', [
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 26'),
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintRotateAroundCenter table) to Paint subtable.'),
('Fixed', 'angle', None, None, ''),
('Fixed', 'centerX', None, None, ''),
('Fixed', 'centerY', None, None, ''),
]),
# PaintVarRotate
('PaintFormat17', [
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 17'),
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintVarRotate table) to Paint subtable.'),
# PaintVarRotateAroundCenter
('PaintFormat27', [
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 27'),
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintVarRotateAroundCenter table) to Paint subtable.'),
('VarFixed', 'angle', None, None, ''),
('VarFixed', 'centerX', None, None, ''),
('VarFixed', 'centerY', None, None, ''),
]),
# PaintSkew
('PaintFormat18', [
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 18'),
('PaintFormat28', [
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 28'),
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintSkew table) to Paint subtable.'),
('Fixed', 'xSkewAngle', None, None, ''),
('Fixed', 'ySkewAngle', None, None, ''),
]),
# PaintVarSkew
('PaintFormat29', [
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 29'),
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintVarSkew table) to Paint subtable.'),
('VarFixed', 'xSkewAngle', None, None, ''),
('VarFixed', 'ySkewAngle', None, None, ''),
]),
# PaintSkewAroundCenter
('PaintFormat30', [
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 30'),
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintSkewAroundCenter table) to Paint subtable.'),
('Fixed', 'xSkewAngle', None, None, ''),
('Fixed', 'ySkewAngle', None, None, ''),
('Fixed', 'centerX', None, None, ''),
('Fixed', 'centerY', None, None, ''),
]),
# PaintVarSkew
('PaintFormat19', [
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 19'),
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintVarSkew table) to Paint subtable.'),
# PaintVarSkewAroundCenter
('PaintFormat31', [
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 31'),
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintVarSkewAroundCenter table) to Paint subtable.'),
('VarFixed', 'xSkewAngle', None, None, ''),
('VarFixed', 'ySkewAngle', None, None, ''),
('VarFixed', 'centerX', None, None, ''),
@ -1801,8 +1893,8 @@ otData = [
]),
# PaintComposite
('PaintFormat20', [
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 20'),
('PaintFormat32', [
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 32'),
('LOffset24To(Paint)', 'SourcePaint', None, None, 'Offset (from beginning of PaintComposite table) to source Paint subtable.'),
('CompositeMode', 'CompositeMode', None, None, 'A CompositeMode enumeration value.'),
('LOffset24To(Paint)', 'BackdropPaint', None, None, 'Offset (from beginning of PaintComposite table) to backdrop Paint subtable.'),

View File

@ -1346,11 +1346,23 @@ class PaintFormat(IntEnum):
PaintVarTransform = 13
PaintTranslate = 14
PaintVarTranslate = 15
PaintRotate = 16
PaintVarRotate = 17
PaintSkew = 18
PaintVarSkew = 19
PaintComposite = 20
PaintScale = 16
PaintVarScale = 17
PaintScaleAroundCenter = 18
PaintVarScaleAroundCenter = 19
PaintScaleUniform = 20
PaintVarScaleUniform = 21
PaintScaleUniformAroundCenter = 22
PaintVarScaleUniformAroundCenter = 23
PaintRotate = 24
PaintVarRotate = 25
PaintRotateAroundCenter = 26
PaintVarRotateAroundCenter = 27
PaintSkew = 28
PaintVarSkew = 29
PaintSkewAroundCenter = 30
PaintVarSkewAroundCenter = 31
PaintComposite = 32
class Paint(getFormatSwitchingBaseTableClass("uint8")):

View File

@ -394,6 +394,14 @@ def _is_var(fmt):
return fmt.name.startswith("PaintVar")
def _is_around_center(fmt):
return fmt.name.endswith("AroundCenter")
def _is_uniform_scale(fmt):
return "ScaleUniform" in fmt.name
def checkBuildPaintLinearGradient(fmt):
if _is_var(fmt):
inputMapFn = builder.VariableInt
@ -855,86 +863,214 @@ def test_buildPaintVarTranslate():
checkBuildPaintTranslate(ot.PaintFormat.PaintVarTranslate)
def checkBuildPaintScale(fmt):
if _is_var(fmt):
inputMapFn = builder.VariableInt
outputMapFn = lambda v: v.value
else:
inputMapFn = outputMapFn = lambda v: v
around_center = _is_around_center(fmt)
uniform = _is_uniform_scale(fmt)
source = {
"Format": fmt,
"Paint": (
ot.PaintFormat.PaintGlyph,
(ot.PaintFormat.PaintSolid, (0, 1.0)),
"a",
),
}
if uniform:
source["scale"] = 1.5
else:
source["scaleX"] = 1.0
source["scaleY"] = 2.0
if around_center:
source["centerX"] = 127
source["centerY"] = 129
paint = _build(ot.Paint, source)
assert paint.Format == fmt
assert paint.Paint.Format == ot.PaintFormat.PaintGlyph
if uniform:
assert outputMapFn(paint.scale) == 1.5
else:
assert outputMapFn(paint.scaleX) == 1.0
assert outputMapFn(paint.scaleY) == 2.0
if around_center:
assert outputMapFn(paint.centerX) == 127
assert outputMapFn(paint.centerY) == 129
def test_buildPaintScale():
assert not _is_var(ot.PaintFormat.PaintScale)
assert not _is_uniform_scale(ot.PaintFormat.PaintScale)
assert not _is_around_center(ot.PaintFormat.PaintScale)
checkBuildPaintScale(ot.PaintFormat.PaintScale)
def test_buildPaintVarScale():
assert _is_var(ot.PaintFormat.PaintVarScale)
assert not _is_uniform_scale(ot.PaintFormat.PaintVarScale)
assert not _is_around_center(ot.PaintFormat.PaintVarScale)
checkBuildPaintScale(ot.PaintFormat.PaintVarScale)
def test_buildPaintScaleAroundCenter():
assert not _is_var(ot.PaintFormat.PaintScaleAroundCenter)
assert not _is_uniform_scale(ot.PaintFormat.PaintScaleAroundCenter)
assert _is_around_center(ot.PaintFormat.PaintScaleAroundCenter)
checkBuildPaintScale(ot.PaintFormat.PaintScaleAroundCenter)
def test_buildPaintVarScaleAroundCenter():
assert _is_var(ot.PaintFormat.PaintVarScaleAroundCenter)
assert not _is_uniform_scale(ot.PaintFormat.PaintScaleAroundCenter)
assert _is_around_center(ot.PaintFormat.PaintVarScaleAroundCenter)
checkBuildPaintScale(ot.PaintFormat.PaintVarScaleAroundCenter)
def test_buildPaintScaleUniform():
assert not _is_var(ot.PaintFormat.PaintScaleUniform)
assert _is_uniform_scale(ot.PaintFormat.PaintScaleUniform)
assert not _is_around_center(ot.PaintFormat.PaintScaleUniform)
checkBuildPaintScale(ot.PaintFormat.PaintScaleUniform)
def test_buildPaintVarScaleUniform():
assert _is_var(ot.PaintFormat.PaintVarScaleUniform)
assert _is_uniform_scale(ot.PaintFormat.PaintVarScaleUniform)
assert not _is_around_center(ot.PaintFormat.PaintVarScaleUniform)
checkBuildPaintScale(ot.PaintFormat.PaintVarScaleUniform)
def test_buildPaintScaleUniformAroundCenter():
assert not _is_var(ot.PaintFormat.PaintScaleUniformAroundCenter)
assert _is_uniform_scale(ot.PaintFormat.PaintScaleUniformAroundCenter)
assert _is_around_center(ot.PaintFormat.PaintScaleUniformAroundCenter)
checkBuildPaintScale(ot.PaintFormat.PaintScaleUniformAroundCenter)
def test_buildPaintVarScaleUniformAroundCenter():
assert _is_var(ot.PaintFormat.PaintVarScaleUniformAroundCenter)
assert _is_uniform_scale(ot.PaintFormat.PaintVarScaleUniformAroundCenter)
assert _is_around_center(ot.PaintFormat.PaintVarScaleUniformAroundCenter)
checkBuildPaintScale(ot.PaintFormat.PaintVarScaleUniformAroundCenter)
def checkBuildPaintRotate(fmt):
if _is_var(fmt):
inputMapFn = builder.VariableInt
outputMapFn = lambda v: v.value
else:
inputMapFn = outputMapFn = lambda v: v
around_center = _is_around_center(fmt)
paint = _build(
ot.Paint,
{
"Format": fmt,
"Paint": (
ot.PaintFormat.PaintGlyph,
(ot.PaintFormat.PaintSolid, (0, 1.0)),
"a",
),
"angle": 15,
"centerX": 127,
"centerY": 129,
},
)
source = {
"Format": fmt,
"Paint": (
ot.PaintFormat.PaintGlyph,
(ot.PaintFormat.PaintSolid, (0, 1.0)),
"a",
),
"angle": 15,
}
if around_center:
source["centerX"] = 127
source["centerY"] = 129
paint = _build(ot.Paint, source)
assert paint.Format == fmt
assert paint.Paint.Format == ot.PaintFormat.PaintGlyph
assert outputMapFn(paint.angle) == 15
assert outputMapFn(paint.centerX) == 127
assert outputMapFn(paint.centerY) == 129
if around_center:
assert outputMapFn(paint.centerX) == 127
assert outputMapFn(paint.centerY) == 129
def test_buildPaintRotate():
assert not _is_var(ot.PaintFormat.PaintRotate)
assert not _is_around_center(ot.PaintFormat.PaintRotate)
checkBuildPaintRotate(ot.PaintFormat.PaintRotate)
def test_buildPaintVarRotate():
assert _is_var(ot.PaintFormat.PaintVarRotate)
assert not _is_around_center(ot.PaintFormat.PaintVarRotate)
checkBuildPaintRotate(ot.PaintFormat.PaintVarRotate)
def test_buildPaintRotateAroundCenter():
assert not _is_var(ot.PaintFormat.PaintRotateAroundCenter)
assert _is_around_center(ot.PaintFormat.PaintRotateAroundCenter)
checkBuildPaintRotate(ot.PaintFormat.PaintRotateAroundCenter)
def test_buildPaintVarRotateAroundCenter():
assert _is_var(ot.PaintFormat.PaintVarRotateAroundCenter)
assert _is_around_center(ot.PaintFormat.PaintVarRotateAroundCenter)
checkBuildPaintRotate(ot.PaintFormat.PaintVarRotateAroundCenter)
def checkBuildPaintSkew(fmt):
if _is_var(fmt):
inputMapFn = builder.VariableInt
outputMapFn = lambda v: v.value
else:
inputMapFn = outputMapFn = lambda v: v
around_center = _is_around_center(fmt)
paint = _build(
ot.Paint,
{
"Format": fmt,
"Paint": (
ot.PaintFormat.PaintGlyph,
(ot.PaintFormat.PaintSolid, (0, 1.0)),
"a",
),
"xSkewAngle": 15,
"ySkewAngle": 42,
"centerX": 127,
"centerY": 129,
},
)
source = {
"Format": fmt,
"Paint": (
ot.PaintFormat.PaintGlyph,
(ot.PaintFormat.PaintSolid, (0, 1.0)),
"a",
),
"xSkewAngle": 15,
"ySkewAngle": 42,
}
if around_center:
source["centerX"] = 127
source["centerY"] = 129
paint = _build(ot.Paint, source)
assert paint.Format == fmt
assert paint.Paint.Format == ot.PaintFormat.PaintGlyph
assert outputMapFn(paint.xSkewAngle) == 15
assert outputMapFn(paint.ySkewAngle) == 42
assert outputMapFn(paint.centerX) == 127
assert outputMapFn(paint.centerY) == 129
if around_center:
assert outputMapFn(paint.centerX) == 127
assert outputMapFn(paint.centerY) == 129
def test_buildPaintSkew():
assert not _is_var(ot.PaintFormat.PaintSkew)
assert not _is_around_center(ot.PaintFormat.PaintSkew)
checkBuildPaintSkew(ot.PaintFormat.PaintSkew)
def test_buildPaintVarSkew():
assert _is_var(ot.PaintFormat.PaintVarSkew)
assert not _is_around_center(ot.PaintFormat.PaintVarSkew)
checkBuildPaintSkew(ot.PaintFormat.PaintVarSkew)
def test_buildPaintSkewAroundCenter():
assert not _is_var(ot.PaintFormat.PaintSkewAroundCenter)
assert _is_around_center(ot.PaintFormat.PaintSkewAroundCenter)
checkBuildPaintSkew(ot.PaintFormat.PaintSkewAroundCenter)
def test_buildPaintVarSkewAroundCenter():
assert _is_var(ot.PaintFormat.PaintVarSkewAroundCenter)
assert _is_around_center(ot.PaintFormat.PaintVarSkewAroundCenter)
checkBuildPaintSkew(ot.PaintFormat.PaintVarSkewAroundCenter)
def test_buildColrV1():
colorGlyphs = {
"a": (
@ -1039,7 +1175,8 @@ def test_buildColrV1_more_than_255_paints():
assert baseGlyphs.BaseGlyphCount == len(colorGlyphs)
assert baseGlyphs.BaseGlyphPaintRecord[0].BaseGlyph == "a"
assert (
baseGlyphs.BaseGlyphPaintRecord[0].Paint.Format == ot.PaintFormat.PaintColrLayers
baseGlyphs.BaseGlyphPaintRecord[0].Paint.Format
== ot.PaintFormat.PaintColrLayers
)
assert baseGlyphs.BaseGlyphPaintRecord[0].Paint.FirstLayerIndex == 255
assert baseGlyphs.BaseGlyphPaintRecord[0].Paint.NumLayers == num_paints + 1 - 255

View File

@ -99,12 +99,8 @@ TEST_COLOR_GLYPHS = {
},
"xSkewAngle": (-11.0, 0),
"ySkewAngle": (5.0, 0),
"centerX": (253.0, 0),
"centerY": (254.0, 0),
},
"angle": 45.0,
"centerX": 255.0,
"centerY": 256.0,
},
"dx": (257.0, 0),
"dy": (258.0, 0),

View File

@ -1078,7 +1078,7 @@ def colrv1_path(tmp_path):
],
),
"uniE003": {
"Format": ot.PaintFormat.PaintRotate,
"Format": ot.PaintFormat.PaintRotateAroundCenter,
"Paint": {
"Format": ot.PaintFormat.PaintColrGlyph,
"Glyph": "uniE001",

View File

@ -50,7 +50,9 @@ def diff_binary_fragments(font_bytes, expected_fragments):
for expected_bytes, description in expected_fragments:
actual_bytes = font_bytes[pos : pos + len(expected_bytes)]
if actual_bytes != expected_bytes:
print(f'{description} (previous "{prev_desc}", actual_bytes: {"".join("%02x" % v for v in actual_bytes)} bytes: {str(font_bytes[pos:pos+16])}')
print(
f'{description} (previous "{prev_desc}", actual_bytes: {"".join("%02x" % v for v in actual_bytes)} bytes: {str(font_bytes[pos:pos+16])}'
)
errors += 1
pos += len(expected_bytes)
prev_desc = description
@ -141,7 +143,7 @@ COLR_V1_SAMPLE = (
(b"\x04", "BaseGlyphPaintRecord[0].Paint.NumLayers (4)"),
(b"\x00\x00\x00\x00", "BaseGlyphPaintRecord[0].Paint.FirstLayerIndex (0)"),
# BaseGlyphPaintRecord[1]
(b"\x14", "BaseGlyphPaintRecord[1].Paint.Format (20)"),
(b"\x20", "BaseGlyphPaintRecord[1].Paint.Format (32)"),
(b"\x00\x00<", "Offset to SourcePaint from beginning of PaintComposite (60)"),
(b"\x03", "BaseGlyphPaintRecord[1].Paint.CompositeMode [SRC_OVER] (3)"),
(b"\x00\x00\x08", "Offset to BackdropPaint from beginning of PaintComposite (8)"),
@ -256,19 +258,23 @@ COLR_V1_SAMPLE = (
(b"\x00\x00\x0c", "Offset to Paint subtable from beginning of PaintTranslate (12)"),
(b"\x01\x01\x00\x00", "dx (257)"),
(b"\x01\x02\x00\x00", "dy (258)"),
# PaintRotate
(b"\x10", "LayerList.Paint[3].Paint.Format (16)"),
(b"\x00\x00\x10", "Offset to Paint subtable from beginning of PaintRotate (16)"),
# PaintRotateAroundCenter
(b"\x1a", "LayerList.Paint[3].Paint.Format (26)"),
(
b"\x00\x00\x10",
"Offset to Paint subtable from beginning of PaintRotateAroundCenter (16)",
),
(b"\x00\x2d\x00\x00", "angle (45)"),
(b"\x00\xff\x00\x00", "centerX (255)"),
(b"\x01\x00\x00\x00", "centerY (256)"),
# PaintSkew
(b"\x12", "LayerList.Paint[3].Paint.Paint.Format (18)"),
(b"\x00\x00\x14", "Offset to Paint subtable from beginning of PaintSkew (20)"),
(b"\x1c", "LayerList.Paint[3].Paint.Paint.Format (28)"),
(
b"\x00\x00\x0c",
"Offset to Paint subtable from beginning of PaintSkew (12)",
),
(b"\xff\xf5\x00\x00", "xSkewAngle (-11)"),
(b"\x00\x05\x00\x00", "ySkewAngle (5)"),
(b"\x00\xfd\x00\x00", "centerX.value (253)"),
(b"\x00\xfe\x00\x00", "centerY.value (254)"),
# PaintGlyph
(b"\x0a", "LayerList.Paint[3].Paint.Paint.Paint.Format (10)"),
(b"\x00\x00\x06", "Offset to Paint subtable from beginning of PaintGlyph (6)"),
@ -317,7 +323,7 @@ COLR_V1_XML = [
" </BaseGlyphPaintRecord>",
' <BaseGlyphPaintRecord index="1">',
' <BaseGlyph value="glyph00014"/>',
' <Paint Format="20"><!-- PaintComposite -->',
' <Paint Format="32"><!-- PaintComposite -->',
' <SourcePaint Format="11"><!-- PaintColrGlyph -->',
' <Glyph value="glyph00010"/>',
" </SourcePaint>",
@ -455,8 +461,8 @@ COLR_V1_XML = [
' <Glyph value="glyph00013"/>',
" </Paint>",
' <Paint index="3" Format="14"><!-- PaintTranslate -->',
' <Paint Format="16"><!-- PaintRotate -->',
' <Paint Format="18"><!-- PaintSkew -->',
' <Paint Format="26"><!-- PaintRotateAroundCenter -->',
' <Paint Format="28"><!-- PaintSkew -->',
' <Paint Format="10"><!-- PaintGlyph -->',
' <Paint Format="2"><!-- PaintSolid -->',
" <Color>",
@ -468,8 +474,6 @@ COLR_V1_XML = [
" </Paint>",
' <xSkewAngle value="-11.0"/>',
' <ySkewAngle value="5.0"/>',
' <centerX value="253.0"/>',
' <centerY value="254.0"/>',
" </Paint>",
' <angle value="45.0"/>',
' <centerX value="255.0"/>',