Update `--help' text.
[ttfautohint.git] / lib / tagpos.c
blobcc4e66ea4c0a7b57fee461d23d90442bab17fb95
1 /* tagpos.c */
3 /*
4 * Copyright (C) 2011-2014 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 = *(p++) << 8; \
23 val += *(p++)
24 #define OFFSET(val, base, p) val = base; \
25 val += *(p++) << 8; \
26 val += *(p++)
29 /* this simple `Coverage_table' structure wastes memory... */
31 typedef struct Coverage_table_
33 FT_UShort num_glyph_idxs;
34 FT_UShort* glyph_idxs;
35 } Coverage_table;
38 static FT_Error
39 TA_read_coverage_table(FT_Byte* p,
40 Coverage_table* cov,
41 SFNT* sfnt,
42 FONT* font)
44 SFNT_Table* GPOS_table = &font->tables[sfnt->GPOS_idx];
46 FT_UShort* glyph_idxs;
48 FT_UShort CoverageFormat;
49 FT_UShort i;
52 cov->num_glyph_idxs = 0;
53 cov->glyph_idxs = NULL;
55 VALUE(CoverageFormat, p);
57 if (CoverageFormat == 1)
59 FT_UShort GlyphCount;
62 VALUE(GlyphCount, p);
64 /* rough sanity checks */
65 if (GlyphCount * 2 > GPOS_table->len)
66 return FT_Err_Invalid_Table;
67 if (p - GPOS_table->buf > (ptrdiff_t)(GPOS_table->len - GlyphCount * 2))
68 return FT_Err_Invalid_Table;
70 glyph_idxs = (FT_UShort*)malloc(GlyphCount * sizeof (FT_UShort));
71 if (!glyph_idxs)
72 return FT_Err_Out_Of_Memory;
74 /* loop over p */
75 for (i = 0; i < GlyphCount; i++)
77 FT_UShort idx;
80 VALUE(idx, p);
81 glyph_idxs[i] = idx;
84 cov->num_glyph_idxs = GlyphCount;
87 else if (CoverageFormat == 2)
89 FT_UShort RangeCount;
90 FT_UShort start;
91 FT_UShort end;
92 FT_UShort count;
93 FT_Byte* p_start;
96 VALUE(RangeCount, p);
98 /* rough sanity checks */
99 if (RangeCount * 6 > GPOS_table->len)
100 return FT_Err_Invalid_Table;
101 if (p - GPOS_table->buf > (ptrdiff_t)(GPOS_table->len - RangeCount * 6))
102 return FT_Err_Invalid_Table;
104 p_start = p;
105 count = 0;
107 /* loop over p */
108 for (i = 0; i < RangeCount; i++)
110 /* collect number of glyphs */
111 VALUE(start, p);
112 VALUE(end, p);
114 if (end < start)
115 return FT_Err_Invalid_Table;
117 p += 2; /* skip StartCoverageIndex */
118 count += end - start + 1;
121 glyph_idxs = (FT_UShort*)malloc(count * sizeof (FT_UShort));
122 if (!glyph_idxs)
123 return FT_Err_Out_Of_Memory;
125 p = p_start;
126 count = 0;
128 /* loop again over p */
129 for (i = 0; i < RangeCount; i++)
131 FT_UShort j;
134 VALUE(start, p);
135 VALUE(end, p);
136 p += 2; /* skip StartCoverageIndex */
138 for (j = start; j <= end; j++)
139 glyph_idxs[count++] = j;
142 cov->num_glyph_idxs = count;
144 else
145 return FT_Err_Invalid_Table;
147 cov->glyph_idxs = glyph_idxs;
149 return TA_Err_Ok;
153 /* We add a subglyph for each composite glyph. */
154 /* Since subglyphs must contain at least one point, */
155 /* we have to adjust all AnchorPoints in GPOS AnchorTables accordingly. */
156 /* Using the `pointsums' array of the `GLYPH' structure */
157 /* it is straightforward to do that: */
158 /* Assuming that anchor point x is in the interval */
159 /* pointsums[n] <= x < pointsums[n + 1], */
160 /* the new point index is x + n. */
162 static FT_Error
163 TA_update_anchor(FT_Byte* p,
164 FT_UShort glyph_idx,
165 SFNT* sfnt,
166 FONT* font)
168 SFNT_Table* GPOS_table = &font->tables[sfnt->GPOS_idx];
169 SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx];
170 glyf_Data* data = (glyf_Data*)glyf_table->data;
171 GLYPH* glyph = &data->glyphs[glyph_idx];
173 FT_UShort AnchorFormat;
176 /* nothing to do for simple glyphs */
177 if (!glyph->num_components)
178 return TA_Err_Ok;
180 VALUE(AnchorFormat, p);
182 if (AnchorFormat == 2)
184 FT_UShort AnchorPoint;
185 FT_UShort i;
188 p += 4; /* skip XCoordinate and YCoordinate */
189 VALUE(AnchorPoint, p);
191 /* sanity check */
192 if (p > GPOS_table->buf + GPOS_table->len)
193 return FT_Err_Invalid_Table;
195 /* search point offset */
196 for (i = 0; i < glyph->num_pointsums; i++)
197 if (AnchorPoint < glyph->pointsums[i])
198 break;
200 *(p - 2) = HIGH(AnchorPoint + i);
201 *(p - 1) = LOW(AnchorPoint + i);
204 return TA_Err_Ok;
208 static FT_Error
209 TA_handle_cursive_lookup(FT_Byte* Lookup,
210 FT_Byte* p,
211 SFNT* sfnt,
212 FONT* font)
214 FT_UShort SubTableCount;
215 Coverage_table cov;
216 FT_Error error;
219 p += 2; /* skip LookupFlag */
220 VALUE(SubTableCount, p);
222 /* loop over p */
223 for (; SubTableCount > 0; SubTableCount--)
225 FT_Byte* CursivePosFormat1;
226 FT_Byte* Coverage;
227 FT_UShort EntryExitCount;
229 FT_Byte* q;
230 FT_UShort i;
233 OFFSET(CursivePosFormat1, Lookup, p);
235 q = CursivePosFormat1;
236 q += 2; /* skip PosFormat */
237 OFFSET(Coverage, CursivePosFormat1, q);
238 VALUE(EntryExitCount, q);
240 error = TA_read_coverage_table(Coverage, &cov, sfnt, font);
241 if (error)
242 return error;
244 /* sanity check */
245 if (cov.num_glyph_idxs != EntryExitCount)
247 error = FT_Err_Invalid_Table;
248 goto Fail;
251 /* loop over q */
252 for (i = 0; i < EntryExitCount; i++)
254 FT_UShort glyph_idx = cov.glyph_idxs[i];
255 FT_Byte* EntryAnchor;
256 FT_Byte* ExitAnchor;
257 FT_Error error;
260 OFFSET(EntryAnchor, CursivePosFormat1, q);
261 error = TA_update_anchor(EntryAnchor, glyph_idx, sfnt, font);
262 if (error)
263 goto Fail;
265 OFFSET(ExitAnchor, CursivePosFormat1, q);
266 error = TA_update_anchor(ExitAnchor, glyph_idx, sfnt, font);
267 if (error)
268 goto Fail;
271 free(cov.glyph_idxs);
272 cov.glyph_idxs = NULL;
275 return TA_Err_Ok;
277 Fail:
278 free(cov.glyph_idxs);
279 return error;
283 static FT_Error
284 TA_handle_markbase_lookup(FT_Byte* Lookup,
285 FT_Byte* p,
286 SFNT* sfnt,
287 FONT* font)
289 FT_UShort SubTableCount;
290 Coverage_table cov;
291 FT_Error error;
294 p += 2; /* skip LookupFlag */
295 VALUE(SubTableCount, p);
297 /* loop over p */
298 for (; SubTableCount > 0; SubTableCount--)
300 FT_Byte* MarkBasePosFormat1;
301 FT_Byte* MarkCoverage;
302 FT_Byte* BaseCoverage;
303 FT_UShort ClassCount;
304 FT_UShort MarkCount;
305 FT_Byte* MarkArray;
306 FT_UShort BaseCount;
307 FT_Byte* BaseArray;
309 FT_Byte* q;
310 FT_UShort i;
313 OFFSET(MarkBasePosFormat1, Lookup, p);
315 q = MarkBasePosFormat1;
316 q += 2; /* skip PosFormat */
317 OFFSET(MarkCoverage, MarkBasePosFormat1, q);
318 OFFSET(BaseCoverage, MarkBasePosFormat1, q);
319 VALUE(ClassCount, q);
320 OFFSET(MarkArray, MarkBasePosFormat1, q);
321 OFFSET(BaseArray, MarkBasePosFormat1, q);
323 error = TA_read_coverage_table(MarkCoverage, &cov, sfnt, font);
324 if (error)
325 return error;
327 q = MarkArray;
328 VALUE(MarkCount, q);
330 /* sanity check */
331 if (cov.num_glyph_idxs != MarkCount)
333 error = FT_Err_Invalid_Table;
334 goto Fail;
337 /* loop over q */
338 for (i = 0; i < MarkCount; i++)
340 FT_UShort glyph_idx = cov.glyph_idxs[i];
341 FT_Byte* MarkAnchor;
342 FT_Error error;
345 q += 2; /* skip Class */
346 OFFSET(MarkAnchor, MarkArray, q);
347 error = TA_update_anchor(MarkAnchor, glyph_idx, sfnt, font);
348 if (error)
349 return error;
352 free(cov.glyph_idxs);
354 error = TA_read_coverage_table(BaseCoverage, &cov, sfnt, font);
355 if (error)
356 return error;
358 q = BaseArray;
359 VALUE(BaseCount, q);
361 /* sanity check */
362 if (cov.num_glyph_idxs != BaseCount)
364 error = FT_Err_Invalid_Table;
365 goto Fail;
368 /* loop over q */
369 for (i = 0; i < BaseCount; i++)
371 FT_UShort glyph_idx = cov.glyph_idxs[i];
372 FT_UShort cc = ClassCount;
375 for (; cc > 0; cc--)
377 FT_Byte* BaseAnchor;
378 FT_Error error;
381 OFFSET(BaseAnchor, BaseArray, q);
382 error = TA_update_anchor(BaseAnchor, glyph_idx, sfnt, font);
383 if (error)
384 return error;
388 free(cov.glyph_idxs);
389 cov.glyph_idxs = NULL;
392 return TA_Err_Ok;
394 Fail:
395 free(cov.glyph_idxs);
396 return error;
400 static FT_Error
401 TA_handle_marklig_lookup(FT_Byte* Lookup,
402 FT_Byte* p,
403 SFNT* sfnt,
404 FONT* font)
406 FT_UShort SubTableCount;
407 Coverage_table cov;
408 FT_Error error;
411 p += 2; /* skip LookupFlag */
412 VALUE(SubTableCount, p);
414 /* loop over p */
415 for (; SubTableCount > 0; SubTableCount--)
417 FT_Byte* MarkLigPosFormat1;
418 FT_Byte* MarkCoverage;
419 FT_Byte* LigatureCoverage;
420 FT_UShort ClassCount;
421 FT_UShort MarkCount;
422 FT_Byte* MarkArray;
423 FT_UShort LigatureCount;
424 FT_Byte* LigatureArray;
426 FT_Byte* q;
427 FT_UShort i;
430 OFFSET(MarkLigPosFormat1, Lookup, p);
432 q = MarkLigPosFormat1;
433 q += 2; /* skip PosFormat */
434 OFFSET(MarkCoverage, MarkLigPosFormat1, q);
435 OFFSET(LigatureCoverage, MarkLigPosFormat1, q);
436 VALUE(ClassCount, q);
437 OFFSET(MarkArray, MarkLigPosFormat1, q);
438 OFFSET(LigatureArray, MarkLigPosFormat1, q);
440 error = TA_read_coverage_table(MarkCoverage, &cov, sfnt, font);
441 if (error)
442 return error;
444 q = MarkArray;
445 VALUE(MarkCount, q);
447 /* sanity check */
448 if (cov.num_glyph_idxs != MarkCount)
450 error = FT_Err_Invalid_Table;
451 goto Fail;
454 /* loop over q */
455 for (i = 0; i < MarkCount; i++)
457 FT_UShort glyph_idx = cov.glyph_idxs[i];
458 FT_Byte* MarkAnchor;
459 FT_Error error;
462 q += 2; /* skip Class */
463 OFFSET(MarkAnchor, MarkArray, q);
464 error = TA_update_anchor(MarkAnchor, glyph_idx, sfnt, font);
465 if (error)
466 return error;
469 free(cov.glyph_idxs);
471 error = TA_read_coverage_table(LigatureCoverage, &cov, sfnt, font);
472 if (error)
473 return error;
475 q = LigatureArray;
476 VALUE(LigatureCount, q);
478 /* sanity check */
479 if (cov.num_glyph_idxs != LigatureCount)
481 error = FT_Err_Invalid_Table;
482 goto Fail;
485 /* loop over q */
486 for (i = 0; i < LigatureCount; i++)
488 FT_UShort glyph_idx = cov.glyph_idxs[i];
489 FT_Byte* LigatureAttach;
490 FT_UShort ComponentCount;
491 FT_Byte* r;
494 OFFSET(LigatureAttach, LigatureArray, q);
496 r = LigatureAttach;
497 VALUE(ComponentCount, r);
499 /* loop over r */
500 for (; ComponentCount > 0; ComponentCount--)
502 FT_UShort cc = ClassCount;
505 for (; cc > 0; cc--)
507 FT_Byte* LigatureAnchor;
508 FT_Error error;
511 OFFSET(LigatureAnchor, LigatureAttach, r);
512 error = TA_update_anchor(LigatureAnchor, glyph_idx, sfnt, font);
513 if (error)
514 return error;
519 free(cov.glyph_idxs);
520 cov.glyph_idxs = NULL;
523 return TA_Err_Ok;
525 Fail:
526 free(cov.glyph_idxs);
527 return error;
531 static FT_Error
532 TA_handle_markmark_lookup(FT_Byte* Lookup,
533 FT_Byte* p,
534 SFNT* sfnt,
535 FONT* font)
537 FT_UShort SubTableCount;
538 Coverage_table cov;
539 FT_Error error;
542 p += 2; /* skip LookupFlag */
543 VALUE(SubTableCount, p);
545 /* loop over p */
546 for (; SubTableCount > 0; SubTableCount--)
548 FT_Byte* MarkMarkPosFormat1;
549 FT_Byte* Mark1Coverage;
550 FT_Byte* Mark2Coverage;
551 FT_UShort ClassCount;
552 FT_UShort Mark1Count;
553 FT_Byte* Mark1Array;
554 FT_UShort Mark2Count;
555 FT_Byte* Mark2Array;
557 FT_Byte* q;
558 FT_UShort i;
561 OFFSET(MarkMarkPosFormat1, Lookup, p);
563 q = MarkMarkPosFormat1;
564 q += 2; /* skip PosFormat */
565 OFFSET(Mark1Coverage, MarkMarkPosFormat1, q);
566 OFFSET(Mark2Coverage, MarkMarkPosFormat1, q);
567 VALUE(ClassCount, q);
568 OFFSET(Mark1Array, MarkMarkPosFormat1, q);
569 OFFSET(Mark2Array, MarkMarkPosFormat1, q);
571 error = TA_read_coverage_table(Mark1Coverage, &cov, sfnt, font);
572 if (error)
573 return error;
575 q = Mark1Array;
576 VALUE(Mark1Count, q);
578 /* sanity check */
579 if (cov.num_glyph_idxs != Mark1Count)
581 error = FT_Err_Invalid_Table;
582 goto Fail;
585 /* loop over q */
586 for (i = 0; i < Mark1Count; i++)
588 FT_UShort glyph_idx = cov.glyph_idxs[i];
589 FT_Byte* Mark1Anchor;
590 FT_Error error;
593 q += 2; /* skip Class */
594 OFFSET(Mark1Anchor, Mark1Array, q);
595 error = TA_update_anchor(Mark1Anchor, glyph_idx, sfnt, font);
596 if (error)
597 return error;
600 free(cov.glyph_idxs);
602 error = TA_read_coverage_table(Mark2Coverage, &cov, sfnt, font);
603 if (error)
604 return error;
606 q = Mark2Array;
607 VALUE(Mark2Count, q);
609 /* sanity check */
610 if (cov.num_glyph_idxs != Mark2Count)
612 error = FT_Err_Invalid_Table;
613 goto Fail;
616 /* loop over q */
617 for (i = 0; i < Mark2Count; i++)
619 FT_UShort glyph_idx = cov.glyph_idxs[i];
620 FT_UShort cc = ClassCount;
623 for (; cc > 0; cc--)
625 FT_Byte* Mark2Anchor;
626 FT_Error error;
629 OFFSET(Mark2Anchor, Mark2Array, q);
630 error = TA_update_anchor(Mark2Anchor, glyph_idx, sfnt, font);
631 if (error)
632 return error;
636 free(cov.glyph_idxs);
637 cov.glyph_idxs = NULL;
640 return TA_Err_Ok;
642 Fail:
643 free(cov.glyph_idxs);
644 return error;
648 #define Cursive 3
649 #define MarkBase 4
650 #define MarkLig 5
651 #define MarkMark 6
653 FT_Error
654 TA_sfnt_update_GPOS_table(SFNT* sfnt,
655 FONT* font)
657 SFNT_Table* GPOS_table;
658 FT_Byte* buf;
660 FT_Byte* LookupList;
661 FT_UShort LookupCount;
662 FT_Byte* p;
665 if (sfnt->GPOS_idx == MISSING)
666 return TA_Err_Ok;
668 GPOS_table = &font->tables[sfnt->GPOS_idx];
669 buf = GPOS_table->buf;
670 p = buf;
672 if (GPOS_table->processed)
673 return TA_Err_Ok;
675 p += 8; /* skip Version, ScriptList, and FeatureList */
676 OFFSET(LookupList, buf, p);
678 p = LookupList;
679 VALUE(LookupCount, p);
681 /* loop over p */
682 for (; LookupCount > 0; LookupCount--)
684 FT_Byte* Lookup;
685 FT_UShort LookupType;
686 FT_Byte* q;
687 FT_Error error = TA_Err_Ok;
690 OFFSET(Lookup, LookupList, p);
692 q = Lookup;
693 VALUE(LookupType, q);
695 if (LookupType == Cursive)
696 error = TA_handle_cursive_lookup(Lookup, q, sfnt, font);
697 else if (LookupType == MarkBase)
698 error = TA_handle_markbase_lookup(Lookup, q, sfnt, font);
699 else if (LookupType == MarkLig)
700 error = TA_handle_marklig_lookup(Lookup, q, sfnt, font);
701 else if (LookupType == MarkMark)
702 error = TA_handle_markmark_lookup(Lookup, q, sfnt, font);
704 if (error)
705 return error;
708 GPOS_table->checksum = TA_table_compute_checksum(GPOS_table->buf,
709 GPOS_table->len);
710 GPOS_table->processed = 1;
712 return TA_Err_Ok;
715 /* end of tagpos.c */