xref: /aosp_15_r20/external/freetype/src/svg/ftsvg.c (revision 63949dbd25bcc50c4e1178497ff9e9574d44fc5a)
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