}
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);
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;
{
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);
::qsort (arrayZ, len, sizeof (Type), Type::cmp);
}
- private:
inline bool sanitize_shallow (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
DEFINE_SIZE_ARRAY (8, strikes);
};
+struct sbix_accelerator_t : sbix::accelerator_t {};
+
} /* namespace OT */
#endif /* HB_OT_COLOR_SBIX_TABLE_HH */
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:
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);
{
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:
{
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)
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;
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>
DEFINE_SIZE_STATIC (10);
};
+struct SVG_accelerator_t : SVG::accelerator_t {};
+
} /* namespace OT */
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)
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
{
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);
+}
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
#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"
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. */
// 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"
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); \
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);
}
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);
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);
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
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);
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);