Repository: fonttools/fonttools

Issue:
[colorLib/ttLib.tables.otTables] Should default for VariableValue.varIdx be 0xFFFFFFFF?
The default varIdx for a VariableValue object is 0.

When building color glyphs with colorLib, when a field in a Var structure is not a tuple but a simple value, this default varIdx is used.

To me it would make more sense for this default to be 0xFFFFFFFF, meaning "no variations". This would be more convenient when constructing variable COLRv1 glyphs. At the moment I have to set 0xFFFFFFFF explicitly in my color glyph Paint dict.

What do you think, @anthrotype and @behdad?

https://github.com/fonttools/fonttools/blob/9c18e2a07d10d61dd377cca285bbd11dc188d1b0/Lib/fontTools/ttLib/tables/otTables.py#L1259-L1264


Discussion:
I think that predates the addition of the non-variable Paint formats. The idea (untested tbh) was that zeros would compress away better than 0xFFFFFFFF when woff2-ing the fonts, and the actual varIdx value is ignored when a COLR table has no VarStore.
But you're right, 0xFFFFFFFF is better as default value now that we do have `PaintVar*` variants.
Should I make a PR?

I'm using these values for fields that have no variations in an otherwise variable PaintVarXxxx, with a non-NULL VarStore, so 0x0 has an actual meaning there.

I assume with the current state of things it makes no sense to have PaintVarXxx tables in a COLRv1 table without a VarStore?
> Should I make a PR?

yes thanks!

> it makes no sense to have PaintVarXxx tables in a COLRv1 table without a VarStore?

no, it doesn't. fwiw nanoemoji only uses the non-var paints currently.
> The idea (untested tbh) was that zeros would compress away better than 0xFFFFFFFF when woff2-ing the fonts, and the actual varIdx value is ignored when a COLR table has no VarStore.

Who decided that?

Resolving patch:
diff --git a/Lib/fontTools/ttLib/tables/otTables.py b/Lib/fontTools/ttLib/tables/otTables.py
--- a/Lib/fontTools/ttLib/tables/otTables.py
+++ b/Lib/fontTools/ttLib/tables/otTables.py
@@ -1261,7 +1261,7 @@ class VariableValue(namedtuple("VariableValue", ["value", "varIdx"])):
 
 	_value_mapper = None
 
