diff --git a/docs/harfbuzz-docs.xml b/docs/harfbuzz-docs.xml
index 2d2827a66..b685bfd3a 100644
--- a/docs/harfbuzz-docs.xml
+++ b/docs/harfbuzz-docs.xml
@@ -57,6 +57,7 @@
+
diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt
index a35d3aa39..e4f89d264 100644
--- a/docs/harfbuzz-sections.txt
+++ b/docs/harfbuzz-sections.txt
@@ -191,8 +191,11 @@ HB_DEPRECATED_FOR
hb-draw
hb_draw_funcs_create
+hb_draw_funcs_get_empty
hb_draw_funcs_reference
hb_draw_funcs_destroy
+hb_draw_funcs_set_user_data
+hb_draw_funcs_get_user_data
hb_draw_funcs_make_immutable
hb_draw_funcs_is_immutable
hb_draw_move_to_func_t
@@ -215,6 +218,55 @@ hb_draw_funcs_t
hb_draw_state_t
+
+hb-paint
+hb_paint_funcs_t
+hb_paint_funcs_create
+hb_paint_funcs_get_empty
+hb_paint_funcs_reference
+hb_paint_funcs_destroy
+hb_paint_funcs_set_user_data
+hb_paint_funcs_get_user_data
+hb_paint_funcs_make_immutable
+hb_paint_funcs_is_immutable
+
+hb_paint_push_transform_func_t
+hb_paint_funcs_set_push_transform_func
+hb_paint_pop_transform_func_t
+hb_paint_funcs_set_pop_transform_func
+hb_paint_push_clip_glyph_func_t
+hb_paint_funcs_set_push_clip_glyph_func
+hb_paint_push_clip_rectangle_func_t
+hb_paint_funcs_set_push_clip_rectangle_func
+hb_paint_pop_clip_func_t
+hb_paint_funcs_set_pop_clip_func
+hb_paint_color_func_t
+hb_paint_funcs_set_color_func
+HB_PAINT_IMAGE_FORMAT_PNG
+HB_PAINT_IMAGE_FORMAT_SVG
+HB_PAINT_IMAGE_FORMAT_BGRA
+hb_paint_image_func_t
+hb_paint_funcs_set_image_func
+hb_color_line_t
+hb_color_stop_t
+hb_color_line_get_color_stops_func_t
+hb_color_line_get_color_stops
+hb_paint_extend_t
+hb_color_line_get_extend_func_t
+hb_color_line_get_extend
+hb_paint_linear_gradient_func_t
+hb_paint_funcs_set_linear_gradient_func
+hb_paint_radial_gradient_func_t
+hb_paint_funcs_set_radial_gradient_func
+hb_paint_sweep_gradient_func_t
+hb_paint_funcs_set_sweep_gradient_func
+hb_paint_composite_mode_t
+hb_paint_push_group_func_t
+hb_paint_funcs_set_push_group_func
+hb_paint_pop_group_func_t
+hb_paint_funcs_set_pop_group_func
+
+
hb-deprecated
HB_BUFFER_FLAGS_DEFAULT
@@ -324,6 +376,8 @@ hb_font_get_glyph_v_origin
hb_font_get_glyph_origin_for_direction
hb_font_get_glyph_name
hb_font_get_glyph_shape
+hb_font_draw_glyph
+hb_font_paint_glyph
hb_font_get_nominal_glyph
hb_font_get_nominal_glyphs
hb_font_get_variation_glyph
@@ -386,6 +440,10 @@ hb_font_get_glyph_name_func_t
hb_font_funcs_set_glyph_name_func
hb_font_get_glyph_shape_func_t
hb_font_funcs_set_glyph_shape_func
+hb_font_draw_glyph_func_t
+hb_font_funcs_set_draw_glyph_func
+hb_font_paint_glyph_func_t
+hb_font_funcs_set_paint_glyph_func
hb_font_get_nominal_glyph_func_t
hb_font_funcs_set_nominal_glyph_func
hb_font_get_nominal_glyphs_func_t
@@ -485,6 +543,7 @@ hb_ot_color_glyph_get_layers
hb_ot_color_glyph_reference_png
hb_ot_color_glyph_reference_svg
hb_ot_color_has_layers
+hb_ot_color_has_paint
hb_ot_color_has_palettes
hb_ot_color_has_png
hb_ot_color_has_svg
diff --git a/perf/benchmark-font.cc b/perf/benchmark-font.cc
index 98b6310d2..4688d6923 100644
--- a/perf/benchmark-font.cc
+++ b/perf/benchmark-font.cc
@@ -163,7 +163,7 @@ static void BM_Font (benchmark::State &state,
hb_draw_funcs_t *draw_funcs = _draw_funcs_create ();
for (auto _ : state)
for (unsigned gid = 0; gid < num_glyphs; ++gid)
- hb_font_get_glyph_shape (font, gid, draw_funcs, nullptr);
+ hb_font_draw_glyph (font, gid, draw_funcs, nullptr);
break;
hb_draw_funcs_destroy (draw_funcs);
}
diff --git a/src/Makefile.sources b/src/Makefile.sources
index 6c4fc5de7..d49e6a716 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -69,6 +69,7 @@ HB_BASE_sources = \
hb-ot-cmap-table.hh \
hb-ot-color-cbdt-table.hh \
hb-ot-color-colr-table.hh \
+ hb-ot-color-colr-table.cc \
hb-ot-color-cpal-table.hh \
hb-ot-color-sbix-table.hh \
hb-ot-color-svg-table.hh \
@@ -88,6 +89,9 @@ HB_BASE_sources = \
hb-ot-layout-common.hh \
hb-ot-layout-gdef-table.hh \
hb-ot-layout-gpos-table.hh \
+ hb-paint.cc \
+ hb-paint.hh \
+ hb-paint-extents.hh \
hb-ot-layout-gsub-table.hh \
OT/glyf/glyf.hh \
OT/glyf/glyf-helpers.hh \
@@ -290,6 +294,7 @@ HB_BASE_headers = \
hb-ot-shape.h \
hb-ot-var.h \
hb-ot.h \
+ hb-paint.h \
hb-set.h \
hb-shape-plan.h \
hb-shape.h \
@@ -301,7 +306,7 @@ HB_BASE_headers = \
# Optional Sources and Headers with external deps
-HB_FT_sources = hb-ft.cc
+HB_FT_sources = hb-ft.cc hb-ft-colr.hh
HB_FT_headers = hb-ft.h
HB_GLIB_sources = hb-glib.cc
diff --git a/src/OT/glyf/glyf.hh b/src/OT/glyf/glyf.hh
index e0c92f0c9..58af9ead5 100644
--- a/src/OT/glyf/glyf.hh
+++ b/src/OT/glyf/glyf.hh
@@ -7,6 +7,7 @@
#include "../../hb-ot-hmtx-table.hh"
#include "../../hb-ot-var-gvar-table.hh"
#include "../../hb-draw.hh"
+#include "../../hb-paint.hh"
#include "glyf-helpers.hh"
#include "Glyph.hh"
@@ -332,6 +333,15 @@ struct glyf_accelerator_t
return glyph_for_gid (gid).get_extents_without_var_scaled (font, *this, extents);
}
+ bool paint_glyph (hb_font_t *font, hb_codepoint_t gid, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const
+ {
+ funcs->push_clip_glyph (data, gid, font);
+ funcs->color (data, true, foreground);
+ funcs->pop_clip (data);
+
+ return true;
+ }
+
const glyf_impl::Glyph
glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const
{
diff --git a/src/harfbuzz-subset.cc b/src/harfbuzz-subset.cc
index a43485e6f..c5c66747a 100644
--- a/src/harfbuzz-subset.cc
+++ b/src/harfbuzz-subset.cc
@@ -14,6 +14,7 @@
#include "hb-number.cc"
#include "hb-ot-cff1-table.cc"
#include "hb-ot-cff2-table.cc"
+#include "hb-ot-color-colr-table.cc"
#include "hb-ot-color.cc"
#include "hb-ot-face.cc"
#include "hb-ot-font.cc"
@@ -40,6 +41,7 @@
#include "hb-ot-shaper-vowel-constraints.cc"
#include "hb-ot-tag.cc"
#include "hb-ot-var.cc"
+#include "hb-paint.cc"
#include "hb-set.cc"
#include "hb-shape-plan.cc"
#include "hb-shape.cc"
diff --git a/src/harfbuzz.cc b/src/harfbuzz.cc
index fe4e21db0..03196eaa6 100644
--- a/src/harfbuzz.cc
+++ b/src/harfbuzz.cc
@@ -19,6 +19,7 @@
#include "hb-number.cc"
#include "hb-ot-cff1-table.cc"
#include "hb-ot-cff2-table.cc"
+#include "hb-ot-color-colr-table.cc"
#include "hb-ot-color.cc"
#include "hb-ot-face.cc"
#include "hb-ot-font.cc"
@@ -45,6 +46,7 @@
#include "hb-ot-shaper-vowel-constraints.cc"
#include "hb-ot-tag.cc"
#include "hb-ot-var.cc"
+#include "hb-paint.cc"
#include "hb-set.cc"
#include "hb-shape-plan.cc"
#include "hb-shape.cc"
diff --git a/src/hb-common.h b/src/hb-common.h
index e92feb989..a5da4e76a 100644
--- a/src/hb-common.h
+++ b/src/hb-common.h
@@ -897,6 +897,32 @@ HB_EXTERN uint8_t
hb_color_get_blue (hb_color_t color);
#define hb_color_get_blue(color) (((color) >> 24) & 0xFF)
+/**
+ * hb_glyph_extents_t:
+ * @x_bearing: Distance from the x-origin to the left extremum of the glyph.
+ * @y_bearing: Distance from the top extremum of the glyph to the y-origin.
+ * @width: Distance from the left extremum of the glyph to the right extremum.
+ * @height: Distance from the top extremum of the glyph to the bottom extremum.
+ *
+ * Glyph extent values, measured in font units.
+ *
+ * Note that @height is negative, in coordinate systems that grow up.
+ **/
+typedef struct hb_glyph_extents_t {
+ hb_position_t x_bearing;
+ hb_position_t y_bearing;
+ hb_position_t width;
+ hb_position_t height;
+} hb_glyph_extents_t;
+
+/**
+ * hb_font_t:
+ *
+ * Data type for holding fonts.
+ *
+ */
+typedef struct hb_font_t hb_font_t;
+
HB_END_DECLS
#endif /* HB_COMMON_H */
diff --git a/src/hb-config.hh b/src/hb-config.hh
index 98b1e9d0c..22ae1613d 100644
--- a/src/hb-config.hh
+++ b/src/hb-config.hh
@@ -64,6 +64,7 @@
#define HB_NO_CFF
#define HB_NO_COLOR
#define HB_NO_DRAW
+#define HB_NO_PAINT
#define HB_NO_ERRNO
#define HB_NO_FACE_COLLECT_UNICODES
#define HB_NO_GETENV
diff --git a/src/hb-cplusplus.hh b/src/hb-cplusplus.hh
index a210ab796..531ef1b7c 100644
--- a/src/hb-cplusplus.hh
+++ b/src/hb-cplusplus.hh
@@ -160,6 +160,8 @@ HB_DEFINE_VTABLE (map);
HB_DEFINE_VTABLE (set);
HB_DEFINE_VTABLE (shape_plan);
HB_DEFINE_VTABLE (unicode_funcs);
+HB_DEFINE_VTABLE (draw_funcs);
+HB_DEFINE_VTABLE (paint_funcs);
#undef HB_DEFINE_VTABLE
diff --git a/src/hb-draw.cc b/src/hb-draw.cc
index 9d75c6537..9877dd41b 100644
--- a/src/hb-draw.cc
+++ b/src/hb-draw.cc
@@ -35,6 +35,8 @@
* @include: hb.h
*
* Functions for drawing (extracting) glyph shapes.
+ *
+ * The #hb_draw_funcs_t struct can be used with hb_font_draw_glyph().
**/
static void
@@ -198,6 +200,20 @@ DEFINE_NULL_INSTANCE (hb_draw_funcs_t) =
}
};
+/**
+ * hb_draw_funcs_get_empty:
+ *
+ * Fetches the singleton empty draw-functions structure.
+ *
+ * Return value: (transfer full): The empty draw-functions structure
+ *
+ * Since: REPLACEME
+ **/
+hb_draw_funcs_t *
+hb_draw_funcs_get_empty ()
+{
+ return const_cast (&Null (hb_draw_funcs_t));
+}
/**
* hb_draw_funcs_reference: (skip)
@@ -248,6 +264,49 @@ hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs)
hb_free (dfuncs);
}
+/**
+ * hb_draw_funcs_set_user_data: (skip)
+ * @dfuncs: The draw-functions structure
+ * @key: The user-data key
+ * @data: A pointer to the user data
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
+ * @replace: Whether to replace an existing data with the same key
+ *
+ * Attaches a user-data key/data pair to the specified draw-functions structure.
+ *
+ * Return value: `true` if success, `false` otherwise
+ *
+ * Since: REPLACEME
+ **/
+hb_bool_t
+hb_draw_funcs_set_user_data (hb_draw_funcs_t *dfuncs,
+ hb_user_data_key_t *key,
+ void * data,
+ hb_destroy_func_t destroy,
+ hb_bool_t replace)
+{
+ return hb_object_set_user_data (dfuncs, key, data, destroy, replace);
+}
+
+/**
+ * hb_draw_funcs_get_user_data: (skip)
+ * @dfuncs: The draw-functions structure
+ * @key: The user-data key to query
+ *
+ * Fetches the user-data associated with the specified key,
+ * attached to the specified draw-functions structure.
+ *
+ * Return value: (transfer none): A pointer to the user data
+ *
+ * Since: REPLACEME
+ **/
+void *
+hb_draw_funcs_get_user_data (const hb_draw_funcs_t *dfuncs,
+ hb_user_data_key_t *key)
+{
+ return hb_object_get_user_data (dfuncs, key);
+}
+
/**
* hb_draw_funcs_make_immutable:
* @dfuncs: draw functions
diff --git a/src/hb-draw.h b/src/hb-draw.h
index 9bcdd9947..9ca0b4006 100644
--- a/src/hb-draw.h
+++ b/src/hb-draw.h
@@ -92,7 +92,7 @@ typedef struct hb_draw_funcs_t hb_draw_funcs_t;
/**
* hb_draw_move_to_func_t:
* @dfuncs: draw functions object
- * @draw_data: The data accompanying the draw functions in hb_font_get_glyph_shape()
+ * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph()
* @st: current draw state
* @to_x: X component of target point
* @to_y: Y component of target point
@@ -112,7 +112,7 @@ typedef void (*hb_draw_move_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data
/**
* hb_draw_line_to_func_t:
* @dfuncs: draw functions object
- * @draw_data: The data accompanying the draw functions in hb_font_get_glyph_shape()
+ * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph()
* @st: current draw state
* @to_x: X component of target point
* @to_y: Y component of target point
@@ -132,7 +132,7 @@ typedef void (*hb_draw_line_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data
/**
* hb_draw_quadratic_to_func_t:
* @dfuncs: draw functions object
- * @draw_data: The data accompanying the draw functions in hb_font_get_glyph_shape()
+ * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph()
* @st: current draw state
* @control_x: X component of control point
* @control_y: Y component of control point
@@ -155,7 +155,7 @@ typedef void (*hb_draw_quadratic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw
/**
* hb_draw_cubic_to_func_t:
* @dfuncs: draw functions object
- * @draw_data: The data accompanying the draw functions in hb_font_get_glyph_shape()
+ * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph()
* @st: current draw state
* @control1_x: X component of first control point
* @control1_y: Y component of first control point
@@ -181,7 +181,7 @@ typedef void (*hb_draw_cubic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_dat
/**
* hb_draw_close_path_func_t:
* @dfuncs: draw functions object
- * @draw_data: The data accompanying the draw functions in hb_font_get_glyph_shape()
+ * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph()
* @st: current draw state
* @user_data: User data pointer passed to hb_draw_funcs_set_close_path_func()
*
@@ -279,12 +279,27 @@ hb_draw_funcs_set_close_path_func (hb_draw_funcs_t *dfuncs,
HB_EXTERN hb_draw_funcs_t *
hb_draw_funcs_create (void);
+HB_EXTERN hb_draw_funcs_t *
+hb_draw_funcs_get_empty (void);
+
HB_EXTERN hb_draw_funcs_t *
hb_draw_funcs_reference (hb_draw_funcs_t *dfuncs);
HB_EXTERN void
hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs);
+HB_EXTERN hb_bool_t
+hb_draw_funcs_set_user_data (hb_draw_funcs_t *dfuncs,
+ hb_user_data_key_t *key,
+ void * data,
+ hb_destroy_func_t destroy,
+ hb_bool_t replace);
+
+
+HB_EXTERN void *
+hb_draw_funcs_get_user_data (const hb_draw_funcs_t *dfuncs,
+ hb_user_data_key_t *key);
+
HB_EXTERN void
hb_draw_funcs_make_immutable (hb_draw_funcs_t *dfuncs);
diff --git a/src/hb-font.cc b/src/hb-font.cc
index 0ce3e2608..28d3a4b2c 100644
--- a/src/hb-font.cc
+++ b/src/hb-font.cc
@@ -30,6 +30,7 @@
#include "hb-font.hh"
#include "hb-draw.hh"
+#include "hb-paint.hh"
#include "hb-machinery.hh"
#include "hb-ot.h"
@@ -503,23 +504,34 @@ hb_font_get_glyph_from_name_default (hb_font_t *font,
}
static void
-hb_font_get_glyph_shape_nil (hb_font_t *font HB_UNUSED,
- void *font_data HB_UNUSED,
- hb_codepoint_t glyph,
- hb_draw_funcs_t *draw_funcs,
- void *draw_data,
- void *user_data HB_UNUSED)
+hb_font_draw_glyph_nil (hb_font_t *font HB_UNUSED,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t glyph,
+ hb_draw_funcs_t *draw_funcs,
+ void *draw_data,
+ void *user_data HB_UNUSED)
{
}
+static void
+hb_font_paint_glyph_nil (hb_font_t *font HB_UNUSED,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t glyph HB_UNUSED,
+ hb_paint_funcs_t *paint_funcs HB_UNUSED,
+ void *paint_data HB_UNUSED,
+ unsigned int palette HB_UNUSED,
+ hb_color_t foreground HB_UNUSED,
+ void *user_data HB_UNUSED)
+{
+}
-typedef struct hb_font_get_glyph_shape_default_adaptor_t {
+typedef struct hb_font_draw_glyph_default_adaptor_t {
hb_draw_funcs_t *draw_funcs;
void *draw_data;
float x_scale;
float y_scale;
float slant;
-} hb_font_get_glyph_shape_default_adaptor_t;
+} hb_font_draw_glyph_default_adaptor_t;
static void
hb_draw_move_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED,
@@ -528,7 +540,7 @@ hb_draw_move_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED,
float to_x, float to_y,
void *user_data HB_UNUSED)
{
- hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
+ hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data;
float x_scale = adaptor->x_scale;
float y_scale = adaptor->y_scale;
float slant = adaptor->slant;
@@ -543,7 +555,7 @@ hb_draw_line_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data,
float to_x, float to_y,
void *user_data HB_UNUSED)
{
- hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
+ hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data;
float x_scale = adaptor->x_scale;
float y_scale = adaptor->y_scale;
float slant = adaptor->slant;
@@ -562,7 +574,7 @@ hb_draw_quadratic_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data
float to_x, float to_y,
void *user_data HB_UNUSED)
{
- hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
+ hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data;
float x_scale = adaptor->x_scale;
float y_scale = adaptor->y_scale;
float slant = adaptor->slant;
@@ -583,7 +595,7 @@ hb_draw_cubic_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data,
float to_x, float to_y,
void *user_data HB_UNUSED)
{
- hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
+ hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data;
float x_scale = adaptor->x_scale;
float y_scale = adaptor->y_scale;
float slant = adaptor->slant;
@@ -602,7 +614,7 @@ hb_draw_close_path_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data,
hb_draw_state_t *st,
void *user_data HB_UNUSED)
{
- hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data;
+ hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data;
adaptor->draw_funcs->emit_close_path (adaptor->draw_data, *st);
}
@@ -618,14 +630,14 @@ static const hb_draw_funcs_t _hb_draw_funcs_default = {
};
static void
-hb_font_get_glyph_shape_default (hb_font_t *font,
+hb_font_draw_glyph_default (hb_font_t *font,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_draw_funcs_t *draw_funcs,
void *draw_data,
void *user_data HB_UNUSED)
{
- hb_font_get_glyph_shape_default_adaptor_t adaptor = {
+ hb_font_draw_glyph_default_adaptor_t adaptor = {
draw_funcs,
draw_data,
font->parent->x_scale ? (float) font->x_scale / (float) font->parent->x_scale : 0.f,
@@ -634,11 +646,34 @@ hb_font_get_glyph_shape_default (hb_font_t *font,
(float) font->x_scale / (float) font->parent->y_scale : 0.f
};
- font->parent->get_glyph_shape (glyph,
+ font->parent->draw_glyph (glyph,
const_cast (&_hb_draw_funcs_default),
&adaptor);
}
+static void
+hb_font_paint_glyph_default (hb_font_t *font,
+ void *font_data,
+ hb_codepoint_t glyph,
+ hb_paint_funcs_t *paint_funcs,
+ void *paint_data,
+ unsigned int palette,
+ hb_color_t foreground,
+ void *user_data)
+{
+ paint_funcs->push_transform (paint_data,
+ font->parent->x_scale ? (float) font->x_scale / (float) font->parent->x_scale : 0.f,
+ font->parent->y_scale ? (font->slant - font->parent->slant) *
+ (float) font->x_scale / (float) font->parent->y_scale : 0.f,
+ 0.f,
+ font->parent->y_scale ? (float) font->y_scale / (float) font->parent->y_scale : 0.f,
+ 0.f, 0.f);
+
+ font->parent->paint_glyph (glyph, paint_funcs, paint_data, palette, foreground);
+
+ paint_funcs->pop_transform (paint_data);
+}
+
DEFINE_NULL_INSTANCE (hb_font_funcs_t) =
{
HB_OBJECT_HEADER_STATIC,
@@ -647,7 +682,7 @@ DEFINE_NULL_INSTANCE (hb_font_funcs_t) =
nullptr,
{
{
-#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_nil,
+#define HB_FONT_FUNC_IMPLEMENT(get_,name) hb_font_##get_##name##_nil,
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
}
@@ -661,7 +696,7 @@ static const hb_font_funcs_t _hb_font_funcs_default = {
nullptr,
{
{
-#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_default,
+#define HB_FONT_FUNC_IMPLEMENT(get_,name) hb_font_##get_##name##_default,
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
}
@@ -739,7 +774,7 @@ hb_font_funcs_destroy (hb_font_funcs_t *ffuncs)
if (ffuncs->destroy)
{
-#define HB_FONT_FUNC_IMPLEMENT(name) if (ffuncs->destroy->name) \
+#define HB_FONT_FUNC_IMPLEMENT(get_,name) if (ffuncs->destroy->name) \
ffuncs->destroy->name (!ffuncs->user_data ? nullptr : ffuncs->user_data->name);
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
@@ -879,11 +914,11 @@ fail:
return false;
}
-#define HB_FONT_FUNC_IMPLEMENT(name) \
+#define HB_FONT_FUNC_IMPLEMENT(get_,name) \
\
void \
hb_font_funcs_set_##name##_func (hb_font_funcs_t *ffuncs, \
- hb_font_get_##name##_func_t func, \
+ hb_font_##get_##name##_func_t func, \
void *user_data, \
hb_destroy_func_t destroy) \
{ \
@@ -899,7 +934,7 @@ hb_font_funcs_set_##name##_func (hb_font_funcs_t *ffuncs, \
if (func) \
ffuncs->get.f.name = func; \
else \
- ffuncs->get.f.name = hb_font_get_##name##_default; \
+ ffuncs->get.f.name = hb_font_##get_##name##_default; \
\
if (ffuncs->user_data) \
ffuncs->user_data->name = user_data; \
@@ -1357,13 +1392,66 @@ hb_font_get_glyph_from_name (hb_font_t *font,
* objects, with @draw_data passed to them.
*
* Since: 4.0.0
- **/
+ */
void
hb_font_get_glyph_shape (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_draw_funcs_t *dfuncs, void *draw_data)
+{
+ hb_font_draw_glyph (font, glyph, dfuncs, draw_data);
+}
+
+/**
+ * hb_font_draw_glyph:
+ * @font: #hb_font_t to work upon
+ * @glyph: : The glyph ID
+ * @dfuncs: #hb_draw_funcs_t to draw to
+ * @draw_data: User data to pass to draw callbacks
+ *
+ * Draws the outline that corresponds to a glyph in the specified @font.
+ *
+ * The outline is returned by way of calls to the callbacks of the @dfuncs
+ * objects, with @draw_data passed to them.
+ *
+ * Since: REPLACEME
+ **/
+void
+hb_font_draw_glyph (hb_font_t *font,
hb_codepoint_t glyph,
hb_draw_funcs_t *dfuncs, void *draw_data)
{
- font->get_glyph_shape (glyph, dfuncs, draw_data);
+ font->draw_glyph (glyph, dfuncs, draw_data);
+}
+
+/**
+ * hb_font_paint_glyph:
+ * @font: #hb_font_t to work upon
+ * @glyph: The glyph ID
+ * @pfuncs: #hb_paint_funcs_t to paint with
+ * @paint_data: User data to pass to paint callbacks
+ * @palette: The index of the font's color palette to use
+ * @foreground: The foreground color, unpremultipled
+ *
+ * Paints the glyph.
+ *
+ * The painting instructions are returned by way of calls to
+ * the callbacks of the @funcs object, with @paint_data passed
+ * to them.
+ *
+ * If the font has color palettes (see hb_ot_color_has_palettes()),
+ * then @palette selects the palette to use. If the font doesn't
+ * have palettes, passing 0 is fine.
+ *
+ * Since: REPLACEME
+ */
+void
+hb_font_paint_glyph (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_paint_funcs_t *pfuncs, void *paint_data,
+ unsigned int palette,
+ hb_color_t foreground)
+{
+ font->paint_glyph (glyph, pfuncs, paint_data, palette, foreground);
}
/* A bit higher-level, and with fallback */
@@ -2328,9 +2416,8 @@ hb_font_get_ptem (hb_font_t *font)
* HarfBuzz needs to know this value to adjust shaping results,
* metrics, and style values to match the slanted rendering.
*
- * Note: The glyph shape fetched via the
- * hb_font_get_glyph_shape() is slanted to reflect this value
- * as well.
+ * Note: The glyph shape fetched via the hb_font_draw_glyph()
+ * function is slanted to reflect this value as well.
*
* Note: The slant value is a ratio. For example, a
* 20% slant would be represented as a 0.2 value.
@@ -2754,3 +2841,13 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
trampoline_destroy);
}
#endif
+
+
+void
+hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_glyph_shape_func_t func,
+ void *user_data,
+ hb_destroy_func_t destroy /* May be NULL. */)
+{
+ hb_font_funcs_set_draw_glyph_func (ffuncs, func, user_data, destroy);
+}
diff --git a/src/hb-font.h b/src/hb-font.h
index e2c3df4a5..a5859c962 100644
--- a/src/hb-font.h
+++ b/src/hb-font.h
@@ -34,18 +34,10 @@
#include "hb-common.h"
#include "hb-face.h"
#include "hb-draw.h"
+#include "hb-paint.h"
HB_BEGIN_DECLS
-/**
- * hb_font_t:
- *
- * Data type for holding fonts.
- *
- */
-typedef struct hb_font_t hb_font_t;
-
-
/*
* hb_font_funcs_t
*/
@@ -97,7 +89,7 @@ HB_EXTERN hb_bool_t
hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs);
-/* font and glyph extents */
+/* font extents */
/**
* hb_font_extents_t:
@@ -126,24 +118,6 @@ typedef struct hb_font_extents_t {
hb_position_t reserved1;
} hb_font_extents_t;
-/**
- * hb_glyph_extents_t:
- * @x_bearing: Distance from the x-origin to the left extremum of the glyph.
- * @y_bearing: Distance from the top extremum of the glyph to the y-origin.
- * @width: Distance from the left extremum of the glyph to the right extremum.
- * @height: Distance from the top extremum of the glyph to the bottom extremum.
- *
- * Glyph extent values, measured in font units.
- *
- * Note that @height is negative, in coordinate systems that grow up.
- **/
-typedef struct hb_glyph_extents_t {
- hb_position_t x_bearing;
- hb_position_t y_bearing;
- hb_position_t width;
- hb_position_t height;
-} hb_glyph_extents_t;
-
/* func types */
/**
@@ -524,12 +498,53 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *
*
* Since: 4.0.0
*
+ * Deprecated: REPLACEME: Use #hb_font_draw_glyph_func_t instead
**/
typedef void (*hb_font_get_glyph_shape_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t glyph,
hb_draw_funcs_t *draw_funcs, void *draw_data,
void *user_data);
+/**
+ * hb_font_draw_glyph_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @glyph: The glyph ID to query
+ * @draw_funcs: The draw functions to send the shape data to
+ * @draw_data: The data accompanying the draw functions
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * Since: REPLACEME
+ *
+ **/
+typedef void (*hb_font_draw_glyph_func_t) (hb_font_t *font, void *font_data,
+ hb_codepoint_t glyph,
+ hb_draw_funcs_t *draw_funcs, void *draw_data,
+ void *user_data);
+
+/**
+ * hb_font_paint_glyph_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @glyph: The glyph ID to query
+ * @paint_funcs: The paint functions to use
+ * @paint_data: The data accompanying the paint functions
+ * @palette: The color palette to use
+ * @foreground: The foreground color
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * Since: REPLACEME
+ */
+typedef void (*hb_font_paint_glyph_func_t) (hb_font_t *font, void *font_data,
+ hb_codepoint_t glyph,
+ hb_paint_funcs_t *paint_funcs, void *paint_data,
+ unsigned int palette,
+ hb_color_t foreground,
+ void *user_data);
/* func setters */
@@ -796,15 +811,51 @@ hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs,
* @user_data: Data to pass to @func
* @destroy: (nullable): The function to call when @user_data is not needed anymore
*
- * Sets the implementation function for #hb_font_get_glyph_shape_func_t.
+ * Sets the implementation function for #hb_font_get_glyph_shape_func_t,
+ * which is the same as #hb_font_draw_glyph_func_t.
*
* Since: 4.0.0
+ *
+ * Deprecated: REPLACEME: Use hb_font_set_draw_glyph_func() instead
**/
HB_EXTERN void
hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_shape_func_t func,
void *user_data, hb_destroy_func_t destroy);
+/**
+ * hb_font_funcs_set_draw_glyph_func:
+ * @ffuncs: A font-function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
+ *
+ * Sets the implementation function for #hb_font_draw_glyph_func_t,
+ * which is the same as #hb_font_get_glyph_shape_func_t.
+ *
+ * Since: REPLACEME
+ **/
+HB_EXTERN void
+hb_font_funcs_set_draw_glyph_func (hb_font_funcs_t *ffuncs,
+ hb_font_draw_glyph_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_paint_glyph_func:
+ * @ffuncs: A font-function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is no longer needed
+ *
+ * Sets the implementation function for #hb_font_paint_glyph_func_t.
+ *
+ * Since: REPLACEME
+ */
+HB_EXTERN void
+hb_font_funcs_set_paint_glyph_func (hb_font_funcs_t *ffuncs,
+ hb_font_paint_glyph_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+
/* func dispatch */
HB_EXTERN hb_bool_t
@@ -890,6 +941,17 @@ hb_font_get_glyph_shape (hb_font_t *font,
hb_codepoint_t glyph,
hb_draw_funcs_t *dfuncs, void *draw_data);
+HB_EXTERN void
+hb_font_draw_glyph (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_draw_funcs_t *dfuncs, void *draw_data);
+
+HB_EXTERN void
+hb_font_paint_glyph (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_paint_funcs_t *pfuncs, void *paint_data,
+ unsigned int palette,
+ hb_color_t foreground);
/* high-level funcs, with fallback */
diff --git a/src/hb-font.hh b/src/hb-font.hh
index a8b3ee5c4..83f0d8701 100644
--- a/src/hb-font.hh
+++ b/src/hb-font.hh
@@ -40,24 +40,25 @@
*/
#define HB_FONT_FUNCS_IMPLEMENT_CALLBACKS \
- HB_FONT_FUNC_IMPLEMENT (font_h_extents) \
- HB_FONT_FUNC_IMPLEMENT (font_v_extents) \
- HB_FONT_FUNC_IMPLEMENT (nominal_glyph) \
- HB_FONT_FUNC_IMPLEMENT (nominal_glyphs) \
- HB_FONT_FUNC_IMPLEMENT (variation_glyph) \
- HB_FONT_FUNC_IMPLEMENT (glyph_h_advance) \
- HB_FONT_FUNC_IMPLEMENT (glyph_v_advance) \
- HB_FONT_FUNC_IMPLEMENT (glyph_h_advances) \
- HB_FONT_FUNC_IMPLEMENT (glyph_v_advances) \
- HB_FONT_FUNC_IMPLEMENT (glyph_h_origin) \
- HB_FONT_FUNC_IMPLEMENT (glyph_v_origin) \
- HB_FONT_FUNC_IMPLEMENT (glyph_h_kerning) \
- HB_IF_NOT_DEPRECATED (HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning)) \
- HB_FONT_FUNC_IMPLEMENT (glyph_extents) \
- HB_FONT_FUNC_IMPLEMENT (glyph_contour_point) \
- HB_FONT_FUNC_IMPLEMENT (glyph_name) \
- HB_FONT_FUNC_IMPLEMENT (glyph_from_name) \
- HB_FONT_FUNC_IMPLEMENT (glyph_shape) \
+ HB_FONT_FUNC_IMPLEMENT (get_,font_h_extents) \
+ HB_FONT_FUNC_IMPLEMENT (get_,font_v_extents) \
+ HB_FONT_FUNC_IMPLEMENT (get_,nominal_glyph) \
+ HB_FONT_FUNC_IMPLEMENT (get_,nominal_glyphs) \
+ HB_FONT_FUNC_IMPLEMENT (get_,variation_glyph) \
+ HB_FONT_FUNC_IMPLEMENT (get_,glyph_h_advance) \
+ HB_FONT_FUNC_IMPLEMENT (get_,glyph_v_advance) \
+ HB_FONT_FUNC_IMPLEMENT (get_,glyph_h_advances) \
+ HB_FONT_FUNC_IMPLEMENT (get_,glyph_v_advances) \
+ HB_FONT_FUNC_IMPLEMENT (get_,glyph_h_origin) \
+ HB_FONT_FUNC_IMPLEMENT (get_,glyph_v_origin) \
+ HB_FONT_FUNC_IMPLEMENT (get_,glyph_h_kerning) \
+ HB_IF_NOT_DEPRECATED (HB_FONT_FUNC_IMPLEMENT (get_,glyph_v_kerning)) \
+ HB_FONT_FUNC_IMPLEMENT (get_,glyph_extents) \
+ HB_FONT_FUNC_IMPLEMENT (get_,glyph_contour_point) \
+ HB_FONT_FUNC_IMPLEMENT (get_,glyph_name) \
+ HB_FONT_FUNC_IMPLEMENT (get_,glyph_from_name) \
+ HB_FONT_FUNC_IMPLEMENT (,draw_glyph) \
+ HB_FONT_FUNC_IMPLEMENT (,paint_glyph) \
/* ^--- Add new callbacks here */
struct hb_font_funcs_t
@@ -65,13 +66,13 @@ struct hb_font_funcs_t
hb_object_header_t header;
struct {
-#define HB_FONT_FUNC_IMPLEMENT(name) void *name;
+#define HB_FONT_FUNC_IMPLEMENT(get_,name) void *name;
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
} *user_data;
struct {
-#define HB_FONT_FUNC_IMPLEMENT(name) hb_destroy_func_t name;
+#define HB_FONT_FUNC_IMPLEMENT(get_,name) hb_destroy_func_t name;
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
} *destroy;
@@ -79,12 +80,12 @@ struct hb_font_funcs_t
/* Don't access these directly. Call font->get_*() instead. */
union get_t {
struct get_funcs_t {
-#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_func_t name;
+#define HB_FONT_FUNC_IMPLEMENT(get_,name) hb_font_##get_##name##_func_t name;
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
} f;
void (*array[0
-#define HB_FONT_FUNC_IMPLEMENT(name) +1
+#define HB_FONT_FUNC_IMPLEMENT(get_,name) +1
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
]) ();
@@ -198,7 +199,7 @@ struct hb_font_t
HB_INTERNAL bool has_func_set (unsigned int i);
/* has_* ... */
-#define HB_FONT_FUNC_IMPLEMENT(name) \
+#define HB_FONT_FUNC_IMPLEMENT(get_,name) \
bool \
has_##name##_func () \
{ \
@@ -392,15 +393,26 @@ struct hb_font_t
!klass->user_data ? nullptr : klass->user_data->glyph_from_name);
}
- void get_glyph_shape (hb_codepoint_t glyph,
- hb_draw_funcs_t *draw_funcs, void *draw_data)
+ void draw_glyph (hb_codepoint_t glyph,
+ hb_draw_funcs_t *draw_funcs, void *draw_data)
{
- klass->get.f.glyph_shape (this, user_data,
- glyph,
- draw_funcs, draw_data,
- !klass->user_data ? nullptr : klass->user_data->glyph_shape);
+ klass->get.f.draw_glyph (this, user_data,
+ glyph,
+ draw_funcs, draw_data,
+ !klass->user_data ? nullptr : klass->user_data->draw_glyph);
}
+ void paint_glyph (hb_codepoint_t glyph,
+ hb_paint_funcs_t *paint_funcs, void *paint_data,
+ unsigned int palette,
+ hb_color_t foreground)
+ {
+ klass->get.f.paint_glyph (this, user_data,
+ glyph,
+ paint_funcs, paint_data,
+ palette, foreground,
+ !klass->user_data ? nullptr : klass->user_data->paint_glyph);
+ }
/* A bit higher-level, and with fallback */
diff --git a/src/hb-ft-colr.hh b/src/hb-ft-colr.hh
new file mode 100644
index 000000000..3fb40e109
--- /dev/null
+++ b/src/hb-ft-colr.hh
@@ -0,0 +1,547 @@
+/*
+ * Copyright © 2022 Behdad Esfahbod
+ *
+ * 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.
+ */
+
+#ifndef HB_FT_COLR_HH
+#define HB_FT_COLR_HH
+
+#include "hb.hh"
+
+#include "hb-paint-extents.hh"
+
+#include FT_COLOR_H
+
+#ifndef HB_NO_PAINT
+
+#ifdef TT_SUPPORT_COLRV1
+
+static hb_paint_composite_mode_t
+_hb_ft_paint_composite_mode (FT_Composite_Mode mode)
+{
+ switch (mode)
+ {
+ case FT_COLR_COMPOSITE_CLEAR: return HB_PAINT_COMPOSITE_MODE_CLEAR;
+ case FT_COLR_COMPOSITE_SRC: return HB_PAINT_COMPOSITE_MODE_SRC;
+ case FT_COLR_COMPOSITE_DEST: return HB_PAINT_COMPOSITE_MODE_DEST;
+ case FT_COLR_COMPOSITE_SRC_OVER: return HB_PAINT_COMPOSITE_MODE_SRC_OVER;
+ case FT_COLR_COMPOSITE_DEST_OVER: return HB_PAINT_COMPOSITE_MODE_DEST_OVER;
+ case FT_COLR_COMPOSITE_SRC_IN: return HB_PAINT_COMPOSITE_MODE_SRC_IN;
+ case FT_COLR_COMPOSITE_DEST_IN: return HB_PAINT_COMPOSITE_MODE_DEST_IN;
+ case FT_COLR_COMPOSITE_SRC_OUT: return HB_PAINT_COMPOSITE_MODE_SRC_OUT;
+ case FT_COLR_COMPOSITE_DEST_OUT: return HB_PAINT_COMPOSITE_MODE_DEST_OUT;
+ case FT_COLR_COMPOSITE_SRC_ATOP: return HB_PAINT_COMPOSITE_MODE_SRC_ATOP;
+ case FT_COLR_COMPOSITE_DEST_ATOP: return HB_PAINT_COMPOSITE_MODE_DEST_ATOP;
+ case FT_COLR_COMPOSITE_XOR: return HB_PAINT_COMPOSITE_MODE_XOR;
+ case FT_COLR_COMPOSITE_PLUS: return HB_PAINT_COMPOSITE_MODE_PLUS;
+ case FT_COLR_COMPOSITE_SCREEN: return HB_PAINT_COMPOSITE_MODE_SCREEN;
+ case FT_COLR_COMPOSITE_OVERLAY: return HB_PAINT_COMPOSITE_MODE_OVERLAY;
+ case FT_COLR_COMPOSITE_DARKEN: return HB_PAINT_COMPOSITE_MODE_DARKEN;
+ case FT_COLR_COMPOSITE_LIGHTEN: return HB_PAINT_COMPOSITE_MODE_LIGHTEN;
+ case FT_COLR_COMPOSITE_COLOR_DODGE: return HB_PAINT_COMPOSITE_MODE_COLOR_DODGE;
+ case FT_COLR_COMPOSITE_COLOR_BURN: return HB_PAINT_COMPOSITE_MODE_COLOR_BURN;
+ case FT_COLR_COMPOSITE_HARD_LIGHT: return HB_PAINT_COMPOSITE_MODE_HARD_LIGHT;
+ case FT_COLR_COMPOSITE_SOFT_LIGHT: return HB_PAINT_COMPOSITE_MODE_SOFT_LIGHT;
+ case FT_COLR_COMPOSITE_DIFFERENCE: return HB_PAINT_COMPOSITE_MODE_DIFFERENCE;
+ case FT_COLR_COMPOSITE_EXCLUSION: return HB_PAINT_COMPOSITE_MODE_EXCLUSION;
+ case FT_COLR_COMPOSITE_MULTIPLY: return HB_PAINT_COMPOSITE_MODE_MULTIPLY;
+ case FT_COLR_COMPOSITE_HSL_HUE: return HB_PAINT_COMPOSITE_MODE_HSL_HUE;
+ case FT_COLR_COMPOSITE_HSL_SATURATION: return HB_PAINT_COMPOSITE_MODE_HSL_SATURATION;
+ case FT_COLR_COMPOSITE_HSL_COLOR: return HB_PAINT_COMPOSITE_MODE_HSL_COLOR;
+ case FT_COLR_COMPOSITE_HSL_LUMINOSITY: return HB_PAINT_COMPOSITE_MODE_HSL_LUMINOSITY;
+
+ case FT_COLR_COMPOSITE_MAX: HB_FALLTHROUGH;
+ default: return HB_PAINT_COMPOSITE_MODE_CLEAR;
+ }
+}
+
+typedef struct hb_ft_paint_context_t hb_ft_paint_context_t;
+
+static void
+_hb_ft_paint (hb_ft_paint_context_t *c,
+ FT_OpaquePaint opaque_paint);
+
+struct hb_ft_paint_context_t
+{
+ hb_ft_paint_context_t (const hb_ft_font_t *ft_font,
+ hb_font_t *font,
+ hb_paint_funcs_t *paint_funcs, void *paint_data,
+ FT_Color *palette,
+ hb_color_t foreground) :
+ ft_font (ft_font), font(font),
+ funcs (paint_funcs), data (paint_data),
+ palette (palette), foreground (foreground) {}
+
+ void recurse (FT_OpaquePaint paint)
+ {
+ if (depth_left <= 0) return;
+ depth_left--;
+ _hb_ft_paint (this, paint);
+ depth_left++;
+ }
+
+ const hb_ft_font_t *ft_font;
+ hb_font_t *font;
+ hb_paint_funcs_t *funcs;
+ void *data;
+ FT_Color *palette;
+ hb_color_t foreground;
+ int depth_left = 128;
+};
+
+static unsigned
+_hb_ft_color_line_get_color_stops (hb_color_line_t *color_line,
+ void *color_line_data,
+ unsigned int start,
+ unsigned int *count,
+ hb_color_stop_t *color_stops,
+ void *user_data)
+{
+ FT_ColorLine *cl = (FT_ColorLine *) color_line_data;
+ hb_ft_paint_context_t *c = (hb_ft_paint_context_t *) user_data;
+
+ if (count)
+ {
+ FT_ColorStop stop;
+ unsigned wrote = 0;
+ FT_ColorStopIterator iter = cl->color_stop_iterator;
+
+ if (start >= cl->color_stop_iterator.num_color_stops)
+ {
+ *count = 0;
+ return cl->color_stop_iterator.num_color_stops;
+ }
+
+ while (cl->color_stop_iterator.current_color_stop < start)
+ FT_Get_Colorline_Stops(c->ft_font->ft_face,
+ &stop,
+ &cl->color_stop_iterator);
+
+ while (count && *count &&
+ FT_Get_Colorline_Stops(c->ft_font->ft_face,
+ &stop,
+ &cl->color_stop_iterator))
+ {
+ color_stops->offset = stop.stop_offset / 16384.f;
+ color_stops->is_foreground = stop.color.palette_index == 0xFFFF;
+ if (color_stops->is_foreground)
+ color_stops->color = HB_COLOR (hb_color_get_blue (c->foreground),
+ hb_color_get_green (c->foreground),
+ hb_color_get_red (c->foreground),
+ (hb_color_get_alpha (c->foreground) * stop.color.alpha) >> 14);
+ else
+ {
+ FT_Color ft_color = c->palette[stop.color.palette_index];
+ color_stops->color = HB_COLOR (ft_color.blue,
+ ft_color.green,
+ ft_color.red,
+ (ft_color.alpha * stop.color.alpha) >> 14);
+ }
+
+ color_stops++;
+ wrote++;
+ }
+
+ *count = wrote;
+
+ // reset the iterator for next time
+ cl->color_stop_iterator = iter;
+ }
+
+ return cl->color_stop_iterator.num_color_stops;
+}
+
+static hb_paint_extend_t
+_hb_ft_color_line_get_extend (hb_color_line_t *color_line,
+ void *color_line_data,
+ void *user_data)
+{
+ FT_ColorLine *c = (FT_ColorLine *) color_line_data;
+ switch (c->extend)
+ {
+ default:
+ case FT_COLR_PAINT_EXTEND_PAD: return HB_PAINT_EXTEND_PAD;
+ case FT_COLR_PAINT_EXTEND_REPEAT: return HB_PAINT_EXTEND_REPEAT;
+ case FT_COLR_PAINT_EXTEND_REFLECT: return HB_PAINT_EXTEND_REFLECT;
+ }
+}
+
+void
+_hb_ft_paint (hb_ft_paint_context_t *c,
+ FT_OpaquePaint opaque_paint)
+{
+ FT_Face ft_face = c->ft_font->ft_face;
+ FT_COLR_Paint paint;
+ if (!FT_Get_Paint (ft_face, opaque_paint, &paint))
+ return;
+
+ switch (paint.format)
+ {
+ case FT_COLR_PAINTFORMAT_COLR_LAYERS:
+ {
+ FT_OpaquePaint other_paint = {0};
+ while (FT_Get_Paint_Layers (ft_face,
+ &paint.u.colr_layers.layer_iterator,
+ &other_paint))
+ {
+ c->funcs->push_group (c->data);
+ c->recurse (other_paint);
+ c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
+ }
+ }
+ break;
+ case FT_COLR_PAINTFORMAT_SOLID:
+ {
+ bool is_foreground = paint.u.solid.color.palette_index == 0xFFFF;
+ hb_color_t color;
+ if (is_foreground)
+ color = HB_COLOR (hb_color_get_blue (c->foreground),
+ hb_color_get_green (c->foreground),
+ hb_color_get_red (c->foreground),
+ (hb_color_get_alpha (c->foreground) * paint.u.solid.color.alpha) >> 14);
+ else
+ {
+ FT_Color ft_color = c->palette[paint.u.solid.color.palette_index];
+ color = HB_COLOR (ft_color.blue,
+ ft_color.green,
+ ft_color.red,
+ (ft_color.alpha * paint.u.solid.color.alpha) >> 14);
+ }
+ c->funcs->color (c->data, is_foreground, color);
+ }
+ break;
+ case FT_COLR_PAINTFORMAT_LINEAR_GRADIENT:
+ {
+ hb_color_line_t cl = {
+ &paint.u.linear_gradient.colorline,
+ _hb_ft_color_line_get_color_stops, c,
+ _hb_ft_color_line_get_extend, nullptr
+ };
+
+ c->funcs->linear_gradient (c->data, &cl,
+ paint.u.linear_gradient.p0.x / 65536.f,
+ paint.u.linear_gradient.p0.y / 65536.f,
+ paint.u.linear_gradient.p1.x / 65536.f,
+ paint.u.linear_gradient.p1.y / 65536.f,
+ paint.u.linear_gradient.p2.x / 65536.f,
+ paint.u.linear_gradient.p2.y / 65536.f);
+ }
+ break;
+ case FT_COLR_PAINTFORMAT_RADIAL_GRADIENT:
+ {
+ hb_color_line_t cl = {
+ &paint.u.linear_gradient.colorline,
+ _hb_ft_color_line_get_color_stops, c,
+ _hb_ft_color_line_get_extend, nullptr
+ };
+
+ c->funcs->radial_gradient (c->data, &cl,
+ paint.u.radial_gradient.c0.x / 65536.f,
+ paint.u.radial_gradient.c0.y / 65536.f,
+ paint.u.radial_gradient.r0 / 65536.f,
+ paint.u.radial_gradient.c1.x / 65536.f,
+ paint.u.radial_gradient.c1.y / 65536.f,
+ paint.u.radial_gradient.r1 / 65536.f);
+ }
+ break;
+ case FT_COLR_PAINTFORMAT_SWEEP_GRADIENT:
+ {
+ hb_color_line_t cl = {
+ &paint.u.linear_gradient.colorline,
+ _hb_ft_color_line_get_color_stops, c,
+ _hb_ft_color_line_get_extend, nullptr
+ };
+
+ c->funcs->sweep_gradient (c->data, &cl,
+ paint.u.sweep_gradient.center.x / 65536.f,
+ paint.u.sweep_gradient.center.y / 65536.f,
+ (paint.u.sweep_gradient.start_angle / 65536.f + 1) * (float) M_PI,
+ (paint.u.sweep_gradient.end_angle / 65536.f + 1) * (float) M_PI);
+ }
+ break;
+ case FT_COLR_PAINTFORMAT_GLYPH:
+ {
+ c->funcs->push_inverse_root_transform (c->data, c->font);
+ c->ft_font->lock.unlock ();
+ c->funcs->push_clip_glyph (c->data, paint.u.glyph.glyphID, c->font);
+ c->ft_font->lock.lock ();
+ c->funcs->push_root_transform (c->data, c->font);
+ c->recurse (paint.u.glyph.paint);
+ c->funcs->pop_root_transform (c->data);
+ c->funcs->pop_clip (c->data);
+ c->funcs->pop_inverse_root_transform (c->data);
+ }
+ break;
+ case FT_COLR_PAINTFORMAT_COLR_GLYPH:
+ {
+ FT_OpaquePaint other_paint = {0};
+ if (FT_Get_Color_Glyph_Paint (ft_face, paint.u.colr_glyph.glyphID,
+ FT_COLOR_NO_ROOT_TRANSFORM,
+ &other_paint))
+ {
+ bool has_clip_box;
+ FT_ClipBox clip_box;
+ has_clip_box = FT_Get_Color_Glyph_ClipBox (ft_face, paint.u.colr_glyph.glyphID, &clip_box);
+ has_clip_box = 0;
+
+ if (has_clip_box)
+ c->funcs->push_clip_rectangle (c->data,
+ clip_box.bottom_left.x / 64.f,
+ clip_box.bottom_left.y / 64.f,
+ clip_box.top_right.x / 64.f,
+ clip_box.top_right.y / 64.f);
+ c->recurse (other_paint);
+ if (has_clip_box)
+ c->funcs->pop_clip (c->data);
+ }
+ }
+ break;
+ case FT_COLR_PAINTFORMAT_TRANSFORM:
+ {
+ c->funcs->push_transform (c->data,
+ paint.u.transform.affine.xx / 65536.f,
+ paint.u.transform.affine.yx / 65536.f,
+ paint.u.transform.affine.xy / 65536.f,
+ paint.u.transform.affine.yy / 65536.f,
+ paint.u.transform.affine.dx / 65536.f,
+ paint.u.transform.affine.dy / 65536.f);
+ c->recurse (paint.u.transform.paint);
+ c->funcs->pop_transform (c->data);
+ }
+ break;
+ case FT_COLR_PAINTFORMAT_TRANSLATE:
+ {
+ c->funcs->push_transform (c->data,
+ 0.f, 0.f, 0.f, 0.f,
+ paint.u.translate.dx / 65536.f,
+ paint.u.translate.dy / 65536.f);
+ c->recurse (paint.u.translate.paint);
+ c->funcs->pop_transform (c->data);
+ }
+ break;
+ case FT_COLR_PAINTFORMAT_SCALE:
+ {
+ bool has_translate = paint.u.scale.center_x != 0 || paint.u.scale.center_y != 0;
+ if (has_translate)
+ c->funcs->push_transform (c->data,
+ 1.f, 0.f, 0.f, 1.f,
+ +paint.u.scale.center_x / 65536.f,
+ +paint.u.scale.center_y / 65536.f);
+ c->funcs->push_transform (c->data,
+ paint.u.scale.scale_x / 65536.f,
+ 0.f, 0.f,
+ paint.u.scale.scale_y / 65536.f,
+ 0.f, 0.f);
+ if (has_translate)
+ c->funcs->push_transform (c->data,
+ 1.f, 0.f, 0.f, 1.f,
+ -paint.u.scale.center_x / 65536.f,
+ -paint.u.scale.center_y / 65536.f);
+ c->recurse (paint.u.scale.paint);
+ c->funcs->pop_transform (c->data);
+ if (has_translate)
+ {
+ c->funcs->pop_transform (c->data);
+ c->funcs->pop_transform (c->data);
+ }
+ }
+ break;
+ case FT_COLR_PAINTFORMAT_ROTATE:
+ {
+ float a = paint.u.rotate.angle / 65536.f;
+ float cc = cosf (a * (float) M_PI);
+ float ss = sinf (a * (float) M_PI);
+ c->funcs->push_transform (c->data,
+ 1.f, 0.f, 0.f, 1.f,
+ +paint.u.rotate.center_x / 65536.f,
+ +paint.u.rotate.center_y / 65536.f);
+ c->funcs->push_transform (c->data, cc, ss, -ss, cc, 0., 0.);
+ c->funcs->push_transform (c->data,
+ 1.f, 0.f, 0.f, 1.f,
+ -paint.u.rotate.center_x / 65536.f,
+ -paint.u.rotate.center_y / 65536.f);
+ c->recurse (paint.u.rotate.paint);
+ c->funcs->pop_transform (c->data);
+ c->funcs->pop_transform (c->data);
+ c->funcs->pop_transform (c->data);
+ }
+ break;
+ case FT_COLR_PAINTFORMAT_SKEW:
+ {
+ float x = +tanf (paint.u.skew.x_skew_angle / 65536.f * (float) M_PI);
+ float y = -tanf (paint.u.skew.y_skew_angle / 65536.f * (float) M_PI);
+ c->funcs->push_transform (c->data,
+ 1.f, 0.f, 0.f, 1.f,
+ +paint.u.skew.center_x / 65536.f,
+ +paint.u.skew.center_y / 65536.f);
+ c->funcs->push_transform (c->data, 1., y, x, 1., 0., 0.);
+ c->funcs->push_transform (c->data,
+ 1.f, 0.f, 0.f, 1.f,
+ -paint.u.skew.center_x / 65536.f,
+ -paint.u.skew.center_y / 65536.f);
+ c->recurse (paint.u.skew.paint);
+ c->funcs->pop_transform (c->data);
+ c->funcs->pop_transform (c->data);
+ c->funcs->pop_transform (c->data);
+ }
+ break;
+ case FT_COLR_PAINTFORMAT_COMPOSITE:
+ {
+ c->funcs->push_group (c->data);
+ c->recurse (paint.u.composite.backdrop_paint);
+ c->funcs->push_group (c->data);
+ c->recurse (paint.u.composite.source_paint);
+ c->funcs->pop_group (c->data, _hb_ft_paint_composite_mode (paint.u.composite.composite_mode));
+ c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
+ }
+ break;
+
+ case FT_COLR_PAINT_FORMAT_MAX: break;
+ default: HB_FALLTHROUGH;
+ case FT_COLR_PAINTFORMAT_UNSUPPORTED: break;
+ }
+}
+
+#endif
+
+static bool
+hb_ft_paint_glyph_colr (hb_font_t *font,
+ void *font_data,
+ hb_codepoint_t gid,
+ hb_paint_funcs_t *paint_funcs, void *paint_data,
+ unsigned int palette_index,
+ hb_color_t foreground,
+ void *user_data)
+{
+ const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ FT_Face ft_face = ft_font->ft_face;
+
+ /* Face is locked. */
+
+ FT_Error error;
+ FT_Color* palette;
+ FT_LayerIterator iterator;
+
+ FT_Bool have_layers;
+ FT_UInt layer_glyph_index;
+ FT_UInt layer_color_index;
+
+ error = FT_Palette_Select(ft_face, palette_index, &palette);
+ if (error)
+ palette = NULL;
+
+#ifdef TT_SUPPORT_COLRV1
+ /* COLRv1 */
+ FT_OpaquePaint paint = {0};
+ if (FT_Get_Color_Glyph_Paint (ft_face, gid,
+ FT_COLOR_NO_ROOT_TRANSFORM,
+ &paint))
+ {
+ bool is_bounded = true;
+ FT_ClipBox clip_box;
+ if (FT_Get_Color_Glyph_ClipBox (ft_face, gid, &clip_box))
+ paint_funcs->push_clip_rectangle (paint_data,
+ clip_box.bottom_left.x - font->slant_xy * clip_box.bottom_left.y,
+ clip_box.bottom_left.y,
+ clip_box.top_right.x - font->slant_xy * clip_box.top_right.y,
+ clip_box.top_right.y);
+ else
+ {
+ auto *extents_funcs = hb_paint_extents_get_funcs ();
+ hb_paint_extents_context_t extents_data;
+ hb_ft_paint_context_t c (ft_font, font,
+ extents_funcs, &extents_data,
+ palette, foreground);
+ _hb_ft_paint (&c, paint);
+ hb_extents_t extents = extents_data.get_extents ();
+ is_bounded = extents_data.is_bounded ();
+ paint_funcs->push_clip_rectangle (paint_data,
+ extents.xmin,
+ extents.ymin,
+ extents.xmax,
+ extents.ymax);
+
+ hb_paint_funcs_destroy (extents_funcs);
+ }
+
+ paint_funcs->push_root_transform (paint_data, font);
+
+ hb_ft_paint_context_t c (ft_font, font,
+ paint_funcs, paint_data,
+ palette, foreground);
+
+ if (is_bounded)
+ _hb_ft_paint (&c, paint);
+
+ paint_funcs->pop_root_transform (paint_data);
+ paint_funcs->pop_clip (paint_data);
+
+ return true;
+ }
+#endif
+
+ /* COLRv0 */
+ iterator.p = NULL;
+ have_layers = FT_Get_Color_Glyph_Layer(ft_face,
+ gid,
+ &layer_glyph_index,
+ &layer_color_index,
+ &iterator);
+
+ if (palette && have_layers)
+ {
+ do
+ {
+ hb_bool_t is_foreground = true;
+ hb_color_t color = foreground;
+
+ if ( layer_color_index != 0xFFFF )
+ {
+ FT_Color layer_color = palette[layer_color_index];
+ color = HB_COLOR (layer_color.blue,
+ layer_color.green,
+ layer_color.red,
+ layer_color.alpha);
+ is_foreground = false;
+ }
+
+ ft_font->lock.unlock ();
+ paint_funcs->push_clip_glyph (paint_data, layer_glyph_index, font);
+ ft_font->lock.lock ();
+ paint_funcs->color (paint_data, is_foreground, color);
+ paint_funcs->pop_clip (paint_data);
+
+ } while (FT_Get_Color_Glyph_Layer(ft_face,
+ gid,
+ &layer_glyph_index,
+ &layer_color_index,
+ &iterator));
+ return true;
+ }
+
+ return false;
+}
+
+#endif
+
+
+#endif /* HB_FT_COLR_HH */
diff --git a/src/hb-ft.cc b/src/hb-ft.cc
index 097c52f7f..70cdcbe81 100644
--- a/src/hb-ft.cc
+++ b/src/hb-ft.cc
@@ -33,17 +33,19 @@
#include "hb-ft.h"
+#include "hb-cache.hh"
#include "hb-draw.hh"
#include "hb-font.hh"
#include "hb-machinery.hh"
-#include "hb-cache.hh"
#include "hb-ot-os2-table.hh"
#include "hb-ot-shaper-arabic-pua.hh"
+#include "hb-paint.hh"
#include FT_ADVANCES_H
#include FT_MULTIPLE_MASTERS_H
#include FT_OUTLINE_H
#include FT_TRUETYPE_TABLES_H
+#include FT_COLOR_H
/**
@@ -777,11 +779,11 @@ _hb_ft_cubic_to (const FT_Vector *control1,
}
static void
-hb_ft_get_glyph_shape (hb_font_t *font HB_UNUSED,
- void *font_data,
- hb_codepoint_t glyph,
- hb_draw_funcs_t *draw_funcs, void *draw_data,
- void *user_data HB_UNUSED)
+hb_ft_draw_glyph (hb_font_t *font HB_UNUSED,
+ void *font_data,
+ hb_codepoint_t glyph,
+ hb_draw_funcs_t *draw_funcs, void *draw_data,
+ void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
hb_lock_t lock (ft_font->lock);
@@ -811,6 +813,88 @@ hb_ft_get_glyph_shape (hb_font_t *font HB_UNUSED,
}
#endif
+#ifndef HB_NO_PAINT
+
+#include "hb-ft-colr.hh"
+
+static void
+hb_ft_paint_glyph (hb_font_t *font,
+ void *font_data,
+ hb_codepoint_t gid,
+ hb_paint_funcs_t *paint_funcs, void *paint_data,
+ unsigned int palette_index,
+ hb_color_t foreground,
+ void *user_data)
+{
+ const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
+ FT_Face ft_face = ft_font->ft_face;
+
+ /* We release the lock before calling into callbacks, such that
+ * eg. draw API can call back into the face.*/
+
+ if (unlikely (FT_Load_Glyph (ft_face, gid,
+ ft_font->load_flags | FT_LOAD_COLOR)))
+ return;
+
+ if (ft_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)
+ {
+ if (hb_ft_paint_glyph_colr (font, font_data, gid,
+ paint_funcs, paint_data,
+ palette_index, foreground,
+ user_data))
+ return;
+
+ /* Simple outline. */
+ ft_font->lock.unlock ();
+ paint_funcs->push_clip_glyph (paint_data, gid, font);
+ ft_font->lock.lock ();
+ paint_funcs->color (paint_data, true, foreground);
+ paint_funcs->pop_clip (paint_data);
+
+ return;
+ }
+
+ auto *glyph = ft_face->glyph;
+ if (glyph->format == FT_GLYPH_FORMAT_BITMAP)
+ {
+ auto &bitmap = glyph->bitmap;
+ if (bitmap.pixel_mode == FT_PIXEL_MODE_BGRA)
+ {
+ if (bitmap.pitch != (signed) bitmap.width * 4)
+ return;
+
+ ft_font->lock.unlock ();
+
+ hb_blob_t *blob = hb_blob_create ((const char *) bitmap.buffer,
+ bitmap.pitch * bitmap.rows,
+ HB_MEMORY_MODE_DUPLICATE,
+ nullptr, nullptr);
+
+ hb_glyph_extents_t extents;
+ if (!hb_font_get_glyph_extents (font, gid, &extents))
+ goto out;
+
+ paint_funcs->image (paint_data,
+ blob,
+ bitmap.width,
+ bitmap.rows,
+ HB_PAINT_IMAGE_FORMAT_BGRA,
+ font->slant_xy,
+ &extents);
+
+ out:
+ hb_blob_destroy (blob);
+ ft_font->lock.lock ();
+ }
+
+ return;
+ }
+
+ /* TODO Support image, COLRv0/1. */
+}
+#endif
+
static inline void free_static_ft_funcs ();
@@ -844,7 +928,11 @@ static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_tpush_clip_glyph (data, glyph, font);
+ funcs->color (data, true, foreground);
+ funcs->pop_clip (data);
+
+ return true;
+}
+
bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const
{
#ifdef HB_NO_OT_FONT_CFF
diff --git a/src/hb-ot-cff1-table.hh b/src/hb-ot-cff1-table.hh
index bb856c9dd..c68763fe4 100644
--- a/src/hb-ot-cff1-table.hh
+++ b/src/hb-ot-cff1-table.hh
@@ -30,6 +30,7 @@
#include "hb-ot-cff-common.hh"
#include "hb-subset-cff1.hh"
#include "hb-draw.hh"
+#include "hb-paint.hh"
#define HB_STRING_ARRAY_NAME cff1_std_strings
#define HB_STRING_ARRAY_LIST "hb-ot-cff1-std-str.hh"
@@ -1426,6 +1427,7 @@ struct cff1
}
HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const;
+ HB_INTERNAL bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const;
HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const;
HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const;
diff --git a/src/hb-ot-cff2-table.cc b/src/hb-ot-cff2-table.cc
index d530fc2ee..795556555 100644
--- a/src/hb-ot-cff2-table.cc
+++ b/src/hb-ot-cff2-table.cc
@@ -143,6 +143,15 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
return true;
}
+bool OT::cff2::accelerator_t::paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const
+{
+ funcs->push_clip_glyph (data, glyph, font);
+ funcs->color (data, true, foreground);
+ funcs->pop_clip (data);
+
+ return true;
+}
+
struct cff2_path_param_t
{
cff2_path_param_t (hb_font_t *font_, hb_draw_session_t &draw_session_)
diff --git a/src/hb-ot-cff2-table.hh b/src/hb-ot-cff2-table.hh
index 9081930bb..9a3d2d013 100644
--- a/src/hb-ot-cff2-table.hh
+++ b/src/hb-ot-cff2-table.hh
@@ -30,6 +30,7 @@
#include "hb-ot-cff-common.hh"
#include "hb-subset-cff2.hh"
#include "hb-draw.hh"
+#include "hb-paint.hh"
namespace CFF {
@@ -516,6 +517,7 @@ struct cff2
HB_INTERNAL bool get_extents (hb_font_t *font,
hb_codepoint_t glyph,
hb_glyph_extents_t *extents) const;
+ HB_INTERNAL bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const;
HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const;
};
diff --git a/src/hb-ot-color-cbdt-table.hh b/src/hb-ot-color-cbdt-table.hh
index 4f8fa0123..c326770a8 100644
--- a/src/hb-ot-color-cbdt-table.hh
+++ b/src/hb-ot-color-cbdt-table.hh
@@ -28,6 +28,7 @@
#define HB_OT_COLOR_CBDT_TABLE_HH
#include "hb-open-type.hh"
+#include "hb-paint.hh"
/*
* CBLC -- Color Bitmap Location
@@ -80,14 +81,15 @@ struct SmallGlyphMetrics
return_trace (c->check_struct (this));
}
- void get_extents (hb_font_t *font, hb_glyph_extents_t *extents) const
+ void get_extents (hb_font_t *font, hb_glyph_extents_t *extents, bool scale) const
{
extents->x_bearing = bearingX;
extents->y_bearing = bearingY;
extents->width = width;
extents->height = -static_cast (height);
- font->scale_glyph_extents (extents);
+ if (scale)
+ font->scale_glyph_extents (extents);
}
HBUINT8 height;
@@ -309,7 +311,7 @@ struct IndexSubtable
}
}
- bool get_extents (hb_glyph_extents_t *extents HB_UNUSED) const
+ bool get_extents (hb_glyph_extents_t *extents HB_UNUSED, bool scale HB_UNUSED) const
{
switch (u.header.indexFormat)
{
@@ -506,8 +508,8 @@ struct IndexSubtableRecord
return num_missing;
}
- bool get_extents (hb_glyph_extents_t *extents, const void *base) const
- { return (base+offsetToSubtable).get_extents (extents); }
+ bool get_extents (hb_glyph_extents_t *extents, const void *base, bool scale) const
+ { return (base+offsetToSubtable).get_extents (extents, scale); }
bool get_image_data (unsigned int gid,
const void *base,
@@ -835,7 +837,7 @@ struct CBDT
}
bool
- get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
+ get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents, bool scale = true) const
{
const void *base;
const BitmapSizeTable &strike = this->cblc->choose_strike (font);
@@ -843,7 +845,7 @@ struct CBDT
if (!subtable_record || !strike.ppemX || !strike.ppemY)
return false;
- if (subtable_record->get_extents (extents, base))
+ if (subtable_record->get_extents (extents, base, scale))
return true;
unsigned int image_offset = 0, image_length = 0, image_format = 0;
@@ -860,26 +862,29 @@ struct CBDT
if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
return false;
auto &glyphFormat17 = StructAtOffset (this->cbdt, image_offset);
- glyphFormat17.glyphMetrics.get_extents (font, extents);
+ glyphFormat17.glyphMetrics.get_extents (font, extents, scale);
break;
}
case 18: {
if (unlikely (image_length < GlyphBitmapDataFormat18::min_size))
return false;
auto &glyphFormat18 = StructAtOffset (this->cbdt, image_offset);
- glyphFormat18.glyphMetrics.get_extents (font, extents);
+ glyphFormat18.glyphMetrics.get_extents (font, extents, scale);
break;
}
default: return false; /* TODO: Support other image formats. */
}
/* Convert to font units. */
- float x_scale = upem / (float) strike.ppemX;
- float y_scale = upem / (float) strike.ppemY;
- extents->x_bearing = roundf (extents->x_bearing * x_scale);
- extents->y_bearing = roundf (extents->y_bearing * y_scale);
- extents->width = roundf (extents->width * x_scale);
- extents->height = roundf (extents->height * y_scale);
+ if (scale)
+ {
+ float x_scale = upem / (float) strike.ppemX;
+ float y_scale = upem / (float) strike.ppemY;
+ extents->x_bearing = roundf (extents->x_bearing * x_scale);
+ extents->y_bearing = roundf (extents->y_bearing * y_scale);
+ extents->width = roundf (extents->width * x_scale);
+ extents->height = roundf (extents->height * y_scale);
+ }
return true;
}
@@ -936,6 +941,39 @@ struct CBDT
bool has_data () const { return cbdt.get_length (); }
+ bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const
+ {
+ hb_glyph_extents_t extents;
+ hb_glyph_extents_t pixel_extents;
+ hb_blob_t *blob = reference_png (font, glyph);
+
+ if (unlikely (blob == hb_blob_get_empty ()))
+ return false;
+
+ if (unlikely (!hb_font_get_glyph_extents (font, glyph, &extents)))
+ return false;
+
+ if (unlikely (!get_extents (font, glyph, &pixel_extents, false)))
+ return false;
+
+ funcs->push_clip_rectangle (data,
+ extents.x_bearing, extents.y_bearing,
+ extents.x_bearing + extents.width,
+ extents.y_bearing + extents.height);
+
+ funcs->image (data,
+ blob,
+ pixel_extents.width, -pixel_extents.height,
+ HB_PAINT_IMAGE_FORMAT_PNG,
+ font->slant_xy,
+ &extents);
+
+ funcs->pop_clip (data);
+
+ hb_blob_destroy (blob);
+ return true;
+ }
+
private:
hb_blob_ptr_t cblc;
hb_blob_ptr_t cbdt;
diff --git a/src/hb-ot-color-colr-table.cc b/src/hb-ot-color-colr-table.cc
new file mode 100644
index 000000000..f7cf00712
--- /dev/null
+++ b/src/hb-ot-color-colr-table.cc
@@ -0,0 +1,27 @@
+#include "hb-ot-color-colr-table.hh"
+
+namespace OT {
+
+void PaintColrLayers::paint_glyph (hb_paint_context_t *c) const
+{
+ const LayerList &paint_offset_lists = c->get_colr_table ()->get_layerList ();
+ for (unsigned i = firstLayerIndex; i < firstLayerIndex + numLayers; i++)
+ {
+ const Paint &paint = paint_offset_lists.get_paint (i);
+ c->funcs->push_group (c->data);
+ c->recurse (paint);
+ c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
+ }
+}
+
+void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const
+{
+ const COLR *colr_table = c->get_colr_table ();
+ const Paint *paint = colr_table->get_base_glyph_paint (gid);
+
+ // TODO apply clipbox
+ if (paint)
+ c->recurse (*paint);
+}
+
+}
diff --git a/src/hb-ot-color-colr-table.hh b/src/hb-ot-color-colr-table.hh
index 79b0b476c..c14033233 100644
--- a/src/hb-ot-color-colr-table.hh
+++ b/src/hb-ot-color-colr-table.hh
@@ -28,9 +28,12 @@
#ifndef HB_OT_COLOR_COLR_TABLE_HH
#define HB_OT_COLOR_COLR_TABLE_HH
+#include "hb.hh"
#include "hb-open-type.hh"
#include "hb-ot-layout-common.hh"
#include "hb-ot-var-common.hh"
+#include "hb-paint.hh"
+#include "hb-paint-extents.hh"
/*
* COLR -- Color
@@ -42,9 +45,77 @@
#define HB_COLRV1_MAX_NESTING_LEVEL 128
#endif
+
+namespace OT {
+struct hb_paint_context_t;
+}
+
namespace OT {
struct COLR;
+
+struct Paint;
+
+struct hb_paint_context_t :
+ hb_dispatch_context_t
+{
+ template
+ return_t dispatch (const T &obj) { obj.paint_glyph (this); return hb_empty_t (); }
+ static return_t default_return_value () { return hb_empty_t (); }
+
+ const COLR* get_colr_table () const
+ { return reinterpret_cast (base); }
+
+public:
+ const void *base;
+ hb_paint_funcs_t *funcs;
+ void *data;
+ hb_font_t *font;
+ unsigned int palette;
+ hb_color_t foreground;
+ VarStoreInstancer &instancer;
+ int depth_left = HB_COLRV1_MAX_NESTING_LEVEL;
+
+ hb_paint_context_t (const void *base_,
+ hb_paint_funcs_t *funcs_,
+ void *data_,
+ hb_font_t *font_,
+ unsigned int palette_,
+ hb_color_t foreground_,
+ VarStoreInstancer &instancer_) :
+ base (base_),
+ funcs (funcs_),
+ data (data_),
+ font (font_),
+ palette (palette_),
+ foreground (foreground_),
+ instancer (instancer_)
+ { }
+
+ hb_color_t get_color (unsigned int color_index, float alpha, hb_bool_t *is_foreground)
+ {
+ hb_color_t color = foreground;
+
+ *is_foreground = true;
+
+ if (color_index != 0xffff)
+ {
+ unsigned int clen = 1;
+ hb_face_t *face = hb_font_get_face (font);
+
+ hb_ot_color_palette_get_colors (face, palette, color_index, &clen, &color);
+ *is_foreground = false;
+ }
+
+ return HB_COLOR (hb_color_get_blue (color),
+ hb_color_get_green (color),
+ hb_color_get_red (color),
+ hb_color_get_alpha (color) * alpha);
+ }
+
+ inline void recurse (const Paint &paint);
+};
+
struct hb_colrv1_closure_context_t :
hb_dispatch_context_t
{
@@ -160,6 +231,8 @@ struct BaseGlyphRecord
template
struct Variable
{
+ static constexpr bool is_variable = true;
+
Variable* copy (hb_serialize_context_t *c) const
{
TRACE_SERIALIZE (this);
@@ -182,6 +255,23 @@ struct Variable
return_trace (c->check_struct (this) && value.sanitize (c));
}
+ void paint_glyph (hb_paint_context_t *c) const
+ {
+ value.paint_glyph (c, varIdxBase);
+ }
+
+ void get_color_stop (hb_paint_context_t *c,
+ hb_color_stop_t *stop,
+ const VarStoreInstancer &instancer) const
+ {
+ value.get_color_stop (c, stop, varIdxBase, instancer);
+ }
+
+ hb_paint_extend_t get_extend () const
+ {
+ return value.get_extend ();
+ }
+
protected:
T value;
public:
@@ -193,6 +283,8 @@ struct Variable
template
struct NoVariable
{
+ static constexpr bool is_variable = false;
+
static constexpr uint32_t varIdxBase = VarIdx::NO_VARIATION;
NoVariable* copy (hb_serialize_context_t *c) const
@@ -216,6 +308,23 @@ struct NoVariable
return_trace (c->check_struct (this) && value.sanitize (c));
}
+ void paint_glyph (hb_paint_context_t *c) const
+ {
+ value.paint_glyph (c, varIdxBase);
+ }
+
+ void get_color_stop (hb_paint_context_t *c,
+ hb_color_stop_t *stop,
+ const VarStoreInstancer &instancer) const
+ {
+ value.get_color_stop (c, stop, VarIdx::NO_VARIATION, instancer);
+ }
+
+ hb_paint_extend_t get_extend () const
+ {
+ return value.get_extend ();
+ }
+
T value;
public:
DEFINE_SIZE_STATIC (T::static_size);
@@ -243,6 +352,17 @@ struct ColorStop
return_trace (c->check_struct (this));
}
+ void get_color_stop (hb_paint_context_t *c,
+ hb_color_stop_t *out,
+ uint32_t varIdx,
+ const VarStoreInstancer &instancer) const
+ {
+ out->offset = stopOffset.to_float(instancer (varIdx, 0));
+ out->color = c->get_color (paletteIndex,
+ alpha.to_float (instancer (varIdx, 1)),
+ &out->is_foreground);
+ }
+
F2DOT14 stopOffset;
HBUINT16 paletteIndex;
F2DOT14 alpha;
@@ -294,6 +414,52 @@ struct ColorLine
stops.sanitize (c));
}
+ /* get up to count stops from start */
+ unsigned int
+ get_color_stops (hb_paint_context_t *c,
+ unsigned int start,
+ unsigned int *count,
+ hb_color_stop_t *color_stops,
+ const VarStoreInstancer &instancer) const
+ {
+ unsigned int len = stops.len;
+
+ if (count && color_stops)
+ {
+ unsigned int i;
+ for (i = 0; i < *count && start + i < len; i++)
+ stops[start + i].get_color_stop (c, &color_stops[i], instancer);
+ *count = i;
+ }
+
+ return len;
+ }
+
+ HB_INTERNAL static unsigned int static_get_color_stops (hb_color_line_t *color_line,
+ void *color_line_data,
+ unsigned int start,
+ unsigned int *count,
+ hb_color_stop_t *color_stops,
+ void *user_data)
+ {
+ const ColorLine *thiz = (const ColorLine *) color_line_data;
+ hb_paint_context_t *c = (hb_paint_context_t *) user_data;
+ return thiz->get_color_stops (c, start, count, color_stops, c->instancer);
+ }
+
+ hb_paint_extend_t get_extend () const
+ {
+ return (hb_paint_extend_t) (unsigned int) extend;
+ }
+
+ HB_INTERNAL static hb_paint_extend_t static_get_extend (hb_color_line_t *color_line,
+ void *color_line_data,
+ void *user_data)
+ {
+ const ColorLine *thiz = (const ColorLine *) color_line_data;
+ return thiz->get_extend ();
+ }
+
Extend extend;
Array16Of> stops;
public:
@@ -357,6 +523,17 @@ struct Affine2x3
return_trace (c->check_struct (this));
}
+ void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+ {
+ c->funcs->push_transform (c->data,
+ xx.to_float (c->instancer (varIdxBase, 0)),
+ yx.to_float (c->instancer (varIdxBase, 1)),
+ xy.to_float (c->instancer (varIdxBase, 2)),
+ yy.to_float (c->instancer (varIdxBase, 3)),
+ dx.to_float (c->instancer (varIdxBase, 4)),
+ dy.to_float (c->instancer (varIdxBase, 5)));
+ }
+
F16DOT16 xx;
F16DOT16 yx;
F16DOT16 xy;
@@ -388,6 +565,8 @@ struct PaintColrLayers
return_trace (c->check_struct (this));
}
+ HB_INTERNAL void paint_glyph (hb_paint_context_t *c) const;
+
HBUINT8 format; /* format = 1 */
HBUINT8 numLayers;
HBUINT32 firstLayerIndex; /* index into COLRv1::layerList */
@@ -415,6 +594,17 @@ struct PaintSolid
return_trace (c->check_struct (this));
}
+ void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+ {
+ hb_bool_t is_foreground;
+ hb_color_t color;
+
+ color = c->get_color (paletteIndex,
+ alpha.to_float (c->instancer (varIdxBase, 0)),
+ &is_foreground);
+ c->funcs->color (c->data, is_foreground, color);
+ }
+
HBUINT8 format; /* format = 2(noVar) or 3(Var)*/
HBUINT16 paletteIndex;
F2DOT14 alpha;
@@ -443,6 +633,23 @@ struct PaintLinearGradient
return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
}
+ void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+ {
+ hb_color_line_t cl = {
+ (void *) &(this+colorLine),
+ (this+colorLine).static_get_color_stops, c,
+ (this+colorLine).static_get_extend, nullptr
+ };
+
+ c->funcs->linear_gradient (c->data, &cl,
+ x0 + c->instancer (varIdxBase, 0),
+ y0 + c->instancer (varIdxBase, 1),
+ x1 + c->instancer (varIdxBase, 2),
+ y1 + c->instancer (varIdxBase, 3),
+ x2 + c->instancer (varIdxBase, 4),
+ y2 + c->instancer (varIdxBase, 5));
+ }
+
HBUINT8 format; /* format = 4(noVar) or 5 (Var) */
Offset24To> colorLine; /* Offset (from beginning of PaintLinearGradient
* table) to ColorLine subtable. */
@@ -477,6 +684,23 @@ struct PaintRadialGradient
return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
}
+ void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+ {
+ hb_color_line_t cl = {
+ (void *) &(this+colorLine),
+ (this+colorLine).static_get_color_stops, c,
+ (this+colorLine).static_get_extend, nullptr
+ };
+
+ c->funcs->radial_gradient (c->data, &cl,
+ x0 + c->instancer (varIdxBase, 0),
+ y0 + c->instancer (varIdxBase, 1),
+ radius0 + c->instancer (varIdxBase, 2),
+ x1 + c->instancer (varIdxBase, 3),
+ y1 + c->instancer (varIdxBase, 4),
+ radius1 + c->instancer (varIdxBase, 5));
+ }
+
HBUINT8 format; /* format = 6(noVar) or 7 (Var) */
Offset24To> colorLine; /* Offset (from beginning of PaintRadialGradient
* table) to ColorLine subtable. */
@@ -511,6 +735,21 @@ struct PaintSweepGradient
return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
}
+ void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+ {
+ hb_color_line_t cl = {
+ (void *) &(this+colorLine),
+ (this+colorLine).static_get_color_stops, c,
+ (this+colorLine).static_get_extend, nullptr
+ };
+
+ c->funcs->sweep_gradient (c->data, &cl,
+ centerX + c->instancer (varIdxBase, 0),
+ centerY + c->instancer (varIdxBase, 1),
+ (startAngle.to_float (c->instancer (varIdxBase, 2)) + 1) * (float) M_PI,
+ (endAngle.to_float (c->instancer (varIdxBase, 3)) + 1) * (float) M_PI);
+ }
+
HBUINT8 format; /* format = 8(noVar) or 9 (Var) */
Offset24To> colorLine; /* Offset (from beginning of PaintSweepGradient
* table) to ColorLine subtable. */
@@ -522,8 +761,6 @@ struct PaintSweepGradient
DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size + 2 * F2DOT14::static_size);
};
-struct Paint;
-
// Paint a non-COLR glyph, filled as indicated by paint.
struct PaintGlyph
{
@@ -548,6 +785,17 @@ struct PaintGlyph
return_trace (c->check_struct (this) && paint.sanitize (c, this));
}
+ void paint_glyph (hb_paint_context_t *c) const
+ {
+ c->funcs->push_inverse_root_transform (c->data, c->font);
+ c->funcs->push_clip_glyph (c->data, gid, c->font);
+ c->funcs->push_root_transform (c->data, c->font);
+ c->recurse (this+paint);
+ c->funcs->pop_root_transform (c->data);
+ c->funcs->pop_clip (c->data);
+ c->funcs->pop_inverse_root_transform (c->data);
+ }
+
HBUINT8 format; /* format = 10 */
Offset24To paint; /* Offset (from beginning of PaintGlyph table) to Paint subtable. */
HBUINT16 gid;
@@ -575,6 +823,8 @@ struct PaintColrGlyph
return_trace (c->check_struct (this));
}
+ HB_INTERNAL void paint_glyph (hb_paint_context_t *c) const;
+
HBUINT8 format; /* format = 11 */
HBUINT16 gid;
public:
@@ -603,6 +853,13 @@ struct PaintTransform
transform.sanitize (c, this));
}
+ void paint_glyph (hb_paint_context_t *c) const
+ {
+ (this+transform).paint_glyph (c);
+ c->recurse (this+src);
+ c->funcs->pop_transform (c->data);
+ }
+
HBUINT8 format; /* format = 12(noVar) or 13 (Var) */
Offset24To src; /* Offset (from beginning of PaintTransform table) to Paint subtable. */
Offset24To> transform;
@@ -629,6 +886,16 @@ struct PaintTranslate
return_trace (c->check_struct (this) && src.sanitize (c, this));
}
+ void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+ {
+ c->funcs->push_transform (c->data,
+ 1., 0., 0., 1.,
+ dx + c->instancer (varIdxBase, 0),
+ dy + c->instancer (varIdxBase, 0));
+ c->recurse (this+src);
+ c->funcs->pop_transform (c->data);
+ }
+
HBUINT8 format; /* format = 14(noVar) or 15 (Var) */
Offset24To src; /* Offset (from beginning of PaintTranslate table) to Paint subtable. */
FWORD dx;
@@ -656,6 +923,17 @@ struct PaintScale
return_trace (c->check_struct (this) && src.sanitize (c, this));
}
+ void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+ {
+ c->funcs->push_transform (c->data,
+ scaleX.to_float (c->instancer (varIdxBase, 0)),
+ 0., 0.,
+ scaleY.to_float (c->instancer (varIdxBase, 1)),
+ 0., 0.);
+ c->recurse (this+src);
+ c->funcs->pop_transform (c->data);
+ }
+
HBUINT8 format; /* format = 16 (noVar) or 17(Var) */
Offset24To src; /* Offset (from beginning of PaintScale table) to Paint subtable. */
F2DOT14 scaleX;
@@ -683,6 +961,23 @@ struct PaintScaleAroundCenter
return_trace (c->check_struct (this) && src.sanitize (c, this));
}
+ void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+ {
+ float tCenterX = centerX + c->instancer (varIdxBase, 2);
+ float tCenterY = centerY + c->instancer (varIdxBase, 3);
+ c->funcs->push_transform (c->data, 0., 0., 0., 0., +tCenterX, +tCenterY);
+ c->funcs->push_transform (c->data,
+ scaleX.to_float (c->instancer (varIdxBase, 0)),
+ 0., 0.,
+ scaleY.to_float (c->instancer (varIdxBase, 1)),
+ 0., 0.);
+ c->funcs->push_transform (c->data, 0., 0., 0., 0., -tCenterX, -tCenterY);
+ c->recurse (this+src);
+ c->funcs->pop_transform (c->data);
+ c->funcs->pop_transform (c->data);
+ c->funcs->pop_transform (c->data);
+ }
+
HBUINT8 format; /* format = 18 (noVar) or 19(Var) */
Offset24To src; /* Offset (from beginning of PaintScaleAroundCenter table) to Paint subtable. */
F2DOT14 scaleX;
@@ -712,6 +1007,14 @@ struct PaintScaleUniform
return_trace (c->check_struct (this) && src.sanitize (c, this));
}
+ void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+ {
+ float s = scale + c->instancer (varIdxBase, 0);
+ c->funcs->push_transform (c->data, s, 0., 0., s, 0., 0.);
+ c->recurse (this+src);
+ c->funcs->pop_transform (c->data);
+ }
+
HBUINT8 format; /* format = 20 (noVar) or 21(Var) */
Offset24To src; /* Offset (from beginning of PaintScaleUniform table) to Paint subtable. */
F2DOT14 scale;
@@ -738,6 +1041,20 @@ struct PaintScaleUniformAroundCenter
return_trace (c->check_struct (this) && src.sanitize (c, this));
}
+ void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+ {
+ float s = scale + c->instancer (varIdxBase, 0);
+ float tCenterX = centerX + c->instancer (varIdxBase, 1);
+ float tCenterY = centerY + c->instancer (varIdxBase, 2);
+ c->funcs->push_transform (c->data, 0., 0., 0., 0., +tCenterX, +tCenterY);
+ c->funcs->push_transform (c->data, s, 0., 0., s, 0., 0.);
+ c->funcs->push_transform (c->data, 0., 0., 0., 0., -tCenterX, -tCenterY);
+ c->recurse (this+src);
+ c->funcs->pop_transform (c->data);
+ c->funcs->pop_transform (c->data);
+ c->funcs->pop_transform (c->data);
+ }
+
HBUINT8 format; /* format = 22 (noVar) or 23(Var) */
Offset24To src; /* Offset (from beginning of PaintScaleUniformAroundCenter table) to Paint subtable. */
F2DOT14 scale;
@@ -766,6 +1083,16 @@ struct PaintRotate
return_trace (c->check_struct (this) && src.sanitize (c, this));
}
+ void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+ {
+ float a = angle.to_float (c->instancer (varIdxBase, 0));
+ float cc = cosf (a * (float) M_PI);
+ float ss = sinf (a * (float) M_PI);
+ c->funcs->push_transform (c->data, cc, ss, -ss, cc, 0., 0.);
+ c->recurse (this+src);
+ c->funcs->pop_transform (c->data);
+ }
+
HBUINT8 format; /* format = 24 (noVar) or 25(Var) */
Offset24To src; /* Offset (from beginning of PaintRotate table) to Paint subtable. */
F2DOT14 angle;
@@ -792,6 +1119,22 @@ struct PaintRotateAroundCenter
return_trace (c->check_struct (this) && src.sanitize (c, this));
}
+ void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+ {
+ float a = angle.to_float (c->instancer (varIdxBase, 0));
+ float cc = cosf (a * (float) M_PI);
+ float ss = sinf (a * (float) M_PI);
+ float tCenterX = centerX + c->instancer (varIdxBase, 1);
+ float tCenterY = centerY + c->instancer (varIdxBase, 2);
+ c->funcs->push_transform (c->data, 0., 0., 0., 0., +tCenterX, +tCenterY);
+ c->funcs->push_transform (c->data, cc, ss, -ss, cc, 0., 0.);
+ c->funcs->push_transform (c->data, 0., 0., 0., 0., -tCenterX, -tCenterY);
+ c->recurse (this+src);
+ c->funcs->pop_transform (c->data);
+ c->funcs->pop_transform (c->data);
+ c->funcs->pop_transform (c->data);
+ }
+
HBUINT8 format; /* format = 26 (noVar) or 27(Var) */
Offset24To src; /* Offset (from beginning of PaintRotateAroundCenter table) to Paint subtable. */
F2DOT14 angle;
@@ -820,6 +1163,15 @@ struct PaintSkew
return_trace (c->check_struct (this) && src.sanitize (c, this));
}
+ void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+ {
+ float x = +tanf (xSkewAngle.to_float(c->instancer (varIdxBase, 0)) * (float) M_PI);
+ float y = -tanf (ySkewAngle.to_float(c->instancer (varIdxBase, 1)) * (float) M_PI);
+ c->funcs->push_transform (c->data, 1., y, x, 1., 0., 0.);
+ c->recurse (this+src);
+ c->funcs->pop_transform (c->data);
+ }
+
HBUINT8 format; /* format = 28(noVar) or 29 (Var) */
Offset24To src; /* Offset (from beginning of PaintSkew table) to Paint subtable. */
F2DOT14 xSkewAngle;
@@ -847,6 +1199,21 @@ struct PaintSkewAroundCenter
return_trace (c->check_struct (this) && src.sanitize (c, this));
}
+ void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+ {
+ float x = +tanf (xSkewAngle.to_float(c->instancer (varIdxBase, 0)) * (float) M_PI);
+ float y = -tanf (ySkewAngle.to_float(c->instancer (varIdxBase, 1)) * (float) M_PI);
+ float tCenterX = centerX + c->instancer (varIdxBase, 2);
+ float tCenterY = centerY + c->instancer (varIdxBase, 3);
+ c->funcs->push_transform (c->data, 0., 0., 0., 0., +tCenterX, +tCenterY);
+ c->funcs->push_transform (c->data, 1., y, x, 1., 0., 0.);
+ c->funcs->push_transform (c->data, 0., 0., 0., 0., -tCenterX, -tCenterY);
+ c->recurse (this+src);
+ c->funcs->pop_transform (c->data);
+ c->funcs->pop_transform (c->data);
+ c->funcs->pop_transform (c->data);
+ }
+
HBUINT8 format; /* format = 30(noVar) or 31 (Var) */
Offset24To src; /* Offset (from beginning of PaintSkewAroundCenter table) to Paint subtable. */
F2DOT14 xSkewAngle;
@@ -879,6 +1246,16 @@ struct PaintComposite
backdrop.sanitize (c, this));
}
+ void paint_glyph (hb_paint_context_t *c) const
+ {
+ c->funcs->push_group (c->data);
+ c->recurse (this+backdrop);
+ c->funcs->push_group (c->data);
+ c->recurse (this+src);
+ c->funcs->pop_group (c->data, (hb_paint_composite_mode_t) (int) mode);
+ c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
+ }
+
HBUINT8 format; /* format = 32 */
Offset24To src; /* Offset (from beginning of PaintComposite table) to source Paint subtable. */
CompositeMode mode; /* If mode is unrecognized use COMPOSITE_CLEAR */
@@ -1194,35 +1571,35 @@ struct Paint
union {
HBUINT8 format;
PaintColrLayers paintformat1;
- PaintSolid paintformat2;
+ NoVariable paintformat2;
Variable paintformat3;
- PaintLinearGradient paintformat4;
+ NoVariable> paintformat4;
Variable> paintformat5;
- PaintRadialGradient paintformat6;
+ NoVariable> paintformat6;
Variable> paintformat7;
- PaintSweepGradient paintformat8;
+ NoVariable> paintformat8;
Variable> paintformat9;
PaintGlyph paintformat10;
PaintColrGlyph paintformat11;
PaintTransform paintformat12;
PaintTransform paintformat13;
- PaintTranslate paintformat14;
+ NoVariable paintformat14;
Variable paintformat15;
- PaintScale paintformat16;
+ NoVariable paintformat16;
Variable paintformat17;
- PaintScaleAroundCenter paintformat18;
+ NoVariable paintformat18;
Variable paintformat19;
- PaintScaleUniform paintformat20;
+ NoVariable paintformat20;
Variable paintformat21;
- PaintScaleUniformAroundCenter paintformat22;
+ NoVariable paintformat22;
Variable paintformat23;
- PaintRotate paintformat24;
+ NoVariable paintformat24;
Variable paintformat25;
- PaintRotateAroundCenter paintformat26;
+ NoVariable paintformat26;
Variable paintformat27;
- PaintSkew paintformat28;
+ NoVariable paintformat28;
Variable paintformat29;
- PaintSkewAroundCenter paintformat30;
+ NoVariable paintformat30;
Variable paintformat31;
PaintComposite paintformat32;
} u;
@@ -1323,7 +1700,8 @@ struct COLR
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
- bool has_data () const { return numBaseGlyphs; }
+ bool has_v0_data () const { return numBaseGlyphs; }
+ bool has_v1_data () const { return (this+baseGlyphList).len; }
unsigned int get_glyph_layers (hb_codepoint_t glyph,
unsigned int start_offset,
@@ -1589,6 +1967,19 @@ struct COLR
return_trace (true);
}
+ const Paint *get_base_glyph_paint (hb_codepoint_t glyph) const
+ {
+ const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList;
+ const BaseGlyphPaintRecord* record = get_base_glyph_paintrecord (glyph);
+ if (record)
+ {
+ const Paint &paint = &baseglyph_paintrecords+record->paint;
+ return &paint;
+ }
+ else
+ return nullptr;
+ }
+
bool
get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
{
@@ -1607,6 +1998,115 @@ struct COLR
return true;
}
+ auto *extents_funcs = hb_paint_extents_get_funcs ();
+ hb_paint_extents_context_t extents_data;
+ paint_glyph (font, glyph, extents_funcs, &extents_data, 0, HB_COLOR(0,0,0,0));
+
+ hb_extents_t e = extents_data.get_extents ();
+ extents->x_bearing = e.xmin;
+ extents->y_bearing = e.ymax;
+ extents->width = e.xmax - e.xmin;
+ extents->height = e.ymin - e.ymax;
+
+ hb_paint_funcs_destroy (extents_funcs);
+
+ return true;
+ }
+
+ bool
+ paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, unsigned int palette, hb_color_t foreground, bool clip = true) const
+ {
+ VarStoreInstancer instancer (this+varStore,
+ this+varIdxMap,
+ hb_array (font->coords, font->num_coords));
+ hb_paint_context_t c (this, funcs, data, font, palette, foreground, instancer);
+
+ if (version == 1)
+ {
+ const Paint *paint = get_base_glyph_paint (glyph);
+ if (paint)
+ {
+ // COLRv1 glyph
+
+ VarStoreInstancer instancer (this+varStore,
+ this+varIdxMap,
+ hb_array (font->coords, font->num_coords));
+
+ bool is_bounded = true;
+ bool pop_clip_first = true;
+ if (clip)
+ {
+ hb_glyph_extents_t extents;
+ if ((this+clipList).get_extents (glyph,
+ &extents,
+ instancer))
+ {
+ c.funcs->push_root_transform (c.data, font);
+
+ c.funcs->push_clip_rectangle (c.data,
+ extents.x_bearing,
+ extents.y_bearing + extents.height,
+ extents.x_bearing + extents.width,
+ extents.y_bearing);
+ }
+ else
+ {
+ auto *extents_funcs = hb_paint_extents_get_funcs ();
+ hb_paint_extents_context_t extents_data;
+
+ paint_glyph (font, glyph,
+ extents_funcs, &extents_data,
+ palette, foreground,
+ false);
+
+ hb_extents_t extents = extents_data.get_extents ();
+ is_bounded = extents_data.is_bounded ();
+ c.funcs->push_clip_rectangle (c.data,
+ extents.xmin,
+ extents.ymin,
+ extents.xmax,
+ extents.ymax);
+
+ hb_paint_funcs_destroy (extents_funcs);
+
+ c.funcs->push_root_transform (c.data, font);
+
+ pop_clip_first = false;
+ }
+ }
+
+ if (is_bounded)
+ c.recurse (*paint);
+
+ if (clip && pop_clip_first)
+ c.funcs->pop_clip (c.data);
+
+ c.funcs->pop_root_transform (c.data);
+
+ if (clip && !pop_clip_first)
+ c.funcs->pop_clip (c.data);
+
+ return true;
+ }
+ }
+
+ const BaseGlyphRecord *record = get_base_glyph_record (glyph);
+ if (record && ((hb_codepoint_t) record->glyphId == glyph))
+ {
+ // COLRv0 glyph
+ for (const auto &r : (this+layersZ).as_array (numLayers)
+ .sub_array (record->firstLayerIdx, record->numLayers))
+ {
+ hb_bool_t is_foreground;
+ hb_color_t color = c.get_color (r.colorIdx, 1., &is_foreground);
+ c.funcs->push_clip_glyph (c.data, r.glyphId, c.font);
+ c.funcs->color (c.data, is_foreground, color);
+ c.funcs->pop_clip (c.data);
+ }
+
+ return true;
+ }
+
return false;
}
@@ -1632,7 +2132,15 @@ struct COLR_accelerator_t : COLR::accelerator_t {
COLR_accelerator_t (hb_face_t *face) : COLR::accelerator_t (face) {}
};
+void
+hb_paint_context_t::recurse (const Paint &paint)
+{
+ depth_left--;
+ if (depth_left > 0)
+ paint.dispatch (this);
+ depth_left++;
+}
+
} /* namespace OT */
-
#endif /* HB_OT_COLOR_COLR_TABLE_HH */
diff --git a/src/hb-ot-color-colrv1-paint.hh b/src/hb-ot-color-colrv1-paint.hh
new file mode 100644
index 000000000..75a8539ac
--- /dev/null
+++ b/src/hb-ot-color-colrv1-paint.hh
@@ -0,0 +1,286 @@
+/*
+ * Copyright © 2022 Matthias Clasen
+ *
+ * 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.
+ *
+ */
+
+#ifndef HB_OT_COLR_COLRV1_PAINT_HH
+#define HB_OT_COLR_COLRV1_PAINT_HH
+
+#include "hb-open-type.hh"
+#include "hb-ot-layout-common.hh"
+#include "hb-ot-color-colr-table.hh"
+
+/*
+ * COLR -- Color
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/colr
+ */
+namespace OT {
+
+struct hb_colrv1_paint_context_t :
+ hb_dispatch_context_t
+{
+ template
+ return_t dispatch (const T &obj)
+ {
+ obj.paint (this);
+ return hb_empty_t ();
+ }
+
+ const COLR* get_colr_table () const
+ { return reinterpret_cast (base); }
+
+ public:
+ const void *base;
+ hb_paint_funcs_t *funcs;
+ void *paint_data;
+
+ hb_colrv1_paint_context_t (const void *base_, hb_paint_funcs_t *funcs_, void *paint_data_)
+ base (base_), funcs (funcs_), paint_data (paint_data_)
+ {}
+
+ void push_transform (float xx, float yx,
+ float xy, float yy,
+ float x0, float y0)
+ {
+ funcs->push_transform (paint_data, xx, yx, xy, yy, x0, y0);
+ }
+
+ void pop_transform ()
+ {
+ funcs->pop_transform (paint_data);
+ }
+
+ void push_clip (hb_codepoint_t gid)
+ {
+ funcs->push_clip (paint_data, gid);
+ }
+
+ void pop_clip ()
+ {
+ funcs->pop_clip (paint_data);
+ }
+
+ void solid (unsigned int color_index)
+ {
+ funcs->solid (paint_data, color_index);
+ }
+
+ void linear_gradient (hb_color_line *color_line,
+ float x0, float y0,
+ float x1, float y1,
+ float x2, float y2)
+ {
+ funcs->linear_gradient (paint_data,
+ color_line, x0, y0, x1, y1, x2, y2);
+ }
+
+ void radial_gradient (hb_color_line *color_line,
+ float x0, float y0, float r0,
+ float x1, float y1, float r1)
+ {
+ funcs->radial_gradient (paint_data,
+ color_line, x0, y0, r0, x1, y1, r1);
+ }
+
+ void sweep_gradient (hb_color_line *color_line,
+ float x0, float y0,
+ float start_angle, float end_angle)'
+ {
+ funcs->sweep_gradient (paint_data,
+ color_line, x0, y0, start_angle, end_angle);
+ }
+
+ void push_group ()
+ {
+ funcs->push_group (paint_data);
+ }
+
+ void pop_group_and_composite (hb_paint_composite_mode_t mode)
+ {
+ funcs->pop_group_and_composite (paint_data, mode);
+ }
+}
+
+HB_INTERNAL void PaintColrLayers::paint (hb_colrv1_paint_context_t *c) const
+{
+ const COLR *colr_table = c->get_colr_table ();
+ const LayerList &paint_offset_lists = colr_table->get_layerList ();
+ for (unsigned i = firstLayerIndex; i < firstLayerIndex + numLayers; i++)
+ {
+ const Paint &paint = std::addressof (paint_offset_lists) + paint_offset_lists[i];
+ c->push_group ();
+ paint.dispatch (c);
+ c->pop_group_and_composite (HB_PAINT_COMPOSITE_MODE_OVER);
+ }
+}
+
+HB_INTERNAL void PaintGlyph::paint (hb_colrv1_paint_context_t *c) const
+{
+ c->push_clip (gid);
+ (this+paint).dispatch (c);
+ c->pop_clip ();
+}
+
+HB_INTERNAL void PaintColrGlyph::paint (hb_colrv1_paint_context_t *c) const
+{
+ const COLR *colr_table = c->get_colr_table ();
+ const BaseGlyphPaintRecord* baseglyph_paintrecord = colr_table->get_base_glyph_paintrecord (gid);
+ if (!baseglyph_paintrecord) return;
+
+ c->push_clip (gid);
+ const BaseGlyphList &baseglyph_list = colr_table->get_baseglyphList ();
+ (&baseglyph_list+baseglyph_paintrecord->paint).dispatch (c);
+ c->pop_clip ();
+}
+
+template class Var>
+HB_INTERNAL void PaintTransform::paint (hb_colrv1_paint_context_t* c) const
+{
+ c->push_transform (transform.xx, transform.yx,
+ transform.xy, transform.yy,
+ transform.dx, transform.dy);
+ (this+src).dispatch (c);
+ c->pop_transform ();
+}
+
+HB_INTERNAL void PaintTranslate::paint (hb_colrv1_paint_context_t* c) const
+{
+ c->push_transform (0, 0, 0, 0, dx, dy);
+ (this+src).dispatch (c);
+ c->pop_transform ();
+}
+
+HB_INTERNAL void PaintScale::paint (hb_colrv1_paint_context_t* c) const
+{
+ c->push_transform (scaleX, 0, 0, scaleY, 0, 0);
+ (this+src).dispatch (c);
+ c->pop_transform ();
+}
+
+HB_INTERNAL void PaintScaleAroundCenter::paint (hb_colrv1_paint_context_t* c) const
+{
+ c->push_transform (0, 0, 0, 0, - centerX, - centerY);
+ c->push_transform (scaleX, 0, 0, scaleY, 0, 0);
+ c->push_transform (0, 0, 0, 0, centerX, centerY);
+ (this+src).dispatch (c);
+ c->pop_transform ();
+ c->pop_transform ();
+ c->pop_transform ();
+}
+
+HB_INTERNAL void PaintScaleUniform::paint (hb_colrv1_paint_context_t* c) const
+{
+ c->push_transform (scale, 0, 0, scale, 0, 0);
+ (this+src).dispatch (c);
+ c->pop_transform ();
+}
+
+HB_INTERNAL void PaintScaleUniformAroundCenter::paint (hb_colrv1_paint_context_t* c) const
+{
+ c->push_transform (0, 0, 0, 0, - centerX, - centerY);
+ c->push_transform (scale, 0, 0, scale, 0, 0);
+ c->push_transform (0, 0, 0, 0, centerX, centerY);
+ (this+src).dispatch (c);
+ c->pop_transform ();
+ c->pop_transform ();
+ c->pop_transform ();
+}
+
+HB_INTERNAL void PaintRotate::paint (hb_colrv1_paint_context_t* c) const
+{
+ c->push_transform (cos (angle), sin (angle),
+ - sin (angle), cos (angle),
+ 0, 0);
+ (this+src).dispatch (c);
+ c->pop_transform ();
+}
+
+HB_INTERNAL void PaintRotateAroundCenter::paint (hb_colrv1_paint_context_t* c) const
+{
+ c->push_transform (0, 0, 0, 0, - centerX, - centerY);
+ c->push_transform (cos (angle), sin (angle),
+ - sin (angle), cos (angle),
+ 0, 0);
+ c->push_transform (0, 0, 0, 0, centerX, centerY);
+ (this+src).dispatch (c);
+ c->pop_transform ();
+ c->pop_transform ();
+ c->pop_transform ();
+}
+
+HB_INTERNAL void PaintSkew::paint (hb_colrv1_paint_context_t* c) const
+{
+ c->push_transform (1, tan (ySkewAngle),
+ - tan (xSkewAngle), 1,
+ 0, 0);
+ (this+src).dispatch (c);
+ c->pop_transform ();
+}
+
+HB_INTERNAL void PaintSkewAroundCenter::paint (hb_colrv1_paint_context_t* c) const
+{
+ c->push_transform (0, 0, 0, 0, - centerX, - centerY);
+ c->push_transform (1, tan (ySkewAngle),
+ - tan (xSkewAngle), 1,
+ 0, 0);
+ c->push_transform (0, 0, 0, 0, centerX, centerY);
+ (this+src).dispatch (c);
+ c->pop_transform ();
+ c->pop_transform ();
+ c->pop_transform ();
+}
+
+HB_INTERNAL void PaintComposite::paint (hb_colrv1_paint_context_t* c) const
+{
+ c->push_group ();
+ (this+src).dispatch (c);
+ c->push_group ();
+ (this+backdrop).dispatch (c);
+ c->pop_group_and_composite (mode);
+ c->pop_group_and_composite (HB_PAINT_COMPOSITE_MODE_OVER);
+}
+
+HB_INTERNAL void PaintSolid::paint (hb_colrv1_paint_context_t *c) const
+{
+ c->solid (paletteIndex);
+}
+
+HB_INTERNAL void PaintLinearGradient::paint (hb_colrv1_paint_context_t *c) const
+{
+ c->linear_gradient (color_line, x0, y0, x1, y1, x2, y2);
+}
+
+HB_INTERNAL void PaintRadialGradient::paint (hb_colrv1_paint_context_t *c) const
+{
+ c->radial_gradient (color_line, x0, y0, radius0, x1, y1, radius1);
+}
+
+HB_INTERNAL void PaintSweepGradient::paint (hb_colrv1_paint_context_t *c) const
+{
+ c->sweep_gradient (color_line, centerX, centerY, startAngle, endAngle);
+}
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_COLR_COLRV1_CLOSURE_HH */
diff --git a/src/hb-ot-color-sbix-table.hh b/src/hb-ot-color-sbix-table.hh
index 1d1d2e89d..10d4b3a85 100644
--- a/src/hb-ot-color-sbix-table.hh
+++ b/src/hb-ot-color-sbix-table.hh
@@ -30,6 +30,7 @@
#include "hb-open-type.hh"
#include "hb-ot-layout-common.hh"
+#include "hb-paint.hh"
/*
* sbix -- Standard Bitmap Graphics
@@ -213,10 +214,11 @@ struct sbix
bool get_extents (hb_font_t *font,
hb_codepoint_t glyph,
- hb_glyph_extents_t *extents) const
+ hb_glyph_extents_t *extents,
+ bool scale = true) const
{
/* We only support PNG right now, and following function checks type. */
- return get_png_extents (font, glyph, extents);
+ return get_png_extents (font, glyph, extents, scale);
}
hb_blob_t *reference_png (hb_font_t *font,
@@ -231,6 +233,37 @@ struct sbix
num_glyphs, available_ppem);
}
+ bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const
+ {
+ if (!has_data ())
+ return false;
+
+ int x_offset = 0, y_offset = 0;
+ unsigned int strike_ppem = 0;
+ hb_blob_t *blob = reference_png (font, glyph, &x_offset, &y_offset, &strike_ppem);
+ hb_glyph_extents_t extents;
+ hb_glyph_extents_t pixel_extents;
+
+ if (blob == hb_blob_get_empty ())
+ return false;
+
+ if (!hb_font_get_glyph_extents (font, glyph, &extents))
+ return false;
+
+ if (unlikely (!get_extents (font, glyph, &pixel_extents, false)))
+ return false;
+
+ funcs->image (data,
+ blob,
+ pixel_extents.width, -pixel_extents.height,
+ HB_PAINT_IMAGE_FORMAT_PNG,
+ font->slant_xy,
+ &extents);
+
+ hb_blob_destroy (blob);
+ return true;
+ }
+
private:
const SBIXStrike &choose_strike (hb_font_t *font) const
@@ -285,7 +318,8 @@ struct sbix
bool get_png_extents (hb_font_t *font,
hb_codepoint_t glyph,
- hb_glyph_extents_t *extents) const
+ hb_glyph_extents_t *extents,
+ bool scale = true) const
{
/* Following code is safe to call even without data.
* But faster to short-circuit. */
@@ -310,7 +344,7 @@ struct sbix
extents->height = -1 * png.IHDR.height;
/* Convert to font units. */
- if (strike_ppem)
+ if (strike_ppem && scale)
{
float scale = font->face->get_upem () / (float) strike_ppem;
extents->x_bearing = roundf (extents->x_bearing * scale);
@@ -318,15 +352,9 @@ struct sbix
extents->width = roundf (extents->width * scale);
extents->height = roundf (extents->height * scale);
}
- else
- {
- extents->x_bearing = extents->x_bearing;
- extents->y_bearing = extents->y_bearing;
- extents->width = extents->width;
- extents->height = extents->height;
- }
- font->scale_glyph_extents (extents);
+ if (scale)
+ font->scale_glyph_extents (extents);
hb_blob_destroy (blob);
diff --git a/src/hb-ot-color-svg-table.hh b/src/hb-ot-color-svg-table.hh
index fc649f100..042faa384 100644
--- a/src/hb-ot-color-svg-table.hh
+++ b/src/hb-ot-color-svg-table.hh
@@ -26,6 +26,8 @@
#define HB_OT_COLOR_SVG_TABLE_HH
#include "hb-open-type.hh"
+#include "hb-blob.hh"
+#include "hb-paint.hh"
/*
* SVG -- SVG (Scalable Vector Graphics)
@@ -91,8 +93,31 @@ struct SVG
bool has_data () const { return table->has_data (); }
+ bool paint_glyph (hb_font_t *font HB_UNUSED, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const
+ {
+ if (!has_data ())
+ return false;
+
+ hb_blob_t *blob = reference_blob_for_glyph (glyph);
+
+ if (blob == hb_blob_get_empty ())
+ return false;
+
+ funcs->image (data,
+ blob,
+ 0, 0,
+ HB_PAINT_IMAGE_FORMAT_SVG,
+ font->slant_xy,
+ nullptr);
+
+ hb_blob_destroy (blob);
+ return true;
+ }
+
private:
hb_blob_ptr_t