1from fontTools import ttLib
2from fontTools.misc.testTools import getXML, parseXML
3from fontTools.ttLib.tables.C_O_L_R_ import table_C_O_L_R_
4
5import binascii
6import pytest
7
8
9COLR_V0_SAMPLE = (
10    (b"\x00\x00", "Version (0)"),
11    (b"\x00\x01", "BaseGlyphRecordCount (1)"),
12    (
13        b"\x00\x00\x00\x0e",
14        "Offset to BaseGlyphRecordArray from beginning of table (14)",
15    ),
16    (b"\x00\x00\x00\x14", "Offset to LayerRecordArray from beginning of table (20)"),
17    (b"\x00\x03", "LayerRecordCount (3)"),
18    (b"\x00\x06", "BaseGlyphRecord[0].BaseGlyph (6)"),
19    (b"\x00\x00", "BaseGlyphRecord[0].FirstLayerIndex (0)"),
20    (b"\x00\x03", "BaseGlyphRecord[0].NumLayers (3)"),
21    (b"\x00\x07", "LayerRecord[0].LayerGlyph (7)"),
22    (b"\x00\x00", "LayerRecord[0].PaletteIndex (0)"),
23    (b"\x00\x08", "LayerRecord[1].LayerGlyph (8)"),
24    (b"\x00\x01", "LayerRecord[1].PaletteIndex (1)"),
25    (b"\x00\t", "LayerRecord[2].LayerGlyph (9)"),
26    (b"\x00\x02", "LayerRecord[3].PaletteIndex (2)"),
27)
28
29COLR_V0_DATA = b"".join(t[0] for t in COLR_V0_SAMPLE)
30
31
32COLR_V0_XML = [
33    '<version value="0"/>',
34    '<ColorGlyph name="glyph00006">',
35    '  <layer colorID="0" name="glyph00007"/>',
36    '  <layer colorID="1" name="glyph00008"/>',
37    '  <layer colorID="2" name="glyph00009"/>',
38    "</ColorGlyph>",
39]
40
41
42def dump(table, ttFont=None):
43    print("\n".join(getXML(table.toXML, ttFont)))
44
45
46def diff_binary_fragments(font_bytes, expected_fragments):
47    pos = 0
48    prev_desc = ""
49    errors = 0
50    for expected_bytes, description in expected_fragments:
51        actual_bytes = font_bytes[pos : pos + len(expected_bytes)]
52        if actual_bytes != expected_bytes:
53            print(f'{description} (previous "{prev_desc}", actual_bytes: {"".join("%02x" % v for v in actual_bytes)} bytes: {str(font_bytes[pos:pos+16])}')
54            errors += 1
55        pos += len(expected_bytes)
56        prev_desc = description
57    assert errors == 0
58    assert pos == len(
59        font_bytes
60    ), f"Leftover font bytes, used {pos} of {len(font_bytes)}"
61
62
63@pytest.fixture
64def font():
65    font = ttLib.TTFont()
66    font.setGlyphOrder(["glyph%05d" % i for i in range(30)])
67    return font
68
69
70class COLR_V0_Test(object):
71    def test_decompile_and_compile(self, font):
72        colr = table_C_O_L_R_()
73        colr.decompile(COLR_V0_DATA, font)
74        diff_binary_fragments(colr.compile(font), COLR_V0_SAMPLE)
75
76    def test_decompile_and_dump_xml(self, font):
77        colr = table_C_O_L_R_()
78        colr.decompile(COLR_V0_DATA, font)
79
80        dump(colr, font)
81        assert getXML(colr.toXML, font) == COLR_V0_XML
82
83    def test_load_from_xml_and_compile(self, font):
84        colr = table_C_O_L_R_()
85        for name, attrs, content in parseXML(COLR_V0_XML):
86            colr.fromXML(name, attrs, content, font)
87
88        diff_binary_fragments(colr.compile(font), COLR_V0_SAMPLE)
89
90    def test_round_trip_xml(self, font):
91        colr = table_C_O_L_R_()
92        for name, attrs, content in parseXML(COLR_V0_XML):
93            colr.fromXML(name, attrs, content, font)
94        compiled = colr.compile(font)
95
96        colr = table_C_O_L_R_()
97        colr.decompile(compiled, font)
98        assert getXML(colr.toXML, font) == COLR_V0_XML
99
100
101COLR_V1_SAMPLE = (
102    (b"\x00\x01", "Version (1)"),
103    (b"\x00\x01", "BaseGlyphRecordCount (1)"),
104    (
105        b"\x00\x00\x00\x1a",
106        "Offset to BaseGlyphRecordArray from beginning of table (26)",
107    ),
108    (b"\x00\x00\x00 ", "Offset to LayerRecordArray from beginning of table (32)"),
109    (b"\x00\x03", "LayerRecordCount (3)"),
110    (b"\x00\x00\x00,", "Offset to BaseGlyphV1List from beginning of table (44)"),
111    (b"\x00\x00\x00\xac", "Offset to LayerV1List from beginning of table (172)"),
112    (b"\x00\x00\x00\x00", "Offset to VarStore (NULL)"),
113    (b"\x00\x06", "BaseGlyphRecord[0].BaseGlyph (6)"),
114    (b"\x00\x00", "BaseGlyphRecord[0].FirstLayerIndex (0)"),
115    (b"\x00\x03", "BaseGlyphRecord[0].NumLayers (3)"),
116    (b"\x00\x07", "LayerRecord[0].LayerGlyph (7)"),
117    (b"\x00\x00", "LayerRecord[0].PaletteIndex (0)"),
118    (b"\x00\x08", "LayerRecord[1].LayerGlyph (8)"),
119    (b"\x00\x01", "LayerRecord[1].PaletteIndex (1)"),
120    (b"\x00\t", "LayerRecord[2].LayerGlyph (9)"),
121    (b"\x00\x02", "LayerRecord[2].PaletteIndex (2)"),
122    # BaseGlyphV1List
123    (b"\x00\x00\x00\x03", "BaseGlyphV1List.BaseGlyphCount (3)"),
124    (b"\x00\n", "BaseGlyphV1List.BaseGlyphV1Record[0].BaseGlyph (10)"),
125    (
126        b"\x00\x00\x00\x16",
127        "Offset to Paint table from beginning of BaseGlyphV1List (22)",
128    ),
129    (b"\x00\x0e", "BaseGlyphV1List.BaseGlyphV1Record[1].BaseGlyph (14)"),
130    (
131        b"\x00\x00\x00\x1c",
132        "Offset to Paint table from beginning of BaseGlyphV1List (28)",
133    ),
134    (b"\x00\x0f", "BaseGlyphV1List.BaseGlyphV1Record[2].BaseGlyph (15)"),
135    (
136        b"\x00\x00\x00\x5b",
137        "Offset to Paint table from beginning of BaseGlyphV1List (91)",
138    ),
139    # BaseGlyphV1Record[0]
140    (b"\x01", "BaseGlyphV1Record[0].Paint.Format (1)"),
141    (b"\x04", "BaseGlyphV1Record[0].Paint.NumLayers (4)"),
142    (b"\x00\x00\x00\x00", "BaseGlyphV1Record[0].Paint.FirstLayerIndex (0)"),
143    # BaseGlyphV1Record[1]
144    (b"\x14", "BaseGlyphV1Record[1].Paint.Format (20)"),
145    (b"\x00\x00<", "Offset to SourcePaint from beginning of PaintComposite (60)"),
146    (b"\x03", "BaseGlyphV1Record[1].Paint.CompositeMode [SRC_OVER] (3)"),
147    (b"\x00\x00\x08", "Offset to BackdropPaint from beginning of PaintComposite (8)"),
148    (b"\x0d", "BaseGlyphV1Record[1].Paint.BackdropPaint.Format (13)"),
149    (b"\x00\x00\x34", "Offset to Paint from beginning of PaintVarTransform (52)"),
150    (b"\x00\x01\x00\x00\x00\x00\x00\x00", "Affine2x3.xx.value (1.0)"),
151    (b"\x00\x00\x00\x00\x00\x00\x00\x00", "Affine2x3.xy.value (0.0)"),
152    (b"\x00\x00\x00\x00\x00\x00\x00\x00", "Affine2x3.yx.value (0.0)"),
153    (b"\x00\x01\x00\x00\x00\x00\x00\x00", "Affine2x3.yy.value (1.0)"),
154    (b"\x01\x2c\x00\x00\x00\x00\x00\x00", "Affine2x3.dx.value (300.0)"),
155    (b"\x00\x00\x00\x00\x00\x00\x00\x00", "Affine2x3.dy.value (0.0)"),
156    (b"\x0b", "BaseGlyphV1Record[1].Paint.SourcePaint.Format (11)"),
157    (b"\x00\n", "BaseGlyphV1Record[1].Paint.SourcePaint.Glyph (10)"),
158    # BaseGlyphV1Record[2]
159    (b"\x0a", "BaseGlyphV1Record[2].Paint.Format (10)"),
160    (b"\x00\x00\x06", "Offset to Paint subtable from beginning of PaintGlyph (6)"),
161    (b"\x00\x0b", "BaseGlyphV1Record[2].Paint.Glyph (11)"),
162    (b"\x08", "BaseGlyphV1Record[2].Paint.Paint.Format (8)"),
163    (b"\x00\x00\x10", "Offset to ColorLine from beginning of PaintSweepGradient (16)"),
164    (b"\x01\x03", "centerX (259)"),
165    (b"\x01\x2c", "centerY (300)"),
166    (b"\x00\x2d\x00\x00", "startAngle (45.0)"),
167    (b"\x00\x87\x00\x00", "endAngle (135.0)"),
168    (b"\x00", "ColorLine.Extend (0; pad)"),
169    (b"\x00\x02", "ColorLine.StopCount (2)"),
170    (b"\x00\x00", "ColorLine.ColorStop[0].StopOffset (0.0)"),
171    (b"\x00\x03", "ColorLine.ColorStop[0].Color.PaletteIndex (3)"),
172    (b"@\x00", "ColorLine.ColorStop[0].Color.Alpha (1.0)"),
173    (b"@\x00", "ColorLine.ColorStop[1].StopOffset (1.0)"),
174    (b"\x00\x05", "ColorLine.ColorStop[1].Color.PaletteIndex (5)"),
175    (b"@\x00", "ColorLine.ColorStop[1].Color.Alpha (1.0)"),
176    # LayerV1List
177    (b"\x00\x00\x00\x04", "LayerV1List.LayerCount (4)"),
178    (
179        b"\x00\x00\x00\x14",
180        "First Offset to Paint table from beginning of LayerV1List (20)",
181    ),
182    (
183        b"\x00\x00\x00\x23",
184        "Second Offset to Paint table from beginning of LayerV1List (35)",
185    ),
186    (
187        b"\x00\x00\x00\x4e",
188        "Third Offset to Paint table from beginning of LayerV1List (78)",
189    ),
190    (
191        b"\x00\x00\x00\xb7",
192        "Fourth Offset to Paint table from beginning of LayerV1List (183)",
193    ),
194    # PaintGlyph glyph00011
195    (b"\x0a", "LayerV1List.Paint[0].Format (10)"),
196    (b"\x00\x00\x06", "Offset24 to Paint subtable from beginning of PaintGlyph (6)"),
197    (b"\x00\x0b", "LayerV1List.Paint[0].Glyph (glyph00011)"),
198    # PaintVarSolid
199    (b"\x03", "LayerV1List.Paint[0].Paint.Format (3)"),
200    (b"\x00\x02", "Paint.Color.PaletteIndex (2)"),
201    (b" \x00", "Paint.Color.Alpha.value (0.5)"),
202    (b"\x00\x00\x00\x00", "Paint.Color.Alpha.varIdx (0)"),
203    # PaintGlyph glyph00012
204    (b"\x0a", "LayerV1List.Paint[1].Format (10)"),
205    (b"\x00\x00\x06", "Offset to Paint subtable from beginning of PaintGlyph (6)"),
206    (b"\x00\x0c", "LayerV1List.Paint[1].Glyph (glyph00012)"),
207    (b"\x04", "LayerV1List.Paint[1].Paint.Format (4)"),
208    (b"\x00\x00\x10", "Offset to ColorLine from beginning of PaintLinearGradient (16)"),
209    (b"\x00\x01", "Paint.x0 (1)"),
210    (b"\x00\x02", "Paint.y0 (2)"),
211    (b"\xff\xfd", "Paint.x1 (-3)"),
212    (b"\xff\xfc", "Paint.y1 (-4)"),
213    (b"\x00\x05", "Paint.x2 (5)"),
214    (b"\x00\x06", "Paint.y2 (6)"),
215    (b"\x01", "ColorLine.Extend (1; repeat)"),
216    (b"\x00\x03", "ColorLine.StopCount (3)"),
217    (b"\x00\x00", "ColorLine.ColorStop[0].StopOffset (0.0)"),
218    (b"\x00\x03", "ColorLine.ColorStop[0].Color.PaletteIndex (3)"),
219    (b"@\x00", "ColorLine.ColorStop[0].Color.Alpha (1.0)"),
220    (b" \x00", "ColorLine.ColorStop[1].StopOffset (0.5)"),
221    (b"\x00\x04", "ColorLine.ColorStop[1].Color.PaletteIndex (4)"),
222    (b"@\x00", "ColorLine.ColorStop[1].Color.Alpha (1.0)"),
223    (b"@\x00", "ColorLine.ColorStop[2].StopOffset (1.0)"),
224    (b"\x00\x05", "ColorLine.ColorStop[2].Color.PaletteIndex (5)"),
225    (b"@\x00", "ColorLine.ColorStop[2].Color.Alpha (1.0)"),
226    # PaintGlyph glyph00013
227    (b"\x0a", "LayerV1List.Paint[2].Format (10)"),
228    (b"\x00\x00\x06", "Offset to Paint subtable from beginning of PaintGlyph (6)"),
229    (b"\x00\r", "LayerV1List.Paint[2].Glyph (13)"),
230    (b"\x0c", "LayerV1List.Paint[2].Paint.Format (12)"),
231    (b"\x00\x00\x1c", "Offset to Paint subtable from beginning of PaintTransform (28)"),
232    (b"\xff\xf3\x00\x00", "Affine2x3.xx (-13)"),
233    (b"\x00\x0e\x00\x00", "Affine2x3.xy (14)"),
234    (b"\x00\x0f\x00\x00", "Affine2x3.yx (15)"),
235    (b"\xff\xef\x00\x00", "Affine2x3.yy (-17)"),
236    (b"\x00\x12\x00\x00", "Affine2x3.yy (18)"),
237    (b"\x00\x13\x00\x00", "Affine2x3.yy (19)"),
238    (b"\x07", "LayerV1List.Paint[2].Paint.Paint.Format (7)"),
239    (b"\x00\x00(", "Offset to ColorLine from beginning of PaintVarRadialGradient (40)"),
240    (b"\x00\x07\x00\x00\x00\x00", "Paint.x0.value (7)"),
241    (b"\x00\x08\x00\x00\x00\x00", "Paint.y0.value (8)"),
242    (b"\x00\t\x00\x00\x00\x00", "Paint.r0.value (9)"),
243    (b"\x00\n\x00\x00\x00\x00", "Paint.x1.value (10)"),
244    (b"\x00\x0b\x00\x00\x00\x00", "Paint.y1.value (11)"),
245    (b"\x00\x0c\x00\x00\x00\x00", "Paint.r1.value (12)"),
246    (b"\x00", "ColorLine.Extend (0; pad)"),
247    (b"\x00\x02", "ColorLine.StopCount (2)"),
248    (b"\x00\x00\x00\x00\x00\x00", "ColorLine.ColorStop[0].StopOffset.value (0.0)"),
249    (b"\x00\x06", "ColorLine.ColorStop[0].Color.PaletteIndex (6)"),
250    (b"@\x00\x00\x00\x00\x00", "ColorLine.ColorStop[0].Color.Alpha.value (1.0)"),
251    (b"@\x00\x00\x00\x00\x00", "ColorLine.ColorStop[1].StopOffset.value (1.0)"),
252    (b"\x00\x07", "ColorLine.ColorStop[1].Color.PaletteIndex (7)"),
253    (b"\x19\x9a\x00\x00\x00\x00", "ColorLine.ColorStop[1].Color.Alpha.value (0.4)"),
254    # PaintTranslate
255    (b"\x0e", "LayerV1List.Paint[3].Format (14)"),
256    (b"\x00\x00\x0c", "Offset to Paint subtable from beginning of PaintTranslate (12)"),
257    (b"\x01\x01\x00\x00", "dx (257)"),
258    (b"\x01\x02\x00\x00", "dy (258)"),
259    # PaintRotate
260    (b"\x10", "LayerV1List.Paint[3].Paint.Format (16)"),
261    (b"\x00\x00\x10", "Offset to Paint subtable from beginning of PaintRotate (16)"),
262    (b"\x00\x2d\x00\x00", "angle (45)"),
263    (b"\x00\xff\x00\x00", "centerX (255)"),
264    (b"\x01\x00\x00\x00", "centerY (256)"),
265    # PaintSkew
266    (b"\x12", "LayerV1List.Paint[3].Paint.Paint.Format (18)"),
267    (b"\x00\x00\x14", "Offset to Paint subtable from beginning of PaintSkew (20)"),
268    (b"\xff\xf5\x00\x00", "xSkewAngle (-11)"),
269    (b"\x00\x05\x00\x00", "ySkewAngle (5)"),
270    (b"\x00\xfd\x00\x00", "centerX.value (253)"),
271    (b"\x00\xfe\x00\x00", "centerY.value (254)"),
272    # PaintGlyph
273    (b"\x0a", "LayerV1List.Paint[3].Paint.Paint.Paint.Format (10)"),
274    (b"\x00\x00\x06", "Offset to Paint subtable from beginning of PaintGlyph (6)"),
275    (b"\x00\x0b", "LayerV1List.Paint[2].Glyph (11)"),
276    # PaintSolid
277    (b"\x02", "LayerV1List.Paint[0].Paint.Paint.Paint.Paint.Format (2)"),
278    (b"\x00\x02", "Paint.Color.PaletteIndex (2)"),
279    (b" \x00", "Paint.Color.Alpha (0.5)"),
280)
281
282COLR_V1_DATA = b"".join(t[0] for t in COLR_V1_SAMPLE)
283
284COLR_V1_XML = [
285    '<Version value="1"/>',
286    "<!-- BaseGlyphRecordCount=1 -->",
287    "<BaseGlyphRecordArray>",
288    '  <BaseGlyphRecord index="0">',
289    '    <BaseGlyph value="glyph00006"/>',
290    '    <FirstLayerIndex value="0"/>',
291    '    <NumLayers value="3"/>',
292    "  </BaseGlyphRecord>",
293    "</BaseGlyphRecordArray>",
294    "<LayerRecordArray>",
295    '  <LayerRecord index="0">',
296    '    <LayerGlyph value="glyph00007"/>',
297    '    <PaletteIndex value="0"/>',
298    "  </LayerRecord>",
299    '  <LayerRecord index="1">',
300    '    <LayerGlyph value="glyph00008"/>',
301    '    <PaletteIndex value="1"/>',
302    "  </LayerRecord>",
303    '  <LayerRecord index="2">',
304    '    <LayerGlyph value="glyph00009"/>',
305    '    <PaletteIndex value="2"/>',
306    "  </LayerRecord>",
307    "</LayerRecordArray>",
308    "<!-- LayerRecordCount=3 -->",
309    "<BaseGlyphV1List>",
310    "  <!-- BaseGlyphCount=3 -->",
311    '  <BaseGlyphV1Record index="0">',
312    '    <BaseGlyph value="glyph00010"/>',
313    '    <Paint Format="1"><!-- PaintColrLayers -->',
314    '      <NumLayers value="4"/>',
315    '      <FirstLayerIndex value="0"/>',
316    "    </Paint>",
317    "  </BaseGlyphV1Record>",
318    '  <BaseGlyphV1Record index="1">',
319    '    <BaseGlyph value="glyph00014"/>',
320    '    <Paint Format="20"><!-- PaintComposite -->',
321    '      <SourcePaint Format="11"><!-- PaintColrGlyph -->',
322    '        <Glyph value="glyph00010"/>',
323    "      </SourcePaint>",
324    '      <CompositeMode value="src_over"/>',
325    '      <BackdropPaint Format="13"><!-- PaintVarTransform -->',
326    '        <Paint Format="11"><!-- PaintColrGlyph -->',
327    '          <Glyph value="glyph00010"/>',
328    "        </Paint>",
329    "        <Transform>",
330    '          <xx value="1.0"/>',
331    '          <yx value="0.0"/>',
332    '          <xy value="0.0"/>',
333    '          <yy value="1.0"/>',
334    '          <dx value="300.0"/>',
335    '          <dy value="0.0"/>',
336    "        </Transform>",
337    "      </BackdropPaint>",
338    "    </Paint>",
339    "  </BaseGlyphV1Record>",
340    '  <BaseGlyphV1Record index="2">',
341    '    <BaseGlyph value="glyph00015"/>',
342    '    <Paint Format="10"><!-- PaintGlyph -->',
343    '      <Paint Format="8"><!-- PaintSweepGradient -->',
344    "        <ColorLine>",
345    '          <Extend value="pad"/>',
346    "          <!-- StopCount=2 -->",
347    '          <ColorStop index="0">',
348    '            <StopOffset value="0.0"/>',
349    "            <Color>",
350    '              <PaletteIndex value="3"/>',
351    '              <Alpha value="1.0"/>',
352    "            </Color>",
353    "          </ColorStop>",
354    '          <ColorStop index="1">',
355    '            <StopOffset value="1.0"/>',
356    "            <Color>",
357    '              <PaletteIndex value="5"/>',
358    '              <Alpha value="1.0"/>',
359    "            </Color>",
360    "          </ColorStop>",
361    "        </ColorLine>",
362    '        <centerX value="259"/>',
363    '        <centerY value="300"/>',
364    '        <startAngle value="45.0"/>',
365    '        <endAngle value="135.0"/>',
366    "      </Paint>",
367    '      <Glyph value="glyph00011"/>',
368    "    </Paint>",
369    "  </BaseGlyphV1Record>",
370    "</BaseGlyphV1List>",
371    "<LayerV1List>",
372    "  <!-- LayerCount=4 -->",
373    '  <Paint index="0" Format="10"><!-- PaintGlyph -->',
374    '    <Paint Format="3"><!-- PaintVarSolid -->',
375    "      <Color>",
376    '        <PaletteIndex value="2"/>',
377    '        <Alpha value="0.5"/>',
378    "      </Color>",
379    "    </Paint>",
380    '    <Glyph value="glyph00011"/>',
381    "  </Paint>",
382    '  <Paint index="1" Format="10"><!-- PaintGlyph -->',
383    '    <Paint Format="4"><!-- PaintLinearGradient -->',
384    "      <ColorLine>",
385    '        <Extend value="repeat"/>',
386    "        <!-- StopCount=3 -->",
387    '        <ColorStop index="0">',
388    '          <StopOffset value="0.0"/>',
389    "          <Color>",
390    '            <PaletteIndex value="3"/>',
391    '            <Alpha value="1.0"/>',
392    "          </Color>",
393    "        </ColorStop>",
394    '        <ColorStop index="1">',
395    '          <StopOffset value="0.5"/>',
396    "          <Color>",
397    '            <PaletteIndex value="4"/>',
398    '            <Alpha value="1.0"/>',
399    "          </Color>",
400    "        </ColorStop>",
401    '        <ColorStop index="2">',
402    '          <StopOffset value="1.0"/>',
403    "          <Color>",
404    '            <PaletteIndex value="5"/>',
405    '            <Alpha value="1.0"/>',
406    "          </Color>",
407    "        </ColorStop>",
408    "      </ColorLine>",
409    '      <x0 value="1"/>',
410    '      <y0 value="2"/>',
411    '      <x1 value="-3"/>',
412    '      <y1 value="-4"/>',
413    '      <x2 value="5"/>',
414    '      <y2 value="6"/>',
415    "    </Paint>",
416    '    <Glyph value="glyph00012"/>',
417    "  </Paint>",
418    '  <Paint index="2" Format="10"><!-- PaintGlyph -->',
419    '    <Paint Format="12"><!-- PaintTransform -->',
420    '      <Paint Format="7"><!-- PaintVarRadialGradient -->',
421    "        <ColorLine>",
422    '          <Extend value="pad"/>',
423    "          <!-- StopCount=2 -->",
424    '          <ColorStop index="0">',
425    '            <StopOffset value="0.0"/>',
426    "            <Color>",
427    '              <PaletteIndex value="6"/>',
428    '              <Alpha value="1.0"/>',
429    "            </Color>",
430    "          </ColorStop>",
431    '          <ColorStop index="1">',
432    '            <StopOffset value="1.0"/>',
433    "            <Color>",
434    '              <PaletteIndex value="7"/>',
435    '              <Alpha value="0.4"/>',
436    "            </Color>",
437    "          </ColorStop>",
438    "        </ColorLine>",
439    '        <x0 value="7"/>',
440    '        <y0 value="8"/>',
441    '        <r0 value="9"/>',
442    '        <x1 value="10"/>',
443    '        <y1 value="11"/>',
444    '        <r1 value="12"/>',
445    "      </Paint>",
446    "      <Transform>",
447    '        <xx value="-13.0"/>',
448    '        <yx value="14.0"/>',
449    '        <xy value="15.0"/>',
450    '        <yy value="-17.0"/>',
451    '        <dx value="18.0"/>',
452    '        <dy value="19.0"/>',
453    "      </Transform>",
454    "    </Paint>",
455    '    <Glyph value="glyph00013"/>',
456    "  </Paint>",
457    '  <Paint index="3" Format="14"><!-- PaintTranslate -->',
458    '    <Paint Format="16"><!-- PaintRotate -->',
459    '      <Paint Format="18"><!-- PaintSkew -->',
460    '        <Paint Format="10"><!-- PaintGlyph -->',
461    '          <Paint Format="2"><!-- PaintSolid -->',
462    "            <Color>",
463    '              <PaletteIndex value="2"/>',
464    '              <Alpha value="0.5"/>',
465    "            </Color>",
466    "          </Paint>",
467    '          <Glyph value="glyph00011"/>',
468    "        </Paint>",
469    '        <xSkewAngle value="-11.0"/>',
470    '        <ySkewAngle value="5.0"/>',
471    '        <centerX value="253.0"/>',
472    '        <centerY value="254.0"/>',
473    "      </Paint>",
474    '      <angle value="45.0"/>',
475    '      <centerX value="255.0"/>',
476    '      <centerY value="256.0"/>',
477    "    </Paint>",
478    '    <dx value="257.0"/>',
479    '    <dy value="258.0"/>',
480    "  </Paint>",
481    "</LayerV1List>",
482]
483
484
485class COLR_V1_Test(object):
486    def test_decompile_and_compile(self, font):
487        colr = table_C_O_L_R_()
488        colr.decompile(COLR_V1_DATA, font)
489        diff_binary_fragments(colr.compile(font), COLR_V1_SAMPLE)
490
491    def test_decompile_and_dump_xml(self, font):
492        colr = table_C_O_L_R_()
493        colr.decompile(COLR_V1_DATA, font)
494
495        dump(colr, font)
496        assert getXML(colr.toXML, font) == COLR_V1_XML
497
498    def test_load_from_xml_and_compile(self, font):
499        colr = table_C_O_L_R_()
500        for name, attrs, content in parseXML(COLR_V1_XML):
501            colr.fromXML(name, attrs, content, font)
502        diff_binary_fragments(colr.compile(font), COLR_V1_SAMPLE)
503
504    def test_round_trip_xml(self, font):
505        colr = table_C_O_L_R_()
506        for name, attrs, content in parseXML(COLR_V1_XML):
507            colr.fromXML(name, attrs, content, font)
508        compiled = colr.compile(font)
509
510        colr = table_C_O_L_R_()
511        colr.decompile(compiled, font)
512        assert getXML(colr.toXML, font) == COLR_V1_XML
513