1 /****************************************************************************
2  *
3  * ftmm.c
4  *
5  *   Multiple Master font support (body).
6  *
7  * Copyright (C) 1996-2019 by
8  * David Turner, Robert Wilhelm, and Werner Lemberg.
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 
19 #include <ft2build.h>
20 #include FT_INTERNAL_DEBUG_H
21 
22 #include FT_MULTIPLE_MASTERS_H
23 #include FT_INTERNAL_OBJECTS_H
24 #include FT_SERVICE_MULTIPLE_MASTERS_H
25 #include FT_SERVICE_METRICS_VARIATIONS_H
26 
27 
28   /**************************************************************************
29    *
30    * The macro FT_COMPONENT is used in trace mode.  It is an implicit
31    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
32    * messages during execution.
33    */
34 #undef  FT_COMPONENT
35 #define FT_COMPONENT  mm
36 
37 
38   static FT_Error
ft_face_get_mm_service(FT_Face face,FT_Service_MultiMasters * aservice)39   ft_face_get_mm_service( FT_Face                   face,
40                           FT_Service_MultiMasters  *aservice )
41   {
42     FT_Error  error;
43 
44 
45     *aservice = NULL;
46 
47     if ( !face )
48       return FT_THROW( Invalid_Face_Handle );
49 
50     error = FT_ERR( Invalid_Argument );
51 
52     if ( FT_HAS_MULTIPLE_MASTERS( face ) )
53     {
54       FT_FACE_LOOKUP_SERVICE( face,
55                               *aservice,
56                               MULTI_MASTERS );
57 
58       if ( *aservice )
59         error = FT_Err_Ok;
60     }
61 
62     return error;
63   }
64 
65 
66   static FT_Error
ft_face_get_mvar_service(FT_Face face,FT_Service_MetricsVariations * aservice)67   ft_face_get_mvar_service( FT_Face                        face,
68                             FT_Service_MetricsVariations  *aservice )
69   {
70     FT_Error  error;
71 
72 
73     *aservice = NULL;
74 
75     if ( !face )
76       return FT_THROW( Invalid_Face_Handle );
77 
78     error = FT_ERR( Invalid_Argument );
79 
80     if ( FT_HAS_MULTIPLE_MASTERS( face ) )
81     {
82       FT_FACE_LOOKUP_SERVICE( face,
83                               *aservice,
84                               METRICS_VARIATIONS );
85 
86       if ( *aservice )
87         error = FT_Err_Ok;
88     }
89 
90     return error;
91   }
92 
93 
94   /* documentation is in ftmm.h */
95 
96   FT_EXPORT_DEF( FT_Error )
FT_Get_Multi_Master(FT_Face face,FT_Multi_Master * amaster)97   FT_Get_Multi_Master( FT_Face           face,
98                        FT_Multi_Master  *amaster )
99   {
100     FT_Error                 error;
101     FT_Service_MultiMasters  service;
102 
103 
104     /* check of `face' delayed to `ft_face_get_mm_service' */
105 
106     if ( !amaster )
107       return FT_THROW( Invalid_Argument );
108 
109     error = ft_face_get_mm_service( face, &service );
110     if ( !error )
111     {
112       error = FT_ERR( Invalid_Argument );
113       if ( service->get_mm )
114         error = service->get_mm( face, amaster );
115     }
116 
117     return error;
118   }
119 
120 
121   /* documentation is in ftmm.h */
122 
123   FT_EXPORT_DEF( FT_Error )
FT_Get_MM_Var(FT_Face face,FT_MM_Var ** amaster)124   FT_Get_MM_Var( FT_Face      face,
125                  FT_MM_Var*  *amaster )
126   {
127     FT_Error                 error;
128     FT_Service_MultiMasters  service;
129 
130 
131     /* check of `face' delayed to `ft_face_get_mm_service' */
132 
133     if ( !amaster )
134       return FT_THROW( Invalid_Argument );
135 
136     error = ft_face_get_mm_service( face, &service );
137     if ( !error )
138     {
139       error = FT_ERR( Invalid_Argument );
140       if ( service->get_mm_var )
141         error = service->get_mm_var( face, amaster );
142     }
143 
144     return error;
145   }
146 
147 
148   /* documentation is in ftmm.h */
149 
150   FT_EXPORT_DEF( FT_Error )
FT_Done_MM_Var(FT_Library library,FT_MM_Var * amaster)151   FT_Done_MM_Var( FT_Library  library,
152                   FT_MM_Var*  amaster )
153   {
154     FT_Memory  memory;
155 
156 
157     if ( !library )
158       return FT_THROW( Invalid_Library_Handle );
159 
160     memory = library->memory;
161     FT_FREE( amaster );
162 
163     return FT_Err_Ok;
164   }
165 
166 
167   /* documentation is in ftmm.h */
168 
169   FT_EXPORT_DEF( FT_Error )
FT_Set_MM_Design_Coordinates(FT_Face face,FT_UInt num_coords,FT_Long * coords)170   FT_Set_MM_Design_Coordinates( FT_Face   face,
171                                 FT_UInt   num_coords,
172                                 FT_Long*  coords )
173   {
174     FT_Error                 error;
175     FT_Service_MultiMasters  service;
176 
177 
178     /* check of `face' delayed to `ft_face_get_mm_service' */
179 
180     if ( num_coords && !coords )
181       return FT_THROW( Invalid_Argument );
182 
183     error = ft_face_get_mm_service( face, &service );
184     if ( !error )
185     {
186       error = FT_ERR( Invalid_Argument );
187       if ( service->set_mm_design )
188         error = service->set_mm_design( face, num_coords, coords );
189     }
190 
191     /* enforce recomputation of auto-hinting data */
192     if ( !error && face->autohint.finalizer )
193     {
194       face->autohint.finalizer( face->autohint.data );
195       face->autohint.data = NULL;
196     }
197 
198     return error;
199   }
200 
201 
202   /* documentation is in ftmm.h */
203 
204   FT_EXPORT_DEF( FT_Error )
FT_Set_MM_WeightVector(FT_Face face,FT_UInt len,FT_Fixed * weightvector)205   FT_Set_MM_WeightVector( FT_Face    face,
206                           FT_UInt    len,
207                           FT_Fixed*  weightvector )
208   {
209     FT_Error                 error;
210     FT_Service_MultiMasters  service;
211 
212 
213     /* check of `face' delayed to `ft_face_get_mm_service' */
214 
215     if ( len && !weightvector )
216       return FT_THROW( Invalid_Argument );
217 
218     error = ft_face_get_mm_service( face, &service );
219     if ( !error )
220     {
221       error = FT_ERR( Invalid_Argument );
222       if ( service->set_mm_weightvector )
223         error = service->set_mm_weightvector( face, len, weightvector );
224     }
225 
226     /* enforce recomputation of auto-hinting data */
227     if ( !error && face->autohint.finalizer )
228     {
229       face->autohint.finalizer( face->autohint.data );
230       face->autohint.data = NULL;
231     }
232 
233     return error;
234   }
235 
236 
237   FT_EXPORT_DEF( FT_Error )
FT_Get_MM_WeightVector(FT_Face face,FT_UInt * len,FT_Fixed * weightvector)238   FT_Get_MM_WeightVector( FT_Face    face,
239                           FT_UInt*   len,
240                           FT_Fixed*  weightvector )
241   {
242     FT_Error                 error;
243     FT_Service_MultiMasters  service;
244 
245 
246     /* check of `face' delayed to `ft_face_get_mm_service' */
247 
248     if ( len && !weightvector )
249       return FT_THROW( Invalid_Argument );
250 
251     error = ft_face_get_mm_service( face, &service );
252     if ( !error )
253     {
254       error = FT_ERR( Invalid_Argument );
255       if ( service->get_mm_weightvector )
256         error = service->get_mm_weightvector( face, len, weightvector );
257     }
258 
259     return error;
260   }
261 
262 
263   /* documentation is in ftmm.h */
264 
265   FT_EXPORT_DEF( FT_Error )
FT_Set_Var_Design_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)266   FT_Set_Var_Design_Coordinates( FT_Face    face,
267                                  FT_UInt    num_coords,
268                                  FT_Fixed*  coords )
269   {
270     FT_Error                      error;
271     FT_Service_MultiMasters       service_mm   = NULL;
272     FT_Service_MetricsVariations  service_mvar = NULL;
273 
274 
275     /* check of `face' delayed to `ft_face_get_mm_service' */
276 
277     if ( num_coords && !coords )
278       return FT_THROW( Invalid_Argument );
279 
280     error = ft_face_get_mm_service( face, &service_mm );
281     if ( !error )
282     {
283       error = FT_ERR( Invalid_Argument );
284       if ( service_mm->set_var_design )
285         error = service_mm->set_var_design( face, num_coords, coords );
286 
287       /* internal error code -1 means `no change'; we can exit immediately */
288       if ( error == -1 )
289         return FT_Err_Ok;
290     }
291 
292     if ( !error )
293     {
294       (void)ft_face_get_mvar_service( face, &service_mvar );
295 
296       if ( service_mvar && service_mvar->metrics_adjust )
297         service_mvar->metrics_adjust( face );
298     }
299 
300     /* enforce recomputation of auto-hinting data */
301     if ( !error && face->autohint.finalizer )
302     {
303       face->autohint.finalizer( face->autohint.data );
304       face->autohint.data = NULL;
305     }
306 
307     return error;
308   }
309 
310 
311   /* documentation is in ftmm.h */
312 
313   FT_EXPORT_DEF( FT_Error )
FT_Get_Var_Design_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)314   FT_Get_Var_Design_Coordinates( FT_Face    face,
315                                  FT_UInt    num_coords,
316                                  FT_Fixed*  coords )
317   {
318     FT_Error                 error;
319     FT_Service_MultiMasters  service;
320 
321 
322     /* check of `face' delayed to `ft_face_get_mm_service' */
323 
324     if ( !coords )
325       return FT_THROW( Invalid_Argument );
326 
327     error = ft_face_get_mm_service( face, &service );
328     if ( !error )
329     {
330       error = FT_ERR( Invalid_Argument );
331       if ( service->get_var_design )
332         error = service->get_var_design( face, num_coords, coords );
333     }
334 
335     return error;
336   }
337 
338 
339   /* documentation is in ftmm.h */
340 
341   FT_EXPORT_DEF( FT_Error )
FT_Set_MM_Blend_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)342   FT_Set_MM_Blend_Coordinates( FT_Face    face,
343                                FT_UInt    num_coords,
344                                FT_Fixed*  coords )
345   {
346     FT_Error                      error;
347     FT_Service_MultiMasters       service_mm   = NULL;
348     FT_Service_MetricsVariations  service_mvar = NULL;
349 
350 
351     /* check of `face' delayed to `ft_face_get_mm_service' */
352 
353     if ( num_coords && !coords )
354       return FT_THROW( Invalid_Argument );
355 
356     error = ft_face_get_mm_service( face, &service_mm );
357     if ( !error )
358     {
359       error = FT_ERR( Invalid_Argument );
360       if ( service_mm->set_mm_blend )
361         error = service_mm->set_mm_blend( face, num_coords, coords );
362 
363       /* internal error code -1 means `no change'; we can exit immediately */
364       if ( error == -1 )
365         return FT_Err_Ok;
366     }
367 
368     if ( !error )
369     {
370       (void)ft_face_get_mvar_service( face, &service_mvar );
371 
372       if ( service_mvar && service_mvar->metrics_adjust )
373         service_mvar->metrics_adjust( face );
374     }
375 
376     /* enforce recomputation of auto-hinting data */
377     if ( !error && face->autohint.finalizer )
378     {
379       face->autohint.finalizer( face->autohint.data );
380       face->autohint.data = NULL;
381     }
382 
383     return error;
384   }
385 
386 
387   /* documentation is in ftmm.h */
388 
389   /* This is exactly the same as the previous function.  It exists for */
390   /* orthogonality.                                                    */
391 
392   FT_EXPORT_DEF( FT_Error )
FT_Set_Var_Blend_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)393   FT_Set_Var_Blend_Coordinates( FT_Face    face,
394                                 FT_UInt    num_coords,
395                                 FT_Fixed*  coords )
396   {
397     FT_Error                      error;
398     FT_Service_MultiMasters       service_mm   = NULL;
399     FT_Service_MetricsVariations  service_mvar = NULL;
400 
401 
402     /* check of `face' delayed to `ft_face_get_mm_service' */
403 
404     if ( num_coords && !coords )
405       return FT_THROW( Invalid_Argument );
406 
407     error = ft_face_get_mm_service( face, &service_mm );
408     if ( !error )
409     {
410       error = FT_ERR( Invalid_Argument );
411       if ( service_mm->set_mm_blend )
412         error = service_mm->set_mm_blend( face, num_coords, coords );
413 
414       /* internal error code -1 means `no change'; we can exit immediately */
415       if ( error == -1 )
416         return FT_Err_Ok;
417     }
418 
419     if ( !error )
420     {
421       (void)ft_face_get_mvar_service( face, &service_mvar );
422 
423       if ( service_mvar && service_mvar->metrics_adjust )
424         service_mvar->metrics_adjust( face );
425     }
426 
427     /* enforce recomputation of auto-hinting data */
428     if ( !error && face->autohint.finalizer )
429     {
430       face->autohint.finalizer( face->autohint.data );
431       face->autohint.data = NULL;
432     }
433 
434     return error;
435   }
436 
437 
438   /* documentation is in ftmm.h */
439 
440   FT_EXPORT_DEF( FT_Error )
FT_Get_MM_Blend_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)441   FT_Get_MM_Blend_Coordinates( FT_Face    face,
442                                FT_UInt    num_coords,
443                                FT_Fixed*  coords )
444   {
445     FT_Error                 error;
446     FT_Service_MultiMasters  service;
447 
448 
449     /* check of `face' delayed to `ft_face_get_mm_service' */
450 
451     if ( !coords )
452       return FT_THROW( Invalid_Argument );
453 
454     error = ft_face_get_mm_service( face, &service );
455     if ( !error )
456     {
457       error = FT_ERR( Invalid_Argument );
458       if ( service->get_mm_blend )
459         error = service->get_mm_blend( face, num_coords, coords );
460     }
461 
462     return error;
463   }
464 
465 
466   /* documentation is in ftmm.h */
467 
468   /* This is exactly the same as the previous function.  It exists for */
469   /* orthogonality.                                                    */
470 
471   FT_EXPORT_DEF( FT_Error )
FT_Get_Var_Blend_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)472   FT_Get_Var_Blend_Coordinates( FT_Face    face,
473                                 FT_UInt    num_coords,
474                                 FT_Fixed*  coords )
475   {
476     FT_Error                 error;
477     FT_Service_MultiMasters  service;
478 
479 
480     /* check of `face' delayed to `ft_face_get_mm_service' */
481 
482     if ( !coords )
483       return FT_THROW( Invalid_Argument );
484 
485     error = ft_face_get_mm_service( face, &service );
486     if ( !error )
487     {
488       error = FT_ERR( Invalid_Argument );
489       if ( service->get_mm_blend )
490         error = service->get_mm_blend( face, num_coords, coords );
491     }
492 
493     return error;
494   }
495 
496 
497   /* documentation is in ftmm.h */
498 
499   FT_EXPORT_DEF( FT_Error )
FT_Get_Var_Axis_Flags(FT_MM_Var * master,FT_UInt axis_index,FT_UInt * flags)500   FT_Get_Var_Axis_Flags( FT_MM_Var*  master,
501                          FT_UInt     axis_index,
502                          FT_UInt*    flags )
503   {
504     FT_UShort*  axis_flags;
505 
506 
507     if ( !master || !flags )
508       return FT_THROW( Invalid_Argument );
509 
510     if ( axis_index >= master->num_axis )
511       return FT_THROW( Invalid_Argument );
512 
513     /* the axis flags array immediately follows the data of `master' */
514     axis_flags = (FT_UShort*)&( master[1] );
515     *flags     = axis_flags[axis_index];
516 
517     return FT_Err_Ok;
518   }
519 
520 
521   /* documentation is in ftmm.h */
522 
523   FT_EXPORT_DEF( FT_Error )
FT_Set_Named_Instance(FT_Face face,FT_UInt instance_index)524   FT_Set_Named_Instance( FT_Face  face,
525                          FT_UInt  instance_index )
526   {
527     FT_Error  error;
528 
529     FT_Service_MultiMasters       service_mm   = NULL;
530     FT_Service_MetricsVariations  service_mvar = NULL;
531 
532 
533     /* check of `face' delayed to `ft_face_get_mm_service' */
534 
535     error = ft_face_get_mm_service( face, &service_mm );
536     if ( !error )
537     {
538       error = FT_ERR( Invalid_Argument );
539       if ( service_mm->set_instance )
540         error = service_mm->set_instance( face, instance_index );
541     }
542 
543     if ( !error )
544     {
545       (void)ft_face_get_mvar_service( face, &service_mvar );
546 
547       if ( service_mvar && service_mvar->metrics_adjust )
548         service_mvar->metrics_adjust( face );
549     }
550 
551     /* enforce recomputation of auto-hinting data */
552     if ( !error && face->autohint.finalizer )
553     {
554       face->autohint.finalizer( face->autohint.data );
555       face->autohint.data = NULL;
556     }
557 
558     if ( !error )
559     {
560       face->face_index  = ( instance_index << 16 )        |
561                           ( face->face_index & 0xFFFFL );
562       face->face_flags &= ~FT_FACE_FLAG_VARIATION;
563     }
564 
565     return error;
566   }
567 
568 
569 /* END */
570