Commit f9d05eb32695dfcbc5c7ae747c0c794e64cc55b8

Werner Lemberg 2018-06-14T21:02:49

Provide iterative API to access `COLR' data. This solution doesn't store any data in an `FT_GlyphSlot' object. * include/freetype/freetype.h (FT_LayerIterator): New structure. (FT_Get_Color_Glyph_Layer): New function. * include/freetype/internal/sfnt.h (TT_Get_Colr_Layer_Func): New function type. (SFNT_Interface, FT_DEFINE_SFNT_INTERFACE): Add it. * src/base/ftobjs.c (FT_Get_Color_Glyph_Layer): Implement it. * src/sfnt/ttcolr.c (tt_face_get_colr_layer): New function. * src/sfnt/ttcolr.h: Updated. * src/sfnt/sfdriver.c (sfnt_interface): Updated.

diff --git a/ChangeLog b/ChangeLog
index b1bec04..5df7fa5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,25 @@
 2018-06-14  Werner Lemberg  <wl@gnu.org>
 
+	Provide iterative API to access `COLR' data.
+
+	This solution doesn't store any data in an `FT_GlyphSlot' object.
+
+	* include/freetype/freetype.h (FT_LayerIterator): New structure.
+	(FT_Get_Color_Glyph_Layer): New function.
+
+	* include/freetype/internal/sfnt.h (TT_Get_Colr_Layer_Func): New
+	function type.
+	(SFNT_Interface, FT_DEFINE_SFNT_INTERFACE): Add it.
+
+	* src/base/ftobjs.c (FT_Get_Color_Glyph_Layer): Implement it.
+
+	* src/sfnt/ttcolr.c (tt_face_get_colr_layer): New function.
+	* src/sfnt/ttcolr.h: Updated.
+
+	* src/sfnt/sfdriver.c (sfnt_interface): Updated.
+
+2018-06-14  Werner Lemberg  <wl@gnu.org>
+
 	Add glyph index and glyph load flags to glyph slot.
 
 	* include/freetype/freetype.h (FT_GlyphSlotRec): Rename unused
diff --git a/include/freetype/freetype.h b/include/freetype/freetype.h
index 35e6ed6..02abd8a 100644
--- a/include/freetype/freetype.h
+++ b/include/freetype/freetype.h
@@ -3101,7 +3101,7 @@ FT_BEGIN_HEADER
    *     blending of the color glyph layers associated with the glyph index,
    *     using the same bitmap format as embedded color bitmap images.  This
    *     is mainly for convenience; for full control of color layers use
-   *     @FT_Get_GlyphLayers and FreeType's color functions like
+   *     @FT_Get_Color_Glyph_Layer and FreeType's color functions like
    *     @FT_Palette_Select instead of setting FT_LOAD_COLOR for rendering
    *     so that the client application can handle blending by itself.
    *
@@ -4264,6 +4264,101 @@ FT_BEGIN_HEADER
                       FT_Glyph_Layer  *alayers );
 
 
