Merge pull request #3938 from harfbuzz/wip/matthiasc/paint-api
hb-paint API
This commit is contained in:
commit
f9081fc358
|
@ -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"/>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
141
src/hb-font.cc
141
src/hb-font.cc
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "hb-font.hh"
|
||||
#include "hb-draw.hh"
|
||||
#include "hb-paint.hh"
|
||||
#include "hb-machinery.hh"
|
||||
|
||||
#include "hb-ot.h"
|
||||
|
@ -503,7 +504,7 @@ 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,
|
||||
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,
|
||||
|
@ -512,14 +513,25 @@ hb_font_get_glyph_shape_nil (hb_font_t *font 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)
|
||||
{
|
||||
font->get_glyph_shape (glyph, dfuncs, 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->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);
|
||||
}
|
||||
|
|
120
src/hb-font.h
120
src/hb-font.h
|
@ -34,18 +34,10 @@
|
|||
#include "hb-common.h"
|
||||
#include "hb-face.h"
|
||||
#include "hb-draw.h"
|
||||
#include "hb-paint.h"
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* hb_font_t:
|
||||
*
|
||||
* Data type for holding fonts.
|
||||
*
|
||||
*/
|
||||
typedef struct hb_font_t hb_font_t;
|
||||
|
||||
|
||||
/*
|
||||
* hb_font_funcs_t
|
||||
*/
|
||||
|
@ -97,7 +89,7 @@ HB_EXTERN hb_bool_t
|
|||
hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs);
|
||||
|
||||
|
||||
/* font and glyph extents */
|
||||
/* font extents */
|
||||
|
||||
/**
|
||||
* hb_font_extents_t:
|
||||
|
@ -126,24 +118,6 @@ typedef struct hb_font_extents_t {
|
|||
hb_position_t reserved1;
|
||||
} hb_font_extents_t;
|
||||
|
||||
/**
|
||||
* hb_glyph_extents_t:
|
||||
* @x_bearing: Distance from the x-origin to the left extremum of the glyph.
|
||||
* @y_bearing: Distance from the top extremum of the glyph to the y-origin.
|
||||
* @width: Distance from the left extremum of the glyph to the right extremum.
|
||||
* @height: Distance from the top extremum of the glyph to the bottom extremum.
|
||||
*
|
||||
* Glyph extent values, measured in font units.
|
||||
*
|
||||
* Note that @height is negative, in coordinate systems that grow up.
|
||||
**/
|
||||
typedef struct hb_glyph_extents_t {
|
||||
hb_position_t x_bearing;
|
||||
hb_position_t y_bearing;
|
||||
hb_position_t width;
|
||||
hb_position_t height;
|
||||
} hb_glyph_extents_t;
|
||||
|
||||
/* func types */
|
||||
|
||||
/**
|
||||
|
@ -524,12 +498,53 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *
|
|||
*
|
||||
* Since: 4.0.0
|
||||
*
|
||||
* Deprecated: REPLACEME: Use #hb_font_draw_glyph_func_t instead
|
||||
**/
|
||||
typedef void (*hb_font_get_glyph_shape_func_t) (hb_font_t *font, void *font_data,
|
||||
hb_codepoint_t glyph,
|
||||
hb_draw_funcs_t *draw_funcs, void *draw_data,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* hb_font_draw_glyph_func_t:
|
||||
* @font: #hb_font_t to work upon
|
||||
* @font_data: @font user data pointer
|
||||
* @glyph: The glyph ID to query
|
||||
* @draw_funcs: The draw functions to send the shape data to
|
||||
* @draw_data: The data accompanying the draw functions
|
||||
* @user_data: User data pointer passed by the caller
|
||||
*
|
||||
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
|
||||
*
|
||||
* Since: REPLACEME
|
||||
*
|
||||
**/
|
||||
typedef void (*hb_font_draw_glyph_func_t) (hb_font_t *font, void *font_data,
|
||||
hb_codepoint_t glyph,
|
||||
hb_draw_funcs_t *draw_funcs, void *draw_data,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* hb_font_paint_glyph_func_t:
|
||||
* @font: #hb_font_t to work upon
|
||||
* @font_data: @font user data pointer
|
||||
* @glyph: The glyph ID to query
|
||||
* @paint_funcs: The paint functions to use
|
||||
* @paint_data: The data accompanying the paint functions
|
||||
* @palette: The color palette to use
|
||||
* @foreground: The foreground color
|
||||
* @user_data: User data pointer passed by the caller
|
||||
*
|
||||
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
|
||||
*
|
||||
* Since: REPLACEME
|
||||
*/
|
||||
typedef void (*hb_font_paint_glyph_func_t) (hb_font_t *font, void *font_data,
|
||||
hb_codepoint_t glyph,
|
||||
hb_paint_funcs_t *paint_funcs, void *paint_data,
|
||||
unsigned int palette,
|
||||
hb_color_t foreground,
|
||||
void *user_data);
|
||||
|
||||
/* func setters */
|
||||
|
||||
|
@ -796,15 +811,51 @@ hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs,
|
|||
* @user_data: Data to pass to @func
|
||||
* @destroy: (nullable): The function to call when @user_data is not needed anymore
|
||||
*
|
||||
* Sets the implementation function for #hb_font_get_glyph_shape_func_t.
|
||||
* Sets the implementation function for #hb_font_get_glyph_shape_func_t,
|
||||
* which is the same as #hb_font_draw_glyph_func_t.
|
||||
*
|
||||
* Since: 4.0.0
|
||||
*
|
||||
* Deprecated: REPLACEME: Use hb_font_set_draw_glyph_func() instead
|
||||
**/
|
||||
HB_EXTERN void
|
||||
hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs,
|
||||
hb_font_get_glyph_shape_func_t func,
|
||||
void *user_data, hb_destroy_func_t destroy);
|
||||
|
||||
/**
|
||||
* hb_font_funcs_set_draw_glyph_func:
|
||||
* @ffuncs: A font-function structure
|
||||
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
|
||||
* @user_data: Data to pass to @func
|
||||
* @destroy: (nullable): The function to call when @user_data is not needed anymore
|
||||
*
|
||||
* Sets the implementation function for #hb_font_draw_glyph_func_t,
|
||||
* which is the same as #hb_font_get_glyph_shape_func_t.
|
||||
*
|
||||
* Since: REPLACEME
|
||||
**/
|
||||
HB_EXTERN void
|
||||
hb_font_funcs_set_draw_glyph_func (hb_font_funcs_t *ffuncs,
|
||||
hb_font_draw_glyph_func_t func,
|
||||
void *user_data, hb_destroy_func_t destroy);
|
||||
|
||||
/**
|
||||
* hb_font_funcs_set_paint_glyph_func:
|
||||
* @ffuncs: A font-function structure
|
||||
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
|
||||
* @user_data: Data to pass to @func
|
||||
* @destroy: (nullable): The function to call when @user_data is no longer needed
|
||||
*
|
||||
* Sets the implementation function for #hb_font_paint_glyph_func_t.
|
||||
*
|
||||
* Since: REPLACEME
|
||||
*/
|
||||
HB_EXTERN void
|
||||
hb_font_funcs_set_paint_glyph_func (hb_font_funcs_t *ffuncs,
|
||||
hb_font_paint_glyph_func_t func,
|
||||
void *user_data, hb_destroy_func_t destroy);
|
||||
|
||||
/* func dispatch */
|
||||
|
||||
HB_EXTERN hb_bool_t
|
||||
|
@ -890,6 +941,17 @@ hb_font_get_glyph_shape (hb_font_t *font,
|
|||
hb_codepoint_t glyph,
|
||||
hb_draw_funcs_t *dfuncs, void *draw_data);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_font_draw_glyph (hb_font_t *font,
|
||||
hb_codepoint_t glyph,
|
||||
hb_draw_funcs_t *dfuncs, void *draw_data);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_font_paint_glyph (hb_font_t *font,
|
||||
hb_codepoint_t glyph,
|
||||
hb_paint_funcs_t *pfuncs, void *paint_data,
|
||||
unsigned int palette,
|
||||
hb_color_t foreground);
|
||||
|
||||
/* high-level funcs, with fallback */
|
||||
|
||||
|
|
|
@ -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,
|
||||
void draw_glyph (hb_codepoint_t glyph,
|
||||
hb_draw_funcs_t *draw_funcs, void *draw_data)
|
||||
{
|
||||
klass->get.f.glyph_shape (this, user_data,
|
||||
klass->get.f.draw_glyph (this, user_data,
|
||||
glyph,
|
||||
draw_funcs, draw_data,
|
||||
!klass->user_data ? nullptr : klass->user_data->glyph_shape);
|
||||
!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 */
|
||||
|
||||
|
|
|
@ -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 */
|
94
src/hb-ft.cc
94
src/hb-ft.cc
|
@ -33,17 +33,19 @@
|
|||
|
||||
#include "hb-ft.h"
|
||||
|
||||
#include "hb-cache.hh"
|
||||
#include "hb-draw.hh"
|
||||
#include "hb-font.hh"
|
||||
#include "hb-machinery.hh"
|
||||
#include "hb-cache.hh"
|
||||
#include "hb-ot-os2-table.hh"
|
||||
#include "hb-ot-shaper-arabic-pua.hh"
|
||||
#include "hb-paint.hh"
|
||||
|
||||
#include FT_ADVANCES_H
|
||||
#include FT_MULTIPLE_MASTERS_H
|
||||
#include FT_OUTLINE_H
|
||||
#include FT_TRUETYPE_TABLES_H
|
||||
#include FT_COLOR_H
|
||||
|
||||
|
||||
/**
|
||||
|
@ -777,7 +779,7 @@ _hb_ft_cubic_to (const FT_Vector *control1,
|
|||
}
|
||||
|
||||
static void
|
||||
hb_ft_get_glyph_shape (hb_font_t *font 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,
|
||||
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 ())
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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_)
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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,13 +81,14 @@ 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);
|
||||
|
||||
if (scale)
|
||||
font->scale_glyph_extents (extents);
|
||||
}
|
||||
|
||||
|
@ -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. */
|
||||
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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
|
@ -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,14 +352,8 @@ 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;
|
||||
}
|
||||
|
||||
if (scale)
|
||||
font->scale_glyph_extents (extents);
|
||||
|
||||
hb_blob_destroy (blob);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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,7 +425,7 @@ 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,
|
||||
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,
|
||||
|
@ -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);
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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 */
|
1
src/hb.h
1
src/hb.h
|
@ -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"
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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
|
@ -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',
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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"},
|
||||
|
|
|
@ -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, ¢er, &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);
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
hb_view_sources = [
|
||||
'hb-view.cc',
|
||||
'hb-cairo-utils.c'
|
||||
]
|
||||
|
||||
hb_shape_sources = [
|
||||
|
|
Loading…
Reference in New Issue