Merge pull request #3938 from harfbuzz/wip/matthiasc/paint-api

hb-paint API
This commit is contained in:
Behdad Esfahbod 2022-12-24 09:51:11 -07:00 committed by GitHub
commit f9081fc358
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
69 changed files with 17648 additions and 346 deletions

View File

@ -57,6 +57,7 @@
<xi:include href="xml/hb-buffer.xml"/>
<xi:include href="xml/hb-common.xml"/>
<xi:include href="xml/hb-draw.xml"/>
<xi:include href="xml/hb-paint.xml"/>
<xi:include href="xml/hb-deprecated.xml"/>
<xi:include href="xml/hb-face.xml"/>
<xi:include href="xml/hb-font.xml"/>

View File

@ -191,8 +191,11 @@ HB_DEPRECATED_FOR
<SECTION>
<FILE>hb-draw</FILE>
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
</SECTION>
<SECTION>
<FILE>hb-paint</FILE>
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
</SECTION>
<SECTION>
<FILE>hb-deprecated</FILE>
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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<hb_draw_funcs_t *> (&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

View File

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

View File

@ -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_t *> (&_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>Note: The glyph shape fetched via the
* hb_font_get_glyph_shape() is slanted to reflect this value
* as well.</note>
* <note>Note: The glyph shape fetched via the hb_font_draw_glyph()
* function is slanted to reflect this value as well.</note>
*
* <note>Note: The slant value is a ratio. For example, a
* 20% slant would be represented as a 0.2 value.</note>
@ -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);
}

View File

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

View File

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

547
src/hb-ft-colr.hh Normal file
View File

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

View File

@ -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_t<hb_ft
hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, nullptr, nullptr);
#ifndef HB_NO_DRAW
hb_font_funcs_set_glyph_shape_func (funcs, hb_ft_get_glyph_shape, nullptr, nullptr);
hb_font_funcs_set_draw_glyph_func (funcs, hb_ft_draw_glyph, nullptr, nullptr);
#endif
#ifndef HB_NO_PAINT
hb_font_funcs_set_paint_glyph_func (funcs, hb_ft_paint_glyph, nullptr, nullptr);
#endif
hb_font_funcs_make_immutable (funcs);

View File

@ -91,6 +91,7 @@ hb_gobject_##name##_get_type () \
HB_DEFINE_OBJECT_TYPE (buffer)
HB_DEFINE_OBJECT_TYPE (blob)
HB_DEFINE_OBJECT_TYPE (draw_funcs)
HB_DEFINE_OBJECT_TYPE (paint_funcs)
HB_DEFINE_OBJECT_TYPE (face)
HB_DEFINE_OBJECT_TYPE (font)
HB_DEFINE_OBJECT_TYPE (font_funcs)

View File

@ -52,6 +52,10 @@ HB_EXTERN GType
hb_gobject_draw_funcs_get_type (void);
#define HB_GOBJECT_TYPE_DRAW_FUNCS (hb_gobject_draw_funcs_get_type ())
HB_EXTERN GType
hb_gobject_paint_funcs_get_type (void);
#define HB_GOBJECT_TYPE_PAINT_FUNCS (hb_gobject_paint_funcs_get_type ())
HB_EXTERN GType
hb_gobject_face_get_type (void);
#define HB_GOBJECT_TYPE_FACE (hb_gobject_face_get_type ())

View File

@ -553,6 +553,15 @@ bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoin
return true;
}
bool OT::cff1::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;
}
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

View File

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

View File

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

View File

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

View File

