Imported Upstream version 8.2.2
[platform/upstream/harfbuzz.git] / src / hb-cairo.cc
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
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
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
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
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 {
106   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
124 void free_static_cairo_draw_funcs ()
125 {
126   static_cairo_draw_funcs.free_instance ();
127 }
128
129 static hb_draw_funcs_t *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
356 _hb_cairo_destroy_map (void *p)
357 {
358   hb_map_destroy ((hb_map_t *) p);
359 }
360
361 static hb_bool_t
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 {
420   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
448 void free_static_cairo_paint_funcs ()
449 {
450   static_cairo_paint_funcs.free_instance ();
451 }
452
453 static hb_paint_funcs_t *
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
466 static void hb_cairo_face_destroy (void *p) { hb_face_destroy ((hb_face_t *) p); }
467 static void hb_cairo_font_destroy (void *p) { hb_font_destroy ((hb_font_t *) p); }
468
469 static cairo_status_t
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 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
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
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
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 *
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 *
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 *
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 *
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 *
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
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 *
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
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
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
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