1 /***************************************************************************/
2 /*                                                                         */
3 /*  ftmm.c                                                                 */
4 /*                                                                         */
5 /*    Multiple Master font support (body).                                 */
6 /*                                                                         */
7 /*  Copyright 1996-2018 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  trace_mm
36 
37 
38   static FT_Error
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
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 )
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 )
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 )
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 )
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 )
205   FT_Set_Var_Design_Coordinates( FT_Face    face,
206                                  FT_UInt    num_coords,
207                                  FT_Fixed*  coords )
208   {
209     FT_Error                      error;
210     FT_Service_MultiMasters       service_mm   = NULL;
211     FT_Service_MetricsVariations  service_mvar = NULL;
212 
213 
214     /* check of `face' delayed to `ft_face_get_mm_service' */
215 
216     if ( num_coords && !coords )
217       return FT_THROW( Invalid_Argument );
218 
219     error = ft_face_get_mm_service( face, &service_mm );
220     if ( !error )
221     {
222       error = FT_ERR( Invalid_Argument );
223       if ( service_mm->set_var_design )
224         error = service_mm->set_var_design( face, num_coords, coords );
225 
226       /* internal error code -1 means `no change'; we can exit immediately */
227       if ( error == -1 )
228         return FT_Err_Ok;
229     }
230 
231     if ( !error )
232     {
233       (void)ft_face_get_mvar_service( face, &service_mvar );
234 
235       if ( service_mvar && service_mvar->metrics_adjust )
236         service_mvar->metrics_adjust( face );
237     }
238 
239     /* enforce recomputation of auto-hinting data */
240     if ( !error && face->autohint.finalizer )
241     {
242       face->autohint.finalizer( face->autohint.data );
243       face->autohint.data = NULL;
244     }
245 
246     return error;
247   }
248 
249 
250   /* documentation is in ftmm.h */
251 
252   FT_EXPORT_DEF( FT_Error )
253   FT_Get_Var_Design_Coordinates( FT_Face    face,
254                                  FT_UInt    num_coords,
255                                  FT_Fixed*  coords )
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 ( !coords )
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_var_design )
271         error = service->get_var_design( face, num_coords, coords );
272     }
273 
274     return error;
275   }
276 
277 
278   /* documentation is in ftmm.h */
279 
280   FT_EXPORT_DEF( FT_Error )
281   FT_Set_MM_Blend_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_mm_blend )
300         error = service_mm->set_mm_blend( face, num_coords, coords );
301 
302       /* internal error code -1 means `no change'; we can exit immediately */
303       if ( error == -1 )
304         return FT_Err_Ok;
305     }
306 
307     if ( !error )
308     {
309       (void)ft_face_get_mvar_service( face, &service_mvar );
310 
311       if ( service_mvar && service_mvar->metrics_adjust )
312         service_mvar->metrics_adjust( face );
313     }
314 
315     /* enforce recomputation of auto-hinting data */
316     if ( !error && face->autohint.finalizer )
317     {
318       face->autohint.finalizer( face->autohint.data );
319       face->autohint.data = NULL;
320     }
321 
322     return error;
323   }
324 
325 
326   /* documentation is in ftmm.h */
327 
328   /* This is exactly the same as the previous function.  It exists for */
329   /* orthogonality.                                                    */
330 
331   FT_EXPORT_DEF( FT_Error )
332   FT_Set_Var_Blend_Coordinates( FT_Face    face,
333                                 FT_UInt    num_coords,
334                                 FT_Fixed*  coords )
335   {
336     FT_Error                      error;
337     FT_Service_MultiMasters       service_mm   = NULL;
338     FT_Service_MetricsVariations  service_mvar = NULL;
339 
340 
341     /* check of `face' delayed to `ft_face_get_mm_service' */
342 
343     if ( num_coords && !coords )
344       return FT_THROW( Invalid_Argument );
345 
346     error = ft_face_get_mm_service( face, &service_mm );
347     if ( !error )
348     {
349       error = FT_ERR( Invalid_Argument );
350       if ( service_mm->set_mm_blend )
351         error = service_mm->set_mm_blend( face, num_coords, coords );
352 
353       /* internal error code -1 means `no change'; we can exit immediately */
354       if ( error == -1 )
355         return FT_Err_Ok;
356     }
357 
358     if ( !error )
359     {
360       (void)ft_face_get_mvar_service( face, &service_mvar );
361 
362       if ( service_mvar && service_mvar->metrics_adjust )
363         service_mvar->metrics_adjust( face );
364     }
365 
366     /* enforce recomputation of auto-hinting data */
367     if ( !error && face->autohint.finalizer )
368     {
369       face->autohint.finalizer( face->autohint.data );
370       face->autohint.data = NULL;
371     }
372 
373     return error;
374   }
375 
376 
377   /* documentation is in ftmm.h */
378 
379   FT_EXPORT_DEF( FT_Error )
380   FT_Get_MM_Blend_Coordinates( FT_Face    face,
381                                FT_UInt    num_coords,
382                                FT_Fixed*  coords )
383   {
384     FT_Error                 error;
385     FT_Service_MultiMasters  service;
386 
387 
388     /* check of `face' delayed to `ft_face_get_mm_service' */
389 
390     if ( !coords )
391       return FT_THROW( Invalid_Argument );
392 
393     error = ft_face_get_mm_service( face, &service );
394     if ( !error )
395     {
396       error = FT_ERR( Invalid_Argument );
397       if ( service->get_mm_blend )
398         error = service->get_mm_blend( face, num_coords, coords );
399     }
400 
401     return error;
402   }
403 
404 
405   /* documentation is in ftmm.h */
406 
407   /* This is exactly the same as the previous function.  It exists for */
408   /* orthogonality.                                                    */
409 
410   FT_EXPORT_DEF( FT_Error )
411   FT_Get_Var_Blend_Coordinates( FT_Face    face,
412                                 FT_UInt    num_coords,
413                                 FT_Fixed*  coords )
414   {
415     FT_Error                 error;
416     FT_Service_MultiMasters  service;
417 
418 
419     /* check of `face' delayed to `ft_face_get_mm_service' */
420 
421     if ( !coords )
422       return FT_THROW( Invalid_Argument );
423 
424     error = ft_face_get_mm_service( face, &service );
425     if ( !error )
426     {
427       error = FT_ERR( Invalid_Argument );
428       if ( service->get_mm_blend )
429         error = service->get_mm_blend( face, num_coords, coords );
430     }
431 
432     return error;
433   }
434 
435 
436   /* documentation is in ftmm.h */
437 
438   FT_EXPORT_DEF( FT_Error )
439   FT_Get_Var_Axis_Flags( FT_MM_Var*  master,
440                          FT_UInt     axis_index,
441                          FT_UInt*    flags )
442   {
443     FT_UShort*  axis_flags;
444 
445 
446     if ( !master || !flags )
447       return FT_THROW( Invalid_Argument );
448 
449     if ( axis_index >= master->num_axis )
450       return FT_THROW( Invalid_Argument );
451 
452     /* the axis flags array immediately follows the data of `master' */
453     axis_flags = (FT_UShort*)&( master[1] );
454     *flags     = axis_flags[axis_index];
455 
456     return FT_Err_Ok;
457   }
458 
459 
460   /* documentation is in ftmm.h */
461 
462   FT_EXPORT_DEF( FT_Error )
463   FT_Set_Named_Instance( FT_Face  face,
464                          FT_UInt  instance_index )
465   {
466     FT_Error  error;
467 
468     FT_Service_MultiMasters       service_mm   = NULL;
469     FT_Service_MetricsVariations  service_mvar = NULL;
470 
471 
472     /* check of `face' delayed to `ft_face_get_mm_service' */
473 
474     error = ft_face_get_mm_service( face, &service_mm );
475     if ( !error )
476     {
477       error = FT_ERR( Invalid_Argument );
478       if ( service_mm->set_instance )
479         error = service_mm->set_instance( face, instance_index );
480     }
481 
482     if ( !error )
483     {
484       (void)ft_face_get_mvar_service( face, &service_mvar );
485 
486       if ( service_mvar && service_mvar->metrics_adjust )
487         service_mvar->metrics_adjust( face );
488     }
489 
490     /* enforce recomputation of auto-hinting data */
491     if ( !error && face->autohint.finalizer )
492     {
493       face->autohint.finalizer( face->autohint.data );
494       face->autohint.data = NULL;
495     }
496 
497     if ( !error )
498     {
499       face->face_index  = ( instance_index << 16 )        |
500                           ( face->face_index & 0xFFFFL );
501       face->face_flags &= ~FT_FACE_FLAG_VARIATION;
502     }
503 
504     return error;
505   }
506 
507 
508 /* END */
509