[svg] Add public API
authorEbrahim Byagowi <ebrahim@gnu.org>
Tue, 23 Oct 2018 14:30:48 +0000 (18:00 +0330)
committerEbrahim Byagowi <ebrahim@gnu.org>
Fri, 26 Oct 2018 05:46:44 +0000 (09:16 +0330)
* hb_ot_color_has_svg
* hb_ot_color_glyph_svg_create_blob

src/dump-emoji.cc
src/hb-open-type.hh
src/hb-ot-color-sbix-table.hh
src/hb-ot-color-svg-table.hh
src/hb-ot-color.cc
src/hb-ot-color.h
src/hb-ot-face.cc
src/hb-ot-face.hh
src/hb-ot-layout.cc
test/api/test-ot-color.c

index 2f79fc6..97aab00 100644 (file)
@@ -69,26 +69,40 @@ sbix_callback (const uint8_t* data, unsigned int length,
 }
 
 static void
-svg_callback (const uint8_t* data, unsigned int length,
-             unsigned int start_glyph, unsigned int end_glyph)
+svg_dump (hb_face_t *face)
 {
-  char output_path[255];
-  if (start_glyph == end_glyph)
-    sprintf (output_path, "out/svg-%d.svg", start_glyph);
-  else
-    sprintf (output_path, "out/svg-%d-%d.svg", start_glyph, end_glyph);
+  unsigned glyph_count = hb_face_get_glyph_count (face);
 
-  // append "z" if the content is gzipped
-  if ((data[0] == 0x1F) && (data[1] == 0x8B))
-    strcat (output_path, "z");
+  for (unsigned int glyph_id = 0; glyph_id < glyph_count; glyph_id++)
+  {
+    hb_codepoint_t start_glyph_id, end_glyph_id;
+    hb_blob_t *blob = hb_ot_color_glyph_svg_create_blob (face, glyph_id,
+                                                        &start_glyph_id, &end_glyph_id);
 
-  FILE *f = fopen (output_path, "wb");
-  fwrite (data, 1, length, f);
-  fclose (f);
+    if (hb_blob_get_length (blob) == 0) continue;
+
+    char output_path[255];
+    if (start_glyph_id == end_glyph_id)
+      sprintf (output_path, "out/svg-%d.svg", start_glyph_id);
+    else
+      sprintf (output_path, "out/svg-%d-%d.svg", start_glyph_id, end_glyph_id);
+
+    unsigned int length;
+    const char *data = hb_blob_get_data (blob, &length);
+    // append "z" if the content is gzipped, https://stackoverflow.com/a/6059405
+    if (length > 2 && (data[0] == '\x1F') && (data[1] == '\x8B'))
+        strcat (output_path, "z");
+
+    FILE *f = fopen (output_path, "wb");
+    fwrite (data, 1, length, f);
+    fclose (f);
+
+    if (glyph_id < end_glyph_id) glyph_id = end_glyph_id;
+  }
 }
 
 static void
-colr_cpal_rendering (hb_face_t *face, cairo_font_face_t *cairo_face)
+colr_cpal_dump (hb_face_t *face, cairo_font_face_t *cairo_face)
 {
   unsigned int upem = hb_face_get_upem (face);
 
@@ -268,10 +282,8 @@ main (int argc, char **argv)
   sbix.dump (sbix_callback);
   sbix.fini ();
 
-  OT::SVG::accelerator_t svg;
-  svg.init (face);
-  svg.dump (svg_callback);
-  svg.fini ();
+  if (hb_ot_color_has_svg (face))
+    svg_dump (face);
 
   cairo_font_face_t *cairo_face;
   {
@@ -281,7 +293,8 @@ main (int argc, char **argv)
     FT_New_Face (library, argv[1], 0, &ftface);
     cairo_face = cairo_ft_font_face_create_for_ft_face (ftface, 0);
   }
-  colr_cpal_rendering (face, cairo_face);
+  if (hb_ot_color_has_layers (face) && hb_ot_color_has_palettes (face))
+    colr_cpal_dump (face, cairo_face);
 
   unsigned int num_glyphs = hb_face_get_glyph_count (face);
   unsigned int upem = hb_face_get_upem (face);
index 8b7ea09..8d17f3e 100644 (file)
@@ -523,7 +523,6 @@ struct ArrayOf
     ::qsort (arrayZ, len, sizeof (Type), Type::cmp);
   }
 