@ -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<int> (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<GlyphBitmapDataFormat17> (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<GlyphBitmapDataFormat18> (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> cblc;
hb_blob_ptr_t<CBDT> cbdt;

View File

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

View File

@ -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<hb_paint_context_t>
{
template <typename T>
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<const COLR *> (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<hb_colrv1_closure_context_t>
{
@ -160,6 +231,8 @@ struct BaseGlyphRecord
template <typename T>
struct Variable
{
static constexpr bool is_variable = true;
Variable<T>* 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 <typename T>
struct NoVariable
{
static constexpr bool is_variable = false;
static constexpr uint32_t varIdxBase = VarIdx::NO_VARIATION;
NoVariable<T>* 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<Var<ColorStop>> 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<Var>> 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<Var>> 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<Var>> 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> 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<Paint> src; /* Offset (from beginning of PaintTransform table) to Paint subtable. */
Offset24To<Var<Affine2x3>> 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<Paint> 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<Paint> 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<Paint> 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<Paint> 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<Paint> 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<Paint> 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<Paint> 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<Paint> 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<Paint> 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<Paint> 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<PaintSolid> paintformat2;
Variable<PaintSolid> paintformat3;
PaintLinearGradient<NoVariable> paintformat4;
NoVariable<PaintLinearGradient<NoVariable>> paintformat4;
Variable<PaintLinearGradient<Variable>> paintformat5;
PaintRadialGradient<NoVariable> paintformat6;
NoVariable<PaintRadialGradient<NoVariable>> paintformat6;
Variable<PaintRadialGradient<Variable>> paintformat7;
PaintSweepGradient<NoVariable> paintformat8;
NoVariable<PaintSweepGradient<NoVariable>> paintformat8;
Variable<PaintSweepGradient<Variable>> paintformat9;
PaintGlyph paintformat10;
PaintColrGlyph paintformat11;
PaintTransform<NoVariable> paintformat12;
PaintTransform<Variable> paintformat13;
PaintTranslate paintformat14;
NoVariable<PaintTranslate> paintformat14;
Variable<PaintTranslate> paintformat15;
PaintScale paintformat16;
NoVariable<PaintScale> paintformat16;
Variable<PaintScale> paintformat17;
PaintScaleAroundCenter paintformat18;
NoVariable<PaintScaleAroundCenter> paintformat18;
Variable<PaintScaleAroundCenter> paintformat19;
PaintScaleUniform paintformat20;
NoVariable<PaintScaleUniform> paintformat20;
Variable<PaintScaleUniform> paintformat21;
PaintScaleUniformAroundCenter paintformat22;
NoVariable<PaintScaleUniformAroundCenter> paintformat22;
Variable<PaintScaleUniformAroundCenter> paintformat23;
PaintRotate paintformat24;
NoVariable<PaintRotate> paintformat24;
Variable<PaintRotate> paintformat25;
PaintRotateAroundCenter paintformat26;
NoVariable<PaintRotateAroundCenter> paintformat26;
Variable<PaintRotateAroundCenter> paintformat27;
PaintSkew paintformat28;
NoVariable<PaintSkew> paintformat28;
Variable<PaintSkew> paintformat29;
PaintSkewAroundCenter paintformat30;
NoVariable<PaintSkewAroundCenter> paintformat30;
Variable<PaintSkewAroundCenter> 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 */

View File

@ -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<hb_colrv1_paint_context_t>
{
template <typename T>
return_t dispatch (const T &obj)
{
obj.paint (this);
return hb_empty_t ();
}
const COLR* get_colr_table () const
{ return reinterpret_cast<const COLR *> (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 <template<typename> class Var>
HB_INTERNAL void PaintTransform<Var>::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 */

View File

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

View File

@ -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<SVG> table;
public:
DEFINE_SIZE_STATIC (sizeof (hb_blob_ptr_t<SVG>));
};
const SVGDocumentIndexEntry &get_glyph_entry (hb_codepoint_t glyph_id) const

View File

@ -167,6 +167,10 @@ hb_ot_color_palette_get_flags (hb_face_t *face,
* for allocating a buffer of suitable size before calling
* hb_ot_color_palette_get_colors() a second time.
*
* The RGBA values in the palette are unpremultiplied. See the
* OpenType spec [CPAL](https://learn.microsoft.com/en-us/typography/opentype/spec/cpal)
* section for details.
*
* Return value: the total number of colors in the palette
*
* Since: 2.1.0
@ -190,7 +194,8 @@ hb_ot_color_palette_get_colors (hb_face_t *face,
* hb_ot_color_has_layers:
* @face: #hb_face_t to work upon
*
* Tests whether a face includes any `COLR` color layers.
* Tests whether a face includes a `COLR` table
* with data according to COLRv0.
*
* Return value: `true` if data found, `false` otherwise
*
@ -199,7 +204,24 @@ hb_ot_color_palette_get_colors (hb_face_t *face,
hb_bool_t
hb_ot_color_has_layers (hb_face_t *face)
{
return face->table.COLR->has_data ();
return face->table.COLR->has_v0_data ();
}
/**
* hb_ot_color_has_paint:
* @face: #hb_face_t to work upon
*
* Tests where a face includes a `COLR` table
* with data according to COLRv1.
*
* Return value: `true` if data found, `false` otherwise
*
* Since: REPLACEME
*/
hb_bool_t
hb_ot_color_has_paint (hb_face_t *face)
{
return face->table.COLR->has_v1_data ();
}
/**

View File

@ -120,6 +120,11 @@ hb_ot_color_glyph_get_layers (hb_face_t *face,
unsigned int *layer_count, /* IN/OUT. May be NULL. */
hb_ot_color_layer_t *layers /* OUT. May be NULL. */);
/* COLRv1 */
HB_EXTERN hb_bool_t
hb_ot_color_has_paint (hb_face_t *face);
/*
* SVG
*/

View File

@ -46,6 +46,7 @@
#include "hb-ot-color-cbdt-table.hh"
#include "hb-ot-color-sbix-table.hh"
#include "hb-ot-color-colr-table.hh"
#include "hb-ot-color-svg-table.hh"
/**
@ -424,11 +425,11 @@ hb_ot_get_font_v_extents (hb_font_t *font,
#ifndef HB_NO_DRAW
static void
hb_ot_get_glyph_shape (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_ot_draw_glyph (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_draw_session_t draw_session (draw_funcs, draw_data, font->slant_xy);
if (font->face->table.glyf->get_path (font, glyph, draw_session)) return;
@ -439,6 +440,32 @@ hb_ot_get_glyph_shape (hb_font_t *font,
}
#endif
#ifndef HB_NO_PAINT
static void
hb_ot_paint_glyph (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)
{
#ifndef HB_NO_COLOR
if (font->face->table.COLR->paint_glyph (font, glyph, paint_funcs, paint_data, palette, foreground)) return;
if (font->face->table.SVG->paint_glyph (font, glyph, paint_funcs, paint_data)) return;
#ifndef HB_NO_OT_FONT_BITMAP
if (font->face->table.CBDT->paint_glyph (font, glyph, paint_funcs, paint_data)) return;
if (font->face->table.sbix->paint_glyph (font, glyph, paint_funcs, paint_data)) return;
#endif
#endif
if (font->face->table.glyf->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return;
#ifndef HB_NO_CFF
if (font->face->table.cff1->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return;
if (font->face->table.cff2->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return;
#endif
}
#endif
static inline void free_static_ot_funcs ();
static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot_font_funcs_lazy_loader_t>
@ -462,7 +489,11 @@ static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot
#endif
#ifndef HB_NO_DRAW
hb_font_funcs_set_glyph_shape_func (funcs, hb_ot_get_glyph_shape, nullptr, nullptr);
hb_font_funcs_set_draw_glyph_func (funcs, hb_ot_draw_glyph, nullptr, nullptr);
#endif
#ifndef HB_NO_PAINT
hb_font_funcs_set_paint_glyph_func (funcs, hb_ot_paint_glyph, nullptr, nullptr);
#endif
hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, nullptr, nullptr);

540
src/hb-paint-extents.hh Normal file
View File

@ -0,0 +1,540 @@
/*
* 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_PAINT_EXTENTS_HH
#define HB_PAINT_EXTENTS_HH
#include "hb.hh"
#include "hb-paint.hh"
#include "hb-draw.h"
typedef struct hb_extents_t
{
hb_extents_t () {}
hb_extents_t (float xmin, float ymin, float xmax, float ymax) :
xmin (xmin), ymin (ymin), xmax (xmax), ymax (ymax) {}
bool is_empty () const { return xmin > xmax; }
float xmin = 0.f;
float ymin = 0.f;
float xmax = -1.f;
float ymax = -1.f;
} hb_extents_t;
typedef struct hb_transform_t
{
hb_transform_t () {}
hb_transform_t (float xx, float yx,
float xy, float yy,
float x0, float y0) :
xx (xx), yx (yx), xy (xy), yy (yy), x0 (x0), y0 (y0) {}
void multiply (const hb_transform_t &o)
{
/* Copied from cairo, with "o" being "a" there and "this" being "b" there. */
hb_transform_t r;
r.xx = o.xx * xx + o.yx * xy;
r.yx = o.xx * yx + o.yx * yy;
r.xy = o.xy * xx + o.yy * xy;
r.yy = o.xy * yx + o.yy * yy;
r.x0 = o.x0 * xx + o.y0 * xy + x0;
r.y0 = o.x0 * yx + o.y0 * yy + y0;
*this = r;
}
void transform_distance (float &dx, float &dy)
{
float new_x = xx * dx + xy * dy;
float new_y = yx * dx + yy * dy;
dx = new_x;
dy = new_y;
}
void transform_point (float &x, float &y)
{
transform_distance (x, y);
x += x0;
y += y0;
}
void transform_extents (hb_extents_t extents)
{
float quad_x[4], quad_y[4];
quad_x[0] = extents.xmin;
quad_y[0] = extents.ymin;
quad_x[1] = extents.xmin;
quad_y[1] = extents.ymax;
quad_x[2] = extents.xmax;
quad_y[2] = extents.ymin;
quad_x[3] = extents.xmax;
quad_y[3] = extents.ymax;
for (unsigned i = 0; i < 4; i++)
transform_point (quad_x[i], quad_y[i]);
extents.xmin = extents.xmax = quad_x[0];
extents.ymin = extents.ymax = quad_y[0];
for (unsigned i = 1; i < 4; i++)
{
extents.xmin = hb_min (extents.xmin, quad_x[i]);
extents.ymin = hb_min (extents.ymin, quad_y[i]);
extents.xmax = hb_max (extents.xmax, quad_x[i]);
extents.ymax = hb_max (extents.ymax, quad_y[i]);
}
}
float xx = 1.f;
float yx = 0.f;
float xy = 0.f;
float yy = 1.f;
float x0 = 0.f;
float y0 = 0.f;
} hb_transform_t;
typedef struct hb_bounds_t
{
enum status_t {
EMPTY,
BOUNDED,
UNBOUNDED,
};
hb_bounds_t (status_t status) : status (status) {}
hb_bounds_t (const hb_extents_t &extents) :
status (extents.is_empty () ? EMPTY : BOUNDED), extents (extents) {}
status_t status;
hb_extents_t extents;
} hb_bounds_t;
typedef struct hb_paint_extents_context_t hb_paint_extents_context_t;
struct hb_paint_extents_context_t {
hb_paint_extents_context_t ()
{
clips.push (hb_bounds_t{hb_bounds_t::UNBOUNDED});
groups.push (hb_bounds_t{hb_bounds_t::EMPTY});
transforms.push (hb_transform_t{});
}
hb_extents_t get_extents ()
{
return groups.tail().extents;
}
bool is_bounded ()
{
return groups.tail().status != hb_bounds_t::UNBOUNDED;
}
void push_transform (const hb_transform_t &trans)
{
hb_transform_t r = transforms.tail ();
r.multiply (trans);
transforms.push (r);
}
void pop_transform ()
{
transforms.pop ();
}
void push_clip (hb_extents_t extents)
{
/* Transform extents and push a new clip. */
hb_transform_t &r = transforms.tail ();
r.transform_extents (extents);
hb_bounds_t b {extents};
clips.push (b);
}
void pop_clip ()
{
clips.pop ();
}
void push_group ()
{
groups.push (hb_bounds_t{hb_bounds_t::EMPTY});
}
void pop_group (hb_paint_composite_mode_t mode)
{
const hb_bounds_t src_bounds = groups.pop ();
hb_bounds_t &backdrop_bounds = groups.tail ();
switch ((int) mode)
{
case HB_PAINT_COMPOSITE_MODE_CLEAR:
backdrop_bounds.status = hb_bounds_t::EMPTY;
break;
case HB_PAINT_COMPOSITE_MODE_SRC:
case HB_PAINT_COMPOSITE_MODE_SRC_OUT:
backdrop_bounds = src_bounds;
break;
case HB_PAINT_COMPOSITE_MODE_DEST:
case HB_PAINT_COMPOSITE_MODE_DEST_OUT:
break;
case HB_PAINT_COMPOSITE_MODE_SRC_IN:
case HB_PAINT_COMPOSITE_MODE_DEST_IN:
// Intersect
if (src_bounds.status == hb_bounds_t::EMPTY)
backdrop_bounds.status = hb_bounds_t::EMPTY;
else if (src_bounds.status == hb_bounds_t::BOUNDED)
{
if (backdrop_bounds.status == hb_bounds_t::UNBOUNDED)
backdrop_bounds = src_bounds;
else if (backdrop_bounds.status == hb_bounds_t::BOUNDED)
{
backdrop_bounds.extents.xmin = hb_max (backdrop_bounds.extents.xmin, src_bounds.extents.xmin);
backdrop_bounds.extents.ymin = hb_max (backdrop_bounds.extents.ymin, src_bounds.extents.ymin);
backdrop_bounds.extents.xmax = hb_min (backdrop_bounds.extents.xmax, src_bounds.extents.xmax);
backdrop_bounds.extents.ymax = hb_min (backdrop_bounds.extents.ymax, src_bounds.extents.ymax);
if (backdrop_bounds.extents.xmin >= backdrop_bounds.extents.xmax ||
backdrop_bounds.extents.ymin >= backdrop_bounds.extents.ymax)
backdrop_bounds.status = hb_bounds_t::EMPTY;
}
}
break;
default:
// Union
if (src_bounds.status == hb_bounds_t::UNBOUNDED)
backdrop_bounds.status = hb_bounds_t::UNBOUNDED;
else if (src_bounds.status == hb_bounds_t::BOUNDED)
{
if (backdrop_bounds.status == hb_bounds_t::EMPTY)
backdrop_bounds = src_bounds;
else if (backdrop_bounds.status == hb_bounds_t::BOUNDED)
{
backdrop_bounds.extents.xmin = hb_min (backdrop_bounds.extents.xmin, src_bounds.extents.xmin);
backdrop_bounds.extents.ymin = hb_min (backdrop_bounds.extents.ymin, src_bounds.extents.ymin);
backdrop_bounds.extents.xmax = hb_max (backdrop_bounds.extents.xmax, src_bounds.extents.xmax);
backdrop_bounds.extents.ymax = hb_max (backdrop_bounds.extents.ymax, src_bounds.extents.ymax);
}
}
break;
}
}
void paint ()
{
/* Union current clip bounds with current group bounds. */
const hb_bounds_t &clip = clips.tail ();
hb_bounds_t &group = groups.tail ();
if (clip.status == hb_bounds_t::EMPTY)
return; // Shouldn't happen
if (group.status == hb_bounds_t::UNBOUNDED)
return;
if (group.status == hb_bounds_t::EMPTY)
{
group = clip;
return;
}
/* Group is bounded now. Clip is not empty. */
if (clip.status == hb_bounds_t::UNBOUNDED)
{
group.status = hb_bounds_t::UNBOUNDED;
return;
}
/* Both are bounded. Union. */
group.extents.xmin = hb_min (group.extents.xmin, clip.extents.xmin);
group.extents.ymin = hb_min (group.extents.ymin, clip.extents.ymin);
group.extents.xmax = hb_max (group.extents.xmax, clip.extents.xmax);
group.extents.ymax = hb_max (group.extents.ymax, clip.extents.ymax);
}
hb_vector_t<hb_bounds_t> clips;
hb_vector_t<hb_bounds_t> groups;
hb_vector_t<hb_transform_t> transforms;
};
static void
hb_paint_extents_push_transform (hb_paint_funcs_t *funcs HB_UNUSED,
void *paint_data,
float xx, float yx,
float xy, float yy,
float dx, float dy,
void *user_data HB_UNUSED)
{
hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
c->push_transform (hb_transform_t {xx, yx, xy, yy, dx, dy});
}
static void
hb_paint_extents_pop_transform (hb_paint_funcs_t *funcs HB_UNUSED,
void *paint_data,
void *user_data HB_UNUSED)
{
hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
c->pop_transform ();
}
static void
add_point (hb_extents_t *extents,
float x, float y)
{
if (extents->xmax < extents->xmin)
{
extents->xmin = extents->xmax = x;
extents->ymin = extents->ymax = y;
}
else
{
extents->xmin = hb_min (extents->xmin, x);
extents->ymin = hb_min (extents->ymin, y);
extents->xmax = hb_max (extents->xmax, x);
extents->ymax = hb_max (extents->ymax, y);
}
}
static void
move_to (hb_draw_funcs_t *dfuncs,
void *data,
hb_draw_state_t *st,
float to_x, float to_y,
void *)
{
hb_extents_t *extents = (hb_extents_t *)data;
add_point (extents, to_x, to_y);
}
static void
line_to (hb_draw_funcs_t *dfuncs,
void *data,
hb_draw_state_t *st,
float to_x, float to_y,
void *)
{
hb_extents_t *extents = (hb_extents_t *)data;
add_point (extents, to_x, to_y);
}
static void
cubic_to (hb_draw_funcs_t *dfuncs,
void *data,
hb_draw_state_t *st,
float control1_x, float control1_y,
float control2_x, float control2_y,
float to_x, float to_y,
void *)
{
hb_extents_t *extents = (hb_extents_t *)data;
add_point (extents, control1_x, control1_y);
add_point (extents, control2_x, control2_y);
add_point (extents, to_x, to_y);
}
static void
close_path (hb_draw_funcs_t *dfuncs,
void *data,
hb_draw_state_t *st,
void *)
{
}
static hb_draw_funcs_t *
hb_draw_extent_get_funcs ()
{
hb_draw_funcs_t *funcs = hb_draw_funcs_create ();
hb_draw_funcs_set_move_to_func (funcs, move_to, nullptr, nullptr);
hb_draw_funcs_set_line_to_func (funcs, line_to, nullptr, nullptr);
hb_draw_funcs_set_cubic_to_func (funcs, cubic_to, nullptr, nullptr);
hb_draw_funcs_set_close_path_func (funcs, close_path, nullptr, nullptr);
return funcs;
}
static void
hb_paint_extents_push_clip_glyph (hb_paint_funcs_t *funcs HB_UNUSED,
void *paint_data,
hb_codepoint_t glyph,
hb_font_t *font,
void *user_data HB_UNUSED)
{
hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
hb_extents_t extents;
hb_draw_funcs_t *draw_extent_funcs = hb_draw_extent_get_funcs ();
hb_font_draw_glyph (font, glyph, draw_extent_funcs, &extents);
hb_draw_funcs_destroy (draw_extent_funcs);
c->push_clip (extents);
}
static void
hb_paint_extents_push_clip_rectangle (hb_paint_funcs_t *funcs HB_UNUSED,
void *paint_data,
float xmin, float ymin, float xmax, float ymax,
void *user_data)
{
hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
hb_extents_t extents = {xmin, ymin, xmax, ymax};
c->push_clip (extents);
}
static void
hb_paint_extents_pop_clip (hb_paint_funcs_t *funcs HB_UNUSED,
void *paint_data,
void *user_data HB_UNUSED)
{
hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
c->pop_clip ();
}
static void
hb_paint_extents_push_group (hb_paint_funcs_t *funcs HB_UNUSED,
void *paint_data,
void *user_data HB_UNUSED)
{
hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
c->push_group ();
}
static void
hb_paint_extents_pop_group (hb_paint_funcs_t *funcs HB_UNUSED,
void *paint_data,
hb_paint_composite_mode_t mode,
void *user_data HB_UNUSED)
{
hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
c->pop_group (mode);
}
static void
hb_paint_extents_paint_image (hb_paint_funcs_t *funcs HB_UNUSED,
void *paint_data,
hb_blob_t *blob HB_UNUSED,
unsigned int width HB_UNUSED,
unsigned int height HB_UNUSED,
hb_tag_t format HB_UNUSED,
float slant HB_UNUSED,
hb_glyph_extents_t *glyph_extents,
void *user_data HB_UNUSED)
{
hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
hb_extents_t extents = {(float) glyph_extents->x_bearing,
(float) glyph_extents->y_bearing + glyph_extents->height,
(float) glyph_extents->x_bearing + glyph_extents->width,
(float) glyph_extents->y_bearing};
c->push_clip (extents);
c->paint ();
c->pop_clip ();
}
static void
hb_paint_extents_paint_color (hb_paint_funcs_t *funcs HB_UNUSED,
void *paint_data,
hb_bool_t use_foreground HB_UNUSED,
hb_color_t color HB_UNUSED,
void *user_data HB_UNUSED)
{
hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
c->paint ();
}
static void
hb_paint_extents_paint_linear_gradient (hb_paint_funcs_t *funcs HB_UNUSED,
void *paint_data,
hb_color_line_t *color_line HB_UNUSED,
float x0 HB_UNUSED, float y0 HB_UNUSED,
float x1 HB_UNUSED, float y1 HB_UNUSED,
float x2 HB_UNUSED, float y2 HB_UNUSED,
void *user_data HB_UNUSED)
{
hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
c->paint ();
}
static void
hb_paint_extents_paint_radial_gradient (hb_paint_funcs_t *funcs HB_UNUSED,
void *paint_data,
hb_color_line_t *color_line HB_UNUSED,
float x0 HB_UNUSED, float y0 HB_UNUSED, float r0 HB_UNUSED,
float x1 HB_UNUSED, float y1 HB_UNUSED, float r1 HB_UNUSED,
void *user_data HB_UNUSED)
{
hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
c->paint ();
}
static void
hb_paint_extents_paint_sweep_gradient (hb_paint_funcs_t *funcs HB_UNUSED,
void *paint_data,
hb_color_line_t *color_line HB_UNUSED,
float cx HB_UNUSED, float cy HB_UNUSED,
float start_angle HB_UNUSED,
float end_angle HB_UNUSED,
void *user_data HB_UNUSED)
{
hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
c->paint ();
}
static inline hb_paint_funcs_t *
hb_paint_extents_get_funcs ()
{
hb_paint_funcs_t *funcs = hb_paint_funcs_create ();
hb_paint_funcs_set_push_transform_func (funcs, hb_paint_extents_push_transform, nullptr, nullptr);
hb_paint_funcs_set_pop_transform_func (funcs, hb_paint_extents_pop_transform, nullptr, nullptr);
hb_paint_funcs_set_push_clip_glyph_func (funcs, hb_paint_extents_push_clip_glyph, nullptr, nullptr);
hb_paint_funcs_set_push_clip_rectangle_func (funcs, hb_paint_extents_push_clip_rectangle, nullptr, nullptr);
hb_paint_funcs_set_pop_clip_func (funcs, hb_paint_extents_pop_clip, nullptr, nullptr);
hb_paint_funcs_set_push_group_func (funcs, hb_paint_extents_push_group, nullptr, nullptr);
hb_paint_funcs_set_pop_group_func (funcs, hb_paint_extents_pop_group, nullptr, nullptr);
hb_paint_funcs_set_color_func (funcs, hb_paint_extents_paint_color, nullptr, nullptr);
hb_paint_funcs_set_image_func (funcs, hb_paint_extents_paint_image, nullptr, nullptr);
hb_paint_funcs_set_linear_gradient_func (funcs, hb_paint_extents_paint_linear_gradient, nullptr, nullptr);
hb_paint_funcs_set_radial_gradient_func (funcs, hb_paint_extents_paint_radial_gradient, nullptr, nullptr);
hb_paint_funcs_set_sweep_gradient_func (funcs, hb_paint_extents_paint_sweep_gradient, nullptr, nullptr);
return funcs;
}
#endif /* HB_PAINT_EXTENTS_HH */

429
src/hb-paint.cc Normal file
View File

@ -0,0 +1,429 @@
/*
* 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.
*/
#include "hb.hh"
#ifndef HB_NO_PAINT
#include "hb-paint.hh"
/**
* SECTION: hb-paint
* @title: hb-paint
* @short_description: Glyph painting
* @include: hb.h
*
* Functions for painting glyphs.
*
* The main purpose of these functions is to paint (extract) color glyph layers
* from the COLRv1 table, but the API works for drawing ordinary outlines and
* images as well.
*
* The #hb_paint_funcs_t struct can be used with hb_font_paint_glyph().
**/
static void
hb_paint_push_transform_nil (hb_paint_funcs_t *funcs, void *paint_data,
float xx, float yx,
float xy, float yy,
float dx, float dy,
void *user_data) {}
static void
hb_paint_pop_transform_nil (hb_paint_funcs_t *funcs, void *paint_data,
void *user_data) {}
static void
hb_paint_push_clip_glyph_nil (hb_paint_funcs_t *funcs, void *paint_data,
hb_codepoint_t glyph,
hb_font_t *font,
void *user_data) {}
static void
hb_paint_push_clip_rectangle_nil (hb_paint_funcs_t *funcs, void *paint_data,
float xmin, float ymin, float xmax, float ymax,
void *user_data) {}
static void
hb_paint_pop_clip_nil (hb_paint_funcs_t *funcs, void *paint_data,
void *user_data) {}
static void
hb_paint_color_nil (hb_paint_funcs_t *funcs, void *paint_data,
hb_bool_t is_foreground,
hb_color_t color,
void *user_data) {}
static void
hb_paint_image_nil (hb_paint_funcs_t *funcs, void *paint_data,
hb_blob_t *image,
unsigned int width,
unsigned int height,
hb_tag_t format,
float slant_xy,
hb_glyph_extents_t *extents,
void *user_data) {}
static void
hb_paint_linear_gradient_nil (hb_paint_funcs_t *funcs, void *paint_data,
hb_color_line_t *color_line,
float x0, float y0,
float x1, float y1,
float x2, float y2,
void *user_data) {}
static void
hb_paint_radial_gradient_nil (hb_paint_funcs_t *funcs, void *paint_data,
hb_color_line_t *color_line,
float x0, float y0, float r0,
float x1, float y1, float r1,
void *user_data) {}
static void
hb_paint_sweep_gradient_nil (hb_paint_funcs_t *funcs, void *paint_data,
hb_color_line_t *color_line,
float x0, float y0,
float start_angle,
float end_angle,
void *user_data) {}
static void
hb_paint_push_group_nil (hb_paint_funcs_t *funcs, void *paint_data,
void *user_data) {}
static void
hb_paint_pop_group_nil (hb_paint_funcs_t *funcs, void *paint_data,
hb_paint_composite_mode_t mode,
void *user_data) {}
static bool
_hb_paint_funcs_set_preamble (hb_paint_funcs_t *funcs,
bool func_is_null,
void **user_data,
hb_destroy_func_t *destroy)
{
if (hb_object_is_immutable (funcs))
{
if (*destroy)
(*destroy) (*user_data);
return false;
}
if (func_is_null)
{
if (*destroy)
(*destroy) (*user_data);
*destroy = nullptr;
*user_data = nullptr;
}
return true;
}
static bool
_hb_paint_funcs_set_middle (hb_paint_funcs_t *funcs,
void *user_data,
hb_destroy_func_t destroy)
{
if (user_data && !funcs->user_data)
{
funcs->user_data = (decltype (funcs->user_data)) hb_calloc (1, sizeof (*funcs->user_data));
if (unlikely (!funcs->user_data))
goto fail;
}
if (destroy && !funcs->destroy)
{
funcs->destroy = (decltype (funcs->destroy)) hb_calloc (1, sizeof (*funcs->destroy));
if (unlikely (!funcs->destroy))
goto fail;
}
return true;
fail:
if (destroy)
(destroy) (user_data);
return false;
}
#define HB_PAINT_FUNC_IMPLEMENT(name) \
\
void \
hb_paint_funcs_set_##name##_func (hb_paint_funcs_t *funcs, \
hb_paint_##name##_func_t func, \
void *user_data, \
hb_destroy_func_t destroy) \
{ \
if (!_hb_paint_funcs_set_preamble (funcs, !func, &user_data, &destroy)) \
return; \
\
if (funcs->destroy && funcs->destroy->name) \
funcs->destroy->name (!funcs->user_data ? nullptr : funcs->user_data->name);\
\
if (!_hb_paint_funcs_set_middle (funcs, user_data, destroy)) \
return; \
\
if (func) \
funcs->func.name = func; \
else \
funcs->func.name = hb_paint_##name##_nil; \
\
if (funcs->user_data) \
funcs->user_data->name = user_data; \
if (funcs->destroy) \
funcs->destroy->name = destroy; \
}
HB_PAINT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_PAINT_FUNC_IMPLEMENT
/**
* hb_paint_funcs_create:
*
* Creates a new #hb_paint_funcs_t structure of paint functions.
*
* The initial reference count of 1 should be released with hb_paint_funcs_destroy()
* when you are done using the #hb_paint_funcs_t. This function never returns
* `NULL`. If memory cannot be allocated, a special singleton #hb_paint_funcs_t
* object will be returned.
*
* Returns value: (transfer full): the paint-functions structure
*
* Since: REPLACEME
*/
hb_paint_funcs_t *
hb_paint_funcs_create ()
{
hb_paint_funcs_t *funcs;
if (unlikely (!(funcs = hb_object_create<hb_paint_funcs_t> ())))
return const_cast<hb_paint_funcs_t *> (&Null (hb_paint_funcs_t));
funcs->func = Null (hb_paint_funcs_t).func;
return funcs;
}
DEFINE_NULL_INSTANCE (hb_paint_funcs_t) =
{
HB_OBJECT_HEADER_STATIC,
{
#define HB_PAINT_FUNC_IMPLEMENT(name) hb_paint_##name##_nil,
HB_PAINT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_PAINT_FUNC_IMPLEMENT
}
};
/**
* hb_paint_funcs_get_empty:
*
* Fetches the singleton empty paint-functions structure.
*
* Return value: (transfer full): The empty paint-functions structure
*
* Since: REPLACEME
**/
hb_paint_funcs_t *
hb_paint_funcs_get_empty ()
{
return const_cast<hb_paint_funcs_t *> (&Null (hb_paint_funcs_t));
}
/**
* hb_paint_funcs_reference: (skip)
* @funcs: The paint-functions structure
*
* Increases the reference count on a paint-functions structure.
*
* This prevents @funcs from being destroyed until a matching
* call to hb_paint_funcs_destroy() is made.
*
* Return value: The paint-functions structure
*
* Since: REPLACEME
*/
hb_paint_funcs_t *
hb_paint_funcs_reference (hb_paint_funcs_t *funcs)
{
return hb_object_reference (funcs);
}
/**
* hb_paint_funcs_destroy: (skip)
* @funcs: The paint-functions structure
*
* Decreases the reference count on a paint-functions structure.
*
* When the reference count reaches zero, the structure
* is destroyed, freeing all memory.
*
* Since: REPLACEME
*/
void
hb_paint_funcs_destroy (hb_paint_funcs_t *funcs)
{
if (!hb_object_destroy (funcs)) return;
if (funcs->destroy)
{
#define HB_PAINT_FUNC_IMPLEMENT(name) \
if (funcs->destroy->name) funcs->destroy->name (!funcs->user_data ? nullptr : funcs->user_data->name);
HB_PAINT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_PAINT_FUNC_IMPLEMENT
}
hb_free (funcs->destroy);
hb_free (funcs->user_data);
hb_free (funcs);
}
/**
* hb_paint_funcs_set_user_data: (skip)
* @funcs: The paint-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 paint-functions structure.
*
* Return value: `true` if success, `false` otherwise
*
* Since: REPLACEME
**/
hb_bool_t
hb_paint_funcs_set_user_data (hb_paint_funcs_t *funcs,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy,
hb_bool_t replace)
{
return hb_object_set_user_data (funcs, key, data, destroy, replace);
}
/**
* hb_paint_funcs_get_user_data: (skip)
* @funcs: The paint-functions structure
* @key: The user-data key to query
*
* Fetches the user-data associated with the specified key,
* attached to the specified paint-functions structure.
*
* Return value: (transfer none): A pointer to the user data
*
* Since: REPLACEME
**/
void *
hb_paint_funcs_get_user_data (const hb_paint_funcs_t *funcs,
hb_user_data_key_t *key)
{
return hb_object_get_user_data (funcs, key);
}
/**
* hb_paint_funcs_make_immutable:
* @funcs: The paint-functions structure
*
* Makes a paint-functions structure immutable.
*
* After this call, all attempts to set one of the callbacks
* on @funcs will fail.
*
* Since: REPLACEME
*/
void
hb_paint_funcs_make_immutable (hb_paint_funcs_t *funcs)
{
if (hb_object_is_immutable (funcs))
return;
hb_object_make_immutable (funcs);
}
/**
* hb_paint_funcs_is_immutable:
* @funcs: The paint-functions structure
*
* Tests whether a paint-functions structure is immutable.
*
* Return value: `true` if @funcs is immutable, `false` otherwise
*
* Since: REPLACEME
*/
hb_bool_t
hb_paint_funcs_is_immutable (hb_paint_funcs_t *funcs)
{
return hb_object_is_immutable (funcs);
}
/**
* hb_color_line_get_color_stops:
* @color_line: a #hb_color_line_t object
* @start: the index of the first color stop to return
* @count: (inout) (optional): Input = the maximum number of feature tags to return;
* Output = the actual number of feature tags returned (may be zero)
* @color_stops: (out) (array length=count) (optional): Array of #hb_color_stop_t to populate
*
* Fetches a list of color stops from the given color line object.
*
* Note that due to variations being applied, the returned color stops
* may be out of order. It is the callers responsibility to ensure that
* color stops are sorted by their offset before they are used.
*
* Return value: the total number of color stops in @cl
*
* Since: REPLACEME
*/
unsigned int
hb_color_line_get_color_stops (hb_color_line_t *color_line,
unsigned int start,
unsigned int *count,
hb_color_stop_t *color_stops)
{
return color_line->get_color_stops (color_line,
color_line->data,
start, count,
color_stops,
color_line->get_color_stops_user_data);
}
/**
* hb_color_line_get_extend:
* @color_line: a #hb_color_line_t object
*
* Fetches the extend mode of the color line object.
*
* Since: REPLACEME
*/
hb_paint_extend_t
hb_color_line_get_extend (hb_color_line_t *color_line)
{
return color_line->get_extend (color_line,
color_line->data,
color_line->get_extend_user_data);
}
#endif

767
src/hb-paint.h Normal file
View File

@ -0,0 +1,767 @@
/*
* 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.
*/
#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
#ifndef HB_PAINT_H
#define HB_PAINT_H
#include "hb-common.h"
HB_BEGIN_DECLS
/**
* hb_paint_funcs_t:
*
* Glyph paint callbacks.
*
* The callbacks assume that the caller maintains a stack
* of current transforms, clips and intermediate surfaces,
* as evidenced by the pairs of push/pop callbacks. The
* push/pop calls will be properly nested, so it is fine
* to store the different kinds of object on a single stack.
*
* Not all callbacks are required for all kinds of glyphs.
* For rendering COLRv0 or non-color outline glyphs, the
* gradient callbacks are not needed, and the composite
* callback only needs to handle simple alpha compositing
* (#HB_PAINT_COMPOSITE_MODE_SRC_OVER).
*
* The paint-image callback is only needed for glyphs
* with image blobs in the CBDT, sbix or SVG tables.
*
* Since: REPLACEME
**/
typedef struct hb_paint_funcs_t hb_paint_funcs_t;
HB_EXTERN hb_paint_funcs_t *
hb_paint_funcs_create (void);
HB_EXTERN hb_paint_funcs_t *
hb_paint_funcs_get_empty (void);
HB_EXTERN hb_paint_funcs_t *
hb_paint_funcs_reference (hb_paint_funcs_t *funcs);
HB_EXTERN void
hb_paint_funcs_destroy (hb_paint_funcs_t *funcs);
HB_EXTERN hb_bool_t
hb_paint_funcs_set_user_data (hb_paint_funcs_t *funcs,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy,
hb_bool_t replace);
HB_EXTERN void *
hb_paint_funcs_get_user_data (const hb_paint_funcs_t *funcs,
hb_user_data_key_t *key);
HB_EXTERN void
hb_paint_funcs_make_immutable (hb_paint_funcs_t *funcs);
HB_EXTERN hb_bool_t
hb_paint_funcs_is_immutable (hb_paint_funcs_t *funcs);
/**
* hb_paint_push_transform_func_t:
* @funcs: paint functions object
* @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
* @xx: xx component of the transform matrix
* @yx: yx component of the transform matrix
* @xy: xy component of the transform matrix
* @yy: yy component of the transform matrix
* @dx: dx component of the transform matrix
* @dy: dy component of the transform matrix
* @user_data: User data pointer passed to hb_paint_funcs_set_push_transform_func()
*
* A virtual method for the #hb_paint_funcs_t to apply
* a transform to subsequent paint calls.
*
* This transform is applied after the current transform,
* and remains in effect until a matching call to
* the #hb_paint_funcs_pop_transform_func_t vfunc.
*
* Since: REPLACEME
*/
typedef void (*hb_paint_push_transform_func_t) (hb_paint_funcs_t *funcs,
void *paint_data,
float xx, float yx,
float xy, float yy,
float dx, float dy,
void *user_data);
/**
* hb_paint_pop_transform_func_t:
* @funcs: paint functions object
* @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
* @user_data: User data pointer passed to hb_paint_funcs_set_pop_transform_func()
*
* A virtual method for the #hb_paint_funcs_t to undo
* the effect of a prior call to the #hb_paint_funcs_push_transform_func_t
* vfunc.
*
* Since: REPLACEME
*/
typedef void (*hb_paint_pop_transform_func_t) (hb_paint_funcs_t *funcs,
void *paint_data,
void *user_data);
/**
* hb_paint_push_clip_glyph_func_t:
* @funcs: paint functions object
* @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
* @glyph: the glyph ID
* @font: the font
* @user_data: User data pointer passed to hb_paint_funcs_set_push_clip_glyph_func()
*
* A virtual method for the #hb_paint_funcs_t to clip
* subsequent paint calls to the outline of a glyph.
*
* The coordinates of the glyph outline are interpreted according
* to the current transform.
*
* This clip is applied in addition to the current clip,
* and remains in effect until a matching call to
* the #hb_paint_funcs_pop_clip_func_t vfunc.
*
* Since: REPLACEME
*/
typedef void (*hb_paint_push_clip_glyph_func_t) (hb_paint_funcs_t *funcs,
void *paint_data,
hb_codepoint_t glyph,
hb_font_t *font,
void *user_data);
/**
* hb_paint_push_clip_rectangle_func_t:
* @funcs: paint functions object
* @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
* @xmin: min X for the rectangle
* @ymin: min Y for the rectangle
* @xmax: max X for the rectangle
* @ymax: max Y for the rectangle
* @user_data: User data pointer passed to hb_paint_funcs_set_push_clip_rectangle_func()
*
* A virtual method for the #hb_paint_funcs_t to clip
* subsequent paint calls to a rectangle.
*
* The coordinates of the rectangle are interpreted according
* to the current transform.
*
* This clip is applied in addition to the current clip,
* and remains in effect until a matching call to
* the #hb_paint_funcs_pop_clip_func_t vfunc.
*
* Since: REPLACEME
*/
typedef void (*hb_paint_push_clip_rectangle_func_t) (hb_paint_funcs_t *funcs,
void *paint_data,
float xmin, float ymin,
float xmax, float ymax,
void *user_data);
/**
* hb_paint_pop_clip_func_t:
* @funcs: paint functions object
* @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
* @user_data: User data pointer passed to hb_paint_funcs_set_pop_clip_func()
*
* A virtual method for the #hb_paint_funcs_t to undo
* the effect of a prior call to the #hb_paint_funcs_push_clip_glyph_func_t
* or #hb_paint_funcs_push_clip_rectangle_func_t vfuncs.
*
* Since: REPLACEME
*/
typedef void (*hb_paint_pop_clip_func_t) (hb_paint_funcs_t *funcs,
void *paint_data,
void *user_data);
/**
* hb_paint_color_func_t:
* @funcs: paint functions object
* @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
* @is_foreground: whether the color is the foreground
* @color: The color to use, unpremultiplied
* @user_data: User data pointer passed to hb_paint_funcs_set_color_func()
*
* A virtual method for the #hb_paint_funcs_t to paint a
* color everywhere within the current clip.
*
* Since: REPLACEME
*/
typedef void (*hb_paint_color_func_t) (hb_paint_funcs_t *funcs,
void *paint_data,
hb_bool_t is_foreground,
hb_color_t color,
void *user_data);
/**
* HB_PAINT_IMAGE_FORMAT_PNG:
*
* Tag identifying PNG images in #hb_paint_image_func_t callbacks.
*
* Since: REPLACEME
*/
#define HB_PAINT_IMAGE_FORMAT_PNG HB_TAG('p','n','g',' ')
/**
* HB_PAINT_IMAGE_FORMAT_SVG:
*
* Tag identifying SVG images in #hb_paint_image_func_t callbacks.
*
* Since: REPLACEME
*/
#define HB_PAINT_IMAGE_FORMAT_SVG HB_TAG('s','v','g',' ')
/**
* HB_PAINT_IMAGE_FORMAT_BGRA:
*
* Tag identifying raw pixel-data images in #hb_paint_image_func_t callbacks.
* The data is in BGRA pre-multiplied sRGBA color-space format.
*
* Since: REPLACEME
*/
#define HB_PAINT_IMAGE_FORMAT_BGRA HB_TAG('B','G','R','A')
/**
* hb_paint_image_func_t:
* @funcs: paint functions object
* @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
* @image: the image data
* @width: width of the raster image in pixels, or 0
* @height: height of the raster image in pixels, or 0
* @format: the image format as a tag
* @slant: the synthetic slant ratio to be applied to the image during rendering
* @extents: (nullable): glyph extents for desired rendering
* @user_data: User data pointer passed to hb_paint_funcs_set_image_func()
*
* A virtual method for the #hb_paint_funcs_t to paint a glyph image.
*
* This method is called for glyphs with image blobs in the CBDT,
* sbix or SVG tables. The @format identifies the kind of data that
* is contained in @image. Possible values include #HB_PAINT_IMAGE_FORMAT_PNG
* #HB_PAINT_IMAGE_FORMAT_SVG and #HB_PAINT_IMAGE_FORMAT_BGRA.
*
* The image dimensions and glyph extents are provided if available,
* and should be used to size and position the image.
*
* Since: REPLACEME
*/
typedef void (*hb_paint_image_func_t) (hb_paint_funcs_t *funcs,
void *paint_data,
hb_blob_t *image,
unsigned int width,
unsigned int height,
hb_tag_t format,
float slant,
hb_glyph_extents_t *extents,
void *user_data);
/**
* hb_color_stop_t:
* @offset: the offset of the color stop
* @is_foreground: whether the color is the foreground
* @color: the color, unpremultiplied
*
* Information about a color stop on a color line.
*
* Color lines typically have offsets ranging between 0 and 1,
* but that is not required.
*
* Note: despite @color being unpremultiplied here, interpolation in
* gradients shall happen in premultiplied space. See the OpenType spec
* [COLR](https://learn.microsoft.com/en-us/typography/opentype/spec/colr)
* section for details.
*
* Since: REPLACEME
*/
typedef struct {
float offset;
hb_bool_t is_foreground;
hb_color_t color;
} hb_color_stop_t;
/**
* hb_paint_extend_t:
*
* The values of this enumeration determine how color values
* outside the minimum and maximum defined offset on a #hb_color_line_t
* are determined.
*
* See the OpenType spec [COLR](https://learn.microsoft.com/en-us/typography/opentype/spec/colr)
* section for details.
*/
typedef enum {
HB_PAINT_EXTEND_PAD,
HB_PAINT_EXTEND_REPEAT,
HB_PAINT_EXTEND_REFLECT
} hb_paint_extend_t;
typedef struct hb_color_line_t hb_color_line_t;
typedef unsigned int (*hb_color_line_get_color_stops_func_t) (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);
typedef hb_paint_extend_t (*hb_color_line_get_extend_func_t) (hb_color_line_t *color_line,
void *color_line_data,
void *user_data);
/**
* hb_color_line_t:
*
* A struct containing color information for a gradient.
*
* Since: REPLACEME
*/
struct hb_color_line_t {
void *data;
hb_color_line_get_color_stops_func_t get_color_stops;
void *get_color_stops_user_data;
hb_color_line_get_extend_func_t get_extend;
void *get_extend_user_data;
void *reserved0;
void *reserved1;
void *reserved2;
void *reserved3;
void *reserved5;
void *reserved6;
void *reserved7;
void *reserved8;
};
HB_EXTERN unsigned int
hb_color_line_get_color_stops (hb_color_line_t *color_line,
unsigned int start,
unsigned int *count,
hb_color_stop_t *color_stops);
HB_EXTERN hb_paint_extend_t
hb_color_line_get_extend (hb_color_line_t *color_line);
/**
* hb_paint_linear_gradient_func_t:
* @funcs: paint functions object
* @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
* @color_line: Color information for the gradient
* @x0: X coordinate of the first point
* @y0: Y coordinate of the first point
* @x1: X coordinate of the second point
* @y1: Y coordinate of the second point
* @x2: X coordinate of the third point
* @y2: Y coordinate of the third point
* @user_data: User data pointer passed to hb_paint_funcs_set_linear_gradient_func()
*
* A virtual method for the #hb_paint_funcs_t to paint a linear
* gradient everywhere within the current clip.
*
* The @color_line object contains information about the colors of the gradients.
* It is only valid for the duration of the callback, you cannot keep it around.
*
* The coordinates of the points are interpreted according
* to the current transform.
*
* See the OpenType spec [COLR](https://learn.microsoft.com/en-us/typography/opentype/spec/colr)
* section for details on how the points define the direction
* of the gradient, and how to interpret the @color_line.
*
* Since: REPLACEME
*/
typedef void (*hb_paint_linear_gradient_func_t) (hb_paint_funcs_t *funcs,
void *paint_data,
hb_color_line_t *color_line,
float x0, float y0,
float x1, float y1,
float x2, float y2,
void *user_data);
/**
* hb_paint_radial_gradient_func_t:
* @funcs: paint functions object
* @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
* @color_line: Color information for the gradient
* @x0: X coordinate of the first circle's center
* @y0: Y coordinate of the first circle's center
* @r0: radius of the first circle
* @x1: X coordinate of the second circle's center
* @y1: Y coordinate of the second circle's center
* @r1: radius of the second circle
* @user_data: User data pointer passed to hb_paint_funcs_set_radial_gradient_func()
*
* A virtual method for the #hb_paint_funcs_t to paint a radial
* gradient everywhere within the current clip.
*
* The @color_line object contains information about the colors of the gradients.
* It is only valid for the duration of the callback, you cannot keep it around.
*
* The coordinates of the points are interpreted according
* to the current transform.
*
* See the OpenType spec [COLR](https://learn.microsoft.com/en-us/typography/opentype/spec/colr)
* section for details on how the points define the direction
* of the gradient, and how to interpret the @color_line.
*
* Since: REPLACEME
*/
typedef void (*hb_paint_radial_gradient_func_t) (hb_paint_funcs_t *funcs,
void *paint_data,
hb_color_line_t *color_line,
float x0, float y0, float r0,
float x1, float y1, float r1,
void *user_data);
/**
* hb_paint_sweep_gradient_func_t:
* @funcs: paint functions object
* @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
* @color_line: Color information for the gradient
* @x0: X coordinate of the circle's center
* @y0: Y coordinate of the circle's center
* @start_angle: the start angle, in radians
* @end_angle: the end angle, in radians
* @user_data: User data pointer passed to hb_paint_funcs_set_sweep_gradient_func()
*
* A virtual method for the #hb_paint_funcs_t to paint a sweep
* gradient everywhere within the current clip.
*
* The @color_line object contains information about the colors of the gradients.
* It is only valid for the duration of the callback, you cannot keep it around.
*
* The coordinates of the points are interpreted according
* to the current transform.
*
* See the OpenType spec [COLR](https://learn.microsoft.com/en-us/typography/opentype/spec/colr)
* section for details on how the points define the direction
* of the gradient, and how to interpret the @color_line.
*
* Since: REPLACEME
*/
typedef void (*hb_paint_sweep_gradient_func_t) (hb_paint_funcs_t *funcs,
void *paint_data,
hb_color_line_t *color_line,
float x0, float y0,
float start_angle,
float end_angle,
void *user_data);
/**
* hb_paint_composite_mode_t:
*
* The values of this enumeration describe the compositing modes
* that can be used when combining temporary redirected drawing
* with the backdrop.
*
* See the OpenType spec [COLR](https://learn.microsoft.com/en-us/typography/opentype/spec/colr)
* section for details.
*/
typedef enum {
HB_PAINT_COMPOSITE_MODE_CLEAR,
HB_PAINT_COMPOSITE_MODE_SRC,
HB_PAINT_COMPOSITE_MODE_DEST,
HB_PAINT_COMPOSITE_MODE_SRC_OVER,
HB_PAINT_COMPOSITE_MODE_DEST_OVER,
HB_PAINT_COMPOSITE_MODE_SRC_IN,
HB_PAINT_COMPOSITE_MODE_DEST_IN,
HB_PAINT_COMPOSITE_MODE_SRC_OUT,
HB_PAINT_COMPOSITE_MODE_DEST_OUT,
HB_PAINT_COMPOSITE_MODE_SRC_ATOP,
HB_PAINT_COMPOSITE_MODE_DEST_ATOP,
HB_PAINT_COMPOSITE_MODE_XOR,
HB_PAINT_COMPOSITE_MODE_PLUS,
HB_PAINT_COMPOSITE_MODE_SCREEN,
HB_PAINT_COMPOSITE_MODE_OVERLAY,
HB_PAINT_COMPOSITE_MODE_DARKEN,
HB_PAINT_COMPOSITE_MODE_LIGHTEN,
HB_PAINT_COMPOSITE_MODE_COLOR_DODGE,
HB_PAINT_COMPOSITE_MODE_COLOR_BURN,
HB_PAINT_COMPOSITE_MODE_HARD_LIGHT,
HB_PAINT_COMPOSITE_MODE_SOFT_LIGHT,
HB_PAINT_COMPOSITE_MODE_DIFFERENCE,
HB_PAINT_COMPOSITE_MODE_EXCLUSION,
HB_PAINT_COMPOSITE_MODE_MULTIPLY,
HB_PAINT_COMPOSITE_MODE_HSL_HUE,
HB_PAINT_COMPOSITE_MODE_HSL_SATURATION,
HB_PAINT_COMPOSITE_MODE_HSL_COLOR,
HB_PAINT_COMPOSITE_MODE_HSL_LUMINOSITY,
} hb_paint_composite_mode_t;
/**
* hb_paint_push_group_func_t:
* @funcs: paint functions object
* @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
* @user_data: User data pointer passed to hb_paint_funcs_set_push_group_func()
*
* A virtual method for the #hb_paint_funcs_t to use
* an intermediate surface for subsequent paint calls.
*
* The drawing will be redirected to an intermediate surface
* until a matching call to the #hb_paint_funcs_pop_group_func_t
* vfunc.
*
* Since: REPLACEME
*/
typedef void (*hb_paint_push_group_func_t) (hb_paint_funcs_t *funcs,
void *paint_data,
void *user_data);
/**
* hb_paint_pop_group_func_t:
* @funcs: paint functions object
* @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
* @mode: the compositing mode to use
* @user_data: User data pointer passed to hb_paint_funcs_set_pop_group_func()
*
* A virtual method for the #hb_paint_funcs_t to undo
* the effect of a prior call to the #hb_paint_funcs_push_group_func_t
* vfunc.
*
* This call stops the redirection to the intermediate surface,
* and then composites it on the previous surface, using the
* compositing mode passed to this call.
*
* Since: REPLACEME
*/
typedef void (*hb_paint_pop_group_func_t) (hb_paint_funcs_t *funcs,
void *paint_data,
hb_paint_composite_mode_t mode,
void *user_data);
/**
* hb_paint_funcs_set_push_transform_func:
* @funcs: A paint functions struct
* @func: (closure user_data) (destroy destroy) (scope notified): The push-transform callback
* @user_data: Data to pass to @func
* @destroy: (nullable): Function to call when @user_data is no longer needed
*
* Sets the push-transform callback on the paint functions struct.
*
* Since: REPLACEME
*/
HB_EXTERN void
hb_paint_funcs_set_push_transform_func (hb_paint_funcs_t *funcs,
hb_paint_push_transform_func_t func,
void *user_data,
hb_destroy_func_t destroy);
/**
* hb_paint_funcs_set_pop_transform_func:
* @funcs: A paint functions struct
* @func: (closure user_data) (destroy destroy) (scope notified): The pop-transform callback
* @user_data: Data to pass to @func
* @destroy: (nullable): Function to call when @user_data is no longer needed
*
* Sets the pop-transform callback on the paint functions struct.
*
* Since: REPLACEME
*/
HB_EXTERN void
hb_paint_funcs_set_pop_transform_func (hb_paint_funcs_t *funcs,
hb_paint_pop_transform_func_t func,
void *user_data,
hb_destroy_func_t destroy);
/**
* hb_paint_funcs_set_push_clip_glyph_func:
* @funcs: A paint functions struct
* @func: (closure user_data) (destroy destroy) (scope notified): The push-clip-glyph callback
* @user_data: Data to pass to @func
* @destroy: (nullable): Function to call when @user_data is no longer needed
*
* Sets the push-clip-glyph callback on the paint functions struct.
*
* Since: REPLACEME
*/
HB_EXTERN void
hb_paint_funcs_set_push_clip_glyph_func (hb_paint_funcs_t *funcs,
hb_paint_push_clip_glyph_func_t func,
void *user_data,
hb_destroy_func_t destroy);
/**
* hb_paint_funcs_set_push_clip_rectangle_func:
* @funcs: A paint functions struct
* @func: (closure user_data) (destroy destroy) (scope notified): The push-clip-rectangle callback
* @user_data: Data to pass to @func
* @destroy: (nullable): Function to call when @user_data is no longer needed
*
* Sets the push-clip-rect callback on the paint functions struct.
*
* Since: REPLACEME
*/
HB_EXTERN void
hb_paint_funcs_set_push_clip_rectangle_func (hb_paint_funcs_t *funcs,
hb_paint_push_clip_rectangle_func_t func,
void *user_data,
hb_destroy_func_t destroy);
/**
* hb_paint_funcs_set_pop_clip_func:
* @funcs: A paint functions struct
* @func: (closure user_data) (destroy destroy) (scope notified): The pop-clip callback
* @user_data: Data to pass to @func
* @destroy: (nullable): Function to call when @user_data is no longer needed
*
* Sets the pop-clip callback on the paint functions struct.
*
* Since: REPLACEME
*/
HB_EXTERN void
hb_paint_funcs_set_pop_clip_func (hb_paint_funcs_t *funcs,
hb_paint_pop_clip_func_t func,
void *user_data,
hb_destroy_func_t destroy);
/**
* hb_paint_funcs_set_color_func:
* @funcs: A paint functions struct
* @func: (closure user_data) (destroy destroy) (scope notified): The paint-color callback
* @user_data: Data to pass to @func
* @destroy: (nullable): Function to call when @user_data is no longer needed
*
* Sets the paint-color callback on the paint functions struct.
*
* Since: REPLACEME
*/
HB_EXTERN void
hb_paint_funcs_set_color_func (hb_paint_funcs_t *funcs,
hb_paint_color_func_t func,
void *user_data,
hb_destroy_func_t destroy);
/**
* hb_paint_funcs_set_image_func:
* @funcs: A paint functions struct
* @func: (closure user_data) (destroy destroy) (scope notified): The paint-image callback
* @user_data: Data to pass to @func
* @destroy: (nullable): Function to call when @user_data is no longer needed
*
* Sets the paint-image callback on the paint functions struct.
*
* Since: REPLACEME
*/
HB_EXTERN void
hb_paint_funcs_set_image_func (hb_paint_funcs_t *funcs,
hb_paint_image_func_t func,
void *user_data,
hb_destroy_func_t destroy);
/**
* hb_paint_funcs_set_linear_gradient_func:
* @funcs: A paint functions struct
* @func: (closure user_data) (destroy destroy) (scope notified): The linear-gradient callback
* @user_data: Data to pass to @func
* @destroy: (nullable): Function to call when @user_data is no longer needed
*
* Sets the linear-gradient callback on the paint functions struct.
*
* Since: REPLACEME
*/
HB_EXTERN void
hb_paint_funcs_set_linear_gradient_func (hb_paint_funcs_t *funcs,
hb_paint_linear_gradient_func_t func,
void *user_data,
hb_destroy_func_t destroy);
/**
* hb_paint_funcs_set_radial_gradient_func:
* @funcs: A paint functions struct
* @func: (closure user_data) (destroy destroy) (scope notified): The radial-gradient callback
* @user_data: Data to pass to @func
* @destroy: (nullable): Function to call when @user_data is no longer needed
*
* Sets the radial-gradient callback on the paint functions struct.
*
* Since: REPLACEME
*/
HB_EXTERN void
hb_paint_funcs_set_radial_gradient_func (hb_paint_funcs_t *funcs,
hb_paint_radial_gradient_func_t func,
void *user_data,
hb_destroy_func_t destroy);
/**
* hb_paint_funcs_set_sweep_gradient_func:
* @funcs: A paint functions struct
* @func: (closure user_data) (destroy destroy) (scope notified): The sweep-gradient callback
* @user_data: Data to pass to @func
* @destroy: (nullable): Function to call when @user_data is no longer needed
*
* Sets the sweep-gradient callback on the paint functions struct.
*
* Since: REPLACEME
*/
HB_EXTERN void
hb_paint_funcs_set_sweep_gradient_func (hb_paint_funcs_t *funcs,
hb_paint_sweep_gradient_func_t func,
void *user_data,
hb_destroy_func_t destroy);
/**
* hb_paint_funcs_set_push_group_func:
* @funcs: A paint functions struct
* @func: (closure user_data) (destroy destroy) (scope notified): The push-group callback
* @user_data: Data to pass to @func
* @destroy: (nullable): Function to call when @user_data is no longer needed
*
* Sets the push-group callback on the paint functions struct.
*
* Since: REPLACEME
*/
HB_EXTERN void
hb_paint_funcs_set_push_group_func (hb_paint_funcs_t *funcs,
hb_paint_push_group_func_t func,
void *user_data,
hb_destroy_func_t destroy);
/**
* hb_paint_funcs_set_pop_group_func:
* @funcs: A paint functions struct
* @func: (closure user_data) (destroy destroy) (scope notified): The pop-group callback
* @user_data: Data to pass to @func
* @destroy: (nullable): Function to call when @user_data is no longer needed
*
* Sets the pop-group callback on the paint functions struct.
*
* Since: REPLACEME
*/
HB_EXTERN void
hb_paint_funcs_set_pop_group_func (hb_paint_funcs_t *funcs,
hb_paint_pop_group_func_t func,
void *user_data,
hb_destroy_func_t destroy);
HB_END_DECLS
#endif /* HB_PAINT_H */

178
src/hb-paint.hh Normal file
View File

@ -0,0 +1,178 @@
/*
* 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_PAINT_HH
#define HB_PAINT_HH
#include "hb.hh"
#include "hb-face.hh"
#include "hb-font.hh"
#define HB_PAINT_FUNCS_IMPLEMENT_CALLBACKS \
HB_PAINT_FUNC_IMPLEMENT (push_transform) \
HB_PAINT_FUNC_IMPLEMENT (pop_transform) \
HB_PAINT_FUNC_IMPLEMENT (push_clip_glyph) \
HB_PAINT_FUNC_IMPLEMENT (push_clip_rectangle) \
HB_PAINT_FUNC_IMPLEMENT (pop_clip) \
HB_PAINT_FUNC_IMPLEMENT (color) \
HB_PAINT_FUNC_IMPLEMENT (image) \
HB_PAINT_FUNC_IMPLEMENT (linear_gradient) \
HB_PAINT_FUNC_IMPLEMENT (radial_gradient) \
HB_PAINT_FUNC_IMPLEMENT (sweep_gradient) \
HB_PAINT_FUNC_IMPLEMENT (push_group) \
HB_PAINT_FUNC_IMPLEMENT (pop_group) \
/* ^--- Add new callbacks here */
struct hb_paint_funcs_t
{
hb_object_header_t header;
struct {
#define HB_PAINT_FUNC_IMPLEMENT(name) hb_paint_##name##_func_t name;
HB_PAINT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_PAINT_FUNC_IMPLEMENT
} func;
struct {
#define HB_PAINT_FUNC_IMPLEMENT(name) void *name;
HB_PAINT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_PAINT_FUNC_IMPLEMENT
} *user_data;
struct {
#define HB_PAINT_FUNC_IMPLEMENT(name) hb_destroy_func_t name;
HB_PAINT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_PAINT_FUNC_IMPLEMENT
} *destroy;
void push_transform (void *paint_data,
float xx, float yx,
float xy, float yy,
float dx, float dy)
{ func.push_transform (this, paint_data,
xx, yx, xy, yy, dx, dy,
!user_data ? nullptr : user_data->push_transform); }
void pop_transform (void *paint_data)
{ func.pop_transform (this, paint_data,
!user_data ? nullptr : user_data->pop_transform); }
void push_clip_glyph (void *paint_data,
hb_codepoint_t glyph,
hb_font_t *font)
{ func.push_clip_glyph (this, paint_data,
glyph,
font,
!user_data ? nullptr : user_data->push_clip_glyph); }
void push_clip_rectangle (void *paint_data,
float xmin, float ymin, float xmax, float ymax)
{ func.push_clip_rectangle (this, paint_data,
xmin, ymin, xmax, ymax,
!user_data ? nullptr : user_data->push_clip_rectangle); }
void pop_clip (void *paint_data)
{ func.pop_clip (this, paint_data,
!user_data ? nullptr : user_data->pop_clip); }
void color (void *paint_data,
hb_bool_t is_foreground,
hb_color_t color)
{ func.color (this, paint_data,
is_foreground, color,
!user_data ? nullptr : user_data->color); }
void image (void *paint_data,
hb_blob_t *image,
unsigned width, unsigned height,
hb_tag_t format,
float slant,
hb_glyph_extents_t *extents)
{ func.image (this, paint_data,
image, width, height, format, slant, extents,
!user_data ? nullptr : user_data->image); }
void linear_gradient (void *paint_data,
hb_color_line_t *color_line,
float x0, float y0,
float x1, float y1,
float x2, float y2)
{ func.linear_gradient (this, paint_data,
color_line, x0, y0, x1, y1, x2, y2,
!user_data ? nullptr : user_data->linear_gradient); }
void radial_gradient (void *paint_data,
hb_color_line_t *color_line,
float x0, float y0, float r0,
float x1, float y1, float r1)
{ func.radial_gradient (this, paint_data,
color_line, x0, y0, r0, x1, y1, r1,
!user_data ? nullptr : user_data->radial_gradient); }
void sweep_gradient (void *paint_data,
hb_color_line_t *color_line,
float x0, float y0,
float start_angle,
float end_angle)
{ func.sweep_gradient (this, paint_data,
color_line, x0, y0, start_angle, end_angle,
!user_data ? nullptr : user_data->sweep_gradient); }
void push_group (void *paint_data)
{ func.push_group (this, paint_data,
!user_data ? nullptr : user_data->push_group); }
void pop_group (void *paint_data,
hb_paint_composite_mode_t mode)
{ func.pop_group (this, paint_data,
mode,
!user_data ? nullptr : user_data->pop_group); }
void push_root_transform (void *paint_data,
const hb_font_t *font)
{
int xscale = font->x_scale, yscale = font->y_scale;
float upem = font->face->get_upem ();
float slant = font->slant_xy;
func.push_transform (this, paint_data,
xscale/upem, 0, slant * yscale/upem, yscale/upem, 0, 0,
!user_data ? nullptr : user_data->push_transform);
}
void pop_root_transform (void *paint_data)
{
func.pop_transform (this, paint_data,
!user_data ? nullptr : user_data->pop_transform);
}
void push_inverse_root_transform (void *paint_data,
hb_font_t *font)
{
int xscale = font->x_scale, yscale = font->y_scale;
float upem = font->face->get_upem ();
float slant = font->slant_xy;
func.push_transform (this, paint_data,
upem/xscale, 0, -slant * upem/xscale, upem/yscale, 0, 0,
!user_data ? nullptr : user_data->push_transform);
}
void pop_inverse_root_transform (void *paint_data)
{
func.pop_transform (this, paint_data,
!user_data ? nullptr : user_data->pop_transform);
}
};
DECLARE_NULL_INSTANCE (hb_paint_funcs_t);
#endif /* HB_PAINT_HH */

View File

@ -36,6 +36,7 @@
#include "hb-face.h"
#include "hb-font.h"
#include "hb-map.h"
#include "hb-paint.h"
#include "hb-set.h"
#include "hb-shape.h"
#include "hb-shape-plan.h"

View File

@ -44,6 +44,9 @@ hb_base_sources = files(
'hb-dispatch.hh',
'hb-draw.cc',
'hb-draw.hh',
'hb-paint.cc',
'hb-paint.hh',
'hb-paint-extents.hh',
'hb-face.cc',
'hb-face.hh',
'hb-fallback-shape.cc',
@ -73,6 +76,7 @@ hb_base_sources = files(
'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',
@ -276,6 +280,7 @@ hb_base_headers = files(
'hb-cplusplus.hh',
'hb-deprecated.h',
'hb-draw.h',
'hb-paint.h',
'hb-face.h',
'hb-font.h',
'hb-map.h',
@ -301,7 +306,7 @@ hb_base_headers += hb_version_h
# Optional Sources and Headers with external deps
hb_ft_sources = files('hb-ft.cc')
hb_ft_sources = files('hb-ft.cc', 'hb-ft-colr.hh')
hb_ft_headers = files('hb-ft.h')
hb_glib_sources = files('hb-glib.cc')

View File

@ -14,7 +14,10 @@ libs:
EXTRA_DIST += meson.build
EXTRA_DIST += fonts
EXTRA_DIST += \
fonts \
results \
$(NULL)
LINK = $(CXXLINK)
@ -56,6 +59,7 @@ TEST_PROGS = \
test-ot-tag \
test-ot-extents-cff \
test-ot-metrics-tt-var \
test-paint \
test-set \
test-shape \
test-style \
@ -87,6 +91,9 @@ TEST_PROGS = \
test_draw_CPPFLAGS = $(AM_CPPFLAGS)
test_draw_LDADD = $(LDADD)
test_paint_CPPFLAGS = $(AM_CPPFLAGS)
test_paint_LDADD = $(LDADD)
test_subset_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
test_subset_cmap_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
test_subset_drop_tables_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
@ -133,6 +140,9 @@ if HAVE_FREETYPE
test_draw_CPPFLAGS += $(FREETYPE_CFLAGS)
test_draw_LDADD += $(FREETYPE_LIBS)
test_paint_CPPFLAGS += $(FREETYPE_CFLAGS)
test_paint_LDADD += $(FREETYPE_LIBS)
TEST_PROGS += \
test-ot-math \
$(NULL)

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -32,6 +32,7 @@ tests = [
'test-ot-tag.c',
'test-ot-extents-cff.c',
'test-ot-metrics-tt-var.c',
'test-paint.c',
'test-subset-repacker.c',
'test-set.c',
'test-shape.c',

View File

@ -0,0 +1,117 @@
start transform 0.019531 0.000000 0.000000 0.019531 0.000000 0.000000
start clip rectangle 64.000000 -224.000000 1216.000000 928.000000
push group
start transform 51.200001 0.000000 -0.000000 51.200001 0.000000 0.000000
start clip glyph 13
start transform 0.019531 0.000000 0.000000 0.019531 0.000000 0.000000
start transform 1.000000 0.000000 0.000000 0.976807 0.000000 0.000000
radial gradient
p0 280.000000 440.000000 radius 0.000000
p1 280.000000 440.000000 radius 467.000000
colors
0.000000 186 141 104 255
0.448792 183 138 103 255
0.808594 173 130 100 255
1.000000 164 123 98 255
end transform
end transform
end clip
end transform
pop group mode 3
push group
start transform 51.200001 0.000000 -0.000000 51.200001 0.000000 0.000000
start clip glyph 14
start transform 0.019531 0.000000 0.000000 0.019531 0.000000 0.000000
linear gradient
p0 231.000000 -27.000000
p1 1019.000000 -27.000000
p2 231.000000 -815.000000
colors
0.000000 164 123 98 255
1.000000 164 123 98 255
end transform
end clip
end transform
pop group mode 3
push group
start transform 51.200001 0.000000 -0.000000 51.200001 0.000000 0.000000
start clip glyph 15
start transform 0.019531 0.000000 0.000000 0.019531 0.000000 0.000000
solid 145 103 77 255
end transform
end clip
end transform
pop group mode 3
push group
start transform 51.200001 0.000000 -0.000000 51.200001 0.000000 0.000000
start clip glyph 16
start transform 0.019531 0.000000 0.000000 0.019531 0.000000 0.000000
solid 30 136 229 255
end transform
end clip
end transform
pop group mode 3
push group
start transform 51.200001 0.000000 -0.000000 51.200001 0.000000 0.000000
start clip glyph 21
start transform 0.019531 0.000000 0.000000 0.019531 0.000000 0.000000
solid 145 103 77 255
end transform
end clip
end transform
pop group mode 3
push group
push group
start transform 51.200001 0.000000 -0.000000 51.200001 0.000000 0.000000
start clip glyph 16
start transform 0.019531 0.000000 0.000000 0.019531 0.000000 0.000000
linear gradient
p0 669.000000 776.000000
p1 180.000000 -106.000000
p2 -212.000000 1265.000000
colors
0.000000 100 181 246 255
1.000000 33 150 243 255
end transform
end clip
end transform
pop group mode 3
push group
start transform 51.200001 0.000000 -0.000000 51.200001 0.000000 0.000000
start clip glyph 18
start transform 0.019531 0.000000 0.000000 0.019531 0.000000 0.000000
solid 66 66 66 51
end transform
end clip
end transform
pop group mode 3
pop group mode 3
push group
start transform 51.200001 0.000000 -0.000000 51.200001 0.000000 0.000000
start clip glyph 19
start transform 0.019531 0.000000 0.000000 0.019531 0.000000 0.000000
start transform 1.000000 0.000000 0.000000 0.969116 0.000000 0.000000
radial gradient
p0 588.000000 198.000000 radius 0.000000
p1 588.000000 198.000000 radius 342.000000
colors
0.000000 186 141 104 255
0.448792 183 138 103 255
0.808594 173 130 100 255
1.000000 164 123 98 255
end transform
end transform
end clip
end transform
pop group mode 3
push group
start transform 51.200001 0.000000 -0.000000 51.200001 0.000000 0.000000
start clip glyph 20
start transform 0.019531 0.000000 0.000000 0.019531 0.000000 0.000000
solid 145 103 77 255
end transform
end clip
end transform
pop group mode 3
end clip
end transform

View File

@ -0,0 +1,117 @@
start transform 0.019531 0.000000 0.003906 0.019531 0.000000 0.000000
start clip rectangle 64.000000 -224.000000 1216.000000 928.000000
push group
start transform 51.200001 0.000000 -10.240000 51.200001 0.000000 0.000000
start clip glyph 13
start transform 0.019531 0.000000 0.003906 0.019531 0.000000 0.000000
start transform 1.000000 0.000000 0.000000 0.976807 0.000000 0.000000
radial gradient
p0 280.000000 440.000000 radius 0.000000
p1 280.000000 440.000000 radius 467.000000
colors
0.000000 186 141 104 255
0.448792 183 138 103 255
0.808594 173 130 100 255
1.000000 164 123 98 255
end transform
end transform
end clip
end transform
pop group mode 3
push group
start transform 51.200001 0.000000 -10.240000 51.200001 0.000000 0.000000
start clip glyph 14
start transform 0.019531 0.000000 0.003906 0.019531 0.000000 0.000000
linear gradient
p0 231.000000 -27.000000
p1 1019.000000 -27.000000
p2 231.000000 -815.000000
colors
0.000000 164 123 98 255
1.000000 164 123 98 255
end transform
end clip
end transform
pop group mode 3
push group
start transform 51.200001 0.000000 -10.240000 51.200001 0.000000 0.000000
start clip glyph 15
start transform 0.019531 0.000000 0.003906 0.019531 0.000000 0.000000
solid 145 103 77 255
end transform
end clip
end transform
pop group mode 3
push group
start transform 51.200001 0.000000 -10.240000 51.200001 0.000000 0.000000
start clip glyph 16
start transform 0.019531 0.000000 0.003906 0.019531 0.000000 0.000000
solid 30 136 229 255
end transform
end clip
end transform
pop group mode 3
push group
start transform 51.200001 0.000000 -10.240000 51.200001 0.000000 0.000000
start clip glyph 21
start transform 0.019531 0.000000 0.003906 0.019531 0.000000 0.000000
solid 145 103 77 255
end transform
end clip
end transform
pop group mode 3
push group
push group
start transform 51.200001 0.000000 -10.240000 51.200001 0.000000 0.000000
start clip glyph 16
start transform 0.019531 0.000000 0.003906 0.019531 0.000000 0.000000
linear gradient
p0 669.000000 776.000000
p1 180.000000 -106.000000
p2 -212.000000 1265.000000
colors
0.000000 100 181 246 255
1.000000 33 150 243 255
end transform
end clip
end transform
pop group mode 3
push group
start transform 51.200001 0.000000 -10.240000 51.200001 0.000000 0.000000
start clip glyph 18
start transform 0.019531 0.000000 0.003906 0.019531 0.000000 0.000000
solid 66 66 66 51
end transform
end clip
end transform
pop group mode 3
pop group mode 3
push group
start transform 51.200001 0.000000 -10.240000 51.200001 0.000000 0.000000
start clip glyph 19
start transform 0.019531 0.000000 0.003906 0.019531 0.000000 0.000000
start transform 1.000000 0.000000 0.000000 0.969116 0.000000 0.000000
radial gradient
p0 588.000000 198.000000 radius 0.000000
p1 588.000000 198.000000 radius 342.000000
colors
0.000000 186 141 104 255
0.448792 183 138 103 255
0.808594 173 130 100 255
1.000000 164 123 98 255
end transform
end transform
end clip
end transform
pop group mode 3
push group
start transform 51.200001 0.000000 -10.240000 51.200001 0.000000 0.000000
start clip glyph 20
start transform 0.019531 0.000000 0.003906 0.019531 0.000000 0.000000
solid 145 103 77 255
end transform
end clip
end transform
pop group mode 3
end clip
end transform

View File

@ -0,0 +1,12 @@
start clip glyph 16
solid 81 61 50 255
end clip
start clip glyph 17
solid 245 185 68 255
end clip
start clip glyph 18
solid 224 142 55 255
end clip
start clip glyph 19
solid 245 202 86 255
end clip

View File

@ -0,0 +1,12 @@
start clip glyph 8
solid 81 61 50 255
end clip
start clip glyph 9
solid 245 185 68 255
end clip
start clip glyph 10
solid 224 142 55 255
end clip
start clip glyph 11
solid 245 202 86 255
end clip

View File

@ -0,0 +1,12 @@
start clip glyph 12
solid 81 61 50 255
end clip
start clip glyph 13
solid 245 185 68 255
end clip
start clip glyph 14
solid 224 142 55 255
end clip
start clip glyph 15
solid 245 202 86 255
end clip

View File

@ -0,0 +1,18 @@
start transform 0.020000 0.000000 0.000000 0.020000 0.000000 0.000000
start clip rectangle 0.000000 0.000000 1000.000000 1000.000000
start transform 50.000000 0.000000 -0.000000 50.000000 0.000000 0.000000
start clip glyph 174
start transform 0.020000 0.000000 0.000000 0.020000 0.000000 0.000000
sweep gradient
center 500.000000 600.000000
angles 0.000000 6.283185
colors
0.250000 250 240 230 255
0.416687 0 0 255 255
0.583313 255 0 0 255
0.750000 47 79 79 255
end transform
end clip
end transform
end clip
end transform

View File

@ -0,0 +1,28 @@
start clip rectangle 5.000000 5.000000 15.000000 15.000000
start transform 0.020000 0.000000 0.000000 0.020000 0.000000 0.000000
push group
start transform 50.000000 0.000000 -0.000000 50.000000 0.000000 0.000000
start clip glyph 3
start transform 0.020000 0.000000 0.000000 0.020000 0.000000 0.000000
solid 0 0 255 127
end transform
end clip
end transform
push group
start transform 0.000000 0.000000 0.000000 0.000000 1000.000000 1000.000000
start transform 1.000000 -0.363874 -0.176283 1.000000 0.000000 0.000000
start transform 0.000000 0.000000 0.000000 0.000000 -1000.000000 -1000.000000
start transform 50.000000 0.000000 -0.000000 50.000000 0.000000 0.000000
start clip glyph 3
start transform 0.020000 0.000000 0.000000 0.020000 0.000000 0.000000
solid 255 165 0 178
end transform
end clip
end transform
end transform
end transform
end transform
pop group mode 4
pop group mode 3
end transform
end clip

View File

@ -0,0 +1,24 @@
start clip rectangle 5.000000 5.000000 15.000000 15.000000
start transform 0.020000 0.000000 0.000000 0.020000 0.000000 0.000000
push group
start transform 50.000000 0.000000 -0.000000 50.000000 0.000000 0.000000
start clip glyph 3
start transform 0.020000 0.000000 0.000000 0.020000 0.000000 0.000000
solid 0 0 255 127
end transform
end clip
end transform
push group
start transform 1.000000 0.000000 0.000000 1.000000 200.000000 200.000000
start transform 50.000000 0.000000 -0.000000 50.000000 0.000000 0.000000
start clip glyph 3
start transform 0.020000 0.000000 0.000000 0.020000 0.000000 0.000000
solid 255 165 0 178
end transform
end clip
end transform
end transform
pop group mode 4
pop group mode 3
end transform
end clip

View File

@ -0,0 +1,45 @@
start transform 0.020000 0.000000 0.000000 0.020000 0.000000 0.000000
start clip rectangle 0.000000 0.000000 1000.000000 1000.000000
push group
start transform 50.000000 0.000000 -0.000000 50.000000 0.000000 0.000000
start clip glyph 3
start transform 0.020000 0.000000 0.000000 0.020000 0.000000 0.000000
solid 0 0 0 255
end transform
end clip
end transform
pop group mode 3
push group
push group
start transform 0.000000 0.000000 0.000000 0.000000 333.000000 667.000000
start transform 8192.000000 0.000000 0.000000 8192.000000 0.000000 0.000000
start transform 0.000000 0.000000 0.000000 0.000000 -333.000000 -667.000000
start transform 50.000000 0.000000 -0.000000 50.000000 0.000000 0.000000
start clip glyph 2
start transform 0.020000 0.000000 0.000000 0.020000 0.000000 0.000000
solid 255 220 1 255
end transform
end clip
end transform
end transform
end transform
end transform
push group
start transform 0.000000 0.000000 0.000000 0.000000 667.000000 333.000000
start transform 8192.000000 0.000000 0.000000 8192.000000 0.000000 0.000000
start transform 0.000000 0.000000 0.000000 0.000000 -667.000000 -333.000000
start transform 50.000000 0.000000 -0.000000 50.000000 0.000000 0.000000
start clip glyph 2
start transform 0.020000 0.000000 0.000000 0.020000 0.000000 0.000000
solid 104 199 232 255
end transform
end clip
end transform
end transform
end transform
end transform
pop group mode 5
pop group mode 3
pop group mode 3
end clip
end transform

View File

@ -0,0 +1,18 @@
start transform 0.020000 0.000000 0.000000 0.020000 0.000000 0.000000
start clip rectangle 100.000000 250.000000 1200.000000 950.000000
start transform 50.000000 0.000000 -0.000000 50.000000 0.000000 0.000000
start clip glyph 165
start transform 0.020000 0.000000 0.000000 0.020000 0.000000 0.000000
linear gradient
p0 100.000000 950.000000
p1 2300.000000 950.000000
p2 -1000.000000 250.000000
colors
0.000000 255 0 0 255
0.500000 0 0 255 255
1.000000 255 255 0 255
end transform
end clip
end transform
end clip
end transform

View File

@ -0,0 +1,32 @@
start transform 0.020000 0.000000 0.000000 0.020000 0.000000 0.000000
start clip rectangle 0.000000 0.000000 1000.000000 1000.000000
push group
start transform 1.000000 0.000000 0.000000 1.000000 150.000000 0.000000
start transform 50.000000 0.000000 -0.000000 50.000000 0.000000 0.000000
start clip glyph 174
start transform 0.020000 0.000000 0.000000 0.020000 0.000000 0.000000
solid 0 128 0 255
end transform
end clip
end transform
end transform
pop group mode 3
push group
start transform 1.000000 0.000000 0.000000 1.000000 -150.000000 0.000000
start transform 50.000000 0.000000 -0.000000 50.000000 0.000000 0.000000
start clip glyph 174
start transform 0.020000 0.000000 0.000000 0.020000 0.000000 0.000000
linear gradient
p0 500.000000 250.000000
p1 500.000000 950.000000
p2 600.000000 250.000000
colors
0.000000 255 0 0 255
1.000000 0 0 255 255
end transform
end clip
end transform
end transform
pop group mode 3
end clip
end transform

View File

@ -0,0 +1,17 @@
start transform 0.020000 0.000000 0.000000 0.020000 0.000000 0.000000
start clip rectangle 100.000000 250.000000 900.000000 950.000000
start transform 50.000000 0.000000 -0.000000 50.000000 0.000000 0.000000
start clip glyph 6
start transform 0.020000 0.000000 0.000000 0.020000 0.000000 0.000000
linear gradient
p0 100.000000 250.000000
p1 900.000000 250.000000
p2 100.000000 300.000000
colors
0.000000 255 0 0 255
1.000000 0 0 255 255
end transform
end clip
end transform
end clip
end transform

View File

@ -0,0 +1,17 @@
start transform 0.020000 0.000000 0.000000 0.020000 0.000000 0.000000
start clip rectangle 0.000000 0.000000 1000.000000 1000.000000
start transform 50.000000 0.000000 -0.000000 50.000000 0.000000 0.000000
start clip glyph 2
start transform 0.020000 0.000000 0.000000 0.020000 0.000000 0.000000
radial gradient
p0 166.000000 768.000000 radius 0.000000
p1 166.000000 768.000000 radius 256.000000
colors
0.000000 0 128 0 255
0.500000 255 255 255 255
1.000000 255 0 0 255
end transform
end clip
end transform
end clip
end transform

View File

@ -182,7 +182,7 @@ static hb_draw_funcs_t *funcs2; /* this one translates quadratic calls to cubic
static void
test_hb_draw_empty (void)
{
hb_font_get_glyph_shape (hb_font_get_empty (), 3, funcs, NULL);
hb_font_draw_glyph (hb_font_get_empty (), 3, funcs, NULL);
}
static void
@ -200,10 +200,10 @@ test_hb_draw_glyf (void)
};
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 4, funcs, &draw_data);
hb_font_draw_glyph (font, 4, funcs, &draw_data);
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 3, funcs, &draw_data);
hb_font_draw_glyph (font, 3, funcs, &draw_data);
char expected[] = "M275,442Q232,442 198,420Q164,397 145,353Q126,309 126,245"
"Q126,182 147,139Q167,95 204,73Q240,50 287,50Q330,50 367,70"
"Q404,90 427,128L451,116Q431,54 384,21Q336,-13 266,-13"
@ -215,7 +215,7 @@ test_hb_draw_glyf (void)
/* Test translating quadratic calls to cubic by a _draw_funcs_t that doesn't set the callback */
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 3, funcs2, &draw_data);
hb_font_draw_glyph (font, 3, funcs2, &draw_data);
char expected2[] = "M275,442C246,442 221,435 198,420C175,405 158,382 145,353"
"C132,324 126,288 126,245C126,203 133,168 147,139C160,110 179,88 204,73"
"C228,58 256,50 287,50C316,50 342,57 367,70C392,83 412,103 427,128"
@ -233,7 +233,7 @@ test_hb_draw_glyf (void)
hb_font_set_variations (font, &var, 1);
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 3, funcs, &draw_data);
hb_font_draw_glyph (font, 3, funcs, &draw_data);
char expected3[] = "M323,448Q297,448 271,430Q244,412 226,371Q209,330 209,261"
"Q209,204 225,166Q242,127 272,107Q303,86 344,86Q378,86 404,101"
"Q430,115 451,137L488,103Q458,42 404,13Q350,-16 279,-16"
@ -259,7 +259,7 @@ test_hb_draw_cff1 (void)
.size = sizeof (str),
.consumed = 0
};
hb_font_get_glyph_shape (font, 3, funcs, &draw_data);
hb_font_draw_glyph (font, 3, funcs, &draw_data);
char expected[] = "M203,367C227,440 248,512 268,588L272,588C293,512 314,440 338,367L369,267L172,267L203,367Z"
"M3,0L88,0L151,200L390,200L452,0L541,0L319,656L225,656L3,0Z"
"M300,653L342,694L201,861L143,806L300,653Z";
@ -282,7 +282,7 @@ test_hb_draw_cff1_rline (void)
.size = sizeof (str),
.consumed = 0
};
hb_font_get_glyph_shape (font, 1, funcs, &draw_data);
hb_font_draw_glyph (font, 1, funcs, &draw_data);
char expected[] = "M775,400C705,400 650,343 650,274L650,250L391,250L713,572L392,893"
"L287,1000C311,942 296,869 250,823C250,823 286,858 321,823L571,572"
"L150,150L750,150L750,276C750,289 761,300 775,300C789,300 800,289 800,276"
@ -307,7 +307,7 @@ test_hb_draw_cff2 (void)
};
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 3, funcs, &draw_data);
hb_font_draw_glyph (font, 3, funcs, &draw_data);
char expected[] = "M275,442C303,442 337,435 371,417L325,454L350,366"
"C357,341 370,321 403,321C428,321 443,333 448,358"
"C435,432 361,487 272,487C153,487 43,393 43,236"
@ -321,7 +321,7 @@ test_hb_draw_cff2 (void)
hb_font_set_variations (font, &var, 1);
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 3, funcs, &draw_data);
hb_font_draw_glyph (font, 3, funcs, &draw_data);
char expected2[] = "M323,448C356,448 380,441 411,427L333,469L339,401"
"C343,322 379,297 420,297C458,297 480,314 492,352"
"C486,433 412,501 303,501C148,501 25,406 25,241"
@ -347,19 +347,19 @@ test_hb_draw_ttf_parser_tests (void)
hb_face_destroy (face);
{
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 0, funcs, &draw_data);
hb_font_draw_glyph (font, 0, funcs, &draw_data);
char expected[] = "M50,0L50,750L450,750L450,0L50,0Z";
g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
}
{
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 1, funcs, &draw_data);
hb_font_draw_glyph (font, 1, funcs, &draw_data);
char expected[] = "M56,416L56,487L514,487L514,416L56,416ZM56,217L56,288L514,288L514,217L56,217Z";
g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
}
{
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 4, funcs, &draw_data);
hb_font_draw_glyph (font, 4, funcs, &draw_data);
char expected[] = "M332,468L197,468L197,0L109,0L109,468L15,468L15,509L109,539"
"L109,570Q109,674 155,720Q201,765 283,765Q315,765 342,760"
"Q368,754 387,747L364,678Q348,683 327,688Q306,693 284,693"
@ -371,13 +371,13 @@ test_hb_draw_ttf_parser_tests (void)
}
{
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 5, funcs, &draw_data);
hb_font_draw_glyph (font, 5, funcs, &draw_data);
char expected[] = "M15,0Q15,0 15,0Z";
g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
}
{
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 6, funcs, &draw_data);
hb_font_draw_glyph (font, 6, funcs, &draw_data);
char expected[] = "M346,468L211,468L211,0L123,0L123,468L29,468L29,509L123,539"
"L123,570Q123,674 169,720Q215,765 297,765Q329,765 356,760"
"Q382,754 401,747L378,678Q362,683 341,688Q320,693 298,693"
@ -394,7 +394,7 @@ test_hb_draw_ttf_parser_tests (void)
hb_face_destroy (face);
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 1, funcs, &draw_data);
hb_font_draw_glyph (font, 1, funcs, &draw_data);
char expected[] = "M0,0C100,0 150,-20 250,-20C350,-20 400,0 500,0C500,100 520,150 520,250"
"C520,350 500,400 500,500C400,500 350,520 250,520C150,520 100,500 0,500"
"C0,400 -20,350 -20,250C-20,150 0,100 0,0ZM50,50C50,130 34,170 34,250"
@ -411,7 +411,7 @@ test_hb_draw_ttf_parser_tests (void)
hb_face_destroy (face);
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 1, funcs, &draw_data);
hb_font_draw_glyph (font, 1, funcs, &draw_data);
char expected[] = "M82,0L164,0L164,486L82,486L82,0Z"
"M124,586C156,586 181,608 181,639C181,671 156,692 124,692"
"C92,692 67,671 67,639C67,608 92,586 124,586Z";
@ -438,7 +438,7 @@ test_hb_draw_font_kit_glyphs_tests (void)
/* should get a path for the glyph */
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 37, funcs, &draw_data);
hb_font_draw_glyph (font, 37, funcs, &draw_data);
char expected[] = "M201,1462L614,1462Q905,1462 1035,1375Q1165,1288 1165,1100"
"Q1165,970 1093,886Q1020,801 881,776L881,766Q1214,709 1214,416"
"Q1214,220 1082,110Q949,0 711,0L201,0L201,1462ZM371,836L651,836"
@ -449,7 +449,7 @@ test_hb_draw_font_kit_glyphs_tests (void)
/* should get a path for the glyph */
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 171, funcs, &draw_data);
hb_font_draw_glyph (font, 171, funcs, &draw_data);
char expected2[] = "M639,-20Q396,-20 256,128Q115,276 115,539Q115,804 246,960Q376,1116 596,1116"
"Q802,1116 922,981Q1042,845 1042,623L1042,518L287,518Q292,325 385,225"
"Q477,125 645,125Q822,125 995,199L995,51Q907,13 829,-3Q750,-20 639,-20Z"
@ -475,7 +475,7 @@ test_hb_draw_font_kit_glyphs_tests (void)
/* should resolve composite glyphs recursively */
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, codepoint, funcs, &draw_data);
hb_font_draw_glyph (font, codepoint, funcs, &draw_data);
char expected[] = "M581,274L443,274Q409,274 384,259Q359,243 348,219Q336,194 340,166"
"Q343,138 365,111L468,-13Q470,-10 473,-6Q475,-3 477,0L253,0Q225,0 203,8"
"Q180,15 168,32Q155,48 155,73L155,269L50,269L50,73Q50,24 69,-10"
@ -491,7 +491,7 @@ test_hb_draw_font_kit_glyphs_tests (void)
/* should transform points of a composite glyph */
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 2, funcs, &draw_data); /* 2 == arAlef.fina */
hb_font_draw_glyph (font, 2, funcs, &draw_data); /* 2 == arAlef.fina */
char expected2[] = "M155,624L155,84Q150,90 146,95Q141,99 136,105"
"L292,105L292,0L156,0Q128,0 104,14Q79,27 65,51"
"Q50,74 50,104L50,624L155,624ZM282,105L312,105"
@ -507,7 +507,7 @@ test_hb_draw_font_kit_glyphs_tests (void)
hb_face_destroy (face);
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 5, funcs, &draw_data);
hb_font_draw_glyph (font, 5, funcs, &draw_data);
char expected[] = "M90,0L258,0C456,0 564,122 564,331C564,539 456,656 254,656L90,656L90,0Z"
"M173,68L173,588L248,588C401,588 478,496 478,331C478,165 401,68 248,68L173,68Z";
g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
@ -522,7 +522,7 @@ test_hb_draw_font_kit_glyphs_tests (void)
hb_face_destroy (face);
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 1, funcs, &draw_data);
hb_font_draw_glyph (font, 1, funcs, &draw_data);
char expected[] = "M139,390C175,390 205,419 205,459C205,501 175,530 139,530C103,530 73,501 73,459"
"C73,419 103,390 139,390ZM139,-13C175,-13 205,15 205,56C205,97 175,127 139,127"
"C103,127 73,97 73,56C73,15 103,-13 139,-13Z";
@ -567,7 +567,7 @@ test_hb_draw_font_kit_variations_tests (void)
hb_buffer_destroy (buffer);
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, codepoint, funcs, &draw_data);
hb_font_draw_glyph (font, codepoint, funcs, &draw_data);
char expected[] = "M371,-102L371,539L914,539L914,-27Q914,-102 840,-102"
"Q796,-102 755,-98L742,-59Q790,-66 836,-66Q871,-66 871,-31L871,504"
"L414,504L414,-102L371,-102ZM203,-94Q138,-94 86,-90L74,-52"
@ -612,7 +612,7 @@ test_hb_draw_font_kit_variations_tests (void)
hb_buffer_destroy (buffer);
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, codepoint, funcs, &draw_data);
hb_font_draw_glyph (font, codepoint, funcs, &draw_data);
char expected[] = "M371,-102L371,539L914,539L914,-27Q914,-102 840,-102Q796,-102 755,-98"
"L742,-59Q790,-66 836,-66Q871,-66 871,-31L871,504L414,504L414,-102"
"L371,-102ZM203,-94Q138,-94 86,-90L74,-52Q137,-59 188,-59Q211,-59 222,-46"
@ -656,7 +656,7 @@ test_hb_draw_font_kit_variations_tests (void)
hb_buffer_destroy (buffer);
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, codepoint, funcs, &draw_data);
hb_font_draw_glyph (font, codepoint, funcs, &draw_data);
char expected[] = "M371,-102L371,539L914,539L914,-27Q914,-102 840,-102Q796,-102 755,-98"
"L742,-59Q790,-66 836,-66Q871,-66 871,-31L871,504L414,504L414,-102"
"L371,-102ZM203,-94Q138,-94 86,-90L74,-52Q137,-59 188,-59Q211,-59 222,-46"
@ -703,7 +703,7 @@ test_hb_draw_font_kit_variations_tests (void)
hb_buffer_destroy (buffer);
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, codepoint, funcs, &draw_data);
hb_font_draw_glyph (font, codepoint, funcs, &draw_data);
char expected[] = "M246,15C188,15 147,27 101,68L142,23L117,117C111,143 96,149 81,149"
"C65,149 56,141 52,126C71,40 137,-13 244,-13C348,-13 436,46 436,156"
"C436,229 405,295 271,349L247,359C160,393 119,439 119,506"
@ -727,7 +727,7 @@ test_hb_draw_font_kit_variations_tests (void)
hb_buffer_destroy (buffer);
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, codepoint, funcs, &draw_data);
hb_font_draw_glyph (font, codepoint, funcs, &draw_data);
char expected[] = "M251,36C206,36 165,42 118,61L176,21L161,99C151,152 129,167 101,167"
"C78,167 61,155 51,131C54,43 133,-14 247,-14C388,-14 474,64 474,171"
"C474,258 430,321 294,370L257,383C188,406 150,438 150,499"
@ -752,7 +752,7 @@ test_hb_draw_font_kit_variations_tests (void)
hb_buffer_destroy (buffer);
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, codepoint, funcs, &draw_data);
hb_font_draw_glyph (font, codepoint, funcs, &draw_data);
char expected[] = "M258,38C197,38 167,48 118,71L192,19L183,103C177,155 155,174 115,174"
"C89,174 64,161 51,125C52,36 124,-16 258,-16C417,-16 513,67 513,175"
"C513,278 457,328 322,388L289,403C232,429 203,452 203,500C203,562 244,589 301,589"
@ -787,7 +787,7 @@ test_hb_draw_estedad_vf (void)
hb_font_set_variations (font, &var, 1);
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 156, funcs, &draw_data);
hb_font_draw_glyph (font, 156, funcs, &draw_data);
/* Skip empty path where all the points of a path are equal */
char expected[] = "M150,1158L182,1158Q256,1158 317,1170Q377,1182 421,1213L421,430L521,430"
"L521,1490L421,1490L421,1320Q393,1279 344,1262Q294,1244 182,1244L150,1244"
@ -797,7 +797,7 @@ test_hb_draw_estedad_vf (void)
g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 180, funcs, &draw_data);
hb_font_draw_glyph (font, 180, funcs, &draw_data);
/* Skip empty path where all the points of a path are equal */
char expected2[] = "M120,693Q120,545 177,414Q233,282 333,182Q433,81 567,24"
"Q701,-33 856,-33Q1010,-33 1144,24Q1277,81 1377,182Q1477,282 1534,414"
@ -817,7 +817,7 @@ test_hb_draw_estedad_vf (void)
g_assert_cmpmem (str, draw_data.consumed, expected2, sizeof (expected2) - 1);
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 262, funcs, &draw_data);
hb_font_draw_glyph (font, 262, funcs, &draw_data);
/* Skip empty path where all the points of a path are equal */
char expected3[] = "M422,598Q495,598 545,548Q595,498 595,426Q595,353 545,303Q494,252 422,252"
"Q350,252 300,303Q250,353 250,426Q250,499 300,549Q349,598 422,598ZM422,698"
@ -847,7 +847,7 @@ test_hb_draw_stroking (void)
hb_face_destroy (face);
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 6, funcs, &draw_data);
hb_font_draw_glyph (font, 6, funcs, &draw_data);
/* Skip empty path where all the points of a path are equal */
char expected[] = "M436,1522Q436,1280 531,1060Q625,839 784,680Q943,521 1164,427Q1384,332 1626,332"
"Q1868,332 2089,427Q2309,521 2468,680Q2627,839 2722,1060Q2816,1280 2816,1522"
@ -862,7 +862,7 @@ test_hb_draw_stroking (void)
g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 7, funcs, &draw_data);
hb_font_draw_glyph (font, 7, funcs, &draw_data);
char expected2[] = "M436,1522Q436,1280 531,1060Q625,839 784,680Q943,521 1164,427"
"Q1384,332 1626,332Q1868,332 2089,427Q2309,521 2468,680"
"Q2627,839 2722,1060Q2816,1280 2816,1522Q2816,1764 2722,1985"
@ -888,14 +888,14 @@ test_hb_draw_stroking (void)
hb_face_destroy (face);
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 4, funcs, &draw_data);
hb_font_draw_glyph (font, 4, funcs, &draw_data);
/* Skip empty path in CFF */
char expected[] = "M106,372C106,532 237,662 397,662C557,662 688,532 688,372C688,212 557,81 397,81C237,81 106,212 106,372Z"
"M62,373C62,188 212,39 397,39C582,39 731,188 731,373C731,558 582,708 397,708C212,708 62,558 62,373Z";
g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 5, funcs, &draw_data);
hb_font_draw_glyph (font, 5, funcs, &draw_data);
/* Fold consequent move-to commands */
char expected2[] = "M106,372C106,532 237,662 397,662C557,662 688,532 688,372"
"C688,212 557,81 397,81C237,81 106,212 106,372ZM62,373"
@ -970,7 +970,7 @@ test_hb_draw_synthetic_slant (void)
hb_font_set_synthetic_slant (font, 0.2f);
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 37, funcs, &draw_data);
hb_font_draw_glyph (font, 37, funcs, &draw_data);
char expected[] = "M493,1462L906,1462Q1197,1462 1310,1375Q1423,1288 1385,1100"
"Q1359,970 1270,886Q1180,801 1036,776L1034,766Q1356,709 1297,416"
"Q1258,220 1104,110Q949,0 711,0L201,0L493,1462ZM538,836L818,836"
@ -988,7 +988,7 @@ test_hb_draw_synthetic_slant (void)
hb_font_set_synthetic_slant (font, 0.2f);
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 5, funcs, &draw_data);
hb_font_draw_glyph (font, 5, funcs, &draw_data);
char expected[] = "M90,0L258,0C456,0 588,122 630,331C672,539 587,656 385,656L221,656L90,0Z"
"M187,68L291,588L366,588C519,588 577,496 544,331C511,165 415,68 262,68L187,68Z";
g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
@ -1015,7 +1015,7 @@ test_hb_draw_subfont_scale (void)
hb_font_set_scale (font2, x*2, y*2);
draw_data.consumed = 0;
hb_font_get_glyph_shape (font1, 37, funcs, &draw_data);
hb_font_draw_glyph (font1, 37, funcs, &draw_data);
char expected1[] = "M201,1462L614,1462Q905,1462 1035,1375Q1165,1288 1165,1100"
"Q1165,970 1093,886Q1020,801 881,776L881,766Q1214,709 1214,416"
"Q1214,220 1082,110Q949,0 711,0L201,0L201,1462ZM371,836L651,836"
@ -1025,7 +1025,7 @@ test_hb_draw_subfont_scale (void)
g_assert_cmpmem (str, draw_data.consumed, expected1, sizeof (expected1) - 1);
draw_data.consumed = 0;
hb_font_get_glyph_shape (font2, 37, funcs, &draw_data);
hb_font_draw_glyph (font2, 37, funcs, &draw_data);
char expected2[] = "M402,2924L1228,2924Q1810,2924 2070,2750Q2330,2576 2330,2200"
"Q2330,1940 2185,1771Q2040,1602 1762,1552L1762,1532Q2428,1418 2428,832"
"Q2428,440 2163,220Q1898,0 1422,0L402,0L402,2924ZM742,1672L1302,1672"
@ -1047,13 +1047,13 @@ test_hb_draw_subfont_scale (void)
hb_font_set_scale (font2, x*2, y*2);
draw_data.consumed = 0;
hb_font_get_glyph_shape (font1, 5, funcs, &draw_data);
hb_font_draw_glyph (font1, 5, funcs, &draw_data);
char expected1[] = "M90,0L258,0C456,0 564,122 564,331C564,539 456,656 254,656L90,656L90,0Z"
"M173,68L173,588L248,588C401,588 478,496 478,331C478,165 401,68 248,68L173,68Z";
g_assert_cmpmem (str, draw_data.consumed, expected1, sizeof (expected1) - 1);
draw_data.consumed = 0;
hb_font_get_glyph_shape (font2, 5, funcs, &draw_data);
hb_font_draw_glyph (font2, 5, funcs, &draw_data);
char expected2[] = "M180,0L516,0C912,0 1128,244 1128,662C1128,1078 912,1312 508,1312L180,1312L180,0Z"
"M346,136L346,1176L496,1176C802,1176 956,992 956,662C956,330 802,136 496,136L346,136Z";
g_assert_cmpmem (str, draw_data.consumed, expected2, sizeof (expected2) - 1);
@ -1089,13 +1089,13 @@ static void test_hb_draw_ft (void)
hb_face_destroy (face);
{
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 0, funcs, &draw_data);
hb_font_draw_glyph (font, 0, funcs, &draw_data);
char expected[] = "M50,0L50,750L450,750L450,0L50,0Z";
g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
}
{
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 5, funcs, &draw_data);
hb_font_draw_glyph (font, 5, funcs, &draw_data);
char expected[] = "M15,0Q15,0 15,0Z";
g_assert_cmpmem (str, draw_data.consumed, expected, sizeof (expected) - 1);
}
@ -1108,7 +1108,7 @@ static void test_hb_draw_ft (void)
hb_face_destroy (face);
draw_data.consumed = 0;
hb_font_get_glyph_shape (font, 1, funcs, &draw_data);
hb_font_draw_glyph (font, 1, funcs, &draw_data);
char expected[] = "M0,0C100,0 150,-20 250,-20C350,-20 400,0 500,0C500,100 520,150 520,250"
"C520,350 500,400 500,500C400,500 350,520 250,520C150,520 100,500 0,500"
"C0,400 -20,350 -20,250C-20,150 0,100 0,0ZM50,50C50,130 34,170 34,250"

