• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(
54                f'{description} (previous "{prev_desc}", actual_bytes: {"".join("%02x" % v for v in actual_bytes)} bytes: {str(font_bytes[pos:pos+16])}'
55            )
56            errors += 1
57        pos += len(expected_bytes)
58        prev_desc = description
59    assert errors == 0
60    assert pos == len(
61        font_bytes
62    ), f"Leftover font bytes, used {pos} of {len(font_bytes)}"
63
64
65@pytest.fixture
66def font():
67    font = ttLib.TTFont()
68    font.setGlyphOrder(["glyph%05d" % i for i in range(30)])
69    return font
70
71
72class COLR_V0_Test(object):
73    def test_decompile_and_compile(self, font):
74        colr = table_C_O_L_R_()
75        colr.decompile(COLR_V0_DATA, font)
76        diff_binary_fragments(colr.compile(font), COLR_V0_SAMPLE)
77
78    def test_decompile_and_dump_xml(self, font):
79        colr = table_C_O_L_R_()
80        colr.decompile(COLR_V0_DATA, font)
81
82        dump(colr, font)
83        assert getXML(colr.toXML, font) == COLR_V0_XML
84
85    def test_load_from_xml_and_compile(self, font):
86        colr = table_C_O_L_R_()
87        for name, attrs, content in parseXML(COLR_V0_XML):
88            colr.fromXML(name, attrs, content, font)
89
90        diff_binary_fragments(colr.compile(font), COLR_V0_SAMPLE)
91
92    def test_round_trip_xml(self, font):
93        colr = table_C_O_L_R_()
94        for name, attrs, content in parseXML(COLR_V0_XML):
95            colr.fromXML(name, attrs, content, font)
96        compiled = colr.compile(font)
97
98        colr = table_C_O_L_R_()
99        colr.decompile(compiled, font)
100        assert getXML(colr.toXML, font) == COLR_V0_XML
101
102
103COLR_V1_SAMPLE = (
104    (b"\x00\x01", "Version (1)"),
105    (b"\x00\x01", "BaseGlyphRecordCount (1)"),
106    (
107        b"\x00\x00\x00\x22",
108        "Offset to BaseGlyphRecordArray from beginning of table (34)",
109    ),
110    (b"\x00\x00\x00\x28", "Offset to LayerRecordArray from beginning of table (40)"),
111    (b"\x00\x03", "LayerRecordCount (3)"),
112    (b"\x00\x00\x00\x34", "Offset to BaseGlyphList from beginning of table (52)"),
113    (b"\x00\x00\x00\x9f", "Offset to LayerList from beginning of table (159)"),
114    (b"\x00\x00\x01\x62", "Offset to ClipList (354)"),
115    (b"\x00\x00\x00\x00", "Offset to DeltaSetIndexMap (NULL)"),
116    (b"\x00\x00\x00\x00", "Offset to VarStore (NULL)"),
117    (b"\x00\x06", "BaseGlyphRecord[0].BaseGlyph (6)"),
118    (b"\x00\x00", "BaseGlyphRecord[0].FirstLayerIndex (0)"),
119    (b"\x00\x03", "BaseGlyphRecord[0].NumLayers (3)"),
120    (b"\x00\x07", "LayerRecord[0].LayerGlyph (7)"),
121    (b"\x00\x00", "LayerRecord[0].PaletteIndex (0)"),
122    (b"\x00\x08", "LayerRecord[1].LayerGlyph (8)"),
123    (b"\x00\x01", "LayerRecord[1].PaletteIndex (1)"),
124    (b"\x00\t", "LayerRecord[2].LayerGlyph (9)"),
125    (b"\x00\x02", "LayerRecord[2].PaletteIndex (2)"),
126    # BaseGlyphList
127    (b"\x00\x00\x00\x03", "BaseGlyphList.BaseGlyphCount (3)"),
128    (b"\x00\n", "BaseGlyphList.BaseGlyphPaintRecord[0].BaseGlyph (10)"),
129    (
130        b"\x00\x00\x00\x16",
131        "Offset to Paint table from beginning of BaseGlyphList (22)",
132    ),
133    (b"\x00\x0e", "BaseGlyphList.BaseGlyphPaintRecord[1].BaseGlyph (14)"),
134    (
135        b"\x00\x00\x00\x1c",
136        "Offset to Paint table from beginning of BaseGlyphList (28)",
137    ),
138    (b"\x00\x0f", "BaseGlyphList.BaseGlyphPaintRecord[2].BaseGlyph (15)"),
139    (
140        b"\x00\x00\x00\x4a",
141        "Offset to Paint table from beginning of BaseGlyphList (74)",
142    ),
143    # BaseGlyphPaintRecord[0]
144    (b"\x01", "BaseGlyphPaintRecord[0].Paint.Format (1)"),
145    (b"\x04", "BaseGlyphPaintRecord[0].Paint.NumLayers (4)"),
146    (b"\x00\x00\x00\x00", "BaseGlyphPaintRecord[0].Paint.FirstLayerIndex (0)"),
147    # BaseGlyphPaintRecord[1]
148    (b"\x20", "BaseGlyphPaintRecord[1].Paint.Format (32)"),
149    (b"\x00\x00\x0f", "Offset to SourcePaint from beginning of PaintComposite (15)"),
150    (b"\x03", "BaseGlyphPaintRecord[1].Paint.CompositeMode [SRC_OVER] (3)"),
151    (b"\x00\x00\x08", "Offset to BackdropPaint from beginning of PaintComposite (8)"),
152    (b"\x0d", "BaseGlyphPaintRecord[1].Paint.BackdropPaint.Format (13)"),
153    (b"\x00\x00\x07", "Offset to Paint from beginning of PaintVarTransform (7)"),
154    (b"\x00\x00\x0a", "Offset to VarAffine2x3 from beginning of PaintVarTransform (10)"),
155    (b"\x0b", "BaseGlyphPaintRecord[1].Paint.BackdropPaint.Format (11)"),
156    (b"\x00\x0a", "BaseGlyphPaintRecord[1].Paint.BackdropPaint.Glyph (10)"),
157    (b"\x00\x01\x00\x00", "VarAffine2x3.xx (1.0)"),
158    (b"\x00\x00\x00\x00", "VarAffine2x3.xy (0.0)"),
159    (b"\x00\x00\x00\x00", "VarAffine2x3.yx (0.0)"),
160    (b"\x00\x01\x00\x00", "VarAffine2x3.yy (1.0)"),
161    (b"\x01\x2c\x00\x00", "VarAffine2x3.dx (300.0)"),
162    (b"\x00\x00\x00\x00", "VarAffine2x3.dy (0.0)"),
163    (b"\x00\x00\x00\x00", "VarIndexBase (0)"),
164    (b"\x0a", "BaseGlyphPaintRecord[1].Paint.SourcePaint.Format (10)"),
165    (b"\x00\x00\x06", "Offset to Paint subtable from beginning of PaintGlyph (6)"),
166    (b"\x00\x0b", "BaseGlyphPaintRecord[1].Paint.SourcePaint.Glyph (11)"),
167    (b"\x08", "BaseGlyphPaintRecord[1].Paint.SourcePaint.Paint.Format (8)"),
168    (b"\x00\x00\x0c", "Offset to ColorLine from beginning of PaintSweepGradient (12)"),
169    (b"\x01\x03", "centerX (259)"),
170    (b"\x01\x2c", "centerY (300)"),
171    (b"\x10\x00", "startAngle (0.25)"),
172    (b"\x30\x00", "endAngle (0.75)"),
173    (b"\x00", "ColorLine.Extend (0; pad)"),
174    (b"\x00\x02", "ColorLine.StopCount (2)"),
175    (b"\x00\x00", "ColorLine.ColorStop[0].StopOffset (0.0)"),
176    (b"\x00\x03", "ColorLine.ColorStop[0].PaletteIndex (3)"),
177    (b"@\x00", "ColorLine.ColorStop[0].Alpha (1.0)"),
178    (b"@\x00", "ColorLine.ColorStop[1].StopOffset (1.0)"),
179    (b"\x00\x05", "ColorLine.ColorStop[1].PaletteIndex (5)"),
180    (b"@\x00", "ColorLine.ColorStop[1].Alpha (1.0)"),
181    # LayerList
182    (b"\x00\x00\x00\x04", "LayerList.LayerCount (4)"),
183    (
184        b"\x00\x00\x00\x14",
185        "First Offset to Paint table from beginning of LayerList (20)",
186    ),
187    (
188        b"\x00\x00\x00\x23",
189        "Second Offset to Paint table from beginning of LayerList (35)",
190    ),
191    (
192        b"\x00\x00\x00\x4e",
193        "Third Offset to Paint table from beginning of LayerList (78)",
194    ),
195    (
196        b"\x00\x00\x00\x9e",
197        "Fourth Offset to Paint table from beginning of LayerList (158)",
198    ),
199    # BaseGlyphPaintRecord[2]
200    (b"\x0a", "BaseGlyphPaintRecord[2].Paint.Format (10)"),
201    (b"\x00\x00\x06", "Offset to Paint subtable from beginning of PaintGlyph (6)"),
202    (b"\x00\x0b", "BaseGlyphPaintRecord[2].Paint.Glyph (11)"),
203    # PaintVarSolid
204    (b"\x03", "LayerList.Paint[0].Paint.Format (3)"),
205    (b"\x00\x02", "Paint.PaletteIndex (2)"),
206    (b" \x00", "Paint.Alpha.value (0.5)"),
207    (b"\x00\x00\x00\x06", "VarIndexBase (6)"),
208    # PaintGlyph glyph00012
209    (b"\x0a", "LayerList.Paint[1].Format (10)"),
210    (b"\x00\x00\x06", "Offset to Paint subtable from beginning of PaintGlyph (6)"),
211    (b"\x00\x0c", "LayerList.Paint[1].Glyph (glyph00012)"),
212    (b"\x04", "LayerList.Paint[1].Paint.Format (4)"),
213    (b"\x00\x00\x10", "Offset to ColorLine from beginning of PaintLinearGradient (16)"),
214    (b"\x00\x01", "Paint.x0 (1)"),
215    (b"\x00\x02", "Paint.y0 (2)"),
216    (b"\xff\xfd", "Paint.x1 (-3)"),
217    (b"\xff\xfc", "Paint.y1 (-4)"),
218    (b"\x00\x05", "Paint.x2 (5)"),
219    (b"\x00\x06", "Paint.y2 (6)"),
220    (b"\x01", "ColorLine.Extend (1; repeat)"),
221    (b"\x00\x03", "ColorLine.StopCount (3)"),
222    (b"\x00\x00", "ColorLine.ColorStop[0].StopOffset (0.0)"),
223    (b"\x00\x03", "ColorLine.ColorStop[0].PaletteIndex (3)"),
224    (b"@\x00", "ColorLine.ColorStop[0].Alpha (1.0)"),
225    (b" \x00", "ColorLine.ColorStop[1].StopOffset (0.5)"),
226    (b"\x00\x04", "ColorLine.ColorStop[1].PaletteIndex (4)"),
227    (b"@\x00", "ColorLine.ColorStop[1].Alpha (1.0)"),
228    (b"@\x00", "ColorLine.ColorStop[2].StopOffset (1.0)"),
229    (b"\x00\x05", "ColorLine.ColorStop[2].PaletteIndex (5)"),
230    (b"@\x00", "ColorLine.ColorStop[2].Alpha (1.0)"),
231    # PaintGlyph glyph00013
232    (b"\x0a", "LayerList.Paint[2].Format (10)"),
233    (b"\x00\x00\x06", "Offset to Paint subtable from beginning of PaintGlyph (6)"),
234    (b"\x00\x0d", "LayerList.Paint[2].Glyph (13)"),
235    (b"\x0c", "LayerList.Paint[2].Paint.Format (12)"),
236    (b"\x00\x00\x07", "Offset to Paint subtable from beginning of PaintTransform (7)"),
237    (b"\x00\x00\x32", "Offset to Affine2x3 subtable from beginning of PaintTransform (50)"),
238    (b"\x07", "LayerList.Paint[2].Paint.Paint.Format (7)"),
239    (b"\x00\x00\x14", "Offset to ColorLine from beginning of PaintVarRadialGradient (20)"),
240    (b"\x00\x07", "Paint.x0.value (7)"),
241    (b"\x00\x08", "Paint.y0.value (8)"),
242    (b"\x00\t", "Paint.r0.value (9)"),
243    (b"\x00\n", "Paint.x1.value (10)"),
244    (b"\x00\x0b", "Paint.y1.value (11)"),
245    (b"\x00\x0c", "Paint.r1.value (12)"),
246    (b"\xff\xff\xff\xff", "VarIndexBase (0xFFFFFFFF)"),
247    (b"\x00", "ColorLine.Extend (0; pad)"),
248    (b"\x00\x02", "ColorLine.StopCount (2)"),
249    (b"\x00\x00", "ColorLine.ColorStop[0].StopOffset.value (0.0)"),
250    (b"\x00\x06", "ColorLine.ColorStop[0].PaletteIndex (6)"),
251    (b"@\x00", "ColorLine.ColorStop[0].Alpha.value (1.0)"),
252    (b"\xff\xff\xff\xff", "VarIndexBase (0xFFFFFFFF)"),
253    (b"@\x00", "ColorLine.ColorStop[1].StopOffset.value (1.0)"),
254    (b"\x00\x07", "ColorLine.ColorStop[1].PaletteIndex (7)"),
255    (b"\x19\x9a", "ColorLine.ColorStop[1].Alpha.value (0.4)"),
256
257    (b"\x00\x00\x00\x07", "VarIndexBase (7)"),
258    (b"\xff\xf3\x00\x00", "Affine2x3.xx (-13)"),
259    (b"\x00\x0e\x00\x00", "Affine2x3.xy (14)"),
260    (b"\x00\x0f\x00\x00", "Affine2x3.yx (15)"),
261    (b"\xff\xef\x00\x00", "Affine2x3.yy (-17)"),
262    (b"\x00\x12\x00\x00", "Affine2x3.yy (18)"),
263    (b"\x00\x13\x00\x00", "Affine2x3.yy (19)"),
264
265    # PaintTranslate
266    (b"\x0e", "LayerList.Paint[3].Format (14)"),
267    (b"\x00\x00\x08", "Offset to Paint subtable from beginning of PaintTranslate (8)"),
268    (b"\x01\x01", "dx (257)"),
269    (b"\x01\x02", "dy (258)"),
270
271    # PaintRotateAroundCenter
272    (b"\x1a", "LayerList.Paint[3].Paint.Format (26)"),
273    (
274        b"\x00\x00\x0a",
275        "Offset to Paint subtable from beginning of PaintRotateAroundCenter (11)",
276    ),
277    (b"\x10\x00", "angle (0.25)"),
278    (b"\x00\xff", "centerX (255)"),
279    (b"\x01\x00", "centerY (256)"),
280
281    # PaintSkew
282    (b"\x1c", "LayerList.Paint[3].Paint.Paint.Format (28)"),
283    (
284        b"\x00\x00\x08",
285        "Offset to Paint subtable from beginning of PaintSkew (8)",
286    ),
287    (b"\xfc\x17", "xSkewAngle (-0.0611)"),
288    (b"\x01\xc7", "ySkewAngle (0.0278)"),
289
290    # PaintGlyph
291    (b"\x0a", "LayerList.Paint[3].Paint.Paint.Paint.Format (10)"),
292    (b"\x00\x00\x06", "Offset to Paint subtable from beginning of PaintGlyph (6)"),
293    (b"\x00\x0b", "LayerList.Paint[2].Glyph (11)"),
294
295    # PaintSolid
296    (b"\x02", "LayerList.Paint[0].Paint.Paint.Paint.Paint.Format (2)"),
297    (b"\x00\x02", "Paint.PaletteIndex (2)"),
298    (b" \x00", "Paint.Alpha (0.5)"),
299
300    # ClipList
301    (b'\x01', "ClipList.Format (1)"),
302    (b'\x00\x00\x00\x02', "ClipList.ClipCount (2)"),
303    (b'\x00\x0a', "ClipRecord[0].StartGlyphID (10)"),
304    (b'\x00\x0a', "ClipRecord[0].EndGlyphID (10)"),
305    (b'\x00\x00\x13', "Offset to ClipBox subtable from beginning of ClipList (19)"),
306    (b'\x00\x0e', "ClipRecord[1].StartGlyphID (14)"),
307    (b'\x00\x0f', "ClipRecord[1].EndGlyphID (15)"),
308    (b'\x00\x00\x20', "Offset to ClipBox subtable from beginning of ClipList (32)"),
309
310    (b'\x02', "ClipBox.Format (2)"),
311    (b'\x00\x00', "ClipBox.xMin (0)"),
312    (b'\x00\x00', "ClipBox.yMin (0)"),
313    (b'\x01\xf4', "ClipBox.xMax (500)"),
314    (b'\x01\xf4', "ClipBox.yMax (500)"),
315    (b'\x00\x00\x00\t', "ClipBox.VarIndexBase (9)"),
316
317    (b'\x01', "ClipBox.Format (1)"),
318    (b'\x00\x00', "ClipBox.xMin (0)"),
319    (b'\x00\x00', "ClipBox.yMin (0)"),
320    (b'\x03\xe8', "ClipBox.xMax (1000)"),
321    (b'\x03\xe8', "ClipBox.yMax (1000)"),
322)
323
324COLR_V1_DATA = b"".join(t[0] for t in COLR_V1_SAMPLE)
325
326COLR_V1_XML = [
327    '<Version value="1"/>',
328    "<!-- BaseGlyphRecordCount=1 -->",
329    "<BaseGlyphRecordArray>",
330    '  <BaseGlyphRecord index="0">',
331    '    <BaseGlyph value="glyph00006"/>',
332    '    <FirstLayerIndex value="0"/>',
333    '    <NumLayers value="3"/>',
334    "  </BaseGlyphRecord>",
335    "</BaseGlyphRecordArray>",
336    "<LayerRecordArray>",
337    '  <LayerRecord index="0">',
338    '    <LayerGlyph value="glyph00007"/>',
339    '    <PaletteIndex value="0"/>',
340    "  </LayerRecord>",
341    '  <LayerRecord index="1">',
342    '    <LayerGlyph value="glyph00008"/>',
343    '    <PaletteIndex value="1"/>',
344    "  </LayerRecord>",
345    '  <LayerRecord index="2">',
346    '    <LayerGlyph value="glyph00009"/>',
347    '    <PaletteIndex value="2"/>',
348    "  </LayerRecord>",
349    "</LayerRecordArray>",
350    "<!-- LayerRecordCount=3 -->",
351    "<BaseGlyphList>",
352    "  <!-- BaseGlyphCount=3 -->",
353    '  <BaseGlyphPaintRecord index="0">',
354    '    <BaseGlyph value="glyph00010"/>',
355    '    <Paint Format="1"><!-- PaintColrLayers -->',
356    '      <NumLayers value="4"/>',
357    '      <FirstLayerIndex value="0"/>',
358    "    </Paint>",
359    "  </BaseGlyphPaintRecord>",
360    '  <BaseGlyphPaintRecord index="1">',
361    '    <BaseGlyph value="glyph00014"/>',
362    '    <Paint Format="32"><!-- PaintComposite -->',
363    '      <SourcePaint Format="11"><!-- PaintColrGlyph -->',
364    '        <Glyph value="glyph00010"/>',
365    "      </SourcePaint>",
366    '      <CompositeMode value="src_over"/>',
367    '      <BackdropPaint Format="13"><!-- PaintVarTransform -->',
368    '        <Paint Format="11"><!-- PaintColrGlyph -->',
369    '          <Glyph value="glyph00010"/>',
370    "        </Paint>",
371    "        <Transform>",
372    '          <xx value="1.0"/>',
373    '          <yx value="0.0"/>',
374    '          <xy value="0.0"/>',
375    '          <yy value="1.0"/>',
376    '          <dx value="300.0"/>',
377    '          <dy value="0.0"/>',
378    '          <VarIndexBase value="0"/>',
379    "        </Transform>",
380    "      </BackdropPaint>",
381    "    </Paint>",
382    "  </BaseGlyphPaintRecord>",
383    '  <BaseGlyphPaintRecord index="2">',
384    '    <BaseGlyph value="glyph00015"/>',
385    '    <Paint Format="10"><!-- PaintGlyph -->',
386    '      <Paint Format="8"><!-- PaintSweepGradient -->',
387    "        <ColorLine>",
388    '          <Extend value="pad"/>',
389    "          <!-- StopCount=2 -->",
390    '          <ColorStop index="0">',
391    '            <StopOffset value="0.0"/>',
392    '            <PaletteIndex value="3"/>',
393    '            <Alpha value="1.0"/>',
394    "          </ColorStop>",
395    '          <ColorStop index="1">',
396    '            <StopOffset value="1.0"/>',
397    '            <PaletteIndex value="5"/>',
398    '            <Alpha value="1.0"/>',
399    "          </ColorStop>",
400    "        </ColorLine>",
401    '        <centerX value="259"/>',
402    '        <centerY value="300"/>',
403    '        <startAngle value="45.0"/>',
404    '        <endAngle value="135.0"/>',
405    "      </Paint>",
406    '      <Glyph value="glyph00011"/>',
407    "    </Paint>",
408    "  </BaseGlyphPaintRecord>",
409    "</BaseGlyphList>",
410    "<LayerList>",
411    "  <!-- LayerCount=4 -->",
412    '  <Paint index="0" Format="10"><!-- PaintGlyph -->',
413    '    <Paint Format="3"><!-- PaintVarSolid -->',
414    '      <PaletteIndex value="2"/>',
415    '      <Alpha value="0.5"/>',
416    '      <VarIndexBase value="6"/>',
417    "    </Paint>",
418    '    <Glyph value="glyph00011"/>',
419    "  </Paint>",
420    '  <Paint index="1" Format="10"><!-- PaintGlyph -->',
421    '    <Paint Format="4"><!-- PaintLinearGradient -->',
422    "      <ColorLine>",
423    '        <Extend value="repeat"/>',
424    "        <!-- StopCount=3 -->",
425    '        <ColorStop index="0">',
426    '          <StopOffset value="0.0"/>',
427    '          <PaletteIndex value="3"/>',
428    '          <Alpha value="1.0"/>',
429    "        </ColorStop>",
430    '        <ColorStop index="1">',
431    '          <StopOffset value="0.5"/>',
432    '          <PaletteIndex value="4"/>',
433    '          <Alpha value="1.0"/>',
434    "        </ColorStop>",
435    '        <ColorStop index="2">',
436    '          <StopOffset value="1.0"/>',
437    '          <PaletteIndex value="5"/>',
438    '          <Alpha value="1.0"/>',
439    "        </ColorStop>",
440    "      </ColorLine>",
441    '      <x0 value="1"/>',
442    '      <y0 value="2"/>',
443    '      <x1 value="-3"/>',
444    '      <y1 value="-4"/>',
445    '      <x2 value="5"/>',
446    '      <y2 value="6"/>',
447    "    </Paint>",
448    '    <Glyph value="glyph00012"/>',
449    "  </Paint>",
450    '  <Paint index="2" Format="10"><!-- PaintGlyph -->',
451    '    <Paint Format="12"><!-- PaintTransform -->',
452    '      <Paint Format="7"><!-- PaintVarRadialGradient -->',
453    "        <ColorLine>",
454    '          <Extend value="pad"/>',
455    "          <!-- StopCount=2 -->",
456    '          <ColorStop index="0">',
457    '            <StopOffset value="0.0"/>',
458    '            <PaletteIndex value="6"/>',
459    '            <Alpha value="1.0"/>',
460    "            <VarIndexBase/>",
461    "          </ColorStop>",
462    '          <ColorStop index="1">',
463    '            <StopOffset value="1.0"/>',
464    '            <PaletteIndex value="7"/>',
465    '            <Alpha value="0.4"/>',
466    '            <VarIndexBase value="7"/>',
467    "          </ColorStop>",
468    "        </ColorLine>",
469    '        <x0 value="7"/>',
470    '        <y0 value="8"/>',
471    '        <r0 value="9"/>',
472    '        <x1 value="10"/>',
473    '        <y1 value="11"/>',
474    '        <r1 value="12"/>',
475    "        <VarIndexBase/>",
476    "      </Paint>",
477    "      <Transform>",
478    '        <xx value="-13.0"/>',
479    '        <yx value="14.0"/>',
480    '        <xy value="15.0"/>',
481    '        <yy value="-17.0"/>',
482    '        <dx value="18.0"/>',
483    '        <dy value="19.0"/>',
484    "      </Transform>",
485    "    </Paint>",
486    '    <Glyph value="glyph00013"/>',
487    "  </Paint>",
488    '  <Paint index="3" Format="14"><!-- PaintTranslate -->',
489    '    <Paint Format="26"><!-- PaintRotateAroundCenter -->',
490    '      <Paint Format="28"><!-- PaintSkew -->',
491    '        <Paint Format="10"><!-- PaintGlyph -->',
492    '          <Paint Format="2"><!-- PaintSolid -->',
493    '            <PaletteIndex value="2"/>',
494    '            <Alpha value="0.5"/>',
495    "          </Paint>",
496    '          <Glyph value="glyph00011"/>',
497    "        </Paint>",
498    '        <xSkewAngle value="-11.0"/>',
499    '        <ySkewAngle value="5.0"/>',
500    "      </Paint>",
501    '      <angle value="45.0"/>',
502    '      <centerX value="255"/>',
503    '      <centerY value="256"/>',
504    "    </Paint>",
505    '    <dx value="257"/>',
506    '    <dy value="258"/>',
507    "  </Paint>",
508    "</LayerList>",
509    '<ClipList Format="1">',
510    "  <Clip>",
511    '    <Glyph value="glyph00010"/>',
512    '    <ClipBox Format="2">',
513    '      <xMin value="0"/>',
514    '      <yMin value="0"/>',
515    '      <xMax value="500"/>',
516    '      <yMax value="500"/>',
517    '      <VarIndexBase value="9"/>',
518    "    </ClipBox>",
519    "  </Clip>",
520    "  <Clip>",
521    '    <Glyph value="glyph00014"/>',
522    '    <Glyph value="glyph00015"/>',
523    '    <ClipBox Format="1">',
524    '      <xMin value="0"/>',
525    '      <yMin value="0"/>',
526    '      <xMax value="1000"/>',
527    '      <yMax value="1000"/>',
528    "    </ClipBox>",
529    "  </Clip>",
530    "</ClipList>",
531]
532
533COLR_V1_VAR_XML = [
534    '<VarIndexMap Format="0">',
535    '  <Map index="0" outer="1" inner="1"/>',
536    '  <Map index="1" outer="1" inner="0"/>',
537    '  <Map index="2" outer="1" inner="0"/>',
538    '  <Map index="3" outer="1" inner="1"/>',
539    '  <Map index="4" outer="1" inner="0"/>',
540    '  <Map index="5" outer="1" inner="0"/>',
541    '  <Map index="6" outer="0" inner="2"/>',
542    '  <Map index="7" outer="0" inner="0"/>',
543    '  <Map index="8" outer="0" inner="1"/>',
544    '  <Map index="9" outer="1" inner="0"/>',
545    '  <Map index="10" outer="1" inner="0"/>',
546    '  <Map index="11" outer="0" inner="3"/>',
547    '  <Map index="12" outer="0" inner="3"/>',
548    "</VarIndexMap>",
549    '<VarStore Format="1">',
550    '  <Format value="1"/>',
551    "  <VarRegionList>",
552    "    <!-- RegionAxisCount=1 -->",
553    "    <!-- RegionCount=1 -->",
554    '    <Region index="0">',
555    '      <VarRegionAxis index="0">',
556    '        <StartCoord value="0.0"/>',
557    '        <PeakCoord value="1.0"/>',
558    '        <EndCoord value="1.0"/>',
559    "      </VarRegionAxis>",
560    "    </Region>",
561    "  </VarRegionList>",
562    "  <!-- VarDataCount=2 -->",
563    '  <VarData index="0">',
564    "    <!-- ItemCount=4 -->",
565    '    <NumShorts value="1"/>',
566    "    <!-- VarRegionCount=1 -->",
567    '    <VarRegionIndex index="0" value="0"/>',
568    '    <Item index="0" value="[-3277]"/>',
569    '    <Item index="1" value="[6553]"/>',
570    '    <Item index="2" value="[8192]"/>',
571    '    <Item index="3" value="[500]"/>',
572    "  </VarData>",
573    '  <VarData index="1">',
574    "    <!-- ItemCount=2 -->",
575    '    <NumShorts value="32769"/>',
576    "    <!-- VarRegionCount=1 -->",
577    '    <VarRegionIndex index="0" value="0"/>',
578    '    <Item index="0" value="[0]"/>',
579    '    <Item index="1" value="[65536]"/>',
580    "  </VarData>",
581    "</VarStore>",
582]
583
584
585class COLR_V1_Test(object):
586    def test_decompile_and_compile(self, font):
587        colr = table_C_O_L_R_()
588        colr.decompile(COLR_V1_DATA, font)
589        diff_binary_fragments(colr.compile(font), COLR_V1_SAMPLE)
590
591    def test_decompile_and_dump_xml(self, font):
592        colr = table_C_O_L_R_()
593        colr.decompile(COLR_V1_DATA, font)
594
595        dump(colr, font)
596        assert getXML(colr.toXML, font) == COLR_V1_XML
597
598    def test_load_from_xml_and_compile(self, font):
599        colr = table_C_O_L_R_()
600        for name, attrs, content in parseXML(COLR_V1_XML):
601            colr.fromXML(name, attrs, content, font)
602        diff_binary_fragments(colr.compile(font), COLR_V1_SAMPLE)
603
604    def test_round_trip_xml(self, font):
605        colr = table_C_O_L_R_()
606        for name, attrs, content in parseXML(COLR_V1_XML):
607            colr.fromXML(name, attrs, content, font)
608        compiled = colr.compile(font)
609
610        colr = table_C_O_L_R_()
611        colr.decompile(compiled, font)
612        assert getXML(colr.toXML, font) == COLR_V1_XML
613
614
615class COLR_V1_Variable_Test(object):
616    def test_round_trip_xml(self, font):
617        colr = table_C_O_L_R_()
618        xml = COLR_V1_XML + COLR_V1_VAR_XML
619        for name, attrs, content in parseXML(xml):
620            colr.fromXML(name, attrs, content, font)
621        compiled = colr.compile(font)
622
623        colr = table_C_O_L_R_()
624        colr.decompile(compiled, font)
625        assert getXML(colr.toXML, font) == xml
626