-	def __new__(cls, value, varIdx=0):
+	def __new__(cls, value, varIdx=0xFFFFFFFF):
 		return super().__new__(
 			cls,
 			cls._value_mapper(value) if cls._value_mapper else value,


Test patch:
diff --git a/Tests/colorLib/builder_test.py b/Tests/colorLib/builder_test.py
--- a/Tests/colorLib/builder_test.py
+++ b/Tests/colorLib/builder_test.py
@@ -241,7 +241,7 @@ def test_buildVarColorIndex_Minimal():
     c = _build(ot.VarColorIndex, 1)
     assert c.PaletteIndex == 1
     assert c.Alpha.value == 1.0
-    assert c.Alpha.varIdx == 0
+    assert c.Alpha.varIdx == 0xFFFFFFFF
 
 
 def test_buildColorIndex():
diff --git a/Tests/ttLib/tables/C_O_L_R_test.py b/Tests/ttLib/tables/C_O_L_R_test.py
--- a/Tests/ttLib/tables/C_O_L_R_test.py
+++ b/Tests/ttLib/tables/C_O_L_R_test.py
@@ -147,12 +147,12 @@ def test_round_trip_xml(self, font):
     (b"\x00\x00\x08", "Offset to BackdropPaint from beginning of PaintComposite (8)"),
     (b"\x0d", "BaseGlyphV1Record[1].Paint.BackdropPaint.Format (13)"),
     (b"\x00\x00\x34", "Offset to Paint from beginning of PaintVarTransform (52)"),
-    (b"\x00\x01\x00\x00\x00\x00\x00\x00", "Affine2x3.xx.value (1.0)"),
-    (b"\x00\x00\x00\x00\x00\x00\x00\x00", "Affine2x3.xy.value (0.0)"),
-    (b"\x00\x00\x00\x00\x00\x00\x00\x00", "Affine2x3.yx.value (0.0)"),
-    (b"\x00\x01\x00\x00\x00\x00\x00\x00", "Affine2x3.yy.value (1.0)"),
-    (b"\x01\x2c\x00\x00\x00\x00\x00\x00", "Affine2x3.dx.value (300.0)"),
-    (b"\x00\x00\x00\x00\x00\x00\x00\x00", "Affine2x3.dy.value (0.0)"),
+    (b"\x00\x01\x00\x00\xff\xff\xff\xff", "Affine2x3.xx.value (1.0)"),
+    (b"\x00\x00\x00\x00\xff\xff\xff\xff", "Affine2x3.xy.value (0.0)"),
+    (b"\x00\x00\x00\x00\xff\xff\xff\xff", "Affine2x3.yx.value (0.0)"),
+    (b"\x00\x01\x00\x00\xff\xff\xff\xff", "Affine2x3.yy.value (1.0)"),
+    (b"\x01\x2c\x00\x00\xff\xff\xff\xff", "Affine2x3.dx.value (300.0)"),
+    (b"\x00\x00\x00\x00\xff\xff\xff\xff", "Affine2x3.dy.value (0.0)"),
     (b"\x0b", "BaseGlyphV1Record[1].Paint.SourcePaint.Format (11)"),
     (b"\x00\n", "BaseGlyphV1Record[1].Paint.SourcePaint.Glyph (10)"),
     # BaseGlyphV1Record[2]
@@ -199,7 +199,7 @@ def test_round_trip_xml(self, font):
     (b"\x03", "LayerV1List.Paint[0].Paint.Format (3)"),
     (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"\xff\xff\xff\xff", "Paint.Color.Alpha.varIdx (0xFFFFFFFF)"),
     # PaintGlyph glyph00012
     (b"\x0a", "LayerV1List.Paint[1].Format (10)"),
     (b"\x00\x00\x06", "Offset to Paint subtable from beginning of PaintGlyph (6)"),
@@ -237,20 +237,20 @@ def test_round_trip_xml(self, font):
     (b"\x00\x13\x00\x00", "Affine2x3.yy (19)"),
     (b"\x07", "LayerV1List.Paint[2].Paint.Paint.Format (7)"),
     (b"\x00\x00(", "Offset to ColorLine from beginning of PaintVarRadialGradient (40)"),
-    (b"\x00\x07\x00\x00\x00\x00", "Paint.x0.value (7)"),
-    (b"\x00\x08\x00\x00\x00\x00", "Paint.y0.value (8)"),
-    (b"\x00\t\x00\x00\x00\x00", "Paint.r0.value (9)"),
-    (b"\x00\n\x00\x00\x00\x00", "Paint.x1.value (10)"),
-    (b"\x00\x0b\x00\x00\x00\x00", "Paint.y1.value (11)"),
-    (b"\x00\x0c\x00\x00\x00\x00", "Paint.r1.value (12)"),
+    (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", "ColorLine.Extend (0; pad)"),
     (b"\x00\x02", "ColorLine.StopCount (2)"),
-    (b"\x00\x00\x00\x00\x00\x00", "ColorLine.ColorStop[0].StopOffset.value (0.0)"),
+    (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\x00\x00\x00\x00", "ColorLine.ColorStop[0].Color.Alpha.value (1.0)"),
-    (b"@\x00\x00\x00\x00\x00", "ColorLine.ColorStop[1].StopOffset.value (1.0)"),
+    (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\x00\x00\x00\x00", "ColorLine.ColorStop[1].Color.Alpha.value (0.4)"),
+    (b"\x19\x9a\xff\xff\xff\xff", "ColorLine.ColorStop[1].Color.Alpha.value (0.4)"),
     # PaintTranslate
     (b"\x0e", "LayerV1List.Paint[3].Format (14)"),
     (b"\x00\x00\x0c", "Offset to Paint subtable from beginning of PaintTranslate (12)"),