View File

@ -480,6 +480,7 @@ main (int argc, char **argv)
hb_test_add (test_hb_ot_color_has_data);
hb_test_add (test_hb_ot_color_png);
hb_test_add (test_hb_ot_color_svg);
status = hb_test_run();
hb_face_destroy (cpal_v0);
hb_face_destroy (cpal_v1);

569
test/api/test-paint.c Normal file
View File

@ -0,0 +1,569 @@
/*
* 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.
*/
#include "hb-test.h"
#include <hb-features.h>
#include <hb-ot.h>
#ifdef HB_HAS_FREETYPE
#include <hb-ft.h>
#endif
/* Unit tests for hb-paint.h */
/* ---- */
typedef struct {
int level;
GString *string;
} paint_data_t;
static void
print (paint_data_t *data,
const char *format,
...)
{
va_list args;
g_string_append_printf (data->string, "%*s", 2 * data->level, "");
va_start (args, format);
g_string_append_vprintf (data->string, format, args);
va_end (args);
g_string_append (data->string, "\n");
}
static void
push_transform (hb_paint_funcs_t *funcs,
void *paint_data,
float xx, float yx,
float xy, float yy,
float dx, float dy,
void *user_data)
{
paint_data_t *data = user_data;
print (data, "start transform %f %f %f %f %f %f", xx, yx, xy, yy, dx, dy);
data->level++;
}
static void
pop_transform (hb_paint_funcs_t *funcs,
void *paint_data,
void *user_data)
{
paint_data_t *data = user_data;
data->level--;
print (data, "end transform");
}
static void
push_clip_glyph (hb_paint_funcs_t *funcs,
void *paint_data,
hb_codepoint_t glyph,
hb_font_t *font,
void *user_data)
{
paint_data_t *data = user_data;
print (data, "start clip glyph %u", glyph);
data->level++;
}
static void
push_clip_rectangle (hb_paint_funcs_t *funcs,
void *paint_data,
float xmin, float ymin, float xmax, float ymax,
void *user_data)
{
paint_data_t *data = user_data;
print (data, "start clip rectangle %f %f %f %f", xmin, ymin, xmax, ymax);
data->level++;
}
static void
pop_clip (hb_paint_funcs_t *funcs,
void *paint_data,
void *user_data)
{
paint_data_t *data = user_data;
data->level--;
print (data, "end clip");
}
static void
paint_color (hb_paint_funcs_t *funcs,
void *paint_data,
hb_bool_t use_foreground,
hb_color_t color,
void *user_data)
{
paint_data_t *data = user_data;
print (data, "solid %d %d %d %d",
hb_color_get_red (color),
hb_color_get_green (color),
hb_color_get_blue (color),
hb_color_get_alpha (color));
}
static void
paint_image (hb_paint_funcs_t *funcs,
void *paint_data,
hb_blob_t *blob,
unsigned int width,
unsigned int height,
hb_tag_t format,
float slant,
hb_glyph_extents_t *extents,
void *user_data)
{
paint_data_t *data = user_data;
char buf[5] = { 0, };
hb_tag_to_string (format, buf);
print (data, "image type %s size %u %u slant %f extents %d %d %d %d\n",
buf, width, height, slant,
extents->x_bearing, extents->y_bearing, extents->width, extents->height);
}
static void
print_color_line (paint_data_t *data,
hb_color_line_t *color_line)
{
hb_color_stop_t *stops;
unsigned int len;
len = hb_color_line_get_color_stops (color_line, 0, NULL, NULL);
stops = alloca (len * sizeof (hb_color_stop_t));
hb_color_line_get_color_stops (color_line, 0, &len, stops);
print (data, "colors");
data->level += 1;
for (unsigned int i = 0; i < len; i++)
print (data, "%f %d %d %d %d",
stops[i].offset,
hb_color_get_red (stops[i].color),
hb_color_get_green (stops[i].color),
hb_color_get_blue (stops[i].color),
hb_color_get_alpha (stops[i].color));
data->level -= 1;
}
static void
paint_linear_gradient (hb_paint_funcs_t *funcs,
void *paint_data,
hb_color_line_t *color_line,
float x0, float y0,
float x1, float y1,
float x2, float y2,
void *user_data)
{
paint_data_t *data = user_data;
print (data, "linear gradient");
data->level += 1;
print (data, "p0 %f %f", x0, y0);
print (data, "p1 %f %f", x1, y1);
print (data, "p2 %f %f", x2, y2);
print_color_line (data, color_line);
data->level -= 1;
}
static void
paint_radial_gradient (hb_paint_funcs_t *funcs,
void *paint_data,
hb_color_line_t *color_line,
float x0, float y0, float r0,
float x1, float y1, float r1,
void *user_data)
{
paint_data_t *data = user_data;
print (data, "radial gradient");
data->level += 1;
print (data, "p0 %f %f radius %f", x0, y0, r0);
print (data, "p1 %f %f radius %f", x1, y1, r1);
print_color_line (data, color_line);
data->level -= 1;
}
static void
paint_sweep_gradient (hb_paint_funcs_t *funcs,
void *paint_data,
hb_color_line_t *color_line,
float cx, float cy,
float start_angle,
float end_angle,
void *user_data)
{
paint_data_t *data = user_data;
print (data, "sweep gradient");
data->level++;
print (data, "center %f %f", cx, cy);
print (data, "angles %f %f", start_angle, end_angle);
print_color_line (data, color_line);
data->level -= 1;
}
static void
push_group (hb_paint_funcs_t *funcs,
void *paint_data,
void *user_data)
{
paint_data_t *data = user_data;
print (data, "push group");
data->level++;
}
static void
pop_group (hb_paint_funcs_t *funcs,
void *paint_data,
hb_paint_composite_mode_t mode,
void *user_data)
{
paint_data_t *data = user_data;
data->level--;
print (data, "pop group mode %d", mode);
}
typedef struct {
const char *font_file;
int scale;
float slant;
hb_codepoint_t glyph;
unsigned int palette;
const char *output;
} paint_test_t;
#define NOTO_HAND "fonts/noto_handwriting-cff2_colr_1.otf"
#define TEST_GLYPHS "fonts/test_glyphs-glyf_colr_1.ttf"
#define ROCHER_ABC "fonts/RocherColorGX.abc.ttf"
/* To verify the rendering visually, use
*
* hb-view --font-size SCALE --font-slant SLANT --font-palette PALETTE FONT --glyphs [gidGID=0+1000]
*
* where GID is the glyph value of the test.
*/
static paint_test_t paint_tests[] = {
/* COLRv1 */
{ NOTO_HAND, 20, 0., 10, 0, "hand-20-0-10" },
{ NOTO_HAND, 20, 0.2, 10, 0, "hand-20-0.2-10" },
{ TEST_GLYPHS, 20, 0, 6, 0, "test-20-0-6" }, // linear gradient
{ TEST_GLYPHS, 20, 0, 10, 0, "test-20-0-10" }, // sweep gradient
{ TEST_GLYPHS, 20, 0, 92, 0, "test-20-0-92" }, // radial gradient
{ TEST_GLYPHS, 20, 0, 106, 0, "test-20-0-106" },
{ TEST_GLYPHS, 20, 0, 116, 0, "test-20-0-116" }, // compositing
{ TEST_GLYPHS, 20, 0, 123, 0, "test-20-0-123" },
{ TEST_GLYPHS, 20, 0, 165, 0, "test-20-0-165" }, // linear gradient
{ TEST_GLYPHS, 20, 0, 175, 0, "test-20-0-175" }, // layers
/* COLRv0 */
{ ROCHER_ABC, 120, 0.3, 1, 0, "rocher-120-0.3-1" },
{ ROCHER_ABC, 120, 0.3, 2, 2, "rocher-120-0.3-2" },
{ ROCHER_ABC, 120, 0, 3, 200, "rocher-120-0-3" },
};
#ifdef HB_HAS_FREETYPE
static FT_Library library;
#endif
static void
test_hb_paint (gconstpointer d,
hb_bool_t use_ft)
{
const paint_test_t *test = d;
hb_face_t *face;
hb_font_t *font;
hb_paint_funcs_t *funcs;
paint_data_t data;
char *file;
char *buffer;
gsize len;
GError *error = NULL;
#ifdef HB_HAS_FREETYPE
if (use_ft)
{
FT_Face ft_face;
char *path;
path = g_test_build_filename (G_TEST_DIST, test->font_file, NULL);
if (FT_New_Face (library, path, 0, &ft_face) != 0)
{
g_test_message ("Failed to create FT_Face for %s", path);
g_test_fail ();
g_free (path);
return;
}
face = hb_ft_face_create_referenced (ft_face);
FT_Done_Face (ft_face);
g_free (path);
}
else
#endif
{
face = hb_test_open_font_file (test->font_file);
}
font = hb_font_create (face);
hb_font_set_scale (font, test->scale, test->scale);
hb_font_set_synthetic_slant (font, test->slant);
funcs = hb_paint_funcs_create ();
hb_paint_funcs_set_push_transform_func (funcs, push_transform, &data, NULL);
hb_paint_funcs_set_pop_transform_func (funcs, pop_transform, &data, NULL);
hb_paint_funcs_set_push_clip_glyph_func (funcs, push_clip_glyph, &data, NULL);
hb_paint_funcs_set_push_clip_rectangle_func (funcs, push_clip_rectangle, &data, NULL);
hb_paint_funcs_set_pop_clip_func (funcs, pop_clip, &data, NULL);
hb_paint_funcs_set_push_group_func (funcs, push_group, &data, NULL);
hb_paint_funcs_set_pop_group_func (funcs, pop_group, &data, NULL);
hb_paint_funcs_set_color_func (funcs, paint_color, &data, NULL);
hb_paint_funcs_set_image_func (funcs, paint_image, &data, NULL);
hb_paint_funcs_set_linear_gradient_func (funcs, paint_linear_gradient, &data, NULL);
hb_paint_funcs_set_radial_gradient_func (funcs, paint_radial_gradient, &data, NULL);
hb_paint_funcs_set_sweep_gradient_func (funcs, paint_sweep_gradient, &data, NULL);
data.string = g_string_new ("");
data.level = 0;
hb_font_paint_glyph (font, test->glyph, funcs, &data, 0, HB_COLOR (0, 0, 0, 255));
/* Run
*
* GENERATE_DATA=1 G_TEST_SRCDIR=./test/api ./build/test/api/test-ot-color -p TESTCASE > test/api/results/OUTPUT
*
* to produce the expected results file.
*/
if (getenv ("GENERATE_DATA"))
{
g_print ("%s", data.string->str);
exit (0);
}
file = g_test_build_filename (G_TEST_DIST, "results", test->output, NULL);
if (!g_file_get_contents (file, &buffer, &len, &error))
{
g_test_message ("File %s not found.", file);
g_test_fail ();
return;
}
char **lines = g_strsplit (data.string->str, "\n", 0);
char **expected;
if (strstr (buffer, "\r\n"))
expected = g_strsplit (buffer, "\r\n", 0);
else
expected = g_strsplit (buffer, "\n", 0);
if (g_strv_length (lines) != g_strv_length (expected))
{
g_test_message ("Unexpected number of lines in output (%d instead of %d)", g_strv_length (lines), g_strv_length (expected));
g_test_fail ();
}
else
{
unsigned int length = g_strv_length (lines);
for (unsigned int i = 0; i < length; i++)
{
if (strcmp (lines[i], expected[i]) != 0)
{
int pos;
for (pos = 0; lines[i][pos]; pos++)
if (lines[i][pos] != expected[i][pos])
break;
g_test_message ("Unxpected output at %d:%d (%#x instead of %#x):\n%s", i, pos, (unsigned int)lines[i][pos], (unsigned int)expected[i][pos], data.string->str);
g_test_fail ();
}
}
}
g_strfreev (lines);
g_strfreev (expected);
g_free (buffer);
g_free (file);
g_string_free (data.string, TRUE);
hb_paint_funcs_destroy (funcs);
hb_font_destroy (font);
hb_face_destroy (face);
}
static void
test_hb_paint_ot (gconstpointer data)
{
test_hb_paint (data, 0);
}
static void
test_hb_paint_ft (gconstpointer data)
{
#ifdef HB_HAS_FREETYPE
test_hb_paint (data, 1);
#else
g_test_skip_printf ("freetype support not present");
#endif
}
static void
scrutinize_linear_gradient (hb_paint_funcs_t *funcs,
void *paint_data,
hb_color_line_t *color_line,
float x0, float y0,
float x1, float y1,
float x2, float y2,
void *user_data)
{
hb_bool_t *result = paint_data;
hb_color_stop_t *stops;
unsigned int len;
hb_color_stop_t *stops2;
unsigned int len2;
*result = FALSE;
len = hb_color_line_get_color_stops (color_line, 0, NULL, NULL);
if (len == 0)
return;
stops = malloc (len * sizeof (hb_color_stop_t));
stops2 = malloc (len * sizeof (hb_color_stop_t));
hb_color_line_get_color_stops (color_line, 0, &len, stops);
hb_color_line_get_color_stops (color_line, 0, &len, stops2);
// check that we can get stops twice
if (memcmp (stops, stops2, len * sizeof (hb_color_stop_t)) != 0)
{
free (stops);
free (stops2);
return;
}
// check that we can get a single stop in the middle
len2 = 1;
hb_color_line_get_color_stops (color_line, len - 1, &len2, stops2);
if (memcmp (&stops[len - 1], stops2, sizeof (hb_color_stop_t)) != 0)
{
free (stops);
free (stops2);
return;
}
free (stops);
free (stops2);
*result = TRUE;
}
static void
test_color_stops (hb_bool_t use_ft)
{
hb_face_t *face;
hb_font_t *font;
hb_paint_funcs_t *funcs;
hb_bool_t result = FALSE;
#ifdef HB_HAS_FREETYPE
if (use_ft)
{
FT_Face ft_face;
char *path;
path = g_test_build_filename (G_TEST_DIST, NOTO_HAND, NULL);
if (FT_New_Face (library, path, 0, &ft_face) != 0)
{
g_test_message ("Failed to create FT_Face for %s", path);
g_test_fail ();
g_free (path);
return;
}
face = hb_ft_face_create_referenced (ft_face);
FT_Done_Face (ft_face);
g_free (path);
}
else
#endif
face = hb_test_open_font_file (NOTO_HAND);
font = hb_font_create (face);
funcs = hb_paint_funcs_create ();
hb_paint_funcs_set_linear_gradient_func (funcs, scrutinize_linear_gradient, NULL, NULL);
hb_font_paint_glyph (font, 10, funcs, &result, 0, HB_COLOR (0, 0, 0, 255));
g_assert_true (result);
hb_paint_funcs_destroy (funcs);
hb_font_destroy (font);
hb_face_destroy (face);
}
static void
test_color_stops_ot (void)
{
test_color_stops (0);
}
static void
test_color_stops_ft (void)
{
test_color_stops (1);
}
int
main (int argc, char **argv)
{
int status = 0;
#ifdef HB_HAS_FREETYPE
FT_Init_FreeType (&library);
#endif
hb_test_init (&argc, &argv);
for (unsigned int i = 0; i < G_N_ELEMENTS (paint_tests); i++)
{
hb_test_add_data_flavor (&paint_tests[i], paint_tests[i].output, test_hb_paint_ot);
hb_test_add_data_flavor (&paint_tests[i], paint_tests[i].output, test_hb_paint_ft);
}
hb_test_add (test_color_stops_ot);
hb_test_add (test_color_stops_ft);
status = hb_test_run();
return status;
}

