Merge pull request #2008 from fonttools/colrv1-rev2

Update COLRv1 impl following proposed changes in the draft spec
This commit is contained in:
Cosimo Lupo 2020-07-10 09:57:00 +01:00 committed by GitHub
commit 4594a0c378
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 253 additions and 309 deletions

View File

@ -35,7 +35,6 @@ _ColorStopsList = Sequence[_ColorStopInput]
_ExtendInput = Union[int, str, ExtendMode]
_ColorLineInput = Union[_Kwargs, ot.ColorLine]
_PointTuple = Tuple[_ScalarInput, _ScalarInput]
_PointInput = Union[_PointTuple, ot.Point]
_AffineTuple = Tuple[_ScalarInput, _ScalarInput, _ScalarInput, _ScalarInput]
_AffineInput = Union[_AffineTuple, ot.Affine2x2]
@ -132,7 +131,7 @@ def buildCOLR(
colr.BaseGlyphRecordArray = colr.LayerRecordArray = None
if colorGlyphsV1:
colr.BaseGlyphV1Array = buildBaseGlyphV1Array(colorGlyphsV1, glyphMap)
colr.BaseGlyphV1List = buildBaseGlyphV1List(colorGlyphsV1, glyphMap)
if version is None:
version = 1 if (varStore or colorGlyphsV1) else 0
@ -275,7 +274,7 @@ def buildCPAL(
# COLR v1 tables
# See draft proposal at: https://github.com/googlefonts/colr-gradients-spec
_DEFAULT_TRANSPARENCY = VariableFloat(0.0)
_DEFAULT_ALPHA = VariableFloat(1.0)
def _splitSolidAndGradientGlyphs(
@ -290,7 +289,7 @@ def _splitSolidAndGradientGlyphs(
paint = _to_ot_paint(paint)
if (
paint.Format != 1
or paint.Color.Transparency.value != _DEFAULT_TRANSPARENCY.value
or paint.Color.Alpha.value != _DEFAULT_ALPHA.value
):
allSolidColors = False
newLayers.append((layerGlyph, paint))
@ -323,32 +322,32 @@ _to_variable_float = partial(_to_variable_value, cls=VariableFloat)
_to_variable_int = partial(_to_variable_value, cls=VariableInt)
def buildColor(
paletteIndex: int, transparency: _ScalarInput = _DEFAULT_TRANSPARENCY
) -> ot.Color:
self = ot.Color()
def buildColorIndex(
paletteIndex: int, alpha: _ScalarInput = _DEFAULT_ALPHA
) -> ot.ColorIndex:
self = ot.ColorIndex()
self.PaletteIndex = int(paletteIndex)
self.Transparency = _to_variable_float(transparency)
self.Alpha = _to_variable_float(alpha)
return self
def buildSolidColorPaint(
paletteIndex: int, transparency: _ScalarInput = _DEFAULT_TRANSPARENCY
paletteIndex: int, alpha: _ScalarInput = _DEFAULT_ALPHA
) -> ot.Paint:
self = ot.Paint()
self.Format = 1
self.Color = buildColor(paletteIndex, transparency)
self.Color = buildColorIndex(paletteIndex, alpha)
return self
def buildColorStop(
offset: _ScalarInput,
paletteIndex: int,
transparency: _ScalarInput = _DEFAULT_TRANSPARENCY,
alpha: _ScalarInput = _DEFAULT_ALPHA,
) -> ot.ColorStop:
self = ot.ColorStop()
self.StopOffset = _to_variable_float(offset)
self.Color = buildColor(paletteIndex, transparency)
self.Color = buildColorIndex(paletteIndex, alpha)
return self
@ -380,20 +379,6 @@ def buildColorLine(
return self
def buildPoint(x: _ScalarInput, y: _ScalarInput) -> ot.Point:
self = ot.Point()
# positions are encoded as Int16 so round to int
self.x = _to_variable_int(x)
self.y = _to_variable_int(y)
return self
def _to_variable_point(pt: _PointInput) -> ot.Point:
if isinstance(pt, ot.Point):
return pt
return buildPoint(*pt)
def _to_color_line(obj):
if isinstance(obj, ot.ColorLine):
return obj
@ -404,9 +389,9 @@ def _to_color_line(obj):
def buildLinearGradientPaint(
colorLine: _ColorLineInput,
p0: _PointInput,
p1: _PointInput,
p2: Optional[_PointInput] = None,
p0: _PointTuple,
p1: _PointTuple,
p2: Optional[_PointTuple] = None,
) -> ot.Paint:
self = ot.Paint()
self.Format = 2
@ -414,8 +399,9 @@ def buildLinearGradientPaint(
if p2 is None:
p2 = copy.copy(p1)
for i, pt in enumerate((p0, p1, p2)):
setattr(self, f"p{i}", _to_variable_point(pt))
for i, (x, y) in enumerate((p0, p1, p2)):
setattr(self, f"x{i}", _to_variable_int(x))
setattr(self, f"y{i}", _to_variable_int(y))
return self
@ -433,27 +419,25 @@ def buildAffine2x2(
def buildRadialGradientPaint(
colorLine: _ColorLineInput,
c0: _PointInput,
c1: _PointInput,
c0: _PointTuple,
c1: _PointTuple,
r0: _ScalarInput,
r1: _ScalarInput,
affine: Optional[_AffineInput] = None,
transform: Optional[_AffineInput] = None,
) -> ot.Paint:
self = ot.Paint()
self.Format = 3
self.ColorLine = _to_color_line(colorLine)
for i, pt in [(0, c0), (1, c1)]:
setattr(self, f"c{i}", _to_variable_point(pt))
for i, r in [(0, r0), (1, r1)]:
# distances are encoded as UShort so we round to int
for i, (x, y), r in [(0, c0, r0), (1, c1, r1)]:
setattr(self, f"x{i}", _to_variable_int(x))
setattr(self, f"y{i}", _to_variable_int(y))
setattr(self, f"r{i}", _to_variable_int(r))
if affine is not None and not isinstance(affine, ot.Affine2x2):
affine = buildAffine2x2(*affine)
self.Affine = affine
if transform is not None and not isinstance(transform, ot.Affine2x2):
transform = buildAffine2x2(*transform)
self.Transform = transform
return self
@ -476,10 +460,10 @@ def buildLayerV1Record(layerGlyph: str, paint: _PaintInput) -> ot.LayerV1Record:
return self
def buildLayerV1Array(
def buildLayerV1List(
layers: Sequence[Union[_LayerTuple, ot.LayerV1Record]]
) -> ot.LayerV1Array:
self = ot.LayerV1Array()
) -> ot.LayerV1List:
self = ot.LayerV1List()
self.LayerCount = len(layers)
records = []
for layer in layers:
@ -494,20 +478,20 @@ def buildLayerV1Array(
def buildBaseGlyphV1Record(
baseGlyph: str, layers: Union[_LayersList, ot.LayerV1Array]
) -> ot.BaseGlyphV1Array:
baseGlyph: str, layers: Union[_LayersList, ot.LayerV1List]
) -> ot.BaseGlyphV1List:
self = ot.BaseGlyphV1Record()
self.BaseGlyph = baseGlyph
if not isinstance(layers, ot.LayerV1Array):
layers = buildLayerV1Array(layers)
self.LayerV1Array = layers
if not isinstance(layers, ot.LayerV1List):
layers = buildLayerV1List(layers)
self.LayerV1List = layers
return self
def buildBaseGlyphV1Array(
colorGlyphs: Union[_ColorGlyphsDict, Dict[str, ot.LayerV1Array]],
def buildBaseGlyphV1List(
colorGlyphs: Union[_ColorGlyphsDict, Dict[str, ot.LayerV1List]],
glyphMap: Optional[Mapping[str, int]] = None,
) -> ot.BaseGlyphV1Array:
) -> ot.BaseGlyphV1List:
if glyphMap is not None:
colorGlyphItems = sorted(
colorGlyphs.items(), key=lambda item: glyphMap[item[0]]
@ -518,7 +502,7 @@ def buildBaseGlyphV1Array(
buildBaseGlyphV1Record(baseGlyph, layers)
for baseGlyph, layers in colorGlyphItems
]
self = ot.BaseGlyphV1Array()
self = ot.BaseGlyphV1List()
self.BaseGlyphCount = len(records)
self.BaseGlyphV1Record = records
return self

View File

@ -134,48 +134,38 @@ class OTTableReader(object):
offset = self.offset + offset
return self.__class__(self.data, self.localState, offset, self.tableTag)
def readUShort(self):
def readValue(self, typecode, staticSize):
pos = self.pos
newpos = pos + 2
value, = struct.unpack(">H", self.data[pos:newpos])
newpos = pos + staticSize
value, = struct.unpack(f">{typecode}", self.data[pos:newpos])
self.pos = newpos
return value
def readUShortArray(self, count):
def readUShort(self):
return self.readValue("H", staticSize=2)
def readArray(self, typecode, staticSize, count):
pos = self.pos
newpos = pos + count * 2
value = array.array("H", self.data[pos:newpos])
newpos = pos + count * staticSize
value = array.array(typecode, self.data[pos:newpos])
if sys.byteorder != "big": value.byteswap()
self.pos = newpos
return value
def readUShortArray(self, count):
return self.readArray("H", staticSize=2, count=count)
def readInt8(self):
pos = self.pos
newpos = pos + 1
value, = struct.unpack(">b", self.data[pos:newpos])
self.pos = newpos
return value
return self.readValue("b", staticSize=1)
def readShort(self):
pos = self.pos
newpos = pos + 2
value, = struct.unpack(">h", self.data[pos:newpos])
self.pos = newpos
return value
return self.readValue("h", staticSize=2)
def readLong(self):
pos = self.pos
newpos = pos + 4
value, = struct.unpack(">l", self.data[pos:newpos])
self.pos = newpos
return value
return self.readValue("l", staticSize=4)
def readUInt8(self):
pos = self.pos
newpos = pos + 1
value, = struct.unpack(">B", self.data[pos:newpos])
self.pos = newpos
return value
return self.readValue("B", staticSize=1)
def readUInt24(self):
pos = self.pos
@ -185,11 +175,7 @@ class OTTableReader(object):
return value
def readULong(self):
pos = self.pos
newpos = pos + 4
value, = struct.unpack(">L", self.data[pos:newpos])
self.pos = newpos
return value
return self.readValue("L", staticSize=4)
def readTag(self):
pos = self.pos
@ -417,6 +403,9 @@ class OTTableWriter(object):
# But we just care about first one right now.
return subwriter
def writeValue(self, typecode, value):
self.items.append(struct.pack(f">{typecode}", value))
def writeUShort(self, value):
assert 0 <= value < 0x10000, value
self.items.append(struct.pack(">H", value))

View File

@ -295,9 +295,10 @@ class Tag(SimpleValue):
class GlyphID(SimpleValue):
staticSize = 2
typecode = "H"
def readArray(self, reader, font, tableDict, count):
glyphOrder = font.getGlyphOrder()
gids = reader.readUShortArray(count)
gids = reader.readArray(self.typecode, self.staticSize, count)
try:
l = [glyphOrder[gid] for gid in gids]
except IndexError:
@ -305,9 +306,14 @@ class GlyphID(SimpleValue):
l = [font.getGlyphName(gid) for gid in gids]
return l
def read(self, reader, font, tableDict):
return font.getGlyphName(reader.readUShort())
return font.getGlyphName(reader.readValue(self.typecode, self.staticSize))
def write(self, writer, font, tableDict, value, repeatIndex=None):
writer.writeUShort(font.getGlyphID(value))
writer.writeValue(self.typecode, font.getGlyphID(value))
class GlyphID32(GlyphID):
staticSize = 4
typecode = "L"
class NameID(UShort):
@ -1680,22 +1686,22 @@ class _NamedTupleConverter(BaseConverter):
return self.tupleClass(**kwargs)
class VariableScalar(_NamedTupleConverter):
class VarFixed(_NamedTupleConverter):
tupleClass = VariableFloat
converterClasses = [Fixed, ULong]
class VariableNormalizedScalar(_NamedTupleConverter):
class VarF2Dot14(_NamedTupleConverter):
tupleClass = VariableFloat
converterClasses = [F2Dot14, ULong]
class VariablePosition(_NamedTupleConverter):
class VarInt16(_NamedTupleConverter):
tupleClass = VariableInt
converterClasses = [Short, ULong]
class VariableDistance(_NamedTupleConverter):
class VarUInt16(_NamedTupleConverter):
tupleClass = VariableInt
converterClasses = [UShort, ULong]
@ -1725,6 +1731,7 @@ converterMapping = {
"Version": Version,
"Tag": Tag,
"GlyphID": GlyphID,
"GlyphID32": GlyphID32,
"NameID": NameID,
"DeciPoints": DeciPoints,
"Fixed": Fixed,
@ -1755,8 +1762,8 @@ converterMapping = {
"LOffsetTo": lambda C: partial(LTable, tableClass=C),
# Variable types
"VariableScalar": VariableScalar,
"VariableNormalizedScalar": VariableNormalizedScalar,
"VariablePosition": VariablePosition,
"VariableDistance": VariableDistance,
"VarFixed": VarFixed,
"VarF2Dot14": VarF2Dot14,
"VarInt16": VarInt16,
"VarUInt16": VarUInt16,
}

View File

@ -1549,7 +1549,7 @@ otData = [
('LOffset', 'BaseGlyphRecordArray', None, None, 'Offset (from beginning of COLR table) to Base Glyph records.'),
('LOffset', 'LayerRecordArray', None, None, 'Offset (from beginning of COLR table) to Layer Records.'),
('uint16', 'LayerRecordCount', None, None, 'Number of Layer Records.'),
('LOffset', 'BaseGlyphV1Array', None, 'Version >= 1', 'Offset (from beginning of COLR table) to array of Version-1 Base Glyph records.'),
('LOffset', 'BaseGlyphV1List', None, 'Version >= 1', 'Offset (from beginning of COLR table) to array of Version-1 Base Glyph records.'),
('LOffset', 'VarStore', None, 'Version >= 1', 'Offset to variation store (may be NULL)'),
]),
@ -1572,46 +1572,41 @@ otData = [
('uint16', 'PaletteIndex', None, None, 'Index value to use with a selected color palette.'),
]),
('BaseGlyphV1Array', [
('BaseGlyphV1List', [
('uint32', 'BaseGlyphCount', None, None, 'Number of Version-1 Base Glyph records'),
('struct', 'BaseGlyphV1Record', 'BaseGlyphCount', 0, 'Array of Version-1 Base Glyph records'),
]),
('BaseGlyphV1Record', [
('GlyphID', 'BaseGlyph', None, None, 'Glyph ID of reference glyph.'),
('LOffset', 'LayerV1Array', None, None, 'Offset (from beginning of BaseGlyphV1Array) to LayerV1Array.'),
('LOffset', 'LayerV1List', None, None, 'Offset (from beginning of BaseGlyphV1List) to LayerV1List.'),
]),
('LayerV1Array', [
('LayerV1List', [
('uint32', 'LayerCount', None, None, 'Number of Version-1 Layer records'),
('struct', 'LayerV1Record', 'LayerCount', 0, 'Array of Version-1 Layer records'),
]),
('LayerV1Record', [
('GlyphID', 'LayerGlyph', None, None, 'Glyph ID of layer glyph (must be in z-order from bottom to top).'),
('LOffset', 'Paint', None, None, 'Offset (from beginning of LayerV1Array) to Paint subtable.'),
('LOffset', 'Paint', None, None, 'Offset (from beginning of LayerV1List) to Paint subtable.'),
]),
('Affine2x2', [
('VariableScalar', 'xx', None, None, ''),
('VariableScalar', 'xy', None, None, ''),
('VariableScalar', 'yx', None, None, ''),
('VariableScalar', 'yy', None, None, ''),
('VarFixed', 'xx', None, None, ''),
('VarFixed', 'xy', None, None, ''),
('VarFixed', 'yx', None, None, ''),
('VarFixed', 'yy', None, None, ''),
]),
('Point', [
('VariablePosition', 'x', None, None, ''),
('VariablePosition', 'y', None, None, ''),
]),
('Color', [
('ColorIndex', [
('uint16', 'PaletteIndex', None, None, 'Index value to use with a selected color palette.'),
('VariableNormalizedScalar', 'Transparency', None, None, 'Values outsided [0.,1.] reserved'),
('VarF2Dot14', 'Alpha', None, None, 'Values outsided [0.,1.] reserved'),
]),
('ColorStop', [
('VariableNormalizedScalar', 'StopOffset', None, None, ''),
('Color', 'Color', None, None, ''),
('VarF2Dot14', 'StopOffset', None, None, ''),
('ColorIndex', 'Color', None, None, ''),
]),
('ColorLine', [
@ -1622,24 +1617,29 @@ otData = [
('PaintFormat1', [
('uint16', 'PaintFormat', None, None, 'Format identifier-format = 1'),
('Color', 'Color', None, None, 'A solid color paint.'),
('ColorIndex', 'Color', None, None, 'A solid color paint.'),
]),
('PaintFormat2', [
('uint16', 'PaintFormat', None, None, 'Format identifier-format = 2'),
('LOffset', 'ColorLine', None, None, 'Offset (from beginning of Paint table) to ColorLine subtable.'),
('Point', 'p0', None, None, ''),
('Point', 'p1', None, None, ''),
('Point', 'p2', None, None, 'Normal; equal to p1 in simple cases.'),
('VarInt16', 'x0', None, None, ''),
('VarInt16', 'y0', None, None, ''),
('VarInt16', 'x1', None, None, ''),
('VarInt16', 'y1', None, None, ''),
('VarInt16', 'x2', None, None, ''),
('VarInt16', 'y2', None, None, ''),
]),
('PaintFormat3', [
('uint16', 'PaintFormat', None, None, 'Format identifier-format = 3'),
('LOffset', 'ColorLine', None, None, 'Offset (from beginning of Paint table) to ColorLine subtable.'),
('Point', 'c0', None, None, ''),
('Point', 'c1', None, None, ''),
('VariableDistance', 'r0', None, None, ''),
('VariableDistance', 'r1', None, None, ''),
('LOffsetTo(Affine2x2)', 'Affine', None, None, 'Offset (from beginning of Paint table) to Affine2x2 subtable.'),
('VarInt16', 'x0', None, None, ''),
('VarInt16', 'y0', None, None, ''),
('VarUInt16', 'r0', None, None, ''),
('VarInt16', 'x1', None, None, ''),
('VarInt16', 'y1', None, None, ''),
('VarUInt16', 'r1', None, None, ''),
('LOffsetTo(Affine2x2)', 'Transform', None, None, 'Offset (from beginning of Paint table) to Affine2x2 subtable.'),
]),
]

View File

@ -1197,7 +1197,7 @@ class BaseGlyphRecordArray(BaseTable):
return self.__dict__.copy()
class BaseGlyphV1Array(BaseTable):
class BaseGlyphV1List(BaseTable):
def preWrite(self, font):
self.BaseGlyphV1Record = sorted(

View File

@ -188,63 +188,61 @@ def test_buildCPAL_invalid_color():
builder.buildCPAL([[(0, 0, 0, 0)], [(1, 1, -1, 2)]])
def test_buildColor():
c = builder.buildColor(0)
def test_buildColorIndex():
c = builder.buildColorIndex(0)
assert c.PaletteIndex == 0
assert c.Transparency.value == 0.0
assert c.Transparency.varIdx == 0
assert c.Alpha.value == 1.0
assert c.Alpha.varIdx == 0
c = builder.buildColor(1, transparency=0.5)
c = builder.buildColorIndex(1, alpha=0.5)
assert c.PaletteIndex == 1
assert c.Transparency.value == 0.5
assert c.Transparency.varIdx == 0
assert c.Alpha.value == 0.5
assert c.Alpha.varIdx == 0
c = builder.buildColor(3, transparency=builder.VariableFloat(0.5, varIdx=2))
c = builder.buildColorIndex(3, alpha=builder.VariableFloat(0.5, varIdx=2))
assert c.PaletteIndex == 3
assert c.Transparency.value == 0.5
assert c.Transparency.varIdx == 2
assert c.Alpha.value == 0.5
assert c.Alpha.varIdx == 2
def test_buildSolidColorPaint():
p = builder.buildSolidColorPaint(0)
assert p.Format == 1
assert p.Color.PaletteIndex == 0
assert p.Color.Transparency.value == 0.0
assert p.Color.Transparency.varIdx == 0
assert p.Color.Alpha.value == 1.0
assert p.Color.Alpha.varIdx == 0
p = builder.buildSolidColorPaint(1, transparency=0.5)
p = builder.buildSolidColorPaint(1, alpha=0.5)
assert p.Format == 1
assert p.Color.PaletteIndex == 1
assert p.Color.Transparency.value == 0.5
assert p.Color.Transparency.varIdx == 0
assert p.Color.Alpha.value == 0.5
assert p.Color.Alpha.varIdx == 0
p = builder.buildSolidColorPaint(
3, transparency=builder.VariableFloat(0.5, varIdx=2)
)
p = builder.buildSolidColorPaint(3, alpha=builder.VariableFloat(0.5, varIdx=2))
assert p.Format == 1
assert p.Color.PaletteIndex == 3
assert p.Color.Transparency.value == 0.5
assert p.Color.Transparency.varIdx == 2
assert p.Color.Alpha.value == 0.5
assert p.Color.Alpha.varIdx == 2
def test_buildColorStop():
s = builder.buildColorStop(0.1, 2)
assert s.StopOffset == builder.VariableFloat(0.1)
assert s.Color.PaletteIndex == 2
assert s.Color.Transparency == builder._DEFAULT_TRANSPARENCY
assert s.Color.Alpha == builder._DEFAULT_ALPHA
s = builder.buildColorStop(offset=0.2, paletteIndex=3, transparency=0.4)
s = builder.buildColorStop(offset=0.2, paletteIndex=3, alpha=0.4)
assert s.StopOffset == builder.VariableFloat(0.2)
assert s.Color == builder.buildColor(3, transparency=0.4)
assert s.Color == builder.buildColorIndex(3, alpha=0.4)
s = builder.buildColorStop(
offset=builder.VariableFloat(0.0, varIdx=1),
paletteIndex=0,
transparency=builder.VariableFloat(0.3, varIdx=2),
alpha=builder.VariableFloat(0.3, varIdx=2),
)
assert s.StopOffset == builder.VariableFloat(0.0, varIdx=1)
assert s.Color.PaletteIndex == 0
assert s.Color.Transparency == builder.VariableFloat(0.3, varIdx=2)
assert s.Color.Alpha == builder.VariableFloat(0.3, varIdx=2)
def test_buildColorLine():
@ -272,42 +270,20 @@ def test_buildColorLine():
] == stops
stops = [
{"offset": (0.0, 1), "paletteIndex": 0, "transparency": (0.5, 2)},
{"offset": (1.0, 3), "paletteIndex": 1, "transparency": (0.3, 4)},
{"offset": (0.0, 1), "paletteIndex": 0, "alpha": (0.5, 2)},
{"offset": (1.0, 3), "paletteIndex": 1, "alpha": (0.3, 4)},
]
cline = builder.buildColorLine(stops)
assert [
{
"offset": cs.StopOffset,
"paletteIndex": cs.Color.PaletteIndex,
"transparency": cs.Color.Transparency,
"alpha": cs.Color.Alpha,
}
for cs in cline.ColorStop
] == stops
def test_buildPoint():
pt = builder.buildPoint(0, 1)
assert pt.x == builder.VariableInt(0)
assert pt.y == builder.VariableInt(1)
pt = builder.buildPoint(
builder.VariableInt(2, varIdx=1), builder.VariableInt(3, varIdx=2)
)
assert pt.x == builder.VariableInt(2, varIdx=1)
assert pt.y == builder.VariableInt(3, varIdx=2)
# float coords are rounded
pt = builder.buildPoint(x=-2.5, y=3.5)
assert pt.x == builder.VariableInt(-2)
assert pt.y == builder.VariableInt(4)
# tuple args are cast to VariableInt namedtuple
pt = builder.buildPoint((1, 2), (3, 4))
assert pt.x == builder.VariableInt(1, varIdx=2)
assert pt.y == builder.VariableInt(3, varIdx=4)
def test_buildAffine2x2():
matrix = builder.buildAffine2x2(1.5, 0, 0.5, 2.0)
assert matrix.xx == builder.VariableFloat(1.5)
@ -320,49 +296,48 @@ def test_buildLinearGradientPaint():
color_stops = [
builder.buildColorStop(0.0, 0),
builder.buildColorStop(0.5, 1),
builder.buildColorStop(1.0, 2, transparency=0.8),
builder.buildColorStop(1.0, 2, alpha=0.8),
]
color_line = builder.buildColorLine(color_stops, extend=builder.ExtendMode.REPEAT)
p0 = builder.buildPoint(x=100, y=200)
p1 = builder.buildPoint(x=150, y=250)
p0 = (builder.VariableInt(100), builder.VariableInt(200))
p1 = (builder.VariableInt(150), builder.VariableInt(250))
gradient = builder.buildLinearGradientPaint(color_line, p0, p1)
assert gradient.Format == 2
assert gradient.ColorLine == color_line
assert gradient.p0 == p0
assert gradient.p1 == p1
assert gradient.p2 == gradient.p1
assert gradient.p2 is not gradient.p1
assert (gradient.x0, gradient.y0) == p0
assert (gradient.x1, gradient.y1) == p1
assert (gradient.x2, gradient.y2) == p1
gradient = builder.buildLinearGradientPaint({"stops": color_stops}, p0, p1)
assert gradient.ColorLine.Extend == builder.ExtendMode.PAD
assert gradient.ColorLine.ColorStop == color_stops
gradient = builder.buildLinearGradientPaint(color_line, p0, p1, p2=(150, 230))
assert gradient.p2 == builder.buildPoint(x=150, y=230)
assert gradient.p2 != gradient.p1
assert (gradient.x2.value, gradient.y2.value) == (150, 230)
assert (gradient.x2, gradient.y2) != (gradient.x1, gradient.y1)
def test_buildRadialGradientPaint():
color_stops = [
builder.buildColorStop(0.0, 0),
builder.buildColorStop(0.5, 1),
builder.buildColorStop(1.0, 2, transparency=0.8),
builder.buildColorStop(1.0, 2, alpha=0.8),
]
color_line = builder.buildColorLine(color_stops, extend=builder.ExtendMode.REPEAT)
c0 = builder.buildPoint(x=100, y=200)
c1 = builder.buildPoint(x=150, y=250)
c0 = (builder.VariableInt(100), builder.VariableInt(200))
c1 = (builder.VariableInt(150), builder.VariableInt(250))
r0 = builder.VariableInt(10)
r1 = builder.VariableInt(5)
gradient = builder.buildRadialGradientPaint(color_line, c0, c1, r0, r1)
assert gradient.Format == 3
assert gradient.ColorLine == color_line
assert gradient.c0 == c0
assert gradient.c1 == c1
assert (gradient.x0, gradient.y0) == c0
assert (gradient.x1, gradient.y1) == c1
assert gradient.r0 == r0
assert gradient.r1 == r1
assert gradient.Affine is None
assert gradient.Transform is None
gradient = builder.buildRadialGradientPaint({"stops": color_stops}, c0, c1, r0, r1)
assert gradient.ColorLine.Extend == builder.ExtendMode.PAD
@ -370,14 +345,14 @@ def test_buildRadialGradientPaint():
matrix = builder.buildAffine2x2(2.0, 0.0, 0.0, 2.0)
gradient = builder.buildRadialGradientPaint(
color_line, c0, c1, r0, r1, affine=matrix
color_line, c0, c1, r0, r1, transform=matrix
)
assert gradient.Affine == matrix
assert gradient.Transform == matrix
gradient = builder.buildRadialGradientPaint(
color_line, c0, c1, r0, r1, affine=(2.0, 0.0, 0.0, 2.0)
color_line, c0, c1, r0, r1, transform=(2.0, 0.0, 0.0, 2.0)
)
assert gradient.Affine == matrix
assert gradient.Transform == matrix
def test_buildLayerV1Record():
@ -389,7 +364,7 @@ def test_buildLayerV1Record():
layer = builder.buildLayerV1Record("a", builder.buildSolidColorPaint(3, 0.9))
assert layer.Paint.Format == 1
assert layer.Paint.Color.PaletteIndex == 3
assert layer.Paint.Color.Transparency.value == 0.9
assert layer.Paint.Color.Alpha.value == 0.9
layer = builder.buildLayerV1Record(
"a",
@ -402,10 +377,10 @@ def test_buildLayerV1Record():
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.p0.x.value == 100
assert layer.Paint.p0.y.value == 200
assert layer.Paint.p1.x.value == 150
assert layer.Paint.p1.y.value == 250
assert layer.Paint.x0.value == 100
assert layer.Paint.y0.value == 200
assert layer.Paint.x1.value == 150
assert layer.Paint.y1.value == 250
layer = builder.buildLayerV1Record(
"a",
@ -413,7 +388,7 @@ def test_buildLayerV1Record():
{
"stops": [
(0.0, 5),
{"offset": 0.5, "paletteIndex": 6, "transparency": 0.8},
{"offset": 0.5, "paletteIndex": 6, "alpha": 0.8},
(1.0, 7),
]
},
@ -428,14 +403,14 @@ def test_buildLayerV1Record():
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
assert layer.Paint.ColorLine.ColorStop[1].Color.Transparency.value == 0.8
assert layer.Paint.ColorLine.ColorStop[1].Color.Alpha.value == 0.8
assert layer.Paint.ColorLine.ColorStop[2].StopOffset.value == 1.0
assert layer.Paint.ColorLine.ColorStop[2].Color.PaletteIndex == 7
assert layer.Paint.c0.x.value == 50
assert layer.Paint.c0.y.value == 50
assert layer.Paint.c1.x.value == 75
assert layer.Paint.c1.y.value == 75
assert layer.Paint.x0.value == 50
assert layer.Paint.y0.value == 50
assert layer.Paint.r0.value == 30
assert layer.Paint.x1.value == 75
assert layer.Paint.y1.value == 75
assert layer.Paint.r1.value == 10
@ -472,10 +447,10 @@ def test_buildLayerV1Record_from_dict():
assert layer.Paint.r0.value == 4
def test_buildLayerV1Array():
def test_buildLayerV1List():
layers = [
("a", 1),
("b", {"format": 1, "paletteIndex": 2, "transparency": 0.5}),
("b", {"format": 1, "paletteIndex": 2, "alpha": 0.5}),
(
"c",
{
@ -492,7 +467,7 @@ def test_buildLayerV1Array():
"colorLine": {
"stops": [
{"offset": 0.0, "paletteIndex": 5},
{"offset": 0.5, "paletteIndex": 6, "transparency": 0.8},
{"offset": 0.5, "paletteIndex": 6, "alpha": 0.8},
{"offset": 1.0, "paletteIndex": 7},
]
},
@ -504,28 +479,28 @@ def test_buildLayerV1Array():
),
builder.buildLayerV1Record("e", builder.buildSolidColorPaint(8)),
]
layersArray = builder.buildLayerV1Array(layers)
layers = builder.buildLayerV1List(layers)
assert layersArray.LayerCount == len(layersArray.LayerV1Record)
assert all(isinstance(l, ot.LayerV1Record) for l in layersArray.LayerV1Record)
assert layers.LayerCount == len(layers.LayerV1Record)
assert all(isinstance(l, ot.LayerV1Record) for l in layers.LayerV1Record)
def test_buildBaseGlyphV1Record():
baseGlyphRec = builder.buildBaseGlyphV1Record("a", [("b", 0), ("c", 1)])
assert baseGlyphRec.BaseGlyph == "a"
assert isinstance(baseGlyphRec.LayerV1Array, ot.LayerV1Array)
assert isinstance(baseGlyphRec.LayerV1List, ot.LayerV1List)
layerArray = builder.buildLayerV1Array([("b", 0), ("c", 1)])
baseGlyphRec = builder.buildBaseGlyphV1Record("a", layerArray)
layers = builder.buildLayerV1List([("b", 0), ("c", 1)])
baseGlyphRec = builder.buildBaseGlyphV1Record("a", layers)
assert baseGlyphRec.BaseGlyph == "a"
assert baseGlyphRec.LayerV1Array == layerArray
assert baseGlyphRec.LayerV1List == layers
def test_buildBaseGlyphV1Array():
def test_buildBaseGlyphV1List():
colorGlyphs = {
"a": [("b", 0), ("c", 1)],
"d": [
("e", {"format": 1, "paletteIndex": 2, "transparency": 0.8}),
("e", {"format": 1, "paletteIndex": 2, "alpha": 0.8}),
(
"f",
{
@ -538,7 +513,7 @@ def test_buildBaseGlyphV1Array():
},
),
],
"g": builder.buildLayerV1Array([("h", 5)]),
"g": builder.buildLayerV1List([("h", 5)]),
}
glyphMap = {
".notdef": 0,
@ -552,17 +527,17 @@ def test_buildBaseGlyphV1Array():
"h": 8,
}
baseGlyphArray = builder.buildBaseGlyphV1Array(colorGlyphs, glyphMap)
assert baseGlyphArray.BaseGlyphCount == len(colorGlyphs)
assert baseGlyphArray.BaseGlyphV1Record[0].BaseGlyph == "d"
assert baseGlyphArray.BaseGlyphV1Record[1].BaseGlyph == "a"
assert baseGlyphArray.BaseGlyphV1Record[2].BaseGlyph == "g"
baseGlyphs = builder.buildBaseGlyphV1List(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"
baseGlyphArray = builder.buildBaseGlyphV1Array(colorGlyphs)
assert baseGlyphArray.BaseGlyphCount == len(colorGlyphs)
assert baseGlyphArray.BaseGlyphV1Record[0].BaseGlyph == "a"
assert baseGlyphArray.BaseGlyphV1Record[1].BaseGlyph == "d"
assert baseGlyphArray.BaseGlyphV1Record[2].BaseGlyph == "g"
baseGlyphs = builder.buildBaseGlyphV1List(colorGlyphs)
assert baseGlyphs.BaseGlyphCount == len(colorGlyphs)
assert baseGlyphs.BaseGlyphV1Record[0].BaseGlyph == "a"
assert baseGlyphs.BaseGlyphV1Record[1].BaseGlyph == "d"
assert baseGlyphs.BaseGlyphV1Record[2].BaseGlyph == "g"
def test_splitSolidAndGradientGlyphs():
@ -581,7 +556,7 @@ def test_splitSolidAndGradientGlyphs():
assert not colorGlyphsV1
colorGlyphs = {
"a": [("b", builder.buildSolidColorPaint(paletteIndex=0, transparency=1.0))]
"a": [("b", builder.buildSolidColorPaint(paletteIndex=0, alpha=0.0))]
}
colorGlyphsV0, colorGlyphsV1 = builder._splitSolidAndGradientGlyphs(colorGlyphs)
@ -649,7 +624,7 @@ class BuildCOLRTest(object):
"r1": 2,
},
),
("c", {"format": 1, "paletteIndex": 2, "transparency": 0.8}),
("c", {"format": 1, "paletteIndex": 2, "alpha": 0.8}),
],
"d": [
(
@ -706,19 +681,18 @@ class BuildCOLRTest(object):
assert colr.table.LayerRecordCount == 2
assert isinstance(colr.table.LayerRecordArray, ot.LayerRecordArray)
assert isinstance(colr.table.BaseGlyphV1Array, ot.BaseGlyphV1Array)
assert colr.table.BaseGlyphV1Array.BaseGlyphCount == 1
assert isinstance(colr.table.BaseGlyphV1List, ot.BaseGlyphV1List)
assert colr.table.BaseGlyphV1List.BaseGlyphCount == 1
assert isinstance(
colr.table.BaseGlyphV1Array.BaseGlyphV1Record[0], ot.BaseGlyphV1Record
colr.table.BaseGlyphV1List.BaseGlyphV1Record[0], ot.BaseGlyphV1Record
)
assert colr.table.BaseGlyphV1Array.BaseGlyphV1Record[0].BaseGlyph == "d"
assert colr.table.BaseGlyphV1List.BaseGlyphV1Record[0].BaseGlyph == "d"
assert isinstance(
colr.table.BaseGlyphV1Array.BaseGlyphV1Record[0].LayerV1Array,
ot.LayerV1Array,
colr.table.BaseGlyphV1List.BaseGlyphV1Record[0].LayerV1List, ot.LayerV1List
)
assert (
colr.table.BaseGlyphV1Array.BaseGlyphV1Record[0]
.LayerV1Array.LayerV1Record[0]
colr.table.BaseGlyphV1List.BaseGlyphV1Record[0]
.LayerV1List.LayerV1Record[0]
.LayerGlyph
== "e"
)

View File

@ -71,7 +71,7 @@ COLR_V1_DATA = (
b"\x00\x00\x00\x16" # Offset to BaseGlyphRecordArray from beginning of table (22)
b"\x00\x00\x00\x1c" # Offset to LayerRecordArray from beginning of table (28)
b"\x00\x03" # LayerRecordCount (3)
b"\x00\x00\x00(" # Offset to BaseGlyphV1Array from beginning of table (40)
b"\x00\x00\x00(" # Offset to BaseGlyphV1List from beginning of table (40)
b"\x00\x00\x00\x00" # Offset to VarStore (NULL)
b"\x00\x06" # BaseGlyphRecord[0].BaseGlyph (6)
b"\x00\x00" # BaseGlyphRecord[0].FirstLayerIndex (0)
@ -82,62 +82,62 @@ COLR_V1_DATA = (
b"\x00\x01" # LayerRecord[1].PaletteIndex (1)
b"\x00\t" # LayerRecord[2].LayerGlyph (9)
b"\x00\x02" # LayerRecord[2].PaletteIndex (2)
b"\x00\x00\x00\x01" # BaseGlyphV1Array.BaseGlyphCount (1)
b"\x00\n" # BaseGlyphV1Array.BaseGlyphV1Record[0].BaseGlyph (10)
b"\x00\x00\x00\n" # Offset to LayerV1Array from beginning of BaseGlyphV1Array (10)
b"\x00\x00\x00\x03" # LayerV1Array.LayerCount (3)
b"\x00\x0b" # LayerV1Array.LayerV1Record[0].LayerGlyph (11)
b"\x00\x00\x00\x16" # Offset to Paint from beginning of LayerV1Array (22)
b"\x00\x0c" # LayerV1Array.LayerV1Record[1].LayerGlyph (12)
b"\x00\x00\x00 " # Offset to Paint from beginning of LayerV1Array (32)
b"\x00\r" # LayerV1Array.LayerV1Record[2].LayerGlyph (13)
b"\x00\x00\x00x" # Offset to Paint from beginning of LayerV1Array (120)
b"\x00\x00\x00\x01" # BaseGlyphV1List.BaseGlyphCount (1)
b"\x00\n" # BaseGlyphV1List.BaseGlyphV1Record[0].BaseGlyph (10)
b"\x00\x00\x00\n" # Offset to LayerV1List from beginning of BaseGlyphV1List (10)
b"\x00\x00\x00\x03" # LayerV1List.LayerCount (3)
b"\x00\x0b" # LayerV1List.LayerV1Record[0].LayerGlyph (11)
b"\x00\x00\x00\x16" # Offset to Paint from beginning of LayerV1List (22)
b"\x00\x0c" # LayerV1List.LayerV1Record[1].LayerGlyph (12)
b"\x00\x00\x00 " # Offset to Paint from beginning of LayerV1List (32)
b"\x00\r" # LayerV1List.LayerV1Record[2].LayerGlyph (13)
b"\x00\x00\x00x" # Offset to Paint from beginning of LayerV1List (120)
b"\x00\x01" # Paint.Format (1)
b"\x00\x02" # Paint.Color.PaletteIndex (2)
b" \x00" # Paint.Color.Transparency.value (0.5)
b"\x00\x00\x00\x00" # Paint.Color.Transparency.varIdx (0)
b" \x00" # Paint.Color.Alpha.value (0.5)
b"\x00\x00\x00\x00" # Paint.Color.Alpha.varIdx (0)
b"\x00\x02" # Paint.Format (2)
b"\x00\x00\x00*" # Offset to ColorLine from beginning of Paint (42)
b"\x00\x01" # Paint.p0.x.value (1)
b"\x00\x00\x00\x00" # Paint.p0.x.varIdx (0)
b"\x00\x02" # Paint.p0.y.value (2)
b"\x00\x00\x00\x00" # Paint.p0.y.varIdx (0)
b"\xff\xfd" # Paint.p1.x.value (-3)
b"\x00\x00\x00\x00" # Paint.p1.x.varIdx (0)
b"\xff\xfc" # Paint.p1.y.value (-4)
b"\x00\x00\x00\x00" # Paint.p1.y.varIdx (0)
b"\x00\x05" # Paint.p2.x.value (5)
b"\x00\x00\x00\x00" # Paint.p2.y.varIdx (0)
b"\x00\x06" # Paint.p2.y.value (5)
b"\x00\x00\x00\x00" # Paint.p2.y.varIdx (0)
b"\x00\x01" # Paint.x0.value (1)
b"\x00\x00\x00\x00" # Paint.x0.varIdx (0)
b"\x00\x02" # Paint.y0.value (2)
b"\x00\x00\x00\x00" # Paint.y0.varIdx (0)
b"\xff\xfd" # Paint.x1.value (-3)
b"\x00\x00\x00\x00" # Paint.x1.varIdx (0)
b"\xff\xfc" # Paint.y1.value (-4)
b"\x00\x00\x00\x00" # Paint.y1.varIdx (0)
b"\x00\x05" # Paint.x2.value (5)
b"\x00\x00\x00\x00" # Paint.x2.varIdx (0)
b"\x00\x06" # Paint.y2.value (5)
b"\x00\x00\x00\x00" # Paint.y2.varIdx (0)
b"\x00\x01" # ColorLine.Extend (1 or "repeat")
b"\x00\x03" # ColorLine.StopCount (3)
b"\x00\x00" # ColorLine.ColorStop[0].StopOffset.value (0.0)
b"\x00\x00\x00\x00" # ColorLine.ColorStop[0].StopOffset.varIdx (0)
b"\x00\x03" # ColorLine.ColorStop[0].Color.PaletteIndex (3)
b"\x00\x00" # ColorLine.ColorStop[0].Color.Transparency.value (0.0)
b"\x00\x00\x00\x00" # ColorLine.ColorStop[0].Color.Transparency.varIdx (0)
b"@\x00" # ColorLine.ColorStop[0].Color.Alpha.value (1.0)
b"\x00\x00\x00\x00" # ColorLine.ColorStop[0].Color.Alpha.varIdx (0)
b" \x00" # ColorLine.ColorStop[1].StopOffset.value (0.5)
b"\x00\x00\x00\x00" # ColorLine.ColorStop[1].StopOffset.varIdx (0)
b"\x00\x04" # ColorLine.ColorStop[1].Color.PaletteIndex (4)
b"\x00\x00" # ColorLine.ColorStop[1].Color.Transparency.value (0.0)
b"\x00\x00\x00\x00" # ColorLine.ColorStop[1].Color.Transparency.varIdx (0)
b"@\x00" # ColorLine.ColorStop[1].Color.Alpha.value (1.0)
b"\x00\x00\x00\x00" # ColorLine.ColorStop[1].Color.Alpha.varIdx (0)
b"@\x00" # ColorLine.ColorStop[2].StopOffset.value (1.0)
b"\x00\x00\x00\x00" # ColorLine.ColorStop[2].StopOffset.varIdx (0)
b"\x00\x05" # ColorLine.ColorStop[2].Color.PaletteIndex (5)
b"\x00\x00" # ColorLine.ColorStop[2].Color.Transparency.value (0.0)
b"\x00\x00\x00\x00" # ColorLine.ColorStop[2].Color.Transparency.varIdx (0)
b"@\x00" # ColorLine.ColorStop[2].Color.Alpha.value (1.0)
b"\x00\x00\x00\x00" # ColorLine.ColorStop[2].Color.Alpha.varIdx (0)
b"\x00\x03" # Paint.Format (3)
b"\x00\x00\x00." # Offset to ColorLine from beginning of Paint (46)
b"\x00\x07" # Paint.c0.x.value (7)
b"\x00\x07" # Paint.x0.value (7)
b"\x00\x00\x00\x00"
b"\x00\x08" # Paint.c0.y.value (8)
b"\x00\x08" # Paint.y0.value (8)
b"\x00\x00\x00\x00"
b"\x00\t" # Paint.c1.x.value (9)
b"\x00\t" # Paint.r0.value (9)
b"\x00\x00\x00\x00"
b"\x00\n" # Paint.c1.y.value (10)
b"\x00\n" # Paint.x1.value (10)
b"\x00\x00\x00\x00"
b"\x00\x0b" # Paint.r0.value (11)
b"\x00\x0b" # Paint.y1.value (11)
b"\x00\x00\x00\x00"
b"\x00\x0c" # Paint.r1.value (12)
b"\x00\x00\x00\x00"
@ -147,12 +147,12 @@ COLR_V1_DATA = (
b"\x00\x00" # ColorLine.ColorStop[0].StopOffset.value (0.0)
b"\x00\x00\x00\x00"
b"\x00\x06" # ColorLine.ColorStop[0].Color.PaletteIndex (6)
b"\x00\x00"
b"@\x00" # ColorLine.ColorStop[0].Color.Alpha.value (1.0)
b"\x00\x00\x00\x00"
b"@\x00" # ColorLine.ColorStop[1].StopOffset.value (1.0)
b"\x00\x00\x00\x00"
b"\x00\x07" # ColorLine.ColorStop[1].Color.PaletteIndex (7)
b"\x19\x9a" # ColorLine.ColorStop[1].Color.Transparency.value (0.4)
b"\x19\x9a" # ColorLine.ColorStop[1].Color.Alpha.value (0.4)
b"\x00\x00\x00\x00"
b"\xff\xf3\x00\x00" # Affine2x2.xx.value (-13)
b"\x00\x00\x00\x00"
@ -190,18 +190,18 @@ COLR_V1_XML = [
" </LayerRecord>",
"</LayerRecordArray>",
"<!-- LayerRecordCount=3 -->",
"<BaseGlyphV1Array>",
"<BaseGlyphV1List>",
" <!-- BaseGlyphCount=1 -->",
' <BaseGlyphV1Record index="0">',
' <BaseGlyph value="glyph00010"/>',
" <LayerV1Array>",
" <LayerV1List>",
" <!-- LayerCount=3 -->",
' <LayerV1Record index="0">',
' <LayerGlyph value="glyph00011"/>',
' <Paint Format="1">',
" <Color>",
' <PaletteIndex value="2"/>',
' <Transparency value="0.5"/>',
' <Alpha value="0.5"/>',
" </Color>",
" </Paint>",
" </LayerV1Record>",
@ -215,36 +215,30 @@ COLR_V1_XML = [
' <StopOffset value="0.0"/>',
" <Color>",
' <PaletteIndex value="3"/>',
' <Transparency value="0.0"/>',
' <Alpha value="1.0"/>',
" </Color>",
" </ColorStop>",
' <ColorStop index="1">',
' <StopOffset value="0.5"/>',
" <Color>",
' <PaletteIndex value="4"/>',
' <Transparency value="0.0"/>',
' <Alpha value="1.0"/>',
" </Color>",
" </ColorStop>",
' <ColorStop index="2">',
' <StopOffset value="1.0"/>',
" <Color>",
' <PaletteIndex value="5"/>',
' <Transparency value="0.0"/>',
' <Alpha value="1.0"/>',
" </Color>",
" </ColorStop>",
" </ColorLine>",
" <p0>",
' <x value="1"/>',
' <y value="2"/>',
" </p0>",
" <p1>",
' <x value="-3"/>',
' <y value="-4"/>',
" </p1>",
" <p2>",
' <x value="5"/>',
' <y value="6"/>',
" </p2>",
' <x0 value="1"/>',
' <y0 value="2"/>',
' <x1 value="-3"/>',
' <y1 value="-4"/>',
' <x2 value="5"/>',
' <y2 value="6"/>',
" </Paint>",
" </LayerV1Record>",
' <LayerV1Record index="2">',
@ -257,38 +251,34 @@ COLR_V1_XML = [
' <StopOffset value="0.0"/>',
" <Color>",
' <PaletteIndex value="6"/>',
' <Transparency value="0.0"/>',
' <Alpha value="1.0"/>',
" </Color>",
" </ColorStop>",
' <ColorStop index="1">',
' <StopOffset value="1.0"/>',
" <Color>",
' <PaletteIndex value="7"/>',
' <Transparency value="0.4"/>',
' <Alpha value="0.4"/>',
" </Color>",
" </ColorStop>",
" </ColorLine>",
" <c0>",
' <x value="7"/>',
' <y value="8"/>',
" </c0>",
" <c1>",
' <x value="9"/>',
' <y value="10"/>',
" </c1>",
' <r0 value="11"/>',
' <x0 value="7"/>',
' <y0 value="8"/>',
' <r0 value="9"/>',
' <x1 value="10"/>',
' <y1 value="11"/>',
' <r1 value="12"/>',
" <Affine>",
" <Transform>",
' <xx value="-13.0"/>',
' <xy value="14.0"/>',
' <yx value="15.0"/>',
' <yy value="-17.0"/>',
" </Affine>",
" </Transform>",
" </Paint>",
" </LayerV1Record>",
" </LayerV1Array>",
" </LayerV1List>",
" </BaseGlyphV1Record>",
"</BaseGlyphV1Array>",
"</BaseGlyphV1List>",
]