From 1dffbae240133faa5957df751115526ad41f812a Mon Sep 17 00:00:00 2001 From: Cosimo Lupo Date: Tue, 28 Jun 2022 17:36:40 +0100 Subject: [PATCH] =?UTF-8?q?support=20proposed=20PaintSweepGradient's=20ang?= =?UTF-8?q?les=20with=20+1.0=20(180=C2=B0)=20bias?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the upcoming draft of COLR spec, PaintSweepGradient's startAngle/endAngle are encoded with a +1.0 bias to allow for representation of a full +360° positive angle. Normal F2Dot14-fraction-of-half-circle angles can only represent angles between -360 <= angle < +360 This is a breaking change and will need to be coordinated with rendering implementations (at least FreeType/Skia). --- Lib/fontTools/ttLib/tables/otConverters.py | 11 +++++++++-- Lib/fontTools/ttLib/tables/otData.py | 8 ++++---- Tests/ttLib/tables/C_O_L_R_test.py | 4 ++-- Tests/varLib/merger_test.py | 12 ++++++------ 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/Lib/fontTools/ttLib/tables/otConverters.py b/Lib/fontTools/ttLib/tables/otConverters.py index 61125878f..b08f1f191 100644 --- a/Lib/fontTools/ttLib/tables/otConverters.py +++ b/Lib/fontTools/ttLib/tables/otConverters.py @@ -452,13 +452,14 @@ class F2Dot14(BaseFixedValue): class Angle(F2Dot14): # angles are specified in degrees, and encoded as F2Dot14 fractions of half # circle: e.g. 1.0 => 180, -0.5 => -90, -2.0 => -360, etc. + bias = 0.0 factor = 1.0/(1<<14) * 180 # 0.010986328125 @classmethod def fromInt(cls, value): - return super().fromInt(value) * 180 + return (super().fromInt(value) + cls.bias) * 180 @classmethod def toInt(cls, value): - return super().toInt(value / 180) + return super().toInt((value / 180) - cls.bias) @classmethod def fromString(cls, value): # quantize to nearest multiples of minimum fixed-precision angle @@ -467,6 +468,11 @@ class Angle(F2Dot14): def toString(cls, value): return nearestMultipleShortestRepr(value, cls.factor) +class BiasedAngle(Angle): + # A bias of 1.0 is used in the representation of start and end angles + # of COLRv1 PaintSweepGradients to allow for encoding +360deg + bias = 1.0 + class Version(SimpleValue): staticSize = 4 def read(self, reader, font, tableDict): @@ -1773,6 +1779,7 @@ converterMapping = { "Fixed": Fixed, "F2Dot14": F2Dot14, "Angle": Angle, + "BiasedAngle": BiasedAngle, "struct": Struct, "Offset": Table, "LOffset": LTable, diff --git a/Lib/fontTools/ttLib/tables/otData.py b/Lib/fontTools/ttLib/tables/otData.py index 8357ecd2f..2e65869f2 100755 --- a/Lib/fontTools/ttLib/tables/otData.py +++ b/Lib/fontTools/ttLib/tables/otData.py @@ -1755,8 +1755,8 @@ otData = [ ('Offset24', 'ColorLine', None, None, 'Offset (from beginning of PaintSweepGradient table) to ColorLine subtable.'), ('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.'), + ('BiasedAngle', 'startAngle', None, None, 'Start of the angular range of the gradient.'), + ('BiasedAngle', 'endAngle', None, None, 'End of the angular range of the gradient.'), ]), # PaintVarSweepGradient ('PaintFormat9', [ @@ -1764,8 +1764,8 @@ otData = [ ('LOffset24To(VarColorLine)', 'ColorLine', None, None, 'Offset (from beginning of PaintVarSweepGradient table) to VarColorLine subtable.'), ('int16', 'centerX', None, None, 'Center x coordinate. VarIndexBase + 0.'), ('int16', 'centerY', None, None, 'Center y coordinate. VarIndexBase + 1.'), - ('Angle', 'startAngle', None, None, 'Start of the angular range of the gradient. VarIndexBase + 2.'), - ('Angle', 'endAngle', None, None, 'End of the angular range of the gradient. VarIndexBase + 3.'), + ('BiasedAngle', 'startAngle', None, None, 'Start of the angular range of the gradient. VarIndexBase + 2.'), + ('BiasedAngle', 'endAngle', None, None, 'End of the angular range of the gradient. VarIndexBase + 3.'), ('VarIndex', 'VarIndexBase', None, None, 'Base index into DeltaSetIndexMap.'), ]), diff --git a/Tests/ttLib/tables/C_O_L_R_test.py b/Tests/ttLib/tables/C_O_L_R_test.py index 11ddd67f5..132449ea5 100644 --- a/Tests/ttLib/tables/C_O_L_R_test.py +++ b/Tests/ttLib/tables/C_O_L_R_test.py @@ -400,8 +400,8 @@ COLR_V1_XML = [ " ", ' ', ' ', - ' ', - ' ', + ' ', + ' ', " ", ' ', " ", diff --git a/Tests/varLib/merger_test.py b/Tests/varLib/merger_test.py index 8b9970c58..aa7a69984 100644 --- a/Tests/varLib/merger_test.py +++ b/Tests/varLib/merger_test.py @@ -619,8 +619,8 @@ class COLRVariationMergerTest: }, "centerX": 0, "centerY": 0, - "startAngle": -360, - "endAngle": 0, + "startAngle": 0, + "endAngle": 360, }, "Transform": (1.0, 0, 0, 1.0, 0, 0), }, @@ -641,8 +641,8 @@ class COLRVariationMergerTest: }, "centerX": 256, "centerY": 0, - "startAngle": -360, - "endAngle": 0, + "startAngle": 0, + "endAngle": 360, }, # Transform.xx below produces the same VarStore delta as the # above PaintSweepGradient's centerX because, when Fixed16.16 @@ -675,8 +675,8 @@ class COLRVariationMergerTest: " ", ' ', ' ', - ' ', - ' ', + ' ', + ' ', ' ', " ", " ",