Merge pull request #2118 from fonttools/colr_angles

Update to latest COLR v1 (PaintRotate, PaintSkew)
This commit is contained in:
Cosimo Lupo 2020-12-04 11:06:14 +00:00 committed by GitHub
commit 6e9bb9bb06
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 330 additions and 159 deletions

View File

@ -542,6 +542,38 @@ class LayerV1ListBuilder:
ot_paint.Paint = self.buildPaint(paint) ot_paint.Paint = self.buildPaint(paint)
return ot_paint return ot_paint
def buildPaintRotate(
self,
paint: _PaintInput,
angle: _ScalarInput,
centerX: _ScalarInput,
centerY: _ScalarInput,
) -> ot.Paint:
ot_paint = ot.Paint()
ot_paint.Format = int(ot.Paint.Format.PaintRotate)
ot_paint.Paint = self.buildPaint(paint)
ot_paint.angle = _to_variable_f16dot16_float(angle)
ot_paint.centerX = _to_variable_f16dot16_float(centerX)
ot_paint.centerY = _to_variable_f16dot16_float(centerY)
return ot_paint
def buildPaintSkew(
self,
paint: _PaintInput,
xSkewAngle: _ScalarInput,
ySkewAngle: _ScalarInput,
centerX: _ScalarInput,
centerY: _ScalarInput,
) -> ot.Paint:
ot_paint = ot.Paint()
ot_paint.Format = int(ot.Paint.Format.PaintSkew)
ot_paint.Paint = self.buildPaint(paint)
ot_paint.xSkewAngle = _to_variable_f16dot16_float(xSkewAngle)
ot_paint.ySkewAngle = _to_variable_f16dot16_float(ySkewAngle)
ot_paint.centerX = _to_variable_f16dot16_float(centerX)
ot_paint.centerY = _to_variable_f16dot16_float(centerY)
return ot_paint
def buildPaintComposite( def buildPaintComposite(
self, self,
mode: _CompositeInput, mode: _CompositeInput,

View File

@ -1664,6 +1664,23 @@ otData = [
]), ]),
('PaintFormat8', [ ('PaintFormat8', [
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 8'),
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintRotate table) to Paint subtable.'),
('VarFixed', 'angle', None, None, ''),
('VarFixed', 'centerX', None, None, ''),
('VarFixed', 'centerY', None, None, ''),
]),
('PaintFormat9', [
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 9'),
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintRotate table) to Paint subtable.'),
('VarFixed', 'xSkewAngle', None, None, ''),
('VarFixed', 'ySkewAngle', None, None, ''),
('VarFixed', 'centerX', None, None, ''),
('VarFixed', 'centerY', None, None, ''),
]),
('PaintFormat10', [
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 8'), ('uint8', 'PaintFormat', None, None, 'Format identifier-format = 8'),
('LOffset24To(Paint)', 'SourcePaint', None, None, 'Offset (from beginning of PaintComposite table) to source Paint subtable.'), ('LOffset24To(Paint)', 'SourcePaint', None, None, 'Offset (from beginning of PaintComposite table) to source Paint subtable.'),
('CompositeMode', 'CompositeMode', None, None, 'A CompositeMode enumeration value.'), ('CompositeMode', 'CompositeMode', None, None, 'A CompositeMode enumeration value.'),

View File

@ -1334,7 +1334,9 @@ class Paint(getFormatSwitchingBaseTableClass("uint8")):
PaintGlyph = 5 PaintGlyph = 5
PaintColrGlyph = 6 PaintColrGlyph = 6
PaintTransform = 7 PaintTransform = 7
PaintComposite = 8 PaintRotate = 8
PaintSkew = 9
PaintComposite = 10
def getFormatName(self): def getFormatName(self):
try: try:

View File

@ -544,7 +544,7 @@ def test_buildPaintComposite():
composite = layerBuilder.buildPaintComposite( composite = layerBuilder.buildPaintComposite(
mode=ot.CompositeMode.SRC_OVER, mode=ot.CompositeMode.SRC_OVER,
source={ source={
"format": 8, "format": 10,
"mode": "src_over", "mode": "src_over",
"source": {"format": 5, "glyph": "c", "paint": 2}, "source": {"format": 5, "glyph": "c", "paint": 2},
"backdrop": {"format": 5, "glyph": "b", "paint": 1}, "backdrop": {"format": 5, "glyph": "b", "paint": 1},
@ -574,6 +574,44 @@ def test_buildPaintComposite():
assert composite.BackdropPaint.Paint.Color.PaletteIndex == 0 assert composite.BackdropPaint.Paint.Color.PaletteIndex == 0
def test_buildPaintRotate():
layerBuilder = LayerV1ListBuilder()
paint = layerBuilder.buildPaintRotate(
paint=layerBuilder.buildPaintGlyph(
"a", layerBuilder.buildPaintSolid(paletteIndex=0, alpha=1.0)
),
angle=15,
centerX=127,
centerY=129,
)
assert paint.Format == ot.Paint.Format.PaintRotate
assert paint.Paint.Format == ot.Paint.Format.PaintGlyph
assert paint.angle.value == 15
assert paint.centerX.value == 127
assert paint.centerY.value == 129
def test_buildPaintRotate():
layerBuilder = LayerV1ListBuilder()
paint = layerBuilder.buildPaintSkew(
paint=layerBuilder.buildPaintGlyph(
"a", layerBuilder.buildPaintSolid(paletteIndex=0, alpha=1.0)
),
xSkewAngle=15,
ySkewAngle=42,
centerX=127,
centerY=129,
)
assert paint.Format == ot.Paint.Format.PaintSkew
assert paint.Paint.Format == ot.Paint.Format.PaintGlyph
assert paint.xSkewAngle.value == 15
assert paint.ySkewAngle.value == 42
assert paint.centerX.value == 127
assert paint.centerY.value == 129
def test_buildColrV1(): def test_buildColrV1():
colorGlyphs = { colorGlyphs = {
"a": [("b", 0), ("c", 1)], "a": [("b", 0), ("c", 1)],

View File

@ -2,26 +2,32 @@ from fontTools import ttLib
from fontTools.misc.testTools import getXML, parseXML from fontTools.misc.testTools import getXML, parseXML
from fontTools.ttLib.tables.C_O_L_R_ import table_C_O_L_R_ from fontTools.ttLib.tables.C_O_L_R_ import table_C_O_L_R_
import binascii
import pytest import pytest
COLR_V0_DATA = ( COLR_V0_SAMPLE = (
b"\x00\x00" # Version (0) (b"\x00\x00", "Version (0)"),
b"\x00\x01" # BaseGlyphRecordCount (1) (b"\x00\x01", "BaseGlyphRecordCount (1)"),
b"\x00\x00\x00\x0e" # Offset to BaseGlyphRecordArray from beginning of table (14) (
b"\x00\x00\x00\x14" # Offset to LayerRecordArray from beginning of table (20) b"\x00\x00\x00\x0e",
b"\x00\x03" # LayerRecordCount (3) "Offset to BaseGlyphRecordArray from beginning of table (14)",
b"\x00\x06" # BaseGlyphRecord[0].BaseGlyph (6) ),
b"\x00\x00" # BaseGlyphRecord[0].FirstLayerIndex (0) (b"\x00\x00\x00\x14", "Offset to LayerRecordArray from beginning of table (20)"),
b"\x00\x03" # BaseGlyphRecord[0].NumLayers (3) (b"\x00\x03", "LayerRecordCount (3)"),
b"\x00\x07" # LayerRecord[0].LayerGlyph (7) (b"\x00\x06", "BaseGlyphRecord[0].BaseGlyph (6)"),
b"\x00\x00" # LayerRecord[0].PaletteIndex (0) (b"\x00\x00", "BaseGlyphRecord[0].FirstLayerIndex (0)"),
b"\x00\x08" # LayerRecord[1].LayerGlyph (8) (b"\x00\x03", "BaseGlyphRecord[0].NumLayers (3)"),
b"\x00\x01" # LayerRecord[1].PaletteIndex (1) (b"\x00\x07", "LayerRecord[0].LayerGlyph (7)"),
b"\x00\t" # LayerRecord[2].LayerGlyph (9) (b"\x00\x00", "LayerRecord[0].PaletteIndex (0)"),
b"\x00\x02" # LayerRecord[3].PaletteIndex (2) (b"\x00\x08", "LayerRecord[1].LayerGlyph (8)"),
(b"\x00\x01", "LayerRecord[1].PaletteIndex (1)"),
(b"\x00\t", "LayerRecord[2].LayerGlyph (9)"),
(b"\x00\x02", "LayerRecord[3].PaletteIndex (2)"),
) )
COLR_V0_DATA = b"".join(t[0] for t in COLR_V0_SAMPLE)
COLR_V0_XML = [ COLR_V0_XML = [
'<version value="0"/>', '<version value="0"/>',
@ -37,6 +43,21 @@ def dump(table, ttFont=None):
print("\n".join(getXML(table.toXML, ttFont))) print("\n".join(getXML(table.toXML, ttFont)))
def diff_binary_fragments(font_bytes, expected_fragments):
pos = 0
prev_desc = ""
for expected_bytes, description in expected_fragments:
actual_bytes = font_bytes[pos : pos + len(expected_bytes)]
assert (
actual_bytes == expected_bytes
), f'{description} (previous "{prev_desc}", bytes: {str(font_bytes[pos:pos+16])}'
pos += len(expected_bytes)
prev_desc = description
assert pos == len(
font_bytes
), f"Leftover font bytes, used {pos} of {len(font_bytes)}"
@pytest.fixture @pytest.fixture
def font(): def font():
font = ttLib.TTFont() font = ttLib.TTFont()
@ -48,7 +69,7 @@ class COLR_V0_Test(object):
def test_decompile_and_compile(self, font): def test_decompile_and_compile(self, font):
colr = table_C_O_L_R_() colr = table_C_O_L_R_()
colr.decompile(COLR_V0_DATA, font) colr.decompile(COLR_V0_DATA, font)
assert colr.compile(font) == COLR_V0_DATA diff_binary_fragments(colr.compile(font), COLR_V0_SAMPLE)
def test_decompile_and_dump_xml(self, font): def test_decompile_and_dump_xml(self, font):
colr = table_C_O_L_R_() colr = table_C_O_L_R_()
@ -62,145 +83,177 @@ class COLR_V0_Test(object):
for name, attrs, content in parseXML(COLR_V0_XML): for name, attrs, content in parseXML(COLR_V0_XML):
colr.fromXML(name, attrs, content, font) colr.fromXML(name, attrs, content, font)
assert colr.compile(font) == COLR_V0_DATA diff_binary_fragments(colr.compile(font), COLR_V0_SAMPLE)
def test_round_trip_xml(self, font):
colr = table_C_O_L_R_()
for name, attrs, content in parseXML(COLR_V0_XML):
colr.fromXML(name, attrs, content, font)
compiled = colr.compile(font)
colr = table_C_O_L_R_()
colr.decompile(compiled, font)
assert getXML(colr.toXML, font) == COLR_V0_XML
COLR_V1_DATA = ( COLR_V1_SAMPLE = (
b"\x00\x01" # Version (1) (b"\x00\x01", "Version (1)"),
b"\x00\x01" # BaseGlyphRecordCount (1) (b"\x00\x01", "BaseGlyphRecordCount (1)"),
b"\x00\x00\x00\x1a" # Offset to BaseGlyphRecordArray from beginning of table (26) (
b"\x00\x00\x00 " # Offset to LayerRecordArray from beginning of table (32) b"\x00\x00\x00\x1a",
b"\x00\x03" # LayerRecordCount (3) "Offset to BaseGlyphRecordArray from beginning of table (26)",
b"\x00\x00\x00," # Offset to BaseGlyphV1List from beginning of table (44) ),
b"\x00\x00\x00\x81" # Offset to LayerV1List from beginning of table (129) (b"\x00\x00\x00 ", "Offset to LayerRecordArray from beginning of table (32)"),
b"\x00\x00\x00\x00" # Offset to VarStore (NULL) (b"\x00\x03", "LayerRecordCount (3)"),
b"\x00\x06" # BaseGlyphRecord[0].BaseGlyph (6) (b"\x00\x00\x00,", "Offset to BaseGlyphV1List from beginning of table (44)"),
b"\x00\x00" # BaseGlyphRecord[0].FirstLayerIndex (0) (b"\x00\x00\x00\x81", "Offset to LayerV1List from beginning of table (129)"),
b"\x00\x03" # BaseGlyphRecord[0].NumLayers (3) (b"\x00\x00\x00\x00", "Offset to VarStore (NULL)"),
b"\x00\x07" # LayerRecord[0].LayerGlyph (7) (b"\x00\x06", "BaseGlyphRecord[0].BaseGlyph (6)"),
b"\x00\x00" # LayerRecord[0].PaletteIndex (0) (b"\x00\x00", "BaseGlyphRecord[0].FirstLayerIndex (0)"),
b"\x00\x08" # LayerRecord[1].LayerGlyph (8) (b"\x00\x04", "BaseGlyphRecord[0].NumLayers (4)"),
b"\x00\x01" # LayerRecord[1].PaletteIndex (1) (b"\x00\x07", "LayerRecord[0].LayerGlyph (7)"),
b"\x00\t" # LayerRecord[2].LayerGlyph (9) (b"\x00\x00", "LayerRecord[0].PaletteIndex (0)"),
b"\x00\x02" # LayerRecord[2].PaletteIndex (2) (b"\x00\x08", "LayerRecord[1].LayerGlyph (8)"),
b"\x00\x00\x00\x02" # BaseGlyphV1List.BaseGlyphCount (2) (b"\x00\x01", "LayerRecord[1].PaletteIndex (1)"),
b"\x00\n" # BaseGlyphV1List.BaseGlyphV1Record[0].BaseGlyph (10) (b"\x00\t", "LayerRecord[2].LayerGlyph (9)"),
b"\x00\x00\x00\x10" # Offset to Paint table from beginning of BaseGlyphV1List (16) (b"\x00\x02", "LayerRecord[2].PaletteIndex (2)"),
b"\x00\x0e" # BaseGlyphV1List.BaseGlyphV1Record[1].BaseGlyph (14) (b"\x00\x00\x00\x02", "BaseGlyphV1List.BaseGlyphCount (2)"),
b"\x00\x00\x00\x16" # Offset to Paint table from beginning of BaseGlyphV1List (22) (b"\x00\n", "BaseGlyphV1List.BaseGlyphV1Record[0].BaseGlyph (10)"),
b"\x01" # BaseGlyphV1Record[0].Paint.Format (1) (
b"\x03" # BaseGlyphV1Record[0].Paint.NumLayers (3) b"\x00\x00\x00\x10",
b"\x00\x00\x00\x00" # BaseGlyphV1Record[0].Paint.FirstLayerIndex (0) "Offset to Paint table from beginning of BaseGlyphV1List (16)",
b"\x08" # BaseGlyphV1Record[1].Paint.Format (8) ),
b"\x00\x00<" # Offset to SourcePaint from beginning of PaintComposite (60) (b"\x00\x0e", "BaseGlyphV1List.BaseGlyphV1Record[1].BaseGlyph (14)"),
b"\x03" # BaseGlyphV1Record[1].Paint.CompositeMode [SRC_OVER] (3) (
b"\x00\x00\x08" # Offset to BackdropPaint from beginning of PaintComposite (8) b"\x00\x00\x00\x16",
b"\x07" # BaseGlyphV1Record[1].Paint.BackdropPaint.Format (7) "Offset to Paint table from beginning of BaseGlyphV1List (22)",
b"\x00\x004" # Offset to Paint from beginning of PaintTransform (52) ),
b"\x00\x01\x00\x00" # Affine2x3.xx.value (1.0) (b"\x01", "BaseGlyphV1Record[0].Paint.Format (1)"),
b"\x00\x00\x00\x00" (b"\x04", "BaseGlyphV1Record[0].Paint.NumLayers (4)"),
b"\x00\x00\x00\x00" # Affine2x3.xy.value (0.0) (b"\x00\x00\x00\x00", "BaseGlyphV1Record[0].Paint.FirstLayerIndex (0)"),
b"\x00\x00\x00\x00" (b"\x0A", "BaseGlyphV1Record[1].Paint.Format (10)"),
b"\x00\x00\x00\x00" # Affine2x3.yx.value (0.0) (b"\x00\x00<", "Offset to SourcePaint from beginning of PaintComposite (60)"),
b"\x00\x00\x00\x00" (b"\x03", "BaseGlyphV1Record[1].Paint.CompositeMode [SRC_OVER] (3)"),
b"\x00\x01\x00\x00" # Affine2x3.yy.value (1.0) (b"\x00\x00\x08", "Offset to BackdropPaint from beginning of PaintComposite (8)"),
b"\x00\x00\x00\x00" (b"\x07", "BaseGlyphV1Record[1].Paint.BackdropPaint.Format (7)"),
b"\x01,\x00\x00" # Affine2x3.dx.value (300.0) (b"\x00\x00\x34", "Offset to Paint from beginning of PaintTransform (52)"),
b"\x00\x00\x00\x00" (b"\x00\x01\x00\x00\x00\x00\x00\x00", "Affine2x3.xx.value (1.0)"),
b"\x00\x00\x00\x00" # Affine2x3.dy.value (0.0) (b"\x00\x00\x00\x00\x00\x00\x00\x00", "Affine2x3.xy.value (0.0)"),
b"\x00\x00\x00\x00" (b"\x00\x00\x00\x00\x00\x00\x00\x00", "Affine2x3.yx.value (0.0)"),
b"\x06" # BaseGlyphV1Record[1].Paint.SourcePaint.Format (6) (b"\x00\x01\x00\x00\x00\x00\x00\x00", "Affine2x3.yy.value (1.0)"),
b"\x00\n" # BaseGlyphV1Record[1].Paint.SourcePaint.Glyph (10) (b"\x01\x2c\x00\x00\x00\x00\x00\x00", "Affine2x3.dx.value (300.0)"),
b"\x00\x00\x00\x03" # LayerV1List.LayerCount (3) (b"\x00\x00\x00\x00\x00\x00\x00\x00", "Affine2x3.dy.value (0.0)"),
b"\x00\x00\x00\x10" # Offset to Paint table from beginning of LayerV1List (16) (b"\x06", "BaseGlyphV1Record[1].Paint.SourcePaint.Format (6)"),
b"\x00\x00\x00\x1f" # Offset to Paint table from beginning of LayerV1List (31) (b"\x00\n", "BaseGlyphV1Record[1].Paint.SourcePaint.Glyph (10)"),
b"\x00\x00\x00z" # Offset to Paint table from beginning of LayerV1List (122) (b"\x00\x00\x00\x04", "LayerV1List.LayerCount (4)"),
b"\x05" # LayerV1List.Paint[0].Format (5) (
b"\x00\x00\x06" # Offset to Paint subtable from beginning of PaintGlyph (6) b"\x00\x00\x00\x14",
b"\x00\x0b" # LayerV1List.Paint[0].Glyph (11) "First Offset to Paint table from beginning of LayerV1List (20)",
b"\x02" # LayerV1List.Paint[0].Paint.Format (2) ),
b"\x00\x02" # Paint.Color.PaletteIndex (2) (
b" \x00" # Paint.Color.Alpha.value (0.5) b"\x00\x00\x00\x1a",
b"\x00\x00\x00\x00" # Paint.Color.Alpha.varIdx (0) "Second Offset to Paint table from beginning of LayerV1List (26)",
b"\x05" # LayerV1List.Paint[1].Format (5) ),
b"\x00\x00\x06" # Offset to Paint subtable from beginning of PaintGlyph (6) (
b"\x00\x0c" # LayerV1List.Paint[1].Glyph (12) b"\x00\x00\x00u",
b"\x03" # LayerV1List.Paint[1].Paint.Format (3) "Third Offset to Paint table from beginning of LayerV1List (117)",
b"\x00\x00(" # Offset to ColorLine from beginning of PaintLinearGradient (40) ),
b"\x00\x01" # Paint.x0.value (1) (
b"\x00\x00\x00\x00" # Paint.x0.varIdx (0) b"\x00\x00\x00\xf6",
b"\x00\x02" # Paint.y0.value (2) "Fourth Offset to Paint table from beginning of LayerV1List (246)",
b"\x00\x00\x00\x00" # Paint.y0.varIdx (0) ),
b"\xff\xfd" # Paint.x1.value (-3) # PaintGlyph glyph00011
b"\x00\x00\x00\x00" # Paint.x1.varIdx (0) (b"\x05", "LayerV1List.Paint[0].Format (5)"),
b"\xff\xfc" # Paint.y1.value (-4) (b"\x00\x01\x28", "Offset24 to Paint subtable from beginning of PaintGlyph (296)"),
b"\x00\x00\x00\x00" # Paint.y1.varIdx (0) (b"\x00\x0b", "LayerV1List.Paint[0].Glyph (glyph00011)"),
b"\x00\x05" # Paint.x2.value (5) # PaintGlyph glyph00012
b"\x00\x00\x00\x00" # Paint.x2.varIdx (0) (b"\x05", "LayerV1List.Paint[1].Format (5)"),
b"\x00\x06" # Paint.y2.value (6) (b"\x00\x00\x06", "Offset to Paint subtable from beginning of PaintGlyph (6)"),
b"\x00\x00\x00\x00" # Paint.y2.varIdx (0) (b"\x00\x0c", "LayerV1List.Paint[1].Glyph (glyph00012)"),
b"\x01" # ColorLine.Extend (1 or "repeat") (b"\x03", "LayerV1List.Paint[1].Paint.Format (3)"),
b"\x00\x03" # ColorLine.StopCount (3) (b"\x00\x00(", "Offset to ColorLine from beginning of PaintLinearGradient (40)"),
b"\x00\x00" # ColorLine.ColorStop[0].StopOffset.value (0.0) (b"\x00\x01", "Paint.x0.value (1)"),
b"\x00\x00\x00\x00" # ColorLine.ColorStop[0].StopOffset.varIdx (0) (b"\x00\x00\x00\x00", "Paint.x0.varIdx (0)"),
b"\x00\x03" # ColorLine.ColorStop[0].Color.PaletteIndex (3) (b"\x00\x02", "Paint.y0.value (2)"),
b"@\x00" # ColorLine.ColorStop[0].Color.Alpha.value (1.0) (b"\x00\x00\x00\x00", "Paint.y0.varIdx (0)"),
b"\x00\x00\x00\x00" # ColorLine.ColorStop[0].Color.Alpha.varIdx (0) (b"\xff\xfd", "Paint.x1.value (-3)"),
b" \x00" # ColorLine.ColorStop[1].StopOffset.value (0.5) (b"\x00\x00\x00\x00", "Paint.x1.varIdx (0)"),
b"\x00\x00\x00\x00" # ColorLine.ColorStop[1].StopOffset.varIdx (0) (b"\xff\xfc", "Paint.y1.value (-4)"),
b"\x00\x04" # ColorLine.ColorStop[1].Color.PaletteIndex (4) (b"\x00\x00\x00\x00", "Paint.y1.varIdx (0)"),
b"@\x00" # ColorLine.ColorStop[1].Color.Alpha.value (1.0) (b"\x00\x05", "Paint.x2.value (5)"),
b"\x00\x00\x00\x00" # ColorLine.ColorStop[1].Color.Alpha.varIdx (0) (b"\x00\x00\x00\x00", "Paint.x2.varIdx (0)"),
b"@\x00" # ColorLine.ColorStop[2].StopOffset.value (1.0) (b"\x00\x06", "Paint.y2.value (6)"),
b"\x00\x00\x00\x00" # ColorLine.ColorStop[2].StopOffset.varIdx (0) (b"\x00\x00\x00\x00", "Paint.y2.varIdx (0)"),
b"\x00\x05" # ColorLine.ColorStop[2].Color.PaletteIndex (5) (b"\x01", "ColorLine.Extend (1; repeat)"),
b"@\x00" # ColorLine.ColorStop[2].Color.Alpha.value (1.0) (b"\x00\x03", "ColorLine.StopCount (3)"),
b"\x00\x00\x00\x00" # ColorLine.ColorStop[2].Color.Alpha.varIdx (0) (b"\x00\x00", "ColorLine.ColorStop[0].StopOffset.value (0.0)"),
b"\x05" # LayerV1List.Paint[2].Format (5) (b"\x00\x00\x00\x00", "ColorLine.ColorStop[0].StopOffset.varIdx (0)"),
b"\x00\x00\x06" # Offset to Paint subtable from beginning of PaintGlyph (6) (b"\x00\x03", "ColorLine.ColorStop[0].Color.PaletteIndex (3)"),
b"\x00\r" # LayerV1List.Paint[2].Glyph (13) (b"@\x00", "ColorLine.ColorStop[0].Color.Alpha.value (1.0)"),
b"\x07" # LayerV1List.Paint[2].Paint.Format (5) (b"\x00\x00\x00\x00", "ColorLine.ColorStop[0].Color.Alpha.varIdx (0)"),
b"\x00\x004" # Offset to Paint subtable from beginning of PaintTransform (52) (b" \x00", "ColorLine.ColorStop[1].StopOffset.value (0.5)"),
b"\xff\xf3\x00\x00" # Affine2x3.xx.value (-13) (b"\x00\x00\x00\x00", "ColorLine.ColorStop[1].StopOffset.varIdx (0)"),
b"\x00\x00\x00\x00" (b"\x00\x04", "ColorLine.ColorStop[1].Color.PaletteIndex (4)"),
b"\x00\x0e\x00\x00" # Affine2x3.xy.value (14) (b"@\x00", "ColorLine.ColorStop[1].Color.Alpha.value (1.0)"),
b"\x00\x00\x00\x00" (b"\x00\x00\x00\x00", "ColorLine.ColorStop[1].Color.Alpha.varIdx (0)"),
b"\x00\x0f\x00\x00" # Affine2x3.yx.value (15) (b"@\x00", "ColorLine.ColorStop[2].StopOffset.value (1.0)"),
b"\x00\x00\x00\x00" (b"\x00\x00\x00\x00", "ColorLine.ColorStop[2].StopOffset.varIdx (0)"),
b"\xff\xef\x00\x00" # Affine2x3.yy.value (-17) (b"\x00\x05", "ColorLine.ColorStop[2].Color.PaletteIndex (5)"),
b"\x00\x00\x00\x00" (b"@\x00", "ColorLine.ColorStop[2].Color.Alpha.value (1.0)"),
b"\x00\x12\x00\x00" # Affine2x3.yy.value (18) (b"\x00\x00\x00\x00", "ColorLine.ColorStop[2].Color.Alpha.varIdx (0)"),
b"\x00\x00\x00\x00" # PaintGlyph glyph00013
b"\x00\x13\x00\x00" # Affine2x3.yy.value (19) (b"\x05", "LayerV1List.Paint[2].Format (5)"),
b"\x00\x00\x00\x00" (b"\x00\x00\x06", "Offset to Paint subtable from beginning of PaintGlyph (6)"),
b"\x04" # LayerV1List.Paint[2].Paint.Paint.Format (4) (b"\x00\r", "LayerV1List.Paint[2].Glyph (13)"),
b"\x00\x00(" # Offset to ColorLine from beginning of PaintRadialGradient (40) (b"\x07", "LayerV1List.Paint[2].Paint.Format (5)"),
b"\x00\x07" # Paint.x0.value (7) (b"\x00\x00\x34", "Offset to Paint subtable from beginning of PaintTransform (52)"),
b"\x00\x00\x00\x00" (b"\xff\xf3\x00\x00\x00\x00\x00\x00", "Affine2x3.xx.value (-13)"),
b"\x00\x08" # Paint.y0.value (8) (b"\x00\x0e\x00\x00\x00\x00\x00\x00", "Affine2x3.xy.value (14)"),
b"\x00\x00\x00\x00" (b"\x00\x0f\x00\x00\x00\x00\x00\x00", "Affine2x3.yx.value (15)"),
b"\x00\t" # Paint.r0.value (9) (b"\xff\xef\x00\x00\x00\x00\x00\x00", "Affine2x3.yy.value (-17)"),
b"\x00\x00\x00\x00" (b"\x00\x12\x00\x00\x00\x00\x00\x00", "Affine2x3.yy.value (18)"),
b"\x00\n" # Paint.x1.value (10) (b"\x00\x13\x00\x00\x00\x00\x00\x00", "Affine2x3.yy.value (19)"),
b"\x00\x00\x00\x00" (b"\x04", "LayerV1List.Paint[2].Paint.Paint.Format (4)"),
b"\x00\x0b" # Paint.y1.value (11) (b"\x00\x00(", "Offset to ColorLine from beginning of PaintRadialGradient (40)"),
b"\x00\x00\x00\x00" (b"\x00\x07\x00\x00\x00\x00", "Paint.x0.value (7)"),
b"\x00\x0c" # Paint.r1.value (12) (b"\x00\x08\x00\x00\x00\x00", "Paint.y0.value (8)"),
b"\x00\x00\x00\x00" (b"\x00\t\x00\x00\x00\x00", "Paint.r0.value (9)"),
b"\x00" # ColorLine.Extend (0 or "pad") (b"\x00\n\x00\x00\x00\x00", "Paint.x1.value (10)"),
b"\x00\x02" # ColorLine.StopCount (2) (b"\x00\x0b\x00\x00\x00\x00", "Paint.y1.value (11)"),
b"\x00\x00" # ColorLine.ColorStop[0].StopOffset.value (0.0) (b"\x00\x0c\x00\x00\x00\x00", "Paint.r1.value (12)"),
b"\x00\x00\x00\x00" (b"\x00", "ColorLine.Extend (0; pad)"),
b"\x00\x06" # ColorLine.ColorStop[0].Color.PaletteIndex (6) (b"\x00\x02", "ColorLine.StopCount (2)"),
b"@\x00" # ColorLine.ColorStop[0].Color.Alpha.value (1.0) (b"\x00\x00\x00\x00\x00\x00", "ColorLine.ColorStop[0].StopOffset.value (0.0)"),
b"\x00\x00\x00\x00" (b"\x00\x06", "ColorLine.ColorStop[0].Color.PaletteIndex (6)"),
b"@\x00" # ColorLine.ColorStop[1].StopOffset.value (1.0) (b"@\x00\x00\x00\x00\x00", "ColorLine.ColorStop[0].Color.Alpha.value (1.0)"),
b"\x00\x00\x00\x00" (b"@\x00\x00\x00\x00\x00", "ColorLine.ColorStop[1].StopOffset.value (1.0)"),
b"\x00\x07" # ColorLine.ColorStop[1].Color.PaletteIndex (7) (b"\x00\x07", "ColorLine.ColorStop[1].Color.PaletteIndex (7)"),
b"\x19\x9a" # ColorLine.ColorStop[1].Color.Alpha.value (0.4) (b"\x19\x9a\x00\x00\x00\x00", "ColorLine.ColorStop[1].Color.Alpha.value (0.4)"),
b"\x00\x00\x00\x00" # PaintRotate
(b"\x08", "LayerV1List.Paint[3].Format (8)"),
(b"\x00\x00\x1c", "Offset to Paint subtable from beginning of PaintRotate (28)"),
(b"\x00\x2d\x00\x00\x00\x00\x00\x00", "angle.value (45)"),
(b"\x00\xff\x00\x00\x00\x00\x00\x00", "centerX.value (255)"),
(b"\x01\x00\x00\x00\x00\x00\x00\x00", "centerY.value (256)"),
# PaintSkew
(b"\x09", "LayerV1List.Paint[3].Format (9)"),
(b"\x00\x00\x24", "Offset to Paint subtable from beginning of PaintSkew (36)"),
(b"\xff\xf5\x00\x00\x00\x00\x00\x00", "xSkewAngle (-11)"),
(b"\x00\x05\x00\x00\x00\x00\x00\x00", "ySkewAngle (5)"),
(b"\x00\xfd\x00\x00\x00\x00\x00\x00", "centerX.value (253)"),
(b"\x00\xfe\x00\x00\x00\x00\x00\x00", "centerY.value (254)"),
# PaintGlyph
(b"\x05", "LayerV1List.Paint[2].Format (5)"),
(b"\x00\x00\x06", "Offset to Paint subtable from beginning of PaintGlyph (6)"),
(b"\x00\x0b", "LayerV1List.Paint[2].Glyph (11)"),
# PaintSolid
(b"\x02", "LayerV1List.Paint[0].Paint.Format (2)"),
(b"\x00\x02", "Paint.Color.PaletteIndex (2)"),
(b" \x00", "Paint.Color.Alpha.value (0.5)"),
(b"\x00\x00\x00\x00", "Paint.Color.Alpha.varIdx (0)"),
) )
COLR_V1_DATA = b"".join(t[0] for t in COLR_V1_SAMPLE)
COLR_V1_XML = [ COLR_V1_XML = [
'<Version value="1"/>', '<Version value="1"/>',
@ -209,7 +262,7 @@ COLR_V1_XML = [
' <BaseGlyphRecord index="0">', ' <BaseGlyphRecord index="0">',
' <BaseGlyph value="glyph00006"/>', ' <BaseGlyph value="glyph00006"/>',
' <FirstLayerIndex value="0"/>', ' <FirstLayerIndex value="0"/>',
' <NumLayers value="3"/>', ' <NumLayers value="4"/>',
" </BaseGlyphRecord>", " </BaseGlyphRecord>",
"</BaseGlyphRecordArray>", "</BaseGlyphRecordArray>",
"<LayerRecordArray>", "<LayerRecordArray>",
@ -232,13 +285,13 @@ COLR_V1_XML = [
' <BaseGlyphV1Record index="0">', ' <BaseGlyphV1Record index="0">',
' <BaseGlyph value="glyph00010"/>', ' <BaseGlyph value="glyph00010"/>',
' <Paint Format="1"><!-- PaintColrLayers -->', ' <Paint Format="1"><!-- PaintColrLayers -->',
' <NumLayers value="3"/>', ' <NumLayers value="4"/>',
' <FirstLayerIndex value="0"/>', ' <FirstLayerIndex value="0"/>',
" </Paint>", " </Paint>",
" </BaseGlyphV1Record>", " </BaseGlyphV1Record>",
' <BaseGlyphV1Record index="1">', ' <BaseGlyphV1Record index="1">',
' <BaseGlyph value="glyph00014"/>', ' <BaseGlyph value="glyph00014"/>',
' <Paint Format="8"><!-- PaintComposite -->', ' <Paint Format="10"><!-- PaintComposite -->',
' <SourcePaint Format="6"><!-- PaintColrGlyph -->', ' <SourcePaint Format="6"><!-- PaintColrGlyph -->',
' <Glyph value="glyph00010"/>', ' <Glyph value="glyph00010"/>',
" </SourcePaint>", " </SourcePaint>",
@ -260,7 +313,7 @@ COLR_V1_XML = [
" </BaseGlyphV1Record>", " </BaseGlyphV1Record>",
"</BaseGlyphV1List>", "</BaseGlyphV1List>",
"<LayerV1List>", "<LayerV1List>",
" <!-- LayerCount=3 -->", " <!-- LayerCount=4 -->",
' <Paint index="0" Format="5"><!-- PaintGlyph -->', ' <Paint index="0" Format="5"><!-- PaintGlyph -->',
' <Paint Format="2"><!-- PaintSolid -->', ' <Paint Format="2"><!-- PaintSolid -->',
" <Color>", " <Color>",
@ -345,6 +398,26 @@ COLR_V1_XML = [
" </Paint>", " </Paint>",
' <Glyph value="glyph00013"/>', ' <Glyph value="glyph00013"/>',
" </Paint>", " </Paint>",
' <Paint index="3" Format="8"><!-- PaintRotate -->',
' <Paint Format="9"><!-- PaintSkew -->',
' <Paint Format="5"><!-- PaintGlyph -->',
' <Paint Format="2"><!-- PaintSolid -->',
" <Color>",
' <PaletteIndex value="2"/>',
' <Alpha value="0.5"/>',
" </Color>",
" </Paint>",
' <Glyph value="glyph00011"/>',
" </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"/>',
' <centerY value="256.0"/>',
" </Paint>",
"</LayerV1List>", "</LayerV1List>",
] ]
@ -353,7 +426,7 @@ class COLR_V1_Test(object):
def test_decompile_and_compile(self, font): def test_decompile_and_compile(self, font):
colr = table_C_O_L_R_() colr = table_C_O_L_R_()
colr.decompile(COLR_V1_DATA, font) colr.decompile(COLR_V1_DATA, font)
assert colr.compile(font) == COLR_V1_DATA diff_binary_fragments(colr.compile(font), COLR_V1_SAMPLE)
def test_decompile_and_dump_xml(self, font): def test_decompile_and_dump_xml(self, font):
colr = table_C_O_L_R_() colr = table_C_O_L_R_()
@ -366,5 +439,14 @@ class COLR_V1_Test(object):
colr = table_C_O_L_R_() colr = table_C_O_L_R_()
for name, attrs, content in parseXML(COLR_V1_XML): for name, attrs, content in parseXML(COLR_V1_XML):
colr.fromXML(name, attrs, content, font) colr.fromXML(name, attrs, content, font)
diff_binary_fragments(colr.compile(font), COLR_V1_SAMPLE)
assert colr.compile(font) == COLR_V1_DATA def test_round_trip_xml(self, font):
colr = table_C_O_L_R_()
for name, attrs, content in parseXML(COLR_V1_XML):
colr.fromXML(name, attrs, content, font)
compiled = colr.compile(font)
colr = table_C_O_L_R_()
colr.decompile(compiled, font)
assert getXML(colr.toXML, font) == COLR_V1_XML