1 /**************************************************************************** 2 * 3 * ftsdf.c 4 * 5 * Signed Distance Field support for outline fonts (body). 6 * 7 * Copyright (C) 2020-2021 by 8 * David Turner, Robert Wilhelm, and Werner Lemberg. 9 * 10 * Written by Anuj Verma. 11 * 12 * This file is part of the FreeType project, and may only be used, 13 * modified, and distributed under the terms of the FreeType project 14 * license, LICENSE.TXT. By continuing to use, modify, or distribute 15 * this file you indicate that you have read the license and 16 * understand and accept it fully. 17 * 18 */ 19 20 21 #include <freetype/internal/ftobjs.h> 22 #include <freetype/internal/ftdebug.h> 23 #include <freetype/ftoutln.h> 24 #include <freetype/fttrigon.h> 25 #include <freetype/ftbitmap.h> 26 #include "ftsdf.h" 27 28 #include "ftsdferrs.h" 29 30 31 /************************************************************************** 32 * 33 * A brief technical overview of how the SDF rasterizer works 34 * ---------------------------------------------------------- 35 * 36 * [Notes]: 37 * * SDF stands for Signed Distance Field everywhere. 38 * 39 * * This renderer generates SDF directly from outlines. There is 40 * another renderer called 'bsdf', which converts bitmaps to SDF; see 41 * file `ftbsdf.c` for more. 42 * 43 * * The basic idea of generating the SDF is taken from Viktor Chlumsky's 44 * research paper. The paper explains both single and multi-channel 45 * SDF, however, this implementation only generates single-channel SDF. 46 * 47 * Chlumsky, Viktor: Shape Decomposition for Multi-channel Distance 48 * Fields. Master's thesis. Czech Technical University in Prague, 49 * Faculty of InformationTechnology, 2015. 50 * 51 * For more information: https://github.com/Chlumsky/msdfgen 52 * 53 * ======================================================================== 54 * 55 * Generating SDF from outlines is pretty straightforward. 56 * 57 * (1) We have a set of contours that make the outline of a shape/glyph. 58 * Each contour comprises of several edges, with three types of edges. 59 * 60 * * line segments 61 * * conic Bezier curves 62 * * cubic Bezier curves 63 * 64 * (2) Apart from the outlines we also have a two-dimensional grid, namely 65 * the bitmap that is used to represent the final SDF data. 66 * 67 * (3) In order to generate SDF, our task is to find shortest signed 68 * distance from each grid point to the outline. The 'signed 69 * distance' means that if the grid point is filled by any contour 70 * then its sign is positive, otherwise it is negative. The pseudo 71 * code is as follows. 72 * 73 * ``` 74 * foreach grid_point (x, y): 75 * { 76 * int min_dist = INT_MAX; 77 * 78 * foreach contour in outline: 79 * { 80 * foreach edge in contour: 81 * { 82 * // get shortest distance from point (x, y) to the edge 83 * d = get_min_dist(x, y, edge); 84 * 85 * if (d < min_dist) 86 * min_dist = d; 87 * } 88 * 89 * bitmap[x, y] = min_dist; 90 * } 91 * } 92 * ``` 93 * 94 * (4) After running this algorithm the bitmap contains information about 95 * the shortest distance from each point to the outline of the shape. 96 * Of course, while this is the most straightforward way of generating 97 * SDF, we use various optimizations in our implementation. See the 98 * `sdf_generate_*' functions in this file for all details. 99 * 100 * The optimization currently used by default is subdivision; see 101 * function `sdf_generate_subdivision` for more. 102 * 103 * Also, to see how we compute the shortest distance from a point to 104 * each type of edge, check out the `get_min_distance_*' functions. 105 * 106 */ 107 108 109 /************************************************************************** 110 * 111 * The macro FT_COMPONENT is used in trace mode. It is an implicit 112 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log 113 * messages during execution. 114 */ 115 #undef FT_COMPONENT 116 #define FT_COMPONENT sdf 117 118 119 /************************************************************************** 120 * 121 * definitions 122 * 123 */ 124 125 /* 126 * If set to 1, the rasterizer uses Newton-Raphson's method for finding 127 * the shortest distance from a point to a conic curve. 128 * 129 * If set to 0, an analytical method gets used instead, which computes the 130 * roots of a cubic polynomial to find the shortest distance. However, 131 * the analytical method can currently underflow; we thus use Newton's 132 * method by default. 133 */ 134 #ifndef USE_NEWTON_FOR_CONIC 135 #define USE_NEWTON_FOR_CONIC 1 136 #endif 137 138 /* 139 * The number of intervals a Bezier curve gets sampled and checked to find 140 * the shortest distance. 141 */ 142 #define MAX_NEWTON_DIVISIONS 4 143 144 /* 145 * The number of steps of Newton's iterations in each interval of the 146 * Bezier curve. Basically, we run Newton's approximation 147 * 148 * x -= Q(t) / Q'(t) 149 * 150 * for each division to get the shortest distance. 151 */ 152 #define MAX_NEWTON_STEPS 4 153 154 /* 155 * The epsilon distance (in 16.16 fractional units) used for corner 156 * resolving. If the difference of two distances is less than this value 157 * they will be checked for a corner if they are ambiguous. 158 */ 159 #define CORNER_CHECK_EPSILON 32 160 161 #if 0 162 /* 163 * Coarse grid dimension. Will probably be removed in the future because 164 * coarse grid optimization is the slowest algorithm. 165 */ 166 #define CG_DIMEN 8 167 #endif 168 169 170 /************************************************************************** 171 * 172 * macros 173 * 174 */ 175 176 #define MUL_26D6( a, b ) ( ( ( a ) * ( b ) ) / 64 ) 177 #define VEC_26D6_DOT( p, q ) ( MUL_26D6( p.x, q.x ) + \ 178 MUL_26D6( p.y, q.y ) ) 179 180 181 /************************************************************************** 182 * 183 * structures and enums 184 * 185 */ 186 187 /************************************************************************** 188 * 189 * @Struct: 190 * SDF_TRaster 191 * 192 * @Description: 193 * This struct is used in place of @FT_Raster and is stored within the 194 * internal FreeType renderer struct. While rasterizing it is passed to 195 * the @FT_Raster_RenderFunc function, which then can be used however we 196 * want. 197 * 198 * @Fields: 199 * memory :: 200 * Used internally to allocate intermediate memory while raterizing. 201 * 202 */ 203 typedef struct SDF_TRaster_ 204 { 205 FT_Memory memory; 206 207 } SDF_TRaster, *SDF_PRaster; 208 209 210 /************************************************************************** 211 * 212 * @Enum: 213 * SDF_Edge_Type 214 * 215 * @Description: 216 * Enumeration of all curve types present in fonts. 217 * 218 * @Fields: 219 * SDF_EDGE_UNDEFINED :: 220 * Undefined edge, simply used to initialize and detect errors. 221 * 222 * SDF_EDGE_LINE :: 223 * Line segment with start and end point. 224 * 225 * SDF_EDGE_CONIC :: 226 * A conic/quadratic Bezier curve with start, end, and one control 227 * point. 228 * 229 * SDF_EDGE_CUBIC :: 230 * A cubic Bezier curve with start, end, and two control points. 231 * 232 */ 233 typedef enum SDF_Edge_Type_ 234 { 235 SDF_EDGE_UNDEFINED = 0, 236 SDF_EDGE_LINE = 1, 237 SDF_EDGE_CONIC = 2, 238 SDF_EDGE_CUBIC = 3 239 240 } SDF_Edge_Type; 241 242 243 /************************************************************************** 244 * 245 * @Enum: 246 * SDF_Contour_Orientation 247 * 248 * @Description: 249 * Enumeration of all orientation values of a contour. We determine the 250 * orientation by calculating the area covered by a contour. Contrary 251 * to values returned by @FT_Outline_Get_Orientation, 252 * `SDF_Contour_Orientation` is independent of the fill rule, which can 253 * be different for different font formats. 254 * 255 * @Fields: 256 * SDF_ORIENTATION_NONE :: 257 * Undefined orientation, used for initialization and error detection. 258 * 259 * SDF_ORIENTATION_CW :: 260 * Clockwise orientation (positive area covered). 261 * 262 * SDF_ORIENTATION_CCW :: 263 * Counter-clockwise orientation (negative area covered). 264 * 265 * @Note: 266 * See @FT_Outline_Get_Orientation for more details. 267 * 268 */ 269 typedef enum SDF_Contour_Orientation_ 270 { 271 SDF_ORIENTATION_NONE = 0, 272 SDF_ORIENTATION_CW = 1, 273 SDF_ORIENTATION_CCW = 2 274 275 } SDF_Contour_Orientation; 276 277 278 /************************************************************************** 279 * 280 * @Struct: 281 * SDF_Edge 282 * 283 * @Description: 284 * Represent an edge of a contour. 285 * 286 * @Fields: 287 * start_pos :: 288 * Start position of an edge. Valid for all types of edges. 289 * 290 * end_pos :: 291 * Etart position of an edge. Valid for all types of edges. 292 * 293 * control_a :: 294 * A control point of the edge. Valid only for `SDF_EDGE_CONIC` 295 * and `SDF_EDGE_CUBIC`. 296 * 297 * control_b :: 298 * Another control point of the edge. Valid only for 299 * `SDF_EDGE_CONIC`. 300 * 301 * edge_type :: 302 * Type of the edge, see @SDF_Edge_Type for all possible edge types. 303 * 304 * next :: 305 * Used to create a singly linked list, which can be interpreted 306 * as a contour. 307 * 308 */ 309 typedef struct SDF_Edge_ 310 { 311 FT_26D6_Vec start_pos; 312 FT_26D6_Vec end_pos; 313 FT_26D6_Vec control_a; 314 FT_26D6_Vec control_b; 315 316 SDF_Edge_Type edge_type; 317 318 struct SDF_Edge_* next; 319 320 } SDF_Edge; 321 322 323 /************************************************************************** 324 * 325 * @Struct: 326 * SDF_Contour 327 * 328 * @Description: 329 * Represent a complete contour, which contains a list of edges. 330 * 331 * @Fields: 332 * last_pos :: 333 * Contains the value of `end_pos' of the last edge in the list of 334 * edges. Useful while decomposing the outline with 335 * @FT_Outline_Decompose. 336 * 337 * edges :: 338 * Linked list of all the edges that make the contour. 339 * 340 * next :: 341 * Used to create a singly linked list, which can be interpreted as a 342 * complete shape or @FT_Outline. 343 * 344 */ 345 typedef struct SDF_Contour_ 346 { 347 FT_26D6_Vec last_pos; 348 SDF_Edge* edges; 349 350 struct SDF_Contour_* next; 351 352 } SDF_Contour; 353 354 355 /************************************************************************** 356 * 357 * @Struct: 358 * SDF_Shape 359 * 360 * @Description: 361 * Represent a complete shape, which is the decomposition of 362 * @FT_Outline. 363 * 364 * @Fields: 365 * memory :: 366 * Used internally to allocate memory. 367 * 368 * contours :: 369 * Linked list of all the contours that make the shape. 370 * 371 */ 372 typedef struct SDF_Shape_ 373 { 374 FT_Memory memory; 375 SDF_Contour* contours; 376 377 } SDF_Shape; 378 379 380 /************************************************************************** 381 * 382 * @Struct: 383 * SDF_Signed_Distance 384 * 385 * @Description: 386 * Represent signed distance of a point, i.e., the distance of the edge 387 * nearest to the point. 388 * 389 * @Fields: 390 * distance :: 391 * Distance of the point from the nearest edge. Can be squared or 392 * absolute depending on the `USE_SQUARED_DISTANCES` macro defined in 393 * file `ftsdfcommon.h`. 394 * 395 * cross :: 396 * Cross product of the shortest distance vector (i.e., the vector 397 * from the point to the nearest edge) and the direction of the edge 398 * at the nearest point. This is used to resolve ambiguities of 399 * `sign`. 400 * 401 * sign :: 402 * A value used to indicate whether the distance vector is outside or 403 * inside the contour corresponding to the edge. 404 * 405 * @Note: 406 * `sign` may or may not be correct, therefore it must be checked 407 * properly in case there is an ambiguity. 408 * 409 */ 410 typedef struct SDF_Signed_Distance_ 411 { 412 FT_16D16 distance; 413 FT_16D16 cross; 414 FT_Char sign; 415 416 } SDF_Signed_Distance; 417 418 419 /************************************************************************** 420 * 421 * @Struct: 422 * SDF_Params 423 * 424 * @Description: 425 * Yet another internal parameters required by the rasterizer. 426 * 427 * @Fields: 428 * orientation :: 429 * This is not the @SDF_Contour_Orientation value but @FT_Orientation, 430 * which determines whether clockwise-oriented outlines are to be 431 * filled or counter-clockwise-oriented ones. 432 * 433 * flip_sign :: 434 * If set to true, flip the sign. By default the points filled by the 435 * outline are positive. 436 * 437 * flip_y :: 438 * If set to true the output bitmap is upside-down. Can be useful 439 * because OpenGL and DirectX use different coordinate systems for 440 * textures. 441 * 442 * overload_sign :: 443 * In the subdivision and bounding box optimization, the default 444 * outside sign is taken as -1. This parameter can be used to modify 445 * that behaviour. For example, while generating SDF for a single 446 * counter-clockwise contour, the outside sign should be 1. 447 * 448 */ 449 typedef struct SDF_Params_ 450 { 451 FT_Orientation orientation; 452 FT_Bool flip_sign; 453 FT_Bool flip_y; 454 455 FT_Int overload_sign; 456 457 } SDF_Params; 458 459 460 /************************************************************************** 461 * 462 * constants, initializer, and destructor 463 * 464 */ 465 466 static 467 const FT_Vector zero_vector = { 0, 0 }; 468 469 static 470 const SDF_Edge null_edge = { { 0, 0 }, { 0, 0 }, 471 { 0, 0 }, { 0, 0 }, 472 SDF_EDGE_UNDEFINED, NULL }; 473 474 static 475 const SDF_Contour null_contour = { { 0, 0 }, NULL, NULL }; 476 477 static 478 const SDF_Shape null_shape = { NULL, NULL }; 479 480 static 481 const SDF_Signed_Distance max_sdf = { INT_MAX, 0, 0 }; 482 483 484 /* Create a new @SDF_Edge on the heap and assigns the `edge` */ 485 /* pointer to the newly allocated memory. */ 486 static FT_Error sdf_edge_new(FT_Memory memory,SDF_Edge ** edge)487 sdf_edge_new( FT_Memory memory, 488 SDF_Edge** edge ) 489 { 490 FT_Error error = FT_Err_Ok; 491 SDF_Edge* ptr = NULL; 492 493 494 if ( !memory || !edge ) 495 { 496 error = FT_THROW( Invalid_Argument ); 497 goto Exit; 498 } 499 500 if ( !FT_QALLOC( ptr, sizeof ( *ptr ) ) ) 501 { 502 *ptr = null_edge; 503 *edge = ptr; 504 } 505 506 Exit: 507 return error; 508 } 509 510 511 /* Free the allocated `edge` variable. */ 512 static void sdf_edge_done(FT_Memory memory,SDF_Edge ** edge)513 sdf_edge_done( FT_Memory memory, 514 SDF_Edge** edge ) 515 { 516 if ( !memory || !edge || !*edge ) 517 return; 518 519 FT_FREE( *edge ); 520 } 521 522 523 /* Create a new @SDF_Contour on the heap and assign */ 524 /* the `contour` pointer to the newly allocated memory. */ 525 static FT_Error sdf_contour_new(FT_Memory memory,SDF_Contour ** contour)526 sdf_contour_new( FT_Memory memory, 527 SDF_Contour** contour ) 528 { 529 FT_Error error = FT_Err_Ok; 530 SDF_Contour* ptr = NULL; 531 532 533 if ( !memory || !contour ) 534 { 535 error = FT_THROW( Invalid_Argument ); 536 goto Exit; 537 } 538 539 if ( !FT_QALLOC( ptr, sizeof ( *ptr ) ) ) 540 { 541 *ptr = null_contour; 542 *contour = ptr; 543 } 544 545 Exit: 546 return error; 547 } 548 549 550 /* Free the allocated `contour` variable. */ 551 /* Also free the list of edges. */ 552 static void sdf_contour_done(FT_Memory memory,SDF_Contour ** contour)553 sdf_contour_done( FT_Memory memory, 554 SDF_Contour** contour ) 555 { 556 SDF_Edge* edges; 557 SDF_Edge* temp; 558 559 560 if ( !memory || !contour || !*contour ) 561 return; 562 563 edges = (*contour)->edges; 564 565 /* release all edges */ 566 while ( edges ) 567 { 568 temp = edges; 569 edges = edges->next; 570 571 sdf_edge_done( memory, &temp ); 572 } 573 574 FT_FREE( *contour ); 575 } 576 577 578 /* Create a new @SDF_Shape on the heap and assign */ 579 /* the `shape` pointer to the newly allocated memory. */ 580 static FT_Error sdf_shape_new(FT_Memory memory,SDF_Shape ** shape)581 sdf_shape_new( FT_Memory memory, 582 SDF_Shape** shape ) 583 { 584 FT_Error error = FT_Err_Ok; 585 SDF_Shape* ptr = NULL; 586 587 588 if ( !memory || !shape ) 589 { 590 error = FT_THROW( Invalid_Argument ); 591 goto Exit; 592 } 593 594 if ( !FT_QALLOC( ptr, sizeof ( *ptr ) ) ) 595 { 596 *ptr = null_shape; 597 ptr->memory = memory; 598 *shape = ptr; 599 } 600 601 Exit: 602 return error; 603 } 604 605 606 /* Free the allocated `shape` variable. */ 607 /* Also free the list of contours. */ 608 static void sdf_shape_done(SDF_Shape ** shape)609 sdf_shape_done( SDF_Shape** shape ) 610 { 611 FT_Memory memory; 612 SDF_Contour* contours; 613 SDF_Contour* temp; 614 615 616 if ( !shape || !*shape ) 617 return; 618 619 memory = (*shape)->memory; 620 contours = (*shape)->contours; 621 622 if ( !memory ) 623 return; 624 625 /* release all contours */ 626 while ( contours ) 627 { 628 temp = contours; 629 contours = contours->next; 630 631 sdf_contour_done( memory, &temp ); 632 } 633 634 /* release the allocated shape struct */ 635 FT_FREE( *shape ); 636 } 637 638 639 /************************************************************************** 640 * 641 * shape decomposition functions 642 * 643 */ 644 645 /* This function is called when starting a new contour at `to`, */ 646 /* which gets added to the shape's list. */ 647 static FT_Error sdf_move_to(const FT_26D6_Vec * to,void * user)648 sdf_move_to( const FT_26D6_Vec* to, 649 void* user ) 650 { 651 SDF_Shape* shape = ( SDF_Shape* )user; 652 SDF_Contour* contour = NULL; 653 654 FT_Error error = FT_Err_Ok; 655 FT_Memory memory = shape->memory; 656 657 658 if ( !to || !user ) 659 { 660 error = FT_THROW( Invalid_Argument ); 661 goto Exit; 662 } 663 664 FT_CALL( sdf_contour_new( memory, &contour ) ); 665 666 contour->last_pos = *to; 667 contour->next = shape->contours; 668 shape->contours = contour; 669 670 Exit: 671 return error; 672 } 673 674 675 /* This function is called when there is a line in the */ 676 /* contour. The line starts at the previous edge point and */ 677 /* stops at `to`. */ 678 static FT_Error sdf_line_to(const FT_26D6_Vec * to,void * user)679 sdf_line_to( const FT_26D6_Vec* to, 680 void* user ) 681 { 682 SDF_Shape* shape = ( SDF_Shape* )user; 683 SDF_Edge* edge = NULL; 684 SDF_Contour* contour = NULL; 685 686 FT_Error error = FT_Err_Ok; 687 FT_Memory memory = shape->memory; 688 689 690 if ( !to || !user ) 691 { 692 error = FT_THROW( Invalid_Argument ); 693 goto Exit; 694 } 695 696 contour = shape->contours; 697 698 if ( contour->last_pos.x == to->x && 699 contour->last_pos.y == to->y ) 700 goto Exit; 701 702 FT_CALL( sdf_edge_new( memory, &edge ) ); 703 704 edge->edge_type = SDF_EDGE_LINE; 705 edge->start_pos = contour->last_pos; 706 edge->end_pos = *to; 707 708 edge->next = contour->edges; 709 contour->edges = edge; 710 contour->last_pos = *to; 711 712 Exit: 713 return error; 714 } 715 716 717 /* This function is called when there is a conic Bezier curve */ 718 /* in the contour. The curve starts at the previous edge point */ 719 /* and stops at `to`, with control point `control_1`. */ 720 static FT_Error sdf_conic_to(const FT_26D6_Vec * control_1,const FT_26D6_Vec * to,void * user)721 sdf_conic_to( const FT_26D6_Vec* control_1, 722 const FT_26D6_Vec* to, 723 void* user ) 724 { 725 SDF_Shape* shape = ( SDF_Shape* )user; 726 SDF_Edge* edge = NULL; 727 SDF_Contour* contour = NULL; 728 729 FT_Error error = FT_Err_Ok; 730 FT_Memory memory = shape->memory; 731 732 733 if ( !control_1 || !to || !user ) 734 { 735 error = FT_THROW( Invalid_Argument ); 736 goto Exit; 737 } 738 739 contour = shape->contours; 740 741 FT_CALL( sdf_edge_new( memory, &edge ) ); 742 743 edge->edge_type = SDF_EDGE_CONIC; 744 edge->start_pos = contour->last_pos; 745 edge->control_a = *control_1; 746 edge->end_pos = *to; 747 748 edge->next = contour->edges; 749 contour->edges = edge; 750 contour->last_pos = *to; 751 752 Exit: 753 return error; 754 } 755 756 757 /* This function is called when there is a cubic Bezier curve */ 758 /* in the contour. The curve starts at the previous edge point */ 759 /* and stops at `to`, with two control points `control_1` and */ 760 /* `control_2`. */ 761 static FT_Error sdf_cubic_to(const FT_26D6_Vec * control_1,const FT_26D6_Vec * control_2,const FT_26D6_Vec * to,void * user)762 sdf_cubic_to( const FT_26D6_Vec* control_1, 763 const FT_26D6_Vec* control_2, 764 const FT_26D6_Vec* to, 765 void* user ) 766 { 767 SDF_Shape* shape = ( SDF_Shape* )user; 768 SDF_Edge* edge = NULL; 769 SDF_Contour* contour = NULL; 770 771 FT_Error error = FT_Err_Ok; 772 FT_Memory memory = shape->memory; 773 774 775 if ( !control_2 || !control_1 || !to || !user ) 776 { 777 error = FT_THROW( Invalid_Argument ); 778 goto Exit; 779 } 780 781 contour = shape->contours; 782 783 FT_CALL( sdf_edge_new( memory, &edge ) ); 784 785 edge->edge_type = SDF_EDGE_CUBIC; 786 edge->start_pos = contour->last_pos; 787 edge->control_a = *control_1; 788 edge->control_b = *control_2; 789 edge->end_pos = *to; 790 791 edge->next = contour->edges; 792 contour->edges = edge; 793 contour->last_pos = *to; 794 795 Exit: 796 return error; 797 } 798 799 800 /* Construct the structure to hold all four outline */ 801 /* decomposition functions. */ 802 FT_DEFINE_OUTLINE_FUNCS( 803 sdf_decompose_funcs, 804 805 (FT_Outline_MoveTo_Func) sdf_move_to, /* move_to */ 806 (FT_Outline_LineTo_Func) sdf_line_to, /* line_to */ 807 (FT_Outline_ConicTo_Func)sdf_conic_to, /* conic_to */ 808 (FT_Outline_CubicTo_Func)sdf_cubic_to, /* cubic_to */ 809 810 0, /* shift */ 811 0 /* delta */ 812 ) 813 814 815 /* Decompose `outline` and put it into the `shape` structure. */ 816 static FT_Error sdf_outline_decompose(FT_Outline * outline,SDF_Shape * shape)817 sdf_outline_decompose( FT_Outline* outline, 818 SDF_Shape* shape ) 819 { 820 FT_Error error = FT_Err_Ok; 821 822 823 if ( !outline || !shape ) 824 { 825 error = FT_THROW( Invalid_Argument ); 826 goto Exit; 827 } 828 829 error = FT_Outline_Decompose( outline, 830 &sdf_decompose_funcs, 831 (void*)shape ); 832 833 Exit: 834 return error; 835 } 836 837 838 /************************************************************************** 839 * 840 * utility functions 841 * 842 */ 843 844 /* Return the control box of an edge. The control box is a rectangle */ 845 /* in which all the control points can fit tightly. */ 846 static FT_CBox get_control_box(SDF_Edge edge)847 get_control_box( SDF_Edge edge ) 848 { 849 FT_CBox cbox = { 0, 0, 0, 0 }; 850 FT_Bool is_set = 0; 851 852 853 switch ( edge.edge_type ) 854 { 855 case SDF_EDGE_CUBIC: 856 cbox.xMin = edge.control_b.x; 857 cbox.xMax = edge.control_b.x; 858 cbox.yMin = edge.control_b.y; 859 cbox.yMax = edge.control_b.y; 860 861 is_set = 1; 862 /* fall through */ 863 864 case SDF_EDGE_CONIC: 865 if ( is_set ) 866 { 867 cbox.xMin = edge.control_a.x < cbox.xMin 868 ? edge.control_a.x 869 : cbox.xMin; 870 cbox.xMax = edge.control_a.x > cbox.xMax 871 ? edge.control_a.x 872 : cbox.xMax; 873 874 cbox.yMin = edge.control_a.y < cbox.yMin 875 ? edge.control_a.y 876 : cbox.yMin; 877 cbox.yMax = edge.control_a.y > cbox.yMax 878 ? edge.control_a.y 879 : cbox.yMax; 880 } 881 else 882 { 883 cbox.xMin = edge.control_a.x; 884 cbox.xMax = edge.control_a.x; 885 cbox.yMin = edge.control_a.y; 886 cbox.yMax = edge.control_a.y; 887 888 is_set = 1; 889 } 890 /* fall through */ 891 892 case SDF_EDGE_LINE: 893 if ( is_set ) 894 { 895 cbox.xMin = edge.start_pos.x < cbox.xMin 896 ? edge.start_pos.x 897 : cbox.xMin; 898 cbox.xMax = edge.start_pos.x > cbox.xMax 899 ? edge.start_pos.x 900 : cbox.xMax; 901 902 cbox.yMin = edge.start_pos.y < cbox.yMin 903 ? edge.start_pos.y 904 : cbox.yMin; 905 cbox.yMax = edge.start_pos.y > cbox.yMax 906 ? edge.start_pos.y 907 : cbox.yMax; 908 } 909 else 910 { 911 cbox.xMin = edge.start_pos.x; 912 cbox.xMax = edge.start_pos.x; 913 cbox.yMin = edge.start_pos.y; 914 cbox.yMax = edge.start_pos.y; 915 } 916 917 cbox.xMin = edge.end_pos.x < cbox.xMin 918 ? edge.end_pos.x 919 : cbox.xMin; 920 cbox.xMax = edge.end_pos.x > cbox.xMax 921 ? edge.end_pos.x 922 : cbox.xMax; 923 924 cbox.yMin = edge.end_pos.y < cbox.yMin 925 ? edge.end_pos.y 926 : cbox.yMin; 927 cbox.yMax = edge.end_pos.y > cbox.yMax 928 ? edge.end_pos.y 929 : cbox.yMax; 930 931 break; 932 933 default: 934 break; 935 } 936 937 return cbox; 938 } 939 940 941 /* Return orientation of a single contour. */ 942 /* Note that the orientation is independent of the fill rule! */ 943 /* So, for TTF a clockwise-oriented contour has to be filled */ 944 /* and the opposite for OTF fonts. */ 945 static SDF_Contour_Orientation get_contour_orientation(SDF_Contour * contour)946 get_contour_orientation ( SDF_Contour* contour ) 947 { 948 SDF_Edge* head = NULL; 949 FT_26D6 area = 0; 950 951 952 /* return none if invalid parameters */ 953 if ( !contour || !contour->edges ) 954 return SDF_ORIENTATION_NONE; 955 956 head = contour->edges; 957 958 /* Calculate the area of the control box for all edges. */ 959 while ( head ) 960 { 961 switch ( head->edge_type ) 962 { 963 case SDF_EDGE_LINE: 964 area += MUL_26D6( ( head->end_pos.x - head->start_pos.x ), 965 ( head->end_pos.y + head->start_pos.y ) ); 966 break; 967 968 case SDF_EDGE_CONIC: 969 area += MUL_26D6( head->control_a.x - head->start_pos.x, 970 head->control_a.y + head->start_pos.y ); 971 area += MUL_26D6( head->end_pos.x - head->control_a.x, 972 head->end_pos.y + head->control_a.y ); 973 break; 974 975 case SDF_EDGE_CUBIC: 976 area += MUL_26D6( head->control_a.x - head->start_pos.x, 977 head->control_a.y + head->start_pos.y ); 978 area += MUL_26D6( head->control_b.x - head->control_a.x, 979 head->control_b.y + head->control_a.y ); 980 area += MUL_26D6( head->end_pos.x - head->control_b.x, 981 head->end_pos.y + head->control_b.y ); 982 break; 983 984 default: 985 return SDF_ORIENTATION_NONE; 986 } 987 988 head = head->next; 989 } 990 991 /* Clockwise contours cover a positive area, and counter-clockwise */ 992 /* contours cover a negative area. */ 993 if ( area > 0 ) 994 return SDF_ORIENTATION_CW; 995 else 996 return SDF_ORIENTATION_CCW; 997 } 998 999 1000 /* This function is exactly the same as the one */ 1001 /* in the smooth renderer. It splits a conic */ 1002 /* into two conics exactly half way at t = 0.5. */ 1003 static void split_conic(FT_26D6_Vec * base)1004 split_conic( FT_26D6_Vec* base ) 1005 { 1006 FT_26D6 a, b; 1007 1008 1009 base[4].x = base[2].x; 1010 a = base[0].x + base[1].x; 1011 b = base[1].x + base[2].x; 1012 base[3].x = b / 2; 1013 base[2].x = ( a + b ) / 4; 1014 base[1].x = a / 2; 1015 1016 base[4].y = base[2].y; 1017 a = base[0].y + base[1].y; 1018 b = base[1].y + base[2].y; 1019 base[3].y = b / 2; 1020 base[2].y = ( a + b ) / 4; 1021 base[1].y = a / 2; 1022 } 1023 1024 1025 /* This function is exactly the same as the one */ 1026 /* in the smooth renderer. It splits a cubic */ 1027 /* into two cubics exactly half way at t = 0.5. */ 1028 static void split_cubic(FT_26D6_Vec * base)1029 split_cubic( FT_26D6_Vec* base ) 1030 { 1031 FT_26D6 a, b, c; 1032 1033 1034 base[6].x = base[3].x; 1035 a = base[0].x + base[1].x; 1036 b = base[1].x + base[2].x; 1037 c = base[2].x + base[3].x; 1038 base[5].x = c / 2; 1039 c += b; 1040 base[4].x = c / 4; 1041 base[1].x = a / 2; 1042 a += b; 1043 base[2].x = a / 4; 1044 base[3].x = ( a + c ) / 8; 1045 1046 base[6].y = base[3].y; 1047 a = base[0].y + base[1].y; 1048 b = base[1].y + base[2].y; 1049 c = base[2].y + base[3].y; 1050 base[5].y = c / 2; 1051 c += b; 1052 base[4].y = c / 4; 1053 base[1].y = a / 2; 1054 a += b; 1055 base[2].y = a / 4; 1056 base[3].y = ( a + c ) / 8; 1057 } 1058 1059 1060 /* Split a conic Bezier curve into a number of lines */ 1061 /* and add them to `out'. */ 1062 /* */ 1063 /* This function uses recursion; we thus need */ 1064 /* parameter `max_splits' for stopping. */ 1065 static FT_Error split_sdf_conic(FT_Memory memory,FT_26D6_Vec * control_points,FT_Int max_splits,SDF_Edge ** out)1066 split_sdf_conic( FT_Memory memory, 1067 FT_26D6_Vec* control_points, 1068 FT_Int max_splits, 1069 SDF_Edge** out ) 1070 { 1071 FT_Error error = FT_Err_Ok; 1072 FT_26D6_Vec cpos[5]; 1073 SDF_Edge* left,* right; 1074 1075 1076 if ( !memory || !out ) 1077 { 1078 error = FT_THROW( Invalid_Argument ); 1079 goto Exit; 1080 } 1081 1082 /* split conic outline */ 1083 cpos[0] = control_points[0]; 1084 cpos[1] = control_points[1]; 1085 cpos[2] = control_points[2]; 1086 1087 split_conic( cpos ); 1088 1089 /* If max number of splits is done */ 1090 /* then stop and add the lines to */ 1091 /* the list. */ 1092 if ( max_splits <= 2 ) 1093 goto Append; 1094 1095 /* Otherwise keep splitting. */ 1096 FT_CALL( split_sdf_conic( memory, &cpos[0], max_splits / 2, out ) ); 1097 FT_CALL( split_sdf_conic( memory, &cpos[2], max_splits / 2, out ) ); 1098 1099 /* [NOTE]: This is not an efficient way of */ 1100 /* splitting the curve. Check the deviation */ 1101 /* instead and stop if the deviation is less */ 1102 /* than a pixel. */ 1103 1104 goto Exit; 1105 1106 Append: 1107 /* Do allocation and add the lines to the list. */ 1108 1109 FT_CALL( sdf_edge_new( memory, &left ) ); 1110 FT_CALL( sdf_edge_new( memory, &right ) ); 1111 1112 left->start_pos = cpos[0]; 1113 left->end_pos = cpos[2]; 1114 left->edge_type = SDF_EDGE_LINE; 1115 1116 right->start_pos = cpos[2]; 1117 right->end_pos = cpos[4]; 1118 right->edge_type = SDF_EDGE_LINE; 1119 1120 left->next = right; 1121 right->next = (*out); 1122 *out = left; 1123 1124 Exit: 1125 return error; 1126 } 1127 1128 1129 /* Split a cubic Bezier curve into a number of lines */ 1130 /* and add them to `out`. */ 1131 /* */ 1132 /* This function uses recursion; we thus need */ 1133 /* parameter `max_splits' for stopping. */ 1134 static FT_Error split_sdf_cubic(FT_Memory memory,FT_26D6_Vec * control_points,FT_Int max_splits,SDF_Edge ** out)1135 split_sdf_cubic( FT_Memory memory, 1136 FT_26D6_Vec* control_points, 1137 FT_Int max_splits, 1138 SDF_Edge** out ) 1139 { 1140 FT_Error error = FT_Err_Ok; 1141 FT_26D6_Vec cpos[7]; 1142 SDF_Edge* left,* right; 1143 1144 1145 if ( !memory || !out ) 1146 { 1147 error = FT_THROW( Invalid_Argument ); 1148 goto Exit; 1149 } 1150 1151 /* split the conic */ 1152 cpos[0] = control_points[0]; 1153 cpos[1] = control_points[1]; 1154 cpos[2] = control_points[2]; 1155 cpos[3] = control_points[3]; 1156 1157 split_cubic( cpos ); 1158 1159 /* If max number of splits is done */ 1160 /* then stop and add the lines to */ 1161 /* the list. */ 1162 if ( max_splits <= 2 ) 1163 goto Append; 1164 1165 /* Otherwise keep splitting. */ 1166 FT_CALL( split_sdf_cubic( memory, &cpos[0], max_splits / 2, out ) ); 1167 FT_CALL( split_sdf_cubic( memory, &cpos[3], max_splits / 2, out ) ); 1168 1169 /* [NOTE]: This is not an efficient way of */ 1170 /* splitting the curve. Check the deviation */ 1171 /* instead and stop if the deviation is less */ 1172 /* than a pixel. */ 1173 1174 goto Exit; 1175 1176 Append: 1177 /* Do allocation and add the lines to the list. */ 1178 1179 FT_CALL( sdf_edge_new( memory, &left) ); 1180 FT_CALL( sdf_edge_new( memory, &right) ); 1181 1182 left->start_pos = cpos[0]; 1183 left->end_pos = cpos[3]; 1184 left->edge_type = SDF_EDGE_LINE; 1185 1186 right->start_pos = cpos[3]; 1187 right->end_pos = cpos[6]; 1188 right->edge_type = SDF_EDGE_LINE; 1189 1190 left->next = right; 1191 right->next = (*out); 1192 *out = left; 1193 1194 Exit: 1195 return error; 1196 } 1197 1198 1199 /* Subdivide an entire shape into line segments */ 1200 /* such that it doesn't look visually different */ 1201 /* from the original curve. */ 1202 static FT_Error split_sdf_shape(SDF_Shape * shape)1203 split_sdf_shape( SDF_Shape* shape ) 1204 { 1205 FT_Error error = FT_Err_Ok; 1206 FT_Memory memory; 1207 1208 SDF_Contour* contours; 1209 SDF_Contour* new_contours = NULL; 1210 1211 1212 if ( !shape || !shape->memory ) 1213 { 1214 error = FT_THROW( Invalid_Argument ); 1215 goto Exit; 1216 } 1217 1218 contours = shape->contours; 1219 memory = shape->memory; 1220 1221 /* for each contour */ 1222 while ( contours ) 1223 { 1224 SDF_Edge* edges = contours->edges; 1225 SDF_Edge* new_edges = NULL; 1226 1227 SDF_Contour* tempc; 1228 1229 1230 /* for each edge */ 1231 while ( edges ) 1232 { 1233 SDF_Edge* edge = edges; 1234 SDF_Edge* temp; 1235 1236 switch ( edge->edge_type ) 1237 { 1238 case SDF_EDGE_LINE: 1239 /* Just create a duplicate edge in case */ 1240 /* it is a line. We can use the same edge. */ 1241 FT_CALL( sdf_edge_new( memory, &temp ) ); 1242 1243 ft_memcpy( temp, edge, sizeof ( *edge ) ); 1244 1245 temp->next = new_edges; 1246 new_edges = temp; 1247 break; 1248 1249 case SDF_EDGE_CONIC: 1250 /* Subdivide the curve and add it to the list. */ 1251 { 1252 FT_26D6_Vec ctrls[3]; 1253 1254 1255 ctrls[0] = edge->start_pos; 1256 ctrls[1] = edge->control_a; 1257 ctrls[2] = edge->end_pos; 1258 1259 error = split_sdf_conic( memory, ctrls, 32, &new_edges ); 1260 } 1261 break; 1262 1263 case SDF_EDGE_CUBIC: 1264 /* Subdivide the curve and add it to the list. */ 1265 { 1266 FT_26D6_Vec ctrls[4]; 1267 1268 1269 ctrls[0] = edge->start_pos; 1270 ctrls[1] = edge->control_a; 1271 ctrls[2] = edge->control_b; 1272 ctrls[3] = edge->end_pos; 1273 1274 error = split_sdf_cubic( memory, ctrls, 32, &new_edges ); 1275 } 1276 break; 1277 1278 default: 1279 error = FT_THROW( Invalid_Argument ); 1280 goto Exit; 1281 } 1282 1283 edges = edges->next; 1284 } 1285 1286 /* add to the contours list */ 1287 FT_CALL( sdf_contour_new( memory, &tempc ) ); 1288 1289 tempc->next = new_contours; 1290 tempc->edges = new_edges; 1291 new_contours = tempc; 1292 new_edges = NULL; 1293 1294 /* deallocate the contour */ 1295 tempc = contours; 1296 contours = contours->next; 1297 1298 sdf_contour_done( memory, &tempc ); 1299 } 1300 1301 shape->contours = new_contours; 1302 1303 Exit: 1304 return error; 1305 } 1306 1307 1308 /************************************************************************** 1309 * 1310 * for debugging 1311 * 1312 */ 1313 1314 #ifdef FT_DEBUG_LEVEL_TRACE 1315 1316 static void sdf_shape_dump(SDF_Shape * shape)1317 sdf_shape_dump( SDF_Shape* shape ) 1318 { 1319 FT_UInt num_contours = 0; 1320 1321 FT_UInt total_edges = 0; 1322 FT_UInt total_lines = 0; 1323 FT_UInt total_conic = 0; 1324 FT_UInt total_cubic = 0; 1325 1326 SDF_Contour* contour_list; 1327 1328 1329 if ( !shape ) 1330 { 1331 FT_TRACE5(( "sdf_shape_dump: null shape\n" )); 1332 return; 1333 } 1334 1335 contour_list = shape->contours; 1336 1337 FT_TRACE5(( "sdf_shape_dump (values are in 26.6 format):\n" )); 1338 1339 while ( contour_list ) 1340 { 1341 FT_UInt num_edges = 0; 1342 SDF_Edge* edge_list; 1343 SDF_Contour* contour = contour_list; 1344 1345 1346 FT_TRACE5(( " Contour %d\n", num_contours )); 1347 1348 edge_list = contour->edges; 1349 1350 while ( edge_list ) 1351 { 1352 SDF_Edge* edge = edge_list; 1353 1354 1355 FT_TRACE5(( " %3d: ", num_edges )); 1356 1357 switch ( edge->edge_type ) 1358 { 1359 case SDF_EDGE_LINE: 1360 FT_TRACE5(( "Line: (%ld, %ld) -- (%ld, %ld)\n", 1361 edge->start_pos.x, edge->start_pos.y, 1362 edge->end_pos.x, edge->end_pos.y )); 1363 total_lines++; 1364 break; 1365 1366 case SDF_EDGE_CONIC: 1367 FT_TRACE5(( "Conic: (%ld, %ld) .. (%ld, %ld) .. (%ld, %ld)\n", 1368 edge->start_pos.x, edge->start_pos.y, 1369 edge->control_a.x, edge->control_a.y, 1370 edge->end_pos.x, edge->end_pos.y )); 1371 total_conic++; 1372 break; 1373 1374 case SDF_EDGE_CUBIC: 1375 FT_TRACE5(( "Cubic: (%ld, %ld) .. (%ld, %ld)" 1376 " .. (%ld, %ld) .. (%ld %ld)\n", 1377 edge->start_pos.x, edge->start_pos.y, 1378 edge->control_a.x, edge->control_a.y, 1379 edge->control_b.x, edge->control_b.y, 1380 edge->end_pos.x, edge->end_pos.y )); 1381 total_cubic++; 1382 break; 1383 1384 default: 1385 break; 1386 } 1387 1388 num_edges++; 1389 total_edges++; 1390 edge_list = edge_list->next; 1391 } 1392 1393 num_contours++; 1394 contour_list = contour_list->next; 1395 } 1396 1397 FT_TRACE5(( "\n" )); 1398 FT_TRACE5(( " total number of contours = %d\n", num_contours )); 1399 FT_TRACE5(( " total number of edges = %d\n", total_edges )); 1400 FT_TRACE5(( " |__lines = %d\n", total_lines )); 1401 FT_TRACE5(( " |__conic = %d\n", total_conic )); 1402 FT_TRACE5(( " |__cubic = %d\n", total_cubic )); 1403 } 1404 1405 #endif /* FT_DEBUG_LEVEL_TRACE */ 1406 1407 1408 /************************************************************************** 1409 * 1410 * math functions 1411 * 1412 */ 1413 1414 #if !USE_NEWTON_FOR_CONIC 1415 1416 /* [NOTE]: All the functions below down until rasterizer */ 1417 /* can be avoided if we decide to subdivide the */ 1418 /* curve into lines. */ 1419 1420 /* This function uses Newton's iteration to find */ 1421 /* the cube root of a fixed-point integer. */ 1422 static FT_16D16 cube_root(FT_16D16 val)1423 cube_root( FT_16D16 val ) 1424 { 1425 /* [IMPORTANT]: This function is not good as it may */ 1426 /* not break, so use a lookup table instead. Or we */ 1427 /* can use an algorithm similar to `square_root`. */ 1428 1429 FT_Int v, g, c; 1430 1431 1432 if ( val == 0 || 1433 val == -FT_INT_16D16( 1 ) || 1434 val == FT_INT_16D16( 1 ) ) 1435 return val; 1436 1437 v = val < 0 ? -val : val; 1438 g = square_root( v ); 1439 c = 0; 1440 1441 while ( 1 ) 1442 { 1443 c = FT_MulFix( FT_MulFix( g, g ), g ) - v; 1444 c = FT_DivFix( c, 3 * FT_MulFix( g, g ) ); 1445 1446 g -= c; 1447 1448 if ( ( c < 0 ? -c : c ) < 30 ) 1449 break; 1450 } 1451 1452 return val < 0 ? -g : g; 1453 } 1454 1455 1456 /* Calculate the perpendicular by using '1 - base^2'. */ 1457 /* Then use arctan to compute the angle. */ 1458 static FT_16D16 arc_cos(FT_16D16 val)1459 arc_cos( FT_16D16 val ) 1460 { 1461 FT_16D16 p; 1462 FT_16D16 b = val; 1463 FT_16D16 one = FT_INT_16D16( 1 ); 1464 1465 1466 if ( b > one ) 1467 b = one; 1468 if ( b < -one ) 1469 b = -one; 1470 1471 p = one - FT_MulFix( b, b ); 1472 p = square_root( p ); 1473 1474 return FT_Atan2( b, p ); 1475 } 1476 1477 1478 /* Compute roots of a quadratic polynomial, assign them to `out`, */ 1479 /* and return number of real roots. */ 1480 /* */ 1481 /* The procedure can be found at */ 1482 /* */ 1483 /* https://mathworld.wolfram.com/QuadraticFormula.html */ 1484 static FT_UShort solve_quadratic_equation(FT_26D6 a,FT_26D6 b,FT_26D6 c,FT_16D16 out[2])1485 solve_quadratic_equation( FT_26D6 a, 1486 FT_26D6 b, 1487 FT_26D6 c, 1488 FT_16D16 out[2] ) 1489 { 1490 FT_16D16 discriminant = 0; 1491 1492 1493 a = FT_26D6_16D16( a ); 1494 b = FT_26D6_16D16( b ); 1495 c = FT_26D6_16D16( c ); 1496 1497 if ( a == 0 ) 1498 { 1499 if ( b == 0 ) 1500 return 0; 1501 else 1502 { 1503 out[0] = FT_DivFix( -c, b ); 1504 1505 return 1; 1506 } 1507 } 1508 1509 discriminant = FT_MulFix( b, b ) - 4 * FT_MulFix( a, c ); 1510 1511 if ( discriminant < 0 ) 1512 return 0; 1513 else if ( discriminant == 0 ) 1514 { 1515 out[0] = FT_DivFix( -b, 2 * a ); 1516 1517 return 1; 1518 } 1519 else 1520 { 1521 discriminant = square_root( discriminant ); 1522 1523 out[0] = FT_DivFix( -b + discriminant, 2 * a ); 1524 out[1] = FT_DivFix( -b - discriminant, 2 * a ); 1525 1526 return 2; 1527 } 1528 } 1529 1530 1531 /* Compute roots of a cubic polynomial, assign them to `out`, */ 1532 /* and return number of real roots. */ 1533 /* */ 1534 /* The procedure can be found at */ 1535 /* */ 1536 /* https://mathworld.wolfram.com/CubicFormula.html */ 1537 static FT_UShort solve_cubic_equation(FT_26D6 a,FT_26D6 b,FT_26D6 c,FT_26D6 d,FT_16D16 out[3])1538 solve_cubic_equation( FT_26D6 a, 1539 FT_26D6 b, 1540 FT_26D6 c, 1541 FT_26D6 d, 1542 FT_16D16 out[3] ) 1543 { 1544 FT_16D16 q = 0; /* intermediate */ 1545 FT_16D16 r = 0; /* intermediate */ 1546 1547 FT_16D16 a2 = b; /* x^2 coefficients */ 1548 FT_16D16 a1 = c; /* x coefficients */ 1549 FT_16D16 a0 = d; /* constant */ 1550 1551 FT_16D16 q3 = 0; 1552 FT_16D16 r2 = 0; 1553 FT_16D16 a23 = 0; 1554 FT_16D16 a22 = 0; 1555 FT_16D16 a1x2 = 0; 1556 1557 1558 /* cutoff value for `a` to be a cubic, otherwise solve quadratic */ 1559 if ( a == 0 || FT_ABS( a ) < 16 ) 1560 return solve_quadratic_equation( b, c, d, out ); 1561 1562 if ( d == 0 ) 1563 { 1564 out[0] = 0; 1565 1566 return solve_quadratic_equation( a, b, c, out + 1 ) + 1; 1567 } 1568 1569 /* normalize the coefficients; this also makes them 16.16 */ 1570 a2 = FT_DivFix( a2, a ); 1571 a1 = FT_DivFix( a1, a ); 1572 a0 = FT_DivFix( a0, a ); 1573 1574 /* compute intermediates */ 1575 a1x2 = FT_MulFix( a1, a2 ); 1576 a22 = FT_MulFix( a2, a2 ); 1577 a23 = FT_MulFix( a22, a2 ); 1578 1579 q = ( 3 * a1 - a22 ) / 9; 1580 r = ( 9 * a1x2 - 27 * a0 - 2 * a23 ) / 54; 1581 1582 /* [BUG]: `q3` and `r2` still cause underflow. */ 1583 1584 q3 = FT_MulFix( q, q ); 1585 q3 = FT_MulFix( q3, q ); 1586 1587 r2 = FT_MulFix( r, r ); 1588 1589 if ( q3 < 0 && r2 < -q3 ) 1590 { 1591 FT_16D16 t = 0; 1592 1593 1594 q3 = square_root( -q3 ); 1595 t = FT_DivFix( r, q3 ); 1596 1597 if ( t > ( 1 << 16 ) ) 1598 t = ( 1 << 16 ); 1599 if ( t < -( 1 << 16 ) ) 1600 t = -( 1 << 16 ); 1601 1602 t = arc_cos( t ); 1603 a2 /= 3; 1604 q = 2 * square_root( -q ); 1605 1606 out[0] = FT_MulFix( q, FT_Cos( t / 3 ) ) - a2; 1607 out[1] = FT_MulFix( q, FT_Cos( ( t + FT_ANGLE_PI * 2 ) / 3 ) ) - a2; 1608 out[2] = FT_MulFix( q, FT_Cos( ( t + FT_ANGLE_PI * 4 ) / 3 ) ) - a2; 1609 1610 return 3; 1611 } 1612 1613 else if ( r2 == -q3 ) 1614 { 1615 FT_16D16 s = 0; 1616 1617 1618 s = cube_root( r ); 1619 a2 /= -3; 1620 1621 out[0] = a2 + ( 2 * s ); 1622 out[1] = a2 - s; 1623 1624 return 2; 1625 } 1626 1627 else 1628 { 1629 FT_16D16 s = 0; 1630 FT_16D16 t = 0; 1631 FT_16D16 dis = 0; 1632 1633 1634 if ( q3 == 0 ) 1635 dis = FT_ABS( r ); 1636 else 1637 dis = square_root( q3 + r2 ); 1638 1639 s = cube_root( r + dis ); 1640 t = cube_root( r - dis ); 1641 a2 /= -3; 1642 out[0] = ( a2 + ( s + t ) ); 1643 1644 return 1; 1645 } 1646 } 1647 1648 #endif /* !USE_NEWTON_FOR_CONIC */ 1649 1650 1651 /*************************************************************************/ 1652 /*************************************************************************/ 1653 /** **/ 1654 /** RASTERIZER **/ 1655 /** **/ 1656 /*************************************************************************/ 1657 /*************************************************************************/ 1658 1659 /************************************************************************** 1660 * 1661 * @Function: 1662 * resolve_corner 1663 * 1664 * @Description: 1665 * At some places on the grid two edges can give opposite directions; 1666 * this happens when the closest point is on one of the endpoint. In 1667 * that case we need to check the proper sign. 1668 * 1669 * This can be visualized by an example: 1670 * 1671 * ``` 1672 * x 1673 * 1674 * o 1675 * ^ \ 1676 * / \ 1677 * / \ 1678 * (a) / \ (b) 1679 * / \ 1680 * / \ 1681 * / v 1682 * ``` 1683 * 1684 * Suppose `x` is the point whose shortest distance from an arbitrary 1685 * contour we want to find out. It is clear that `o` is the nearest 1686 * point on the contour. Now to determine the sign we do a cross 1687 * product of the shortest distance vector and the edge direction, i.e., 1688 * 1689 * ``` 1690 * => sign = cross(x - o, direction(a)) 1691 * ``` 1692 * 1693 * Using the right hand thumb rule we can see that the sign will be 1694 * positive. 1695 * 1696 * If we use `b', however, we have 1697 * 1698 * ``` 1699 * => sign = cross(x - o, direction(b)) 1700 * ``` 1701 * 1702 * In this case the sign will be negative. To determine the correct 1703 * sign we thus divide the plane in two halves and check which plane the 1704 * point lies in. 1705 * 1706 * ``` 1707 * | 1708 * x | 1709 * | 1710 * o 1711 * ^|\ 1712 * / | \ 1713 * / | \ 1714 * (a) / | \ (b) 1715 * / | \ 1716 * / \ 1717 * / v 1718 * ``` 1719 * 1720 * We can see that `x` lies in the plane of `a`, so we take the sign 1721 * determined by `a`. This test can be easily done by calculating the 1722 * orthogonality and taking the greater one. 1723 * 1724 * The orthogonality is simply the sinus of the two vectors (i.e., 1725 * x - o) and the corresponding direction. We efficiently pre-compute 1726 * the orthogonality with the corresponding `get_min_distance_*` 1727 * functions. 1728 * 1729 * @Input: 1730 * sdf1 :: 1731 * First signed distance (can be any of `a` or `b`). 1732 * 1733 * sdf1 :: 1734 * Second signed distance (can be any of `a` or `b`). 1735 * 1736 * @Return: 1737 * The correct signed distance, which is computed by using the above 1738 * algorithm. 1739 * 1740 * @Note: 1741 * The function does not care about the actual distance, it simply 1742 * returns the signed distance which has a larger cross product. As a 1743 * consequence, this function should not be used if the two distances 1744 * are fairly apart. In that case simply use the signed distance with 1745 * a shorter absolute distance. 1746 * 1747 */ 1748 static SDF_Signed_Distance resolve_corner(SDF_Signed_Distance sdf1,SDF_Signed_Distance sdf2)1749 resolve_corner( SDF_Signed_Distance sdf1, 1750 SDF_Signed_Distance sdf2 ) 1751 { 1752 return FT_ABS( sdf1.cross ) > FT_ABS( sdf2.cross ) ? sdf1 : sdf2; 1753 } 1754 1755 1756 /************************************************************************** 1757 * 1758 * @Function: 1759 * get_min_distance_line 1760 * 1761 * @Description: 1762 * Find the shortest distance from the `line` segment to a given `point` 1763 * and assign it to `out`. Use it for line segments only. 1764 * 1765 * @Input: 1766 * line :: 1767 * The line segment to which the shortest distance is to be computed. 1768 * 1769 * point :: 1770 * Point from which the shortest distance is to be computed. 1771 * 1772 * @Output: 1773 * out :: 1774 * Signed distance from `point` to `line`. 1775 * 1776 * @Return: 1777 * FreeType error, 0 means success. 1778 * 1779 * @Note: 1780 * The `line' parameter must have an edge type of `SDF_EDGE_LINE`. 1781 * 1782 */ 1783 static FT_Error get_min_distance_line(SDF_Edge * line,FT_26D6_Vec point,SDF_Signed_Distance * out)1784 get_min_distance_line( SDF_Edge* line, 1785 FT_26D6_Vec point, 1786 SDF_Signed_Distance* out ) 1787 { 1788 /* 1789 * In order to calculate the shortest distance from a point to 1790 * a line segment, we do the following. Let's assume that 1791 * 1792 * ``` 1793 * a = start point of the line segment 1794 * b = end point of the line segment 1795 * p = point from which shortest distance is to be calculated 1796 * ``` 1797 * 1798 * (1) Write the parametric equation of the line. 1799 * 1800 * ``` 1801 * point_on_line = a + (b - a) * t (t is the factor) 1802 * ``` 1803 * 1804 * (2) Find the projection of point `p` on the line. The projection 1805 * will be perpendicular to the line, which allows us to get the 1806 * solution by making the dot product zero. 1807 * 1808 * ``` 1809 * (point_on_line - a) . (p - point_on_line) = 0 1810 * 1811 * (point_on_line) 1812 * (a) x-------o----------------x (b) 1813 * |_| 1814 * | 1815 * | 1816 * (p) 1817 * ``` 1818 * 1819 * (3) Simplification of the above equation yields the factor of 1820 * `point_on_line`: 1821 * 1822 * ``` 1823 * t = ((p - a) . (b - a)) / |b - a|^2 1824 * ``` 1825 * 1826 * (4) We clamp factor `t` between [0.0f, 1.0f] because `point_on_line` 1827 * can be outside of the line segment: 1828 * 1829 * ``` 1830 * (point_on_line) 1831 * (a) x------------------------x (b) -----o--- 1832 * |_| 1833 * | 1834 * | 1835 * (p) 1836 * ``` 1837 * 1838 * (5) Finally, the distance we are interested in is 1839 * 1840 * ``` 1841 * |point_on_line - p| 1842 * ``` 1843 */ 1844 1845 FT_Error error = FT_Err_Ok; 1846 1847 FT_Vector a; /* start position */ 1848 FT_Vector b; /* end position */ 1849 FT_Vector p; /* current point */ 1850 1851 FT_26D6_Vec line_segment; /* `b` - `a` */ 1852 FT_26D6_Vec p_sub_a; /* `p` - `a` */ 1853 1854 FT_26D6 sq_line_length; /* squared length of `line_segment` */ 1855 FT_16D16 factor; /* factor of the nearest point */ 1856 FT_26D6 cross; /* used to determine sign */ 1857 1858 FT_16D16_Vec nearest_point; /* `point_on_line` */ 1859 FT_16D16_Vec nearest_vector; /* `p` - `nearest_point` */ 1860 1861 1862 if ( !line || !out ) 1863 { 1864 error = FT_THROW( Invalid_Argument ); 1865 goto Exit; 1866 } 1867 1868 if ( line->edge_type != SDF_EDGE_LINE ) 1869 { 1870 error = FT_THROW( Invalid_Argument ); 1871 goto Exit; 1872 } 1873 1874 a = line->start_pos; 1875 b = line->end_pos; 1876 p = point; 1877 1878 line_segment.x = b.x - a.x; 1879 line_segment.y = b.y - a.y; 1880 1881 p_sub_a.x = p.x - a.x; 1882 p_sub_a.y = p.y - a.y; 1883 1884 sq_line_length = ( line_segment.x * line_segment.x ) / 64 + 1885 ( line_segment.y * line_segment.y ) / 64; 1886 1887 /* currently factor is 26.6 */ 1888 factor = ( p_sub_a.x * line_segment.x ) / 64 + 1889 ( p_sub_a.y * line_segment.y ) / 64; 1890 1891 /* now factor is 16.16 */ 1892 factor = FT_DivFix( factor, sq_line_length ); 1893 1894 /* clamp the factor between 0.0 and 1.0 in fixed point */ 1895 if ( factor > FT_INT_16D16( 1 ) ) 1896 factor = FT_INT_16D16( 1 ); 1897 if ( factor < 0 ) 1898 factor = 0; 1899 1900 nearest_point.x = FT_MulFix( FT_26D6_16D16( line_segment.x ), 1901 factor ); 1902 nearest_point.y = FT_MulFix( FT_26D6_16D16( line_segment.y ), 1903 factor ); 1904 1905 nearest_point.x = FT_26D6_16D16( a.x ) + nearest_point.x; 1906 nearest_point.y = FT_26D6_16D16( a.y ) + nearest_point.y; 1907 1908 nearest_vector.x = nearest_point.x - FT_26D6_16D16( p.x ); 1909 nearest_vector.y = nearest_point.y - FT_26D6_16D16( p.y ); 1910 1911 cross = FT_MulFix( nearest_vector.x, line_segment.y ) - 1912 FT_MulFix( nearest_vector.y, line_segment.x ); 1913 1914 /* assign the output */ 1915 out->sign = cross < 0 ? 1 : -1; 1916 out->distance = VECTOR_LENGTH_16D16( nearest_vector ); 1917 1918 /* Instead of finding `cross` for checking corner we */ 1919 /* directly set it here. This is more efficient */ 1920 /* because if the distance is perpendicular we can */ 1921 /* directly set it to 1. */ 1922 if ( factor != 0 && factor != FT_INT_16D16( 1 ) ) 1923 out->cross = FT_INT_16D16( 1 ); 1924 else 1925 { 1926 /* [OPTIMIZATION]: Pre-compute this direction. */ 1927 /* If not perpendicular then compute `cross`. */ 1928 FT_Vector_NormLen( &line_segment ); 1929 FT_Vector_NormLen( &nearest_vector ); 1930 1931 out->cross = FT_MulFix( line_segment.x, nearest_vector.y ) - 1932 FT_MulFix( line_segment.y, nearest_vector.x ); 1933 } 1934 1935 Exit: 1936 return error; 1937 } 1938 1939 1940 /************************************************************************** 1941 * 1942 * @Function: 1943 * get_min_distance_conic 1944 * 1945 * @Description: 1946 * Find the shortest distance from the `conic` Bezier curve to a given 1947 * `point` and assign it to `out`. Use it for conic/quadratic curves 1948 * only. 1949 * 1950 * @Input: 1951 * conic :: 1952 * The conic Bezier curve to which the shortest distance is to be 1953 * computed. 1954 * 1955 * point :: 1956 * Point from which the shortest distance is to be computed. 1957 * 1958 * @Output: 1959 * out :: 1960 * Signed distance from `point` to `conic`. 1961 * 1962 * @Return: 1963 * FreeType error, 0 means success. 1964 * 1965 * @Note: 1966 * The `conic` parameter must have an edge type of `SDF_EDGE_CONIC`. 1967 * 1968 */ 1969 1970 #if !USE_NEWTON_FOR_CONIC 1971 1972 /* 1973 * The function uses an analytical method to find the shortest distance 1974 * which is faster than the Newton-Raphson method, but has underflows at 1975 * the moment. Use Newton's method if you can see artifacts in the SDF. 1976 */ 1977 static FT_Error get_min_distance_conic(SDF_Edge * conic,FT_26D6_Vec point,SDF_Signed_Distance * out)1978 get_min_distance_conic( SDF_Edge* conic, 1979 FT_26D6_Vec point, 1980 SDF_Signed_Distance* out ) 1981 { 1982 /* 1983 * The procedure to find the shortest distance from a point to a 1984 * quadratic Bezier curve is similar to the line segment algorithm. The 1985 * shortest distance is perpendicular to the Bezier curve; the only 1986 * difference from line is that there can be more than one 1987 * perpendicular, and we also have to check the endpoints, because the 1988 * perpendicular may not be the shortest. 1989 * 1990 * Let's assume that 1991 * ``` 1992 * p0 = first endpoint 1993 * p1 = control point 1994 * p2 = second endpoint 1995 * p = point from which shortest distance is to be calculated 1996 * ``` 1997 * 1998 * (1) The equation of a quadratic Bezier curve can be written as 1999 * 2000 * ``` 2001 * B(t) = (1 - t)^2 * p0 + 2(1 - t)t * p1 + t^2 * p2 2002 * ``` 2003 * 2004 * with `t` a factor in the range [0.0f, 1.0f]. This equation can 2005 * be rewritten as 2006 * 2007 * ``` 2008 * B(t) = t^2 * (p0 - 2p1 + p2) + 2t * (p1 - p0) + p0 2009 * ``` 2010 * 2011 * With 2012 * 2013 * ``` 2014 * A = p0 - 2p1 + p2 2015 * B = p1 - p0 2016 * ``` 2017 * 2018 * we have 2019 * 2020 * ``` 2021 * B(t) = t^2 * A + 2t * B + p0 2022 * ``` 2023 * 2024 * (2) The derivative of the last equation above is 2025 * 2026 * ``` 2027 * B'(t) = 2 *(tA + B) 2028 * ``` 2029 * 2030 * (3) To find the shortest distance from `p` to `B(t)` we find the 2031 * point on the curve at which the shortest distance vector (i.e., 2032 * `B(t) - p`) and the direction (i.e., `B'(t)`) make 90 degrees. 2033 * In other words, we make the dot product zero. 2034 * 2035 * ``` 2036 * (B(t) - p) . (B'(t)) = 0 2037 * (t^2 * A + 2t * B + p0 - p) . (2 * (tA + B)) = 0 2038 * ``` 2039 * 2040 * After simplifying we get a cubic equation 2041 * 2042 * ``` 2043 * at^3 + bt^2 + ct + d = 0 2044 * ``` 2045 * 2046 * with 2047 * 2048 * ``` 2049 * a = A.A 2050 * b = 3A.B 2051 * c = 2B.B + A.p0 - A.p 2052 * d = p0.B - p.B 2053 * ``` 2054 * 2055 * (4) Now the roots of the equation can be computed using 'Cardano's 2056 * Cubic formula'; we clamp the roots in the range [0.0f, 1.0f]. 2057 * 2058 * [note]: `B` and `B(t)` are different in the above equations. 2059 */ 2060 2061 FT_Error error = FT_Err_Ok; 2062 2063 FT_26D6_Vec aA, bB; /* A, B in the above comment */ 2064 FT_26D6_Vec nearest_point; /* point on curve nearest to `point` */ 2065 FT_26D6_Vec direction; /* direction of curve at `nearest_point` */ 2066 2067 FT_26D6_Vec p0, p1, p2; /* control points of a conic curve */ 2068 FT_26D6_Vec p; /* `point` to which shortest distance */ 2069 2070 FT_26D6 a, b, c, d; /* cubic coefficients */ 2071 2072 FT_16D16 roots[3] = { 0, 0, 0 }; /* real roots of the cubic eq. */ 2073 FT_16D16 min_factor; /* factor at `nearest_point` */ 2074 FT_16D16 cross; /* to determine the sign */ 2075 FT_16D16 min = FT_INT_MAX; /* shortest squared distance */ 2076 2077 FT_UShort num_roots; /* number of real roots of cubic */ 2078 FT_UShort i; 2079 2080 2081 if ( !conic || !out ) 2082 { 2083 error = FT_THROW( Invalid_Argument ); 2084 goto Exit; 2085 } 2086 2087 if ( conic->edge_type != SDF_EDGE_CONIC ) 2088 { 2089 error = FT_THROW( Invalid_Argument ); 2090 goto Exit; 2091 } 2092 2093 p0 = conic->start_pos; 2094 p1 = conic->control_a; 2095 p2 = conic->end_pos; 2096 p = point; 2097 2098 /* compute substitution coefficients */ 2099 aA.x = p0.x - 2 * p1.x + p2.x; 2100 aA.y = p0.y - 2 * p1.y + p2.y; 2101 2102 bB.x = p1.x - p0.x; 2103 bB.y = p1.y - p0.y; 2104 2105 /* compute cubic coefficients */ 2106 a = VEC_26D6_DOT( aA, aA ); 2107 2108 b = 3 * VEC_26D6_DOT( aA, bB ); 2109 2110 c = 2 * VEC_26D6_DOT( bB, bB ) + 2111 VEC_26D6_DOT( aA, p0 ) - 2112 VEC_26D6_DOT( aA, p ); 2113 2114 d = VEC_26D6_DOT( p0, bB ) - 2115 VEC_26D6_DOT( p, bB ); 2116 2117 /* find the roots */ 2118 num_roots = solve_cubic_equation( a, b, c, d, roots ); 2119 2120 if ( num_roots == 0 ) 2121 { 2122 roots[0] = 0; 2123 roots[1] = FT_INT_16D16( 1 ); 2124 num_roots = 2; 2125 } 2126 2127 /* [OPTIMIZATION]: Check the roots, clamp them and discard */ 2128 /* duplicate roots. */ 2129 2130 /* convert these values to 16.16 for further computation */ 2131 aA.x = FT_26D6_16D16( aA.x ); 2132 aA.y = FT_26D6_16D16( aA.y ); 2133 2134 bB.x = FT_26D6_16D16( bB.x ); 2135 bB.y = FT_26D6_16D16( bB.y ); 2136 2137 p0.x = FT_26D6_16D16( p0.x ); 2138 p0.y = FT_26D6_16D16( p0.y ); 2139 2140 p.x = FT_26D6_16D16( p.x ); 2141 p.y = FT_26D6_16D16( p.y ); 2142 2143 for ( i = 0; i < num_roots; i++ ) 2144 { 2145 FT_16D16 t = roots[i]; 2146 FT_16D16 t2 = 0; 2147 FT_16D16 dist = 0; 2148 2149 FT_16D16_Vec curve_point; 2150 FT_16D16_Vec dist_vector; 2151 2152 /* 2153 * Ideally we should discard the roots which are outside the range 2154 * [0.0, 1.0] and check the endpoints of the Bezier curve, but Behdad 2155 * Esfahbod proved the following lemma. 2156 * 2157 * Lemma: 2158 * 2159 * (1) If the closest point on the curve [0, 1] is to the endpoint at 2160 * `t` = 1 and the cubic has no real roots at `t` = 1 then the 2161 * cubic must have a real root at some `t` > 1. 2162 * 2163 * (2) Similarly, if the closest point on the curve [0, 1] is to the 2164 * endpoint at `t` = 0 and the cubic has no real roots at `t` = 0 2165 * then the cubic must have a real root at some `t` < 0. 2166 * 2167 * Now because of this lemma we only need to clamp the roots and that 2168 * will take care of the endpoints. 2169 * 2170 * For more details see 2171 * 2172 * https://lists.nongnu.org/archive/html/freetype-devel/2020-06/msg00147.html 2173 */ 2174 2175 if ( t < 0 ) 2176 t = 0; 2177 if ( t > FT_INT_16D16( 1 ) ) 2178 t = FT_INT_16D16( 1 ); 2179 2180 t2 = FT_MulFix( t, t ); 2181 2182 /* B(t) = t^2 * A + 2t * B + p0 - p */ 2183 curve_point.x = FT_MulFix( aA.x, t2 ) + 2184 2 * FT_MulFix( bB.x, t ) + p0.x; 2185 curve_point.y = FT_MulFix( aA.y, t2 ) + 2186 2 * FT_MulFix( bB.y, t ) + p0.y; 2187 2188 /* `curve_point` - `p` */ 2189 dist_vector.x = curve_point.x - p.x; 2190 dist_vector.y = curve_point.y - p.y; 2191 2192 dist = VECTOR_LENGTH_16D16( dist_vector ); 2193 2194 if ( dist < min ) 2195 { 2196 min = dist; 2197 nearest_point = curve_point; 2198 min_factor = t; 2199 } 2200 } 2201 2202 /* B'(t) = 2 * (tA + B) */ 2203 direction.x = 2 * FT_MulFix( aA.x, min_factor ) + 2 * bB.x; 2204 direction.y = 2 * FT_MulFix( aA.y, min_factor ) + 2 * bB.y; 2205 2206 /* determine the sign */ 2207 cross = FT_MulFix( nearest_point.x - p.x, direction.y ) - 2208 FT_MulFix( nearest_point.y - p.y, direction.x ); 2209 2210 /* assign the values */ 2211 out->distance = min; 2212 out->sign = cross < 0 ? 1 : -1; 2213 2214 if ( min_factor != 0 && min_factor != FT_INT_16D16( 1 ) ) 2215 out->cross = FT_INT_16D16( 1 ); /* the two are perpendicular */ 2216 else 2217 { 2218 /* convert to nearest vector */ 2219 nearest_point.x -= FT_26D6_16D16( p.x ); 2220 nearest_point.y -= FT_26D6_16D16( p.y ); 2221 2222 /* compute `cross` if not perpendicular */ 2223 FT_Vector_NormLen( &direction ); 2224 FT_Vector_NormLen( &nearest_point ); 2225 2226 out->cross = FT_MulFix( direction.x, nearest_point.y ) - 2227 FT_MulFix( direction.y, nearest_point.x ); 2228 } 2229 2230 Exit: 2231 return error; 2232 } 2233 2234 #else /* USE_NEWTON_FOR_CONIC */ 2235 2236 /* 2237 * The function uses Newton's approximation to find the shortest distance, 2238 * which is a bit slower than the analytical method but doesn't cause 2239 * underflow. 2240 */ 2241 static FT_Error get_min_distance_conic(SDF_Edge * conic,FT_26D6_Vec point,SDF_Signed_Distance * out)2242 get_min_distance_conic( SDF_Edge* conic, 2243 FT_26D6_Vec point, 2244 SDF_Signed_Distance* out ) 2245 { 2246 /* 2247 * This method uses Newton-Raphson's approximation to find the shortest 2248 * distance from a point to a conic curve. It does not involve solving 2249 * any cubic equation, that is why there is no risk of underflow. 2250 * 2251 * Let's assume that 2252 * 2253 * ``` 2254 * p0 = first endpoint 2255 * p1 = control point 2256 * p3 = second endpoint 2257 * p = point from which shortest distance is to be calculated 2258 * ``` 2259 * 2260 * (1) The equation of a quadratic Bezier curve can be written as 2261 * 2262 * ``` 2263 * B(t) = (1 - t)^2 * p0 + 2(1 - t)t * p1 + t^2 * p2 2264 * ``` 2265 * 2266 * with `t` the factor in the range [0.0f, 1.0f]. The above 2267 * equation can be rewritten as 2268 * 2269 * ``` 2270 * B(t) = t^2 * (p0 - 2p1 + p2) + 2t * (p1 - p0) + p0 2271 * ``` 2272 * 2273 * With 2274 * 2275 * ``` 2276 * A = p0 - 2p1 + p2 2277 * B = 2 * (p1 - p0) 2278 * ``` 2279 * 2280 * we have 2281 * 2282 * ``` 2283 * B(t) = t^2 * A + t * B + p0 2284 * ``` 2285 * 2286 * (2) The derivative of the above equation is 2287 * 2288 * ``` 2289 * B'(t) = 2t * A + B 2290 * ``` 2291 * 2292 * (3) The second derivative of the above equation is 2293 * 2294 * ``` 2295 * B''(t) = 2A 2296 * ``` 2297 * 2298 * (4) The equation `P(t)` of the distance from point `p` to the curve 2299 * can be written as 2300 * 2301 * ``` 2302 * P(t) = t^2 * A + t^2 * B + p0 - p 2303 * ``` 2304 * 2305 * With 2306 * 2307 * ``` 2308 * C = p0 - p 2309 * ``` 2310 * 2311 * we have 2312 * 2313 * ``` 2314 * P(t) = t^2 * A + t * B + C 2315 * ``` 2316 * 2317 * (5) Finally, the equation of the angle between `B(t)` and `P(t)` can 2318 * be written as 2319 * 2320 * ``` 2321 * Q(t) = P(t) . B'(t) 2322 * ``` 2323 * 2324 * (6) Our task is to find a value of `t` such that the above equation 2325 * `Q(t)` becomes zero, this is, the point-to-curve vector makes 2326 * 90~degrees with the curve. We solve this with the Newton-Raphson 2327 * method. 2328 * 2329 * (7) We first assume an arbitary value of factor `t`, which we then 2330 * improve. 2331 * 2332 * ``` 2333 * t := Q(t) / Q'(t) 2334 * ``` 2335 * 2336 * Putting the value of `Q(t)` from the above equation gives 2337 * 2338 * ``` 2339 * t := P(t) . B'(t) / derivative(P(t) . B'(t)) 2340 * t := P(t) . B'(t) / 2341 * (P'(t) . B'(t) + P(t) . B''(t)) 2342 * ``` 2343 * 2344 * Note that `P'(t)` is the same as `B'(t)` because the constant is 2345 * gone due to the derivative. 2346 * 2347 * (8) Finally we get the equation to improve the factor as 2348 * 2349 * ``` 2350 * t := P(t) . B'(t) / 2351 * (B'(t) . B'(t) + P(t) . B''(t)) 2352 * ``` 2353 * 2354 * [note]: `B` and `B(t)` are different in the above equations. 2355 */ 2356 2357 FT_Error error = FT_Err_Ok; 2358 2359 FT_26D6_Vec aA, bB, cC; /* A, B, C in the above comment */ 2360 FT_26D6_Vec nearest_point; /* point on curve nearest to `point` */ 2361 FT_26D6_Vec direction; /* direction of curve at `nearest_point` */ 2362 2363 FT_26D6_Vec p0, p1, p2; /* control points of a conic curve */ 2364 FT_26D6_Vec p; /* `point` to which shortest distance */ 2365 2366 FT_16D16 min_factor = 0; /* factor at `nearest_point' */ 2367 FT_16D16 cross; /* to determine the sign */ 2368 FT_16D16 min = FT_INT_MAX; /* shortest squared distance */ 2369 2370 FT_UShort iterations; 2371 FT_UShort steps; 2372 2373 2374 if ( !conic || !out ) 2375 { 2376 error = FT_THROW( Invalid_Argument ); 2377 goto Exit; 2378 } 2379 2380 if ( conic->edge_type != SDF_EDGE_CONIC ) 2381 { 2382 error = FT_THROW( Invalid_Argument ); 2383 goto Exit; 2384 } 2385 2386 p0 = conic->start_pos; 2387 p1 = conic->control_a; 2388 p2 = conic->end_pos; 2389 p = point; 2390 2391 /* compute substitution coefficients */ 2392 aA.x = p0.x - 2 * p1.x + p2.x; 2393 aA.y = p0.y - 2 * p1.y + p2.y; 2394 2395 bB.x = 2 * ( p1.x - p0.x ); 2396 bB.y = 2 * ( p1.y - p0.y ); 2397 2398 cC.x = p0.x; 2399 cC.y = p0.y; 2400 2401 /* do Newton's iterations */ 2402 for ( iterations = 0; iterations <= MAX_NEWTON_DIVISIONS; iterations++ ) 2403 { 2404 FT_16D16 factor = FT_INT_16D16( iterations ) / MAX_NEWTON_DIVISIONS; 2405 FT_16D16 factor2; 2406 FT_16D16 length; 2407 2408 FT_16D16_Vec curve_point; /* point on the curve */ 2409 FT_16D16_Vec dist_vector; /* `curve_point` - `p` */ 2410 2411 FT_26D6_Vec d1; /* first derivative */ 2412 FT_26D6_Vec d2; /* second derivative */ 2413 2414 FT_16D16 temp1; 2415 FT_16D16 temp2; 2416 2417 2418 for ( steps = 0; steps < MAX_NEWTON_STEPS; steps++ ) 2419 { 2420 factor2 = FT_MulFix( factor, factor ); 2421 2422 /* B(t) = t^2 * A + t * B + p0 */ 2423 curve_point.x = FT_MulFix( aA.x, factor2 ) + 2424 FT_MulFix( bB.x, factor ) + cC.x; 2425 curve_point.y = FT_MulFix( aA.y, factor2 ) + 2426 FT_MulFix( bB.y, factor ) + cC.y; 2427 2428 /* convert to 16.16 */ 2429 curve_point.x = FT_26D6_16D16( curve_point.x ); 2430 curve_point.y = FT_26D6_16D16( curve_point.y ); 2431 2432 /* P(t) in the comment */ 2433 dist_vector.x = curve_point.x - FT_26D6_16D16( p.x ); 2434 dist_vector.y = curve_point.y - FT_26D6_16D16( p.y ); 2435 2436 length = VECTOR_LENGTH_16D16( dist_vector ); 2437 2438 if ( length < min ) 2439 { 2440 min = length; 2441 min_factor = factor; 2442 nearest_point = curve_point; 2443 } 2444 2445 /* This is Newton's approximation. */ 2446 /* */ 2447 /* t := P(t) . B'(t) / */ 2448 /* (B'(t) . B'(t) + P(t) . B''(t)) */ 2449 2450 /* B'(t) = 2tA + B */ 2451 d1.x = FT_MulFix( aA.x, 2 * factor ) + bB.x; 2452 d1.y = FT_MulFix( aA.y, 2 * factor ) + bB.y; 2453 2454 /* B''(t) = 2A */ 2455 d2.x = 2 * aA.x; 2456 d2.y = 2 * aA.y; 2457 2458 dist_vector.x /= 1024; 2459 dist_vector.y /= 1024; 2460 2461 /* temp1 = P(t) . B'(t) */ 2462 temp1 = VEC_26D6_DOT( dist_vector, d1 ); 2463 2464 /* temp2 = B'(t) . B'(t) + P(t) . B''(t) */ 2465 temp2 = VEC_26D6_DOT( d1, d1 ) + 2466 VEC_26D6_DOT( dist_vector, d2 ); 2467 2468 factor -= FT_DivFix( temp1, temp2 ); 2469 2470 if ( factor < 0 || factor > FT_INT_16D16( 1 ) ) 2471 break; 2472 } 2473 } 2474 2475 /* B'(t) = 2t * A + B */ 2476 direction.x = 2 * FT_MulFix( aA.x, min_factor ) + bB.x; 2477 direction.y = 2 * FT_MulFix( aA.y, min_factor ) + bB.y; 2478 2479 /* determine the sign */ 2480 cross = FT_MulFix( nearest_point.x - FT_26D6_16D16( p.x ), 2481 direction.y ) - 2482 FT_MulFix( nearest_point.y - FT_26D6_16D16( p.y ), 2483 direction.x ); 2484 2485 /* assign the values */ 2486 out->distance = min; 2487 out->sign = cross < 0 ? 1 : -1; 2488 2489 if ( min_factor != 0 && min_factor != FT_INT_16D16( 1 ) ) 2490 out->cross = FT_INT_16D16( 1 ); /* the two are perpendicular */ 2491 else 2492 { 2493 /* convert to nearest vector */ 2494 nearest_point.x -= FT_26D6_16D16( p.x ); 2495 nearest_point.y -= FT_26D6_16D16( p.y ); 2496 2497 /* compute `cross` if not perpendicular */ 2498 FT_Vector_NormLen( &direction ); 2499 FT_Vector_NormLen( &nearest_point ); 2500 2501 out->cross = FT_MulFix( direction.x, nearest_point.y ) - 2502 FT_MulFix( direction.y, nearest_point.x ); 2503 } 2504 2505 Exit: 2506 return error; 2507 } 2508 2509 2510 #endif /* USE_NEWTON_FOR_CONIC */ 2511 2512 2513 /************************************************************************** 2514 * 2515 * @Function: 2516 * get_min_distance_cubic 2517 * 2518 * @Description: 2519 * Find the shortest distance from the `cubic` Bezier curve to a given 2520 * `point` and assigns it to `out`. Use it for cubic curves only. 2521 * 2522 * @Input: 2523 * cubic :: 2524 * The cubic Bezier curve to which the shortest distance is to be 2525 * computed. 2526 * 2527 * point :: 2528 * Point from which the shortest distance is to be computed. 2529 * 2530 * @Output: 2531 * out :: 2532 * Signed distance from `point` to `cubic`. 2533 * 2534 * @Return: 2535 * FreeType error, 0 means success. 2536 * 2537 * @Note: 2538 * The function uses Newton's approximation to find the shortest 2539 * distance. Another way would be to divide the cubic into conic or 2540 * subdivide the curve into lines, but that is not implemented. 2541 * 2542 * The `cubic` parameter must have an edge type of `SDF_EDGE_CUBIC`. 2543 * 2544 */ 2545 static FT_Error get_min_distance_cubic(SDF_Edge * cubic,FT_26D6_Vec point,SDF_Signed_Distance * out)2546 get_min_distance_cubic( SDF_Edge* cubic, 2547 FT_26D6_Vec point, 2548 SDF_Signed_Distance* out ) 2549 { 2550 /* 2551 * The procedure to find the shortest distance from a point to a cubic 2552 * Bezier curve is similar to quadratic curve algorithm. The only 2553 * difference is that while calculating factor `t`, instead of a cubic 2554 * polynomial equation we have to find the roots of a 5th degree 2555 * polynomial equation. Solving this would require a significant amount 2556 * of time, and still the results may not be accurate. We are thus 2557 * going to directly approximate the value of `t` using the Newton-Raphson 2558 * method. 2559 * 2560 * Let's assume that 2561 * 2562 * ``` 2563 * p0 = first endpoint 2564 * p1 = first control point 2565 * p2 = second control point 2566 * p3 = second endpoint 2567 * p = point from which shortest distance is to be calculated 2568 * ``` 2569 * 2570 * (1) The equation of a cubic Bezier curve can be written as 2571 * 2572 * ``` 2573 * B(t) = (1 - t)^3 * p0 + 3(1 - t)^2 t * p1 + 2574 * 3(1 - t)t^2 * p2 + t^3 * p3 2575 * ``` 2576 * 2577 * The equation can be expanded and written as 2578 * 2579 * ``` 2580 * B(t) = t^3 * (-p0 + 3p1 - 3p2 + p3) + 2581 * 3t^2 * (p0 - 2p1 + p2) + 3t * (-p0 + p1) + p0 2582 * ``` 2583 * 2584 * With 2585 * 2586 * ``` 2587 * A = -p0 + 3p1 - 3p2 + p3 2588 * B = 3(p0 - 2p1 + p2) 2589 * C = 3(-p0 + p1) 2590 * ``` 2591 * 2592 * we have 2593 * 2594 * ``` 2595 * B(t) = t^3 * A + t^2 * B + t * C + p0 2596 * ``` 2597 * 2598 * (2) The derivative of the above equation is 2599 * 2600 * ``` 2601 * B'(t) = 3t^2 * A + 2t * B + C 2602 * ``` 2603 * 2604 * (3) The second derivative of the above equation is 2605 * 2606 * ``` 2607 * B''(t) = 6t * A + 2B 2608 * ``` 2609 * 2610 * (4) The equation `P(t)` of the distance from point `p` to the curve 2611 * can be written as 2612 * 2613 * ``` 2614 * P(t) = t^3 * A + t^2 * B + t * C + p0 - p 2615 * ``` 2616 * 2617 * With 2618 * 2619 * ``` 2620 * D = p0 - p 2621 * ``` 2622 * 2623 * we have 2624 * 2625 * ``` 2626 * P(t) = t^3 * A + t^2 * B + t * C + D 2627 * ``` 2628 * 2629 * (5) Finally the equation of the angle between `B(t)` and `P(t)` can 2630 * be written as 2631 * 2632 * ``` 2633 * Q(t) = P(t) . B'(t) 2634 * ``` 2635 * 2636 * (6) Our task is to find a value of `t` such that the above equation 2637 * `Q(t)` becomes zero, this is, the point-to-curve vector makes 2638 * 90~degree with curve. We solve this with the Newton-Raphson 2639 * method. 2640 * 2641 * (7) We first assume an arbitary value of factor `t`, which we then 2642 * improve. 2643 * 2644 * ``` 2645 * t := Q(t) / Q'(t) 2646 * ``` 2647 * 2648 * Putting the value of `Q(t)` from the above equation gives 2649 * 2650 * ``` 2651 * t := P(t) . B'(t) / derivative(P(t) . B'(t)) 2652 * t := P(t) . B'(t) / 2653 * (P'(t) . B'(t) + P(t) . B''(t)) 2654 * ``` 2655 * 2656 * Note that `P'(t)` is the same as `B'(t)` because the constant is 2657 * gone due to the derivative. 2658 * 2659 * (8) Finally we get the equation to improve the factor as 2660 * 2661 * ``` 2662 * t := P(t) . B'(t) / 2663 * (B'(t) . B'( t ) + P(t) . B''(t)) 2664 * ``` 2665 * 2666 * [note]: `B` and `B(t)` are different in the above equations. 2667 */ 2668 2669 FT_Error error = FT_Err_Ok; 2670 2671 FT_26D6_Vec aA, bB, cC, dD; /* A, B, C in the above comment */ 2672 FT_16D16_Vec nearest_point; /* point on curve nearest to `point` */ 2673 FT_16D16_Vec direction; /* direction of curve at `nearest_point` */ 2674 2675 FT_26D6_Vec p0, p1, p2, p3; /* control points of a cubic curve */ 2676 FT_26D6_Vec p; /* `point` to which shortest distance */ 2677 2678 FT_16D16 min_factor = 0; /* factor at shortest distance */ 2679 FT_16D16 min_factor_sq = 0; /* factor at shortest distance */ 2680 FT_16D16 cross; /* to determine the sign */ 2681 FT_16D16 min = FT_INT_MAX; /* shortest distance */ 2682 2683 FT_UShort iterations; 2684 FT_UShort steps; 2685 2686 2687 if ( !cubic || !out ) 2688 { 2689 error = FT_THROW( Invalid_Argument ); 2690 goto Exit; 2691 } 2692 2693 if ( cubic->edge_type != SDF_EDGE_CUBIC ) 2694 { 2695 error = FT_THROW( Invalid_Argument ); 2696 goto Exit; 2697 } 2698 2699 p0 = cubic->start_pos; 2700 p1 = cubic->control_a; 2701 p2 = cubic->control_b; 2702 p3 = cubic->end_pos; 2703 p = point; 2704 2705 /* compute substitution coefficients */ 2706 aA.x = -p0.x + 3 * ( p1.x - p2.x ) + p3.x; 2707 aA.y = -p0.y + 3 * ( p1.y - p2.y ) + p3.y; 2708 2709 bB.x = 3 * ( p0.x - 2 * p1.x + p2.x ); 2710 bB.y = 3 * ( p0.y - 2 * p1.y + p2.y ); 2711 2712 cC.x = 3 * ( p1.x - p0.x ); 2713 cC.y = 3 * ( p1.y - p0.y ); 2714 2715 dD.x = p0.x; 2716 dD.y = p0.y; 2717 2718 for ( iterations = 0; iterations <= MAX_NEWTON_DIVISIONS; iterations++ ) 2719 { 2720 FT_16D16 factor = FT_INT_16D16( iterations ) / MAX_NEWTON_DIVISIONS; 2721 2722 FT_16D16 factor2; /* factor^2 */ 2723 FT_16D16 factor3; /* factor^3 */ 2724 FT_16D16 length; 2725 2726 FT_16D16_Vec curve_point; /* point on the curve */ 2727 FT_16D16_Vec dist_vector; /* `curve_point' - `p' */ 2728 2729 FT_26D6_Vec d1; /* first derivative */ 2730 FT_26D6_Vec d2; /* second derivative */ 2731 2732 FT_16D16 temp1; 2733 FT_16D16 temp2; 2734 2735 2736 for ( steps = 0; steps < MAX_NEWTON_STEPS; steps++ ) 2737 { 2738 factor2 = FT_MulFix( factor, factor ); 2739 factor3 = FT_MulFix( factor2, factor ); 2740 2741 /* B(t) = t^3 * A + t^2 * B + t * C + D */ 2742 curve_point.x = FT_MulFix( aA.x, factor3 ) + 2743 FT_MulFix( bB.x, factor2 ) + 2744 FT_MulFix( cC.x, factor ) + dD.x; 2745 curve_point.y = FT_MulFix( aA.y, factor3 ) + 2746 FT_MulFix( bB.y, factor2 ) + 2747 FT_MulFix( cC.y, factor ) + dD.y; 2748 2749 /* convert to 16.16 */ 2750 curve_point.x = FT_26D6_16D16( curve_point.x ); 2751 curve_point.y = FT_26D6_16D16( curve_point.y ); 2752 2753 /* P(t) in the comment */ 2754 dist_vector.x = curve_point.x - FT_26D6_16D16( p.x ); 2755 dist_vector.y = curve_point.y - FT_26D6_16D16( p.y ); 2756 2757 length = VECTOR_LENGTH_16D16( dist_vector ); 2758 2759 if ( length < min ) 2760 { 2761 min = length; 2762 min_factor = factor; 2763 min_factor_sq = factor2; 2764 nearest_point = curve_point; 2765 } 2766 2767 /* This the Newton's approximation. */ 2768 /* */ 2769 /* t := P(t) . B'(t) / */ 2770 /* (B'(t) . B'(t) + P(t) . B''(t)) */ 2771 2772 /* B'(t) = 3t^2 * A + 2t * B + C */ 2773 d1.x = FT_MulFix( aA.x, 3 * factor2 ) + 2774 FT_MulFix( bB.x, 2 * factor ) + cC.x; 2775 d1.y = FT_MulFix( aA.y, 3 * factor2 ) + 2776 FT_MulFix( bB.y, 2 * factor ) + cC.y; 2777 2778 /* B''(t) = 6t * A + 2B */ 2779 d2.x = FT_MulFix( aA.x, 6 * factor ) + 2 * bB.x; 2780 d2.y = FT_MulFix( aA.y, 6 * factor ) + 2 * bB.y; 2781 2782 dist_vector.x /= 1024; 2783 dist_vector.y /= 1024; 2784 2785 /* temp1 = P(t) . B'(t) */ 2786 temp1 = VEC_26D6_DOT( dist_vector, d1 ); 2787 2788 /* temp2 = B'(t) . B'(t) + P(t) . B''(t) */ 2789 temp2 = VEC_26D6_DOT( d1, d1 ) + 2790 VEC_26D6_DOT( dist_vector, d2 ); 2791 2792 factor -= FT_DivFix( temp1, temp2 ); 2793 2794 if ( factor < 0 || factor > FT_INT_16D16( 1 ) ) 2795 break; 2796 } 2797 } 2798 2799 /* B'(t) = 3t^2 * A + 2t * B + C */ 2800 direction.x = FT_MulFix( aA.x, 3 * min_factor_sq ) + 2801 FT_MulFix( bB.x, 2 * min_factor ) + cC.x; 2802 direction.y = FT_MulFix( aA.y, 3 * min_factor_sq ) + 2803 FT_MulFix( bB.y, 2 * min_factor ) + cC.y; 2804 2805 /* determine the sign */ 2806 cross = FT_MulFix( nearest_point.x - FT_26D6_16D16( p.x ), 2807 direction.y ) - 2808 FT_MulFix( nearest_point.y - FT_26D6_16D16( p.y ), 2809 direction.x ); 2810 2811 /* assign the values */ 2812 out->distance = min; 2813 out->sign = cross < 0 ? 1 : -1; 2814 2815 if ( min_factor != 0 && min_factor != FT_INT_16D16( 1 ) ) 2816 out->cross = FT_INT_16D16( 1 ); /* the two are perpendicular */ 2817 else 2818 { 2819 /* convert to nearest vector */ 2820 nearest_point.x -= FT_26D6_16D16( p.x ); 2821 nearest_point.y -= FT_26D6_16D16( p.y ); 2822 2823 /* compute `cross` if not perpendicular */ 2824 FT_Vector_NormLen( &direction ); 2825 FT_Vector_NormLen( &nearest_point ); 2826 2827 out->cross = FT_MulFix( direction.x, nearest_point.y ) - 2828 FT_MulFix( direction.y, nearest_point.x ); 2829 } 2830 2831 Exit: 2832 return error; 2833 } 2834 2835 2836 /************************************************************************** 2837 * 2838 * @Function: 2839 * sdf_edge_get_min_distance 2840 * 2841 * @Description: 2842 * Find shortest distance from `point` to any type of `edge`. It checks 2843 * the edge type and then calls the relevant `get_min_distance_*` 2844 * function. 2845 * 2846 * @Input: 2847 * edge :: 2848 * An edge to which the shortest distance is to be computed. 2849 * 2850 * point :: 2851 * Point from which the shortest distance is to be computed. 2852 * 2853 * @Output: 2854 * out :: 2855 * Signed distance from `point` to `edge`. 2856 * 2857 * @Return: 2858 * FreeType error, 0 means success. 2859 * 2860 */ 2861 static FT_Error sdf_edge_get_min_distance(SDF_Edge * edge,FT_26D6_Vec point,SDF_Signed_Distance * out)2862 sdf_edge_get_min_distance( SDF_Edge* edge, 2863 FT_26D6_Vec point, 2864 SDF_Signed_Distance* out ) 2865 { 2866 FT_Error error = FT_Err_Ok; 2867 2868 2869 if ( !edge || !out ) 2870 { 2871 error = FT_THROW( Invalid_Argument ); 2872 goto Exit; 2873 } 2874 2875 /* edge-specific distance calculation */ 2876 switch ( edge->edge_type ) 2877 { 2878 case SDF_EDGE_LINE: 2879 get_min_distance_line( edge, point, out ); 2880 break; 2881 2882 case SDF_EDGE_CONIC: 2883 get_min_distance_conic( edge, point, out ); 2884 break; 2885 2886 case SDF_EDGE_CUBIC: 2887 get_min_distance_cubic( edge, point, out ); 2888 break; 2889 2890 default: 2891 error = FT_THROW( Invalid_Argument ); 2892 } 2893 2894 Exit: 2895 return error; 2896 } 2897 2898 2899 /* `sdf_generate' is not used at the moment */ 2900 #if 0 2901 2902 #error "DO NOT USE THIS!" 2903 #error "The function still outputs 16-bit data, which might cause memory" 2904 #error "corruption. If required I will add this later." 2905 2906 /************************************************************************** 2907 * 2908 * @Function: 2909 * sdf_contour_get_min_distance 2910 * 2911 * @Description: 2912 * Iterate over all edges that make up the contour, find the shortest 2913 * distance from a point to this contour, and assigns result to `out`. 2914 * 2915 * @Input: 2916 * contour :: 2917 * A contour to which the shortest distance is to be computed. 2918 * 2919 * point :: 2920 * Point from which the shortest distance is to be computed. 2921 * 2922 * @Output: 2923 * out :: 2924 * Signed distance from the `point' to the `contour'. 2925 * 2926 * @Return: 2927 * FreeType error, 0 means success. 2928 * 2929 * @Note: 2930 * The function does not return a signed distance for each edge which 2931 * makes up the contour, it simply returns the shortest of all the 2932 * edges. 2933 * 2934 */ 2935 static FT_Error sdf_contour_get_min_distance(SDF_Contour * contour,FT_26D6_Vec point,SDF_Signed_Distance * out)2936 sdf_contour_get_min_distance( SDF_Contour* contour, 2937 FT_26D6_Vec point, 2938 SDF_Signed_Distance* out ) 2939 { 2940 FT_Error error = FT_Err_Ok; 2941 SDF_Signed_Distance min_dist = max_sdf; 2942 SDF_Edge* edge_list; 2943 2944 2945 if ( !contour || !out ) 2946 { 2947 error = FT_THROW( Invalid_Argument ); 2948 goto Exit; 2949 } 2950 2951 edge_list = contour->edges; 2952 2953 /* iterate over all the edges manually */ 2954 while ( edge_list ) 2955 { 2956 SDF_Signed_Distance current_dist = max_sdf; 2957 FT_16D16 diff; 2958 2959 2960 FT_CALL( sdf_edge_get_min_distance( edge_list, 2961 point, 2962 ¤t_dist ) ); 2963 2964 if ( current_dist.distance >= 0 ) 2965 { 2966 diff = current_dist.distance - min_dist.distance; 2967 2968 2969 if ( FT_ABS(diff ) < CORNER_CHECK_EPSILON ) 2970 min_dist = resolve_corner( min_dist, current_dist ); 2971 else if ( diff < 0 ) 2972 min_dist = current_dist; 2973 } 2974 else 2975 FT_TRACE0(( "sdf_contour_get_min_distance: Overflow.\n" )); 2976 2977 edge_list = edge_list->next; 2978 } 2979 2980 *out = min_dist; 2981 2982 Exit: 2983 return error; 2984 } 2985 2986 2987 /************************************************************************** 2988 * 2989 * @Function: 2990 * sdf_generate 2991 * 2992 * @Description: 2993 * This is the main function that is responsible for generating signed 2994 * distance fields. The function does not align or compute the size of 2995 * `bitmap`; therefore the calling application must set up `bitmap` 2996 * properly and transform the `shape' appropriately in advance. 2997 * 2998 * Currently we check all pixels against all contours and all edges. 2999 * 3000 * @Input: 3001 * internal_params :: 3002 * Internal parameters and properties required by the rasterizer. See 3003 * @SDF_Params for more. 3004 * 3005 * shape :: 3006 * A complete shape which is used to generate SDF. 3007 * 3008 * spread :: 3009 * Maximum distances to be allowed in the output bitmap. 3010 * 3011 * @Output: 3012 * bitmap :: 3013 * The output bitmap which will contain the SDF information. 3014 * 3015 * @Return: 3016 * FreeType error, 0 means success. 3017 * 3018 */ 3019 static FT_Error sdf_generate(const SDF_Params internal_params,const SDF_Shape * shape,FT_UInt spread,const FT_Bitmap * bitmap)3020 sdf_generate( const SDF_Params internal_params, 3021 const SDF_Shape* shape, 3022 FT_UInt spread, 3023 const FT_Bitmap* bitmap ) 3024 { 3025 FT_Error error = FT_Err_Ok; 3026 3027 FT_UInt width = 0; 3028 FT_UInt rows = 0; 3029 FT_UInt x = 0; /* used to loop in x direction, i.e., width */ 3030 FT_UInt y = 0; /* used to loop in y direction, i.e., rows */ 3031 FT_UInt sp_sq = 0; /* `spread` [* `spread`] as a 16.16 fixed value */ 3032 3033 FT_Short* buffer; 3034 3035 3036 if ( !shape || !bitmap ) 3037 { 3038 error = FT_THROW( Invalid_Argument ); 3039 goto Exit; 3040 } 3041 3042 if ( spread < MIN_SPREAD || spread > MAX_SPREAD ) 3043 { 3044 error = FT_THROW( Invalid_Argument ); 3045 goto Exit; 3046 } 3047 3048 width = bitmap->width; 3049 rows = bitmap->rows; 3050 buffer = (FT_Short*)bitmap->buffer; 3051 3052 if ( USE_SQUARED_DISTANCES ) 3053 sp_sq = FT_INT_16D16( spread * spread ); 3054 else 3055 sp_sq = FT_INT_16D16( spread ); 3056 3057 if ( width == 0 || rows == 0 ) 3058 { 3059 FT_TRACE0(( "sdf_generate:" 3060 " Cannot render glyph with width/height == 0\n" )); 3061 FT_TRACE0(( " " 3062 " (width, height provided [%d, %d])\n", 3063 width, rows )); 3064 3065 error = FT_THROW( Cannot_Render_Glyph ); 3066 goto Exit; 3067 } 3068 3069 /* loop over all rows */ 3070 for ( y = 0; y < rows; y++ ) 3071 { 3072 /* loop over all pixels of a row */ 3073 for ( x = 0; x < width; x++ ) 3074 { 3075 /* `grid_point` is the current pixel position; */ 3076 /* our task is to find the shortest distance */ 3077 /* from this point to the entire shape. */ 3078 FT_26D6_Vec grid_point = zero_vector; 3079 SDF_Signed_Distance min_dist = max_sdf; 3080 SDF_Contour* contour_list; 3081 3082 FT_UInt index; 3083 FT_Short value; 3084 3085 3086 grid_point.x = FT_INT_26D6( x ); 3087 grid_point.y = FT_INT_26D6( y ); 3088 3089 /* This `grid_point' is at the corner, but we */ 3090 /* use the center of the pixel. */ 3091 grid_point.x += FT_INT_26D6( 1 ) / 2; 3092 grid_point.y += FT_INT_26D6( 1 ) / 2; 3093 3094 contour_list = shape->contours; 3095 3096 /* iterate over all contours manually */ 3097 while ( contour_list ) 3098 { 3099 SDF_Signed_Distance current_dist = max_sdf; 3100 3101 3102 FT_CALL( sdf_contour_get_min_distance( contour_list, 3103 grid_point, 3104 ¤t_dist ) ); 3105 3106 if ( current_dist.distance < min_dist.distance ) 3107 min_dist = current_dist; 3108 3109 contour_list = contour_list->next; 3110 } 3111 3112 /* [OPTIMIZATION]: if (min_dist > sp_sq) then simply clamp */ 3113 /* the value to spread to avoid square_root */ 3114 3115 /* clamp the values to spread */ 3116 if ( min_dist.distance > sp_sq ) 3117 min_dist.distance = sp_sq; 3118 3119 /* square_root the values and fit in a 6.10 fixed point */ 3120 if ( USE_SQUARED_DISTANCES ) 3121 min_dist.distance = square_root( min_dist.distance ); 3122 3123 if ( internal_params.orientation == FT_ORIENTATION_FILL_LEFT ) 3124 min_dist.sign = -min_dist.sign; 3125 if ( internal_params.flip_sign ) 3126 min_dist.sign = -min_dist.sign; 3127 3128 min_dist.distance /= 64; /* convert from 16.16 to 22.10 */ 3129 3130 value = min_dist.distance & 0x0000FFFF; /* truncate to 6.10 */ 3131 value *= min_dist.sign; 3132 3133 if ( internal_params.flip_y ) 3134 index = y * width + x; 3135 else 3136 index = ( rows - y - 1 ) * width + x; 3137 3138 buffer[index] = value; 3139 } 3140 } 3141 3142 Exit: 3143 return error; 3144 } 3145 3146 #endif /* 0 */ 3147 3148 3149 /************************************************************************** 3150 * 3151 * @Function: 3152 * sdf_generate_bounding_box 3153 * 3154 * @Description: 3155 * This function does basically the same thing as `sdf_generate` above 3156 * but more efficiently. 3157 * 3158 * Instead of checking all pixels against all edges, we loop over all 3159 * edges and only check pixels around the control box of the edge; the 3160 * control box is increased by the spread in all directions. Anything 3161 * outside of the control box that exceeds `spread` doesn't need to be 3162 * computed. 3163 * 3164 * Lastly, to determine the sign of unchecked pixels, we do a single 3165 * pass of all rows starting with a '+' sign and flipping when we come 3166 * across a '-' sign and continue. This also eliminates the possibility 3167 * of overflow because we only check the proximity of the curve. 3168 * Therefore we can use squared distanced safely. 3169 * 3170 * @Input: 3171 * internal_params :: 3172 * Internal parameters and properties required by the rasterizer. 3173 * See @SDF_Params for more. 3174 * 3175 * shape :: 3176 * A complete shape which is used to generate SDF. 3177 * 3178 * spread :: 3179 * Maximum distances to be allowed in the output bitmap. 3180 * 3181 * @Output: 3182 * bitmap :: 3183 * The output bitmap which will contain the SDF information. 3184 * 3185 * @Return: 3186 * FreeType error, 0 means success. 3187 * 3188 */ 3189 static FT_Error sdf_generate_bounding_box(const SDF_Params internal_params,const SDF_Shape * shape,FT_UInt spread,const FT_Bitmap * bitmap)3190 sdf_generate_bounding_box( const SDF_Params internal_params, 3191 const SDF_Shape* shape, 3192 FT_UInt spread, 3193 const FT_Bitmap* bitmap ) 3194 { 3195 FT_Error error = FT_Err_Ok; 3196 FT_Memory memory = NULL; 3197 3198 FT_Int width, rows, i, j; 3199 FT_Int sp_sq; /* max value to check */ 3200 3201 SDF_Contour* contours; /* list of all contours */ 3202 FT_SDFFormat* buffer; /* the bitmap buffer */ 3203 3204 /* This buffer has the same size in indices as the */ 3205 /* bitmap buffer. When we check a pixel position for */ 3206 /* a shortest distance we keep it in this buffer. */ 3207 /* This way we can find out which pixel is set, */ 3208 /* and also determine the signs properly. */ 3209 SDF_Signed_Distance* dists = NULL; 3210 3211 const FT_16D16 fixed_spread = FT_INT_16D16( spread ); 3212 3213 3214 if ( !shape || !bitmap ) 3215 { 3216 error = FT_THROW( Invalid_Argument ); 3217 goto Exit; 3218 } 3219 3220 if ( spread < MIN_SPREAD || spread > MAX_SPREAD ) 3221 { 3222 error = FT_THROW( Invalid_Argument ); 3223 goto Exit; 3224 } 3225 3226 memory = shape->memory; 3227 if ( !memory ) 3228 { 3229 error = FT_THROW( Invalid_Argument ); 3230 goto Exit; 3231 } 3232 3233 if ( FT_ALLOC( dists, 3234 bitmap->width * bitmap->rows * sizeof ( *dists ) ) ) 3235 goto Exit; 3236 3237 contours = shape->contours; 3238 width = (FT_Int)bitmap->width; 3239 rows = (FT_Int)bitmap->rows; 3240 buffer = (FT_SDFFormat*)bitmap->buffer; 3241 3242 if ( USE_SQUARED_DISTANCES ) 3243 sp_sq = fixed_spread * fixed_spread; 3244 else 3245 sp_sq = fixed_spread; 3246 3247 if ( width == 0 || rows == 0 ) 3248 { 3249 FT_TRACE0(( "sdf_generate:" 3250 " Cannot render glyph with width/height == 0\n" )); 3251 FT_TRACE0(( " " 3252 " (width, height provided [%d, %d])", width, rows )); 3253 3254 error = FT_THROW( Cannot_Render_Glyph ); 3255 goto Exit; 3256 } 3257 3258 /* loop over all contours */ 3259 while ( contours ) 3260 { 3261 SDF_Edge* edges = contours->edges; 3262 3263 3264 /* loop over all edges */ 3265 while ( edges ) 3266 { 3267 FT_CBox cbox; 3268 FT_Int x, y; 3269 3270 3271 /* get the control box and increase it by `spread' */ 3272 cbox = get_control_box( *edges ); 3273 3274 cbox.xMin = ( cbox.xMin - 63 ) / 64 - ( FT_Pos )spread; 3275 cbox.xMax = ( cbox.xMax + 63 ) / 64 + ( FT_Pos )spread; 3276 cbox.yMin = ( cbox.yMin - 63 ) / 64 - ( FT_Pos )spread; 3277 cbox.yMax = ( cbox.yMax + 63 ) / 64 + ( FT_Pos )spread; 3278 3279 /* now loop over the pixels in the control box. */ 3280 for ( y = cbox.yMin; y < cbox.yMax; y++ ) 3281 { 3282 for ( x = cbox.xMin; x < cbox.xMax; x++ ) 3283 { 3284 FT_26D6_Vec grid_point = zero_vector; 3285 SDF_Signed_Distance dist = max_sdf; 3286 FT_UInt index = 0; 3287 3288 3289 if ( x < 0 || x >= width ) 3290 continue; 3291 if ( y < 0 || y >= rows ) 3292 continue; 3293 3294 grid_point.x = FT_INT_26D6( x ); 3295 grid_point.y = FT_INT_26D6( y ); 3296 3297 /* This `grid_point` is at the corner, but we */ 3298 /* use the center of the pixel. */ 3299 grid_point.x += FT_INT_26D6( 1 ) / 2; 3300 grid_point.y += FT_INT_26D6( 1 ) / 2; 3301 3302 FT_CALL( sdf_edge_get_min_distance( edges, 3303 grid_point, 3304 &dist ) ); 3305 3306 if ( internal_params.orientation == FT_ORIENTATION_FILL_LEFT ) 3307 dist.sign = -dist.sign; 3308 3309 /* ignore if the distance is greater than spread; */ 3310 /* otherwise it creates artifacts due to the wrong sign */ 3311 if ( dist.distance > sp_sq ) 3312 continue; 3313 3314 /* square_root the values and fit in a 6.10 fixed-point */ 3315 if ( USE_SQUARED_DISTANCES ) 3316 dist.distance = square_root( dist.distance ); 3317 3318 if ( internal_params.flip_y ) 3319 index = (FT_UInt)( y * width + x ); 3320 else 3321 index = (FT_UInt)( ( rows - y - 1 ) * width + x ); 3322 3323 /* check whether the pixel is set or not */ 3324 if ( dists[index].sign == 0 ) 3325 dists[index] = dist; 3326 else if ( dists[index].distance > dist.distance ) 3327 dists[index] = dist; 3328 else if ( FT_ABS( dists[index].distance - dist.distance ) 3329 < CORNER_CHECK_EPSILON ) 3330 dists[index] = resolve_corner( dists[index], dist ); 3331 } 3332 } 3333 3334 edges = edges->next; 3335 } 3336 3337 contours = contours->next; 3338 } 3339 3340 /* final pass */ 3341 for ( j = 0; j < rows; j++ ) 3342 { 3343 /* We assume the starting pixel of each row is outside. */ 3344 FT_Char current_sign = -1; 3345 FT_UInt index; 3346 3347 3348 if ( internal_params.overload_sign != 0 ) 3349 current_sign = internal_params.overload_sign < 0 ? -1 : 1; 3350 3351 for ( i = 0; i < width; i++ ) 3352 { 3353 index = (FT_UInt)( j * width + i ); 3354 3355 /* if the pixel is not set */ 3356 /* its shortest distance is more than `spread` */ 3357 if ( dists[index].sign == 0 ) 3358 dists[index].distance = fixed_spread; 3359 else 3360 current_sign = dists[index].sign; 3361 3362 /* clamp the values */ 3363 if ( dists[index].distance > fixed_spread ) 3364 dists[index].distance = fixed_spread; 3365 3366 /* flip sign if required */ 3367 dists[index].distance *= internal_params.flip_sign ? -current_sign 3368 : current_sign; 3369 3370 /* concatenate to appropriate format */ 3371 buffer[index] = map_fixed_to_sdf( dists[index].distance, 3372 fixed_spread ); 3373 } 3374 } 3375 3376 Exit: 3377 FT_FREE( dists ); 3378 return error; 3379 } 3380 3381 3382 /************************************************************************** 3383 * 3384 * @Function: 3385 * sdf_generate_subdivision 3386 * 3387 * @Description: 3388 * Subdivide the shape into a number of straight lines, then use the 3389 * above `sdf_generate_bounding_box` function to generate the SDF. 3390 * 3391 * Note: After calling this function `shape` no longer has the original 3392 * edges, it only contains lines. 3393 * 3394 * @Input: 3395 * internal_params :: 3396 * Internal parameters and properties required by the rasterizer. 3397 * See @SDF_Params for more. 3398 * 3399 * shape :: 3400 * A complete shape which is used to generate SDF. 3401 * 3402 * spread :: 3403 * Maximum distances to be allowed inthe output bitmap. 3404 * 3405 * @Output: 3406 * bitmap :: 3407 * The output bitmap which will contain the SDF information. 3408 * 3409 * @Return: 3410 * FreeType error, 0 means success. 3411 * 3412 */ 3413 static FT_Error sdf_generate_subdivision(const SDF_Params internal_params,SDF_Shape * shape,FT_UInt spread,const FT_Bitmap * bitmap)3414 sdf_generate_subdivision( const SDF_Params internal_params, 3415 SDF_Shape* shape, 3416 FT_UInt spread, 3417 const FT_Bitmap* bitmap ) 3418 { 3419 /* 3420 * Thanks to Alexei for providing the idea of this optimization. 3421 * 3422 * We take advantage of two facts. 3423 * 3424 * (1) Computing the shortest distance from a point to a line segment is 3425 * very fast. 3426 * (2) We don't have to compute the shortest distance for the entire 3427 * two-dimensional grid. 3428 * 3429 * Both ideas lead to the following optimization. 3430 * 3431 * (1) Split the outlines into a number of line segments. 3432 * 3433 * (2) For each line segment, only process its neighborhood. 3434 * 3435 * (3) Compute the closest distance to the line only for neighborhood 3436 * grid points. 3437 * 3438 * This greatly reduces the number of grid points to check. 3439 */ 3440 3441 FT_Error error = FT_Err_Ok; 3442 3443 3444 FT_CALL( split_sdf_shape( shape ) ); 3445 FT_CALL( sdf_generate_bounding_box( internal_params, 3446 shape, spread, bitmap ) ); 3447 3448 Exit: 3449 return error; 3450 } 3451 3452 3453 /************************************************************************** 3454 * 3455 * @Function: 3456 * sdf_generate_with_overlaps 3457 * 3458 * @Description: 3459 * This function can be used to generate SDF for glyphs with overlapping 3460 * contours. The function generates SDF for contours separately on 3461 * separate bitmaps (to generate SDF it uses 3462 * `sdf_generate_subdivision`). At the end it simply combines all the 3463 * SDF into the output bitmap; this fixes all the signs and removes 3464 * overlaps. 3465 * 3466 * @Input: 3467 * internal_params :: 3468 * Internal parameters and properties required by the rasterizer. See 3469 * @SDF_Params for more. 3470 * 3471 * shape :: 3472 * A complete shape which is used to generate SDF. 3473 * 3474 * spread :: 3475 * Maximum distances to be allowed in the output bitmap. 3476 * 3477 * @Output: 3478 * bitmap :: 3479 * The output bitmap which will contain the SDF information. 3480 * 3481 * @Return: 3482 * FreeType error, 0 means success. 3483 * 3484 * @Note: 3485 * The function cannot generate a proper SDF for glyphs with 3486 * self-intersecting contours because we cannot separate them into two 3487 * separate bitmaps. In case of self-intersecting contours it is 3488 * necessary to remove the overlaps before generating the SDF. 3489 * 3490 */ 3491 static FT_Error sdf_generate_with_overlaps(SDF_Params internal_params,SDF_Shape * shape,FT_UInt spread,const FT_Bitmap * bitmap)3492 sdf_generate_with_overlaps( SDF_Params internal_params, 3493 SDF_Shape* shape, 3494 FT_UInt spread, 3495 const FT_Bitmap* bitmap ) 3496 { 3497 FT_Error error = FT_Err_Ok; 3498 3499 FT_Int num_contours; /* total number of contours */ 3500 FT_Int i, j; /* iterators */ 3501 FT_Int width, rows; /* width and rows of the bitmap */ 3502 FT_Bitmap* bitmaps; /* separate bitmaps for contours */ 3503 3504 SDF_Contour* contour; /* temporary variable to iterate */ 3505 SDF_Contour* temp_contour; /* temporary contour */ 3506 SDF_Contour* head; /* head of the contour list */ 3507 SDF_Shape temp_shape; /* temporary shape */ 3508 3509 FT_Memory memory; /* to allocate memory */ 3510 FT_SDFFormat* t; /* target bitmap buffer */ 3511 FT_Bool flip_sign; /* flip sign? */ 3512 3513 /* orientation of all the separate contours */ 3514 SDF_Contour_Orientation* orientations; 3515 3516 3517 bitmaps = NULL; 3518 orientations = NULL; 3519 head = NULL; 3520 3521 if ( !shape || !bitmap || !shape->memory ) 3522 return FT_THROW( Invalid_Argument ); 3523 3524 /* Disable `flip_sign` to avoid extra complication */ 3525 /* during the combination phase. */ 3526 flip_sign = internal_params.flip_sign; 3527 internal_params.flip_sign = 0; 3528 3529 contour = shape->contours; 3530 memory = shape->memory; 3531 temp_shape.memory = memory; 3532 width = (FT_Int)bitmap->width; 3533 rows = (FT_Int)bitmap->rows; 3534 num_contours = 0; 3535 3536 /* find the number of contours in the shape */ 3537 while ( contour ) 3538 { 3539 num_contours++; 3540 contour = contour->next; 3541 } 3542 3543 /* allocate the bitmaps to generate SDF for separate contours */ 3544 if ( FT_ALLOC( bitmaps, 3545 (FT_UInt)num_contours * sizeof ( *bitmaps ) ) ) 3546 goto Exit; 3547 3548 /* allocate array to hold orientation for all contours */ 3549 if ( FT_ALLOC( orientations, 3550 (FT_UInt)num_contours * sizeof ( *orientations ) ) ) 3551 goto Exit; 3552 3553 contour = shape->contours; 3554 3555 /* Iterate over all contours and generate SDF separately. */ 3556 for ( i = 0; i < num_contours; i++ ) 3557 { 3558 /* initialize the corresponding bitmap */ 3559 FT_Bitmap_Init( &bitmaps[i] ); 3560 3561 bitmaps[i].width = bitmap->width; 3562 bitmaps[i].rows = bitmap->rows; 3563 bitmaps[i].pitch = bitmap->pitch; 3564 bitmaps[i].num_grays = bitmap->num_grays; 3565 bitmaps[i].pixel_mode = bitmap->pixel_mode; 3566 3567 /* allocate memory for the buffer */ 3568 if ( FT_ALLOC( bitmaps[i].buffer, 3569 bitmap->rows * (FT_UInt)bitmap->pitch ) ) 3570 goto Exit; 3571 3572 /* determine the orientation */ 3573 orientations[i] = get_contour_orientation( contour ); 3574 3575 /* The `overload_sign` property is specific to */ 3576 /* `sdf_generate_bounding_box`. This basically */ 3577 /* overloads the default sign of the outside */ 3578 /* pixels, which is necessary for */ 3579 /* counter-clockwise contours. */ 3580 if ( orientations[i] == SDF_ORIENTATION_CCW && 3581 internal_params.orientation == FT_ORIENTATION_FILL_RIGHT ) 3582 internal_params.overload_sign = 1; 3583 else if ( orientations[i] == SDF_ORIENTATION_CW && 3584 internal_params.orientation == FT_ORIENTATION_FILL_LEFT ) 3585 internal_params.overload_sign = 1; 3586 else 3587 internal_params.overload_sign = 0; 3588 3589 /* Make `contour->next` NULL so that there is */ 3590 /* one contour in the list. Also hold the next */ 3591 /* contour in a temporary variable so as to */ 3592 /* restore the original value. */ 3593 temp_contour = contour->next; 3594 contour->next = NULL; 3595 3596 /* Use `temp_shape` to hold the new contour. */ 3597 /* Now, `temp_shape` has only one contour. */ 3598 temp_shape.contours = contour; 3599 3600 /* finally generate the SDF */ 3601 FT_CALL( sdf_generate_subdivision( internal_params, 3602 &temp_shape, 3603 spread, 3604 &bitmaps[i] ) ); 3605 3606 /* Restore the original `next` variable. */ 3607 contour->next = temp_contour; 3608 3609 /* Since `split_sdf_shape` deallocated the original */ 3610 /* contours list we need to assign the new value to */ 3611 /* the shape's contour. */ 3612 temp_shape.contours->next = head; 3613 head = temp_shape.contours; 3614 3615 /* Simply flip the orientation in case of post-script fonts */ 3616 /* so as to avoid modificatons in the combining phase. */ 3617 if ( internal_params.orientation == FT_ORIENTATION_FILL_LEFT ) 3618 { 3619 if ( orientations[i] == SDF_ORIENTATION_CW ) 3620 orientations[i] = SDF_ORIENTATION_CCW; 3621 else if ( orientations[i] == SDF_ORIENTATION_CCW ) 3622 orientations[i] = SDF_ORIENTATION_CW; 3623 } 3624 3625 contour = contour->next; 3626 } 3627 3628 /* assign the new contour list to `shape->contours` */ 3629 shape->contours = head; 3630 3631 /* cast the output bitmap buffer */ 3632 t = (FT_SDFFormat*)bitmap->buffer; 3633 3634 /* Iterate over all pixels and combine all separate */ 3635 /* contours. These are the rules for combining: */ 3636 /* */ 3637 /* (1) For all clockwise contours, compute the largest */ 3638 /* value. Name this as `val_c`. */ 3639 /* (2) For all counter-clockwise contours, compute the */ 3640 /* smallest value. Name this as `val_ac`. */ 3641 /* (3) Now, finally use the smaller value of `val_c' */ 3642 /* and `val_ac'. */ 3643 for ( j = 0; j < rows; j++ ) 3644 { 3645 for ( i = 0; i < width; i++ ) 3646 { 3647 FT_Int id = j * width + i; /* index of current pixel */ 3648 FT_Int c; /* contour iterator */ 3649 3650 FT_SDFFormat val_c = 0; /* max clockwise value */ 3651 FT_SDFFormat val_ac = UCHAR_MAX; /* min counter-clockwise val */ 3652 3653 3654 /* iterate through all the contours */ 3655 for ( c = 0; c < num_contours; c++ ) 3656 { 3657 /* current contour value */ 3658 FT_SDFFormat temp = ( (FT_SDFFormat*)bitmaps[c].buffer )[id]; 3659 3660 3661 if ( orientations[c] == SDF_ORIENTATION_CW ) 3662 val_c = FT_MAX( val_c, temp ); /* clockwise */ 3663 else 3664 val_ac = FT_MIN( val_ac, temp ); /* counter-clockwise */ 3665 } 3666 3667 /* Finally find the smaller of the two and assign to output. */ 3668 /* Also apply `flip_sign` if set. */ 3669 t[id] = FT_MIN( val_c, val_ac ); 3670 3671 if ( flip_sign ) 3672 t[id] = invert_sign( t[id] ); 3673 } 3674 } 3675 3676 Exit: 3677 /* deallocate orientations array */ 3678 if ( orientations ) 3679 FT_FREE( orientations ); 3680 3681 /* deallocate temporary bitmaps */ 3682 if ( bitmaps ) 3683 { 3684 if ( num_contours == 0 ) 3685 error = FT_THROW( Raster_Corrupted ); 3686 else 3687 { 3688 for ( i = 0; i < num_contours; i++ ) 3689 FT_FREE( bitmaps[i].buffer ); 3690 3691 FT_FREE( bitmaps ); 3692 } 3693 } 3694 3695 /* restore the `flip_sign` property */ 3696 internal_params.flip_sign = flip_sign; 3697 3698 return error; 3699 } 3700 3701 3702 /************************************************************************** 3703 * 3704 * interface functions 3705 * 3706 */ 3707 3708 static FT_Error sdf_raster_new(FT_Memory memory,SDF_PRaster * araster)3709 sdf_raster_new( FT_Memory memory, 3710 SDF_PRaster* araster ) 3711 { 3712 FT_Error error; 3713 SDF_PRaster raster = NULL; 3714 3715 3716 if ( !FT_NEW( raster ) ) 3717 raster->memory = memory; 3718 3719 *araster = raster; 3720 3721 return error; 3722 } 3723 3724 3725 static void sdf_raster_reset(FT_Raster raster,unsigned char * pool_base,unsigned long pool_size)3726 sdf_raster_reset( FT_Raster raster, 3727 unsigned char* pool_base, 3728 unsigned long pool_size ) 3729 { 3730 FT_UNUSED( raster ); 3731 FT_UNUSED( pool_base ); 3732 FT_UNUSED( pool_size ); 3733 } 3734 3735 3736 static FT_Error sdf_raster_set_mode(FT_Raster raster,unsigned long mode,void * args)3737 sdf_raster_set_mode( FT_Raster raster, 3738 unsigned long mode, 3739 void* args ) 3740 { 3741 FT_UNUSED( raster ); 3742 FT_UNUSED( mode ); 3743 FT_UNUSED( args ); 3744 3745 return FT_Err_Ok; 3746 } 3747 3748 3749 static FT_Error sdf_raster_render(FT_Raster raster,const FT_Raster_Params * params)3750 sdf_raster_render( FT_Raster raster, 3751 const FT_Raster_Params* params ) 3752 { 3753 FT_Error error = FT_Err_Ok; 3754 SDF_TRaster* sdf_raster = (SDF_TRaster*)raster; 3755 FT_Outline* outline = NULL; 3756 const SDF_Raster_Params* sdf_params = (const SDF_Raster_Params*)params; 3757 3758 FT_Memory memory = NULL; 3759 SDF_Shape* shape = NULL; 3760 SDF_Params internal_params; 3761 3762 3763 /* check for valid arguments */ 3764 if ( !sdf_raster || !sdf_params ) 3765 { 3766 error = FT_THROW( Invalid_Argument ); 3767 goto Exit; 3768 } 3769 3770 outline = (FT_Outline*)sdf_params->root.source; 3771 3772 /* check whether outline is valid */ 3773 if ( !outline ) 3774 { 3775 error = FT_THROW( Invalid_Outline ); 3776 goto Exit; 3777 } 3778 3779 /* if the outline is empty, return */ 3780 if ( outline->n_points <= 0 || outline->n_contours <= 0 ) 3781 goto Exit; 3782 3783 /* check whether the outline has valid fields */ 3784 if ( !outline->contours || !outline->points ) 3785 { 3786 error = FT_THROW( Invalid_Outline ); 3787 goto Exit; 3788 } 3789 3790 /* check whether spread is set properly */ 3791 if ( sdf_params->spread > MAX_SPREAD || 3792 sdf_params->spread < MIN_SPREAD ) 3793 { 3794 FT_TRACE0(( "sdf_raster_render:" 3795 " The `spread' field of `SDF_Raster_Params' is invalid,\n" )); 3796 FT_TRACE0(( " " 3797 " the value of this field must be within [%d, %d].\n", 3798 MIN_SPREAD, MAX_SPREAD )); 3799 FT_TRACE0(( " " 3800 " Also, you must pass `SDF_Raster_Params' instead of\n" )); 3801 FT_TRACE0(( " " 3802 " the default `FT_Raster_Params' while calling\n" )); 3803 FT_TRACE0(( " " 3804 " this function and set the fields properly.\n" )); 3805 3806 error = FT_THROW( Invalid_Argument ); 3807 goto Exit; 3808 } 3809 3810 memory = sdf_raster->memory; 3811 if ( !memory ) 3812 { 3813 FT_TRACE0(( "sdf_raster_render:" 3814 " Raster not setup properly,\n" )); 3815 FT_TRACE0(( " " 3816 " unable to find memory handle.\n" )); 3817 3818 error = FT_THROW( Invalid_Handle ); 3819 goto Exit; 3820 } 3821 3822 /* set up the parameters */ 3823 internal_params.orientation = FT_Outline_Get_Orientation( outline ); 3824 internal_params.flip_sign = sdf_params->flip_sign; 3825 internal_params.flip_y = sdf_params->flip_y; 3826 internal_params.overload_sign = 0; 3827 3828 FT_CALL( sdf_shape_new( memory, &shape ) ); 3829 3830 FT_CALL( sdf_outline_decompose( outline, shape ) ); 3831 3832 if ( sdf_params->overlaps ) 3833 FT_CALL( sdf_generate_with_overlaps( internal_params, 3834 shape, sdf_params->spread, 3835 sdf_params->root.target ) ); 3836 else 3837 FT_CALL( sdf_generate_subdivision( internal_params, 3838 shape, sdf_params->spread, 3839 sdf_params->root.target ) ); 3840 3841 if ( shape ) 3842 sdf_shape_done( &shape ); 3843 3844 Exit: 3845 return error; 3846 } 3847 3848 3849 static void sdf_raster_done(FT_Raster raster)3850 sdf_raster_done( FT_Raster raster ) 3851 { 3852 FT_Memory memory = (FT_Memory)((SDF_TRaster*)raster)->memory; 3853 3854 3855 FT_FREE( raster ); 3856 } 3857 3858 3859 FT_DEFINE_RASTER_FUNCS( 3860 ft_sdf_raster, 3861 3862 FT_GLYPH_FORMAT_OUTLINE, 3863 3864 (FT_Raster_New_Func) sdf_raster_new, /* raster_new */ 3865 (FT_Raster_Reset_Func) sdf_raster_reset, /* raster_reset */ 3866 (FT_Raster_Set_Mode_Func)sdf_raster_set_mode, /* raster_set_mode */ 3867 (FT_Raster_Render_Func) sdf_raster_render, /* raster_render */ 3868 (FT_Raster_Done_Func) sdf_raster_done /* raster_done */ 3869 ) 3870 3871 3872 /* END */ 3873