1 /**************************************************************************** 2 * 3 * ftsdfrend.c 4 * 5 * Signed Distance Field renderer interface (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/ftdebug.h> 22 #include <freetype/internal/ftobjs.h> 23 #include <freetype/internal/services/svprop.h> 24 #include <freetype/ftoutln.h> 25 #include <freetype/ftbitmap.h> 26 #include "ftsdfrend.h" 27 #include "ftsdf.h" 28 29 #include "ftsdferrs.h" 30 31 32 /************************************************************************** 33 * 34 * The macro FT_COMPONENT is used in trace mode. It is an implicit 35 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log 36 * messages during execution. 37 */ 38 #undef FT_COMPONENT 39 #define FT_COMPONENT sdf 40 41 42 /************************************************************************** 43 * 44 * macros and default property values 45 * 46 */ 47 #define SDF_RENDERER( rend ) ( (SDF_Renderer)rend ) 48 49 50 /************************************************************************** 51 * 52 * for setting properties 53 * 54 */ 55 56 /* property setter function */ 57 static FT_Error sdf_property_set(FT_Module module,const char * property_name,const void * value,FT_Bool value_is_string)58 sdf_property_set( FT_Module module, 59 const char* property_name, 60 const void* value, 61 FT_Bool value_is_string ) 62 { 63 FT_Error error = FT_Err_Ok; 64 SDF_Renderer render = SDF_RENDERER( FT_RENDERER( module ) ); 65 66 FT_UNUSED( value_is_string ); 67 68 69 if ( ft_strcmp( property_name, "spread" ) == 0 ) 70 { 71 FT_Int val = *(const FT_Int*)value; 72 73 74 if ( val > MAX_SPREAD || val < MIN_SPREAD ) 75 { 76 FT_TRACE0(( "[sdf] sdf_property_set:" 77 " the `spread' property can have a value\n" )); 78 FT_TRACE0(( " " 79 " within range [%d, %d] (value provided: %d)\n", 80 MIN_SPREAD, MAX_SPREAD, val )); 81 82 error = FT_THROW( Invalid_Argument ); 83 goto Exit; 84 } 85 86 render->spread = (FT_UInt)val; 87 FT_TRACE7(( "[sdf] sdf_property_set:" 88 " updated property `spread' to %d\n", val )); 89 } 90 91 else if ( ft_strcmp( property_name, "flip_sign" ) == 0 ) 92 { 93 FT_Int val = *(const FT_Int*)value; 94 95 96 render->flip_sign = val ? 1 : 0; 97 FT_TRACE7(( "[sdf] sdf_property_set:" 98 " updated property `flip_sign' to %d\n", val )); 99 } 100 101 else if ( ft_strcmp( property_name, "flip_y" ) == 0 ) 102 { 103 FT_Int val = *(const FT_Int*)value; 104 105 106 render->flip_y = val ? 1 : 0; 107 FT_TRACE7(( "[sdf] sdf_property_set:" 108 " updated property `flip_y' to %d\n", val )); 109 } 110 111 else if ( ft_strcmp( property_name, "overlaps" ) == 0 ) 112 { 113 FT_Bool val = *(const FT_Bool*)value; 114 115 116 render->overlaps = val; 117 FT_TRACE7(( "[sdf] sdf_property_set:" 118 " updated property `overlaps' to %d\n", val )); 119 } 120 121 else 122 { 123 FT_TRACE0(( "[sdf] sdf_property_set:" 124 " missing property `%s'\n", property_name )); 125 error = FT_THROW( Missing_Property ); 126 } 127 128 Exit: 129 return error; 130 } 131 132 133 /* property getter function */ 134 static FT_Error sdf_property_get(FT_Module module,const char * property_name,void * value)135 sdf_property_get( FT_Module module, 136 const char* property_name, 137 void* value ) 138 { 139 FT_Error error = FT_Err_Ok; 140 SDF_Renderer render = SDF_RENDERER( FT_RENDERER( module ) ); 141 142 143 if ( ft_strcmp( property_name, "spread" ) == 0 ) 144 { 145 FT_UInt* val = (FT_UInt*)value; 146 147 148 *val = render->spread; 149 } 150 151 else if ( ft_strcmp( property_name, "flip_sign" ) == 0 ) 152 { 153 FT_Int* val = (FT_Int*)value; 154 155 156 *val = render->flip_sign; 157 } 158 159 else if ( ft_strcmp( property_name, "flip_y" ) == 0 ) 160 { 161 FT_Int* val = (FT_Int*)value; 162 163 164 *val = render->flip_y; 165 } 166 167 else if ( ft_strcmp( property_name, "overlaps" ) == 0 ) 168 { 169 FT_Int* val = (FT_Int*)value; 170 171 172 *val = render->overlaps; 173 } 174 175 else 176 { 177 FT_TRACE0(( "[sdf] sdf_property_get:" 178 " missing property `%s'\n", property_name )); 179 error = FT_THROW( Missing_Property ); 180 } 181 182 return error; 183 } 184 185 186 FT_DEFINE_SERVICE_PROPERTIESREC( 187 sdf_service_properties, 188 189 (FT_Properties_SetFunc)sdf_property_set, /* set_property */ 190 (FT_Properties_GetFunc)sdf_property_get ) /* get_property */ 191 192 193 FT_DEFINE_SERVICEDESCREC1( 194 sdf_services, 195 196 FT_SERVICE_ID_PROPERTIES, &sdf_service_properties ) 197 198 199 static FT_Module_Interface ft_sdf_requester(FT_Renderer render,const char * module_interface)200 ft_sdf_requester( FT_Renderer render, 201 const char* module_interface ) 202 { 203 FT_UNUSED( render ); 204 205 return ft_service_list_lookup( sdf_services, module_interface ); 206 } 207 208 209 /*************************************************************************/ 210 /*************************************************************************/ 211 /** **/ 212 /** OUTLINE TO SDF CONVERTER **/ 213 /** **/ 214 /*************************************************************************/ 215 /*************************************************************************/ 216 217 /************************************************************************** 218 * 219 * interface functions 220 * 221 */ 222 223 static FT_Error ft_sdf_init(FT_Renderer render)224 ft_sdf_init( FT_Renderer render ) 225 { 226 SDF_Renderer sdf_render = SDF_RENDERER( render ); 227 228 229 sdf_render->spread = DEFAULT_SPREAD; 230 sdf_render->flip_sign = 0; 231 sdf_render->flip_y = 0; 232 sdf_render->overlaps = 0; 233 234 return FT_Err_Ok; 235 } 236 237 238 static void ft_sdf_done(FT_Renderer render)239 ft_sdf_done( FT_Renderer render ) 240 { 241 FT_UNUSED( render ); 242 } 243 244 245 /* generate signed distance field from a glyph's slot image */ 246 static FT_Error ft_sdf_render(FT_Renderer module,FT_GlyphSlot slot,FT_Render_Mode mode,const FT_Vector * origin)247 ft_sdf_render( FT_Renderer module, 248 FT_GlyphSlot slot, 249 FT_Render_Mode mode, 250 const FT_Vector* origin ) 251 { 252 FT_Error error = FT_Err_Ok; 253 FT_Outline* outline = &slot->outline; 254 FT_Bitmap* bitmap = &slot->bitmap; 255 FT_Memory memory = NULL; 256 FT_Renderer render = NULL; 257 258 FT_Pos x_shift = 0; 259 FT_Pos y_shift = 0; 260 261 FT_Pos x_pad = 0; 262 FT_Pos y_pad = 0; 263 264 SDF_Raster_Params params; 265 SDF_Renderer sdf_module = SDF_RENDERER( module ); 266 267 268 render = &sdf_module->root; 269 memory = render->root.memory; 270 271 /* check whether slot format is correct before rendering */ 272 if ( slot->format != render->glyph_format ) 273 { 274 error = FT_THROW( Invalid_Glyph_Format ); 275 goto Exit; 276 } 277 278 /* check whether render mode is correct */ 279 if ( mode != FT_RENDER_MODE_SDF ) 280 { 281 error = FT_THROW( Cannot_Render_Glyph ); 282 goto Exit; 283 } 284 285 /* deallocate the previously allocated bitmap */ 286 if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) 287 { 288 FT_FREE( bitmap->buffer ); 289 slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; 290 } 291 292 /* preset the bitmap using the glyph's outline; */ 293 /* the sdf bitmap is similar to an anti-aliased bitmap */ 294 /* with a slightly bigger size and different pixel mode */ 295 if ( ft_glyphslot_preset_bitmap( slot, FT_RENDER_MODE_NORMAL, origin ) ) 296 { 297 error = FT_THROW( Raster_Overflow ); 298 goto Exit; 299 } 300 301 /* the rows and pitch must be valid after presetting the */ 302 /* bitmap using outline */ 303 if ( !bitmap->rows || !bitmap->pitch ) 304 { 305 FT_ERROR(( "ft_sdf_render: failed to preset bitmap\n" )); 306 307 error = FT_THROW( Cannot_Render_Glyph ); 308 goto Exit; 309 } 310 311 /* the padding will simply be equal to the `spread' */ 312 x_pad = sdf_module->spread; 313 y_pad = sdf_module->spread; 314 315 /* apply the padding; will be in all the directions */ 316 bitmap->rows += y_pad * 2; 317 bitmap->width += x_pad * 2; 318 319 /* ignore the pitch, pixel mode and set custom */ 320 bitmap->pixel_mode = FT_PIXEL_MODE_GRAY; 321 bitmap->pitch = (int)( bitmap->width ); 322 bitmap->num_grays = 255; 323 324 /* allocate new buffer */ 325 if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) ) 326 goto Exit; 327 328 slot->internal->flags |= FT_GLYPH_OWN_BITMAP; 329 330 slot->bitmap_top += y_pad; 331 slot->bitmap_left -= x_pad; 332 333 x_shift = 64 * -slot->bitmap_left; 334 y_shift = 64 * -slot->bitmap_top; 335 y_shift += 64 * (FT_Int)bitmap->rows; 336 337 if ( origin ) 338 { 339 x_shift += origin->x; 340 y_shift += origin->y; 341 } 342 343 /* translate outline to render it into the bitmap */ 344 if ( x_shift || y_shift ) 345 FT_Outline_Translate( outline, x_shift, y_shift ); 346 347 /* set up parameters */ 348 params.root.target = bitmap; 349 params.root.source = outline; 350 params.root.flags = FT_RASTER_FLAG_SDF; 351 params.spread = sdf_module->spread; 352 params.flip_sign = sdf_module->flip_sign; 353 params.flip_y = sdf_module->flip_y; 354 params.overlaps = sdf_module->overlaps; 355 356 /* render the outline */ 357 error = render->raster_render( render->raster, 358 (const FT_Raster_Params*)¶ms ); 359 360 /* transform the outline back to the original state */ 361 if ( x_shift || y_shift ) 362 FT_Outline_Translate( outline, -x_shift, -y_shift ); 363 364 Exit: 365 if ( !error ) 366 { 367 /* the glyph is successfully rendered to a bitmap */ 368 slot->format = FT_GLYPH_FORMAT_BITMAP; 369 } 370 else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) 371 { 372 FT_FREE( bitmap->buffer ); 373 slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; 374 } 375 376 return error; 377 } 378 379 380 /* transform the glyph using matrix and/or delta */ 381 static FT_Error ft_sdf_transform(FT_Renderer render,FT_GlyphSlot slot,const FT_Matrix * matrix,const FT_Vector * delta)382 ft_sdf_transform( FT_Renderer render, 383 FT_GlyphSlot slot, 384 const FT_Matrix* matrix, 385 const FT_Vector* delta ) 386 { 387 FT_Error error = FT_Err_Ok; 388 389 390 if ( slot->format != render->glyph_format ) 391 { 392 error = FT_THROW( Invalid_Argument ); 393 goto Exit; 394 } 395 396 if ( matrix ) 397 FT_Outline_Transform( &slot->outline, matrix ); 398 399 if ( delta ) 400 FT_Outline_Translate( &slot->outline, delta->x, delta->y ); 401 402 Exit: 403 return error; 404 } 405 406 407 /* return the control box of a glyph's outline */ 408 static void ft_sdf_get_cbox(FT_Renderer render,FT_GlyphSlot slot,FT_BBox * cbox)409 ft_sdf_get_cbox( FT_Renderer render, 410 FT_GlyphSlot slot, 411 FT_BBox* cbox ) 412 { 413 FT_ZERO( cbox ); 414 415 if ( slot->format == render->glyph_format ) 416 FT_Outline_Get_CBox( &slot->outline, cbox ); 417 } 418 419 420 /* set render specific modes or attributes */ 421 static FT_Error ft_sdf_set_mode(FT_Renderer render,FT_ULong mode_tag,FT_Pointer data)422 ft_sdf_set_mode( FT_Renderer render, 423 FT_ULong mode_tag, 424 FT_Pointer data ) 425 { 426 /* pass it to the rasterizer */ 427 return render->clazz->raster_class->raster_set_mode( render->raster, 428 mode_tag, 429 data ); 430 } 431 432 433 FT_DEFINE_RENDERER( 434 ft_sdf_renderer_class, 435 436 FT_MODULE_RENDERER, 437 sizeof ( SDF_Renderer_Module ), 438 439 "sdf", 440 0x10000L, 441 0x20000L, 442 443 NULL, 444 445 (FT_Module_Constructor)ft_sdf_init, 446 (FT_Module_Destructor) ft_sdf_done, 447 (FT_Module_Requester) ft_sdf_requester, 448 449 FT_GLYPH_FORMAT_OUTLINE, 450 451 (FT_Renderer_RenderFunc) ft_sdf_render, /* render_glyph */ 452 (FT_Renderer_TransformFunc)ft_sdf_transform, /* transform_glyph */ 453 (FT_Renderer_GetCBoxFunc) ft_sdf_get_cbox, /* get_glyph_cbox */ 454 (FT_Renderer_SetModeFunc) ft_sdf_set_mode, /* set_mode */ 455 456 (FT_Raster_Funcs*)&ft_sdf_raster /* raster_class */ 457 ) 458 459 460 /*************************************************************************/ 461 /*************************************************************************/ 462 /** **/ 463 /** BITMAP TO SDF CONVERTER **/ 464 /** **/ 465 /*************************************************************************/ 466 /*************************************************************************/ 467 468 /* generate signed distance field from glyph's bitmap */ 469 static FT_Error ft_bsdf_render(FT_Renderer module,FT_GlyphSlot slot,FT_Render_Mode mode,const FT_Vector * origin)470 ft_bsdf_render( FT_Renderer module, 471 FT_GlyphSlot slot, 472 FT_Render_Mode mode, 473 const FT_Vector* origin ) 474 { 475 FT_Error error = FT_Err_Ok; 476 FT_Memory memory = NULL; 477 478 FT_Bitmap* bitmap = &slot->bitmap; 479 FT_Renderer render = NULL; 480 FT_Bitmap target; 481 482 FT_Pos x_pad = 0; 483 FT_Pos y_pad = 0; 484 485 SDF_Raster_Params params; 486 SDF_Renderer sdf_module = SDF_RENDERER( module ); 487 488 489 /* initialize the bitmap in case any error occurs */ 490 FT_Bitmap_Init( &target ); 491 492 render = &sdf_module->root; 493 memory = render->root.memory; 494 495 /* check whether slot format is correct before rendering */ 496 if ( slot->format != render->glyph_format ) 497 { 498 error = FT_THROW( Invalid_Glyph_Format ); 499 goto Exit; 500 } 501 502 /* check whether render mode is correct */ 503 if ( mode != FT_RENDER_MODE_SDF ) 504 { 505 error = FT_THROW( Cannot_Render_Glyph ); 506 goto Exit; 507 } 508 509 if ( origin ) 510 { 511 FT_ERROR(( "ft_bsdf_render: can't translate the bitmap\n" )); 512 513 error = FT_THROW( Unimplemented_Feature ); 514 goto Exit; 515 } 516 517 /* Do not generate SDF if the bitmap is not owned by the */ 518 /* glyph: it might be that the source buffer is already freed. */ 519 if ( !( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) ) 520 { 521 FT_ERROR(( "ft_bsdf_render: can't generate SDF from" 522 " unowned source bitmap\n" )); 523 524 error = FT_THROW( Invalid_Argument ); 525 goto Exit; 526 } 527 528 if ( !bitmap->rows || !bitmap->pitch ) 529 { 530 FT_ERROR(( "ft_bsdf_render: invalid bitmap size\n" )); 531 532 error = FT_THROW( Invalid_Argument ); 533 goto Exit; 534 } 535 536 FT_Bitmap_New( &target ); 537 538 /* padding will simply be equal to `spread` */ 539 x_pad = sdf_module->spread; 540 y_pad = sdf_module->spread; 541 542 /* apply padding, which extends to all directions */ 543 target.rows = bitmap->rows + y_pad * 2; 544 target.width = bitmap->width + x_pad * 2; 545 546 /* set up the target bitmap */ 547 target.pixel_mode = FT_PIXEL_MODE_GRAY; 548 target.pitch = (int)( target.width ); 549 target.num_grays = 255; 550 551 if ( FT_ALLOC_MULT( target.buffer, target.rows, target.pitch ) ) 552 goto Exit; 553 554 /* set up parameters */ 555 params.root.target = ⌖ 556 params.root.source = bitmap; 557 params.root.flags = FT_RASTER_FLAG_SDF; 558 params.spread = sdf_module->spread; 559 params.flip_sign = sdf_module->flip_sign; 560 params.flip_y = sdf_module->flip_y; 561 562 error = render->raster_render( render->raster, 563 (const FT_Raster_Params*)¶ms ); 564 565 Exit: 566 if ( !error ) 567 { 568 /* the glyph is successfully converted to a SDF */ 569 if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) 570 { 571 FT_FREE( bitmap->buffer ); 572 slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; 573 } 574 575 slot->bitmap = target; 576 slot->bitmap_top += y_pad; 577 slot->bitmap_left -= x_pad; 578 slot->internal->flags |= FT_GLYPH_OWN_BITMAP; 579 } 580 else if ( target.buffer ) 581 FT_FREE( target.buffer ); 582 583 return error; 584 } 585 586 587 FT_DEFINE_RENDERER( 588 ft_bitmap_sdf_renderer_class, 589 590 FT_MODULE_RENDERER, 591 sizeof ( SDF_Renderer_Module ), 592 593 "bsdf", 594 0x10000L, 595 0x20000L, 596 597 NULL, 598 599 (FT_Module_Constructor)ft_sdf_init, 600 (FT_Module_Destructor) ft_sdf_done, 601 (FT_Module_Requester) ft_sdf_requester, 602 603 FT_GLYPH_FORMAT_BITMAP, 604 605 (FT_Renderer_RenderFunc) ft_bsdf_render, /* render_glyph */ 606 (FT_Renderer_TransformFunc)ft_sdf_transform, /* transform_glyph */ 607 (FT_Renderer_GetCBoxFunc) ft_sdf_get_cbox, /* get_glyph_cbox */ 608 (FT_Renderer_SetModeFunc) ft_sdf_set_mode, /* set_mode */ 609 610 (FT_Raster_Funcs*)&ft_bitmap_sdf_raster /* raster_class */ 611 ) 612 613 614 /* END */ 615