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