diff options
Diffstat (limited to 'Tests/colorLib/builder_test.py')
-rw-r--r-- | Tests/colorLib/builder_test.py | 850 |
1 files changed, 523 insertions, 327 deletions
diff --git a/Tests/colorLib/builder_test.py b/Tests/colorLib/builder_test.py index 81da2818..7259db4d 100644 --- a/Tests/colorLib/builder_test.py +++ b/Tests/colorLib/builder_test.py @@ -1,8 +1,9 @@ +from copy import deepcopy from fontTools.ttLib import newTable from fontTools.ttLib.tables import otTables as ot from fontTools.colorLib import builder from fontTools.colorLib.geometry import round_start_circle_stable_containment, Circle -from fontTools.colorLib.builder import LayerV1ListBuilder, _build_n_ary_tree +from fontTools.colorLib.builder import LayerListBuilder, _build_n_ary_tree from fontTools.colorLib.table_builder import TableBuilder from fontTools.colorLib.errors import ColorLibError import pytest @@ -10,11 +11,11 @@ from typing import List def _build(cls, source): - return LayerV1ListBuilder().tableBuilder.build(cls, source) + return LayerListBuilder().tableBuilder.build(cls, source) def _buildPaint(source): - return LayerV1ListBuilder().buildPaint(source) + return LayerListBuilder().buildPaint(source) def test_buildCOLR_v0(): @@ -231,92 +232,63 @@ def test_buildCPAL_invalid_color(): builder.buildCPAL([[(0, 0, 0, 0)], [(1, 1, -1, 2)]]) -def test_buildColorIndex_Minimal(): - c = _build(ot.ColorIndex, 1) - assert c.PaletteIndex == 1 - assert c.Alpha == 1.0 - - -def test_buildVarColorIndex_Minimal(): - c = _build(ot.VarColorIndex, 1) - assert c.PaletteIndex == 1 - assert c.Alpha.value == 1.0 - assert c.Alpha.varIdx == 0 - - -def test_buildColorIndex(): - c = _build(ot.ColorIndex, (1, 0.5)) - assert c.PaletteIndex == 1 - assert c.Alpha == 0.5 - - -def test_buildVarColorIndex(): - c = _build(ot.VarColorIndex, (3, builder.VariableFloat(0.5, varIdx=2))) - assert c.PaletteIndex == 3 - assert c.Alpha.value == 0.5 - assert c.Alpha.varIdx == 2 - - def test_buildPaintSolid(): p = _buildPaint((ot.PaintFormat.PaintSolid, 0)) assert p.Format == ot.PaintFormat.PaintSolid - assert p.Color.PaletteIndex == 0 - assert p.Color.Alpha == 1.0 + assert p.PaletteIndex == 0 + assert p.Alpha == 1.0 def test_buildPaintSolid_Alpha(): - p = _buildPaint((ot.PaintFormat.PaintSolid, (1, 0.5))) + p = _buildPaint((ot.PaintFormat.PaintSolid, 1, 0.5)) assert p.Format == ot.PaintFormat.PaintSolid - assert p.Color.PaletteIndex == 1 - assert p.Color.Alpha == 0.5 + assert p.PaletteIndex == 1 + assert p.Alpha == 0.5 def test_buildPaintVarSolid(): - p = _buildPaint( - (ot.PaintFormat.PaintVarSolid, (3, builder.VariableFloat(0.5, varIdx=2))) - ) + p = _buildPaint((ot.PaintFormat.PaintVarSolid, 3, 0.5, 2)) assert p.Format == ot.PaintFormat.PaintVarSolid - assert p.Color.PaletteIndex == 3 - assert p.Color.Alpha.value == 0.5 - assert p.Color.Alpha.varIdx == 2 + assert p.PaletteIndex == 3 + assert p.Alpha == 0.5 + assert p.VarIndexBase == 2 def test_buildVarColorStop_DefaultAlpha(): s = _build(ot.ColorStop, (0.1, 2)) assert s.StopOffset == 0.1 - assert s.Color.PaletteIndex == 2 - assert s.Color.Alpha == builder._DEFAULT_ALPHA.value + assert s.PaletteIndex == 2 + assert s.Alpha == builder._DEFAULT_ALPHA def test_buildVarColorStop_DefaultAlpha(): s = _build(ot.VarColorStop, (0.1, 2)) - assert s.StopOffset == builder.VariableFloat(0.1) - assert s.Color.PaletteIndex == 2 - assert s.Color.Alpha == builder._DEFAULT_ALPHA + assert s.StopOffset == 0.1 + assert s.PaletteIndex == 2 + assert s.Alpha == builder._DEFAULT_ALPHA def test_buildColorStop(): - s = _build( - ot.ColorStop, {"StopOffset": 0.2, "Color": {"PaletteIndex": 3, "Alpha": 0.4}} - ) + s = _build(ot.ColorStop, {"StopOffset": 0.2, "PaletteIndex": 3, "Alpha": 0.4}) assert s.StopOffset == 0.2 - assert s.Color == _build(ot.ColorIndex, (3, 0.4)) + assert s.PaletteIndex == 3 + assert s.Alpha == 0.4 def test_buildColorStop_Variable(): s = _build( ot.VarColorStop, { - "StopOffset": builder.VariableFloat(0.0, varIdx=1), - "Color": { - "PaletteIndex": 0, - "Alpha": builder.VariableFloat(0.3, varIdx=2), - }, + "StopOffset": 0.0, + "PaletteIndex": 0, + "Alpha": 0.3, + "VarIndexBase": 1, }, ) - assert s.StopOffset == builder.VariableFloat(0.0, varIdx=1) - assert s.Color.PaletteIndex == 0 - assert s.Color.Alpha == builder.VariableFloat(0.3, varIdx=2) + assert s.StopOffset == 0.0 + assert s.PaletteIndex == 0 + assert s.Alpha == 0.3 + assert s.VarIndexBase == 1 def test_buildColorLine_StopList(): @@ -325,7 +297,7 @@ def test_buildColorLine_StopList(): cline = _build(ot.ColorLine, {"ColorStop": stops}) assert cline.Extend == builder.ExtendMode.PAD assert cline.StopCount == 3 - assert [(cs.StopOffset, cs.Color.PaletteIndex) for cs in cline.ColorStop] == stops + assert [(cs.StopOffset, cs.PaletteIndex) for cs in cline.ColorStop] == stops cline = _build(ot.ColorLine, {"Extend": "pad", "ColorStop": stops}) assert cline.Extend == builder.ExtendMode.PAD @@ -343,86 +315,98 @@ def test_buildColorLine_StopList(): cline = _build( ot.ColorLine, {"ColorStop": [_build(ot.ColorStop, s) for s in stops]} ) - assert [(cs.StopOffset, cs.Color.PaletteIndex) for cs in cline.ColorStop] == stops + assert [(cs.StopOffset, cs.PaletteIndex) for cs in cline.ColorStop] == stops def test_buildVarColorLine_StopMap(): stops = [ - {"StopOffset": (0.0, (1,)), "Color": {"PaletteIndex": 0, "Alpha": (0.5, 2)}}, - {"StopOffset": (1.0, (3,)), "Color": {"PaletteIndex": 1, "Alpha": (0.3, 4)}}, + {"StopOffset": 0.0, "PaletteIndex": 0, "Alpha": 0.5, "VarIndexBase": 1}, + {"StopOffset": 1.0, "PaletteIndex": 1, "Alpha": 0.3, "VarIndexBase": 3}, ] cline = _build(ot.VarColorLine, {"ColorStop": stops}) assert [ { "StopOffset": cs.StopOffset, - "Color": { - "PaletteIndex": cs.Color.PaletteIndex, - "Alpha": cs.Color.Alpha, - }, + "PaletteIndex": cs.PaletteIndex, + "Alpha": cs.Alpha, + "VarIndexBase": cs.VarIndexBase, } for cs in cline.ColorStop ] == stops -def checkBuildAffine2x3(cls, resultMapFn): +def checkBuildAffine2x3(cls, variable=False): matrix = _build(cls, (1.5, 0, 0.5, 2.0, 1.0, -3.0)) - assert matrix.xx == resultMapFn(1.5) - assert matrix.yx == resultMapFn(0.0) - assert matrix.xy == resultMapFn(0.5) - assert matrix.yy == resultMapFn(2.0) - assert matrix.dx == resultMapFn(1.0) - assert matrix.dy == resultMapFn(-3.0) + assert matrix.xx == 1.5 + assert matrix.yx == 0.0 + assert matrix.xy == 0.5 + assert matrix.yy == 2.0 + assert matrix.dx == 1.0 + assert matrix.dy == -3.0 + if variable: + assert matrix.VarIndexBase == 0xFFFFFFFF def test_buildAffine2x3(): - checkBuildAffine2x3(ot.Affine2x3, lambda v: v) + checkBuildAffine2x3(ot.Affine2x3) def test_buildVarAffine2x3(): - checkBuildAffine2x3(ot.VarAffine2x3, builder.VariableFloat) + checkBuildAffine2x3(ot.VarAffine2x3, variable=True) -def _sample_stops(cls): - return [ - _build(cls, (0.0, 0)), - _build(cls, (0.5, 1)), - _build(cls, (1.0, (2, 0.8))), +def _sample_stops(variable): + cls = ot.ColorStop if not variable else ot.VarColorStop + stop_sources = [ + {"StopOffset": 0.0, "PaletteIndex": 0}, + {"StopOffset": 0.5, "PaletteIndex": 1}, + {"StopOffset": 1.0, "PaletteIndex": 2, "Alpha": 0.8}, ] + if variable: + for i, src in enumerate(stop_sources, start=123): + src["VarIndexBase"] = i + return [_build(cls, src) for src in stop_sources] def _is_var(fmt): return fmt.name.startswith("PaintVar") -def checkBuildPaintLinearGradient(fmt): - if _is_var(fmt): - inputMapFn = builder.VariableInt - outputMapFn = lambda v: v.value - color_stops = _sample_stops(ot.VarColorStop) - else: - inputMapFn = outputMapFn = lambda v: v - color_stops = _sample_stops(ot.ColorStop) +def _is_around_center(fmt): + return fmt.name.endswith("AroundCenter") - x0, y0, x1, y1, x2, y2 = tuple(inputMapFn(v) for v in (1, 2, 3, 4, 5, 6)) - gradient = _buildPaint( - { - "Format": fmt, - "ColorLine": {"ColorStop": color_stops}, - "x0": x0, - "y0": y0, - "x1": x1, - "y1": y1, - "x2": x2, - "y2": y2, - }, - ) + +def _is_uniform_scale(fmt): + return "ScaleUniform" in fmt.name + + +def checkBuildPaintLinearGradient(fmt): + variable = _is_var(fmt) + color_stops = _sample_stops(variable) + + x0, y0, x1, y1, x2, y2 = (1, 2, 3, 4, 5, 6) + source = { + "Format": fmt, + "ColorLine": {"ColorStop": color_stops}, + "x0": x0, + "y0": y0, + "x1": x1, + "y1": y1, + "x2": x2, + "y2": y2, + } + if variable: + source["VarIndexBase"] = 7 + gradient = _buildPaint(source) assert gradient.ColorLine.Extend == builder.ExtendMode.PAD assert gradient.ColorLine.ColorStop == color_stops gradient = _buildPaint(gradient) - assert (outputMapFn(gradient.x0), outputMapFn(gradient.y0)) == (1, 2) - assert (outputMapFn(gradient.x1), outputMapFn(gradient.y1)) == (3, 4) - assert (outputMapFn(gradient.x2), outputMapFn(gradient.y2)) == (5, 6) + assert (gradient.x0, gradient.y0) == (1, 2) + assert (gradient.x1, gradient.y1) == (3, 4) + assert (gradient.x2, gradient.y2) == (5, 6) + if variable: + assert gradient.VarIndexBase == 7 def test_buildPaintLinearGradient(): @@ -430,57 +414,60 @@ def test_buildPaintLinearGradient(): checkBuildPaintLinearGradient(ot.PaintFormat.PaintLinearGradient) -def test_buildVarPaintLinearGradient(): +def test_buildPaintVarLinearGradient(): assert _is_var(ot.PaintFormat.PaintVarLinearGradient) checkBuildPaintLinearGradient(ot.PaintFormat.PaintVarLinearGradient) def checkBuildPaintRadialGradient(fmt): - if _is_var(fmt): - inputMapFn = builder.VariableInt - outputMapFn = lambda v: v - color_stops = _sample_stops(ot.VarColorStop) - line_cls = ot.VarColorLine - else: - inputMapFn = outputMapFn = lambda v: v - color_stops = _sample_stops(ot.ColorStop) - line_cls = ot.ColorLine + variable = _is_var(fmt) + color_stops = _sample_stops(variable) + line_cls = ot.VarColorLine if variable else ot.ColorLine color_line = _build( line_cls, {"ColorStop": color_stops, "Extend": builder.ExtendMode.REPEAT} ) - c0 = (inputMapFn(100), inputMapFn(200)) - c1 = (inputMapFn(150), inputMapFn(250)) - r0 = inputMapFn(10) - r1 = inputMapFn(5) + c0 = (100, 200) + c1 = (150, 250) + r0 = 10 + r1 = 5 + varIndexBase = 0 + + source = [fmt, color_line, *c0, r0, *c1, r1] + if variable: + source.append(varIndexBase) - gradient = _build(ot.Paint, (fmt, color_line, *c0, r0, *c1, r1)) + gradient = _build(ot.Paint, tuple(source)) assert gradient.Format == fmt assert gradient.ColorLine == color_line - assert (outputMapFn(gradient.x0), outputMapFn(gradient.y0)) == c0 - assert (outputMapFn(gradient.x1), outputMapFn(gradient.y1)) == c1 - assert outputMapFn(gradient.r0) == r0 - assert outputMapFn(gradient.r1) == r1 - - gradient = _build( - ot.Paint, - { - "Format": fmt, - "ColorLine": {"ColorStop": color_stops}, - "x0": c0[0], - "y0": c0[1], - "x1": c1[0], - "y1": c1[1], - "r0": r0, - "r1": r1, - }, - ) + assert (gradient.x0, gradient.y0) == c0 + assert (gradient.x1, gradient.y1) == c1 + assert gradient.r0 == r0 + assert gradient.r1 == r1 + if variable: + assert gradient.VarIndexBase == varIndexBase + + source = { + "Format": fmt, + "ColorLine": {"ColorStop": color_stops}, + "x0": c0[0], + "y0": c0[1], + "x1": c1[0], + "y1": c1[1], + "r0": r0, + "r1": r1, + } + if variable: + source["VarIndexBase"] = varIndexBase + gradient = _build(ot.Paint, source) assert gradient.ColorLine.Extend == builder.ExtendMode.PAD assert gradient.ColorLine.ColorStop == color_stops - assert (outputMapFn(gradient.x0), outputMapFn(gradient.y0)) == c0 - assert (outputMapFn(gradient.x1), outputMapFn(gradient.y1)) == c1 - assert outputMapFn(gradient.r0) == r0 - assert outputMapFn(gradient.r1) == r1 + assert (gradient.x0, gradient.y0) == c0 + assert (gradient.x1, gradient.y1) == c1 + assert gradient.r0 == r0 + assert gradient.r1 == r1 + if variable: + assert gradient.VarIndexBase == varIndexBase def test_buildPaintRadialGradient(): @@ -494,33 +481,26 @@ def test_buildPaintVarRadialGradient(): def checkPaintSweepGradient(fmt): - if _is_var(fmt): - outputMapFn = lambda v: v.value - else: - outputMapFn = lambda v: v - - paint = _buildPaint( - { - "Format": fmt, - "ColorLine": { - "ColorStop": ( - (0.0, 0), - (0.5, 1), - (1.0, (2, 0.8)), - ) - }, - "centerX": 127, - "centerY": 129, - "startAngle": 15, - "endAngle": 42, - } - ) + variable = _is_var(fmt) + source = { + "Format": fmt, + "ColorLine": {"ColorStop": _sample_stops(variable)}, + "centerX": 127, + "centerY": 129, + "startAngle": 15, + "endAngle": 42, + } + if variable: + source["VarIndexBase"] = 666 + paint = _buildPaint(source) assert paint.Format == fmt - assert outputMapFn(paint.centerX) == 127 - assert outputMapFn(paint.centerY) == 129 - assert outputMapFn(paint.startAngle) == 15 - assert outputMapFn(paint.endAngle) == 42 + assert paint.centerX == 127 + assert paint.centerY == 129 + assert paint.startAngle == 15 + assert paint.endAngle == 42 + if variable: + assert paint.VarIndexBase == 666 def test_buildPaintSweepGradient(): @@ -548,22 +528,19 @@ def test_buildPaintGlyph_Solid(): assert layer.Format == ot.PaintFormat.PaintGlyph assert layer.Glyph == "a" assert layer.Paint.Format == ot.PaintFormat.PaintSolid - assert layer.Paint.Color.PaletteIndex == 2 + assert layer.Paint.PaletteIndex == 2 layer = _build( ot.Paint, ( ot.PaintFormat.PaintGlyph, - ( - ot.PaintFormat.PaintSolid, - (3, 0.9), - ), + (ot.PaintFormat.PaintSolid, 3, 0.9), "a", ), ) assert layer.Paint.Format == ot.PaintFormat.PaintSolid - assert layer.Paint.Color.PaletteIndex == 3 - assert layer.Paint.Color.Alpha == 0.9 + assert layer.Paint.PaletteIndex == 3 + assert layer.Paint.Alpha == 0.9 def test_buildPaintGlyph_VarLinearGradient(): @@ -586,14 +563,14 @@ def test_buildPaintGlyph_VarLinearGradient(): assert layer.Format == ot.PaintFormat.PaintGlyph assert layer.Glyph == "a" assert layer.Paint.Format == ot.PaintFormat.PaintVarLinearGradient - assert layer.Paint.ColorLine.ColorStop[0].StopOffset.value == 0.0 - assert layer.Paint.ColorLine.ColorStop[0].Color.PaletteIndex == 3 - assert layer.Paint.ColorLine.ColorStop[1].StopOffset.value == 1.0 - assert layer.Paint.ColorLine.ColorStop[1].Color.PaletteIndex == 4 - assert layer.Paint.x0.value == 100 - assert layer.Paint.y0.value == 200 - assert layer.Paint.x1.value == 150 - assert layer.Paint.y1.value == 250 + assert layer.Paint.ColorLine.ColorStop[0].StopOffset == 0.0 + assert layer.Paint.ColorLine.ColorStop[0].PaletteIndex == 3 + assert layer.Paint.ColorLine.ColorStop[1].StopOffset == 1.0 + assert layer.Paint.ColorLine.ColorStop[1].PaletteIndex == 4 + assert layer.Paint.x0 == 100 + assert layer.Paint.y0 == 200 + assert layer.Paint.x1 == 150 + assert layer.Paint.y1 == 250 def test_buildPaintGlyph_RadialGradient(): @@ -607,7 +584,7 @@ def test_buildPaintGlyph_RadialGradient(): "pad", [ (0.0, 5), - {"StopOffset": 0.5, "Color": {"PaletteIndex": 6, "Alpha": 0.8}}, + {"StopOffset": 0.5, "PaletteIndex": 6, "Alpha": 0.8}, (1.0, 7), ], ), @@ -624,12 +601,12 @@ def test_buildPaintGlyph_RadialGradient(): assert layer.Format == ot.PaintFormat.PaintGlyph assert layer.Paint.Format == ot.PaintFormat.PaintRadialGradient assert layer.Paint.ColorLine.ColorStop[0].StopOffset == 0.0 - assert layer.Paint.ColorLine.ColorStop[0].Color.PaletteIndex == 5 + assert layer.Paint.ColorLine.ColorStop[0].PaletteIndex == 5 assert layer.Paint.ColorLine.ColorStop[1].StopOffset == 0.5 - assert layer.Paint.ColorLine.ColorStop[1].Color.PaletteIndex == 6 - assert layer.Paint.ColorLine.ColorStop[1].Color.Alpha == 0.8 + assert layer.Paint.ColorLine.ColorStop[1].PaletteIndex == 6 + assert layer.Paint.ColorLine.ColorStop[1].Alpha == 0.8 assert layer.Paint.ColorLine.ColorStop[2].StopOffset == 1.0 - assert layer.Paint.ColorLine.ColorStop[2].Color.PaletteIndex == 7 + assert layer.Paint.ColorLine.ColorStop[2].PaletteIndex == 7 assert layer.Paint.x0 == 50 assert layer.Paint.y0 == 50 assert layer.Paint.r0 == 30 @@ -651,7 +628,7 @@ def test_buildPaintGlyph_Dict_Solid(): assert layer.Format == ot.PaintFormat.PaintGlyph assert layer.Glyph == "a" assert layer.Paint.Format == ot.PaintFormat.PaintSolid - assert layer.Paint.Color.PaletteIndex == 1 + assert layer.Paint.PaletteIndex == 1 def test_buildPaintGlyph_Dict_VarLinearGradient(): @@ -673,7 +650,7 @@ def test_buildPaintGlyph_Dict_VarLinearGradient(): assert layer.Format == ot.PaintFormat.PaintGlyph assert layer.Glyph == "a" assert layer.Paint.Format == ot.PaintFormat.PaintVarLinearGradient - assert layer.Paint.ColorLine.ColorStop[0].StopOffset.value == 0.0 + assert layer.Paint.ColorLine.ColorStop[0].StopOffset == 0.0 def test_buildPaintGlyph_Dict_RadialGradient(): @@ -704,19 +681,21 @@ def test_buildPaintColrGlyph(): def checkBuildPaintTransform(fmt): - if _is_var(fmt): - inputMapFn = builder.VariableFloat - outputMapFn = lambda v: v.value + variable = _is_var(fmt) + if variable: affine_cls = ot.VarAffine2x3 else: - inputMapFn = outputMapFn = lambda v: v affine_cls = ot.Affine2x3 + affine_src = [1, 2, 3, 4, 5, 6] + if variable: + affine_src.append(7) + paint = _buildPaint( ( int(fmt), - (ot.PaintFormat.PaintGlyph, (ot.PaintFormat.PaintSolid, (0, 1.0)), "a"), - _build(affine_cls, (1, 2, 3, 4, 5, 6)), + (ot.PaintFormat.PaintGlyph, (ot.PaintFormat.PaintSolid, 0, 1.0), "a"), + _build(affine_cls, tuple(affine_src)), ), ) @@ -724,18 +703,23 @@ def checkBuildPaintTransform(fmt): assert paint.Paint.Format == ot.PaintFormat.PaintGlyph assert paint.Paint.Paint.Format == ot.PaintFormat.PaintSolid - assert outputMapFn(paint.Transform.xx) == 1.0 - assert outputMapFn(paint.Transform.yx) == 2.0 - assert outputMapFn(paint.Transform.xy) == 3.0 - assert outputMapFn(paint.Transform.yy) == 4.0 - assert outputMapFn(paint.Transform.dx) == 5.0 - assert outputMapFn(paint.Transform.dy) == 6.0 - + assert paint.Transform.xx == 1.0 + assert paint.Transform.yx == 2.0 + assert paint.Transform.xy == 3.0 + assert paint.Transform.yy == 4.0 + assert paint.Transform.dx == 5.0 + assert paint.Transform.dy == 6.0 + if variable: + assert paint.Transform.VarIndexBase == 7 + + affine_src = [1, 2, 3, 0.3333, 10, 10] + if variable: + affine_src.append(456) # VarIndexBase paint = _build( ot.Paint, { "Format": fmt, - "Transform": (1, 2, 3, 0.3333, 10, 10), + "Transform": tuple(affine_src), "Paint": { "Format": int(ot.PaintFormat.PaintRadialGradient), "ColorLine": {"ColorStop": [(0.0, 0), (1.0, 1)]}, @@ -750,12 +734,14 @@ def checkBuildPaintTransform(fmt): ) assert paint.Format == fmt - assert outputMapFn(paint.Transform.xx) == 1.0 - assert outputMapFn(paint.Transform.yx) == 2.0 - assert outputMapFn(paint.Transform.xy) == 3.0 - assert outputMapFn(paint.Transform.yy) == 0.3333 - assert outputMapFn(paint.Transform.dx) == 10 - assert outputMapFn(paint.Transform.dy) == 10 + assert paint.Transform.xx == 1.0 + assert paint.Transform.yx == 2.0 + assert paint.Transform.xy == 3.0 + assert paint.Transform.yy == 0.3333 + assert paint.Transform.dx == 10 + assert paint.Transform.dy == 10 + if variable: + assert paint.Transform.VarIndexBase == 456 assert paint.Paint.Format == ot.PaintFormat.PaintRadialGradient @@ -794,7 +780,8 @@ def test_buildPaintComposite(): "Glyph": "a", "Paint": { "Format": ot.PaintFormat.PaintSolid, - "Color": (0, 1.0), + "PaletteIndex": 0, + "Alpha": 0.5, }, }, }, @@ -805,44 +792,44 @@ def test_buildPaintComposite(): assert composite.SourcePaint.SourcePaint.Format == ot.PaintFormat.PaintGlyph assert composite.SourcePaint.SourcePaint.Glyph == "c" assert composite.SourcePaint.SourcePaint.Paint.Format == ot.PaintFormat.PaintSolid - assert composite.SourcePaint.SourcePaint.Paint.Color.PaletteIndex == 2 + assert composite.SourcePaint.SourcePaint.Paint.PaletteIndex == 2 assert composite.SourcePaint.CompositeMode == ot.CompositeMode.SRC_OVER assert composite.SourcePaint.BackdropPaint.Format == ot.PaintFormat.PaintGlyph assert composite.SourcePaint.BackdropPaint.Glyph == "b" assert composite.SourcePaint.BackdropPaint.Paint.Format == ot.PaintFormat.PaintSolid - assert composite.SourcePaint.BackdropPaint.Paint.Color.PaletteIndex == 1 + assert composite.SourcePaint.BackdropPaint.Paint.PaletteIndex == 1 assert composite.CompositeMode == ot.CompositeMode.SRC_OVER assert composite.BackdropPaint.Format == ot.PaintFormat.PaintGlyph assert composite.BackdropPaint.Glyph == "a" assert composite.BackdropPaint.Paint.Format == ot.PaintFormat.PaintSolid - assert composite.BackdropPaint.Paint.Color.PaletteIndex == 0 + assert composite.BackdropPaint.Paint.PaletteIndex == 0 + assert composite.BackdropPaint.Paint.Alpha == 0.5 def checkBuildPaintTranslate(fmt): - if _is_var(fmt): - inputMapFn = builder.VariableInt - outputMapFn = lambda v: v.value - else: - inputMapFn = outputMapFn = lambda v: v + variable = _is_var(fmt) - paint = _build( - ot.Paint, - { - "Format": fmt, - "Paint": ( - ot.PaintFormat.PaintGlyph, - (ot.PaintFormat.PaintSolid, (0, 1.0)), - "a", - ), - "dx": 123, - "dy": -345, - }, - ) + source = { + "Format": fmt, + "Paint": ( + ot.PaintFormat.PaintGlyph, + (ot.PaintFormat.PaintSolid, 0, 1.0), + "a", + ), + "dx": 123, + "dy": -345, + } + if variable: + source["VarIndexBase"] = 678 + + paint = _build(ot.Paint, source) assert paint.Format == fmt assert paint.Paint.Format == ot.PaintFormat.PaintGlyph - assert outputMapFn(paint.dx) == 123 - assert outputMapFn(paint.dy) == -345 + assert paint.dx == 123 + assert paint.dy == -345 + if variable: + assert paint.VarIndexBase == 678 def test_buildPaintTranslate(): @@ -855,86 +842,212 @@ def test_buildPaintVarTranslate(): checkBuildPaintTranslate(ot.PaintFormat.PaintVarTranslate) -def checkBuildPaintRotate(fmt): - if _is_var(fmt): - inputMapFn = builder.VariableInt - outputMapFn = lambda v: v.value +def checkBuildPaintScale(fmt): + variable = _is_var(fmt) + around_center = _is_around_center(fmt) + uniform = _is_uniform_scale(fmt) + + source = { + "Format": fmt, + "Paint": ( + ot.PaintFormat.PaintGlyph, + (ot.PaintFormat.PaintSolid, 0, 1.0), + "a", + ), + } + if uniform: + source["scale"] = 1.5 else: - inputMapFn = outputMapFn = lambda v: v + source["scaleX"] = 1.0 + source["scaleY"] = 2.0 + if around_center: + source["centerX"] = 127 + source["centerY"] = 129 + if variable: + source["VarIndexBase"] = 666 - paint = _build( - ot.Paint, - { - "Format": fmt, - "Paint": ( - ot.PaintFormat.PaintGlyph, - (ot.PaintFormat.PaintSolid, (0, 1.0)), - "a", - ), - "angle": 15, - "centerX": 127, - "centerY": 129, - }, - ) + paint = _build(ot.Paint, source) + + assert paint.Format == fmt + assert paint.Paint.Format == ot.PaintFormat.PaintGlyph + if uniform: + assert paint.scale == 1.5 + else: + assert paint.scaleX == 1.0 + assert paint.scaleY == 2.0 + if around_center: + assert paint.centerX == 127 + assert paint.centerY == 129 + if variable: + assert paint.VarIndexBase == 666 + + +def test_buildPaintScale(): + assert not _is_var(ot.PaintFormat.PaintScale) + assert not _is_uniform_scale(ot.PaintFormat.PaintScale) + assert not _is_around_center(ot.PaintFormat.PaintScale) + checkBuildPaintScale(ot.PaintFormat.PaintScale) + + +def test_buildPaintVarScale(): + assert _is_var(ot.PaintFormat.PaintVarScale) + assert not _is_uniform_scale(ot.PaintFormat.PaintVarScale) + assert not _is_around_center(ot.PaintFormat.PaintVarScale) + checkBuildPaintScale(ot.PaintFormat.PaintVarScale) + + +def test_buildPaintScaleAroundCenter(): + assert not _is_var(ot.PaintFormat.PaintScaleAroundCenter) + assert not _is_uniform_scale(ot.PaintFormat.PaintScaleAroundCenter) + assert _is_around_center(ot.PaintFormat.PaintScaleAroundCenter) + checkBuildPaintScale(ot.PaintFormat.PaintScaleAroundCenter) + + +def test_buildPaintVarScaleAroundCenter(): + assert _is_var(ot.PaintFormat.PaintVarScaleAroundCenter) + assert not _is_uniform_scale(ot.PaintFormat.PaintScaleAroundCenter) + assert _is_around_center(ot.PaintFormat.PaintVarScaleAroundCenter) + checkBuildPaintScale(ot.PaintFormat.PaintVarScaleAroundCenter) + + +def test_buildPaintScaleUniform(): + assert not _is_var(ot.PaintFormat.PaintScaleUniform) + assert _is_uniform_scale(ot.PaintFormat.PaintScaleUniform) + assert not _is_around_center(ot.PaintFormat.PaintScaleUniform) + checkBuildPaintScale(ot.PaintFormat.PaintScaleUniform) + + +def test_buildPaintVarScaleUniform(): + assert _is_var(ot.PaintFormat.PaintVarScaleUniform) + assert _is_uniform_scale(ot.PaintFormat.PaintVarScaleUniform) + assert not _is_around_center(ot.PaintFormat.PaintVarScaleUniform) + checkBuildPaintScale(ot.PaintFormat.PaintVarScaleUniform) + + +def test_buildPaintScaleUniformAroundCenter(): + assert not _is_var(ot.PaintFormat.PaintScaleUniformAroundCenter) + assert _is_uniform_scale(ot.PaintFormat.PaintScaleUniformAroundCenter) + assert _is_around_center(ot.PaintFormat.PaintScaleUniformAroundCenter) + checkBuildPaintScale(ot.PaintFormat.PaintScaleUniformAroundCenter) + + +def test_buildPaintVarScaleUniformAroundCenter(): + assert _is_var(ot.PaintFormat.PaintVarScaleUniformAroundCenter) + assert _is_uniform_scale(ot.PaintFormat.PaintVarScaleUniformAroundCenter) + assert _is_around_center(ot.PaintFormat.PaintVarScaleUniformAroundCenter) + checkBuildPaintScale(ot.PaintFormat.PaintVarScaleUniformAroundCenter) + + +def checkBuildPaintRotate(fmt): + variable = _is_var(fmt) + around_center = _is_around_center(fmt) + + source = { + "Format": fmt, + "Paint": ( + ot.PaintFormat.PaintGlyph, + (ot.PaintFormat.PaintSolid, 0, 1.0), + "a", + ), + "angle": 15, + } + if around_center: + source["centerX"] = 127 + source["centerY"] = 129 + + paint = _build(ot.Paint, source) assert paint.Format == fmt assert paint.Paint.Format == ot.PaintFormat.PaintGlyph - assert outputMapFn(paint.angle) == 15 - assert outputMapFn(paint.centerX) == 127 - assert outputMapFn(paint.centerY) == 129 + assert paint.angle == 15 + if around_center: + assert paint.centerX == 127 + assert paint.centerY == 129 + if variable: + assert paint.VarIndexBase == 0xFFFFFFFF def test_buildPaintRotate(): assert not _is_var(ot.PaintFormat.PaintRotate) + assert not _is_around_center(ot.PaintFormat.PaintRotate) checkBuildPaintRotate(ot.PaintFormat.PaintRotate) def test_buildPaintVarRotate(): assert _is_var(ot.PaintFormat.PaintVarRotate) + assert not _is_around_center(ot.PaintFormat.PaintVarRotate) checkBuildPaintRotate(ot.PaintFormat.PaintVarRotate) +def test_buildPaintRotateAroundCenter(): + assert not _is_var(ot.PaintFormat.PaintRotateAroundCenter) + assert _is_around_center(ot.PaintFormat.PaintRotateAroundCenter) + checkBuildPaintRotate(ot.PaintFormat.PaintRotateAroundCenter) + + +def test_buildPaintVarRotateAroundCenter(): + assert _is_var(ot.PaintFormat.PaintVarRotateAroundCenter) + assert _is_around_center(ot.PaintFormat.PaintVarRotateAroundCenter) + checkBuildPaintRotate(ot.PaintFormat.PaintVarRotateAroundCenter) + + def checkBuildPaintSkew(fmt): - if _is_var(fmt): - inputMapFn = builder.VariableInt - outputMapFn = lambda v: v.value - else: - inputMapFn = outputMapFn = lambda v: v + variable = _is_var(fmt) + around_center = _is_around_center(fmt) - paint = _build( - ot.Paint, - { - "Format": fmt, - "Paint": ( - ot.PaintFormat.PaintGlyph, - (ot.PaintFormat.PaintSolid, (0, 1.0)), - "a", - ), - "xSkewAngle": 15, - "ySkewAngle": 42, - "centerX": 127, - "centerY": 129, - }, - ) + source = { + "Format": fmt, + "Paint": ( + ot.PaintFormat.PaintGlyph, + (ot.PaintFormat.PaintSolid, 0, 1.0), + "a", + ), + "xSkewAngle": 15, + "ySkewAngle": 42, + } + if around_center: + source["centerX"] = 127 + source["centerY"] = 129 + if variable: + source["VarIndexBase"] = 0 + + paint = _build(ot.Paint, source) assert paint.Format == fmt assert paint.Paint.Format == ot.PaintFormat.PaintGlyph - assert outputMapFn(paint.xSkewAngle) == 15 - assert outputMapFn(paint.ySkewAngle) == 42 - assert outputMapFn(paint.centerX) == 127 - assert outputMapFn(paint.centerY) == 129 + assert paint.xSkewAngle == 15 + assert paint.ySkewAngle == 42 + if around_center: + assert paint.centerX == 127 + assert paint.centerY == 129 + if variable: + assert paint.VarIndexBase == 0 def test_buildPaintSkew(): assert not _is_var(ot.PaintFormat.PaintSkew) + assert not _is_around_center(ot.PaintFormat.PaintSkew) checkBuildPaintSkew(ot.PaintFormat.PaintSkew) def test_buildPaintVarSkew(): assert _is_var(ot.PaintFormat.PaintVarSkew) + assert not _is_around_center(ot.PaintFormat.PaintVarSkew) checkBuildPaintSkew(ot.PaintFormat.PaintVarSkew) +def test_buildPaintSkewAroundCenter(): + assert not _is_var(ot.PaintFormat.PaintSkewAroundCenter) + assert _is_around_center(ot.PaintFormat.PaintSkewAroundCenter) + checkBuildPaintSkew(ot.PaintFormat.PaintSkewAroundCenter) + + +def test_buildPaintVarSkewAroundCenter(): + assert _is_var(ot.PaintFormat.PaintVarSkewAroundCenter) + assert _is_around_center(ot.PaintFormat.PaintVarSkewAroundCenter) + checkBuildPaintSkew(ot.PaintFormat.PaintVarSkewAroundCenter) + + def test_buildColrV1(): colorGlyphs = { "a": ( @@ -951,7 +1064,8 @@ def test_buildColrV1(): ot.PaintFormat.PaintGlyph, { "Format": int(ot.PaintFormat.PaintSolid), - "Color": {"PaletteIndex": 2, "Alpha": 0.8}, + "PaletteIndex": 2, + "Alpha": 0.8, }, "e", ), @@ -994,15 +1108,15 @@ def test_buildColrV1(): # TODO(anthrotype) should we split into two tests? - seems two distinct validations layers, baseGlyphs = builder.buildColrV1(colorGlyphs, glyphMap) assert baseGlyphs.BaseGlyphCount == len(colorGlyphs) - assert baseGlyphs.BaseGlyphV1Record[0].BaseGlyph == "d" - assert baseGlyphs.BaseGlyphV1Record[1].BaseGlyph == "a" - assert baseGlyphs.BaseGlyphV1Record[2].BaseGlyph == "g" + assert baseGlyphs.BaseGlyphPaintRecord[0].BaseGlyph == "d" + assert baseGlyphs.BaseGlyphPaintRecord[1].BaseGlyph == "a" + assert baseGlyphs.BaseGlyphPaintRecord[2].BaseGlyph == "g" layers, baseGlyphs = builder.buildColrV1(colorGlyphs) assert baseGlyphs.BaseGlyphCount == len(colorGlyphs) - assert baseGlyphs.BaseGlyphV1Record[0].BaseGlyph == "a" - assert baseGlyphs.BaseGlyphV1Record[1].BaseGlyph == "d" - assert baseGlyphs.BaseGlyphV1Record[2].BaseGlyph == "g" + assert baseGlyphs.BaseGlyphPaintRecord[0].BaseGlyph == "a" + assert baseGlyphs.BaseGlyphPaintRecord[1].BaseGlyph == "d" + assert baseGlyphs.BaseGlyphPaintRecord[2].BaseGlyph == "g" def test_buildColrV1_more_than_255_paints(): @@ -1037,16 +1151,17 @@ def test_buildColrV1_more_than_255_paints(): ) assert baseGlyphs.BaseGlyphCount == len(colorGlyphs) - assert baseGlyphs.BaseGlyphV1Record[0].BaseGlyph == "a" + assert baseGlyphs.BaseGlyphPaintRecord[0].BaseGlyph == "a" assert ( - baseGlyphs.BaseGlyphV1Record[0].Paint.Format == ot.PaintFormat.PaintColrLayers + baseGlyphs.BaseGlyphPaintRecord[0].Paint.Format + == ot.PaintFormat.PaintColrLayers ) - assert baseGlyphs.BaseGlyphV1Record[0].Paint.FirstLayerIndex == 255 - assert baseGlyphs.BaseGlyphV1Record[0].Paint.NumLayers == num_paints + 1 - 255 + assert baseGlyphs.BaseGlyphPaintRecord[0].Paint.FirstLayerIndex == 255 + assert baseGlyphs.BaseGlyphPaintRecord[0].Paint.NumLayers == num_paints + 1 - 255 def test_split_color_glyphs_by_version(): - layerBuilder = LayerV1ListBuilder() + layerBuilder = LayerListBuilder() colorGlyphs = { "a": [ ("b", 0), @@ -1113,7 +1228,7 @@ def test_build_layerv1list_empty(): # BaseGlyph, tuple form "a": ( int(ot.PaintFormat.PaintGlyph), - (2, (2, 0.8)), + (int(ot.PaintFormat.PaintSolid), 2, 0.8), "b", ), # BaseGlyph, map form @@ -1141,16 +1256,15 @@ def test_build_layerv1list_empty(): assertIsColrV1(colr) assertNoV0Content(colr) - # 2 v1 glyphs, none in LayerV1List - assert colr.table.BaseGlyphV1List.BaseGlyphCount == 2 - assert len(colr.table.BaseGlyphV1List.BaseGlyphV1Record) == 2 - assert colr.table.LayerV1List.LayerCount == 0 - assert len(colr.table.LayerV1List.Paint) == 0 + # 2 v1 glyphs, none in LayerList + assert colr.table.BaseGlyphList.BaseGlyphCount == 2 + assert len(colr.table.BaseGlyphList.BaseGlyphPaintRecord) == 2 + assert colr.table.LayerList is None def _paint_names(paints) -> List[str]: # prints a predictable string from a paint list to enable - # semi-readable assertions on a LayerV1List order. + # semi-readable assertions on a LayerList order. result = [] for paint in paints: if paint.Format == int(ot.PaintFormat.PaintGlyph): @@ -1165,7 +1279,11 @@ def _paint_names(paints) -> List[str]: def test_build_layerv1list_simple(): # Two colr glyphs, each with two layers the first of which is common # All layers use the same solid paint - solid_paint = {"Format": 2, "Color": {"PaletteIndex": 2, "Alpha": 0.8}} + solid_paint = { + "Format": int(ot.PaintFormat.PaintSolid), + "PaletteIndex": 2, + "Alpha": 0.8, + } backdrop = { "Format": int(ot.PaintFormat.PaintGlyph), "Paint": solid_paint, @@ -1182,7 +1300,7 @@ def test_build_layerv1list_simple(): "Glyph": "b_fore", } - # list => PaintColrLayers, contents should land in LayerV1List + # list => PaintColrLayers, contents should land in LayerList colr = builder.buildCOLR( { "a": ( @@ -1206,12 +1324,12 @@ def test_build_layerv1list_simple(): assertIsColrV1(colr) assertNoV0Content(colr) - # 2 v1 glyphs, 4 paints in LayerV1List + # 2 v1 glyphs, 4 paints in LayerList # A single shared backdrop isn't worth accessing by slice - assert colr.table.BaseGlyphV1List.BaseGlyphCount == 2 - assert len(colr.table.BaseGlyphV1List.BaseGlyphV1Record) == 2 - assert colr.table.LayerV1List.LayerCount == 4 - assert _paint_names(colr.table.LayerV1List.Paint) == [ + assert colr.table.BaseGlyphList.BaseGlyphCount == 2 + assert len(colr.table.BaseGlyphList.BaseGlyphPaintRecord) == 2 + assert colr.table.LayerList.LayerCount == 4 + assert _paint_names(colr.table.LayerList.Paint) == [ "back", "a_fore", "back", @@ -1221,7 +1339,11 @@ def test_build_layerv1list_simple(): def test_build_layerv1list_with_sharing(): # Three colr glyphs, each with two layers in common - solid_paint = {"Format": 2, "Color": (2, 0.8)} + solid_paint = { + "Format": int(ot.PaintFormat.PaintSolid), + "PaletteIndex": 2, + "Alpha": 0.8, + } backdrop = [ { "Format": int(ot.PaintFormat.PaintGlyph), @@ -1255,7 +1377,7 @@ def test_build_layerv1list_with_sharing(): "Glyph": "c_back", } - # list => PaintColrLayers, which means contents should be in LayerV1List + # list => PaintColrLayers, which means contents should be in LayerList colr = builder.buildCOLR( { "a": (ot.PaintFormat.PaintColrLayers, backdrop + [a_foreground]), @@ -1271,17 +1393,17 @@ def test_build_layerv1list_with_sharing(): assertIsColrV1(colr) assertNoV0Content(colr) - # 2 v1 glyphs, 4 paints in LayerV1List + # 2 v1 glyphs, 4 paints in LayerList # A single shared backdrop isn't worth accessing by slice - baseGlyphs = colr.table.BaseGlyphV1List.BaseGlyphV1Record - assert colr.table.BaseGlyphV1List.BaseGlyphCount == 3 + baseGlyphs = colr.table.BaseGlyphList.BaseGlyphPaintRecord + assert colr.table.BaseGlyphList.BaseGlyphCount == 3 assert len(baseGlyphs) == 3 assert _paint_names([b.Paint for b in baseGlyphs]) == [ "Layers[0:3]", "Layers[3:6]", "Layers[6:8]", ] - assert _paint_names(colr.table.LayerV1List.Paint) == [ + assert _paint_names(colr.table.LayerList.Paint) == [ "back1", "back2", "a_fore", @@ -1291,7 +1413,7 @@ def test_build_layerv1list_with_sharing(): "c_back", "Layers[0:2]", ] - assert colr.table.LayerV1List.LayerCount == 8 + assert colr.table.LayerList.LayerCount == 8 def test_build_layerv1list_with_overlaps(): @@ -1300,14 +1422,15 @@ def test_build_layerv1list_with_overlaps(): "Format": ot.PaintFormat.PaintGlyph, "Paint": { "Format": ot.PaintFormat.PaintSolid, - "Color": {"PaletteIndex": 2, "Alpha": 0.8}, + "PaletteIndex": 2, + "Alpha": 0.8, }, "Glyph": c, } for c in "abcdefghi" ] - # list => PaintColrLayers, which means contents should be in LayerV1List + # list => PaintColrLayers, which means contents should be in LayerList colr = builder.buildCOLR( { "a": (ot.PaintFormat.PaintColrLayers, paints[0:4]), @@ -1320,10 +1443,10 @@ def test_build_layerv1list_with_overlaps(): assertIsColrV1(colr) assertNoV0Content(colr) - baseGlyphs = colr.table.BaseGlyphV1List.BaseGlyphV1Record - # assert colr.table.BaseGlyphV1List.BaseGlyphCount == 2 + baseGlyphs = colr.table.BaseGlyphList.BaseGlyphPaintRecord + # assert colr.table.BaseGlyphList.BaseGlyphCount == 2 - assert _paint_names(colr.table.LayerV1List.Paint) == [ + assert _paint_names(colr.table.LayerList.Paint) == [ "a", "b", "c", @@ -1341,7 +1464,7 @@ def test_build_layerv1list_with_overlaps(): "Layers[4:7]", "Layers[7:11]", ] - assert colr.table.LayerV1List.LayerCount == 11 + assert colr.table.LayerList.LayerCount == 11 def test_explicit_version_1(): @@ -1397,7 +1520,11 @@ class BuildCOLRTest(object): ), ( ot.PaintFormat.PaintGlyph, - {"Format": 2, "Color": {"PaletteIndex": 2, "Alpha": 0.8}}, + { + "Format": ot.PaintFormat.PaintSolid, + "PaletteIndex": 2, + "Alpha": 0.8, + }, "c", ), ], @@ -1455,7 +1582,7 @@ class BuildCOLRTest(object): ), ( ot.PaintFormat.PaintGlyph, - (ot.PaintFormat.PaintSolid, (2, 0.8)), + (ot.PaintFormat.PaintSolid, 2, 0.8), "f", ), ], @@ -1470,14 +1597,14 @@ class BuildCOLRTest(object): assert colr.table.LayerRecordCount == 2 assert isinstance(colr.table.LayerRecordArray, ot.LayerRecordArray) - assert isinstance(colr.table.BaseGlyphV1List, ot.BaseGlyphV1List) - assert colr.table.BaseGlyphV1List.BaseGlyphCount == 1 + assert isinstance(colr.table.BaseGlyphList, ot.BaseGlyphList) + assert colr.table.BaseGlyphList.BaseGlyphCount == 1 assert isinstance( - colr.table.BaseGlyphV1List.BaseGlyphV1Record[0], ot.BaseGlyphV1Record + colr.table.BaseGlyphList.BaseGlyphPaintRecord[0], ot.BaseGlyphPaintRecord ) - assert colr.table.BaseGlyphV1List.BaseGlyphV1Record[0].BaseGlyph == "d" - assert isinstance(colr.table.LayerV1List, ot.LayerV1List) - assert colr.table.LayerV1List.Paint[0].Glyph == "e" + assert colr.table.BaseGlyphList.BaseGlyphPaintRecord[0].BaseGlyph == "d" + assert isinstance(colr.table.LayerList, ot.LayerList) + assert colr.table.LayerList.Paint[0].Glyph == "e" def test_explicit_version_0(self): colr = builder.buildCOLR({"a": [("b", 0), ("c", 1)]}, version=0) @@ -1528,12 +1655,71 @@ class BuildCOLRTest(object): }, ) - assert len(colr.table.LayerV1List.Paint) == 0, "PaintColrLayers should be gone" - assert colr.table.BaseGlyphV1List.BaseGlyphCount == 1 - paint = colr.table.BaseGlyphV1List.BaseGlyphV1Record[0].Paint + assert colr.table.LayerList is None, "PaintColrLayers should be gone" + assert colr.table.BaseGlyphList.BaseGlyphCount == 1 + paint = colr.table.BaseGlyphList.BaseGlyphPaintRecord[0].Paint assert paint.Format == ot.PaintFormat.PaintGlyph assert paint.Paint.Format == ot.PaintFormat.PaintSolid + def test_build_clip_list(self): + colr = builder.buildCOLR( + { + "a": ( + ot.PaintFormat.PaintGlyph, + (ot.PaintFormat.PaintSolid, 0), + "b", + ), + "c": ( + ot.PaintFormat.PaintGlyph, + (ot.PaintFormat.PaintSolid, 1), + "d", + ), + }, + clipBoxes={ + "a": (0, 0, 1000, 1000, 0), # optional 5th: varIndexBase + "c": (-100.8, -200.4, 1100.1, 1200.5), # floats get rounded + "e": (0, 0, 10, 10), # missing base glyph 'e' is ignored + }, + ) + + assert colr.table.ClipList.Format == 1 + clipBoxes = colr.table.ClipList.clips + assert [ + (baseGlyph, clipBox.as_tuple()) for baseGlyph, clipBox in clipBoxes.items() + ] == [ + ("a", (0, 0, 1000, 1000, 0)), + ("c", (-101, -201, 1101, 1201)), + ] + assert clipBoxes["a"].Format == 2 + assert clipBoxes["c"].Format == 1 + + def test_duplicate_base_glyphs(self): + # If > 1 base glyphs refer to equivalent list of layers we expect them to share + # the same PaintColrLayers. + layers = { + "Format": ot.PaintFormat.PaintColrLayers, + "Layers": [ + (ot.PaintFormat.PaintGlyph, (ot.PaintFormat.PaintSolid, 0), "d"), + (ot.PaintFormat.PaintGlyph, (ot.PaintFormat.PaintSolid, 1), "e"), + ], + } + # I copy the layers to ensure equality is by content, not by identity + colr = builder.buildCOLR( + {"a": layers, "b": deepcopy(layers), "c": deepcopy(layers)} + ).table + + baseGlyphs = colr.BaseGlyphList.BaseGlyphPaintRecord + assert len(baseGlyphs) == 3 + + assert baseGlyphs[0].BaseGlyph == "a" + assert baseGlyphs[1].BaseGlyph == "b" + assert baseGlyphs[2].BaseGlyph == "c" + + expected = {"Format": 1, "FirstLayerIndex": 0, "NumLayers": 2} + assert baseGlyphs[0].Paint.__dict__ == expected + assert baseGlyphs[1].Paint.__dict__ == expected + assert baseGlyphs[2].Paint.__dict__ == expected + class TrickyRadialGradientTest: @staticmethod @@ -1561,6 +1747,16 @@ class TrickyRadialGradientTest: r1 = 260.0072 assert self.round_start_circle(c0, r0, c1, r1, inside=True) == ((386, 71), 0) + def test_noto_emoji_horns_sign_u1f918_1f3fc(self): + # This radial gradient is taken from noto-emoji's 'SIGNS OF THE HORNS' + # (1f918_1f3fc). We check that c0 is inside c1 both before and after rounding. + c0 = (-437.6789059060543, -2116.9237094478003) + r0 = 0.0 + c1 = (-488.7330118252256, -1876.5036857045086) + r1 = 245.77147821915673 + assert self.circle_inside_circle(c0, r0, c1, r1) + assert self.circle_inside_circle(c0, r0, c1, r1, rounded=True) + @pytest.mark.parametrize( "c0, r0, c1, r1, inside, expected", [ |