-  private:
   inline bool sanitize_shallow (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
index 1b643c7..1dd0a5c 100644 (file)
@@ -142,6 +142,8 @@ struct sbix
   DEFINE_SIZE_ARRAY (8, strikes);
 };
 
+struct sbix_accelerator_t : sbix::accelerator_t {};
+
 } /* namespace OT */
 
 #endif /* HB_OT_COLOR_SBIX_TABLE_HH */
index 53d4668..fc5b866 100644 (file)
@@ -41,12 +41,22 @@ namespace OT {
 struct SVGDocumentIndexEntry
 {
   friend struct SVG;
+  friend struct SVGDocumentIndex;
 
-  inline bool sanitize (hb_sanitize_context_t *c, const void* base) const
+  inline int cmp (hb_codepoint_t g) const
+  { return g < startGlyphID ? -1 : g > endGlyphID ? 1 : 0; }
+
+  static int cmp (const void *pa, const void *pb)
+  {
+    const hb_codepoint_t *a = (const hb_codepoint_t *) pa;
+    const SVGDocumentIndexEntry *b = (const SVGDocumentIndexEntry *) pb;
+    return b->cmp (*a);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-                 (base+svgDoc).sanitize (c, svgDocLength));
+    return_trace (c->check_struct (this));
   }
 
   protected:
@@ -57,7 +67,7 @@ struct SVGDocumentIndexEntry
   LOffsetTo<UnsizedArrayOf<HBUINT8>, false>
                svgDoc;         /* Offset from the beginning of the SVG Document Index
                                 * to an SVG document. Must be non-zero. */
-  HBUINT32 svgDocLength;       /* Length of the SVG document.
+  HBUINT32     svgDocLength;   /* Length of the SVG document.
                                 * Must be non-zero. */
   public:
   DEFINE_SIZE_STATIC (12);
@@ -67,11 +77,22 @@ struct SVGDocumentIndex
 {
   friend struct SVG;
 
+  inline const SVGDocumentIndexEntry &get_glyph_entry (hb_codepoint_t glyph_id) const
+  {
+    const SVGDocumentIndexEntry *rec;
+    rec = (SVGDocumentIndexEntry *) bsearch (&glyph_id,
+                                            &entries.arrayZ,
+                                            entries.len,
+                                            sizeof (SVGDocumentIndexEntry),
+                                            SVGDocumentIndexEntry::cmp);
+    return likely (rec && glyph_id <= rec->endGlyphID) ? *rec : Null(SVGDocumentIndexEntry);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
-                 entries.sanitize (c, this));
+                 entries.sanitize_shallow (c));
   }
 
   protected:
@@ -85,13 +106,6 @@ struct SVG
 {
   static const hb_tag_t tableTag = HB_OT_TAG_SVG;
 
-  inline bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this) &&
-                         (this+svgDocIndex).sanitize (c)));
-  }
-
   struct accelerator_t
   {
     inline void init (hb_face_t *face)
@@ -106,20 +120,39 @@ struct SVG
       hb_blob_destroy (svg_blob);
     }
 
