diff --git a/Lib/fontTools/colorLib/builder.py b/Lib/fontTools/colorLib/builder.py
index 5e7d8c6eb..d5084f456 100644
--- a/Lib/fontTools/colorLib/builder.py
+++ b/Lib/fontTools/colorLib/builder.py
@@ -542,6 +542,38 @@ class LayerV1ListBuilder:
ot_paint.Paint = self.buildPaint(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(
self,
mode: _CompositeInput,
diff --git a/Lib/fontTools/ttLib/tables/otData.py b/Lib/fontTools/ttLib/tables/otData.py
index f260a542a..776cf75ba 100755
--- a/Lib/fontTools/ttLib/tables/otData.py
+++ b/Lib/fontTools/ttLib/tables/otData.py
@@ -1664,6 +1664,23 @@ otData = [
]),
('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'),
('LOffset24To(Paint)', 'SourcePaint', None, None, 'Offset (from beginning of PaintComposite table) to source Paint subtable.'),
('CompositeMode', 'CompositeMode', None, None, 'A CompositeMode enumeration value.'),
diff --git a/Lib/fontTools/ttLib/tables/otTables.py b/Lib/fontTools/ttLib/tables/otTables.py
index 7a04d5aa1..c4208a55f 100644
--- a/Lib/fontTools/ttLib/tables/otTables.py
+++ b/Lib/fontTools/ttLib/tables/otTables.py
@@ -1334,7 +1334,9 @@ class Paint(getFormatSwitchingBaseTableClass("uint8")):
PaintGlyph = 5
PaintColrGlyph = 6
PaintTransform = 7
- PaintComposite = 8
+ PaintRotate = 8
+ PaintSkew = 9
+ PaintComposite = 10
def getFormatName(self):
try:
diff --git a/Tests/colorLib/builder_test.py b/Tests/colorLib/builder_test.py
index 86b5f9e92..152e16e08 100644
--- a/Tests/colorLib/builder_test.py
+++ b/Tests/colorLib/builder_test.py
@@ -544,7 +544,7 @@ def test_buildPaintComposite():
composite = layerBuilder.buildPaintComposite(
mode=ot.CompositeMode.SRC_OVER,
source={
- "format": 8,
+ "format": 10,
"mode": "src_over",
"source": {"format": 5, "glyph": "c", "paint": 2},
"backdrop": {"format": 5, "glyph": "b", "paint": 1},
@@ -574,6 +574,44 @@ def test_buildPaintComposite():
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():
colorGlyphs = {
"a": [("b", 0), ("c", 1)],
diff --git a/Tests/ttLib/tables/C_O_L_R_test.py b/Tests/ttLib/tables/C_O_L_R_test.py
index 0a1d9df9d..76e9e61a1 100644
--- a/Tests/ttLib/tables/C_O_L_R_test.py
+++ b/Tests/ttLib/tables/C_O_L_R_test.py
@@ -2,26 +2,32 @@ from fontTools import ttLib
from fontTools.misc.testTools import getXML, parseXML
from fontTools.ttLib.tables.C_O_L_R_ import table_C_O_L_R_
+import binascii
import pytest
-COLR_V0_DATA = (
- b"\x00\x00" # Version (0)
- 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\x03" # LayerRecordCount (3)
- b"\x00\x06" # BaseGlyphRecord[0].BaseGlyph (6)
- b"\x00\x00" # BaseGlyphRecord[0].FirstLayerIndex (0)
- b"\x00\x03" # BaseGlyphRecord[0].NumLayers (3)
- b"\x00\x07" # LayerRecord[0].LayerGlyph (7)
- b"\x00\x00" # LayerRecord[0].PaletteIndex (0)
- 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_SAMPLE = (
+ (b"\x00\x00", "Version (0)"),
+ (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\x03", "LayerRecordCount (3)"),
+ (b"\x00\x06", "BaseGlyphRecord[0].BaseGlyph (6)"),
+ (b"\x00\x00", "BaseGlyphRecord[0].FirstLayerIndex (0)"),
+ (b"\x00\x03", "BaseGlyphRecord[0].NumLayers (3)"),
+ (b"\x00\x07", "LayerRecord[0].LayerGlyph (7)"),
+ (b"\x00\x00", "LayerRecord[0].PaletteIndex (0)"),
+ (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 = [
'',
@@ -37,6 +43,21 @@ def dump(table, ttFont=None):
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
def font():
font = ttLib.TTFont()
@@ -48,7 +69,7 @@ class COLR_V0_Test(object):
def test_decompile_and_compile(self, font):
colr = table_C_O_L_R_()
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):
colr = table_C_O_L_R_()
@@ -62,145 +83,177 @@ class COLR_V0_Test(object):
for name, attrs, content in parseXML(COLR_V0_XML):
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 = (
- b"\x00\x01" # Version (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\x03" # LayerRecordCount (3)
- 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\x00" # Offset to VarStore (NULL)
- b"\x00\x06" # BaseGlyphRecord[0].BaseGlyph (6)
- b"\x00\x00" # BaseGlyphRecord[0].FirstLayerIndex (0)
- b"\x00\x03" # BaseGlyphRecord[0].NumLayers (3)
- b"\x00\x07" # LayerRecord[0].LayerGlyph (7)
- b"\x00\x00" # LayerRecord[0].PaletteIndex (0)
- 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[2].PaletteIndex (2)
- b"\x00\x00\x00\x02" # BaseGlyphV1List.BaseGlyphCount (2)
- b"\x00\n" # BaseGlyphV1List.BaseGlyphV1Record[0].BaseGlyph (10)
- b"\x00\x00\x00\x10" # Offset to Paint table from beginning of BaseGlyphV1List (16)
- b"\x00\x0e" # BaseGlyphV1List.BaseGlyphV1Record[1].BaseGlyph (14)
- b"\x00\x00\x00\x16" # Offset to Paint table from beginning of BaseGlyphV1List (22)
- b"\x01" # BaseGlyphV1Record[0].Paint.Format (1)
- b"\x03" # BaseGlyphV1Record[0].Paint.NumLayers (3)
- b"\x00\x00\x00\x00" # BaseGlyphV1Record[0].Paint.FirstLayerIndex (0)
- b"\x08" # BaseGlyphV1Record[1].Paint.Format (8)
- b"\x00\x00<" # Offset to SourcePaint from beginning of PaintComposite (60)
- b"\x03" # BaseGlyphV1Record[1].Paint.CompositeMode [SRC_OVER] (3)
- b"\x00\x00\x08" # Offset to BackdropPaint from beginning of PaintComposite (8)
- b"\x07" # BaseGlyphV1Record[1].Paint.BackdropPaint.Format (7)
- b"\x00\x004" # Offset to Paint from beginning of PaintTransform (52)
- b"\x00\x01\x00\x00" # Affine2x3.xx.value (1.0)
- b"\x00\x00\x00\x00"
- b"\x00\x00\x00\x00" # Affine2x3.xy.value (0.0)
- b"\x00\x00\x00\x00"
- b"\x00\x00\x00\x00" # Affine2x3.yx.value (0.0)
- b"\x00\x00\x00\x00"
- b"\x00\x01\x00\x00" # Affine2x3.yy.value (1.0)
- b"\x00\x00\x00\x00"
- b"\x01,\x00\x00" # Affine2x3.dx.value (300.0)
- b"\x00\x00\x00\x00"
- b"\x00\x00\x00\x00" # Affine2x3.dy.value (0.0)
- b"\x00\x00\x00\x00"
- b"\x06" # BaseGlyphV1Record[1].Paint.SourcePaint.Format (6)
- b"\x00\n" # BaseGlyphV1Record[1].Paint.SourcePaint.Glyph (10)
- b"\x00\x00\x00\x03" # LayerV1List.LayerCount (3)
- b"\x00\x00\x00\x10" # Offset to Paint table from beginning of LayerV1List (16)
- b"\x00\x00\x00\x1f" # Offset to Paint table from beginning of LayerV1List (31)
- b"\x00\x00\x00z" # Offset to Paint table from beginning of LayerV1List (122)
- b"\x05" # LayerV1List.Paint[0].Format (5)
- b"\x00\x00\x06" # Offset to Paint subtable from beginning of PaintGlyph (6)
- b"\x00\x0b" # LayerV1List.Paint[0].Glyph (11)
- 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)
- 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"\x03" # LayerV1List.Paint[1].Paint.Format (3)
- 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\x02" # Paint.y0.value (2)
- b"\x00\x00\x00\x00" # Paint.y0.varIdx (0)
- b"\xff\xfd" # Paint.x1.value (-3)
- b"\x00\x00\x00\x00" # Paint.x1.varIdx (0)
- b"\xff\xfc" # Paint.y1.value (-4)
- b"\x00\x00\x00\x00" # Paint.y1.varIdx (0)
- b"\x00\x05" # Paint.x2.value (5)
- b"\x00\x00\x00\x00" # Paint.x2.varIdx (0)
- b"\x00\x06" # Paint.y2.value (6)
- b"\x00\x00\x00\x00" # Paint.y2.varIdx (0)
- b"\x01" # ColorLine.Extend (1 or "repeat")
- b"\x00\x03" # ColorLine.StopCount (3)
- b"\x00\x00" # ColorLine.ColorStop[0].StopOffset.value (0.0)
- b"\x00\x00\x00\x00" # ColorLine.ColorStop[0].StopOffset.varIdx (0)
- b"\x00\x03" # ColorLine.ColorStop[0].Color.PaletteIndex (3)
- b"@\x00" # ColorLine.ColorStop[0].Color.Alpha.value (1.0)
- b"\x00\x00\x00\x00" # ColorLine.ColorStop[0].Color.Alpha.varIdx (0)
- b" \x00" # ColorLine.ColorStop[1].StopOffset.value (0.5)
- b"\x00\x00\x00\x00" # ColorLine.ColorStop[1].StopOffset.varIdx (0)
- b"\x00\x04" # ColorLine.ColorStop[1].Color.PaletteIndex (4)
- b"@\x00" # ColorLine.ColorStop[1].Color.Alpha.value (1.0)
- b"\x00\x00\x00\x00" # ColorLine.ColorStop[1].Color.Alpha.varIdx (0)
- b"@\x00" # ColorLine.ColorStop[2].StopOffset.value (1.0)
- b"\x00\x00\x00\x00" # ColorLine.ColorStop[2].StopOffset.varIdx (0)
- b"\x00\x05" # ColorLine.ColorStop[2].Color.PaletteIndex (5)
- b"@\x00" # ColorLine.ColorStop[2].Color.Alpha.value (1.0)
- b"\x00\x00\x00\x00" # ColorLine.ColorStop[2].Color.Alpha.varIdx (0)
- b"\x05" # LayerV1List.Paint[2].Format (5)
- b"\x00\x00\x06" # Offset to Paint subtable from beginning of PaintGlyph (6)
- b"\x00\r" # LayerV1List.Paint[2].Glyph (13)
- b"\x07" # LayerV1List.Paint[2].Paint.Format (5)
- b"\x00\x004" # Offset to Paint subtable from beginning of PaintTransform (52)
- b"\xff\xf3\x00\x00" # Affine2x3.xx.value (-13)
- b"\x00\x00\x00\x00"
- b"\x00\x0e\x00\x00" # Affine2x3.xy.value (14)
- b"\x00\x00\x00\x00"
- b"\x00\x0f\x00\x00" # Affine2x3.yx.value (15)
- b"\x00\x00\x00\x00"
- b"\xff\xef\x00\x00" # Affine2x3.yy.value (-17)
- b"\x00\x00\x00\x00"
- b"\x00\x12\x00\x00" # Affine2x3.yy.value (18)
- b"\x00\x00\x00\x00"
- b"\x00\x13\x00\x00" # Affine2x3.yy.value (19)
- b"\x00\x00\x00\x00"
- b"\x04" # LayerV1List.Paint[2].Paint.Paint.Format (4)
- b"\x00\x00(" # Offset to ColorLine from beginning of PaintRadialGradient (40)
- b"\x00\x07" # Paint.x0.value (7)
- b"\x00\x00\x00\x00"
- b"\x00\x08" # Paint.y0.value (8)
- b"\x00\x00\x00\x00"
- b"\x00\t" # Paint.r0.value (9)
- b"\x00\x00\x00\x00"
- b"\x00\n" # Paint.x1.value (10)
- b"\x00\x00\x00\x00"
- b"\x00\x0b" # Paint.y1.value (11)
- b"\x00\x00\x00\x00"
- b"\x00\x0c" # Paint.r1.value (12)
- b"\x00\x00\x00\x00"
- b"\x00" # ColorLine.Extend (0 or "pad")
- b"\x00\x02" # ColorLine.StopCount (2)
- b"\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[0].Color.Alpha.value (1.0)
- b"\x00\x00\x00\x00"
- b"@\x00" # ColorLine.ColorStop[1].StopOffset.value (1.0)
- b"\x00\x00\x00\x00"
- b"\x00\x07" # ColorLine.ColorStop[1].Color.PaletteIndex (7)
- b"\x19\x9a" # ColorLine.ColorStop[1].Color.Alpha.value (0.4)
- b"\x00\x00\x00\x00"
+COLR_V1_SAMPLE = (
+ (b"\x00\x01", "Version (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\x03", "LayerRecordCount (3)"),
+ (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\x00", "Offset to VarStore (NULL)"),
+ (b"\x00\x06", "BaseGlyphRecord[0].BaseGlyph (6)"),
+ (b"\x00\x00", "BaseGlyphRecord[0].FirstLayerIndex (0)"),
+ (b"\x00\x04", "BaseGlyphRecord[0].NumLayers (4)"),
+ (b"\x00\x07", "LayerRecord[0].LayerGlyph (7)"),
+ (b"\x00\x00", "LayerRecord[0].PaletteIndex (0)"),
+ (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[2].PaletteIndex (2)"),
+ (b"\x00\x00\x00\x02", "BaseGlyphV1List.BaseGlyphCount (2)"),
+ (b"\x00\n", "BaseGlyphV1List.BaseGlyphV1Record[0].BaseGlyph (10)"),
+ (
+ b"\x00\x00\x00\x10",
+ "Offset to Paint table from beginning of BaseGlyphV1List (16)",
+ ),
+ (b"\x00\x0e", "BaseGlyphV1List.BaseGlyphV1Record[1].BaseGlyph (14)"),
+ (
+ b"\x00\x00\x00\x16",
+ "Offset to Paint table from beginning of BaseGlyphV1List (22)",
+ ),
+ (b"\x01", "BaseGlyphV1Record[0].Paint.Format (1)"),
+ (b"\x04", "BaseGlyphV1Record[0].Paint.NumLayers (4)"),
+ (b"\x00\x00\x00\x00", "BaseGlyphV1Record[0].Paint.FirstLayerIndex (0)"),
+ (b"\x0A", "BaseGlyphV1Record[1].Paint.Format (10)"),
+ (b"\x00\x00<", "Offset to SourcePaint from beginning of PaintComposite (60)"),
+ (b"\x03", "BaseGlyphV1Record[1].Paint.CompositeMode [SRC_OVER] (3)"),
+ (b"\x00\x00\x08", "Offset to BackdropPaint from beginning of PaintComposite (8)"),
+ (b"\x07", "BaseGlyphV1Record[1].Paint.BackdropPaint.Format (7)"),
+ (b"\x00\x00\x34", "Offset to Paint from beginning of PaintTransform (52)"),
+ (b"\x00\x01\x00\x00\x00\x00\x00\x00", "Affine2x3.xx.value (1.0)"),
+ (b"\x00\x00\x00\x00\x00\x00\x00\x00", "Affine2x3.xy.value (0.0)"),
+ (b"\x00\x00\x00\x00\x00\x00\x00\x00", "Affine2x3.yx.value (0.0)"),
+ (b"\x00\x01\x00\x00\x00\x00\x00\x00", "Affine2x3.yy.value (1.0)"),
+ (b"\x01\x2c\x00\x00\x00\x00\x00\x00", "Affine2x3.dx.value (300.0)"),
+ (b"\x00\x00\x00\x00\x00\x00\x00\x00", "Affine2x3.dy.value (0.0)"),
+ (b"\x06", "BaseGlyphV1Record[1].Paint.SourcePaint.Format (6)"),
+ (b"\x00\n", "BaseGlyphV1Record[1].Paint.SourcePaint.Glyph (10)"),
+ (b"\x00\x00\x00\x04", "LayerV1List.LayerCount (4)"),
+ (
+ b"\x00\x00\x00\x14",
+ "First Offset to Paint table from beginning of LayerV1List (20)",
+ ),
+ (
+ b"\x00\x00\x00\x1a",
+ "Second Offset to Paint table from beginning of LayerV1List (26)",
+ ),
+ (
+ b"\x00\x00\x00u",
+ "Third Offset to Paint table from beginning of LayerV1List (117)",
+ ),
+ (
+ b"\x00\x00\x00\xf6",
+ "Fourth Offset to Paint table from beginning of LayerV1List (246)",
+ ),
+ # PaintGlyph glyph00011
+ (b"\x05", "LayerV1List.Paint[0].Format (5)"),
+ (b"\x00\x01\x28", "Offset24 to Paint subtable from beginning of PaintGlyph (296)"),
+ (b"\x00\x0b", "LayerV1List.Paint[0].Glyph (glyph00011)"),
+ # PaintGlyph glyph00012
+ (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 (glyph00012)"),
+ (b"\x03", "LayerV1List.Paint[1].Paint.Format (3)"),
+ (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\x02", "Paint.y0.value (2)"),
+ (b"\x00\x00\x00\x00", "Paint.y0.varIdx (0)"),
+ (b"\xff\xfd", "Paint.x1.value (-3)"),
+ (b"\x00\x00\x00\x00", "Paint.x1.varIdx (0)"),
+ (b"\xff\xfc", "Paint.y1.value (-4)"),
+ (b"\x00\x00\x00\x00", "Paint.y1.varIdx (0)"),
+ (b"\x00\x05", "Paint.x2.value (5)"),
+ (b"\x00\x00\x00\x00", "Paint.x2.varIdx (0)"),
+ (b"\x00\x06", "Paint.y2.value (6)"),
+ (b"\x00\x00\x00\x00", "Paint.y2.varIdx (0)"),
+ (b"\x01", "ColorLine.Extend (1; repeat)"),
+ (b"\x00\x03", "ColorLine.StopCount (3)"),
+ (b"\x00\x00", "ColorLine.ColorStop[0].StopOffset.value (0.0)"),
+ (b"\x00\x00\x00\x00", "ColorLine.ColorStop[0].StopOffset.varIdx (0)"),
+ (b"\x00\x03", "ColorLine.ColorStop[0].Color.PaletteIndex (3)"),
+ (b"@\x00", "ColorLine.ColorStop[0].Color.Alpha.value (1.0)"),
+ (b"\x00\x00\x00\x00", "ColorLine.ColorStop[0].Color.Alpha.varIdx (0)"),
+ (b" \x00", "ColorLine.ColorStop[1].StopOffset.value (0.5)"),
+ (b"\x00\x00\x00\x00", "ColorLine.ColorStop[1].StopOffset.varIdx (0)"),
+ (b"\x00\x04", "ColorLine.ColorStop[1].Color.PaletteIndex (4)"),
+ (b"@\x00", "ColorLine.ColorStop[1].Color.Alpha.value (1.0)"),
+ (b"\x00\x00\x00\x00", "ColorLine.ColorStop[1].Color.Alpha.varIdx (0)"),
+ (b"@\x00", "ColorLine.ColorStop[2].StopOffset.value (1.0)"),
+ (b"\x00\x00\x00\x00", "ColorLine.ColorStop[2].StopOffset.varIdx (0)"),
+ (b"\x00\x05", "ColorLine.ColorStop[2].Color.PaletteIndex (5)"),
+ (b"@\x00", "ColorLine.ColorStop[2].Color.Alpha.value (1.0)"),
+ (b"\x00\x00\x00\x00", "ColorLine.ColorStop[2].Color.Alpha.varIdx (0)"),
+ # PaintGlyph glyph00013
+ (b"\x05", "LayerV1List.Paint[2].Format (5)"),
+ (b"\x00\x00\x06", "Offset to Paint subtable from beginning of PaintGlyph (6)"),
+ (b"\x00\r", "LayerV1List.Paint[2].Glyph (13)"),
+ (b"\x07", "LayerV1List.Paint[2].Paint.Format (5)"),
+ (b"\x00\x00\x34", "Offset to Paint subtable from beginning of PaintTransform (52)"),
+ (b"\xff\xf3\x00\x00\x00\x00\x00\x00", "Affine2x3.xx.value (-13)"),
+ (b"\x00\x0e\x00\x00\x00\x00\x00\x00", "Affine2x3.xy.value (14)"),
+ (b"\x00\x0f\x00\x00\x00\x00\x00\x00", "Affine2x3.yx.value (15)"),
+ (b"\xff\xef\x00\x00\x00\x00\x00\x00", "Affine2x3.yy.value (-17)"),
+ (b"\x00\x12\x00\x00\x00\x00\x00\x00", "Affine2x3.yy.value (18)"),
+ (b"\x00\x13\x00\x00\x00\x00\x00\x00", "Affine2x3.yy.value (19)"),
+ (b"\x04", "LayerV1List.Paint[2].Paint.Paint.Format (4)"),
+ (b"\x00\x00(", "Offset to ColorLine from beginning of PaintRadialGradient (40)"),
+ (b"\x00\x07\x00\x00\x00\x00", "Paint.x0.value (7)"),
+ (b"\x00\x08\x00\x00\x00\x00", "Paint.y0.value (8)"),
+ (b"\x00\t\x00\x00\x00\x00", "Paint.r0.value (9)"),
+ (b"\x00\n\x00\x00\x00\x00", "Paint.x1.value (10)"),
+ (b"\x00\x0b\x00\x00\x00\x00", "Paint.y1.value (11)"),
+ (b"\x00\x0c\x00\x00\x00\x00", "Paint.r1.value (12)"),
+ (b"\x00", "ColorLine.Extend (0; pad)"),
+ (b"\x00\x02", "ColorLine.StopCount (2)"),
+ (b"\x00\x00\x00\x00\x00\x00", "ColorLine.ColorStop[0].StopOffset.value (0.0)"),
+ (b"\x00\x06", "ColorLine.ColorStop[0].Color.PaletteIndex (6)"),
+ (b"@\x00\x00\x00\x00\x00", "ColorLine.ColorStop[0].Color.Alpha.value (1.0)"),
+ (b"@\x00\x00\x00\x00\x00", "ColorLine.ColorStop[1].StopOffset.value (1.0)"),
+ (b"\x00\x07", "ColorLine.ColorStop[1].Color.PaletteIndex (7)"),
+ (b"\x19\x9a\x00\x00\x00\x00", "ColorLine.ColorStop[1].Color.Alpha.value (0.4)"),
+ # 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 = [
'',
@@ -209,7 +262,7 @@ COLR_V1_XML = [
' ',
' ',
' ',
- ' ',
+ ' ',
" ",
"",
"",
@@ -232,13 +285,13 @@ COLR_V1_XML = [
' ',
' ',
' ',
- ' ',
+ ' ',
' ',
" ",
" ",
' ',
' ',
- ' ',
+ ' ',
' ',
' ',
" ",
@@ -260,7 +313,7 @@ COLR_V1_XML = [
" ",
"",
"",
- " ",
+ " ",
' ',
' ',
" ",
@@ -345,6 +398,26 @@ COLR_V1_XML = [
" ",
' ',
" ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ " ",
+ " ",
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ " ",
"",
]
@@ -353,7 +426,7 @@ class COLR_V1_Test(object):
def test_decompile_and_compile(self, font):
colr = table_C_O_L_R_()
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):
colr = table_C_O_L_R_()
@@ -366,5 +439,14 @@ class COLR_V1_Test(object):
colr = table_C_O_L_R_()
for name, attrs, content in parseXML(COLR_V1_XML):
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