Commit 54c5ad5c9215feca69614565be7ec2030ee46cfb

Dominik Röttsches 2021-02-10T19:24:13

[sfnt] Implement 'COLR' v1 sweep gradients. * freetype.h (FT_PaintSweepGradient): Add `FT_PaintSweepGradient` to represent a 'COLR' v1 sweep gradient. Update format. (FT_PaintFormat): Update shifted paint formats. Sync with spec. * sfnt/ttcolr.c (read_paint): Logic to parse sweep gradients. Fix struct access in radial gradient implementation.

diff --git a/ChangeLog b/ChangeLog
index d310fac..62400f4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2021-02-10  Dominik Röttsches  <drott@chromium.org>
+
+	[sfnt] Implement 'COLR' v1 sweep gradients.
+
+	* freetype.h (FT_PaintSweepGradient): Add `FT_PaintSweepGradient` to
+	represent a 'COLR' v1 sweep gradient.
+	Update format.
+	(FT_PaintFormat): Update shifted paint formats.
+	Sync with spec.
+	* sfnt/ttcolr.c (read_paint): Logic to parse sweep gradients.
+	Fix struct access in radial gradient implementation.
+
 2021-02-09  Dominik Röttsches  <drott@chromium.org>
 
 	[sfnt] Provide optional root transform for 'COLR' v1 glyph graph.
diff --git a/include/freetype/freetype.h b/include/freetype/freetype.h
index 5d8e8dc..c157796 100644
--- a/include/freetype/freetype.h
+++ b/include/freetype/freetype.h
@@ -4235,14 +4235,15 @@ FT_BEGIN_HEADER
     FT_COLR_PAINTFORMAT_SOLID           = 2,
     FT_COLR_PAINTFORMAT_LINEAR_GRADIENT = 3,
     FT_COLR_PAINTFORMAT_RADIAL_GRADIENT = 4,
-    FT_COLR_PAINTFORMAT_GLYPH           = 5,
-    FT_COLR_PAINTFORMAT_COLR_GLYPH      = 6,
-    FT_COLR_PAINTFORMAT_TRANSFORMED     = 7,
-    FT_COLR_PAINTFORMAT_TRANSLATE       = 8,
-    FT_COLR_PAINTFORMAT_ROTATE          = 9,
-    FT_COLR_PAINTFORMAT_SKEW            = 10,
-    FT_COLR_PAINTFORMAT_COMPOSITE       = 11,
-    FT_COLR_PAINT_FORMAT_MAX            = 12,
+    FT_COLR_PAINTFORMAT_SWEEP_GRADIENT  = 5,
+    FT_COLR_PAINTFORMAT_GLYPH           = 6,
+    FT_COLR_PAINTFORMAT_COLR_GLYPH      = 7,
+    FT_COLR_PAINTFORMAT_TRANSFORMED     = 8,
+    FT_COLR_PAINTFORMAT_TRANSLATE       = 9,
+    FT_COLR_PAINTFORMAT_ROTATE          = 10,
+    FT_COLR_PAINTFORMAT_SKEW            = 11,
+    FT_COLR_PAINTFORMAT_COMPOSITE       = 12,
+    FT_COLR_PAINT_FORMAT_MAX            = 13,
     FT_COLR_PAINTFORMAT_UNSUPPORTED     = 255
 
   } FT_PaintFormat;