+  /**********************************************************************
+   *
+   * @struct:
+   *   FT_LayerIterator
+   *
+   * @description:
+   *   This iterator object is needed for @FT_Get_Color_Glyph_Layer.
+   *
+   * @fields:
+   *   num_layers ::
+   *     The number of glyph layers for the requested glyph index.  Will be
+   *     set by @FT_Get_Color_Glyph_Layer.
+   *
+   *   layer ::
+   *     The current layer.  Will be set by @FT_Get_Color_Glyph_Layer.
+   *
+   *   p ::
+   *     An opaque pointer into `COLR' table data.  The caller must set this
+   *     to NULL before the first call of @FT_Get_Color_Glyph_Layer.
+   */
+  typedef struct  FT_LayerIterator_
+  {
+    FT_UInt   num_layers;
+    FT_UInt   layer;
+    FT_Byte*  p;
+
+  } FT_LayerIterator;
+
+
+  /*************************************************************************
+   *
+   * @func:
+   *   FT_Get_Color_Glyph_Layer
+   *
+   * @description:
+   *   This is an interface to the `COLR' table in OpenType fonts to
+   *   iteratively retrieve the colored glyph layers associated with the
+   *   current glyph slot.
+   *
+   *     https://docs.microsoft.com/en-us/typography/opentype/spec/colr
+   *
+   *   The glyph layer data for a given glyph index, if present, provides an
+   *   alternative, multi-colour glyph representation: Instead of rendering
+   *   the outline or bitmap with the given glyph index, glyphs with the
+   *   indices and colors returned by this function are rendered layer by
+   *   layer.
+   *
+   *   The returned elements are ordered in the z~direction from bottom to
+   *   top; the `n'th element should be rendered with the associated palette
+   *   color and blended on top of the already rendered layers (elements 0,
+   *   1, ..., n-1).
+   *
+   * @input:
+   *   face ::
+   *     A handle to the parent face object.
+   *
+   *   base_glyph ::
+   *     The glyph index the colored glyph layers are associated with.
+   *
+   * @inout:
+   *   iterator ::
+   *     An @FT_LayerIterator object.  For the first call you should set
+   *     `iterator->p' to NULL.  For all following calls, simply use the
+   *     same object again.
+   *
+   * @output:
+   *   acolor_index ::
+   *     The color index into the font face's color palette of the current
+   *     layer.  The value 0xFFFF is special; it doesn't reference a palette
+   *     entry but indicates that the text foreground color should be used
+   *     instead (to be set up by the application outside of FreeType).
+   *
+   *     The color palette can be retrieved with @FT_Palette_Select.
+   *
+   * @return:
+   *     The glyph index of the current layer.  If there are no more layers
+   *     (or if there are no layers at all), value~0 gets returned.  In case
+   *     of an error, value~0 is returned also.
+   *
+   * @note:
+   *   This function is necessary if you want to handle glyph layers by
+   *   yourself.  In particular, functions that operate with @FT_GlyphRec
+   *   objects (like @FT_Get_Glyph or @FT_Glyph_To_Bitmap) don't have access
+   *   to this information.
+   *
+   *   @FT_Render_Glyph, however, handles colored glyph layers
+   *   automatically if the @FT_LOAD_COLOR flag is passed to it.
+   */
+  FT_EXPORT( FT_UInt )
+  FT_Get_Color_Glyph_Layer( FT_Face            face,
+                            FT_UInt            base_glyph,
+                            FT_UInt           *acolor_index,
+                            FT_LayerIterator*  iterator );
+
+
   /**************************************************************************
    *
    * @Enum:
diff --git a/include/freetype/internal/sfnt.h b/include/freetype/internal/sfnt.h
index 731c7fe..2093c28 100644
--- a/include/freetype/internal/sfnt.h
+++ b/include/freetype/internal/sfnt.h
@@ -529,6 +529,46 @@ FT_BEGIN_HEADER
   /**************************************************************************
    *
    * @FuncType:
+   *   TT_Get_Colr_Layer_Func
+   *
+   * @Description:
+   *   Iteratively get the color layer data of a given glyph index.
+   *
+   * @Input:
+   *   face ::
+   *     The target face object.
+   *
+   *   base_glyph ::
+   *     The glyph index the colored glyph layers are associated with.
+   *
+   * @inout:
+   *   iterator ::
+   *     An @FT_LayerIterator object.  For the first call you should set
+   *     `iterator->p' to NULL.  For all following calls, simply use the
+   *     same object again.
+   *
+   * @output:
+   *   acolor_index ::
+   *     The color index into the font face's color palette of the current
+   *     layer.  The value 0xFFFF is special; it doesn't reference a palette
+   *     entry but indicates that the text foreground color should be used
+   *     instead (to be set up by the application outside of FreeType).
+   *
+   * @return:
+   *   The glyph index of the current layer.  If there are no more layers
+   *   (or if there are no layers at all), value~0 gets returned.  In case
+   *   of an error, value~0 is returned also.
+   */
+  typedef FT_UInt
+  (*TT_Get_Colr_Layer_Func)( TT_Face            face,
+                             FT_UInt            base_glyph,
+                             FT_UInt           *acolor_index,
+                             FT_LayerIterator*  iterator );
+
+
+  /**************************************************************************
+   *
+   * @FuncType:
    *   TT_Blend_Colr_Func
    *
    * @Description:
@@ -769,6 +809,7 @@ FT_BEGIN_HEADER
     TT_Free_Table_Func           free_colr;
     TT_Set_Palette_Func          set_palette;
     TT_Load_Colr_Layer_Func      load_colr_layer;
+    TT_Get_Colr_Layer_Func       get_colr_layer;
     TT_Blend_Colr_Func           colr_blend;
 
     TT_Get_Metrics_Func          get_metrics;
@@ -819,6 +860,7 @@ FT_BEGIN_HEADER
           free_colr_,                    \
           set_palette_,                  \
           load_colr_layer_,              \
+          get_colr_layer_,               \
           colr_blend_,                   \
           get_metrics_,                  \
           get_name_,                     \
@@ -859,6 +901,7 @@ FT_BEGIN_HEADER
     free_colr_,                          \
     set_palette_,                        \
     load_colr_layer_,                    \
+    get_colr_layer_,                     \
     colr_blend_,                         \
     get_metrics_,                        \
     get_name_,                           \
diff --git a/src/base/ftobjs.c b/src/base/ftobjs.c
index bd3c039..29a1c11 100644
--- a/src/base/ftobjs.c
+++ b/src/base/ftobjs.c
@@ -5490,4 +5490,35 @@
   }
 
 
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_UInt )
+  FT_Get_Color_Glyph_Layer( FT_Face            face,
+                            FT_UInt            base_glyph,
+                            FT_UInt           *acolor_index,
+                            FT_LayerIterator*  iterator )
+  {
+    TT_Face       ttface;
+    SFNT_Service  sfnt;
+
+
+    if ( !face                                   ||
+         !acolor_index                           ||
+         !iterator                               ||
+         base_glyph >= (FT_UInt)face->num_glyphs )
+      return 0;
+
+    if ( !FT_IS_SFNT( face ) )
+      return 0;
+
+    ttface = (TT_Face)face;
+    sfnt   = (SFNT_Service)ttface->sfnt;
+
+    return sfnt->get_colr_layer( ttface,
+                                 base_glyph,
+                                 acolor_index,
+                                 iterator );
+  }
+
+
 /* END */
