1 /*
2 * Copyright © 2022 Red Hat, Inc.
3 *
4 * This is part of HarfBuzz, a text shaping library.
5 *
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
11 *
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16 * DAMAGE.
17 *
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23 *
24 * Red Hat Author(s): Matthias Clasen
25 */
26
27 #include "hb.hh"
28
29 #ifdef HAVE_CAIRO
30
31 #include "hb-cairo.h"
32
33 #include "hb-cairo-utils.hh"
34
35 #include "hb-machinery.hh"
36 #include "hb-utf.hh"
37
38
39 /**
40 * SECTION:hb-cairo
41 * @title: hb-cairo
42 * @short_description: Cairo integration
43 * @include: hb-cairo.h
44 *
45 * Functions for using HarfBuzz with the cairo library.
46 *
47 * HarfBuzz supports using cairo for rendering.
48 **/
49
50 static void
hb_cairo_move_to(hb_draw_funcs_t * dfuncs HB_UNUSED,void * draw_data,hb_draw_state_t * st HB_UNUSED,float to_x,float to_y,void * user_data HB_UNUSED)51 hb_cairo_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
52 void *draw_data,
53 hb_draw_state_t *st HB_UNUSED,
54 float to_x, float to_y,
55 void *user_data HB_UNUSED)
56 {
57 cairo_t *cr = (cairo_t *) draw_data;
58
59 cairo_move_to (cr, (double) to_x, (double) to_y);
60 }
61
62 static void
hb_cairo_line_to(hb_draw_funcs_t * dfuncs HB_UNUSED,void * draw_data,hb_draw_state_t * st HB_UNUSED,float to_x,float to_y,void * user_data HB_UNUSED)63 hb_cairo_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
64 void *draw_data,
65 hb_draw_state_t *st HB_UNUSED,
66 float to_x, float to_y,
67 void *user_data HB_UNUSED)
68 {
69 cairo_t *cr = (cairo_t *) draw_data;
70
71 cairo_line_to (cr, (double) to_x, (double) to_y);
72 }
73
74 static void
hb_cairo_cubic_to(hb_draw_funcs_t * dfuncs HB_UNUSED,void * draw_data,hb_draw_state_t * st HB_UNUSED,float control1_x,float control1_y,float control2_x,float control2_y,float to_x,float to_y,void * user_data HB_UNUSED)75 hb_cairo_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
76 void *draw_data,
77 hb_draw_state_t *st HB_UNUSED,
78 float control1_x, float control1_y,
79 float control2_x, float control2_y,
80 float to_x, float to_y,
81 void *user_data HB_UNUSED)
82 {
83 cairo_t *cr = (cairo_t *) draw_data;
84
85 cairo_curve_to (cr,
86 (double) control1_x, (double) control1_y,
87 (double) control2_x, (double) control2_y,
88 (double) to_x, (double) to_y);
89 }
90
91 static void
hb_cairo_close_path(hb_draw_funcs_t * dfuncs HB_UNUSED,void * draw_data,hb_draw_state_t * st HB_UNUSED,void * user_data HB_UNUSED)92 hb_cairo_close_path (hb_draw_funcs_t *dfuncs HB_UNUSED,
93 void *draw_data,
94 hb_draw_state_t *st HB_UNUSED,
95 void *user_data HB_UNUSED)
96 {
97 cairo_t *cr = (cairo_t *) draw_data;
98
99 cairo_close_path (cr);
100 }
101
102 static inline void free_static_cairo_draw_funcs ();
103
104 static struct hb_cairo_draw_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t<hb_cairo_draw_funcs_lazy_loader_t>
105 {
createhb_cairo_draw_funcs_lazy_loader_t106 static hb_draw_funcs_t *create ()
107 {
108 hb_draw_funcs_t *funcs = hb_draw_funcs_create ();
109
110 hb_draw_funcs_set_move_to_func (funcs, hb_cairo_move_to, nullptr, nullptr);
111 hb_draw_funcs_set_line_to_func (funcs, hb_cairo_line_to, nullptr, nullptr);
112 hb_draw_funcs_set_cubic_to_func (funcs, hb_cairo_cubic_to, nullptr, nullptr);
113 hb_draw_funcs_set_close_path_func (funcs, hb_cairo_close_path, nullptr, nullptr);
114
115 hb_draw_funcs_make_immutable (funcs);
116
117 hb_atexit (free_static_cairo_draw_funcs);
118
119 return funcs;
120 }
121 } static_cairo_draw_funcs;
122
123 static inline
free_static_cairo_draw_funcs()124 void free_static_cairo_draw_funcs ()
125 {
126 static_cairo_draw_funcs.free_instance ();
127 }
128
129 static hb_draw_funcs_t *
hb_cairo_draw_get_funcs()130 hb_cairo_draw_get_funcs ()
131 {
132 return static_cairo_draw_funcs.get_unconst ();
133 }
134
135
136 #ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC
137
138 static void
hb_cairo_push_transform(hb_paint_funcs_t * pfuncs HB_UNUSED,void * paint_data,float xx,float yx,float xy,float yy,float dx,float dy,void * user_data HB_UNUSED)139 hb_cairo_push_transform (hb_paint_funcs_t *pfuncs HB_UNUSED,
140 void *paint_data,
141 float xx, float yx,
142 float xy, float yy,
143 float dx, float dy,
144 void *user_data HB_UNUSED)
145 {
146 hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
147 cairo_t *cr = c->cr;
148
149 cairo_matrix_t m;
150
151 cairo_save (cr);
152 cairo_matrix_init (&m, (double) xx, (double) yx,
153 (double) xy, (double) yy,
154 (double) dx, (double) dy);
155 cairo_transform (cr, &m);
156 }
157
158 static void
hb_cairo_pop_transform(hb_paint_funcs_t * pfuncs HB_UNUSED,void * paint_data,void * user_data HB_UNUSED)159 hb_cairo_pop_transform (hb_paint_funcs_t *pfuncs HB_UNUSED,
160 void *paint_data,
161 void *user_data HB_UNUSED)
162 {
163 hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
164 cairo_t *cr = c->cr;
165
166 cairo_restore (cr);
167 }
168
169 static hb_bool_t
hb_cairo_paint_color_glyph(hb_paint_funcs_t * pfuncs HB_UNUSED,void * paint_data,hb_codepoint_t glyph,hb_font_t * font,void * user_data HB_UNUSED)170 hb_cairo_paint_color_glyph (hb_paint_funcs_t *pfuncs HB_UNUSED,
171 void *paint_data,
172 hb_codepoint_t glyph,
173 hb_font_t *font,
174 void *user_data HB_UNUSED)
175 {
176 hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
177 cairo_t *cr = c->cr;
178
179 cairo_save (cr);
180
181 hb_position_t x_scale, y_scale;
182 hb_font_get_scale (font, &x_scale, &y_scale);
183 cairo_scale (cr, x_scale, y_scale);
184
185 cairo_glyph_t cairo_glyph = { glyph, 0, 0 };
186 cairo_set_scaled_font (cr, c->scaled_font);
187 cairo_set_font_size (cr, 1);
188 cairo_show_glyphs (cr, &cairo_glyph, 1);
189
190 cairo_restore (cr);
191
192 return true;
193 }
194
195 static void
hb_cairo_push_clip_glyph(hb_paint_funcs_t * pfuncs HB_UNUSED,void * paint_data,hb_codepoint_t glyph,hb_font_t * font,void * user_data HB_UNUSED)196 hb_cairo_push_clip_glyph (hb_paint_funcs_t *pfuncs HB_UNUSED,
197 void *paint_data,
198 hb_codepoint_t glyph,
199 hb_font_t *font,
200 void *user_data HB_UNUSED)
201 {
202 hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
203 cairo_t *cr = c->cr;
204
205 cairo_save (cr);
206 cairo_new_path (cr);
207 hb_font_draw_glyph (font, glyph, hb_cairo_draw_get_funcs (), cr);
208 cairo_close_path (cr);
209 cairo_clip (cr);
210 }
211
212 static void
hb_cairo_push_clip_rectangle(hb_paint_funcs_t * pfuncs HB_UNUSED,void * paint_data,float xmin,float ymin,float xmax,float ymax,void * user_data HB_UNUSED)213 hb_cairo_push_clip_rectangle (hb_paint_funcs_t *pfuncs HB_UNUSED,
214 void *paint_data,
215 float xmin, float ymin, float xmax, float ymax,
216 void *user_data HB_UNUSED)
217 {
218 hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
219 cairo_t *cr = c->cr;
220
221 cairo_save (cr);
222 cairo_rectangle (cr,
223 (double) xmin, (double) ymin,
224 (double) (xmax - xmin), (double) (ymax - ymin));
225 cairo_clip (cr);
226 }
227
228 static void
hb_cairo_pop_clip(hb_paint_funcs_t * pfuncs HB_UNUSED,void * paint_data,void * user_data HB_UNUSED)229 hb_cairo_pop_clip (hb_paint_funcs_t *pfuncs HB_UNUSED,
230 void *paint_data,
231 void *user_data HB_UNUSED)
232 {
233 hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
234 cairo_t *cr = c->cr;
235
236 cairo_restore (cr);
237 }
238
239 static void
hb_cairo_push_group(hb_paint_funcs_t * pfuncs HB_UNUSED,void * paint_data,void * user_data HB_UNUSED)240 hb_cairo_push_group (hb_paint_funcs_t *pfuncs HB_UNUSED,
241 void *paint_data,
242 void *user_data HB_UNUSED)
243 {
244 hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
245 cairo_t *cr = c->cr;
246
247 cairo_save (cr);
248 cairo_push_group (cr);
249 }
250
251 static void
hb_cairo_pop_group(hb_paint_funcs_t * pfuncs HB_UNUSED,void * paint_data,hb_paint_composite_mode_t mode,void * user_data HB_UNUSED)252 hb_cairo_pop_group (hb_paint_funcs_t *pfuncs HB_UNUSED,
253 void *paint_data,
254 hb_paint_composite_mode_t mode,
255 void *user_data HB_UNUSED)
256 {
257 hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
258 cairo_t *cr = c->cr;
259
260 cairo_pop_group_to_source (cr);
261 cairo_set_operator (cr, _hb_paint_composite_mode_to_cairo (mode));
262 cairo_paint (cr);
263
264 cairo_restore (cr);
265 }
266
267 static void
hb_cairo_paint_color(hb_paint_funcs_t * pfuncs HB_UNUSED,void * paint_data,hb_bool_t use_foreground,hb_color_t color,void * user_data HB_UNUSED)268 hb_cairo_paint_color (hb_paint_funcs_t *pfuncs HB_UNUSED,
269 void *paint_data,
270 hb_bool_t use_foreground,
271 hb_color_t color,
272 void *user_data HB_UNUSED)
273 {
274 hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
275 cairo_t *cr = c->cr;
276
277 if (use_foreground)
278 {
279 #ifdef HAVE_CAIRO_USER_SCALED_FONT_GET_FOREGROUND_SOURCE
280 double r, g, b, a;
281 cairo_pattern_t *foreground = cairo_user_scaled_font_get_foreground_source (c->scaled_font);
282 if (cairo_pattern_get_rgba (foreground, &r, &g, &b, &a) == CAIRO_STATUS_SUCCESS)
283 cairo_set_source_rgba (cr, r, g, b, a * hb_color_get_alpha (color) / 255.);
284 else
285 #endif
286 cairo_set_source_rgba (cr, 0, 0, 0, hb_color_get_alpha (color) / 255.);
287 }
288 else
289 cairo_set_source_rgba (cr,
290 hb_color_get_red (color) / 255.,
291 hb_color_get_green (color) / 255.,
292 hb_color_get_blue (color) / 255.,
293 hb_color_get_alpha (color) / 255.);
294 cairo_paint (cr);
295 }
296
297 static hb_bool_t
hb_cairo_paint_image(hb_paint_funcs_t * pfuncs HB_UNUSED,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 HB_UNUSED)298 hb_cairo_paint_image (hb_paint_funcs_t *pfuncs HB_UNUSED,
299 void *paint_data,
300 hb_blob_t *blob,
301 unsigned width,
302 unsigned height,
303 hb_tag_t format,
304 float slant,
305 hb_glyph_extents_t *extents,
306 void *user_data HB_UNUSED)
307 {
308 hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
309
310 return _hb_cairo_paint_glyph_image (c, blob, width, height, format, slant, extents);
311 }
312
313 static void
hb_cairo_paint_linear_gradient(hb_paint_funcs_t * pfuncs HB_UNUSED,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_UNUSED)314 hb_cairo_paint_linear_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED,
315 void *paint_data,
316 hb_color_line_t *color_line,
317 float x0, float y0,
318 float x1, float y1,
319 float x2, float y2,
320 void *user_data HB_UNUSED)
321 {
322 hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
323
324 _hb_cairo_paint_linear_gradient (c, color_line, x0, y0, x1, y1, x2, y2);
325 }
326
327 static void
hb_cairo_paint_radial_gradient(hb_paint_funcs_t * pfuncs HB_UNUSED,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_UNUSED)328 hb_cairo_paint_radial_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED,
329 void *paint_data,
330 hb_color_line_t *color_line,
331 float x0, float y0, float r0,
332 float x1, float y1, float r1,
333 void *user_data HB_UNUSED)
334 {
335 hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
336
337 _hb_cairo_paint_radial_gradient (c, color_line, x0, y0, r0, x1, y1, r1);
338 }
339
340 static void
hb_cairo_paint_sweep_gradient(hb_paint_funcs_t * pfuncs HB_UNUSED,void * paint_data,hb_color_line_t * color_line,float x0,float y0,float start_angle,float end_angle,void * user_data HB_UNUSED)341 hb_cairo_paint_sweep_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED,
342 void *paint_data,
343 hb_color_line_t *color_line,
344 float x0, float y0,
345 float start_angle, float end_angle,
346 void *user_data HB_UNUSED)
347 {
348 hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
349
350 _hb_cairo_paint_sweep_gradient (c, color_line, x0, y0, start_angle, end_angle);
351 }
352
353 static const cairo_user_data_key_t color_cache_key = {0};
354
355 static void
_hb_cairo_destroy_map(void * p)356 _hb_cairo_destroy_map (void *p)
357 {
358 hb_map_destroy ((hb_map_t *) p);
359 }
360
361 static hb_bool_t
hb_cairo_paint_custom_palette_color(hb_paint_funcs_t * funcs,void * paint_data,unsigned int color_index,hb_color_t * color,void * user_data HB_UNUSED)362 hb_cairo_paint_custom_palette_color (hb_paint_funcs_t *funcs,
363 void *paint_data,
364 unsigned int color_index,
365 hb_color_t *color,
366 void *user_data HB_UNUSED)
367 {
368 #ifdef HAVE_CAIRO_FONT_OPTIONS_GET_CUSTOM_PALETTE_COLOR
369 hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
370 cairo_t *cr = c->cr;
371
372 #define HB_DEADBEEF HB_TAG(0xDE,0xAD,0xBE,0xEF)
373
374 hb_map_t *color_cache = c->color_cache;
375 hb_codepoint_t *v;
376 if (likely (color_cache && color_cache->has (color_index, &v)))
377 {
378 if (*v == HB_DEADBEEF)
379 return false;
380 *color = *v;
381 return true;
382 }
383
384 cairo_font_options_t *options;
385 double red, green, blue, alpha;
386
387 options = cairo_font_options_create ();
388 cairo_get_font_options (cr, options);
389 if (CAIRO_STATUS_SUCCESS ==
390 cairo_font_options_get_custom_palette_color (options, color_index,
391 &red, &green, &blue, &alpha))
392 {
393 cairo_font_options_destroy (options);
394 *color = HB_COLOR (round (255 * blue),
395 round (255 * green),
396 round (255 * red),
397 round (255 * alpha));
398
399 if (likely (color_cache && *color != HB_DEADBEEF))
400 color_cache->set (color_index, *color);
401
402 return true;
403 }
404 cairo_font_options_destroy (options);
405
406 if (likely (color_cache))
407 color_cache->set (color_index, HB_DEADBEEF);
408
409 #undef HB_DEADBEEF
410
411 #endif
412
413 return false;
414 }
415
416 static inline void free_static_cairo_paint_funcs ();
417
418 static struct hb_cairo_paint_funcs_lazy_loader_t : hb_paint_funcs_lazy_loader_t<hb_cairo_paint_funcs_lazy_loader_t>
419 {
createhb_cairo_paint_funcs_lazy_loader_t420 static hb_paint_funcs_t *create ()
421 {
422 hb_paint_funcs_t *funcs = hb_paint_funcs_create ();
423
424 hb_paint_funcs_set_push_transform_func (funcs, hb_cairo_push_transform, nullptr, nullptr);
425 hb_paint_funcs_set_pop_transform_func (funcs, hb_cairo_pop_transform, nullptr, nullptr);
426 hb_paint_funcs_set_color_glyph_func (funcs, hb_cairo_paint_color_glyph, nullptr, nullptr);
427 hb_paint_funcs_set_push_clip_glyph_func (funcs, hb_cairo_push_clip_glyph, nullptr, nullptr);
428 hb_paint_funcs_set_push_clip_rectangle_func (funcs, hb_cairo_push_clip_rectangle, nullptr, nullptr);
429 hb_paint_funcs_set_pop_clip_func (funcs, hb_cairo_pop_clip, nullptr, nullptr);
430 hb_paint_funcs_set_push_group_func (funcs, hb_cairo_push_group, nullptr, nullptr);
431 hb_paint_funcs_set_pop_group_func (funcs, hb_cairo_pop_group, nullptr, nullptr);
432 hb_paint_funcs_set_color_func (funcs, hb_cairo_paint_color, nullptr, nullptr);
433 hb_paint_funcs_set_image_func (funcs, hb_cairo_paint_image, nullptr, nullptr);
434 hb_paint_funcs_set_linear_gradient_func (funcs, hb_cairo_paint_linear_gradient, nullptr, nullptr);
435 hb_paint_funcs_set_radial_gradient_func (funcs, hb_cairo_paint_radial_gradient, nullptr, nullptr);
436 hb_paint_funcs_set_sweep_gradient_func (funcs, hb_cairo_paint_sweep_gradient, nullptr, nullptr);
437 hb_paint_funcs_set_custom_palette_color_func (funcs, hb_cairo_paint_custom_palette_color, nullptr, nullptr);
438
439 hb_paint_funcs_make_immutable (funcs);
440
441 hb_atexit (free_static_cairo_paint_funcs);
442
443 return funcs;
444 }
445 } static_cairo_paint_funcs;
446
447 static inline
free_static_cairo_paint_funcs()448 void free_static_cairo_paint_funcs ()
449 {
450 static_cairo_paint_funcs.free_instance ();
451 }
452
453 static hb_paint_funcs_t *
hb_cairo_paint_get_funcs()454 hb_cairo_paint_get_funcs ()
455 {
456 return static_cairo_paint_funcs.get_unconst ();
457 }
458 #endif
459
460 static const cairo_user_data_key_t hb_cairo_face_user_data_key = {0};
461 static const cairo_user_data_key_t hb_cairo_font_user_data_key = {0};
462 static const cairo_user_data_key_t hb_cairo_font_init_func_user_data_key = {0};
463 static const cairo_user_data_key_t hb_cairo_font_init_user_data_user_data_key = {0};
464 static const cairo_user_data_key_t hb_cairo_scale_factor_user_data_key = {0};
465
hb_cairo_face_destroy(void * p)466 static void hb_cairo_face_destroy (void *p) { hb_face_destroy ((hb_face_t *) p); }
hb_cairo_font_destroy(void * p)467 static void hb_cairo_font_destroy (void *p) { hb_font_destroy ((hb_font_t *) p); }
468
469 static cairo_status_t
hb_cairo_init_scaled_font(cairo_scaled_font_t * scaled_font,cairo_t * cr HB_UNUSED,cairo_font_extents_t * extents)470 hb_cairo_init_scaled_font (cairo_scaled_font_t *scaled_font,
471 cairo_t *cr HB_UNUSED,
472 cairo_font_extents_t *extents)
473 {
474 cairo_font_face_t *font_face = cairo_scaled_font_get_font_face (scaled_font);
475
476 hb_font_t *font = (hb_font_t *) cairo_font_face_get_user_data (font_face,
477 &hb_cairo_font_user_data_key);
478
479 if (!font)
480 {
481 hb_face_t *face = (hb_face_t *) cairo_font_face_get_user_data (font_face,
482 &hb_cairo_face_user_data_key);
483 font = hb_font_create (face);
484
485 #if !defined(HB_NO_VAR) && CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,16,0)
486 cairo_font_options_t *font_options = cairo_font_options_create ();
487
488 // Set variations
489 cairo_scaled_font_get_font_options (scaled_font, font_options);
490 const char *variations = cairo_font_options_get_variations (font_options);
491 hb_vector_t<hb_variation_t> vars;
492 const char *p = variations;
493 while (p && *p)
494 {
495 const char *end = strpbrk ((char *) p, ", ");
496 hb_variation_t var;
497 if (hb_variation_from_string (p, end ? end - p : -1, &var))
498 vars.push (var);
499 p = end ? end + 1 : nullptr;
500 }
501 hb_font_set_variations (font, &vars[0], vars.length);
502
503 cairo_font_options_destroy (font_options);
504 #endif
505
506 // Set scale; Note: should NOT set slant, or we'll double-slant.
507 unsigned scale_factor = hb_cairo_font_face_get_scale_factor (font_face);
508 if (scale_factor)
509 {
510 cairo_matrix_t font_matrix;
511 cairo_scaled_font_get_scale_matrix (scaled_font, &font_matrix);
512 hb_font_set_scale (font,
513 round (font_matrix.xx * scale_factor),
514 round (font_matrix.yy * scale_factor));
515 }
516
517 auto *init_func = (hb_cairo_font_init_func_t)
518 cairo_font_face_get_user_data (font_face,
519 &hb_cairo_font_init_func_user_data_key);
520 if (init_func)
521 {
522 void *user_data = cairo_font_face_get_user_data (font_face,
523 &hb_cairo_font_init_user_data_user_data_key);
524 font = init_func (font, scaled_font, user_data);
525 }
526
527 hb_font_make_immutable (font);
528 }
529
530 cairo_scaled_font_set_user_data (scaled_font,
531 &hb_cairo_font_user_data_key,
532 (void *) hb_font_reference (font),
533 hb_cairo_font_destroy);
534
535 hb_position_t x_scale, y_scale;
536 hb_font_get_scale (font, &x_scale, &y_scale);
537
538 hb_font_extents_t hb_extents;
539 hb_font_get_h_extents (font, &hb_extents);
540
541 extents->ascent = (double) hb_extents.ascender / y_scale;
542 extents->descent = (double) -hb_extents.descender / y_scale;
543 extents->height = extents->ascent + extents->descent;
544
545 #ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC
546 hb_map_t *color_cache = hb_map_create ();
547 if (unlikely (CAIRO_STATUS_SUCCESS != cairo_scaled_font_set_user_data (scaled_font,
548 &color_cache_key,
549 color_cache,
550 _hb_cairo_destroy_map)))
551 hb_map_destroy (color_cache);
552 #endif
553
554 return CAIRO_STATUS_SUCCESS;
555 }
556
557 static cairo_status_t
hb_cairo_text_to_glyphs(cairo_scaled_font_t * scaled_font,const char * utf8,int utf8_len,cairo_glyph_t ** glyphs,int * num_glyphs,cairo_text_cluster_t ** clusters,int * num_clusters,cairo_text_cluster_flags_t * cluster_flags)558 hb_cairo_text_to_glyphs (cairo_scaled_font_t *scaled_font,
559 const char *utf8,
560 int utf8_len,
561 cairo_glyph_t **glyphs,
562 int *num_glyphs,
563 cairo_text_cluster_t **clusters,
564 int *num_clusters,
565 cairo_text_cluster_flags_t *cluster_flags)
566 {
567 hb_font_t *font = (hb_font_t *) cairo_scaled_font_get_user_data (scaled_font,
568 &hb_cairo_font_user_data_key);
569
570 hb_buffer_t *buffer = hb_buffer_create ();
571 hb_buffer_add_utf8 (buffer, utf8, utf8_len, 0, utf8_len);
572 hb_buffer_guess_segment_properties (buffer);
573 hb_shape (font, buffer, nullptr, 0);
574
575 hb_cairo_glyphs_from_buffer (buffer,
576 true,
577 font->x_scale, font->y_scale,
578 0., 0.,
579 utf8, utf8_len,
580 glyphs, (unsigned *) num_glyphs,
581 clusters, (unsigned *) num_clusters,
582 cluster_flags);
583
584 hb_buffer_destroy (buffer);
585
586 return CAIRO_STATUS_SUCCESS;
587 }
588
589 static cairo_status_t
hb_cairo_render_glyph(cairo_scaled_font_t * scaled_font,unsigned long glyph,cairo_t * cr,cairo_text_extents_t * extents)590 hb_cairo_render_glyph (cairo_scaled_font_t *scaled_font,
591 unsigned long glyph,
592 cairo_t *cr,
593 cairo_text_extents_t *extents)
594 {
595 hb_font_t *font = (hb_font_t *) cairo_scaled_font_get_user_data (scaled_font,
596 &hb_cairo_font_user_data_key);
597
598 hb_position_t x_scale, y_scale;
599 hb_font_get_scale (font, &x_scale, &y_scale);
600 cairo_scale (cr, +1./x_scale, -1./y_scale);
601
602 hb_font_draw_glyph (font, glyph, hb_cairo_draw_get_funcs (), cr);
603
604 cairo_fill (cr);
605
606 return CAIRO_STATUS_SUCCESS;
607 }
608
609 #ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC
610
611 static cairo_status_t
hb_cairo_render_color_glyph(cairo_scaled_font_t * scaled_font,unsigned long glyph,cairo_t * cr,cairo_text_extents_t * extents)612 hb_cairo_render_color_glyph (cairo_scaled_font_t *scaled_font,
613 unsigned long glyph,
614 cairo_t *cr,
615 cairo_text_extents_t *extents)
616 {
617 hb_font_t *font = (hb_font_t *) cairo_scaled_font_get_user_data (scaled_font,
618 &hb_cairo_font_user_data_key);
619
620 unsigned int palette = 0;
621 #ifdef CAIRO_COLOR_PALETTE_DEFAULT
622 cairo_font_options_t *options = cairo_font_options_create ();
623 cairo_scaled_font_get_font_options (scaled_font, options);
624 palette = cairo_font_options_get_color_palette (options);
625 cairo_font_options_destroy (options);
626 #endif
627
628 hb_color_t color = HB_COLOR (0, 0, 0, 255);
629 hb_position_t x_scale, y_scale;
630 hb_font_get_scale (font, &x_scale, &y_scale);
631 cairo_scale (cr, +1./x_scale, -1./y_scale);
632
633 hb_cairo_context_t c;
634 c.scaled_font = scaled_font;
635 c.cr = cr;
636 c.color_cache = (hb_map_t *) cairo_scaled_font_get_user_data (scaled_font, &color_cache_key);
637
638 hb_font_paint_glyph (font, glyph, hb_cairo_paint_get_funcs (), &c, palette, color);
639
640
641 return CAIRO_STATUS_SUCCESS;
642 }
643
644 #endif
645
646 static cairo_font_face_t *
user_font_face_create(hb_face_t * face)647 user_font_face_create (hb_face_t *face)
648 {
649 cairo_font_face_t *cairo_face;
650
651 cairo_face = cairo_user_font_face_create ();
652 cairo_user_font_face_set_init_func (cairo_face, hb_cairo_init_scaled_font);
653 cairo_user_font_face_set_text_to_glyphs_func (cairo_face, hb_cairo_text_to_glyphs);
654 cairo_user_font_face_set_render_glyph_func (cairo_face, hb_cairo_render_glyph);
655 #ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC
656 if (hb_ot_color_has_png (face) || hb_ot_color_has_layers (face) || hb_ot_color_has_paint (face))
657 cairo_user_font_face_set_render_color_glyph_func (cairo_face, hb_cairo_render_color_glyph);
658 #endif
659
660 if (unlikely (CAIRO_STATUS_SUCCESS != cairo_font_face_set_user_data (cairo_face,
661 &hb_cairo_face_user_data_key,
662 (void *) hb_face_reference (face),
663 hb_cairo_face_destroy)))
664 hb_face_destroy (face);
665
666 return cairo_face;
667 }
668
669 /**
670 * hb_cairo_font_face_create_for_font:
671 * @font: a #hb_font_t
672 *
673 * Creates a #cairo_font_face_t for rendering text according
674 * to @font.
675 *
676 * Note that the scale of @font does not affect the rendering,
677 * but the variations and slant that are set on @font do.
678 *
679 * Returns: (transfer full): a newly created #cairo_font_face_t
680 *
681 * Since: 7.0.0
682 */
683 cairo_font_face_t *
hb_cairo_font_face_create_for_font(hb_font_t * font)684 hb_cairo_font_face_create_for_font (hb_font_t *font)
685 {
686 hb_font_make_immutable (font);
687
688 auto *cairo_face = user_font_face_create (font->face);
689
690 if (unlikely (CAIRO_STATUS_SUCCESS != cairo_font_face_set_user_data (cairo_face,
691 &hb_cairo_font_user_data_key,
692 (void *) hb_font_reference (font),
693 hb_cairo_font_destroy)))
694 hb_font_destroy (font);
695
696 return cairo_face;
697 }
698
699 /**
700 * hb_cairo_font_face_get_font:
701 * @font_face: a #cairo_font_face_t
702 *
703 * Gets the #hb_font_t that @font_face was created from.
704 *
705 * Returns: (nullable) (transfer none): the #hb_font_t that @font_face was created from
706 *
707 * Since: 7.0.0
708 */
709 hb_font_t *
hb_cairo_font_face_get_font(cairo_font_face_t * font_face)710 hb_cairo_font_face_get_font (cairo_font_face_t *font_face)
711 {
712 return (hb_font_t *) cairo_font_face_get_user_data (font_face,
713 &hb_cairo_font_user_data_key);
714 }
715
716 /**
717 * hb_cairo_font_face_create_for_face:
718 * @face: a #hb_face_t
719 *
720 * Creates a #cairo_font_face_t for rendering text according
721 * to @face.
722 *
723 * Returns: (transfer full): a newly created #cairo_font_face_t
724 *
725 * Since: 7.0.0
726 */
727 cairo_font_face_t *
hb_cairo_font_face_create_for_face(hb_face_t * face)728 hb_cairo_font_face_create_for_face (hb_face_t *face)
729 {
730 hb_face_make_immutable (face);
731
732 return user_font_face_create (face);
733 }
734
735 /**
736 * hb_cairo_font_face_get_face:
737 * @font_face: a #cairo_font_face_t
738 *
739 * Gets the #hb_face_t associated with @font_face.
740 *
741 * Returns: (nullable) (transfer none): the #hb_face_t associated with @font_face
742 *
743 * Since: 7.0.0
744 */
745 hb_face_t *
hb_cairo_font_face_get_face(cairo_font_face_t * font_face)746 hb_cairo_font_face_get_face (cairo_font_face_t *font_face)
747 {
748 return (hb_face_t *) cairo_font_face_get_user_data (font_face,
749 &hb_cairo_face_user_data_key);
750 }
751
752 /**
753 * hb_cairo_font_face_set_font_init_func:
754 * @font_face: a #cairo_font_face_t
755 * @func: The virtual method to use
756 * @user_data: user data accompanying the method
757 * @destroy: function to call when @user_data is not needed anymore
758 *
759 * Set the virtual method to be called when a cairo
760 * face created using hb_cairo_font_face_create_for_face()
761 * creates an #hb_font_t for a #cairo_scaled_font_t.
762 *
763 * Since: 7.0.0
764 */
765 void
hb_cairo_font_face_set_font_init_func(cairo_font_face_t * font_face,hb_cairo_font_init_func_t func,void * user_data,hb_destroy_func_t destroy)766 hb_cairo_font_face_set_font_init_func (cairo_font_face_t *font_face,
767 hb_cairo_font_init_func_t func,
768 void *user_data,
769 hb_destroy_func_t destroy)
770 {
771 cairo_font_face_set_user_data (font_face,
772 &hb_cairo_font_init_func_user_data_key,
773 (void *) func,
774 nullptr);
775 if (unlikely (CAIRO_STATUS_SUCCESS != cairo_font_face_set_user_data (font_face,
776 &hb_cairo_font_init_user_data_user_data_key,
777 (void *) user_data,
778 destroy)) && destroy)
779 {
780 destroy (user_data);
781 cairo_font_face_set_user_data (font_face,
782 &hb_cairo_font_init_func_user_data_key,
783 nullptr,
784 nullptr);
785 }
786 }
787
788 /**
789 * hb_cairo_scaled_font_get_font:
790 * @scaled_font: a #cairo_scaled_font_t
791 *
792 * Gets the #hb_font_t associated with @scaled_font.
793 *
794 * Returns: (nullable) (transfer none): the #hb_font_t associated with @scaled_font
795 *
796 * Since: 7.0.0
797 */
798 hb_font_t *
hb_cairo_scaled_font_get_font(cairo_scaled_font_t * scaled_font)799 hb_cairo_scaled_font_get_font (cairo_scaled_font_t *scaled_font)
800 {
801 return (hb_font_t *) cairo_scaled_font_get_user_data (scaled_font, &hb_cairo_font_user_data_key);
802 }
803
804
805 /**
806 * hb_cairo_font_face_set_scale_factor:
807 * @scale_factor: The scale factor to use. See below
808 * @font_face: a #cairo_font_face_t
809 *
810 * Sets the scale factor of the @font_face. Default scale
811 * factor is zero.
812 *
813 * When a #cairo_font_face_t is created from a #hb_face_t using
814 * hb_cairo_font_face_create_for_face(), such face will create
815 * #hb_font_t objects during scaled-font creation. The scale
816 * factor defines how the scale set on such #hb_font_t objects
817 * relates to the font-matrix (as such font size) of the cairo
818 * scaled-font.
819 *
820 * If the scale-factor is zero (default), then the scale of the
821 * #hb_font_t object will be left at default, which is the UPEM
822 * value of the respective #hb_face_t.
823 *
824 * If the scale-factor is set to non-zero, then the X and Y scale
825 * of the #hb_font_t object will be respectively set to the
826 * @scale_factor times the xx and yy elements of the scale-matrix
827 * of the cairo scaled-font being created.
828 *
829 * When using the hb_cairo_glyphs_from_buffer() API to convert the
830 * HarfBuzz glyph buffer that resulted from shaping with such a #hb_font_t,
831 * if the scale-factor was non-zero, you can pass it directly to
832 * that API as both X and Y scale factors.
833 *
834 * If the scale-factor was zero however, or the cairo face was
835 * created using the alternative constructor
836 * hb_cairo_font_face_create_for_font(), you need to calculate the
837 * correct X/Y scale-factors to pass to hb_cairo_glyphs_from_buffer()
838 * by dividing the #hb_font_t X/Y scale-factors by the
839 * cairo scaled-font's scale-matrix XX/YY components respectively
840 * and use those values. Or if you know that relationship offhand
841 * (because you set the scale of the #hb_font_t yourself), use
842 * the conversion rate involved.
843 *
844 * Since: 7.0.0
845 */
846 void
hb_cairo_font_face_set_scale_factor(cairo_font_face_t * font_face,unsigned int scale_factor)847 hb_cairo_font_face_set_scale_factor (cairo_font_face_t *font_face,
848 unsigned int scale_factor)
849 {
850 cairo_font_face_set_user_data (font_face,
851 &hb_cairo_scale_factor_user_data_key,
852 (void *) (uintptr_t) scale_factor,
853 nullptr);
854 }
855
856 /**
857 * hb_cairo_font_face_get_scale_factor:
858 * @font_face: a #cairo_font_face_t
859 *
860 * Gets the scale factor set on the @font_face. Defaults to zero.
861 * See hb_cairo_font_face_set_scale_factor() for details.
862 *
863 * Returns: the scale factor of @font_face
864 *
865 * Since: 7.0.0
866 */
867 unsigned int
hb_cairo_font_face_get_scale_factor(cairo_font_face_t * font_face)868 hb_cairo_font_face_get_scale_factor (cairo_font_face_t *font_face)
869 {
870 return (unsigned int) (uintptr_t)
871 cairo_font_face_get_user_data (font_face,
872 &hb_cairo_scale_factor_user_data_key);
873 }
874
875
876 /**
877 * hb_cairo_glyphs_from_buffer:
878 * @buffer: a #hb_buffer_t containing glyphs
879 * @utf8_clusters: `true` if @buffer clusters are in bytes, instead of characters
880 * @x_scale_factor: scale factor to divide #hb_position_t Y values by
881 * @y_scale_factor: scale factor to divide #hb_position_t X values by
882 * @x: X position to place first glyph
883 * @y: Y position to place first glyph
884 * @utf8: (nullable): the text that was shaped in @buffer
885 * @utf8_len: the length of @utf8 in bytes
886 * @glyphs: (out): return location for an array of #cairo_glyph_t
887 * @num_glyphs: (inout): return location for the length of @glyphs
888 * @clusters: (out) (nullable): return location for an array of cluster positions
889 * @num_clusters: (inout) (nullable): return location for the length of @clusters
890 * @cluster_flags: (out) (nullable): return location for cluster flags
891 *
892 * Extracts information from @buffer in a form that can be
893 * passed to cairo_show_text_glyphs() or cairo_show_glyphs().
894 * This API is modeled after cairo_scaled_font_text_to_glyphs() and
895 * cairo_user_scaled_font_text_to_glyphs_func_t.
896 *
897 * The @num_glyphs argument should be preset to the number of glyph entries available
898 * in the @glyphs buffer. If the @glyphs buffer is `NULL`, the value of
899 * @num_glyphs must be zero. If the provided glyph array is too short for
900 * the conversion (or for convenience), a new glyph array may be allocated
901 * using cairo_glyph_allocate() and placed in @glyphs. Upon return,
902 * @num_glyphs should contain the number of generated glyphs. If the value
903 * @glyphs points at has changed after the call, the caller will free the
904 * allocated glyph array using cairo_glyph_free(). The caller will also free
905 * the original value of @glyphs, so this function shouldn't do so.
906 *
907 * If @clusters is not `NULL`, then @num_clusters and @cluster_flags
908 * should not be either, and @utf8 must be provided, and cluster
909 * mapping will be computed. The semantics of how
910 * cluster array allocation works is similar to the glyph array. That is,
911 * if @clusters initially points to a non-`NULL` value, that array may be used
912 * as a cluster buffer, and @num_clusters points to the number of cluster
913 * entries available there. If the provided cluster array is too short for
914 * the conversion (or for convenience), a new cluster array may be allocated
915 * using cairo_text_cluster_allocate() and placed in @clusters. In this case,
916 * the original value of @clusters will still be freed by the caller. Upon
917 * return, @num_clusters will contain the number of generated clusters.
918 * If the value @clusters points at has changed after the call, the caller
919 * will free the allocated cluster array using cairo_text_cluster_free().
920 *
921 * See hb_cairo_font_face_set_scale_factor() for the details of
922 * the @scale_factor argument.
923 *
924 * The returned @glyphs vector actually has `@num_glyphs + 1` entries in
925 * it and the x,y values of the extra entry at the end add up the advance
926 * x,y of all the glyphs in the @buffer.
927 *
928 * Since: 7.0.0
929 */
930 void
hb_cairo_glyphs_from_buffer(hb_buffer_t * buffer,hb_bool_t utf8_clusters,double x_scale_factor,double y_scale_factor,double x,double y,const char * utf8,int utf8_len,cairo_glyph_t ** glyphs,unsigned int * num_glyphs,cairo_text_cluster_t ** clusters,unsigned int * num_clusters,cairo_text_cluster_flags_t * cluster_flags)931 hb_cairo_glyphs_from_buffer (hb_buffer_t *buffer,
932 hb_bool_t utf8_clusters,
933 double x_scale_factor,
934 double y_scale_factor,
935 double x,
936 double y,
937 const char *utf8,
938 int utf8_len,
939 cairo_glyph_t **glyphs,
940 unsigned int *num_glyphs,
941 cairo_text_cluster_t **clusters,
942 unsigned int *num_clusters,
943 cairo_text_cluster_flags_t *cluster_flags)
944 {
945 if (utf8 && utf8_len < 0)
946 utf8_len = strlen (utf8);
947
948 unsigned orig_num_glyphs = *num_glyphs;
949 *num_glyphs = hb_buffer_get_length (buffer);
950 hb_glyph_info_t *hb_glyph = hb_buffer_get_glyph_infos (buffer, nullptr);
951 hb_glyph_position_t *hb_position = hb_buffer_get_glyph_positions (buffer, nullptr);
952 if (orig_num_glyphs < *num_glyphs + 1)
953 *glyphs = cairo_glyph_allocate (*num_glyphs + 1);
954
955 if (clusters && utf8)
956 {
957 unsigned orig_num_clusters = *num_clusters;
958 *num_clusters = *num_glyphs ? 1 : 0;
959 for (unsigned int i = 1; i < *num_glyphs; i++)
960 if (hb_glyph[i].cluster != hb_glyph[i-1].cluster)
961 (*num_clusters)++;
962 if (orig_num_clusters < *num_clusters)
963 *clusters = cairo_text_cluster_allocate (*num_clusters);
964 }
965
966 double x_scale = x_scale_factor ? 1. / x_scale_factor : 0.;
967 double y_scale = y_scale_factor ? 1. / y_scale_factor : 0.;
968 hb_position_t hx = 0, hy = 0;
969 int i;
970 for (i = 0; i < (int) *num_glyphs; i++)
971 {
972 (*glyphs)[i].index = hb_glyph[i].codepoint;
973 (*glyphs)[i].x = x + (+hb_position->x_offset + hx) * x_scale;
974 (*glyphs)[i].y = y + (-hb_position->y_offset + hy) * y_scale;
975 hx += hb_position->x_advance;
976 hy += -hb_position->y_advance;
977
978 hb_position++;
979 }
980 (*glyphs)[i].index = -1;
981 (*glyphs)[i].x = round (hx * x_scale);
982 (*glyphs)[i].y = round (hy * y_scale);
983
984 if (clusters && *num_clusters && utf8)
985 {
986 hb_memset ((void *) *clusters, 0, *num_clusters * sizeof ((*clusters)[0]));
987 hb_bool_t backward = HB_DIRECTION_IS_BACKWARD (hb_buffer_get_direction (buffer));
988 *cluster_flags = backward ? CAIRO_TEXT_CLUSTER_FLAG_BACKWARD : (cairo_text_cluster_flags_t) 0;
989 unsigned int cluster = 0;
990 const char *start = utf8, *end;
991 (*clusters)[cluster].num_glyphs++;
992 if (backward)
993 {
994 for (i = *num_glyphs - 2; i >= 0; i--)
995 {
996 if (hb_glyph[i].cluster != hb_glyph[i+1].cluster)
997 {
998 assert (hb_glyph[i].cluster > hb_glyph[i+1].cluster);
999 if (utf8_clusters)
1000 end = start + hb_glyph[i].cluster - hb_glyph[i+1].cluster;
1001 else
1002 end = (const char *) hb_utf_offset_to_pointer<hb_utf8_t> ((const uint8_t *) start,
1003 (signed) (hb_glyph[i].cluster - hb_glyph[i+1].cluster));
1004 (*clusters)[cluster].num_bytes = end - start;
1005 start = end;
1006 cluster++;
1007 }
1008 (*clusters)[cluster].num_glyphs++;
1009 }
1010 (*clusters)[cluster].num_bytes = utf8 + utf8_len - start;
1011 }
1012 else
1013 {
1014 for (i = 1; i < (int) *num_glyphs; i++)
1015 {
1016 if (hb_glyph[i].cluster != hb_glyph[i-1].cluster)
1017 {
1018 assert (hb_glyph[i].cluster > hb_glyph[i-1].cluster);
1019 if (utf8_clusters)
1020 end = start + hb_glyph[i].cluster - hb_glyph[i-1].cluster;
1021 else
1022 end = (const char *) hb_utf_offset_to_pointer<hb_utf8_t> ((const uint8_t *) start,
1023 (signed) (hb_glyph[i].cluster - hb_glyph[i-1].cluster));
1024 (*clusters)[cluster].num_bytes = end - start;
1025 start = end;
1026 cluster++;
1027 }
1028 (*clusters)[cluster].num_glyphs++;
1029 }
1030 (*clusters)[cluster].num_bytes = utf8 + utf8_len - start;
1031 }
1032 }
1033 else if (num_clusters)
1034 *num_clusters = 0;
1035 }
1036
1037 #endif
1038