View File

@ -151,7 +151,7 @@ extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
hb_set_t *set = hb_set_create ();
for (unsigned gid = 0; gid < glyph_count; ++gid)
{
hb_font_get_glyph_shape (font, gid, funcs, &draw_data);
hb_font_draw_glyph (font, gid, funcs, &draw_data);
/* Glyph extents also may practices the similar path, call it now that is related */
hb_glyph_extents_t extents;

View File

@ -2,6 +2,8 @@ HB_VIEW_sources = \
ansi-print.hh \
face-options.hh \
font-options.hh \
hb-cairo-utils.h \
hb-cairo-utils.c \
hb-view.cc \
helper-cairo-ansi.hh \
helper-cairo-ft.hh \

View File

@ -69,6 +69,7 @@ struct font_options_t : face_options_t
mutable double font_size_y = DEFAULT_FONT_SIZE;
char *font_funcs = nullptr;
int ft_load_flags = 2;
unsigned int palette = 0;
hb_font_t *font = nullptr;
};
@ -287,6 +288,7 @@ font_options_t::add_options (option_parser_t *parser)
G_OPTION_ARG_DOUBLE, &this->ptem, "Set font point-size (default: 0; disabled)", "point-size"},
{"font-slant", 0, 0,
G_OPTION_ARG_DOUBLE, &this->slant, "Set synthetic slant (default: 0)", "slant ratio; eg. 0.2"},
{"font-palette", 0, 0, G_OPTION_ARG_INT, &this->palette, "Set font palette (default: 0)", "index"},
{"font-funcs", 0, 0, G_OPTION_ARG_STRING, &this->font_funcs, text, "impl"},
{"sub-font", 0, G_OPTION_FLAG_HIDDEN,
G_OPTION_ARG_NONE, &this->sub_font, "Create a sub-font (default: false)", "boolean"},

