blob: 8fe93eb657feb4f37630aee2c62031dd4a31b43d [file] [log] [blame]
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001/*
2 * Copyright (C) 2007,2008,2009 Red Hat, Inc.
3 *
Behdad Esfahbodc755cb32010-04-22 00:11:43 -04004 * This is part of HarfBuzz, a text shaping library.
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04005 *
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;
Behdad Esfahbodc91facd2009-08-26 18:53:43 -040037
Behdad Esfahbodc65b26a2009-11-18 11:27:33 -050038typedef Value ValueRecord[VAR0];
39ASSERT_SIZE_VAR (ValueRecord, 0, Value);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040040
Behdad Esfahbodfca6a0d2009-05-21 04:49:04 -040041struct ValueFormat : USHORT
42{
43 enum
44 {
45 xPlacement = 0x0001, /* Includes horizontal adjustment for placement */
46 yPlacement = 0x0002, /* Includes vertical adjustment for placement */
47 xAdvance = 0x0004, /* Includes horizontal adjustment for advance */
48 yAdvance = 0x0008, /* Includes vertical adjustment for advance */
49 xPlaDevice = 0x0010, /* Includes horizontal Device table for placement */
50 yPlaDevice = 0x0020, /* Includes vertical Device table for placement */
51 xAdvDevice = 0x0040, /* Includes horizontal Device table for advance */
52 yAdvDevice = 0x0080, /* Includes vertical Device table for advance */
Behdad Esfahbode4b92b82009-05-26 15:38:53 -040053 ignored = 0x0F00, /* Was used in TrueType Open for MM fonts */
Behdad Esfahbodeba8b4f2010-03-29 00:04:12 -040054 reserved = 0xF000, /* For future use */
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -040055
Behdad Esfahbodeba8b4f2010-03-29 00:04:12 -040056 devices = 0x00F0 /* Mask for having any Device table */
Behdad Esfahbodfca6a0d2009-05-21 04:49:04 -040057 };
58
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -040059/* All fields are options. Only those available advance the value pointer. */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040060#if 0
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040061 SHORT xPlacement; /* Horizontal adjustment for
62 * placement--in design units */
63 SHORT yPlacement; /* Vertical adjustment for
64 * placement--in design units */
65 SHORT xAdvance; /* Horizontal adjustment for
66 * advance--in design units (only used
67 * for horizontal writing) */
68 SHORT yAdvance; /* Vertical adjustment for advance--in
69 * design units (only used for vertical
70 * writing) */
71 Offset xPlaDevice; /* Offset to Device table for
72 * horizontal placement--measured from
73 * beginning of PosTable (may be NULL) */
74 Offset yPlaDevice; /* Offset to Device table for vertical
75 * placement--measured from beginning
76 * of PosTable (may be NULL) */
77 Offset xAdvDevice; /* Offset to Device table for
78 * horizontal advance--measured from
79 * beginning of PosTable (may be NULL) */
80 Offset yAdvDevice; /* Offset to Device table for vertical
81 * advance--measured from beginning of
82 * PosTable (may be NULL) */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040083#endif
84
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -040085 inline unsigned int get_len () const
86 { return _hb_popcount32 ((unsigned int) *this); }
87 inline unsigned int get_size () const
88 { return get_len () * Value::get_size (); }
89
Behdad Esfahbod63493f92010-05-05 01:01:05 -040090 void apply_value (hb_ot_layout_context_t *layout,
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -040091 const char *base,
92 const Value *values,
93 hb_internal_glyph_position_t *glyph_pos) const
94 {
95 unsigned int x_ppem, y_ppem;
96 hb_16dot16_t x_scale, y_scale;
97 unsigned int format = *this;
98
99 if (!format) return;
100
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400101 x_scale = layout->font->x_scale;
102 y_scale = layout->font->y_scale;
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400103 /* design units -> fractional pixel */
Behdad Esfahbod06558d22010-04-19 02:34:10 -0400104 if (format & xPlacement) glyph_pos->x_offset += _hb_16dot16_mul_round (x_scale, *(SHORT*)values++);
105 if (format & yPlacement) glyph_pos->y_offset += _hb_16dot16_mul_round (y_scale, *(SHORT*)values++);
106 if (format & xAdvance) glyph_pos->x_advance += _hb_16dot16_mul_round (x_scale, *(SHORT*)values++);
107 if (format & yAdvance) glyph_pos->y_advance += _hb_16dot16_mul_round (y_scale, *(SHORT*)values++);
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400108
Behdad Esfahboda8d960b2010-04-29 14:31:56 -0400109 if (!has_device ()) return;
110
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400111 x_ppem = layout->font->x_ppem;
112 y_ppem = layout->font->y_ppem;
Behdad Esfahboda8d960b2010-04-29 14:31:56 -0400113
114 if (!x_ppem && !y_ppem) return;
115
Behdad Esfahbod0090dc02009-07-30 16:28:45 -0400116 /* pixel -> fractional pixel */
117 if (format & xPlaDevice) {
Behdad Esfahbod4b8487d2010-03-16 03:46:17 -0400118 if (x_ppem) glyph_pos->x_offset += (base+*(OffsetTo<Device>*)values++).get_delta (x_ppem) << 16; else values++;
Behdad Esfahbod0090dc02009-07-30 16:28:45 -0400119 }
120 if (format & yPlaDevice) {
Behdad Esfahbod4b8487d2010-03-16 03:46:17 -0400121 if (y_ppem) glyph_pos->y_offset += (base+*(OffsetTo<Device>*)values++).get_delta (y_ppem) << 16; else values++;
Behdad Esfahbod0090dc02009-07-30 16:28:45 -0400122 }
123 if (format & xAdvDevice) {
Behdad Esfahbod4b8487d2010-03-16 03:46:17 -0400124 if (x_ppem) glyph_pos->x_advance += (base+*(OffsetTo<Device>*)values++).get_delta (x_ppem) << 16; else values++;
Behdad Esfahbod0090dc02009-07-30 16:28:45 -0400125 }
126 if (format & yAdvDevice) {
Behdad Esfahbod4b8487d2010-03-16 03:46:17 -0400127 if (y_ppem) glyph_pos->y_advance += (base+*(OffsetTo<Device>*)values++).get_delta (y_ppem) << 16; else values++;
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400128 }
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400129 }
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400130
131 private:
Behdad Esfahbod39840472010-05-05 00:23:19 -0400132 inline bool sanitize_value_devices (hb_sanitize_context_t *context, void *base, const Value *values) {
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400133 unsigned int format = *this;
134
135 if (format & xPlacement) values++;
136 if (format & yPlacement) values++;
137 if (format & xAdvance) values++;
138 if (format & yAdvance) values++;
139
Behdad Esfahbod2226fc92010-05-04 15:12:17 -0400140 if ((format & xPlaDevice) && !SANITIZE_WITH_BASE (base, *(OffsetTo<Device>*)values++)) return false;
141 if ((format & yPlaDevice) && !SANITIZE_WITH_BASE (base, *(OffsetTo<Device>*)values++)) return false;
142 if ((format & xAdvDevice) && !SANITIZE_WITH_BASE (base, *(OffsetTo<Device>*)values++)) return false;
143 if ((format & yAdvDevice) && !SANITIZE_WITH_BASE (base, *(OffsetTo<Device>*)values++)) return false;
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400144
145 return true;
146 }
147
148 public:
149
Behdad Esfahboda8d960b2010-04-29 14:31:56 -0400150 inline bool has_device () const {
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400151 unsigned int format = *this;
152 return (format & devices) != 0;
153 }
154
Behdad Esfahbod39840472010-05-05 00:23:19 -0400155 inline bool sanitize_value (hb_sanitize_context_t *context, void *base, const Value *values) {
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400156 TRACE_SANITIZE ();
157
158 return SANITIZE_MEM (values, get_size ()) &&
Behdad Esfahbod39840472010-05-05 00:23:19 -0400159 (!has_device () || sanitize_value_devices (context, base, values));
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400160 }
161
Behdad Esfahbod39840472010-05-05 00:23:19 -0400162 inline bool sanitize_values (hb_sanitize_context_t *context, void *base, const Value *values, unsigned int count) {
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400163 TRACE_SANITIZE ();
164 unsigned int len = get_len ();
165
166 if (!SANITIZE_ARRAY (values, get_size (), count)) return false;
167
168 if (!has_device ()) return true;
169
170 for (unsigned int i = 0; i < count; i++) {
Behdad Esfahbod39840472010-05-05 00:23:19 -0400171 if (!sanitize_value_devices (context, base, values))
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400172 return false;
173 values += len;
174 }
175
176 return true;
177 }
178
Behdad Esfahbod278a91f2010-04-22 13:59:39 -0400179 /* Just sanitize referenced Device tables. Doesn't check the values themselves. */
Behdad Esfahbod39840472010-05-05 00:23:19 -0400180 inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *context, void *base, const Value *values, unsigned int count, unsigned int stride) {
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400181 TRACE_SANITIZE ();
182
183 if (!has_device ()) return true;
184
185 for (unsigned int i = 0; i < count; i++) {
Behdad Esfahbod39840472010-05-05 00:23:19 -0400186 if (!sanitize_value_devices (context, base, values))
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400187 return false;
188 values += stride;
189 }
190
191 return true;
192 }
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400193};
194ASSERT_SIZE (ValueFormat, 2);
195
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400196
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400197struct AnchorFormat1
198{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400199 friend struct Anchor;
200
201 private:
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400202 inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id HB_UNUSED,
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400203 hb_position_t *x, hb_position_t *y) const
204 {
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400205 *x = _hb_16dot16_mul_round (layout->font->x_scale, xCoordinate);
206 *y = _hb_16dot16_mul_round (layout->font->y_scale, yCoordinate);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400207 }
208
Behdad Esfahbod39840472010-05-05 00:23:19 -0400209 inline bool sanitize (hb_sanitize_context_t *context) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400210 TRACE_SANITIZE ();
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400211 return SANITIZE_SELF ();
212 }
213
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400214 private:
215 USHORT format; /* Format identifier--format = 1 */
216 SHORT xCoordinate; /* Horizontal value--in design units */
217 SHORT yCoordinate; /* Vertical value--in design units */
218};
219ASSERT_SIZE (AnchorFormat1, 6);
220
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400221struct AnchorFormat2
222{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400223 friend struct Anchor;
224
225 private:
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400226 inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id,
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400227 hb_position_t *x, hb_position_t *y) const
228 {
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400229 unsigned int x_ppem = layout->font->x_ppem;
230 unsigned int y_ppem = layout->font->y_ppem;
Behdad Esfahbod6f729b42010-04-29 03:59:06 -0400231 hb_position_t cx, cy;
232 hb_bool_t ret;
233
234 if (x_ppem || y_ppem)
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400235 ret = hb_font_get_contour_point (layout->font, layout->face, anchorPoint, glyph_id, &cx, &cy);
236 *x = x_ppem && ret ? cx : _hb_16dot16_mul_round (layout->font->x_scale, xCoordinate);
237 *y = y_ppem && ret ? cy : _hb_16dot16_mul_round (layout->font->y_scale, yCoordinate);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400238 }
239
Behdad Esfahbod39840472010-05-05 00:23:19 -0400240 inline bool sanitize (hb_sanitize_context_t *context) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400241 TRACE_SANITIZE ();
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400242 return SANITIZE_SELF ();
243 }
244
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400245 private:
246 USHORT format; /* Format identifier--format = 2 */
247 SHORT xCoordinate; /* Horizontal value--in design units */
248 SHORT yCoordinate; /* Vertical value--in design units */
249 USHORT anchorPoint; /* Index to glyph contour point */
250};
251ASSERT_SIZE (AnchorFormat2, 8);
252
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400253struct AnchorFormat3
254{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400255 friend struct Anchor;
256
257 private:
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400258 inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id HB_UNUSED,
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400259 hb_position_t *x, hb_position_t *y) const
260 {
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400261 *x = _hb_16dot16_mul_round (layout->font->x_scale, xCoordinate);
262 *y = _hb_16dot16_mul_round (layout->font->y_scale, yCoordinate);
Behdad Esfahbodc18ec2b2009-05-21 04:54:01 -0400263
Behdad Esfahbod4b8487d2010-03-16 03:46:17 -0400264 /* pixel -> fractional pixel */
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400265 if (layout->font->x_ppem)
266 *x += (this+xDeviceTable).get_delta (layout->font->x_ppem) << 16;
267 if (layout->font->y_ppem)
268 *y += (this+yDeviceTable).get_delta (layout->font->y_ppem) << 16;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400269 }
270
Behdad Esfahbod39840472010-05-05 00:23:19 -0400271 inline bool sanitize (hb_sanitize_context_t *context) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400272 TRACE_SANITIZE ();
Behdad Esfahbod4d4cce92010-05-04 14:57:55 -0400273 return SANITIZE_SELF ()
Behdad Esfahbodbb029af2010-05-04 15:28:52 -0400274 && SANITIZE_WITH_BASE (this, xDeviceTable)
275 && SANITIZE_WITH_BASE (this, yDeviceTable);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400276 }
277
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400278 private:
279 USHORT format; /* Format identifier--format = 3 */
280 SHORT xCoordinate; /* Horizontal value--in design units */
281 SHORT yCoordinate; /* Vertical value--in design units */
282 OffsetTo<Device>
283 xDeviceTable; /* Offset to Device table for X
284 * coordinate-- from beginning of
285 * Anchor table (may be NULL) */
286 OffsetTo<Device>
287 yDeviceTable; /* Offset to Device table for Y
288 * coordinate-- from beginning of
289 * Anchor table (may be NULL) */
290};
291ASSERT_SIZE (AnchorFormat3, 10);
292
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400293struct Anchor
294{
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400295 inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id,
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400296 hb_position_t *x, hb_position_t *y) const
297 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400298 *x = *y = 0;
299 switch (u.format) {
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400300 case 1: u.format1->get_anchor (layout, glyph_id, x, y); return;
301 case 2: u.format2->get_anchor (layout, glyph_id, x, y); return;
302 case 3: u.format3->get_anchor (layout, glyph_id, x, y); return;
303 default: return;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400304 }
305 }
306
Behdad Esfahbod39840472010-05-05 00:23:19 -0400307 inline bool sanitize (hb_sanitize_context_t *context) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400308 TRACE_SANITIZE ();
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400309 if (!SANITIZE (u.format)) return false;
310 switch (u.format) {
Behdad Esfahbod39840472010-05-05 00:23:19 -0400311 case 1: return u.format1->sanitize (context);
312 case 2: return u.format2->sanitize (context);
313 case 3: return u.format3->sanitize (context);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400314 default:return true;
315 }
316 }
317
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400318 private:
319 union {
320 USHORT format; /* Format identifier */
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -0500321 AnchorFormat1 format1[VAR];
322 AnchorFormat2 format2[VAR];
323 AnchorFormat3 format3[VAR];
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400324 } u;
325};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400326
327
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400328struct AnchorMatrix
329{
330 inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols) const {
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400331 if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400332 return this+matrix[row * cols + col];
333 }
334
Behdad Esfahbod39840472010-05-05 00:23:19 -0400335 inline bool sanitize (hb_sanitize_context_t *context, unsigned int cols) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400336 TRACE_SANITIZE ();
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400337 if (!SANITIZE_SELF ()) return false;
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400338 if (unlikely (cols >= ((unsigned int) -1) / rows)) return false;
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400339 unsigned int count = rows * cols;
Behdad Esfahbod4b8487d2010-03-16 03:46:17 -0400340 if (!SANITIZE_ARRAY (matrix, matrix[0].get_size (), count)) return false;
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400341 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodbb029af2010-05-04 15:28:52 -0400342 if (!SANITIZE_WITH_BASE (this, matrix[i])) return false;
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400343 return true;
344 }
345
346 USHORT rows; /* Number of rows */
347 private:
348 OffsetTo<Anchor>
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -0500349 matrix[VAR]; /* Matrix of offsets to Anchor tables--
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400350 * from beginning of AnchorMatrix table */
351};
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -0500352ASSERT_SIZE_VAR (AnchorMatrix, 2, OffsetTo<Anchor>);
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400353
354
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400355struct MarkRecord
356{
Behdad Esfahbod377bfc52009-05-21 04:58:24 -0400357 friend struct MarkArray;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400358
Behdad Esfahbod4b8487d2010-03-16 03:46:17 -0400359 static inline unsigned int get_size () { return sizeof (MarkRecord); }
360
Behdad Esfahbod39840472010-05-05 00:23:19 -0400361 inline bool sanitize (hb_sanitize_context_t *context, void *base) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400362 TRACE_SANITIZE ();
Behdad Esfahbod2226fc92010-05-04 15:12:17 -0400363 return SANITIZE_SELF ()
364 && SANITIZE_WITH_BASE (base, markAnchor);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400365 }
366
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400367 private:
368 USHORT klass; /* Class defined for this mark */
369 OffsetTo<Anchor>
370 markAnchor; /* Offset to Anchor table--from
371 * beginning of MarkArray table */
372};
373ASSERT_SIZE (MarkRecord, 4);
374
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400375struct MarkArray
376{
Behdad Esfahbodb41f2102009-08-14 19:33:24 -0400377 inline bool apply (APPLY_ARG_DEF,
378 unsigned int mark_index, unsigned int glyph_index,
379 const AnchorMatrix &anchors, unsigned int class_count,
380 unsigned int glyph_pos) const
381 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400382 TRACE_APPLY ();
Behdad Esfahbodb41f2102009-08-14 19:33:24 -0400383 const MarkRecord &record = markRecord[mark_index];
384 unsigned int mark_class = record.klass;
385
386 const Anchor& mark_anchor = this + record.markAnchor;
387 const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count);
388
389 hb_position_t mark_x, mark_y, base_x, base_y;
390
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400391 mark_anchor.get_anchor (context->layout, IN_CURGLYPH (), &mark_x, &mark_y);
392 glyph_anchor.get_anchor (context->layout, IN_GLYPH (glyph_pos), &base_x, &base_y);
Behdad Esfahbodb41f2102009-08-14 19:33:24 -0400393
394 hb_internal_glyph_position_t *o = POSITION (buffer->in_pos);
Behdad Esfahbodb41f2102009-08-14 19:33:24 -0400395 o->x_advance = 0;
396 o->y_advance = 0;
Behdad Esfahbod9bef3612009-11-05 12:20:11 -0500397 o->x_offset = base_x - mark_x;
398 o->y_offset = base_y - mark_y;
Behdad Esfahbodb41f2102009-08-14 19:33:24 -0400399 o->back = buffer->in_pos - glyph_pos;
400
401 buffer->in_pos++;
402 return true;
403 }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400404
Behdad Esfahbod39840472010-05-05 00:23:19 -0400405 inline bool sanitize (hb_sanitize_context_t *context) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400406 TRACE_SANITIZE ();
Behdad Esfahbodbb029af2010-05-04 15:28:52 -0400407 return SANITIZE_WITH_BASE (this, markRecord);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400408 }
409
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400410 private:
411 ArrayOf<MarkRecord>
412 markRecord; /* Array of MarkRecords--in Coverage order */
413};
414ASSERT_SIZE (MarkArray, 2);
415
416
417/* Lookups */
418
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400419struct SinglePosFormat1
420{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400421 friend struct SinglePos;
422
423 private:
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400424 inline bool apply (APPLY_ARG_DEF) const
425 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400426 TRACE_APPLY ();
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400427 unsigned int index = (this+coverage) (IN_CURGLYPH ());
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400428 if (likely (index == NOT_COVERED))
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400429 return false;
430
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400431 valueFormat.apply_value (context->layout, CharP(this), values, CURPOSITION ());
Behdad Esfahbodf53d4342009-05-30 22:17:32 -0400432
433 buffer->in_pos++;
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400434 return true;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400435 }
436
Behdad Esfahbod39840472010-05-05 00:23:19 -0400437 inline bool sanitize (hb_sanitize_context_t *context) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400438 TRACE_SANITIZE ();
Behdad Esfahbodbb029af2010-05-04 15:28:52 -0400439 return SANITIZE_SELF ()
440 && SANITIZE_WITH_BASE (this, coverage)
Behdad Esfahbod39840472010-05-05 00:23:19 -0400441 && valueFormat.sanitize_value (context, CharP(this), values);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400442 }
443
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400444 private:
445 USHORT format; /* Format identifier--format = 1 */
446 OffsetTo<Coverage>
447 coverage; /* Offset to Coverage table--from
448 * beginning of subtable */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400449 ValueFormat valueFormat; /* Defines the types of data in the
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400450 * ValueRecord */
451 ValueRecord values; /* Defines positioning
452 * value(s)--applied to all glyphs in
453 * the Coverage table */
454};
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -0500455ASSERT_SIZE_VAR (SinglePosFormat1, 6, ValueRecord);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400456
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400457struct SinglePosFormat2
458{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400459 friend struct SinglePos;
460
461 private:
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400462 inline bool apply (APPLY_ARG_DEF) const
463 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400464 TRACE_APPLY ();
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400465 unsigned int index = (this+coverage) (IN_CURGLYPH ());
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400466 if (likely (index == NOT_COVERED))
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400467 return false;
468
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400469 if (likely (index >= valueCount))
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400470 return false;
471
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400472 valueFormat.apply_value (context->layout, CharP(this),
Behdad Esfahbod4b8487d2010-03-16 03:46:17 -0400473 &values[index * valueFormat.get_len ()],
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400474 CURPOSITION ());
Behdad Esfahbodf53d4342009-05-30 22:17:32 -0400475
476 buffer->in_pos++;
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400477 return true;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400478 }
479
Behdad Esfahbod39840472010-05-05 00:23:19 -0400480 inline bool sanitize (hb_sanitize_context_t *context) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400481 TRACE_SANITIZE ();
Behdad Esfahbodbb029af2010-05-04 15:28:52 -0400482 return SANITIZE_SELF ()
483 && SANITIZE_WITH_BASE (this, coverage)
Behdad Esfahbod39840472010-05-05 00:23:19 -0400484 && valueFormat.sanitize_values (context, CharP(this), values, valueCount);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400485 }
486
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400487 private:
488 USHORT format; /* Format identifier--format = 2 */
489 OffsetTo<Coverage>
490 coverage; /* Offset to Coverage table--from
491 * beginning of subtable */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400492 ValueFormat valueFormat; /* Defines the types of data in the
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400493 * ValueRecord */
494 USHORT valueCount; /* Number of ValueRecords */
495 ValueRecord values; /* Array of ValueRecords--positioning
496 * values applied to glyphs */
497};
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -0500498ASSERT_SIZE_VAR (SinglePosFormat2, 8, ValueRecord);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400499
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400500struct SinglePos
501{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400502 friend struct PosLookupSubTable;
503
504 private:
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400505 inline bool apply (APPLY_ARG_DEF) const
506 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400507 TRACE_APPLY ();
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400508 switch (u.format) {
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400509 case 1: return u.format1->apply (APPLY_ARG);
510 case 2: return u.format2->apply (APPLY_ARG);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400511 default:return false;
512 }
513 }
514
Behdad Esfahbod39840472010-05-05 00:23:19 -0400515 inline bool sanitize (hb_sanitize_context_t *context) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400516 TRACE_SANITIZE ();
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400517 if (!SANITIZE (u.format)) return false;
518 switch (u.format) {
Behdad Esfahbod39840472010-05-05 00:23:19 -0400519 case 1: return u.format1->sanitize (context);
520 case 2: return u.format2->sanitize (context);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400521 default:return true;
522 }
523 }
524
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400525 private:
526 union {
527 USHORT format; /* Format identifier */
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -0500528 SinglePosFormat1 format1[VAR];
529 SinglePosFormat2 format2[VAR];
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400530 } u;
531};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400532
533
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400534struct PairValueRecord
535{
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400536 friend struct PairPosFormat1;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400537
538 private:
539 GlyphID secondGlyph; /* GlyphID of second glyph in the
540 * pair--first glyph is listed in the
541 * Coverage table */
542 ValueRecord values; /* Positioning data for the first glyph
543 * followed by for second glyph */
544};
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -0500545ASSERT_SIZE_VAR (PairValueRecord, 2, ValueRecord);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400546
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400547struct PairSet
548{
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400549 friend struct PairPosFormat1;
550
Behdad Esfahbodeba8b4f2010-03-29 00:04:12 -0400551 /* Note: Doesn't sanitize the Device entries in the ValueRecord */
Behdad Esfahbod39840472010-05-05 00:23:19 -0400552 inline bool sanitize (hb_sanitize_context_t *context, unsigned int format_len) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400553 TRACE_SANITIZE ();
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400554 if (!SANITIZE_SELF ()) return false;
555 unsigned int count = (1 + format_len) * len;
Behdad Esfahbod278a91f2010-04-22 13:59:39 -0400556 return SANITIZE_ARRAY (array, USHORT::get_size (), count);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400557 }
558
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400559 private:
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400560 USHORT len; /* Number of PairValueRecords */
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400561 PairValueRecord
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -0500562 array[VAR]; /* Array of PairValueRecords--ordered
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400563 * by GlyphID of the second glyph */
564};
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -0500565ASSERT_SIZE_VAR (PairSet, 2, PairValueRecord);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400566
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400567struct PairPosFormat1
568{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400569 friend struct PairPos;
570
571 private:
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400572 inline bool apply (APPLY_ARG_DEF) const
573 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400574 TRACE_APPLY ();
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400575 unsigned int end = MIN (buffer->in_length, buffer->in_pos + context_length);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400576 if (unlikely (buffer->in_pos + 2 > end))
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400577 return false;
578
579 unsigned int index = (this+coverage) (IN_CURGLYPH ());
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400580 if (likely (index == NOT_COVERED))
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400581 return false;
582
583 unsigned int j = buffer->in_pos + 1;
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400584 while (_hb_ot_layout_skip_mark (context->layout->face, IN_INFO (j), context->lookup_flag, NULL))
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400585 {
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400586 if (unlikely (j == end))
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400587 return false;
588 j++;
589 }
590
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400591 unsigned int len1 = valueFormat1.get_len ();
592 unsigned int len2 = valueFormat2.get_len ();
Behdad Esfahbod4b8487d2010-03-16 03:46:17 -0400593 unsigned int record_size = USHORT::get_size () * (1 + len1 + len2);
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400594
Behdad Esfahbodeba8b4f2010-03-29 00:04:12 -0400595 const PairSet &pair_set = this+pairSet[index];
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400596 unsigned int count = pair_set.len;
597 const PairValueRecord *record = pair_set.array;
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400598 for (unsigned int i = 0; i < count; i++)
599 {
600 if (IN_GLYPH (j) == record->secondGlyph)
601 {
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400602 valueFormat1.apply_value (context->layout, CharP(this), &record->values[0], CURPOSITION ());
603 valueFormat2.apply_value (context->layout, CharP(this), &record->values[len1], POSITION (j));
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400604 if (len2)
605 j++;
606 buffer->in_pos = j;
607 return true;
608 }
Behdad Esfahboda3263aa2010-04-22 18:29:09 -0400609 record = &StructAtOffset<PairValueRecord> (*record, record_size);
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400610 }
611
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400612 return false;
613 }
614
Behdad Esfahbod39840472010-05-05 00:23:19 -0400615 inline bool sanitize (hb_sanitize_context_t *context) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400616 TRACE_SANITIZE ();
Behdad Esfahbodeba8b4f2010-03-29 00:04:12 -0400617
618 unsigned int len1 = valueFormat1.get_len ();
619 unsigned int len2 = valueFormat2.get_len ();
620
Behdad Esfahbodbb029af2010-05-04 15:28:52 -0400621 if (!(SANITIZE_SELF ()
622 && SANITIZE_WITH_BASE (this, coverage)
Behdad Esfahbod39840472010-05-05 00:23:19 -0400623 && likely (pairSet.sanitize (context, CharP(this), len1 + len2)))) return false;
Behdad Esfahbodeba8b4f2010-03-29 00:04:12 -0400624
625 if (!(valueFormat1.has_device () || valueFormat2.has_device ())) return true;
626
627 unsigned int stride = 1 + len1 + len2;
628 unsigned int count1 = pairSet.len;
629 for (unsigned int i = 0; i < count1; i++)
630 {
631 const PairSet &pair_set = this+pairSet[i];
632
633 unsigned int count2 = pair_set.len;
634 const PairValueRecord *record = pair_set.array;
Behdad Esfahbod39840472010-05-05 00:23:19 -0400635 if (!(valueFormat1.sanitize_values_stride_unsafe (context, CharP(this), &record->values[0], count2, stride) &&
636 valueFormat2.sanitize_values_stride_unsafe (context, CharP(this), &record->values[len1], count2, stride)))
Behdad Esfahbodeba8b4f2010-03-29 00:04:12 -0400637 return false;
638 }
639
640 return true;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400641 }
642
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400643 private:
644 USHORT format; /* Format identifier--format = 1 */
645 OffsetTo<Coverage>
646 coverage; /* Offset to Coverage table--from
647 * beginning of subtable */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400648 ValueFormat valueFormat1; /* Defines the types of data in
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400649 * ValueRecord1--for the first glyph
650 * in the pair--may be zero (0) */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400651 ValueFormat valueFormat2; /* Defines the types of data in
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400652 * ValueRecord2--for the second glyph
653 * in the pair--may be zero (0) */
654 OffsetArrayOf<PairSet>
655 pairSet; /* Array of PairSet tables
656 * ordered by Coverage Index */
657};
658ASSERT_SIZE (PairPosFormat1, 10);
659
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400660struct PairPosFormat2
661{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400662 friend struct PairPos;
663
664 private:
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400665 inline bool apply (APPLY_ARG_DEF) const
666 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400667 TRACE_APPLY ();
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400668 unsigned int end = MIN (buffer->in_length, buffer->in_pos + context_length);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400669 if (unlikely (buffer->in_pos + 2 > end))
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400670 return false;
671
672 unsigned int index = (this+coverage) (IN_CURGLYPH ());
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400673 if (likely (index == NOT_COVERED))
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400674 return false;
675
676 unsigned int j = buffer->in_pos + 1;
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400677 while (_hb_ot_layout_skip_mark (context->layout->face, IN_INFO (j), context->lookup_flag, NULL))
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400678 {
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400679 if (unlikely (j == end))
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400680 return false;
681 j++;
682 }
683
684 unsigned int len1 = valueFormat1.get_len ();
685 unsigned int len2 = valueFormat2.get_len ();
686 unsigned int record_len = len1 + len2;
687
688 unsigned int klass1 = (this+classDef1) (IN_CURGLYPH ());
689 unsigned int klass2 = (this+classDef2) (IN_GLYPH (j));
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400690 if (unlikely (klass1 >= class1Count || klass2 >= class2Count))
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400691 return false;
692
Behdad Esfahbod4b8487d2010-03-16 03:46:17 -0400693 const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400694 valueFormat1.apply_value (context->layout, CharP(this), v, CURPOSITION ());
695 valueFormat2.apply_value (context->layout, CharP(this), v + len1, POSITION (j));
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400696
697 if (len2)
698 j++;
699 buffer->in_pos = j;
700
701 return true;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400702 }
703
Behdad Esfahbod39840472010-05-05 00:23:19 -0400704 inline bool sanitize (hb_sanitize_context_t *context) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400705 TRACE_SANITIZE ();
Behdad Esfahbodbb029af2010-05-04 15:28:52 -0400706 if (!(SANITIZE_SELF ()
707 && SANITIZE_WITH_BASE (this, coverage)
708 && SANITIZE_WITH_BASE (this, classDef1)
709 && SANITIZE_WITH_BASE (this, classDef2))) return false;
Behdad Esfahbod815a73e2009-08-14 17:31:16 -0400710
Behdad Esfahbodeba8b4f2010-03-29 00:04:12 -0400711 unsigned int len1 = valueFormat1.get_len ();
712 unsigned int len2 = valueFormat2.get_len ();
713 unsigned int stride = len1 + len2;
Behdad Esfahbod4b8487d2010-03-16 03:46:17 -0400714 unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
Behdad Esfahbodeba8b4f2010-03-29 00:04:12 -0400715 unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
716 return SANITIZE_ARRAY (values, record_size, count) &&
Behdad Esfahbod39840472010-05-05 00:23:19 -0400717 valueFormat1.sanitize_values_stride_unsafe (context, CharP(this), &values[0], count, stride) &&
718 valueFormat2.sanitize_values_stride_unsafe (context, CharP(this), &values[len1], count, stride);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400719 }
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400720
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400721 private:
722 USHORT format; /* Format identifier--format = 2 */
723 OffsetTo<Coverage>
724 coverage; /* Offset to Coverage table--from
725 * beginning of subtable */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400726 ValueFormat valueFormat1; /* ValueRecord definition--for the
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400727 * first glyph of the pair--may be zero
728 * (0) */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400729 ValueFormat valueFormat2; /* ValueRecord definition--for the
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400730 * second glyph of the pair--may be
731 * zero (0) */
732 OffsetTo<ClassDef>
733 classDef1; /* Offset to ClassDef table--from
734 * beginning of PairPos subtable--for
735 * the first glyph of the pair */
736 OffsetTo<ClassDef>
737 classDef2; /* Offset to ClassDef table--from
738 * beginning of PairPos subtable--for
739 * the second glyph of the pair */
740 USHORT class1Count; /* Number of classes in ClassDef1
741 * table--includes Class0 */
742 USHORT class2Count; /* Number of classes in ClassDef2
743 * table--includes Class0 */
744 ValueRecord values; /* Matrix of value pairs:
745 * class1-major, class2-minor,
746 * Each entry has value1 and value2 */
747};
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -0500748ASSERT_SIZE_VAR (PairPosFormat2, 16, ValueRecord);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400749
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400750struct PairPos
751{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400752 friend struct PosLookupSubTable;
753
754 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400755 inline bool apply (APPLY_ARG_DEF) const
756 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400757 TRACE_APPLY ();
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400758 switch (u.format) {
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400759 case 1: return u.format1->apply (APPLY_ARG);
760 case 2: return u.format2->apply (APPLY_ARG);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400761 default:return false;
762 }
763 }
764
Behdad Esfahbod39840472010-05-05 00:23:19 -0400765 inline bool sanitize (hb_sanitize_context_t *context) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400766 TRACE_SANITIZE ();
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400767 if (!SANITIZE (u.format)) return false;
768 switch (u.format) {
Behdad Esfahbod39840472010-05-05 00:23:19 -0400769 case 1: return u.format1->sanitize (context);
770 case 2: return u.format2->sanitize (context);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400771 default:return true;
772 }
773 }
774
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400775 private:
776 union {
777 USHORT format; /* Format identifier */
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -0500778 PairPosFormat1 format1[VAR];
779 PairPosFormat2 format2[VAR];
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400780 } u;
781};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400782
783
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400784struct EntryExitRecord
785{
Behdad Esfahbod4b8487d2010-03-16 03:46:17 -0400786 static inline unsigned int get_size () { return sizeof (EntryExitRecord); }
787
Behdad Esfahbod39840472010-05-05 00:23:19 -0400788 inline bool sanitize (hb_sanitize_context_t *context, void *base) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400789 TRACE_SANITIZE ();
Behdad Esfahbod2226fc92010-05-04 15:12:17 -0400790 return SANITIZE_WITH_BASE (base, entryAnchor)
791 && SANITIZE_WITH_BASE (base, exitAnchor);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400792 }
793
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400794 OffsetTo<Anchor>
795 entryAnchor; /* Offset to EntryAnchor table--from
796 * beginning of CursivePos
797 * subtable--may be NULL */
798 OffsetTo<Anchor>
799 exitAnchor; /* Offset to ExitAnchor table--from
800 * beginning of CursivePos
801 * subtable--may be NULL */
802};
803ASSERT_SIZE (EntryExitRecord, 4);
804
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400805struct CursivePosFormat1
806{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400807 friend struct CursivePos;
808
809 private:
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400810 inline bool apply (APPLY_ARG_DEF) const
811 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400812 TRACE_APPLY ();
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400813 /* Now comes the messiest part of the whole OpenType
814 specification. At first glance, cursive connections seem easy
815 to understand, but there are pitfalls! The reason is that
816 the specs don't mention how to compute the advance values
817 resp. glyph offsets. I was told it would be an omission, to
818 be fixed in the next OpenType version... Again many thanks to
819 Andrei Burago <andreib@microsoft.com> for clarifications.
820
821 Consider the following example:
822
823 | xadv1 |
824 +---------+
825 | |
826 +-----+--+ 1 |
827 | | .| |
828 | 0+--+------+
829 | 2 |
830 | |
831 0+--------+
832 | xadv2 |
833
834 glyph1: advance width = 12
835 anchor point = (3,1)
836
837 glyph2: advance width = 11
838 anchor point = (9,4)
839
840 LSB is 1 for both glyphs (so the boxes drawn above are glyph
841 bboxes). Writing direction is R2L; `0' denotes the glyph's
842 coordinate origin.
843
844 Now the surprising part: The advance width of the *left* glyph
845 (resp. of the *bottom* glyph) will be modified, no matter
846 whether the writing direction is L2R or R2L (resp. T2B or
847 B2T)! This assymetry is caused by the fact that the glyph's
848 coordinate origin is always the lower left corner for all
849 writing directions.
850
851 Continuing the above example, we can compute the new
852 (horizontal) advance width of glyph2 as
853
854 9 - 3 = 6 ,
855
856 and the new vertical offset of glyph2 as
857
858 1 - 4 = -3 .
859
860
861 Vertical writing direction is far more complicated:
862
863 a) Assuming that we recompute the advance height of the lower glyph:
864
865 --
866 +---------+
867 -- | |
868 +-----+--+ 1 | yadv1
869 | | .| |
870 yadv2 | 0+--+------+ -- BSB1 --
871 | 2 | -- -- y_offset
872 | |
873 BSB2 -- 0+--------+ --
874 -- --
875
876 glyph1: advance height = 6
877 anchor point = (3,1)
878
879 glyph2: advance height = 7
880 anchor point = (9,4)
881
882 TSB is 1 for both glyphs; writing direction is T2B.
883
884
885 BSB1 = yadv1 - (TSB1 + ymax1)
886 BSB2 = yadv2 - (TSB2 + ymax2)
887 y_offset = y2 - y1
888
889 vertical advance width of glyph2
890 = y_offset + BSB2 - BSB1
891 = (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1))
892 = y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1)
893 = y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1
894
895
896 b) Assuming that we recompute the advance height of the upper glyph:
897
898 -- --
899 +---------+ -- TSB1
900 -- -- | |
901 TSB2 -- +-----+--+ 1 | yadv1 ymax1
902 | | .| |
903 yadv2 | 0+--+------+ -- --
904 ymax2 | 2 | -- y_offset
905 | |
906 -- 0+--------+ --
907 --
908
909 glyph1: advance height = 6
910 anchor point = (3,1)
911
912 glyph2: advance height = 7
913 anchor point = (9,4)
914
915 TSB is 1 for both glyphs; writing direction is T2B.
916
917 y_offset = y2 - y1
918
919 vertical advance width of glyph2
920 = TSB1 + ymax1 + y_offset - (TSB2 + ymax2)
921 = TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2
922
923
924 Comparing a) with b) shows that b) is easier to compute. I'll wait
925 for a reply from Andrei to see what should really be implemented...
926
927 Since horizontal advance widths or vertical advance heights
928 can be used alone but not together, no ambiguity occurs. */
929
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400930 struct hb_ot_layout_context_t::info_t::gpos_t *gpi = &context->layout->info.gpos;
Behdad Esfahbod0f7e6b22009-05-20 04:16:35 -0400931 hb_codepoint_t last_pos = gpi->last;
Behdad Esfahbodc968fc22009-05-25 04:04:24 -0400932 gpi->last = HB_OT_LAYOUT_GPOS_NO_LAST;
Behdad Esfahbod0f7e6b22009-05-20 04:16:35 -0400933
934 /* We don't handle mark glyphs here. */
Behdad Esfahbod6617ead2010-04-29 02:25:30 -0400935 if (context->property == HB_OT_LAYOUT_GLYPH_CLASS_MARK)
Behdad Esfahbod0f7e6b22009-05-20 04:16:35 -0400936 return false;
937
938 unsigned int index = (this+coverage) (IN_CURGLYPH ());
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400939 if (likely (index == NOT_COVERED))
Behdad Esfahbod0f7e6b22009-05-20 04:16:35 -0400940 return false;
941
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400942 const EntryExitRecord &record = entryExitRecord[index];
943
Behdad Esfahbodc968fc22009-05-25 04:04:24 -0400944 if (last_pos == HB_OT_LAYOUT_GPOS_NO_LAST || !record.entryAnchor)
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400945 goto end;
946
Behdad Esfahbod6c8108c2009-05-26 22:26:08 -0400947 hb_position_t entry_x, entry_y;
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400948 (this+record.entryAnchor).get_anchor (context->layout, IN_CURGLYPH (), &entry_x, &entry_y);
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400949
Behdad Esfahbodcc83ae12009-05-27 00:17:37 -0400950 /* TODO vertical */
951
Behdad Esfahbod02a37062009-07-29 18:41:25 -0400952 if (buffer->direction == HB_DIRECTION_RTL)
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400953 {
Behdad Esfahbod9db8ad72009-11-06 16:47:31 -0500954 /* advance is absolute, not relative */
955 POSITION (buffer->in_pos)->x_advance = entry_x - gpi->anchor_x;
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400956 }
957 else
958 {
Behdad Esfahbod9db8ad72009-11-06 16:47:31 -0500959 /* advance is absolute, not relative */
960 POSITION (last_pos)->x_advance = gpi->anchor_x - entry_x;
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400961 }
962
Behdad Esfahbod6617ead2010-04-29 02:25:30 -0400963 if (context->lookup_flag & LookupFlag::RightToLeft)
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400964 {
Behdad Esfahbod0f7e6b22009-05-20 04:16:35 -0400965 POSITION (last_pos)->cursive_chain = last_pos - buffer->in_pos;
Behdad Esfahbod9bef3612009-11-05 12:20:11 -0500966 POSITION (last_pos)->y_offset = entry_y - gpi->anchor_y;
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400967 }
968 else
969 {
Behdad Esfahbod0f7e6b22009-05-20 04:16:35 -0400970 POSITION (buffer->in_pos)->cursive_chain = buffer->in_pos - last_pos;
Behdad Esfahbod9bef3612009-11-05 12:20:11 -0500971 POSITION (buffer->in_pos)->y_offset = gpi->anchor_y - entry_y;
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400972 }
973
974 end:
975 if (record.exitAnchor)
Behdad Esfahbod0f7e6b22009-05-20 04:16:35 -0400976 {
977 gpi->last = buffer->in_pos;
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400978 (this+record.exitAnchor).get_anchor (context->layout, IN_CURGLYPH (), &gpi->anchor_x, &gpi->anchor_y);
Behdad Esfahbod0f7e6b22009-05-20 04:16:35 -0400979 }
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400980
981 buffer->in_pos++;
982 return true;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400983 }
984
Behdad Esfahbod39840472010-05-05 00:23:19 -0400985 inline bool sanitize (hb_sanitize_context_t *context) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400986 TRACE_SANITIZE ();
Behdad Esfahbodbb029af2010-05-04 15:28:52 -0400987 return SANITIZE_WITH_BASE (this, coverage)
988 && SANITIZE_WITH_BASE (this, entryExitRecord);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400989 }
990
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400991 private:
992 USHORT format; /* Format identifier--format = 1 */
993 OffsetTo<Coverage>
994 coverage; /* Offset to Coverage table--from
995 * beginning of subtable */
996 ArrayOf<EntryExitRecord>
997 entryExitRecord; /* Array of EntryExit records--in
998 * Coverage Index order */
999};
1000ASSERT_SIZE (CursivePosFormat1, 6);
1001
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001002struct CursivePos
1003{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001004 friend struct PosLookupSubTable;
1005
1006 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001007 inline bool apply (APPLY_ARG_DEF) const
1008 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001009 TRACE_APPLY ();
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001010 switch (u.format) {
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -04001011 case 1: return u.format1->apply (APPLY_ARG);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001012 default:return false;
1013 }
1014 }
1015
Behdad Esfahbod39840472010-05-05 00:23:19 -04001016 inline bool sanitize (hb_sanitize_context_t *context) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001017 TRACE_SANITIZE ();
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001018 if (!SANITIZE (u.format)) return false;
1019 switch (u.format) {
Behdad Esfahbod39840472010-05-05 00:23:19 -04001020 case 1: return u.format1->sanitize (context);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001021 default:return true;
1022 }
1023 }
1024
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001025 private:
1026 union {
1027 USHORT format; /* Format identifier */
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -05001028 CursivePosFormat1 format1[VAR];
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001029 } u;
1030};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001031
1032
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -04001033typedef AnchorMatrix BaseArray; /* base-major--
1034 * in order of BaseCoverage Index--,
1035 * mark-minor--
Behdad Esfahbodfb3b5cc2009-05-21 04:47:05 -04001036 * ordered by class--zero-based. */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001037
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001038struct MarkBasePosFormat1
1039{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001040 friend struct MarkBasePos;
1041
1042 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001043 inline bool apply (APPLY_ARG_DEF) const
1044 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001045 TRACE_APPLY ();
Behdad Esfahbod357ccde2009-05-21 06:32:01 -04001046 unsigned int mark_index = (this+markCoverage) (IN_CURGLYPH ());
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001047 if (likely (mark_index == NOT_COVERED))
Behdad Esfahbod357ccde2009-05-21 06:32:01 -04001048 return false;
1049
1050 /* now we search backwards for a non-mark glyph */
Behdad Esfahbod1376fb72010-04-29 02:19:21 -04001051 unsigned int property;
Behdad Esfahbodb2b18ef2009-08-14 19:37:18 -04001052 unsigned int j = buffer->in_pos;
Behdad Esfahbod0532ed12009-08-12 15:40:04 -04001053 do
Behdad Esfahbod357ccde2009-05-21 06:32:01 -04001054 {
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001055 if (unlikely (!j))
Behdad Esfahbod80ea5bd2009-05-26 17:58:37 -04001056 return false;
Behdad Esfahbodb2b18ef2009-08-14 19:37:18 -04001057 j--;
Behdad Esfahbod63493f92010-05-05 01:01:05 -04001058 } while (_hb_ot_layout_skip_mark (context->layout->face, IN_INFO (j), LookupFlag::IgnoreMarks, &property));
Behdad Esfahbod0532ed12009-08-12 15:40:04 -04001059
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001060#if 0
Behdad Esfahbod80ea5bd2009-05-26 17:58:37 -04001061 /* The following assertion is too strong. */
1062 if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH))
Behdad Esfahbod357ccde2009-05-21 06:32:01 -04001063 return false;
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001064#endif
Behdad Esfahbod357ccde2009-05-21 06:32:01 -04001065
1066 unsigned int base_index = (this+baseCoverage) (IN_GLYPH (j));
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001067 if (base_index == NOT_COVERED)
Behdad Esfahbod357ccde2009-05-21 06:32:01 -04001068 return false;
1069
Behdad Esfahbodb41f2102009-08-14 19:33:24 -04001070 return (this+markArray).apply (APPLY_ARG, mark_index, base_index, this+baseArray, classCount, j);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001071 }
1072
Behdad Esfahbod39840472010-05-05 00:23:19 -04001073 inline bool sanitize (hb_sanitize_context_t *context) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001074 TRACE_SANITIZE ();
Behdad Esfahbodbe742842010-05-04 14:47:05 -04001075 return SANITIZE_SELF ()
Behdad Esfahbodbb029af2010-05-04 15:28:52 -04001076 && SANITIZE_WITH_BASE (this, markCoverage)
1077 && SANITIZE_WITH_BASE (this, baseCoverage)
1078 && SANITIZE_WITH_BASE (this, markArray)
Behdad Esfahbod39840472010-05-05 00:23:19 -04001079 && likely (baseArray.sanitize (context, CharP(this), (unsigned int) classCount));
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001080 }
1081
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001082 private:
1083 USHORT format; /* Format identifier--format = 1 */
Behdad Esfahbodfb3b5cc2009-05-21 04:47:05 -04001084 OffsetTo<Coverage>
1085 markCoverage; /* Offset to MarkCoverage table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001086 * beginning of MarkBasePos subtable */
Behdad Esfahbodfb3b5cc2009-05-21 04:47:05 -04001087 OffsetTo<Coverage>
1088 baseCoverage; /* Offset to BaseCoverage table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001089 * beginning of MarkBasePos subtable */
1090 USHORT classCount; /* Number of classes defined for marks */
Behdad Esfahbodfb3b5cc2009-05-21 04:47:05 -04001091 OffsetTo<MarkArray>
1092 markArray; /* Offset to MarkArray table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001093 * beginning of MarkBasePos subtable */
Behdad Esfahbodfb3b5cc2009-05-21 04:47:05 -04001094 OffsetTo<BaseArray>
1095 baseArray; /* Offset to BaseArray table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001096 * beginning of MarkBasePos subtable */
1097};
1098ASSERT_SIZE (MarkBasePosFormat1, 12);
1099
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001100struct MarkBasePos
1101{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001102 friend struct PosLookupSubTable;
1103
1104 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001105 inline bool apply (APPLY_ARG_DEF) const
1106 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001107 TRACE_APPLY ();
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001108 switch (u.format) {
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -04001109 case 1: return u.format1->apply (APPLY_ARG);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001110 default:return false;
1111 }
1112 }
1113
Behdad Esfahbod39840472010-05-05 00:23:19 -04001114 inline bool sanitize (hb_sanitize_context_t *context) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001115 TRACE_SANITIZE ();
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001116 if (!SANITIZE (u.format)) return false;
1117 switch (u.format) {
Behdad Esfahbod39840472010-05-05 00:23:19 -04001118 case 1: return u.format1->sanitize (context);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001119 default:return true;
1120 }
1121 }
1122
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001123 private:
1124 union {
1125 USHORT format; /* Format identifier */
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -05001126 MarkBasePosFormat1 format1[VAR];
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001127 } u;
1128};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001129
1130
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -04001131typedef AnchorMatrix LigatureAttach; /* component-major--
1132 * in order of writing direction--,
1133 * mark-minor--
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001134 * ordered by class--zero-based. */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001135
Behdad Esfahbod3564ee52009-08-14 18:32:56 -04001136typedef OffsetListOf<LigatureAttach> LigatureArray;
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001137 /* Array of LigatureAttach
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001138 * tables ordered by
1139 * LigatureCoverage Index */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001140
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001141struct MarkLigPosFormat1
1142{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001143 friend struct MarkLigPos;
1144
1145 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001146 inline bool apply (APPLY_ARG_DEF) const
1147 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001148 TRACE_APPLY ();
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001149 unsigned int mark_index = (this+markCoverage) (IN_CURGLYPH ());
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001150 if (likely (mark_index == NOT_COVERED))
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001151 return false;
1152
1153 /* now we search backwards for a non-mark glyph */
Behdad Esfahbod1376fb72010-04-29 02:19:21 -04001154 unsigned int property;
Behdad Esfahbodb2b18ef2009-08-14 19:37:18 -04001155 unsigned int j = buffer->in_pos;
Behdad Esfahbod0532ed12009-08-12 15:40:04 -04001156 do
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001157 {
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001158 if (unlikely (!j))
Behdad Esfahbod80ea5bd2009-05-26 17:58:37 -04001159 return false;
Behdad Esfahbodb2b18ef2009-08-14 19:37:18 -04001160 j--;
Behdad Esfahbod63493f92010-05-05 01:01:05 -04001161 } while (_hb_ot_layout_skip_mark (context->layout->face, IN_INFO (j), LookupFlag::IgnoreMarks, &property));
Behdad Esfahbod0532ed12009-08-12 15:40:04 -04001162
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001163#if 0
Behdad Esfahbod80ea5bd2009-05-26 17:58:37 -04001164 /* The following assertion is too strong. */
1165 if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE))
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001166 return false;
1167#endif
1168
1169 unsigned int lig_index = (this+ligatureCoverage) (IN_GLYPH (j));
1170 if (lig_index == NOT_COVERED)
1171 return false;
1172
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001173 const LigatureArray& lig_array = this+ligatureArray;
Behdad Esfahbod3564ee52009-08-14 18:32:56 -04001174 const LigatureAttach& lig_attach = lig_array[lig_index];
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -04001175
1176 /* Find component to attach to */
Behdad Esfahbodb2b18ef2009-08-14 19:37:18 -04001177 unsigned int comp_count = lig_attach.rows;
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001178 if (unlikely (!comp_count))
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001179 return false;
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001180 unsigned int comp_index;
1181 /* We must now check whether the ligature ID of the current mark glyph
1182 * is identical to the ligature ID of the found ligature. If yes, we
1183 * can directly use the component index. If not, we attach the mark
1184 * glyph to the last component of the ligature. */
Behdad Esfahbodc3f9f7e2009-11-05 16:16:14 -05001185 if (IN_LIGID (j) && IN_LIGID (j) == IN_LIGID (buffer->in_pos) && IN_COMPONENT (buffer->in_pos))
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001186 {
Behdad Esfahbodc3f9f7e2009-11-05 16:16:14 -05001187 comp_index = IN_COMPONENT (buffer->in_pos) - 1;
Behdad Esfahbodb2b18ef2009-08-14 19:37:18 -04001188 if (comp_index >= comp_count)
1189 comp_index = comp_count - 1;
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001190 }
1191 else
Behdad Esfahbodb2b18ef2009-08-14 19:37:18 -04001192 comp_index = comp_count - 1;
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001193
Behdad Esfahbodb41f2102009-08-14 19:33:24 -04001194 return (this+markArray).apply (APPLY_ARG, mark_index, comp_index, lig_attach, classCount, j);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001195 }
1196
Behdad Esfahbod39840472010-05-05 00:23:19 -04001197 inline bool sanitize (hb_sanitize_context_t *context) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001198 TRACE_SANITIZE ();
Behdad Esfahbodbe742842010-05-04 14:47:05 -04001199 return SANITIZE_SELF ()
Behdad Esfahbodbb029af2010-05-04 15:28:52 -04001200 && SANITIZE_WITH_BASE (this, markCoverage)
1201 && SANITIZE_WITH_BASE (this, ligatureCoverage)
1202 && SANITIZE_WITH_BASE (this, markArray)
Behdad Esfahbod39840472010-05-05 00:23:19 -04001203 && likely (ligatureArray.sanitize (context, CharP(this), (unsigned int) classCount));
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001204 }
1205
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001206 private:
1207 USHORT format; /* Format identifier--format = 1 */
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001208 OffsetTo<Coverage>
1209 markCoverage; /* Offset to Mark Coverage table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001210 * beginning of MarkLigPos subtable */
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001211 OffsetTo<Coverage>
1212 ligatureCoverage; /* Offset to Ligature Coverage
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001213 * table--from beginning of MarkLigPos
1214 * subtable */
1215 USHORT classCount; /* Number of defined mark classes */
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001216 OffsetTo<MarkArray>
1217 markArray; /* Offset to MarkArray table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001218 * beginning of MarkLigPos subtable */
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001219 OffsetTo<LigatureArray>
1220 ligatureArray; /* Offset to LigatureArray table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001221 * beginning of MarkLigPos subtable */
1222};
1223ASSERT_SIZE (MarkLigPosFormat1, 12);
1224
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001225struct MarkLigPos
1226{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001227 friend struct PosLookupSubTable;
1228
1229 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001230 inline bool apply (APPLY_ARG_DEF) const
1231 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001232 TRACE_APPLY ();
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001233 switch (u.format) {
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -04001234 case 1: return u.format1->apply (APPLY_ARG);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001235 default:return false;
1236 }
1237 }
1238
Behdad Esfahbod39840472010-05-05 00:23:19 -04001239 inline bool sanitize (hb_sanitize_context_t *context) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001240 TRACE_SANITIZE ();
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001241 if (!SANITIZE (u.format)) return false;
1242 switch (u.format) {
Behdad Esfahbod39840472010-05-05 00:23:19 -04001243 case 1: return u.format1->sanitize (context);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001244 default:return true;
1245 }
1246 }
1247
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001248 private:
1249 union {
1250 USHORT format; /* Format identifier */
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -05001251 MarkLigPosFormat1 format1[VAR];
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001252 } u;
1253};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001254
1255
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -04001256typedef AnchorMatrix Mark2Array; /* mark2-major--
1257 * in order of Mark2Coverage Index--,
1258 * mark1-minor--
1259 * ordered by class--zero-based. */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001260
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001261struct MarkMarkPosFormat1
1262{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001263 friend struct MarkMarkPos;
1264
1265 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001266 inline bool apply (APPLY_ARG_DEF) const
1267 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001268 TRACE_APPLY ();
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001269 unsigned int mark1_index = (this+mark1Coverage) (IN_CURGLYPH ());
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001270 if (likely (mark1_index == NOT_COVERED))
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001271 return false;
1272
1273 /* now we search backwards for a suitable mark glyph until a non-mark glyph */
Behdad Esfahbod1376fb72010-04-29 02:19:21 -04001274 unsigned int property;
Behdad Esfahbodb2b18ef2009-08-14 19:37:18 -04001275 unsigned int j = buffer->in_pos;
Behdad Esfahbod0532ed12009-08-12 15:40:04 -04001276 do
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001277 {
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001278 if (unlikely (!j))
Behdad Esfahbod80ea5bd2009-05-26 17:58:37 -04001279 return false;
Behdad Esfahbodb2b18ef2009-08-14 19:37:18 -04001280 j--;
Behdad Esfahbod63493f92010-05-05 01:01:05 -04001281 } while (_hb_ot_layout_skip_mark (context->layout->face, IN_INFO (j), context->lookup_flag, &property));
Behdad Esfahbod0532ed12009-08-12 15:40:04 -04001282
Behdad Esfahbod80ea5bd2009-05-26 17:58:37 -04001283 if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
1284 return false;
1285
1286 /* Two marks match only if they belong to the same base, or same component
Behdad Esfahbodc3f9f7e2009-11-05 16:16:14 -05001287 * of the same ligature. That is, the component numbers must match, and
1288 * if those are non-zero, the ligid number should also match. */
1289 if ((IN_COMPONENT (j) != IN_COMPONENT (buffer->in_pos)) ||
1290 (IN_COMPONENT (j) && IN_LIGID (j) != IN_LIGID (buffer->in_pos)))
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001291 return false;
1292
1293 unsigned int mark2_index = (this+mark2Coverage) (IN_GLYPH (j));
1294 if (mark2_index == NOT_COVERED)
1295 return false;
1296
Behdad Esfahbodb41f2102009-08-14 19:33:24 -04001297 return (this+mark1Array).apply (APPLY_ARG, mark1_index, mark2_index, this+mark2Array, classCount, j);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001298 }
1299
Behdad Esfahbod39840472010-05-05 00:23:19 -04001300 inline bool sanitize (hb_sanitize_context_t *context) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001301 TRACE_SANITIZE ();
Behdad Esfahbodbe742842010-05-04 14:47:05 -04001302 return SANITIZE_SELF ()
Behdad Esfahbodbb029af2010-05-04 15:28:52 -04001303 && SANITIZE_WITH_BASE (this, mark1Coverage)
1304 && SANITIZE_WITH_BASE (this, mark2Coverage)
1305 && SANITIZE_WITH_BASE (this, mark1Array)
Behdad Esfahbod39840472010-05-05 00:23:19 -04001306 && likely (mark2Array.sanitize (context, CharP(this), (unsigned int) classCount));
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001307 }
1308
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001309 private:
1310 USHORT format; /* Format identifier--format = 1 */
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001311 OffsetTo<Coverage>
1312 mark1Coverage; /* Offset to Combining Mark1 Coverage
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001313 * table--from beginning of MarkMarkPos
1314 * subtable */
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001315 OffsetTo<Coverage>
1316 mark2Coverage; /* Offset to Combining Mark2 Coverage
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001317 * table--from beginning of MarkMarkPos
1318 * subtable */
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001319 USHORT classCount; /* Number of defined mark classes */
1320 OffsetTo<MarkArray>
1321 mark1Array; /* Offset to Mark1Array table--from
1322 * beginning of MarkMarkPos subtable */
1323 OffsetTo<Mark2Array>
1324 mark2Array; /* Offset to Mark2Array table--from
1325 * beginning of MarkMarkPos subtable */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001326};
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001327ASSERT_SIZE (MarkMarkPosFormat1, 12);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001328
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001329struct MarkMarkPos
1330{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001331 friend struct PosLookupSubTable;
1332
1333 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001334 inline bool apply (APPLY_ARG_DEF) const
1335 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001336 TRACE_APPLY ();
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001337 switch (u.format) {
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -04001338 case 1: return u.format1->apply (APPLY_ARG);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001339 default:return false;
1340 }
1341 }
1342
Behdad Esfahbod39840472010-05-05 00:23:19 -04001343 inline bool sanitize (hb_sanitize_context_t *context) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001344 TRACE_SANITIZE ();
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001345 if (!SANITIZE (u.format)) return false;
1346 switch (u.format) {
Behdad Esfahbod39840472010-05-05 00:23:19 -04001347 case 1: return u.format1->sanitize (context);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001348 default:return true;
1349 }
1350 }
1351
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001352 private:
1353 union {
1354 USHORT format; /* Format identifier */
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -05001355 MarkMarkPosFormat1 format1[VAR];
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001356 } u;
1357};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001358
1359
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -04001360static inline bool position_lookup (APPLY_ARG_DEF, unsigned int lookup_index);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001361
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001362struct ContextPos : Context
1363{
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04001364 friend struct PosLookupSubTable;
1365
1366 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001367 inline bool apply (APPLY_ARG_DEF) const
Behdad Esfahbod0535b502009-08-28 17:14:33 -04001368 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001369 TRACE_APPLY ();
Behdad Esfahbod0535b502009-08-28 17:14:33 -04001370 return Context::apply (APPLY_ARG, position_lookup);
1371 }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001372};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001373
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001374struct ChainContextPos : ChainContext
1375{
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04001376 friend struct PosLookupSubTable;
1377
1378 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001379 inline bool apply (APPLY_ARG_DEF) const
Behdad Esfahbod0535b502009-08-28 17:14:33 -04001380 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001381 TRACE_APPLY ();
Behdad Esfahbod0535b502009-08-28 17:14:33 -04001382 return ChainContext::apply (APPLY_ARG, position_lookup);
1383 }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001384};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001385
1386
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04001387struct ExtensionPos : Extension
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001388{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001389 friend struct PosLookupSubTable;
1390
1391 private:
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001392 inline const struct PosLookupSubTable& get_subtable (void) const
Behdad Esfahbod3b2c2df2010-04-22 16:51:42 -04001393 {
1394 unsigned int offset = get_offset ();
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001395 if (unlikely (!offset)) return Null(PosLookupSubTable);
Behdad Esfahboda3263aa2010-04-22 18:29:09 -04001396 return StructAtOffset<PosLookupSubTable> (*this, offset);
Behdad Esfahbod3b2c2df2010-04-22 16:51:42 -04001397 }
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001398
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04001399 inline bool apply (APPLY_ARG_DEF) const;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001400
Behdad Esfahbod39840472010-05-05 00:23:19 -04001401 inline bool sanitize (hb_sanitize_context_t *context);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001402};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001403
1404
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04001405
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001406/*
1407 * PosLookup
1408 */
1409
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001410
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001411struct PosLookupSubTable
1412{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001413 friend struct PosLookup;
1414
Behdad Esfahbodff05d252009-05-20 03:53:00 -04001415 enum {
1416 Single = 1,
1417 Pair = 2,
1418 Cursive = 3,
1419 MarkBase = 4,
1420 MarkLig = 5,
1421 MarkMark = 6,
1422 Context = 7,
1423 ChainContext = 8,
Behdad Esfahbod8f034d52009-08-18 16:41:59 -04001424 Extension = 9
Behdad Esfahbodff05d252009-05-20 03:53:00 -04001425 };
1426
Behdad Esfahbod20b035d2009-08-10 19:00:36 -04001427 inline bool apply (APPLY_ARG_DEF, unsigned int lookup_type) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001428 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001429 TRACE_APPLY ();
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001430 switch (lookup_type) {
Behdad Esfahbodff05d252009-05-20 03:53:00 -04001431 case Single: return u.single->apply (APPLY_ARG);
1432 case Pair: return u.pair->apply (APPLY_ARG);
1433 case Cursive: return u.cursive->apply (APPLY_ARG);
1434 case MarkBase: return u.markBase->apply (APPLY_ARG);
1435 case MarkLig: return u.markLig->apply (APPLY_ARG);
1436 case MarkMark: return u.markMark->apply (APPLY_ARG);
1437 case Context: return u.context->apply (APPLY_ARG);
1438 case ChainContext: return u.chainContext->apply (APPLY_ARG);
1439 case Extension: return u.extension->apply (APPLY_ARG);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001440 default:return false;
1441 }
1442 }
1443
Behdad Esfahbod39840472010-05-05 00:23:19 -04001444 inline bool sanitize (hb_sanitize_context_t *context) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001445 TRACE_SANITIZE ();
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001446 if (!SANITIZE (u.format)) return false;
1447 switch (u.format) {
Behdad Esfahbod39840472010-05-05 00:23:19 -04001448 case Single: return u.single->sanitize (context);
1449 case Pair: return u.pair->sanitize (context);
1450 case Cursive: return u.cursive->sanitize (context);
1451 case MarkBase: return u.markBase->sanitize (context);
1452 case MarkLig: return u.markLig->sanitize (context);
1453 case MarkMark: return u.markMark->sanitize (context);
1454 case Context: return u.context->sanitize (context);
1455 case ChainContext: return u.chainContext->sanitize (context);
1456 case Extension: return u.extension->sanitize (context);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001457 default:return true;
1458 }
1459 }
1460
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001461 private:
1462 union {
Behdad Esfahbodff05d252009-05-20 03:53:00 -04001463 USHORT format;
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -05001464 SinglePos single[VAR];
1465 PairPos pair[VAR];
1466 CursivePos cursive[VAR];
1467 MarkBasePos markBase[VAR];
1468 MarkLigPos markLig[VAR];
1469 MarkMarkPos markMark[VAR];
1470 ContextPos context[VAR];
1471 ChainContextPos chainContext[VAR];
1472 ExtensionPos extension[VAR];
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001473 } u;
1474};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001475
1476
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001477struct PosLookup : Lookup
1478{
1479 inline const PosLookupSubTable& get_subtable (unsigned int i) const
Behdad Esfahbod187454c2010-04-23 16:35:01 -04001480 { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001481
Behdad Esfahbod63493f92010-05-05 01:01:05 -04001482 inline bool apply_once (hb_ot_layout_context_t *layout,
Behdad Esfahbod923923f2009-05-22 17:58:09 -04001483 hb_buffer_t *buffer,
1484 unsigned int context_length,
Behdad Esfahbod173fde72010-04-29 01:47:30 -04001485 unsigned int nesting_level_left,
1486 unsigned int apply_depth) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001487 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001488 unsigned int lookup_type = get_type ();
Behdad Esfahbod6617ead2010-04-29 02:25:30 -04001489 hb_apply_context_t context[1];
Behdad Esfahbod923923f2009-05-22 17:58:09 -04001490
Behdad Esfahbod63493f92010-05-05 01:01:05 -04001491 context->layout = layout;
Behdad Esfahbod6617ead2010-04-29 02:25:30 -04001492 context->nesting_level_left = nesting_level_left;
1493 context->lookup_flag = get_flag ();
Behdad Esfahbod1376fb72010-04-29 02:19:21 -04001494
Behdad Esfahbod63493f92010-05-05 01:01:05 -04001495 if (!_hb_ot_layout_check_glyph_property (context->layout->face, IN_CURINFO (), context->lookup_flag, &context->property))
Behdad Esfahbod923923f2009-05-22 17:58:09 -04001496 return false;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001497
1498 for (unsigned int i = 0; i < get_subtable_count (); i++)
Behdad Esfahbod173fde72010-04-29 01:47:30 -04001499 if (get_subtable (i).apply (APPLY_ARG, lookup_type))
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001500 return true;
1501
1502 return false;
1503 }
1504
Behdad Esfahbod63493f92010-05-05 01:01:05 -04001505 inline bool apply_string (hb_ot_layout_context_t *layout,
Behdad Esfahbod20b035d2009-08-10 19:00:36 -04001506 hb_buffer_t *buffer,
1507 hb_mask_t mask) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001508 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001509 bool ret = false;
1510
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001511 if (unlikely (!buffer->in_length))
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001512 return false;
1513
Behdad Esfahbod63493f92010-05-05 01:01:05 -04001514 layout->info.gpos.last = HB_OT_LAYOUT_GPOS_NO_LAST; /* no last valid glyph for cursive pos. */
Behdad Esfahbod9c42f052009-05-18 17:43:49 -04001515
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001516 buffer->in_pos = 0;
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001517 while (buffer->in_pos < buffer->in_length)
1518 {
Behdad Esfahbod9c42f052009-05-18 17:43:49 -04001519 bool done;
Behdad Esfahbod468769b2009-08-08 16:53:23 -04001520 if (~IN_MASK (buffer->in_pos) & mask)
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001521 {
Behdad Esfahbod63493f92010-05-05 01:01:05 -04001522 done = apply_once (layout, buffer, NO_CONTEXT, MAX_NESTING_LEVEL, 0);
Behdad Esfahbod9c42f052009-05-18 17:43:49 -04001523 ret |= done;
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001524 }
1525 else
1526 {
Behdad Esfahbod9c42f052009-05-18 17:43:49 -04001527 done = false;
1528 /* Contrary to properties defined in GDEF, user-defined properties
1529 will always stop a possible cursive positioning. */
Behdad Esfahbod63493f92010-05-05 01:01:05 -04001530 layout->info.gpos.last = HB_OT_LAYOUT_GPOS_NO_LAST;
Behdad Esfahbod9c42f052009-05-18 17:43:49 -04001531 }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001532
Behdad Esfahbod9c42f052009-05-18 17:43:49 -04001533 if (!done)
1534 buffer->in_pos++;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001535 }
1536
1537 return ret;
1538 }
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001539
Behdad Esfahbod39840472010-05-05 00:23:19 -04001540 inline bool sanitize (hb_sanitize_context_t *context) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001541 TRACE_SANITIZE ();
Behdad Esfahbod39840472010-05-05 00:23:19 -04001542 if (unlikely (!Lookup::sanitize (context))) return false;
Behdad Esfahbod187454c2010-04-23 16:35:01 -04001543 OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable);
Behdad Esfahbodbb029af2010-05-04 15:28:52 -04001544 return SANITIZE_WITH_BASE (this, list);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001545 }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001546};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001547
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001548typedef OffsetListOf<PosLookup> PosLookupList;
1549ASSERT_SIZE (PosLookupList, 2);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001550
1551/*
1552 * GPOS
1553 */
1554
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001555struct GPOS : GSUBGPOS
1556{
Behdad Esfahboda328d662009-08-04 20:27:05 -04001557 static const hb_tag_t Tag = HB_OT_TAG_GPOS;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001558
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001559 inline const PosLookup& get_lookup (unsigned int i) const
Behdad Esfahbod187454c2010-04-23 16:35:01 -04001560 { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001561
Behdad Esfahbod63493f92010-05-05 01:01:05 -04001562 inline bool position_lookup (hb_ot_layout_context_t *layout,
Behdad Esfahbod468769b2009-08-08 16:53:23 -04001563 hb_buffer_t *buffer,
1564 unsigned int lookup_index,
1565 hb_mask_t mask) const
Behdad Esfahbod63493f92010-05-05 01:01:05 -04001566 { return get_lookup (lookup_index).apply_string (layout, buffer, mask); }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001567
Behdad Esfahbod39840472010-05-05 00:23:19 -04001568 inline bool sanitize (hb_sanitize_context_t *context) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001569 TRACE_SANITIZE ();
Behdad Esfahbod39840472010-05-05 00:23:19 -04001570 if (unlikely (!GSUBGPOS::sanitize (context))) return false;
Behdad Esfahbod187454c2010-04-23 16:35:01 -04001571 OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
Behdad Esfahbodbb029af2010-05-04 15:28:52 -04001572 return SANITIZE_WITH_BASE (this, list);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001573 }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001574};
1575ASSERT_SIZE (GPOS, 10);
1576
1577
1578/* Out-of-class implementation for methods recursing */
1579
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04001580inline bool ExtensionPos::apply (APPLY_ARG_DEF) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001581{
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001582 TRACE_APPLY ();
Behdad Esfahboda065f472010-04-22 20:15:11 -04001583 return get_subtable ().apply (APPLY_ARG, get_type ());
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001584}
1585
Behdad Esfahbod39840472010-05-05 00:23:19 -04001586inline bool ExtensionPos::sanitize (hb_sanitize_context_t *context)
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001587{
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001588 TRACE_SANITIZE ();
Behdad Esfahbod39840472010-05-05 00:23:19 -04001589 if (unlikely (!Extension::sanitize (context))) return false;
Behdad Esfahbod3b2c2df2010-04-22 16:51:42 -04001590 unsigned int offset = get_offset ();
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001591 if (unlikely (!offset)) return true;
Behdad Esfahboda3263aa2010-04-22 18:29:09 -04001592 return SANITIZE (StructAtOffset<PosLookupSubTable> (*this, offset));
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001593}
1594
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001595static inline bool position_lookup (APPLY_ARG_DEF, unsigned int lookup_index)
1596{
Behdad Esfahbod63493f92010-05-05 01:01:05 -04001597 const GPOS &gpos = *(context->layout->face->ot_layout.gpos);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001598 const PosLookup &l = gpos.get_lookup (lookup_index);
1599
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001600 if (unlikely (context->nesting_level_left == 0))
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001601 return false;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001602
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001603 if (unlikely (context_length < 1))
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001604 return false;
1605
Behdad Esfahbod63493f92010-05-05 01:01:05 -04001606 return l.apply_once (context->layout, buffer, context_length, context->nesting_level_left - 1, apply_depth + 1);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001607}
1608
1609
Behdad Esfahbod5f5b24f2009-08-02 20:03:12 -04001610#endif /* HB_OT_LAYOUT_GPOS_PRIVATE_HH */