blob: 292de0d35f2b733269b7bc3057274526ba8ea8b8 [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
Behdad Esfahbod5f5b24f2009-08-02 20:03:12 -040027#ifndef HB_OT_LAYOUT_GPOS_PRIVATE_HH
28#define HB_OT_LAYOUT_GPOS_PRIVATE_HH
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040029
Behdad Esfahbod5f5b24f2009-08-02 20:03:12 -040030#include "hb-ot-layout-gsubgpos-private.hh"
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040031
Behdad Esfahbodc968fc22009-05-25 04:04:24 -040032#define HB_OT_LAYOUT_GPOS_NO_LAST ((unsigned int) -1)
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040033
34/* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
35
36typedef SHORT Value;
37typedef Value ValueRecord[];
38
Behdad Esfahbodfca6a0d2009-05-21 04:49:04 -040039struct ValueFormat : USHORT
40{
41 enum
42 {
43 xPlacement = 0x0001, /* Includes horizontal adjustment for placement */
44 yPlacement = 0x0002, /* Includes vertical adjustment for placement */
45 xAdvance = 0x0004, /* Includes horizontal adjustment for advance */
46 yAdvance = 0x0008, /* Includes vertical adjustment for advance */
47 xPlaDevice = 0x0010, /* Includes horizontal Device table for placement */
48 yPlaDevice = 0x0020, /* Includes vertical Device table for placement */
49 xAdvDevice = 0x0040, /* Includes horizontal Device table for advance */
50 yAdvDevice = 0x0080, /* Includes vertical Device table for advance */
Behdad Esfahbode4b92b82009-05-26 15:38:53 -040051 ignored = 0x0F00, /* Was used in TrueType Open for MM fonts */
Behdad Esfahbodfca6a0d2009-05-21 04:49:04 -040052 reserved = 0xF000, /* For future use */
53 };
54
55 inline unsigned int get_len () const
Behdad Esfahbod79420ad2009-05-26 12:24:16 -040056 { return _hb_popcount32 ((unsigned int) *this); }
Behdad Esfahbod42b778f2009-08-04 13:30:49 -040057 inline unsigned int get_size () const
58 { return get_len () * sizeof (Value); }
Behdad Esfahbodfca6a0d2009-05-21 04:49:04 -040059
Behdad Esfahbod15164d92009-08-04 13:57:41 -040060 void apply_value (hb_ot_layout_context_t *context,
61 const char *base,
62 const Value *values,
63 hb_internal_glyph_position_t *glyph_pos) const
Behdad Esfahbodfca6a0d2009-05-21 04:49:04 -040064 {
65 unsigned int x_ppem, y_ppem;
66 hb_16dot16_t x_scale, y_scale;
Behdad Esfahbodfca6a0d2009-05-21 04:49:04 -040067 unsigned int format = *this;
68
69 if (!format)
70 return;
71
72 /* All fields are options. Only those available advance the value
73 * pointer. */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040074#if 0
75struct ValueRecord {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040076 SHORT xPlacement; /* Horizontal adjustment for
77 * placement--in design units */
78 SHORT yPlacement; /* Vertical adjustment for
79 * placement--in design units */
80 SHORT xAdvance; /* Horizontal adjustment for
81 * advance--in design units (only used
82 * for horizontal writing) */
83 SHORT yAdvance; /* Vertical adjustment for advance--in
84 * design units (only used for vertical
85 * writing) */
86 Offset xPlaDevice; /* Offset to Device table for
87 * horizontal placement--measured from
88 * beginning of PosTable (may be NULL) */
89 Offset yPlaDevice; /* Offset to Device table for vertical
90 * placement--measured from beginning
91 * of PosTable (may be NULL) */
92 Offset xAdvDevice; /* Offset to Device table for
93 * horizontal advance--measured from
94 * beginning of PosTable (may be NULL) */
95 Offset yAdvDevice; /* Offset to Device table for vertical
96 * advance--measured from beginning of
97 * PosTable (may be NULL) */
98};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040099#endif
100
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400101 x_scale = context->font->x_scale;
102 y_scale = context->font->y_scale;
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400103 /* design units -> fractional pixel */
104 if (format & xPlacement)
Behdad Esfahbod64e33f02009-05-26 18:57:56 -0400105 glyph_pos->x_pos += x_scale * *(SHORT*)values++ / 0x10000;
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400106 if (format & yPlacement)
Behdad Esfahbod64e33f02009-05-26 18:57:56 -0400107 glyph_pos->y_pos += y_scale * *(SHORT*)values++ / 0x10000;
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400108 if (format & xAdvance)
Behdad Esfahbod64e33f02009-05-26 18:57:56 -0400109 glyph_pos->x_advance += x_scale * *(SHORT*)values++ / 0x10000;
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400110 if (format & yAdvance)
Behdad Esfahbod64e33f02009-05-26 18:57:56 -0400111 glyph_pos->y_advance += y_scale * *(SHORT*)values++ / 0x10000;
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400112
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400113 x_ppem = context->font->x_ppem;
114 y_ppem = context->font->y_ppem;
Behdad Esfahbod0090dc02009-07-30 16:28:45 -0400115 /* pixel -> fractional pixel */
116 if (format & xPlaDevice) {
117 if (x_ppem)
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400118 glyph_pos->x_pos += (base+*(OffsetTo<Device>*)values++).get_delta (x_ppem) << 6;
Behdad Esfahbod0090dc02009-07-30 16:28:45 -0400119 else
120 values++;
121 }
122 if (format & yPlaDevice) {
123 if (y_ppem)
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400124 glyph_pos->y_pos += (base+*(OffsetTo<Device>*)values++).get_delta (y_ppem) << 6;
Behdad Esfahbod0090dc02009-07-30 16:28:45 -0400125 else
126 values++;
127 }
128 if (format & xAdvDevice) {
129 if (x_ppem)
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400130 glyph_pos->x_advance += (base+*(OffsetTo<Device>*)values++).get_delta (x_ppem) << 6;
Behdad Esfahbod0090dc02009-07-30 16:28:45 -0400131 else
132 values++;
133 }
134 if (format & yAdvDevice) {
135 if (y_ppem)
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400136 glyph_pos->y_advance += (base+*(OffsetTo<Device>*)values++).get_delta (y_ppem) << 6;
Behdad Esfahbod0090dc02009-07-30 16:28:45 -0400137 else
138 values++;
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400139 }
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400140 }
141};
142ASSERT_SIZE (ValueFormat, 2);
143
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400144
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400145struct AnchorFormat1
146{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400147 friend struct Anchor;
148
149 private:
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400150 inline void get_anchor (hb_ot_layout_context_t *context, hb_codepoint_t glyph_id,
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400151 hb_position_t *x, hb_position_t *y) const
152 {
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400153 *x = context->font->x_scale * xCoordinate / 0x10000;
154 *y = context->font->y_scale * yCoordinate / 0x10000;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400155 }
156
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400157 inline bool sanitize (SANITIZE_ARG_DEF) {
158 return SANITIZE_SELF ();
159 }
160
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400161 private:
162 USHORT format; /* Format identifier--format = 1 */
163 SHORT xCoordinate; /* Horizontal value--in design units */
164 SHORT yCoordinate; /* Vertical value--in design units */
165};
166ASSERT_SIZE (AnchorFormat1, 6);
167
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400168struct AnchorFormat2
169{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400170 friend struct Anchor;
171
172 private:
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400173 inline void get_anchor (hb_ot_layout_context_t *context, hb_codepoint_t glyph_id,
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400174 hb_position_t *x, hb_position_t *y) const
175 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400176 /* TODO Contour */
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400177 *x = context->font->x_scale * xCoordinate / 0x10000;
178 *y = context->font->y_scale * yCoordinate / 0x10000;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400179 }
180
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400181 inline bool sanitize (SANITIZE_ARG_DEF) {
182 return SANITIZE_SELF ();
183 }
184
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400185 private:
186 USHORT format; /* Format identifier--format = 2 */
187 SHORT xCoordinate; /* Horizontal value--in design units */
188 SHORT yCoordinate; /* Vertical value--in design units */
189 USHORT anchorPoint; /* Index to glyph contour point */
190};
191ASSERT_SIZE (AnchorFormat2, 8);
192
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400193struct AnchorFormat3
194{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400195 friend struct Anchor;
196
197 private:
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400198 inline void get_anchor (hb_ot_layout_context_t *context, hb_codepoint_t glyph_id,
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400199 hb_position_t *x, hb_position_t *y) const
200 {
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400201 *x = context->font->x_scale * xCoordinate / 0x10000;
202 *y = context->font->y_scale * yCoordinate / 0x10000;
Behdad Esfahbodc18ec2b2009-05-21 04:54:01 -0400203
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400204 if (context->font->x_ppem)
205 *x += (this+xDeviceTable).get_delta (context->font->x_ppem) << 6;
206 if (context->font->y_ppem)
207 *y += (this+yDeviceTable).get_delta (context->font->y_ppem) << 6;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400208 }
209
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400210 inline bool sanitize (SANITIZE_ARG_DEF) {
211 return SANITIZE_SELF () && SANITIZE_THIS2 (xDeviceTable, yDeviceTable);
212 }
213
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400214 private:
215 USHORT format; /* Format identifier--format = 3 */
216 SHORT xCoordinate; /* Horizontal value--in design units */
217 SHORT yCoordinate; /* Vertical value--in design units */
218 OffsetTo<Device>
219 xDeviceTable; /* Offset to Device table for X
220 * coordinate-- from beginning of
221 * Anchor table (may be NULL) */
222 OffsetTo<Device>
223 yDeviceTable; /* Offset to Device table for Y
224 * coordinate-- from beginning of
225 * Anchor table (may be NULL) */
226};
227ASSERT_SIZE (AnchorFormat3, 10);
228
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400229struct Anchor
230{
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400231 inline void get_anchor (hb_ot_layout_context_t *context, hb_codepoint_t glyph_id,
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400232 hb_position_t *x, hb_position_t *y) const
233 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400234 *x = *y = 0;
235 switch (u.format) {
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400236 case 1: u.format1->get_anchor (context, glyph_id, x, y); return;
237 case 2: u.format2->get_anchor (context, glyph_id, x, y); return;
238 case 3: u.format3->get_anchor (context, glyph_id, x, y); return;
239 default: return;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400240 }
241 }
242
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400243 inline bool sanitize (SANITIZE_ARG_DEF) {
244 if (!SANITIZE (u.format)) return false;
245 switch (u.format) {
246 case 1: return u.format1->sanitize (SANITIZE_ARG);
247 case 2: return u.format2->sanitize (SANITIZE_ARG);
248 case 3: return u.format3->sanitize (SANITIZE_ARG);
249 default:return true;
250 }
251 }
252
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400253 private:
254 union {
255 USHORT format; /* Format identifier */
256 AnchorFormat1 format1[];
257 AnchorFormat2 format2[];
258 AnchorFormat3 format3[];
259 } u;
260};
261ASSERT_SIZE (Anchor, 2);
262
263
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400264struct MarkRecord
265{
Behdad Esfahbod377bfc52009-05-21 04:58:24 -0400266 friend struct MarkArray;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400267
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400268 inline bool sanitize (SANITIZE_ARG_DEF, const void *base) {
269 return SANITIZE_SELF () && SANITIZE_BASE (markAnchor, base);
270 }
271
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400272 private:
273 USHORT klass; /* Class defined for this mark */
274 OffsetTo<Anchor>
275 markAnchor; /* Offset to Anchor table--from
276 * beginning of MarkArray table */
277};
278ASSERT_SIZE (MarkRecord, 4);
279
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400280struct MarkArray
281{
Behdad Esfahbod357ccde2009-05-21 06:32:01 -0400282 inline unsigned int get_class (unsigned int index) const { return markRecord[index].klass; }
283 inline const Anchor& get_anchor (unsigned int index) const { return this+markRecord[index].markAnchor; }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400284
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400285 inline bool sanitize (SANITIZE_ARG_DEF) {
286 return SANITIZE_THIS (markRecord);
287 }
288
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400289 private:
290 ArrayOf<MarkRecord>
291 markRecord; /* Array of MarkRecords--in Coverage order */
292};
293ASSERT_SIZE (MarkArray, 2);
294
295
296/* Lookups */
297
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400298struct SinglePosFormat1
299{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400300 friend struct SinglePos;
301
302 private:
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400303 inline bool apply (APPLY_ARG_DEF) const
304 {
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400305 unsigned int index = (this+coverage) (IN_CURGLYPH ());
306 if (HB_LIKELY (index == NOT_COVERED))
307 return false;
308
Behdad Esfahbod196598b2009-08-04 11:04:32 -0400309 valueFormat.apply_value (context, CONST_CHARP(this), values, CURPOSITION ());
Behdad Esfahbodf53d4342009-05-30 22:17:32 -0400310
311 buffer->in_pos++;
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400312 return true;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400313 }
314
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400315 inline bool sanitize (SANITIZE_ARG_DEF) {
316 return SANITIZE_SELF () && SANITIZE_THIS (coverage) &&
317 SANITIZE_MEM (values, valueFormat.get_size ());
318 }
319
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400320 private:
321 USHORT format; /* Format identifier--format = 1 */
322 OffsetTo<Coverage>
323 coverage; /* Offset to Coverage table--from
324 * beginning of subtable */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400325 ValueFormat valueFormat; /* Defines the types of data in the
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400326 * ValueRecord */
327 ValueRecord values; /* Defines positioning
328 * value(s)--applied to all glyphs in
329 * the Coverage table */
330};
331ASSERT_SIZE (SinglePosFormat1, 6);
332
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400333struct SinglePosFormat2
334{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400335 friend struct SinglePos;
336
337 private:
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400338 inline bool apply (APPLY_ARG_DEF) const
339 {
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400340 unsigned int index = (this+coverage) (IN_CURGLYPH ());
341 if (HB_LIKELY (index == NOT_COVERED))
342 return false;
343
344 if (HB_LIKELY (index >= valueCount))
345 return false;
346
Behdad Esfahbod196598b2009-08-04 11:04:32 -0400347 valueFormat.apply_value (context, CONST_CHARP(this),
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400348 values + index * valueFormat.get_len (),
349 CURPOSITION ());
Behdad Esfahbodf53d4342009-05-30 22:17:32 -0400350
351 buffer->in_pos++;
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400352 return true;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400353 }
354
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400355 inline bool sanitize (SANITIZE_ARG_DEF) {
356 return SANITIZE_SELF () && SANITIZE_THIS (coverage) &&
357 SANITIZE_MEM (values, valueFormat.get_size () * valueCount);
358 }
359
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400360 private:
361 USHORT format; /* Format identifier--format = 2 */
362 OffsetTo<Coverage>
363 coverage; /* Offset to Coverage table--from
364 * beginning of subtable */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400365 ValueFormat valueFormat; /* Defines the types of data in the
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400366 * ValueRecord */
367 USHORT valueCount; /* Number of ValueRecords */
368 ValueRecord values; /* Array of ValueRecords--positioning
369 * values applied to glyphs */
370};
371ASSERT_SIZE (SinglePosFormat2, 8);
372
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400373struct SinglePos
374{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400375 friend struct PosLookupSubTable;
376
377 private:
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400378 inline bool apply (APPLY_ARG_DEF) const
379 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400380 switch (u.format) {
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400381 case 1: return u.format1->apply (APPLY_ARG);
382 case 2: return u.format2->apply (APPLY_ARG);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400383 default:return false;
384 }
385 }
386
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400387 inline bool sanitize (SANITIZE_ARG_DEF) {
388 if (!SANITIZE (u.format)) return false;
389 switch (u.format) {
390 case 1: return u.format1->sanitize (SANITIZE_ARG);
391 case 2: return u.format2->sanitize (SANITIZE_ARG);
392 default:return true;
393 }
394 }
395
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400396 private:
397 union {
398 USHORT format; /* Format identifier */
399 SinglePosFormat1 format1[];
400 SinglePosFormat2 format2[];
401 } u;
402};
403ASSERT_SIZE (SinglePos, 2);
404
405
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400406struct PairValueRecord
407{
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400408 friend struct PairPosFormat1;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400409
410 private:
411 GlyphID secondGlyph; /* GlyphID of second glyph in the
412 * pair--first glyph is listed in the
413 * Coverage table */
414 ValueRecord values; /* Positioning data for the first glyph
415 * followed by for second glyph */
416};
417ASSERT_SIZE (PairValueRecord, 2);
418
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400419struct PairSet
420{
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400421 friend struct PairPosFormat1;
422
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400423 inline bool sanitize (SANITIZE_ARG_DEF, unsigned int format_len) {
424 if (!SANITIZE_SELF ()) return false;
425 unsigned int count = (1 + format_len) * len;
426 return SANITIZE_MEM (array, sizeof (array[0]) * count);
427 }
428
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400429 private:
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400430 USHORT len; /* Number of PairValueRecords */
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400431 PairValueRecord
432 array[]; /* Array of PairValueRecords--ordered
433 * by GlyphID of the second glyph */
434};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400435ASSERT_SIZE (PairSet, 2);
436
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400437struct PairPosFormat1
438{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400439 friend struct PairPos;
440
441 private:
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400442 inline bool apply (APPLY_ARG_DEF) const
443 {
444 unsigned int end = MIN (buffer->in_length, buffer->in_pos + context_length);
445 if (HB_UNLIKELY (buffer->in_pos + 2 > end))
446 return false;
447
448 unsigned int index = (this+coverage) (IN_CURGLYPH ());
449 if (HB_LIKELY (index == NOT_COVERED))
450 return false;
451
452 unsigned int j = buffer->in_pos + 1;
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -0400453 while (_hb_ot_layout_skip_mark (context->face, IN_INFO (j), lookup_flag, NULL))
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400454 {
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400455 if (HB_UNLIKELY (j == end))
456 return false;
457 j++;
458 }
459
460 const PairSet &pair_set = this+pairSet[index];
461
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400462 unsigned int len1 = valueFormat1.get_len ();
463 unsigned int len2 = valueFormat2.get_len ();
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400464 unsigned int record_len = 1 + len1 + len2;
465
466 unsigned int count = pair_set.len;
467 const PairValueRecord *record = pair_set.array;
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400468 for (unsigned int i = 0; i < count; i++)
469 {
470 if (IN_GLYPH (j) == record->secondGlyph)
471 {
Behdad Esfahbod196598b2009-08-04 11:04:32 -0400472 valueFormat1.apply_value (context, CONST_CHARP(this), record->values, CURPOSITION ());
473 valueFormat2.apply_value (context, CONST_CHARP(this), record->values + len1, POSITION (j));
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400474 if (len2)
475 j++;
476 buffer->in_pos = j;
477 return true;
478 }
479 record += record_len;
480 }
481
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400482 return false;
483 }
484
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400485 inline bool sanitize (SANITIZE_ARG_DEF) {
486 return SANITIZE_SELF () && SANITIZE_THIS (coverage) &&
487 pairSet.sanitize (SANITIZE_ARG, CONST_CHARP(this),
488 valueFormat1.get_len () + valueFormat2.get_len ());
489 }
490
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400491 private:
492 USHORT format; /* Format identifier--format = 1 */
493 OffsetTo<Coverage>
494 coverage; /* Offset to Coverage table--from
495 * beginning of subtable */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400496 ValueFormat valueFormat1; /* Defines the types of data in
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400497 * ValueRecord1--for the first glyph
498 * in the pair--may be zero (0) */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400499 ValueFormat valueFormat2; /* Defines the types of data in
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400500 * ValueRecord2--for the second glyph
501 * in the pair--may be zero (0) */
502 OffsetArrayOf<PairSet>
503 pairSet; /* Array of PairSet tables
504 * ordered by Coverage Index */
505};
506ASSERT_SIZE (PairPosFormat1, 10);
507
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400508struct PairPosFormat2
509{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400510 friend struct PairPos;
511
512 private:
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400513 inline bool apply (APPLY_ARG_DEF) const
514 {
515 unsigned int end = MIN (buffer->in_length, buffer->in_pos + context_length);
516 if (HB_UNLIKELY (buffer->in_pos + 2 > end))
517 return false;
518
519 unsigned int index = (this+coverage) (IN_CURGLYPH ());
520 if (HB_LIKELY (index == NOT_COVERED))
521 return false;
522
523 unsigned int j = buffer->in_pos + 1;
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -0400524 while (_hb_ot_layout_skip_mark (context->face, IN_INFO (j), lookup_flag, NULL))
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400525 {
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400526 if (HB_UNLIKELY (j == end))
527 return false;
528 j++;
529 }
530
531 unsigned int len1 = valueFormat1.get_len ();
532 unsigned int len2 = valueFormat2.get_len ();
533 unsigned int record_len = len1 + len2;
534
535 unsigned int klass1 = (this+classDef1) (IN_CURGLYPH ());
536 unsigned int klass2 = (this+classDef2) (IN_GLYPH (j));
537 if (HB_UNLIKELY (klass1 >= class1Count || klass2 >= class2Count))
538 return false;
539
540 const Value *v = values + record_len * (klass1 * class2Count + klass2);
Behdad Esfahbod196598b2009-08-04 11:04:32 -0400541 valueFormat1.apply_value (context, CONST_CHARP(this), v, CURPOSITION ());
542 valueFormat2.apply_value (context, CONST_CHARP(this), v + len1, POSITION (j));
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400543
544 if (len2)
545 j++;
546 buffer->in_pos = j;
547
548 return true;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400549 }
550
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400551 inline bool sanitize (SANITIZE_ARG_DEF) {
552 return SANITIZE_SELF () && SANITIZE_THIS (coverage) &&
553 SANITIZE_THIS2 (classDef1, classDef2) &&
554 SANITIZE_MEM (values,
555 (valueFormat1.get_size () + valueFormat2.get_size ()) *
556 class1Count * class2Count);
557 }
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400558
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400559 private:
560 USHORT format; /* Format identifier--format = 2 */
561 OffsetTo<Coverage>
562 coverage; /* Offset to Coverage table--from
563 * beginning of subtable */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400564 ValueFormat valueFormat1; /* ValueRecord definition--for the
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400565 * first glyph of the pair--may be zero
566 * (0) */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400567 ValueFormat valueFormat2; /* ValueRecord definition--for the
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400568 * second glyph of the pair--may be
569 * zero (0) */
570 OffsetTo<ClassDef>
571 classDef1; /* Offset to ClassDef table--from
572 * beginning of PairPos subtable--for
573 * the first glyph of the pair */
574 OffsetTo<ClassDef>
575 classDef2; /* Offset to ClassDef table--from
576 * beginning of PairPos subtable--for
577 * the second glyph of the pair */
578 USHORT class1Count; /* Number of classes in ClassDef1
579 * table--includes Class0 */
580 USHORT class2Count; /* Number of classes in ClassDef2
581 * table--includes Class0 */
582 ValueRecord values; /* Matrix of value pairs:
583 * class1-major, class2-minor,
584 * Each entry has value1 and value2 */
585};
586ASSERT_SIZE (PairPosFormat2, 16);
587
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400588struct PairPos
589{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400590 friend struct PosLookupSubTable;
591
592 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400593 inline bool apply (APPLY_ARG_DEF) const
594 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400595 switch (u.format) {
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400596 case 1: return u.format1->apply (APPLY_ARG);
597 case 2: return u.format2->apply (APPLY_ARG);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400598 default:return false;
599 }
600 }
601
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400602 inline bool sanitize (SANITIZE_ARG_DEF) {
603 if (!SANITIZE (u.format)) return false;
604 switch (u.format) {
605 case 1: return u.format1->sanitize (SANITIZE_ARG);
606 case 2: return u.format2->sanitize (SANITIZE_ARG);
607 default:return true;
608 }
609 }
610
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400611 private:
612 union {
613 USHORT format; /* Format identifier */
614 PairPosFormat1 format1[];
615 PairPosFormat2 format2[];
616 } u;
617};
618ASSERT_SIZE (PairPos, 2);
619
620
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400621struct EntryExitRecord
622{
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400623 inline bool sanitize (SANITIZE_ARG_DEF, const void *base) {
624 return SANITIZE_BASE2 (entryAnchor, exitAnchor, base);
625 }
626
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400627 OffsetTo<Anchor>
628 entryAnchor; /* Offset to EntryAnchor table--from
629 * beginning of CursivePos
630 * subtable--may be NULL */
631 OffsetTo<Anchor>
632 exitAnchor; /* Offset to ExitAnchor table--from
633 * beginning of CursivePos
634 * subtable--may be NULL */
635};
636ASSERT_SIZE (EntryExitRecord, 4);
637
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400638struct CursivePosFormat1
639{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400640 friend struct CursivePos;
641
642 private:
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400643 inline bool apply (APPLY_ARG_DEF) const
644 {
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400645 /* Now comes the messiest part of the whole OpenType
646 specification. At first glance, cursive connections seem easy
647 to understand, but there are pitfalls! The reason is that
648 the specs don't mention how to compute the advance values
649 resp. glyph offsets. I was told it would be an omission, to
650 be fixed in the next OpenType version... Again many thanks to
651 Andrei Burago <andreib@microsoft.com> for clarifications.
652
653 Consider the following example:
654
655 | xadv1 |
656 +---------+
657 | |
658 +-----+--+ 1 |
659 | | .| |
660 | 0+--+------+
661 | 2 |
662 | |
663 0+--------+
664 | xadv2 |
665
666 glyph1: advance width = 12
667 anchor point = (3,1)
668
669 glyph2: advance width = 11
670 anchor point = (9,4)
671
672 LSB is 1 for both glyphs (so the boxes drawn above are glyph
673 bboxes). Writing direction is R2L; `0' denotes the glyph's
674 coordinate origin.
675
676 Now the surprising part: The advance width of the *left* glyph
677 (resp. of the *bottom* glyph) will be modified, no matter
678 whether the writing direction is L2R or R2L (resp. T2B or
679 B2T)! This assymetry is caused by the fact that the glyph's
680 coordinate origin is always the lower left corner for all
681 writing directions.
682
683 Continuing the above example, we can compute the new
684 (horizontal) advance width of glyph2 as
685
686 9 - 3 = 6 ,
687
688 and the new vertical offset of glyph2 as
689
690 1 - 4 = -3 .
691
692
693 Vertical writing direction is far more complicated:
694
695 a) Assuming that we recompute the advance height of the lower glyph:
696
697 --
698 +---------+
699 -- | |
700 +-----+--+ 1 | yadv1
701 | | .| |
702 yadv2 | 0+--+------+ -- BSB1 --
703 | 2 | -- -- y_offset
704 | |
705 BSB2 -- 0+--------+ --
706 -- --
707
708 glyph1: advance height = 6
709 anchor point = (3,1)
710
711 glyph2: advance height = 7
712 anchor point = (9,4)
713
714 TSB is 1 for both glyphs; writing direction is T2B.
715
716
717 BSB1 = yadv1 - (TSB1 + ymax1)
718 BSB2 = yadv2 - (TSB2 + ymax2)
719 y_offset = y2 - y1
720
721 vertical advance width of glyph2
722 = y_offset + BSB2 - BSB1
723 = (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1))
724 = y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1)
725 = y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1
726
727
728 b) Assuming that we recompute the advance height of the upper glyph:
729
730 -- --
731 +---------+ -- TSB1
732 -- -- | |
733 TSB2 -- +-----+--+ 1 | yadv1 ymax1
734 | | .| |
735 yadv2 | 0+--+------+ -- --
736 ymax2 | 2 | -- y_offset
737 | |
738 -- 0+--------+ --
739 --
740
741 glyph1: advance height = 6
742 anchor point = (3,1)
743
744 glyph2: advance height = 7
745 anchor point = (9,4)
746
747 TSB is 1 for both glyphs; writing direction is T2B.
748
749 y_offset = y2 - y1
750
751 vertical advance width of glyph2
752 = TSB1 + ymax1 + y_offset - (TSB2 + ymax2)
753 = TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2
754
755
756 Comparing a) with b) shows that b) is easier to compute. I'll wait
757 for a reply from Andrei to see what should really be implemented...
758
759 Since horizontal advance widths or vertical advance heights
760 can be used alone but not together, no ambiguity occurs. */
761
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400762 struct hb_ot_layout_context_t::info_t::gpos_t *gpi = &context->info.gpos;
Behdad Esfahbod0f7e6b22009-05-20 04:16:35 -0400763 hb_codepoint_t last_pos = gpi->last;
Behdad Esfahbodc968fc22009-05-25 04:04:24 -0400764 gpi->last = HB_OT_LAYOUT_GPOS_NO_LAST;
Behdad Esfahbod0f7e6b22009-05-20 04:16:35 -0400765
766 /* We don't handle mark glyphs here. */
767 if (property == HB_OT_LAYOUT_GLYPH_CLASS_MARK)
768 return false;
769
770 unsigned int index = (this+coverage) (IN_CURGLYPH ());
771 if (HB_LIKELY (index == NOT_COVERED))
772 return false;
773
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400774 const EntryExitRecord &record = entryExitRecord[index];
775
Behdad Esfahbodc968fc22009-05-25 04:04:24 -0400776 if (last_pos == HB_OT_LAYOUT_GPOS_NO_LAST || !record.entryAnchor)
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400777 goto end;
778
Behdad Esfahbod6c8108c2009-05-26 22:26:08 -0400779 hb_position_t entry_x, entry_y;
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400780 (this+record.entryAnchor).get_anchor (context, IN_CURGLYPH (), &entry_x, &entry_y);
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400781
Behdad Esfahbodcc83ae12009-05-27 00:17:37 -0400782 /* TODO vertical */
783
Behdad Esfahbod02a37062009-07-29 18:41:25 -0400784 if (buffer->direction == HB_DIRECTION_RTL)
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400785 {
786 POSITION (buffer->in_pos)->x_advance = entry_x - gpi->anchor_x;
787 POSITION (buffer->in_pos)->new_advance = TRUE;
788 }
789 else
790 {
Behdad Esfahbod0f7e6b22009-05-20 04:16:35 -0400791 POSITION (last_pos)->x_advance = gpi->anchor_x - entry_x;
792 POSITION (last_pos)->new_advance = TRUE;
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400793 }
794
795 if (lookup_flag & LookupFlag::RightToLeft)
796 {
Behdad Esfahbod0f7e6b22009-05-20 04:16:35 -0400797 POSITION (last_pos)->cursive_chain = last_pos - buffer->in_pos;
798 POSITION (last_pos)->y_pos = entry_y - gpi->anchor_y;
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400799 }
800 else
801 {
Behdad Esfahbod0f7e6b22009-05-20 04:16:35 -0400802 POSITION (buffer->in_pos)->cursive_chain = buffer->in_pos - last_pos;
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400803 POSITION (buffer->in_pos)->y_pos = gpi->anchor_y - entry_y;
804 }
805
806 end:
807 if (record.exitAnchor)
Behdad Esfahbod0f7e6b22009-05-20 04:16:35 -0400808 {
809 gpi->last = buffer->in_pos;
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400810 (this+record.exitAnchor).get_anchor (context, IN_CURGLYPH (), &gpi->anchor_x, &gpi->anchor_y);
Behdad Esfahbod0f7e6b22009-05-20 04:16:35 -0400811 }
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400812
813 buffer->in_pos++;
814 return true;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400815 }
816
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400817 inline bool sanitize (SANITIZE_ARG_DEF) {
818 return SANITIZE_THIS2 (coverage, entryExitRecord);
819 }
820
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400821 private:
822 USHORT format; /* Format identifier--format = 1 */
823 OffsetTo<Coverage>
824 coverage; /* Offset to Coverage table--from
825 * beginning of subtable */
826 ArrayOf<EntryExitRecord>
827 entryExitRecord; /* Array of EntryExit records--in
828 * Coverage Index order */
829};
830ASSERT_SIZE (CursivePosFormat1, 6);
831
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400832struct CursivePos
833{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400834 friend struct PosLookupSubTable;
835
836 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400837 inline bool apply (APPLY_ARG_DEF) const
838 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400839 switch (u.format) {
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400840 case 1: return u.format1->apply (APPLY_ARG);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400841 default:return false;
842 }
843 }
844
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400845 inline bool sanitize (SANITIZE_ARG_DEF) {
846 if (!SANITIZE (u.format)) return false;
847 switch (u.format) {
848 case 1: return u.format1->sanitize (SANITIZE_ARG);
849 default:return true;
850 }
851 }
852
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400853 private:
854 union {
855 USHORT format; /* Format identifier */
856 CursivePosFormat1 format1[];
857 } u;
858};
859ASSERT_SIZE (CursivePos, 2);
860
861
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400862struct BaseArray
863{
Behdad Esfahbodfb3b5cc2009-05-21 04:47:05 -0400864 friend struct MarkBasePosFormat1;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400865
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400866 inline bool sanitize (SANITIZE_ARG_DEF, unsigned int cols) {
867 if (!SANITIZE_SELF ()) return false;
868 unsigned int count = cols * len;
869 if (!SANITIZE_MEM (matrix, sizeof (matrix[0]) * count)) return false;
870 for (unsigned int i = 0; i < count; i++)
871 if (!SANITIZE_THIS (matrix[i])) return false;
872 return true;
873 }
874
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400875 private:
Behdad Esfahbodfb3b5cc2009-05-21 04:47:05 -0400876 USHORT len; /* Number of rows */
877 OffsetTo<Anchor>
878 matrix[]; /* Matrix of offsets to Anchor tables--
879 * from beginning of BaseArray table--
880 * base-major--in order of
881 * BaseCoverage Index--, mark-minor--
882 * ordered by class--zero-based. */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400883};
884ASSERT_SIZE (BaseArray, 2);
885
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400886struct MarkBasePosFormat1
887{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400888 friend struct MarkBasePos;
889
890 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400891 inline bool apply (APPLY_ARG_DEF) const
892 {
Behdad Esfahbod357ccde2009-05-21 06:32:01 -0400893 unsigned int mark_index = (this+markCoverage) (IN_CURGLYPH ());
894 if (HB_LIKELY (mark_index == NOT_COVERED))
895 return false;
896
897 /* now we search backwards for a non-mark glyph */
Behdad Esfahbod357ccde2009-05-21 06:32:01 -0400898 unsigned int count = buffer->in_pos;
899 unsigned int i = 1, j = count - 1;
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -0400900 while (_hb_ot_layout_skip_mark (context->face, IN_INFO (j), LookupFlag::IgnoreMarks, &property))
Behdad Esfahbod357ccde2009-05-21 06:32:01 -0400901 {
Behdad Esfahbod80ea5bd2009-05-26 17:58:37 -0400902 if (HB_UNLIKELY (i == count))
903 return false;
Behdad Esfahbod357ccde2009-05-21 06:32:01 -0400904 i++, j--;
905 }
Behdad Esfahbodfe550f42009-05-21 08:27:07 -0400906#if 0
Behdad Esfahbod80ea5bd2009-05-26 17:58:37 -0400907 /* The following assertion is too strong. */
908 if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH))
Behdad Esfahbod357ccde2009-05-21 06:32:01 -0400909 return false;
Behdad Esfahbodfe550f42009-05-21 08:27:07 -0400910#endif
Behdad Esfahbod357ccde2009-05-21 06:32:01 -0400911
912 unsigned int base_index = (this+baseCoverage) (IN_GLYPH (j));
Behdad Esfahbodfe550f42009-05-21 08:27:07 -0400913 if (base_index == NOT_COVERED)
Behdad Esfahbod357ccde2009-05-21 06:32:01 -0400914 return false;
915
916 const MarkArray& mark_array = this+markArray;
917 const BaseArray& base_array = this+baseArray;
918
919 unsigned int mark_class = mark_array.get_class (mark_index);
920 const Anchor& mark_anchor = mark_array.get_anchor (mark_index);
921
922 if (HB_UNLIKELY (mark_class >= classCount || base_index >= base_array.len))
923 return false;
924
925 hb_position_t mark_x, mark_y, base_x, base_y;
926
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400927 mark_anchor.get_anchor (context, IN_CURGLYPH (), &mark_x, &mark_y);
Behdad Esfahbod357ccde2009-05-21 06:32:01 -0400928 unsigned int index = base_index * classCount + mark_class;
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400929 (&base_array+base_array.matrix[index]).get_anchor (context, IN_GLYPH (j), &base_x, &base_y);
Behdad Esfahbod357ccde2009-05-21 06:32:01 -0400930
Behdad Esfahbodf1322e52009-08-01 22:53:04 -0400931 hb_internal_glyph_position_t *o = POSITION (buffer->in_pos);
Behdad Esfahbod357ccde2009-05-21 06:32:01 -0400932 o->x_pos = base_x - mark_x;
933 o->y_pos = base_y - mark_y;
934 o->x_advance = 0;
935 o->y_advance = 0;
936 o->back = i;
937
938 buffer->in_pos++;
939 return true;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400940 }
941
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400942 inline bool sanitize (SANITIZE_ARG_DEF) {
943 return SANITIZE_SELF () && SANITIZE_THIS2 (markCoverage, baseCoverage) &&
944 SANITIZE_THIS (markArray) && baseArray.sanitize (SANITIZE_ARG, CONST_CHARP(this), classCount);
945 }
946
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400947 private:
948 USHORT format; /* Format identifier--format = 1 */
Behdad Esfahbodfb3b5cc2009-05-21 04:47:05 -0400949 OffsetTo<Coverage>
950 markCoverage; /* Offset to MarkCoverage table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400951 * beginning of MarkBasePos subtable */
Behdad Esfahbodfb3b5cc2009-05-21 04:47:05 -0400952 OffsetTo<Coverage>
953 baseCoverage; /* Offset to BaseCoverage table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400954 * beginning of MarkBasePos subtable */
955 USHORT classCount; /* Number of classes defined for marks */
Behdad Esfahbodfb3b5cc2009-05-21 04:47:05 -0400956 OffsetTo<MarkArray>
957 markArray; /* Offset to MarkArray table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400958 * beginning of MarkBasePos subtable */
Behdad Esfahbodfb3b5cc2009-05-21 04:47:05 -0400959 OffsetTo<BaseArray>
960 baseArray; /* Offset to BaseArray table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400961 * beginning of MarkBasePos subtable */
962};
963ASSERT_SIZE (MarkBasePosFormat1, 12);
964
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400965struct MarkBasePos
966{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400967 friend struct PosLookupSubTable;
968
969 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400970 inline bool apply (APPLY_ARG_DEF) const
971 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400972 switch (u.format) {
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400973 case 1: return u.format1->apply (APPLY_ARG);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400974 default:return false;
975 }
976 }
977
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400978 inline bool sanitize (SANITIZE_ARG_DEF) {
979 if (!SANITIZE (u.format)) return false;
980 switch (u.format) {
981 case 1: return u.format1->sanitize (SANITIZE_ARG);
982 default:return true;
983 }
984 }
985
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400986 private:
987 union {
988 USHORT format; /* Format identifier */
989 MarkBasePosFormat1 format1[];
990 } u;
991};
992ASSERT_SIZE (MarkBasePos, 2);
993
994
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400995struct LigatureAttach
996{
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -0400997 friend struct MarkLigPosFormat1;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400998
999 private:
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001000 USHORT len; /* Number of ComponentRecords in this
1001 * ligature, ie. number of rows */
1002 OffsetTo<Anchor>
1003 matrix[]; /* Matrix of offsets to Anchor tables--
1004 * from beginning of LigatureAttach table--
1005 * component-major--in order of
1006 * writing direction--, mark-minor--
1007 * ordered by class--zero-based. */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001008};
1009ASSERT_SIZE (LigatureAttach, 2);
1010
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001011typedef OffsetArrayOf<LigatureAttach> LigatureArray;
1012 /* Array of LigatureAttach
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001013 * tables ordered by
1014 * LigatureCoverage Index */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001015ASSERT_SIZE (LigatureArray, 2);
1016
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001017struct MarkLigPosFormat1
1018{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001019 friend struct MarkLigPos;
1020
1021 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001022 inline bool apply (APPLY_ARG_DEF) const
1023 {
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001024 unsigned int mark_index = (this+markCoverage) (IN_CURGLYPH ());
1025 if (HB_LIKELY (mark_index == NOT_COVERED))
1026 return false;
1027
1028 /* now we search backwards for a non-mark glyph */
1029 unsigned int count = buffer->in_pos;
1030 unsigned int i = 1, j = count - 1;
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -04001031 while (_hb_ot_layout_skip_mark (context->face, IN_INFO (j), LookupFlag::IgnoreMarks, &property))
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001032 {
Behdad Esfahbod80ea5bd2009-05-26 17:58:37 -04001033 if (HB_UNLIKELY (i == count))
1034 return false;
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001035 i++, j--;
1036 }
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001037#if 0
Behdad Esfahbod80ea5bd2009-05-26 17:58:37 -04001038 /* The following assertion is too strong. */
1039 if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE))
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001040 return false;
1041#endif
1042
1043 unsigned int lig_index = (this+ligatureCoverage) (IN_GLYPH (j));
1044 if (lig_index == NOT_COVERED)
1045 return false;
1046
1047 const MarkArray& mark_array = this+markArray;
1048 const LigatureArray& lig_array = this+ligatureArray;
1049
1050 unsigned int mark_class = mark_array.get_class (mark_index);
1051 const Anchor& mark_anchor = mark_array.get_anchor (mark_index);
1052
1053 if (HB_UNLIKELY (mark_class >= classCount || lig_index >= lig_array.len))
1054 return false;
1055
1056 const LigatureAttach& lig_attach = &lig_array+lig_array[lig_index];
1057 count = lig_attach.len;
1058 if (HB_UNLIKELY (!count))
1059 return false;
1060
1061 unsigned int comp_index;
1062 /* We must now check whether the ligature ID of the current mark glyph
1063 * is identical to the ligature ID of the found ligature. If yes, we
1064 * can directly use the component index. If not, we attach the mark
1065 * glyph to the last component of the ligature. */
1066 if (IN_LIGID (j) == IN_LIGID (buffer->in_pos))
1067 {
1068 comp_index = IN_COMPONENT (buffer->in_pos);
1069 if (comp_index >= count)
1070 comp_index = count - 1;
1071 }
1072 else
1073 comp_index = count - 1;
1074
1075 hb_position_t mark_x, mark_y, lig_x, lig_y;
1076
Behdad Esfahbod0ead4812009-08-02 17:41:36 -04001077 mark_anchor.get_anchor (context, IN_CURGLYPH (), &mark_x, &mark_y);
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001078 unsigned int index = comp_index * classCount + mark_class;
Behdad Esfahbod0ead4812009-08-02 17:41:36 -04001079 (&lig_attach+lig_attach.matrix[index]).get_anchor (context, IN_GLYPH (j), &lig_x, &lig_y);
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001080
Behdad Esfahbodf1322e52009-08-01 22:53:04 -04001081 hb_internal_glyph_position_t *o = POSITION (buffer->in_pos);
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001082 o->x_pos = lig_x - mark_x;
1083 o->y_pos = lig_y - mark_y;
1084 o->x_advance = 0;
1085 o->y_advance = 0;
1086 o->back = i;
1087
1088 buffer->in_pos++;
1089 return true;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001090 }
1091
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001092 inline bool sanitize (SANITIZE_ARG_DEF) {
1093 return SANITIZE_SELF () &&
1094 SANITIZE_THIS2 (markCoverage, ligatureCoverage) &&
1095 SANITIZE_THIS2 (markArray, ligatureArray);
1096 }
1097
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001098 private:
1099 USHORT format; /* Format identifier--format = 1 */
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001100 OffsetTo<Coverage>
1101 markCoverage; /* Offset to Mark Coverage table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001102 * beginning of MarkLigPos subtable */
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001103 OffsetTo<Coverage>
1104 ligatureCoverage; /* Offset to Ligature Coverage
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001105 * table--from beginning of MarkLigPos
1106 * subtable */
1107 USHORT classCount; /* Number of defined mark classes */
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001108 OffsetTo<MarkArray>
1109 markArray; /* Offset to MarkArray table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001110 * beginning of MarkLigPos subtable */
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001111 OffsetTo<LigatureArray>
1112 ligatureArray; /* Offset to LigatureArray table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001113 * beginning of MarkLigPos subtable */
1114};
1115ASSERT_SIZE (MarkLigPosFormat1, 12);
1116
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001117struct MarkLigPos
1118{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001119 friend struct PosLookupSubTable;
1120
1121 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001122 inline bool apply (APPLY_ARG_DEF) const
1123 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001124 switch (u.format) {
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -04001125 case 1: return u.format1->apply (APPLY_ARG);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001126 default:return false;
1127 }
1128 }
1129
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001130 inline bool sanitize (SANITIZE_ARG_DEF) {
1131 if (!SANITIZE (u.format)) return false;
1132 switch (u.format) {
1133 case 1: return u.format1->sanitize (SANITIZE_ARG);
1134 default:return true;
1135 }
1136 }
1137
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001138 private:
1139 union {
1140 USHORT format; /* Format identifier */
1141 MarkLigPosFormat1 format1[];
1142 } u;
1143};
1144ASSERT_SIZE (MarkLigPos, 2);
1145
1146
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001147struct Mark2Array
1148{
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001149 friend struct MarkMarkPosFormat1;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001150
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001151 inline bool sanitize (SANITIZE_ARG_DEF, unsigned int cols) {
1152 if (!SANITIZE_SELF ()) return false;
1153 unsigned int count = cols * len;
1154 if (!SANITIZE_MEM (matrix, sizeof (matrix[0]) * count)) return false;
1155 for (unsigned int i = 0; i < count; i++)
1156 if (!SANITIZE_THIS (matrix[i])) return false;
1157 return true;
1158 }
1159
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001160 private:
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001161 USHORT len; /* Number of rows */
1162 OffsetTo<Anchor>
1163 matrix[]; /* Matrix of offsets to Anchor tables--
1164 * from beginning of Mark2Array table--
1165 * mark2-major--in order of
1166 * Mark2Coverage Index--, mark1-minor--
1167 * ordered by class--zero-based. */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001168};
1169ASSERT_SIZE (Mark2Array, 2);
1170
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001171struct MarkMarkPosFormat1
1172{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001173 friend struct MarkMarkPos;
1174
1175 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001176 inline bool apply (APPLY_ARG_DEF) const
1177 {
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001178 unsigned int mark1_index = (this+mark1Coverage) (IN_CURGLYPH ());
1179 if (HB_LIKELY (mark1_index == NOT_COVERED))
1180 return false;
1181
1182 /* now we search backwards for a suitable mark glyph until a non-mark glyph */
1183 unsigned int count = buffer->in_pos;
1184 unsigned int i = 1, j = count - 1;
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -04001185 while (_hb_ot_layout_skip_mark (context->face, IN_INFO (j), lookup_flag, &property))
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001186 {
Behdad Esfahbod80ea5bd2009-05-26 17:58:37 -04001187 if (HB_UNLIKELY (i == count))
1188 return false;
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001189 i++, j--;
1190 }
Behdad Esfahbod80ea5bd2009-05-26 17:58:37 -04001191 if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
1192 return false;
1193
1194 /* Two marks match only if they belong to the same base, or same component
1195 * of the same ligature. */
1196 if (IN_LIGID (j) != IN_LIGID (buffer->in_pos) ||
1197 IN_COMPONENT (j) != IN_COMPONENT (buffer->in_pos))
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001198 return false;
1199
1200 unsigned int mark2_index = (this+mark2Coverage) (IN_GLYPH (j));
1201 if (mark2_index == NOT_COVERED)
1202 return false;
1203
1204 const MarkArray& mark1_array = this+mark1Array;
1205 const Mark2Array& mark2_array = this+mark2Array;
1206
1207 unsigned int mark1_class = mark1_array.get_class (mark1_index);
1208 const Anchor& mark1_anchor = mark1_array.get_anchor (mark1_index);
1209
1210 if (HB_UNLIKELY (mark1_class >= classCount || mark2_index >= mark2_array.len))
1211 return false;
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001212
1213 hb_position_t mark1_x, mark1_y, mark2_x, mark2_y;
1214
Behdad Esfahbod0ead4812009-08-02 17:41:36 -04001215 mark1_anchor.get_anchor (context, IN_CURGLYPH (), &mark1_x, &mark1_y);
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001216 unsigned int index = mark2_index * classCount + mark1_class;
Behdad Esfahbod0ead4812009-08-02 17:41:36 -04001217 (&mark2_array+mark2_array.matrix[index]).get_anchor (context, IN_GLYPH (j), &mark2_x, &mark2_y);
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001218
Behdad Esfahbodf1322e52009-08-01 22:53:04 -04001219 hb_internal_glyph_position_t *o = POSITION (buffer->in_pos);
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001220 o->x_pos = mark2_x - mark1_x;
1221 o->y_pos = mark2_y - mark1_y;
1222 o->x_advance = 0;
1223 o->y_advance = 0;
1224 o->back = i;
1225
1226 buffer->in_pos++;
1227 return true;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001228 }
1229
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001230 inline bool sanitize (SANITIZE_ARG_DEF) {
1231 return SANITIZE_SELF () && SANITIZE_THIS2 (mark1Coverage, mark2Coverage) &&
1232 SANITIZE_THIS (mark1Array) && mark2Array.sanitize (SANITIZE_ARG, CONST_CHARP(this), classCount);
1233 }
1234
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001235 private:
1236 USHORT format; /* Format identifier--format = 1 */
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001237 OffsetTo<Coverage>
1238 mark1Coverage; /* Offset to Combining Mark1 Coverage
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001239 * table--from beginning of MarkMarkPos
1240 * subtable */
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001241 OffsetTo<Coverage>
1242 mark2Coverage; /* Offset to Combining Mark2 Coverage
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001243 * table--from beginning of MarkMarkPos
1244 * subtable */
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001245 USHORT classCount; /* Number of defined mark classes */
1246 OffsetTo<MarkArray>
1247 mark1Array; /* Offset to Mark1Array table--from
1248 * beginning of MarkMarkPos subtable */
1249 OffsetTo<Mark2Array>
1250 mark2Array; /* Offset to Mark2Array table--from
1251 * beginning of MarkMarkPos subtable */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001252};
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001253ASSERT_SIZE (MarkMarkPosFormat1, 12);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001254
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001255struct MarkMarkPos
1256{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001257 friend struct PosLookupSubTable;
1258
1259 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001260 inline bool apply (APPLY_ARG_DEF) const
1261 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001262 switch (u.format) {
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -04001263 case 1: return u.format1->apply (APPLY_ARG);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001264 default:return false;
1265 }
1266 }
1267
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001268 inline bool sanitize (SANITIZE_ARG_DEF) {
1269 if (!SANITIZE (u.format)) return false;
1270 switch (u.format) {
1271 case 1: return u.format1->sanitize (SANITIZE_ARG);
1272 default:return true;
1273 }
1274 }
1275
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001276 private:
1277 union {
1278 USHORT format; /* Format identifier */
1279 MarkMarkPosFormat1 format1[];
1280 } u;
1281};
1282ASSERT_SIZE (MarkMarkPos, 2);
1283
1284
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -04001285static inline bool position_lookup (APPLY_ARG_DEF, unsigned int lookup_index);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001286
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001287struct ContextPos : Context
1288{
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04001289 friend struct PosLookupSubTable;
1290
1291 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001292 inline bool apply (APPLY_ARG_DEF) const
Behdad Esfahbod79420ad2009-05-26 12:24:16 -04001293 { return Context::apply (APPLY_ARG, position_lookup); }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001294};
1295ASSERT_SIZE (ContextPos, 2);
1296
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001297struct ChainContextPos : ChainContext
1298{
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04001299 friend struct PosLookupSubTable;
1300
1301 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001302 inline bool apply (APPLY_ARG_DEF) const
Behdad Esfahbod79420ad2009-05-26 12:24:16 -04001303 { return ChainContext::apply (APPLY_ARG, position_lookup); }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001304};
1305ASSERT_SIZE (ChainContextPos, 2);
1306
1307
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04001308struct ExtensionPos : Extension
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001309{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001310 friend struct PosLookupSubTable;
1311
1312 private:
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001313 inline const struct PosLookupSubTable& get_subtable (void) const
1314 { return CONST_CAST (PosLookupSubTable, Extension::get_subtable (), 0); }
1315
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04001316 inline bool apply (APPLY_ARG_DEF) const;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001317
1318 inline bool sanitize (SANITIZE_ARG_DEF);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001319};
1320ASSERT_SIZE (ExtensionPos, 2);
1321
1322
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04001323
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001324/*
1325 * PosLookup
1326 */
1327
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001328
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001329struct PosLookupSubTable
1330{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001331 friend struct PosLookup;
1332
Behdad Esfahbodff05d252009-05-20 03:53:00 -04001333 enum {
1334 Single = 1,
1335 Pair = 2,
1336 Cursive = 3,
1337 MarkBase = 4,
1338 MarkLig = 5,
1339 MarkMark = 6,
1340 Context = 7,
1341 ChainContext = 8,
1342 Extension = 9,
1343 };
1344
Behdad Esfahbod923923f2009-05-22 17:58:09 -04001345 bool apply (APPLY_ARG_DEF, unsigned int lookup_type) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001346 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001347 switch (lookup_type) {
Behdad Esfahbodff05d252009-05-20 03:53:00 -04001348 case Single: return u.single->apply (APPLY_ARG);
1349 case Pair: return u.pair->apply (APPLY_ARG);
1350 case Cursive: return u.cursive->apply (APPLY_ARG);
1351 case MarkBase: return u.markBase->apply (APPLY_ARG);
1352 case MarkLig: return u.markLig->apply (APPLY_ARG);
1353 case MarkMark: return u.markMark->apply (APPLY_ARG);
1354 case Context: return u.context->apply (APPLY_ARG);
1355 case ChainContext: return u.chainContext->apply (APPLY_ARG);
1356 case Extension: return u.extension->apply (APPLY_ARG);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001357 default:return false;
1358 }
1359 }
1360
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001361 bool sanitize (SANITIZE_ARG_DEF) {
1362 if (!SANITIZE (u.format)) return false;
1363 switch (u.format) {
1364 case Single: return u.single->sanitize (SANITIZE_ARG);
1365 case Pair: return u.pair->sanitize (SANITIZE_ARG);
1366 case Cursive: return u.cursive->sanitize (SANITIZE_ARG);
1367 case MarkBase: return u.markBase->sanitize (SANITIZE_ARG);
1368 case MarkLig: return u.markLig->sanitize (SANITIZE_ARG);
1369 case MarkMark: return u.markMark->sanitize (SANITIZE_ARG);
1370 case Context: return u.context->sanitize (SANITIZE_ARG);
1371 case ChainContext: return u.chainContext->sanitize (SANITIZE_ARG);
1372 case Extension: return u.extension->sanitize (SANITIZE_ARG);
1373 default:return true;
1374 }
1375 }
1376
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001377 private:
1378 union {
Behdad Esfahbodff05d252009-05-20 03:53:00 -04001379 USHORT format;
1380 SinglePos single[];
1381 PairPos pair[];
1382 CursivePos cursive[];
1383 MarkBasePos markBase[];
1384 MarkLigPos markLig[];
1385 MarkMarkPos markMark[];
1386 ContextPos context[];
1387 ChainContextPos chainContext[];
1388 ExtensionPos extension[];
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001389 } u;
1390};
1391ASSERT_SIZE (PosLookupSubTable, 2);
1392
1393
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001394struct PosLookup : Lookup
1395{
1396 inline const PosLookupSubTable& get_subtable (unsigned int i) const
Behdad Esfahbod79420ad2009-05-26 12:24:16 -04001397 { return (const PosLookupSubTable&) Lookup::get_subtable (i); }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001398
1399 /* Like get_type(), but looks through extension lookups.
1400 * Never returns Extension */
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001401 inline unsigned int get_effective_type (void) const
1402 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001403 unsigned int type = get_type ();
1404
Behdad Esfahbodff05d252009-05-20 03:53:00 -04001405 if (HB_UNLIKELY (type == PosLookupSubTable::Extension))
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001406 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001407 unsigned int count = get_subtable_count ();
1408 type = get_subtable(0).u.extension->get_type ();
1409 /* The spec says all subtables should have the same type.
1410 * This is specially important if one has a reverse type! */
1411 for (unsigned int i = 1; i < count; i++)
1412 if (get_subtable(i).u.extension->get_type () != type)
1413 return 0;
1414 }
1415
1416 return type;
1417 }
1418
Behdad Esfahbod0ead4812009-08-02 17:41:36 -04001419 inline bool apply_once (hb_ot_layout_context_t *context,
Behdad Esfahbod923923f2009-05-22 17:58:09 -04001420 hb_buffer_t *buffer,
1421 unsigned int context_length,
1422 unsigned int nesting_level_left) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001423 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001424 unsigned int lookup_type = get_type ();
1425 unsigned int lookup_flag = get_flag ();
Behdad Esfahbod923923f2009-05-22 17:58:09 -04001426 unsigned int property;
1427
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -04001428 if (!_hb_ot_layout_check_glyph_property (context->face, IN_CURINFO (), lookup_flag, &property))
Behdad Esfahbod923923f2009-05-22 17:58:09 -04001429 return false;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001430
1431 for (unsigned int i = 0; i < get_subtable_count (); i++)
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -04001432 if (get_subtable (i).apply (APPLY_ARG, lookup_type))
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001433 return true;
1434
1435 return false;
1436 }
1437
Behdad Esfahbod0ead4812009-08-02 17:41:36 -04001438 bool apply_string (hb_ot_layout_context_t *context,
Behdad Esfahbod2a8e6ac2009-05-18 18:21:44 -04001439 hb_buffer_t *buffer,
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001440 hb_ot_layout_feature_mask_t mask) const
1441 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001442 bool ret = false;
1443
1444 if (HB_UNLIKELY (!buffer->in_length))
1445 return false;
1446
Behdad Esfahbod0ead4812009-08-02 17:41:36 -04001447 context->info.gpos.last = HB_OT_LAYOUT_GPOS_NO_LAST; /* no last valid glyph for cursive pos. */
Behdad Esfahbod9c42f052009-05-18 17:43:49 -04001448
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001449 buffer->in_pos = 0;
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001450 while (buffer->in_pos < buffer->in_length)
1451 {
Behdad Esfahbod9c42f052009-05-18 17:43:49 -04001452 bool done;
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001453 if (~IN_PROPERTIES (buffer->in_pos) & mask)
1454 {
Behdad Esfahbod0ead4812009-08-02 17:41:36 -04001455 done = apply_once (context, buffer, NO_CONTEXT, MAX_NESTING_LEVEL);
Behdad Esfahbod9c42f052009-05-18 17:43:49 -04001456 ret |= done;
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001457 }
1458 else
1459 {
Behdad Esfahbod9c42f052009-05-18 17:43:49 -04001460 done = false;
1461 /* Contrary to properties defined in GDEF, user-defined properties
1462 will always stop a possible cursive positioning. */
Behdad Esfahbod0ead4812009-08-02 17:41:36 -04001463 context->info.gpos.last = HB_OT_LAYOUT_GPOS_NO_LAST;
Behdad Esfahbod9c42f052009-05-18 17:43:49 -04001464 }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001465
Behdad Esfahbod9c42f052009-05-18 17:43:49 -04001466 if (!done)
1467 buffer->in_pos++;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001468 }
1469
1470 return ret;
1471 }
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001472
1473 inline bool sanitize (SANITIZE_ARG_DEF) {
1474 if (Lookup::sanitize (SANITIZE_ARG)) return false;
1475 OffsetArrayOf<PosLookupSubTable> &list = (OffsetArrayOf<PosLookupSubTable> &) subTable;
1476 return SANITIZE_THIS (list);
1477 }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001478};
1479ASSERT_SIZE (PosLookup, 6);
1480
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001481typedef OffsetListOf<PosLookup> PosLookupList;
1482ASSERT_SIZE (PosLookupList, 2);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001483
1484/*
1485 * GPOS
1486 */
1487
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001488struct GPOS : GSUBGPOS
1489{
Behdad Esfahboda328d662009-08-04 20:27:05 -04001490 static const hb_tag_t Tag = HB_OT_TAG_GPOS;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001491
Behdad Esfahbod5876bf12009-05-24 00:53:28 -04001492 static inline const GPOS& get_for_data (const char *data)
Behdad Esfahbod79420ad2009-05-26 12:24:16 -04001493 { return (const GPOS&) GSUBGPOS::get_for_data (data); }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001494
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001495 inline const PosLookup& get_lookup (unsigned int i) const
Behdad Esfahbod79420ad2009-05-26 12:24:16 -04001496 { return (const PosLookup&) GSUBGPOS::get_lookup (i); }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001497
Behdad Esfahbod0ead4812009-08-02 17:41:36 -04001498 inline bool position_lookup (hb_ot_layout_context_t *context,
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001499 hb_buffer_t *buffer,
1500 unsigned int lookup_index,
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001501 hb_ot_layout_feature_mask_t mask) const
Behdad Esfahbod0ead4812009-08-02 17:41:36 -04001502 { return get_lookup (lookup_index).apply_string (context, buffer, mask); }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001503
Behdad Esfahbode49a84c2009-08-04 14:33:23 -04001504 bool sanitize (SANITIZE_ARG_DEF) {
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001505 if (GSUBGPOS::sanitize (SANITIZE_ARG)) return false;
1506 OffsetTo<PosLookupList> &list = CAST(OffsetTo<PosLookupList>, lookupList, 0);
1507 return SANITIZE_THIS (list);
1508 }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001509};
1510ASSERT_SIZE (GPOS, 10);
1511
1512
1513/* Out-of-class implementation for methods recursing */
1514
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04001515inline bool ExtensionPos::apply (APPLY_ARG_DEF) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001516{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001517 unsigned int lookup_type = get_type ();
1518
Behdad Esfahbodff05d252009-05-20 03:53:00 -04001519 if (HB_UNLIKELY (lookup_type == PosLookupSubTable::Extension))
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001520 return false;
1521
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001522 return get_subtable ().apply (APPLY_ARG, lookup_type);
1523}
1524
1525inline bool ExtensionPos::sanitize (SANITIZE_ARG_DEF)
1526{
1527 return Extension::sanitize (SANITIZE_ARG) &&
Behdad Esfahbod18939482009-08-04 14:27:56 -04001528 (&(Extension::get_subtable ()) == &Null(LookupSubTable) ||
Behdad Esfahbod5ff4e132009-08-04 21:35:32 -04001529 get_type () == PosLookupSubTable::Extension ||
Behdad Esfahbod18939482009-08-04 14:27:56 -04001530 DECONST_CAST (PosLookupSubTable, get_subtable (), 0).sanitize (SANITIZE_ARG));
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001531}
1532
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001533static inline bool position_lookup (APPLY_ARG_DEF, unsigned int lookup_index)
1534{
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -04001535 const GPOS &gpos = *(context->face->ot_layout.gpos);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001536 const PosLookup &l = gpos.get_lookup (lookup_index);
1537
1538 if (HB_UNLIKELY (nesting_level_left == 0))
1539 return false;
1540 nesting_level_left--;
1541
1542 if (HB_UNLIKELY (context_length < 1))
1543 return false;
1544
Behdad Esfahbod0ead4812009-08-02 17:41:36 -04001545 return l.apply_once (context, buffer, context_length, nesting_level_left);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001546}
1547
1548
Behdad Esfahbod5f5b24f2009-08-02 20:03:12 -04001549#endif /* HB_OT_LAYOUT_GPOS_PRIVATE_HH */