1 /****************************************************************************
2  *
3  * ftmm.c
4  *
5  *   Multiple Master font support (body).
6  *
7  * Copyright (C) 1996-2020 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 
190     /* enforce recomputation of auto-hinting data */
191     if ( !error && face->autohint.finalizer )
192     {
193       face->autohint.finalizer( face->autohint.data );
194       face->autohint.data = NULL;
195     }
196 
197     return error;
198   }
199 
200 
201   /* documentation is in ftmm.h */
202 
203   FT_EXPORT_DEF( FT_Error )
FT_Set_MM_WeightVector(FT_Face face,FT_UInt len,FT_Fixed * weightvector)204   FT_Set_MM_WeightVector( FT_Face    face,
205                           FT_UInt    len,
206                           FT_Fixed*  weightvector )
207   {
208     FT_Error                 error;
209     FT_Service_MultiMasters  service;
210 
211 
212     /* check of `face' delayed to `ft_face_get_mm_service' */
213 
214     if ( len && !weightvector )
215       return FT_THROW( Invalid_Argument );
216 
217     error = ft_face_get_mm_service( face, &service );
218     if ( !error )
219     {
220       error = FT_ERR( Invalid_Argument );
221       if ( service->set_mm_weightvector )
222         error = service->set_mm_weightvector( face, len, weightvector );
223     }
224 
225     /* enforce recomputation of auto-hinting data */
226     if ( !error && face->autohint.finalizer )
227     {
228       face->autohint.finalizer( face->autohint.data );
229       face->autohint.data = NULL;
230     }
231 
232     return error;
233   }
234 
235 
236   FT_EXPORT_DEF( FT_Error )
FT_Get_MM_WeightVector(FT_Face face,FT_UInt * len,FT_Fixed * weightvector)237   FT_Get_MM_WeightVector( FT_Face    face,
238                           FT_UInt*   len,
239                           FT_Fixed*  weightvector )
240   {
241     FT_Error                 error;
242     FT_Service_MultiMasters  service;
243 
244 
245     /* check of `face' delayed to `ft_face_get_mm_service' */
246 
247     if ( len && !weightvector )
248       return FT_THROW( Invalid_Argument );
249 
250     error = ft_face_get_mm_service( face, &service );
251     if ( !error )
252     {
253       error = FT_ERR( Invalid_Argument );
254       if ( service->get_mm_weightvector )
255         error = service->get_mm_weightvector( face, len, weightvector );
256     }
257 
258     return error;
259   }
260 
261 
262   /* documentation is in ftmm.h */
263 
264   FT_EXPORT_DEF( FT_Error )
FT_Set_Var_Design_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)265   FT_Set_Var_Design_Coordinates( FT_Face    face,
266                                  FT_UInt    num_coords,
267                                  FT_Fixed*  coords )
268   {
269     FT_Error                      error;
270     FT_Service_MultiMasters       service_mm   = NULL;
271     FT_Service_MetricsVariations  service_mvar = NULL;
272 
273 
274     /* check of `face' delayed to `ft_face_get_mm_service' */
275 
276     if ( num_coords && !coords )
277       return FT_THROW( Invalid_Argument );
278 
279     error = ft_face_get_mm_service( face, &service_mm );
280     if ( !error )
281     {
282       error = FT_ERR( Invalid_Argument );
283       if ( service_mm->set_var_design )
284         error = service_mm->set_var_design( face, num_coords, coords );
285 
286       /* internal error code -1 means `no change'; we can exit immediately */
287       if ( error == -1 )
288         return FT_Err_Ok;
289     }
290 
291     if ( !error )
292     {
293       (void)ft_face_get_mvar_service( face, &service_mvar );
294 
295       if ( service_mvar && service_mvar->metrics_adjust )
296         service_mvar->metrics_adjust( face );
297     }
298 
299     /* enforce recomputation of auto-hinting data */
300     if ( !error && face->autohint.finalizer )
301     {
302       face->autohint.finalizer( face->autohint.data );
303       face->autohint.data = NULL;
304     }
305 
306     return error;
307   }
308 
309 
310   /* documentation is in ftmm.h */
311 
312   FT_EXPORT_DEF( FT_Error )
FT_Get_Var_Design_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)313   FT_Get_Var_Design_Coordinates( FT_Face    face,
314                                  FT_UInt    num_coords,
315                                  FT_Fixed*  coords )
316   {
317     FT_Error                 error;
318     FT_Service_MultiMasters  service;
319 
320 
321     /* check of `face' delayed to `ft_face_get_mm_service' */
322 
323     if ( !coords )
324       return FT_THROW( Invalid_Argument );
325 
326     error = ft_face_get_mm_service( face, &service );
327     if ( !error )
328     {
329       error = FT_ERR( Invalid_Argument );
330       if ( service->get_var_design )
331         error = service->get_var_design( face, num_coords, coords );
332     }
333 
334     return error;
335   }
336 
337 
338   /* documentation is in ftmm.h */
339 
340   FT_EXPORT_DEF( FT_Error )
FT_Set_MM_Blend_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)341   FT_Set_MM_Blend_Coordinates( FT_Face    face,
342                                FT_UInt    num_coords,
343                                FT_Fixed*  coords )
344   {
345     FT_Error                      error;
346     FT_Service_MultiMasters       service_mm   = NULL;
347     FT_Service_MetricsVariations  service_mvar = NULL;
348 
349 
350     /* check of `face' delayed to `ft_face_get_mm_service' */
351 
352     if ( num_coords && !coords )
353       return FT_THROW( Invalid_Argument );
354 
355     error = ft_face_get_mm_service( face, &service_mm );
356     if ( !error )
357     {
358       error = FT_ERR( Invalid_Argument );
359       if ( service_mm->set_mm_blend )
360         error = service_mm->set_mm_blend( face, num_coords, coords );
361 
362       /* internal error code -1 means `no change'; we can exit immediately */
363       if ( error == -1 )
364         return FT_Err_Ok;
365     }
366 
367     if ( !error )
368     {
369       (void)ft_face_get_mvar_service( face, &service_mvar );
370 
371       if ( service_mvar && service_mvar->metrics_adjust )
372         service_mvar->metrics_adjust( face );
373     }
374 
375     /* enforce recomputation of auto-hinting data */
376     if ( !error && face->autohint.finalizer )
377     {
378       face->autohint.finalizer( face->autohint.data );
379       face->autohint.data = NULL;
380     }
381 
382     return error;
383   }
384 
385 
386   /* documentation is in ftmm.h */
387 
388   /* This is exactly the same as the previous function.  It exists for */
389   /* orthogonality.                                                    */
390 
391   FT_EXPORT_DEF( FT_Error )
FT_Set_Var_Blend_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)392   FT_Set_Var_Blend_Coordinates( FT_Face    face,
393                                 FT_UInt    num_coords,
394                                 FT_Fixed*  coords )
395   {
396     FT_Error                      error;
397     FT_Service_MultiMasters       service_mm   = NULL;
398     FT_Service_MetricsVariations  service_mvar = NULL;
399 
400 
401     /* check of `face' delayed to `ft_face_get_mm_service' */
402 
403     if ( num_coords && !coords )
404       return FT_THROW( Invalid_Argument );
405 
406     error = ft_face_get_mm_service( face, &service_mm );
407     if ( !error )
408     {
409       error = FT_ERR( Invalid_Argument );
410       if ( service_mm->set_mm_blend )
411         error = service_mm->set_mm_blend( face, num_coords, coords );
412 
413       /* internal error code -1 means `no change'; we can exit immediately */
414       if ( error == -1 )
415         return FT_Err_Ok;
416     }
417 
418     if ( !error )
419     {
420       (void)ft_face_get_mvar_service( face, &service_mvar );
421 
422       if ( service_mvar && service_mvar->metrics_adjust )
423         service_mvar->metrics_adjust( face );
424     }
425 
426     /* enforce recomputation of auto-hinting data */
427     if ( !error && face->autohint.finalizer )
428     {
429       face->autohint.finalizer( face->autohint.data );
430       face->autohint.data = NULL;
431     }
432 
433     return error;
434   }
435 
436 
437   /* documentation is in ftmm.h */
438 
439   FT_EXPORT_DEF( FT_Error )
FT_Get_MM_Blend_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)440   FT_Get_MM_Blend_Coordinates( FT_Face    face,
441                                FT_UInt    num_coords,
442                                FT_Fixed*  coords )
443   {
444     FT_Error                 error;
445     FT_Service_MultiMasters  service;
446 
447 
448     /* check of `face' delayed to `ft_face_get_mm_service' */
449 
450     if ( !coords )
451       return FT_THROW( Invalid_Argument );
452 
453     error = ft_face_get_mm_service( face, &service );
454     if ( !error )
455     {
456       error = FT_ERR( Invalid_Argument );
457       if ( service->get_mm_blend )
458         error = service->get_mm_blend( face, num_coords, coords );
459     }
460 
461     return error;
462   }
463 
464 
465   /* documentation is in ftmm.h */
466 
467   /* This is exactly the same as the previous function.  It exists for */
468   /* orthogonality.                                                    */
469 
470   FT_EXPORT_DEF( FT_Error )
FT_Get_Var_Blend_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)471   FT_Get_Var_Blend_Coordinates( FT_Face    face,
472                                 FT_UInt    num_coords,
473                                 FT_Fixed*  coords )
474   {
475     FT_Error                 error;
476     FT_Service_MultiMasters  service;
477 
478 
479     /* check of `face' delayed to `ft_face_get_mm_service' */
480 
481     if ( !coords )
482       return FT_THROW( Invalid_Argument );
483 
484     error = ft_face_get_mm_service( face, &service );
485     if ( !error )
486     {
487       error = FT_ERR( Invalid_Argument );
488       if ( service->get_mm_blend )
489         error = service->get_mm_blend( face, num_coords, coords );
490     }
491 
492     return error;
493   }
494 
495 
496   /* documentation is in ftmm.h */
497 
498   FT_EXPORT_DEF( FT_Error )
FT_Get_Var_Axis_Flags(FT_MM_Var * master,FT_UInt axis_index,FT_UInt * flags)499   FT_Get_Var_Axis_Flags( FT_MM_Var*  master,
500                          FT_UInt     axis_index,
501                          FT_UInt*    flags )
502   {
503     FT_UShort*  axis_flags;
504 
505 
506     if ( !master || !flags )
507       return FT_THROW( Invalid_Argument );
508 
509     if ( axis_index >= master->num_axis )
510       return FT_THROW( Invalid_Argument );
511 
512     /* the axis flags array immediately follows the data of `master' */
513     axis_flags = (FT_UShort*)&( master[1] );
514     *flags     = axis_flags[axis_index];
515 
516     return FT_Err_Ok;
517   }
518 
519 
520   /* documentation is in ftmm.h */
521 
522   FT_EXPORT_DEF( FT_Error )
FT_Set_Named_Instance(FT_Face face,FT_UInt instance_index)523   FT_Set_Named_Instance( FT_Face  face,
524                          FT_UInt  instance_index )
525   {
526     FT_Error  error;
527 
528     FT_Service_MultiMasters       service_mm   = NULL;
529     FT_Service_MetricsVariations  service_mvar = NULL;
530 
531 
532     /* check of `face' delayed to `ft_face_get_mm_service' */
533 
534     error = ft_face_get_mm_service( face, &service_mm );
535     if ( !error )
536     {
537       error = FT_ERR( Invalid_Argument );
538       if ( service_mm->set_instance )
539         error = service_mm->set_instance( face, instance_index );
540     }
541 
542     if ( !error )
543     {
544       (void)ft_face_get_mvar_service( face, &service_mvar );
545 
546       if ( service_mvar && service_mvar->metrics_adjust )
547         service_mvar->metrics_adjust( face );
548     }
549 
550     /* enforce recomputation of auto-hinting data */
551     if ( !error && face->autohint.finalizer )
552     {
553       face->autohint.finalizer( face->autohint.data );
554       face->autohint.data = NULL;
555     }
556 
557     if ( !error )
558     {
559       face->face_index  = ( instance_index << 16 )        |
560                           ( face->face_index & 0xFFFFL );
561       face->face_flags &= ~FT_FACE_FLAG_VARIATION;
562     }
563 
564     return error;
565   }
566 
567 
568 /* END */
569