blob: 22397181675aa7c7251deb11bde2441b21b37d79 [file] [log] [blame]
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001/*
2 * Copyright (C) 2007,2008,2009 Red Hat, Inc.
3 *
4 * This is part of HarfBuzz, an OpenType Layout engine library.
5 *
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
11 *
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16 * DAMAGE.
17 *
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23 *
24 * Red Hat Author(s): Behdad Esfahbod
25 */
26
27#ifndef HB_OT_LAYOUT_GPOS_PRIVATE_H
28#define HB_OT_LAYOUT_GPOS_PRIVATE_H
29
30#include "hb-ot-layout-gsubgpos-private.h"
31
32/* XXX */
33#include "harfbuzz-impl.h"
34
35
36/* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
37
38typedef SHORT Value;
39typedef Value ValueRecord[];
40
41#if 0
42struct ValueRecord {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040043 SHORT xPlacement; /* Horizontal adjustment for
44 * placement--in design units */
45 SHORT yPlacement; /* Vertical adjustment for
46 * placement--in design units */
47 SHORT xAdvance; /* Horizontal adjustment for
48 * advance--in design units (only used
49 * for horizontal writing) */
50 SHORT yAdvance; /* Vertical adjustment for advance--in
51 * design units (only used for vertical
52 * writing) */
53 Offset xPlaDevice; /* Offset to Device table for
54 * horizontal placement--measured from
55 * beginning of PosTable (may be NULL) */
56 Offset yPlaDevice; /* Offset to Device table for vertical
57 * placement--measured from beginning
58 * of PosTable (may be NULL) */
59 Offset xAdvDevice; /* Offset to Device table for
60 * horizontal advance--measured from
61 * beginning of PosTable (may be NULL) */
62 Offset yAdvDevice; /* Offset to Device table for vertical
63 * advance--measured from beginning of
64 * PosTable (may be NULL) */
65};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040066#endif
67
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -040068struct ValueFormat : USHORT {
69
70 enum {
71 xPlacement = 0x0001, /* Includes horizontal adjustment for placement */
72 yPlacement = 0x0002, /* Includes vertical adjustment for placement */
73 xAdvance = 0x0004, /* Includes horizontal adjustment for advance */
74 yAdvance = 0x0008, /* Includes vertical adjustment for advance */
75 xPlaDevice = 0x0010, /* Includes horizontal Device table for placement */
76 yPlaDevice = 0x0020, /* Includes vertical Device table for placement */
77 xAdvDevice = 0x0040, /* Includes horizontal Device table for advance */
78 yAdvDevice = 0x0080, /* Includes vertical Device table for advance */
79 reserved = 0xF000, /* For future use */
80 };
81
82 inline unsigned int get_len () const {
83 return _hb_popcount32 ((unsigned int) *this);
84 }
85
86 const Value* apply_value (hb_ot_layout_t *layout,
87 const char *base,
88 const Value *values,
89 HB_Position glyph_pos) const
90 {
91 unsigned int x_ppem, y_ppem;
92 hb_16dot16_t x_scale, y_scale;
93 unsigned int pixel_value;
94 unsigned int format = *this;
95
96 if (!format)
97 return values;
98
99 x_scale = layout->gpos_info.x_scale;
100 y_scale = layout->gpos_info.y_scale;
101 /* design units -> fractional pixel */
102 if (format & xPlacement)
103 glyph_pos->x_pos += x_scale * *(USHORT*)values++ / 0x10000;
104 if (format & yPlacement)
105 glyph_pos->y_pos += y_scale * *(USHORT*)values++ / 0x10000;
106 if (format & xAdvance)
107 glyph_pos->x_advance += x_scale * *(USHORT*)values++ / 0x10000;
108 if (format & yAdvance)
109 glyph_pos->y_advance += y_scale * *(USHORT*)values++ / 0x10000;
110
111 if (HB_LIKELY (!layout->gpos_info.dvi))
112 {
113 x_ppem = layout->gpos_info.x_ppem;
114 y_ppem = layout->gpos_info.y_ppem;
115 /* pixel -> fractional pixel */
116 if (format & xPlaDevice)
117 glyph_pos->x_pos += (base+*(OffsetTo<Device>*)values++).get_delta (x_ppem) << 6;
118 if (format & yPlaDevice)
119 glyph_pos->y_pos += (base+*(OffsetTo<Device>*)values++).get_delta (y_ppem) << 6;
120 if (format & xAdvDevice)
121 glyph_pos->x_advance += (base+*(OffsetTo<Device>*)values++).get_delta (x_ppem) << 6;
122 if (format & yAdvDevice)
123 glyph_pos->y_advance += (base+*(OffsetTo<Device>*)values++).get_delta (y_ppem) << 6;
124 }
125 else
126 {
127 if (format & xPlaDevice) values++;
128 if (format & yPlaDevice) values++;
129 if (format & xAdvDevice) values++;
130 if (format & yAdvDevice) values++;
131 }
132
133 return values;
134 }
135};
136ASSERT_SIZE (ValueFormat, 2);
137
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400138
139struct AnchorFormat1 {
140
141 friend struct Anchor;
142
143 private:
144 inline void get_anchor (hb_ot_layout_t *layout, hb_codepoint_t glyph_id,
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400145 hb_position_t *x, hb_position_t *y) const
146 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400147 *x = layout->gpos_info.x_scale * xCoordinate / 0x10000;
148 *y = layout->gpos_info.y_scale * yCoordinate / 0x10000;
149 }
150
151 private:
152 USHORT format; /* Format identifier--format = 1 */
153 SHORT xCoordinate; /* Horizontal value--in design units */
154 SHORT yCoordinate; /* Vertical value--in design units */
155};
156ASSERT_SIZE (AnchorFormat1, 6);
157
158struct AnchorFormat2 {
159
160 friend struct Anchor;
161
162 private:
163 inline void get_anchor (hb_ot_layout_t *layout, hb_codepoint_t glyph_id,
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400164 hb_position_t *x, hb_position_t *y) const
165 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400166 /* TODO Contour */
167 *x = layout->gpos_info.x_scale * xCoordinate / 0x10000;
168 *y = layout->gpos_info.y_scale * yCoordinate / 0x10000;
169 }
170
171 private:
172 USHORT format; /* Format identifier--format = 2 */
173 SHORT xCoordinate; /* Horizontal value--in design units */
174 SHORT yCoordinate; /* Vertical value--in design units */
175 USHORT anchorPoint; /* Index to glyph contour point */
176};
177ASSERT_SIZE (AnchorFormat2, 8);
178
179struct AnchorFormat3 {
180
181 friend struct Anchor;
182
183 private:
184 inline void get_anchor (hb_ot_layout_t *layout, hb_codepoint_t glyph_id,
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400185 hb_position_t *x, hb_position_t *y) const
186 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400187 /* TODO Device */
188 *x += layout->gpos_info.x_scale * xCoordinate / 0x10000;
189 *y += layout->gpos_info.y_scale * yCoordinate / 0x10000;
190 }
191
192 private:
193 USHORT format; /* Format identifier--format = 3 */
194 SHORT xCoordinate; /* Horizontal value--in design units */
195 SHORT yCoordinate; /* Vertical value--in design units */
196 OffsetTo<Device>
197 xDeviceTable; /* Offset to Device table for X
198 * coordinate-- from beginning of
199 * Anchor table (may be NULL) */
200 OffsetTo<Device>
201 yDeviceTable; /* Offset to Device table for Y
202 * coordinate-- from beginning of
203 * Anchor table (may be NULL) */
204};
205ASSERT_SIZE (AnchorFormat3, 10);
206
207struct Anchor {
208
209 inline void get_anchor (hb_ot_layout_t *layout, hb_codepoint_t glyph_id,
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400210 hb_position_t *x, hb_position_t *y) const
211 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400212 *x = *y = 0;
213 switch (u.format) {
214 case 1: u.format1->get_anchor (layout, glyph_id, x, y); return;
215 case 2: u.format2->get_anchor (layout, glyph_id, x, y); return;
216 case 3: u.format3->get_anchor (layout, glyph_id, x, y); return;
217 default: return;
218 }
219 }
220
221 private:
222 union {
223 USHORT format; /* Format identifier */
224 AnchorFormat1 format1[];
225 AnchorFormat2 format2[];
226 AnchorFormat3 format3[];
227 } u;
228};
229ASSERT_SIZE (Anchor, 2);
230
231
232struct MarkRecord {
233 /* TODO */
234
235 private:
236 USHORT klass; /* Class defined for this mark */
237 OffsetTo<Anchor>
238 markAnchor; /* Offset to Anchor table--from
239 * beginning of MarkArray table */
240};
241ASSERT_SIZE (MarkRecord, 4);
242
243struct MarkArray {
244 /* TODO */
245
246 private:
247 ArrayOf<MarkRecord>
248 markRecord; /* Array of MarkRecords--in Coverage order */
249};
250ASSERT_SIZE (MarkArray, 2);
251
252
253/* Lookups */
254
255struct SinglePosFormat1 {
256
257 friend struct SinglePos;
258
259 private:
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400260 inline bool apply (APPLY_ARG_DEF) const
261 {
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400262 unsigned int index = (this+coverage) (IN_CURGLYPH ());
263 if (HB_LIKELY (index == NOT_COVERED))
264 return false;
265
266 valueFormat.apply_value (layout, (const char *) this, values, CURPOSITION ());
267 return true;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400268 }
269
270 private:
271 USHORT format; /* Format identifier--format = 1 */
272 OffsetTo<Coverage>
273 coverage; /* Offset to Coverage table--from
274 * beginning of subtable */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400275 ValueFormat valueFormat; /* Defines the types of data in the
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400276 * ValueRecord */
277 ValueRecord values; /* Defines positioning
278 * value(s)--applied to all glyphs in
279 * the Coverage table */
280};
281ASSERT_SIZE (SinglePosFormat1, 6);
282
283struct SinglePosFormat2 {
284
285 friend struct SinglePos;
286
287 private:
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400288 inline bool apply (APPLY_ARG_DEF) const
289 {
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400290 unsigned int index = (this+coverage) (IN_CURGLYPH ());
291 if (HB_LIKELY (index == NOT_COVERED))
292 return false;
293
294 if (HB_LIKELY (index >= valueCount))
295 return false;
296
297 valueFormat.apply_value (layout, (const char *) this,
298 values + index * valueFormat.get_len (),
299 CURPOSITION ());
300 return true;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400301 }
302
303 private:
304 USHORT format; /* Format identifier--format = 2 */
305 OffsetTo<Coverage>
306 coverage; /* Offset to Coverage table--from
307 * beginning of subtable */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400308 ValueFormat valueFormat; /* Defines the types of data in the
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400309 * ValueRecord */
310 USHORT valueCount; /* Number of ValueRecords */
311 ValueRecord values; /* Array of ValueRecords--positioning
312 * values applied to glyphs */
313};
314ASSERT_SIZE (SinglePosFormat2, 8);
315
316struct SinglePos {
317
318 friend struct PosLookupSubTable;
319
320 private:
321
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400322 inline bool apply (APPLY_ARG_DEF) const
323 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400324 switch (u.format) {
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400325 case 1: return u.format1->apply (APPLY_ARG);
326 case 2: return u.format2->apply (APPLY_ARG);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400327 default:return false;
328 }
329 }
330
331 private:
332 union {
333 USHORT format; /* Format identifier */
334 SinglePosFormat1 format1[];
335 SinglePosFormat2 format2[];
336 } u;
337};
338ASSERT_SIZE (SinglePos, 2);
339
340
341struct PairValueRecord {
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400342
343 friend struct PairPosFormat1;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400344
345 private:
346 GlyphID secondGlyph; /* GlyphID of second glyph in the
347 * pair--first glyph is listed in the
348 * Coverage table */
349 ValueRecord values; /* Positioning data for the first glyph
350 * followed by for second glyph */
351};
352ASSERT_SIZE (PairValueRecord, 2);
353
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400354struct PairSet {
355
356 friend struct PairPosFormat1;
357
358 private:
359 inline bool apply (APPLY_ARG_DEF,
360 ValueFormat &f1, ValueFormat &f2,
361 unsigned int next_pos) const {
362
363
364 return true;
365 }
366
367 private:
368 USHORT len; /* Number of PairValueRecords */
369 /* XXX */
370 PairValueRecord
371 array[]; /* Array of PairValueRecords--ordered
372 * by GlyphID of the second glyph */
373};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400374ASSERT_SIZE (PairSet, 2);
375
376struct PairPosFormat1 {
377
378 friend struct PairPos;
379
380 private:
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400381 inline bool apply (APPLY_ARG_DEF) const
382 {
383 unsigned int end = MIN (buffer->in_length, buffer->in_pos + context_length);
384 if (HB_UNLIKELY (buffer->in_pos + 2 > end))
385 return false;
386
387 unsigned int index = (this+coverage) (IN_CURGLYPH ());
388 if (HB_LIKELY (index == NOT_COVERED))
389 return false;
390
391 unsigned int j = buffer->in_pos + 1;
392 while (!_hb_ot_layout_check_glyph_property (layout, IN_ITEM (j), lookup_flag, &property)) {
393 if (HB_UNLIKELY (j == end))
394 return false;
395 j++;
396 }
397
398 const PairSet &pair_set = this+pairSet[index];
399
400 unsigned int len1 = valueFormat1.get_len (),
401 len2 = valueFormat2.get_len ();
402 unsigned int record_len = 1 + len1 + len2;
403
404 unsigned int count = pair_set.len;
405 const PairValueRecord *record = pair_set.array;
406 for (unsigned int i = 0; i < count; i++) {
407 if (IN_GLYPH (j) == record->secondGlyph) {
408 valueFormat1.apply_value (layout, (const char *) this, record->values, CURPOSITION ());
409 valueFormat2.apply_value (layout, (const char *) this, record->values + len1, POSITION (j));
410 if (len2)
411 j++;
412 buffer->in_pos = j;
413 return true;
414 }
415 record += record_len;
416 }
417
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400418 return false;
419 }
420
421 private:
422 USHORT format; /* Format identifier--format = 1 */
423 OffsetTo<Coverage>
424 coverage; /* Offset to Coverage table--from
425 * beginning of subtable */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400426 ValueFormat valueFormat1; /* Defines the types of data in
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400427 * ValueRecord1--for the first glyph
428 * in the pair--may be zero (0) */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400429 ValueFormat valueFormat2; /* Defines the types of data in
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400430 * ValueRecord2--for the second glyph
431 * in the pair--may be zero (0) */
432 OffsetArrayOf<PairSet>
433 pairSet; /* Array of PairSet tables
434 * ordered by Coverage Index */
435};
436ASSERT_SIZE (PairPosFormat1, 10);
437
438struct PairPosFormat2 {
439
440 friend struct PairPos;
441
442 private:
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400443 inline bool apply (APPLY_ARG_DEF) const {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400444 /* TODO */
445 return false;
446 }
447
448 private:
449 USHORT format; /* Format identifier--format = 2 */
450 OffsetTo<Coverage>
451 coverage; /* Offset to Coverage table--from
452 * beginning of subtable */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400453 ValueFormat valueFormat1; /* ValueRecord definition--for the
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400454 * first glyph of the pair--may be zero
455 * (0) */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400456 ValueFormat valueFormat2; /* ValueRecord definition--for the
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400457 * second glyph of the pair--may be
458 * zero (0) */
459 OffsetTo<ClassDef>
460 classDef1; /* Offset to ClassDef table--from
461 * beginning of PairPos subtable--for
462 * the first glyph of the pair */
463 OffsetTo<ClassDef>
464 classDef2; /* Offset to ClassDef table--from
465 * beginning of PairPos subtable--for
466 * the second glyph of the pair */
467 USHORT class1Count; /* Number of classes in ClassDef1
468 * table--includes Class0 */
469 USHORT class2Count; /* Number of classes in ClassDef2
470 * table--includes Class0 */
471 ValueRecord values; /* Matrix of value pairs:
472 * class1-major, class2-minor,
473 * Each entry has value1 and value2 */
474};
475ASSERT_SIZE (PairPosFormat2, 16);
476
477struct PairPos {
478
479 friend struct PosLookupSubTable;
480
481 private:
482
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400483 inline bool apply (APPLY_ARG_DEF) const {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400484 switch (u.format) {
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400485 case 1: return u.format1->apply (APPLY_ARG);
486 case 2: return u.format2->apply (APPLY_ARG);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400487 default:return false;
488 }
489 }
490
491 private:
492 union {
493 USHORT format; /* Format identifier */
494 PairPosFormat1 format1[];
495 PairPosFormat2 format2[];
496 } u;
497};
498ASSERT_SIZE (PairPos, 2);
499
500
501struct EntryExitRecord {
502 /* TODO */
503
504 private:
505 OffsetTo<Anchor>
506 entryAnchor; /* Offset to EntryAnchor table--from
507 * beginning of CursivePos
508 * subtable--may be NULL */
509 OffsetTo<Anchor>
510 exitAnchor; /* Offset to ExitAnchor table--from
511 * beginning of CursivePos
512 * subtable--may be NULL */
513};
514ASSERT_SIZE (EntryExitRecord, 4);
515
516struct CursivePosFormat1 {
517
518 friend struct CursivePos;
519
520 private:
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400521 inline bool apply (APPLY_ARG_DEF) const {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400522 /* TODO */
523 return false;
524 }
525
526 private:
527 USHORT format; /* Format identifier--format = 1 */
528 OffsetTo<Coverage>
529 coverage; /* Offset to Coverage table--from
530 * beginning of subtable */
531 ArrayOf<EntryExitRecord>
532 entryExitRecord; /* Array of EntryExit records--in
533 * Coverage Index order */
534};
535ASSERT_SIZE (CursivePosFormat1, 6);
536
537struct CursivePos {
538
539 friend struct PosLookupSubTable;
540
541 private:
542
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400543 inline bool apply (APPLY_ARG_DEF) const {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400544 switch (u.format) {
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400545 case 1: return u.format1->apply (APPLY_ARG);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400546 default:return false;
547 }
548 }
549
550 private:
551 union {
552 USHORT format; /* Format identifier */
553 CursivePosFormat1 format1[];
554 } u;
555};
556ASSERT_SIZE (CursivePos, 2);
557
558
559struct BaseRecord {
560 /* TODO */
561
562 private:
563 Offset baseAnchor[]; /* Array of offsets (one per class)
564 * to Anchor tables--from beginning
565 * of BaseArray table--ordered by
566 * class--zero--based */
567};
568ASSERT_SIZE (BaseRecord, 0);
569
570struct BaseArray {
571 /* TODO */
572
573 private:
574 USHORT baseCount; /* Number of BaseRecords */
575 BaseRecord baseRecord[]; /* Array of BaseRecords--in order of
576 * BaseCoverage Index */
577};
578ASSERT_SIZE (BaseArray, 2);
579
580struct MarkBasePosFormat1 {
581
582 friend struct MarkBasePos;
583
584 private:
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400585 inline bool apply (APPLY_ARG_DEF) const {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400586 /* TODO */
587 return false;
588 }
589
590 private:
591 USHORT format; /* Format identifier--format = 1 */
592 Offset markCoverage; /* Offset to MarkCoverage table--from
593 * beginning of MarkBasePos subtable */
594 Offset baseCoverage; /* Offset to BaseCoverage table--from
595 * beginning of MarkBasePos subtable */
596 USHORT classCount; /* Number of classes defined for marks */
597 Offset markArray; /* Offset to MarkArray table--from
598 * beginning of MarkBasePos subtable */
599 /* XXXXXXXXXXXXX */
600 Offset baseArray; /* Offset to BaseArray table--from
601 * beginning of MarkBasePos subtable */
602};
603ASSERT_SIZE (MarkBasePosFormat1, 12);
604
605struct MarkBasePos {
606
607 friend struct PosLookupSubTable;
608
609 private:
610
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400611 inline bool apply (APPLY_ARG_DEF) const {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400612 switch (u.format) {
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400613 case 1: return u.format1->apply (APPLY_ARG);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400614 default:return false;
615 }
616 }
617
618 private:
619 union {
620 USHORT format; /* Format identifier */
621 MarkBasePosFormat1 format1[];
622 } u;
623};
624ASSERT_SIZE (MarkBasePos, 2);
625
626
627struct ComponentRecord {
628 /* TODO */
629
630 private:
631 OffsetTo<Anchor>
632 ligatureAnchor[]; /* Array of offsets (one per class)
633 * to Anchor tables--from beginning
634 * of LigatureAttach table--ordered
635 * by class--NULL if a component
636 * does not have an attachment for a
637 * class--zero--based array */
638};
639ASSERT_SIZE (ComponentRecord, 0);
640
641struct LigatureAttach {
642 /* TODO */
643
644 private:
645 /* XXXXXXXXXXXXX */
646 USHORT componentCount; /* Number of ComponentRecords in this
647 * ligature */
648 ComponentRecord
649 componentRecord[]; /* Array of ComponentRecords--ordered
650 * in writing direction */
651};
652ASSERT_SIZE (LigatureAttach, 2);
653
654struct LigatureArray {
655 /* TODO */
656
657 private:
658 OffsetArrayOf<LigatureAttach>
659 ligatureAttach; /* Array of LigatureAttach
660 * tables ordered by
661 * LigatureCoverage Index */
662};
663ASSERT_SIZE (LigatureArray, 2);
664
665struct MarkLigPosFormat1 {
666
667 friend struct MarkLigPos;
668
669 private:
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400670 inline bool apply (APPLY_ARG_DEF) const {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400671 /* TODO */
672 return false;
673 }
674
675 private:
676 USHORT format; /* Format identifier--format = 1 */
677 Offset markCoverage; /* Offset to Mark Coverage table--from
678 * beginning of MarkLigPos subtable */
679 Offset ligatureCoverage; /* Offset to Ligature Coverage
680 * table--from beginning of MarkLigPos
681 * subtable */
682 USHORT classCount; /* Number of defined mark classes */
683 Offset markArray; /* Offset to MarkArray table--from
684 * beginning of MarkLigPos subtable */
685 Offset ligatureArray; /* Offset to LigatureArray table--from
686 * beginning of MarkLigPos subtable */
687};
688ASSERT_SIZE (MarkLigPosFormat1, 12);
689
690struct MarkLigPos {
691
692 friend struct PosLookupSubTable;
693
694 private:
695
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400696 inline bool apply (APPLY_ARG_DEF) const {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400697 switch (u.format) {
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400698 case 1: return u.format1->apply (APPLY_ARG);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400699 default:return false;
700 }
701 }
702
703 private:
704 union {
705 USHORT format; /* Format identifier */
706 MarkLigPosFormat1 format1[];
707 } u;
708};
709ASSERT_SIZE (MarkLigPos, 2);
710
711
712struct Mark2Record {
713 /* TODO */
714
715 private:
716 OffsetTo<Anchor>
717 mark2Anchor[]; /* Array of offsets (one per class)
718 * to Anchor tables--from beginning of
719 * Mark2Array table--zero--based array */
720};
721
722struct Mark2Array {
723 /* TODO */
724
725 private:
726 USHORT mark2Count; /* Number of Mark2 records */
727 Mark2Record mark2Record[]; /* Array of Mark2Records--in Coverage
728 * order */
729};
730ASSERT_SIZE (Mark2Array, 2);
731
732struct MarkMarkPosFormat1 {
733
734 friend struct MarkMarkPos;
735
736 private:
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400737 inline bool apply (APPLY_ARG_DEF) const {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400738 /* TODO */
739 return false;
740 }
741
742 private:
743 USHORT format; /* Format identifier--format = 1 */
744 Offset mark1Coverage; /* Offset to Combining Mark Coverage
745 * table--from beginning of MarkMarkPos
746 * subtable */
747 Offset mark2Coverage; /* Offset to Base Mark Coverage
748 * table--from beginning of MarkMarkPos
749 * subtable */
750 USHORT offset; /* Mark1Array */
751 Offset mark2Array; /* Offset to Mark2Array table for
752 * Mark2--from beginning of MarkMarkPos
753 * subtable */
754};
755ASSERT_SIZE (MarkMarkPosFormat1, 10);
756
757struct MarkMarkPos {
758
759 friend struct PosLookupSubTable;
760
761 private:
762
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400763 inline bool apply (APPLY_ARG_DEF) const {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400764 switch (u.format) {
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400765 case 1: return u.format1->apply (APPLY_ARG);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400766 default:return false;
767 }
768 }
769
770 private:
771 union {
772 USHORT format; /* Format identifier */
773 MarkMarkPosFormat1 format1[];
774 } u;
775};
776ASSERT_SIZE (MarkMarkPos, 2);
777
778
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400779static inline bool position_lookup (APPLY_ARG_DEF, unsigned int lookup_index);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400780
781struct ContextPos : Context {
782
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400783 inline bool apply (APPLY_ARG_DEF) const {
784 return Context::apply (APPLY_ARG, position_lookup);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400785 }
786};
787ASSERT_SIZE (ContextPos, 2);
788
789struct ChainContextPos : ChainContext {
790
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400791 inline bool apply (APPLY_ARG_DEF) const {
792 return ChainContext::apply (APPLY_ARG, position_lookup);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400793 }
794};
795ASSERT_SIZE (ChainContextPos, 2);
796
797
798struct ExtensionPosFormat1 {
799
800 friend struct ExtensionPos;
801
802 private:
803 inline unsigned int get_type (void) const { return extensionLookupType; }
804 inline unsigned int get_offset (void) const { return (extensionOffset[0] << 16) + extensionOffset[1]; }
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400805 inline bool apply (APPLY_ARG_DEF) const;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400806
807 private:
808 USHORT format; /* Format identifier. Set to 1. */
809 USHORT extensionLookupType; /* Lookup type of subtable referenced
810 * by ExtensionOffset (i.e. the
811 * extension subtable). */
812 USHORT extensionOffset[2]; /* Offset to the extension subtable,
813 * of lookup type subtable.
814 * Defined as two shorts to avoid
815 * alignment requirements. */
816};
817ASSERT_SIZE (ExtensionPosFormat1, 8);
818
819struct ExtensionPos {
820
821 friend struct PosLookup;
822 friend struct PosLookupSubTable;
823
824 private:
825
826 inline unsigned int get_type (void) const {
827 switch (u.format) {
828 case 1: return u.format1->get_type ();
829 default:return 0;
830 }
831 }
832
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400833 inline bool apply (APPLY_ARG_DEF) const {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400834 switch (u.format) {
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400835 case 1: return u.format1->apply (APPLY_ARG);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400836 default:return false;
837 }
838 }
839
840 private:
841 union {
842 USHORT format; /* Format identifier */
843 ExtensionPosFormat1 format1[];
844 } u;
845};
846ASSERT_SIZE (ExtensionPos, 2);
847
848
849/*
850 * PosLookup
851 */
852
853enum {
854 GPOS_Single = 1,
855 GPOS_Pair = 2,
856 GPOS_Cursive = 3,
857 GPOS_MarkBase = 4,
858 GPOS_MarkLig = 5,
859 GPOS_MarkMark = 6,
860 GPOS_Context = 7,
861 GPOS_ChainContext = 8,
862 GPOS_Extension = 9,
863};
864
865
866struct PosLookupSubTable {
867
868 friend struct PosLookup;
869
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400870 inline bool apply (APPLY_ARG_DEF, unsigned int lookup_type) const {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400871
872 switch (lookup_type) {
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400873 case GPOS_Single: return u.single->apply (APPLY_ARG);
874 case GPOS_Pair: return u.pair->apply (APPLY_ARG);
875 case GPOS_Cursive: return u.cursive->apply (APPLY_ARG);
876 case GPOS_MarkBase: return u.markBase->apply (APPLY_ARG);
877 case GPOS_MarkLig: return u.markLig->apply (APPLY_ARG);
878 case GPOS_MarkMark: return u.markMark->apply (APPLY_ARG);
879 case GPOS_Context: return u.context->apply (APPLY_ARG);
880 case GPOS_ChainContext: return u.chainContext->apply (APPLY_ARG);
881 case GPOS_Extension: return u.extension->apply (APPLY_ARG);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400882 default:return false;
883 }
884 }
885
886 private:
887 union {
888 USHORT format;
889 SinglePos single[];
890 PairPos pair[];
891 CursivePos cursive[];
892 MarkBasePos markBase[];
893 MarkLigPos markLig[];
894 MarkMarkPos markMark[];
895 ContextPos context[];
896 ChainContextPos chainContext[];
897 ExtensionPos extension[];
898 } u;
899};
900ASSERT_SIZE (PosLookupSubTable, 2);
901
902
903struct PosLookup : Lookup {
904
905 inline const PosLookupSubTable& get_subtable (unsigned int i) const {
Behdad Esfahbodf6c8a6e2009-05-18 18:01:19 -0400906 return (const PosLookupSubTable&) Lookup::get_subtable (i);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400907 }
908
909 /* Like get_type(), but looks through extension lookups.
910 * Never returns Extension */
911 inline unsigned int get_effective_type (void) const {
912 unsigned int type = get_type ();
913
914 if (HB_UNLIKELY (type == GPOS_Extension)) {
915 unsigned int count = get_subtable_count ();
916 type = get_subtable(0).u.extension->get_type ();
917 /* The spec says all subtables should have the same type.
918 * This is specially important if one has a reverse type! */
919 for (unsigned int i = 1; i < count; i++)
920 if (get_subtable(i).u.extension->get_type () != type)
921 return 0;
922 }
923
924 return type;
925 }
926
Behdad Esfahbod2a8e6ac2009-05-18 18:21:44 -0400927 inline bool apply_subtables (hb_ot_layout_t *layout,
928 hb_buffer_t *buffer,
929 unsigned int context_length,
930 unsigned int nesting_level_left,
931 unsigned int property) const {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400932 unsigned int lookup_type = get_type ();
933 unsigned int lookup_flag = get_flag ();
934
935 for (unsigned int i = 0; i < get_subtable_count (); i++)
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400936 if (get_subtable (i).apply (APPLY_ARG, lookup_type))
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400937 return true;
938
939 return false;
940 }
941
Behdad Esfahbod2a8e6ac2009-05-18 18:21:44 -0400942 inline bool apply_once (hb_ot_layout_t *layout, hb_buffer_t *buffer) const {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400943
944 unsigned int lookup_flag = get_flag ();
945
946 unsigned int property;
947 if (!_hb_ot_layout_check_glyph_property (layout, IN_CURITEM (), lookup_flag, &property))
948 return false;
949
Behdad Esfahbod2a8e6ac2009-05-18 18:21:44 -0400950 return apply_subtables (layout, buffer, NO_CONTEXT, MAX_NESTING_LEVEL, property);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400951 }
952
Behdad Esfahbod2a8e6ac2009-05-18 18:21:44 -0400953 bool apply_string (hb_ot_layout_t *layout,
954 hb_buffer_t *buffer,
955 hb_ot_layout_feature_mask_t mask) const {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400956
957 bool ret = false;
958
959 if (HB_UNLIKELY (!buffer->in_length))
960 return false;
961
Behdad Esfahbod9c42f052009-05-18 17:43:49 -0400962 layout->gpos_info.last = 0xFFFF; /* no last valid glyph for cursive pos. */
963
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400964 buffer->in_pos = 0;
965 while (buffer->in_pos < buffer->in_length) {
966
Behdad Esfahbod9c42f052009-05-18 17:43:49 -0400967 bool done;
968 if (~IN_PROPERTIES (buffer->in_pos) & mask) {
Behdad Esfahbod2a8e6ac2009-05-18 18:21:44 -0400969 done = apply_once (layout, buffer);
Behdad Esfahbod9c42f052009-05-18 17:43:49 -0400970 ret |= done;
971 } else {
972 done = false;
973 /* Contrary to properties defined in GDEF, user-defined properties
974 will always stop a possible cursive positioning. */
975 layout->gpos_info.last = 0xFFFF;
976 }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400977
Behdad Esfahbod9c42f052009-05-18 17:43:49 -0400978 if (!done)
979 buffer->in_pos++;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400980 }
981
982 return ret;
983 }
984};
985ASSERT_SIZE (PosLookup, 6);
986
987
988/*
989 * GPOS
990 */
991
992struct GPOS : GSUBGPOS {
993 static const hb_tag_t Tag = HB_TAG ('G','P','O','S');
994
995 STATIC_DEFINE_GET_FOR_DATA (GPOS);
996 /* XXX check version here? */
997
998 inline const PosLookup& get_lookup (unsigned int i) const {
Behdad Esfahbodf6c8a6e2009-05-18 18:01:19 -0400999 return (PosLookup&)(((GSUBGPOS *)this)->get_lookup (i));
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001000 }
1001
1002 inline bool position_lookup (hb_ot_layout_t *layout,
1003 hb_buffer_t *buffer,
1004 unsigned int lookup_index,
1005 hb_ot_layout_feature_mask_t mask) const {
Behdad Esfahbod2a8e6ac2009-05-18 18:21:44 -04001006 return get_lookup (lookup_index).apply_string (layout, buffer, mask);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001007 }
1008
1009};
1010ASSERT_SIZE (GPOS, 10);
1011
1012
1013/* Out-of-class implementation for methods recursing */
1014
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -04001015inline bool ExtensionPosFormat1::apply (APPLY_ARG_DEF) const {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001016 unsigned int lookup_type = get_type ();
1017
1018 if (HB_UNLIKELY (lookup_type == GPOS_Extension))
1019 return false;
1020
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -04001021 return ((PosLookupSubTable&)*(((char *) this) + get_offset ())).apply (APPLY_ARG, lookup_type);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001022}
1023
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -04001024static inline bool position_lookup (APPLY_ARG_DEF, unsigned int lookup_index) {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001025 const GPOS &gpos = *(layout->gpos);
1026 const PosLookup &l = gpos.get_lookup (lookup_index);
1027
1028 if (HB_UNLIKELY (nesting_level_left == 0))
1029 return false;
1030 nesting_level_left--;
1031
1032 if (HB_UNLIKELY (context_length < 1))
1033 return false;
1034
Behdad Esfahbod2a8e6ac2009-05-18 18:21:44 -04001035 return l.apply_subtables (layout, buffer, context_length, nesting_level_left, property);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001036}
1037
1038
1039#endif /* HB_OT_LAYOUT_GPOS_PRIVATE_H */