Merge pull request #2372 from fonttools/colrv1-var-idx-map
[COLRv1] add DeltaSetIndexMap, remove ColorIndex
This commit is contained in:
commit
2f1fbd6374
@ -26,20 +26,10 @@ from fontTools.ttLib.tables import C_O_L_R_
|
||||
from fontTools.ttLib.tables import C_P_A_L_
|
||||
from fontTools.ttLib.tables import _n_a_m_e
|
||||
from fontTools.ttLib.tables import otTables as ot
|
||||
from fontTools.ttLib.tables.otTables import (
|
||||
ExtendMode,
|
||||
CompositeMode,
|
||||
VariableValue,
|
||||
VariableFloat,
|
||||
VariableInt,
|
||||
)
|
||||
from fontTools.ttLib.tables.otTables import ExtendMode, CompositeMode
|
||||
from .errors import ColorLibError
|
||||
from .geometry import round_start_circle_stable_containment
|
||||
from .table_builder import (
|
||||
convertTupleClass,
|
||||
BuildCallback,
|
||||
TableBuilder,
|
||||
)
|
||||
from .table_builder import BuildCallback, TableBuilder
|
||||
|
||||
|
||||
# TODO move type aliases to colorLib.types?
|
||||
@ -52,53 +42,46 @@ _ColorGlyphsV0Dict = Dict[str, Sequence[Tuple[str, int]]]
|
||||
|
||||
|
||||
MAX_PAINT_COLR_LAYER_COUNT = 255
|
||||
_DEFAULT_ALPHA = VariableFloat(1.0)
|
||||
_DEFAULT_ALPHA = 1.0
|
||||
_MAX_REUSE_LEN = 32
|
||||
|
||||
|
||||
def _beforeBuildPaintVarRadialGradient(paint, source, srcMapFn=lambda v: v):
|
||||
# normalize input types (which may or may not specify a varIdx)
|
||||
x0 = convertTupleClass(VariableFloat, source["x0"])
|
||||
y0 = convertTupleClass(VariableFloat, source["y0"])
|
||||
r0 = convertTupleClass(VariableFloat, source["r0"])
|
||||
x1 = convertTupleClass(VariableFloat, source["x1"])
|
||||
y1 = convertTupleClass(VariableFloat, source["y1"])
|
||||
r1 = convertTupleClass(VariableFloat, source["r1"])
|
||||
def _beforeBuildPaintRadialGradient(paint, source):
|
||||
x0 = source["x0"]
|
||||
y0 = source["y0"]
|
||||
r0 = source["r0"]
|
||||
x1 = source["x1"]
|
||||
y1 = source["y1"]
|
||||
r1 = source["r1"]
|
||||
|
||||
# TODO apparently no builder_test confirms this works (?)
|
||||
|
||||
# avoid abrupt change after rounding when c0 is near c1's perimeter
|
||||
c = round_start_circle_stable_containment(
|
||||
(x0.value, y0.value), r0.value, (x1.value, y1.value), r1.value
|
||||
)
|
||||
x0, y0 = x0._replace(value=c.centre[0]), y0._replace(value=c.centre[1])
|
||||
r0 = r0._replace(value=c.radius)
|
||||
c = round_start_circle_stable_containment((x0, y0), r0, (x1, y1), r1)
|
||||
x0, y0 = c.centre
|
||||
r0 = c.radius
|
||||
|
||||
# update source to ensure paint is built with corrected values
|
||||
source["x0"] = srcMapFn(x0)
|
||||
source["y0"] = srcMapFn(y0)
|
||||
source["r0"] = srcMapFn(r0)
|
||||
source["x1"] = srcMapFn(x1)
|
||||
source["y1"] = srcMapFn(y1)
|
||||
source["r1"] = srcMapFn(r1)
|
||||
source["x0"] = x0
|
||||
source["y0"] = y0
|
||||
source["r0"] = r0
|
||||
source["x1"] = x1
|
||||
source["y1"] = y1
|
||||
source["r1"] = r1
|
||||
|
||||
return paint, source
|
||||
|
||||
|
||||
def _beforeBuildPaintRadialGradient(paint, source):
|
||||
return _beforeBuildPaintVarRadialGradient(paint, source, lambda v: v.value)
|
||||
def _defaultColorStop():
|
||||
colorStop = ot.ColorStop()
|
||||
colorStop.Alpha = _DEFAULT_ALPHA
|
||||
return colorStop
|
||||
|
||||
|
||||
def _defaultColorIndex():
|
||||
colorIndex = ot.ColorIndex()
|
||||
colorIndex.Alpha = _DEFAULT_ALPHA.value
|
||||
return colorIndex
|
||||
|
||||
|
||||
def _defaultVarColorIndex():
|
||||
colorIndex = ot.VarColorIndex()
|
||||
colorIndex.Alpha = _DEFAULT_ALPHA
|
||||
return colorIndex
|
||||
def _defaultVarColorStop():
|
||||
colorStop = ot.VarColorStop()
|
||||
colorStop.Alpha = _DEFAULT_ALPHA
|
||||
return colorStop
|
||||
|
||||
|
||||
def _defaultColorLine():
|
||||
@ -113,6 +96,12 @@ def _defaultVarColorLine():
|
||||
return colorLine
|
||||
|
||||
|
||||
def _defaultPaintSolid():
|
||||
paint = ot.Paint()
|
||||
paint.Alpha = _DEFAULT_ALPHA
|
||||
return paint
|
||||
|
||||
|
||||
def _buildPaintCallbacks():
|
||||
return {
|
||||
(
|
||||
@ -124,11 +113,21 @@ def _buildPaintCallbacks():
|
||||
BuildCallback.BEFORE_BUILD,
|
||||
ot.Paint,
|
||||
ot.PaintFormat.PaintVarRadialGradient,
|
||||
): _beforeBuildPaintVarRadialGradient,
|
||||
(BuildCallback.CREATE_DEFAULT, ot.ColorIndex): _defaultColorIndex,
|
||||
(BuildCallback.CREATE_DEFAULT, ot.VarColorIndex): _defaultVarColorIndex,
|
||||
): _beforeBuildPaintRadialGradient,
|
||||
(BuildCallback.CREATE_DEFAULT, ot.ColorStop): _defaultColorStop,
|
||||
(BuildCallback.CREATE_DEFAULT, ot.VarColorStop): _defaultVarColorStop,
|
||||
(BuildCallback.CREATE_DEFAULT, ot.ColorLine): _defaultColorLine,
|
||||
(BuildCallback.CREATE_DEFAULT, ot.VarColorLine): _defaultVarColorLine,
|
||||
(
|
||||
BuildCallback.CREATE_DEFAULT,
|
||||
ot.Paint,
|
||||
ot.PaintFormat.PaintSolid,
|
||||
): _defaultPaintSolid,
|
||||
(
|
||||
BuildCallback.CREATE_DEFAULT,
|
||||
ot.Paint,
|
||||
ot.PaintFormat.PaintVarSolid,
|
||||
): _defaultPaintSolid,
|
||||
}
|
||||
|
||||
|
||||
@ -183,6 +182,7 @@ def buildCOLR(
|
||||
version: Optional[int] = None,
|
||||
glyphMap: Optional[Mapping[str, int]] = None,
|
||||
varStore: Optional[ot.VarStore] = None,
|
||||
varIndexMap: Optional[ot.DeltaSetIndexMap] = None,
|
||||
) -> C_O_L_R_.table_C_O_L_R_:
|
||||
"""Build COLR table from color layers mapping.
|
||||
Args:
|
||||
@ -196,6 +196,7 @@ def buildCOLR(
|
||||
glyphMap: a map from glyph names to glyph indices, as returned from
|
||||
TTFont.getReverseGlyphMap(), to optionally sort base records by GID.
|
||||
varStore: Optional ItemVarationStore for deltas associated with v1 layer.
|
||||
varIndexMap: Optional DeltaSetIndexMap for deltas associated with v1 layer.
|
||||
Return:
|
||||
A new COLR table.
|
||||
"""
|
||||
@ -229,6 +230,7 @@ def buildCOLR(
|
||||
if version == 0:
|
||||
self.ColorLayers = self._decompileColorLayersV0(colr)
|
||||
else:
|
||||
colr.VarIndexMap = varIndexMap
|
||||
colr.VarStore = varStore
|
||||
self.table = colr
|
||||
|
||||
|
@ -17,10 +17,9 @@ from fontTools.ttLib.tables.otConverters import (
|
||||
Short,
|
||||
UInt8,
|
||||
UShort,
|
||||
VarInt16,
|
||||
VarUInt16,
|
||||
IntValue,
|
||||
FloatValue,
|
||||
OptionalValue,
|
||||
)
|
||||
from fontTools.misc.roundTools import otRound
|
||||
|
||||
@ -39,7 +38,7 @@ class BuildCallback(enum.Enum):
|
||||
"""
|
||||
AFTER_BUILD = enum.auto()
|
||||
|
||||
"""Keyed on (CREATE_DEFAULT, class).
|
||||
"""Keyed on (CREATE_DEFAULT, class[, Format if available]).
|
||||
Receives no arguments.
|
||||
Should return a new instance of class.
|
||||
"""
|
||||
@ -50,37 +49,29 @@ def _assignable(convertersByName):
|
||||
return {k: v for k, v in convertersByName.items() if not isinstance(v, ComputedInt)}
|
||||
|
||||
|
||||
def convertTupleClass(tupleClass, value):
|
||||
if isinstance(value, tupleClass):
|
||||
return value
|
||||
if isinstance(value, tuple):
|
||||
return tupleClass(*value)
|
||||
return tupleClass(value)
|
||||
|
||||
|
||||
def _isNonStrSequence(value):
|
||||
return isinstance(value, collections.abc.Sequence) and not isinstance(value, str)
|
||||
|
||||
|
||||
def _set_format(dest, source):
|
||||
def _split_format(cls, source):
|
||||
if _isNonStrSequence(source):
|
||||
assert len(source) > 0, f"{type(dest)} needs at least format from {source}"
|
||||
dest.Format = source[0]
|
||||
source = source[1:]
|
||||
assert len(source) > 0, f"{cls} needs at least format from {source}"
|
||||
fmt, remainder = source[0], source[1:]
|
||||
elif isinstance(source, collections.abc.Mapping):
|
||||
assert "Format" in source, f"{type(dest)} needs at least Format from {source}"
|
||||
dest.Format = source["Format"]
|
||||
assert "Format" in source, f"{cls} needs at least Format from {source}"
|
||||
remainder = source.copy()
|
||||
fmt = remainder.pop("Format")
|
||||
else:
|
||||
raise ValueError(f"Not sure how to populate {type(dest)} from {source}")
|
||||
raise ValueError(f"Not sure how to populate {cls} from {source}")
|
||||
|
||||
assert isinstance(
|
||||
dest.Format, collections.abc.Hashable
|
||||
), f"{type(dest)} Format is not hashable: {dest.Format}"
|
||||
fmt, collections.abc.Hashable
|
||||
), f"{cls} Format is not hashable: {fmt!r}"
|
||||
assert (
|
||||
dest.Format in dest.convertersByName
|
||||
), f"{dest.Format} invalid Format of {cls}"
|
||||
fmt in cls.convertersByName
|
||||
), f"{cls} invalid Format: {fmt!r}"
|
||||
|
||||
return source
|
||||
return fmt, remainder
|
||||
|
||||
|
||||
class TableBuilder:
|
||||
@ -97,13 +88,9 @@ class TableBuilder:
|
||||
self._callbackTable = callbackTable
|
||||
|
||||
def _convert(self, dest, field, converter, value):
|
||||
tupleClass = getattr(converter, "tupleClass", None)
|
||||
enumClass = getattr(converter, "enumClass", None)
|
||||
|
||||
if tupleClass:
|
||||
value = convertTupleClass(tupleClass, value)
|
||||
|
||||
elif enumClass:
|
||||
if enumClass:
|
||||
if isinstance(value, enumClass):
|
||||
pass
|
||||
elif isinstance(value, str):
|
||||
@ -140,6 +127,11 @@ class TableBuilder:
|
||||
return source
|
||||
|
||||
callbackKey = (cls,)
|
||||
fmt = None
|
||||
if issubclass(cls, FormatSwitchingBaseTable):
|
||||
fmt, source = _split_format(cls, source)
|
||||
callbackKey = (cls, fmt)
|
||||
|
||||
dest = self._callbackTable.get(
|
||||
(BuildCallback.CREATE_DEFAULT,) + callbackKey, lambda: cls()
|
||||
)()
|
||||
@ -150,11 +142,9 @@ class TableBuilder:
|
||||
|
||||
# For format switchers we need to resolve converters based on format
|
||||
if issubclass(cls, FormatSwitchingBaseTable):
|
||||
source = _set_format(dest, source)
|
||||
|
||||
dest.Format = fmt
|
||||
convByName = _assignable(convByName[dest.Format])
|
||||
skippedFields.add("Format")
|
||||
callbackKey = (cls, dest.Format)
|
||||
|
||||
# Convert sequence => mapping so before thunk only has to handle one format
|
||||
if _isNonStrSequence(source):
|
||||
@ -182,6 +172,10 @@ class TableBuilder:
|
||||
# let's try as a 1-tuple
|
||||
dest = self.build(cls, (source,))
|
||||
|
||||
for field, conv in convByName.items():
|
||||
if not hasattr(dest, field) and isinstance(conv, OptionalValue):
|
||||
setattr(dest, field, conv.DEFAULT)
|
||||
|
||||
dest = self._callbackTable.get(
|
||||
(BuildCallback.AFTER_BUILD,) + callbackKey, lambda d: d
|
||||
)(dest)
|
||||
@ -210,11 +204,8 @@ class TableUnbuilder:
|
||||
continue
|
||||
value = getattr(table, converter.name)
|
||||
|
||||
tupleClass = getattr(converter, "tupleClass", None)
|
||||
enumClass = getattr(converter, "enumClass", None)
|
||||
if tupleClass:
|
||||
source[converter.name] = tuple(value)
|
||||
elif enumClass:
|
||||
if enumClass:
|
||||
source[converter.name] = value.name.lower()
|
||||
elif isinstance(converter, Struct):
|
||||
if converter.repeat:
|
||||
|
@ -2117,11 +2117,11 @@ def prune_post_subset(self, font, options):
|
||||
colors_by_index = defaultdict(list)
|
||||
|
||||
def collect_colors_by_index(paint):
|
||||
if hasattr(paint, "Color"): # either solid colors...
|
||||
colors_by_index[paint.Color.PaletteIndex].append(paint.Color)
|
||||
if hasattr(paint, "PaletteIndex"): # either solid colors...
|
||||
colors_by_index[paint.PaletteIndex].append(paint)
|
||||
elif hasattr(paint, "ColorLine"): # ... or gradient color stops
|
||||
for stop in paint.ColorLine.ColorStop:
|
||||
colors_by_index[stop.Color.PaletteIndex].append(stop.Color)
|
||||
colors_by_index[stop.PaletteIndex].append(stop)
|
||||
|
||||
if colr.version == 0:
|
||||
for layers in colr.ColorLayers.values():
|
||||
|
@ -14,8 +14,8 @@ from .otBase import (CountReference, FormatSwitchingBaseTable,
|
||||
OTTableReader, OTTableWriter, ValueRecordFactory)
|
||||
from .otTables import (lookupTypes, AATStateTable, AATState, AATAction,
|
||||
ContextualMorphAction, LigatureMorphAction,
|
||||
InsertionMorphAction, MorxSubtable, VariableFloat,
|
||||
VariableInt, ExtendMode as _ExtendMode,
|
||||
InsertionMorphAction, MorxSubtable,
|
||||
ExtendMode as _ExtendMode,
|
||||
CompositeMode as _CompositeMode)
|
||||
from itertools import zip_longest
|
||||
from functools import partial
|
||||
@ -226,6 +226,18 @@ class SimpleValue(BaseConverter):
|
||||
def xmlRead(self, attrs, content, font):
|
||||
return self.fromString(attrs["value"])
|
||||
|
||||
class OptionalValue(SimpleValue):
|
||||
DEFAULT = None
|
||||
def xmlWrite(self, xmlWriter, font, value, name, attrs):
|
||||
if value != self.DEFAULT:
|
||||
attrs.append(("value", self.toString(value)))
|
||||
xmlWriter.simpletag(name, attrs)
|
||||
xmlWriter.newline()
|
||||
def xmlRead(self, attrs, content, font):
|
||||
if "value" in attrs:
|
||||
return self.fromString(attrs["value"])
|
||||
return self.DEFAULT
|
||||
|
||||
class IntValue(SimpleValue):
|
||||
@staticmethod
|
||||
def fromString(value):
|
||||
@ -258,6 +270,9 @@ class Flags32(ULong):
|
||||
def toString(value):
|
||||
return "0x%08X" % value
|
||||
|
||||
class VarIndex(OptionalValue, ULong):
|
||||
DEFAULT = 0xFFFFFFFF
|
||||
|
||||
class Short(IntValue):
|
||||
staticSize = 2
|
||||
def read(self, reader, font, tableDict):
|
||||
@ -1700,104 +1715,6 @@ class LookupFlag(UShort):
|
||||
xmlWriter.comment(" ".join(flags))
|
||||
xmlWriter.newline()
|
||||
|
||||
def _issubclass_namedtuple(x):
|
||||
return (
|
||||
issubclass(x, tuple)
|
||||
and getattr(x, "_fields", None) is not None
|
||||
)
|
||||
|
||||
|
||||
class _NamedTupleConverter(BaseConverter):
|
||||
# subclasses must override this
|
||||
tupleClass = NotImplemented
|
||||
# List[SimpleValue]
|
||||
converterClasses = NotImplemented
|
||||
|
||||
def __init__(self, name, repeat, aux, tableClass=None):
|
||||
# we expect all converters to be subclasses of SimpleValue
|
||||
assert all(issubclass(klass, SimpleValue) for klass in self.converterClasses)
|
||||
assert _issubclass_namedtuple(self.tupleClass), repr(self.tupleClass)
|
||||
assert len(self.tupleClass._fields) == len(self.converterClasses)
|
||||
assert tableClass is None # tableClass is unused by SimplValues
|
||||
BaseConverter.__init__(self, name, repeat, aux)
|
||||
self.converters = [
|
||||
klass(name=name, repeat=None, aux=None)
|
||||
for name, klass in zip(self.tupleClass._fields, self.converterClasses)
|
||||
]
|
||||
self.convertersByName = {conv.name: conv for conv in self.converters}
|
||||
# returned by getRecordSize method
|
||||
self.staticSize = sum(c.staticSize for c in self.converters)
|
||||
|
||||
def read(self, reader, font, tableDict):
|
||||
kwargs = {
|
||||
conv.name: conv.read(reader, font, tableDict)
|
||||
for conv in self.converters
|
||||
}
|
||||
return self.tupleClass(**kwargs)
|
||||
|
||||
def write(self, writer, font, tableDict, value, repeatIndex=None):
|
||||
for conv in self.converters:
|
||||
v = getattr(value, conv.name)
|
||||
# repeatIndex is unused for SimpleValues
|
||||
conv.write(writer, font, tableDict, v, repeatIndex=None)
|
||||
|
||||
def xmlWrite(self, xmlWriter, font, value, name, attrs):
|
||||
assert value is not None
|
||||
defaults = value.__new__.__defaults__ or ()
|
||||
assert len(self.converters) >= len(defaults)
|
||||
values = {}
|
||||
required = object()
|
||||
for conv, default in zip_longest(
|
||||
reversed(self.converters),
|
||||
reversed(defaults),
|
||||
fillvalue=required,
|
||||
):
|
||||
v = getattr(value, conv.name)
|
||||
if default is required or v != default:
|
||||
values[conv.name] = conv.toString(v)
|
||||
if attrs is None:
|
||||
attrs = []
|
||||
attrs.extend(
|
||||
(conv.name, values[conv.name])
|
||||
for conv in self.converters
|
||||
if conv.name in values
|
||||
)
|
||||
xmlWriter.simpletag(name, attrs)
|
||||
xmlWriter.newline()
|
||||
|
||||
def xmlRead(self, attrs, content, font):
|
||||
converters = self.convertersByName
|
||||
kwargs = {
|
||||
k: converters[k].fromString(v)
|
||||
for k, v in attrs.items()
|
||||
}
|
||||
return self.tupleClass(**kwargs)
|
||||
|
||||
|
||||
class VarFixed(_NamedTupleConverter):
|
||||
tupleClass = VariableFloat
|
||||
converterClasses = [Fixed, ULong]
|
||||
|
||||
|
||||
class VarF2Dot14(_NamedTupleConverter):
|
||||
tupleClass = VariableFloat
|
||||
converterClasses = [F2Dot14, ULong]
|
||||
|
||||
|
||||
class VarInt16(_NamedTupleConverter):
|
||||
tupleClass = VariableInt
|
||||
converterClasses = [Short, ULong]
|
||||
|
||||
|
||||
class VarUInt16(_NamedTupleConverter):
|
||||
tupleClass = VariableInt
|
||||
converterClasses = [UShort, ULong]
|
||||
|
||||
|
||||
class VarAngle(_NamedTupleConverter):
|
||||
tupleClass = VariableFloat
|
||||
converterClasses = [F2Dot14, ULong]
|
||||
|
||||
|
||||
class _UInt8Enum(UInt8):
|
||||
enumClass = NotImplemented
|
||||
@ -1830,6 +1747,7 @@ converterMapping = {
|
||||
"uint32": ULong,
|
||||
"char64": Char64,
|
||||
"Flags32": Flags32,
|
||||
"VarIndex": VarIndex,
|
||||
"Version": Version,
|
||||
"Tag": Tag,
|
||||
"GlyphID": GlyphID,
|
||||
@ -1867,11 +1785,4 @@ converterMapping = {
|
||||
"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,
|
||||
"VarF2Dot14": VarF2Dot14,
|
||||
"VarInt16": VarInt16,
|
||||
"VarUInt16": VarUInt16,
|
||||
"VarAngle": VarAngle,
|
||||
}
|
||||
|
@ -988,6 +988,20 @@ otData = [
|
||||
('VarIdxMapValue', 'mapping', '', 0, 'Array of compressed data'),
|
||||
]),
|
||||
|
||||
('DeltaSetIndexMapFormat0', [
|
||||
('uint8', 'Format', None, None, 'Format of the DeltaSetIndexMap = 0'),
|
||||
('uint8', 'EntryFormat', None, None, ''), # Automatically computed
|
||||
('uint16', 'MappingCount', None, None, ''), # Automatically computed
|
||||
('VarIdxMapValue', 'mapping', '', 0, 'Array of compressed data'),
|
||||
]),
|
||||
|
||||
('DeltaSetIndexMapFormat1', [
|
||||
('uint8', 'Format', None, None, 'Format of the DeltaSetIndexMap = 1'),
|
||||
('uint8', 'EntryFormat', None, None, ''), # Automatically computed
|
||||
('uint32', 'MappingCount', None, None, ''), # Automatically computed
|
||||
('VarIdxMapValue', 'mapping', '', 0, 'Array of compressed data'),
|
||||
]),
|
||||
|
||||
# Glyph advance variations
|
||||
|
||||
('HVAR', [
|
||||
@ -1548,6 +1562,7 @@ otData = [
|
||||
('uint16', 'LayerRecordCount', None, None, 'Number of Layer Records.'),
|
||||
('LOffset', 'BaseGlyphList', None, 'Version >= 1', 'Offset (from beginning of COLR table) to array of Version-1 Base Glyph records.'),
|
||||
('LOffset', 'LayerList', None, 'Version >= 1', 'Offset (from beginning of COLR table) to LayerList.'),
|
||||
('LOffsetTo(DeltaSetIndexMap)', 'VarIndexMap', None, 'Version >= 1', 'Offset to DeltaSetIndexMap table (may be NULL)'),
|
||||
('LOffset', 'VarStore', None, 'Version >= 1', 'Offset to variation store (may be NULL)'),
|
||||
]),
|
||||
|
||||
@ -1603,30 +1618,25 @@ otData = [
|
||||
('Fixed', 'dy', None, None, 'Translation in y direction'),
|
||||
]),
|
||||
('VarAffine2x3', [
|
||||
('VarFixed', 'xx', None, None, 'x-part of x basis vector'),
|
||||
('VarFixed', 'yx', None, None, 'y-part of x basis vector'),
|
||||
('VarFixed', 'xy', None, None, 'x-part of y basis vector'),
|
||||
('VarFixed', 'yy', None, None, 'y-part of y basis vector'),
|
||||
('VarFixed', 'dx', None, None, 'Translation in x direction'),
|
||||
('VarFixed', 'dy', None, None, 'Translation in y direction'),
|
||||
]),
|
||||
|
||||
('ColorIndex', [
|
||||
('uint16', 'PaletteIndex', None, None, 'Index value to use with a selected color palette.'),
|
||||
('F2Dot14', 'Alpha', None, None, 'Values outsided [0.,1.] reserved'),
|
||||
]),
|
||||
('VarColorIndex', [
|
||||
('uint16', 'PaletteIndex', None, None, 'Index value to use with a selected color palette.'),
|
||||
('VarF2Dot14', 'Alpha', None, None, 'Values outsided [0.,1.] reserved'),
|
||||
('Fixed', 'xx', None, None, 'x-part of x basis vector'),
|
||||
('Fixed', 'yx', None, None, 'y-part of x basis vector'),
|
||||
('Fixed', 'xy', None, None, 'x-part of y basis vector'),
|
||||
('Fixed', 'yy', None, None, 'y-part of y basis vector'),
|
||||
('Fixed', 'dx', None, None, 'Translation in x direction'),
|
||||
('Fixed', 'dy', None, None, 'Translation in y direction'),
|
||||
('VarIndex', 'VarIndexBase', None, None, 'Base index into DeltaSetIndexMap.'),
|
||||
]),
|
||||
|
||||
('ColorStop', [
|
||||
('F2Dot14', 'StopOffset', None, None, ''),
|
||||
('ColorIndex', 'Color', None, None, ''),
|
||||
('uint16', 'PaletteIndex', None, None, 'Index for a CPAL palette entry.'),
|
||||
('F2Dot14', 'Alpha', None, None, 'Values outsided [0.,1.] reserved'),
|
||||
]),
|
||||
('VarColorStop', [
|
||||
('VarF2Dot14', 'StopOffset', None, None, ''),
|
||||
('VarColorIndex', 'Color', None, None, ''),
|
||||
('F2Dot14', 'StopOffset', None, None, 'VarIndexBase + 0'),
|
||||
('uint16', 'PaletteIndex', None, None, 'Index for a CPAL palette entry.'),
|
||||
('F2Dot14', 'Alpha', None, None, 'Values outsided [0.,1.] reserved. VarIndexBase + 1'),
|
||||
('VarIndex', 'VarIndexBase', None, None, 'Base index into DeltaSetIndexMap.'),
|
||||
]),
|
||||
|
||||
('ColorLine', [
|
||||
@ -1650,12 +1660,15 @@ otData = [
|
||||
# PaintSolid
|
||||
('PaintFormat2', [
|
||||
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 2'),
|
||||
('ColorIndex', 'Color', None, None, 'A solid color paint.'),
|
||||
('uint16', 'PaletteIndex', None, None, 'Index for a CPAL palette entry.'),
|
||||
('F2Dot14', 'Alpha', None, None, 'Values outsided [0.,1.] reserved'),
|
||||
]),
|
||||
# PaintVarSolid
|
||||
('PaintFormat3', [
|
||||
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 3'),
|
||||
('VarColorIndex', 'Color', None, None, 'A solid color paint.'),
|
||||
('uint16', 'PaletteIndex', None, None, 'Index for a CPAL palette entry.'),
|
||||
('F2Dot14', 'Alpha', None, None, 'Values outsided [0.,1.] reserved. VarIndexBase + 0'),
|
||||
('VarIndex', 'VarIndexBase', None, None, 'Base index into DeltaSetIndexMap.'),
|
||||
]),
|
||||
|
||||
# PaintLinearGradient
|
||||
@ -1673,12 +1686,13 @@ otData = [
|
||||
('PaintFormat5', [
|
||||
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 5'),
|
||||
('LOffset24To(VarColorLine)', 'ColorLine', None, None, 'Offset (from beginning of PaintVarLinearGradient table) to VarColorLine subtable.'),
|
||||
('VarInt16', 'x0', None, None, ''),
|
||||
('VarInt16', 'y0', None, None, ''),
|
||||
('VarInt16', 'x1', None, None, ''),
|
||||
('VarInt16', 'y1', None, None, ''),
|
||||
('VarInt16', 'x2', None, None, ''),
|
||||
('VarInt16', 'y2', None, None, ''),
|
||||
('int16', 'x0', None, None, ''),
|
||||
('int16', 'y0', None, None, ''),
|
||||
('int16', 'x1', None, None, ''),
|
||||
('int16', 'y1', None, None, ''),
|
||||
('int16', 'x2', None, None, ''),
|
||||
('int16', 'y2', None, None, ''),
|
||||
('VarIndex', 'VarIndexBase', None, None, 'Base index into DeltaSetIndexMap.'),
|
||||
]),
|
||||
|
||||
# PaintRadialGradient
|
||||
@ -1696,12 +1710,13 @@ otData = [
|
||||
('PaintFormat7', [
|
||||
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 7'),
|
||||
('LOffset24To(VarColorLine)', 'ColorLine', None, None, 'Offset (from beginning of PaintVarRadialGradient table) to VarColorLine 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, ''),
|
||||
('int16', 'x0', None, None, ''),
|
||||
('int16', 'y0', None, None, ''),
|
||||
('uint16', 'r0', None, None, ''),
|
||||
('int16', 'x1', None, None, ''),
|
||||
('int16', 'y1', None, None, ''),
|
||||
('uint16', 'r1', None, None, ''),
|
||||
('VarIndex', 'VarIndexBase', None, None, 'Base index into DeltaSetIndexMap.'),
|
||||
]),
|
||||
|
||||
# PaintSweepGradient
|
||||
@ -1717,10 +1732,11 @@ otData = [
|
||||
('PaintFormat9', [
|
||||
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 9'),
|
||||
('LOffset24To(VarColorLine)', 'ColorLine', None, None, 'Offset (from beginning of PaintVarSweepGradient table) to VarColorLine subtable.'),
|
||||
('VarInt16', 'centerX', None, None, 'Center x coordinate.'),
|
||||
('VarInt16', 'centerY', None, None, 'Center y coordinate.'),
|
||||
('VarAngle', 'startAngle', None, None, 'Start of the angular range of the gradient.'),
|
||||
('VarAngle', 'endAngle', None, None, 'End of the angular range of the gradient.'),
|
||||
('int16', 'centerX', None, None, 'Center x coordinate.'),
|
||||
('int16', 'centerY', None, None, 'Center y coordinate.'),
|
||||
('Angle', 'startAngle', None, None, 'Start of the angular range of the gradient.'),
|
||||
('Angle', 'endAngle', None, None, 'End of the angular range of the gradient.'),
|
||||
('VarIndex', 'VarIndexBase', None, None, 'Base index into DeltaSetIndexMap.'),
|
||||
]),
|
||||
|
||||
# PaintGlyph
|
||||
@ -1760,8 +1776,9 @@ otData = [
|
||||
('PaintFormat15', [
|
||||
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 15'),
|
||||
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintVarTranslate table) to Paint subtable.'),
|
||||
('VarInt16', 'dx', None, None, 'Translation in x direction.'),
|
||||
('VarInt16', 'dy', None, None, 'Translation in y direction.'),
|
||||
('int16', 'dx', None, None, 'Translation in x direction.'),
|
||||
('int16', 'dy', None, None, 'Translation in y direction.'),
|
||||
('VarIndex', 'VarIndexBase', None, None, 'Base index into DeltaSetIndexMap.'),
|
||||
]),
|
||||
|
||||
# PaintScale
|
||||
@ -1775,8 +1792,9 @@ otData = [
|
||||
('PaintFormat17', [
|
||||
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 17'),
|
||||
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintVarScale table) to Paint subtable.'),
|
||||
('VarF2Dot14', 'scaleX', None, None, ''),
|
||||
('VarF2Dot14', 'scaleY', None, None, ''),
|
||||
('F2Dot14', 'scaleX', None, None, ''),
|
||||
('F2Dot14', 'scaleY', None, None, ''),
|
||||
('VarIndex', 'VarIndexBase', None, None, 'Base index into DeltaSetIndexMap.'),
|
||||
]),
|
||||
|
||||
# PaintScaleAroundCenter
|
||||
@ -1792,10 +1810,11 @@ otData = [
|
||||
('PaintFormat19', [
|
||||
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 19'),
|
||||
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintVarScaleAroundCenter table) to Paint subtable.'),
|
||||
('VarF2Dot14', 'scaleX', None, None, ''),
|
||||
('VarF2Dot14', 'scaleY', None, None, ''),
|
||||
('VarInt16', 'centerX', None, None, ''),
|
||||
('VarInt16', 'centerY', None, None, ''),
|
||||
('F2Dot14', 'scaleX', None, None, ''),
|
||||
('F2Dot14', 'scaleY', None, None, ''),
|
||||
('int16', 'centerX', None, None, ''),
|
||||
('int16', 'centerY', None, None, ''),
|
||||
('VarIndex', 'VarIndexBase', None, None, 'Base index into DeltaSetIndexMap.'),
|
||||
]),
|
||||
|
||||
# PaintScaleUniform
|
||||
@ -1808,7 +1827,8 @@ otData = [
|
||||
('PaintFormat21', [
|
||||
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 21'),
|
||||
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintVarScaleUniform table) to Paint subtable.'),
|
||||
('VarF2Dot14', 'scale', None, None, ''),
|
||||
('F2Dot14', 'scale', None, None, ''),
|
||||
('VarIndex', 'VarIndexBase', None, None, 'Base index into DeltaSetIndexMap.'),
|
||||
]),
|
||||
|
||||
# PaintScaleUniformAroundCenter
|
||||
@ -1823,9 +1843,10 @@ otData = [
|
||||
('PaintFormat23', [
|
||||
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 23'),
|
||||
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintVarScaleUniformAroundCenter table) to Paint subtable.'),
|
||||
('VarF2Dot14', 'scale', None, None, ''),
|
||||
('VarInt16', 'centerX', None, None, ''),
|
||||
('VarInt16', 'centerY', None, None, ''),
|
||||
('F2Dot14', 'scale', None, None, ''),
|
||||
('int16', 'centerX', None, None, ''),
|
||||
('int16', 'centerY', None, None, ''),
|
||||
('VarIndex', 'VarIndexBase', None, None, 'Base index into DeltaSetIndexMap.'),
|
||||
]),
|
||||
|
||||
# PaintRotate
|
||||
@ -1838,7 +1859,8 @@ otData = [
|
||||
('PaintFormat25', [
|
||||
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 25'),
|
||||
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintVarRotate table) to Paint subtable.'),
|
||||
('VarAngle', 'angle', None, None, ''),
|
||||
('Angle', 'angle', None, None, ''),
|
||||
('VarIndex', 'VarIndexBase', None, None, 'Base index into DeltaSetIndexMap.'),
|
||||
]),
|
||||
|
||||
# PaintRotateAroundCenter
|
||||
@ -1853,9 +1875,10 @@ otData = [
|
||||
('PaintFormat27', [
|
||||
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 27'),
|
||||
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintVarRotateAroundCenter table) to Paint subtable.'),
|
||||
('VarAngle', 'angle', None, None, ''),
|
||||
('VarInt16', 'centerX', None, None, ''),
|
||||
('VarInt16', 'centerY', None, None, ''),
|
||||
('Angle', 'angle', None, None, ''),
|
||||
('int16', 'centerX', None, None, ''),
|
||||
('int16', 'centerY', None, None, ''),
|
||||
('VarIndex', 'VarIndexBase', None, None, 'Base index into DeltaSetIndexMap.'),
|
||||
]),
|
||||
|
||||
# PaintSkew
|
||||
@ -1869,8 +1892,9 @@ otData = [
|
||||
('PaintFormat29', [
|
||||
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 29'),
|
||||
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintVarSkew table) to Paint subtable.'),
|
||||
('VarAngle', 'xSkewAngle', None, None, ''),
|
||||
('VarAngle', 'ySkewAngle', None, None, ''),
|
||||
('Angle', 'xSkewAngle', None, None, ''),
|
||||
('Angle', 'ySkewAngle', None, None, ''),
|
||||
('VarIndex', 'VarIndexBase', None, None, 'Base index into DeltaSetIndexMap.'),
|
||||
]),
|
||||
|
||||
# PaintSkewAroundCenter
|
||||
@ -1886,10 +1910,11 @@ otData = [
|
||||
('PaintFormat31', [
|
||||
('uint8', 'PaintFormat', None, None, 'Format identifier-format = 31'),
|
||||
('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintVarSkewAroundCenter table) to Paint subtable.'),
|
||||
('VarAngle', 'xSkewAngle', None, None, ''),
|
||||
('VarAngle', 'ySkewAngle', None, None, ''),
|
||||
('VarInt16', 'centerX', None, None, ''),
|
||||
('VarInt16', 'centerY', None, None, ''),
|
||||
('Angle', 'xSkewAngle', None, None, ''),
|
||||
('Angle', 'ySkewAngle', None, None, ''),
|
||||
('int16', 'centerX', None, None, ''),
|
||||
('int16', 'centerY', None, None, ''),
|
||||
('VarIndex', 'VarIndexBase', None, None, 'Base index into DeltaSetIndexMap.'),
|
||||
]),
|
||||
|
||||
# PaintComposite
|
||||
|
@ -618,6 +618,73 @@ class Coverage(FormatSwitchingBaseTable):
|
||||
glyphs.append(attrs["value"])
|
||||
|
||||
|
||||
class DeltaSetIndexMap(getFormatSwitchingBaseTableClass("uint8")):
|
||||
|
||||
def populateDefaults(self, propagator=None):
|
||||
if not hasattr(self, 'mapping'):
|
||||
self.mapping = []
|
||||
|
||||
def postRead(self, rawTable, font):
|
||||
assert (rawTable['EntryFormat'] & 0xFFC0) == 0
|
||||
self.mapping = rawTable['mapping']
|
||||
|
||||
@staticmethod
|
||||
def getEntryFormat(mapping):
|
||||
ored = 0
|
||||
for idx in mapping:
|
||||
ored |= idx
|
||||
|
||||
inner = ored & 0xFFFF
|
||||
innerBits = 0
|
||||
while inner:
|
||||
innerBits += 1
|
||||
inner >>= 1
|
||||
innerBits = max(innerBits, 1)
|
||||
assert innerBits <= 16
|
||||
|
||||
ored = (ored >> (16-innerBits)) | (ored & ((1<<innerBits)-1))
|
||||
if ored <= 0x000000FF:
|
||||
entrySize = 1
|
||||
elif ored <= 0x0000FFFF:
|
||||
entrySize = 2
|
||||
elif ored <= 0x00FFFFFF:
|
||||
entrySize = 3
|
||||
else:
|
||||
entrySize = 4
|
||||
|
||||
return ((entrySize - 1) << 4) | (innerBits - 1)
|
||||
|
||||
def preWrite(self, font):
|
||||
mapping = getattr(self, "mapping", None)
|
||||
if mapping is None:
|
||||
mapping = self.mapping = []
|
||||
self.Format = 1 if len(mapping) > 0xFFFF else 0
|
||||
rawTable = self.__dict__.copy()
|
||||
rawTable['MappingCount'] = len(mapping)
|
||||
rawTable['EntryFormat'] = self.getEntryFormat(mapping)
|
||||
return rawTable
|
||||
|
||||
def toXML2(self, xmlWriter, font):
|
||||
for i, value in enumerate(getattr(self, "mapping", [])):
|
||||
attrs = (
|
||||
('index', i),
|
||||
('outer', value >> 16),
|
||||
('inner', value & 0xFFFF),
|
||||
)
|
||||
xmlWriter.simpletag("Map", attrs)
|
||||
xmlWriter.newline()
|
||||
|
||||
def fromXML(self, name, attrs, content, font):
|
||||
mapping = getattr(self, "mapping", None)
|
||||
if mapping is None:
|
||||
self.mapping = mapping = []
|
||||
index = safeEval(attrs['index'])
|
||||
outer = safeEval(attrs['outer'])
|
||||
inner = safeEval(attrs['inner'])
|
||||
assert inner <= 0xFFFF
|
||||
mapping.insert(index, (outer << 16) | inner)
|
||||
|
||||
|
||||
class VarIdxMap(BaseTable):
|
||||
|
||||
def populateDefaults(self, propagator=None):
|
||||
@ -641,34 +708,9 @@ class VarIdxMap(BaseTable):
|
||||
while len(mapping) > 1 and mapping[-2] == mapping[-1]:
|
||||
del mapping[-1]
|
||||
|
||||
rawTable = { 'mapping': mapping }
|
||||
rawTable = {'mapping': mapping}
|
||||
rawTable['MappingCount'] = len(mapping)
|
||||
|
||||
ored = 0
|
||||
for idx in mapping:
|
||||
ored |= idx
|
||||
|
||||
inner = ored & 0xFFFF
|
||||
innerBits = 0
|
||||
while inner:
|
||||
innerBits += 1
|
||||
inner >>= 1
|
||||
innerBits = max(innerBits, 1)
|
||||
assert innerBits <= 16
|
||||
|
||||
ored = (ored >> (16-innerBits)) | (ored & ((1<<innerBits)-1))
|
||||
if ored <= 0x000000FF:
|
||||
entrySize = 1
|
||||
elif ored <= 0x0000FFFF:
|
||||
entrySize = 2
|
||||
elif ored <= 0x00FFFFFF:
|
||||
entrySize = 3
|
||||
else:
|
||||
entrySize = 4
|
||||
|
||||
entryFormat = ((entrySize - 1) << 4) | (innerBits - 1)
|
||||
|
||||
rawTable['EntryFormat'] = entryFormat
|
||||
rawTable['EntryFormat'] = DeltaSetIndexMap.getEntryFormat(mapping)
|
||||
return rawTable
|
||||
|
||||
def toXML2(self, xmlWriter, font):
|
||||
@ -1255,43 +1297,6 @@ class BaseGlyphList(BaseTable):
|
||||
return self.__dict__.copy()
|
||||
|
||||
|
||||
|
||||
class VariableValue(namedtuple("VariableValue", ["value", "varIdx"])):
|
||||
__slots__ = ()
|
||||
|
||||
_value_mapper = None
|
||||
|
||||
def __new__(cls, value, varIdx=0xFFFFFFFF):
|
||||
return super().__new__(
|
||||
cls,
|
||||
cls._value_mapper(value) if cls._value_mapper else value,
|
||||
varIdx
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _make(cls, iterable):
|
||||
if cls._value_mapper:
|
||||
it = iter(iterable)
|
||||
try:
|
||||
value = next(it)
|
||||
except StopIteration:
|
||||
pass
|
||||
else:
|
||||
value = cls._value_mapper(value)
|
||||
iterable = itertools.chain((value,), it)
|
||||
return super()._make(iterable)
|
||||
|
||||
|
||||
class VariableFloat(VariableValue):
|
||||
__slots__ = ()
|
||||
_value_mapper = float
|
||||
|
||||
|
||||
class VariableInt(VariableValue):
|
||||
__slots__ = ()
|
||||
_value_mapper = otRound
|
||||
|
||||
|
||||
class ExtendMode(IntEnum):
|
||||
PAD = 0
|
||||
REPEAT = 1
|
||||
|
@ -121,6 +121,14 @@ def buildVarIdxMap(varIdxes, glyphOrder):
|
||||
self.mapping = {g:v for g,v in zip(glyphOrder, varIdxes)}
|
||||
return self
|
||||
|
||||
|
||||
def buildDeltaSetIndexMap(varIdxes):
|
||||
self = ot.DeltaSetIndexMap()
|
||||
self.mapping = list(varIdxes)
|
||||
self.Format = 1 if len(varIdxes) > 0xFFFF else 0
|
||||
return self
|
||||
|
||||
|
||||
def buildVarDevTable(varIdx):
|
||||
self = ot.Device()
|
||||
self.DeltaFormat = 0x8000
|
||||
|
@ -231,92 +231,63 @@ def test_buildCPAL_invalid_color():
|
||||
builder.buildCPAL([[(0, 0, 0, 0)], [(1, 1, -1, 2)]])
|
||||
|
||||
|
||||
def test_buildColorIndex_Minimal():
|
||||
c = _build(ot.ColorIndex, 1)
|
||||
assert c.PaletteIndex == 1
|
||||
assert c.Alpha == 1.0
|
||||
|
||||
|
||||
def test_buildVarColorIndex_Minimal():
|
||||
c = _build(ot.VarColorIndex, 1)
|
||||
assert c.PaletteIndex == 1
|
||||
assert c.Alpha.value == 1.0
|
||||
assert c.Alpha.varIdx == 0xFFFFFFFF
|
||||
|
||||
|
||||
def test_buildColorIndex():
|
||||
c = _build(ot.ColorIndex, (1, 0.5))
|
||||
assert c.PaletteIndex == 1
|
||||
assert c.Alpha == 0.5
|
||||
|
||||
|
||||
def test_buildVarColorIndex():
|
||||
c = _build(ot.VarColorIndex, (3, builder.VariableFloat(0.5, varIdx=2)))
|
||||
assert c.PaletteIndex == 3
|
||||
assert c.Alpha.value == 0.5
|
||||
assert c.Alpha.varIdx == 2
|
||||
|
||||
|
||||
def test_buildPaintSolid():
|
||||
p = _buildPaint((ot.PaintFormat.PaintSolid, 0))
|
||||
assert p.Format == ot.PaintFormat.PaintSolid
|
||||
assert p.Color.PaletteIndex == 0
|
||||
assert p.Color.Alpha == 1.0
|
||||
assert p.PaletteIndex == 0
|
||||
assert p.Alpha == 1.0
|
||||
|
||||
|
||||
def test_buildPaintSolid_Alpha():
|
||||
p = _buildPaint((ot.PaintFormat.PaintSolid, (1, 0.5)))
|
||||
p = _buildPaint((ot.PaintFormat.PaintSolid, 1, 0.5))
|
||||
assert p.Format == ot.PaintFormat.PaintSolid
|
||||
assert p.Color.PaletteIndex == 1
|
||||
assert p.Color.Alpha == 0.5
|
||||
assert p.PaletteIndex == 1
|
||||
assert p.Alpha == 0.5
|
||||
|
||||
|
||||
def test_buildPaintVarSolid():
|
||||
p = _buildPaint(
|
||||
(ot.PaintFormat.PaintVarSolid, (3, builder.VariableFloat(0.5, varIdx=2)))
|
||||
)
|
||||
p = _buildPaint((ot.PaintFormat.PaintVarSolid, 3, 0.5, 2))
|
||||
assert p.Format == ot.PaintFormat.PaintVarSolid
|
||||
assert p.Color.PaletteIndex == 3
|
||||
assert p.Color.Alpha.value == 0.5
|
||||
assert p.Color.Alpha.varIdx == 2
|
||||
assert p.PaletteIndex == 3
|
||||
assert p.Alpha == 0.5
|
||||
assert p.VarIndexBase == 2
|
||||
|
||||
|
||||
def test_buildVarColorStop_DefaultAlpha():
|
||||
s = _build(ot.ColorStop, (0.1, 2))
|
||||
assert s.StopOffset == 0.1
|
||||
assert s.Color.PaletteIndex == 2
|
||||
assert s.Color.Alpha == builder._DEFAULT_ALPHA.value
|
||||
assert s.PaletteIndex == 2
|
||||
assert s.Alpha == builder._DEFAULT_ALPHA
|
||||
|
||||
|
||||
def test_buildVarColorStop_DefaultAlpha():
|
||||
s = _build(ot.VarColorStop, (0.1, 2))
|
||||
assert s.StopOffset == builder.VariableFloat(0.1)
|
||||
assert s.Color.PaletteIndex == 2
|
||||
assert s.Color.Alpha == builder._DEFAULT_ALPHA
|
||||
assert s.StopOffset == 0.1
|
||||
assert s.PaletteIndex == 2
|
||||
assert s.Alpha == builder._DEFAULT_ALPHA
|
||||
|
||||
|
||||
def test_buildColorStop():
|
||||
s = _build(
|
||||
ot.ColorStop, {"StopOffset": 0.2, "Color": {"PaletteIndex": 3, "Alpha": 0.4}}
|
||||
)
|
||||
s = _build(ot.ColorStop, {"StopOffset": 0.2, "PaletteIndex": 3, "Alpha": 0.4})
|
||||
assert s.StopOffset == 0.2
|
||||
assert s.Color == _build(ot.ColorIndex, (3, 0.4))
|
||||
assert s.PaletteIndex == 3
|
||||
assert s.Alpha == 0.4
|
||||
|
||||
|
||||
def test_buildColorStop_Variable():
|
||||
s = _build(
|
||||
ot.VarColorStop,
|
||||
{
|
||||
"StopOffset": builder.VariableFloat(0.0, varIdx=1),
|
||||
"Color": {
|
||||
"StopOffset": 0.0,
|
||||
"PaletteIndex": 0,
|
||||
"Alpha": builder.VariableFloat(0.3, varIdx=2),
|
||||
},
|
||||
"Alpha": 0.3,
|
||||
"VarIndexBase": 1,
|
||||
},
|
||||
)
|
||||
assert s.StopOffset == builder.VariableFloat(0.0, varIdx=1)
|
||||
assert s.Color.PaletteIndex == 0
|
||||
assert s.Color.Alpha == builder.VariableFloat(0.3, varIdx=2)
|
||||
assert s.StopOffset == 0.0
|
||||
assert s.PaletteIndex == 0
|
||||
assert s.Alpha == 0.3
|
||||
assert s.VarIndexBase == 1
|
||||
|
||||
|
||||
def test_buildColorLine_StopList():
|
||||
@ -325,7 +296,7 @@ def test_buildColorLine_StopList():
|
||||
cline = _build(ot.ColorLine, {"ColorStop": stops})
|
||||
assert cline.Extend == builder.ExtendMode.PAD
|
||||
assert cline.StopCount == 3
|
||||
assert [(cs.StopOffset, cs.Color.PaletteIndex) for cs in cline.ColorStop] == stops
|
||||
assert [(cs.StopOffset, cs.PaletteIndex) for cs in cline.ColorStop] == stops
|
||||
|
||||
cline = _build(ot.ColorLine, {"Extend": "pad", "ColorStop": stops})
|
||||
assert cline.Extend == builder.ExtendMode.PAD
|
||||
@ -343,51 +314,57 @@ def test_buildColorLine_StopList():
|
||||
cline = _build(
|
||||
ot.ColorLine, {"ColorStop": [_build(ot.ColorStop, s) for s in stops]}
|
||||
)
|
||||
assert [(cs.StopOffset, cs.Color.PaletteIndex) for cs in cline.ColorStop] == stops
|
||||
assert [(cs.StopOffset, cs.PaletteIndex) for cs in cline.ColorStop] == stops
|
||||
|
||||
|
||||
def test_buildVarColorLine_StopMap():
|
||||
stops = [
|
||||
{"StopOffset": (0.0, (1,)), "Color": {"PaletteIndex": 0, "Alpha": (0.5, 2)}},
|
||||
{"StopOffset": (1.0, (3,)), "Color": {"PaletteIndex": 1, "Alpha": (0.3, 4)}},
|
||||
{"StopOffset": 0.0, "PaletteIndex": 0, "Alpha": 0.5, "VarIndexBase": 1},
|
||||
{"StopOffset": 1.0, "PaletteIndex": 1, "Alpha": 0.3, "VarIndexBase": 3},
|
||||
]
|
||||
cline = _build(ot.VarColorLine, {"ColorStop": stops})
|
||||
assert [
|
||||
{
|
||||
"StopOffset": cs.StopOffset,
|
||||
"Color": {
|
||||
"PaletteIndex": cs.Color.PaletteIndex,
|
||||
"Alpha": cs.Color.Alpha,
|
||||
},
|
||||
"PaletteIndex": cs.PaletteIndex,
|
||||
"Alpha": cs.Alpha,
|
||||
"VarIndexBase": cs.VarIndexBase,
|
||||
}
|
||||
for cs in cline.ColorStop
|
||||
] == stops
|
||||
|
||||
|
||||
def checkBuildAffine2x3(cls, resultMapFn):
|
||||
def checkBuildAffine2x3(cls, variable=False):
|
||||
matrix = _build(cls, (1.5, 0, 0.5, 2.0, 1.0, -3.0))
|
||||
assert matrix.xx == resultMapFn(1.5)
|
||||
assert matrix.yx == resultMapFn(0.0)
|
||||
assert matrix.xy == resultMapFn(0.5)
|
||||
assert matrix.yy == resultMapFn(2.0)
|
||||
assert matrix.dx == resultMapFn(1.0)
|
||||
assert matrix.dy == resultMapFn(-3.0)
|
||||
assert matrix.xx == 1.5
|
||||
assert matrix.yx == 0.0
|
||||
assert matrix.xy == 0.5
|
||||
assert matrix.yy == 2.0
|
||||
assert matrix.dx == 1.0
|
||||
assert matrix.dy == -3.0
|
||||
if variable:
|
||||
assert matrix.VarIndexBase == 0xFFFFFFFF
|
||||
|
||||
|
||||
def test_buildAffine2x3():
|
||||
checkBuildAffine2x3(ot.Affine2x3, lambda v: v)
|
||||
checkBuildAffine2x3(ot.Affine2x3)
|
||||
|
||||
|
||||
def test_buildVarAffine2x3():
|
||||
checkBuildAffine2x3(ot.VarAffine2x3, builder.VariableFloat)
|
||||
checkBuildAffine2x3(ot.VarAffine2x3, variable=True)
|
||||
|
||||
|
||||
def _sample_stops(cls):
|
||||
return [
|
||||
_build(cls, (0.0, 0)),
|
||||
_build(cls, (0.5, 1)),
|
||||
_build(cls, (1.0, (2, 0.8))),
|
||||
def _sample_stops(variable):
|
||||
cls = ot.ColorStop if not variable else ot.VarColorStop
|
||||
stop_sources = [
|
||||
{"StopOffset": 0.0, "PaletteIndex": 0},
|
||||
{"StopOffset": 0.5, "PaletteIndex": 1},
|
||||
{"StopOffset": 1.0, "PaletteIndex": 2, "Alpha": 0.8},
|
||||
]
|
||||
if variable:
|
||||
for i, src in enumerate(stop_sources, start=123):
|
||||
src["VarIndexBase"] = i
|
||||
return [_build(cls, src) for src in stop_sources]
|
||||
|
||||
|
||||
def _is_var(fmt):
|
||||
@ -403,17 +380,11 @@ def _is_uniform_scale(fmt):
|
||||
|
||||
|
||||
def checkBuildPaintLinearGradient(fmt):
|
||||
if _is_var(fmt):
|
||||
inputMapFn = builder.VariableInt
|
||||
outputMapFn = lambda v: v.value
|
||||
color_stops = _sample_stops(ot.VarColorStop)
|
||||
else:
|
||||
inputMapFn = outputMapFn = lambda v: v
|
||||
color_stops = _sample_stops(ot.ColorStop)
|
||||
variable = _is_var(fmt)
|
||||
color_stops = _sample_stops(variable)
|
||||
|
||||
x0, y0, x1, y1, x2, y2 = tuple(inputMapFn(v) for v in (1, 2, 3, 4, 5, 6))
|
||||
gradient = _buildPaint(
|
||||
{
|
||||
x0, y0, x1, y1, x2, y2 = (1, 2, 3, 4, 5, 6)
|
||||
source = {
|
||||
"Format": fmt,
|
||||
"ColorLine": {"ColorStop": color_stops},
|
||||
"x0": x0,
|
||||
@ -422,15 +393,19 @@ def checkBuildPaintLinearGradient(fmt):
|
||||
"y1": y1,
|
||||
"x2": x2,
|
||||
"y2": y2,
|
||||
},
|
||||
)
|
||||
}
|
||||
if variable:
|
||||
source["VarIndexBase"] = 7
|
||||
gradient = _buildPaint(source)
|
||||
assert gradient.ColorLine.Extend == builder.ExtendMode.PAD
|
||||
assert gradient.ColorLine.ColorStop == color_stops
|
||||
|
||||
gradient = _buildPaint(gradient)
|
||||
assert (outputMapFn(gradient.x0), outputMapFn(gradient.y0)) == (1, 2)
|
||||
assert (outputMapFn(gradient.x1), outputMapFn(gradient.y1)) == (3, 4)
|
||||
assert (outputMapFn(gradient.x2), outputMapFn(gradient.y2)) == (5, 6)
|
||||
assert (gradient.x0, gradient.y0) == (1, 2)
|
||||
assert (gradient.x1, gradient.y1) == (3, 4)
|
||||
assert (gradient.x2, gradient.y2) == (5, 6)
|
||||
if variable:
|
||||
assert gradient.VarIndexBase == 7
|
||||
|
||||
|
||||
def test_buildPaintLinearGradient():
|
||||
@ -438,41 +413,40 @@ def test_buildPaintLinearGradient():
|
||||
checkBuildPaintLinearGradient(ot.PaintFormat.PaintLinearGradient)
|
||||
|
||||
|
||||
def test_buildVarPaintLinearGradient():
|
||||
def test_buildPaintVarLinearGradient():
|
||||
assert _is_var(ot.PaintFormat.PaintVarLinearGradient)
|
||||
checkBuildPaintLinearGradient(ot.PaintFormat.PaintVarLinearGradient)
|
||||
|
||||
|
||||
def checkBuildPaintRadialGradient(fmt):
|
||||
if _is_var(fmt):
|
||||
inputMapFn = builder.VariableInt
|
||||
outputMapFn = lambda v: v
|
||||
color_stops = _sample_stops(ot.VarColorStop)
|
||||
line_cls = ot.VarColorLine
|
||||
else:
|
||||
inputMapFn = outputMapFn = lambda v: v
|
||||
color_stops = _sample_stops(ot.ColorStop)
|
||||
line_cls = ot.ColorLine
|
||||
variable = _is_var(fmt)
|
||||
color_stops = _sample_stops(variable)
|
||||
line_cls = ot.VarColorLine if variable else ot.ColorLine
|
||||
|
||||
color_line = _build(
|
||||
line_cls, {"ColorStop": color_stops, "Extend": builder.ExtendMode.REPEAT}
|
||||
)
|
||||
c0 = (inputMapFn(100), inputMapFn(200))
|
||||
c1 = (inputMapFn(150), inputMapFn(250))
|
||||
r0 = inputMapFn(10)
|
||||
r1 = inputMapFn(5)
|
||||
c0 = (100, 200)
|
||||
c1 = (150, 250)
|
||||
r0 = 10
|
||||
r1 = 5
|
||||
varIndexBase = 0
|
||||
|
||||
gradient = _build(ot.Paint, (fmt, color_line, *c0, r0, *c1, r1))
|
||||
source = [fmt, color_line, *c0, r0, *c1, r1]
|
||||
if variable:
|
||||
source.append(varIndexBase)
|
||||
|
||||
gradient = _build(ot.Paint, tuple(source))
|
||||
assert gradient.Format == fmt
|
||||
assert gradient.ColorLine == color_line
|
||||
assert (outputMapFn(gradient.x0), outputMapFn(gradient.y0)) == c0
|
||||
assert (outputMapFn(gradient.x1), outputMapFn(gradient.y1)) == c1
|
||||
assert outputMapFn(gradient.r0) == r0
|
||||
assert outputMapFn(gradient.r1) == r1
|
||||
assert (gradient.x0, gradient.y0) == c0
|
||||
assert (gradient.x1, gradient.y1) == c1
|
||||
assert gradient.r0 == r0
|
||||
assert gradient.r1 == r1
|
||||
if variable:
|
||||
assert gradient.VarIndexBase == varIndexBase
|
||||
|
||||
gradient = _build(
|
||||
ot.Paint,
|
||||
{
|
||||
source = {
|
||||
"Format": fmt,
|
||||
"ColorLine": {"ColorStop": color_stops},
|
||||
"x0": c0[0],
|
||||
@ -481,14 +455,18 @@ def checkBuildPaintRadialGradient(fmt):
|
||||
"y1": c1[1],
|
||||
"r0": r0,
|
||||
"r1": r1,
|
||||
},
|
||||
)
|
||||
}
|
||||
if variable:
|
||||
source["VarIndexBase"] = varIndexBase
|
||||
gradient = _build(ot.Paint, source)
|
||||
assert gradient.ColorLine.Extend == builder.ExtendMode.PAD
|
||||
assert gradient.ColorLine.ColorStop == color_stops
|
||||
assert (outputMapFn(gradient.x0), outputMapFn(gradient.y0)) == c0
|
||||
assert (outputMapFn(gradient.x1), outputMapFn(gradient.y1)) == c1
|
||||
assert outputMapFn(gradient.r0) == r0
|
||||
assert outputMapFn(gradient.r1) == r1
|
||||
assert (gradient.x0, gradient.y0) == c0
|
||||
assert (gradient.x1, gradient.y1) == c1
|
||||
assert gradient.r0 == r0
|
||||
assert gradient.r1 == r1
|
||||
if variable:
|
||||
assert gradient.VarIndexBase == varIndexBase
|
||||
|
||||
|
||||
def test_buildPaintRadialGradient():
|
||||
@ -502,33 +480,26 @@ def test_buildPaintVarRadialGradient():
|
||||
|
||||
|
||||
def checkPaintSweepGradient(fmt):
|
||||
if _is_var(fmt):
|
||||
outputMapFn = lambda v: v.value
|
||||
else:
|
||||
outputMapFn = lambda v: v
|
||||
|
||||
paint = _buildPaint(
|
||||
{
|
||||
variable = _is_var(fmt)
|
||||
source = {
|
||||
"Format": fmt,
|
||||
"ColorLine": {
|
||||
"ColorStop": (
|
||||
(0.0, 0),
|
||||
(0.5, 1),
|
||||
(1.0, (2, 0.8)),
|
||||
)
|
||||
},
|
||||
"ColorLine": {"ColorStop": _sample_stops(variable)},
|
||||
"centerX": 127,
|
||||
"centerY": 129,
|
||||
"startAngle": 15,
|
||||
"endAngle": 42,
|
||||
}
|
||||
)
|
||||
if variable:
|
||||
source["VarIndexBase"] = 666
|
||||
paint = _buildPaint(source)
|
||||
|
||||
assert paint.Format == fmt
|
||||
assert outputMapFn(paint.centerX) == 127
|
||||
assert outputMapFn(paint.centerY) == 129
|
||||
assert outputMapFn(paint.startAngle) == 15
|
||||
assert outputMapFn(paint.endAngle) == 42
|
||||
assert paint.centerX == 127
|
||||
assert paint.centerY == 129
|
||||
assert paint.startAngle == 15
|
||||
assert paint.endAngle == 42
|
||||
if variable:
|
||||
assert paint.VarIndexBase == 666
|
||||
|
||||
|
||||
def test_buildPaintSweepGradient():
|
||||
@ -556,22 +527,19 @@ def test_buildPaintGlyph_Solid():
|
||||
assert layer.Format == ot.PaintFormat.PaintGlyph
|
||||
assert layer.Glyph == "a"
|
||||
assert layer.Paint.Format == ot.PaintFormat.PaintSolid
|
||||
assert layer.Paint.Color.PaletteIndex == 2
|
||||
assert layer.Paint.PaletteIndex == 2
|
||||
|
||||
layer = _build(
|
||||
ot.Paint,
|
||||
(
|
||||
ot.PaintFormat.PaintGlyph,
|
||||
(
|
||||
ot.PaintFormat.PaintSolid,
|
||||
(3, 0.9),
|
||||
),
|
||||
(ot.PaintFormat.PaintSolid, 3, 0.9),
|
||||
"a",
|
||||
),
|
||||
)
|
||||
assert layer.Paint.Format == ot.PaintFormat.PaintSolid
|
||||
assert layer.Paint.Color.PaletteIndex == 3
|
||||
assert layer.Paint.Color.Alpha == 0.9
|
||||
assert layer.Paint.PaletteIndex == 3
|
||||
assert layer.Paint.Alpha == 0.9
|
||||
|
||||
|
||||
def test_buildPaintGlyph_VarLinearGradient():
|
||||
@ -594,14 +562,14 @@ def test_buildPaintGlyph_VarLinearGradient():
|
||||
assert layer.Format == ot.PaintFormat.PaintGlyph
|
||||
assert layer.Glyph == "a"
|
||||
assert layer.Paint.Format == ot.PaintFormat.PaintVarLinearGradient
|
||||
assert layer.Paint.ColorLine.ColorStop[0].StopOffset.value == 0.0
|
||||
assert layer.Paint.ColorLine.ColorStop[0].Color.PaletteIndex == 3
|
||||
assert layer.Paint.ColorLine.ColorStop[1].StopOffset.value == 1.0
|
||||
assert layer.Paint.ColorLine.ColorStop[1].Color.PaletteIndex == 4
|
||||
assert layer.Paint.x0.value == 100
|
||||
assert layer.Paint.y0.value == 200
|
||||
assert layer.Paint.x1.value == 150
|
||||
assert layer.Paint.y1.value == 250
|
||||
assert layer.Paint.ColorLine.ColorStop[0].StopOffset == 0.0
|
||||
assert layer.Paint.ColorLine.ColorStop[0].PaletteIndex == 3
|
||||
assert layer.Paint.ColorLine.ColorStop[1].StopOffset == 1.0
|
||||
assert layer.Paint.ColorLine.ColorStop[1].PaletteIndex == 4
|
||||
assert layer.Paint.x0 == 100
|
||||
assert layer.Paint.y0 == 200
|
||||
assert layer.Paint.x1 == 150
|
||||
assert layer.Paint.y1 == 250
|
||||
|
||||
|
||||
def test_buildPaintGlyph_RadialGradient():
|
||||
@ -615,7 +583,7 @@ def test_buildPaintGlyph_RadialGradient():
|
||||
"pad",
|
||||
[
|
||||
(0.0, 5),
|
||||
{"StopOffset": 0.5, "Color": {"PaletteIndex": 6, "Alpha": 0.8}},
|
||||
{"StopOffset": 0.5, "PaletteIndex": 6, "Alpha": 0.8},
|
||||
(1.0, 7),
|
||||
],
|
||||
),
|
||||
@ -632,12 +600,12 @@ def test_buildPaintGlyph_RadialGradient():
|
||||
assert layer.Format == ot.PaintFormat.PaintGlyph
|
||||
assert layer.Paint.Format == ot.PaintFormat.PaintRadialGradient
|
||||
assert layer.Paint.ColorLine.ColorStop[0].StopOffset == 0.0
|
||||
assert layer.Paint.ColorLine.ColorStop[0].Color.PaletteIndex == 5
|
||||
assert layer.Paint.ColorLine.ColorStop[0].PaletteIndex == 5
|
||||
assert layer.Paint.ColorLine.ColorStop[1].StopOffset == 0.5
|
||||
assert layer.Paint.ColorLine.ColorStop[1].Color.PaletteIndex == 6
|
||||
assert layer.Paint.ColorLine.ColorStop[1].Color.Alpha == 0.8
|
||||
assert layer.Paint.ColorLine.ColorStop[1].PaletteIndex == 6
|
||||
assert layer.Paint.ColorLine.ColorStop[1].Alpha == 0.8
|
||||
assert layer.Paint.ColorLine.ColorStop[2].StopOffset == 1.0
|
||||
assert layer.Paint.ColorLine.ColorStop[2].Color.PaletteIndex == 7
|
||||
assert layer.Paint.ColorLine.ColorStop[2].PaletteIndex == 7
|
||||
assert layer.Paint.x0 == 50
|
||||
assert layer.Paint.y0 == 50
|
||||
assert layer.Paint.r0 == 30
|
||||
@ -659,7 +627,7 @@ def test_buildPaintGlyph_Dict_Solid():
|
||||
assert layer.Format == ot.PaintFormat.PaintGlyph
|
||||
assert layer.Glyph == "a"
|
||||
assert layer.Paint.Format == ot.PaintFormat.PaintSolid
|
||||
assert layer.Paint.Color.PaletteIndex == 1
|
||||
assert layer.Paint.PaletteIndex == 1
|
||||
|
||||
|
||||
def test_buildPaintGlyph_Dict_VarLinearGradient():
|
||||
@ -681,7 +649,7 @@ def test_buildPaintGlyph_Dict_VarLinearGradient():
|
||||
assert layer.Format == ot.PaintFormat.PaintGlyph
|
||||
assert layer.Glyph == "a"
|
||||
assert layer.Paint.Format == ot.PaintFormat.PaintVarLinearGradient
|
||||
assert layer.Paint.ColorLine.ColorStop[0].StopOffset.value == 0.0
|
||||
assert layer.Paint.ColorLine.ColorStop[0].StopOffset == 0.0
|
||||
|
||||
|
||||
def test_buildPaintGlyph_Dict_RadialGradient():
|
||||
@ -712,19 +680,21 @@ def test_buildPaintColrGlyph():
|
||||
|
||||
|
||||
def checkBuildPaintTransform(fmt):
|
||||
if _is_var(fmt):
|
||||
inputMapFn = builder.VariableFloat
|
||||
outputMapFn = lambda v: v.value
|
||||
variable = _is_var(fmt)
|
||||
if variable:
|
||||
affine_cls = ot.VarAffine2x3
|
||||
else:
|
||||
inputMapFn = outputMapFn = lambda v: v
|
||||
affine_cls = ot.Affine2x3
|
||||
|
||||
affine_src = [1, 2, 3, 4, 5, 6]
|
||||
if variable:
|
||||
affine_src.append(7)
|
||||
|
||||
paint = _buildPaint(
|
||||
(
|
||||
int(fmt),
|
||||
(ot.PaintFormat.PaintGlyph, (ot.PaintFormat.PaintSolid, (0, 1.0)), "a"),
|
||||
_build(affine_cls, (1, 2, 3, 4, 5, 6)),
|
||||
(ot.PaintFormat.PaintGlyph, (ot.PaintFormat.PaintSolid, 0, 1.0), "a"),
|
||||
_build(affine_cls, tuple(affine_src)),
|
||||
),
|
||||
)
|
||||
|
||||
@ -732,18 +702,23 @@ def checkBuildPaintTransform(fmt):
|
||||
assert paint.Paint.Format == ot.PaintFormat.PaintGlyph
|
||||
assert paint.Paint.Paint.Format == ot.PaintFormat.PaintSolid
|
||||
|
||||
assert outputMapFn(paint.Transform.xx) == 1.0
|
||||
assert outputMapFn(paint.Transform.yx) == 2.0
|
||||
assert outputMapFn(paint.Transform.xy) == 3.0
|
||||
assert outputMapFn(paint.Transform.yy) == 4.0
|
||||
assert outputMapFn(paint.Transform.dx) == 5.0
|
||||
assert outputMapFn(paint.Transform.dy) == 6.0
|
||||
assert paint.Transform.xx == 1.0
|
||||
assert paint.Transform.yx == 2.0
|
||||
assert paint.Transform.xy == 3.0
|
||||
assert paint.Transform.yy == 4.0
|
||||
assert paint.Transform.dx == 5.0
|
||||
assert paint.Transform.dy == 6.0
|
||||
if variable:
|
||||
assert paint.Transform.VarIndexBase == 7
|
||||
|
||||
affine_src = [1, 2, 3, 0.3333, 10, 10]
|
||||
if variable:
|
||||
affine_src.append(456) # VarIndexBase
|
||||
paint = _build(
|
||||
ot.Paint,
|
||||
{
|
||||
"Format": fmt,
|
||||
"Transform": (1, 2, 3, 0.3333, 10, 10),
|
||||
"Transform": tuple(affine_src),
|
||||
"Paint": {
|
||||
"Format": int(ot.PaintFormat.PaintRadialGradient),
|
||||
"ColorLine": {"ColorStop": [(0.0, 0), (1.0, 1)]},
|
||||
@ -758,12 +733,14 @@ def checkBuildPaintTransform(fmt):
|
||||
)
|
||||
|
||||
assert paint.Format == fmt
|
||||
assert outputMapFn(paint.Transform.xx) == 1.0
|
||||
assert outputMapFn(paint.Transform.yx) == 2.0
|
||||
assert outputMapFn(paint.Transform.xy) == 3.0
|
||||
assert outputMapFn(paint.Transform.yy) == 0.3333
|
||||
assert outputMapFn(paint.Transform.dx) == 10
|
||||
assert outputMapFn(paint.Transform.dy) == 10
|
||||
assert paint.Transform.xx == 1.0
|
||||
assert paint.Transform.yx == 2.0
|
||||
assert paint.Transform.xy == 3.0
|
||||
assert paint.Transform.yy == 0.3333
|
||||
assert paint.Transform.dx == 10
|
||||
assert paint.Transform.dy == 10
|
||||
if variable:
|
||||
assert paint.Transform.VarIndexBase == 456
|
||||
assert paint.Paint.Format == ot.PaintFormat.PaintRadialGradient
|
||||
|
||||
|
||||
@ -802,7 +779,8 @@ def test_buildPaintComposite():
|
||||
"Glyph": "a",
|
||||
"Paint": {
|
||||
"Format": ot.PaintFormat.PaintSolid,
|
||||
"Color": (0, 1.0),
|
||||
"PaletteIndex": 0,
|
||||
"Alpha": 0.5,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -813,44 +791,44 @@ def test_buildPaintComposite():
|
||||
assert composite.SourcePaint.SourcePaint.Format == ot.PaintFormat.PaintGlyph
|
||||
assert composite.SourcePaint.SourcePaint.Glyph == "c"
|
||||
assert composite.SourcePaint.SourcePaint.Paint.Format == ot.PaintFormat.PaintSolid
|
||||
assert composite.SourcePaint.SourcePaint.Paint.Color.PaletteIndex == 2
|
||||
assert composite.SourcePaint.SourcePaint.Paint.PaletteIndex == 2
|
||||
assert composite.SourcePaint.CompositeMode == ot.CompositeMode.SRC_OVER
|
||||
assert composite.SourcePaint.BackdropPaint.Format == ot.PaintFormat.PaintGlyph
|
||||
assert composite.SourcePaint.BackdropPaint.Glyph == "b"
|
||||
assert composite.SourcePaint.BackdropPaint.Paint.Format == ot.PaintFormat.PaintSolid
|
||||
assert composite.SourcePaint.BackdropPaint.Paint.Color.PaletteIndex == 1
|
||||
assert composite.SourcePaint.BackdropPaint.Paint.PaletteIndex == 1
|
||||
assert composite.CompositeMode == ot.CompositeMode.SRC_OVER
|
||||
assert composite.BackdropPaint.Format == ot.PaintFormat.PaintGlyph
|
||||
assert composite.BackdropPaint.Glyph == "a"
|
||||
assert composite.BackdropPaint.Paint.Format == ot.PaintFormat.PaintSolid
|
||||
assert composite.BackdropPaint.Paint.Color.PaletteIndex == 0
|
||||
assert composite.BackdropPaint.Paint.PaletteIndex == 0
|
||||
assert composite.BackdropPaint.Paint.Alpha == 0.5
|
||||
|
||||
|
||||
def checkBuildPaintTranslate(fmt):
|
||||
if _is_var(fmt):
|
||||
inputMapFn = builder.VariableInt
|
||||
outputMapFn = lambda v: v.value
|
||||
else:
|
||||
inputMapFn = outputMapFn = lambda v: v
|
||||
variable = _is_var(fmt)
|
||||
|
||||
paint = _build(
|
||||
ot.Paint,
|
||||
{
|
||||
source = {
|
||||
"Format": fmt,
|
||||
"Paint": (
|
||||
ot.PaintFormat.PaintGlyph,
|
||||
(ot.PaintFormat.PaintSolid, (0, 1.0)),
|
||||
(ot.PaintFormat.PaintSolid, 0, 1.0),
|
||||
"a",
|
||||
),
|
||||
"dx": 123,
|
||||
"dy": -345,
|
||||
},
|
||||
)
|
||||
}
|
||||
if variable:
|
||||
source["VarIndexBase"] = 678
|
||||
|
||||
paint = _build(ot.Paint, source)
|
||||
|
||||
assert paint.Format == fmt
|
||||
assert paint.Paint.Format == ot.PaintFormat.PaintGlyph
|
||||
assert outputMapFn(paint.dx) == 123
|
||||
assert outputMapFn(paint.dy) == -345
|
||||
assert paint.dx == 123
|
||||
assert paint.dy == -345
|
||||
if variable:
|
||||
assert paint.VarIndexBase == 678
|
||||
|
||||
|
||||
def test_buildPaintTranslate():
|
||||
@ -864,11 +842,7 @@ def test_buildPaintVarTranslate():
|
||||
|
||||
|
||||
def checkBuildPaintScale(fmt):
|
||||
if _is_var(fmt):
|
||||
inputMapFn = builder.VariableInt
|
||||
outputMapFn = lambda v: v.value
|
||||
else:
|
||||
inputMapFn = outputMapFn = lambda v: v
|
||||
variable = _is_var(fmt)
|
||||
around_center = _is_around_center(fmt)
|
||||
uniform = _is_uniform_scale(fmt)
|
||||
|
||||
@ -876,7 +850,7 @@ def checkBuildPaintScale(fmt):
|
||||
"Format": fmt,
|
||||
"Paint": (
|
||||
ot.PaintFormat.PaintGlyph,
|
||||
(ot.PaintFormat.PaintSolid, (0, 1.0)),
|
||||
(ot.PaintFormat.PaintSolid, 0, 1.0),
|
||||
"a",
|
||||
),
|
||||
}
|
||||
@ -888,19 +862,23 @@ def checkBuildPaintScale(fmt):
|
||||
if around_center:
|
||||
source["centerX"] = 127
|
||||
source["centerY"] = 129
|
||||
if variable:
|
||||
source["VarIndexBase"] = 666
|
||||
|
||||
paint = _build(ot.Paint, source)
|
||||
|
||||
assert paint.Format == fmt
|
||||
assert paint.Paint.Format == ot.PaintFormat.PaintGlyph
|
||||
if uniform:
|
||||
assert outputMapFn(paint.scale) == 1.5
|
||||
assert paint.scale == 1.5
|
||||
else:
|
||||
assert outputMapFn(paint.scaleX) == 1.0
|
||||
assert outputMapFn(paint.scaleY) == 2.0
|
||||
assert paint.scaleX == 1.0
|
||||
assert paint.scaleY == 2.0
|
||||
if around_center:
|
||||
assert outputMapFn(paint.centerX) == 127
|
||||
assert outputMapFn(paint.centerY) == 129
|
||||
assert paint.centerX == 127
|
||||
assert paint.centerY == 129
|
||||
if variable:
|
||||
assert paint.VarIndexBase == 666
|
||||
|
||||
|
||||
def test_buildPaintScale():
|
||||
@ -960,18 +938,14 @@ def test_buildPaintVarScaleUniformAroundCenter():
|
||||
|
||||
|
||||
def checkBuildPaintRotate(fmt):
|
||||
if _is_var(fmt):
|
||||
inputMapFn = builder.VariableInt
|
||||
outputMapFn = lambda v: v.value
|
||||
else:
|
||||
inputMapFn = outputMapFn = lambda v: v
|
||||
variable = _is_var(fmt)
|
||||
around_center = _is_around_center(fmt)
|
||||
|
||||
source = {
|
||||
"Format": fmt,
|
||||
"Paint": (
|
||||
ot.PaintFormat.PaintGlyph,
|
||||
(ot.PaintFormat.PaintSolid, (0, 1.0)),
|
||||
(ot.PaintFormat.PaintSolid, 0, 1.0),
|
||||
"a",
|
||||
),
|
||||
"angle": 15,
|
||||
@ -984,10 +958,12 @@ def checkBuildPaintRotate(fmt):
|
||||
|
||||
assert paint.Format == fmt
|
||||
assert paint.Paint.Format == ot.PaintFormat.PaintGlyph
|
||||
assert outputMapFn(paint.angle) == 15
|
||||
assert paint.angle == 15
|
||||
if around_center:
|
||||
assert outputMapFn(paint.centerX) == 127
|
||||
assert outputMapFn(paint.centerY) == 129
|
||||
assert paint.centerX == 127
|
||||
assert paint.centerY == 129
|
||||
if variable:
|
||||
assert paint.VarIndexBase == 0xFFFFFFFF
|
||||
|
||||
|
||||
def test_buildPaintRotate():
|
||||
@ -1015,18 +991,14 @@ def test_buildPaintVarRotateAroundCenter():
|
||||
|
||||
|
||||
def checkBuildPaintSkew(fmt):
|
||||
if _is_var(fmt):
|
||||
inputMapFn = builder.VariableInt
|
||||
outputMapFn = lambda v: v.value
|
||||
else:
|
||||
inputMapFn = outputMapFn = lambda v: v
|
||||
variable = _is_var(fmt)
|
||||
around_center = _is_around_center(fmt)
|
||||
|
||||
source = {
|
||||
"Format": fmt,
|
||||
"Paint": (
|
||||
ot.PaintFormat.PaintGlyph,
|
||||
(ot.PaintFormat.PaintSolid, (0, 1.0)),
|
||||
(ot.PaintFormat.PaintSolid, 0, 1.0),
|
||||
"a",
|
||||
),
|
||||
"xSkewAngle": 15,
|
||||
@ -1035,16 +1007,20 @@ def checkBuildPaintSkew(fmt):
|
||||
if around_center:
|
||||
source["centerX"] = 127
|
||||
source["centerY"] = 129
|
||||
if variable:
|
||||
source["VarIndexBase"] = 0
|
||||
|
||||
paint = _build(ot.Paint, source)
|
||||
|
||||
assert paint.Format == fmt
|
||||
assert paint.Paint.Format == ot.PaintFormat.PaintGlyph
|
||||
assert outputMapFn(paint.xSkewAngle) == 15
|
||||
assert outputMapFn(paint.ySkewAngle) == 42
|
||||
assert paint.xSkewAngle == 15
|
||||
assert paint.ySkewAngle == 42
|
||||
if around_center:
|
||||
assert outputMapFn(paint.centerX) == 127
|
||||
assert outputMapFn(paint.centerY) == 129
|
||||
assert paint.centerX == 127
|
||||
assert paint.centerY == 129
|
||||
if variable:
|
||||
assert paint.VarIndexBase == 0
|
||||
|
||||
|
||||
def test_buildPaintSkew():
|
||||
@ -1087,7 +1063,8 @@ def test_buildColrV1():
|
||||
ot.PaintFormat.PaintGlyph,
|
||||
{
|
||||
"Format": int(ot.PaintFormat.PaintSolid),
|
||||
"Color": {"PaletteIndex": 2, "Alpha": 0.8},
|
||||
"PaletteIndex": 2,
|
||||
"Alpha": 0.8,
|
||||
},
|
||||
"e",
|
||||
),
|
||||
@ -1250,7 +1227,7 @@ def test_build_layerv1list_empty():
|
||||
# BaseGlyph, tuple form
|
||||
"a": (
|
||||
int(ot.PaintFormat.PaintGlyph),
|
||||
(2, (2, 0.8)),
|
||||
(int(ot.PaintFormat.PaintSolid), 2, 0.8),
|
||||
"b",
|
||||
),
|
||||
# BaseGlyph, map form
|
||||
@ -1301,7 +1278,11 @@ def _paint_names(paints) -> List[str]:
|
||||
def test_build_layerv1list_simple():
|
||||
# Two colr glyphs, each with two layers the first of which is common
|
||||
# All layers use the same solid paint
|
||||
solid_paint = {"Format": 2, "Color": {"PaletteIndex": 2, "Alpha": 0.8}}
|
||||
solid_paint = {
|
||||
"Format": int(ot.PaintFormat.PaintSolid),
|
||||
"PaletteIndex": 2,
|
||||
"Alpha": 0.8,
|
||||
}
|
||||
backdrop = {
|
||||
"Format": int(ot.PaintFormat.PaintGlyph),
|
||||
"Paint": solid_paint,
|
||||
@ -1357,7 +1338,11 @@ def test_build_layerv1list_simple():
|
||||
|
||||
def test_build_layerv1list_with_sharing():
|
||||
# Three colr glyphs, each with two layers in common
|
||||
solid_paint = {"Format": 2, "Color": (2, 0.8)}
|
||||
solid_paint = {
|
||||
"Format": int(ot.PaintFormat.PaintSolid),
|
||||
"PaletteIndex": 2,
|
||||
"Alpha": 0.8,
|
||||
}
|
||||
backdrop = [
|
||||
{
|
||||
"Format": int(ot.PaintFormat.PaintGlyph),
|
||||
@ -1436,7 +1421,8 @@ def test_build_layerv1list_with_overlaps():
|
||||
"Format": ot.PaintFormat.PaintGlyph,
|
||||
"Paint": {
|
||||
"Format": ot.PaintFormat.PaintSolid,
|
||||
"Color": {"PaletteIndex": 2, "Alpha": 0.8},
|
||||
"PaletteIndex": 2,
|
||||
"Alpha": 0.8,
|
||||
},
|
||||
"Glyph": c,
|
||||
}
|
||||
@ -1533,7 +1519,11 @@ class BuildCOLRTest(object):
|
||||
),
|
||||
(
|
||||
ot.PaintFormat.PaintGlyph,
|
||||
{"Format": 2, "Color": {"PaletteIndex": 2, "Alpha": 0.8}},
|
||||
{
|
||||
"Format": ot.PaintFormat.PaintSolid,
|
||||
"PaletteIndex": 2,
|
||||
"Alpha": 0.8,
|
||||
},
|
||||
"c",
|
||||
),
|
||||
],
|
||||
@ -1591,7 +1581,7 @@ class BuildCOLRTest(object):
|
||||
),
|
||||
(
|
||||
ot.PaintFormat.PaintGlyph,
|
||||
(ot.PaintFormat.PaintSolid, (2, 0.8)),
|
||||
(ot.PaintFormat.PaintSolid, 2, 0.8),
|
||||
"f",
|
||||
),
|
||||
],
|
||||
|
@ -12,7 +12,8 @@ TEST_COLOR_GLYPHS = {
|
||||
"Format": int(ot.PaintFormat.PaintGlyph),
|
||||
"Paint": {
|
||||
"Format": int(ot.PaintFormat.PaintSolid),
|
||||
"Color": {"PaletteIndex": 2, "Alpha": 0.5},
|
||||
"PaletteIndex": 2,
|
||||
"Alpha": 0.5,
|
||||
},
|
||||
"Glyph": "glyph00011",
|
||||
},
|
||||
@ -24,25 +25,32 @@ TEST_COLOR_GLYPHS = {
|
||||
"Extend": "repeat",
|
||||
"ColorStop": [
|
||||
{
|
||||
"StopOffset": (0.0, 0),
|
||||
"Color": {"PaletteIndex": 3, "Alpha": (1.0, 0)},
|
||||
"StopOffset": 0.0,
|
||||
"PaletteIndex": 3,
|
||||
"Alpha": 1.0,
|
||||
"VarIndexBase": 0,
|
||||
},
|
||||
{
|
||||
"StopOffset": (0.5, 0),
|
||||
"Color": {"PaletteIndex": 4, "Alpha": (1.0, 0)},
|
||||
"StopOffset": 0.5,
|
||||
"PaletteIndex": 4,
|
||||
"Alpha": 1.0,
|
||||
"VarIndexBase": 1,
|
||||
},
|
||||
{
|
||||
"StopOffset": (1.0, 0),
|
||||
"Color": {"PaletteIndex": 5, "Alpha": (1.0, 0)},
|
||||
"StopOffset": 1.0,
|
||||
"PaletteIndex": 5,
|
||||
"Alpha": 1.0,
|
||||
"VarIndexBase": 2,
|
||||
},
|
||||
],
|
||||
},
|
||||
"x0": (1, 0),
|
||||
"y0": (2, 0),
|
||||
"x1": (-3, 0),
|
||||
"y1": (-4, 0),
|
||||
"x2": (5, 0),
|
||||
"y2": (6, 0),
|
||||
"x0": 1,
|
||||
"y0": 2,
|
||||
"x1": -3,
|
||||
"y1": -4,
|
||||
"x2": 5,
|
||||
"y2": 6,
|
||||
"VarIndexBase": 0xFFFFFFFF,
|
||||
},
|
||||
"Glyph": "glyph00012",
|
||||
},
|
||||
@ -57,11 +65,13 @@ TEST_COLOR_GLYPHS = {
|
||||
"ColorStop": [
|
||||
{
|
||||
"StopOffset": 0,
|
||||
"Color": {"PaletteIndex": 6, "Alpha": 1.0},
|
||||
"PaletteIndex": 6,
|
||||
"Alpha": 1.0,
|
||||
},
|
||||
{
|
||||
"StopOffset": 1.0,
|
||||
"Color": {"PaletteIndex": 7, "Alpha": 0.4},
|
||||
"PaletteIndex": 7,
|
||||
"Alpha": 0.4,
|
||||
},
|
||||
],
|
||||
},
|
||||
@ -73,12 +83,13 @@ TEST_COLOR_GLYPHS = {
|
||||
"r1": 12,
|
||||
},
|
||||
"Transform": {
|
||||
"xx": (-13.0, 0),
|
||||
"yx": (14.0, 0),
|
||||
"xy": (15.0, 0),
|
||||
"yy": (-17.0, 0),
|
||||
"dx": (18.0, 0),
|
||||
"dy": (19.0, 0),
|
||||
"xx": -13.0,
|
||||
"yx": 14.0,
|
||||
"xy": 15.0,
|
||||
"yy": -17.0,
|
||||
"dx": 18.0,
|
||||
"dy": 19.0,
|
||||
"VarIndexBase": 3,
|
||||
},
|
||||
},
|
||||
"Glyph": "glyph00013",
|
||||
@ -93,17 +104,20 @@ TEST_COLOR_GLYPHS = {
|
||||
"Format": int(ot.PaintFormat.PaintGlyph),
|
||||
"Paint": {
|
||||
"Format": int(ot.PaintFormat.PaintSolid),
|
||||
"Color": {"PaletteIndex": 2, "Alpha": 0.5},
|
||||
"PaletteIndex": 2,
|
||||
"Alpha": 0.5,
|
||||
},
|
||||
"Glyph": "glyph00011",
|
||||
},
|
||||
"xSkewAngle": (-11.0, 0),
|
||||
"ySkewAngle": (5.0, 0),
|
||||
"xSkewAngle": -11.0,
|
||||
"ySkewAngle": 5.0,
|
||||
"VarIndexBase": 4,
|
||||
},
|
||||
"angle": 45.0,
|
||||
},
|
||||
"dx": (257.0, 0),
|
||||
"dy": (258.0, 0),
|
||||
"dx": 257.0,
|
||||
"dy": 258.0,
|
||||
"VarIndexBase": 5,
|
||||
},
|
||||
],
|
||||
},
|
||||
@ -139,11 +153,13 @@ TEST_COLOR_GLYPHS = {
|
||||
"ColorStop": [
|
||||
{
|
||||
"StopOffset": 0.0,
|
||||
"Color": {"PaletteIndex": 3, "Alpha": 1.0},
|
||||
"PaletteIndex": 3,
|
||||
"Alpha": 1.0,
|
||||
},
|
||||
{
|
||||
"StopOffset": 1.0,
|
||||
"Color": {"PaletteIndex": 5, "Alpha": 1.0},
|
||||
"PaletteIndex": 5,
|
||||
"Alpha": 1.0,
|
||||
},
|
||||
],
|
||||
},
|
||||
@ -161,7 +177,9 @@ TEST_COLOR_GLYPHS = {
|
||||
"Format": int(ot.PaintFormat.PaintGlyph),
|
||||
"Paint": {
|
||||
"Format": int(ot.PaintFormat.PaintVarSolid),
|
||||
"Color": {"PaletteIndex": 2, "Alpha": (0.5, 0)},
|
||||
"PaletteIndex": 2,
|
||||
"Alpha": 0.5,
|
||||
"VarIndexBase": 6,
|
||||
},
|
||||
"Glyph": "glyph00011",
|
||||
},
|
||||
@ -173,25 +191,32 @@ TEST_COLOR_GLYPHS = {
|
||||
"Extend": "repeat",
|
||||
"ColorStop": [
|
||||
{
|
||||
"StopOffset": (0.0, 0),
|
||||
"Color": {"PaletteIndex": 3, "Alpha": (1.0, 0)},
|
||||
"StopOffset": 0.0,
|
||||
"PaletteIndex": 3,
|
||||
"Alpha": 1.0,
|
||||
"VarIndexBase": 7,
|
||||
},
|
||||
{
|
||||
"StopOffset": (0.5, 0),
|
||||
"Color": {"PaletteIndex": 4, "Alpha": (1.0, 0)},
|
||||
"StopOffset": 0.5,
|
||||
"PaletteIndex": 4,
|
||||
"Alpha": 1.0,
|
||||
"VarIndexBase": 8,
|
||||
},
|
||||
{
|
||||
"StopOffset": (1.0, 0),
|
||||
"Color": {"PaletteIndex": 5, "Alpha": (1.0, 0)},
|
||||
"StopOffset": 1.0,
|
||||
"PaletteIndex": 5,
|
||||
"Alpha": 1.0,
|
||||
"VarIndexBase": 9,
|
||||
},
|
||||
],
|
||||
},
|
||||
"x0": (1, 0),
|
||||
"y0": (2, 0),
|
||||
"x1": (-3, 0),
|
||||
"y1": (-4, 0),
|
||||
"x2": (5, 0),
|
||||
"y2": (6, 0),
|
||||
"x0": 1,
|
||||
"y0": 2,
|
||||
"x1": -3,
|
||||
"y1": -4,
|
||||
"x2": 5,
|
||||
"y2": 6,
|
||||
"VarIndexBase": 0xFFFFFFFF,
|
||||
},
|
||||
"Glyph": "glyph00012",
|
||||
},
|
||||
|
@ -1013,7 +1013,7 @@ def colrv1_path(tmp_path):
|
||||
},
|
||||
{
|
||||
"Format": ot.PaintFormat.PaintGlyph,
|
||||
"Paint": (ot.PaintFormat.PaintSolid, (2, 0.3)),
|
||||
"Paint": (ot.PaintFormat.PaintSolid, 2, 0.3),
|
||||
"Glyph": "glyph00011",
|
||||
},
|
||||
],
|
||||
@ -1044,7 +1044,7 @@ def colrv1_path(tmp_path):
|
||||
},
|
||||
{
|
||||
"Format": ot.PaintFormat.PaintGlyph,
|
||||
"Paint": (ot.PaintFormat.PaintSolid, (1, 0.5)),
|
||||
"Paint": (ot.PaintFormat.PaintSolid, 1, 0.5),
|
||||
"Glyph": "glyph00013",
|
||||
},
|
||||
],
|
||||
@ -1159,9 +1159,9 @@ def test_subset_COLRv1_and_CPAL(colrv1_path):
|
||||
]
|
||||
assert len(layers) == 2
|
||||
# check v1 palette indices were remapped
|
||||
assert layers[0].Paint.Paint.ColorLine.ColorStop[0].Color.PaletteIndex == 0
|
||||
assert layers[0].Paint.Paint.ColorLine.ColorStop[1].Color.PaletteIndex == 1
|
||||
assert layers[1].Paint.Color.PaletteIndex == 0
|
||||
assert layers[0].Paint.Paint.ColorLine.ColorStop[0].PaletteIndex == 0
|
||||
assert layers[0].Paint.Paint.ColorLine.ColorStop[1].PaletteIndex == 1
|
||||
assert layers[1].Paint.PaletteIndex == 0
|
||||
|
||||
baseRecV0 = colr.BaseGlyphRecordArray.BaseGlyphRecord[0]
|
||||
assert baseRecV0.BaseGlyph == "uniE004"
|
||||
|
@ -104,13 +104,14 @@ COLR_V1_SAMPLE = (
|
||||
(b"\x00\x01", "Version (1)"),
|
||||
(b"\x00\x01", "BaseGlyphRecordCount (1)"),
|
||||
(
|
||||
b"\x00\x00\x00\x1a",
|
||||
"Offset to BaseGlyphRecordArray from beginning of table (26)",
|
||||
b"\x00\x00\x00\x1e",
|
||||
"Offset to BaseGlyphRecordArray from beginning of table (30)",
|
||||
),
|
||||
(b"\x00\x00\x00 ", "Offset to LayerRecordArray from beginning of table (32)"),
|
||||
(b"\x00\x00\x00\x24", "Offset to LayerRecordArray from beginning of table (36)"),
|
||||
(b"\x00\x03", "LayerRecordCount (3)"),
|
||||
(b"\x00\x00\x00,", "Offset to BaseGlyphList from beginning of table (44)"),
|
||||
(b"\x00\x00\x00\xab", "Offset to LayerList from beginning of table (171)"),
|
||||
(b"\x00\x00\x00\x30", "Offset to BaseGlyphList from beginning of table (48)"),
|
||||
(b"\x00\x00\x00\x9b", "Offset to LayerList from beginning of table (155)"),
|
||||
(b"\x00\x00\x00\x00", "Offset to DeltaSetIndexMap (NULL)"),
|
||||
(b"\x00\x00\x00\x00", "Offset to VarStore (NULL)"),
|
||||
(b"\x00\x06", "BaseGlyphRecord[0].BaseGlyph (6)"),
|
||||
(b"\x00\x00", "BaseGlyphRecord[0].FirstLayerIndex (0)"),
|
||||
@ -135,8 +136,8 @@ COLR_V1_SAMPLE = (
|
||||
),
|
||||
(b"\x00\x0f", "BaseGlyphList.BaseGlyphPaintRecord[2].BaseGlyph (15)"),
|
||||
(
|
||||
b"\x00\x00\x00\x5e",
|
||||
"Offset to Paint table from beginning of BaseGlyphList (94)",
|
||||
b"\x00\x00\x00\x4a",
|
||||
"Offset to Paint table from beginning of BaseGlyphList (74)",
|
||||
),
|
||||
# BaseGlyphPaintRecord[0]
|
||||
(b"\x01", "BaseGlyphPaintRecord[0].Paint.Format (1)"),
|
||||
@ -152,12 +153,13 @@ COLR_V1_SAMPLE = (
|
||||
(b"\x00\x00\x0a", "Offset to VarAffine2x3 from beginning of PaintVarTransform (10)"),
|
||||
(b"\x0b", "BaseGlyphPaintRecord[1].Paint.BackdropPaint.Format (11)"),
|
||||
(b"\x00\x0a", "BaseGlyphPaintRecord[1].Paint.BackdropPaint.Glyph (10)"),
|
||||
(b"\x00\x01\x00\x00\xff\xff\xff\xff", "VarAffine2x3.xx (1.0)"),
|
||||
(b"\x00\x00\x00\x00\xff\xff\xff\xff", "VarAffine2x3.xy (0.0)"),
|
||||
(b"\x00\x00\x00\x00\xff\xff\xff\xff", "VarAffine2x3.yx (0.0)"),
|
||||
(b"\x00\x01\x00\x00\xff\xff\xff\xff", "VarAffine2x3.yy (1.0)"),
|
||||
(b"\x01\x2c\x00\x00\xff\xff\xff\xff", "VarAffine2x3.dx (300.0)"),
|
||||
(b"\x00\x00\x00\x00\xff\xff\xff\xff", "VarAffine2x3.dy (0.0)"),
|
||||
(b"\x00\x01\x00\x00", "VarAffine2x3.xx (1.0)"),
|
||||
(b"\x00\x00\x00\x00", "VarAffine2x3.xy (0.0)"),
|
||||
(b"\x00\x00\x00\x00", "VarAffine2x3.yx (0.0)"),
|
||||
(b"\x00\x01\x00\x00", "VarAffine2x3.yy (1.0)"),
|
||||
(b"\x01\x2c\x00\x00", "VarAffine2x3.dx (300.0)"),
|
||||
(b"\x00\x00\x00\x00", "VarAffine2x3.dy (0.0)"),
|
||||
(b"\x00\x00\x00\x00", "VarIndexBase (0)"),
|
||||
(b"\x0a", "BaseGlyphPaintRecord[1].Paint.SourcePaint.Format (10)"),
|
||||
(b"\x00\x00\x06", "Offset to Paint subtable from beginning of PaintGlyph (6)"),
|
||||
(b"\x00\x0b", "BaseGlyphPaintRecord[1].Paint.SourcePaint.Glyph (11)"),
|
||||
@ -170,11 +172,11 @@ COLR_V1_SAMPLE = (
|
||||
(b"\x00", "ColorLine.Extend (0; pad)"),
|
||||
(b"\x00\x02", "ColorLine.StopCount (2)"),
|
||||
(b"\x00\x00", "ColorLine.ColorStop[0].StopOffset (0.0)"),
|
||||
(b"\x00\x03", "ColorLine.ColorStop[0].Color.PaletteIndex (3)"),
|
||||
(b"@\x00", "ColorLine.ColorStop[0].Color.Alpha (1.0)"),
|
||||
(b"\x00\x03", "ColorLine.ColorStop[0].PaletteIndex (3)"),
|
||||
(b"@\x00", "ColorLine.ColorStop[0].Alpha (1.0)"),
|
||||
(b"@\x00", "ColorLine.ColorStop[1].StopOffset (1.0)"),
|
||||
(b"\x00\x05", "ColorLine.ColorStop[1].Color.PaletteIndex (5)"),
|
||||
(b"@\x00", "ColorLine.ColorStop[1].Color.Alpha (1.0)"),
|
||||
(b"\x00\x05", "ColorLine.ColorStop[1].PaletteIndex (5)"),
|
||||
(b"@\x00", "ColorLine.ColorStop[1].Alpha (1.0)"),
|
||||
# LayerList
|
||||
(b"\x00\x00\x00\x04", "LayerList.LayerCount (4)"),
|
||||
(
|
||||
@ -190,8 +192,8 @@ COLR_V1_SAMPLE = (
|
||||
"Third Offset to Paint table from beginning of LayerList (78)",
|
||||
),
|
||||
(
|
||||
b"\x00\x00\x00\xba",
|
||||
"Fourth Offset to Paint table from beginning of LayerList (186)",
|
||||
b"\x00\x00\x00\x9e",
|
||||
"Fourth Offset to Paint table from beginning of LayerList (158)",
|
||||
),
|
||||
# BaseGlyphPaintRecord[2]
|
||||
(b"\x0a", "BaseGlyphPaintRecord[2].Paint.Format (10)"),
|
||||
@ -199,9 +201,9 @@ COLR_V1_SAMPLE = (
|
||||
(b"\x00\x0b", "BaseGlyphPaintRecord[2].Paint.Glyph (11)"),
|
||||
# PaintVarSolid
|
||||
(b"\x03", "LayerList.Paint[0].Paint.Format (3)"),
|
||||
(b"\x00\x02", "Paint.Color.PaletteIndex (2)"),
|
||||
(b" \x00", "Paint.Color.Alpha.value (0.5)"),
|
||||
(b"\xff\xff\xff\xff", "Paint.Color.Alpha.varIdx (0xFFFFFFFF)"),
|
||||
(b"\x00\x02", "Paint.PaletteIndex (2)"),
|
||||
(b" \x00", "Paint.Alpha.value (0.5)"),
|
||||
(b"\x00\x00\x00\x06", "VarIndexBase (6)"),
|
||||
# PaintGlyph glyph00012
|
||||
(b"\x0a", "LayerList.Paint[1].Format (10)"),
|
||||
(b"\x00\x00\x06", "Offset to Paint subtable from beginning of PaintGlyph (6)"),
|
||||
@ -217,38 +219,41 @@ COLR_V1_SAMPLE = (
|
||||
(b"\x01", "ColorLine.Extend (1; repeat)"),
|
||||
(b"\x00\x03", "ColorLine.StopCount (3)"),
|
||||
(b"\x00\x00", "ColorLine.ColorStop[0].StopOffset (0.0)"),
|
||||
(b"\x00\x03", "ColorLine.ColorStop[0].Color.PaletteIndex (3)"),
|
||||
(b"@\x00", "ColorLine.ColorStop[0].Color.Alpha (1.0)"),
|
||||
(b"\x00\x03", "ColorLine.ColorStop[0].PaletteIndex (3)"),
|
||||
(b"@\x00", "ColorLine.ColorStop[0].Alpha (1.0)"),
|
||||
(b" \x00", "ColorLine.ColorStop[1].StopOffset (0.5)"),
|
||||
(b"\x00\x04", "ColorLine.ColorStop[1].Color.PaletteIndex (4)"),
|
||||
(b"@\x00", "ColorLine.ColorStop[1].Color.Alpha (1.0)"),
|
||||
(b"\x00\x04", "ColorLine.ColorStop[1].PaletteIndex (4)"),
|
||||
(b"@\x00", "ColorLine.ColorStop[1].Alpha (1.0)"),
|
||||
(b"@\x00", "ColorLine.ColorStop[2].StopOffset (1.0)"),
|
||||
(b"\x00\x05", "ColorLine.ColorStop[2].Color.PaletteIndex (5)"),
|
||||
(b"@\x00", "ColorLine.ColorStop[2].Color.Alpha (1.0)"),
|
||||
(b"\x00\x05", "ColorLine.ColorStop[2].PaletteIndex (5)"),
|
||||
(b"@\x00", "ColorLine.ColorStop[2].Alpha (1.0)"),
|
||||
# PaintGlyph glyph00013
|
||||
(b"\x0a", "LayerList.Paint[2].Format (10)"),
|
||||
(b"\x00\x00\x06", "Offset to Paint subtable from beginning of PaintGlyph (6)"),
|
||||
(b"\x00\x0d", "LayerList.Paint[2].Glyph (13)"),
|
||||
(b"\x0c", "LayerList.Paint[2].Paint.Format (12)"),
|
||||
(b"\x00\x00\x07", "Offset to Paint subtable from beginning of PaintTransform (7)"),
|
||||
(b"\x00\x00\x4e", "Offset to Affine2x3 subtable from beginning of PaintTransform (78)"),
|
||||
(b"\x00\x00\x32", "Offset to Affine2x3 subtable from beginning of PaintTransform (50)"),
|
||||
(b"\x07", "LayerList.Paint[2].Paint.Paint.Format (7)"),
|
||||
(b"\x00\x00(", "Offset to ColorLine from beginning of PaintVarRadialGradient (40)"),
|
||||
(b"\x00\x07\xff\xff\xff\xff", "Paint.x0.value (7)"),
|
||||
(b"\x00\x08\xff\xff\xff\xff", "Paint.y0.value (8)"),
|
||||
(b"\x00\t\xff\xff\xff\xff", "Paint.r0.value (9)"),
|
||||
(b"\x00\n\xff\xff\xff\xff", "Paint.x1.value (10)"),
|
||||
(b"\x00\x0b\xff\xff\xff\xff", "Paint.y1.value (11)"),
|
||||
(b"\x00\x0c\xff\xff\xff\xff", "Paint.r1.value (12)"),
|
||||
(b"\x00\x00\x14", "Offset to ColorLine from beginning of PaintVarRadialGradient (20)"),
|
||||
(b"\x00\x07", "Paint.x0.value (7)"),
|
||||
(b"\x00\x08", "Paint.y0.value (8)"),
|
||||
(b"\x00\t", "Paint.r0.value (9)"),
|
||||
(b"\x00\n", "Paint.x1.value (10)"),
|
||||
(b"\x00\x0b", "Paint.y1.value (11)"),
|
||||
(b"\x00\x0c", "Paint.r1.value (12)"),
|
||||
(b"\xff\xff\xff\xff", "VarIndexBase (0xFFFFFFFF)"),
|
||||
(b"\x00", "ColorLine.Extend (0; pad)"),
|
||||
(b"\x00\x02", "ColorLine.StopCount (2)"),
|
||||
(b"\x00\x00\xff\xff\xff\xff", "ColorLine.ColorStop[0].StopOffset.value (0.0)"),
|
||||
(b"\x00\x06", "ColorLine.ColorStop[0].Color.PaletteIndex (6)"),
|
||||
(b"@\x00\xff\xff\xff\xff", "ColorLine.ColorStop[0].Color.Alpha.value (1.0)"),
|
||||
(b"@\x00\xff\xff\xff\xff", "ColorLine.ColorStop[1].StopOffset.value (1.0)"),
|
||||
(b"\x00\x07", "ColorLine.ColorStop[1].Color.PaletteIndex (7)"),
|
||||
(b"\x19\x9a\xff\xff\xff\xff", "ColorLine.ColorStop[1].Color.Alpha.value (0.4)"),
|
||||
(b"\x00\x00", "ColorLine.ColorStop[0].StopOffset.value (0.0)"),
|
||||
(b"\x00\x06", "ColorLine.ColorStop[0].PaletteIndex (6)"),
|
||||
(b"@\x00", "ColorLine.ColorStop[0].Alpha.value (1.0)"),
|
||||
(b"\xff\xff\xff\xff", "VarIndexBase (0xFFFFFFFF)"),
|
||||
(b"@\x00", "ColorLine.ColorStop[1].StopOffset.value (1.0)"),
|
||||
(b"\x00\x07", "ColorLine.ColorStop[1].PaletteIndex (7)"),
|
||||
(b"\x19\x9a", "ColorLine.ColorStop[1].Alpha.value (0.4)"),
|
||||
|
||||
(b"\x00\x00\x00\x07", "VarIndexBase (7)"),
|
||||
(b"\xff\xf3\x00\x00", "Affine2x3.xx (-13)"),
|
||||
(b"\x00\x0e\x00\x00", "Affine2x3.xy (14)"),
|
||||
(b"\x00\x0f\x00\x00", "Affine2x3.yx (15)"),
|
||||
@ -288,8 +293,8 @@ COLR_V1_SAMPLE = (
|
||||
|
||||
# PaintSolid
|
||||
(b"\x02", "LayerList.Paint[0].Paint.Paint.Paint.Paint.Format (2)"),
|
||||
(b"\x00\x02", "Paint.Color.PaletteIndex (2)"),
|
||||
(b" \x00", "Paint.Color.Alpha (0.5)"),
|
||||
(b"\x00\x02", "Paint.PaletteIndex (2)"),
|
||||
(b" \x00", "Paint.Alpha (0.5)"),
|
||||
)
|
||||
|
||||
COLR_V1_DATA = b"".join(t[0] for t in COLR_V1_SAMPLE)
|
||||
@ -346,6 +351,7 @@ COLR_V1_XML = [
|
||||
' <yy value="1.0"/>',
|
||||
' <dx value="300.0"/>',
|
||||
' <dy value="0.0"/>',
|
||||
' <VarIndexBase value="0"/>',
|
||||
" </Transform>",
|
||||
" </BackdropPaint>",
|
||||
" </Paint>",
|
||||
@ -359,17 +365,13 @@ COLR_V1_XML = [
|
||||
" <!-- StopCount=2 -->",
|
||||
' <ColorStop index="0">',
|
||||
' <StopOffset value="0.0"/>',
|
||||
" <Color>",
|
||||
' <PaletteIndex value="3"/>',
|
||||
' <Alpha value="1.0"/>',
|
||||
" </Color>",
|
||||
" </ColorStop>",
|
||||
' <ColorStop index="1">',
|
||||
' <StopOffset value="1.0"/>',
|
||||
" <Color>",
|
||||
' <PaletteIndex value="5"/>',
|
||||
' <Alpha value="1.0"/>',
|
||||
" </Color>",
|
||||
" </ColorStop>",
|
||||
" </ColorLine>",
|
||||
' <centerX value="259"/>',
|
||||
@ -385,10 +387,9 @@ COLR_V1_XML = [
|
||||
" <!-- LayerCount=4 -->",
|
||||
' <Paint index="0" Format="10"><!-- PaintGlyph -->',
|
||||
' <Paint Format="3"><!-- PaintVarSolid -->',
|
||||
" <Color>",
|
||||
' <PaletteIndex value="2"/>',
|
||||
' <Alpha value="0.5"/>',
|
||||
" </Color>",
|
||||
' <VarIndexBase value="6"/>',
|
||||
" </Paint>",
|
||||
' <Glyph value="glyph00011"/>',
|
||||
" </Paint>",
|
||||
@ -399,24 +400,18 @@ COLR_V1_XML = [
|
||||
" <!-- StopCount=3 -->",
|
||||
' <ColorStop index="0">',
|
||||
' <StopOffset value="0.0"/>',
|
||||
" <Color>",
|
||||
' <PaletteIndex value="3"/>',
|
||||
' <Alpha value="1.0"/>',
|
||||
" </Color>",
|
||||
" </ColorStop>",
|
||||
' <ColorStop index="1">',
|
||||
' <StopOffset value="0.5"/>',
|
||||
" <Color>",
|
||||
' <PaletteIndex value="4"/>',
|
||||
' <Alpha value="1.0"/>',
|
||||
" </Color>",
|
||||
" </ColorStop>",
|
||||
' <ColorStop index="2">',
|
||||
' <StopOffset value="1.0"/>',
|
||||
" <Color>",
|
||||
' <PaletteIndex value="5"/>',
|
||||
' <Alpha value="1.0"/>',
|
||||
" </Color>",
|
||||
" </ColorStop>",
|
||||
" </ColorLine>",
|
||||
' <x0 value="1"/>',
|
||||
@ -436,17 +431,15 @@ COLR_V1_XML = [
|
||||
" <!-- StopCount=2 -->",
|
||||
' <ColorStop index="0">',
|
||||
' <StopOffset value="0.0"/>',
|
||||
" <Color>",
|
||||
' <PaletteIndex value="6"/>',
|
||||
' <Alpha value="1.0"/>',
|
||||
" </Color>",
|
||||
" <VarIndexBase/>",
|
||||
" </ColorStop>",
|
||||
' <ColorStop index="1">',
|
||||
' <StopOffset value="1.0"/>',
|
||||
" <Color>",
|
||||
' <PaletteIndex value="7"/>',
|
||||
' <Alpha value="0.4"/>',
|
||||
" </Color>",
|
||||
' <VarIndexBase value="7"/>',
|
||||
" </ColorStop>",
|
||||
" </ColorLine>",
|
||||
' <x0 value="7"/>',
|
||||
@ -455,6 +448,7 @@ COLR_V1_XML = [
|
||||
' <x1 value="10"/>',
|
||||
' <y1 value="11"/>',
|
||||
' <r1 value="12"/>',
|
||||
" <VarIndexBase/>",
|
||||
" </Paint>",
|
||||
" <Transform>",
|
||||
' <xx value="-13.0"/>',
|
||||
@ -472,10 +466,8 @@ COLR_V1_XML = [
|
||||
' <Paint Format="28"><!-- PaintSkew -->',
|
||||
' <Paint Format="10"><!-- PaintGlyph -->',
|
||||
' <Paint Format="2"><!-- PaintSolid -->',
|
||||
" <Color>",
|
||||
' <PaletteIndex value="2"/>',
|
||||
' <Alpha value="0.5"/>',
|
||||
" </Color>",
|
||||
" </Paint>",
|
||||
' <Glyph value="glyph00011"/>',
|
||||
" </Paint>",
|
||||
@ -492,6 +484,52 @@ COLR_V1_XML = [
|
||||
"</LayerList>",
|
||||
]
|
||||
|
||||
COLR_V1_VAR_XML = [
|
||||
'<VarIndexMap Format="0">',
|
||||
' <Map index="0" outer="1" inner="1"/>',
|
||||
' <Map index="1" outer="1" inner="0"/>',
|
||||
' <Map index="2" outer="1" inner="0"/>',
|
||||
' <Map index="3" outer="1" inner="1"/>',
|
||||
' <Map index="4" outer="1" inner="0"/>',
|
||||
' <Map index="5" outer="1" inner="0"/>',
|
||||
' <Map index="6" outer="0" inner="2"/>',
|
||||
' <Map index="7" outer="0" inner="0"/>',
|
||||
' <Map index="8" outer="0" inner="1"/>',
|
||||
"</VarIndexMap>",
|
||||
'<VarStore Format="1">',
|
||||
' <Format value="1"/>',
|
||||
" <VarRegionList>",
|
||||
" <!-- RegionAxisCount=1 -->",
|
||||
" <!-- RegionCount=1 -->",
|
||||
' <Region index="0">',
|
||||
' <VarRegionAxis index="0">',
|
||||
' <StartCoord value="0.0"/>',
|
||||
' <PeakCoord value="1.0"/>',
|
||||
' <EndCoord value="1.0"/>',
|
||||
" </VarRegionAxis>",
|
||||
" </Region>",
|
||||
" </VarRegionList>",
|
||||
" <!-- VarDataCount=2 -->",
|
||||
' <VarData index="0">',
|
||||
" <!-- ItemCount=3 -->",
|
||||
' <NumShorts value="1"/>',
|
||||
" <!-- VarRegionCount=1 -->",
|
||||
' <VarRegionIndex index="0" value="0"/>',
|
||||
' <Item index="0" value="[-3277]"/>',
|
||||
' <Item index="1" value="[6553]"/>',
|
||||
' <Item index="2" value="[8192]"/>',
|
||||
" </VarData>",
|
||||
' <VarData index="1">',
|
||||
" <!-- ItemCount=2 -->",
|
||||
' <NumShorts value="32769"/>',
|
||||
" <!-- VarRegionCount=1 -->",
|
||||
' <VarRegionIndex index="0" value="0"/>',
|
||||
' <Item index="0" value="[0]"/>',
|
||||
' <Item index="1" value="[65536]"/>',
|
||||
" </VarData>",
|
||||
"</VarStore>",
|
||||
]
|
||||
|
||||
|
||||
class COLR_V1_Test(object):
|
||||
def test_decompile_and_compile(self, font):
|
||||
@ -521,3 +559,16 @@ class COLR_V1_Test(object):
|
||||
colr = table_C_O_L_R_()
|
||||
colr.decompile(compiled, font)
|
||||
assert getXML(colr.toXML, font) == COLR_V1_XML
|
||||
|
||||
|
||||
class COLR_V1_Variable_Test(object):
|
||||
def test_round_trip_xml(self, font):
|
||||
colr = table_C_O_L_R_()
|
||||
xml = COLR_V1_XML + COLR_V1_VAR_XML
|
||||
for name, attrs, content in parseXML(xml):
|
||||
colr.fromXML(name, attrs, content, font)
|
||||
compiled = colr.compile(font)
|
||||
|
||||
colr = table_C_O_L_R_()
|
||||
colr.decompile(compiled, font)
|
||||
assert getXML(colr.toXML, font) == xml
|
||||
|
Loading…
x
Reference in New Issue
Block a user