diff --git a/Lib/fontTools/colorLib/builder.py b/Lib/fontTools/colorLib/builder.py index dae00b918..48ade4482 100644 --- a/Lib/fontTools/colorLib/builder.py +++ b/Lib/fontTools/colorLib/builder.py @@ -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 diff --git a/Lib/fontTools/ttLib/tables/otBase.py b/Lib/fontTools/ttLib/tables/otBase.py index 786238a72..aa00c97ba 100644 --- a/Lib/fontTools/ttLib/tables/otBase.py +++ b/Lib/fontTools/ttLib/tables/otBase.py @@ -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)) diff --git a/Lib/fontTools/ttLib/tables/otConverters.py b/Lib/fontTools/ttLib/tables/otConverters.py index b737e5c47..a05a7ef89 100644 --- a/Lib/fontTools/ttLib/tables/otConverters.py +++ b/Lib/fontTools/ttLib/tables/otConverters.py @@ -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, } diff --git a/Lib/fontTools/ttLib/tables/otData.py b/Lib/fontTools/ttLib/tables/otData.py index b893a7b48..8a12881e9 100755 --- a/Lib/fontTools/ttLib/tables/otData.py +++ b/Lib/fontTools/ttLib/tables/otData.py @@ -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.'), ]), ] diff --git a/Lib/fontTools/ttLib/tables/otTables.py b/Lib/fontTools/ttLib/tables/otTables.py index fa8638a4e..b821fa36c 100644 --- a/Lib/fontTools/ttLib/tables/otTables.py +++ b/Lib/fontTools/ttLib/tables/otTables.py @@ -1197,7 +1197,7 @@ class BaseGlyphRecordArray(BaseTable): return self.__dict__.copy() -class BaseGlyphV1Array(BaseTable): +class BaseGlyphV1List(BaseTable): def preWrite(self, font): self.BaseGlyphV1Record = sorted( diff --git a/Tests/colorLib/builder_test.py b/Tests/colorLib/builder_test.py index 24cac8bec..e7ea6b614 100644 --- a/Tests/colorLib/builder_test.py +++ b/Tests/colorLib/builder_test.py @@ -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" ) diff --git a/Tests/ttLib/tables/C_O_L_R_test.py b/Tests/ttLib/tables/C_O_L_R_test.py index cdd94afa7..5fb9e4c26 100644 --- a/Tests/ttLib/tables/C_O_L_R_test.py +++ b/Tests/ttLib/tables/C_O_L_R_test.py @@ -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 = [ " ", "", "", - "", + "", " ", ' ', ' ', - " ", + " ", " ", ' ', ' ', ' ', " ", ' ', - ' ', + ' ', " ", " ", " ", @@ -215,36 +215,30 @@ COLR_V1_XML = [ ' ', " ", ' ', - ' ', + ' ', " ", " ", ' ', ' ', " ", ' ', - ' ', + ' ', " ", " ", ' ', ' ', " ", ' ', - ' ', + ' ', " ", " ", " ", - " ", - ' ', - ' ', - " ", - " ", - ' ', - ' ', - " ", - " ", - ' ', - ' ', - " ", + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', " ", " ", ' ', @@ -257,38 +251,34 @@ COLR_V1_XML = [ ' ', " ", ' ', - ' ', + ' ', " ", " ", ' ', ' ', " ", ' ', - ' ', + ' ', " ", " ", " ", - " ", - ' ', - ' ', - " ", - " ", - ' ', - ' ', - " ", - ' ', + ' ', + ' ', + ' ', + ' ', + ' ', ' ', - " ", + " ", ' ', ' ', ' ', ' ', - " ", + " ", " ", " ", - " ", + " ", " ", - "", + "", ]