hb-draw.cc (14346B)
1 /* 2 * Copyright © 2019-2020 Ebrahim Byagowi 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 25 #include "hb.hh" 26 27 #ifndef HB_NO_DRAW 28 29 #include "hb-draw.hh" 30 31 #include "hb-geometry.hh" 32 33 #include "hb-machinery.hh" 34 35 36 /** 37 * SECTION:hb-draw 38 * @title: hb-draw 39 * @short_description: Glyph drawing 40 * @include: hb.h 41 * 42 * Functions for drawing (extracting) glyph shapes. 43 * 44 * The #hb_draw_funcs_t struct can be used with hb_font_draw_glyph(). 45 **/ 46 47 static void 48 hb_draw_move_to_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED, 49 hb_draw_state_t *st HB_UNUSED, 50 float to_x HB_UNUSED, float to_y HB_UNUSED, 51 void *user_data HB_UNUSED) {} 52 53 static void 54 hb_draw_line_to_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED, 55 hb_draw_state_t *st HB_UNUSED, 56 float to_x HB_UNUSED, float to_y HB_UNUSED, 57 void *user_data HB_UNUSED) {} 58 59 static void 60 hb_draw_quadratic_to_nil (hb_draw_funcs_t *dfuncs, void *draw_data, 61 hb_draw_state_t *st, 62 float control_x, float control_y, 63 float to_x, float to_y, 64 void *user_data HB_UNUSED) 65 { 66 #define HB_TWO_THIRD 0.66666666666666666666666667f 67 dfuncs->emit_cubic_to (draw_data, *st, 68 st->current_x + (control_x - st->current_x) * HB_TWO_THIRD, 69 st->current_y + (control_y - st->current_y) * HB_TWO_THIRD, 70 to_x + (control_x - to_x) * HB_TWO_THIRD, 71 to_y + (control_y - to_y) * HB_TWO_THIRD, 72 to_x, to_y); 73 #undef HB_TWO_THIRD 74 } 75 76 static void 77 hb_draw_cubic_to_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED, 78 hb_draw_state_t *st HB_UNUSED, 79 float control1_x HB_UNUSED, float control1_y HB_UNUSED, 80 float control2_x HB_UNUSED, float control2_y HB_UNUSED, 81 float to_x HB_UNUSED, float to_y HB_UNUSED, 82 void *user_data HB_UNUSED) {} 83 84 static void 85 hb_draw_close_path_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED, 86 hb_draw_state_t *st HB_UNUSED, 87 void *user_data HB_UNUSED) {} 88 89 90 static bool 91 _hb_draw_funcs_set_preamble (hb_draw_funcs_t *dfuncs, 92 bool func_is_null, 93 void **user_data, 94 hb_destroy_func_t *destroy) 95 { 96 if (hb_object_is_immutable (dfuncs)) 97 { 98 if (*destroy) 99 (*destroy) (*user_data); 100 return false; 101 } 102 103 if (func_is_null) 104 { 105 if (*destroy) 106 (*destroy) (*user_data); 107 *destroy = nullptr; 108 *user_data = nullptr; 109 } 110 111 return true; 112 } 113 114 static bool 115 _hb_draw_funcs_set_middle (hb_draw_funcs_t *dfuncs, 116 void *user_data, 117 hb_destroy_func_t destroy) 118 { 119 if (user_data && !dfuncs->user_data) 120 { 121 dfuncs->user_data = (decltype (dfuncs->user_data)) hb_calloc (1, sizeof (*dfuncs->user_data)); 122 if (unlikely (!dfuncs->user_data)) 123 goto fail; 124 } 125 if (destroy && !dfuncs->destroy) 126 { 127 dfuncs->destroy = (decltype (dfuncs->destroy)) hb_calloc (1, sizeof (*dfuncs->destroy)); 128 if (unlikely (!dfuncs->destroy)) 129 goto fail; 130 } 131 132 return true; 133 134 fail: 135 if (destroy) 136 (destroy) (user_data); 137 return false; 138 } 139 140 #define HB_DRAW_FUNC_IMPLEMENT(name) \ 141 \ 142 void \ 143 hb_draw_funcs_set_##name##_func (hb_draw_funcs_t *dfuncs, \ 144 hb_draw_##name##_func_t func, \ 145 void *user_data, \ 146 hb_destroy_func_t destroy) \ 147 { \ 148 if (!_hb_draw_funcs_set_preamble (dfuncs, !func, &user_data, &destroy))\ 149 return; \ 150 \ 151 if (dfuncs->destroy && dfuncs->destroy->name) \ 152 dfuncs->destroy->name (!dfuncs->user_data ? nullptr : dfuncs->user_data->name); \ 153 \ 154 if (!_hb_draw_funcs_set_middle (dfuncs, user_data, destroy)) \ 155 return; \ 156 \ 157 if (func) \ 158 dfuncs->func.name = func; \ 159 else \ 160 dfuncs->func.name = hb_draw_##name##_nil; \ 161 \ 162 if (dfuncs->user_data) \ 163 dfuncs->user_data->name = user_data; \ 164 if (dfuncs->destroy) \ 165 dfuncs->destroy->name = destroy; \ 166 } 167 168 HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS 169 #undef HB_DRAW_FUNC_IMPLEMENT 170 171 /** 172 * hb_draw_funcs_create: 173 * 174 * Creates a new draw callbacks object. 175 * 176 * Return value: (transfer full): 177 * A newly allocated #hb_draw_funcs_t with a reference count of 1. The initial 178 * reference count should be released with hb_draw_funcs_destroy when you are 179 * done using the #hb_draw_funcs_t. This function never returns `NULL`. If 180 * memory cannot be allocated, a special singleton #hb_draw_funcs_t object will 181 * be returned. 182 * 183 * Since: 4.0.0 184 **/ 185 hb_draw_funcs_t * 186 hb_draw_funcs_create () 187 { 188 hb_draw_funcs_t *dfuncs; 189 if (unlikely (!(dfuncs = hb_object_create<hb_draw_funcs_t> ()))) 190 return const_cast<hb_draw_funcs_t *> (&Null (hb_draw_funcs_t)); 191 192 dfuncs->func = Null (hb_draw_funcs_t).func; 193 194 return dfuncs; 195 } 196 197 DEFINE_NULL_INSTANCE (hb_draw_funcs_t) = 198 { 199 HB_OBJECT_HEADER_STATIC, 200 201 { 202 #define HB_DRAW_FUNC_IMPLEMENT(name) hb_draw_##name##_nil, 203 HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS 204 #undef HB_DRAW_FUNC_IMPLEMENT 205 } 206 }; 207 208 /** 209 * hb_draw_funcs_get_empty: 210 * 211 * Fetches the singleton empty draw-functions structure. 212 * 213 * Return value: (transfer full): The empty draw-functions structure 214 * 215 * Since: 7.0.0 216 **/ 217 hb_draw_funcs_t * 218 hb_draw_funcs_get_empty () 219 { 220 return const_cast<hb_draw_funcs_t *> (&Null (hb_draw_funcs_t)); 221 } 222 223 /** 224 * hb_draw_funcs_reference: (skip) 225 * @dfuncs: draw functions 226 * 227 * Increases the reference count on @dfuncs by one. 228 * 229 * This prevents @dfuncs from being destroyed until a matching 230 * call to hb_draw_funcs_destroy() is made. 231 * 232 * Return value: (transfer full): 233 * The referenced #hb_draw_funcs_t. 234 * 235 * Since: 4.0.0 236 **/ 237 hb_draw_funcs_t * 238 hb_draw_funcs_reference (hb_draw_funcs_t *dfuncs) 239 { 240 return hb_object_reference (dfuncs); 241 } 242 243 /** 244 * hb_draw_funcs_destroy: (skip) 245 * @dfuncs: draw functions 246 * 247 * Deallocate the @dfuncs. 248 * Decreases the reference count on @dfuncs by one. If the result is zero, then 249 * @dfuncs and all associated resources are freed. See hb_draw_funcs_reference(). 250 * 251 * Since: 4.0.0 252 **/ 253 void 254 hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs) 255 { 256 if (!hb_object_destroy (dfuncs)) return; 257 258 if (dfuncs->destroy) 259 { 260 #define HB_DRAW_FUNC_IMPLEMENT(name) \ 261 if (dfuncs->destroy->name) dfuncs->destroy->name (!dfuncs->user_data ? nullptr : dfuncs->user_data->name); 262 HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS 263 #undef HB_DRAW_FUNC_IMPLEMENT 264 } 265 266 hb_free (dfuncs->destroy); 267 hb_free (dfuncs->user_data); 268 269 hb_free (dfuncs); 270 } 271 272 /** 273 * hb_draw_funcs_set_user_data: (skip) 274 * @dfuncs: The draw-functions structure 275 * @key: The user-data key 276 * @data: A pointer to the user data 277 * @destroy: (nullable): A callback to call when @data is not needed anymore 278 * @replace: Whether to replace an existing data with the same key 279 * 280 * Attaches a user-data key/data pair to the specified draw-functions structure. 281 * 282 * Return value: `true` if success, `false` otherwise 283 * 284 * Since: 7.0.0 285 **/ 286 hb_bool_t 287 hb_draw_funcs_set_user_data (hb_draw_funcs_t *dfuncs, 288 hb_user_data_key_t *key, 289 void * data, 290 hb_destroy_func_t destroy, 291 hb_bool_t replace) 292 { 293 return hb_object_set_user_data (dfuncs, key, data, destroy, replace); 294 } 295 296 /** 297 * hb_draw_funcs_get_user_data: (skip) 298 * @dfuncs: The draw-functions structure 299 * @key: The user-data key to query 300 * 301 * Fetches the user-data associated with the specified key, 302 * attached to the specified draw-functions structure. 303 * 304 * Return value: (transfer none): A pointer to the user data 305 * 306 * Since: 7.0.0 307 **/ 308 void * 309 hb_draw_funcs_get_user_data (const hb_draw_funcs_t *dfuncs, 310 hb_user_data_key_t *key) 311 { 312 return hb_object_get_user_data (dfuncs, key); 313 } 314 315 /** 316 * hb_draw_funcs_make_immutable: 317 * @dfuncs: draw functions 318 * 319 * Makes @dfuncs object immutable. 320 * 321 * Since: 4.0.0 322 **/ 323 void 324 hb_draw_funcs_make_immutable (hb_draw_funcs_t *dfuncs) 325 { 326 if (hb_object_is_immutable (dfuncs)) 327 return; 328 329 hb_object_make_immutable (dfuncs); 330 } 331 332 /** 333 * hb_draw_funcs_is_immutable: 334 * @dfuncs: draw functions 335 * 336 * Checks whether @dfuncs is immutable. 337 * 338 * Return value: `true` if @dfuncs is immutable, `false` otherwise 339 * 340 * Since: 4.0.0 341 **/ 342 hb_bool_t 343 hb_draw_funcs_is_immutable (hb_draw_funcs_t *dfuncs) 344 { 345 return hb_object_is_immutable (dfuncs); 346 } 347 348 349 /** 350 * hb_draw_move_to: 351 * @dfuncs: draw functions 352 * @draw_data: associated draw data passed by the caller 353 * @st: current draw state 354 * @to_x: X component of target point 355 * @to_y: Y component of target point 356 * 357 * Perform a "move-to" draw operation. 358 * 359 * Since: 4.0.0 360 **/ 361 void 362 hb_draw_move_to (hb_draw_funcs_t *dfuncs, void *draw_data, 363 hb_draw_state_t *st, 364 float to_x, float to_y) 365 { 366 dfuncs->move_to (draw_data, *st, 367 to_x, to_y); 368 } 369 370 /** 371 * hb_draw_line_to: 372 * @dfuncs: draw functions 373 * @draw_data: associated draw data passed by the caller 374 * @st: current draw state 375 * @to_x: X component of target point 376 * @to_y: Y component of target point 377 * 378 * Perform a "line-to" draw operation. 379 * 380 * Since: 4.0.0 381 **/ 382 void 383 hb_draw_line_to (hb_draw_funcs_t *dfuncs, void *draw_data, 384 hb_draw_state_t *st, 385 float to_x, float to_y) 386 { 387 dfuncs->line_to (draw_data, *st, 388 to_x, to_y); 389 } 390 391 /** 392 * hb_draw_quadratic_to: 393 * @dfuncs: draw functions 394 * @draw_data: associated draw data passed by the caller 395 * @st: current draw state 396 * @control_x: X component of control point 397 * @control_y: Y component of control point 398 * @to_x: X component of target point 399 * @to_y: Y component of target point 400 * 401 * Perform a "quadratic-to" draw operation. 402 * 403 * Since: 4.0.0 404 **/ 405 void 406 hb_draw_quadratic_to (hb_draw_funcs_t *dfuncs, void *draw_data, 407 hb_draw_state_t *st, 408 float control_x, float control_y, 409 float to_x, float to_y) 410 { 411 dfuncs->quadratic_to (draw_data, *st, 412 control_x, control_y, 413 to_x, to_y); 414 } 415 416 /** 417 * hb_draw_cubic_to: 418 * @dfuncs: draw functions 419 * @draw_data: associated draw data passed by the caller 420 * @st: current draw state 421 * @control1_x: X component of first control point 422 * @control1_y: Y component of first control point 423 * @control2_x: X component of second control point 424 * @control2_y: Y component of second control point 425 * @to_x: X component of target point 426 * @to_y: Y component of target point 427 * 428 * Perform a "cubic-to" draw operation. 429 * 430 * Since: 4.0.0 431 **/ 432 void 433 hb_draw_cubic_to (hb_draw_funcs_t *dfuncs, void *draw_data, 434 hb_draw_state_t *st, 435 float control1_x, float control1_y, 436 float control2_x, float control2_y, 437 float to_x, float to_y) 438 { 439 dfuncs->cubic_to (draw_data, *st, 440 control1_x, control1_y, 441 control2_x, control2_y, 442 to_x, to_y); 443 } 444 445 /** 446 * hb_draw_close_path: 447 * @dfuncs: draw functions 448 * @draw_data: associated draw data passed by the caller 449 * @st: current draw state 450 * 451 * Perform a "close-path" draw operation. 452 * 453 * Since: 4.0.0 454 **/ 455 void 456 hb_draw_close_path (hb_draw_funcs_t *dfuncs, void *draw_data, 457 hb_draw_state_t *st) 458 { 459 dfuncs->close_path (draw_data, *st); 460 } 461 462 463 static void 464 hb_draw_extents_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED, 465 void *data, 466 hb_draw_state_t *st, 467 float to_x, float to_y, 468 void *user_data HB_UNUSED) 469 { 470 hb_extents_t<> *extents = (hb_extents_t<> *) data; 471 472 extents->add_point (to_x, to_y); 473 } 474 475 static void 476 hb_draw_extents_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED, 477 void *data, 478 hb_draw_state_t *st, 479 float to_x, float to_y, 480 void *user_data HB_UNUSED) 481 { 482 hb_extents_t<> *extents = (hb_extents_t<> *) data; 483 484 extents->add_point (to_x, to_y); 485 } 486 487 static void 488 hb_draw_extents_quadratic_to (hb_draw_funcs_t *dfuncs HB_UNUSED, 489 void *data, 490 hb_draw_state_t *st, 491 float control_x, float control_y, 492 float to_x, float to_y, 493 void *user_data HB_UNUSED) 494 { 495 hb_extents_t<> *extents = (hb_extents_t<> *) data; 496 497 extents->add_point (control_x, control_y); 498 extents->add_point (to_x, to_y); 499 } 500 501 static void 502 hb_draw_extents_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED, 503 void *data, 504 hb_draw_state_t *st, 505 float control1_x, float control1_y, 506 float control2_x, float control2_y, 507 float to_x, float to_y, 508 void *user_data HB_UNUSED) 509 { 510 hb_extents_t<> *extents = (hb_extents_t<> *) data; 511 512 extents->add_point (control1_x, control1_y); 513 extents->add_point (control2_x, control2_y); 514 extents->add_point (to_x, to_y); 515 } 516 517 static inline void free_static_draw_extents_funcs (); 518 519 static struct hb_draw_extents_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t<hb_draw_extents_funcs_lazy_loader_t> 520 { 521 static hb_draw_funcs_t *create () 522 { 523 hb_draw_funcs_t *funcs = hb_draw_funcs_create (); 524 525 hb_draw_funcs_set_move_to_func (funcs, hb_draw_extents_move_to, nullptr, nullptr); 526 hb_draw_funcs_set_line_to_func (funcs, hb_draw_extents_line_to, nullptr, nullptr); 527 hb_draw_funcs_set_quadratic_to_func (funcs, hb_draw_extents_quadratic_to, nullptr, nullptr); 528 hb_draw_funcs_set_cubic_to_func (funcs, hb_draw_extents_cubic_to, nullptr, nullptr); 529 530 hb_draw_funcs_make_immutable (funcs); 531 532 hb_atexit (free_static_draw_extents_funcs); 533 534 return funcs; 535 } 536 } static_draw_extents_funcs; 537 538 static inline 539 void free_static_draw_extents_funcs () 540 { 541 static_draw_extents_funcs.free_instance (); 542 } 543 544 hb_draw_funcs_t * 545 hb_draw_extents_get_funcs () 546 { 547 return static_draw_extents_funcs.get_unconst (); 548 } 549 550 551 #endif