• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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