845
util/hb-cairo-utils.c Normal file
View File

@ -0,0 +1,845 @@
/*
* Copyright © 2022 Red Hat, Inc
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Matthias Clasen
*/
#include "config.h"
#include "hb-cairo-utils.h"
#include <cairo.h>
#include <hb-ot.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define _USE_MATH_DEFINES
#include <math.h>
#include <assert.h>
#ifndef MIN
#define MIN(x,y) ((x) < (y) ? (x) : (y))
#endif
#ifndef MAX
#define MAX(x,y) ((x) > (y) ? (x) : (y))
#endif
#ifndef FALSE
#define TRUE 1
#define FALSE 0
#endif
#define PREALLOCATED_COLOR_STOPS 16
typedef struct {
float r, g, b, a;
} color_t;
static inline cairo_extend_t
cairo_extend (hb_paint_extend_t extend)
{
switch (extend)
{
case HB_PAINT_EXTEND_PAD: return CAIRO_EXTEND_PAD;
case HB_PAINT_EXTEND_REPEAT: return CAIRO_EXTEND_REPEAT;
case HB_PAINT_EXTEND_REFLECT: return CAIRO_EXTEND_REFLECT;
default:;
}
return CAIRO_EXTEND_PAD;
}
#ifdef CAIRO_HAS_PNG_FUNCTIONS
typedef struct
{
hb_blob_t *blob;
unsigned int offset;
} read_blob_data_t;
static cairo_status_t
read_blob (void *closure,
unsigned char *data,
unsigned int length)
{
read_blob_data_t *r = (read_blob_data_t *) closure;
const char *d;
unsigned int size;
d = hb_blob_get_data (r->blob, &size);
if (r->offset + length > size)
return CAIRO_STATUS_READ_ERROR;
memcpy (data, d + r->offset, length);
r->offset += length;
return CAIRO_STATUS_SUCCESS;
}
#endif
static const cairo_user_data_key_t *_hb_cairo_surface_blob_user_data_key = {0};
static void
_hb_cairo_destroy_blob (void *p)
{
hb_blob_destroy ((hb_blob_t *) p);
}
void
hb_cairo_paint_glyph_image (cairo_t *cr,
hb_blob_t *blob,
unsigned width,
unsigned height,
hb_tag_t format,
float slant,
hb_glyph_extents_t *extents)
{
if (!extents) /* SVG currently. */
return;
cairo_surface_t *surface = NULL;
#ifdef CAIRO_HAS_PNG_FUNCTIONS
if (format == HB_PAINT_IMAGE_FORMAT_PNG)
{
read_blob_data_t r;
r.blob = blob;
r.offset = 0;
surface = cairo_image_surface_create_from_png_stream (read_blob, &r);
/* For PNG, width,height can be unreliable, as is the case for NotoColorEmoji :(.
* Just pull them out of the surface. */
width = cairo_image_surface_get_width (surface);
height = cairo_image_surface_get_width (surface);
}
else
#endif
if (format == HB_PAINT_IMAGE_FORMAT_BGRA)
{
/* Byte-endian conversion. */
unsigned data_size = hb_blob_get_length (blob);
if (data_size < width * height * 4)
return;
unsigned char *data;
#ifdef __BYTE_ORDER
if (__BYTE_ORDER == __BIG_ENDIAN)
{
data = (unsigned char *) hb_blob_get_data_writable (blob, NULL);
if (!data)
return;
unsigned count = width * height * 4;
for (unsigned i = 0; i < count; i += 4)
{
unsigned char b;
b = data[i];
data[i] = data[i+3];
data[i+3] = b;
b = data[i+1];
data[i+1] = data[i+2];
data[i+2] = b;
}
}
else
#endif
data = (unsigned char *) hb_blob_get_data (blob, NULL);
surface = cairo_image_surface_create_for_data (data,
CAIRO_FORMAT_ARGB32,
width, height,
width * 4);
cairo_surface_set_user_data (surface,
_hb_cairo_surface_blob_user_data_key,
hb_blob_reference (blob),
_hb_cairo_destroy_blob);
}
if (!surface)
return;
cairo_save (cr);
/* this clip is here to work around recording surface limitations */
cairo_rectangle (cr,
extents->x_bearing,
extents->y_bearing,
extents->width,
extents->height);
cairo_clip (cr);
cairo_pattern_t *pattern = cairo_pattern_create_for_surface (surface);
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
cairo_matrix_t matrix = {(double) width, 0, 0, (double) height, 0, 0};
cairo_pattern_set_matrix (pattern, &matrix);
/* Undo slant in the extents and apply it in the context. */
extents->width -= extents->height * slant;
extents->x_bearing -= extents->y_bearing * slant;
cairo_matrix_t cairo_matrix = {1., 0., slant, 1., 0., 0.};
cairo_transform (cr, &cairo_matrix);
cairo_translate (cr, extents->x_bearing, extents->y_bearing);
cairo_scale (cr, extents->width, extents->height);
cairo_set_source (cr, pattern);
cairo_paint (cr);
cairo_pattern_destroy (pattern);
cairo_surface_destroy (surface);
cairo_restore (cr);
}
static void
reduce_anchors (float x0, float y0,
float x1, float y1,
float x2, float y2,
float *xx0, float *yy0,
float *xx1, float *yy1)
{
float q1x, q1y, q2x, q2y;
float s;
float k;
q2x = x2 - x0;
q2y = y2 - y0;
q1x = y1 - x0;
q1y = y1 - y0;
s = q2x * q2x + q2y * q2y;
if (s < 0.000001f)
{
*xx0 = x0; *yy0 = y0;
*xx1 = x1; *yy1 = y1;
return;
}
k = (q2x * q1x + q2y * q1y) / s;
*xx0 = x0;
*yy0 = y0;
*xx1 = x1 - k * q2x;
*yy1 = y1 - k * q2y;
}
static int
cmp_color_stop (const void *p1,
const void *p2)
{
const hb_color_stop_t *c1 = (const hb_color_stop_t *) p1;
const hb_color_stop_t *c2 = (const hb_color_stop_t *) p2;
if (c1->offset < c2->offset)
return -1;
else if (c1->offset > c2->offset)
return 1;
else
return 0;
}
static void
normalize_color_line (hb_color_stop_t *stops,
unsigned int len,
float *omin,
float *omax)
{
float min, max;
qsort (stops, len, sizeof (hb_color_stop_t), cmp_color_stop);
min = max = stops[0].offset;
for (unsigned int i = 0; i < len; i++)
{
min = MIN (min, stops[i].offset);
max = MAX (max, stops[i].offset);
}
if (min != max)
{
for (unsigned int i = 0; i < len; i++)
stops[i].offset = (stops[i].offset - min) / (max - min);
}
*omin = min;
*omax = max;
}
void
hb_cairo_paint_linear_gradient (cairo_t *cr,
hb_color_line_t *color_line,
float x0, float y0,
float x1, float y1,
float x2, float y2)
{
hb_color_stop_t stops_[PREALLOCATED_COLOR_STOPS];
hb_color_stop_t *stops = stops_;
unsigned int len;
float xx0, yy0, xx1, yy1;
float xxx0, yyy0, xxx1, yyy1;
float min, max;
cairo_pattern_t *pattern;
len = hb_color_line_get_color_stops (color_line, 0, NULL, NULL);
if (len > PREALLOCATED_COLOR_STOPS)
stops = (hb_color_stop_t *) malloc (len * sizeof (hb_color_stop_t));
hb_color_line_get_color_stops (color_line, 0, &len, stops);
reduce_anchors (x0, y0, x1, y1, x2, y2, &xx0, &yy0, &xx1, &yy1);
normalize_color_line (stops, len, &min, &max);
xxx0 = xx0 + min * (xx1 - xx0);
yyy0 = yy0 + min * (yy1 - yy0);
xxx1 = xx0 + max * (xx1 - xx0);
yyy1 = yy0 + max * (yy1 - yy0);
pattern = cairo_pattern_create_linear (xxx0, yyy0, xxx1, yyy1);
cairo_pattern_set_extend (pattern, cairo_extend (hb_color_line_get_extend (color_line)));
for (unsigned int i = 0; i < len; i++)
{
double r, g, b, a;
r = hb_color_get_red (stops[i].color) / 255.;
g = hb_color_get_green (stops[i].color) / 255.;
b = hb_color_get_blue (stops[i].color) / 255.;
a = hb_color_get_alpha (stops[i].color) / 255.;
cairo_pattern_add_color_stop_rgba (pattern, stops[i].offset, r, g, b, a);
}
cairo_set_source (cr, pattern);
cairo_paint (cr);
cairo_pattern_destroy (pattern);
if (stops != stops_)
free (stops);
}
void
hb_cairo_paint_radial_gradient (cairo_t *cr,
hb_color_line_t *color_line,
float x0, float y0, float r0,
float x1, float y1, float r1)
{
hb_color_stop_t stops_[PREALLOCATED_COLOR_STOPS];
hb_color_stop_t *stops = stops_;
unsigned int len;
float min, max;
float xx0, yy0, xx1, yy1;
float rr0, rr1;
cairo_pattern_t *pattern;
len = hb_color_line_get_color_stops (color_line, 0, NULL, NULL);
if (len > PREALLOCATED_COLOR_STOPS)
stops = (hb_color_stop_t *) malloc (len * sizeof (hb_color_stop_t));
hb_color_line_get_color_stops (color_line, 0, &len, stops);
normalize_color_line (stops, len, &min, &max);
xx0 = x0 + min * (x1 - x0);
yy0 = y0 + min * (y1 - y0);
xx1 = x0 + max * (x1 - x0);
yy1 = y0 + max * (y1 - y0);
rr0 = r0 + min * (r1 - r0);
rr1 = r0 + max * (r1 - r0);
pattern = cairo_pattern_create_radial (xx0, yy0, rr0, xx1, yy1, rr1);
cairo_pattern_set_extend (pattern, cairo_extend (hb_color_line_get_extend (color_line)));
for (unsigned int i = 0; i < len; i++)
{
double r, g, b, a;
r = hb_color_get_red (stops[i].color) / 255.;
g = hb_color_get_green (stops[i].color) / 255.;
b = hb_color_get_blue (stops[i].color) / 255.;
a = hb_color_get_alpha (stops[i].color) / 255.;
cairo_pattern_add_color_stop_rgba (pattern, stops[i].offset, r, g, b, a);
}
cairo_set_source (cr, pattern);
cairo_paint (cr);
cairo_pattern_destroy (pattern);
if (stops != stops_)
free (stops);
}
typedef struct {
float x, y;
} Point;
static inline float
interpolate (float f0, float f1, float f)
{
return f0 + f * (f1 - f0);
}
static inline void
premultiply (color_t *c)
{
c->r *= c->a;
c->g *= c->a;
c->b *= c->a;
}
static inline void
unpremultiply (color_t *c)
{
if (c->a != 0.)
{
c->r /= c->a;
c->g /= c->a;
c->b /= c->a;
}
}
static void
interpolate_colors (color_t *c0, color_t *c1, float k, color_t *c)
{
// According to the COLR specification, gradients
// should be interpolated in premultiplied form
premultiply (c0);
premultiply (c1);
c->r = c0->r + k * (c1->r - c0->r);
c->g = c0->g + k * (c1->g - c0->g);
c->b = c0->b + k * (c1->b - c0->b);
c->a = c0->a + k * (c1->a - c0->a);
unpremultiply (c);
}
static inline float
dot (Point p, Point q)
{
return p.x * q.x + p.y * q.y;
}
static inline Point
normalize (Point p)
{
float len = sqrt (dot (p, p));
return (Point) { p.x / len, p.y / len };
}
static inline Point
sum (Point p, Point q)
{
return (Point) { p.x + q.x, p.y + q.y };
}
static inline Point
difference (Point p, Point q)
{
return (Point) { p.x - q.x, p.y - q.y };
}
static inline Point
scale (Point p, float f)
{
return (Point) { p.x * f, p.y * f };
}
typedef struct {
Point center, p0, c0, c1, p1;
color_t color0, color1;
} Patch;
static void
add_patch (cairo_pattern_t *pattern, Point *center, Patch *p)
{
cairo_mesh_pattern_begin_patch (pattern);
cairo_mesh_pattern_move_to (pattern, center->x, center->y);
cairo_mesh_pattern_line_to (pattern, p->p0.x, p->p0.y);
cairo_mesh_pattern_curve_to (pattern,
p->c0.x, p->c0.y,
p->c1.x, p->c1.y,
p->p1.x, p->p1.y);
cairo_mesh_pattern_line_to (pattern, center->x, center->y);
cairo_mesh_pattern_set_corner_color_rgba (pattern, 0,
p->color0.r,
p->color0.g,
p->color0.b,
p->color0.a);
cairo_mesh_pattern_set_corner_color_rgba (pattern, 1,
p->color0.r,
p->color0.g,
p->color0.b,
p->color0.a);
cairo_mesh_pattern_set_corner_color_rgba (pattern, 2,
p->color1.r,
p->color1.g,
p->color1.b,
p->color1.a);
cairo_mesh_pattern_set_corner_color_rgba (pattern, 3,
p->color1.r,
p->color1.g,
p->color1.b,
p->color1.a);
cairo_mesh_pattern_end_patch (pattern);
}
#define MAX_ANGLE (M_PI / 8.)
static void
add_sweep_gradient_patches1 (float cx, float cy, float radius,
float a0, color_t *c0,
float a1, color_t *c1,
cairo_pattern_t *pattern)
{
Point center = (Point) { cx, cy };
int num_splits;
Point p0;
color_t color0, color1;
num_splits = ceilf (fabs (a1 - a0) / MAX_ANGLE);
p0 = (Point) { cosf (a0), sinf (a0) };
color0 = *c0;
for (int a = 0; a < num_splits; a++)
{
float k = (a + 1.) / num_splits;
float angle1;
Point p1;
Point A, U;
Point C0, C1;
Patch patch;
angle1 = interpolate (a0, a1, k);
interpolate_colors (c0, c1, k, &color1);
patch.color0 = color0;
patch.color1 = color1;
p1 = (Point) { cosf (angle1), sinf (angle1) };
patch.p0 = sum (center, scale (p0, radius));
patch.p1 = sum (center, scale (p1, radius));
A = normalize (sum (p0, p1));
U = (Point) { -A.y, A.x };
C0 = sum (A, scale (U, dot (difference (p0, A), p0) / dot (U, p0)));
C1 = sum (A, scale (U, dot (difference (p1, A), p1) / dot (U, p1)));
patch.c0 = sum (center, scale (sum (C0, scale (difference (C0, p0), 0.33333)), radius));
patch.c1 = sum (center, scale (sum (C1, scale (difference (C1, p1), 0.33333)), radius));
add_patch (pattern, &center, &patch);
p0 = p1;
color0 = color1;
}
}
static void
add_sweep_gradient_patches (hb_color_stop_t *stops,
unsigned int n_stops,
cairo_extend_t extend,
float cx, float cy,
float radius,
float start_angle,
float end_angle,
cairo_pattern_t *pattern)
{
float angles_[PREALLOCATED_COLOR_STOPS];
float *angles = angles_;
color_t colors_[PREALLOCATED_COLOR_STOPS];
color_t *colors = colors_;
color_t color0, color1;
if (start_angle == end_angle)
{
if (extend == CAIRO_EXTEND_PAD)
{
color_t c;
if (start_angle > 0)
{
c.r = hb_color_get_red (stops[0].color) / 255.;
c.g = hb_color_get_green (stops[0].color) / 255.;
c.b = hb_color_get_blue (stops[0].color) / 255.;
c.a = hb_color_get_alpha (stops[0].color) / 255.;
add_sweep_gradient_patches1 (cx, cy, radius,
0., &c,
start_angle, &c,
pattern);
}
if (end_angle < 2 * M_PI)
{
c.r = hb_color_get_red (stops[n_stops - 1].color) / 255.;
c.g = hb_color_get_green (stops[n_stops - 1].color) / 255.;
c.b = hb_color_get_blue (stops[n_stops - 1].color) / 255.;
c.a = hb_color_get_alpha (stops[n_stops - 1].color) / 255.;
add_sweep_gradient_patches1 (cx, cy, radius,
end_angle, &c,
2 * M_PI, &c,
pattern);
}
}
return;
}
assert (start_angle != end_angle);
/* handle directions */
if (end_angle < start_angle)
{
float angle = end_angle;
end_angle = start_angle;
start_angle = angle;
for (unsigned i = 0; i < n_stops - 1 - i; i++)
{
hb_color_stop_t stop = stops[i];
stops[i] = stops[n_stops - 1 - i];
stops[n_stops - 1 - i] = stop;
}
}
if (n_stops > PREALLOCATED_COLOR_STOPS)
{
angles = (float *) malloc (sizeof (float) * n_stops);
colors = (color_t *) malloc (sizeof (color_t) * n_stops);
}
for (unsigned i = 0; i < n_stops; i++)
{
angles[i] = start_angle + stops[i].offset * (end_angle - start_angle);
colors[i].r = hb_color_get_red (stops[i].color) / 255.;
colors[i].g = hb_color_get_green (stops[i].color) / 255.;
colors[i].b = hb_color_get_blue (stops[i].color) / 255.;
colors[i].a = hb_color_get_alpha (stops[i].color) / 255.;
}
if (extend == CAIRO_EXTEND_PAD)
{
unsigned pos;
color0 = colors[0];
for (pos = 0; pos < n_stops; pos++)
{
if (angles[pos] >= 0)
{
if (pos > 0)
{
float k = (0 - angles[pos - 1]) / (angles[pos] - angles[pos - 1]);
interpolate_colors (&colors[pos-1], &colors[pos], k, &color0);
}
break;
}
}
if (pos == n_stops)
{
/* everything is below 0 */
color0 = colors[n_stops-1];
add_sweep_gradient_patches1 (cx, cy, radius,
0., &color0,
2 * M_PI, &color0,
pattern);
goto done;
}
add_sweep_gradient_patches1 (cx, cy, radius,
0., &color0,
angles[pos], &colors[pos],
pattern);
for (pos++; pos < n_stops; pos++)
{
if (angles[pos] <= 2 * M_PI)
{
add_sweep_gradient_patches1 (cx, cy, radius,
angles[pos - 1], &colors[pos-1],
angles[pos], &colors[pos],
pattern);
}
else
{
float k = (2 * M_PI - angles[pos - 1]) / (angles[pos] - angles[pos - 1]);
interpolate_colors (&colors[pos - 1], &colors[pos], k, &color1);
add_sweep_gradient_patches1 (cx, cy, radius,
angles[pos - 1], &colors[pos - 1],
2 * M_PI, &color1,
pattern);
break;
}
}
if (pos == n_stops)
{
/* everything is below 2*M_PI */
color0 = colors[n_stops - 1];
add_sweep_gradient_patches1 (cx, cy, radius,
angles[n_stops - 1], &color0,
2 * M_PI, &color0,
pattern);
goto done;
}
}
else
{
int k;
float span;
span = angles[n_stops - 1] - angles[0];
k = 0;
if (angles[0] >= 0)
{
float ss = angles[0];
while (ss > 0)
{
if (span > 0)
{
ss -= span;
k--;
}
else
{
ss += span;
k++;
}
}
}
else if (angles[0] < 0)
{
float ee = angles[n_stops - 1];
while (ee < 0)
{
if (span > 0)
{
ee += span;
k++;
}
else
{
ee -= span;
k--;
}
}
}
//assert (angles[0] + k * span <= 0 && 0 < angles[n_stops - 1] + k * span);
for (unsigned l = k; 1; l++)
{
for (unsigned i = 1; i < n_stops; i++)
{
float a0, a1;
color_t *c0, *c1;
if ((l % 2 != 0) && (extend == CAIRO_EXTEND_REFLECT))
{
a0 = angles[0] + angles[n_stops - 1] - angles[n_stops - 1 - (i-1)] + l * span;
a1 = angles[0] + angles[n_stops - 1] - angles[n_stops - 1 - i] + l * span;
c0 = &colors[n_stops - 1 - (i - 1)];
c1 = &colors[n_stops - 1 - i];
}
else
{
a0 = angles[i-1] + l * span;
a1 = angles[i] + l * span;
c0 = &colors[i-1];
c1 = &colors[i];
}
if (a1 < 0)
continue;
if (a0 < 0)
{
color_t color;
float f = (0 - a0)/(a1 - a0);
interpolate_colors (c0, c1, f, &color);
add_sweep_gradient_patches1 (cx, cy, radius,
0, &color,
a1, c1,
pattern);
}
else if (a1 >= 2 * M_PI)
{
color_t color;
float f = (2 * M_PI - a0)/(a1 - a0);
interpolate_colors (c0, c1, f, &color);
add_sweep_gradient_patches1 (cx, cy, radius,
a0, c0,
2 * M_PI, &color,
pattern);
goto done;
}
else
{
add_sweep_gradient_patches1 (cx, cy, radius,
a0, c0,
a1, c1,
pattern);
}
}
}
}
done:
if (angles != angles_)
free (angles);
if (colors != colors_)
free (colors);
}
void
hb_cairo_paint_sweep_gradient (cairo_t *cr,
hb_color_line_t *color_line,
float cx, float cy,
float start_angle,
float end_angle)
{
unsigned int len;
hb_color_stop_t stops_[PREALLOCATED_COLOR_STOPS];
hb_color_stop_t *stops = stops_;
cairo_extend_t extend;
double x1, y1, x2, y2;
float max_x, max_y, radius;
cairo_pattern_t *pattern;
len = hb_color_line_get_color_stops (color_line, 0, NULL, NULL);
if (len > PREALLOCATED_COLOR_STOPS)
stops = (hb_color_stop_t *) malloc (len * sizeof (hb_color_stop_t));
hb_color_line_get_color_stops (color_line, 0, &len, stops);
qsort (stops, len, sizeof (hb_color_stop_t), cmp_color_stop);
cairo_clip_extents (cr, &x1, &y1, &x2, &y2);
max_x = MAX ((x1 - cx) * (x1 - cx), (x2 - cx) * (x2 - cx));
max_y = MAX ((y1 - cy) * (y1 - cy), (y2 - cy) * (y2 - cy));
radius = sqrt (max_x + max_y);
extend = cairo_extend (hb_color_line_get_extend (color_line));
pattern = cairo_pattern_create_mesh ();
add_sweep_gradient_patches (stops, len, extend, cx, cy,
radius, start_angle, end_angle, pattern);
cairo_set_source (cr, pattern);
cairo_paint (cr);
cairo_pattern_destroy (pattern);
if (stops != stops_)
free (stops);
}

