2020-02-17 18:28:24 +00:00
|
|
|
from fontTools.ttLib import newTable
|
2020-03-10 15:34:53 +00:00
|
|
|
from fontTools.ttLib.tables import otTables as ot
|
2020-02-17 11:58:29 +00:00
|
|
|
from fontTools.colorLib import builder
|
2020-11-10 21:51:33 -08:00
|
|
|
from fontTools.colorLib.builder import LayerV1ListBuilder
|
2020-02-17 11:58:29 +00:00
|
|
|
from fontTools.colorLib.errors import ColorLibError
|
|
|
|
import pytest
|
2020-11-03 23:33:01 -08:00
|
|
|
from typing import List
|
2020-02-17 11:58:29 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_buildCOLR_v0():
|
|
|
|
color_layer_lists = {
|
|
|
|
"a": [("a.color0", 0), ("a.color1", 1)],
|
|
|
|
"b": [("b.color1", 1), ("b.color0", 0)],
|
|
|
|
}
|
|
|
|
|
|
|
|
colr = builder.buildCOLR(color_layer_lists)
|
|
|
|
|
|
|
|
assert colr.tableTag == "COLR"
|
|
|
|
assert colr.version == 0
|
|
|
|
assert colr.ColorLayers["a"][0].name == "a.color0"
|
|
|
|
assert colr.ColorLayers["a"][0].colorID == 0
|
|
|
|
assert colr.ColorLayers["a"][1].name == "a.color1"
|
|
|
|
assert colr.ColorLayers["a"][1].colorID == 1
|
|
|
|
assert colr.ColorLayers["b"][0].name == "b.color1"
|
|
|
|
assert colr.ColorLayers["b"][0].colorID == 1
|
|
|
|
assert colr.ColorLayers["b"][1].name == "b.color0"
|
|
|
|
assert colr.ColorLayers["b"][1].colorID == 0
|
|
|
|
|
|
|
|
|
|
|
|
def test_buildCPAL_v0():
|
|
|
|
palettes = [
|
|
|
|
[(0.68, 0.20, 0.32, 1.0), (0.45, 0.68, 0.21, 1.0)],
|
|
|
|
[(0.68, 0.20, 0.32, 0.6), (0.45, 0.68, 0.21, 0.6)],
|
|
|
|
[(0.68, 0.20, 0.32, 0.3), (0.45, 0.68, 0.21, 0.3)],
|
|
|
|
]
|
|
|
|
|
|
|
|
cpal = builder.buildCPAL(palettes)
|
|
|
|
|
|
|
|
assert cpal.tableTag == "CPAL"
|
|
|
|
assert cpal.version == 0
|
|
|
|
assert cpal.numPaletteEntries == 2
|
|
|
|
|
|
|
|
assert len(cpal.palettes) == 3
|
|
|
|
assert [tuple(c) for c in cpal.palettes[0]] == [
|
|
|
|
(82, 51, 173, 255),
|
|
|
|
(54, 173, 115, 255),
|
|
|
|
]
|
|
|
|
assert [tuple(c) for c in cpal.palettes[1]] == [
|
|
|
|
(82, 51, 173, 153),
|
|
|
|
(54, 173, 115, 153),
|
|
|
|
]
|
|
|
|
assert [tuple(c) for c in cpal.palettes[2]] == [
|
|
|
|
(82, 51, 173, 76),
|
|
|
|
(54, 173, 115, 76),
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
def test_buildCPAL_palettes_different_lengths():
|
|
|
|
with pytest.raises(ColorLibError, match="have different lengths"):
|
|
|
|
builder.buildCPAL([[(1, 1, 1, 1)], [(0, 0, 0, 1), (0.5, 0.5, 0.5, 1)]])
|
2020-02-17 18:28:24 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_buildPaletteLabels():
|
|
|
|
name_table = newTable("name")
|
|
|
|
name_table.names = []
|
|
|
|
|
|
|
|
name_ids = builder.buildPaletteLabels(
|
|
|
|
[None, "hi", {"en": "hello", "de": "hallo"}], name_table
|
|
|
|
)
|
|
|
|
|
|
|
|
assert name_ids == [0xFFFF, 256, 257]
|
|
|
|
|
|
|
|
assert len(name_table.names) == 3
|
|
|
|
assert str(name_table.names[0]) == "hi"
|
|
|
|
assert name_table.names[0].nameID == 256
|
|
|
|
|
|
|
|
assert str(name_table.names[1]) == "hallo"
|
|
|
|
assert name_table.names[1].nameID == 257
|
|
|
|
|
|
|
|
assert str(name_table.names[2]) == "hello"
|
|
|
|
assert name_table.names[2].nameID == 257
|
|
|
|
|
|
|
|
|
|
|
|
def test_build_CPAL_v1_types_no_labels():
|
|
|
|
palettes = [
|
|
|
|
[(0.1, 0.2, 0.3, 1.0), (0.4, 0.5, 0.6, 1.0)],
|
|
|
|
[(0.1, 0.2, 0.3, 0.6), (0.4, 0.5, 0.6, 0.6)],
|
|
|
|
[(0.1, 0.2, 0.3, 0.3), (0.4, 0.5, 0.6, 0.3)],
|
|
|
|
]
|
|
|
|
paletteTypes = [
|
|
|
|
builder.ColorPaletteType.USABLE_WITH_LIGHT_BACKGROUND,
|
|
|
|
builder.ColorPaletteType.USABLE_WITH_DARK_BACKGROUND,
|
|
|
|
builder.ColorPaletteType.USABLE_WITH_LIGHT_BACKGROUND
|
|
|
|
| builder.ColorPaletteType.USABLE_WITH_DARK_BACKGROUND,
|
|
|
|
]
|
|
|
|
|
|
|
|
cpal = builder.buildCPAL(palettes, paletteTypes=paletteTypes)
|
|
|
|
|
|
|
|
assert cpal.tableTag == "CPAL"
|
|
|
|
assert cpal.version == 1
|
|
|
|
assert cpal.numPaletteEntries == 2
|
|
|
|
assert len(cpal.palettes) == 3
|
|
|
|
|
|
|
|
assert cpal.paletteTypes == paletteTypes
|
|
|
|
assert cpal.paletteLabels == [cpal.NO_NAME_ID] * len(palettes)
|
|
|
|
assert cpal.paletteEntryLabels == [cpal.NO_NAME_ID] * cpal.numPaletteEntries
|
|
|
|
|
|
|
|
|
|
|
|
def test_build_CPAL_v1_labels():
|
|
|
|
palettes = [
|
|
|
|
[(0.1, 0.2, 0.3, 1.0), (0.4, 0.5, 0.6, 1.0)],
|
|
|
|
[(0.1, 0.2, 0.3, 0.6), (0.4, 0.5, 0.6, 0.6)],
|
|
|
|
[(0.1, 0.2, 0.3, 0.3), (0.4, 0.5, 0.6, 0.3)],
|
|
|
|
]
|
|
|
|
paletteLabels = ["First", {"en": "Second", "it": "Seconda"}, None]
|
|
|
|
paletteEntryLabels = ["Foo", "Bar"]
|
|
|
|
|
|
|
|
with pytest.raises(TypeError, match="nameTable is required"):
|
|
|
|
builder.buildCPAL(palettes, paletteLabels=paletteLabels)
|
|
|
|
with pytest.raises(TypeError, match="nameTable is required"):
|
|
|
|
builder.buildCPAL(palettes, paletteEntryLabels=paletteEntryLabels)
|
|
|
|
|
|
|
|
name_table = newTable("name")
|
|
|
|
name_table.names = []
|
|
|
|
|
|
|
|
cpal = builder.buildCPAL(
|
|
|
|
palettes,
|
|
|
|
paletteLabels=paletteLabels,
|
|
|
|
paletteEntryLabels=paletteEntryLabels,
|
|
|
|
nameTable=name_table,
|
|
|
|
)
|
|
|
|
|
|
|
|
assert cpal.tableTag == "CPAL"
|
|
|
|
assert cpal.version == 1
|
|
|
|
assert cpal.numPaletteEntries == 2
|
|
|
|
assert len(cpal.palettes) == 3
|
|
|
|
|
|
|
|
assert cpal.paletteTypes == [cpal.DEFAULT_PALETTE_TYPE] * len(palettes)
|
|
|
|
assert cpal.paletteLabels == [256, 257, cpal.NO_NAME_ID]
|
|
|
|
assert cpal.paletteEntryLabels == [258, 259]
|
|
|
|
|
|
|
|
assert name_table.getDebugName(256) == "First"
|
|
|
|
assert name_table.getDebugName(257) == "Second"
|
|
|
|
assert name_table.getDebugName(258) == "Foo"
|
|
|
|
assert name_table.getDebugName(259) == "Bar"
|
|
|
|
|
|
|
|
|
|
|
|
def test_invalid_ColorPaletteType():
|
|
|
|
with pytest.raises(ValueError, match="not a valid ColorPaletteType"):
|
|
|
|
builder.ColorPaletteType(-1)
|
|
|
|
with pytest.raises(ValueError, match="not a valid ColorPaletteType"):
|
|
|
|
builder.ColorPaletteType(4)
|
|
|
|
with pytest.raises(ValueError, match="not a valid ColorPaletteType"):
|
|
|
|
builder.ColorPaletteType("abc")
|
|
|
|
|
|
|
|
|
|
|
|
def test_buildCPAL_v1_invalid_args_length():
|
|
|
|
with pytest.raises(ColorLibError, match="Expected 2 paletteTypes, got 1"):
|
|
|
|
builder.buildCPAL([[(0, 0, 0, 0)], [(1, 1, 1, 1)]], paletteTypes=[1])
|
|
|
|
|
|
|
|
with pytest.raises(ColorLibError, match="Expected 2 paletteLabels, got 1"):
|
|
|
|
builder.buildCPAL(
|
|
|
|
[[(0, 0, 0, 0)], [(1, 1, 1, 1)]],
|
|
|
|
paletteLabels=["foo"],
|
|
|
|
nameTable=newTable("name"),
|
|
|
|
)
|
|
|
|
|
|
|
|
with pytest.raises(ColorLibError, match="Expected 1 paletteEntryLabels, got 0"):
|
|
|
|
cpal = builder.buildCPAL(
|
|
|
|
[[(0, 0, 0, 0)], [(1, 1, 1, 1)]],
|
|
|
|
paletteEntryLabels=[],
|
|
|
|
nameTable=newTable("name"),
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def test_buildCPAL_invalid_color():
|
|
|
|
with pytest.raises(
|
|
|
|
ColorLibError,
|
|
|
|
match=r"In palette\[0\]\[1\]: expected \(R, G, B, A\) tuple, got \(1, 1, 1\)",
|
|
|
|
):
|
|
|
|
builder.buildCPAL([[(1, 1, 1, 1), (1, 1, 1)]])
|
|
|
|
|
|
|
|
with pytest.raises(
|
|
|
|
ColorLibError,
|
|
|
|
match=(
|
|
|
|
r"palette\[1\]\[0\] has invalid out-of-range "
|
|
|
|
r"\[0..1\] color: \(1, 1, -1, 2\)"
|
|
|
|
),
|
|
|
|
):
|
|
|
|
builder.buildCPAL([[(0, 0, 0, 0)], [(1, 1, -1, 2)]])
|
2020-03-09 16:58:13 +00:00
|
|
|
|
|
|
|
|
2020-07-02 10:27:47 +01:00
|
|
|
def test_buildColorIndex():
|
|
|
|
c = builder.buildColorIndex(0)
|
2020-03-09 16:58:13 +00:00
|
|
|
assert c.PaletteIndex == 0
|
2020-07-02 10:27:47 +01:00
|
|
|
assert c.Alpha.value == 1.0
|
|
|
|
assert c.Alpha.varIdx == 0
|
2020-03-09 16:58:13 +00:00
|
|
|
|
2020-07-02 10:27:47 +01:00
|
|
|
c = builder.buildColorIndex(1, alpha=0.5)
|
2020-03-09 16:58:13 +00:00
|
|
|
assert c.PaletteIndex == 1
|
2020-07-02 10:27:47 +01:00
|
|
|
assert c.Alpha.value == 0.5
|
|
|
|
assert c.Alpha.varIdx == 0
|
2020-03-09 16:58:13 +00:00
|
|
|
|
2020-07-02 10:27:47 +01:00
|
|
|
c = builder.buildColorIndex(3, alpha=builder.VariableFloat(0.5, varIdx=2))
|
2020-03-09 16:58:13 +00:00
|
|
|
assert c.PaletteIndex == 3
|
2020-07-02 10:27:47 +01:00
|
|
|
assert c.Alpha.value == 0.5
|
|
|
|
assert c.Alpha.varIdx == 2
|
2020-03-09 16:58:13 +00:00
|
|
|
|
|
|
|
|
2020-10-09 18:30:50 +01:00
|
|
|
def test_buildPaintSolid():
|
2020-11-10 21:51:33 -08:00
|
|
|
p = LayerV1ListBuilder().buildPaintSolid(0)
|
2020-10-26 15:47:22 +00:00
|
|
|
assert p.Format == ot.Paint.Format.PaintSolid
|
2020-03-09 16:58:13 +00:00
|
|
|
assert p.Color.PaletteIndex == 0
|
2020-07-02 10:27:47 +01:00
|
|
|
assert p.Color.Alpha.value == 1.0
|
|
|
|
assert p.Color.Alpha.varIdx == 0
|
2020-03-09 16:58:13 +00:00
|
|
|
|
2020-11-10 21:51:33 -08:00
|
|
|
p = LayerV1ListBuilder().buildPaintSolid(1, alpha=0.5)
|
2020-10-26 15:47:22 +00:00
|
|
|
assert p.Format == ot.Paint.Format.PaintSolid
|
2020-03-09 16:58:13 +00:00
|
|
|
assert p.Color.PaletteIndex == 1
|
2020-07-02 10:27:47 +01:00
|
|
|
assert p.Color.Alpha.value == 0.5
|
|
|
|
assert p.Color.Alpha.varIdx == 0
|
2020-03-09 16:58:13 +00:00
|
|
|
|
2020-11-10 21:51:33 -08:00
|
|
|
p = LayerV1ListBuilder().buildPaintSolid(
|
|
|
|
3, alpha=builder.VariableFloat(0.5, varIdx=2)
|
|
|
|
)
|
2020-10-26 15:47:22 +00:00
|
|
|
assert p.Format == ot.Paint.Format.PaintSolid
|
2020-03-09 16:58:13 +00:00
|
|
|
assert p.Color.PaletteIndex == 3
|
2020-07-02 10:27:47 +01:00
|
|
|
assert p.Color.Alpha.value == 0.5
|
|
|
|
assert p.Color.Alpha.varIdx == 2
|
2020-03-09 16:58:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_buildColorStop():
|
2020-03-12 16:03:11 +00:00
|
|
|
s = builder.buildColorStop(0.1, 2)
|
2020-03-09 16:58:13 +00:00
|
|
|
assert s.StopOffset == builder.VariableFloat(0.1)
|
|
|
|
assert s.Color.PaletteIndex == 2
|
2020-07-02 10:27:47 +01:00
|
|
|
assert s.Color.Alpha == builder._DEFAULT_ALPHA
|
2020-03-09 16:58:13 +00:00
|
|
|
|
2020-07-02 10:27:47 +01:00
|
|
|
s = builder.buildColorStop(offset=0.2, paletteIndex=3, alpha=0.4)
|
2020-03-09 16:58:13 +00:00
|
|
|
assert s.StopOffset == builder.VariableFloat(0.2)
|
2020-07-02 10:27:47 +01:00
|
|
|
assert s.Color == builder.buildColorIndex(3, alpha=0.4)
|
2020-03-09 16:58:13 +00:00
|
|
|
|
|
|
|
s = builder.buildColorStop(
|
|
|
|
offset=builder.VariableFloat(0.0, varIdx=1),
|
2020-03-12 16:03:11 +00:00
|
|
|
paletteIndex=0,
|
2020-07-02 10:27:47 +01:00
|
|
|
alpha=builder.VariableFloat(0.3, varIdx=2),
|
2020-03-09 16:58:13 +00:00
|
|
|
)
|
|
|
|
assert s.StopOffset == builder.VariableFloat(0.0, varIdx=1)
|
|
|
|
assert s.Color.PaletteIndex == 0
|
2020-07-02 10:27:47 +01:00
|
|
|
assert s.Color.Alpha == builder.VariableFloat(0.3, varIdx=2)
|
2020-03-09 16:58:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_buildColorLine():
|
|
|
|
stops = [(0.0, 0), (0.5, 1), (1.0, 2)]
|
|
|
|
|
|
|
|
cline = builder.buildColorLine(stops)
|
|
|
|
assert cline.Extend == builder.ExtendMode.PAD
|
|
|
|
assert cline.StopCount == 3
|
|
|
|
assert [
|
|
|
|
(cs.StopOffset.value, cs.Color.PaletteIndex) for cs in cline.ColorStop
|
|
|
|
] == stops
|
|
|
|
|
2020-03-11 13:27:59 +00:00
|
|
|
cline = builder.buildColorLine(stops, extend="pad")
|
|
|
|
assert cline.Extend == builder.ExtendMode.PAD
|
|
|
|
|
2020-03-09 16:58:13 +00:00
|
|
|
cline = builder.buildColorLine(stops, extend=builder.ExtendMode.REPEAT)
|
|
|
|
assert cline.Extend == builder.ExtendMode.REPEAT
|
|
|
|
|
|
|
|
cline = builder.buildColorLine(stops, extend=builder.ExtendMode.REFLECT)
|
|
|
|
assert cline.Extend == builder.ExtendMode.REFLECT
|
|
|
|
|
2020-03-12 16:03:11 +00:00
|
|
|
cline = builder.buildColorLine([builder.buildColorStop(*s) for s in stops])
|
2020-03-09 16:58:13 +00:00
|
|
|
assert [
|
|
|
|
(cs.StopOffset.value, cs.Color.PaletteIndex) for cs in cline.ColorStop
|
|
|
|
] == stops
|
|
|
|
|
2020-03-11 13:27:59 +00:00
|
|
|
stops = [
|
2020-07-02 10:27:47 +01:00
|
|
|
{"offset": (0.0, 1), "paletteIndex": 0, "alpha": (0.5, 2)},
|
|
|
|
{"offset": (1.0, 3), "paletteIndex": 1, "alpha": (0.3, 4)},
|
2020-03-11 13:27:59 +00:00
|
|
|
]
|
2020-03-10 11:38:29 +00:00
|
|
|
cline = builder.buildColorLine(stops)
|
|
|
|
assert [
|
2020-03-12 16:03:11 +00:00
|
|
|
{
|
|
|
|
"offset": cs.StopOffset,
|
|
|
|
"paletteIndex": cs.Color.PaletteIndex,
|
2020-07-02 10:27:47 +01:00
|
|
|
"alpha": cs.Color.Alpha,
|
2020-03-12 16:03:11 +00:00
|
|
|
}
|
2020-03-10 11:38:29 +00:00
|
|
|
for cs in cline.ColorStop
|
|
|
|
] == stops
|
|
|
|
|
2020-03-09 16:58:13 +00:00
|
|
|
|
2020-10-09 18:16:51 +01:00
|
|
|
def test_buildAffine2x3():
|
2020-10-30 19:27:54 +00:00
|
|
|
matrix = builder.buildAffine2x3((1.5, 0, 0.5, 2.0, 1.0, -3.0))
|
2020-03-09 19:19:41 +00:00
|
|
|
assert matrix.xx == builder.VariableFloat(1.5)
|
2020-10-30 19:27:54 +00:00
|
|
|
assert matrix.yx == builder.VariableFloat(0.0)
|
|
|
|
assert matrix.xy == builder.VariableFloat(0.5)
|
2020-03-09 19:19:41 +00:00
|
|
|
assert matrix.yy == builder.VariableFloat(2.0)
|
2020-10-09 18:16:51 +01:00
|
|
|
assert matrix.dx == builder.VariableFloat(1.0)
|
|
|
|
assert matrix.dy == builder.VariableFloat(-3.0)
|
2020-03-09 19:19:41 +00:00
|
|
|
|
|
|
|
|
2020-10-09 18:30:50 +01:00
|
|
|
def test_buildPaintLinearGradient():
|
2020-11-10 21:51:33 -08:00
|
|
|
layerBuilder = LayerV1ListBuilder()
|
2020-03-09 19:19:41 +00:00
|
|
|
color_stops = [
|
2020-03-12 16:03:11 +00:00
|
|
|
builder.buildColorStop(0.0, 0),
|
|
|
|
builder.buildColorStop(0.5, 1),
|
2020-07-02 10:27:47 +01:00
|
|
|
builder.buildColorStop(1.0, 2, alpha=0.8),
|
2020-03-09 19:19:41 +00:00
|
|
|
]
|
|
|
|
color_line = builder.buildColorLine(color_stops, extend=builder.ExtendMode.REPEAT)
|
2020-07-02 12:11:40 +01:00
|
|
|
p0 = (builder.VariableInt(100), builder.VariableInt(200))
|
|
|
|
p1 = (builder.VariableInt(150), builder.VariableInt(250))
|
2020-03-09 19:19:41 +00:00
|
|
|
|
2020-11-10 21:51:33 -08:00
|
|
|
gradient = layerBuilder.buildPaintLinearGradient(color_line, p0, p1)
|
|
|
|
assert gradient.Format == 3
|
2020-03-09 19:19:41 +00:00
|
|
|
assert gradient.ColorLine == color_line
|
2020-07-02 12:11:40 +01:00
|
|
|
assert (gradient.x0, gradient.y0) == p0
|
|
|
|
assert (gradient.x1, gradient.y1) == p1
|
|
|
|
assert (gradient.x2, gradient.y2) == p1
|
2020-03-09 19:19:41 +00:00
|
|
|
|
2020-11-10 21:51:33 -08:00
|
|
|
gradient = layerBuilder.buildPaintLinearGradient({"stops": color_stops}, p0, p1)
|
2020-03-09 19:19:41 +00:00
|
|
|
assert gradient.ColorLine.Extend == builder.ExtendMode.PAD
|
|
|
|
assert gradient.ColorLine.ColorStop == color_stops
|
|
|
|
|
2020-11-10 21:51:33 -08:00
|
|
|
gradient = layerBuilder.buildPaintLinearGradient(color_line, p0, p1, p2=(150, 230))
|
2020-07-02 12:11:40 +01:00
|
|
|
assert (gradient.x2.value, gradient.y2.value) == (150, 230)
|
|
|
|
assert (gradient.x2, gradient.y2) != (gradient.x1, gradient.y1)
|
2020-03-09 19:19:41 +00:00
|
|
|
|
|
|
|
|
2020-10-09 18:30:50 +01:00
|
|
|
def test_buildPaintRadialGradient():
|
2020-11-10 21:51:33 -08:00
|
|
|
layerBuilder = LayerV1ListBuilder()
|
2020-03-09 19:19:41 +00:00
|
|
|
color_stops = [
|
2020-03-12 16:03:11 +00:00
|
|
|
builder.buildColorStop(0.0, 0),
|
|
|
|
builder.buildColorStop(0.5, 1),
|
2020-07-02 10:27:47 +01:00
|
|
|
builder.buildColorStop(1.0, 2, alpha=0.8),
|
2020-03-09 19:19:41 +00:00
|
|
|
]
|
|
|
|
color_line = builder.buildColorLine(color_stops, extend=builder.ExtendMode.REPEAT)
|
2020-07-02 12:11:40 +01:00
|
|
|
c0 = (builder.VariableInt(100), builder.VariableInt(200))
|
|
|
|
c1 = (builder.VariableInt(150), builder.VariableInt(250))
|
2020-03-09 19:19:41 +00:00
|
|
|
r0 = builder.VariableInt(10)
|
|
|
|
r1 = builder.VariableInt(5)
|
|
|
|
|
2020-11-10 21:51:33 -08:00
|
|
|
gradient = layerBuilder.buildPaintRadialGradient(color_line, c0, c1, r0, r1)
|
2020-10-26 15:47:22 +00:00
|
|
|
assert gradient.Format == ot.Paint.Format.PaintRadialGradient
|
2020-03-09 19:19:41 +00:00
|
|
|
assert gradient.ColorLine == color_line
|
2020-07-02 12:11:40 +01:00
|
|
|
assert (gradient.x0, gradient.y0) == c0
|
|
|
|
assert (gradient.x1, gradient.y1) == c1
|
2020-03-09 19:19:41 +00:00
|
|
|
assert gradient.r0 == r0
|
|
|
|
assert gradient.r1 == r1
|
|
|
|
|
2020-11-10 21:51:33 -08:00
|
|
|
gradient = layerBuilder.buildPaintRadialGradient(
|
|
|
|
{"stops": color_stops}, c0, c1, r0, r1
|
|
|
|
)
|
2020-03-09 19:19:41 +00:00
|
|
|
assert gradient.ColorLine.Extend == builder.ExtendMode.PAD
|
|
|
|
assert gradient.ColorLine.ColorStop == color_stops
|
|
|
|
|
2020-03-10 15:34:53 +00:00
|
|
|
|
2020-11-03 23:33:01 -08:00
|
|
|
def test_buildPaintGlyph_Solid():
|
2020-11-10 21:51:33 -08:00
|
|
|
layerBuilder = LayerV1ListBuilder()
|
|
|
|
layer = layerBuilder.buildPaintGlyph("a", 2)
|
2020-10-09 18:16:51 +01:00
|
|
|
assert layer.Glyph == "a"
|
2020-10-26 15:47:22 +00:00
|
|
|
assert layer.Paint.Format == ot.Paint.Format.PaintSolid
|
2020-03-10 15:34:53 +00:00
|
|
|
assert layer.Paint.Color.PaletteIndex == 2
|
|
|
|
|
2020-11-10 21:51:33 -08:00
|
|
|
layer = layerBuilder.buildPaintGlyph("a", layerBuilder.buildPaintSolid(3, 0.9))
|
2020-10-26 15:47:22 +00:00
|
|
|
assert layer.Paint.Format == ot.Paint.Format.PaintSolid
|
2020-03-10 15:34:53 +00:00
|
|
|
assert layer.Paint.Color.PaletteIndex == 3
|
2020-07-02 10:27:47 +01:00
|
|
|
assert layer.Paint.Color.Alpha.value == 0.9
|
2020-03-10 15:34:53 +00:00
|
|
|
|
2020-11-03 23:33:01 -08:00
|
|
|
|
|
|
|
def test_buildPaintGlyph_LinearGradient():
|
2020-11-10 21:51:33 -08:00
|
|
|
layerBuilder = LayerV1ListBuilder()
|
|
|
|
layer = layerBuilder.buildPaintGlyph(
|
2020-03-10 15:34:53 +00:00
|
|
|
"a",
|
2020-11-10 21:51:33 -08:00
|
|
|
layerBuilder.buildPaintLinearGradient(
|
2020-03-11 13:27:59 +00:00
|
|
|
{"stops": [(0.0, 3), (1.0, 4)]}, (100, 200), (150, 250)
|
|
|
|
),
|
2020-03-10 15:34:53 +00:00
|
|
|
)
|
2020-10-26 15:47:22 +00:00
|
|
|
assert layer.Paint.Format == ot.Paint.Format.PaintLinearGradient
|
2020-03-10 15:34:53 +00:00
|
|
|
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
|
2020-07-02 12:11:40 +01:00
|
|
|
assert layer.Paint.x0.value == 100
|
|
|
|
assert layer.Paint.y0.value == 200
|
|
|
|
assert layer.Paint.x1.value == 150
|
|
|
|
assert layer.Paint.y1.value == 250
|
2020-03-10 15:34:53 +00:00
|
|
|
|
2020-11-03 23:33:01 -08:00
|
|
|
|
|
|
|
def test_buildPaintGlyph_RadialGradient():
|
2020-11-10 21:51:33 -08:00
|
|
|
layerBuilder = LayerV1ListBuilder()
|
|
|
|
layer = layerBuilder.buildPaintGlyph(
|
2020-03-10 15:34:53 +00:00
|
|
|
"a",
|
2020-11-10 21:51:33 -08:00
|
|
|
layerBuilder.buildPaintRadialGradient(
|
2020-03-11 13:27:59 +00:00
|
|
|
{
|
|
|
|
"stops": [
|
|
|
|
(0.0, 5),
|
2020-07-02 10:27:47 +01:00
|
|
|
{"offset": 0.5, "paletteIndex": 6, "alpha": 0.8},
|
2020-03-11 13:27:59 +00:00
|
|
|
(1.0, 7),
|
|
|
|
]
|
|
|
|
},
|
|
|
|
(50, 50),
|
|
|
|
(75, 75),
|
|
|
|
30,
|
|
|
|
10,
|
2020-03-10 15:34:53 +00:00
|
|
|
),
|
|
|
|
)
|
2020-10-26 15:47:22 +00:00
|
|
|
assert layer.Paint.Format == ot.Paint.Format.PaintRadialGradient
|
2020-03-10 15:34:53 +00:00
|
|
|
assert layer.Paint.ColorLine.ColorStop[0].StopOffset.value == 0.0
|
|
|
|
assert layer.Paint.ColorLine.ColorStop[0].Color.PaletteIndex == 5
|
|
|
|
assert layer.Paint.ColorLine.ColorStop[1].StopOffset.value == 0.5
|
|
|
|
assert layer.Paint.ColorLine.ColorStop[1].Color.PaletteIndex == 6
|
2020-07-02 10:27:47 +01:00
|
|
|
assert layer.Paint.ColorLine.ColorStop[1].Color.Alpha.value == 0.8
|
2020-03-10 15:34:53 +00:00
|
|
|
assert layer.Paint.ColorLine.ColorStop[2].StopOffset.value == 1.0
|
|
|
|
assert layer.Paint.ColorLine.ColorStop[2].Color.PaletteIndex == 7
|
2020-07-02 12:11:40 +01:00
|
|
|
assert layer.Paint.x0.value == 50
|
|
|
|
assert layer.Paint.y0.value == 50
|
2020-03-10 15:34:53 +00:00
|
|
|
assert layer.Paint.r0.value == 30
|
2020-07-02 12:11:40 +01:00
|
|
|
assert layer.Paint.x1.value == 75
|
|
|
|
assert layer.Paint.y1.value == 75
|
2020-03-10 15:34:53 +00:00
|
|
|
assert layer.Paint.r1.value == 10
|
|
|
|
|
|
|
|
|
2020-11-03 23:33:01 -08:00
|
|
|
def test_buildPaintGlyph_Dict_Solid():
|
2020-11-10 21:51:33 -08:00
|
|
|
layerBuilder = LayerV1ListBuilder()
|
|
|
|
layer = layerBuilder.buildPaintGlyph("a", {"format": 2, "paletteIndex": 0})
|
2020-10-09 18:16:51 +01:00
|
|
|
assert layer.Glyph == "a"
|
2020-10-26 15:47:22 +00:00
|
|
|
assert layer.Paint.Format == ot.Paint.Format.PaintSolid
|
2020-03-11 13:27:59 +00:00
|
|
|
assert layer.Paint.Color.PaletteIndex == 0
|
|
|
|
|
2020-11-03 23:33:01 -08:00
|
|
|
|
|
|
|
def test_buildPaintGlyph_Dict_LinearGradient():
|
2020-11-10 21:51:33 -08:00
|
|
|
layerBuilder = LayerV1ListBuilder()
|
|
|
|
layer = layerBuilder.buildPaintGlyph(
|
2020-03-11 13:27:59 +00:00
|
|
|
"a",
|
|
|
|
{
|
2020-11-10 21:51:33 -08:00
|
|
|
"format": 3,
|
2020-03-11 13:27:59 +00:00
|
|
|
"colorLine": {"stops": [(0.0, 0), (1.0, 1)]},
|
|
|
|
"p0": (0, 0),
|
|
|
|
"p1": (10, 10),
|
|
|
|
},
|
|
|
|
)
|
2020-10-26 15:47:22 +00:00
|
|
|
assert layer.Paint.Format == ot.Paint.Format.PaintLinearGradient
|
2020-03-11 13:27:59 +00:00
|
|
|
assert layer.Paint.ColorLine.ColorStop[0].StopOffset.value == 0.0
|
|
|
|
|
2020-11-03 23:33:01 -08:00
|
|
|
|
|
|
|
def test_buildPaintGlyph_Dict_RadialGradient():
|
2020-11-10 21:51:33 -08:00
|
|
|
layerBuilder = LayerV1ListBuilder()
|
|
|
|
layer = layerBuilder.buildPaintGlyph(
|
2020-03-11 13:27:59 +00:00
|
|
|
"a",
|
|
|
|
{
|
2020-11-10 21:51:33 -08:00
|
|
|
"format": 4,
|
2020-03-11 13:27:59 +00:00
|
|
|
"colorLine": {"stops": [(0.0, 0), (1.0, 1)]},
|
|
|
|
"c0": (0, 0),
|
|
|
|
"c1": (10, 10),
|
|
|
|
"r0": 4,
|
|
|
|
"r1": 0,
|
|
|
|
},
|
|
|
|
)
|
2020-10-26 15:47:22 +00:00
|
|
|
assert layer.Paint.Format == ot.Paint.Format.PaintRadialGradient
|
2020-03-11 13:27:59 +00:00
|
|
|
assert layer.Paint.r0.value == 4
|
|
|
|
|
|
|
|
|
2020-11-03 23:33:01 -08:00
|
|
|
def test_buildPaintColrGlyph():
|
2020-11-10 21:51:33 -08:00
|
|
|
paint = LayerV1ListBuilder().buildPaintColrGlyph("a")
|
2020-11-03 23:33:01 -08:00
|
|
|
assert paint.Format == ot.Paint.Format.PaintColrGlyph
|
2020-10-26 16:12:38 +00:00
|
|
|
assert paint.Glyph == "a"
|
|
|
|
|
|
|
|
|
|
|
|
def test_buildPaintTransform():
|
2020-11-10 21:51:33 -08:00
|
|
|
layerBuilder = LayerV1ListBuilder()
|
|
|
|
paint = layerBuilder.buildPaintTransform(
|
2020-10-30 19:27:54 +00:00
|
|
|
transform=builder.buildAffine2x3((1, 2, 3, 4, 5, 6)),
|
2020-11-10 21:51:33 -08:00
|
|
|
paint=layerBuilder.buildPaintGlyph(
|
2020-10-26 16:12:38 +00:00
|
|
|
glyph="a",
|
2020-11-10 21:51:33 -08:00
|
|
|
paint=layerBuilder.buildPaintSolid(paletteIndex=0, alpha=1.0),
|
2020-10-26 16:12:38 +00:00
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
assert paint.Format == ot.Paint.Format.PaintTransform
|
2020-11-10 21:51:33 -08:00
|
|
|
assert paint.Paint.Format == ot.Paint.Format.PaintGlyph
|
|
|
|
assert paint.Paint.Paint.Format == ot.Paint.Format.PaintSolid
|
|
|
|
|
2020-10-26 16:12:38 +00:00
|
|
|
assert paint.Transform.xx.value == 1.0
|
2020-10-30 19:27:54 +00:00
|
|
|
assert paint.Transform.yx.value == 2.0
|
|
|
|
assert paint.Transform.xy.value == 3.0
|
2020-10-26 16:12:38 +00:00
|
|
|
assert paint.Transform.yy.value == 4.0
|
|
|
|
assert paint.Transform.dx.value == 5.0
|
|
|
|
assert paint.Transform.dy.value == 6.0
|
|
|
|
|
2020-11-10 21:51:33 -08:00
|
|
|
paint = layerBuilder.buildPaintTransform(
|
2020-10-26 16:12:38 +00:00
|
|
|
(1, 0, 0, 0.3333, 10, 10),
|
|
|
|
{
|
2020-11-10 21:51:33 -08:00
|
|
|
"format": 4,
|
2020-10-26 16:12:38 +00:00
|
|
|
"colorLine": {"stops": [(0.0, 0), (1.0, 1)]},
|
|
|
|
"c0": (100, 100),
|
|
|
|
"c1": (100, 100),
|
|
|
|
"r0": 0,
|
|
|
|
"r1": 50,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
assert paint.Format == ot.Paint.Format.PaintTransform
|
|
|
|
assert paint.Transform.xx.value == 1.0
|
|
|
|
assert paint.Transform.yx.value == 0.0
|
2020-10-30 19:27:54 +00:00
|
|
|
assert paint.Transform.xy.value == 0.0
|
2020-10-26 16:12:38 +00:00
|
|
|
assert paint.Transform.yy.value == 0.3333
|
|
|
|
assert paint.Transform.dx.value == 10
|
|
|
|
assert paint.Transform.dy.value == 10
|
|
|
|
assert paint.Paint.Format == ot.Paint.Format.PaintRadialGradient
|
|
|
|
|
|
|
|
|
|
|
|
def test_buildPaintComposite():
|
2020-11-10 21:51:33 -08:00
|
|
|
layerBuilder = LayerV1ListBuilder()
|
|
|
|
composite = layerBuilder.buildPaintComposite(
|
2020-10-26 16:12:38 +00:00
|
|
|
mode=ot.CompositeMode.SRC_OVER,
|
|
|
|
source={
|
2020-11-10 21:51:33 -08:00
|
|
|
"format": 8,
|
2020-10-26 16:12:38 +00:00
|
|
|
"mode": "src_over",
|
2020-11-10 21:51:33 -08:00
|
|
|
"source": {"format": 5, "glyph": "c", "paint": 2},
|
|
|
|
"backdrop": {"format": 5, "glyph": "b", "paint": 1},
|
2020-10-26 16:12:38 +00:00
|
|
|
},
|
2020-11-10 21:51:33 -08:00
|
|
|
backdrop=layerBuilder.buildPaintGlyph(
|
|
|
|
"a", layerBuilder.buildPaintSolid(paletteIndex=0, alpha=1.0)
|
2020-10-26 16:12:38 +00:00
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
assert composite.Format == ot.Paint.Format.PaintComposite
|
|
|
|
assert composite.SourcePaint.Format == ot.Paint.Format.PaintComposite
|
|
|
|
assert composite.SourcePaint.SourcePaint.Format == ot.Paint.Format.PaintGlyph
|
|
|
|
assert composite.SourcePaint.SourcePaint.Glyph == "c"
|
|
|
|
assert composite.SourcePaint.SourcePaint.Paint.Format == ot.Paint.Format.PaintSolid
|
|
|
|
assert composite.SourcePaint.SourcePaint.Paint.Color.PaletteIndex == 2
|
|
|
|
assert composite.SourcePaint.CompositeMode == ot.CompositeMode.SRC_OVER
|
|
|
|
assert composite.SourcePaint.BackdropPaint.Format == ot.Paint.Format.PaintGlyph
|
|
|
|
assert composite.SourcePaint.BackdropPaint.Glyph == "b"
|
|
|
|
assert (
|
|
|
|
composite.SourcePaint.BackdropPaint.Paint.Format == ot.Paint.Format.PaintSolid
|
|
|
|
)
|
|
|
|
assert composite.SourcePaint.BackdropPaint.Paint.Color.PaletteIndex == 1
|
|
|
|
assert composite.CompositeMode == ot.CompositeMode.SRC_OVER
|
|
|
|
assert composite.BackdropPaint.Format == ot.Paint.Format.PaintGlyph
|
|
|
|
assert composite.BackdropPaint.Glyph == "a"
|
|
|
|
assert composite.BackdropPaint.Paint.Format == ot.Paint.Format.PaintSolid
|
|
|
|
assert composite.BackdropPaint.Paint.Color.PaletteIndex == 0
|
|
|
|
|
|
|
|
|
2020-11-03 23:33:01 -08:00
|
|
|
def test_buildColrV1():
|
2020-03-10 15:34:53 +00:00
|
|
|
colorGlyphs = {
|
|
|
|
"a": [("b", 0), ("c", 1)],
|
|
|
|
"d": [
|
2020-11-10 21:51:33 -08:00
|
|
|
("e", {"format": 2, "paletteIndex": 2, "alpha": 0.8}),
|
2020-03-10 15:34:53 +00:00
|
|
|
(
|
|
|
|
"f",
|
2020-03-11 13:27:59 +00:00
|
|
|
{
|
2020-11-10 21:51:33 -08:00
|
|
|
"format": 4,
|
2020-03-11 13:27:59 +00:00
|
|
|
"colorLine": {"stops": [(0.0, 3), (1.0, 4)], "extend": "reflect"},
|
|
|
|
"c0": (0, 0),
|
|
|
|
"c1": (0, 0),
|
|
|
|
"r0": 10,
|
|
|
|
"r1": 0,
|
|
|
|
},
|
2020-03-10 15:34:53 +00:00
|
|
|
),
|
|
|
|
],
|
2020-11-03 23:33:01 -08:00
|
|
|
"g": [("h", 5)],
|
2020-03-10 15:34:53 +00:00
|
|
|
}
|
|
|
|
glyphMap = {
|
|
|
|
".notdef": 0,
|
|
|
|
"a": 4,
|
|
|
|
"b": 3,
|
|
|
|
"c": 2,
|
|
|
|
"d": 1,
|
|
|
|
"e": 5,
|
|
|
|
"f": 6,
|
|
|
|
"g": 7,
|
|
|
|
"h": 8,
|
|
|
|
}
|
|
|
|
|
2020-11-03 23:33:01 -08:00
|
|
|
# TODO(anthrotype) should we split into two tests? - seems two distinct validations
|
|
|
|
layers, baseGlyphs = builder.buildColrV1(colorGlyphs, glyphMap)
|
2020-07-01 18:29:26 +01:00
|
|
|
assert baseGlyphs.BaseGlyphCount == len(colorGlyphs)
|
|
|
|
assert baseGlyphs.BaseGlyphV1Record[0].BaseGlyph == "d"
|
|
|
|
assert baseGlyphs.BaseGlyphV1Record[1].BaseGlyph == "a"
|
|
|
|
assert baseGlyphs.BaseGlyphV1Record[2].BaseGlyph == "g"
|
|
|
|
|
2020-11-03 23:33:01 -08:00
|
|
|
layers, baseGlyphs = builder.buildColrV1(colorGlyphs)
|
2020-07-01 18:29:26 +01:00
|
|
|
assert baseGlyphs.BaseGlyphCount == len(colorGlyphs)
|
|
|
|
assert baseGlyphs.BaseGlyphV1Record[0].BaseGlyph == "a"
|
|
|
|
assert baseGlyphs.BaseGlyphV1Record[1].BaseGlyph == "d"
|
|
|
|
assert baseGlyphs.BaseGlyphV1Record[2].BaseGlyph == "g"
|
2020-03-11 14:22:58 +00:00
|
|
|
|
|
|
|
|
2020-10-09 18:16:51 +01:00
|
|
|
def test_split_color_glyphs_by_version():
|
2020-11-10 21:51:33 -08:00
|
|
|
layerBuilder = LayerV1ListBuilder()
|
2020-03-11 14:22:58 +00:00
|
|
|
colorGlyphs = {
|
|
|
|
"a": [
|
|
|
|
("b", 0),
|
|
|
|
("c", 1),
|
2020-10-09 18:16:51 +01:00
|
|
|
("d", 2),
|
|
|
|
("e", 3),
|
2020-03-11 14:22:58 +00:00
|
|
|
]
|
|
|
|
}
|
|
|
|
|
2020-10-09 18:16:51 +01:00
|
|
|
colorGlyphsV0, colorGlyphsV1 = builder._split_color_glyphs_by_version(colorGlyphs)
|
2020-03-11 14:22:58 +00:00
|
|
|
|
|
|
|
assert colorGlyphsV0 == {"a": [("b", 0), ("c", 1), ("d", 2), ("e", 3)]}
|
|
|
|
assert not colorGlyphsV1
|
|
|
|
|
2020-11-10 21:51:33 -08:00
|
|
|
colorGlyphs = {
|
|
|
|
"a": [("b", layerBuilder.buildPaintSolid(paletteIndex=0, alpha=0.0))]
|
|
|
|
}
|
2020-03-11 14:22:58 +00:00
|
|
|
|
2020-10-09 18:16:51 +01:00
|
|
|
colorGlyphsV0, colorGlyphsV1 = builder._split_color_glyphs_by_version(colorGlyphs)
|
2020-03-11 14:22:58 +00:00
|
|
|
|
|
|
|
assert not colorGlyphsV0
|
|
|
|
assert colorGlyphsV1 == colorGlyphs
|
|
|
|
|
|
|
|
colorGlyphs = {
|
|
|
|
"a": [("b", 0)],
|
|
|
|
"c": [
|
|
|
|
("d", 1),
|
|
|
|
(
|
|
|
|
"e",
|
|
|
|
{
|
2020-11-10 21:51:33 -08:00
|
|
|
"format": 3,
|
2020-03-11 14:22:58 +00:00
|
|
|
"colorLine": {"stops": [(0.0, 2), (1.0, 3)]},
|
|
|
|
"p0": (0, 0),
|
|
|
|
"p1": (10, 10),
|
|
|
|
},
|
|
|
|
),
|
|
|
|
],
|
|
|
|
}
|
|
|
|
|
2020-10-09 18:16:51 +01:00
|
|
|
colorGlyphsV0, colorGlyphsV1 = builder._split_color_glyphs_by_version(colorGlyphs)
|
2020-03-11 14:22:58 +00:00
|
|
|
|
|
|
|
assert colorGlyphsV0 == {"a": [("b", 0)]}
|
|
|
|
assert "a" not in colorGlyphsV1
|
|
|
|
assert "c" in colorGlyphsV1
|
|
|
|
assert len(colorGlyphsV1["c"]) == 2
|
|
|
|
|
2020-03-11 16:46:33 +00:00
|
|
|
|
2020-11-03 23:33:01 -08:00
|
|
|
def assertIsColrV1(colr):
|
|
|
|
assert colr.version == 1
|
|
|
|
assert not hasattr(colr, "ColorLayers")
|
|
|
|
assert hasattr(colr, "table")
|
|
|
|
assert isinstance(colr.table, ot.COLR)
|
|
|
|
|
|
|
|
|
|
|
|
def assertNoV0Content(colr):
|
|
|
|
assert colr.table.BaseGlyphRecordCount == 0
|
|
|
|
assert colr.table.BaseGlyphRecordArray is None
|
|
|
|
assert colr.table.LayerRecordCount == 0
|
|
|
|
assert colr.table.LayerRecordArray is None
|
|
|
|
|
|
|
|
|
|
|
|
def test_build_layerv1list_empty():
|
2020-11-04 21:59:30 -08:00
|
|
|
# Nobody uses PaintColrLayers (format 8), no layerlist
|
2020-11-03 23:33:01 -08:00
|
|
|
colr = builder.buildCOLR(
|
|
|
|
{
|
|
|
|
"a": {
|
2020-11-10 21:51:33 -08:00
|
|
|
"format": 5, # PaintGlyph
|
|
|
|
"paint": {"format": 2, "paletteIndex": 2, "alpha": 0.8},
|
2020-11-03 23:33:01 -08:00
|
|
|
"glyph": "b",
|
|
|
|
},
|
2020-11-04 21:59:30 -08:00
|
|
|
# A list of 1 shouldn't become a PaintColrLayers
|
2020-11-10 21:51:33 -08:00
|
|
|
"b": [
|
|
|
|
{
|
|
|
|
"format": 5, # PaintGlyph
|
|
|
|
"paint": {
|
|
|
|
"format": 3,
|
|
|
|
"colorLine": {
|
|
|
|
"stops": [(0.0, 2), (1.0, 3)],
|
|
|
|
"extend": "reflect",
|
|
|
|
},
|
|
|
|
"p0": (1, 2),
|
|
|
|
"p1": (3, 4),
|
|
|
|
"p2": (2, 2),
|
2020-11-03 23:33:01 -08:00
|
|
|
},
|
2020-11-10 21:51:33 -08:00
|
|
|
"glyph": "bb",
|
|
|
|
}
|
|
|
|
],
|
2020-11-03 23:33:01 -08:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
|
def _paint_names(paints) -> List[str]:
|
|
|
|
# prints a predictable string from a paint list to enable
|
|
|
|
# semi-readable assertions on a LayerV1List order.
|
|
|
|
result = []
|
|
|
|
for paint in paints:
|
|
|
|
if paint.Format == int(ot.Paint.Format.PaintGlyph):
|
|
|
|
result.append(paint.Glyph)
|
|
|
|
elif paint.Format == int(ot.Paint.Format.PaintColrLayers):
|
2020-11-10 21:51:33 -08:00
|
|
|
result.append(
|
|
|
|
f"Layers[{paint.FirstLayerIndex}:{paint.FirstLayerIndex+paint.NumLayers}]"
|
|
|
|
)
|
2020-11-03 23:33:01 -08:00
|
|
|
return result
|
|
|
|
|
2020-11-06 14:59:52 -08:00
|
|
|
|
2020-11-03 23:33:01 -08:00
|
|
|
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
|
2020-11-10 21:51:33 -08:00
|
|
|
solid_paint = {"format": 2, "paletteIndex": 2, "alpha": 0.8}
|
2020-11-03 23:33:01 -08:00
|
|
|
backdrop = {
|
2020-11-10 21:51:33 -08:00
|
|
|
"format": 5, # PaintGlyph
|
2020-11-03 23:33:01 -08:00
|
|
|
"paint": solid_paint,
|
|
|
|
"glyph": "back",
|
|
|
|
}
|
|
|
|
a_foreground = {
|
2020-11-10 21:51:33 -08:00
|
|
|
"format": 5, # PaintGlyph
|
2020-11-03 23:33:01 -08:00
|
|
|
"paint": solid_paint,
|
|
|
|
"glyph": "a_fore",
|
|
|
|
}
|
|
|
|
b_foreground = {
|
2020-11-10 21:51:33 -08:00
|
|
|
"format": 5, # PaintGlyph
|
2020-11-03 23:33:01 -08:00
|
|
|
"paint": solid_paint,
|
|
|
|
"glyph": "b_fore",
|
|
|
|
}
|
|
|
|
|
|
|
|
# list => PaintColrLayers, which means contents should be in LayerV1List
|
|
|
|
colr = builder.buildCOLR(
|
|
|
|
{
|
|
|
|
"a": [
|
|
|
|
backdrop,
|
|
|
|
a_foreground,
|
|
|
|
],
|
|
|
|
"b": [
|
|
|
|
backdrop,
|
|
|
|
b_foreground,
|
|
|
|
],
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
assertIsColrV1(colr)
|
|
|
|
assertNoV0Content(colr)
|
|
|
|
|
|
|
|
# 2 v1 glyphs, 4 paints in LayerV1List
|
|
|
|
# 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
|
2020-11-10 21:51:33 -08:00
|
|
|
assert _paint_names(colr.table.LayerV1List.Paint) == [
|
|
|
|
"back",
|
|
|
|
"a_fore",
|
|
|
|
"back",
|
|
|
|
"b_fore",
|
|
|
|
]
|
2020-11-03 23:33:01 -08:00
|
|
|
|
|
|
|
|
|
|
|
def test_build_layerv1list_with_sharing():
|
|
|
|
# Three colr glyphs, each with two layers in common
|
2020-11-10 21:51:33 -08:00
|
|
|
solid_paint = {"format": 2, "paletteIndex": 2, "alpha": 0.8}
|
2020-11-03 23:33:01 -08:00
|
|
|
backdrop = [
|
|
|
|
{
|
2020-11-10 21:51:33 -08:00
|
|
|
"format": 5, # PaintGlyph
|
2020-11-03 23:33:01 -08:00
|
|
|
"paint": solid_paint,
|
|
|
|
"glyph": "back1",
|
|
|
|
},
|
|
|
|
{
|
2020-11-10 21:51:33 -08:00
|
|
|
"format": 5, # PaintGlyph
|
2020-11-03 23:33:01 -08:00
|
|
|
"paint": solid_paint,
|
|
|
|
"glyph": "back2",
|
|
|
|
},
|
2020-11-10 21:51:33 -08:00
|
|
|
]
|
2020-11-03 23:33:01 -08:00
|
|
|
a_foreground = {
|
2020-11-10 21:51:33 -08:00
|
|
|
"format": 5, # PaintGlyph
|
2020-11-03 23:33:01 -08:00
|
|
|
"paint": solid_paint,
|
|
|
|
"glyph": "a_fore",
|
|
|
|
}
|
|
|
|
b_background = {
|
2020-11-10 21:51:33 -08:00
|
|
|
"format": 5, # PaintGlyph
|
2020-11-03 23:33:01 -08:00
|
|
|
"paint": solid_paint,
|
|
|
|
"glyph": "b_back",
|
|
|
|
}
|
|
|
|
b_foreground = {
|
2020-11-10 21:51:33 -08:00
|
|
|
"format": 5, # PaintGlyph
|
2020-11-03 23:33:01 -08:00
|
|
|
"paint": solid_paint,
|
|
|
|
"glyph": "b_fore",
|
|
|
|
}
|
|
|
|
c_background = {
|
2020-11-10 21:51:33 -08:00
|
|
|
"format": 5, # PaintGlyph
|
2020-11-03 23:33:01 -08:00
|
|
|
"paint": solid_paint,
|
|
|
|
"glyph": "c_back",
|
|
|
|
}
|
|
|
|
|
|
|
|
# list => PaintColrLayers, which means contents should be in LayerV1List
|
|
|
|
colr = builder.buildCOLR(
|
|
|
|
{
|
|
|
|
"a": backdrop + [a_foreground],
|
|
|
|
"b": [b_background] + backdrop + [b_foreground],
|
|
|
|
"c": [c_background] + backdrop,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
assertIsColrV1(colr)
|
|
|
|
assertNoV0Content(colr)
|
|
|
|
|
|
|
|
# 2 v1 glyphs, 4 paints in LayerV1List
|
|
|
|
# A single shared backdrop isn't worth accessing by slice
|
|
|
|
baseGlyphs = colr.table.BaseGlyphV1List.BaseGlyphV1Record
|
|
|
|
assert colr.table.BaseGlyphV1List.BaseGlyphCount == 3
|
|
|
|
assert len(baseGlyphs) == 3
|
2020-11-10 21:51:33 -08:00
|
|
|
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) == [
|
|
|
|
"back1",
|
|
|
|
"back2",
|
|
|
|
"a_fore",
|
|
|
|
"b_back",
|
|
|
|
"Layers[0:2]",
|
|
|
|
"b_fore",
|
|
|
|
"c_back",
|
|
|
|
"Layers[0:2]",
|
|
|
|
]
|
2020-11-03 23:33:01 -08:00
|
|
|
assert colr.table.LayerV1List.LayerCount == 8
|
|
|
|
|
2020-11-10 21:51:33 -08:00
|
|
|
|
2020-11-06 14:59:52 -08:00
|
|
|
def test_build_layerv1list_with_overlaps():
|
|
|
|
paints = [
|
|
|
|
{
|
2020-11-10 21:51:33 -08:00
|
|
|
"format": 5, # PaintGlyph
|
|
|
|
"paint": {"format": 2, "paletteIndex": 2, "alpha": 0.8},
|
2020-11-06 14:59:52 -08:00
|
|
|
"glyph": c,
|
|
|
|
}
|
|
|
|
for c in "abcdefghi"
|
|
|
|
]
|
|
|
|
|
|
|
|
# list => PaintColrLayers, which means contents should be in LayerV1List
|
|
|
|
colr = builder.buildCOLR(
|
|
|
|
{
|
|
|
|
"a": paints[0:4],
|
|
|
|
"b": paints[0:6],
|
|
|
|
"c": paints[2:8],
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
assertIsColrV1(colr)
|
|
|
|
assertNoV0Content(colr)
|
|
|
|
|
|
|
|
baseGlyphs = colr.table.BaseGlyphV1List.BaseGlyphV1Record
|
2020-11-10 21:51:33 -08:00
|
|
|
# assert colr.table.BaseGlyphV1List.BaseGlyphCount == 2
|
2020-11-06 14:59:52 -08:00
|
|
|
|
2020-11-10 21:51:33 -08:00
|
|
|
assert _paint_names(colr.table.LayerV1List.Paint) == [
|
|
|
|
"a",
|
|
|
|
"b",
|
|
|
|
"c",
|
|
|
|
"d",
|
|
|
|
"Layers[0:4]",
|
|
|
|
"e",
|
|
|
|
"f",
|
|
|
|
"Layers[2:4]",
|
|
|
|
"Layers[5:7]",
|
|
|
|
"g",
|
|
|
|
"h",
|
|
|
|
]
|
|
|
|
assert _paint_names([b.Paint for b in baseGlyphs]) == [
|
|
|
|
"Layers[0:4]",
|
|
|
|
"Layers[4:7]",
|
|
|
|
"Layers[7:11]",
|
|
|
|
]
|
2020-11-06 14:59:52 -08:00
|
|
|
assert colr.table.LayerV1List.LayerCount == 11
|
|
|
|
|
2020-11-10 21:51:33 -08:00
|
|
|
|
2020-03-11 16:46:33 +00:00
|
|
|
class BuildCOLRTest(object):
|
|
|
|
def test_automatic_version_all_solid_color_glyphs(self):
|
|
|
|
colr = builder.buildCOLR({"a": [("b", 0), ("c", 1)]})
|
|
|
|
assert colr.version == 0
|
|
|
|
assert hasattr(colr, "ColorLayers")
|
|
|
|
assert colr.ColorLayers["a"][0].name == "b"
|
|
|
|
assert colr.ColorLayers["a"][1].name == "c"
|
|
|
|
|
|
|
|
def test_automatic_version_no_solid_color_glyphs(self):
|
|
|
|
colr = builder.buildCOLR(
|
|
|
|
{
|
|
|
|
"a": [
|
|
|
|
(
|
|
|
|
"b",
|
|
|
|
{
|
2020-11-10 21:51:33 -08:00
|
|
|
"format": 4,
|
2020-03-11 16:46:33 +00:00
|
|
|
"colorLine": {
|
|
|
|
"stops": [(0.0, 0), (1.0, 1)],
|
|
|
|
"extend": "repeat",
|
|
|
|
},
|
|
|
|
"c0": (1, 0),
|
|
|
|
"c1": (10, 0),
|
|
|
|
"r0": 4,
|
|
|
|
"r1": 2,
|
|
|
|
},
|
|
|
|
),
|
2020-11-10 21:51:33 -08:00
|
|
|
("c", {"format": 2, "paletteIndex": 2, "alpha": 0.8}),
|
2020-03-11 16:46:33 +00:00
|
|
|
],
|
|
|
|
"d": [
|
|
|
|
(
|
|
|
|
"e",
|
|
|
|
{
|
2020-11-10 21:51:33 -08:00
|
|
|
"format": 3,
|
2020-03-11 16:46:33 +00:00
|
|
|
"colorLine": {
|
|
|
|
"stops": [(0.0, 2), (1.0, 3)],
|
|
|
|
"extend": "reflect",
|
|
|
|
},
|
|
|
|
"p0": (1, 2),
|
|
|
|
"p1": (3, 4),
|
|
|
|
"p2": (2, 2),
|
|
|
|
},
|
2020-11-04 21:59:30 -08:00
|
|
|
),
|
2020-03-11 16:46:33 +00:00
|
|
|
],
|
|
|
|
}
|
|
|
|
)
|
2020-11-03 23:33:01 -08:00
|
|
|
assertIsColrV1(colr)
|
2020-03-11 16:46:33 +00:00
|
|
|
assert colr.table.BaseGlyphRecordCount == 0
|
|
|
|
assert colr.table.BaseGlyphRecordArray is None
|
|
|
|
assert colr.table.LayerRecordCount == 0
|
|
|
|
assert colr.table.LayerRecordArray is None
|
|
|
|
|
|
|
|
def test_automatic_version_mixed_solid_and_gradient_glyphs(self):
|
|
|
|
colr = builder.buildCOLR(
|
|
|
|
{
|
|
|
|
"a": [("b", 0), ("c", 1)],
|
|
|
|
"d": [
|
|
|
|
(
|
|
|
|
"e",
|
|
|
|
{
|
2020-11-10 21:51:33 -08:00
|
|
|
"format": 3,
|
2020-03-11 16:46:33 +00:00
|
|
|
"colorLine": {"stops": [(0.0, 2), (1.0, 3)]},
|
|
|
|
"p0": (1, 2),
|
|
|
|
"p1": (3, 4),
|
|
|
|
"p2": (2, 2),
|
|
|
|
},
|
2020-11-04 21:59:30 -08:00
|
|
|
),
|
2020-11-10 21:51:33 -08:00
|
|
|
("f", {"format": 2, "paletteIndex": 2, "alpha": 0.8}),
|
2020-03-11 16:46:33 +00:00
|
|
|
],
|
|
|
|
}
|
|
|
|
)
|
2020-11-03 23:33:01 -08:00
|
|
|
assertIsColrV1(colr)
|
2020-03-11 16:46:33 +00:00
|
|
|
assert colr.table.VarStore is None
|
|
|
|
|
|
|
|
assert colr.table.BaseGlyphRecordCount == 1
|
|
|
|
assert isinstance(colr.table.BaseGlyphRecordArray, ot.BaseGlyphRecordArray)
|
|
|
|
assert colr.table.LayerRecordCount == 2
|
|
|
|
assert isinstance(colr.table.LayerRecordArray, ot.LayerRecordArray)
|
|
|
|
|
2020-07-01 18:16:07 +01:00
|
|
|
assert isinstance(colr.table.BaseGlyphV1List, ot.BaseGlyphV1List)
|
|
|
|
assert colr.table.BaseGlyphV1List.BaseGlyphCount == 1
|
2020-03-11 16:46:33 +00:00
|
|
|
assert isinstance(
|
2020-07-01 18:16:07 +01:00
|
|
|
colr.table.BaseGlyphV1List.BaseGlyphV1Record[0], ot.BaseGlyphV1Record
|
2020-03-11 16:46:33 +00:00
|
|
|
)
|
2020-07-01 18:16:07 +01:00
|
|
|
assert colr.table.BaseGlyphV1List.BaseGlyphV1Record[0].BaseGlyph == "d"
|
2020-11-10 21:51:33 -08:00
|
|
|
assert isinstance(colr.table.LayerV1List, ot.LayerV1List)
|
2020-11-03 23:33:01 -08:00
|
|
|
assert colr.table.LayerV1List.Paint[0].Glyph == "e"
|
2020-03-11 16:46:33 +00:00
|
|
|
|
|
|
|
def test_explicit_version_0(self):
|
|
|
|
colr = builder.buildCOLR({"a": [("b", 0), ("c", 1)]}, version=0)
|
|
|
|
assert colr.version == 0
|
|
|
|
assert hasattr(colr, "ColorLayers")
|
|
|
|
|
|
|
|
def test_explicit_version_1(self):
|
|
|
|
colr = builder.buildCOLR({"a": [("b", 0), ("c", 1)]}, version=1)
|
|
|
|
assert colr.version == 1
|
|
|
|
assert not hasattr(colr, "ColorLayers")
|
|
|
|
assert hasattr(colr, "table")
|
|
|
|
assert isinstance(colr.table, ot.COLR)
|
|
|
|
assert colr.table.VarStore is None
|