ReactOS 0.4.16-dev-1063-gd722e70
ttgxvar.c
Go to the documentation of this file.
1/****************************************************************************
2 *
3 * ttgxvar.c
4 *
5 * TrueType GX Font Variation loader
6 *
7 * Copyright (C) 2004-2019 by
8 * David Turner, Robert Wilhelm, Werner Lemberg, and George Williams.
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 /**************************************************************************
20 *
21 * Apple documents the `fvar', `gvar', `cvar', and `avar' tables at
22 *
23 * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6[fgca]var.html
24 *
25 * The documentation for `gvar' is not intelligible; `cvar' refers you
26 * to `gvar' and is thus also incomprehensible.
27 *
28 * The documentation for `avar' appears correct, but Apple has no fonts
29 * with an `avar' table, so it is hard to test.
30 *
31 * Many thanks to John Jenkins (at Apple) in figuring this out.
32 *
33 *
34 * Apple's `kern' table has some references to tuple indices, but as
35 * there is no indication where these indices are defined, nor how to
36 * interpolate the kerning values (different tuples have different
37 * classes) this issue is ignored.
38 *
39 */
40
41
42#include <ft2build.h>
43#include FT_INTERNAL_DEBUG_H
44#include FT_CONFIG_CONFIG_H
45#include FT_INTERNAL_STREAM_H
46#include FT_INTERNAL_SFNT_H
47#include FT_TRUETYPE_TAGS_H
48#include FT_TRUETYPE_IDS_H
49#include FT_MULTIPLE_MASTERS_H
50#include FT_LIST_H
51
52#include "ttpload.h"
53#include "ttgxvar.h"
54
55#include "tterrors.h"
56
57
58#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
59
60
61#define FT_Stream_FTell( stream ) \
62 (FT_ULong)( (stream)->cursor - (stream)->base )
63#define FT_Stream_SeekSet( stream, off ) \
64 (stream)->cursor = \
65 ( (off) < (FT_ULong)( (stream)->limit - (stream)->base ) ) \
66 ? (stream)->base + (off) \
67 : (stream)->limit
68
69
70 /* some macros we need */
71#define FT_fdot14ToFixed( x ) \
72 ( (FT_Fixed)( (FT_ULong)(x) << 2 ) )
73#define FT_intToFixed( i ) \
74 ( (FT_Fixed)( (FT_ULong)(i) << 16 ) )
75#define FT_fixedToInt( x ) \
76 ( (FT_Short)( ( (FT_UInt32)(x) + 0x8000U ) >> 16 ) )
77
78
79 /**************************************************************************
80 *
81 * The macro FT_COMPONENT is used in trace mode. It is an implicit
82 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
83 * messages during execution.
84 */
85#undef FT_COMPONENT
86#define FT_COMPONENT ttgxvar
87
88
89 /*************************************************************************/
90 /*************************************************************************/
91 /***** *****/
92 /***** Internal Routines *****/
93 /***** *****/
94 /*************************************************************************/
95 /*************************************************************************/
96
97
98 /**************************************************************************
99 *
100 * The macro ALL_POINTS is used in `ft_var_readpackedpoints'. It
101 * indicates that there is a delta for every point without needing to
102 * enumerate all of them.
103 */
104
105 /* ensure that value `0' has the same width as a pointer */
106#define ALL_POINTS (FT_UShort*)~(FT_PtrDist)0
107
108
109#define GX_PT_POINTS_ARE_WORDS 0x80U
110#define GX_PT_POINT_RUN_COUNT_MASK 0x7FU
111
112
113 /**************************************************************************
114 *
115 * @Function:
116 * ft_var_readpackedpoints
117 *
118 * @Description:
119 * Read a set of points to which the following deltas will apply.
120 * Points are packed with a run length encoding.
121 *
122 * @Input:
123 * stream ::
124 * The data stream.
125 *
126 * size ::
127 * The size of the table holding the data.
128 *
129 * @Output:
130 * point_cnt ::
131 * The number of points read. A zero value means that
132 * all points in the glyph will be affected, without
133 * enumerating them individually.
134 *
135 * @Return:
136 * An array of FT_UShort containing the affected points or the
137 * special value ALL_POINTS.
138 */
139 static FT_UShort*
140 ft_var_readpackedpoints( FT_Stream stream,
142 FT_UInt *point_cnt )
143 {
145 FT_UInt n;
146 FT_UInt runcnt;
147 FT_UInt i, j;
149 FT_Memory memory = stream->memory;
151
152 FT_UNUSED( error );
153
154
155 *point_cnt = 0;
156
157 n = FT_GET_BYTE();
158 if ( n == 0 )
159 return ALL_POINTS;
160
161 if ( n & GX_PT_POINTS_ARE_WORDS )
162 {
163 n &= GX_PT_POINT_RUN_COUNT_MASK;
164 n <<= 8;
165 n |= FT_GET_BYTE();
166 }
167
168 if ( n > size )
169 {
170 FT_TRACE1(( "ft_var_readpackedpoints: number of points too large\n" ));
171 return NULL;
172 }
173
174 /* in the nested loops below we increase `i' twice; */
175 /* it is faster to simply allocate one more slot */
176 /* than to add another test within the loop */
177 if ( FT_NEW_ARRAY( points, n + 1 ) )
178 return NULL;
179
180 *point_cnt = n;
181
182 first = 0;
183 i = 0;
184 while ( i < n )
185 {
186 runcnt = FT_GET_BYTE();
187 if ( runcnt & GX_PT_POINTS_ARE_WORDS )
188 {
189 runcnt &= GX_PT_POINT_RUN_COUNT_MASK;
190 first += FT_GET_USHORT();
191 points[i++] = first;
192
193 /* first point not included in run count */
194 for ( j = 0; j < runcnt; j++ )
195 {
196 first += FT_GET_USHORT();
197 points[i++] = first;
198 if ( i >= n )
199 break;
200 }
201 }
202 else
203 {
204 first += FT_GET_BYTE();
205 points[i++] = first;
206
207 for ( j = 0; j < runcnt; j++ )
208 {
209 first += FT_GET_BYTE();
210 points[i++] = first;
211 if ( i >= n )
212 break;
213 }
214 }
215 }
216
217 return points;
218 }
219
220
221#define GX_DT_DELTAS_ARE_ZERO 0x80U
222#define GX_DT_DELTAS_ARE_WORDS 0x40U
223#define GX_DT_DELTA_RUN_COUNT_MASK 0x3FU
224
225
226 /**************************************************************************
227 *
228 * @Function:
229 * ft_var_readpackeddeltas
230 *
231 * @Description:
232 * Read a set of deltas. These are packed slightly differently than
233 * points. In particular there is no overall count.
234 *
235 * @Input:
236 * stream ::
237 * The data stream.
238 *
239 * size ::
240 * The size of the table holding the data.
241 *
242 * delta_cnt ::
243 * The number of deltas to be read.
244 *
245 * @Return:
246 * An array of FT_Fixed containing the deltas for the affected
247 * points. (This only gets the deltas for one dimension. It will
248 * generally be called twice, once for x, once for y. When used in
249 * cvt table, it will only be called once.)
250 *
251 * We use FT_Fixed to avoid accumulation errors while summing up all
252 * deltas (the rounding to integer values happens as the very last
253 * step).
254 */
255 static FT_Fixed*
256 ft_var_readpackeddeltas( FT_Stream stream,
258 FT_UInt delta_cnt )
259 {
260 FT_Fixed *deltas = NULL;
261 FT_UInt runcnt, cnt;
262 FT_UInt i, j;
263 FT_Memory memory = stream->memory;
265
266 FT_UNUSED( error );
267
268
269 if ( delta_cnt > size )
270 {
271 FT_TRACE1(( "ft_var_readpackeddeltas: number of points too large\n" ));
272 return NULL;
273 }
274
275 if ( FT_NEW_ARRAY( deltas, delta_cnt ) )
276 return NULL;
277
278 i = 0;
279 while ( i < delta_cnt )
280 {
281 runcnt = FT_GET_BYTE();
282 cnt = runcnt & GX_DT_DELTA_RUN_COUNT_MASK;
283
284 if ( runcnt & GX_DT_DELTAS_ARE_ZERO )
285 {
286 /* `runcnt' zeroes get added */
287 for ( j = 0; j <= cnt && i < delta_cnt; j++ )
288 deltas[i++] = 0;
289 }
290 else if ( runcnt & GX_DT_DELTAS_ARE_WORDS )
291 {
292 /* `runcnt' shorts from the stack */
293 for ( j = 0; j <= cnt && i < delta_cnt; j++ )
294 deltas[i++] = FT_intToFixed( FT_GET_SHORT() );
295 }
296 else
297 {
298 /* `runcnt' signed bytes from the stack */
299 for ( j = 0; j <= cnt && i < delta_cnt; j++ )
300 deltas[i++] = FT_intToFixed( FT_GET_CHAR() );
301 }
302
303 if ( j <= cnt )
304 {
305 /* bad format */
306 FT_FREE( deltas );
307 return NULL;
308 }
309 }
310
311 return deltas;
312 }
313
314
315 /**************************************************************************
316 *
317 * @Function:
318 * ft_var_load_avar
319 *
320 * @Description:
321 * Parse the `avar' table if present. It need not be, so we return
322 * nothing.
323 *
324 * @InOut:
325 * face ::
326 * The font face.
327 */
328 static void
329 ft_var_load_avar( TT_Face face )
330 {
332 FT_Memory memory = stream->memory;
333 GX_Blend blend = face->blend;
334 GX_AVarSegment segment;
337 FT_Long axisCount;
338 FT_Int i, j;
339 FT_ULong table_len;
340
341 FT_UNUSED( error );
342
343
344 FT_TRACE2(( "AVAR " ));
345
346 blend->avar_loaded = TRUE;
347 error = face->goto_table( face, TTAG_avar, stream, &table_len );
348 if ( error )
349 {
350 FT_TRACE2(( "is missing\n" ));
351 return;
352 }
353
354 if ( FT_FRAME_ENTER( table_len ) )
355 return;
356
358 axisCount = FT_GET_LONG();
359
360 if ( version != 0x00010000L )
361 {
362 FT_TRACE2(( "bad table version\n" ));
363 goto Exit;
364 }
365
366 FT_TRACE2(( "loaded\n" ));
367
368 if ( axisCount != (FT_Long)blend->mmvar->num_axis )
369 {
370 FT_TRACE2(( "ft_var_load_avar: number of axes in `avar' and `fvar'\n"
371 " table are different\n" ));
372 goto Exit;
373 }
374
375 if ( FT_NEW_ARRAY( blend->avar_segment, axisCount ) )
376 goto Exit;
377
378 segment = &blend->avar_segment[0];
379 for ( i = 0; i < axisCount; i++, segment++ )
380 {
381 FT_TRACE5(( " axis %d:\n", i ));
382
383 segment->pairCount = FT_GET_USHORT();
384 if ( (FT_ULong)segment->pairCount * 4 > table_len ||
385 FT_NEW_ARRAY( segment->correspondence, segment->pairCount ) )
386 {
387 /* Failure. Free everything we have done so far. We must do */
388 /* it right now since loading the `avar' table is optional. */
389
390 for ( j = i - 1; j >= 0; j-- )
391 FT_FREE( blend->avar_segment[j].correspondence );
392
393 FT_FREE( blend->avar_segment );
394 blend->avar_segment = NULL;
395 goto Exit;
396 }
397
398 for ( j = 0; j < segment->pairCount; j++ )
399 {
400 /* convert to Fixed */
401 segment->correspondence[j].fromCoord = FT_GET_SHORT() * 4;
402 segment->correspondence[j].toCoord = FT_GET_SHORT() * 4;
403
404 FT_TRACE5(( " mapping %.5f to %.5f\n",
405 segment->correspondence[j].fromCoord / 65536.0,
406 segment->correspondence[j].toCoord / 65536.0 ));
407 }
408
409 FT_TRACE5(( "\n" ));
410 }
411
412 Exit:
414 }
415
416
417 static FT_Error
418 ft_var_load_item_variation_store( TT_Face face,
420 GX_ItemVarStore itemStore )
421 {
423 FT_Memory memory = stream->memory;
424
427 FT_ULong region_offset;
428 FT_UInt i, j, k;
429 FT_UInt shortDeltaCount;
430
431 GX_Blend blend = face->blend;
432 GX_ItemVarData varData;
433
434 FT_ULong* dataOffsetArray = NULL;
435
436
437 if ( FT_STREAM_SEEK( offset ) ||
439 goto Exit;
440
441 if ( format != 1 )
442 {
443 FT_TRACE2(( "ft_var_load_item_variation_store: bad store format %d\n",
444 format ));
445 error = FT_THROW( Invalid_Table );
446 goto Exit;
447 }
448
449 /* read top level fields */
450 if ( FT_READ_ULONG( region_offset ) ||
451 FT_READ_USHORT( itemStore->dataCount ) )
452 goto Exit;
453
454 /* we need at least one entry in `itemStore->varData' */
455 if ( !itemStore->dataCount )
456 {
457 FT_TRACE2(( "ft_var_load_item_variation_store: missing varData\n" ));
458 error = FT_THROW( Invalid_Table );
459 goto Exit;
460 }
461
462 /* make temporary copy of item variation data offsets; */
463 /* we will parse region list first, then come back */
464 if ( FT_NEW_ARRAY( dataOffsetArray, itemStore->dataCount ) )
465 goto Exit;
466
467 for ( i = 0; i < itemStore->dataCount; i++ )
468 {
469 if ( FT_READ_ULONG( dataOffsetArray[i] ) )
470 goto Exit;
471 }
472
473 /* parse array of region records (region list) */
474 if ( FT_STREAM_SEEK( offset + region_offset ) )
475 goto Exit;
476
477 if ( FT_READ_USHORT( itemStore->axisCount ) ||
478 FT_READ_USHORT( itemStore->regionCount ) )
479 goto Exit;
480
481 if ( itemStore->axisCount != (FT_Long)blend->mmvar->num_axis )
482 {
483 FT_TRACE2(( "ft_var_load_item_variation_store:"
484 " number of axes in item variation store\n"
485 " "
486 " and `fvar' table are different\n" ));
487 error = FT_THROW( Invalid_Table );
488 goto Exit;
489 }
490
491 if ( FT_NEW_ARRAY( itemStore->varRegionList, itemStore->regionCount ) )
492 goto Exit;
493
494 for ( i = 0; i < itemStore->regionCount; i++ )
495 {
496 GX_AxisCoords axisCoords;
497
498
499 if ( FT_NEW_ARRAY( itemStore->varRegionList[i].axisList,
500 itemStore->axisCount ) )
501 goto Exit;
502
503 axisCoords = itemStore->varRegionList[i].axisList;
504
505 for ( j = 0; j < itemStore->axisCount; j++ )
506 {
507 FT_Short start, peak, end;
508
509
510 if ( FT_READ_SHORT( start ) ||
511 FT_READ_SHORT( peak ) ||
512 FT_READ_SHORT( end ) )
513 goto Exit;
514
515 axisCoords[j].startCoord = FT_fdot14ToFixed( start );
516 axisCoords[j].peakCoord = FT_fdot14ToFixed( peak );
517 axisCoords[j].endCoord = FT_fdot14ToFixed( end );
518 }
519 }
520
521 /* end of region list parse */
522
523 /* use dataOffsetArray now to parse varData items */
524 if ( FT_NEW_ARRAY( itemStore->varData, itemStore->dataCount ) )
525 goto Exit;
526
527 for ( i = 0; i < itemStore->dataCount; i++ )
528 {
529 varData = &itemStore->varData[i];
530
531 if ( FT_STREAM_SEEK( offset + dataOffsetArray[i] ) )
532 goto Exit;
533
534 if ( FT_READ_USHORT( varData->itemCount ) ||
535 FT_READ_USHORT( shortDeltaCount ) ||
536 FT_READ_USHORT( varData->regionIdxCount ) )
537 goto Exit;
538
539 /* check some data consistency */
540 if ( shortDeltaCount > varData->regionIdxCount )
541 {
542 FT_TRACE2(( "bad short count %d or region count %d\n",
543 shortDeltaCount,
544 varData->regionIdxCount ));
545 error = FT_THROW( Invalid_Table );
546 goto Exit;
547 }
548
549 if ( varData->regionIdxCount > itemStore->regionCount )
550 {
551 FT_TRACE2(( "inconsistent regionCount %d in varData[%d]\n",
552 varData->regionIdxCount,
553 i ));
554 error = FT_THROW( Invalid_Table );
555 goto Exit;
556 }
557
558 /* parse region indices */
559 if ( FT_NEW_ARRAY( varData->regionIndices,
560 varData->regionIdxCount ) )
561 goto Exit;
562
563 for ( j = 0; j < varData->regionIdxCount; j++ )
564 {
565 if ( FT_READ_USHORT( varData->regionIndices[j] ) )
566 goto Exit;
567
568 if ( varData->regionIndices[j] >= itemStore->regionCount )
569 {
570 FT_TRACE2(( "bad region index %d\n",
571 varData->regionIndices[j] ));
572 error = FT_THROW( Invalid_Table );
573 goto Exit;
574 }
575 }
576
577 /* Parse delta set. */
578 /* */
579 /* On input, deltas are (shortDeltaCount + regionIdxCount) bytes */
580 /* each; on output, deltas are expanded to `regionIdxCount' shorts */
581 /* each. */
582 if ( FT_NEW_ARRAY( varData->deltaSet,
583 varData->regionIdxCount * varData->itemCount ) )
584 goto Exit;
585
586 /* the delta set is stored as a 2-dimensional array of shorts; */
587 /* sign-extend signed bytes to signed shorts */
588 for ( j = 0; j < varData->itemCount * varData->regionIdxCount; )
589 {
590 for ( k = 0; k < shortDeltaCount; k++, j++ )
591 {
592 /* read the short deltas */
593 FT_Short delta;
594
595
596 if ( FT_READ_SHORT( delta ) )
597 goto Exit;
598
599 varData->deltaSet[j] = delta;
600 }
601
602 for ( ; k < varData->regionIdxCount; k++, j++ )
603 {
604 /* read the (signed) byte deltas */
605 FT_Char delta;
606
607
608 if ( FT_READ_CHAR( delta ) )
609 goto Exit;
610
611 varData->deltaSet[j] = delta;
612 }
613 }
614 }
615
616 Exit:
617 FT_FREE( dataOffsetArray );
618
619 return error;
620 }
621
622
623 static FT_Error
624 ft_var_load_delta_set_index_mapping( TT_Face face,
626 GX_DeltaSetIdxMap map,
627 GX_ItemVarStore itemStore )
628 {
630 FT_Memory memory = stream->memory;
631
633
635 FT_UInt entrySize;
636 FT_UInt innerBitCount;
637 FT_UInt innerIndexMask;
638 FT_UInt i, j;
639
640
641 if ( FT_STREAM_SEEK( offset ) ||
643 FT_READ_USHORT( map->mapCount ) )
644 goto Exit;
645
646 if ( format & 0xFFC0 )
647 {
648 FT_TRACE2(( "bad map format %d\n", format ));
649 error = FT_THROW( Invalid_Table );
650 goto Exit;
651 }
652
653 /* bytes per entry: 1, 2, 3, or 4 */
654 entrySize = ( ( format & 0x0030 ) >> 4 ) + 1;
655 innerBitCount = ( format & 0x000F ) + 1;
656 innerIndexMask = ( 1 << innerBitCount ) - 1;
657
658 if ( FT_NEW_ARRAY( map->innerIndex, map->mapCount ) )
659 goto Exit;
660
661 if ( FT_NEW_ARRAY( map->outerIndex, map->mapCount ) )
662 goto Exit;
663
664 for ( i = 0; i < map->mapCount; i++ )
665 {
666 FT_UInt mapData = 0;
667 FT_UInt outerIndex, innerIndex;
668
669
670 /* read map data one unsigned byte at a time, big endian */
671 for ( j = 0; j < entrySize; j++ )
672 {
674
675
676 if ( FT_READ_BYTE( data ) )
677 goto Exit;
678
679 mapData = ( mapData << 8 ) | data;
680 }
681
682 outerIndex = mapData >> innerBitCount;
683
684 if ( outerIndex >= itemStore->dataCount )
685 {
686 FT_TRACE2(( "outerIndex[%d] == %d out of range\n",
687 i,
688 outerIndex ));
689 error = FT_THROW( Invalid_Table );
690 goto Exit;
691 }
692
693 map->outerIndex[i] = outerIndex;
694
695 innerIndex = mapData & innerIndexMask;
696
697 if ( innerIndex >= itemStore->varData[outerIndex].itemCount )
698 {
699 FT_TRACE2(( "innerIndex[%d] == %d out of range\n",
700 i,
701 innerIndex ));
702 error = FT_THROW( Invalid_Table );
703 goto Exit;
704 }
705
706 map->innerIndex[i] = innerIndex;
707 }
708
709 Exit:
710 return error;
711 }
712
713
714 /**************************************************************************
715 *
716 * @Function:
717 * ft_var_load_hvvar
718 *
719 * @Description:
720 * If `vertical' is zero, parse the `HVAR' table and set
721 * `blend->hvar_loaded' to TRUE. On success, `blend->hvar_checked'
722 * is set to TRUE.
723 *
724 * If `vertical' is not zero, parse the `VVAR' table and set
725 * `blend->vvar_loaded' to TRUE. On success, `blend->vvar_checked'
726 * is set to TRUE.
727 *
728 * Some memory may remain allocated on error; it is always freed in
729 * `tt_done_blend', however.
730 *
731 * @InOut:
732 * face ::
733 * The font face.
734 *
735 * @Return:
736 * FreeType error code. 0 means success.
737 */
738 static FT_Error
739 ft_var_load_hvvar( TT_Face face,
740 FT_Bool vertical )
741 {
743 FT_Memory memory = stream->memory;
744
745 GX_Blend blend = face->blend;
746
747 GX_HVVarTable table;
748
750 FT_UShort majorVersion;
751 FT_ULong table_len;
752 FT_ULong table_offset;
753 FT_ULong store_offset;
754 FT_ULong widthMap_offset;
755
756
757 if ( vertical )
758 {
759 blend->vvar_loaded = TRUE;
760
761 FT_TRACE2(( "VVAR " ));
762
763 error = face->goto_table( face, TTAG_VVAR, stream, &table_len );
764 }
765 else
766 {
767 blend->hvar_loaded = TRUE;
768
769 FT_TRACE2(( "HVAR " ));
770
771 error = face->goto_table( face, TTAG_HVAR, stream, &table_len );
772 }
773
774 if ( error )
775 {
776 FT_TRACE2(( "is missing\n" ));
777 goto Exit;
778 }
779
780 table_offset = FT_STREAM_POS();
781
782 /* skip minor version */
783 if ( FT_READ_USHORT( majorVersion ) ||
784 FT_STREAM_SKIP( 2 ) )
785 goto Exit;
786
787 if ( majorVersion != 1 )
788 {
789 FT_TRACE2(( "bad table version %d\n", majorVersion ));
790 error = FT_THROW( Invalid_Table );
791 goto Exit;
792 }
793
794 if ( FT_READ_ULONG( store_offset ) ||
795 FT_READ_ULONG( widthMap_offset ) )
796 goto Exit;
797
798 if ( vertical )
799 {
800 if ( FT_NEW( blend->vvar_table ) )
801 goto Exit;
802 table = blend->vvar_table;
803 }
804 else
805 {
806 if ( FT_NEW( blend->hvar_table ) )
807 goto Exit;
808 table = blend->hvar_table;
809 }
810
811 error = ft_var_load_item_variation_store(
812 face,
813 table_offset + store_offset,
814 &table->itemStore );
815 if ( error )
816 goto Exit;
817
818 if ( widthMap_offset )
819 {
820 error = ft_var_load_delta_set_index_mapping(
821 face,
822 table_offset + widthMap_offset,
823 &table->widthMap,
824 &table->itemStore );
825 if ( error )
826 goto Exit;
827 }
828
829 FT_TRACE2(( "loaded\n" ));
831
832 Exit:
833 if ( !error )
834 {
835 if ( vertical )
836 {
837 blend->vvar_checked = TRUE;
838
839 /* FreeType doesn't provide functions to quickly retrieve */
840 /* TSB, BSB, or VORG values; we thus don't have to implement */
841 /* support for those three item variation stores. */
842
843 face->variation_support |= TT_FACE_FLAG_VAR_VADVANCE;
844 }
845 else
846 {
847 blend->hvar_checked = TRUE;
848
849 /* FreeType doesn't provide functions to quickly retrieve */
850 /* LSB or RSB values; we thus don't have to implement */
851 /* support for those two item variation stores. */
852
853 face->variation_support |= TT_FACE_FLAG_VAR_HADVANCE;
854 }
855 }
856
857 return error;
858 }
859
860
861 static FT_Int
862 ft_var_get_item_delta( TT_Face face,
863 GX_ItemVarStore itemStore,
864 FT_UInt outerIndex,
865 FT_UInt innerIndex )
866 {
867 GX_ItemVarData varData;
868 FT_Short* deltaSet;
869
870 FT_UInt master, j;
871 FT_Fixed netAdjustment = 0; /* accumulated adjustment */
872 FT_Fixed scaledDelta;
873 FT_Fixed delta;
874
875
876 /* See pseudo code from `Font Variations Overview' */
877 /* in the OpenType specification. */
878
879 varData = &itemStore->varData[outerIndex];
880 deltaSet = &varData->deltaSet[varData->regionIdxCount * innerIndex];
881
882 /* outer loop steps through master designs to be blended */
883 for ( master = 0; master < varData->regionIdxCount; master++ )
884 {
885 FT_Fixed scalar = 0x10000L;
886 FT_UInt regionIndex = varData->regionIndices[master];
887
888 GX_AxisCoords axis = itemStore->varRegionList[regionIndex].axisList;
889
890
891 /* inner loop steps through axes in this region */
892 for ( j = 0; j < itemStore->axisCount; j++, axis++ )
893 {
894 /* compute the scalar contribution of this axis; */
895 /* ignore invalid ranges */
896 if ( axis->startCoord > axis->peakCoord ||
897 axis->peakCoord > axis->endCoord )
898 continue;
899
900 else if ( axis->startCoord < 0 &&
901 axis->endCoord > 0 &&
902 axis->peakCoord != 0 )
903 continue;
904
905 /* peak of 0 means ignore this axis */
906 else if ( axis->peakCoord == 0 )
907 continue;
908
909 else if ( face->blend->normalizedcoords[j] == axis->peakCoord )
910 continue;
911
912 /* ignore this region if coords are out of range */
913 else if ( face->blend->normalizedcoords[j] <= axis->startCoord ||
914 face->blend->normalizedcoords[j] >= axis->endCoord )
915 {
916 scalar = 0;
917 break;
918 }
919
920 /* cumulative product of all the axis scalars */
921 else if ( face->blend->normalizedcoords[j] < axis->peakCoord )
922 scalar =
923 FT_MulDiv( scalar,
924 face->blend->normalizedcoords[j] - axis->startCoord,
925 axis->peakCoord - axis->startCoord );
926 else
927 scalar =
928 FT_MulDiv( scalar,
929 axis->endCoord - face->blend->normalizedcoords[j],
930 axis->endCoord - axis->peakCoord );
931 } /* per-axis loop */
932
933 /* get the scaled delta for this region */
934 delta = FT_intToFixed( deltaSet[master] );
935 scaledDelta = FT_MulFix( scalar, delta );
936
937 /* accumulate the adjustments from each region */
938 netAdjustment = netAdjustment + scaledDelta;
939
940 } /* per-region loop */
941
942 return FT_fixedToInt( netAdjustment );
943 }
944
945
946 /**************************************************************************
947 *
948 * @Function:
949 * tt_hvadvance_adjust
950 *
951 * @Description:
952 * Apply `HVAR' advance width or `VVAR' advance height adjustment of
953 * a given glyph.
954 *
955 * @Input:
956 * gindex ::
957 * The glyph index.
958 *
959 * vertical ::
960 * If set, handle `VVAR' table.
961 *
962 * @InOut:
963 * face ::
964 * The font face.
965 *
966 * adelta ::
967 * Points to width or height value that gets modified.
968 */
969 static FT_Error
970 tt_hvadvance_adjust( TT_Face face,
971 FT_UInt gindex,
972 FT_Int *avalue,
973 FT_Bool vertical )
974 {
976 FT_UInt innerIndex, outerIndex;
977 FT_Int delta;
978
979 GX_HVVarTable table;
980
981
982 if ( !face->doblend || !face->blend )
983 goto Exit;
984
985 if ( vertical )
986 {
987 if ( !face->blend->vvar_loaded )
988 {
989 /* initialize vvar table */
990 face->blend->vvar_error = ft_var_load_hvvar( face, 1 );
991 }
992
993 if ( !face->blend->vvar_checked )
994 {
995 error = face->blend->vvar_error;
996 goto Exit;
997 }
998
999 table = face->blend->vvar_table;
1000 }
1001 else
1002 {
1003 if ( !face->blend->hvar_loaded )
1004 {
1005 /* initialize hvar table */
1006 face->blend->hvar_error = ft_var_load_hvvar( face, 0 );
1007 }
1008
1009 if ( !face->blend->hvar_checked )
1010 {
1011 error = face->blend->hvar_error;
1012 goto Exit;
1013 }
1014
1015 table = face->blend->hvar_table;
1016 }
1017
1018 /* advance width or height adjustments are always present in an */
1019 /* `HVAR' or `VVAR' table; no need to test for this capability */
1020
1021 if ( table->widthMap.innerIndex )
1022 {
1023 FT_UInt idx = gindex;
1024
1025
1026 if ( idx >= table->widthMap.mapCount )
1027 idx = table->widthMap.mapCount - 1;
1028
1029 /* trust that HVAR parser has checked indices */
1030 outerIndex = table->widthMap.outerIndex[idx];
1031 innerIndex = table->widthMap.innerIndex[idx];
1032 }
1033 else
1034 {
1035 GX_ItemVarData varData;
1036
1037
1038 /* no widthMap data */
1039 outerIndex = 0;
1040 innerIndex = gindex;
1041
1042 varData = &table->itemStore.varData[outerIndex];
1043 if ( gindex >= varData->itemCount )
1044 {
1045 FT_TRACE2(( "gindex %d out of range\n", gindex ));
1046 error = FT_THROW( Invalid_Argument );
1047 goto Exit;
1048 }
1049 }
1050
1051 delta = ft_var_get_item_delta( face,
1052 &table->itemStore,
1053 outerIndex,
1054 innerIndex );
1055
1056 FT_TRACE5(( "%s value %d adjusted by %d unit%s (%s)\n",
1057 vertical ? "vertical height" : "horizontal width",
1058 *avalue,
1059 delta,
1060 delta == 1 ? "" : "s",
1061 vertical ? "VVAR" : "HVAR" ));
1062
1063 *avalue += delta;
1064
1065 Exit:
1066 return error;
1067 }
1068
1069
1071 tt_hadvance_adjust( TT_Face face,
1072 FT_UInt gindex,
1073 FT_Int *avalue )
1074 {
1075 return tt_hvadvance_adjust( face, gindex, avalue, 0 );
1076 }
1077
1078
1080 tt_vadvance_adjust( TT_Face face,
1081 FT_UInt gindex,
1082 FT_Int *avalue )
1083 {
1084 return tt_hvadvance_adjust( face, gindex, avalue, 1 );
1085 }
1086
1087
1088#define GX_VALUE_SIZE 8
1089
1090 /* all values are FT_Short or FT_UShort entities; */
1091 /* we treat them consistently as FT_Short */
1092#define GX_VALUE_CASE( tag, dflt ) \
1093 case MVAR_TAG_ ## tag : \
1094 p = (FT_Short*)&face->dflt; \
1095 break
1096
1097#define GX_GASP_CASE( idx ) \
1098 case MVAR_TAG_GASP_ ## idx : \
1099 if ( idx < face->gasp.numRanges - 1 ) \
1100 p = (FT_Short*)&face->gasp.gaspRanges[idx].maxPPEM; \
1101 else \
1102 p = NULL; \
1103 break
1104
1105
1106 static FT_Short*
1107 ft_var_get_value_pointer( TT_Face face,
1108 FT_ULong mvar_tag )
1109 {
1110 FT_Short* p;
1111
1112
1113 switch ( mvar_tag )
1114 {
1115 GX_GASP_CASE( 0 );
1116 GX_GASP_CASE( 1 );
1117 GX_GASP_CASE( 2 );
1118 GX_GASP_CASE( 3 );
1119 GX_GASP_CASE( 4 );
1120 GX_GASP_CASE( 5 );
1121 GX_GASP_CASE( 6 );
1122 GX_GASP_CASE( 7 );
1123 GX_GASP_CASE( 8 );
1124 GX_GASP_CASE( 9 );
1125
1126 GX_VALUE_CASE( CPHT, os2.sCapHeight );
1127 GX_VALUE_CASE( HASC, os2.sTypoAscender );
1128 GX_VALUE_CASE( HCLA, os2.usWinAscent );
1129 GX_VALUE_CASE( HCLD, os2.usWinDescent );
1130 GX_VALUE_CASE( HCOF, horizontal.caret_Offset );
1131 GX_VALUE_CASE( HCRN, horizontal.caret_Slope_Run );
1132 GX_VALUE_CASE( HCRS, horizontal.caret_Slope_Rise );
1133 GX_VALUE_CASE( HDSC, os2.sTypoDescender );
1134 GX_VALUE_CASE( HLGP, os2.sTypoLineGap );
1135 GX_VALUE_CASE( SBXO, os2.ySubscriptXOffset);
1136 GX_VALUE_CASE( SBXS, os2.ySubscriptXSize );
1137 GX_VALUE_CASE( SBYO, os2.ySubscriptYOffset );
1138 GX_VALUE_CASE( SBYS, os2.ySubscriptYSize );
1139 GX_VALUE_CASE( SPXO, os2.ySuperscriptXOffset );
1140 GX_VALUE_CASE( SPXS, os2.ySuperscriptXSize );
1141 GX_VALUE_CASE( SPYO, os2.ySuperscriptYOffset );
1142 GX_VALUE_CASE( SPYS, os2.ySuperscriptYSize );
1143 GX_VALUE_CASE( STRO, os2.yStrikeoutPosition );
1144 GX_VALUE_CASE( STRS, os2.yStrikeoutSize );
1145 GX_VALUE_CASE( UNDO, postscript.underlinePosition );
1146 GX_VALUE_CASE( UNDS, postscript.underlineThickness );
1147 GX_VALUE_CASE( VASC, vertical.Ascender );
1148 GX_VALUE_CASE( VCOF, vertical.caret_Offset );
1149 GX_VALUE_CASE( VCRN, vertical.caret_Slope_Run );
1150 GX_VALUE_CASE( VCRS, vertical.caret_Slope_Rise );
1151 GX_VALUE_CASE( VDSC, vertical.Descender );
1152 GX_VALUE_CASE( VLGP, vertical.Line_Gap );
1153 GX_VALUE_CASE( XHGT, os2.sxHeight );
1154
1155 default:
1156 /* ignore unknown tag */
1157 p = NULL;
1158 }
1159
1160 return p;
1161 }
1162
1163
1164 /**************************************************************************
1165 *
1166 * @Function:
1167 * ft_var_load_mvar
1168 *
1169 * @Description:
1170 * Parse the `MVAR' table.
1171 *
1172 * Some memory may remain allocated on error; it is always freed in
1173 * `tt_done_blend', however.
1174 *
1175 * @InOut:
1176 * face ::
1177 * The font face.
1178 */
1179 static void
1180 ft_var_load_mvar( TT_Face face )
1181 {
1183 FT_Memory memory = stream->memory;
1184
1185 GX_Blend blend = face->blend;
1186 GX_ItemVarStore itemStore;
1187 GX_Value value, limit;
1188
1190 FT_UShort majorVersion;
1191 FT_ULong table_len;
1192 FT_ULong table_offset;
1193 FT_UShort store_offset;
1194 FT_ULong records_offset;
1195
1196
1197 FT_TRACE2(( "MVAR " ));
1198
1199 error = face->goto_table( face, TTAG_MVAR, stream, &table_len );
1200 if ( error )
1201 {
1202 FT_TRACE2(( "is missing\n" ));
1203 return;
1204 }
1205
1206 table_offset = FT_STREAM_POS();
1207
1208 /* skip minor version */
1209 if ( FT_READ_USHORT( majorVersion ) ||
1210 FT_STREAM_SKIP( 2 ) )
1211 return;
1212
1213 if ( majorVersion != 1 )
1214 {
1215 FT_TRACE2(( "bad table version %d\n", majorVersion ));
1216 return;
1217 }
1218
1219 if ( FT_NEW( blend->mvar_table ) )
1220 return;
1221
1222 /* skip reserved entry and value record size */
1223 if ( FT_STREAM_SKIP( 4 ) ||
1224 FT_READ_USHORT( blend->mvar_table->valueCount ) ||
1225 FT_READ_USHORT( store_offset ) )
1226 return;
1227
1228 records_offset = FT_STREAM_POS();
1229
1230 error = ft_var_load_item_variation_store(
1231 face,
1232 table_offset + store_offset,
1233 &blend->mvar_table->itemStore );
1234 if ( error )
1235 return;
1236
1237 if ( FT_NEW_ARRAY( blend->mvar_table->values,
1238 blend->mvar_table->valueCount ) )
1239 return;
1240
1241 if ( FT_STREAM_SEEK( records_offset ) ||
1242 FT_FRAME_ENTER( blend->mvar_table->valueCount * GX_VALUE_SIZE ) )
1243 return;
1244
1245 value = blend->mvar_table->values;
1246 limit = value + blend->mvar_table->valueCount;
1247 itemStore = &blend->mvar_table->itemStore;
1248
1249 for ( ; value < limit; value++ )
1250 {
1251 value->tag = FT_GET_ULONG();
1252 value->outerIndex = FT_GET_USHORT();
1253 value->innerIndex = FT_GET_USHORT();
1254
1255 if ( value->outerIndex >= itemStore->dataCount ||
1256 value->innerIndex >= itemStore->varData[value->outerIndex]
1257 .itemCount )
1258 {
1259 error = FT_THROW( Invalid_Table );
1260 break;
1261 }
1262 }
1263
1264 FT_FRAME_EXIT();
1265
1266 if ( error )
1267 return;
1268
1269 FT_TRACE2(( "loaded\n" ));
1270
1271 value = blend->mvar_table->values;
1272 limit = value + blend->mvar_table->valueCount;
1273
1274 /* save original values of the data MVAR is going to modify */
1275 for ( ; value < limit; value++ )
1276 {
1277 FT_Short* p = ft_var_get_value_pointer( face, value->tag );
1278
1279
1280 if ( p )
1281 value->unmodified = *p;
1282#ifdef FT_DEBUG_LEVEL_TRACE
1283 else
1284 FT_TRACE1(( "ft_var_load_mvar: Ignoring unknown tag `%c%c%c%c'\n",
1285 (FT_Char)( value->tag >> 24 ),
1286 (FT_Char)( value->tag >> 16 ),
1287 (FT_Char)( value->tag >> 8 ),
1288 (FT_Char)( value->tag ) ));
1289#endif
1290 }
1291
1292 face->variation_support |= TT_FACE_FLAG_VAR_MVAR;
1293 }
1294
1295
1296 static FT_Error
1297 tt_size_reset_iterator( FT_ListNode node,
1298 void* user )
1299 {
1301
1302 FT_UNUSED( user );
1303
1304
1305 tt_size_reset( size, 1 );
1306
1307 return FT_Err_Ok;
1308 }
1309
1310
1311 /**************************************************************************
1312 *
1313 * @Function:
1314 * tt_apply_mvar
1315 *
1316 * @Description:
1317 * Apply `MVAR' table adjustments.
1318 *
1319 * @InOut:
1320 * face ::
1321 * The font face.
1322 */
1323 FT_LOCAL_DEF( void )
1324 tt_apply_mvar( TT_Face face )
1325 {
1326 GX_Blend blend = face->blend;
1327 GX_Value value, limit;
1328 FT_Short mvar_hasc_delta = 0;
1329 FT_Short mvar_hdsc_delta = 0;
1330 FT_Short mvar_hlgp_delta = 0;
1331
1332
1333 if ( !( face->variation_support & TT_FACE_FLAG_VAR_MVAR ) )
1334 return;
1335
1336 value = blend->mvar_table->values;
1337 limit = value + blend->mvar_table->valueCount;
1338
1339 for ( ; value < limit; value++ )
1340 {
1341 FT_Short* p = ft_var_get_value_pointer( face, value->tag );
1342 FT_Int delta;
1343
1344
1345 delta = ft_var_get_item_delta( face,
1346 &blend->mvar_table->itemStore,
1347 value->outerIndex,
1348 value->innerIndex );
1349
1350 if ( p )
1351 {
1352 FT_TRACE5(( "value %c%c%c%c (%d unit%s) adjusted by %d unit%s (MVAR)\n",
1353 (FT_Char)( value->tag >> 24 ),
1354 (FT_Char)( value->tag >> 16 ),
1355 (FT_Char)( value->tag >> 8 ),
1356 (FT_Char)( value->tag ),
1357 value->unmodified,
1358 value->unmodified == 1 ? "" : "s",
1359 delta,
1360 delta == 1 ? "" : "s" ));
1361
1362 /* since we handle both signed and unsigned values as FT_Short, */
1363 /* ensure proper overflow arithmetic */
1364 *p = (FT_Short)( value->unmodified + (FT_Short)delta );
1365
1366 /* Treat hasc, hdsc and hlgp specially, see below. */
1367 if ( value->tag == MVAR_TAG_HASC )
1368 mvar_hasc_delta = (FT_Short)delta;
1369 else if ( value->tag == MVAR_TAG_HDSC )
1370 mvar_hdsc_delta = (FT_Short)delta;
1371 else if ( value->tag == MVAR_TAG_HLGP )
1372 mvar_hlgp_delta = (FT_Short)delta;
1373 }
1374 }
1375
1376 /* adjust all derived values */
1377 {
1378 FT_Face root = &face->root;
1379
1380 /*
1381 * Apply the deltas of hasc, hdsc and hlgp to the FT_Face's ascender,
1382 * descender and height attributes, no matter how they were originally
1383 * computed.
1384 *
1385 * (Code that ignores those and accesses the font's metrics values
1386 * directly is already served by the delta application code above.)
1387 *
1388 * The MVAR table supports variations for both typo and win metrics.
1389 * According to Behdad Esfahbod, the thinking of the working group was
1390 * that no one uses win metrics anymore for setting line metrics (the
1391 * specification even calls these metrics "horizontal clipping
1392 * ascent/descent", probably for their role on the Windows platform in
1393 * computing clipping boxes), and new fonts should use typo metrics, so
1394 * typo deltas should be applied to whatever sfnt_load_face decided the
1395 * line metrics should be.
1396 *
1397 * Before, the following led to different line metrics between default
1398 * outline and instances, visible when e.g. the default outlines were
1399 * used as the regular face and instances for everything else:
1400 *
1401 * 1. sfnt_load_face applied the hhea metrics by default.
1402 * 2. This code later applied the typo metrics by default, regardless of
1403 * whether they were actually changed or the font had the OS/2 table's
1404 * fsSelection's bit 7 (USE_TYPO_METRICS) set.
1405 */
1406 FT_Short current_line_gap = root->height - root->ascender +
1407 root->descender;
1408
1409
1410 root->ascender = root->ascender + mvar_hasc_delta;
1411 root->descender = root->descender + mvar_hdsc_delta;
1412 root->height = root->ascender - root->descender +
1413 current_line_gap + mvar_hlgp_delta;
1414
1415 root->underline_position = face->postscript.underlinePosition -
1416 face->postscript.underlineThickness / 2;
1417 root->underline_thickness = face->postscript.underlineThickness;
1418
1419 /* iterate over all FT_Size objects and call `tt_size_reset' */
1420 /* to propagate the metrics changes */
1421 FT_List_Iterate( &root->sizes_list,
1422 tt_size_reset_iterator,
1423 NULL );
1424 }
1425 }
1426
1427
1428 typedef struct GX_GVar_Head_
1429 {
1431 FT_UShort axisCount;
1432 FT_UShort globalCoordCount;
1433 FT_ULong offsetToCoord;
1434 FT_UShort glyphCount;
1436 FT_ULong offsetToData;
1437
1438 } GX_GVar_Head;
1439
1440
1441 /**************************************************************************
1442 *
1443 * @Function:
1444 * ft_var_load_gvar
1445 *
1446 * @Description:
1447 * Parse the `gvar' table if present. If `fvar' is there, `gvar' had
1448 * better be there too.
1449 *
1450 * @InOut:
1451 * face ::
1452 * The font face.
1453 *
1454 * @Return:
1455 * FreeType error code. 0 means success.
1456 */
1457 static FT_Error
1458 ft_var_load_gvar( TT_Face face )
1459 {
1461 FT_Memory memory = stream->memory;
1462 GX_Blend blend = face->blend;
1464 FT_UInt i, j;
1465 FT_ULong table_len;
1466 FT_ULong gvar_start;
1467 FT_ULong offsetToData;
1468 GX_GVar_Head gvar_head;
1469
1470 static const FT_Frame_Field gvar_fields[] =
1471 {
1472
1473#undef FT_STRUCTURE
1474#define FT_STRUCTURE GX_GVar_Head
1475
1476 FT_FRAME_START( 20 ),
1478 FT_FRAME_USHORT( axisCount ),
1479 FT_FRAME_USHORT( globalCoordCount ),
1480 FT_FRAME_ULONG ( offsetToCoord ),
1481 FT_FRAME_USHORT( glyphCount ),
1483 FT_FRAME_ULONG ( offsetToData ),
1485 };
1486
1487
1488 FT_TRACE2(( "GVAR " ));
1489
1490 if ( FT_SET_ERROR( face->goto_table( face,
1491 TTAG_gvar,
1492 stream,
1493 &table_len ) ) )
1494 {
1495 FT_TRACE2(( "is missing\n" ));
1496 goto Exit;
1497 }
1498
1499 gvar_start = FT_STREAM_POS( );
1500 if ( FT_STREAM_READ_FIELDS( gvar_fields, &gvar_head ) )
1501 goto Exit;
1502
1503 if ( gvar_head.version != 0x00010000L )
1504 {
1505 FT_TRACE1(( "bad table version\n" ));
1506 error = FT_THROW( Invalid_Table );
1507 goto Exit;
1508 }
1509
1510 if ( gvar_head.axisCount != (FT_UShort)blend->mmvar->num_axis )
1511 {
1512 FT_TRACE1(( "ft_var_load_gvar: number of axes in `gvar' and `cvar'\n"
1513 " table are different\n" ));
1514 error = FT_THROW( Invalid_Table );
1515 goto Exit;
1516 }
1517
1518 /* rough sanity check, ignoring offsets */
1519 if ( (FT_ULong)gvar_head.globalCoordCount * gvar_head.axisCount >
1520 table_len / 2 )
1521 {
1522 FT_TRACE1(( "ft_var_load_gvar:"
1523 " invalid number of global coordinates\n" ));
1524 error = FT_THROW( Invalid_Table );
1525 goto Exit;
1526 }
1527
1528 /* rough sanity check: offsets can be either 2 or 4 bytes */
1529 if ( (FT_ULong)gvar_head.glyphCount *
1530 ( ( gvar_head.flags & 1 ) ? 4 : 2 ) > table_len )
1531 {
1532 FT_TRACE1(( "ft_var_load_gvar: invalid number of glyphs\n" ));
1533 error = FT_THROW( Invalid_Table );
1534 goto Exit;
1535 }
1536
1537 FT_TRACE2(( "loaded\n" ));
1538
1539 blend->gvar_size = table_len;
1540 blend->tuplecount = gvar_head.globalCoordCount;
1541 blend->gv_glyphcnt = gvar_head.glyphCount;
1542 offsetToData = gvar_start + gvar_head.offsetToData;
1543
1544 FT_TRACE5(( "gvar: there %s %d shared coordinate%s:\n",
1545 blend->tuplecount == 1 ? "is" : "are",
1546 blend->tuplecount,
1547 blend->tuplecount == 1 ? "" : "s" ));
1548
1549 if ( FT_NEW_ARRAY( blend->glyphoffsets, blend->gv_glyphcnt + 1 ) )
1550 goto Exit;
1551
1552 if ( gvar_head.flags & 1 )
1553 {
1554 FT_ULong limit = gvar_start + table_len;
1555
1556
1557 /* long offsets (one more offset than glyphs, to mark size of last) */
1558 if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 4L ) )
1559 goto Exit;
1560
1561 for ( i = 0; i <= blend->gv_glyphcnt; i++ )
1562 {
1563 blend->glyphoffsets[i] = offsetToData + FT_GET_ULONG();
1564 /* use `>', not `>=' */
1565 if ( blend->glyphoffsets[i] > limit )
1566 {
1567 FT_TRACE2(( "ft_var_load_gvar:"
1568 " invalid glyph variation data offset for index %d\n",
1569 i ));
1570 error = FT_THROW( Invalid_Table );
1571 break;
1572 }
1573 }
1574 }
1575 else
1576 {
1577 FT_ULong limit = gvar_start + table_len;
1578
1579
1580 /* short offsets (one more offset than glyphs, to mark size of last) */
1581 if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 2L ) )
1582 goto Exit;
1583
1584 for ( i = 0; i <= blend->gv_glyphcnt; i++ )
1585 {
1586 blend->glyphoffsets[i] = offsetToData + FT_GET_USHORT() * 2;
1587 /* use `>', not `>=' */
1588 if ( blend->glyphoffsets[i] > limit )
1589 {
1590 FT_TRACE2(( "ft_var_load_gvar:"
1591 " invalid glyph variation data offset for index %d\n",
1592 i ));
1593 error = FT_THROW( Invalid_Table );
1594 break;
1595 }
1596 }
1597 }
1598
1599 FT_FRAME_EXIT();
1600 if ( error )
1601 goto Exit;
1602
1603 if ( blend->tuplecount != 0 )
1604 {
1605 if ( FT_NEW_ARRAY( blend->tuplecoords,
1606 gvar_head.axisCount * blend->tuplecount ) )
1607 goto Exit;
1608
1609 if ( FT_STREAM_SEEK( gvar_start + gvar_head.offsetToCoord ) ||
1610 FT_FRAME_ENTER( blend->tuplecount * gvar_head.axisCount * 2L ) )
1611 goto Exit;
1612
1613 for ( i = 0; i < blend->tuplecount; i++ )
1614 {
1615 FT_TRACE5(( " [ " ));
1616 for ( j = 0; j < (FT_UInt)gvar_head.axisCount; j++ )
1617 {
1618 blend->tuplecoords[i * gvar_head.axisCount + j] =
1619 FT_GET_SHORT() * 4; /* convert to FT_Fixed */
1620 FT_TRACE5(( "%.5f ",
1621 blend->tuplecoords[i * gvar_head.axisCount + j] / 65536.0 ));
1622 }
1623 FT_TRACE5(( "]\n" ));
1624 }
1625
1626 FT_TRACE5(( "\n" ));
1627
1628 FT_FRAME_EXIT();
1629 }
1630
1631 Exit:
1632 return error;
1633 }
1634
1635
1636 /**************************************************************************
1637 *
1638 * @Function:
1639 * ft_var_apply_tuple
1640 *
1641 * @Description:
1642 * Figure out whether a given tuple (design) applies to the current
1643 * blend, and if so, what is the scaling factor.
1644 *
1645 * @Input:
1646 * blend ::
1647 * The current blend of the font.
1648 *
1649 * tupleIndex ::
1650 * A flag saying whether this is an intermediate
1651 * tuple or not.
1652 *
1653 * tuple_coords ::
1654 * The coordinates of the tuple in normalized axis
1655 * units.
1656 *
1657 * im_start_coords ::
1658 * The initial coordinates where this tuple starts
1659 * to apply (for intermediate coordinates).
1660 *
1661 * im_end_coords ::
1662 * The final coordinates after which this tuple no
1663 * longer applies (for intermediate coordinates).
1664 *
1665 * @Return:
1666 * An FT_Fixed value containing the scaling factor.
1667 */
1668 static FT_Fixed
1669 ft_var_apply_tuple( GX_Blend blend,
1670 FT_UShort tupleIndex,
1671 FT_Fixed* tuple_coords,
1672 FT_Fixed* im_start_coords,
1673 FT_Fixed* im_end_coords )
1674 {
1675 FT_UInt i;
1676 FT_Fixed apply = 0x10000L;
1677
1678
1679 for ( i = 0; i < blend->num_axis; i++ )
1680 {
1681 FT_TRACE6(( " axis %d coordinate %.5f:\n",
1682 i, blend->normalizedcoords[i] / 65536.0 ));
1683
1684 /* It's not clear why (for intermediate tuples) we don't need */
1685 /* to check against start/end -- the documentation says we don't. */
1686 /* Similarly, it's unclear why we don't need to scale along the */
1687 /* axis. */
1688
1689 if ( tuple_coords[i] == 0 )
1690 {
1691 FT_TRACE6(( " tuple coordinate is zero, ignore\n", i ));
1692 continue;
1693 }
1694
1695 if ( blend->normalizedcoords[i] == 0 )
1696 {
1697 FT_TRACE6(( " axis coordinate is zero, stop\n" ));
1698 apply = 0;
1699 break;
1700 }
1701
1702 if ( blend->normalizedcoords[i] == tuple_coords[i] )
1703 {
1704 FT_TRACE6(( " tuple coordinate %.5f fits perfectly\n",
1705 tuple_coords[i] / 65536.0 ));
1706 /* `apply' does not change */
1707 continue;
1708 }
1709
1710 if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) )
1711 {
1712 /* not an intermediate tuple */
1713
1714 if ( blend->normalizedcoords[i] < FT_MIN( 0, tuple_coords[i] ) ||
1715 blend->normalizedcoords[i] > FT_MAX( 0, tuple_coords[i] ) )
1716 {
1717 FT_TRACE6(( " tuple coordinate %.5f is exceeded, stop\n",
1718 tuple_coords[i] / 65536.0 ));
1719 apply = 0;
1720 break;
1721 }
1722
1723 FT_TRACE6(( " tuple coordinate %.5f fits\n",
1724 tuple_coords[i] / 65536.0 ));
1725 apply = FT_MulDiv( apply,
1726 blend->normalizedcoords[i],
1727 tuple_coords[i] );
1728 }
1729 else
1730 {
1731 /* intermediate tuple */
1732
1733 if ( blend->normalizedcoords[i] <= im_start_coords[i] ||
1734 blend->normalizedcoords[i] >= im_end_coords[i] )
1735 {
1736 FT_TRACE6(( " intermediate tuple range ]%.5f;%.5f[ is exceeded,"
1737 " stop\n",
1738 im_start_coords[i] / 65536.0,
1739 im_end_coords[i] / 65536.0 ));
1740 apply = 0;
1741 break;
1742 }
1743
1744 FT_TRACE6(( " intermediate tuple range ]%.5f;%.5f[ fits\n",
1745 im_start_coords[i] / 65536.0,
1746 im_end_coords[i] / 65536.0 ));
1747 if ( blend->normalizedcoords[i] < tuple_coords[i] )
1748 apply = FT_MulDiv( apply,
1749 blend->normalizedcoords[i] - im_start_coords[i],
1750 tuple_coords[i] - im_start_coords[i] );
1751 else
1752 apply = FT_MulDiv( apply,
1753 im_end_coords[i] - blend->normalizedcoords[i],
1754 im_end_coords[i] - tuple_coords[i] );
1755 }
1756 }
1757
1758 FT_TRACE6(( " apply factor is %.5f\n", apply / 65536.0 ));
1759
1760 return apply;
1761 }
1762
1763
1764 /* convert from design coordinates to normalized coordinates */
1765
1766 static void
1767 ft_var_to_normalized( TT_Face face,
1768 FT_UInt num_coords,
1771 {
1772 GX_Blend blend;
1773 FT_MM_Var* mmvar;
1774 FT_UInt i, j;
1775 FT_Var_Axis* a;
1776 GX_AVarSegment av;
1777
1778
1779 blend = face->blend;
1780 mmvar = blend->mmvar;
1781
1782 if ( num_coords > mmvar->num_axis )
1783 {
1784 FT_TRACE2(( "ft_var_to_normalized:"
1785 " only using first %d of %d coordinates\n",
1786 mmvar->num_axis, num_coords ));
1787 num_coords = mmvar->num_axis;
1788 }
1789
1790 /* Axis normalization is a two-stage process. First we normalize */
1791 /* based on the [min,def,max] values for the axis to be [-1,0,1]. */
1792 /* Then, if there's an `avar' table, we renormalize this range. */
1793
1794 a = mmvar->axis;
1795 for ( i = 0; i < num_coords; i++, a++ )
1796 {
1798
1799
1800 FT_TRACE5(( " %d: %.5f\n", i, coord / 65536.0 ));
1801 if ( coord > a->maximum || coord < a->minimum )
1802 {
1803 FT_TRACE1((
1804 "ft_var_to_normalized: design coordinate %.5f\n"
1805 " is out of range [%.5f;%.5f]; clamping\n",
1806 coord / 65536.0,
1807 a->minimum / 65536.0,
1808 a->maximum / 65536.0 ));
1809
1810 if ( coord > a->maximum )
1811 coord = a->maximum;
1812 else
1813 coord = a->minimum;
1814 }
1815
1816 if ( coord < a->def )
1817 normalized[i] = -FT_DivFix( SUB_LONG( coord, a->def ),
1818 SUB_LONG( a->minimum, a->def ) );
1819 else if ( coord > a->def )
1820 normalized[i] = FT_DivFix( SUB_LONG( coord, a->def ),
1821 SUB_LONG( a->maximum, a->def ) );
1822 else
1823 normalized[i] = 0;
1824 }
1825
1826 FT_TRACE5(( "\n" ));
1827
1828 for ( ; i < mmvar->num_axis; i++ )
1829 normalized[i] = 0;
1830
1831 if ( blend->avar_segment )
1832 {
1833 FT_TRACE5(( "normalized design coordinates"
1834 " before applying `avar' data:\n" ));
1835
1836 av = blend->avar_segment;
1837 for ( i = 0; i < mmvar->num_axis; i++, av++ )
1838 {
1839 for ( j = 1; j < (FT_UInt)av->pairCount; j++ )
1840 {
1841 if ( normalized[i] < av->correspondence[j].fromCoord )
1842 {
1843 FT_TRACE5(( " %.5f\n", normalized[i] / 65536.0 ));
1844
1845 normalized[i] =
1846 FT_MulDiv( normalized[i] - av->correspondence[j - 1].fromCoord,
1847 av->correspondence[j].toCoord -
1848 av->correspondence[j - 1].toCoord,
1849 av->correspondence[j].fromCoord -
1850 av->correspondence[j - 1].fromCoord ) +
1851 av->correspondence[j - 1].toCoord;
1852 break;
1853 }
1854 }
1855 }
1856 }
1857 }
1858
1859
1860 /* convert from normalized coordinates to design coordinates */
1861
1862 static void
1863 ft_var_to_design( TT_Face face,
1864 FT_UInt num_coords,
1866 FT_Fixed* design )
1867 {
1868 GX_Blend blend;
1869 FT_MM_Var* mmvar;
1870 FT_Var_Axis* a;
1871
1872 FT_UInt i, j, nc;
1873
1874
1875 blend = face->blend;
1876
1877 nc = num_coords;
1878 if ( num_coords > blend->num_axis )
1879 {
1880 FT_TRACE2(( "ft_var_to_design:"
1881 " only using first %d of %d coordinates\n",
1882 blend->num_axis, num_coords ));
1883 nc = blend->num_axis;
1884 }
1885
1886 for ( i = 0; i < nc; i++ )
1887 design[i] = coords[i];
1888
1889 for ( ; i < num_coords; i++ )
1890 design[i] = 0;
1891
1892 if ( blend->avar_segment )
1893 {
1894 GX_AVarSegment av = blend->avar_segment;
1895
1896
1897 FT_TRACE5(( "design coordinates"
1898 " after removing `avar' distortion:\n" ));
1899
1900 for ( i = 0; i < nc; i++, av++ )
1901 {
1902 for ( j = 1; j < (FT_UInt)av->pairCount; j++ )
1903 {
1904 if ( design[i] < av->correspondence[j].toCoord )
1905 {
1906 design[i] =
1907 FT_MulDiv( design[i] - av->correspondence[j - 1].toCoord,
1908 av->correspondence[j].fromCoord -
1909 av->correspondence[j - 1].fromCoord,
1910 av->correspondence[j].toCoord -
1911 av->correspondence[j - 1].toCoord ) +
1912 av->correspondence[j - 1].fromCoord;
1913
1914 FT_TRACE5(( " %.5f\n", design[i] / 65536.0 ));
1915 break;
1916 }
1917 }
1918 }
1919 }
1920
1921 mmvar = blend->mmvar;
1922 a = mmvar->axis;
1923
1924 for ( i = 0; i < nc; i++, a++ )
1925 {
1926 if ( design[i] < 0 )
1927 design[i] = a->def + FT_MulFix( design[i],
1928 a->def - a->minimum );
1929 else if ( design[i] > 0 )
1930 design[i] = a->def + FT_MulFix( design[i],
1931 a->maximum - a->def );
1932 else
1933 design[i] = a->def;
1934 }
1935 }
1936
1937
1938 /*************************************************************************/
1939 /*************************************************************************/
1940 /***** *****/
1941 /***** MULTIPLE MASTERS SERVICE FUNCTIONS *****/
1942 /***** *****/
1943 /*************************************************************************/
1944 /*************************************************************************/
1945
1946
1947 typedef struct GX_FVar_Head_
1948 {
1950 FT_UShort offsetToData;
1951 FT_UShort axisCount;
1952 FT_UShort axisSize;
1953 FT_UShort instanceCount;
1954 FT_UShort instanceSize;
1955
1956 } GX_FVar_Head;
1957
1958
1959 typedef struct fvar_axis_
1960 {
1961 FT_ULong axisTag;
1962 FT_Fixed minValue;
1963 FT_Fixed defaultValue;
1964 FT_Fixed maxValue;
1966 FT_UShort nameID;
1967
1968 } GX_FVar_Axis;
1969
1970
1971 /**************************************************************************
1972 *
1973 * @Function:
1974 * TT_Get_MM_Var
1975 *
1976 * @Description:
1977 * Check that the font's `fvar' table is valid, parse it, and return
1978 * those data. It also loads (and parses) the `MVAR' table, if
1979 * possible.
1980 *
1981 * @InOut:
1982 * face ::
1983 * The font face.
1984 * TT_Get_MM_Var initializes the blend structure.
1985 *
1986 * @Output:
1987 * master ::
1988 * The `fvar' data (must be freed by caller). Can be NULL,
1989 * which makes this function simply load MM support.
1990 *
1991 * @Return:
1992 * FreeType error code. 0 means success.
1993 */
1995 TT_Get_MM_Var( TT_Face face,
1996 FT_MM_Var* *master )
1997 {
1998 FT_Stream stream = face->root.stream;
1999 FT_Memory memory = face->root.memory;
2000 FT_ULong table_len;
2002 FT_ULong fvar_start = 0;
2003 FT_UInt i, j;
2004 FT_MM_Var* mmvar = NULL;
2005 FT_Fixed* next_coords;
2006 FT_Fixed* nsc;
2007 FT_String* next_name;
2008 FT_Var_Axis* a;
2009 FT_Fixed* c;
2011 GX_FVar_Head fvar_head;
2012 FT_Bool usePsName = 0;
2013 FT_UInt num_instances;
2014 FT_UInt num_axes;
2015 FT_UShort* axis_flags;
2016
2017 FT_Offset mmvar_size;
2018 FT_Offset axis_flags_size;
2019 FT_Offset axis_size;
2020 FT_Offset namedstyle_size;
2021 FT_Offset next_coords_size;
2022 FT_Offset next_name_size;
2023
2024 FT_Bool need_init;
2025
2026 static const FT_Frame_Field fvar_fields[] =
2027 {
2028
2029#undef FT_STRUCTURE
2030#define FT_STRUCTURE GX_FVar_Head
2031
2032 FT_FRAME_START( 16 ),
2034 FT_FRAME_USHORT ( offsetToData ),
2036 FT_FRAME_USHORT ( axisCount ),
2037 FT_FRAME_USHORT ( axisSize ),
2038 FT_FRAME_USHORT ( instanceCount ),
2039 FT_FRAME_USHORT ( instanceSize ),
2041 };
2042
2043 static const FT_Frame_Field fvaraxis_fields[] =
2044 {
2045
2046#undef FT_STRUCTURE
2047#define FT_STRUCTURE GX_FVar_Axis
2048
2049 FT_FRAME_START( 20 ),
2050 FT_FRAME_ULONG ( axisTag ),
2051 FT_FRAME_LONG ( minValue ),
2052 FT_FRAME_LONG ( defaultValue ),
2053 FT_FRAME_LONG ( maxValue ),
2055 FT_FRAME_USHORT( nameID ),
2057 };
2058
2059
2060 /* read the font data and set up the internal representation */
2061 /* if not already done */
2062
2063 need_init = !face->blend;
2064
2065 if ( need_init )
2066 {
2067 FT_TRACE2(( "FVAR " ));
2068
2069 /* both `fvar' and `gvar' must be present */
2070 if ( FT_SET_ERROR( face->goto_table( face, TTAG_gvar,
2071 stream, &table_len ) ) )
2072 {
2073 /* CFF2 is an alternate to gvar here */
2074 if ( FT_SET_ERROR( face->goto_table( face, TTAG_CFF2,
2075 stream, &table_len ) ) )
2076 {
2077 FT_TRACE1(( "\n"
2078 "TT_Get_MM_Var: `gvar' or `CFF2' table is missing\n" ));
2079 goto Exit;
2080 }
2081 }
2082
2083 if ( FT_SET_ERROR( face->goto_table( face, TTAG_fvar,
2084 stream, &table_len ) ) )
2085 {
2086 FT_TRACE1(( "is missing\n" ));
2087 goto Exit;
2088 }
2089
2090 fvar_start = FT_STREAM_POS( );
2091
2092 /* the validity of the `fvar' header data was already checked */
2093 /* in function `sfnt_init_face' */
2094 if ( FT_STREAM_READ_FIELDS( fvar_fields, &fvar_head ) )
2095 goto Exit;
2096
2097 usePsName = FT_BOOL( fvar_head.instanceSize ==
2098 6 + 4 * fvar_head.axisCount );
2099
2100 FT_TRACE2(( "loaded\n" ));
2101
2102 FT_TRACE5(( "%d variation ax%s\n",
2103 fvar_head.axisCount,
2104 fvar_head.axisCount == 1 ? "is" : "es" ));
2105
2106 if ( FT_NEW( face->blend ) )
2107 goto Exit;
2108
2109 num_axes = fvar_head.axisCount;
2110 face->blend->num_axis = num_axes;
2111 }
2112 else
2113 num_axes = face->blend->num_axis;
2114
2115 /* `num_instances' holds the number of all named instances, */
2116 /* including the default instance which might be missing */
2117 /* in fvar's table of named instances */
2118 num_instances = (FT_UInt)face->root.style_flags >> 16;
2119
2120 /* prepare storage area for MM data; this cannot overflow */
2121 /* 32-bit arithmetic because of the size limits used in the */
2122 /* `fvar' table validity check in `sfnt_init_face' */
2123
2124 /* the various `*_size' variables, which we also use as */
2125 /* offsets into the `mmlen' array, must be multiples of the */
2126 /* pointer size (except the last one); without such an */
2127 /* alignment there might be runtime errors due to */
2128 /* misaligned addresses */
2129#undef ALIGN_SIZE
2130#define ALIGN_SIZE( n ) \
2131 ( ( (n) + sizeof (void*) - 1 ) & ~( sizeof (void*) - 1 ) )
2132
2133 mmvar_size = ALIGN_SIZE( sizeof ( FT_MM_Var ) );
2134 axis_flags_size = ALIGN_SIZE( num_axes *
2135 sizeof ( FT_UShort ) );
2136 axis_size = ALIGN_SIZE( num_axes *
2137 sizeof ( FT_Var_Axis ) );
2138 namedstyle_size = ALIGN_SIZE( num_instances *
2139 sizeof ( FT_Var_Named_Style ) );
2140 next_coords_size = ALIGN_SIZE( num_instances *
2141 num_axes *
2142 sizeof ( FT_Fixed ) );
2143 next_name_size = num_axes * 5;
2144
2145 if ( need_init )
2146 {
2147 face->blend->mmvar_len = mmvar_size +
2148 axis_flags_size +
2149 axis_size +
2150 namedstyle_size +
2151 next_coords_size +
2152 next_name_size;
2153
2154 if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) )
2155 goto Exit;
2156 face->blend->mmvar = mmvar;
2157
2158 /* set up pointers and offsets into the `mmvar' array; */
2159 /* the data gets filled in later on */
2160
2161 mmvar->num_axis =
2162 num_axes;
2163 mmvar->num_designs =
2164 ~0U; /* meaningless in this context; each glyph */
2165 /* may have a different number of designs */
2166 /* (or tuples, as called by Apple) */
2167 mmvar->num_namedstyles =
2168 num_instances;
2169
2170 /* alas, no public field in `FT_Var_Axis' for axis flags */
2171 axis_flags =
2172 (FT_UShort*)( (char*)mmvar + mmvar_size );
2173 mmvar->axis =
2174 (FT_Var_Axis*)( (char*)axis_flags + axis_flags_size );
2175 mmvar->namedstyle =
2176 (FT_Var_Named_Style*)( (char*)mmvar->axis + axis_size );
2177
2178 next_coords = (FT_Fixed*)( (char*)mmvar->namedstyle +
2179 namedstyle_size );
2180 for ( i = 0; i < num_instances; i++ )
2181 {
2182 mmvar->namedstyle[i].coords = next_coords;
2183 next_coords += num_axes;
2184 }
2185
2186 next_name = (FT_String*)( (char*)mmvar->namedstyle +
2187 namedstyle_size + next_coords_size );
2188 for ( i = 0; i < num_axes; i++ )
2189 {
2190 mmvar->axis[i].name = next_name;
2191 next_name += 5;
2192 }
2193
2194 /* now fill in the data */
2195
2196 if ( FT_STREAM_SEEK( fvar_start + fvar_head.offsetToData ) )
2197 goto Exit;
2198
2199 a = mmvar->axis;
2200 for ( i = 0; i < num_axes; i++ )
2201 {
2202 GX_FVar_Axis axis_rec;
2203
2204#ifdef FT_DEBUG_LEVEL_TRACE
2205 int invalid = 0;
2206#endif
2207
2208
2209 if ( FT_STREAM_READ_FIELDS( fvaraxis_fields, &axis_rec ) )
2210 goto Exit;
2211 a->tag = axis_rec.axisTag;
2212 a->minimum = axis_rec.minValue;
2213 a->def = axis_rec.defaultValue;
2214 a->maximum = axis_rec.maxValue;
2215 a->strid = axis_rec.nameID;
2216
2217 a->name[0] = (FT_String)( a->tag >> 24 );
2218 a->name[1] = (FT_String)( ( a->tag >> 16 ) & 0xFF );
2219 a->name[2] = (FT_String)( ( a->tag >> 8 ) & 0xFF );
2220 a->name[3] = (FT_String)( ( a->tag ) & 0xFF );
2221 a->name[4] = '\0';
2222
2223 *axis_flags = axis_rec.flags;
2224
2225 if ( a->minimum > a->def ||
2226 a->def > a->maximum )
2227 {
2228 a->minimum = a->def;
2229 a->maximum = a->def;
2230
2231#ifdef FT_DEBUG_LEVEL_TRACE
2232 invalid = 1;
2233#endif
2234 }
2235
2236#ifdef FT_DEBUG_LEVEL_TRACE
2237 if ( i == 0 )
2238 FT_TRACE5(( " idx tag "
2239 /* " XXX `XXXX'" */
2240 " minimum default maximum flags\n" ));
2241 /* " XXXX.XXXXX XXXX.XXXXX XXXX.XXXXX 0xXXXX" */
2242
2243 FT_TRACE5(( " %3d `%s'"
2244 " %10.5f %10.5f %10.5f 0x%04X%s\n",
2245 i,
2246 a->name,
2247 a->minimum / 65536.0,
2248 a->def / 65536.0,
2249 a->maximum / 65536.0,
2250 *axis_flags,
2251 invalid ? " (invalid, disabled)" : "" ));
2252#endif
2253
2254 a++;
2255 axis_flags++;
2256 }
2257
2258 FT_TRACE5(( "\n" ));
2259
2260 /* named instance coordinates are stored as design coordinates; */
2261 /* we have to convert them to normalized coordinates also */
2262 if ( FT_NEW_ARRAY( face->blend->normalized_stylecoords,
2263 num_axes * num_instances ) )
2264 goto Exit;
2265
2266 if ( fvar_head.instanceCount && !face->blend->avar_loaded )
2267 {
2269
2270
2271 ft_var_load_avar( face );
2272
2273 if ( FT_STREAM_SEEK( offset ) )
2274 goto Exit;
2275 }
2276
2277 FT_TRACE5(( "%d instance%s\n",
2278 fvar_head.instanceCount,
2279 fvar_head.instanceCount == 1 ? "" : "s" ));
2280
2281 ns = mmvar->namedstyle;
2282 nsc = face->blend->normalized_stylecoords;
2283 for ( i = 0; i < fvar_head.instanceCount; i++, ns++ )
2284 {
2285 /* PostScript names add 2 bytes to the instance record size */
2286 if ( FT_FRAME_ENTER( ( usePsName ? 6L : 4L ) +
2287 4L * num_axes ) )
2288 goto Exit;
2289
2290 ns->strid = FT_GET_USHORT();
2291 (void) /* flags = */ FT_GET_USHORT();
2292
2293 c = ns->coords;
2294 for ( j = 0; j < num_axes; j++, c++ )
2295 *c = FT_GET_LONG();
2296
2297 /* valid psid values are 6, [256;32767], and 0xFFFF */
2298 if ( usePsName )
2299 ns->psid = FT_GET_USHORT();
2300 else
2301 ns->psid = 0xFFFF;
2302
2303#ifdef FT_DEBUG_LEVEL_TRACE
2304 {
2306
2307 FT_String* strname = NULL;
2308 FT_String* psname = NULL;
2309
2310 FT_ULong pos;
2311
2312
2313 pos = FT_STREAM_POS();
2314
2315 if ( ns->strid != 0xFFFF )
2316 {
2318 (FT_UShort)ns->strid,
2319 &strname );
2320 if ( strname && !ft_strcmp( strname, ".notdef" ) )
2321 strname = NULL;
2322 }
2323
2324 if ( ns->psid != 0xFFFF )
2325 {
2327 (FT_UShort)ns->psid,
2328 &psname );
2329 if ( psname && !ft_strcmp( psname, ".notdef" ) )
2330 psname = NULL;
2331 }
2332
2334
2335 FT_TRACE5(( " instance %d (%s%s%s, %s%s%s)\n",
2336 i,
2337 strname ? "name: `" : "",
2338 strname ? strname : "unnamed",
2339 strname ? "'" : "",
2340 psname ? "PS name: `" : "",
2341 psname ? psname : "no PS name",
2342 psname ? "'" : "" ));
2343
2344 FT_FREE( strname );
2345 FT_FREE( psname );
2346 }
2347#endif /* FT_DEBUG_LEVEL_TRACE */
2348
2349 ft_var_to_normalized( face, num_axes, ns->coords, nsc );
2350 nsc += num_axes;
2351
2352 FT_FRAME_EXIT();
2353 }
2354
2355 if ( num_instances != fvar_head.instanceCount )
2356 {
2358
2359 FT_Int found, dummy1, dummy2;
2360 FT_UInt strid = ~0U;
2361
2362
2363 /* the default instance is missing in array the */
2364 /* of named instances; try to synthesize an entry */
2365 found = sfnt->get_name_id( face,
2367 &dummy1,
2368 &dummy2 );
2369 if ( found )
2371 else
2372 {
2373 found = sfnt->get_name_id( face,
2375 &dummy1,
2376 &dummy2 );
2377 if ( found )
2379 }
2380
2381 if ( found )
2382 {
2383 found = sfnt->get_name_id( face,
2385 &dummy1,
2386 &dummy2 );
2387 if ( found )
2388 {
2389 FT_TRACE5(( "TT_Get_MM_Var:"
2390 " Adding default instance to named instances\n" ));
2391
2392 ns = &mmvar->namedstyle[fvar_head.instanceCount];
2393
2394 ns->strid = strid;
2395 ns->psid = TT_NAME_ID_PS_NAME;
2396
2397 a = mmvar->axis;
2398 c = ns->coords;
2399 for ( j = 0; j < num_axes; j++, a++, c++ )
2400 *c = a->def;
2401 }
2402 }
2403 }
2404
2405 ft_var_load_mvar( face );
2406 }
2407
2408 /* fill the output array if requested */
2409
2410 if ( master )
2411 {
2412 FT_UInt n;
2413
2414
2415 if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) )
2416 goto Exit;
2417 FT_MEM_COPY( mmvar, face->blend->mmvar, face->blend->mmvar_len );
2418
2419 axis_flags =
2420 (FT_UShort*)( (char*)mmvar + mmvar_size );
2421 mmvar->axis =
2422 (FT_Var_Axis*)( (char*)axis_flags + axis_flags_size );
2423 mmvar->namedstyle =
2424 (FT_Var_Named_Style*)( (char*)mmvar->axis+ axis_size );
2425
2426 next_coords = (FT_Fixed*)( (char*)mmvar->namedstyle +
2427 namedstyle_size );
2428 for ( n = 0; n < mmvar->num_namedstyles; n++ )
2429 {
2430 mmvar->namedstyle[n].coords = next_coords;
2431 next_coords += num_axes;
2432 }
2433
2434 a = mmvar->axis;
2435 next_name = (FT_String*)( (char*)mmvar->namedstyle +
2436 namedstyle_size + next_coords_size );
2437 for ( n = 0; n < num_axes; n++ )
2438 {
2439 a->name = next_name;
2440
2441 /* standard PostScript names for some standard apple tags */
2442 if ( a->tag == TTAG_wght )
2443 a->name = (char*)"Weight";
2444 else if ( a->tag == TTAG_wdth )
2445 a->name = (char*)"Width";
2446 else if ( a->tag == TTAG_opsz )
2447 a->name = (char*)"OpticalSize";
2448 else if ( a->tag == TTAG_slnt )
2449 a->name = (char*)"Slant";
2450
2451 next_name += 5;
2452 a++;
2453 }
2454
2455 *master = mmvar;
2456 }
2457
2458 Exit:
2459 return error;
2460 }
2461
2462
2463 static FT_Error
2464 tt_set_mm_blend( TT_Face face,
2465 FT_UInt num_coords,
2467 FT_Bool set_design_coords )
2468 {
2470 GX_Blend blend;
2471 FT_MM_Var* mmvar;
2472 FT_UInt i;
2473
2474 FT_Bool all_design_coords = FALSE;
2475
2476 FT_Memory memory = face->root.memory;
2477
2478 enum
2479 {
2480 mcvt_retain,
2481 mcvt_modify,
2482 mcvt_load
2483
2484 } manageCvt;
2485
2486
2487 face->doblend = FALSE;
2488
2489 if ( !face->blend )
2490 {
2491 if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
2492 goto Exit;
2493 }
2494
2495 blend = face->blend;
2496 mmvar = blend->mmvar;
2497
2498 if ( num_coords > mmvar->num_axis )
2499 {
2500 FT_TRACE2(( "TT_Set_MM_Blend:"
2501 " only using first %d of %d coordinates\n",
2502 mmvar->num_axis, num_coords ));
2503 num_coords = mmvar->num_axis;
2504 }
2505
2506 FT_TRACE5(( "TT_Set_MM_Blend:\n"
2507 " normalized design coordinates:\n" ));
2508
2509 for ( i = 0; i < num_coords; i++ )
2510 {
2511 FT_TRACE5(( " %.5f\n", coords[i] / 65536.0 ));
2512 if ( coords[i] < -0x00010000L || coords[i] > 0x00010000L )
2513 {
2514 FT_TRACE1(( "TT_Set_MM_Blend: normalized design coordinate %.5f\n"
2515 " is out of range [-1;1]\n",
2516 coords[i] / 65536.0 ));
2517 error = FT_THROW( Invalid_Argument );
2518 goto Exit;
2519 }
2520 }
2521
2522 FT_TRACE5(( "\n" ));
2523
2524 if ( !face->is_cff2 && !blend->glyphoffsets )
2525 if ( FT_SET_ERROR( ft_var_load_gvar( face ) ) )
2526 goto Exit;
2527
2528 if ( !blend->coords )
2529 {
2530 if ( FT_NEW_ARRAY( blend->coords, mmvar->num_axis ) )
2531 goto Exit;
2532
2533 /* the first time we have to compute all design coordinates */
2534 all_design_coords = TRUE;
2535 }
2536
2537 if ( !blend->normalizedcoords )
2538 {
2539 if ( FT_NEW_ARRAY( blend->normalizedcoords, mmvar->num_axis ) )
2540 goto Exit;
2541
2542 manageCvt = mcvt_modify;
2543
2544 /* If we have not set the blend coordinates before this, then the */
2545 /* cvt table will still be what we read from the `cvt ' table and */
2546 /* we don't need to reload it. We may need to change it though... */
2547 }
2548 else
2549 {
2550 FT_Bool have_diff = 0;
2551 FT_UInt j;
2552 FT_Fixed* c;
2553 FT_Fixed* n;
2554
2555
2556 manageCvt = mcvt_retain;
2557
2558 for ( i = 0; i < num_coords; i++ )
2559 {
2560 if ( blend->normalizedcoords[i] != coords[i] )
2561 {
2562 manageCvt = mcvt_load;
2563 have_diff = 1;
2564 break;
2565 }
2566 }
2567
2568 if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) )
2569 {
2570 FT_UInt instance_index = (FT_UInt)face->root.face_index >> 16;
2571
2572
2573 c = blend->normalizedcoords + i;
2574 n = blend->normalized_stylecoords +
2575 ( instance_index - 1 ) * mmvar->num_axis +
2576 i;
2577
2578 for ( j = i; j < mmvar->num_axis; j++, n++, c++ )
2579 if ( *c != *n )
2580 have_diff = 1;
2581 }
2582 else
2583 {
2584 c = blend->normalizedcoords + i;
2585 for ( j = i; j < mmvar->num_axis; j++, c++ )
2586 if ( *c != 0 )
2587 have_diff = 1;
2588 }
2589
2590 /* return value -1 indicates `no change' */
2591 if ( !have_diff )
2592 {
2593 face->doblend = TRUE;
2594
2595 return -1;
2596 }
2597
2598 for ( ; i < mmvar->num_axis; i++ )
2599 {
2600 if ( blend->normalizedcoords[i] != 0 )
2601 {
2602 manageCvt = mcvt_load;
2603 break;
2604 }
2605 }
2606
2607 /* If we don't change the blend coords then we don't need to do */
2608 /* anything to the cvt table. It will be correct. Otherwise we */
2609 /* no longer have the original cvt (it was modified when we set */
2610 /* the blend last time), so we must reload and then modify it. */
2611 }
2612
2613 blend->num_axis = mmvar->num_axis;
2614 FT_MEM_COPY( blend->normalizedcoords,
2615 coords,
2616 num_coords * sizeof ( FT_Fixed ) );
2617
2618 if ( set_design_coords )
2619 ft_var_to_design( face,
2620 all_design_coords ? blend->num_axis : num_coords,
2621 blend->normalizedcoords,
2622 blend->coords );
2623
2624 face->doblend = TRUE;
2625
2626 if ( face->cvt )
2627 {
2628 switch ( manageCvt )
2629 {
2630 case mcvt_load:
2631 /* The cvt table has been loaded already; every time we change the */
2632 /* blend we may need to reload and remodify the cvt table. */
2633 FT_FREE( face->cvt );
2634 face->cvt = NULL;
2635
2636 error = tt_face_load_cvt( face, face->root.stream );
2637 break;
2638
2639 case mcvt_modify:
2640 /* The original cvt table is in memory. All we need to do is */
2641 /* apply the `cvar' table (if any). */
2642 error = tt_face_vary_cvt( face, face->root.stream );
2643 break;
2644
2645 case mcvt_retain:
2646 /* The cvt table is correct for this set of coordinates. */
2647 break;
2648 }
2649 }
2650
2651 /* enforce recomputation of the PostScript name; */
2652 FT_FREE( face->postscript_name );
2653 face->postscript_name = NULL;
2654
2655 Exit:
2656 return error;
2657 }
2658
2659
2660 /**************************************************************************
2661 *
2662 * @Function:
2663 * TT_Set_MM_Blend
2664 *
2665 * @Description:
2666 * Set the blend (normalized) coordinates for this instance of the
2667 * font. Check that the `gvar' table is reasonable and does some
2668 * initial preparation.
2669 *
2670 * @InOut:
2671 * face ::
2672 * The font.
2673 * Initialize the blend structure with `gvar' data.
2674 *
2675 * @Input:
2676 * num_coords ::
2677 * The number of available coordinates. If it is
2678 * larger than the number of axes, ignore the excess
2679 * values. If it is smaller than the number of axes,
2680 * use the default value (0) for the remaining axes.
2681 *
2682 * coords ::
2683 * An array of `num_coords', each between [-1,1].
2684 *
2685 * @Return:
2686 * FreeType error code. 0 means success.
2687 */
2689 TT_Set_MM_Blend( TT_Face face,
2690 FT_UInt num_coords,
2691 FT_Fixed* coords )
2692 {
2694
2695
2696 error = tt_set_mm_blend( face, num_coords, coords, 1 );
2697 if ( error )
2698 return error;
2699
2700 if ( num_coords )
2701 face->root.face_flags |= FT_FACE_FLAG_VARIATION;
2702 else
2703 face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
2704
2705 return FT_Err_Ok;
2706 }
2707
2708
2709 /**************************************************************************
2710 *
2711 * @Function:
2712 * TT_Get_MM_Blend
2713 *
2714 * @Description:
2715 * Get the blend (normalized) coordinates for this instance of the
2716 * font.
2717 *
2718 * @InOut:
2719 * face ::
2720 * The font.
2721 * Initialize the blend structure with `gvar' data.
2722 *
2723 * @Input:
2724 * num_coords ::
2725 * The number of available coordinates. If it is
2726 * larger than the number of axes, set the excess
2727 * values to 0.
2728 *
2729 * coords ::
2730 * An array of `num_coords', each between [-1,1].
2731 *
2732 * @Return:
2733 * FreeType error code. 0 means success.
2734 */
2736 TT_Get_MM_Blend( TT_Face face,
2737 FT_UInt num_coords,
2738 FT_Fixed* coords )
2739 {
2741 GX_Blend blend;
2742 FT_UInt i, nc;
2743
2744
2745 if ( !face->blend )
2746 {
2747 if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
2748 return error;
2749 }
2750
2751 blend = face->blend;
2752
2753 if ( !blend->coords )
2754 {
2755 /* select default instance coordinates */
2756 /* if no instance is selected yet */
2757 if ( FT_SET_ERROR( tt_set_mm_blend( face, 0, NULL, 1 ) ) )
2758 return error;
2759 }
2760
2761 nc = num_coords;
2762 if ( num_coords > blend->num_axis )
2763 {
2764 FT_TRACE2(( "TT_Get_MM_Blend:"
2765 " only using first %d of %d coordinates\n",
2766 blend->num_axis, num_coords ));
2767 nc = blend->num_axis;
2768 }
2769
2770 if ( face->doblend )
2771 {
2772 for ( i = 0; i < nc; i++ )
2773 coords[i] = blend->normalizedcoords[i];
2774 }
2775 else
2776 {
2777 for ( i = 0; i < nc; i++ )
2778 coords[i] = 0;
2779 }
2780
2781 for ( ; i < num_coords; i++ )
2782 coords[i] = 0;
2783
2784 return FT_Err_Ok;
2785 }
2786
2787
2788 /**************************************************************************
2789 *
2790 * @Function:
2791 * TT_Set_Var_Design
2792 *
2793 * @Description:
2794 * Set the coordinates for the instance, measured in the user
2795 * coordinate system. Parse the `avar' table (if present) to convert
2796 * from user to normalized coordinates.
2797 *
2798 * @InOut:
2799 * face ::
2800 * The font face.
2801 * Initialize the blend struct with `gvar' data.
2802 *
2803 * @Input:
2804 * num_coords ::
2805 * The number of available coordinates. If it is
2806 * larger than the number of axes, ignore the excess
2807 * values. If it is smaller than the number of axes,
2808 * use the default values for the remaining axes.
2809 *
2810 * coords ::
2811 * A coordinate array with `num_coords' elements.
2812 *
2813 * @Return:
2814 * FreeType error code. 0 means success.
2815 */
2817 TT_Set_Var_Design( TT_Face face,
2818 FT_UInt num_coords,
2819 FT_Fixed* coords )
2820 {
2822 GX_Blend blend;
2823 FT_MM_Var* mmvar;
2824 FT_UInt i;
2825 FT_Memory memory = face->root.memory;
2826
2827 FT_Fixed* c;
2828 FT_Fixed* n;
2830
2831 FT_Bool have_diff = 0;
2832
2833
2834 if ( !face->blend )
2835 {
2836 if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
2837 goto Exit;
2838 }
2839
2840 blend = face->blend;
2841 mmvar = blend->mmvar;
2842
2843 if ( num_coords > mmvar->num_axis )
2844 {
2845 FT_TRACE2(( "TT_Set_Var_Design:"
2846 " only using first %d of %d coordinates\n",
2847 mmvar->num_axis, num_coords ));
2848 num_coords = mmvar->num_axis;
2849 }
2850
2851 if ( !blend->coords )
2852 {
2853 if ( FT_NEW_ARRAY( blend->coords, mmvar->num_axis ) )
2854 goto Exit;
2855 }
2856
2857 c = blend->coords;
2858 n = coords;
2859 for ( i = 0; i < num_coords; i++, n++, c++ )
2860 {
2861 if ( *c != *n )
2862 {
2863 *c = *n;
2864 have_diff = 1;
2865 }
2866 }
2867
2868 if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) )
2869 {
2870 FT_UInt instance_index;
2871 FT_Var_Named_Style* named_style;
2872
2873
2874 instance_index = (FT_UInt)face->root.face_index >> 16;
2875 named_style = mmvar->namedstyle + instance_index - 1;
2876
2877 n = named_style->coords + num_coords;
2878 for ( ; i < mmvar->num_axis; i++, n++, c++ )
2879 {
2880 if ( *c != *n )
2881 {
2882 *c = *n;
2883 have_diff = 1;
2884 }
2885 }
2886 }
2887 else
2888 {
2889 FT_Var_Axis* a;
2890
2891
2892 a = mmvar->axis + num_coords;
2893 for ( ; i < mmvar->num_axis; i++, a++, c++ )
2894 {
2895 if ( *c != a->def )
2896 {
2897 *c = a->def;
2898 have_diff = 1;
2899 }
2900 }
2901 }
2902
2903 /* return value -1 indicates `no change'; */
2904 /* we can exit early if `normalizedcoords' is already computed */
2905 if ( blend->normalizedcoords && !have_diff )
2906 return -1;
2907
2908 if ( FT_NEW_ARRAY( normalized, mmvar->num_axis ) )
2909 goto Exit;
2910
2911 if ( !face->blend->avar_loaded )
2912 ft_var_load_avar( face );
2913
2914 FT_TRACE5(( "TT_Set_Var_Design:\n"
2915 " normalized design coordinates:\n" ));
2916 ft_var_to_normalized( face, num_coords, blend->coords, normalized );
2917
2918 error = tt_set_mm_blend( face, mmvar->num_axis, normalized, 0 );
2919 if ( error )
2920 goto Exit;
2921
2922 if ( num_coords )
2923 face->root.face_flags |= FT_FACE_FLAG_VARIATION;
2924 else
2925 face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
2926
2927 Exit:
2929 return error;
2930 }
2931
2932
2933 /**************************************************************************
2934 *
2935 * @Function:
2936 * TT_Get_Var_Design
2937 *
2938 * @Description:
2939 * Get the design coordinates of the currently selected interpolated
2940 * font.
2941 *
2942 * @Input:
2943 * face ::
2944 * A handle to the source face.
2945 *
2946 * num_coords ::
2947 * The number of design coordinates to retrieve. If it
2948 * is larger than the number of axes, set the excess
2949 * values to~0.
2950 *
2951 * @Output:
2952 * coords ::
2953 * The design coordinates array.
2954 *
2955 * @Return:
2956 * FreeType error code. 0~means success.
2957 */
2959 TT_Get_Var_Design( TT_Face face,
2960 FT_UInt num_coords,
2961 FT_Fixed* coords )
2962 {
2964 GX_Blend blend;
2965 FT_UInt i, nc;
2966
2967
2968 if ( !face->blend )
2969 {
2970 if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
2971 return error;
2972 }
2973
2974 blend = face->blend;
2975
2976 if ( !blend->coords )
2977 {
2978 /* select default instance coordinates */
2979 /* if no instance is selected yet */
2980 if ( FT_SET_ERROR( tt_set_mm_blend( face, 0, NULL, 1 ) ) )
2981 return error;
2982 }
2983
2984 nc = num_coords;
2985 if ( num_coords > blend->num_axis )
2986 {
2987 FT_TRACE2(( "TT_Get_Var_Design:"
2988 " only using first %d of %d coordinates\n",
2989 blend->num_axis, num_coords ));
2990 nc = blend->num_axis;
2991 }
2992
2993 if ( face->doblend )
2994 {
2995 for ( i = 0; i < nc; i++ )
2996 coords[i] = blend->coords[i];
2997 }
2998 else
2999 {
3000 for ( i = 0; i < nc; i++ )
3001 coords[i] = 0;
3002 }
3003
3004 for ( ; i < num_coords; i++ )
3005 coords[i] = 0;
3006
3007 return FT_Err_Ok;
3008 }
3009
3010
3011 /**************************************************************************
3012 *
3013 * @Function:
3014 * TT_Set_Named_Instance
3015 *
3016 * @Description:
3017 * Set the given named instance, also resetting any further
3018 * variation.
3019 *
3020 * @Input:
3021 * face ::
3022 * A handle to the source face.
3023 *
3024 * instance_index ::
3025 * The instance index, starting with value 1.
3026 * Value 0 indicates to not use an instance.
3027 *
3028 * @Return:
3029 * FreeType error code. 0~means success.
3030 */
3032 TT_Set_Named_Instance( TT_Face face,
3033 FT_UInt instance_index )
3034 {
3035 FT_Error error = FT_ERR( Invalid_Argument );
3036 GX_Blend blend;
3037 FT_MM_Var* mmvar;
3038
3039 FT_UInt num_instances;
3040
3041
3042 if ( !face->blend )
3043 {
3044 if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
3045 goto Exit;
3046 }
3047
3048 blend = face->blend;
3049 mmvar = blend->mmvar;
3050
3051 num_instances = (FT_UInt)face->root.style_flags >> 16;
3052
3053 /* `instance_index' starts with value 1, thus `>' */
3054 if ( instance_index > num_instances )
3055 goto Exit;
3056
3057 if ( instance_index > 0 && mmvar->namedstyle )
3058 {
3059 FT_Memory memory = face->root.memory;
3061
3062 FT_Var_Named_Style* named_style;
3063 FT_String* style_name;
3064
3065
3066 named_style = mmvar->namedstyle + instance_index - 1;
3067
3068 error = sfnt->get_name( face,
3069 (FT_UShort)named_style->strid,
3070 &style_name );
3071 if ( error )
3072 goto Exit;
3073
3074 /* set (or replace) style name */
3075 FT_FREE( face->root.style_name );
3076 face->root.style_name = style_name;
3077
3078 /* finally, select the named instance */
3079 error = TT_Set_Var_Design( face,
3080 mmvar->num_axis,
3081 named_style->coords );
3082 if ( error )
3083 goto Exit;
3084 }
3085 else
3086 error = TT_Set_Var_Design( face, 0, NULL );
3087
3088 face->root.face_index = ( instance_index << 16 ) |
3089 ( face->root.face_index & 0xFFFFL );
3090 face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
3091
3092 Exit:
3093 return error;
3094 }
3095
3096
3097 /*************************************************************************/
3098 /*************************************************************************/
3099 /***** *****/
3100 /***** GX VAR PARSING ROUTINES *****/
3101 /***** *****/
3102 /*************************************************************************/
3103 /*************************************************************************/
3104
3105
3106 /**************************************************************************
3107 *
3108 * @Function:
3109 * tt_face_vary_cvt
3110 *
3111 * @Description:
3112 * Modify the loaded cvt table according to the `cvar' table and the
3113 * font's blend.
3114 *
3115 * @InOut:
3116 * face ::
3117 * A handle to the target face object.
3118 *
3119 * @Input:
3120 * stream ::
3121 * A handle to the input stream.
3122 *
3123 * @Return:
3124 * FreeType error code. 0 means success.
3125 *
3126 * Most errors are ignored. It is perfectly valid not to have a
3127 * `cvar' table even if there is a `gvar' and `fvar' table.
3128 */
3130 tt_face_vary_cvt( TT_Face face,
3132 {
3134 FT_Memory memory = stream->memory;
3135
3136 FT_ULong table_start;
3137 FT_ULong table_len;
3138
3139 FT_UInt tupleCount;
3140 FT_ULong offsetToData;
3141
3142 FT_ULong here;
3143 FT_UInt i, j;
3144
3145 FT_Fixed* tuple_coords = NULL;
3146 FT_Fixed* im_start_coords = NULL;
3147 FT_Fixed* im_end_coords = NULL;
3148
3149 GX_Blend blend = face->blend;
3150
3151 FT_UInt point_count;
3152 FT_UInt spoint_count = 0;
3153
3154 FT_UShort* sharedpoints = NULL;
3155 FT_UShort* localpoints = NULL;
3157
3158 FT_Fixed* deltas = NULL;
3159 FT_Fixed* cvt_deltas = NULL;
3160
3161
3162 FT_TRACE2(( "CVAR " ));
3163
3164 if ( !blend )
3165 {
3166 FT_TRACE2(( "\n"
3167 "tt_face_vary_cvt: no blend specified\n" ));
3168 error = FT_Err_Ok;
3169 goto Exit;
3170 }
3171
3172 if ( !face->cvt )
3173 {
3174 FT_TRACE2(( "\n"
3175 "tt_face_vary_cvt: no `cvt ' table\n" ));
3176 error = FT_Err_Ok;
3177 goto Exit;
3178 }
3179
3180 error = face->goto_table( face, TTAG_cvar, stream, &table_len );
3181 if ( error )
3182 {
3183 FT_TRACE2(( "is missing\n" ));
3184
3185 error = FT_Err_Ok;
3186 goto Exit;
3187 }
3188
3189 if ( FT_FRAME_ENTER( table_len ) )
3190 {
3191 error = FT_Err_Ok;
3192 goto Exit;
3193 }
3194
3195 table_start = FT_Stream_FTell( stream );
3196 if ( FT_GET_LONG() != 0x00010000L )
3197 {
3198 FT_TRACE2(( "bad table version\n" ));
3199
3200 error = FT_Err_Ok;
3201 goto FExit;
3202 }
3203
3204 FT_TRACE2(( "loaded\n" ));
3205
3206 if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis ) ||
3207 FT_NEW_ARRAY( im_start_coords, blend->num_axis ) ||
3208 FT_NEW_ARRAY( im_end_coords, blend->num_axis ) )
3209 goto FExit;
3210
3211 tupleCount = FT_GET_USHORT();
3212 offsetToData = FT_GET_USHORT();
3213
3214 /* rough sanity test */
3215 if ( offsetToData + ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) * 4 >
3216 table_len )
3217 {
3218 FT_TRACE2(( "tt_face_vary_cvt:"
3219 " invalid CVT variation array header\n" ));
3220
3221 error = FT_THROW( Invalid_Table );
3222 goto FExit;
3223 }
3224
3225 offsetToData += table_start;
3226
3227 if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS )
3228 {
3229 here = FT_Stream_FTell( stream );
3230
3231 FT_Stream_SeekSet( stream, offsetToData );
3232
3233 sharedpoints = ft_var_readpackedpoints( stream,
3234 table_len,
3235 &spoint_count );
3236 offsetToData = FT_Stream_FTell( stream );
3237
3238 FT_Stream_SeekSet( stream, here );
3239 }
3240
3241 FT_TRACE5(( "cvar: there %s %d tuple%s:\n",
3242 ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "is" : "are",
3243 tupleCount & GX_TC_TUPLE_COUNT_MASK,
3244 ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "" : "s" ));
3245
3246 if ( FT_NEW_ARRAY( cvt_deltas, face->cvt_size ) )
3247 goto FExit;
3248
3249 for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); i++ )
3250 {
3251 FT_UInt tupleDataSize;
3252 FT_UInt tupleIndex;
3253 FT_Fixed apply;
3254
3255
3256 FT_TRACE6(( " tuple %d:\n", i ));
3257
3258 tupleDataSize = FT_GET_USHORT();
3259 tupleIndex = FT_GET_USHORT();
3260
3261 if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD )
3262 {
3263 for ( j = 0; j < blend->num_axis; j++ )
3264 tuple_coords[j] = FT_GET_SHORT() * 4; /* convert from */
3265 /* short frac to fixed */
3266 }
3267 else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount )
3268 {
3269 FT_TRACE2(( "tt_face_vary_cvt:"
3270 " invalid tuple index\n" ));
3271
3272 error = FT_THROW( Invalid_Table );
3273 goto FExit;
3274 }
3275 else
3276 {
3277 if ( !blend->tuplecoords )
3278 {
3279 FT_TRACE2(( "tt_face_vary_cvt:"
3280 " no valid tuple coordinates available\n" ));
3281
3282 error = FT_THROW( Invalid_Table );
3283 goto FExit;
3284 }
3285
3287 tuple_coords,
3288 blend->tuplecoords +
3289 ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) * blend->num_axis,
3290 blend->num_axis * sizeof ( FT_Fixed ) );
3291 }
3292
3293 if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
3294 {
3295 for ( j = 0; j < blend->num_axis; j++ )
3296 im_start_coords[j] = FT_GET_SHORT() * 4;
3297 for ( j = 0; j < blend->num_axis; j++ )
3298 im_end_coords[j] = FT_GET_SHORT() * 4;
3299 }
3300
3301 apply = ft_var_apply_tuple( blend,
3302 (FT_UShort)tupleIndex,
3303 tuple_coords,
3304 im_start_coords,
3305 im_end_coords );
3306
3307 if ( apply == 0 ) /* tuple isn't active for our blend */
3308 {
3309 offsetToData += tupleDataSize;
3310 continue;
3311 }
3312
3313 here = FT_Stream_FTell( stream );
3314
3315 FT_Stream_SeekSet( stream, offsetToData );
3316
3317 if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS )
3318 {
3319 localpoints = ft_var_readpackedpoints( stream,
3320 table_len,
3321 &point_count );
3322 points = localpoints;
3323 }
3324 else
3325 {
3326 points = sharedpoints;
3327 point_count = spoint_count;
3328 }
3329
3330 deltas = ft_var_readpackeddeltas( stream,
3331 table_len,
3332 point_count == 0 ? face->cvt_size
3333 : point_count );
3334
3335 if ( !points ||
3336 !deltas ||
3337 ( localpoints == ALL_POINTS && point_count != face->cvt_size ) )
3338 ; /* failure, ignore it */
3339
3340 else if ( localpoints == ALL_POINTS )
3341 {
3342#ifdef FT_DEBUG_LEVEL_TRACE
3343 int count = 0;
3344#endif
3345
3346
3347 FT_TRACE7(( " CVT deltas:\n" ));
3348
3349 /* this means that there are deltas for every entry in cvt */
3350 for ( j = 0; j < face->cvt_size; j++ )
3351 {
3352 FT_Fixed old_cvt_delta;
3353
3354
3355 old_cvt_delta = cvt_deltas[j];
3356 cvt_deltas[j] = old_cvt_delta + FT_MulFix( deltas[j], apply );
3357
3358#ifdef FT_DEBUG_LEVEL_TRACE
3359 if ( old_cvt_delta != cvt_deltas[j] )
3360 {
3361 FT_TRACE7(( " %d: %f -> %f\n",
3362 j,
3363 ( FT_intToFixed( face->cvt[j] ) +
3364 old_cvt_delta ) / 65536.0,
3365 ( FT_intToFixed( face->cvt[j] ) +
3366 cvt_deltas[j] ) / 65536.0 ));
3367 count++;
3368 }
3369#endif
3370 }
3371
3372#ifdef FT_DEBUG_LEVEL_TRACE
3373 if ( !count )
3374 FT_TRACE7(( " none\n" ));
3375#endif
3376 }
3377
3378 else
3379 {
3380#ifdef FT_DEBUG_LEVEL_TRACE
3381 int count = 0;
3382#endif
3383
3384
3385 FT_TRACE7(( " CVT deltas:\n" ));
3386
3387 for ( j = 0; j < point_count; j++ )
3388 {
3389 int pindex;
3390 FT_Fixed old_cvt_delta;
3391
3392
3393 pindex = points[j];
3394 if ( (FT_ULong)pindex >= face->cvt_size )
3395 continue;
3396
3397 old_cvt_delta = cvt_deltas[pindex];
3398 cvt_deltas[pindex] = old_cvt_delta + FT_MulFix( deltas[j], apply );
3399
3400#ifdef FT_DEBUG_LEVEL_TRACE
3401 if ( old_cvt_delta != cvt_deltas[pindex] )
3402 {
3403 FT_TRACE7(( " %d: %f -> %f\n",
3404 pindex,
3405 ( FT_intToFixed( face->cvt[pindex] ) +
3406 old_cvt_delta ) / 65536.0,
3407 ( FT_intToFixed( face->cvt[pindex] ) +
3408 cvt_deltas[pindex] ) / 65536.0 ));
3409 count++;
3410 }
3411#endif
3412 }
3413
3414#ifdef FT_DEBUG_LEVEL_TRACE
3415 if ( !count )
3416 FT_TRACE7(( " none\n" ));
3417#endif
3418 }
3419
3420 if ( localpoints != ALL_POINTS )
3421 FT_FREE( localpoints );
3422 FT_FREE( deltas );
3423
3424 offsetToData += tupleDataSize;
3425
3426 FT_Stream_SeekSet( stream, here );
3427 }
3428
3429 FT_TRACE5(( "\n" ));
3430
3431 for ( i = 0; i < face->cvt_size; i++ )
3432 face->cvt[i] += FT_fixedToInt( cvt_deltas[i] );
3433
3434 FExit:
3435 FT_FRAME_EXIT();
3436
3437 Exit:
3438 if ( sharedpoints != ALL_POINTS )
3439 FT_FREE( sharedpoints );
3440 FT_FREE( tuple_coords );
3441 FT_FREE( im_start_coords );
3442 FT_FREE( im_end_coords );
3443 FT_FREE( cvt_deltas );
3444
3445 return error;
3446 }
3447
3448
3449 /* Shift the original coordinates of all points between indices `p1' */
3450 /* and `p2', using the same difference as given by index `ref'. */
3451
3452 /* modeled after `af_iup_shift' */
3453
3454 static void
3455 tt_delta_shift( int p1,
3456 int p2,
3457 int ref,
3458 FT_Vector* in_points,
3459 FT_Vector* out_points )
3460 {
3461 int p;
3462 FT_Vector delta;
3463
3464
3465 delta.x = out_points[ref].x - in_points[ref].x;
3466 delta.y = out_points[ref].y - in_points[ref].y;
3467
3468 if ( delta.x == 0 && delta.y == 0 )
3469 return;
3470
3471 for ( p = p1; p < ref; p++ )
3472 {
3473 out_points[p].x += delta.x;
3474 out_points[p].y += delta.y;
3475 }
3476
3477 for ( p = ref + 1; p <= p2; p++ )
3478 {
3479 out_points[p].x += delta.x;
3480 out_points[p].y += delta.y;
3481 }
3482 }
3483
3484
3485 /* Interpolate the original coordinates of all points with indices */
3486 /* between `p1' and `p2', using `ref1' and `ref2' as the reference */
3487 /* point indices. */
3488
3489 /* modeled after `af_iup_interp', `_iup_worker_interpolate', and */
3490 /* `Ins_IUP' with spec differences in handling ill-defined cases. */
3491 static void
3492 tt_delta_interpolate( int p1,
3493 int p2,
3494 int ref1,
3495 int ref2,
3496 FT_Vector* in_points,
3497 FT_Vector* out_points )
3498 {
3499 int p, i;
3500
3501 FT_Pos out, in1, in2, out1, out2, d1, d2;
3502
3503
3504 if ( p1 > p2 )
3505 return;
3506
3507 /* handle both horizontal and vertical coordinates */
3508 for ( i = 0; i <= 1; i++ )
3509 {
3510 /* shift array pointers so that we can access `foo.y' as `foo.x' */
3511 in_points = (FT_Vector*)( (FT_Pos*)in_points + i );
3512 out_points = (FT_Vector*)( (FT_Pos*)out_points + i );
3513
3514 if ( in_points[ref1].x > in_points[ref2].x )
3515 {
3516 p = ref1;
3517 ref1 = ref2;
3518 ref2 = p;
3519 }
3520
3521 in1 = in_points[ref1].x;
3522 in2 = in_points[ref2].x;
3523 out1 = out_points[ref1].x;
3524 out2 = out_points[ref2].x;
3525 d1 = out1 - in1;
3526 d2 = out2 - in2;
3527
3528 /* If the reference points have the same coordinate but different */
3529 /* delta, inferred delta is zero. Otherwise interpolate. */
3530 if ( in1 != in2 || out1 == out2 )
3531 {
3532 FT_Fixed scale = in1 != in2 ? FT_DivFix( out2 - out1, in2 - in1 )
3533 : 0;
3534
3535
3536 for ( p = p1; p <= p2; p++ )
3537 {
3538 out = in_points[p].x;
3539
3540 if ( out <= in1 )
3541 out += d1;
3542 else if ( out >= in2 )
3543 out += d2;
3544 else
3545 out = out1 + FT_MulFix( out - in1, scale );
3546
3547 out_points[p].x = out;
3548 }
3549 }
3550 }
3551 }
3552
3553
3554 /* Interpolate points without delta values, similar to */
3555 /* the `IUP' hinting instruction. */
3556
3557 /* modeled after `Ins_IUP */
3558
3559 static void
3560 tt_interpolate_deltas( FT_Outline* outline,
3561 FT_Vector* out_points,
3562 FT_Vector* in_points,
3563 FT_Bool* has_delta )
3564 {
3565 FT_Int first_point;
3566 FT_Int end_point;
3567
3568 FT_Int first_delta;
3569 FT_Int cur_delta;
3570
3571 FT_Int point;
3572 FT_Short contour;
3573
3574
3575 /* ignore empty outlines */
3576 if ( !outline->n_contours )
3577 return;
3578
3579 contour = 0;
3580 point = 0;
3581
3582 do
3583 {
3584 end_point = outline->contours[contour];
3585 first_point = point;
3586
3587 /* search first point that has a delta */
3588 while ( point <= end_point && !has_delta[point] )
3589 point++;
3590
3591 if ( point <= end_point )
3592 {
3593 first_delta = point;
3594 cur_delta = point;
3595
3596 point++;
3597
3598 while ( point <= end_point )
3599 {
3600 /* search next point that has a delta */
3601 /* and interpolate intermediate points */
3602 if ( has_delta[point] )
3603 {
3604 tt_delta_interpolate( cur_delta + 1,
3605 point - 1,
3606 cur_delta,
3607 point,
3608 in_points,
3609 out_points );
3610 cur_delta = point;
3611 }
3612
3613 point++;
3614 }
3615
3616 /* shift contour if we only have a single delta */
3617 if ( cur_delta == first_delta )
3618 tt_delta_shift( first_point,
3619 end_point,
3620 cur_delta,
3621 in_points,
3622 out_points );
3623 else
3624 {
3625 /* otherwise handle remaining points */
3626 /* at the end and beginning of the contour */
3627 tt_delta_interpolate( cur_delta + 1,
3628 end_point,
3629 cur_delta,
3630 first_delta,
3631 in_points,
3632 out_points );
3633
3634 if ( first_delta > 0 )
3635 tt_delta_interpolate( first_point,
3636 first_delta - 1,
3637 cur_delta,
3638 first_delta,
3639 in_points,
3640 out_points );
3641 }
3642 }
3643 contour++;
3644
3645 } while ( contour < outline->n_contours );
3646 }
3647
3648
3649 /**************************************************************************
3650 *
3651 * @Function:
3652 * TT_Vary_Apply_Glyph_Deltas
3653 *
3654 * @Description:
3655 * Apply the appropriate deltas to the current glyph.
3656 *
3657 * @Input:
3658 * face ::
3659 * A handle to the target face object.
3660 *
3661 * glyph_index ::
3662 * The index of the glyph being modified.
3663 *
3664 * n_points ::
3665 * The number of the points in the glyph, including
3666 * phantom points.
3667 *
3668 * @InOut:
3669 * outline ::
3670 * The outline to change.
3671 *
3672 * @Return:
3673 * FreeType error code. 0 means success.
3674 */
3676 TT_Vary_Apply_Glyph_Deltas( TT_Face face,
3677 FT_UInt glyph_index,
3679 FT_UInt n_points )
3680 {
3682 FT_Stream stream = face->root.stream;
3683 FT_Memory memory = stream->memory;
3684
3685 FT_Vector* points_org = NULL; /* coordinates in 16.16 format */
3686 FT_Vector* points_out = NULL; /* coordinates in 16.16 format */
3687 FT_Bool* has_delta = NULL;
3688
3689 FT_ULong glyph_start;
3690
3691 FT_UInt tupleCount;
3692 FT_ULong offsetToData;
3694
3695 FT_ULong here;
3696 FT_UInt i, j;
3697
3698 FT_Fixed* tuple_coords = NULL;
3699 FT_Fixed* im_start_coords = NULL;
3700 FT_Fixed* im_end_coords = NULL;
3701
3702 GX_Blend blend = face->blend;
3703
3704 FT_UInt point_count;
3705 FT_UInt spoint_count = 0;
3706
3707 FT_UShort* sharedpoints = NULL;
3708 FT_UShort* localpoints = NULL;
3710
3711 FT_Fixed* deltas_x = NULL;
3712 FT_Fixed* deltas_y = NULL;
3713 FT_Fixed* point_deltas_x = NULL;
3714 FT_Fixed* point_deltas_y = NULL;
3715
3716
3717 if ( !face->doblend || !blend )
3718 return FT_THROW( Invalid_Argument );
3719
3720 if ( glyph_index >= blend->gv_glyphcnt ||
3721 blend->glyphoffsets[glyph_index] ==
3722 blend->glyphoffsets[glyph_index + 1] )
3723 {
3724 FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:"
3725 " no variation data for this glyph\n" ));
3726 return FT_Err_Ok;
3727 }
3728
3729 if ( FT_NEW_ARRAY( points_org, n_points ) ||
3730 FT_NEW_ARRAY( points_out, n_points ) ||
3731 FT_NEW_ARRAY( has_delta, n_points ) )
3732 goto Fail1;
3733
3734 dataSize = blend->glyphoffsets[glyph_index + 1] -
3735 blend->glyphoffsets[glyph_index];
3736
3737 if ( FT_STREAM_SEEK( blend->glyphoffsets[glyph_index] ) ||
3739 goto Fail1;
3740
3741 glyph_start = FT_Stream_FTell( stream );
3742
3743 /* each set of glyph variation data is formatted similarly to `cvar' */
3744
3745 if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis ) ||
3746 FT_NEW_ARRAY( im_start_coords, blend->num_axis ) ||
3747 FT_NEW_ARRAY( im_end_coords, blend->num_axis ) )
3748 goto Fail2;
3749
3750 tupleCount = FT_GET_USHORT();
3751 offsetToData = FT_GET_USHORT();
3752
3753 /* rough sanity test */
3754 if ( offsetToData > dataSize ||
3755 ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) * 4 > dataSize )
3756 {
3757 FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:"
3758 " invalid glyph variation array header\n" ));
3759
3760 error = FT_THROW( Invalid_Table );
3761 goto Fail2;
3762 }
3763
3764 offsetToData += glyph_start;
3765
3766 if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS )
3767 {
3768 here = FT_Stream_FTell( stream );
3769
3770 FT_Stream_SeekSet( stream, offsetToData );
3771
3772 sharedpoints = ft_var_readpackedpoints( stream,
3773 blend->gvar_size,
3774 &spoint_count );
3775 offsetToData = FT_Stream_FTell( stream );
3776
3777 FT_Stream_SeekSet( stream, here );
3778 }
3779
3780 FT_TRACE5(( "gvar: there %s %d tuple%s:\n",
3781 ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "is" : "are",
3782 tupleCount & GX_TC_TUPLE_COUNT_MASK,
3783 ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "" : "s" ));
3784
3785 if ( FT_NEW_ARRAY( point_deltas_x, n_points ) ||
3786 FT_NEW_ARRAY( point_deltas_y, n_points ) )
3787 goto Fail3;
3788
3789 for ( j = 0; j < n_points; j++ )
3790 {
3791 points_org[j].x = FT_intToFixed( outline->points[j].x );
3792 points_org[j].y = FT_intToFixed( outline->points[j].y );
3793 }
3794
3795 for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); i++ )
3796 {
3797 FT_UInt tupleDataSize;
3798 FT_UInt tupleIndex;
3799 FT_Fixed apply;
3800
3801
3802 FT_TRACE6(( " tuple %d:\n", i ));
3803
3804 tupleDataSize = FT_GET_USHORT();
3805 tupleIndex = FT_GET_USHORT();
3806
3807 if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD )
3808 {
3809 for ( j = 0; j < blend->num_axis; j++ )
3810 tuple_coords[j] = FT_GET_SHORT() * 4; /* convert from */
3811 /* short frac to fixed */
3812 }
3813 else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount )
3814 {
3815 FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:"
3816 " invalid tuple index\n" ));
3817
3818 error = FT_THROW( Invalid_Table );
3819 goto Fail3;
3820 }
3821 else
3823 tuple_coords,
3824 blend->tuplecoords +
3825 ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) * blend->num_axis,
3826 blend->num_axis * sizeof ( FT_Fixed ) );
3827
3828 if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
3829 {
3830 for ( j = 0; j < blend->num_axis; j++ )
3831 im_start_coords[j] = FT_GET_SHORT() * 4;
3832 for ( j = 0; j < blend->num_axis; j++ )
3833 im_end_coords[j] = FT_GET_SHORT() * 4;
3834 }
3835
3836 apply = ft_var_apply_tuple( blend,
3837 (FT_UShort)tupleIndex,
3838 tuple_coords,
3839 im_start_coords,
3840 im_end_coords );
3841
3842 if ( apply == 0 ) /* tuple isn't active for our blend */
3843 {
3844 offsetToData += tupleDataSize;
3845 continue;
3846 }
3847
3848 here = FT_Stream_FTell( stream );
3849
3850 FT_Stream_SeekSet( stream, offsetToData );
3851
3852 if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS )
3853 {
3854 localpoints = ft_var_readpackedpoints( stream,
3855 blend->gvar_size,
3856 &point_count );
3857 points = localpoints;
3858 }
3859 else
3860 {
3861 points = sharedpoints;
3862 point_count = spoint_count;
3863 }
3864
3865 deltas_x = ft_var_readpackeddeltas( stream,
3866 blend->gvar_size,
3867 point_count == 0 ? n_points
3868 : point_count );
3869 deltas_y = ft_var_readpackeddeltas( stream,
3870 blend->gvar_size,
3871 point_count == 0 ? n_points
3872 : point_count );
3873
3874 if ( !points || !deltas_y || !deltas_x )
3875 ; /* failure, ignore it */
3876
3877 else if ( points == ALL_POINTS )
3878 {
3879#ifdef FT_DEBUG_LEVEL_TRACE
3880 int count = 0;
3881#endif
3882
3883
3884 FT_TRACE7(( " point deltas:\n" ));
3885
3886 /* this means that there are deltas for every point in the glyph */
3887 for ( j = 0; j < n_points; j++ )
3888 {
3889 FT_Fixed old_point_delta_x = point_deltas_x[j];
3890 FT_Fixed old_point_delta_y = point_deltas_y[j];
3891
3892 FT_Fixed point_delta_x = FT_MulFix( deltas_x[j], apply );
3893 FT_Fixed point_delta_y = FT_MulFix( deltas_y[j], apply );
3894
3895
3896 if ( j < n_points - 4 )
3897 {
3898 point_deltas_x[j] = old_point_delta_x + point_delta_x;
3899 point_deltas_y[j] = old_point_delta_y + point_delta_y;
3900 }
3901 else
3902 {
3903 /* To avoid double adjustment of advance width or height, */
3904 /* adjust phantom points only if there is no HVAR or VVAR */
3905 /* support, respectively. */
3906 if ( j == ( n_points - 4 ) &&
3907 !( face->variation_support &
3909 point_deltas_x[j] = old_point_delta_x + point_delta_x;
3910
3911 else if ( j == ( n_points - 3 ) &&
3912 !( face->variation_support &
3914 point_deltas_x[j] = old_point_delta_x + point_delta_x;
3915
3916 else if ( j == ( n_points - 2 ) &&
3917 !( face->variation_support &
3919 point_deltas_y[j] = old_point_delta_y + point_delta_y;
3920
3921 else if ( j == ( n_points - 1 ) &&
3922 !( face->variation_support &
3924 point_deltas_y[j] = old_point_delta_y + point_delta_y;
3925 }
3926
3927#ifdef FT_DEBUG_LEVEL_TRACE
3928 if ( point_delta_x || point_delta_y )
3929 {
3930 FT_TRACE7(( " %d: (%f, %f) -> (%f, %f)\n",
3931 j,
3932 ( FT_intToFixed( outline->points[j].x ) +
3933 old_point_delta_x ) / 65536.0,
3934 ( FT_intToFixed( outline->points[j].y ) +
3935 old_point_delta_y ) / 65536.0,
3936 ( FT_intToFixed( outline->points[j].x ) +
3937 point_deltas_x[j] ) / 65536.0,
3938 ( FT_intToFixed( outline->points[j].y ) +
3939 point_deltas_y[j] ) / 65536.0 ));
3940 count++;
3941 }
3942#endif
3943 }
3944
3945#ifdef FT_DEBUG_LEVEL_TRACE
3946 if ( !count )
3947 FT_TRACE7(( " none\n" ));
3948#endif
3949 }
3950
3951 else
3952 {
3953#ifdef FT_DEBUG_LEVEL_TRACE
3954 int count = 0;
3955#endif
3956
3957
3958 /* we have to interpolate the missing deltas similar to the */
3959 /* IUP bytecode instruction */
3960 for ( j = 0; j < n_points; j++ )
3961 {
3962 has_delta[j] = FALSE;
3963 points_out[j] = points_org[j];
3964 }
3965
3966 for ( j = 0; j < point_count; j++ )
3967 {
3968 FT_UShort idx = points[j];
3969
3970
3971 if ( idx >= n_points )
3972 continue;
3973
3974 has_delta[idx] = TRUE;
3975
3976 points_out[idx].x += FT_MulFix( deltas_x[j], apply );
3977 points_out[idx].y += FT_MulFix( deltas_y[j], apply );
3978 }
3979
3980 /* no need to handle phantom points here, */
3981 /* since solitary points can't be interpolated */
3982 tt_interpolate_deltas( outline,
3983 points_out,
3984 points_org,
3985 has_delta );
3986
3987 FT_TRACE7(( " point deltas:\n" ));
3988
3989 for ( j = 0; j < n_points; j++ )
3990 {
3991 FT_Fixed old_point_delta_x = point_deltas_x[j];
3992 FT_Fixed old_point_delta_y = point_deltas_y[j];
3993
3994 FT_Pos point_delta_x = points_out[j].x - points_org[j].x;
3995 FT_Pos point_delta_y = points_out[j].y - points_org[j].y;
3996
3997
3998 if ( j < n_points - 4 )
3999 {
4000 point_deltas_x[j] = old_point_delta_x + point_delta_x;
4001 point_deltas_y[j] = old_point_delta_y + point_delta_y;
4002 }
4003 else
4004 {
4005 /* To avoid double adjustment of advance width or height, */
4006 /* adjust phantom points only if there is no HVAR or VVAR */
4007 /* support, respectively. */
4008 if ( j == ( n_points - 4 ) &&
4009 !( face->variation_support &
4011 point_deltas_x[j] = old_point_delta_x + point_delta_x;
4012
4013 else if ( j == ( n_points - 3 ) &&
4014 !( face->variation_support &
4016 point_deltas_x[j] = old_point_delta_x + point_delta_x;
4017
4018 else if ( j == ( n_points - 2 ) &&
4019 !( face->variation_support &
4021 point_deltas_y[j] = old_point_delta_y + point_delta_y;
4022
4023 else if ( j == ( n_points - 1 ) &&
4024 !( face->variation_support &
4026 point_deltas_y[j] = old_point_delta_y + point_delta_y;
4027 }
4028
4029#ifdef FT_DEBUG_LEVEL_TRACE
4030 if ( point_delta_x || point_delta_y )
4031 {
4032 FT_TRACE7(( " %d: (%f, %f) -> (%f, %f)\n",
4033 j,
4034 ( FT_intToFixed( outline->points[j].x ) +
4035 old_point_delta_x ) / 65536.0,
4036 ( FT_intToFixed( outline->points[j].y ) +
4037 old_point_delta_y ) / 65536.0,
4038 ( FT_intToFixed( outline->points[j].x ) +
4039 point_deltas_x[j] ) / 65536.0,
4040 ( FT_intToFixed( outline->points[j].y ) +
4041 point_deltas_y[j] ) / 65536.0 ));
4042 count++;
4043 }
4044#endif
4045 }
4046
4047#ifdef FT_DEBUG_LEVEL_TRACE
4048 if ( !count )
4049 FT_TRACE7(( " none\n" ));
4050#endif
4051 }
4052
4053 if ( localpoints != ALL_POINTS )
4054 FT_FREE( localpoints );
4055 FT_FREE( deltas_x );
4056 FT_FREE( deltas_y );
4057
4058 offsetToData += tupleDataSize;
4059
4060 FT_Stream_SeekSet( stream, here );
4061 }
4062
4063 FT_TRACE5(( "\n" ));
4064
4065 for ( i = 0; i < n_points; i++ )
4066 {
4067 outline->points[i].x += FT_fixedToInt( point_deltas_x[i] );
4068 outline->points[i].y += FT_fixedToInt( point_deltas_y[i] );
4069 }
4070
4071 Fail3:
4072 FT_FREE( point_deltas_x );
4073 FT_FREE( point_deltas_y );
4074
4075 Fail2:
4076 if ( sharedpoints != ALL_POINTS )
4077 FT_FREE( sharedpoints );
4078 FT_FREE( tuple_coords );
4079 FT_FREE( im_start_coords );
4080 FT_FREE( im_end_coords );
4081
4082 FT_FRAME_EXIT();
4083
4084 Fail1:
4085 FT_FREE( points_org );
4086 FT_FREE( points_out );
4087 FT_FREE( has_delta );
4088
4089 return error;
4090 }
4091
4092
4093 /**************************************************************************
4094 *
4095 * @Function:
4096 * tt_get_var_blend
4097 *
4098 * @Description:
4099 * An extended internal version of `TT_Get_MM_Blend' that returns
4100 * pointers instead of copying data, without any initialization of
4101 * the MM machinery in case it isn't loaded yet.
4102 */
4104 tt_get_var_blend( TT_Face face,
4105 FT_UInt *num_coords,
4106 FT_Fixed* *coords,
4107 FT_Fixed* *normalizedcoords,
4108 FT_MM_Var* *mm_var )
4109 {
4110 if ( face->blend )
4111 {
4112 if ( num_coords )
4113 *num_coords = face->blend->num_axis;
4114 if ( coords )
4115 *coords = face->blend->coords;
4116 if ( normalizedcoords )
4117 *normalizedcoords = face->blend->normalizedcoords;
4118 if ( mm_var )
4119 *mm_var = face->blend->mmvar;
4120 }
4121 else
4122 {
4123 if ( num_coords )
4124 *num_coords = 0;
4125 if ( coords )
4126 *coords = NULL;
4127 if ( mm_var )
4128 *mm_var = NULL;
4129 }
4130
4131 return FT_Err_Ok;
4132 }
4133
4134
4135 static void
4136 ft_var_done_item_variation_store( TT_Face face,
4137 GX_ItemVarStore itemStore )
4138 {
4140 FT_UInt i;
4141
4142
4143 if ( itemStore->varData )
4144 {
4145 for ( i = 0; i < itemStore->dataCount; i++ )
4146 {
4147 FT_FREE( itemStore->varData[i].regionIndices );
4148 FT_FREE( itemStore->varData[i].deltaSet );
4149 }
4150
4151 FT_FREE( itemStore->varData );
4152 }
4153
4154 if ( itemStore->varRegionList )
4155 {
4156 for ( i = 0; i < itemStore->regionCount; i++ )
4157 FT_FREE( itemStore->varRegionList[i].axisList );
4158
4159 FT_FREE( itemStore->varRegionList );
4160 }
4161 }
4162
4163
4164 /**************************************************************************
4165 *
4166 * @Function:
4167 * tt_done_blend
4168 *
4169 * @Description:
4170 * Free the blend internal data structure.
4171 */
4172 FT_LOCAL_DEF( void )
4173 tt_done_blend( TT_Face face )
4174 {
4176 GX_Blend blend = face->blend;
4177
4178
4179 if ( blend )
4180 {
4181 FT_UInt i, num_axes;
4182
4183
4184 /* blend->num_axis might not be set up yet */
4185 num_axes = blend->mmvar->num_axis;
4186
4187 FT_FREE( blend->coords );
4188 FT_FREE( blend->normalizedcoords );
4189 FT_FREE( blend->normalized_stylecoords );
4190 FT_FREE( blend->mmvar );
4191
4192 if ( blend->avar_segment )
4193 {
4194 for ( i = 0; i < num_axes; i++ )
4195 FT_FREE( blend->avar_segment[i].correspondence );
4196 FT_FREE( blend->avar_segment );
4197 }
4198
4199 if ( blend->hvar_table )
4200 {
4201 ft_var_done_item_variation_store( face,
4202 &blend->hvar_table->itemStore );
4203
4204 FT_FREE( blend->hvar_table->widthMap.innerIndex );
4205 FT_FREE( blend->hvar_table->widthMap.outerIndex );
4206 FT_FREE( blend->hvar_table );
4207 }
4208
4209 if ( blend->vvar_table )
4210 {
4211 ft_var_done_item_variation_store( face,
4212 &blend->vvar_table->itemStore );
4213
4214 FT_FREE( blend->vvar_table->widthMap.innerIndex );
4215 FT_FREE( blend->vvar_table->widthMap.outerIndex );
4216 FT_FREE( blend->vvar_table );
4217 }
4218
4219 if ( blend->mvar_table )
4220 {
4221 ft_var_done_item_variation_store( face,
4222 &blend->mvar_table->itemStore );
4223
4224 FT_FREE( blend->mvar_table->values );
4225 FT_FREE( blend->mvar_table );
4226 }
4227
4228 FT_FREE( blend->tuplecoords );
4229 FT_FREE( blend->glyphoffsets );
4230 FT_FREE( blend );
4231 }
4232 }
4233
4234#else /* !TT_CONFIG_OPTION_GX_VAR_SUPPORT */
4235
4236 /* ANSI C doesn't like empty source files */
4237 typedef int _tt_gxvar_dummy;
4238
4239#endif /* !TT_CONFIG_OPTION_GX_VAR_SUPPORT */
4240
4241
4242/* END */
void user(int argc, const char *argv[])
Definition: cmds.c:1350
#define U(x)
Definition: wordpad.c:45
#define FT_fdot14ToFixed(x)
Definition: cffload.c:1117
Definition: _map.h:48
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
unsigned int idx
Definition: utils.c:41
static const WCHAR version[]
Definition: asmname.c:66
POINTL point
Definition: edittest.c:50
FT_DivFix(FT_Long a, FT_Long b)
Definition: ftcalc.c:608
#define FT_FACE_FLAG_VARIATION
Definition: freetype.h:1225
#define FT_IS_NAMED_INSTANCE(face)
Definition: freetype.h:1396
FT_MulDiv(FT_Long a, FT_Long b, FT_Long c)
Definition: ftcalc.c:416
FT_MulFix(FT_Long a, FT_Long b)
Definition: ftcalc.c:509
return FT_Err_Ok
Definition: ftbbox.c:527
#define SUB_LONG(a, b)
Definition: ftcalc.h:475
#define FT_LOCAL_DEF(x)
Definition: ftconfig.h:387
#define FT_UNUSED(arg)
Definition: ftconfig.h:100
#define FT_TRACE5(varformat)
Definition: ftdebug.h:190
#define FT_TRACE7(varformat)
Definition: ftdebug.h:192
#define FT_TRACE6(varformat)
Definition: ftdebug.h:191
#define FT_THROW(e)
Definition: ftdebug.h:241
#define FT_TRACE2(varformat)
Definition: ftdebug.h:187
#define FT_TRACE1(varformat)
Definition: ftdebug.h:186
FT_BEGIN_HEADER typedef signed long FT_Pos
Definition: ftimage.h:58
FT_List_Iterate(FT_List list, FT_List_Iterator iterator, void *user)
Definition: ftutil.c:381
#define FT_NEW_ARRAY(ptr, count)
Definition: ftmemory.h:332
#define FT_NEW(ptr)
Definition: ftmemory.h:330
#define FT_SET_ERROR(expression)
Definition: ftmemory.h:42
#define FT_ALLOC(ptr, size)
Definition: ftmemory.h:302
#define FT_FREE(ptr)
Definition: ftmemory.h:328
#define FT_MEM_COPY(dest, source, count)
Definition: ftmemory.h:228
#define FT_FACE(x)
Definition: ftobjs.h:599
#define FT_MIN(a, b)
Definition: ftobjs.h:70
#define FT_FACE_STREAM(x)
Definition: ftobjs.h:606
#define FT_FACE_MEMORY(x)
Definition: ftobjs.h:605
#define FT_MAX(a, b)
Definition: ftobjs.h:71
#define ft_strcmp
Definition: ftstdlib.h:86
#define FT_FRAME_ENTER(size)
Definition: ftstream.h:537
#define FT_READ_USHORT(var)
Definition: ftstream.h:328
#define FT_FRAME_SKIP_SHORT
Definition: ftstream.h:137
#define FT_FRAME_END
Definition: ftstream.h:118
#define FT_GET_ULONG()
Definition: ftstream.h:304
#define FT_GET_CHAR()
Definition: ftstream.h:297
#define FT_STREAM_SEEK(position)
Definition: ftstream.h:514
#define FT_READ_ULONG(var)
Definition: ftstream.h:332
#define FT_STREAM_POS()
Definition: ftstream.h:511
#define FT_GET_SHORT()
Definition: ftstream.h:299
#define FT_FRAME_ULONG(f)
Definition: ftstream.h:121
#define FT_GET_BYTE()
Definition: ftstream.h:298
#define FT_READ_BYTE(var)
Definition: ftstream.h:325
#define FT_READ_CHAR(var)
Definition: ftstream.h:326
#define FT_FRAME_EXIT()
Definition: ftstream.h:542
#define FT_STREAM_READ_FIELDS(fields, object)
Definition: ftstream.h:533
#define FT_STREAM_SKIP(distance)
Definition: ftstream.h:518
#define FT_GET_LONG()
Definition: ftstream.h:303
#define FT_FRAME_START(size)
Definition: ftstream.h:117
#define FT_FRAME_USHORT(f)
Definition: ftstream.h:123
#define FT_READ_SHORT(var)
Definition: ftstream.h:327
#define FT_FRAME_LONG(f)
Definition: ftstream.h:120
#define FT_GET_USHORT()
Definition: ftstream.h:300
typedefFT_BEGIN_HEADER struct FT_MemoryRec_ * FT_Memory
Definition: ftsystem.h:65
signed char FT_Char
Definition: fttypes.h:143
FT_BEGIN_HEADER typedef unsigned char FT_Bool
Definition: fttypes.h:108
unsigned long FT_ULong
Definition: fttypes.h:253
unsigned char FT_Byte
Definition: fttypes.h:154
signed long FT_Fixed
Definition: fttypes.h:287
int FT_Error
Definition: fttypes.h:299
signed long FT_Long
Definition: fttypes.h:242
#define FT_ERR(e)
Definition: fttypes.h:599
unsigned short FT_UShort
Definition: fttypes.h:209
char FT_String
Definition: fttypes.h:187
signed short FT_Short
Definition: fttypes.h:198
unsigned int FT_UInt
Definition: fttypes.h:231
#define FT_BOOL(x)
Definition: fttypes.h:591
size_t FT_Offset
Definition: fttypes.h:323
signed int FT_Int
Definition: fttypes.h:220
GLuint start
Definition: gl.h:1545
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLuint GLuint end
Definition: gl.h:1545
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLdouble n
Definition: glext.h:7729
GLenum GLenum GLenum GLenum GLenum scale
Definition: glext.h:9032
GLsizeiptr size
Definition: glext.h:5919
GLintptr offset
Definition: glext.h:5920
GLuint coord
Definition: glext.h:9511
const GLubyte * c
Definition: glext.h:8905
GLuint coords
Definition: glext.h:7368
GLenum GLuint GLint GLenum face
Definition: glext.h:7025
GLint limit
Definition: glext.h:10326
GLbitfield flags
Definition: glext.h:7161
const GLint * first
Definition: glext.h:5794
GLint GLenum GLboolean normalized
Definition: glext.h:6117
GLenum GLsizei dataSize
Definition: glext.h:11123
GLfloat GLfloat p
Definition: glext.h:8902
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
GLsizei const GLfloat * points
Definition: glext.h:8112
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
#define a
Definition: ke_i.h:78
#define c
Definition: ke_i.h:80
if(dx< 0)
Definition: linetemp.h:194
#define error(str)
Definition: mkdosfs.c:1605
#define for
Definition: utility.h:88
#define TT_NAME_ID_FONT_SUBFAMILY
Definition: font.c:3537
#define ALIGN_SIZE(size, alignment)
Definition: loader.c:39
static char memory[1024 *256]
Definition: process.c:116
static const WCHAR invalid[]
Definition: assoc.c:39
int k
Definition: mpi.c:3369
SFNT_Interface * SFNT_Service
Definition: sfnt.h:784
static void Exit(void)
Definition: sock.c:1330
FT_Var_Axis * axis
Definition: ftmm.h:248
FT_UInt num_designs
Definition: ftmm.h:246
FT_UInt num_namedstyles
Definition: ftmm.h:247
FT_UInt num_axis
Definition: ftmm.h:245
FT_Var_Named_Style * namedstyle
Definition: ftmm.h:249
FT_Fixed def
Definition: ftmm.h:161
FT_String * name
Definition: ftmm.h:158
FT_Fixed * coords
Definition: ftmm.h:195
FT_UInt strid
Definition: ftmm.h:196
FT_Pos x
Definition: ftimage.h:78
FT_Pos y
Definition: ftimage.h:79
TT_Get_Name_ID_Func get_name_id
Definition: sfnt.h:778
TT_Get_Name_Func get_name
Definition: sfnt.h:777
Definition: format.c:58
Definition: mxnamespace.c:45
Definition: mesh.c:5330
Definition: send.c:48
Definition: parse.h:23
SFNT_Service sfnt
Definition: ttdriver.c:209
int _tt_gxvar_dummy
Definition: ttgxvar.c:4237
#define TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY
Definition: ttnameid.h:812
#define TT_NAME_ID_PS_NAME
Definition: ttnameid.h:799
tt_size_reset(TT_Size size, FT_Bool only_height)
Definition: ttobjs.c:1294
tt_face_load_cvt(TT_Face face, FT_Stream stream)
Definition: ttpload.c:322
#define TTAG_avar
Definition: tttags.h:36
#define TTAG_fvar
Definition: tttags.h:60
#define TTAG_HVAR
Definition: tttags.h:67
#define TTAG_gvar
Definition: tttags.h:66
#define TTAG_cvar
Definition: tttags.h:51
#define TTAG_CFF2
Definition: tttags.h:46
#define TTAG_VVAR
Definition: tttags.h:108
#define TTAG_MVAR
Definition: tttags.h:86
#define TT_FACE_FLAG_VAR_HADVANCE
Definition: tttypes.h:1211
#define TT_FACE_FLAG_VAR_LSB
Definition: tttypes.h:1212
#define TT_FACE_FLAG_VAR_TSB
Definition: tttypes.h:1217
struct TT_SizeRec_ * TT_Size
Definition: tttypes.h:1796
#define TT_FACE_FLAG_VAR_VADVANCE
Definition: tttypes.h:1216
#define TT_FACE_FLAG_VAR_MVAR
Definition: tttypes.h:1222
Definition: dlist.c:348
GLvoid * data
Definition: dlist.c:359
Definition: pdh_main.c:96
wchar_t tm const _CrtWcstime_Writes_and_advances_ptr_ count wchar_t ** out
Definition: wcsftime.cpp:383
_In_ size_t cnt
Definition: wcstombs.cpp:43
ActualNumberDriverObjects * sizeof(PDRIVER_OBJECT)) PDRIVER_OBJECT *DriverObjectList