97
util/hb-cairo-utils.h Normal file
View File

@ -0,0 +1,97 @@
/*
* Copyright © 2022 Red Hat, Inc
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Matthias Clasen
*/
#pragma once
#include <hb.h>
#include <cairo.h>
HB_BEGIN_DECLS
static inline cairo_operator_t
hb_paint_composite_mode_to_cairo (hb_paint_composite_mode_t mode)
{
switch (mode)
{
case HB_PAINT_COMPOSITE_MODE_CLEAR: return CAIRO_OPERATOR_CLEAR;
case HB_PAINT_COMPOSITE_MODE_SRC: return CAIRO_OPERATOR_SOURCE;
case HB_PAINT_COMPOSITE_MODE_DEST: return CAIRO_OPERATOR_DEST;
case HB_PAINT_COMPOSITE_MODE_SRC_OVER: return CAIRO_OPERATOR_OVER;
case HB_PAINT_COMPOSITE_MODE_DEST_OVER: return CAIRO_OPERATOR_DEST_OVER;
case HB_PAINT_COMPOSITE_MODE_SRC_IN: return CAIRO_OPERATOR_IN;
case HB_PAINT_COMPOSITE_MODE_DEST_IN: return CAIRO_OPERATOR_DEST_IN;
case HB_PAINT_COMPOSITE_MODE_SRC_OUT: return CAIRO_OPERATOR_OUT;
case HB_PAINT_COMPOSITE_MODE_DEST_OUT: return CAIRO_OPERATOR_DEST_OUT;
case HB_PAINT_COMPOSITE_MODE_SRC_ATOP: return CAIRO_OPERATOR_ATOP;
case HB_PAINT_COMPOSITE_MODE_DEST_ATOP: return CAIRO_OPERATOR_DEST_ATOP;
case HB_PAINT_COMPOSITE_MODE_XOR: return CAIRO_OPERATOR_XOR;
case HB_PAINT_COMPOSITE_MODE_PLUS: return CAIRO_OPERATOR_ADD;
case HB_PAINT_COMPOSITE_MODE_SCREEN: return CAIRO_OPERATOR_SCREEN;
case HB_PAINT_COMPOSITE_MODE_OVERLAY: return CAIRO_OPERATOR_OVERLAY;
case HB_PAINT_COMPOSITE_MODE_DARKEN: return CAIRO_OPERATOR_DARKEN;
case HB_PAINT_COMPOSITE_MODE_LIGHTEN: return CAIRO_OPERATOR_LIGHTEN;
case HB_PAINT_COMPOSITE_MODE_COLOR_DODGE: return CAIRO_OPERATOR_COLOR_DODGE;
case HB_PAINT_COMPOSITE_MODE_COLOR_BURN: return CAIRO_OPERATOR_COLOR_BURN;
case HB_PAINT_COMPOSITE_MODE_HARD_LIGHT: return CAIRO_OPERATOR_HARD_LIGHT;
case HB_PAINT_COMPOSITE_MODE_SOFT_LIGHT: return CAIRO_OPERATOR_SOFT_LIGHT;
case HB_PAINT_COMPOSITE_MODE_DIFFERENCE: return CAIRO_OPERATOR_DIFFERENCE;
case HB_PAINT_COMPOSITE_MODE_EXCLUSION: return CAIRO_OPERATOR_EXCLUSION;
case HB_PAINT_COMPOSITE_MODE_MULTIPLY: return CAIRO_OPERATOR_MULTIPLY;
case HB_PAINT_COMPOSITE_MODE_HSL_HUE: return CAIRO_OPERATOR_HSL_HUE;
case HB_PAINT_COMPOSITE_MODE_HSL_SATURATION: return CAIRO_OPERATOR_HSL_SATURATION;
case HB_PAINT_COMPOSITE_MODE_HSL_COLOR: return CAIRO_OPERATOR_HSL_COLOR;
case HB_PAINT_COMPOSITE_MODE_HSL_LUMINOSITY: return CAIRO_OPERATOR_HSL_LUMINOSITY;
default:;
}
return CAIRO_OPERATOR_SOURCE;
}
void hb_cairo_paint_glyph_image (cairo_t *cr,
hb_blob_t *blob,
unsigned width,
unsigned height,
hb_tag_t format,
float slant,
hb_glyph_extents_t *extents);
void hb_cairo_paint_linear_gradient (cairo_t *cr,
hb_color_line_t *color_line,
float x0, float y0,
float x1, float y1,
float x2, float y2);
void hb_cairo_paint_radial_gradient (cairo_t *cr,
hb_color_line_t *color_line,
float x0, float y0, float r0,
float x1, float y1, float r1);
void hb_cairo_paint_sweep_gradient (cairo_t *cr,
hb_color_line_t *color_line,
float x0, float y0,
float start_angle, float end_angle);
HB_END_DECLS