@@ -4611,7 +4612,6 @@ FT_BEGIN_HEADER
   {
     FT_ColorLine  colorline;
 
-    /* TODO: Potentially expose those as x0, y0 etc. */
     FT_Vector  c0;
     FT_UShort  r0;
     FT_Vector  c1;
@@ -4623,6 +4623,48 @@ FT_BEGIN_HEADER
   /**************************************************************************
    *
    * @struct:
+   *   FT_PaintSweepGradient
+   *
+   * @description:
+   *   A structure representing a `PaintSweepGradient` value of the 'COLR'
+   *   v1 extensions, see
+   *   'https://github.com/googlefonts/colr-gradients-spec'.  The glyph
+   *   layer filled with this paint is drawn filled with a sweep gradient
+   *   from `start_angle` to `end_angle`.
+   *
+   * @fields:
+   *   colorline ::
+   *     The @FT_ColorLine information for this paint, i.e., the list of
+   *     color stops along the gradient.
+   *
+   *   center ::
+   *     The center of the sweep gradient (in font units).
+   *
+   *   start_angle ::
+   *     The start angle of the sweep gradient, in 16.16 fixed point format
+   *     specifying degrees.  Values are given counter-clockwise, starting
+   *     from the (positive) y~axis.
+   *
+   *   end_angle ::
+   *     The end angle of the sweep gradient, in 16.16 fixed point format
+   *     specifying degrees.  Values are given counter-clockwise, starting
+   *     from the (positive) y~axis.
+   *
+   */
+  typedef struct  FT_PaintSweepGradient_
+  {
+    FT_ColorLine  colorline;
+
+    FT_Vector  center;
+    FT_Fixed   start_angle;
+    FT_Fixed   end_angle;
+
+  } FT_PaintSweepGradient;
+
+
+  /**************************************************************************
+   *
+   * @struct:
    *   FT_PaintGlyph
    *
    * @description:
@@ -4853,6 +4895,7 @@ FT_BEGIN_HEADER
    *       * @FT_PaintSolid
    *       * @FT_PaintLinearGradient
    *       * @FT_PaintRadialGradient
+   *       * @FT_PaintSweepGradient
    *       * @FT_PaintTransformed
    *       * @FT_PaintTranslate
    *       * @FT_PaintRotate
@@ -4871,6 +4914,7 @@ FT_BEGIN_HEADER
       FT_PaintSolid           solid;
       FT_PaintLinearGradient  linear_gradient;
       FT_PaintRadialGradient  radial_gradient;
+      FT_PaintSweepGradient   sweep_gradient;
       FT_PaintTransformed     transformed;
       FT_PaintTranslate       translate;
       FT_PaintRotate          rotate;
diff --git a/src/sfnt/ttcolr.c b/src/sfnt/ttcolr.c
index 6ba3a63..b90e35b 100644
--- a/src/sfnt/ttcolr.c
+++ b/src/sfnt/ttcolr.c
@@ -441,7 +441,7 @@
 
       if ( !read_color_line( paint_base,
                              color_line_offset,
-                             &apaint->u.linear_gradient.colorline ) )
+                             &apaint->u.radial_gradient.colorline ) )
         return 0;
 
       /* skip VarIdx entries */
@@ -462,6 +462,28 @@
       FT_NEXT_ULONG ( p );
     }
 
+    else if ( apaint->format == FT_COLR_PAINTFORMAT_SWEEP_GRADIENT )
+    {
+      FT_ULong  color_line_offset = color_line_offset = FT_NEXT_OFF3( p );
+
+
+      if ( !read_color_line( paint_base,
+                             color_line_offset,
+                             &apaint->u.sweep_gradient.colorline ) )
+        return 0;
+
+      /* skip VarIdx entries */
+      apaint->u.sweep_gradient.center.x = FT_NEXT_SHORT ( p );
+      FT_NEXT_ULONG ( p );
+      apaint->u.sweep_gradient.center.y = FT_NEXT_SHORT ( p );
+      FT_NEXT_ULONG ( p );
+
+      apaint->u.sweep_gradient.start_angle = FT_NEXT_LONG( p );
+      FT_NEXT_ULONG ( p );
+      apaint->u.sweep_gradient.end_angle = FT_NEXT_LONG( p );
+      FT_NEXT_ULONG ( p );
+    }
+
     else if ( apaint->format == FT_COLR_PAINTFORMAT_TRANSFORMED )
     {
       FT_UInt32  paint_offset;
@@ -842,7 +864,7 @@
 
       /* `x_scale` and `y_scale` are in 26.6 format, representing the scale
        * factor to get from font units to requested size.  However, expected
-       * return values are in 16.16, so we shift accordingly with rounding. 
+       * return values are in 16.16, so we shift accordingly with rounding.
        */
       ft_root_scale.xx = ( face->root.size->metrics.x_scale + 32 ) >> 6;
       ft_root_scale.xy = 0;