-    inline void
-    dump (void (*callback) (const uint8_t* data, unsigned int length,
-                           unsigned int start_glyph, unsigned int end_glyph)) const
+    inline hb_blob_t*
+    failed_create_blob (hb_codepoint_t  glyph_id,
+                       hb_codepoint_t *start_glyph_id,
+                       hb_codepoint_t *end_glyph_id) const
     {
+      if (start_glyph_id) *start_glyph_id = 0;
+      if (end_glyph_id) *end_glyph_id = 0;
+      return hb_blob_get_empty ();
+    }
+
+    inline hb_blob_t*
+    create_blob (hb_codepoint_t  glyph_id,
+                hb_codepoint_t *start_glyph_id,
+                hb_codepoint_t *end_glyph_id) const
+    {
+      if (unlikely (svg_len == 0))
+        return failed_create_blob (glyph_id, start_glyph_id, end_glyph_id);
       const SVGDocumentIndex &index = svg+svg->svgDocIndex;
-      const ArrayOf<SVGDocumentIndexEntry> &entries = index.entries;
-      for (unsigned int i = 0; i < entries.len; ++i)
-      {
-       const SVGDocumentIndexEntry &entry = entries[i];
-       callback ((const uint8_t*) &entry.svgDoc (&index), entry.svgDocLength,
-                                                 entry.startGlyphID, entry.endGlyphID);
-      }
+      const SVGDocumentIndexEntry &entry = index.get_glyph_entry (glyph_id);
+      if (unlikely (entry.svgDocLength == 0))
+        return failed_create_blob (glyph_id, start_glyph_id, end_glyph_id);
+      unsigned int blob_offset = entry.svgDoc;
+      blob_offset += svg->svgDocIndex;
+      if (unlikely (blob_offset > svg_len || blob_offset + entry.svgDocLength > svg_len))
+        return failed_create_blob (glyph_id, start_glyph_id, end_glyph_id);
+      if (start_glyph_id) *start_glyph_id = entry.startGlyphID;
+      if (end_glyph_id) *end_glyph_id = entry.endGlyphID;
+      return hb_blob_create_sub_blob (svg_blob, blob_offset, entry.svgDocLength);
     }
 
+    inline bool has_data () const
+    { return svg_len; }
+
     private:
     hb_blob_t *svg_blob;
     const SVG *svg;
@@ -127,6 +160,13 @@ struct SVG
     unsigned int svg_len;
   };
 
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this) &&
+                         (this+svgDocIndex).sanitize (c)));
+  }
+
   protected:
   HBUINT16     version;        /* Table version (starting at 0). */
   LOffsetTo<SVGDocumentIndex>
@@ -137,6 +177,8 @@ struct SVG
   DEFINE_SIZE_STATIC (10);
 };
 
+struct SVG_accelerator_t : SVG::accelerator_t {};
+
 } /* namespace OT */
 
 
index 229b6e6..e2f36ca 100644 (file)
@@ -54,6 +54,13 @@ _get_cpal (hb_face_t *face)
   return *(hb_ot_face_data (face)->CPAL.get ());
 }
 
+static inline const OT::SVG_accelerator_t&
+_get_svg (hb_face_t *face)
+{
+  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::SVG_accelerator_t);
+  return *(hb_ot_face_data (face)->SVG.get ());
+}
+
 #if 0
 static inline const OT::CBDT_accelerator_t&
 _get_cbdt (hb_face_t *face)
@@ -68,13 +75,6 @@ _get_sbix (hb_face_t *face)
   if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::sbix);
   return *(hb_ot_face_data (face)->sbix.get ());
 }
-
-static inline const OT::SVG&
-_get_svg (hb_face_t *face)
-{
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::SVG);
-  return *(hb_ot_face_data (face)->SVG.get ());
-}
 #endif
 
 
