sdk-world v2026.11.05
PS2 SDK - world tier (copyleft-allowed, non-essential packages)
Loading...
Searching...
No Matches
ftmm.c
1/****************************************************************************
2 *
3 * ftmm.c
4 *
5 * Multiple Master font support (body).
6 *
7 * Copyright (C) 1996-2025 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
20
21#include <freetype/ftmm.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
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
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 if ( !num_coords && !FT_IS_VARIATION( face ) )
296 return FT_Err_Ok; /* nothing to be done */
297
298 error = ft_face_get_mm_service( face, &service_mm );
299 if ( !error )
300 {
301 error = FT_ERR( Invalid_Argument );
302 if ( service_mm->set_var_design )
303 error = service_mm->set_var_design( face, num_coords, coords );
304
305 if ( !error || error == -1 || error == -2 )
306 {
307 FT_Bool is_variation_old = FT_IS_VARIATION( face );
308
309
310 if ( error != -1 )
311 {
312 if ( error == -2 ) /* -2 means is_variable. */
313 {
314 face->face_flags |= FT_FACE_FLAG_VARIATION;
315 error = FT_Err_Ok;
316 }
317 else
318 face->face_flags &= ~FT_FACE_FLAG_VARIATION;
319 }
320
321 if ( service_mm->construct_ps_name )
322 {
323 if ( error == -1 )
324 {
325 /* The PS name of a named instance and a non-named instance */
326 /* usually differs, even if the axis values are identical. */
327 if ( is_variation_old != FT_IS_VARIATION( face ) )
328 service_mm->construct_ps_name( face );
329 }
330 else
331 service_mm->construct_ps_name( face );
332 }
333 }
334
335 /* internal error code -1 means `no change'; we can exit immediately */
336 if ( error == -1 )
337 return FT_Err_Ok;
338 }
339
340 if ( !error )
341 {
342 (void)ft_face_get_mvar_service( face, &service_mvar );
343
344 if ( service_mvar && service_mvar->metrics_adjust )
345 service_mvar->metrics_adjust( face );
346 }
347
348 /* enforce recomputation of auto-hinting data */
349 if ( !error && face->autohint.finalizer )
350 {
351 face->autohint.finalizer( face->autohint.data );
352 face->autohint.data = NULL;
353 }
354
355 return error;
356 }
357
358
359 /* documentation is in ftmm.h */
360
361 FT_EXPORT_DEF( FT_Error )
362 FT_Get_Var_Design_Coordinates( FT_Face face,
363 FT_UInt num_coords,
364 FT_Fixed* coords )
365 {
366 FT_Error error;
367 FT_Service_MultiMasters service;
368
369
370 /* check of `face' delayed to `ft_face_get_mm_service' */
371
372 if ( !coords )
373 return FT_THROW( Invalid_Argument );
374
375 error = ft_face_get_mm_service( face, &service );
376 if ( !error )
377 {
378 error = FT_ERR( Invalid_Argument );
379 if ( service->get_var_design )
380 error = service->get_var_design( face, num_coords, coords );
381 }
382
383 return error;
384 }
385
386
387 /* documentation is in ftmm.h */
388
389 FT_EXPORT_DEF( FT_Error )
390 FT_Set_MM_Blend_Coordinates( FT_Face face,
391 FT_UInt num_coords,
392 FT_Fixed* coords )
393 {
394 FT_Error error;
395 FT_Service_MultiMasters service_mm = NULL;
396 FT_Service_MetricsVariations service_mvar = NULL;
397
398
399 /* check of `face' delayed to `ft_face_get_mm_service' */
400
401 if ( num_coords && !coords )
402 return FT_THROW( Invalid_Argument );
403
404 error = ft_face_get_mm_service( face, &service_mm );
405 if ( !error )
406 {
407 error = FT_ERR( Invalid_Argument );
408 if ( service_mm->set_mm_blend )
409 error = service_mm->set_mm_blend( face, num_coords, coords );
410
411 if ( !error || error == -1 )
412 {
413 FT_Bool is_variation_old = FT_IS_VARIATION( face );
414
415
416 if ( num_coords )
417 face->face_flags |= FT_FACE_FLAG_VARIATION;
418 else
419 face->face_flags &= ~FT_FACE_FLAG_VARIATION;
420
421 if ( service_mm->construct_ps_name )
422 {
423 if ( error == -1 )
424 {
425 /* The PS name of a named instance and a non-named instance */
426 /* usually differs, even if the axis values are identical. */
427 if ( is_variation_old != FT_IS_VARIATION( face ) )
428 service_mm->construct_ps_name( face );
429 }
430 else
431 service_mm->construct_ps_name( face );
432 }
433 }
434
435 /* internal error code -1 means `no change'; we can exit immediately */
436 if ( error == -1 )
437 return FT_Err_Ok;
438 }
439
440 if ( !error )
441 {
442 (void)ft_face_get_mvar_service( face, &service_mvar );
443
444 if ( service_mvar && service_mvar->metrics_adjust )
445 service_mvar->metrics_adjust( face );
446 }
447
448 /* enforce recomputation of auto-hinting data */
449 if ( !error && face->autohint.finalizer )
450 {
451 face->autohint.finalizer( face->autohint.data );
452 face->autohint.data = NULL;
453 }
454
455 return error;
456 }
457
458
459 /* documentation is in ftmm.h */
460
461 /* This is exactly the same as the previous function. It exists for */
462 /* orthogonality. */
463
464 FT_EXPORT_DEF( FT_Error )
465 FT_Set_Var_Blend_Coordinates( FT_Face face,
466 FT_UInt num_coords,
467 FT_Fixed* coords )
468 {
469 FT_Error error;
470 FT_Service_MultiMasters service_mm = NULL;
471 FT_Service_MetricsVariations service_mvar = NULL;
472
473
474 /* check of `face' delayed to `ft_face_get_mm_service' */
475
476 if ( num_coords && !coords )
477 return FT_THROW( Invalid_Argument );
478
479 error = ft_face_get_mm_service( face, &service_mm );
480 if ( !error )
481 {
482 error = FT_ERR( Invalid_Argument );
483 if ( service_mm->set_mm_blend )
484 error = service_mm->set_mm_blend( face, num_coords, coords );
485
486 if ( !error || error == -1 || error == -2 )
487 {
488 FT_Bool is_variation_old = FT_IS_VARIATION( face );
489
490
491 if ( error != -1 )
492 {
493 if ( error == -2 ) /* -2 means is_variable. */
494 {
495 face->face_flags |= FT_FACE_FLAG_VARIATION;
496 error = FT_Err_Ok;
497 }
498 else
499 face->face_flags &= ~FT_FACE_FLAG_VARIATION;
500 }
501
502 if ( service_mm->construct_ps_name )
503 {
504 if ( error == -1 )
505 {
506 /* The PS name of a named instance and a non-named instance */
507 /* usually differs, even if the axis values are identical. */
508 if ( is_variation_old != FT_IS_VARIATION( face ) )
509 service_mm->construct_ps_name( face );
510 }
511 else
512 service_mm->construct_ps_name( face );
513 }
514 }
515
516 /* internal error code -1 means `no change'; we can exit immediately */
517 if ( error == -1 )
518 return FT_Err_Ok;
519 }
520
521 if ( !error )
522 {
523 (void)ft_face_get_mvar_service( face, &service_mvar );
524
525 if ( service_mvar && service_mvar->metrics_adjust )
526 service_mvar->metrics_adjust( face );
527 }
528
529 /* enforce recomputation of auto-hinting data */
530 if ( !error && face->autohint.finalizer )
531 {
532 face->autohint.finalizer( face->autohint.data );
533 face->autohint.data = NULL;
534 }
535
536 return error;
537 }
538
539
540 /* documentation is in ftmm.h */
541
542 FT_EXPORT_DEF( FT_Error )
543 FT_Get_MM_Blend_Coordinates( FT_Face face,
544 FT_UInt num_coords,
545 FT_Fixed* coords )
546 {
547 FT_Error error;
548 FT_Service_MultiMasters service;
549
550
551 /* check of `face' delayed to `ft_face_get_mm_service' */
552
553 if ( !coords )
554 return FT_THROW( Invalid_Argument );
555
556 error = ft_face_get_mm_service( face, &service );
557 if ( !error )
558 {
559 error = FT_ERR( Invalid_Argument );
560 if ( service->get_mm_blend )
561 error = service->get_mm_blend( face, num_coords, coords );
562 }
563
564 return error;
565 }
566
567
568 /* documentation is in ftmm.h */
569
570 /* This is exactly the same as the previous function. It exists for */
571 /* orthogonality. */
572
573 FT_EXPORT_DEF( FT_Error )
574 FT_Get_Var_Blend_Coordinates( FT_Face face,
575 FT_UInt num_coords,
576 FT_Fixed* coords )
577 {
578 FT_Error error;
579 FT_Service_MultiMasters service;
580
581
582 /* check of `face' delayed to `ft_face_get_mm_service' */
583
584 if ( !coords )
585 return FT_THROW( Invalid_Argument );
586
587 error = ft_face_get_mm_service( face, &service );
588 if ( !error )
589 {
590 error = FT_ERR( Invalid_Argument );
591 if ( service->get_mm_blend )
592 error = service->get_mm_blend( face, num_coords, coords );
593 }
594
595 return error;
596 }
597
598
599 /* documentation is in ftmm.h */
600
601 FT_EXPORT_DEF( FT_Error )
602 FT_Get_Var_Axis_Flags( FT_MM_Var* master,
603 FT_UInt axis_index,
604 FT_UInt* flags )
605 {
606 FT_UShort* axis_flags;
607
608
609 if ( !master || !flags )
610 return FT_THROW( Invalid_Argument );
611
612 if ( axis_index >= master->num_axis )
613 return FT_THROW( Invalid_Argument );
614
615 /* the axis flags array immediately follows the data of `master' */
616 axis_flags = (FT_UShort*)&( master[1] );
617 *flags = axis_flags[axis_index];
618
619 return FT_Err_Ok;
620 }
621
622
623 /* documentation is in ftmm.h */
624
625 FT_EXPORT_DEF( FT_Error )
626 FT_Set_Named_Instance( FT_Face face,
627 FT_UInt instance_index )
628 {
629 FT_Error error;
630
631 FT_Service_MultiMasters service_mm = NULL;
632 FT_Service_MetricsVariations service_mvar = NULL;
633
634
635 /* check of `face' delayed to `ft_face_get_mm_service' */
636
637 error = ft_face_get_mm_service( face, &service_mm );
638 if ( !error )
639 {
640 error = FT_ERR( Invalid_Argument );
641 if ( service_mm->set_named_instance )
642 error = service_mm->set_named_instance( face, instance_index );
643
644 if ( !error || error == -1 )
645 {
646 FT_Bool is_variation_old = FT_IS_VARIATION( face );
647
648
649 face->face_flags &= ~FT_FACE_FLAG_VARIATION;
650 face->face_index = ( instance_index << 16 ) |
651 ( face->face_index & 0xFFFFL );
652
653 if ( service_mm->construct_ps_name )
654 {
655 if ( error == -1 )
656 {
657 /* The PS name of a named instance and a non-named instance */
658 /* usually differs, even if the axis values are identical. */
659 if ( is_variation_old != FT_IS_VARIATION( face ) )
660 service_mm->construct_ps_name( face );
661 }
662 else
663 service_mm->construct_ps_name( face );
664 }
665 }
666
667 /* internal error code -1 means `no change'; we can exit immediately */
668 if ( error == -1 )
669 return FT_Err_Ok;
670 }
671
672 if ( !error )
673 {
674 (void)ft_face_get_mvar_service( face, &service_mvar );
675
676 if ( service_mvar && service_mvar->metrics_adjust )
677 service_mvar->metrics_adjust( face );
678 }
679
680 /* enforce recomputation of auto-hinting data */
681 if ( !error && face->autohint.finalizer )
682 {
683 face->autohint.finalizer( face->autohint.data );
684 face->autohint.data = NULL;
685 }
686
687 return error;
688 }
689
690
691 /* documentation is in ftmm.h */
692
693 FT_EXPORT_DEF( FT_Error )
694 FT_Get_Default_Named_Instance( FT_Face face,
695 FT_UInt *instance_index )
696 {
697 FT_Error error;
698
699 FT_Service_MultiMasters service_mm = NULL;
700
701
702 /* check of `face' delayed to `ft_face_get_mm_service' */
703
704 error = ft_face_get_mm_service( face, &service_mm );
705 if ( !error )
706 {
707 /* no error if `get_default_named_instance` is not available */
708 if ( service_mm->get_default_named_instance )
709 error = service_mm->get_default_named_instance( face,
710 instance_index );
711 else
712 error = FT_Err_Ok;
713 }
714
715 return error;
716 }
717
718
719/* END */