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