[ot-color/png] Implement sbix part

This commit is contained in:
Ebrahim Byagowi 2018-10-26 23:55:11 +03:30
parent 30f18039b3
commit 265ad408ca
7 changed files with 215 additions and 22 deletions

View File

@ -460,9 +460,11 @@ HB_OT_H_IN
<SECTION>
<FILE>hb-ot-color</FILE>
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

View File

@ -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);
}

View File

@ -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;

View File

@ -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<sbix> (face);
sbix_len = hb_blob_get_length (sbix_blob);
sbix_table = sbix_blob->as<sbix> ();
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<hb_vector_t<unsigned int> > data_offsets;
};
protected:

View File

@ -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);
}

View File

@ -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

View File

@ -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);