tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

hb-cairo.cc (33285B)


      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 
    208  hb_font_draw_glyph (font, glyph, hb_cairo_draw_get_funcs (), cr);
    209 
    210  cairo_close_path (cr);
    211  cairo_clip (cr);
    212 }
    213 
    214 static void
    215 hb_cairo_push_clip_rectangle (hb_paint_funcs_t *pfuncs HB_UNUSED,
    216 		      void *paint_data,
    217 		      float xmin, float ymin, float xmax, float ymax,
    218 		      void *user_data HB_UNUSED)
    219 {
    220  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
    221  cairo_t *cr = c->cr;
    222 
    223  cairo_save (cr);
    224  cairo_rectangle (cr,
    225                   (double) xmin, (double) ymin,
    226                   (double) (xmax - xmin), (double) (ymax - ymin));
    227  cairo_clip (cr);
    228 }
    229 
    230 static void
    231 hb_cairo_pop_clip (hb_paint_funcs_t *pfuncs HB_UNUSED,
    232 	   void *paint_data,
    233 	   void *user_data HB_UNUSED)
    234 {
    235  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
    236  cairo_t *cr = c->cr;
    237 
    238  cairo_restore (cr);
    239 }
    240 
    241 static void
    242 hb_cairo_push_group (hb_paint_funcs_t *pfuncs HB_UNUSED,
    243 	     void *paint_data,
    244 	     void *user_data HB_UNUSED)
    245 {
    246  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
    247  cairo_t *cr = c->cr;
    248 
    249  cairo_save (cr);
    250  cairo_push_group (cr);
    251 }
    252 
    253 static void
    254 hb_cairo_pop_group (hb_paint_funcs_t *pfuncs HB_UNUSED,
    255 	    void *paint_data,
    256 	    hb_paint_composite_mode_t mode,
    257 	    void *user_data HB_UNUSED)
    258 {
    259  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
    260  cairo_t *cr = c->cr;
    261 
    262  cairo_pop_group_to_source (cr);
    263  cairo_set_operator (cr, _hb_paint_composite_mode_to_cairo (mode));
    264  cairo_paint (cr);
    265 
    266  cairo_restore (cr);
    267 }
    268 
    269 static void
    270 hb_cairo_paint_color (hb_paint_funcs_t *pfuncs HB_UNUSED,
    271 	      void *paint_data,
    272 	      hb_bool_t use_foreground,
    273 	      hb_color_t color,
    274 	      void *user_data HB_UNUSED)
    275 {
    276  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
    277  cairo_t *cr = c->cr;
    278 
    279  if (use_foreground)
    280  {
    281 #ifdef HAVE_CAIRO_USER_SCALED_FONT_GET_FOREGROUND_SOURCE
    282    double r, g, b, a;
    283    cairo_pattern_t *foreground = cairo_user_scaled_font_get_foreground_source (c->scaled_font);
    284    if (cairo_pattern_get_rgba (foreground, &r, &g, &b, &a) == CAIRO_STATUS_SUCCESS)
    285      cairo_set_source_rgba (cr, r, g, b, a * hb_color_get_alpha (color) / 255.);
    286    else
    287 #endif
    288      cairo_set_source_rgba (cr, 0, 0, 0, hb_color_get_alpha (color) / 255.);
    289  }
    290  else
    291    cairo_set_source_rgba (cr,
    292 		   hb_color_get_red (color) / 255.,
    293 		   hb_color_get_green (color) / 255.,
    294 		   hb_color_get_blue (color) / 255.,
    295 		   hb_color_get_alpha (color) / 255.);
    296  cairo_paint (cr);
    297 }
    298 
    299 static hb_bool_t
    300 hb_cairo_paint_image (hb_paint_funcs_t *pfuncs HB_UNUSED,
    301 	      void *paint_data,
    302 	      hb_blob_t *blob,
    303 	      unsigned width,
    304 	      unsigned height,
    305 	      hb_tag_t format,
    306 	      float slant,
    307 	      hb_glyph_extents_t *extents,
    308 	      void *user_data HB_UNUSED)
    309 {
    310  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
    311 
    312  return _hb_cairo_paint_glyph_image (c, blob, width, height, format, slant, extents);
    313 }
    314 
    315 static void
    316 hb_cairo_paint_linear_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED,
    317 			void *paint_data,
    318 			hb_color_line_t *color_line,
    319 			float x0, float y0,
    320 			float x1, float y1,
    321 			float x2, float y2,
    322 			void *user_data HB_UNUSED)
    323 {
    324  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
    325 
    326  _hb_cairo_paint_linear_gradient (c, color_line, x0, y0, x1, y1, x2, y2);
    327 }
    328 
    329 static void
    330 hb_cairo_paint_radial_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED,
    331 			void *paint_data,
    332 			hb_color_line_t *color_line,
    333 			float x0, float y0, float r0,
    334 			float x1, float y1, float r1,
    335 			void *user_data HB_UNUSED)
    336 {
    337  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
    338 
    339  _hb_cairo_paint_radial_gradient (c, color_line, x0, y0, r0, x1, y1, r1);
    340 }
    341 
    342 static void
    343 hb_cairo_paint_sweep_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED,
    344 		       void *paint_data,
    345 		       hb_color_line_t *color_line,
    346 		       float x0, float y0,
    347 		       float start_angle, float end_angle,
    348 		       void *user_data HB_UNUSED)
    349 {
    350  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
    351 
    352  _hb_cairo_paint_sweep_gradient (c, color_line, x0, y0, start_angle, end_angle);
    353 }
    354 
    355 static const cairo_user_data_key_t color_cache_key = {0};
    356 
    357 static void
    358 _hb_cairo_destroy_map (void *p)
    359 {
    360  hb_map_destroy ((hb_map_t *) p);
    361 }
    362 
    363 static hb_bool_t
    364 hb_cairo_paint_custom_palette_color (hb_paint_funcs_t *funcs,
    365                                     void *paint_data,
    366                                     unsigned int color_index,
    367                                     hb_color_t *color,
    368                                     void *user_data HB_UNUSED)
    369 {
    370 #ifdef HAVE_CAIRO_FONT_OPTIONS_GET_CUSTOM_PALETTE_COLOR
    371  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
    372  cairo_t *cr = c->cr;
    373 
    374 #define HB_DEADBEEF HB_TAG(0xDE,0xAD,0xBE,0xEF)
    375 
    376  hb_map_t *color_cache = c->color_cache;
    377  hb_codepoint_t *v;
    378  if (likely (color_cache && color_cache->has (color_index, &v)))
    379  {
    380    if (*v == HB_DEADBEEF)
    381      return false;
    382    *color = *v;
    383    return true;
    384  }
    385 
    386  cairo_font_options_t *options;
    387  double red, green, blue, alpha;
    388 
    389  options = cairo_font_options_create ();
    390  cairo_get_font_options (cr, options);
    391  if (CAIRO_STATUS_SUCCESS ==
    392      cairo_font_options_get_custom_palette_color (options, color_index,
    393                                                   &red, &green, &blue, &alpha))
    394  {
    395    cairo_font_options_destroy (options);
    396    *color = HB_COLOR (round (255 * blue),
    397 	       round (255 * green),
    398 	       round (255 * red),
    399 	       round (255 * alpha));
    400 
    401    if (likely (color_cache && *color != HB_DEADBEEF))
    402      color_cache->set (color_index, *color);
    403 
    404    return true;
    405  }
    406  cairo_font_options_destroy (options);
    407 
    408  if (likely (color_cache))
    409    color_cache->set (color_index, HB_DEADBEEF);
    410 
    411 #undef HB_DEADBEEF
    412 
    413 #endif
    414 
    415  return false;
    416 }
    417 
    418 static inline void free_static_cairo_paint_funcs ();
    419 
    420 static struct hb_cairo_paint_funcs_lazy_loader_t : hb_paint_funcs_lazy_loader_t<hb_cairo_paint_funcs_lazy_loader_t>
    421 {
    422  static hb_paint_funcs_t *create ()
    423  {
    424    hb_paint_funcs_t *funcs = hb_paint_funcs_create ();
    425 
    426    hb_paint_funcs_set_push_transform_func (funcs, hb_cairo_push_transform, nullptr, nullptr);
    427    hb_paint_funcs_set_pop_transform_func (funcs, hb_cairo_pop_transform, nullptr, nullptr);
    428    hb_paint_funcs_set_color_glyph_func (funcs, hb_cairo_paint_color_glyph, nullptr, nullptr);
    429    hb_paint_funcs_set_push_clip_glyph_func (funcs, hb_cairo_push_clip_glyph, nullptr, nullptr);
    430    hb_paint_funcs_set_push_clip_rectangle_func (funcs, hb_cairo_push_clip_rectangle, nullptr, nullptr);
    431    hb_paint_funcs_set_pop_clip_func (funcs, hb_cairo_pop_clip, nullptr, nullptr);
    432    hb_paint_funcs_set_push_group_func (funcs, hb_cairo_push_group, nullptr, nullptr);
    433    hb_paint_funcs_set_pop_group_func (funcs, hb_cairo_pop_group, nullptr, nullptr);
    434    hb_paint_funcs_set_color_func (funcs, hb_cairo_paint_color, nullptr, nullptr);
    435    hb_paint_funcs_set_image_func (funcs, hb_cairo_paint_image, nullptr, nullptr);
    436    hb_paint_funcs_set_linear_gradient_func (funcs, hb_cairo_paint_linear_gradient, nullptr, nullptr);
    437    hb_paint_funcs_set_radial_gradient_func (funcs, hb_cairo_paint_radial_gradient, nullptr, nullptr);
    438    hb_paint_funcs_set_sweep_gradient_func (funcs, hb_cairo_paint_sweep_gradient, nullptr, nullptr);
    439    hb_paint_funcs_set_custom_palette_color_func (funcs, hb_cairo_paint_custom_palette_color, nullptr, nullptr);
    440 
    441    hb_paint_funcs_make_immutable (funcs);
    442 
    443    hb_atexit (free_static_cairo_paint_funcs);
    444 
    445    return funcs;
    446  }
    447 } static_cairo_paint_funcs;
    448 
    449 static inline
    450 void free_static_cairo_paint_funcs ()
    451 {
    452  static_cairo_paint_funcs.free_instance ();
    453 }
    454 
    455 static hb_paint_funcs_t *
    456 hb_cairo_paint_get_funcs ()
    457 {
    458  return static_cairo_paint_funcs.get_unconst ();
    459 }
    460 #endif
    461 
    462 static const cairo_user_data_key_t hb_cairo_face_user_data_key = {0};
    463 static const cairo_user_data_key_t hb_cairo_font_user_data_key = {0};
    464 static const cairo_user_data_key_t hb_cairo_font_init_func_user_data_key = {0};
    465 static const cairo_user_data_key_t hb_cairo_font_init_user_data_user_data_key = {0};
    466 static const cairo_user_data_key_t hb_cairo_scale_factor_user_data_key = {0};
    467 
    468 static void hb_cairo_face_destroy (void *p) { hb_face_destroy ((hb_face_t *) p); }
    469 static void hb_cairo_font_destroy (void *p) { hb_font_destroy ((hb_font_t *) p); }
    470 
    471 static cairo_status_t
    472 hb_cairo_init_scaled_font (cairo_scaled_font_t  *scaled_font,
    473 		   cairo_t              *cr HB_UNUSED,
    474 		   cairo_font_extents_t *extents)
    475 {
    476  cairo_font_face_t *font_face = cairo_scaled_font_get_font_face (scaled_font);
    477 
    478  hb_font_t *font = (hb_font_t *) cairo_font_face_get_user_data (font_face,
    479 							 &hb_cairo_font_user_data_key);
    480 
    481  if (!font)
    482  {
    483    hb_face_t *face = (hb_face_t *) cairo_font_face_get_user_data (font_face,
    484 							   &hb_cairo_face_user_data_key);
    485    font = hb_font_create (face);
    486 
    487 #if !defined(HB_NO_VAR) && CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,16,0)
    488    cairo_font_options_t *font_options = cairo_font_options_create ();
    489 
    490    // Set variations
    491    cairo_scaled_font_get_font_options (scaled_font, font_options);
    492    const char *variations = cairo_font_options_get_variations (font_options);
    493    hb_vector_t<hb_variation_t> vars;
    494    const char *p = variations;
    495    while (p && *p)
    496    {
    497      const char *end = strpbrk ((char *) p, ", ");
    498      hb_variation_t var;
    499      if (hb_variation_from_string (p, end ? end - p : -1, &var))
    500 vars.push (var);
    501      p = end ? end + 1 : nullptr;
    502    }
    503    hb_font_set_variations (font, &vars[0], vars.length);
    504 
    505    cairo_font_options_destroy (font_options);
    506 #endif
    507 
    508    // Set scale; Note: should NOT set slant, or we'll double-slant.
    509    unsigned scale_factor = hb_cairo_font_face_get_scale_factor (font_face);
    510    if (scale_factor)
    511    {
    512      cairo_matrix_t font_matrix;
    513      cairo_scaled_font_get_scale_matrix (scaled_font, &font_matrix);
    514      hb_font_set_scale (font,
    515 		 round (font_matrix.xx * scale_factor),
    516 		 round (font_matrix.yy * scale_factor));
    517    }
    518 
    519    auto *init_func = (hb_cairo_font_init_func_t)
    520 	      cairo_font_face_get_user_data (font_face,
    521 					     &hb_cairo_font_init_func_user_data_key);
    522    if (init_func)
    523    {
    524      void *user_data = cairo_font_face_get_user_data (font_face,
    525 					       &hb_cairo_font_init_user_data_user_data_key);
    526      font = init_func (font, scaled_font, user_data);
    527    }
    528 
    529    hb_font_make_immutable (font);
    530  }
    531 
    532  cairo_scaled_font_set_user_data (scaled_font,
    533 			   &hb_cairo_font_user_data_key,
    534 			   (void *) hb_font_reference (font),
    535 			   hb_cairo_font_destroy);
    536 
    537  hb_position_t x_scale, y_scale;
    538  hb_font_get_scale (font, &x_scale, &y_scale);
    539 
    540  hb_font_extents_t hb_extents;
    541  hb_font_get_h_extents (font, &hb_extents);
    542 
    543  extents->ascent  = (double)  hb_extents.ascender  / y_scale;
    544  extents->descent = (double) -hb_extents.descender / y_scale;
    545  extents->height  = extents->ascent + extents->descent;
    546 
    547 #ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC
    548  hb_map_t *color_cache = hb_map_create ();
    549  if (unlikely (CAIRO_STATUS_SUCCESS != cairo_scaled_font_set_user_data (scaled_font,
    550 								 &color_cache_key,
    551 								 color_cache,
    552 								 _hb_cairo_destroy_map)))
    553    hb_map_destroy (color_cache);
    554 #endif
    555 
    556  return CAIRO_STATUS_SUCCESS;
    557 }
    558 
    559 static cairo_status_t
    560 hb_cairo_text_to_glyphs (cairo_scaled_font_t        *scaled_font,
    561 		 const char	            *utf8,
    562 		 int		             utf8_len,
    563 		 cairo_glyph_t	           **glyphs,
    564 		 int		            *num_glyphs,
    565 		 cairo_text_cluster_t      **clusters,
    566 		 int		            *num_clusters,
    567 		 cairo_text_cluster_flags_t *cluster_flags)
    568 {
    569  hb_font_t *font = (hb_font_t *) cairo_scaled_font_get_user_data (scaled_font,
    570 							   &hb_cairo_font_user_data_key);
    571 
    572  hb_buffer_t *buffer = hb_buffer_create ();
    573  hb_buffer_add_utf8 (buffer, utf8, utf8_len, 0, utf8_len);
    574  hb_buffer_guess_segment_properties (buffer);
    575  hb_shape (font, buffer, nullptr, 0);
    576 
    577  int x_scale, y_scale;
    578  hb_font_get_scale (font, &x_scale, &y_scale);
    579 
    580  hb_cairo_glyphs_from_buffer (buffer,
    581 		       true,
    582 		       x_scale, y_scale,
    583 		       0., 0.,
    584 		       utf8, utf8_len,
    585 		       glyphs, (unsigned *) num_glyphs,
    586 		       clusters, (unsigned *) num_clusters,
    587 		       cluster_flags);
    588 
    589  hb_buffer_destroy (buffer);
    590 
    591  return CAIRO_STATUS_SUCCESS;
    592 }
    593 
    594 static cairo_status_t
    595 hb_cairo_render_glyph (cairo_scaled_font_t  *scaled_font,
    596 	       unsigned long         glyph,
    597 	       cairo_t              *cr,
    598 	       cairo_text_extents_t *extents)
    599 {
    600  hb_font_t *font = (hb_font_t *) cairo_scaled_font_get_user_data (scaled_font,
    601 							   &hb_cairo_font_user_data_key);
    602 
    603  hb_position_t x_scale, y_scale;
    604  hb_font_get_scale (font, &x_scale, &y_scale);
    605  cairo_scale (cr,
    606        +1. / (x_scale ? x_scale : 1),
    607        -1. / (y_scale ? y_scale : 1));
    608 
    609  if (hb_font_draw_glyph_or_fail (font, glyph, hb_cairo_draw_get_funcs (), cr))
    610    cairo_fill (cr);
    611 
    612  // If draw fails, we still return SUCCESS, as we want empty drawing, not
    613  // setting the cairo object into error.
    614  return CAIRO_STATUS_SUCCESS;
    615 }
    616 
    617 #ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC
    618 
    619 static cairo_status_t
    620 hb_cairo_render_color_glyph (cairo_scaled_font_t  *scaled_font,
    621 		     unsigned long         glyph,
    622 		     cairo_t              *cr,
    623 		     cairo_text_extents_t *extents)
    624 {
    625  hb_font_t *font = (hb_font_t *) cairo_scaled_font_get_user_data (scaled_font,
    626 							   &hb_cairo_font_user_data_key);
    627 
    628  unsigned int palette = 0;
    629 #ifdef CAIRO_COLOR_PALETTE_DEFAULT
    630  cairo_font_options_t *options = cairo_font_options_create ();
    631  cairo_scaled_font_get_font_options (scaled_font, options);
    632  palette = cairo_font_options_get_color_palette (options);
    633  cairo_font_options_destroy (options);
    634 #endif
    635 
    636  hb_color_t color = HB_COLOR (0, 0, 0, 255);
    637  hb_position_t x_scale, y_scale;
    638  hb_font_get_scale (font, &x_scale, &y_scale);
    639  cairo_scale (cr,
    640        +1. / (x_scale ? x_scale : 1),
    641        -1. / (y_scale ? y_scale : 1));
    642 
    643  hb_cairo_context_t c;
    644  c.scaled_font = scaled_font;
    645  c.cr = cr;
    646  c.color_cache = (hb_map_t *) cairo_scaled_font_get_user_data (scaled_font, &color_cache_key);
    647 
    648  if (!hb_font_paint_glyph_or_fail (font, glyph, hb_cairo_paint_get_funcs (), &c, palette, color))
    649    return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
    650 
    651  return CAIRO_STATUS_SUCCESS;
    652 }
    653 
    654 #endif
    655 
    656 static cairo_font_face_t *
    657 user_font_face_create (hb_face_t *face)
    658 {
    659  cairo_font_face_t *cairo_face;
    660 
    661  cairo_face = cairo_user_font_face_create ();
    662  cairo_user_font_face_set_init_func (cairo_face, hb_cairo_init_scaled_font);
    663  cairo_user_font_face_set_text_to_glyphs_func (cairo_face, hb_cairo_text_to_glyphs);
    664  cairo_user_font_face_set_render_glyph_func (cairo_face, hb_cairo_render_glyph);
    665 #ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC
    666  cairo_user_font_face_set_render_color_glyph_func (cairo_face, hb_cairo_render_color_glyph);
    667 #endif
    668 
    669  if (unlikely (CAIRO_STATUS_SUCCESS != cairo_font_face_set_user_data (cairo_face,
    670 							       &hb_cairo_face_user_data_key,
    671 							       (void *) hb_face_reference (face),
    672 							       hb_cairo_face_destroy)))
    673    hb_face_destroy (face);
    674 
    675  return cairo_face;
    676 }
    677 
    678 /**
    679 * hb_cairo_font_face_create_for_font:
    680 * @font: a #hb_font_t
    681 *
    682 * Creates a #cairo_font_face_t for rendering text according
    683 * to @font.
    684 *
    685 * Note that the scale of @font does not affect the rendering,
    686 * but the variations and slant that are set on @font do.
    687 *
    688 * Returns: (transfer full): a newly created #cairo_font_face_t
    689 *
    690 * Since: 7.0.0
    691 */
    692 cairo_font_face_t *
    693 hb_cairo_font_face_create_for_font (hb_font_t *font)
    694 {
    695  hb_font_make_immutable (font);
    696 
    697  auto *hb_face = hb_font_get_face (font);
    698  auto *cairo_face =  user_font_face_create (hb_face);
    699 
    700  if (unlikely (CAIRO_STATUS_SUCCESS != cairo_font_face_set_user_data (cairo_face,
    701 							       &hb_cairo_font_user_data_key,
    702 							       (void *) hb_font_reference (font),
    703 							       hb_cairo_font_destroy)))
    704    hb_font_destroy (font);
    705 
    706  return cairo_face;
    707 }
    708 
    709 /**
    710 * hb_cairo_font_face_get_font:
    711 * @font_face: a #cairo_font_face_t
    712 *
    713 * Gets the #hb_font_t that @font_face was created from.
    714 *
    715 * Returns: (nullable) (transfer none): the #hb_font_t that @font_face was created from
    716 *
    717 * Since: 7.0.0
    718 */
    719 hb_font_t *
    720 hb_cairo_font_face_get_font (cairo_font_face_t *font_face)
    721 {
    722  return (hb_font_t *) cairo_font_face_get_user_data (font_face,
    723 					      &hb_cairo_font_user_data_key);
    724 }
    725 
    726 /**
    727 * hb_cairo_font_face_create_for_face:
    728 * @face: a #hb_face_t
    729 *
    730 * Creates a #cairo_font_face_t for rendering text according
    731 * to @face.
    732 *
    733 * Returns: (transfer full): a newly created #cairo_font_face_t
    734 *
    735 * Since: 7.0.0
    736 */
    737 cairo_font_face_t *
    738 hb_cairo_font_face_create_for_face (hb_face_t *face)
    739 {
    740  hb_face_make_immutable (face);
    741 
    742  return user_font_face_create (face);
    743 }
    744 
    745 /**
    746 * hb_cairo_font_face_get_face:
    747 * @font_face: a #cairo_font_face_t
    748 *
    749 * Gets the #hb_face_t associated with @font_face.
    750 *
    751 * Returns: (nullable) (transfer none): the #hb_face_t associated with @font_face
    752 *
    753 * Since: 7.0.0
    754 */
    755 hb_face_t *
    756 hb_cairo_font_face_get_face (cairo_font_face_t *font_face)
    757 {
    758  return (hb_face_t *) cairo_font_face_get_user_data (font_face,
    759 					      &hb_cairo_face_user_data_key);
    760 }
    761 
    762 /**
    763 * hb_cairo_font_face_set_font_init_func:
    764 * @font_face: a #cairo_font_face_t
    765 * @func: The virtual method to use
    766 * @user_data: user data accompanying the method
    767 * @destroy: function to call when @user_data is not needed anymore
    768 *
    769 * Set the virtual method to be called when a cairo
    770 * face created using hb_cairo_font_face_create_for_face()
    771 * creates an #hb_font_t for a #cairo_scaled_font_t.
    772 *
    773 * Since: 7.0.0
    774 */
    775 void
    776 hb_cairo_font_face_set_font_init_func (cairo_font_face_t *font_face,
    777 			       hb_cairo_font_init_func_t func,
    778 			       void *user_data,
    779 			       hb_destroy_func_t destroy)
    780 {
    781  cairo_font_face_set_user_data (font_face,
    782 			 &hb_cairo_font_init_func_user_data_key,
    783 			 (void *) func,
    784 			 nullptr);
    785  if (unlikely (CAIRO_STATUS_SUCCESS != cairo_font_face_set_user_data (font_face,
    786 							       &hb_cairo_font_init_user_data_user_data_key,
    787 							       (void *) user_data,
    788 							       destroy)) && destroy)
    789  {
    790    destroy (user_data);
    791    cairo_font_face_set_user_data (font_face,
    792 			   &hb_cairo_font_init_func_user_data_key,
    793 			   nullptr,
    794 			   nullptr);
    795  }
    796 }
    797 
    798 /**
    799 * hb_cairo_scaled_font_get_font:
    800 * @scaled_font: a #cairo_scaled_font_t
    801 *
    802 * Gets the #hb_font_t associated with @scaled_font.
    803 *
    804 * Returns: (nullable) (transfer none): the #hb_font_t associated with @scaled_font
    805 *
    806 * Since: 7.0.0
    807 */
    808 hb_font_t *
    809 hb_cairo_scaled_font_get_font (cairo_scaled_font_t *scaled_font)
    810 {
    811  return (hb_font_t *) cairo_scaled_font_get_user_data (scaled_font, &hb_cairo_font_user_data_key);
    812 }
    813 
    814 
    815 /**
    816 * hb_cairo_font_face_set_scale_factor:
    817 * @scale_factor: The scale factor to use. See below
    818 * @font_face: a #cairo_font_face_t
    819 *
    820 * Sets the scale factor of the @font_face. Default scale
    821 * factor is zero.
    822 *
    823 * When a #cairo_font_face_t is created from a #hb_face_t using
    824 * hb_cairo_font_face_create_for_face(), such face will create
    825 * #hb_font_t objects during scaled-font creation.  The scale
    826 * factor defines how the scale set on such #hb_font_t objects
    827 * relates to the font-matrix (as such font size) of the cairo
    828 * scaled-font.
    829 *
    830 * If the scale-factor is zero (default), then the scale of the
    831 * #hb_font_t object will be left at default, which is the UPEM
    832 * value of the respective #hb_face_t.
    833 *
    834 * If the scale-factor is set to non-zero, then the X and Y scale
    835 * of the #hb_font_t object will be respectively set to the
    836 * @scale_factor times the xx and yy elements of the scale-matrix
    837 * of the cairo scaled-font being created.
    838 *
    839 * When using the hb_cairo_glyphs_from_buffer() API to convert the
    840 * HarfBuzz glyph buffer that resulted from shaping with such a #hb_font_t,
    841 * if the scale-factor was non-zero, you can pass it directly to
    842 * that API as both X and Y scale factors.
    843 *
    844 * If the scale-factor was zero however, or the cairo face was
    845 * created using the alternative constructor
    846 * hb_cairo_font_face_create_for_font(), you need to calculate the
    847 * correct X/Y scale-factors to pass to hb_cairo_glyphs_from_buffer()
    848 * by dividing the #hb_font_t X/Y scale-factors by the
    849 * cairo scaled-font's scale-matrix XX/YY components respectively
    850 * and use those values.  Or if you know that relationship offhand
    851 * (because you set the scale of the #hb_font_t yourself), use
    852 * the conversion rate involved.
    853 *
    854 * Since: 7.0.0
    855 */
    856 void
    857 hb_cairo_font_face_set_scale_factor (cairo_font_face_t *font_face,
    858 			     unsigned int scale_factor)
    859 {
    860  cairo_font_face_set_user_data (font_face,
    861 			 &hb_cairo_scale_factor_user_data_key,
    862 			 (void *) (uintptr_t) scale_factor,
    863 			 nullptr);
    864 }
    865 
    866 /**
    867 * hb_cairo_font_face_get_scale_factor:
    868 * @font_face: a #cairo_font_face_t
    869 *
    870 * Gets the scale factor set on the @font_face. Defaults to zero.
    871 * See hb_cairo_font_face_set_scale_factor() for details.
    872 *
    873 * Returns: the scale factor of @font_face
    874 *
    875 * Since: 7.0.0
    876 */
    877 unsigned int
    878 hb_cairo_font_face_get_scale_factor (cairo_font_face_t *font_face)
    879 {
    880  return (unsigned int) (uintptr_t)
    881  cairo_font_face_get_user_data (font_face,
    882 				&hb_cairo_scale_factor_user_data_key);
    883 }
    884 
    885 
    886 /**
    887 * hb_cairo_glyphs_from_buffer:
    888 * @buffer: a #hb_buffer_t containing glyphs
    889 * @utf8_clusters: `true` if @buffer clusters are in bytes, instead of characters
    890 * @x_scale_factor: scale factor to divide #hb_position_t Y values by
    891 * @y_scale_factor: scale factor to divide #hb_position_t X values by
    892 * @x: X position to place first glyph
    893 * @y: Y position to place first glyph
    894 * @utf8: (nullable): the text that was shaped in @buffer
    895 * @utf8_len: the length of @utf8 in bytes
    896 * @glyphs: (out): return location for an array of #cairo_glyph_t
    897 * @num_glyphs: (inout): return location for the length of @glyphs
    898 * @clusters: (out) (nullable): return location for an array of cluster positions
    899 * @num_clusters: (inout) (nullable): return location for the length of @clusters
    900 * @cluster_flags: (out) (nullable): return location for cluster flags
    901 *
    902 * Extracts information from @buffer in a form that can be
    903 * passed to cairo_show_text_glyphs() or cairo_show_glyphs().
    904 * This API is modeled after cairo_scaled_font_text_to_glyphs() and
    905 * cairo_user_scaled_font_text_to_glyphs_func_t.
    906 *
    907 * The @num_glyphs argument should be preset to the number of glyph entries available
    908 * in the @glyphs buffer. If the @glyphs buffer is `NULL`, the value of
    909 * @num_glyphs must be zero.  If the provided glyph array is too short for
    910 * the conversion (or for convenience), a new glyph array may be allocated
    911 * using cairo_glyph_allocate() and placed in @glyphs.  Upon return,
    912 * @num_glyphs should contain the number of generated glyphs.  If the value
    913 * @glyphs points at has changed after the call, the caller will free the
    914 * allocated glyph array using cairo_glyph_free().  The caller will also free
    915 * the original value of @glyphs, so this function shouldn't do so.
    916 *
    917 * If @clusters is not `NULL`, then @num_clusters and @cluster_flags
    918 * should not be either, and @utf8 must be provided, and cluster
    919 * mapping will be computed. The semantics of how
    920 * cluster array allocation works is similar to the glyph array.  That is,
    921 * if @clusters initially points to a non-`NULL` value, that array may be used
    922 * as a cluster buffer, and @num_clusters points to the number of cluster
    923 * entries available there.  If the provided cluster array is too short for
    924 * the conversion (or for convenience), a new cluster array may be allocated
    925 * using cairo_text_cluster_allocate() and placed in @clusters.  In this case,
    926 * the original value of @clusters will still be freed by the caller.  Upon
    927 * return, @num_clusters will contain the number of generated clusters.
    928 * If the value @clusters points at has changed after the call, the caller
    929 * will free the allocated cluster array using cairo_text_cluster_free().
    930 *
    931 * See hb_cairo_font_face_set_scale_factor() for the details of
    932 * the @scale_factor argument.
    933 *
    934 * The returned @glyphs vector actually has `@num_glyphs + 1` entries in
    935 * it and the x,y values of the extra entry at the end add up the advance
    936 * x,y of all the glyphs in the @buffer.
    937 *
    938 * Since: 7.0.0
    939 */
    940 void
    941 hb_cairo_glyphs_from_buffer (hb_buffer_t *buffer,
    942 		     hb_bool_t utf8_clusters,
    943 		     double x_scale_factor,
    944 		     double y_scale_factor,
    945 		     double x,
    946 		     double y,
    947 		     const char *utf8,
    948 		     int utf8_len,
    949 		     cairo_glyph_t **glyphs,
    950 		     unsigned int *num_glyphs,
    951 		     cairo_text_cluster_t **clusters,
    952 		     unsigned int *num_clusters,
    953 		     cairo_text_cluster_flags_t *cluster_flags)
    954 {
    955  if (utf8 && utf8_len < 0)
    956    utf8_len = strlen (utf8);
    957 
    958  unsigned orig_num_glyphs = *num_glyphs;
    959  *num_glyphs = hb_buffer_get_length (buffer);
    960  hb_glyph_info_t *hb_glyph = hb_buffer_get_glyph_infos (buffer, nullptr);
    961  hb_glyph_position_t *hb_position = hb_buffer_get_glyph_positions (buffer, nullptr);
    962  if (orig_num_glyphs < *num_glyphs + 1)
    963    *glyphs = cairo_glyph_allocate (*num_glyphs + 1);
    964 
    965  if (clusters && utf8)
    966  {
    967    unsigned orig_num_clusters = *num_clusters;
    968    *num_clusters = *num_glyphs ? 1 : 0;
    969    for (unsigned int i = 1; i < *num_glyphs; i++)
    970      if (hb_glyph[i].cluster != hb_glyph[i-1].cluster)
    971 (*num_clusters)++;
    972    if (orig_num_clusters < *num_clusters)
    973      *clusters = cairo_text_cluster_allocate (*num_clusters);
    974  }
    975 
    976  double x_scale = x_scale_factor ? 1. / x_scale_factor : 0.;
    977  double y_scale = y_scale_factor ? 1. / y_scale_factor : 0.;
    978  hb_position_t hx = 0, hy = 0;
    979  int i;
    980  for (i = 0; i < (int) *num_glyphs; i++)
    981  {
    982    (*glyphs)[i].index = hb_glyph[i].codepoint;
    983    (*glyphs)[i].x = x + (+hb_position->x_offset + hx) * x_scale;
    984    (*glyphs)[i].y = y + (-hb_position->y_offset + hy) * y_scale;
    985    hx +=  hb_position->x_advance;
    986    hy += -hb_position->y_advance;
    987 
    988    hb_position++;
    989  }
    990  (*glyphs)[i].index = -1;
    991  (*glyphs)[i].x = round (hx * x_scale);
    992  (*glyphs)[i].y = round (hy * y_scale);
    993 
    994  if (clusters && *num_clusters && utf8)
    995  {
    996    hb_memset ((void *) *clusters, 0, *num_clusters * sizeof ((*clusters)[0]));
    997    hb_bool_t backward = HB_DIRECTION_IS_BACKWARD (hb_buffer_get_direction (buffer));
    998    *cluster_flags = backward ? CAIRO_TEXT_CLUSTER_FLAG_BACKWARD : (cairo_text_cluster_flags_t) 0;
    999    unsigned int cluster = 0;
   1000    const char *start = utf8, *end;
   1001    (*clusters)[cluster].num_glyphs++;
   1002    if (backward)
   1003    {
   1004      for (i = *num_glyphs - 2; i >= 0; i--)
   1005      {
   1006 if (hb_glyph[i].cluster != hb_glyph[i+1].cluster)
   1007 {
   1008   assert (hb_glyph[i].cluster > hb_glyph[i+1].cluster);
   1009   if (utf8_clusters)
   1010     end = start + hb_glyph[i].cluster - hb_glyph[i+1].cluster;
   1011   else
   1012     end = (const char *) hb_utf_offset_to_pointer<hb_utf8_t> ((const uint8_t *) start,
   1013 							      (const uint8_t *) utf8, utf8_len,
   1014 							      (signed) (hb_glyph[i].cluster - hb_glyph[i+1].cluster));
   1015   (*clusters)[cluster].num_bytes = end - start;
   1016   start = end;
   1017   cluster++;
   1018 }
   1019 (*clusters)[cluster].num_glyphs++;
   1020      }
   1021      (*clusters)[cluster].num_bytes = utf8 + utf8_len - start;
   1022    }
   1023    else
   1024    {
   1025      for (i = 1; i < (int) *num_glyphs; i++)
   1026      {
   1027 if (hb_glyph[i].cluster != hb_glyph[i-1].cluster)
   1028 {
   1029   assert (hb_glyph[i].cluster > hb_glyph[i-1].cluster);
   1030   if (utf8_clusters)
   1031     end = start + hb_glyph[i].cluster - hb_glyph[i-1].cluster;
   1032   else
   1033     end = (const char *) hb_utf_offset_to_pointer<hb_utf8_t> ((const uint8_t *) start,
   1034 							      (const uint8_t *) utf8, utf8_len,
   1035 							      (signed) (hb_glyph[i].cluster - hb_glyph[i-1].cluster));
   1036   (*clusters)[cluster].num_bytes = end - start;
   1037   start = end;
   1038   cluster++;
   1039 }
   1040 (*clusters)[cluster].num_glyphs++;
   1041      }
   1042      (*clusters)[cluster].num_bytes = utf8 + utf8_len - start;
   1043    }
   1044  }
   1045  else if (num_clusters)
   1046    *num_clusters = 0;
   1047 }
   1048 
   1049 #endif