[sfnt] Support variable 'COLR' v1 color lines. * include/freetype/ftcolor.h (FT_ColorStopIterator): Add field `read_variable` to indicate whether a variation index base should be read. * src/sfnt/ttcolr.c: (FT_PaintFormat_Internal): New enumerations `FT_COLR_PAINTFORMAT_INTERNAL_VAR_LINEAR_GRADIENT` `FT_COLR_PAINTFORMAT_INTERNAL_VAR_RADIAL_GRADIENT`, and `FT_COLR_PAINTFORMAT_INTERNAL_VAR_SWEEP_GRADIENT`. (read_color_line): New parameter `read_variable`; update callers. (read_paint): Handle new enumerations.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
diff --git a/include/freetype/ftcolor.h b/include/freetype/ftcolor.h
index 1328568..17f1dd8 100644
--- a/include/freetype/ftcolor.h
+++ b/include/freetype/ftcolor.h
@@ -521,9 +521,10 @@ FT_BEGIN_HEADER
*
* @description:
* This iterator object is needed for @FT_Get_Colorline_Stops. It keeps
- * state while iterating over the stops of an @FT_ColorLine,
- * representing the `ColorLine` struct of the v1 extensions to 'COLR',
- * see 'https://github.com/googlefonts/colr-gradients-spec'.
+ * state while iterating over the stops of an @FT_ColorLine, representing
+ * the `ColorLine` struct of the v1 extensions to 'COLR', see
+ * 'https://github.com/googlefonts/colr-gradients-spec'. Do not manually
+ * modify fields of this iterator.
*
* @fields:
* num_color_stops ::
@@ -537,6 +538,10 @@ FT_BEGIN_HEADER
* An opaque pointer into 'COLR' table data. Set by @FT_Get_Paint.
* Updated by @FT_Get_Colorline_Stops.
*
+ * read_variable ::
+ * A boolean keeping track of whether variable color lines are to be
+ * read. Set by @FT_Get_Paint.
+ *
* @since:
* 2.11 -- **currently experimental only!** There might be changes
* without retaining backward compatibility of both the API and ABI.
@@ -549,6 +554,8 @@ FT_BEGIN_HEADER
FT_Byte* p;
+ FT_Bool read_variable;
+
} FT_ColorStopIterator;
diff --git a/src/sfnt/ttcolr.c b/src/sfnt/ttcolr.c
index f10113e..e8a3d65 100644
--- a/src/sfnt/ttcolr.c
+++ b/src/sfnt/ttcolr.c
@@ -66,6 +66,9 @@
typedef enum FT_PaintFormat_Internal_
{
FT_COLR_PAINTFORMAT_INTERNAL_VAR_SOLID = 3,
+ FT_COLR_PAINTFORMAT_INTERNAL_VAR_LINEAR_GRADIENT = 5,
+ FT_COLR_PAINTFORMAT_INTERNAL_VAR_RADIAL_GRADIENT = 7,
+ FT_COLR_PAINTFORMAT_INTERNAL_VAR_SWEEP_GRADIENT = 9,
FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER = 18,
FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM = 20,
FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM_CENTER = 22,
@@ -477,8 +480,9 @@
static FT_Bool
- read_color_line( FT_Byte* color_line_p,
- FT_ColorLine *colorline )
+ read_color_line( FT_Byte* color_line_p,
+ FT_ColorLine* colorline,
+ FT_Bool read_variable )
{
FT_Byte* p = color_line_p;
FT_PaintExtend paint_extend;
@@ -493,6 +497,7 @@
colorline->color_stop_iterator.num_color_stops = FT_NEXT_USHORT( p );
colorline->color_stop_iterator.p = p;
colorline->color_stop_iterator.current_color_stop = 0;
+ colorline->color_stop_iterator.read_variable = read_variable;
return 1;
}
@@ -604,6 +609,7 @@
{
FT_Byte* paint_base = p;
FT_Byte* child_table_p = NULL;
+ FT_Bool do_read_var = FALSE;
FT_ULong var_index_base = 0;
/* Longest varIndexBase offset is 5 in the spec. */
FT_ItemVarDelta item_deltas[6] = { 0, 0, 0, 0, 0, 0 };
@@ -691,10 +697,14 @@
if ( !get_child_table_pointer( colr, paint_base, &p, &child_table_p ) )
return 0;
- if ( apaint->format == FT_COLR_PAINTFORMAT_LINEAR_GRADIENT )
+ if ( apaint->format == FT_COLR_PAINTFORMAT_LINEAR_GRADIENT ||
+ ( do_read_var =
+ ( (FT_PaintFormat_Internal)apaint->format ==
+ FT_COLR_PAINTFORMAT_INTERNAL_VAR_LINEAR_GRADIENT ) ) )
{
if ( !read_color_line( child_table_p,
- &apaint->u.linear_gradient.colorline ) )
+ &apaint->u.linear_gradient.colorline,
+ do_read_var ) )
return 0;
/*
@@ -708,16 +718,22 @@
apaint->u.linear_gradient.p2.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
apaint->u.linear_gradient.p2.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
+ apaint->format = FT_COLR_PAINTFORMAT_LINEAR_GRADIENT;
+
return 1;
}
- else if ( apaint->format == FT_COLR_PAINTFORMAT_RADIAL_GRADIENT )
+ else if ( apaint->format == FT_COLR_PAINTFORMAT_RADIAL_GRADIENT ||
+ ( do_read_var =
+ ( (FT_PaintFormat_Internal)apaint->format ==
+ FT_COLR_PAINTFORMAT_INTERNAL_VAR_RADIAL_GRADIENT ) ) )
{
FT_Pos tmp;
if ( !read_color_line( child_table_p,
- &apaint->u.radial_gradient.colorline ) )
+ &apaint->u.radial_gradient.colorline,
+ do_read_var ) )
return 0;
/* In the OpenType specification, `r0` and `r1` are defined as */
@@ -737,13 +753,19 @@
tmp = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
apaint->u.radial_gradient.r1 = tmp < 0 ? FT_INT_MAX : tmp;
+ apaint->format = FT_COLR_PAINTFORMAT_RADIAL_GRADIENT;
+
return 1;
}
- else if ( apaint->format == FT_COLR_PAINTFORMAT_SWEEP_GRADIENT )
+ else if ( apaint->format == FT_COLR_PAINTFORMAT_SWEEP_GRADIENT ||
+ ( do_read_var =
+ ( (FT_PaintFormat_Internal)apaint->format ==
+ FT_COLR_PAINTFORMAT_INTERNAL_VAR_SWEEP_GRADIENT ) ) )
{
if ( !read_color_line( child_table_p,
- &apaint->u.sweep_gradient.colorline ) )
+ &apaint->u.sweep_gradient.colorline,
+ do_read_var) )
return 0;
apaint->u.sweep_gradient.center.x =
@@ -756,6 +778,8 @@
apaint->u.sweep_gradient.end_angle =
F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) );
+ apaint->format = FT_COLR_PAINTFORMAT_SWEEP_GRADIENT;
+
return 1;
}
@@ -1228,6 +1252,8 @@
Colr* colr = (Colr*)face->colr;
FT_Byte* p;
+ FT_Long var_index_base;
+ FT_Int item_deltas[2];
if ( !colr || !colr->table )
@@ -1251,6 +1277,28 @@
color_stop->color.alpha = FT_NEXT_SHORT( p );
+ if ( iterator->read_variable )
+ {
+ /* Pointer p needs to be advanced independently of whether we intend */
+ /* to take variable deltas into account or not. Otherwise iteration */
+ /* would fail due to wrong offsets. */
+ var_index_base = FT_NEXT_ULONG( p );
+
+#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+ if ( VARIABLE_COLRV1_ENABLED )
+ {
+ if ( !get_deltas_for_var_index_base( face, colr,
+ var_index_base,
+ 2,
+ item_deltas ) )
+ return 0;
+
+ color_stop->stop_offset += (FT_Fixed)item_deltas[0] << 2;
+ color_stop->color.alpha += item_deltas[1];
+ }
+#endif
+ }
+
iterator->p = p;
iterator->current_color_stop++;