1 /**************************************************************************** 2 * 3 * ftsvg.c 4 * 5 * The FreeType SVG renderer interface (body). 6 * 7 * Copyright (C) 2022-2023 by 8 * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. 9 * 10 * This file is part of the FreeType project, and may only be used, 11 * modified, and distributed under the terms of the FreeType project 12 * license, LICENSE.TXT. By continuing to use, modify, or distribute 13 * this file you indicate that you have read the license and 14 * understand and accept it fully. 15 * 16 */ 17 18 #include <freetype/internal/ftdebug.h> 19 #include <freetype/internal/ftserv.h> 20 #include <freetype/internal/services/svprop.h> 21 #include <freetype/otsvg.h> 22 #include <freetype/internal/svginterface.h> 23 #include <freetype/ftbbox.h> 24 25 #include "ftsvg.h" 26 #include "svgtypes.h" 27 28 29 /************************************************************************** 30 * 31 * The macro FT_COMPONENT is used in trace mode. It is an implicit 32 * parameter of the FT_TRACE() and FT_ERROR() macros, usued to print/log 33 * messages during execution. 34 */ 35 #undef FT_COMPONENT 36 #define FT_COMPONENT otsvg 37 38 39 #ifdef FT_CONFIG_OPTION_SVG 40 41 /* ft_svg_init */ 42 static FT_Error ft_svg_init(FT_Module module)43 ft_svg_init( FT_Module module ) 44 { 45 SVG_Renderer render = (SVG_Renderer)module; 46 47 FT_Error error = FT_Err_Ok; 48 49 50 render->loaded = FALSE; 51 render->hooks_set = FALSE; 52 53 return error; 54 } 55 56 57 static void ft_svg_done(FT_Module module)58 ft_svg_done( FT_Module module ) 59 { 60 SVG_Renderer render = (SVG_Renderer)module; 61 62 63 if ( render->loaded == TRUE && 64 render->hooks_set == TRUE ) 65 render->hooks.free_svg( &render->state ); 66 67 render->loaded = FALSE; 68 } 69 70 71 static FT_Error ft_svg_preset_slot(FT_Module module,FT_GlyphSlot slot,FT_Bool cache)72 ft_svg_preset_slot( FT_Module module, 73 FT_GlyphSlot slot, 74 FT_Bool cache ) 75 { 76 SVG_Renderer svg_renderer = (SVG_Renderer)module; 77 SVG_RendererHooks hooks = svg_renderer->hooks; 78 79 80 if ( svg_renderer->hooks_set == FALSE ) 81 { 82 FT_TRACE1(( "Hooks are NOT set. Can't render OT-SVG glyphs\n" )); 83 return FT_THROW( Missing_SVG_Hooks ); 84 } 85 86 if ( svg_renderer->loaded == FALSE ) 87 { 88 FT_TRACE3(( "ft_svg_preset_slot: first presetting call," 89 " calling init hook\n" )); 90 hooks.init_svg( &svg_renderer->state ); 91 92 svg_renderer->loaded = TRUE; 93 } 94 95 return hooks.preset_slot( slot, cache, &svg_renderer->state ); 96 } 97 98 99 static FT_Error ft_svg_render(FT_Renderer renderer,FT_GlyphSlot slot,FT_Render_Mode mode,const FT_Vector * origin)100 ft_svg_render( FT_Renderer renderer, 101 FT_GlyphSlot slot, 102 FT_Render_Mode mode, 103 const FT_Vector* origin ) 104 { 105 SVG_Renderer svg_renderer = (SVG_Renderer)renderer; 106 107 FT_Library library = renderer->root.library; 108 FT_Memory memory = library->memory; 109 FT_Error error; 110 111 FT_ULong size_image_buffer; 112 113 SVG_RendererHooks hooks = svg_renderer->hooks; 114 115 116 FT_UNUSED( mode ); 117 FT_UNUSED( origin ); 118 119 if ( mode != FT_RENDER_MODE_NORMAL ) 120 return FT_THROW( Bad_Argument ); 121 122 if ( svg_renderer->hooks_set == FALSE ) 123 { 124 FT_TRACE1(( "Hooks are NOT set. Can't render OT-SVG glyphs\n" )); 125 return FT_THROW( Missing_SVG_Hooks ); 126 } 127 128 if ( svg_renderer->loaded == FALSE ) 129 { 130 FT_TRACE3(( "ft_svg_render: first rendering, calling init hook\n" )); 131 error = hooks.init_svg( &svg_renderer->state ); 132 133 svg_renderer->loaded = TRUE; 134 } 135 136 ft_svg_preset_slot( (FT_Module)renderer, slot, TRUE ); 137 138 size_image_buffer = (FT_ULong)slot->bitmap.pitch * slot->bitmap.rows; 139 /* No `FT_QALLOC` here since we need a clean, empty canvas */ 140 /* to start with. */ 141 if ( FT_ALLOC( slot->bitmap.buffer, size_image_buffer ) ) 142 return error; 143 144 error = hooks.render_svg( slot, &svg_renderer->state ); 145 if ( error ) 146 FT_FREE( slot->bitmap.buffer ); 147 else 148 slot->internal->flags |= FT_GLYPH_OWN_BITMAP; 149 150 return error; 151 } 152 153 154 static const SVG_Interface svg_interface = 155 { 156 ft_svg_preset_slot /* Preset_Bitmap_Func preset_slot */ 157 }; 158 159 160 static FT_Error ft_svg_property_set(FT_Module module,const char * property_name,const void * value,FT_Bool value_is_string)161 ft_svg_property_set( FT_Module module, 162 const char* property_name, 163 const void* value, 164 FT_Bool value_is_string ) 165 { 166 FT_Error error = FT_Err_Ok; 167 SVG_Renderer renderer = (SVG_Renderer)module; 168 169 170 if ( !ft_strcmp( property_name, "svg-hooks" ) ) 171 { 172 SVG_RendererHooks* hooks; 173 174 175 if ( value_is_string == TRUE ) 176 { 177 error = FT_THROW( Invalid_Argument ); 178 goto Exit; 179 } 180 181 hooks = (SVG_RendererHooks*)value; 182 183 if ( !hooks->init_svg || 184 !hooks->free_svg || 185 !hooks->render_svg || 186 !hooks->preset_slot ) 187 { 188 FT_TRACE0(( "ft_svg_property_set:" 189 " SVG rendering hooks not set because\n" )); 190 FT_TRACE0(( " " 191 " at least one function pointer is NULL\n" )); 192 193 error = FT_THROW( Invalid_Argument ); 194 goto Exit; 195 } 196 197 renderer->hooks = *hooks; 198 renderer->hooks_set = TRUE; 199 } 200 else 201 error = FT_THROW( Missing_Property ); 202 203 Exit: 204 return error; 205 } 206 207 208 static FT_Error ft_svg_property_get(FT_Module module,const char * property_name,void * value)209 ft_svg_property_get( FT_Module module, 210 const char* property_name, 211 void* value ) 212 { 213 FT_Error error = FT_Err_Ok; 214 SVG_Renderer renderer = (SVG_Renderer)module; 215 216 217 if ( !ft_strcmp( property_name, "svg-hooks" ) ) 218 { 219 SVG_RendererHooks* hooks = (SVG_RendererHooks*)value; 220 221 222 *hooks = renderer->hooks; 223 } 224 else 225 error = FT_THROW( Missing_Property ); 226 227 return error; 228 } 229 230 FT_DEFINE_SERVICE_PROPERTIESREC(ft_svg_service_properties,ft_svg_property_set,ft_svg_property_get)231 FT_DEFINE_SERVICE_PROPERTIESREC( 232 ft_svg_service_properties, 233 234 ft_svg_property_set, /* FT_Properties_SetFunc set_property */ 235 ft_svg_property_get /* FT_Properties_GetFunc get_property */ 236 ) 237 238 239 FT_DEFINE_SERVICEDESCREC1( 240 ft_svg_services, 241 FT_SERVICE_ID_PROPERTIES, &ft_svg_service_properties ) 242 243 244 FT_CALLBACK_DEF( FT_Module_Interface ) 245 ft_svg_get_interface( FT_Module module, 246 const char* ft_svg_interface ) 247 { 248 FT_Module_Interface result; 249 250 251 FT_UNUSED( module ); 252 253 result = ft_service_list_lookup( ft_svg_services, ft_svg_interface ); 254 if ( result ) 255 return result; 256 257 return 0; 258 } 259 260 261 static FT_Error ft_svg_transform(FT_Renderer renderer,FT_GlyphSlot slot,const FT_Matrix * _matrix,const FT_Vector * _delta)262 ft_svg_transform( FT_Renderer renderer, 263 FT_GlyphSlot slot, 264 const FT_Matrix* _matrix, 265 const FT_Vector* _delta ) 266 { 267 FT_SVG_Document doc = (FT_SVG_Document)slot->other; 268 FT_Matrix* matrix = (FT_Matrix*)_matrix; 269 FT_Vector* delta = (FT_Vector*)_delta; 270 271 FT_Matrix tmp_matrix; 272 FT_Vector tmp_delta; 273 274 FT_Matrix a, b; 275 FT_Pos x, y; 276 277 278 FT_UNUSED( renderer ); 279 280 if ( !matrix ) 281 { 282 tmp_matrix.xx = 0x10000; 283 tmp_matrix.xy = 0; 284 tmp_matrix.yx = 0; 285 tmp_matrix.yy = 0x10000; 286 287 matrix = &tmp_matrix; 288 } 289 290 if ( !delta ) 291 { 292 tmp_delta.x = 0; 293 tmp_delta.y = 0; 294 295 delta = &tmp_delta; 296 } 297 298 a = doc->transform; 299 b = *matrix; 300 FT_Matrix_Multiply( &b, &a ); 301 302 303 x = ADD_LONG( ADD_LONG( FT_MulFix( matrix->xx, doc->delta.x ), 304 FT_MulFix( matrix->xy, doc->delta.y ) ), 305 delta->x ); 306 y = ADD_LONG( ADD_LONG( FT_MulFix( matrix->yx, doc->delta.x ), 307 FT_MulFix( matrix->yy, doc->delta.y ) ), 308 delta->y ); 309 310 doc->delta.x = x; 311 doc->delta.y = y; 312 doc->transform = a; 313 314 return FT_Err_Ok; 315 } 316 317 #endif /* FT_CONFIG_OPTION_SVG */ 318 319 320 #ifdef FT_CONFIG_OPTION_SVG 321 #define PUT_SVG_MODULE( a ) a 322 #define SVG_GLYPH_FORMAT FT_GLYPH_FORMAT_SVG 323 #else 324 #define PUT_SVG_MODULE( a ) NULL 325 #define SVG_GLYPH_FORMAT FT_GLYPH_FORMAT_NONE 326 #endif 327 328 329 FT_DEFINE_RENDERER( 330 ft_svg_renderer_class, 331 332 FT_MODULE_RENDERER, 333 sizeof ( SVG_RendererRec ), 334 335 "ot-svg", 336 0x10000L, 337 0x20000L, 338 339 (const void*)PUT_SVG_MODULE( &svg_interface ), /* module specific interface */ 340 341 PUT_SVG_MODULE( ft_svg_init ), /* FT_Module_Constructor module_init */ 342 PUT_SVG_MODULE( ft_svg_done ), /* FT_Module_Destructor module_done */ 343 PUT_SVG_MODULE( ft_svg_get_interface ), /* FT_Module_Requester get_interface */ 344 345 SVG_GLYPH_FORMAT, 346 347 PUT_SVG_MODULE( ft_svg_render ), /* FT_Renderer_RenderFunc render_glyph */ 348 PUT_SVG_MODULE( ft_svg_transform ), /* FT_Renderer_TransformFunc transform_glyph */ 349 NULL, /* FT_Renderer_GetCBoxFunc get_glyph_cbox */ 350 NULL, /* FT_Renderer_SetModeFunc set_mode */ 351 NULL /* FT_Raster_Funcs* raster_class */ 352 ) 353 354 355 /* END */ 356