1 /**************************************************************************** 2 * 3 * ftsdfrend.c 4 * 5 * Signed Distance Field renderer interface (body). 6 * 7 * Copyright (C) 2020-2023 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_Module module,const char * module_interface)200 ft_sdf_requester( FT_Module module, 201 const char* module_interface ) 202 { 203 FT_UNUSED( module ); 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_Module module)224 ft_sdf_init( FT_Module module ) /* SDF_Renderer */ 225 { 226 SDF_Renderer sdf_render = SDF_RENDERER( module ); 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_Module module)239 ft_sdf_done( FT_Module module ) 240 { 241 FT_UNUSED( module ); 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 /* nothing to render */ 302 if ( !bitmap->rows || !bitmap->pitch ) 303 goto Exit; 304 305 /* the padding will simply be equal to the `spread' */ 306 x_pad = sdf_module->spread; 307 y_pad = sdf_module->spread; 308 309 /* apply the padding; will be in all the directions */ 310 bitmap->rows += y_pad * 2; 311 bitmap->width += x_pad * 2; 312 313 /* ignore the pitch, pixel mode and set custom */ 314 bitmap->pixel_mode = FT_PIXEL_MODE_GRAY; 315 bitmap->pitch = (int)( bitmap->width ); 316 bitmap->num_grays = 255; 317 318 /* allocate new buffer */ 319 if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) ) 320 goto Exit; 321 322 slot->internal->flags |= FT_GLYPH_OWN_BITMAP; 323 324 slot->bitmap_top += y_pad; 325 slot->bitmap_left -= x_pad; 326 327 x_shift = 64 * -slot->bitmap_left; 328 y_shift = 64 * -slot->bitmap_top; 329 y_shift += 64 * (FT_Int)bitmap->rows; 330 331 if ( origin ) 332 { 333 x_shift += origin->x; 334 y_shift += origin->y; 335 } 336 337 /* translate outline to render it into the bitmap */ 338 if ( x_shift || y_shift ) 339 FT_Outline_Translate( outline, x_shift, y_shift ); 340 341 /* set up parameters */ 342 params.root.target = bitmap; 343 params.root.source = outline; 344 params.root.flags = FT_RASTER_FLAG_SDF; 345 params.spread = sdf_module->spread; 346 params.flip_sign = sdf_module->flip_sign; 347 params.flip_y = sdf_module->flip_y; 348 params.overlaps = sdf_module->overlaps; 349 350 /* render the outline */ 351 error = render->raster_render( render->raster, 352 (const FT_Raster_Params*)¶ms ); 353 354 /* transform the outline back to the original state */ 355 if ( x_shift || y_shift ) 356 FT_Outline_Translate( outline, -x_shift, -y_shift ); 357 358 Exit: 359 if ( !error ) 360 { 361 /* the glyph is successfully rendered to a bitmap */ 362 slot->format = FT_GLYPH_FORMAT_BITMAP; 363 } 364 else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) 365 { 366 FT_FREE( bitmap->buffer ); 367 slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; 368 } 369 370 return error; 371 } 372 373 374 /* transform the glyph using matrix and/or delta */ 375 static FT_Error ft_sdf_transform(FT_Renderer render,FT_GlyphSlot slot,const FT_Matrix * matrix,const FT_Vector * delta)376 ft_sdf_transform( FT_Renderer render, 377 FT_GlyphSlot slot, 378 const FT_Matrix* matrix, 379 const FT_Vector* delta ) 380 { 381 FT_Error error = FT_Err_Ok; 382 383 384 if ( slot->format != render->glyph_format ) 385 { 386 error = FT_THROW( Invalid_Argument ); 387 goto Exit; 388 } 389 390 if ( matrix ) 391 FT_Outline_Transform( &slot->outline, matrix ); 392 393 if ( delta ) 394 FT_Outline_Translate( &slot->outline, delta->x, delta->y ); 395 396 Exit: 397 return error; 398 } 399 400 401 /* return the control box of a glyph's outline */ 402 static void ft_sdf_get_cbox(FT_Renderer render,FT_GlyphSlot slot,FT_BBox * cbox)403 ft_sdf_get_cbox( FT_Renderer render, 404 FT_GlyphSlot slot, 405 FT_BBox* cbox ) 406 { 407 FT_ZERO( cbox ); 408 409 if ( slot->format == render->glyph_format ) 410 FT_Outline_Get_CBox( &slot->outline, cbox ); 411 } 412 413 414 /* set render specific modes or attributes */ 415 static FT_Error ft_sdf_set_mode(FT_Renderer render,FT_ULong mode_tag,FT_Pointer data)416 ft_sdf_set_mode( FT_Renderer render, 417 FT_ULong mode_tag, 418 FT_Pointer data ) 419 { 420 /* pass it to the rasterizer */ 421 return render->clazz->raster_class->raster_set_mode( render->raster, 422 mode_tag, 423 data ); 424 } 425 426 427 FT_DEFINE_RENDERER( 428 ft_sdf_renderer_class, 429 430 FT_MODULE_RENDERER, 431 sizeof ( SDF_Renderer_Module ), 432 433 "sdf", 434 0x10000L, 435 0x20000L, 436 437 NULL, 438 439 (FT_Module_Constructor)ft_sdf_init, 440 (FT_Module_Destructor) ft_sdf_done, 441 (FT_Module_Requester) ft_sdf_requester, 442 443 FT_GLYPH_FORMAT_OUTLINE, 444 445 (FT_Renderer_RenderFunc) ft_sdf_render, /* render_glyph */ 446 (FT_Renderer_TransformFunc)ft_sdf_transform, /* transform_glyph */ 447 (FT_Renderer_GetCBoxFunc) ft_sdf_get_cbox, /* get_glyph_cbox */ 448 (FT_Renderer_SetModeFunc) ft_sdf_set_mode, /* set_mode */ 449 450 (FT_Raster_Funcs*)&ft_sdf_raster /* raster_class */ 451 ) 452 453 454 /*************************************************************************/ 455 /*************************************************************************/ 456 /** **/ 457 /** BITMAP TO SDF CONVERTER **/ 458 /** **/ 459 /*************************************************************************/ 460 /*************************************************************************/ 461 462 /* generate signed distance field from glyph's bitmap */ 463 static FT_Error ft_bsdf_render(FT_Renderer module,FT_GlyphSlot slot,FT_Render_Mode mode,const FT_Vector * origin)464 ft_bsdf_render( FT_Renderer module, 465 FT_GlyphSlot slot, 466 FT_Render_Mode mode, 467 const FT_Vector* origin ) 468 { 469 FT_Error error = FT_Err_Ok; 470 FT_Memory memory = NULL; 471 472 FT_Bitmap* bitmap = &slot->bitmap; 473 FT_Renderer render = NULL; 474 FT_Bitmap target; 475 476 FT_Pos x_pad = 0; 477 FT_Pos y_pad = 0; 478 479 SDF_Raster_Params params; 480 SDF_Renderer sdf_module = SDF_RENDERER( module ); 481 482 483 /* initialize the bitmap in case any error occurs */ 484 FT_Bitmap_Init( &target ); 485 486 render = &sdf_module->root; 487 memory = render->root.memory; 488 489 /* check whether slot format is correct before rendering */ 490 if ( slot->format != render->glyph_format ) 491 { 492 error = FT_THROW( Invalid_Glyph_Format ); 493 goto Exit; 494 } 495 496 /* check whether render mode is correct */ 497 if ( mode != FT_RENDER_MODE_SDF ) 498 { 499 error = FT_THROW( Cannot_Render_Glyph ); 500 goto Exit; 501 } 502 503 if ( origin ) 504 { 505 FT_ERROR(( "ft_bsdf_render: can't translate the bitmap\n" )); 506 507 error = FT_THROW( Unimplemented_Feature ); 508 goto Exit; 509 } 510 511 /* nothing to render */ 512 if ( !bitmap->rows || !bitmap->pitch ) 513 goto Exit; 514 515 /* Do not generate SDF if the bitmap is not owned by the */ 516 /* glyph: it might be that the source buffer is already freed. */ 517 if ( !( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) ) 518 { 519 FT_ERROR(( "ft_bsdf_render: can't generate SDF from" 520 " unowned source bitmap\n" )); 521 522 error = FT_THROW( Invalid_Argument ); 523 goto Exit; 524 } 525 526 FT_Bitmap_New( &target ); 527 528 /* padding will simply be equal to `spread` */ 529 x_pad = sdf_module->spread; 530 y_pad = sdf_module->spread; 531 532 /* apply padding, which extends to all directions */ 533 target.rows = bitmap->rows + y_pad * 2; 534 target.width = bitmap->width + x_pad * 2; 535 536 /* set up the target bitmap */ 537 target.pixel_mode = FT_PIXEL_MODE_GRAY; 538 target.pitch = (int)( target.width ); 539 target.num_grays = 255; 540 541 if ( FT_ALLOC_MULT( target.buffer, target.rows, target.pitch ) ) 542 goto Exit; 543 544 /* set up parameters */ 545 params.root.target = ⌖ 546 params.root.source = bitmap; 547 params.root.flags = FT_RASTER_FLAG_SDF; 548 params.spread = sdf_module->spread; 549 params.flip_sign = sdf_module->flip_sign; 550 params.flip_y = sdf_module->flip_y; 551 552 error = render->raster_render( render->raster, 553 (const FT_Raster_Params*)¶ms ); 554 555 Exit: 556 if ( !error ) 557 { 558 /* the glyph is successfully converted to a SDF */ 559 if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) 560 FT_FREE( bitmap->buffer ); 561 562 slot->bitmap = target; 563 slot->bitmap_top += y_pad; 564 slot->bitmap_left -= x_pad; 565 566 if ( target.buffer ) 567 slot->internal->flags |= FT_GLYPH_OWN_BITMAP; 568 } 569 else if ( target.buffer ) 570 FT_FREE( target.buffer ); 571 572 return error; 573 } 574 575 576 FT_DEFINE_RENDERER( 577 ft_bitmap_sdf_renderer_class, 578 579 FT_MODULE_RENDERER, 580 sizeof ( SDF_Renderer_Module ), 581 582 "bsdf", 583 0x10000L, 584 0x20000L, 585 586 NULL, 587 588 (FT_Module_Constructor)ft_sdf_init, 589 (FT_Module_Destructor) ft_sdf_done, 590 (FT_Module_Requester) ft_sdf_requester, 591 592 FT_GLYPH_FORMAT_BITMAP, 593 594 (FT_Renderer_RenderFunc) ft_bsdf_render, /* render_glyph */ 595 (FT_Renderer_TransformFunc)ft_sdf_transform, /* transform_glyph */ 596 (FT_Renderer_GetCBoxFunc) ft_sdf_get_cbox, /* get_glyph_cbox */ 597 (FT_Renderer_SetModeFunc) ft_sdf_set_mode, /* set_mode */ 598 599 (FT_Raster_Funcs*)&ft_bitmap_sdf_raster /* raster_class */ 600 ) 601 602 603 /* END */ 604