diff --git a/Lib/fontTools/ttLib/tables/otConverters.py b/Lib/fontTools/ttLib/tables/otConverters.py index a5ef23325..5351a0e05 100644 --- a/Lib/fontTools/ttLib/tables/otConverters.py +++ b/Lib/fontTools/ttLib/tables/otConverters.py @@ -14,7 +14,8 @@ from .otBase import (CountReference, FormatSwitchingBaseTable, from .otTables import (lookupTypes, AATStateTable, AATState, AATAction, ContextualMorphAction, LigatureMorphAction, InsertionMorphAction, MorxSubtable, VariableFloat, - VariableInt, ExtendMode as _ExtendMode) + VariableInt, ExtendMode as _ExtendMode, + CompositeMode as _CompositeMode) from itertools import zip_longest from functools import partial import struct @@ -1714,15 +1715,25 @@ class VarUInt16(_NamedTupleConverter): converterClasses = [UShort, ULong] -class ExtendMode(UShort): +class _UInt8Enum(UInt8): + enumClass = NotImplemented + def read(self, reader, font, tableDict): - return _ExtendMode(super().read(reader, font, tableDict)) - @staticmethod - def fromString(value): - return getattr(_ExtendMode, value.upper()) - @staticmethod - def toString(value): - return _ExtendMode(value).name.lower() + return self.enumClass(super().read(reader, font, tableDict)) + @classmethod + def fromString(cls, value): + return getattr(cls.enumClass, value.upper()) + @classmethod + def toString(cls, value): + return cls.enumClass(value).name.lower() + + +class ExtendMode(_UInt8Enum): + enumClass = _ExtendMode + + +class CompositeMode(_UInt8Enum): + enumClass = _CompositeMode converterMapping = { @@ -1754,6 +1765,7 @@ converterMapping = { "VarDataValue": VarDataValue, "LookupFlag": LookupFlag, "ExtendMode": ExtendMode, + "CompositeMode": CompositeMode, # AAT "CIDGlyphMap": CIDGlyphMap, @@ -1769,6 +1781,7 @@ converterMapping = { "STXHeader": lambda C: partial(STXHeader, tableClass=C), "OffsetTo": lambda C: partial(Table, tableClass=C), "LOffsetTo": lambda C: partial(LTable, tableClass=C), + "LOffset24To": lambda C: partial(Table24, tableClass=C), # Variable types "VarFixed": VarFixed, diff --git a/Lib/fontTools/ttLib/tables/otData.py b/Lib/fontTools/ttLib/tables/otData.py index 8a12881e9..2dad181f1 100755 --- a/Lib/fontTools/ttLib/tables/otData.py +++ b/Lib/fontTools/ttLib/tables/otData.py @@ -1583,20 +1583,17 @@ otData = [ ]), ('LayerV1List', [ - ('uint32', 'LayerCount', None, None, 'Number of Version-1 Layer records'), - ('struct', 'LayerV1Record', 'LayerCount', 0, 'Array of Version-1 Layer records'), + ('uint8', 'LayerCount', None, None, 'Number of Version-1 Layers'), + ('LOffset', 'Paint', 'LayerCount', 0, 'Array of offsets to Paint tables, from the start of the LayerV1List table.'), ]), - ('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 LayerV1List) to Paint subtable.'), - ]), - - ('Affine2x2', [ + ('Affine2x3', [ ('VarFixed', 'xx', None, None, ''), ('VarFixed', 'xy', None, None, ''), ('VarFixed', 'yx', None, None, ''), ('VarFixed', 'yy', None, None, ''), + ('VarFixed', 'dx', None, None, ''), + ('VarFixed', 'dy', None, None, ''), ]), ('ColorIndex', [ @@ -1616,13 +1613,13 @@ otData = [ ]), ('PaintFormat1', [ - ('uint16', 'PaintFormat', None, None, 'Format identifier-format = 1'), + ('uint8', 'PaintFormat', None, None, 'Format identifier-format = 1'), ('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.'), + ('uint8', 'PaintFormat', None, None, 'Format identifier-format = 2'), + ('Offset24', 'ColorLine', None, None, 'Offset (from beginning of Paint table) to ColorLine subtable.'), ('VarInt16', 'x0', None, None, ''), ('VarInt16', 'y0', None, None, ''), ('VarInt16', 'x1', None, None, ''), @@ -1632,14 +1629,33 @@ otData = [ ]), ('PaintFormat3', [ - ('uint16', 'PaintFormat', None, None, 'Format identifier-format = 3'), - ('LOffset', 'ColorLine', None, None, 'Offset (from beginning of Paint table) to ColorLine subtable.'), + ('uint8', 'PaintFormat', None, None, 'Format identifier-format = 3'), + ('Offset24', 'ColorLine', None, None, 'Offset (from beginning of Paint table) to ColorLine 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.'), + ]), + ('PaintFormat4', [ + ('uint8', 'PaintFormat', None, None, 'Format identifier-format = 4'), + ('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintGlyph table) to Paint subtable.'), + ('GlyphID', 'Glyph', None, None, 'Glyph ID for the source outline.'), + ]), + ('PaintFormat5', [ + ('uint8', 'PaintFormat', None, None, 'Format identifier-format = 5'), + ('GlyphID', 'Glyph', None, None, 'Virtual glyph ID for a BaseGlyphV1List base glyph.'), + ]), + ('PaintFormat6', [ + ('uint8', 'PaintFormat', None, None, 'Format identifier-format = 6'), + ('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintTransformed table) to Paint subtable.'), + ('LOffsetTo(Affine2x3)', 'Transform', None, None, 'Offset (from beginning of PaintTrasformed table) to Affine2x3 subtable.'), + ]), + ('PaintFormat7', [ + ('uint8', 'PaintFormat', None, None, 'Format identifier-format = 7'), + ('LOffset24To(Paint)', 'SourcePaint', None, None, 'Offset (from beginning of PaintComposite table) to source Paint subtable.'), + ('CompositeMode', 'CompositeMode', None, None, 'A CompositeMode enumeration value.'), + ('LOffset24To(Paint)', 'BackdropPaint', None, None, 'Offset (from beginning of PaintComposite table) to backdrop Paint subtable.'), ]), ] diff --git a/Lib/fontTools/ttLib/tables/otTables.py b/Lib/fontTools/ttLib/tables/otTables.py index 6fc56468c..721f56297 100644 --- a/Lib/fontTools/ttLib/tables/otTables.py +++ b/Lib/fontTools/ttLib/tables/otTables.py @@ -1292,6 +1292,38 @@ class ExtendMode(IntEnum): REFLECT = 2 +# Porter-Duff modes for COLRv1 PaintComposite: +# https://github.com/googlefonts/colr-gradients-spec/tree/off_sub_1#compositemode-enumeration +class CompositeMode(IntEnum): + CLEAR = 0 + SRC = 1 + DEST = 2 + SRC_OVER = 3 + DEST_OVER = 4 + SRC_IN = 5 + DEST_IN = 6 + SRC_OUT = 7 + DEST_OUT = 8 + SRC_ATOP = 9 + DEST_ATOP = 10 + XOR = 11 + SCREEN = 12 + OVERLAY = 13 + DARKEN = 14 + LIGHTEN = 15 + COLOR_DODGE = 16 + COLOR_BURN = 17 + HARD_LIGHT = 18 + SOFT_LIGHT = 19 + DIFFERENCE = 20 + EXCLUSION = 21 + MULTIPLY = 22 + HSL_HUE = 23 + HSL_SATURATION = 24 + HSL_COLOR = 25 + HSL_LUMINOSITY = 26 + + # For each subtable format there is a class. However, we don't really distinguish # between "field name" and "format name": often these are the same. Yet there's # a whole bunch of fields with different names. The following dict is a mapping diff --git a/Tests/ttLib/tables/C_O_L_R_test.py b/Tests/ttLib/tables/C_O_L_R_test.py index 5fb9e4c26..4afba940d 100644 --- a/Tests/ttLib/tables/C_O_L_R_test.py +++ b/Tests/ttLib/tables/C_O_L_R_test.py @@ -85,19 +85,22 @@ COLR_V1_DATA = ( 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"\x03" # LayerV1List.LayerCount (3) + b"\x00\x00\x00\r" # Offset to Paint from beginning of LayerV1List (13) + b"\x00\x00\x00\x1c" # Offset to Paint from beginning of LayerV1List (28) + b"\x00\x00\x00w" # Offset to Paint from beginning of LayerV1List (119) + b"\x04" # LayerV1List.Paint[0].Format (4) + b"\x00\x00\x06" # Offset to Paint subtable from beginning of PaintGlyph (6) + b"\x00\x0b" # LayerV1List.Paint[0].Glyph (11) + b"\x01" # LayerV1List.Paint[0].Paint.Format (1) b"\x00\x02" # Paint.Color.PaletteIndex (2) 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"\x04" # LayerV1List.Paint[1].Format (4) + b"\x00\x00\x06" # Offset to Paint subtable from beginning of PaintGlyph (6) + b"\x00\x0c" # LayerV1List.Paint[1].Glyph (12) + b"\x02" # LayerV1List.Paint[1].Paint.Format (2) + b"\x00\x00(" # Offset to ColorLine from beginning of PaintLinearGradient (40) b"\x00\x01" # Paint.x0.value (1) b"\x00\x00\x00\x00" # Paint.x0.varIdx (0) b"\x00\x02" # Paint.y0.value (2) @@ -108,9 +111,9 @@ COLR_V1_DATA = ( 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\x06" # Paint.y2.value (6) b"\x00\x00\x00\x00" # Paint.y2.varIdx (0) - b"\x00\x01" # ColorLine.Extend (1 or "repeat") + b"\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) @@ -127,8 +130,14 @@ COLR_V1_DATA = ( b"\x00\x05" # ColorLine.ColorStop[2].Color.PaletteIndex (5) 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"\x04" # LayerV1List.Paint[2].Format (4) + b"\x00\x00\x06" # Offset to Paint subtable from beginning of PaintGlyph (6) + b"\x00\r" # LayerV1List.Paint[2].Glyph (13) + b"\x06" # LayerV1List.Paint[2].Paint.Format (6) + b"\x00\x00\x08" # Offset to Paint subtable from beginning of PaintTransform (8) + b"\x00\x00\x00O" # Offset to Transform from beginning of PaintTransform (79) + b"\x03" # LayerV1List.Paint[2].Paint.Paint.Format (3) + b"\x00\x00(" # Offset to ColorLine from beginning of PaintRadialGradient (40) b"\x00\x07" # Paint.x0.value (7) b"\x00\x00\x00\x00" b"\x00\x08" # Paint.y0.value (8) @@ -141,26 +150,29 @@ COLR_V1_DATA = ( b"\x00\x00\x00\x00" b"\x00\x0c" # Paint.r1.value (12) b"\x00\x00\x00\x00" - b"\x00\x00\x00N" # Offset to Affine2x2 from beginning of Paint (78) - b"\x00\x00" # ColorLine.Extend (0 or "pad") + b"\x00" # ColorLine.Extend (0 or "pad") b"\x00\x02" # ColorLine.StopCount (2) 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" # ColorLine.ColorStop[0].Color.Alpha.value (1.0) + 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.Alpha.value (0.4) b"\x00\x00\x00\x00" - b"\xff\xf3\x00\x00" # Affine2x2.xx.value (-13) + b"\xff\xf3\x00\x00" # Affine2x3.xx.value (-13) b"\x00\x00\x00\x00" - b"\x00\x0e\x00\x00" # Affine2x2.xy.value (14) + b"\x00\x0e\x00\x00" # Affine2x3.xy.value (14) b"\x00\x00\x00\x00" - b"\x00\x0f\x00\x00" # Affine2x2.yx.value (15) + b"\x00\x0f\x00\x00" # Affine2x3.yx.value (15) b"\x00\x00\x00\x00" - b"\xff\xef\x00\x00" # Affine2x2.yy.value (-17) + b"\xff\xef\x00\x00" # Affine2x3.yy.value (-17) + b"\x00\x00\x00\x00" + b"\x00\x12\x00\x00" # Affine2x3.yy.value (18) + b"\x00\x00\x00\x00" + b"\x00\x13\x00\x00" # Affine2x3.yy.value (19) b"\x00\x00\x00\x00" ) @@ -196,17 +208,16 @@ COLR_V1_XML = [ ' ', " ", " ", - ' ', - ' ', + ' ', ' ', " ", ' ', ' ', " ", " ", - " ", - ' ', - ' ', + ' ', + " ", + ' ', ' ', " ", ' ', @@ -240,42 +251,47 @@ COLR_V1_XML = [ ' ', ' ', " ", - " ", - ' ', - ' ', - ' ', - " ", - ' ', - " ", - ' ', - ' ', - " ", - ' ', - ' ', - " ", - " ", - ' ', - ' ', - " ", - ' ', - ' ', - " ", - " ", - " ", - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', + ' ', + " ", + ' ', + ' ', + ' ', + " ", + ' ', + " ", + ' ', + ' ', + " ", + ' ', + ' ', + " ", + " ", + ' ', + ' ', + " ", + ' ', + ' ', + " ", + " ", + " ", + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + " ", " ", ' ', ' ', ' ', ' ', + ' ', + ' ', " ", " ", - " ", + ' ', + " ", " ", " ", "",