@@ -238,3 +238,42 @@ hb_ot_color_glyph_get_layers (hb_face_t           *face,
 {
   return _get_colr (face).get_glyph_layers (glyph, start_offset, count, layers);
 }
+
+
+/*
+ * SVG
+ */
+
+/**
+ * hb_ot_color_has_svg:
+ * @face: a font face.
+ *
+ * Returns: whether SVG table is available.
+ *
+ * Since: REPLACEME
+ */
+hb_bool_t
+hb_ot_color_has_svg (hb_face_t *face)
+{
+  return _get_svg (face).has_data ();
+}
+
+/**
+ * hb_ot_color_glyph_svg_create_blob:
+ * @face:
+ * @glyph:
+ * @start_glyph: (out) (optional): Start of range this SVG supports
+ * @end_glyph:   (out) (optional): End of range this SVG supports
+ *
+ * Returns:
+ *
+ * Since: REPLACEME
+ */
+hb_blob_t *
+hb_ot_color_glyph_svg_create_blob (hb_face_t      *face,
+                                  hb_codepoint_t  glyph,
+                                  hb_codepoint_t *start_glyph, /* OUT.  May be NULL. */
+                                  hb_codepoint_t *end_glyph    /* OUT.  May be NULL. */)
+{
+  return _get_svg (face).create_blob (glyph, start_glyph, end_glyph);
+}
index 02b76bf..8b31b68 100644 (file)
@@ -111,6 +111,19 @@ hb_ot_color_glyph_get_layers (hb_face_t           *face,
                              unsigned int        *count, /* IN/OUT.  May be NULL. */
                              hb_ot_color_layer_t *layers /* OUT.     May be NULL. */);
 
+/*
+ * SVG
+ */
+
+HB_EXTERN hb_bool_t
+hb_ot_color_has_svg (hb_face_t *face);
+
+HB_EXTERN hb_blob_t *
+hb_ot_color_glyph_svg_create_blob (hb_face_t      *face,
+                                  hb_codepoint_t  glyph,
+                                  hb_codepoint_t *start_glyph, /* OUT.  May be NULL. */
+                                  hb_codepoint_t *end_glyph    /* OUT.  May be NULL. */);
+
 
 HB_END_DECLS
 
index 1bc68d3..0aba2a6 100644 (file)
@@ -32,6 +32,8 @@
 #include "hb-ot-kern-table.hh"
 #include "hb-ot-post-table.hh"
 #include "hb-ot-color-cbdt-table.hh"
+#include "hb-ot-color-sbix-table.hh"
+#include "hb-ot-color-svg-table.hh"
 #include "hb-ot-layout-gdef-table.hh"
 #include "hb-ot-layout-gsub-table.hh"
 #include "hb-ot-layout-gpos-table.hh"
index a45a493..cce2f1d 100644 (file)
@@ -73,8 +73,8 @@
     HB_OT_TABLE(OT, COLR) \
     HB_OT_TABLE(OT, CPAL) \
     HB_OT_ACCELERATOR(OT, CBDT) \
-    HB_OT_TABLE(OT, sbix) \
-    HB_OT_TABLE(OT, SVG) \
+    HB_OT_ACCELERATOR(OT, sbix) \
+    HB_OT_ACCELERATOR(OT, SVG) \
     /* */
 
 /* Declare tables. */
index 096fda2..7f3e6c7 100644 (file)
 // Just so we compile them; unused otherwise:
 #include "hb-ot-layout-base-table.hh"
 #include "hb-ot-layout-jstf-table.hh"
-#include "hb-ot-color-colr-table.hh"
-#include "hb-ot-color-cpal-table.hh"
-#include "hb-ot-color-sbix-table.hh"
-#include "hb-ot-color-svg-table.hh"
 #include "hb-ot-kern-table.hh"
 #include "hb-ot-name-table.hh"
 
index a514c6a..f145a4c 100644 (file)
@@ -103,6 +103,7 @@ static hb_face_t *cpal = NULL;
 static hb_face_t *cbdt = NULL;
 static hb_face_t *sbix = NULL;
 static hb_face_t *svg = NULL;
+static hb_face_t *empty = NULL;
 
 #define assert_color_rgba(colors, i, r, g, b, a) G_STMT_START {        \
   const hb_color_t *_colors = (colors); \
@@ -203,7 +204,6 @@ test_hb_ot_color_palette_get_flags_v1 (void)
 static void
 test_hb_ot_color_palette_get_colors_empty (void)
 {
-  hb_face_t *empty = hb_face_get_empty ();
   g_assert_cmpint (hb_ot_color_palette_get_colors (empty, 0, 0, NULL, NULL), ==, 0);
 }
 
@@ -302,8 +302,6 @@ test_hb_ot_color_palette_get_colors_v1 (void)
 static void
 test_hb_ot_color_palette_color_get_name_id (void)
 {
-  hb_face_t *empty = hb_face_get_empty ();
-
   g_assert_cmpuint (hb_ot_color_palette_color_get_name_id (empty, 0), ==, HB_NAME_ID_INVALID);
   g_assert_cmpuint (hb_ot_color_palette_color_get_name_id (empty, 1), ==, HB_NAME_ID_INVALID);
   g_assert_cmpuint (hb_ot_color_palette_color_get_name_id (empty, 2), ==, HB_NAME_ID_INVALID);
@@ -349,8 +347,6 @@ test_hb_ot_color_glyph_get_layers (void)
 static void
 test_hb_ot_color_has_data (void)
 {
-  hb_face_t *empty = hb_face_get_empty ();
-
   g_assert (hb_ot_color_has_layers (empty) == FALSE);
   g_assert (hb_ot_color_has_layers (cpal_v0) == TRUE);
   g_assert (hb_ot_color_has_layers (cpal_v1) == TRUE);
@@ -366,6 +362,41 @@ test_hb_ot_color_has_data (void)
   g_assert (hb_ot_color_has_palettes (cbdt) == FALSE);
   g_assert (hb_ot_color_has_palettes (sbix) == FALSE);
   g_assert (hb_ot_color_has_palettes (svg) == FALSE);
+
+  g_assert (hb_ot_color_has_svg (empty) == FALSE);
+  g_assert (hb_ot_color_has_svg (cpal_v0) == FALSE);
+  g_assert (hb_ot_color_has_svg (cpal_v1) == FALSE);
+  g_assert (hb_ot_color_has_svg (cpal) == FALSE);
+  g_assert (hb_ot_color_has_svg (cbdt) == FALSE);
+  g_assert (hb_ot_color_has_svg (sbix) == FALSE);
+  g_assert (hb_ot_color_has_svg (svg) == TRUE);
+}
+
+static void
+test_hb_ot_color_svg (void)
+{
+  hb_codepoint_t start_glyph, end_glyph;
+  hb_blob_t *blob;
+
+  blob = hb_ot_color_glyph_svg_create_blob (svg, 0, &start_glyph, &end_glyph);
+  g_assert (hb_blob_get_length (blob) == 0);
+  g_assert (start_glyph == 0);
+  g_assert (end_glyph == 0);
+
+  blob = hb_ot_color_glyph_svg_create_blob (svg, 1, &start_glyph, &end_glyph);
+  unsigned int length;
+  const char *data = hb_blob_get_data (blob, &length);
+  g_assert_cmpuint (length, ==, 146);
+  g_assert_cmpuint (start_glyph, ==, 1);
+  g_assert_cmpuint (end_glyph, ==, 1);
+  g_assert (strncmp (data, "<?xml", 4) == 0);
+  g_assert (strncmp (data + 140, "</svg>", 5) == 0);
+  hb_blob_destroy (blob);
+
+  blob = hb_ot_color_glyph_svg_create_blob (empty, 0, &start_glyph, &end_glyph);
+  g_assert (hb_blob_get_length (blob) == 0);
+  g_assert (start_glyph == 0);
+  g_assert (end_glyph == 0);
 }
 
 int
@@ -380,6 +411,7 @@ main (int argc, char **argv)
   cbdt = hb_test_open_font_file ("fonts/chromacheck-cbdt.ttf");
   sbix = hb_test_open_font_file ("fonts/chromacheck-sbix.ttf");
   svg = hb_test_open_font_file ("fonts/chromacheck-svg.ttf");
+  empty = hb_face_get_empty ();
   hb_test_add (test_hb_ot_color_palette_get_count);
   hb_test_add (test_hb_ot_color_palette_get_name_id_empty);
   hb_test_add (test_hb_ot_color_palette_get_name_id_v0);
@@ -393,6 +425,7 @@ main (int argc, char **argv)
   hb_test_add (test_hb_ot_color_palette_color_get_name_id);
   hb_test_add (test_hb_ot_color_glyph_get_layers);
   hb_test_add (test_hb_ot_color_has_data);
+  hb_test_add (test_hb_ot_color_svg);
   status = hb_test_run();
   hb_face_destroy (cpal_v0);
   hb_face_destroy (cpal_v1);