1from fontTools.ttLib.tables import otTables as ot 2from fontTools.colorLib.builder import buildColrV1 3from fontTools.colorLib.unbuilder import unbuildColrV1 4import pytest 5 6 7TEST_COLOR_GLYPHS = { 8 "glyph00010": { 9 "Format": int(ot.PaintFormat.PaintColrLayers), 10 "Layers": [ 11 { 12 "Format": int(ot.PaintFormat.PaintGlyph), 13 "Paint": { 14 "Format": int(ot.PaintFormat.PaintSolid), 15 "PaletteIndex": 2, 16 "Alpha": 0.5, 17 }, 18 "Glyph": "glyph00011", 19 }, 20 { 21 "Format": int(ot.PaintFormat.PaintGlyph), 22 "Paint": { 23 "Format": int(ot.PaintFormat.PaintVarLinearGradient), 24 "ColorLine": { 25 "Extend": "repeat", 26 "ColorStop": [ 27 { 28 "StopOffset": 0.0, 29 "PaletteIndex": 3, 30 "Alpha": 1.0, 31 "VarIndexBase": 0, 32 }, 33 { 34 "StopOffset": 0.5, 35 "PaletteIndex": 4, 36 "Alpha": 1.0, 37 "VarIndexBase": 1, 38 }, 39 { 40 "StopOffset": 1.0, 41 "PaletteIndex": 5, 42 "Alpha": 1.0, 43 "VarIndexBase": 2, 44 }, 45 ], 46 }, 47 "x0": 1, 48 "y0": 2, 49 "x1": -3, 50 "y1": -4, 51 "x2": 5, 52 "y2": 6, 53 "VarIndexBase": 0xFFFFFFFF, 54 }, 55 "Glyph": "glyph00012", 56 }, 57 { 58 "Format": int(ot.PaintFormat.PaintGlyph), 59 "Paint": { 60 "Format": int(ot.PaintFormat.PaintVarTransform), 61 "Paint": { 62 "Format": int(ot.PaintFormat.PaintRadialGradient), 63 "ColorLine": { 64 "Extend": "pad", 65 "ColorStop": [ 66 { 67 "StopOffset": 0, 68 "PaletteIndex": 6, 69 "Alpha": 1.0, 70 }, 71 { 72 "StopOffset": 1.0, 73 "PaletteIndex": 7, 74 "Alpha": 0.4, 75 }, 76 ], 77 }, 78 "x0": 7, 79 "y0": 8, 80 "r0": 9, 81 "x1": 10, 82 "y1": 11, 83 "r1": 12, 84 }, 85 "Transform": { 86 "xx": -13.0, 87 "yx": 14.0, 88 "xy": 15.0, 89 "yy": -17.0, 90 "dx": 18.0, 91 "dy": 19.0, 92 "VarIndexBase": 3, 93 }, 94 }, 95 "Glyph": "glyph00013", 96 }, 97 { 98 "Format": int(ot.PaintFormat.PaintVarTranslate), 99 "Paint": { 100 "Format": int(ot.PaintFormat.PaintRotate), 101 "Paint": { 102 "Format": int(ot.PaintFormat.PaintVarSkew), 103 "Paint": { 104 "Format": int(ot.PaintFormat.PaintGlyph), 105 "Paint": { 106 "Format": int(ot.PaintFormat.PaintSolid), 107 "PaletteIndex": 2, 108 "Alpha": 0.5, 109 }, 110 "Glyph": "glyph00011", 111 }, 112 "xSkewAngle": -11.0, 113 "ySkewAngle": 5.0, 114 "VarIndexBase": 4, 115 }, 116 "angle": 45.0, 117 }, 118 "dx": 257.0, 119 "dy": 258.0, 120 "VarIndexBase": 5, 121 }, 122 ], 123 }, 124 "glyph00014": { 125 "Format": int(ot.PaintFormat.PaintComposite), 126 "SourcePaint": { 127 "Format": int(ot.PaintFormat.PaintColrGlyph), 128 "Glyph": "glyph00010", 129 }, 130 "CompositeMode": "src_over", 131 "BackdropPaint": { 132 "Format": int(ot.PaintFormat.PaintTransform), 133 "Paint": { 134 "Format": int(ot.PaintFormat.PaintColrGlyph), 135 "Glyph": "glyph00010", 136 }, 137 "Transform": { 138 "xx": 1.0, 139 "yx": 0.0, 140 "xy": 0.0, 141 "yy": 1.0, 142 "dx": 300.0, 143 "dy": 0.0, 144 }, 145 }, 146 }, 147 "glyph00015": { 148 "Format": int(ot.PaintFormat.PaintGlyph), 149 "Paint": { 150 "Format": int(ot.PaintFormat.PaintSweepGradient), 151 "ColorLine": { 152 "Extend": "pad", 153 "ColorStop": [ 154 { 155 "StopOffset": 0.0, 156 "PaletteIndex": 3, 157 "Alpha": 1.0, 158 }, 159 { 160 "StopOffset": 1.0, 161 "PaletteIndex": 5, 162 "Alpha": 1.0, 163 }, 164 ], 165 }, 166 "centerX": 259, 167 "centerY": 300, 168 "startAngle": 45.0, 169 "endAngle": 135.0, 170 }, 171 "Glyph": "glyph00011", 172 }, 173 "glyph00016": { 174 "Format": int(ot.PaintFormat.PaintColrLayers), 175 "Layers": [ 176 { 177 "Format": int(ot.PaintFormat.PaintGlyph), 178 "Paint": { 179 "Format": int(ot.PaintFormat.PaintVarSolid), 180 "PaletteIndex": 2, 181 "Alpha": 0.5, 182 "VarIndexBase": 6, 183 }, 184 "Glyph": "glyph00011", 185 }, 186 { 187 "Format": int(ot.PaintFormat.PaintGlyph), 188 "Paint": { 189 "Format": int(ot.PaintFormat.PaintVarLinearGradient), 190 "ColorLine": { 191 "Extend": "repeat", 192 "ColorStop": [ 193 { 194 "StopOffset": 0.0, 195 "PaletteIndex": 3, 196 "Alpha": 1.0, 197 "VarIndexBase": 7, 198 }, 199 { 200 "StopOffset": 0.5, 201 "PaletteIndex": 4, 202 "Alpha": 1.0, 203 "VarIndexBase": 8, 204 }, 205 { 206 "StopOffset": 1.0, 207 "PaletteIndex": 5, 208 "Alpha": 1.0, 209 "VarIndexBase": 9, 210 }, 211 ], 212 }, 213 "x0": 1, 214 "y0": 2, 215 "x1": -3, 216 "y1": -4, 217 "x2": 5, 218 "y2": 6, 219 "VarIndexBase": 0xFFFFFFFF, 220 }, 221 "Glyph": "glyph00012", 222 }, 223 ], 224 }, 225 # When PaintColrLayers contains more than 255 layers, we build a tree 226 # of nested PaintColrLayers of max 255 items (NumLayers field is a uint8). 227 # Below we test that unbuildColrV1 restores a flat list of layers without 228 # nested PaintColrLayers. 229 "glyph00017": { 230 "Format": int(ot.PaintFormat.PaintColrLayers), 231 "Layers": [ 232 { 233 "Format": int(ot.PaintFormat.PaintGlyph), 234 "Paint": { 235 "Format": int(ot.PaintFormat.PaintSolid), 236 "PaletteIndex": i, 237 "Alpha": 1.0, 238 }, 239 "Glyph": "glyph{str(18 + i).zfill(5)}", 240 } 241 for i in range(256) 242 ], 243 }, 244} 245 246 247def test_unbuildColrV1(): 248 layers, baseGlyphs = buildColrV1(TEST_COLOR_GLYPHS) 249 colorGlyphs = unbuildColrV1(layers, baseGlyphs) 250 assert colorGlyphs == TEST_COLOR_GLYPHS 251 252 253def test_unbuildColrV1_noLayers(): 254 _, baseGlyphsV1 = buildColrV1(TEST_COLOR_GLYPHS) 255 # Just looking to see we don't crash 256 unbuildColrV1(None, baseGlyphsV1) 257