diff --git a/src/sfnt/sfdriver.c b/src/sfnt/sfdriver.c
index 0c3ddc8..e1f4818 100644
--- a/src/sfnt/sfdriver.c
+++ b/src/sfnt/sfdriver.c
@@ -1270,6 +1270,8 @@
                             /* TT_Set_Palette_Func     set_palette     */
     PUT_COLOR_LAYERS( tt_face_load_colr_layers ),
                             /* TT_Load_Colr_Layer_Func load_colr_layer */
+    PUT_COLOR_LAYERS( tt_face_get_colr_layer ),
+                            /* TT_Get_Colr_Layer_Func  get_colr_layer  */
     PUT_COLOR_LAYERS( tt_face_colr_blend_layer ),
                             /* TT_Blend_Colr_Func      colr_blend      */
 
diff --git a/src/sfnt/ttcolr.c b/src/sfnt/ttcolr.c
index 66592b6..323f0ca 100644
--- a/src/sfnt/ttcolr.c
+++ b/src/sfnt/ttcolr.c
@@ -275,6 +275,54 @@
   }
 
 
+  FT_LOCAL_DEF( FT_UInt )
+  tt_face_get_colr_layer( TT_Face            face,
+                          FT_UInt            base_glyph,
+                          FT_UInt           *acolor_index,
+                          FT_LayerIterator*  iterator )
+  {
+    Colr*            colr   = (Colr*)face->colr;
+    BaseGlyphRecord  glyph_record;
+    FT_UInt          glyph_index;
+
+
+    if ( !iterator->p )
+    {
+      /* first call to function */
+      iterator->layer = 0;
+
+      if ( !find_base_glyph_record( colr->base_glyphs,
+                                    colr->num_base_glyphs,
+                                    base_glyph,
+                                    &glyph_record ) )
+        return 0;
+
+      iterator->p = colr->layers +
+                      LAYER_SIZE * glyph_record.first_layer_index;
+
+      if ( glyph_record.num_layers )
+        iterator->num_layers = glyph_record.num_layers;
+      else
+        return 0;
+    }
+
+    if ( iterator->layer >= iterator->num_layers )
+      return 0;
+
+    glyph_index   = FT_NEXT_USHORT( iterator->p );
+    *acolor_index = FT_NEXT_USHORT( iterator->p );
+
+    if ( glyph_index >= FT_FACE( face )->num_glyphs                  ||
+         ( *acolor_index != 0xFFFF                                 &&
+           *acolor_index >= face->palette_data.num_palette_entries ) )
+      return 0;
+
+    iterator->layer++;
+
+    return glyph_index;
+  }
+
+
   FT_LOCAL_DEF( FT_Error )
   tt_face_colr_blend_layer( TT_Face       face,
                             FT_UInt       color_index,
diff --git a/src/sfnt/ttcolr.h b/src/sfnt/ttcolr.h
index a548755..480fd67 100644
--- a/src/sfnt/ttcolr.h
+++ b/src/sfnt/ttcolr.h
@@ -42,6 +42,12 @@ FT_BEGIN_HEADER
                             FT_Glyph_Layer  *ret_layers,
                             FT_UShort*       ret_num_layers );
 
+  FT_LOCAL( FT_UInt )
+  tt_face_get_colr_layer( TT_Face            face,
+                          FT_UInt            base_glyph,
+                          FT_UInt           *acolor_index,
+                          FT_LayerIterator*  iterator );
+
   FT_LOCAL( FT_Error )
   tt_face_colr_blend_layer( TT_Face       face,
                             FT_UInt       color_index,