View File

@ -27,12 +27,40 @@
#ifndef HELPER_CAIRO_USER_HH
#define HELPER_CAIRO_USER_HH
#include "config.h"
#include "font-options.hh"
#include <cairo.h>
#include <hb.h>
#include "hb-blob.hh"
#include "hb-cairo-utils.h"
static bool debug = false;
static int level = 0;
static void print (const char *format, ...) __attribute__((format (printf, 1, 2)));
static void
print (const char *format,
...)
{
va_list args;
if (!debug)
return;
printf ("%*s", 2 * level, "");
va_start (args, format);
vprintf (format, args);
va_end (args);
printf ("\n");
}
static const cairo_user_data_key_t _hb_font_cairo_user_data_key = {0};
static void
move_to (hb_draw_funcs_t *dfuncs,
@ -41,6 +69,8 @@ move_to (hb_draw_funcs_t *dfuncs,
float to_x, float to_y,
void *)
{
print ("move to %f %f",
(double) to_x, (double) to_y);
cairo_move_to (cr,
(double) to_x, (double) to_y);
}
@ -52,6 +82,8 @@ line_to (hb_draw_funcs_t *dfuncs,
float to_x, float to_y,
void *)
{
print ("line to %f %f",
(double) to_x, (double) to_y);
cairo_line_to (cr,
(double) to_x, (double) to_y);
}
@ -65,6 +97,10 @@ cubic_to (hb_draw_funcs_t *dfuncs,
float to_x, float to_y,
void *)
{
print ("cubic to %f %f %f %f %f %f",
(double) control1_x, (double) control1_y,
(double) control2_x, (double) control2_y,
(double) to_x, (double) to_y);
cairo_curve_to (cr,
(double) control1_x, (double) control1_y,
(double) control2_x, (double) control2_y,
@ -77,12 +113,13 @@ close_path (hb_draw_funcs_t *dfuncs,
hb_draw_state_t *st,
void *)
{
print ("close path");
cairo_close_path (cr);
}
static hb_draw_funcs_t *
get_cairo_draw_funcs ()
get_cairo_draw_funcs (void)
{
static hb_draw_funcs_t *funcs;
@ -98,7 +135,299 @@ get_cairo_draw_funcs ()
return funcs;
}
static const cairo_user_data_key_t _hb_font_cairo_user_data_key = {0};
#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC
static void
push_transform (hb_paint_funcs_t *funcs,
void *paint_data,
float xx, float yx,
float xy, float yy,
float dx, float dy,
void *user_data)
{
cairo_t *cr = (cairo_t *)paint_data;
cairo_matrix_t m;
print ("start transform %f %f %f %f %f %f",
(double) xx, (double) yx,
(double) xy, (double) yy,
(double) dx, (double) dy);
level++;
cairo_save (cr);
cairo_matrix_init (&m, (double) xx, (double) yx,
(double) xy, (double) yy,
(double) dx, (double) dy);
cairo_transform (cr, &m);
}
static void
pop_transform (hb_paint_funcs_t *funcs,
void *paint_data,
void *user_data)
{
cairo_t *cr = (cairo_t *)paint_data;
cairo_restore (cr);
level--;
print ("end transform");
}
static void
push_clip_glyph (hb_paint_funcs_t *funcs,
void *paint_data,
hb_codepoint_t glyph,
hb_font_t *font,
void *user_data)
{
cairo_t *cr = (cairo_t *)paint_data;
print ("start clip glyph %u", glyph);
level++;
cairo_save (cr);
cairo_new_path (cr);
hb_font_draw_glyph (font, glyph, get_cairo_draw_funcs (), cr);
cairo_close_path (cr);
cairo_clip (cr);
}
static void
push_clip_rectangle (hb_paint_funcs_t *funcs,
void *paint_data,
float xmin, float ymin, float xmax, float ymax,
void *user_data)
{
cairo_t *cr = (cairo_t *)paint_data;
print ("start clip rectangle %f %f %f %f",
(double) xmin, (double) ymin,
(double) xmax, (double) ymax);
level++;
cairo_save (cr);
cairo_rectangle (cr,
(double) xmin, (double) ymin,
(double) (xmax - xmin), (double) (ymax - ymin));
cairo_clip (cr);
}
static void
pop_clip (hb_paint_funcs_t *funcs,
void *paint_data,
void *user_data)
{
cairo_t *cr = (cairo_t *)paint_data;
cairo_restore (cr);
level--;
print ("end clip");
}
static void
push_group (hb_paint_funcs_t *funcs,
void *paint_data,
void *user_data)
{
cairo_t *cr = (cairo_t *)paint_data;
print ("push group");
level++;
cairo_save (cr);
cairo_push_group (cr);
}
static void
pop_group (hb_paint_funcs_t *funcs,
void *paint_data,
hb_paint_composite_mode_t mode,
void *user_data)
{
cairo_t *cr = (cairo_t *)paint_data;
cairo_pop_group_to_source (cr);
cairo_set_operator (cr, hb_paint_composite_mode_to_cairo (mode));
cairo_paint (cr);
cairo_restore (cr);
level--;
print ("pop group mode %d", mode);
}
static void
paint_color (hb_paint_funcs_t *funcs,
void *paint_data,
hb_bool_t use_foreground,
hb_color_t color,
void *user_data)
{
cairo_t *cr = (cairo_t *)paint_data;
print ("solid (fg %d) %d %d %d %d",
use_foreground,
hb_color_get_red (color),
hb_color_get_green (color),
hb_color_get_blue (color),
hb_color_get_alpha (color));
cairo_set_source_rgba (cr,
hb_color_get_red (color) / 255.,
hb_color_get_green (color) / 255.,
hb_color_get_blue (color) / 255.,
hb_color_get_alpha (color) / 255.);
cairo_paint (cr);
}
static void
paint_image (hb_paint_funcs_t *funcs,
void *paint_data,
hb_blob_t *blob,
unsigned width,
unsigned height,
hb_tag_t format,
float slant,
hb_glyph_extents_t *extents,
void *user_data)
{
cairo_t *cr = (cairo_t *)paint_data;
char buf[5] = { 0, };
hb_tag_to_string (format, buf);
print ("image type '%s' size %u %u slant %f extents %d %d %d %d",
buf, width, height, (double) slant,
extents->x_bearing, extents->y_bearing, extents->width, extents->height);
hb_cairo_paint_glyph_image (cr, blob, width, height, format, slant, extents);
}
static void
print_color_line (hb_color_line_t *color_line)
{
hb_color_stop_t *stops;
unsigned int len;
len = hb_color_line_get_color_stops (color_line, 0, NULL, NULL);
stops = (hb_color_stop_t *)alloca (len * sizeof (hb_color_stop_t));
hb_color_line_get_color_stops (color_line, 0, &len, stops);
print ("colors extend %d", hb_color_line_get_extend (color_line));
level += 1;
for (unsigned int i = 0; i < len; i++)
print ("%f (fg %d) %d %d %d %d",
(double) stops[i].offset,
stops[i].is_foreground,
hb_color_get_red (stops[i].color),
hb_color_get_green (stops[i].color),
hb_color_get_blue (stops[i].color),
hb_color_get_alpha (stops[i].color));
level -= 1;
}
static void
paint_linear_gradient (hb_paint_funcs_t *funcs,
void *paint_data,
hb_color_line_t *color_line,
float x0, float y0,
float x1, float y1,
float x2, float y2,
void *user_data)
{
cairo_t *cr = (cairo_t *)paint_data;
print ("linear gradient");
level += 1;
print ("p0 %f %f", (double) x0, (double) y0);
print ("p1 %f %f", (double) x1, (double) y1);
print ("p2 %f %f", (double) x2, (double) y2);
print_color_line (color_line);
level -= 1;
hb_cairo_paint_linear_gradient (cr, color_line, x0, y0, x1, y1, x2, y2);
}
static void
paint_radial_gradient (hb_paint_funcs_t *funcs,
void *paint_data,
hb_color_line_t *color_line,
float x0, float y0, float r0,
float x1, float y1, float r1,
void *user_data)
{
cairo_t *cr = (cairo_t *)paint_data;
print ("radial gradient");
level += 1;
print ("p0 %f %f radius %f", (double) x0, (double) y0, (double) r0);
print ("p1 %f %f radius %f", (double) x1, (double) y1, (double) r1);
print_color_line (color_line);
level -= 1;
hb_cairo_paint_radial_gradient (cr, color_line, x0, y0, r0, x1, y1, r1);
}
static void
paint_sweep_gradient (hb_paint_funcs_t *funcs,
void *paint_data,
hb_color_line_t *color_line,
float x0, float y0,
float start_angle, float end_angle,
void *user_data)
{
cairo_t *cr = (cairo_t *)paint_data;
print ("sweep gradient");
level++;
print ("center %f %f", (double) x0, (double) y0);
print ("angles %f %f", (double) start_angle, (double) end_angle);
print_color_line (color_line);
level--;
hb_cairo_paint_sweep_gradient (cr, color_line, x0, y0, start_angle, end_angle);
}
static hb_paint_funcs_t *
get_cairo_paint_funcs ()
{
static hb_paint_funcs_t *funcs;
if (!funcs)
{
funcs = hb_paint_funcs_create ();
hb_paint_funcs_set_push_transform_func (funcs, push_transform, nullptr, nullptr);
hb_paint_funcs_set_pop_transform_func (funcs, pop_transform, nullptr, nullptr);
hb_paint_funcs_set_push_clip_glyph_func (funcs, push_clip_glyph, nullptr, nullptr);
hb_paint_funcs_set_push_clip_rectangle_func (funcs, push_clip_rectangle, nullptr, nullptr);
hb_paint_funcs_set_pop_clip_func (funcs, pop_clip, nullptr, nullptr);
hb_paint_funcs_set_push_group_func (funcs, push_group, nullptr, nullptr);
hb_paint_funcs_set_pop_group_func (funcs, pop_group, nullptr, nullptr);
hb_paint_funcs_set_color_func (funcs, paint_color, nullptr, nullptr);
hb_paint_funcs_set_image_func (funcs, paint_image, nullptr, nullptr);
hb_paint_funcs_set_linear_gradient_func (funcs, paint_linear_gradient, nullptr, nullptr);
hb_paint_funcs_set_radial_gradient_func (funcs, paint_radial_gradient, nullptr, nullptr);
hb_paint_funcs_set_sweep_gradient_func (funcs, paint_sweep_gradient, nullptr, nullptr);
}
return funcs;
}
#endif
#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC
static cairo_status_t
render_color_glyph (cairo_scaled_font_t *scaled_font,
unsigned long glyph,
cairo_t *cr,
cairo_text_extents_t *extents);
#endif
static cairo_status_t
render_glyph (cairo_scaled_font_t *scaled_font,
@ -106,6 +435,12 @@ render_glyph (cairo_scaled_font_t *scaled_font,
cairo_t *cr,
cairo_text_extents_t *extents)
{
#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC
static char *p = getenv ("HB_DRAW");
if (p && atoi (p) >= 2)
return render_color_glyph (scaled_font, glyph, cr, extents);
#endif
hb_font_t *font = (hb_font_t *) (cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
&_hb_font_cairo_user_data_key));
@ -113,7 +448,7 @@ render_glyph (cairo_scaled_font_t *scaled_font,
hb_font_get_scale (font, &x_scale, &y_scale);
cairo_scale (cr, +1./x_scale, -1./y_scale);
hb_font_get_glyph_shape (font, glyph, get_cairo_draw_funcs (), cr);
hb_font_draw_glyph (font, glyph, get_cairo_draw_funcs (), cr);
cairo_fill (cr);
return CAIRO_STATUS_SUCCESS;
@ -121,158 +456,45 @@ render_glyph (cairo_scaled_font_t *scaled_font,
#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC
#ifdef CAIRO_HAS_PNG_FUNCTIONS
static inline cairo_status_t
_hb_bytes_read_func (hb_bytes_t *src,
char *data,
unsigned length)
{
if (unlikely (src->length < length))
return CAIRO_STATUS_READ_ERROR;
memcpy (data, src->arrayZ, length);
*src += length;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
render_color_glyph_png (cairo_scaled_font_t *scaled_font,
unsigned long glyph,
cairo_t *cr,
cairo_text_extents_t *extents)
{
hb_font_t *font = (hb_font_t *) (cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
&_hb_font_cairo_user_data_key));
hb_blob_t *blob = hb_ot_color_glyph_reference_png (font, glyph);
if (blob == hb_blob_get_empty ())
return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
hb_position_t x_scale, y_scale;
hb_font_get_scale (font, &x_scale, &y_scale);
cairo_scale (cr, +1./x_scale, -1./y_scale);
/* Draw PNG. */
hb_bytes_t bytes = blob->as_bytes ();
cairo_surface_t *surface = cairo_image_surface_create_from_png_stream ((cairo_read_func_t) _hb_bytes_read_func,
std::addressof (bytes));
hb_blob_destroy (blob);
if (unlikely (cairo_surface_status (surface)) != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (surface);
return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
}
int width = cairo_image_surface_get_width (surface);
int height = cairo_image_surface_get_width (surface);
hb_glyph_extents_t hb_extents;
if (unlikely (!hb_font_get_glyph_extents (font, glyph, &hb_extents)))
{
cairo_surface_destroy (surface);
return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
}
cairo_pattern_t *pattern = cairo_pattern_create_for_surface (surface);
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
cairo_matrix_t matrix = {(double) width, 0, 0, (double) height, 0, 0};
cairo_pattern_set_matrix (pattern, &matrix);
cairo_translate (cr, hb_extents.x_bearing, hb_extents.y_bearing);
cairo_scale (cr, hb_extents.width, hb_extents.height);
cairo_set_source (cr, pattern);
cairo_rectangle (cr, 0, 0, 1, 1);
cairo_fill (cr);
cairo_pattern_destroy (pattern);
cairo_surface_destroy (surface);
return CAIRO_STATUS_SUCCESS;
}
#endif
static cairo_status_t
render_color_glyph_layers (cairo_scaled_font_t *scaled_font,
unsigned long glyph,
cairo_t *cr,
cairo_text_extents_t *extents)
{
hb_font_t *font = (hb_font_t *) (cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
&_hb_font_cairo_user_data_key));
hb_face_t *face = hb_font_get_face (font);
unsigned count = hb_ot_color_glyph_get_layers (face, glyph, 0, nullptr, nullptr);
if (!count)
return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
hb_ot_color_layer_t layers[16];
unsigned offset = 0, len;
do {
len = ARRAY_LENGTH (layers);
hb_ot_color_glyph_get_layers (face, glyph,
offset,
&len,
layers);
for (unsigned i = 0; i < len; i++)
{
hb_color_t color;
unsigned clen = 1;
unsigned color_index = layers[i].color_index;
bool is_foreground = color_index == 65535;
if (!is_foreground)
{
hb_ot_color_palette_get_colors (face,
0/*palette_index*/,
color_index/*start_offset*/,
&clen/*color_count*/,
&color);
if (clen < 1)
continue;
}
cairo_save (cr);
{
if (!is_foreground)
cairo_set_source_rgba (cr,
hb_color_get_red (color) / 255.,
hb_color_get_green (color) / 255.,
hb_color_get_blue (color) / 255.,
hb_color_get_alpha (color) / 255.);
cairo_status_t ret = render_glyph (scaled_font, layers[i].glyph, cr, extents);
if (ret != CAIRO_STATUS_SUCCESS)
return ret;
}
cairo_restore (cr);
}
}
while (len == ARRAY_LENGTH (layers));
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
render_color_glyph (cairo_scaled_font_t *scaled_font,
unsigned long glyph,
cairo_t *cr,
cairo_text_extents_t *extents)
{
cairo_status_t ret = CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
#ifdef CAIRO_HAS_PNG_FUNCTIONS
ret = render_color_glyph_png (scaled_font, glyph, cr, extents);
if (ret != CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED)
return ret;
hb_font_t *font = (hb_font_t *) (cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
&_hb_font_cairo_user_data_key));
unsigned int palette = 0;
#ifdef CAIRO_COLOR_PALETTE_DEFAULT
cairo_font_options_t *options = cairo_font_options_create ();
cairo_scaled_font_get_font_options (scaled_font, options);
palette = cairo_font_options_get_color_palette (options);
cairo_font_options_destroy (options);
#endif
ret = render_color_glyph_layers (scaled_font, glyph, cr, extents);
if (ret != CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED)
return ret;
hb_color_t color = HB_COLOR (0, 0, 0, 255);
cairo_pattern_t *pattern = cairo_get_source (cr);
return render_glyph (scaled_font, glyph, cr, extents);
if (cairo_pattern_get_type (pattern) == CAIRO_PATTERN_TYPE_SOLID)
{
double r, g, b, a;
cairo_pattern_get_rgba (pattern, &r, &g, &b, &a);
color = HB_COLOR ((int)(b * 255.), (int)(g * 255.), (int) (r * 255.), (int)(a * 255.));
}
hb_position_t x_scale, y_scale;
hb_font_get_scale (font, &x_scale, &y_scale);
cairo_scale (cr, +1./x_scale, -1./y_scale);
if (getenv ("HB_PAINT_DEBUG"))
{
debug = atoi (getenv ("HB_PAINT_DEBUG"));
level = 0;
}
hb_font_paint_glyph (font, glyph, get_cairo_paint_funcs (), cr, palette, color);
return CAIRO_STATUS_SUCCESS;
}
#endif
@ -288,10 +510,13 @@ helper_cairo_create_user_font_face (const font_options_t *font_opts)
(cairo_destroy_func_t) hb_font_destroy);
cairo_user_font_face_set_render_glyph_func (cairo_face, render_glyph);
#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC
hb_face_t *face = hb_font_get_face (font_opts->font);
if (hb_ot_color_has_png (face) || hb_ot_color_has_layers (face))
if (hb_ot_color_has_png (face) || hb_ot_color_has_layers (face) || hb_ot_color_has_paint (face))
{
cairo_user_font_face_set_render_color_glyph_func (cairo_face, render_color_glyph);
}
#endif
return cairo_face;
@ -310,7 +535,7 @@ helper_cairo_user_scaled_font_has_color (cairo_scaled_font_t *scaled_font)
hb_font_t *font = (hb_font_t *) (cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
&_hb_font_cairo_user_data_key));
hb_face_t *face = hb_font_get_face (font);
return hb_ot_color_has_png (face) || hb_ot_color_has_layers (face);
return hb_ot_color_has_png (face) || hb_ot_color_has_layers (face) || hb_ot_color_has_paint (face);
}
#endif

View File

@ -118,6 +118,9 @@ helper_cairo_create_scaled_font (const font_options_t *font_opts)
font_options = cairo_font_options_create ();
cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_OFF);
#ifdef CAIRO_COLOR_PALETTE_DEFAULT
cairo_font_options_set_color_palette (font_options, font_opts->palette);
#endif
cairo_scaled_font_t *scaled_font = cairo_scaled_font_create (cairo_face,
&font_matrix,

View File

@ -1,5 +1,6 @@
hb_view_sources = [
'hb-view.cc',
'hb-cairo-utils.c'
]
hb_shape_sources = [