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(SVG_Renderer svg_module)43 ft_svg_init( SVG_Renderer svg_module ) 44 { 45 FT_Error error = FT_Err_Ok; 46 47 48 svg_module->loaded = FALSE; 49 svg_module->hooks_set = FALSE; 50 51 return error; 52 } 53 54 55 static void ft_svg_done(SVG_Renderer svg_module)56 ft_svg_done( SVG_Renderer svg_module ) 57 { 58 if ( svg_module->loaded == TRUE && 59 svg_module->hooks_set == TRUE ) 60 svg_module->hooks.free_svg( &svg_module->state ); 61 62 svg_module->loaded = FALSE; 63 } 64 65 66 static FT_Error ft_svg_preset_slot(FT_Module module,FT_GlyphSlot slot,FT_Bool cache)67 ft_svg_preset_slot( FT_Module module, 68 FT_GlyphSlot slot, 69 FT_Bool cache ) 70 { 71 SVG_Renderer svg_renderer = (SVG_Renderer)module; 72 SVG_RendererHooks hooks = svg_renderer->hooks; 73 74 75 if ( svg_renderer->hooks_set == FALSE ) 76 { 77 FT_TRACE1(( "Hooks are NOT set. Can't render OT-SVG glyphs\n" )); 78 return FT_THROW( Missing_SVG_Hooks ); 79 } 80 81 if ( svg_renderer->loaded == FALSE ) 82 { 83 FT_TRACE3(( "ft_svg_preset_slot: first presetting call," 84 " calling init hook\n" )); 85 hooks.init_svg( &svg_renderer->state ); 86 87 svg_renderer->loaded = TRUE; 88 } 89 90 return hooks.preset_slot( slot, cache, &svg_renderer->state ); 91 } 92 93 94 static FT_Error ft_svg_render(FT_Renderer renderer,FT_GlyphSlot slot,FT_Render_Mode mode,const FT_Vector * origin)95 ft_svg_render( FT_Renderer renderer, 96 FT_GlyphSlot slot, 97 FT_Render_Mode mode, 98 const FT_Vector* origin ) 99 { 100 SVG_Renderer svg_renderer = (SVG_Renderer)renderer; 101 102 FT_Library library = renderer->root.library; 103 FT_Memory memory = library->memory; 104 FT_Error error; 105 106 FT_ULong size_image_buffer; 107 108 SVG_RendererHooks hooks = svg_renderer->hooks; 109 110 111 FT_UNUSED( mode ); 112 FT_UNUSED( origin ); 113 114 if ( mode != FT_RENDER_MODE_NORMAL ) 115 return FT_THROW( Bad_Argument ); 116 117 if ( svg_renderer->hooks_set == FALSE ) 118 { 119 FT_TRACE1(( "Hooks are NOT set. Can't render OT-SVG glyphs\n" )); 120 return FT_THROW( Missing_SVG_Hooks ); 121 } 122 123 if ( svg_renderer->loaded == FALSE ) 124 { 125 FT_TRACE3(( "ft_svg_render: first rendering, calling init hook\n" )); 126 error = hooks.init_svg( &svg_renderer->state ); 127 128 svg_renderer->loaded = TRUE; 129 } 130 131 ft_svg_preset_slot( (FT_Module)renderer, slot, TRUE ); 132 133 size_image_buffer = (FT_ULong)slot->bitmap.pitch * slot->bitmap.rows; 134 /* No `FT_QALLOC` here since we need a clean, empty canvas */ 135 /* to start with. */ 136 if ( FT_ALLOC( slot->bitmap.buffer, size_image_buffer ) ) 137 return error; 138 139 error = hooks.render_svg( slot, &svg_renderer->state ); 140 if ( error ) 141 FT_FREE( slot->bitmap.buffer ); 142 else 143 slot->internal->flags |= FT_GLYPH_OWN_BITMAP; 144 145 return error; 146 } 147 148 149 static const SVG_Interface svg_interface = 150 { 151 (Preset_Bitmap_Func)ft_svg_preset_slot 152 }; 153 154 155 static FT_Error ft_svg_property_set(FT_Module module,const char * property_name,const void * value,FT_Bool value_is_string)156 ft_svg_property_set( FT_Module module, 157 const char* property_name, 158 const void* value, 159 FT_Bool value_is_string ) 160 { 161 FT_Error error = FT_Err_Ok; 162 SVG_Renderer renderer = (SVG_Renderer)module; 163 164 165 if ( !ft_strcmp( property_name, "svg-hooks" ) ) 166 { 167 SVG_RendererHooks* hooks; 168 169 170 if ( value_is_string == TRUE ) 171 { 172 error = FT_THROW( Invalid_Argument ); 173 goto Exit; 174 } 175 176 hooks = (SVG_RendererHooks*)value; 177 178 if ( !hooks->init_svg || 179 !hooks->free_svg || 180 !hooks->render_svg || 181 !hooks->preset_slot ) 182 { 183 FT_TRACE0(( "ft_svg_property_set:" 184 " SVG rendering hooks not set because\n" )); 185 FT_TRACE0(( " " 186 " at least one function pointer is NULL\n" )); 187 188 error = FT_THROW( Invalid_Argument ); 189 goto Exit; 190 } 191 192 renderer->hooks = *hooks; 193 renderer->hooks_set = TRUE; 194 } 195 else 196 error = FT_THROW( Missing_Property ); 197 198 Exit: 199 return error; 200 } 201 202 203 static FT_Error ft_svg_property_get(FT_Module module,const char * property_name,const void * value)204 ft_svg_property_get( FT_Module module, 205 const char* property_name, 206 const void* value ) 207 { 208 FT_Error error = FT_Err_Ok; 209 SVG_Renderer renderer = (SVG_Renderer)module; 210 211 212 if ( !ft_strcmp( property_name, "svg-hooks" ) ) 213 { 214 SVG_RendererHooks* hooks = (SVG_RendererHooks*)value; 215 216 217 *hooks = renderer->hooks; 218 } 219 else 220 error = FT_THROW( Missing_Property ); 221 222 return error; 223 } 224 225 226 FT_DEFINE_SERVICE_PROPERTIESREC( 227 ft_svg_service_properties, 228 229 (FT_Properties_SetFunc)ft_svg_property_set, /* set_property */ 230 (FT_Properties_GetFunc)ft_svg_property_get /* get_property */ 231 ) 232 233 234 FT_DEFINE_SERVICEDESCREC1( 235 ft_svg_services, 236 FT_SERVICE_ID_PROPERTIES, &ft_svg_service_properties ) 237 238 FT_CALLBACK_DEF(FT_Module_Interface)239 FT_CALLBACK_DEF( FT_Module_Interface ) 240 ft_svg_get_interface( FT_Module module, 241 const char* ft_svg_interface ) 242 { 243 FT_Module_Interface result; 244 245 246 FT_UNUSED( module ); 247 248 result = ft_service_list_lookup( ft_svg_services, ft_svg_interface ); 249 if ( result ) 250 return result; 251 252 return 0; 253 } 254 255 256 static FT_Error ft_svg_transform(FT_Renderer renderer,FT_GlyphSlot slot,const FT_Matrix * _matrix,const FT_Vector * _delta)257 ft_svg_transform( FT_Renderer renderer, 258 FT_GlyphSlot slot, 259 const FT_Matrix* _matrix, 260 const FT_Vector* _delta ) 261 { 262 FT_SVG_Document doc = (FT_SVG_Document)slot->other; 263 FT_Matrix* matrix = (FT_Matrix*)_matrix; 264 FT_Vector* delta = (FT_Vector*)_delta; 265 266 FT_Matrix tmp_matrix; 267 FT_Vector tmp_delta; 268 269 FT_Matrix a, b; 270 FT_Pos x, y; 271 272 273 FT_UNUSED( renderer ); 274 275 if ( !matrix ) 276 { 277 tmp_matrix.xx = 0x10000; 278 tmp_matrix.xy = 0; 279 tmp_matrix.yx = 0; 280 tmp_matrix.yy = 0x10000; 281 282 matrix = &tmp_matrix; 283 } 284 285 if ( !delta ) 286 { 287 tmp_delta.x = 0; 288 tmp_delta.y = 0; 289 290 delta = &tmp_delta; 291 } 292 293 a = doc->transform; 294 b = *matrix; 295 FT_Matrix_Multiply( &b, &a ); 296 297 298 x = ADD_LONG( ADD_LONG( FT_MulFix( matrix->xx, doc->delta.x ), 299 FT_MulFix( matrix->xy, doc->delta.y ) ), 300 delta->x ); 301 y = ADD_LONG( ADD_LONG( FT_MulFix( matrix->yx, doc->delta.x ), 302 FT_MulFix( matrix->yy, doc->delta.y ) ), 303 delta->y ); 304 305 doc->delta.x = x; 306 doc->delta.y = y; 307 doc->transform = a; 308 309 return FT_Err_Ok; 310 } 311 312 #endif /* FT_CONFIG_OPTION_SVG */ 313 314 315 #ifdef FT_CONFIG_OPTION_SVG 316 #define PUT_SVG_MODULE( a ) a 317 #define SVG_GLYPH_FORMAT FT_GLYPH_FORMAT_SVG 318 #else 319 #define PUT_SVG_MODULE( a ) NULL 320 #define SVG_GLYPH_FORMAT FT_GLYPH_FORMAT_NONE 321 #endif 322 323 324 FT_DEFINE_RENDERER( 325 ft_svg_renderer_class, 326 327 FT_MODULE_RENDERER, 328 sizeof ( SVG_RendererRec ), 329 330 "ot-svg", 331 0x10000L, 332 0x20000L, 333 334 (const void*)PUT_SVG_MODULE( &svg_interface ), /* module specific interface */ 335 336 (FT_Module_Constructor)PUT_SVG_MODULE( ft_svg_init ), /* module_init */ 337 (FT_Module_Destructor)PUT_SVG_MODULE( ft_svg_done ), /* module_done */ 338 PUT_SVG_MODULE( ft_svg_get_interface ), /* get_interface */ 339 340 SVG_GLYPH_FORMAT, 341 342 (FT_Renderer_RenderFunc) PUT_SVG_MODULE( ft_svg_render ), /* render_glyph */ 343 (FT_Renderer_TransformFunc)PUT_SVG_MODULE( ft_svg_transform ), /* transform_glyph */ 344 NULL, /* get_glyph_cbox */ 345 NULL, /* set_mode */ 346 NULL /* raster_class */ 347 ) 348 349 350 /* END */ 351