• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from fontTools.misc.testTools import getXML, parseXML
2from fontTools.misc.textTools import deHexStr
3from fontTools.ttLib import getTableModule, newTable
4import unittest
5
6
7CPAL_DATA_V0 = deHexStr(
8    "0000 0002 "  # version=0, numPaletteEntries=2
9    "0002 0004 "  # numPalettes=2, numColorRecords=4
10    "00000010 "  # offsetToFirstColorRecord=16
11    "0000 0002 "  # colorRecordIndex=[0, 2]
12    "000000FF FFCC66FF "  # colorRecord #0, #1 (blue/green/red/alpha)
13    "000000FF 000080FF"
14)  # colorRecord #2, #3
15
16
17CPAL_DATA_V0_SHARING_COLORS = deHexStr(
18    "0000 0003 "  # version=0, numPaletteEntries=3
19    "0004 0006 "  # numPalettes=4, numColorRecords=6
20    "00000014 "  # offsetToFirstColorRecord=20
21    "0000 0000 0003 0000 "  # colorRecordIndex=[0, 0, 3, 0]
22    "443322FF 77889911 55555555 "  # colorRecord #0, #1, #2 (BGRA)
23    "443322FF 77889911 FFFFFFFF"
24)  # colorRecord #3, #4, #5
25
26
27CPAL_DATA_V1_NOLABELS_NOTYPES = deHexStr(
28    "0001 0003 "  # version=1, numPaletteEntries=3
29    "0002 0006 "  # numPalettes=2, numColorRecords=6
30    "0000001C  "  # offsetToFirstColorRecord=28
31    "0000 0003 "  # colorRecordIndex=[0, 3]
32    "00000000  "  # offsetToPaletteTypeArray=0
33    "00000000  "  # offsetToPaletteLabelArray=0
34    "00000000  "  # offsetToPaletteEntryLabelArray=0
35    "CAFECAFE 00112233 44556677 "  # colorRecord #0, #1, #2 (BGRA)
36    "31415927 42424242 00331337"
37)  # colorRecord #3, #4, #5
38
39
40CPAL_DATA_V1 = deHexStr(
41    "0001 0003 "  # version=1, numPaletteEntries=3
42    "0002 0006 "  # numPalettes=2, numColorRecords=6
43    "0000001C  "  # offsetToFirstColorRecord=28
44    "0000 0003 "  # colorRecordIndex=[0, 3]
45    "00000034  "  # offsetToPaletteTypeArray=52
46    "0000003C  "  # offsetToPaletteLabelArray=60
47    "00000040  "  # offsetToPaletteEntryLabelArray=64
48    "CAFECAFE 00112233 44556677 "  # colorRecord #0, #1, #2 (BGRA)
49    "31415927 42424242 00331337 "  # colorRecord #3, #4, #5
50    "00000001 00000002 "  # paletteType=[1, 2]
51    "0102 0103 "  # paletteLabel=[258, 259]
52    "0201 0202 0203"
53)  # paletteEntryLabel=[513, 514, 515]
54
55
56class FakeNameTable(object):
57    def __init__(self, names):
58        self.names = names
59
60    def getDebugName(self, nameID):
61        return self.names.get(nameID)
62
63
64class CPALTest(unittest.TestCase):
65    def test_decompile_v0(self):
66        cpal = newTable("CPAL")
67        cpal.decompile(CPAL_DATA_V0, ttFont=None)
68        self.assertEqual(cpal.version, 0)
69        self.assertEqual(cpal.numPaletteEntries, 2)
70        self.assertEqual(
71            repr(cpal.palettes), "[[#000000FF, #66CCFFFF], [#000000FF, #800000FF]]"
72        )
73
74    def test_decompile_v0_sharingColors(self):
75        cpal = newTable("CPAL")
76        cpal.decompile(CPAL_DATA_V0_SHARING_COLORS, ttFont=None)
77        self.assertEqual(cpal.version, 0)
78        self.assertEqual(cpal.numPaletteEntries, 3)
79        self.assertEqual(
80            [repr(p) for p in cpal.palettes],
81            [
82                "[#223344FF, #99887711, #55555555]",
83                "[#223344FF, #99887711, #55555555]",
84                "[#223344FF, #99887711, #FFFFFFFF]",
85                "[#223344FF, #99887711, #55555555]",
86            ],
87        )
88
89    def test_decompile_v1_noLabelsNoTypes(self):
90        cpal = newTable("CPAL")
91        cpal.decompile(CPAL_DATA_V1_NOLABELS_NOTYPES, ttFont=None)
92        self.assertEqual(cpal.version, 1)
93        self.assertEqual(cpal.numPaletteEntries, 3)
94        self.assertEqual(
95            [repr(p) for p in cpal.palettes],
96            [
97                "[#CAFECAFE, #22110033, #66554477]",  # RGBA
98                "[#59413127, #42424242, #13330037]",
99            ],
100        )
101        self.assertEqual(cpal.paletteLabels, [cpal.NO_NAME_ID] * len(cpal.palettes))
102        self.assertEqual(cpal.paletteTypes, [0, 0])
103        self.assertEqual(
104            cpal.paletteEntryLabels, [cpal.NO_NAME_ID] * cpal.numPaletteEntries
105        )
106
107    def test_decompile_v1(self):
108        cpal = newTable("CPAL")
109        cpal.decompile(CPAL_DATA_V1, ttFont=None)
110        self.assertEqual(cpal.version, 1)
111        self.assertEqual(cpal.numPaletteEntries, 3)
112        self.assertEqual(
113            [repr(p) for p in cpal.palettes],
114            [
115                "[#CAFECAFE, #22110033, #66554477]",  # RGBA
116                "[#59413127, #42424242, #13330037]",
117            ],
118        )
119        self.assertEqual(cpal.paletteTypes, [1, 2])
120        self.assertEqual(cpal.paletteLabels, [258, 259])
121        self.assertEqual(cpal.paletteEntryLabels, [513, 514, 515])
122
123    def test_compile_v0(self):
124        cpal = newTable("CPAL")
125        cpal.decompile(CPAL_DATA_V0, ttFont=None)
126        self.assertEqual(cpal.compile(ttFont=None), CPAL_DATA_V0)
127
128    def test_compile_v0_sharingColors(self):
129        cpal = newTable("CPAL")
130        cpal.version = 0
131        Color = getTableModule("CPAL").Color
132        palette1 = [
133            Color(red=0x22, green=0x33, blue=0x44, alpha=0xFF),
134            Color(red=0x99, green=0x88, blue=0x77, alpha=0x11),
135            Color(red=0x55, green=0x55, blue=0x55, alpha=0x55),
136        ]
137        palette2 = [
138            Color(red=0x22, green=0x33, blue=0x44, alpha=0xFF),
139            Color(red=0x99, green=0x88, blue=0x77, alpha=0x11),
140            Color(red=0xFF, green=0xFF, blue=0xFF, alpha=0xFF),
141        ]
142        cpal.numPaletteEntries = len(palette1)
143        cpal.palettes = [palette1, palette1, palette2, palette1]
144        self.assertEqual(cpal.compile(ttFont=None), CPAL_DATA_V0_SHARING_COLORS)
145
146    def test_compile_v1(self):
147        cpal = newTable("CPAL")
148        cpal.decompile(CPAL_DATA_V1, ttFont=None)
149        self.assertEqual(cpal.compile(ttFont=None), CPAL_DATA_V1)
150
151    def test_compile_v1_noLabelsNoTypes(self):
152        cpal = newTable("CPAL")
153        cpal.decompile(CPAL_DATA_V1_NOLABELS_NOTYPES, ttFont=None)
154        self.assertEqual(cpal.compile(ttFont=None), CPAL_DATA_V1_NOLABELS_NOTYPES)
155
156    def test_toXML_v0(self):
157        cpal = newTable("CPAL")
158        cpal.decompile(CPAL_DATA_V0, ttFont=None)
159        self.assertEqual(
160            getXML(cpal.toXML),
161            [
162                '<version value="0"/>',
163                '<numPaletteEntries value="2"/>',
164                '<palette index="0">',
165                '  <color index="0" value="#000000FF"/>',
166                '  <color index="1" value="#66CCFFFF"/>',
167                "</palette>",
168                '<palette index="1">',
169                '  <color index="0" value="#000000FF"/>',
170                '  <color index="1" value="#800000FF"/>',
171                "</palette>",
172            ],
173        )
174
175    def test_toXML_v1(self):
176        name = FakeNameTable(
177            {258: "Spring theme", 259: "Winter theme", 513: "darks", 515: "lights"}
178        )
179        cpal = newTable("CPAL")
180        ttFont = {"name": name, "CPAL": cpal}
181        cpal.decompile(CPAL_DATA_V1, ttFont)
182        self.assertEqual(
183            getXML(cpal.toXML, ttFont),
184            [
185                '<version value="1"/>',
186                '<numPaletteEntries value="3"/>',
187                '<palette index="0" label="258" type="1">',
188                "  <!-- Spring theme -->",
189                '  <color index="0" value="#CAFECAFE"/>',
190                '  <color index="1" value="#22110033"/>',
191                '  <color index="2" value="#66554477"/>',
192                "</palette>",
193                '<palette index="1" label="259" type="2">',
194                "  <!-- Winter theme -->",
195                '  <color index="0" value="#59413127"/>',
196                '  <color index="1" value="#42424242"/>',
197                '  <color index="2" value="#13330037"/>',
198                "</palette>",
199                "<paletteEntryLabels>",
200                '  <label index="0" value="513"/><!-- darks -->',
201                '  <label index="1" value="514"/>',
202                '  <label index="2" value="515"/><!-- lights -->',
203                "</paletteEntryLabels>",
204            ],
205        )
206
207    def test_fromXML_v0(self):
208        cpal = newTable("CPAL")
209        for name, attrs, content in parseXML(
210            '<version value="0"/>'
211            '<numPaletteEntries value="2"/>'
212            '<palette index="0">'
213            '  <color index="0" value="#12345678"/>'
214            '  <color index="1" value="#FEDCBA98"/>'
215            "</palette>"
216        ):
217            cpal.fromXML(name, attrs, content, ttFont=None)
218        self.assertEqual(cpal.version, 0)
219        self.assertEqual(cpal.numPaletteEntries, 2)
220        self.assertEqual(repr(cpal.palettes), "[[#12345678, #FEDCBA98]]")
221
222    def test_fromXML_v1(self):
223        cpal = newTable("CPAL")
224        for name, attrs, content in parseXML(
225            '<version value="1"/>'
226            '<numPaletteEntries value="3"/>'
227            '<palette index="0" label="259" type="2">'
228            '  <color index="0" value="#12345678"/>'
229            '  <color index="1" value="#FEDCBA98"/>'
230            '  <color index="2" value="#CAFECAFE"/>'
231            "</palette>"
232            "<paletteEntryLabels>"
233            '  <label index="1" value="262"/>'
234            "</paletteEntryLabels>"
235        ):
236            cpal.fromXML(name, attrs, content, ttFont=None)
237        self.assertEqual(cpal.version, 1)
238        self.assertEqual(cpal.numPaletteEntries, 3)
239        self.assertEqual(repr(cpal.palettes), "[[#12345678, #FEDCBA98, #CAFECAFE]]")
240        self.assertEqual(cpal.paletteLabels, [259])
241        self.assertEqual(cpal.paletteTypes, [2])
242        self.assertEqual(
243            cpal.paletteEntryLabels, [cpal.NO_NAME_ID, 262, cpal.NO_NAME_ID]
244        )
245
246
247if __name__ == "__main__":
248    import sys
249
250    sys.exit(unittest.main())
251