Path: blob/master/thirdparty/harfbuzz/src/hb-cairo.cc
9902 views
/*1* Copyright © 2022 Red Hat, Inc.2*3* This is part of HarfBuzz, a text shaping library.4*5* Permission is hereby granted, without written agreement and without6* license or royalty fees, to use, copy, modify, and distribute this7* software and its documentation for any purpose, provided that the8* above copyright notice and the following two paragraphs appear in9* all copies of this software.10*11* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR12* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES13* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN14* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH15* DAMAGE.16*17* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,18* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND19* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS20* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO21* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.22*23* Red Hat Author(s): Matthias Clasen24*/2526#include "hb.hh"2728#ifdef HAVE_CAIRO2930#include "hb-cairo.h"3132#include "hb-cairo-utils.hh"3334#include "hb-machinery.hh"35#include "hb-utf.hh"363738/**39* SECTION:hb-cairo40* @title: hb-cairo41* @short_description: Cairo integration42* @include: hb-cairo.h43*44* Functions for using HarfBuzz with the cairo library.45*46* HarfBuzz supports using cairo for rendering.47**/4849static void50hb_cairo_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED,51void *draw_data,52hb_draw_state_t *st HB_UNUSED,53float to_x, float to_y,54void *user_data HB_UNUSED)55{56cairo_t *cr = (cairo_t *) draw_data;5758cairo_move_to (cr, (double) to_x, (double) to_y);59}6061static void62hb_cairo_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED,63void *draw_data,64hb_draw_state_t *st HB_UNUSED,65float to_x, float to_y,66void *user_data HB_UNUSED)67{68cairo_t *cr = (cairo_t *) draw_data;6970cairo_line_to (cr, (double) to_x, (double) to_y);71}7273static void74hb_cairo_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,75void *draw_data,76hb_draw_state_t *st HB_UNUSED,77float control1_x, float control1_y,78float control2_x, float control2_y,79float to_x, float to_y,80void *user_data HB_UNUSED)81{82cairo_t *cr = (cairo_t *) draw_data;8384cairo_curve_to (cr,85(double) control1_x, (double) control1_y,86(double) control2_x, (double) control2_y,87(double) to_x, (double) to_y);88}8990static void91hb_cairo_close_path (hb_draw_funcs_t *dfuncs HB_UNUSED,92void *draw_data,93hb_draw_state_t *st HB_UNUSED,94void *user_data HB_UNUSED)95{96cairo_t *cr = (cairo_t *) draw_data;9798cairo_close_path (cr);99}100101static inline void free_static_cairo_draw_funcs ();102103static struct hb_cairo_draw_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t<hb_cairo_draw_funcs_lazy_loader_t>104{105static hb_draw_funcs_t *create ()106{107hb_draw_funcs_t *funcs = hb_draw_funcs_create ();108109hb_draw_funcs_set_move_to_func (funcs, hb_cairo_move_to, nullptr, nullptr);110hb_draw_funcs_set_line_to_func (funcs, hb_cairo_line_to, nullptr, nullptr);111hb_draw_funcs_set_cubic_to_func (funcs, hb_cairo_cubic_to, nullptr, nullptr);112hb_draw_funcs_set_close_path_func (funcs, hb_cairo_close_path, nullptr, nullptr);113114hb_draw_funcs_make_immutable (funcs);115116hb_atexit (free_static_cairo_draw_funcs);117118return funcs;119}120} static_cairo_draw_funcs;121122static inline123void free_static_cairo_draw_funcs ()124{125static_cairo_draw_funcs.free_instance ();126}127128static hb_draw_funcs_t *129hb_cairo_draw_get_funcs ()130{131return static_cairo_draw_funcs.get_unconst ();132}133134135#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC136137static void138hb_cairo_push_transform (hb_paint_funcs_t *pfuncs HB_UNUSED,139void *paint_data,140float xx, float yx,141float xy, float yy,142float dx, float dy,143void *user_data HB_UNUSED)144{145hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;146cairo_t *cr = c->cr;147148cairo_matrix_t m;149150cairo_save (cr);151cairo_matrix_init (&m, (double) xx, (double) yx,152(double) xy, (double) yy,153(double) dx, (double) dy);154cairo_transform (cr, &m);155}156157static void158hb_cairo_pop_transform (hb_paint_funcs_t *pfuncs HB_UNUSED,159void *paint_data,160void *user_data HB_UNUSED)161{162hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;163cairo_t *cr = c->cr;164165cairo_restore (cr);166}167168static hb_bool_t169hb_cairo_paint_color_glyph (hb_paint_funcs_t *pfuncs HB_UNUSED,170void *paint_data,171hb_codepoint_t glyph,172hb_font_t *font,173void *user_data HB_UNUSED)174{175hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;176cairo_t *cr = c->cr;177178cairo_save (cr);179180hb_position_t x_scale, y_scale;181hb_font_get_scale (font, &x_scale, &y_scale);182cairo_scale (cr, x_scale, -y_scale);183184cairo_glyph_t cairo_glyph = { glyph, 0, 0 };185cairo_set_scaled_font (cr, c->scaled_font);186cairo_set_font_size (cr, 1);187cairo_show_glyphs (cr, &cairo_glyph, 1);188189cairo_restore (cr);190191return true;192}193194static void195hb_cairo_push_clip_glyph (hb_paint_funcs_t *pfuncs HB_UNUSED,196void *paint_data,197hb_codepoint_t glyph,198hb_font_t *font,199void *user_data HB_UNUSED)200{201hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;202cairo_t *cr = c->cr;203204cairo_save (cr);205cairo_new_path (cr);206207hb_font_draw_glyph (font, glyph, hb_cairo_draw_get_funcs (), cr);208209cairo_close_path (cr);210cairo_clip (cr);211}212213static void214hb_cairo_push_clip_rectangle (hb_paint_funcs_t *pfuncs HB_UNUSED,215void *paint_data,216float xmin, float ymin, float xmax, float ymax,217void *user_data HB_UNUSED)218{219hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;220cairo_t *cr = c->cr;221222cairo_save (cr);223cairo_rectangle (cr,224(double) xmin, (double) ymin,225(double) (xmax - xmin), (double) (ymax - ymin));226cairo_clip (cr);227}228229static void230hb_cairo_pop_clip (hb_paint_funcs_t *pfuncs HB_UNUSED,231void *paint_data,232void *user_data HB_UNUSED)233{234hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;235cairo_t *cr = c->cr;236237cairo_restore (cr);238}239240static void241hb_cairo_push_group (hb_paint_funcs_t *pfuncs HB_UNUSED,242void *paint_data,243void *user_data HB_UNUSED)244{245hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;246cairo_t *cr = c->cr;247248cairo_save (cr);249cairo_push_group (cr);250}251252static void253hb_cairo_pop_group (hb_paint_funcs_t *pfuncs HB_UNUSED,254void *paint_data,255hb_paint_composite_mode_t mode,256void *user_data HB_UNUSED)257{258hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;259cairo_t *cr = c->cr;260261cairo_pop_group_to_source (cr);262cairo_set_operator (cr, _hb_paint_composite_mode_to_cairo (mode));263cairo_paint (cr);264265cairo_restore (cr);266}267268static void269hb_cairo_paint_color (hb_paint_funcs_t *pfuncs HB_UNUSED,270void *paint_data,271hb_bool_t use_foreground,272hb_color_t color,273void *user_data HB_UNUSED)274{275hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;276cairo_t *cr = c->cr;277278if (use_foreground)279{280#ifdef HAVE_CAIRO_USER_SCALED_FONT_GET_FOREGROUND_SOURCE281double r, g, b, a;282cairo_pattern_t *foreground = cairo_user_scaled_font_get_foreground_source (c->scaled_font);283if (cairo_pattern_get_rgba (foreground, &r, &g, &b, &a) == CAIRO_STATUS_SUCCESS)284cairo_set_source_rgba (cr, r, g, b, a * hb_color_get_alpha (color) / 255.);285else286#endif287cairo_set_source_rgba (cr, 0, 0, 0, hb_color_get_alpha (color) / 255.);288}289else290cairo_set_source_rgba (cr,291hb_color_get_red (color) / 255.,292hb_color_get_green (color) / 255.,293hb_color_get_blue (color) / 255.,294hb_color_get_alpha (color) / 255.);295cairo_paint (cr);296}297298static hb_bool_t299hb_cairo_paint_image (hb_paint_funcs_t *pfuncs HB_UNUSED,300void *paint_data,301hb_blob_t *blob,302unsigned width,303unsigned height,304hb_tag_t format,305float slant,306hb_glyph_extents_t *extents,307void *user_data HB_UNUSED)308{309hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;310311return _hb_cairo_paint_glyph_image (c, blob, width, height, format, slant, extents);312}313314static void315hb_cairo_paint_linear_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED,316void *paint_data,317hb_color_line_t *color_line,318float x0, float y0,319float x1, float y1,320float x2, float y2,321void *user_data HB_UNUSED)322{323hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;324325_hb_cairo_paint_linear_gradient (c, color_line, x0, y0, x1, y1, x2, y2);326}327328static void329hb_cairo_paint_radial_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED,330void *paint_data,331hb_color_line_t *color_line,332float x0, float y0, float r0,333float x1, float y1, float r1,334void *user_data HB_UNUSED)335{336hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;337338_hb_cairo_paint_radial_gradient (c, color_line, x0, y0, r0, x1, y1, r1);339}340341static void342hb_cairo_paint_sweep_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED,343void *paint_data,344hb_color_line_t *color_line,345float x0, float y0,346float start_angle, float end_angle,347void *user_data HB_UNUSED)348{349hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;350351_hb_cairo_paint_sweep_gradient (c, color_line, x0, y0, start_angle, end_angle);352}353354static const cairo_user_data_key_t color_cache_key = {0};355356static void357_hb_cairo_destroy_map (void *p)358{359hb_map_destroy ((hb_map_t *) p);360}361362static hb_bool_t363hb_cairo_paint_custom_palette_color (hb_paint_funcs_t *funcs,364void *paint_data,365unsigned int color_index,366hb_color_t *color,367void *user_data HB_UNUSED)368{369#ifdef HAVE_CAIRO_FONT_OPTIONS_GET_CUSTOM_PALETTE_COLOR370hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;371cairo_t *cr = c->cr;372373#define HB_DEADBEEF HB_TAG(0xDE,0xAD,0xBE,0xEF)374375hb_map_t *color_cache = c->color_cache;376hb_codepoint_t *v;377if (likely (color_cache && color_cache->has (color_index, &v)))378{379if (*v == HB_DEADBEEF)380return false;381*color = *v;382return true;383}384385cairo_font_options_t *options;386double red, green, blue, alpha;387388options = cairo_font_options_create ();389cairo_get_font_options (cr, options);390if (CAIRO_STATUS_SUCCESS ==391cairo_font_options_get_custom_palette_color (options, color_index,392&red, &green, &blue, &alpha))393{394cairo_font_options_destroy (options);395*color = HB_COLOR (round (255 * blue),396round (255 * green),397round (255 * red),398round (255 * alpha));399400if (likely (color_cache && *color != HB_DEADBEEF))401color_cache->set (color_index, *color);402403return true;404}405cairo_font_options_destroy (options);406407if (likely (color_cache))408color_cache->set (color_index, HB_DEADBEEF);409410#undef HB_DEADBEEF411412#endif413414return false;415}416417static inline void free_static_cairo_paint_funcs ();418419static struct hb_cairo_paint_funcs_lazy_loader_t : hb_paint_funcs_lazy_loader_t<hb_cairo_paint_funcs_lazy_loader_t>420{421static hb_paint_funcs_t *create ()422{423hb_paint_funcs_t *funcs = hb_paint_funcs_create ();424425hb_paint_funcs_set_push_transform_func (funcs, hb_cairo_push_transform, nullptr, nullptr);426hb_paint_funcs_set_pop_transform_func (funcs, hb_cairo_pop_transform, nullptr, nullptr);427hb_paint_funcs_set_color_glyph_func (funcs, hb_cairo_paint_color_glyph, nullptr, nullptr);428hb_paint_funcs_set_push_clip_glyph_func (funcs, hb_cairo_push_clip_glyph, nullptr, nullptr);429hb_paint_funcs_set_push_clip_rectangle_func (funcs, hb_cairo_push_clip_rectangle, nullptr, nullptr);430hb_paint_funcs_set_pop_clip_func (funcs, hb_cairo_pop_clip, nullptr, nullptr);431hb_paint_funcs_set_push_group_func (funcs, hb_cairo_push_group, nullptr, nullptr);432hb_paint_funcs_set_pop_group_func (funcs, hb_cairo_pop_group, nullptr, nullptr);433hb_paint_funcs_set_color_func (funcs, hb_cairo_paint_color, nullptr, nullptr);434hb_paint_funcs_set_image_func (funcs, hb_cairo_paint_image, nullptr, nullptr);435hb_paint_funcs_set_linear_gradient_func (funcs, hb_cairo_paint_linear_gradient, nullptr, nullptr);436hb_paint_funcs_set_radial_gradient_func (funcs, hb_cairo_paint_radial_gradient, nullptr, nullptr);437hb_paint_funcs_set_sweep_gradient_func (funcs, hb_cairo_paint_sweep_gradient, nullptr, nullptr);438hb_paint_funcs_set_custom_palette_color_func (funcs, hb_cairo_paint_custom_palette_color, nullptr, nullptr);439440hb_paint_funcs_make_immutable (funcs);441442hb_atexit (free_static_cairo_paint_funcs);443444return funcs;445}446} static_cairo_paint_funcs;447448static inline449void free_static_cairo_paint_funcs ()450{451static_cairo_paint_funcs.free_instance ();452}453454static hb_paint_funcs_t *455hb_cairo_paint_get_funcs ()456{457return static_cairo_paint_funcs.get_unconst ();458}459#endif460461static const cairo_user_data_key_t hb_cairo_face_user_data_key = {0};462static const cairo_user_data_key_t hb_cairo_font_user_data_key = {0};463static const cairo_user_data_key_t hb_cairo_font_init_func_user_data_key = {0};464static const cairo_user_data_key_t hb_cairo_font_init_user_data_user_data_key = {0};465static const cairo_user_data_key_t hb_cairo_scale_factor_user_data_key = {0};466467static void hb_cairo_face_destroy (void *p) { hb_face_destroy ((hb_face_t *) p); }468static void hb_cairo_font_destroy (void *p) { hb_font_destroy ((hb_font_t *) p); }469470static cairo_status_t471hb_cairo_init_scaled_font (cairo_scaled_font_t *scaled_font,472cairo_t *cr HB_UNUSED,473cairo_font_extents_t *extents)474{475cairo_font_face_t *font_face = cairo_scaled_font_get_font_face (scaled_font);476477hb_font_t *font = (hb_font_t *) cairo_font_face_get_user_data (font_face,478&hb_cairo_font_user_data_key);479480if (!font)481{482hb_face_t *face = (hb_face_t *) cairo_font_face_get_user_data (font_face,483&hb_cairo_face_user_data_key);484font = hb_font_create (face);485486#if !defined(HB_NO_VAR) && CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,16,0)487cairo_font_options_t *font_options = cairo_font_options_create ();488489// Set variations490cairo_scaled_font_get_font_options (scaled_font, font_options);491const char *variations = cairo_font_options_get_variations (font_options);492hb_vector_t<hb_variation_t> vars;493const char *p = variations;494while (p && *p)495{496const char *end = strpbrk ((char *) p, ", ");497hb_variation_t var;498if (hb_variation_from_string (p, end ? end - p : -1, &var))499vars.push (var);500p = end ? end + 1 : nullptr;501}502hb_font_set_variations (font, &vars[0], vars.length);503504cairo_font_options_destroy (font_options);505#endif506507// Set scale; Note: should NOT set slant, or we'll double-slant.508unsigned scale_factor = hb_cairo_font_face_get_scale_factor (font_face);509if (scale_factor)510{511cairo_matrix_t font_matrix;512cairo_scaled_font_get_scale_matrix (scaled_font, &font_matrix);513hb_font_set_scale (font,514round (font_matrix.xx * scale_factor),515round (font_matrix.yy * scale_factor));516}517518auto *init_func = (hb_cairo_font_init_func_t)519cairo_font_face_get_user_data (font_face,520&hb_cairo_font_init_func_user_data_key);521if (init_func)522{523void *user_data = cairo_font_face_get_user_data (font_face,524&hb_cairo_font_init_user_data_user_data_key);525font = init_func (font, scaled_font, user_data);526}527528hb_font_make_immutable (font);529}530531cairo_scaled_font_set_user_data (scaled_font,532&hb_cairo_font_user_data_key,533(void *) hb_font_reference (font),534hb_cairo_font_destroy);535536hb_position_t x_scale, y_scale;537hb_font_get_scale (font, &x_scale, &y_scale);538539hb_font_extents_t hb_extents;540hb_font_get_h_extents (font, &hb_extents);541542extents->ascent = (double) hb_extents.ascender / y_scale;543extents->descent = (double) -hb_extents.descender / y_scale;544extents->height = extents->ascent + extents->descent;545546#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC547hb_map_t *color_cache = hb_map_create ();548if (unlikely (CAIRO_STATUS_SUCCESS != cairo_scaled_font_set_user_data (scaled_font,549&color_cache_key,550color_cache,551_hb_cairo_destroy_map)))552hb_map_destroy (color_cache);553#endif554555return CAIRO_STATUS_SUCCESS;556}557558static cairo_status_t559hb_cairo_text_to_glyphs (cairo_scaled_font_t *scaled_font,560const char *utf8,561int utf8_len,562cairo_glyph_t **glyphs,563int *num_glyphs,564cairo_text_cluster_t **clusters,565int *num_clusters,566cairo_text_cluster_flags_t *cluster_flags)567{568hb_font_t *font = (hb_font_t *) cairo_scaled_font_get_user_data (scaled_font,569&hb_cairo_font_user_data_key);570571hb_buffer_t *buffer = hb_buffer_create ();572hb_buffer_add_utf8 (buffer, utf8, utf8_len, 0, utf8_len);573hb_buffer_guess_segment_properties (buffer);574hb_shape (font, buffer, nullptr, 0);575576int x_scale, y_scale;577hb_font_get_scale (font, &x_scale, &y_scale);578579hb_cairo_glyphs_from_buffer (buffer,580true,581x_scale, y_scale,5820., 0.,583utf8, utf8_len,584glyphs, (unsigned *) num_glyphs,585clusters, (unsigned *) num_clusters,586cluster_flags);587588hb_buffer_destroy (buffer);589590return CAIRO_STATUS_SUCCESS;591}592593static cairo_status_t594hb_cairo_render_glyph (cairo_scaled_font_t *scaled_font,595unsigned long glyph,596cairo_t *cr,597cairo_text_extents_t *extents)598{599hb_font_t *font = (hb_font_t *) cairo_scaled_font_get_user_data (scaled_font,600&hb_cairo_font_user_data_key);601602hb_position_t x_scale, y_scale;603hb_font_get_scale (font, &x_scale, &y_scale);604cairo_scale (cr,605+1. / (x_scale ? x_scale : 1),606-1. / (y_scale ? y_scale : 1));607608if (hb_font_draw_glyph_or_fail (font, glyph, hb_cairo_draw_get_funcs (), cr))609cairo_fill (cr);610611// If draw fails, we still return SUCCESS, as we want empty drawing, not612// setting the cairo object into error.613return CAIRO_STATUS_SUCCESS;614}615616#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC617618static cairo_status_t619hb_cairo_render_color_glyph (cairo_scaled_font_t *scaled_font,620unsigned long glyph,621cairo_t *cr,622cairo_text_extents_t *extents)623{624hb_font_t *font = (hb_font_t *) cairo_scaled_font_get_user_data (scaled_font,625&hb_cairo_font_user_data_key);626627unsigned int palette = 0;628#ifdef CAIRO_COLOR_PALETTE_DEFAULT629cairo_font_options_t *options = cairo_font_options_create ();630cairo_scaled_font_get_font_options (scaled_font, options);631palette = cairo_font_options_get_color_palette (options);632cairo_font_options_destroy (options);633#endif634635hb_color_t color = HB_COLOR (0, 0, 0, 255);636hb_position_t x_scale, y_scale;637hb_font_get_scale (font, &x_scale, &y_scale);638cairo_scale (cr,639+1. / (x_scale ? x_scale : 1),640-1. / (y_scale ? y_scale : 1));641642hb_cairo_context_t c;643c.scaled_font = scaled_font;644c.cr = cr;645c.color_cache = (hb_map_t *) cairo_scaled_font_get_user_data (scaled_font, &color_cache_key);646647if (!hb_font_paint_glyph_or_fail (font, glyph, hb_cairo_paint_get_funcs (), &c, palette, color))648return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;649650return CAIRO_STATUS_SUCCESS;651}652653#endif654655static cairo_font_face_t *656user_font_face_create (hb_face_t *face)657{658cairo_font_face_t *cairo_face;659660cairo_face = cairo_user_font_face_create ();661cairo_user_font_face_set_init_func (cairo_face, hb_cairo_init_scaled_font);662cairo_user_font_face_set_text_to_glyphs_func (cairo_face, hb_cairo_text_to_glyphs);663cairo_user_font_face_set_render_glyph_func (cairo_face, hb_cairo_render_glyph);664#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC665cairo_user_font_face_set_render_color_glyph_func (cairo_face, hb_cairo_render_color_glyph);666#endif667668if (unlikely (CAIRO_STATUS_SUCCESS != cairo_font_face_set_user_data (cairo_face,669&hb_cairo_face_user_data_key,670(void *) hb_face_reference (face),671hb_cairo_face_destroy)))672hb_face_destroy (face);673674return cairo_face;675}676677/**678* hb_cairo_font_face_create_for_font:679* @font: a #hb_font_t680*681* Creates a #cairo_font_face_t for rendering text according682* to @font.683*684* Note that the scale of @font does not affect the rendering,685* but the variations and slant that are set on @font do.686*687* Returns: (transfer full): a newly created #cairo_font_face_t688*689* Since: 7.0.0690*/691cairo_font_face_t *692hb_cairo_font_face_create_for_font (hb_font_t *font)693{694hb_font_make_immutable (font);695696auto *hb_face = hb_font_get_face (font);697auto *cairo_face = user_font_face_create (hb_face);698699if (unlikely (CAIRO_STATUS_SUCCESS != cairo_font_face_set_user_data (cairo_face,700&hb_cairo_font_user_data_key,701(void *) hb_font_reference (font),702hb_cairo_font_destroy)))703hb_font_destroy (font);704705return cairo_face;706}707708/**709* hb_cairo_font_face_get_font:710* @font_face: a #cairo_font_face_t711*712* Gets the #hb_font_t that @font_face was created from.713*714* Returns: (nullable) (transfer none): the #hb_font_t that @font_face was created from715*716* Since: 7.0.0717*/718hb_font_t *719hb_cairo_font_face_get_font (cairo_font_face_t *font_face)720{721return (hb_font_t *) cairo_font_face_get_user_data (font_face,722&hb_cairo_font_user_data_key);723}724725/**726* hb_cairo_font_face_create_for_face:727* @face: a #hb_face_t728*729* Creates a #cairo_font_face_t for rendering text according730* to @face.731*732* Returns: (transfer full): a newly created #cairo_font_face_t733*734* Since: 7.0.0735*/736cairo_font_face_t *737hb_cairo_font_face_create_for_face (hb_face_t *face)738{739hb_face_make_immutable (face);740741return user_font_face_create (face);742}743744/**745* hb_cairo_font_face_get_face:746* @font_face: a #cairo_font_face_t747*748* Gets the #hb_face_t associated with @font_face.749*750* Returns: (nullable) (transfer none): the #hb_face_t associated with @font_face751*752* Since: 7.0.0753*/754hb_face_t *755hb_cairo_font_face_get_face (cairo_font_face_t *font_face)756{757return (hb_face_t *) cairo_font_face_get_user_data (font_face,758&hb_cairo_face_user_data_key);759}760761/**762* hb_cairo_font_face_set_font_init_func:763* @font_face: a #cairo_font_face_t764* @func: The virtual method to use765* @user_data: user data accompanying the method766* @destroy: function to call when @user_data is not needed anymore767*768* Set the virtual method to be called when a cairo769* face created using hb_cairo_font_face_create_for_face()770* creates an #hb_font_t for a #cairo_scaled_font_t.771*772* Since: 7.0.0773*/774void775hb_cairo_font_face_set_font_init_func (cairo_font_face_t *font_face,776hb_cairo_font_init_func_t func,777void *user_data,778hb_destroy_func_t destroy)779{780cairo_font_face_set_user_data (font_face,781&hb_cairo_font_init_func_user_data_key,782(void *) func,783nullptr);784if (unlikely (CAIRO_STATUS_SUCCESS != cairo_font_face_set_user_data (font_face,785&hb_cairo_font_init_user_data_user_data_key,786(void *) user_data,787destroy)) && destroy)788{789destroy (user_data);790cairo_font_face_set_user_data (font_face,791&hb_cairo_font_init_func_user_data_key,792nullptr,793nullptr);794}795}796797/**798* hb_cairo_scaled_font_get_font:799* @scaled_font: a #cairo_scaled_font_t800*801* Gets the #hb_font_t associated with @scaled_font.802*803* Returns: (nullable) (transfer none): the #hb_font_t associated with @scaled_font804*805* Since: 7.0.0806*/807hb_font_t *808hb_cairo_scaled_font_get_font (cairo_scaled_font_t *scaled_font)809{810return (hb_font_t *) cairo_scaled_font_get_user_data (scaled_font, &hb_cairo_font_user_data_key);811}812813814/**815* hb_cairo_font_face_set_scale_factor:816* @scale_factor: The scale factor to use. See below817* @font_face: a #cairo_font_face_t818*819* Sets the scale factor of the @font_face. Default scale820* factor is zero.821*822* When a #cairo_font_face_t is created from a #hb_face_t using823* hb_cairo_font_face_create_for_face(), such face will create824* #hb_font_t objects during scaled-font creation. The scale825* factor defines how the scale set on such #hb_font_t objects826* relates to the font-matrix (as such font size) of the cairo827* scaled-font.828*829* If the scale-factor is zero (default), then the scale of the830* #hb_font_t object will be left at default, which is the UPEM831* value of the respective #hb_face_t.832*833* If the scale-factor is set to non-zero, then the X and Y scale834* of the #hb_font_t object will be respectively set to the835* @scale_factor times the xx and yy elements of the scale-matrix836* of the cairo scaled-font being created.837*838* When using the hb_cairo_glyphs_from_buffer() API to convert the839* HarfBuzz glyph buffer that resulted from shaping with such a #hb_font_t,840* if the scale-factor was non-zero, you can pass it directly to841* that API as both X and Y scale factors.842*843* If the scale-factor was zero however, or the cairo face was844* created using the alternative constructor845* hb_cairo_font_face_create_for_font(), you need to calculate the846* correct X/Y scale-factors to pass to hb_cairo_glyphs_from_buffer()847* by dividing the #hb_font_t X/Y scale-factors by the848* cairo scaled-font's scale-matrix XX/YY components respectively849* and use those values. Or if you know that relationship offhand850* (because you set the scale of the #hb_font_t yourself), use851* the conversion rate involved.852*853* Since: 7.0.0854*/855void856hb_cairo_font_face_set_scale_factor (cairo_font_face_t *font_face,857unsigned int scale_factor)858{859cairo_font_face_set_user_data (font_face,860&hb_cairo_scale_factor_user_data_key,861(void *) (uintptr_t) scale_factor,862nullptr);863}864865/**866* hb_cairo_font_face_get_scale_factor:867* @font_face: a #cairo_font_face_t868*869* Gets the scale factor set on the @font_face. Defaults to zero.870* See hb_cairo_font_face_set_scale_factor() for details.871*872* Returns: the scale factor of @font_face873*874* Since: 7.0.0875*/876unsigned int877hb_cairo_font_face_get_scale_factor (cairo_font_face_t *font_face)878{879return (unsigned int) (uintptr_t)880cairo_font_face_get_user_data (font_face,881&hb_cairo_scale_factor_user_data_key);882}883884885/**886* hb_cairo_glyphs_from_buffer:887* @buffer: a #hb_buffer_t containing glyphs888* @utf8_clusters: `true` if @buffer clusters are in bytes, instead of characters889* @x_scale_factor: scale factor to divide #hb_position_t Y values by890* @y_scale_factor: scale factor to divide #hb_position_t X values by891* @x: X position to place first glyph892* @y: Y position to place first glyph893* @utf8: (nullable): the text that was shaped in @buffer894* @utf8_len: the length of @utf8 in bytes895* @glyphs: (out): return location for an array of #cairo_glyph_t896* @num_glyphs: (inout): return location for the length of @glyphs897* @clusters: (out) (nullable): return location for an array of cluster positions898* @num_clusters: (inout) (nullable): return location for the length of @clusters899* @cluster_flags: (out) (nullable): return location for cluster flags900*901* Extracts information from @buffer in a form that can be902* passed to cairo_show_text_glyphs() or cairo_show_glyphs().903* This API is modeled after cairo_scaled_font_text_to_glyphs() and904* cairo_user_scaled_font_text_to_glyphs_func_t.905*906* The @num_glyphs argument should be preset to the number of glyph entries available907* in the @glyphs buffer. If the @glyphs buffer is `NULL`, the value of908* @num_glyphs must be zero. If the provided glyph array is too short for909* the conversion (or for convenience), a new glyph array may be allocated910* using cairo_glyph_allocate() and placed in @glyphs. Upon return,911* @num_glyphs should contain the number of generated glyphs. If the value912* @glyphs points at has changed after the call, the caller will free the913* allocated glyph array using cairo_glyph_free(). The caller will also free914* the original value of @glyphs, so this function shouldn't do so.915*916* If @clusters is not `NULL`, then @num_clusters and @cluster_flags917* should not be either, and @utf8 must be provided, and cluster918* mapping will be computed. The semantics of how919* cluster array allocation works is similar to the glyph array. That is,920* if @clusters initially points to a non-`NULL` value, that array may be used921* as a cluster buffer, and @num_clusters points to the number of cluster922* entries available there. If the provided cluster array is too short for923* the conversion (or for convenience), a new cluster array may be allocated924* using cairo_text_cluster_allocate() and placed in @clusters. In this case,925* the original value of @clusters will still be freed by the caller. Upon926* return, @num_clusters will contain the number of generated clusters.927* If the value @clusters points at has changed after the call, the caller928* will free the allocated cluster array using cairo_text_cluster_free().929*930* See hb_cairo_font_face_set_scale_factor() for the details of931* the @scale_factor argument.932*933* The returned @glyphs vector actually has `@num_glyphs + 1` entries in934* it and the x,y values of the extra entry at the end add up the advance935* x,y of all the glyphs in the @buffer.936*937* Since: 7.0.0938*/939void940hb_cairo_glyphs_from_buffer (hb_buffer_t *buffer,941hb_bool_t utf8_clusters,942double x_scale_factor,943double y_scale_factor,944double x,945double y,946const char *utf8,947int utf8_len,948cairo_glyph_t **glyphs,949unsigned int *num_glyphs,950cairo_text_cluster_t **clusters,951unsigned int *num_clusters,952cairo_text_cluster_flags_t *cluster_flags)953{954if (utf8 && utf8_len < 0)955utf8_len = strlen (utf8);956957unsigned orig_num_glyphs = *num_glyphs;958*num_glyphs = hb_buffer_get_length (buffer);959hb_glyph_info_t *hb_glyph = hb_buffer_get_glyph_infos (buffer, nullptr);960hb_glyph_position_t *hb_position = hb_buffer_get_glyph_positions (buffer, nullptr);961if (orig_num_glyphs < *num_glyphs + 1)962*glyphs = cairo_glyph_allocate (*num_glyphs + 1);963964if (clusters && utf8)965{966unsigned orig_num_clusters = *num_clusters;967*num_clusters = *num_glyphs ? 1 : 0;968for (unsigned int i = 1; i < *num_glyphs; i++)969if (hb_glyph[i].cluster != hb_glyph[i-1].cluster)970(*num_clusters)++;971if (orig_num_clusters < *num_clusters)972*clusters = cairo_text_cluster_allocate (*num_clusters);973}974975double x_scale = x_scale_factor ? 1. / x_scale_factor : 0.;976double y_scale = y_scale_factor ? 1. / y_scale_factor : 0.;977hb_position_t hx = 0, hy = 0;978int i;979for (i = 0; i < (int) *num_glyphs; i++)980{981(*glyphs)[i].index = hb_glyph[i].codepoint;982(*glyphs)[i].x = x + (+hb_position->x_offset + hx) * x_scale;983(*glyphs)[i].y = y + (-hb_position->y_offset + hy) * y_scale;984hx += hb_position->x_advance;985hy += -hb_position->y_advance;986987hb_position++;988}989(*glyphs)[i].index = -1;990(*glyphs)[i].x = round (hx * x_scale);991(*glyphs)[i].y = round (hy * y_scale);992993if (clusters && *num_clusters && utf8)994{995hb_memset ((void *) *clusters, 0, *num_clusters * sizeof ((*clusters)[0]));996hb_bool_t backward = HB_DIRECTION_IS_BACKWARD (hb_buffer_get_direction (buffer));997*cluster_flags = backward ? CAIRO_TEXT_CLUSTER_FLAG_BACKWARD : (cairo_text_cluster_flags_t) 0;998unsigned int cluster = 0;999const char *start = utf8, *end;1000(*clusters)[cluster].num_glyphs++;1001if (backward)1002{1003for (i = *num_glyphs - 2; i >= 0; i--)1004{1005if (hb_glyph[i].cluster != hb_glyph[i+1].cluster)1006{1007assert (hb_glyph[i].cluster > hb_glyph[i+1].cluster);1008if (utf8_clusters)1009end = start + hb_glyph[i].cluster - hb_glyph[i+1].cluster;1010else1011end = (const char *) hb_utf_offset_to_pointer<hb_utf8_t> ((const uint8_t *) start,1012(const uint8_t *) utf8, utf8_len,1013(signed) (hb_glyph[i].cluster - hb_glyph[i+1].cluster));1014(*clusters)[cluster].num_bytes = end - start;1015start = end;1016cluster++;1017}1018(*clusters)[cluster].num_glyphs++;1019}1020(*clusters)[cluster].num_bytes = utf8 + utf8_len - start;1021}1022else1023{1024for (i = 1; i < (int) *num_glyphs; i++)1025{1026if (hb_glyph[i].cluster != hb_glyph[i-1].cluster)1027{1028assert (hb_glyph[i].cluster > hb_glyph[i-1].cluster);1029if (utf8_clusters)1030end = start + hb_glyph[i].cluster - hb_glyph[i-1].cluster;1031else1032end = (const char *) hb_utf_offset_to_pointer<hb_utf8_t> ((const uint8_t *) start,1033(const uint8_t *) utf8, utf8_len,1034(signed) (hb_glyph[i].cluster - hb_glyph[i-1].cluster));1035(*clusters)[cluster].num_bytes = end - start;1036start = end;1037cluster++;1038}1039(*clusters)[cluster].num_glyphs++;1040}1041(*clusters)[cluster].num_bytes = utf8 + utf8_len - start;1042}1043}1044else if (num_clusters)1045*num_clusters = 0;1046}10471048#endif104910501051