RIP, Vernon...
[ttfautohint.git] / lib / tagpos.c
bloba43080cc787a3b9a48487e0a9dea822a4950fee9
1 /* tagpos.c */
3 /*
4 * Copyright (C) 2011-2016 by Werner Lemberg.
6 * This file is part of the ttfautohint library, and may only be used,
7 * modified, and distributed under the terms given in `COPYING'. By
8 * continuing to use, modify, or distribute this file you indicate that you
9 * have read `COPYING' and understand and accept it fully.
11 * The file `COPYING' mentioned in the previous paragraph is distributed
12 * with the ttfautohint library.
16 #include "ta.h"
19 /* the code below contains many redundancies; */
20 /* it has been written for clarity */
22 #define VALUE(val, p) val = NEXT_USHORT(p)
23 #define OFFSET(val, base, p) val = base + NEXT_USHORT(p)
26 /* this simple `Coverage_table' structure wastes memory... */
28 typedef struct Coverage_table_
30 FT_UShort num_glyph_idxs;
31 FT_UShort* glyph_idxs;
32 } Coverage_table;
35 static FT_Error
36 TA_read_coverage_table(FT_Byte* p,
37 Coverage_table* cov,
38 SFNT* sfnt,
39 FONT* font)
41 SFNT_Table* GPOS_table = &font->tables[sfnt->GPOS_idx];
43 FT_UShort* glyph_idxs;
45 FT_UShort CoverageFormat;
46 FT_UShort i;
49 cov->num_glyph_idxs = 0;
50 cov->glyph_idxs = NULL;
52 VALUE(CoverageFormat, p);
54 if (CoverageFormat == 1)
56 FT_UShort GlyphCount;
59 VALUE(GlyphCount, p);
61 /* rough sanity checks */
62 if (GlyphCount * 2 > GPOS_table->len)
63 return FT_Err_Invalid_Table;
64 if (p - GPOS_table->buf > (ptrdiff_t)(GPOS_table->len - GlyphCount * 2))
65 return FT_Err_Invalid_Table;
67 glyph_idxs = (FT_UShort*)malloc(GlyphCount * sizeof (FT_UShort));
68 if (!glyph_idxs)
69 return FT_Err_Out_Of_Memory;
71 /* loop over p */
72 for (i = 0; i < GlyphCount; i++)
74 FT_UShort idx;
77 VALUE(idx, p);
78 glyph_idxs[i] = idx;
81 cov->num_glyph_idxs = GlyphCount;
84 else if (CoverageFormat == 2)
86 FT_UShort RangeCount;
87 FT_UShort start;
88 FT_UShort end;
89 FT_UShort count;
90 FT_Byte* p_start;
93 VALUE(RangeCount, p);
95 /* rough sanity checks */
96 if (RangeCount * 6 > GPOS_table->len)
97 return FT_Err_Invalid_Table;
98 if (p - GPOS_table->buf > (ptrdiff_t)(GPOS_table->len - RangeCount * 6))
99 return FT_Err_Invalid_Table;
101 p_start = p;
102 count = 0;
104 /* loop over p */
105 for (i = 0; i < RangeCount; i++)
107 /* collect number of glyphs */
108 VALUE(start, p);
109 VALUE(end, p);
111 if (end < start)
112 return FT_Err_Invalid_Table;
114 p += 2; /* skip StartCoverageIndex */
115 count += end - start + 1;
118 glyph_idxs = (FT_UShort*)malloc(count * sizeof (FT_UShort));
119 if (!glyph_idxs)
120 return FT_Err_Out_Of_Memory;
122 p = p_start;
123 count = 0;
125 /* loop again over p */
126 for (i = 0; i < RangeCount; i++)
128 FT_UShort j;
131 VALUE(start, p);
132 VALUE(end, p);
133 p += 2; /* skip StartCoverageIndex */
135 for (j = start; j <= end; j++)
136 glyph_idxs[count++] = j;
139 cov->num_glyph_idxs = count;
141 else
142 return FT_Err_Invalid_Table;
144 cov->glyph_idxs = glyph_idxs;
146 return TA_Err_Ok;
150 /* We add a subglyph for each composite glyph. */
151 /* Since subglyphs must contain at least one point, */
152 /* we have to adjust all AnchorPoints in GPOS AnchorTables accordingly. */
153 /* Using the `pointsums' array of the `GLYPH' structure */
154 /* it is straightforward to do that: */
155 /* Assuming that anchor point x is in the interval */
156 /* pointsums[n] <= x < pointsums[n + 1], */
157 /* the new point index is x + n. */
159 static FT_Error
160 TA_update_anchor(FT_Byte* p,
161 FT_UShort glyph_idx,
162 SFNT* sfnt,
163 FONT* font)
165 SFNT_Table* GPOS_table = &font->tables[sfnt->GPOS_idx];
166 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
167 glyf_Data* data = (glyf_Data*)glyf_table->data;
168 GLYPH* glyph = &data->glyphs[glyph_idx];
170 FT_UShort AnchorFormat;
173 /* nothing to do for simple glyphs */
174 if (!glyph->num_components)
175 return TA_Err_Ok;
177 VALUE(AnchorFormat, p);
179 if (AnchorFormat == 2)
181 FT_UShort AnchorPoint;
182 FT_UShort i;
185 p += 4; /* skip XCoordinate and YCoordinate */
186 VALUE(AnchorPoint, p);
188 /* sanity check */
189 if (p > GPOS_table->buf + GPOS_table->len)
190 return FT_Err_Invalid_Table;
192 /* search point offset */
193 for (i = 0; i < glyph->num_pointsums; i++)
194 if (AnchorPoint < glyph->pointsums[i])
195 break;
197 *(p - 2) = HIGH(AnchorPoint + i);
198 *(p - 1) = LOW(AnchorPoint + i);
201 return TA_Err_Ok;
205 static FT_Error
206 TA_handle_cursive_lookup(FT_Byte* Lookup,
207 FT_Byte* p,
208 SFNT* sfnt,
209 FONT* font)
211 FT_UShort SubTableCount;
212 Coverage_table cov;
213 FT_Error error;
216 p += 2; /* skip LookupFlag */
217 VALUE(SubTableCount, p);
219 /* loop over p */
220 for (; SubTableCount > 0; SubTableCount--)
222 FT_Byte* CursivePosFormat1;
223 FT_Byte* Coverage;
224 FT_UShort EntryExitCount;
226 FT_Byte* q;
227 FT_UShort i;
230 OFFSET(CursivePosFormat1, Lookup, p);
232 q = CursivePosFormat1;
233 q += 2; /* skip PosFormat */
234 OFFSET(Coverage, CursivePosFormat1, q);
235 VALUE(EntryExitCount, q);
237 error = TA_read_coverage_table(Coverage, &cov, sfnt, font);
238 if (error)
239 return error;
241 /* sanity check */
242 if (cov.num_glyph_idxs != EntryExitCount)
244 error = FT_Err_Invalid_Table;
245 goto Fail;
248 /* loop over q */
249 for (i = 0; i < EntryExitCount; i++)
251 FT_UShort glyph_idx = cov.glyph_idxs[i];
252 FT_Byte* EntryAnchor;
253 FT_Byte* ExitAnchor;
256 OFFSET(EntryAnchor, CursivePosFormat1, q);
257 error = TA_update_anchor(EntryAnchor, glyph_idx, sfnt, font);
258 if (error)
259 goto Fail;
261 OFFSET(ExitAnchor, CursivePosFormat1, q);
262 error = TA_update_anchor(ExitAnchor, glyph_idx, sfnt, font);
263 if (error)
264 goto Fail;
267 free(cov.glyph_idxs);
268 cov.glyph_idxs = NULL;
271 return TA_Err_Ok;
273 Fail:
274 free(cov.glyph_idxs);
275 return error;
279 static FT_Error
280 TA_handle_markbase_lookup(FT_Byte* Lookup,
281 FT_Byte* p,
282 SFNT* sfnt,
283 FONT* font)
285 FT_UShort SubTableCount;
286 Coverage_table cov;
287 FT_Error error;
290 p += 2; /* skip LookupFlag */
291 VALUE(SubTableCount, p);
293 /* loop over p */
294 for (; SubTableCount > 0; SubTableCount--)
296 FT_Byte* MarkBasePosFormat1;
297 FT_Byte* MarkCoverage;
298 FT_Byte* BaseCoverage;
299 FT_UShort ClassCount;
300 FT_UShort MarkCount;
301 FT_Byte* MarkArray;
302 FT_UShort BaseCount;
303 FT_Byte* BaseArray;
305 FT_Byte* q;
306 FT_UShort i;
309 OFFSET(MarkBasePosFormat1, Lookup, p);
311 q = MarkBasePosFormat1;
312 q += 2; /* skip PosFormat */
313 OFFSET(MarkCoverage, MarkBasePosFormat1, q);
314 OFFSET(BaseCoverage, MarkBasePosFormat1, q);
315 VALUE(ClassCount, q);
316 OFFSET(MarkArray, MarkBasePosFormat1, q);
317 OFFSET(BaseArray, MarkBasePosFormat1, q);
319 error = TA_read_coverage_table(MarkCoverage, &cov, sfnt, font);
320 if (error)
321 return error;
323 q = MarkArray;
324 VALUE(MarkCount, q);
326 /* sanity check */
327 if (cov.num_glyph_idxs != MarkCount)
329 error = FT_Err_Invalid_Table;
330 goto Fail;
333 /* loop over q */
334 for (i = 0; i < MarkCount; i++)
336 FT_UShort glyph_idx = cov.glyph_idxs[i];
337 FT_Byte* MarkAnchor;
340 q += 2; /* skip Class */
341 OFFSET(MarkAnchor, MarkArray, q);
342 error = TA_update_anchor(MarkAnchor, glyph_idx, sfnt, font);
343 if (error)
344 return error;
347 free(cov.glyph_idxs);
349 error = TA_read_coverage_table(BaseCoverage, &cov, sfnt, font);
350 if (error)
351 return error;
353 q = BaseArray;
354 VALUE(BaseCount, q);
356 /* sanity check */
357 if (cov.num_glyph_idxs != BaseCount)
359 error = FT_Err_Invalid_Table;
360 goto Fail;
363 /* loop over q */
364 for (i = 0; i < BaseCount; i++)
366 FT_UShort glyph_idx = cov.glyph_idxs[i];
367 FT_UShort cc = ClassCount;
370 for (; cc > 0; cc--)
372 FT_Byte* BaseAnchor;
375 OFFSET(BaseAnchor, BaseArray, q);
376 error = TA_update_anchor(BaseAnchor, glyph_idx, sfnt, font);
377 if (error)
378 return error;
382 free(cov.glyph_idxs);
383 cov.glyph_idxs = NULL;
386 return TA_Err_Ok;
388 Fail:
389 free(cov.glyph_idxs);
390 return error;
394 static FT_Error
395 TA_handle_marklig_lookup(FT_Byte* Lookup,
396 FT_Byte* p,
397 SFNT* sfnt,
398 FONT* font)
400 FT_UShort SubTableCount;
401 Coverage_table cov;
402 FT_Error error;
405 p += 2; /* skip LookupFlag */
406 VALUE(SubTableCount, p);
408 /* loop over p */
409 for (; SubTableCount > 0; SubTableCount--)
411 FT_Byte* MarkLigPosFormat1;
412 FT_Byte* MarkCoverage;
413 FT_Byte* LigatureCoverage;
414 FT_UShort ClassCount;
415 FT_UShort MarkCount;
416 FT_Byte* MarkArray;
417 FT_UShort LigatureCount;
418 FT_Byte* LigatureArray;
420 FT_Byte* q;
421 FT_UShort i;
424 OFFSET(MarkLigPosFormat1, Lookup, p);
426 q = MarkLigPosFormat1;
427 q += 2; /* skip PosFormat */
428 OFFSET(MarkCoverage, MarkLigPosFormat1, q);
429 OFFSET(LigatureCoverage, MarkLigPosFormat1, q);
430 VALUE(ClassCount, q);
431 OFFSET(MarkArray, MarkLigPosFormat1, q);
432 OFFSET(LigatureArray, MarkLigPosFormat1, q);
434 error = TA_read_coverage_table(MarkCoverage, &cov, sfnt, font);
435 if (error)
436 return error;
438 q = MarkArray;
439 VALUE(MarkCount, q);
441 /* sanity check */
442 if (cov.num_glyph_idxs != MarkCount)
444 error = FT_Err_Invalid_Table;
445 goto Fail;
448 /* loop over q */
449 for (i = 0; i < MarkCount; i++)
451 FT_UShort glyph_idx = cov.glyph_idxs[i];
452 FT_Byte* MarkAnchor;
455 q += 2; /* skip Class */
456 OFFSET(MarkAnchor, MarkArray, q);
457 error = TA_update_anchor(MarkAnchor, glyph_idx, sfnt, font);
458 if (error)
459 return error;
462 free(cov.glyph_idxs);
464 error = TA_read_coverage_table(LigatureCoverage, &cov, sfnt, font);
465 if (error)
466 return error;
468 q = LigatureArray;
469 VALUE(LigatureCount, q);
471 /* sanity check */
472 if (cov.num_glyph_idxs != LigatureCount)
474 error = FT_Err_Invalid_Table;
475 goto Fail;
478 /* loop over q */
479 for (i = 0; i < LigatureCount; i++)
481 FT_UShort glyph_idx = cov.glyph_idxs[i];
482 FT_Byte* LigatureAttach;
483 FT_UShort ComponentCount;
484 FT_Byte* r;
487 OFFSET(LigatureAttach, LigatureArray, q);
489 r = LigatureAttach;
490 VALUE(ComponentCount, r);
492 /* loop over r */
493 for (; ComponentCount > 0; ComponentCount--)
495 FT_UShort cc = ClassCount;
498 for (; cc > 0; cc--)
500 FT_Byte* LigatureAnchor;
503 OFFSET(LigatureAnchor, LigatureAttach, r);
504 error = TA_update_anchor(LigatureAnchor, glyph_idx, sfnt, font);
505 if (error)
506 return error;
511 free(cov.glyph_idxs);
512 cov.glyph_idxs = NULL;
515 return TA_Err_Ok;
517 Fail:
518 free(cov.glyph_idxs);
519 return error;
523 static FT_Error
524 TA_handle_markmark_lookup(FT_Byte* Lookup,
525 FT_Byte* p,
526 SFNT* sfnt,
527 FONT* font)
529 FT_UShort SubTableCount;
530 Coverage_table cov;
531 FT_Error error;
534 p += 2; /* skip LookupFlag */
535 VALUE(SubTableCount, p);
537 /* loop over p */
538 for (; SubTableCount > 0; SubTableCount--)
540 FT_Byte* MarkMarkPosFormat1;
541 FT_Byte* Mark1Coverage;
542 FT_Byte* Mark2Coverage;
543 FT_UShort ClassCount;
544 FT_UShort Mark1Count;
545 FT_Byte* Mark1Array;
546 FT_UShort Mark2Count;
547 FT_Byte* Mark2Array;
549 FT_Byte* q;
550 FT_UShort i;
553 OFFSET(MarkMarkPosFormat1, Lookup, p);
555 q = MarkMarkPosFormat1;
556 q += 2; /* skip PosFormat */
557 OFFSET(Mark1Coverage, MarkMarkPosFormat1, q);
558 OFFSET(Mark2Coverage, MarkMarkPosFormat1, q);
559 VALUE(ClassCount, q);
560 OFFSET(Mark1Array, MarkMarkPosFormat1, q);
561 OFFSET(Mark2Array, MarkMarkPosFormat1, q);
563 error = TA_read_coverage_table(Mark1Coverage, &cov, sfnt, font);
564 if (error)
565 return error;
567 q = Mark1Array;
568 VALUE(Mark1Count, q);
570 /* sanity check */
571 if (cov.num_glyph_idxs != Mark1Count)
573 error = FT_Err_Invalid_Table;
574 goto Fail;
577 /* loop over q */
578 for (i = 0; i < Mark1Count; i++)
580 FT_UShort glyph_idx = cov.glyph_idxs[i];
581 FT_Byte* Mark1Anchor;
584 q += 2; /* skip Class */
585 OFFSET(Mark1Anchor, Mark1Array, q);
586 error = TA_update_anchor(Mark1Anchor, glyph_idx, sfnt, font);
587 if (error)
588 return error;
591 free(cov.glyph_idxs);
593 error = TA_read_coverage_table(Mark2Coverage, &cov, sfnt, font);
594 if (error)
595 return error;
597 q = Mark2Array;
598 VALUE(Mark2Count, q);
600 /* sanity check */
601 if (cov.num_glyph_idxs != Mark2Count)
603 error = FT_Err_Invalid_Table;
604 goto Fail;
607 /* loop over q */
608 for (i = 0; i < Mark2Count; i++)
610 FT_UShort glyph_idx = cov.glyph_idxs[i];
611 FT_UShort cc = ClassCount;
614 for (; cc > 0; cc--)
616 FT_Byte* Mark2Anchor;
619 OFFSET(Mark2Anchor, Mark2Array, q);
620 error = TA_update_anchor(Mark2Anchor, glyph_idx, sfnt, font);
621 if (error)
622 return error;
626 free(cov.glyph_idxs);
627 cov.glyph_idxs = NULL;
630 return TA_Err_Ok;
632 Fail:
633 free(cov.glyph_idxs);
634 return error;
638 #define Cursive 3
639 #define MarkBase 4
640 #define MarkLig 5
641 #define MarkMark 6
643 FT_Error
644 TA_sfnt_update_GPOS_table(SFNT* sfnt,
645 FONT* font)
647 SFNT_Table* GPOS_table;
648 FT_Byte* buf;
650 FT_Byte* LookupList;
651 FT_UShort LookupCount;
652 FT_Byte* p;
655 if (sfnt->GPOS_idx == MISSING)
656 return TA_Err_Ok;
658 GPOS_table = &font->tables[sfnt->GPOS_idx];
659 buf = GPOS_table->buf;
660 p = buf;
662 if (GPOS_table->processed)
663 return TA_Err_Ok;
665 p += 8; /* skip Version, ScriptList, and FeatureList */
666 OFFSET(LookupList, buf, p);
668 p = LookupList;
669 VALUE(LookupCount, p);
671 /* loop over p */
672 for (; LookupCount > 0; LookupCount--)
674 FT_Byte* Lookup;
675 FT_UShort LookupType;
676 FT_Byte* q;
677 FT_Error error = TA_Err_Ok;
680 OFFSET(Lookup, LookupList, p);
682 q = Lookup;
683 VALUE(LookupType, q);
685 if (LookupType == Cursive)
686 error = TA_handle_cursive_lookup(Lookup, q, sfnt, font);
687 else if (LookupType == MarkBase)
688 error = TA_handle_markbase_lookup(Lookup, q, sfnt, font);
689 else if (LookupType == MarkLig)
690 error = TA_handle_marklig_lookup(Lookup, q, sfnt, font);
691 else if (LookupType == MarkMark)
692 error = TA_handle_markmark_lookup(Lookup, q, sfnt, font);
694 if (error)
695 return error;
698 GPOS_table->checksum = TA_table_compute_checksum(GPOS_table->buf,
699 GPOS_table->len);
700 GPOS_table->processed = 1;
702 return TA_Err_Ok;
705 /* end of tagpos.c */