xref: /aosp_15_r20/external/freetype/src/base/ftmm.c (revision 63949dbd25bcc50c4e1178497ff9e9574d44fc5a)
1 /****************************************************************************
2  *
3  * ftmm.c
4  *
5  *   Multiple Master font support (body).
6  *
7  * Copyright (C) 1996-2023 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 <freetype/internal/ftdebug.h>
20 
21 #include <freetype/ftmm.h>
22 #include <freetype/internal/ftobjs.h>
23 #include <freetype/internal/services/svmm.h>
24 #include <freetype/internal/services/svmetric.h>
25 
26 
27   /**************************************************************************
28    *
29    * The macro FT_COMPONENT is used in trace mode.  It is an implicit
30    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
31    * messages during execution.
32    */
33 #undef  FT_COMPONENT
34 #define FT_COMPONENT  mm
35 
36 
37   static FT_Error
ft_face_get_mm_service(FT_Face face,FT_Service_MultiMasters * aservice)38   ft_face_get_mm_service( FT_Face                   face,
39                           FT_Service_MultiMasters  *aservice )
40   {
41     FT_Error  error;
42 
43 
44     *aservice = NULL;
45 
46     if ( !face )
47       return FT_THROW( Invalid_Face_Handle );
48 
49     error = FT_ERR( Invalid_Argument );
50 
51     if ( FT_HAS_MULTIPLE_MASTERS( face ) )
52     {
53       FT_FACE_LOOKUP_SERVICE( face,
54                               *aservice,
55                               MULTI_MASTERS );
56 
57       if ( *aservice )
58         error = FT_Err_Ok;
59     }
60 
61     return error;
62   }
63 
64 
65   static FT_Error
ft_face_get_mvar_service(FT_Face face,FT_Service_MetricsVariations * aservice)66   ft_face_get_mvar_service( FT_Face                        face,
67                             FT_Service_MetricsVariations  *aservice )
68   {
69     FT_Error  error;
70 
71 
72     *aservice = NULL;
73 
74     if ( !face )
75       return FT_THROW( Invalid_Face_Handle );
76 
77     error = FT_ERR( Invalid_Argument );
78 
79     if ( FT_HAS_MULTIPLE_MASTERS( face ) )
80     {
81       FT_FACE_LOOKUP_SERVICE( face,
82                               *aservice,
83                               METRICS_VARIATIONS );
84 
85       if ( *aservice )
86         error = FT_Err_Ok;
87     }
88 
89     return error;
90   }
91 
92 
93   /* documentation is in ftmm.h */
94 
95   FT_EXPORT_DEF( FT_Error )
FT_Get_Multi_Master(FT_Face face,FT_Multi_Master * amaster)96   FT_Get_Multi_Master( FT_Face           face,
97                        FT_Multi_Master  *amaster )
98   {
99     FT_Error                 error;
100     FT_Service_MultiMasters  service;
101 
102 
103     /* check of `face' delayed to `ft_face_get_mm_service' */
104 
105     if ( !amaster )
106       return FT_THROW( Invalid_Argument );
107 
108     error = ft_face_get_mm_service( face, &service );
109     if ( !error )
110     {
111       error = FT_ERR( Invalid_Argument );
112       if ( service->get_mm )
113         error = service->get_mm( face, amaster );
114     }
115 
116     return error;
117   }
118 
119 
120   /* documentation is in ftmm.h */
121 
122   FT_EXPORT_DEF( FT_Error )
FT_Get_MM_Var(FT_Face face,FT_MM_Var ** amaster)123   FT_Get_MM_Var( FT_Face      face,
124                  FT_MM_Var*  *amaster )
125   {
126     FT_Error                 error;
127     FT_Service_MultiMasters  service;
128 
129 
130     /* check of `face' delayed to `ft_face_get_mm_service' */
131 
132     if ( !amaster )
133       return FT_THROW( Invalid_Argument );
134 
135     error = ft_face_get_mm_service( face, &service );
136     if ( !error )
137     {
138       error = FT_ERR( Invalid_Argument );
139       if ( service->get_mm_var )
140         error = service->get_mm_var( face, amaster );
141     }
142 
143     return error;
144   }
145 
146 
147   /* documentation is in ftmm.h */
148 
149   FT_EXPORT_DEF( FT_Error )
FT_Done_MM_Var(FT_Library library,FT_MM_Var * amaster)150   FT_Done_MM_Var( FT_Library  library,
151                   FT_MM_Var*  amaster )
152   {
153     FT_Memory  memory;
154 
155 
156     if ( !library )
157       return FT_THROW( Invalid_Library_Handle );
158 
159     memory = library->memory;
160     FT_FREE( amaster );
161 
162     return FT_Err_Ok;
163   }
164 
165 
166   /* documentation is in ftmm.h */
167 
168   FT_EXPORT_DEF( FT_Error )
FT_Set_MM_Design_Coordinates(FT_Face face,FT_UInt num_coords,FT_Long * coords)169   FT_Set_MM_Design_Coordinates( FT_Face   face,
170                                 FT_UInt   num_coords,
171                                 FT_Long*  coords )
172   {
173     FT_Error                 error;
174     FT_Service_MultiMasters  service;
175 
176 
177     /* check of `face' delayed to `ft_face_get_mm_service' */
178 
179     if ( num_coords && !coords )
180       return FT_THROW( Invalid_Argument );
181 
182     error = ft_face_get_mm_service( face, &service );
183     if ( !error )
184     {
185       error = FT_ERR( Invalid_Argument );
186       if ( service->set_mm_design )
187         error = service->set_mm_design( face, num_coords, coords );
188 
189       if ( !error )
190       {
191         if ( num_coords )
192           face->face_flags |= FT_FACE_FLAG_VARIATION;
193         else
194           face->face_flags &= ~FT_FACE_FLAG_VARIATION;
195       }
196     }
197 
198     /* enforce recomputation of auto-hinting data */
199     if ( !error && face->autohint.finalizer )
200     {
201       face->autohint.finalizer( face->autohint.data );
202       face->autohint.data = NULL;
203     }
204 
205     return error;
206   }
207 
208 
209   /* documentation is in ftmm.h */
210 
211   FT_EXPORT_DEF( FT_Error )
FT_Set_MM_WeightVector(FT_Face face,FT_UInt len,FT_Fixed * weightvector)212   FT_Set_MM_WeightVector( FT_Face    face,
213                           FT_UInt    len,
214                           FT_Fixed*  weightvector )
215   {
216     FT_Error                 error;
217     FT_Service_MultiMasters  service;
218 
219 
220     /* check of `face' delayed to `ft_face_get_mm_service' */
221 
222     if ( len && !weightvector )
223       return FT_THROW( Invalid_Argument );
224 
225     error = ft_face_get_mm_service( face, &service );
226     if ( !error )
227     {
228       error = FT_ERR( Invalid_Argument );
229       if ( service->set_mm_weightvector )
230         error = service->set_mm_weightvector( face, len, weightvector );
231 
232       if ( !error )
233       {
234         if ( len )
235           face->face_flags |= FT_FACE_FLAG_VARIATION;
236         else
237           face->face_flags &= ~FT_FACE_FLAG_VARIATION;
238       }
239     }
240 
241     /* enforce recomputation of auto-hinting data */
242     if ( !error && face->autohint.finalizer )
243     {
244       face->autohint.finalizer( face->autohint.data );
245       face->autohint.data = NULL;
246     }
247 
248     return error;
249   }
250 
251 
252   FT_EXPORT_DEF( FT_Error )
FT_Get_MM_WeightVector(FT_Face face,FT_UInt * len,FT_Fixed * weightvector)253   FT_Get_MM_WeightVector( FT_Face    face,
254                           FT_UInt*   len,
255                           FT_Fixed*  weightvector )
256   {
257     FT_Error                 error;
258     FT_Service_MultiMasters  service;
259 
260 
261     /* check of `face' delayed to `ft_face_get_mm_service' */
262 
263     if ( len && !weightvector )
264       return FT_THROW( Invalid_Argument );
265 
266     error = ft_face_get_mm_service( face, &service );
267     if ( !error )
268     {
269       error = FT_ERR( Invalid_Argument );
270       if ( service->get_mm_weightvector )
271         error = service->get_mm_weightvector( face, len, weightvector );
272     }
273 
274     return error;
275   }
276 
277 
278   /* documentation is in ftmm.h */
279 
280   FT_EXPORT_DEF( FT_Error )
FT_Set_Var_Design_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)281   FT_Set_Var_Design_Coordinates( FT_Face    face,
282                                  FT_UInt    num_coords,
283                                  FT_Fixed*  coords )
284   {
285     FT_Error                      error;
286     FT_Service_MultiMasters       service_mm   = NULL;
287     FT_Service_MetricsVariations  service_mvar = NULL;
288 
289 
290     /* check of `face' delayed to `ft_face_get_mm_service' */
291 
292     if ( num_coords && !coords )
293       return FT_THROW( Invalid_Argument );
294 
295     error = ft_face_get_mm_service( face, &service_mm );
296     if ( !error )
297     {
298       error = FT_ERR( Invalid_Argument );
299       if ( service_mm->set_var_design )
300         error = service_mm->set_var_design( face, num_coords, coords );
301 
302       if ( !error || error == -1 )
303       {
304         FT_Bool  is_variation_old = FT_IS_VARIATION( face );
305 
306 
307         if ( num_coords )
308           face->face_flags |= FT_FACE_FLAG_VARIATION;
309         else
310           face->face_flags &= ~FT_FACE_FLAG_VARIATION;
311 
312         if ( service_mm->construct_ps_name )
313         {
314           if ( error == -1 )
315           {
316             /* The PS name of a named instance and a non-named instance */
317             /* usually differs, even if the axis values are identical.  */
318             if ( is_variation_old != FT_IS_VARIATION( face ) )
319               service_mm->construct_ps_name( face );
320           }
321           else
322             service_mm->construct_ps_name( face );
323         }
324       }
325 
326       /* internal error code -1 means `no change'; we can exit immediately */
327       if ( error == -1 )
328         return FT_Err_Ok;
329     }
330 
331     if ( !error )
332     {
333       (void)ft_face_get_mvar_service( face, &service_mvar );
334 
335       if ( service_mvar && service_mvar->metrics_adjust )
336         service_mvar->metrics_adjust( face );
337     }
338 
339     /* enforce recomputation of auto-hinting data */
340     if ( !error && face->autohint.finalizer )
341     {
342       face->autohint.finalizer( face->autohint.data );
343       face->autohint.data = NULL;
344     }
345 
346     return error;
347   }
348 
349 
350   /* documentation is in ftmm.h */
351 
352   FT_EXPORT_DEF( FT_Error )
FT_Get_Var_Design_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)353   FT_Get_Var_Design_Coordinates( FT_Face    face,
354                                  FT_UInt    num_coords,
355                                  FT_Fixed*  coords )
356   {
357     FT_Error                 error;
358     FT_Service_MultiMasters  service;
359 
360 
361     /* check of `face' delayed to `ft_face_get_mm_service' */
362 
363     if ( !coords )
364       return FT_THROW( Invalid_Argument );
365 
366     error = ft_face_get_mm_service( face, &service );
367     if ( !error )
368     {
369       error = FT_ERR( Invalid_Argument );
370       if ( service->get_var_design )
371         error = service->get_var_design( face, num_coords, coords );
372     }
373 
374     return error;
375   }
376 
377 
378   /* documentation is in ftmm.h */
379 
380   FT_EXPORT_DEF( FT_Error )
FT_Set_MM_Blend_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)381   FT_Set_MM_Blend_Coordinates( FT_Face    face,
382                                FT_UInt    num_coords,
383                                FT_Fixed*  coords )
384   {
385     FT_Error                      error;
386     FT_Service_MultiMasters       service_mm   = NULL;
387     FT_Service_MetricsVariations  service_mvar = NULL;
388 
389 
390     /* check of `face' delayed to `ft_face_get_mm_service' */
391 
392     if ( num_coords && !coords )
393       return FT_THROW( Invalid_Argument );
394 
395     error = ft_face_get_mm_service( face, &service_mm );
396     if ( !error )
397     {
398       error = FT_ERR( Invalid_Argument );
399       if ( service_mm->set_mm_blend )
400         error = service_mm->set_mm_blend( face, num_coords, coords );
401 
402       if ( !error || error == -1 )
403       {
404         FT_Bool  is_variation_old = FT_IS_VARIATION( face );
405 
406 
407         if ( num_coords )
408           face->face_flags |= FT_FACE_FLAG_VARIATION;
409         else
410           face->face_flags &= ~FT_FACE_FLAG_VARIATION;
411 
412         if ( service_mm->construct_ps_name )
413         {
414           if ( error == -1 )
415           {
416             /* The PS name of a named instance and a non-named instance */
417             /* usually differs, even if the axis values are identical.  */
418             if ( is_variation_old != FT_IS_VARIATION( face ) )
419               service_mm->construct_ps_name( face );
420           }
421           else
422             service_mm->construct_ps_name( face );
423         }
424       }
425 
426       /* internal error code -1 means `no change'; we can exit immediately */
427       if ( error == -1 )
428         return FT_Err_Ok;
429     }
430 
431     if ( !error )
432     {
433       (void)ft_face_get_mvar_service( face, &service_mvar );
434 
435       if ( service_mvar && service_mvar->metrics_adjust )
436         service_mvar->metrics_adjust( face );
437     }
438 
439     /* enforce recomputation of auto-hinting data */
440     if ( !error && face->autohint.finalizer )
441     {
442       face->autohint.finalizer( face->autohint.data );
443       face->autohint.data = NULL;
444     }
445 
446     return error;
447   }
448 
449 
450   /* documentation is in ftmm.h */
451 
452   /* This is exactly the same as the previous function.  It exists for */
453   /* orthogonality.                                                    */
454 
455   FT_EXPORT_DEF( FT_Error )
FT_Set_Var_Blend_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)456   FT_Set_Var_Blend_Coordinates( FT_Face    face,
457                                 FT_UInt    num_coords,
458                                 FT_Fixed*  coords )
459   {
460     FT_Error                      error;
461     FT_Service_MultiMasters       service_mm   = NULL;
462     FT_Service_MetricsVariations  service_mvar = NULL;
463 
464 
465     /* check of `face' delayed to `ft_face_get_mm_service' */
466 
467     if ( num_coords && !coords )
468       return FT_THROW( Invalid_Argument );
469 
470     error = ft_face_get_mm_service( face, &service_mm );
471     if ( !error )
472     {
473       error = FT_ERR( Invalid_Argument );
474       if ( service_mm->set_mm_blend )
475         error = service_mm->set_mm_blend( face, num_coords, coords );
476 
477       if ( !error || error == -1 )
478       {
479         FT_Bool  is_variation_old = FT_IS_VARIATION( face );
480 
481 
482         if ( num_coords )
483           face->face_flags |= FT_FACE_FLAG_VARIATION;
484         else
485           face->face_flags &= ~FT_FACE_FLAG_VARIATION;
486 
487         if ( service_mm->construct_ps_name )
488         {
489           if ( error == -1 )
490           {
491             /* The PS name of a named instance and a non-named instance */
492             /* usually differs, even if the axis values are identical.  */
493             if ( is_variation_old != FT_IS_VARIATION( face ) )
494               service_mm->construct_ps_name( face );
495           }
496           else
497             service_mm->construct_ps_name( face );
498         }
499       }
500 
501       /* internal error code -1 means `no change'; we can exit immediately */
502       if ( error == -1 )
503         return FT_Err_Ok;
504     }
505 
506     if ( !error )
507     {
508       (void)ft_face_get_mvar_service( face, &service_mvar );
509 
510       if ( service_mvar && service_mvar->metrics_adjust )
511         service_mvar->metrics_adjust( face );
512     }
513 
514     /* enforce recomputation of auto-hinting data */
515     if ( !error && face->autohint.finalizer )
516     {
517       face->autohint.finalizer( face->autohint.data );
518       face->autohint.data = NULL;
519     }
520 
521     return error;
522   }
523 
524 
525   /* documentation is in ftmm.h */
526 
527   FT_EXPORT_DEF( FT_Error )
FT_Get_MM_Blend_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)528   FT_Get_MM_Blend_Coordinates( FT_Face    face,
529                                FT_UInt    num_coords,
530                                FT_Fixed*  coords )
531   {
532     FT_Error                 error;
533     FT_Service_MultiMasters  service;
534 
535 
536     /* check of `face' delayed to `ft_face_get_mm_service' */
537 
538     if ( !coords )
539       return FT_THROW( Invalid_Argument );
540 
541     error = ft_face_get_mm_service( face, &service );
542     if ( !error )
543     {
544       error = FT_ERR( Invalid_Argument );
545       if ( service->get_mm_blend )
546         error = service->get_mm_blend( face, num_coords, coords );
547     }
548 
549     return error;
550   }
551 
552 
553   /* documentation is in ftmm.h */
554 
555   /* This is exactly the same as the previous function.  It exists for */
556   /* orthogonality.                                                    */
557 
558   FT_EXPORT_DEF( FT_Error )
FT_Get_Var_Blend_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)559   FT_Get_Var_Blend_Coordinates( FT_Face    face,
560                                 FT_UInt    num_coords,
561                                 FT_Fixed*  coords )
562   {
563     FT_Error                 error;
564     FT_Service_MultiMasters  service;
565 
566 
567     /* check of `face' delayed to `ft_face_get_mm_service' */
568 
569     if ( !coords )
570       return FT_THROW( Invalid_Argument );
571 
572     error = ft_face_get_mm_service( face, &service );
573     if ( !error )
574     {
575       error = FT_ERR( Invalid_Argument );
576       if ( service->get_mm_blend )
577         error = service->get_mm_blend( face, num_coords, coords );
578     }
579 
580     return error;
581   }
582 
583 
584   /* documentation is in ftmm.h */
585 
586   FT_EXPORT_DEF( FT_Error )
FT_Get_Var_Axis_Flags(FT_MM_Var * master,FT_UInt axis_index,FT_UInt * flags)587   FT_Get_Var_Axis_Flags( FT_MM_Var*  master,
588                          FT_UInt     axis_index,
589                          FT_UInt*    flags )
590   {
591     FT_UShort*  axis_flags;
592 
593 
594     if ( !master || !flags )
595       return FT_THROW( Invalid_Argument );
596 
597     if ( axis_index >= master->num_axis )
598       return FT_THROW( Invalid_Argument );
599 
600     /* the axis flags array immediately follows the data of `master' */
601     axis_flags = (FT_UShort*)&( master[1] );
602     *flags     = axis_flags[axis_index];
603 
604     return FT_Err_Ok;
605   }
606 
607 
608   /* documentation is in ftmm.h */
609 
610   FT_EXPORT_DEF( FT_Error )
FT_Set_Named_Instance(FT_Face face,FT_UInt instance_index)611   FT_Set_Named_Instance( FT_Face  face,
612                          FT_UInt  instance_index )
613   {
614     FT_Error  error;
615 
616     FT_Service_MultiMasters       service_mm   = NULL;
617     FT_Service_MetricsVariations  service_mvar = NULL;
618 
619 
620     /* check of `face' delayed to `ft_face_get_mm_service' */
621 
622     error = ft_face_get_mm_service( face, &service_mm );
623     if ( !error )
624     {
625       error = FT_ERR( Invalid_Argument );
626       if ( service_mm->set_named_instance )
627         error = service_mm->set_named_instance( face, instance_index );
628 
629       if ( !error || error == -1 )
630       {
631         FT_Bool  is_variation_old = FT_IS_VARIATION( face );
632 
633 
634         face->face_flags &= ~FT_FACE_FLAG_VARIATION;
635         face->face_index  = ( instance_index << 16 )        |
636                             ( face->face_index & 0xFFFFL );
637 
638         if ( service_mm->construct_ps_name )
639         {
640           if ( error == -1 )
641           {
642             /* The PS name of a named instance and a non-named instance */
643             /* usually differs, even if the axis values are identical.  */
644             if ( is_variation_old != FT_IS_VARIATION( face ) )
645               service_mm->construct_ps_name( face );
646           }
647           else
648             service_mm->construct_ps_name( face );
649         }
650       }
651 
652       /* internal error code -1 means `no change'; we can exit immediately */
653       if ( error == -1 )
654         return FT_Err_Ok;
655     }
656 
657     if ( !error )
658     {
659       (void)ft_face_get_mvar_service( face, &service_mvar );
660 
661       if ( service_mvar && service_mvar->metrics_adjust )
662         service_mvar->metrics_adjust( face );
663     }
664 
665     /* enforce recomputation of auto-hinting data */
666     if ( !error && face->autohint.finalizer )
667     {
668       face->autohint.finalizer( face->autohint.data );
669       face->autohint.data = NULL;
670     }
671 
672     return error;
673   }
674 
675 
676   /* documentation is in ftmm.h */
677 
678   FT_EXPORT_DEF( FT_Error )
FT_Get_Default_Named_Instance(FT_Face face,FT_UInt * instance_index)679   FT_Get_Default_Named_Instance( FT_Face   face,
680                                  FT_UInt  *instance_index )
681   {
682     FT_Error  error;
683 
684     FT_Service_MultiMasters  service_mm = NULL;
685 
686 
687     /* check of `face' delayed to `ft_face_get_mm_service' */
688 
689     error = ft_face_get_mm_service( face, &service_mm );
690     if ( !error )
691     {
692       /* no error if `get_default_named_instance` is not available */
693       if ( service_mm->get_default_named_instance )
694         error = service_mm->get_default_named_instance( face,
695                                                         instance_index );
696       else
697         error = FT_Err_Ok;
698     }
699 
700     return error;
701   }
702 
703 
704 /* END */
705