HB_OT_headers = \
hb-ot.h \
+ hb-ot-color.h \
hb-ot-font.h \
hb-ot-layout.h \
hb-ot-math.h \
fclose (f);
}
-static void colr_cpal_rendering (cairo_font_face_t *cairo_face, unsigned int upem, unsigned int num_glyphs,
- const OT::COLR *colr, const OT::CPAL *cpal)
+static void colr_cpal_rendering (hb_face_t *face, cairo_font_face_t *cairo_face)
{
- for (unsigned int i = 0; i < num_glyphs; ++i)
+ unsigned int upem = hb_face_get_upem (face);
+
+ for (hb_codepoint_t gid = 0; gid < hb_face_get_glyph_count (face); ++gid)
{
- unsigned int first_layer_index, num_layers;
- if (colr->get_base_glyph_record (i, &first_layer_index, &num_layers))
+ unsigned int num_layers = hb_ot_color_get_color_layers (face, gid, 0, nullptr, nullptr, nullptr);
+ if (!num_layers)
+ continue;
+
+ hb_codepoint_t *layer_gids = (hb_codepoint_t*) calloc (num_layers, sizeof (hb_codepoint_t));
+ unsigned int *color_indices = (unsigned int*) calloc (num_layers, sizeof (unsigned int));
+
+ hb_ot_color_get_color_layers (face, gid, 0, &num_layers, layer_gids, color_indices);
+ if (num_layers)
{
// Measure
cairo_text_extents_t extents;
cairo_glyph_t *glyphs = (cairo_glyph_t *) calloc (num_layers, sizeof (cairo_glyph_t));
for (unsigned int j = 0; j < num_layers; ++j)
- {
- hb_codepoint_t glyph_id;
- unsigned int color_index;
- colr->get_layer_record (first_layer_index + j, &glyph_id, &color_index);
- glyphs[j].index = glyph_id;
- }
+ glyphs[j].index = layer_gids[j];
cairo_glyph_extents (cr, glyphs, num_layers, &extents);
free (glyphs);
cairo_surface_destroy (surface);
extents.y_bearing -= extents.height / 20;
// Render
- unsigned int pallet_count = cpal->get_palette_count ();
+ unsigned int pallet_count = hb_ot_color_get_palette_count (face);
for (unsigned int pallet = 0; pallet < pallet_count; ++pallet) {
char output_path[255];
- // If we have more than one pallet, use a better namin
- if (pallet_count == 1)
- sprintf (output_path, "out/colr-%d.svg", i);
- else
- sprintf (output_path, "out/colr-%d-%d.svg", i, pallet);
-
- cairo_surface_t *surface = cairo_svg_surface_create (output_path, extents.width, extents.height);
- cairo_t *cr = cairo_create (surface);
- cairo_set_font_face (cr, cairo_face);
- cairo_set_font_size (cr, upem);
-
- for (unsigned int j = 0; j < num_layers; ++j)
- {
- hb_codepoint_t glyph_id;
- unsigned int color_index;
- colr->get_layer_record (first_layer_index + j, &glyph_id, &color_index);
-
- uint32_t color = cpal->get_color_record_argb (color_index, pallet);
- int alpha = color & 0xFF;
- int r = (color >> 8) & 0xFF;
- int g = (color >> 16) & 0xFF;
- int b = (color >> 24) & 0xFF;
- cairo_set_source_rgba (cr, r / 255., g / 255., b / 255., alpha);
-
- cairo_glyph_t glyph;
- glyph.index = glyph_id;
- glyph.x = -extents.x_bearing;
- glyph.y = -extents.y_bearing;
- cairo_show_glyphs (cr, &glyph, 1);
- }
-
- cairo_surface_destroy (surface);
- cairo_destroy (cr);
+ unsigned int num_colors = hb_ot_color_get_palette_colors (face, pallet, 0, nullptr, nullptr);
+ if (!num_colors)
+ continue;
+
+ hb_ot_color_t *colors = (hb_ot_color_t*) calloc (num_colors, sizeof (hb_ot_color_t));
+ hb_ot_color_get_palette_colors (face, pallet, 0, &num_colors, colors);
+ if (num_colors)
+ {
+ // If we have more than one pallet, use a better namin
+ if (pallet_count == 1)
+ sprintf (output_path, "out/colr-%d.svg", gid);
+ else
+ sprintf (output_path, "out/colr-%d-%d.svg", gid, pallet);
+
+ cairo_surface_t *surface = cairo_svg_surface_create (output_path, extents.width, extents.height);
+ cairo_t *cr = cairo_create (surface);
+ cairo_set_font_face (cr, cairo_face);
+ cairo_set_font_size (cr, upem);
+
+ for (unsigned int layer = 0; layer < num_layers; ++layer)
+ {
+ uint32_t color = 0xFF;
+ if (color_indices[layer] != 0xFFFF)
+ color = colors[color_indices[layer]];
+ int alpha = color & 0xFF;
+ int r = (color >> 8) & 0xFF;
+ int g = (color >> 16) & 0xFF;
+ int b = (color >> 24) & 0xFF;
+ cairo_set_source_rgba (cr, r / 255., g / 255., b / 255., alpha);
+
+ cairo_glyph_t glyph;
+ glyph.index = layer_gids[layer];
+ glyph.x = -extents.x_bearing;
+ glyph.y = -extents.y_bearing;
+ cairo_show_glyphs (cr, &glyph, 1);
+ }
+
+ cairo_surface_destroy (surface);
+ cairo_destroy (cr);
+ }
+ free (colors);
}
}
+
+ free (layer_gids);
+ free (color_indices);
}
}
font_name_file = fopen ("out/_font_name_file.txt", "w");
if (font_name_file == nullptr)
{
- fprintf (stderr, "./out is not accessible, create it please\n");
+ fprintf (stderr, "./out is not accessible as a folder, create it please\n");
exit (1);
}
fwrite (argv[1], 1, strlen (argv[1]), font_name_file);
svg.dump (svg_callback);
svg.fini ();
- hb_blob_t* colr_blob = hb_sanitize_context_t ().reference_table<OT::COLR> (face);
- const OT::COLR *colr = colr_blob->as<OT::COLR> ();
-
- hb_blob_t* cpal_blob = hb_sanitize_context_t ().reference_table<OT::CPAL> (face);
- const OT::CPAL *cpal = cpal_blob->as<OT::CPAL> ();
-
cairo_font_face_t *cairo_face;
{
FT_Library library;
}
unsigned int num_glyphs = hb_face_get_glyph_count (face);
unsigned int upem = hb_face_get_upem (face);
- colr_cpal_rendering (cairo_face, upem, num_glyphs, colr, cpal);
+ colr_cpal_rendering (face, cairo_face);
dump_glyphs (cairo_face, upem, num_glyphs);
if (unlikely (!record))
return false;
- *first_layer = record->firstLayerIdx;
- *num_layers = record->numLayers;
+ if (first_layer) *first_layer = record->firstLayerIdx;
+ if (num_layers) *num_layers = record->numLayers;
return true;
}
inline bool get_layer_record (unsigned int record,
hb_codepoint_t *glyph_id /* OUT */,
- unsigned int *palette_index /* OUT */) const
+ unsigned int *color_index /* OUT */) const
{
if (unlikely (record >= numLayers))
{
*glyph_id = 0;
- *palette_index = 0xFFFF;
+ *color_index = 0xFFFF;
return false;
}
const LayerRecord &layer = (this+layersZ)[record];
- *glyph_id = layer.glyphid;
- *palette_index = layer.colorIdx;
+ if (glyph_id) *glyph_id = layer.glyphid;
+ if (color_index) *color_index = layer.colorIdx;
return true;
}
#define HB_OT_COLOR_CPAL_TABLE_HH
#include "hb-open-type.hh"
+#include "hb-ot-color.h"
/*
*/
/**
- * hb_ot_color_t:
- * ARGB data type for holding color values.
- *
- * Since: REPLACEME
- */
-typedef uint32_t hb_ot_color_t;
-
-
-/**
* hb_ot_color_palette_flags_t:
* @HB_OT_COLOR_PALETTE_FLAG_DEFAULT: default indicating that there is nothing special to note about a color palette.
* @HB_OT_COLOR_PALETTE_FLAG_FOR_LIGHT_BACKGROUND: flag indicating that the color palette is suitable for rendering text on light background.
HB_OT_COLOR_PALETTE_FLAG_FOR_DARK_BACKGROUND = 0x00000002u,
} hb_ot_color_palette_flags_t;
-// HB_EXTERN unsigned int
-// hb_ot_color_get_palette_count (hb_face_t *face);
-
-// HB_EXTERN unsigned int
-// hb_ot_color_get_palette_name_id (hb_face_t *face, unsigned int palette);
-
-// HB_EXTERN hb_ot_color_palette_flags_t
-// hb_ot_color_get_palette_flags (hb_face_t *face, unsigned int palette);
-
-// HB_EXTERN unsigned int
-// hb_ot_color_get_palette_colors (hb_face_t *face,
-// unsigned int palette, /* default=0 */
-// unsigned int start_offset,
-// unsigned int *color_count /* IN/OUT */,
-// hb_ot_color_t *colors /* OUT */);
-
-
-
-
-
-/*
- * CPAL -- Color Palette
- * https://docs.microsoft.com/en-us/typography/opentype/spec/cpal
- */
-#define HB_OT_TAG_CPAL HB_TAG('C','P','A','L')
-
namespace OT {
return numPalettes;
}
- inline hb_ot_color_t
- get_color_record_argb (unsigned int color_index, unsigned int palette) const
+ inline unsigned int get_palette_entries_count () const
+ {
+ return numPaletteEntries;
+ }
+
+ bool
+ get_color_record_argb (unsigned int color_index, unsigned int palette, hb_ot_color_t* color) const
{
if (unlikely (color_index >= numPaletteEntries || palette >= numPalettes))
- return 0;
+ return false;
// No need for more range check as it is already done on #sanitize
const UnsizedArrayOf<BGRAColor>& color_records = this+colorRecordsZ;
- return color_records[colorRecordIndicesZ[palette] + color_index];
+ if (color)
+ *color = color_records[colorRecordIndicesZ[palette] + color_index];
+ return true;
}
protected:
#include "hb-open-type.hh"
#include "hb-ot-color-colr-table.hh"
#include "hb-ot-color-cpal-table.hh"
+#include "hb-ot-face.hh"
#include "hb-ot.h"
#include <stdlib.h>
#include <string.h>
#include "hb-ot-layout.hh"
-#include "hb-shaper.hh"
#if 0
HB_MARK_AS_FLAG_T (hb_ot_color_palette_flags_t)
//HB_SHAPER_DATA_ENSURE_DECLARE(ot, face) Hmm?
+#endif
static inline const OT::COLR&
_get_colr (hb_face_t *face)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::COLR);
- return *(hb_ot_face_data (face)->colr.get ());
+ return *(hb_ot_face_data (face)->COLR.get ());
}
static inline const OT::CPAL&
_get_cpal (hb_face_t *face)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::CPAL);
- return *(hb_ot_face_data (face)->cpal.get ());
+ return *(hb_ot_face_data (face)->CPAL.get ());
}
+HB_EXTERN hb_bool_t
+hb_ot_color_has_cpal_data (hb_face_t *face)
+{
+ return &_get_cpal (face) != &OT::Null(OT::CPAL);
+}
+
+HB_EXTERN hb_bool_t
+hb_ot_color_has_colr_data (hb_face_t *face)
+{
+ return &_get_colr (face) != &OT::Null(OT::COLR);
+}
/**
* hb_ot_color_get_palette_count:
return cpal.get_palette_count ();
}
-
+#if 0
/**
* hb_ot_color_get_palette_name_id:
* @face: a font face.
const OT::CPAL& cpal = _get_cpal(face);
return cpal.get_palette_flags (palette);
}
+#endif
/**
* @color_count: (inout) (optional): on input, how many colors
* can be maximally stored into the @colors array;
* on output, how many colors were actually stored.
- * @colors: (array length=color_count) (optional):
+ * @colors: (array length=color_count) (out) (optional):
* an array of #hb_ot_color_t records. After calling
* this function, @colors will be filled with
* the palette colors. If @colors is NULL, the function
* Since: REPLACEME
*/
unsigned int
-hb_ot_color_get_palette_colors (hb_face_t *face,
- unsigned int palette, /* default=0 */
- unsigned int start_offset,
- unsigned int *color_count /* IN/OUT */,
- hb_ot_color_t *colors /* OUT */)
+hb_ot_color_get_palette_colors (hb_face_t *face,
+ unsigned int palette, /* default=0 */
+ unsigned int start_offset,
+ unsigned int *count /* IN/OUT */,
+ hb_ot_color_t *colors /* OUT */)
{
const OT::CPAL& cpal = _get_cpal(face);
- if (unlikely (palette >= cpal.numPalettes))
+ if (unlikely (palette >= cpal.get_palette_count ()))
{
- if (color_count) *color_count = 0;
+ if (count) *count = 0;
return 0;
}
- const OT::ColorRecord* crec = &cpal.offsetFirstColorRecord (&cpal);
- crec += cpal.colorRecordIndices[palette];
+ unsigned int num_results = 0;
+ if (count)
+ {
+ unsigned int platte_count = MIN<unsigned int>(*count, cpal.get_palette_entries_count () - start_offset);
+ for (unsigned int i = 0; i < platte_count; i++)
+ {
+ if (cpal.get_color_record_argb(start_offset + i, palette, &colors[num_results]))
+ ++num_results;
+ }
+ }
+ if (likely (count)) *count = num_results;
+ return cpal.get_palette_entries_count ();
+}
+
+unsigned int
+hb_ot_color_get_color_layers (hb_face_t *face,
+ hb_codepoint_t gid,
+ unsigned int start_offset,
+ unsigned int *count, /* IN/OUT. May be NULL. */
+ hb_codepoint_t *gids, /* OUT. May be NULL. */
+ unsigned int *color_indices /* OUT. May be NULL. */)
+{
+ const OT::COLR& colr = _get_colr (face);
unsigned int num_results = 0;
- if (likely (color_count && colors))
+ unsigned int start_layer_index, num_layers = 0;
+ if (colr.get_base_glyph_record (gid, &start_layer_index, &num_layers))
{
- for (unsigned int i = start_offset;
- i < cpal.numPaletteEntries && num_results < *color_count; ++i)
+ if (count)
{
- hb_ot_color_t* result = &colors[num_results];
- result->red = crec[i].red;
- result->green = crec[i].green;
- result->blue = crec[i].blue;
- result->alpha = crec[i].alpha;
- ++num_results;
+ unsigned int layer_count = MIN<unsigned int>(*count, num_layers - start_offset);
+ printf ("%d ", *count);
+ for (unsigned int i = 0; i < layer_count; i++)
+ {
+ if (colr.get_layer_record (start_layer_index + start_offset + i,
+ &gids[num_results], &color_indices[num_results]))
+ ++num_results;
+ }
}
}
- if (likely (color_count)) *color_count = num_results;
- return cpal.numPaletteEntries;
+ if (likely (count)) *count = num_results;
+ return num_layers;
}
-#endif
--- /dev/null
+/*
+ * Copyright © 2016 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Sascha Brawer
+ */
+
+#ifndef HB_OT_H_IN
+#error "Include <hb-ot.h> instead."
+#endif
+
+#ifndef HB_OT_COLOR_H
+#define HB_OT_COLOR_H
+
+#include "hb.h"
+
+HB_BEGIN_DECLS
+
+/*
+ * CPAL -- Color Palette
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/cpal
+ */
+#define HB_OT_TAG_CPAL HB_TAG('C','P','A','L')
+
+/**
+ * hb_ot_color_t:
+ * ARGB data type for holding color values.
+ *
+ * Since: REPLACEME
+ */
+typedef uint32_t hb_ot_color_t;
+
+HB_EXTERN hb_bool_t
+hb_ot_color_has_cpal_data (hb_face_t *face);
+
+HB_EXTERN hb_bool_t
+hb_ot_color_has_colr_data (hb_face_t *face);
+
+HB_EXTERN unsigned int
+hb_ot_color_get_palette_count (hb_face_t *face);
+
+// HB_EXTERN unsigned int
+// hb_ot_color_get_palette_name_id (hb_face_t *face, unsigned int palette);
+
+// HB_EXTERN hb_ot_color_palette_flags_t
+// hb_ot_color_get_palette_flags (hb_face_t *face, unsigned int palette);
+
+HB_EXTERN unsigned int
+hb_ot_color_get_palette_colors (hb_face_t *face,
+ unsigned int palette, /* default=0 */
+ unsigned int start_offset,
+ unsigned int *color_count /* IN/OUT */,
+ hb_ot_color_t *colors /* OUT */);
+
+
+HB_EXTERN unsigned int
+hb_ot_color_get_color_layers (hb_face_t *face,
+ hb_codepoint_t gid,
+ unsigned int offset,
+ unsigned int *count, /* IN/OUT */
+ hb_codepoint_t *gids, /* OUT */
+ unsigned int *color_indices /* OUT */);
+
+HB_END_DECLS
+
+#endif /* HB_OT_COLOR_H */
/* OpenType shaping. */ \
HB_OT_TABLE(OT, JSTF) \
HB_OT_TABLE(OT, BASE) \
+ /* OpenType color */ \
+ HB_OT_TABLE(OT, COLR) \
+ HB_OT_TABLE(OT, CPAL) \
/* AAT shaping. */ \
HB_OT_TABLE(AAT, morx) \
HB_OT_TABLE(AAT, kerx) \
#include "hb.h"
+#include "hb-ot-color.h"
#include "hb-ot-font.h"
#include "hb-ot-layout.h"
#include "hb-ot-math.h"
*/
static hb_face_t *cpal_v1 = NULL;
-
-#if 0
#define assert_color_rgba(colors, i, r, g, b, a) G_STMT_START { \
const hb_ot_color_t *_colors = (colors); \
const size_t _i = (i); \
const uint8_t red = (r), green = (g), blue = (b), alpha = (a); \
- if (_colors[_i].red != red) { \
+ if ((_colors[_i] >> 16 & 0xff) != red) { \
g_assertion_message_cmpnum (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
- "colors[" #i "].red", _colors[_i].red, "==", red, 'x'); \
+ "colors[" #i "]", _colors[_i], "==", red, 'x'); \
} \
- if (_colors[_i].green != green) { \
+ if ((_colors[_i] >> 8 & 0xff) != green) { \
g_assertion_message_cmpnum (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
- "colors[" #i "].green", _colors[_i].green, "==", green, 'x'); \
+ "colors[" #i "]", _colors[_i], "==", green, 'x'); \
} \
- if (_colors[_i].blue != blue) { \
+ if ((_colors[_i] & 0xff) != blue) { \
g_assertion_message_cmpnum (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
- "colors[" #i "].blue", colors[i].blue, "==", blue, 'x'); \
+ "colors[" #i "]", colors[_i], "==", blue, 'x'); \
} \
- if (_colors[_i].alpha != alpha) { \
+ if ((_colors[_i] >> 24 & 0xff) != alpha) { \
g_assertion_message_cmpnum (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
- "colors[" #i "].alpha", _colors[_i].alpha, "==", alpha, 'x'); \
+ "colors[" #i "]", _colors[_i], "==", alpha, 'x'); \
} \
} G_STMT_END
}
+#if 0
static void
test_hb_ot_color_get_palette_name_id_empty (void)
{
/* numPalettes=3, so palette #3 is out of bounds */
g_assert_cmpint (hb_ot_color_get_palette_flags (cpal_v0, 3), ==, HB_OT_COLOR_PALETTE_FLAG_DEFAULT);
}
+#endif
static void
assert_color_rgba (colors, 1, 0x77, 0x77, 0x77, 0x77); /* untouched */
assert_color_rgba (colors, 2, 0x77, 0x77, 0x77, 0x77); /* untouched */
}
+
+static inline hb_face_t *
+open_font (const char *font_path)
+{
+#if GLIB_CHECK_VERSION(2,37,2)
+ char* path = g_test_build_filename(G_TEST_DIST, font_path, NULL);
+#else
+ char* path = g_strdup(font_path);
#endif
+ return hb_face_create (hb_blob_create_from_file (path), 0);
+}
+
int
main (int argc, char **argv)
{
int status = 0;
hb_test_init (&argc, &argv);
- // cpal_v0 = hb_test_load_face ("../shaping/data/in-house/fonts/e90374e5e439e00725b4fe7a8d73db57c5a97f82.ttf");
- // cpal_v1 = hb_test_load_face ("../shaping/data/in-house/fonts/319f5d7ebffbefc5c5e6569f8cea73444d7a7268.ttf");
- // hb_test_add (test_hb_ot_color_get_palette_count);
+ cpal_v0 = open_font ("fonts/cpal-v0.ttf");
+ cpal_v1 = open_font ("fonts/cpal-v1.ttf");
+ hb_test_add (test_hb_ot_color_get_palette_count);
// hb_test_add (test_hb_ot_color_get_palette_name_id_empty);
// hb_test_add (test_hb_ot_color_get_palette_name_id_v0);
// hb_test_add (test_hb_ot_color_get_palette_name_id_v1);
// hb_test_add (test_hb_ot_color_get_palette_flags_empty);
// hb_test_add (test_hb_ot_color_get_palette_flags_v0);
// hb_test_add (test_hb_ot_color_get_palette_flags_v1);
- // hb_test_add (test_hb_ot_color_get_palette_colors_empty);
- // hb_test_add (test_hb_ot_color_get_palette_colors_v0);
- // hb_test_add (test_hb_ot_color_get_palette_colors_v1);
+ hb_test_add (test_hb_ot_color_get_palette_colors_empty);
+ hb_test_add (test_hb_ot_color_get_palette_colors_v0);
+ hb_test_add (test_hb_ot_color_get_palette_colors_v1);
status = hb_test_run();
hb_face_destroy (cpal_v0);
hb_face_destroy (cpal_v1);