From c7a4e3dfb5c8dd4f8faf08e327bb1900c0096cf6 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Tue, 23 Oct 2018 18:00:48 +0330 Subject: [PATCH] [svg] Add public API * hb_ot_color_has_svg * hb_ot_color_glyph_svg_create_blob --- src/dump-emoji.cc | 51 ++++++++++++-------- src/hb-open-type.hh | 1 - src/hb-ot-color-sbix-table.hh | 2 + src/hb-ot-color-svg-table.hh | 88 ++++++++++++++++++++++++++--------- src/hb-ot-color.cc | 53 ++++++++++++++++++--- src/hb-ot-color.h | 13 ++++++ src/hb-ot-face.cc | 2 + src/hb-ot-face.hh | 4 +- src/hb-ot-layout.cc | 4 -- test/api/test-ot-color.c | 43 +++++++++++++++-- 10 files changed, 200 insertions(+), 61 deletions(-) diff --git a/src/dump-emoji.cc b/src/dump-emoji.cc index 2f79fc69d..97aab0044 100644 --- a/src/dump-emoji.cc +++ b/src/dump-emoji.cc @@ -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); diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh index 8b7ea0939..8d17f3ed1 100644 --- a/src/hb-open-type.hh +++ b/src/hb-open-type.hh @@ -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); diff --git a/src/hb-ot-color-sbix-table.hh b/src/hb-ot-color-sbix-table.hh index 1b643c77a..1dd0a5c6d 100644 --- a/src/hb-ot-color-sbix-table.hh +++ b/src/hb-ot-color-sbix-table.hh @@ -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 */ diff --git a/src/hb-ot-color-svg-table.hh b/src/hb-ot-color-svg-table.hh index 53d466846..fc5b8662a 100644 --- a/src/hb-ot-color-svg-table.hh +++ b/src/hb-ot-color-svg-table.hh @@ -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, 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 { - const SVGDocumentIndex &index = svg+svg->svgDocIndex; - const ArrayOf &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); - } + 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 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 @@ -137,6 +177,8 @@ struct SVG DEFINE_SIZE_STATIC (10); }; +struct SVG_accelerator_t : SVG::accelerator_t {}; + } /* namespace OT */ diff --git a/src/hb-ot-color.cc b/src/hb-ot-color.cc index 229b6e66f..e2f36ca37 100644 --- a/src/hb-ot-color.cc +++ b/src/hb-ot-color.cc @@ -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); +} diff --git a/src/hb-ot-color.h b/src/hb-ot-color.h index 02b76bffc..8b31b687b 100644 --- a/src/hb-ot-color.h +++ b/src/hb-ot-color.h @@ -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 diff --git a/src/hb-ot-face.cc b/src/hb-ot-face.cc index 1bc68d366..0aba2a691 100644 --- a/src/hb-ot-face.cc +++ b/src/hb-ot-face.cc @@ -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" diff --git a/src/hb-ot-face.hh b/src/hb-ot-face.hh index a45a49361..cce2f1d8f 100644 --- a/src/hb-ot-face.hh +++ b/src/hb-ot-face.hh @@ -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. */ diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index 096fda207..7f3e6c73d 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc @@ -41,10 +41,6 @@ // 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" diff --git a/test/api/test-ot-color.c b/test/api/test-ot-color.c index a514c6aa9..f145a4ce6 100644 --- a/test/api/test-ot-color.c +++ b/test/api/test-ot-color.c @@ -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, "", 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);