diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt index c385984a7..67f9ae2c4 100644 --- a/docs/harfbuzz-sections.txt +++ b/docs/harfbuzz-sections.txt @@ -460,9 +460,11 @@ HB_OT_H_IN
hb-ot-color hb_ot_color_glyph_get_layers +hb_ot_color_glyph_reference_blob_png hb_ot_color_glyph_reference_blob_svg hb_ot_color_has_layers hb_ot_color_has_palettes +hb_ot_color_has_png hb_ot_color_has_svg hb_ot_color_layer_t hb_ot_color_palette_color_get_name_id diff --git a/src/dump-emoji.cc b/src/dump-emoji.cc index c4710a629..7c7392f20 100644 --- a/src/dump-emoji.cc +++ b/src/dump-emoji.cc @@ -58,12 +58,13 @@ cbdt_callback (const uint8_t* data, unsigned int length, } static void -sbix_callback (const uint8_t* data, unsigned int length, - unsigned int group, unsigned int gid) +sbix_callback (hb_blob_t *blob, unsigned int group, unsigned int gid) { char output_path[255]; sprintf (output_path, "out/sbix-%d-%d.png", group, gid); FILE *f = fopen (output_path, "wb"); + unsigned int length; + const char* data = hb_blob_get_data (blob, &length); fwrite (data, 1, length, f); fclose (f); } diff --git a/src/hb-ot-color-cbdt-table.hh b/src/hb-ot-color-cbdt-table.hh index 1e1fe0956..0f64577d3 100644 --- a/src/hb-ot-color-cbdt-table.hh +++ b/src/hb-ot-color-cbdt-table.hh @@ -376,13 +376,6 @@ struct CBDT { static const hb_tag_t tableTag = HB_OT_TAG_CBDT; - inline bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - likely (version.major == 2 || version.major == 3)); - } - struct accelerator_t { inline void init (hb_face_t *face) @@ -511,6 +504,20 @@ struct CBDT } } + inline hb_blob_t* reference_blob_for_glyph (hb_codepoint_t glyph_id, + unsigned int requested_x_ppem, + unsigned int requested_y_ppem, + unsigned int *strike_x_ppem, + unsigned int *strike_y_ppem) const + { +// if (unlikely (cbdt_len == 0)) + return hb_blob_get_empty (); +// return svg->get_glyph_entry (glyph_id).reference_blob (svg_blob, svg->svgDocEntries); + } + + inline bool has_data () const + { return cbdt_len; } + private: hb_blob_t *cblc_blob; hb_blob_t *cbdt_blob; @@ -521,6 +528,12 @@ struct CBDT unsigned int upem; }; + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + likely (version.major == 2 || version.major == 3)); + } protected: FixedVersion<> version; diff --git a/src/hb-ot-color-sbix-table.hh b/src/hb-ot-color-sbix-table.hh index 1dd0a5c6d..97eac9b58 100644 --- a/src/hb-ot-color-sbix-table.hh +++ b/src/hb-ot-color-sbix-table.hh @@ -62,8 +62,6 @@ struct SBIXGlyph struct SBIXStrike { - friend struct sbix; - inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -71,6 +69,48 @@ struct SBIXStrike imageOffsetsZ.sanitize_shallow (c, c->get_num_glyphs () + 1)); } + inline unsigned int get_ppem () const + { return ppem; } + + inline unsigned int get_resolution () const + { return resolution; } + + inline unsigned int blob_size (unsigned int glyph_id) const + { + return imageOffsetsZ[glyph_id + 1] - imageOffsetsZ[glyph_id] - SBIXGlyph::min_size; + } + + inline hb_blob_t *get_glyph_blob (unsigned int glyph_id, + hb_blob_t *sbix_blob, + unsigned int strike_offset, + unsigned int *x_offset, + unsigned int *y_offset, + hb_tag_t requested_file_type, + unsigned int num_glyphs) const + { + if (imageOffsetsZ[glyph_id + 1] - imageOffsetsZ[glyph_id] == 0) + return hb_blob_get_empty (); + + const SBIXGlyph *glyph = &(this+imageOffsetsZ[glyph_id]); + if (unlikely (glyph->graphicType == HB_TAG ('d','u','p','e') && + blob_size (glyph_id) >= 2)) + { + unsigned int new_glyph_id = *((HBUINT16 *) &glyph->data); + if (new_glyph_id < num_glyphs) + { + glyph = &(this+imageOffsetsZ[new_glyph_id]); + glyph_id = new_glyph_id; + } + } + if (unlikely (requested_file_type != glyph->graphicType)) + return hb_blob_get_empty (); + if (likely (x_offset)) *x_offset = glyph->xOffset; + if (likely (y_offset)) *y_offset = glyph->yOffset; + unsigned int offset = strike_offset + SBIXGlyph::min_size; + offset += imageOffsetsZ[glyph_id]; + return hb_blob_create_sub_blob (sbix_blob, offset, blob_size (glyph_id)); + } + protected: HBUINT16 ppem; /* The PPEM size for which this strike was designed. */ HBUINT16 resolution; /* The device pixel density (in PPI) for which this @@ -99,6 +139,7 @@ struct sbix sbix_blob = hb_sanitize_context_t().reference_table (face); sbix_len = hb_blob_get_length (sbix_blob); sbix_table = sbix_blob->as (); + num_glyphs = face->get_num_glyphs (); } inline void fini (void) @@ -106,29 +147,60 @@ struct sbix hb_blob_destroy (sbix_blob); } - inline void dump (void (*callback) (const uint8_t* data, unsigned int length, + inline void dump (void (*callback) (hb_blob_t *data, unsigned int group, unsigned int gid)) const { - for (unsigned group = 0; group < sbix_table->strikes.len; ++group) + for (unsigned group = 0; group < sbix_table->strikes.len; group++) { - const SBIXStrike &strike = sbix_table->strikes[group](sbix_table); - for (unsigned int glyph = 0; glyph < num_glyphs; ++glyph) - if (strike.imageOffsetsZ[glyph + 1] - strike.imageOffsetsZ[glyph] > 0) - { - const SBIXGlyph &sbixGlyph = strike.imageOffsetsZ[glyph]((const void *) &strike); - callback ((const uint8_t*) &sbixGlyph.data, - strike.imageOffsetsZ[glyph + 1] - strike.imageOffsetsZ[glyph] - 8, - group, glyph); - } + const SBIXStrike &strike = sbix_table+sbix_table->strikes[group]; + for (unsigned int glyph_id = 0; glyph_id < num_glyphs; glyph_id++) + { + unsigned int x_offset, y_offset; + hb_tag_t tag; + hb_blob_t *blob; + blob = strike.get_glyph_blob (glyph_id, sbix_blob, sbix_table->strikes[group], + &x_offset, &x_offset, + HB_TAG('p','n','g',' '), num_glyphs); + if (hb_blob_get_length (blob)) callback (blob, group, glyph_id); + } } } + inline hb_blob_t* reference_blob_for_glyph (hb_codepoint_t glyph_id, + unsigned int ptem HB_UNUSED, + unsigned int requested_ppem, + unsigned int requested_file_type, + unsigned int *available_x_ppem, + unsigned int *available_y_ppem) const + { + if (unlikely (sbix_len == 0 || sbix_table->strikes.len == 0)) + return hb_blob_get_empty (); + + /* TODO: Does spec guarantee strikes are ascended sorted? */ + unsigned int group = sbix_table->strikes.len - 1; + if (requested_ppem != 0) + /* TODO: Use bsearch maybe or doesn't worth it? */ + for (group = 0; group < sbix_table->strikes.len; group++) + if ((sbix_table+sbix_table->strikes[group]).get_ppem () >= requested_ppem) + break; + + const SBIXStrike &strike = sbix_table+sbix_table->strikes[group]; + if (available_x_ppem) *available_x_ppem = strike.get_ppem (); + if (available_y_ppem) *available_y_ppem = strike.get_ppem (); + return strike.get_glyph_blob (glyph_id, sbix_blob, sbix_table->strikes[group], + nullptr, nullptr, requested_file_type, num_glyphs); + } + + inline bool has_data () const + { return sbix_len; } + private: hb_blob_t *sbix_blob; const sbix *sbix_table; unsigned int sbix_len; unsigned int num_glyphs; + hb_vector_t > data_offsets; }; protected: diff --git a/src/hb-ot-color.cc b/src/hb-ot-color.cc index 283b3a1e5..8dd3b2a41 100644 --- a/src/hb-ot-color.cc +++ b/src/hb-ot-color.cc @@ -47,6 +47,13 @@ _get_colr (hb_face_t *face) return *(hb_ot_face_data (face)->COLR.get ()); } +static inline const OT::CBDT_accelerator_t& +_get_cbdt (hb_face_t *face) +{ + if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::CBDT_accelerator_t); + return *(hb_ot_face_data (face)->CBDT.get ()); +} + static inline const OT::CPAL& _get_cpal (hb_face_t *face) { @@ -54,6 +61,13 @@ _get_cpal (hb_face_t *face) return *(hb_ot_face_data (face)->CPAL.get ()); } +static inline const OT::sbix_accelerator_t& +_get_sbix (hb_face_t *face) +{ + if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::sbix_accelerator_t); + return *(hb_ot_face_data (face)->sbix.get ()); +} + static inline const OT::SVG_accelerator_t& _get_svg (hb_face_t *face) { @@ -272,3 +286,53 @@ hb_ot_color_glyph_reference_blob_svg (hb_face_t *face, hb_codepoint_t glyph) { return _get_svg (face).reference_blob_for_glyph (glyph); } + + +/* + * PNG, CBDT or sbix + */ + +/** + * hb_ot_color_has_png: + * @face: a font face. + * + * Returns: whether SVG table is available. + * + * Since: REPLACEME + */ +hb_bool_t +hb_ot_color_has_png (hb_face_t *face) +{ + return _get_cbdt (face).has_data () || _get_sbix (face).has_data (); +} + +/** + * hb_ot_color_glyph_reference_blob_svg: + * @font: + * @glyph: + * @strike_x_ppem: (out): + * @strike_y_ppem: (out): + * + * Returns: + * + * Since: REPLACEME + */ +hb_blob_t * +hb_ot_color_glyph_reference_blob_png (hb_font_t *font, + hb_codepoint_t glyph, + unsigned int *strike_x_ppem /* OUT */, + unsigned int *strike_y_ppem /* OUT */) +{ + /* TODO: if (hb_options ().aat ()) then call sbix first */ + + if (_get_cbdt (font->face).has_data ()) + return _get_cbdt (font->face).reference_blob_for_glyph (glyph, font->x_ppem, font->y_ppem, + strike_x_ppem, strike_y_ppem); + + if (_get_sbix (font->face).has_data ()) + return _get_sbix (font->face).reference_blob_for_glyph (glyph, font->ptem, + MAX (font->x_ppem, font->y_ppem), + HB_TAG('p','n','g',' '), + strike_x_ppem, strike_y_ppem); + +} diff --git a/src/hb-ot-color.h b/src/hb-ot-color.h index fb9a9e370..7901a3598 100644 --- a/src/hb-ot-color.h +++ b/src/hb-ot-color.h @@ -121,6 +121,15 @@ hb_ot_color_has_svg (hb_face_t *face); HB_EXTERN hb_blob_t * hb_ot_color_glyph_reference_blob_svg (hb_face_t *face, hb_codepoint_t glyph); +HB_EXTERN hb_bool_t +hb_ot_color_has_png (hb_face_t *face); + +HB_EXTERN hb_blob_t * +hb_ot_color_glyph_reference_blob_png (hb_font_t *font, + hb_codepoint_t glyph, + unsigned int *strike_x_ppem, + unsigned int *strike_y_ppem); + HB_END_DECLS diff --git a/test/api/test-ot-color.c b/test/api/test-ot-color.c index 4ffadeec0..767a3d61a 100644 --- a/test/api/test-ot-color.c +++ b/test/api/test-ot-color.c @@ -370,6 +370,14 @@ test_hb_ot_color_has_data (void) 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); + + g_assert (hb_ot_color_has_png (empty) == FALSE); + g_assert (hb_ot_color_has_png (cpal_v0) == FALSE); + g_assert (hb_ot_color_has_png (cpal_v1) == FALSE); + g_assert (hb_ot_color_has_png (cpal) == FALSE); + g_assert (hb_ot_color_has_png (cbdt) == TRUE); + g_assert (hb_ot_color_has_png (sbix) == TRUE); + g_assert (hb_ot_color_has_png (svg) == FALSE); } static void @@ -392,6 +400,29 @@ test_hb_ot_color_svg (void) g_assert (hb_blob_get_length (blob) == 0); } + +static void +test_hb_ot_color_png (void) +{ + hb_blob_t *blob; + + hb_font_t *sbix_font; + sbix_font = hb_font_create (sbix); + blob = hb_ot_color_glyph_reference_blob_png (sbix_font, 0, NULL, NULL); + g_assert (hb_blob_get_length (blob) == 0); + + unsigned int strike_x_ppem, strike_y_ppem; + blob = hb_ot_color_glyph_reference_blob_png (sbix_font, 1, + &strike_x_ppem, &strike_y_ppem); + unsigned int length; + const char *data = hb_blob_get_data (blob, &length); + g_assert_cmpuint (length, ==, 224); + g_assert_cmpuint (strike_x_ppem, ==, 300); + g_assert_cmpuint (strike_y_ppem, ==, 300); + g_assert (strncmp (data + 1, "PNG", 3) == 0); + hb_blob_destroy (blob); +} + int main (int argc, char **argv) { @@ -418,6 +449,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_png); hb_test_add (test_hb_ot_color_svg); status = hb_test_run(); hb_face_destroy (cpal_v0);