blob: 1860b098b5aaab7fa613336b219fed47765e0888 [file] [log] [blame]
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001/*
Behdad Esfahbod41a93d22010-05-06 12:55:14 -04002 * Copyright (C) 2007,2008,2009,2010 Red Hat, Inc.
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04003 *
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 Esfahbodacdba3f2010-07-23 15:11:18 -040032HB_BEGIN_DECLS
33
Behdad Esfahbod94a23aa2010-05-05 01:13:09 -040034
Behdad Esfahbodc968fc22009-05-25 04:04:24 -040035#define HB_OT_LAYOUT_GPOS_NO_LAST ((unsigned int) -1)
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040036
37/* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
38
Behdad Esfahbodc2ddfd22010-05-06 13:06:15 -040039typedef USHORT Value;
Behdad Esfahbodc91facd2009-08-26 18:53:43 -040040
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -040041typedef Value ValueRecord[VAR];
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040042
Behdad Esfahbodfca6a0d2009-05-21 04:49:04 -040043struct ValueFormat : USHORT
44{
45 enum
46 {
47 xPlacement = 0x0001, /* Includes horizontal adjustment for placement */
48 yPlacement = 0x0002, /* Includes vertical adjustment for placement */
49 xAdvance = 0x0004, /* Includes horizontal adjustment for advance */
50 yAdvance = 0x0008, /* Includes vertical adjustment for advance */
51 xPlaDevice = 0x0010, /* Includes horizontal Device table for placement */
52 yPlaDevice = 0x0020, /* Includes vertical Device table for placement */
53 xAdvDevice = 0x0040, /* Includes horizontal Device table for advance */
54 yAdvDevice = 0x0080, /* Includes vertical Device table for advance */
Behdad Esfahbode4b92b82009-05-26 15:38:53 -040055 ignored = 0x0F00, /* Was used in TrueType Open for MM fonts */
Behdad Esfahbodeba8b4f2010-03-29 00:04:12 -040056 reserved = 0xF000, /* For future use */
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -040057
Behdad Esfahbodeba8b4f2010-03-29 00:04:12 -040058 devices = 0x00F0 /* Mask for having any Device table */
Behdad Esfahbodfca6a0d2009-05-21 04:49:04 -040059 };
60
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -040061/* All fields are options. Only those available advance the value pointer. */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040062#if 0
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040063 SHORT xPlacement; /* Horizontal adjustment for
64 * placement--in design units */
65 SHORT yPlacement; /* Vertical adjustment for
66 * placement--in design units */
67 SHORT xAdvance; /* Horizontal adjustment for
68 * advance--in design units (only used
69 * for horizontal writing) */
70 SHORT yAdvance; /* Vertical adjustment for advance--in
71 * design units (only used for vertical
72 * writing) */
73 Offset xPlaDevice; /* Offset to Device table for
74 * horizontal placement--measured from
75 * beginning of PosTable (may be NULL) */
76 Offset yPlaDevice; /* Offset to Device table for vertical
77 * placement--measured from beginning
78 * of PosTable (may be NULL) */
79 Offset xAdvDevice; /* Offset to Device table for
80 * horizontal advance--measured from
81 * beginning of PosTable (may be NULL) */
82 Offset yAdvDevice; /* Offset to Device table for vertical
83 * advance--measured from beginning of
84 * PosTable (may be NULL) */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040085#endif
86
Behdad Esfahbod7f97d2c2010-10-01 18:58:50 -040087 inline unsigned int get_len (void) const
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -040088 { return _hb_popcount32 ((unsigned int) *this); }
Behdad Esfahbod7f97d2c2010-10-01 18:58:50 -040089 inline unsigned int get_size (void) const
Behdad Esfahbode45d3f82010-05-06 19:33:31 -040090 { return get_len () * Value::static_size; }
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -040091
Behdad Esfahbod63493f92010-05-05 01:01:05 -040092 void apply_value (hb_ot_layout_context_t *layout,
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -040093 const void *base,
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -040094 const Value *values,
Behdad Esfahbod31093752010-05-14 19:55:27 -040095 hb_internal_glyph_position_t &glyph_pos) const
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -040096 {
97 unsigned int x_ppem, y_ppem;
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -040098 unsigned int format = *this;
99
100 if (!format) return;
101
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400102 /* design units -> fractional pixel */
Behdad Esfahbod0a4399c2010-05-19 15:45:06 -0400103 if (format & xPlacement) glyph_pos.x_offset += layout->scale_x (get_short (values++));
104 if (format & yPlacement) glyph_pos.y_offset += layout->scale_y (get_short (values++));
105 if (format & xAdvance) glyph_pos.x_advance += layout->scale_x (get_short (values++));
106 if (format & yAdvance) glyph_pos.y_advance += layout->scale_y (get_short (values++));
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400107
Behdad Esfahboda8d960b2010-04-29 14:31:56 -0400108 if (!has_device ()) return;
109
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400110 x_ppem = layout->font->x_ppem;
111 y_ppem = layout->font->y_ppem;
Behdad Esfahboda8d960b2010-04-29 14:31:56 -0400112
113 if (!x_ppem && !y_ppem) return;
114
Behdad Esfahbod0090dc02009-07-30 16:28:45 -0400115 /* pixel -> fractional pixel */
116 if (format & xPlaDevice) {
Behdad Esfahbodb634beb2010-05-20 17:44:52 +0100117 if (x_ppem) glyph_pos.x_offset += (base + get_device (values++)).get_x_delta (layout); else values++;
Behdad Esfahbod0090dc02009-07-30 16:28:45 -0400118 }
119 if (format & yPlaDevice) {
Behdad Esfahbodb634beb2010-05-20 17:44:52 +0100120 if (y_ppem) glyph_pos.y_offset += (base + get_device (values++)).get_y_delta (layout); else values++;
Behdad Esfahbod0090dc02009-07-30 16:28:45 -0400121 }
122 if (format & xAdvDevice) {
Behdad Esfahbodb634beb2010-05-20 17:44:52 +0100123 if (x_ppem) glyph_pos.x_advance += (base + get_device (values++)).get_x_delta (layout); else values++;
Behdad Esfahbod0090dc02009-07-30 16:28:45 -0400124 }
125 if (format & yAdvDevice) {
Behdad Esfahbodb634beb2010-05-20 17:44:52 +0100126 if (y_ppem) glyph_pos.y_advance += (base + get_device (values++)).get_y_delta (layout); else values++;
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400127 }
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400128 }
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400129
130 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400131 inline bool sanitize_value_devices (hb_sanitize_context_t *c, void *base, Value *values) {
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400132 unsigned int format = *this;
133
134 if (format & xPlacement) values++;
135 if (format & yPlacement) values++;
136 if (format & xAdvance) values++;
137 if (format & yAdvance) values++;
138
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400139 if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
140 if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
141 if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
142 if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400143
144 return true;
145 }
146
Behdad Esfahbodc2ddfd22010-05-06 13:06:15 -0400147 static inline OffsetTo<Device>& get_device (Value* value)
148 { return *CastP<OffsetTo<Device> > (value); }
149 static inline const OffsetTo<Device>& get_device (const Value* value)
150 { return *CastP<OffsetTo<Device> > (value); }
151
152 static inline const SHORT& get_short (const Value* value)
153 { return *CastP<SHORT> (value); }
154
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400155 public:
156
Behdad Esfahbod7f97d2c2010-10-01 18:58:50 -0400157 inline bool has_device (void) const {
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400158 unsigned int format = *this;
159 return (format & devices) != 0;
160 }
161
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400162 inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *values) {
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400163 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400164 return c->check_range (values, get_size ())
165 && (!has_device () || sanitize_value_devices (c, base, values));
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400166 }
167
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400168 inline bool sanitize_values (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count) {
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400169 TRACE_SANITIZE ();
170 unsigned int len = get_len ();
171
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400172 if (!c->check_array (values, get_size (), count)) return false;
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400173
174 if (!has_device ()) return true;
175
176 for (unsigned int i = 0; i < count; i++) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400177 if (!sanitize_value_devices (c, base, values))
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400178 return false;
179 values += len;
180 }
181
182 return true;
183 }
184
Behdad Esfahbod278a91f2010-04-22 13:59:39 -0400185 /* Just sanitize referenced Device tables. Doesn't check the values themselves. */
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400186 inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count, unsigned int stride) {
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400187 TRACE_SANITIZE ();
188
189 if (!has_device ()) return true;
190
191 for (unsigned int i = 0; i < count; i++) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400192 if (!sanitize_value_devices (c, base, values))
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400193 return false;
194 values += stride;
195 }
196
197 return true;
198 }
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400199};
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400200
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400201
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400202struct AnchorFormat1
203{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400204 friend struct Anchor;
205
206 private:
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400207 inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id HB_UNUSED,
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400208 hb_position_t *x, hb_position_t *y) const
209 {
Behdad Esfahbod0a4399c2010-05-19 15:45:06 -0400210 *x = layout->scale_x (xCoordinate);
211 *y = layout->scale_y (yCoordinate);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400212 }
213
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400214 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400215 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400216 return c->check_struct (this);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400217 }
218
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400219 private:
220 USHORT format; /* Format identifier--format = 1 */
221 SHORT xCoordinate; /* Horizontal value--in design units */
222 SHORT yCoordinate; /* Vertical value--in design units */
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400223 public:
224 DEFINE_SIZE_STATIC (6);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400225};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400226
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400227struct AnchorFormat2
228{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400229 friend struct Anchor;
230
231 private:
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400232 inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id,
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400233 hb_position_t *x, hb_position_t *y) const
234 {
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400235 unsigned int x_ppem = layout->font->x_ppem;
236 unsigned int y_ppem = layout->font->y_ppem;
Behdad Esfahbod6f729b42010-04-29 03:59:06 -0400237 hb_position_t cx, cy;
238 hb_bool_t ret;
239
240 if (x_ppem || y_ppem)
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400241 ret = hb_font_get_contour_point (layout->font, layout->face, anchorPoint, glyph_id, &cx, &cy);
Behdad Esfahbod0a4399c2010-05-19 15:45:06 -0400242 *x = x_ppem && ret ? cx : layout->scale_x (xCoordinate);
243 *y = y_ppem && ret ? cy : layout->scale_y (yCoordinate);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400244 }
245
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400246 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400247 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400248 return c->check_struct (this);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400249 }
250
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400251 private:
252 USHORT format; /* Format identifier--format = 2 */
253 SHORT xCoordinate; /* Horizontal value--in design units */
254 SHORT yCoordinate; /* Vertical value--in design units */
255 USHORT anchorPoint; /* Index to glyph contour point */
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400256 public:
257 DEFINE_SIZE_STATIC (8);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400258};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400259
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400260struct AnchorFormat3
261{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400262 friend struct Anchor;
263
264 private:
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400265 inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id HB_UNUSED,
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400266 hb_position_t *x, hb_position_t *y) const
267 {
Behdad Esfahbod0a4399c2010-05-19 15:45:06 -0400268 *x = layout->scale_x (xCoordinate);
269 *y = layout->scale_y (yCoordinate);
Behdad Esfahbodc18ec2b2009-05-21 04:54:01 -0400270
Behdad Esfahbod4b8487d2010-03-16 03:46:17 -0400271 /* pixel -> fractional pixel */
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400272 if (layout->font->x_ppem)
Behdad Esfahbodb634beb2010-05-20 17:44:52 +0100273 *x += (this+xDeviceTable).get_x_delta (layout);
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400274 if (layout->font->y_ppem)
Behdad Esfahbodb634beb2010-05-20 17:44:52 +0100275 *y += (this+yDeviceTable).get_x_delta (layout);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400276 }
277
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400278 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400279 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400280 return c->check_struct (this)
281 && xDeviceTable.sanitize (c, this)
282 && yDeviceTable.sanitize (c, this);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400283 }
284
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400285 private:
286 USHORT format; /* Format identifier--format = 3 */
287 SHORT xCoordinate; /* Horizontal value--in design units */
288 SHORT yCoordinate; /* Vertical value--in design units */
289 OffsetTo<Device>
290 xDeviceTable; /* Offset to Device table for X
291 * coordinate-- from beginning of
292 * Anchor table (may be NULL) */
293 OffsetTo<Device>
294 yDeviceTable; /* Offset to Device table for Y
295 * coordinate-- from beginning of
296 * Anchor table (may be NULL) */
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400297 public:
298 DEFINE_SIZE_STATIC (10);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400299};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400300
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400301struct Anchor
302{
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400303 inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id,
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400304 hb_position_t *x, hb_position_t *y) const
305 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400306 *x = *y = 0;
307 switch (u.format) {
Behdad Esfahboddacebca2010-05-10 19:45:41 -0400308 case 1: u.format1.get_anchor (layout, glyph_id, x, y); return;
309 case 2: u.format2.get_anchor (layout, glyph_id, x, y); return;
310 case 3: u.format3.get_anchor (layout, glyph_id, x, y); return;
Behdad Esfahbod63493f92010-05-05 01:01:05 -0400311 default: return;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400312 }
313 }
314
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400315 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400316 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400317 if (!u.format.sanitize (c)) return false;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400318 switch (u.format) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400319 case 1: return u.format1.sanitize (c);
320 case 2: return u.format2.sanitize (c);
321 case 3: return u.format3.sanitize (c);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400322 default:return true;
323 }
324 }
325
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400326 private:
327 union {
328 USHORT format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -0400329 AnchorFormat1 format1;
330 AnchorFormat2 format2;
331 AnchorFormat3 format3;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400332 } u;
Behdad Esfahboded074222010-05-10 18:08:46 -0400333 public:
Behdad Esfahbod596e4712010-05-10 18:47:48 -0400334 DEFINE_SIZE_UNION (2, format);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400335};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400336
337
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400338struct AnchorMatrix
339{
340 inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols) const {
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400341 if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400342 return this+matrix[row * cols + col];
343 }
344
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400345 inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400346 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400347 if (!c->check_struct (this)) return false;
Behdad Esfahbod258305c2010-08-13 14:10:02 -0400348 if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return false;
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400349 unsigned int count = rows * cols;
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400350 if (!c->check_array (matrix, matrix[0].static_size, count)) return false;
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400351 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400352 if (!matrix[i].sanitize (c, this)) return false;
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400353 return true;
354 }
355
356 USHORT rows; /* Number of rows */
357 private:
358 OffsetTo<Anchor>
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -0500359 matrix[VAR]; /* Matrix of offsets to Anchor tables--
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400360 * from beginning of AnchorMatrix table */
Behdad Esfahbod569da922010-05-10 16:38:32 -0400361 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400362 DEFINE_SIZE_ARRAY (2, matrix);
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400363};
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400364
365
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400366struct MarkRecord
367{
Behdad Esfahbod377bfc52009-05-21 04:58:24 -0400368 friend struct MarkArray;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400369
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400370 inline bool sanitize (hb_sanitize_context_t *c, void *base) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400371 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400372 return c->check_struct (this)
373 && markAnchor.sanitize (c, base);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400374 }
375
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400376 private:
377 USHORT klass; /* Class defined for this mark */
378 OffsetTo<Anchor>
379 markAnchor; /* Offset to Anchor table--from
380 * beginning of MarkArray table */
Behdad Esfahbod569da922010-05-10 16:38:32 -0400381 public:
382 DEFINE_SIZE_STATIC (4);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400383};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400384
Behdad Esfahbodbea34c72010-05-10 17:28:16 -0400385struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage order */
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400386{
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400387 inline bool apply (hb_apply_context_t *c,
Behdad Esfahbodb41f2102009-08-14 19:33:24 -0400388 unsigned int mark_index, unsigned int glyph_index,
389 const AnchorMatrix &anchors, unsigned int class_count,
390 unsigned int glyph_pos) const
391 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400392 TRACE_APPLY ();
Behdad Esfahbodbea34c72010-05-10 17:28:16 -0400393 const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
Behdad Esfahbodb41f2102009-08-14 19:33:24 -0400394 unsigned int mark_class = record.klass;
395
396 const Anchor& mark_anchor = this + record.markAnchor;
397 const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count);
398
399 hb_position_t mark_x, mark_y, base_x, base_y;
400
Behdad Esfahbod36b73c82010-05-14 22:10:39 -0400401 mark_anchor.get_anchor (c->layout, c->buffer->info[c->buffer->i].codepoint, &mark_x, &mark_y);
Behdad Esfahbod7e7007a2010-05-14 22:02:37 -0400402 glyph_anchor.get_anchor (c->layout, c->buffer->info[glyph_pos].codepoint, &base_x, &base_y);
Behdad Esfahbodb41f2102009-08-14 19:33:24 -0400403
Behdad Esfahbod36b73c82010-05-14 22:10:39 -0400404 hb_internal_glyph_position_t &o = c->buffer->pos[c->buffer->i];
Behdad Esfahbod31093752010-05-14 19:55:27 -0400405 o.x_offset = base_x - mark_x;
406 o.y_offset = base_y - mark_y;
Behdad Esfahbod36b73c82010-05-14 22:10:39 -0400407 o.back = c->buffer->i - glyph_pos;
Behdad Esfahbodb41f2102009-08-14 19:33:24 -0400408
Behdad Esfahbod36b73c82010-05-14 22:10:39 -0400409 c->buffer->i++;
Behdad Esfahbodb41f2102009-08-14 19:33:24 -0400410 return true;
411 }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400412
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400413 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400414 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400415 return ArrayOf<MarkRecord>::sanitize (c, this);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400416 }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400417};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400418
419
420/* Lookups */
421
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400422struct SinglePosFormat1
423{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400424 friend struct SinglePos;
425
426 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400427 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400428 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400429 TRACE_APPLY ();
Behdad Esfahbod36b73c82010-05-14 22:10:39 -0400430 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400431 if (likely (index == NOT_COVERED))
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400432 return false;
433
Behdad Esfahbod36b73c82010-05-14 22:10:39 -0400434 valueFormat.apply_value (c->layout, this, values, c->buffer->pos[c->buffer->i]);
Behdad Esfahbodf53d4342009-05-30 22:17:32 -0400435
Behdad Esfahbod36b73c82010-05-14 22:10:39 -0400436 c->buffer->i++;
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400437 return true;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400438 }
439
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400440 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400441 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400442 return c->check_struct (this)
443 && coverage.sanitize (c, this)
444 && valueFormat.sanitize_value (c, this, values);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400445 }
446
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400447 private:
448 USHORT format; /* Format identifier--format = 1 */
449 OffsetTo<Coverage>
450 coverage; /* Offset to Coverage table--from
451 * beginning of subtable */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400452 ValueFormat valueFormat; /* Defines the types of data in the
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400453 * ValueRecord */
454 ValueRecord values; /* Defines positioning
455 * value(s)--applied to all glyphs in
456 * the Coverage table */
Behdad Esfahbod569da922010-05-10 16:38:32 -0400457 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400458 DEFINE_SIZE_ARRAY (6, values);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400459};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400460
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400461struct SinglePosFormat2
462{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400463 friend struct SinglePos;
464
465 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400466 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400467 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400468 TRACE_APPLY ();
Behdad Esfahbod36b73c82010-05-14 22:10:39 -0400469 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400470 if (likely (index == NOT_COVERED))
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400471 return false;
472
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400473 if (likely (index >= valueCount))
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400474 return false;
475
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400476 valueFormat.apply_value (c->layout, this,
Behdad Esfahbod4b8487d2010-03-16 03:46:17 -0400477 &values[index * valueFormat.get_len ()],
Behdad Esfahbod36b73c82010-05-14 22:10:39 -0400478 c->buffer->pos[c->buffer->i]);
Behdad Esfahbodf53d4342009-05-30 22:17:32 -0400479
Behdad Esfahbod36b73c82010-05-14 22:10:39 -0400480 c->buffer->i++;
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400481 return true;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400482 }
483
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400484 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400485 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400486 return c->check_struct (this)
487 && coverage.sanitize (c, this)
488 && valueFormat.sanitize_values (c, this, values, valueCount);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400489 }
490
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400491 private:
492 USHORT format; /* Format identifier--format = 2 */
493 OffsetTo<Coverage>
494 coverage; /* Offset to Coverage table--from
495 * beginning of subtable */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400496 ValueFormat valueFormat; /* Defines the types of data in the
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400497 * ValueRecord */
498 USHORT valueCount; /* Number of ValueRecords */
499 ValueRecord values; /* Array of ValueRecords--positioning
500 * values applied to glyphs */
Behdad Esfahbod569da922010-05-10 16:38:32 -0400501 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400502 DEFINE_SIZE_ARRAY (8, values);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400503};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400504
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400505struct SinglePos
506{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400507 friend struct PosLookupSubTable;
508
509 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400510 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400511 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400512 TRACE_APPLY ();
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400513 switch (u.format) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400514 case 1: return u.format1.apply (c);
515 case 2: return u.format2.apply (c);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400516 default:return false;
517 }
518 }
519
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400520 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400521 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400522 if (!u.format.sanitize (c)) return false;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400523 switch (u.format) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400524 case 1: return u.format1.sanitize (c);
525 case 2: return u.format2.sanitize (c);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400526 default:return true;
527 }
528 }
529
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400530 private:
531 union {
532 USHORT format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -0400533 SinglePosFormat1 format1;
534 SinglePosFormat2 format2;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400535 } u;
536};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400537
538
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400539struct PairValueRecord
540{
Behdad Esfahbod70c9bfd2010-05-11 00:23:50 -0400541 friend struct PairSet;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400542
543 private:
544 GlyphID secondGlyph; /* GlyphID of second glyph in the
545 * pair--first glyph is listed in the
546 * Coverage table */
547 ValueRecord values; /* Positioning data for the first glyph
548 * followed by for second glyph */
Behdad Esfahbod569da922010-05-10 16:38:32 -0400549 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400550 DEFINE_SIZE_ARRAY (2, values);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400551};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400552
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400553struct PairSet
554{
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400555 friend struct PairPosFormat1;
556
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400557 inline bool apply (hb_apply_context_t *c,
Behdad Esfahbod70c9bfd2010-05-11 00:23:50 -0400558 const ValueFormat *valueFormats,
559 unsigned int pos) const
560 {
561 TRACE_APPLY ();
562 unsigned int len1 = valueFormats[0].get_len ();
563 unsigned int len2 = valueFormats[1].get_len ();
564 unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
565
566 unsigned int count = len;
567 const PairValueRecord *record = CastP<PairValueRecord> (array);
568 for (unsigned int i = 0; i < count; i++)
569 {
Behdad Esfahbod7e7007a2010-05-14 22:02:37 -0400570 if (c->buffer->info[pos].codepoint == record->secondGlyph)
Behdad Esfahbod70c9bfd2010-05-11 00:23:50 -0400571 {
Behdad Esfahbod36b73c82010-05-14 22:10:39 -0400572 valueFormats[0].apply_value (c->layout, this, &record->values[0], c->buffer->pos[c->buffer->i]);
Behdad Esfahbod1b621822010-05-14 22:05:53 -0400573 valueFormats[1].apply_value (c->layout, this, &record->values[len1], c->buffer->pos[pos]);
Behdad Esfahbod70c9bfd2010-05-11 00:23:50 -0400574 if (len2)
575 pos++;
Behdad Esfahbod36b73c82010-05-14 22:10:39 -0400576 c->buffer->i = pos;
Behdad Esfahbod70c9bfd2010-05-11 00:23:50 -0400577 return true;
578 }
579 record = &StructAtOffset<PairValueRecord> (record, record_size);
580 }
581
582 return false;
583 }
584
585 struct sanitize_closure_t {
586 void *base;
587 ValueFormat *valueFormats;
588 unsigned int len1; /* valueFormats[0].get_len() */
589 unsigned int stride; /* 1 + len1 + len2 */
590 };
591
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400592 inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400593 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400594 if (!(c->check_struct (this)
595 && c->check_array (array, USHORT::static_size * closure->stride, len))) return false;
Behdad Esfahbod70c9bfd2010-05-11 00:23:50 -0400596
597 unsigned int count = len;
598 PairValueRecord *record = CastP<PairValueRecord> (array);
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400599 return closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride)
600 && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400601 }
602
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400603 private:
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400604 USHORT len; /* Number of PairValueRecords */
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400605 USHORT array[VAR]; /* Array of PairValueRecords--ordered
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400606 * by GlyphID of the second glyph */
Behdad Esfahbod569da922010-05-10 16:38:32 -0400607 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400608 DEFINE_SIZE_ARRAY (2, array);
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400609};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400610
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400611struct PairPosFormat1
612{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400613 friend struct PairPos;
614
615 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400616 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400617 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400618 TRACE_APPLY ();
Behdad Esfahbod36b73c82010-05-14 22:10:39 -0400619 unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
620 if (unlikely (c->buffer->i + 2 > end))
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400621 return false;
622
Behdad Esfahbod36b73c82010-05-14 22:10:39 -0400623 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400624 if (likely (index == NOT_COVERED))
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400625 return false;
626
Behdad Esfahbod36b73c82010-05-14 22:10:39 -0400627 unsigned int j = c->buffer->i + 1;
Behdad Esfahbod7e7007a2010-05-14 22:02:37 -0400628 while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_flag, NULL))
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400629 {
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400630 if (unlikely (j == end))
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400631 return false;
632 j++;
633 }
634
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400635 return (this+pairSet[index]).apply (c, &valueFormat1, j);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400636 }
637
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400638 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400639 TRACE_SANITIZE ();
Behdad Esfahbodeba8b4f2010-03-29 00:04:12 -0400640
641 unsigned int len1 = valueFormat1.get_len ();
642 unsigned int len2 = valueFormat2.get_len ();
Behdad Esfahbod70c9bfd2010-05-11 00:23:50 -0400643 PairSet::sanitize_closure_t closure = {
644 this,
645 &valueFormat1,
646 len1,
647 1 + len1 + len2
648 };
Behdad Esfahbodeba8b4f2010-03-29 00:04:12 -0400649
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400650 return c->check_struct (this)
651 && coverage.sanitize (c, this)
652 && pairSet.sanitize (c, this, &closure);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400653 }
654
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400655 private:
656 USHORT format; /* Format identifier--format = 1 */
657 OffsetTo<Coverage>
658 coverage; /* Offset to Coverage table--from
659 * beginning of subtable */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400660 ValueFormat valueFormat1; /* Defines the types of data in
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400661 * ValueRecord1--for the first glyph
662 * in the pair--may be zero (0) */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400663 ValueFormat valueFormat2; /* Defines the types of data in
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400664 * ValueRecord2--for the second glyph
665 * in the pair--may be zero (0) */
666 OffsetArrayOf<PairSet>
667 pairSet; /* Array of PairSet tables
668 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400669 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400670 DEFINE_SIZE_ARRAY (10, pairSet);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400671};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400672
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400673struct PairPosFormat2
674{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400675 friend struct PairPos;
676
677 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400678 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400679 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400680 TRACE_APPLY ();
Behdad Esfahbod36b73c82010-05-14 22:10:39 -0400681 unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
682 if (unlikely (c->buffer->i + 2 > end))
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400683 return false;
684
Behdad Esfahbod36b73c82010-05-14 22:10:39 -0400685 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400686 if (likely (index == NOT_COVERED))
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400687 return false;
688
Behdad Esfahbod36b73c82010-05-14 22:10:39 -0400689 unsigned int j = c->buffer->i + 1;
Behdad Esfahbod7e7007a2010-05-14 22:02:37 -0400690 while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_flag, NULL))
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400691 {
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400692 if (unlikely (j == end))
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400693 return false;
694 j++;
695 }
696
697 unsigned int len1 = valueFormat1.get_len ();
698 unsigned int len2 = valueFormat2.get_len ();
699 unsigned int record_len = len1 + len2;
700
Behdad Esfahbod36b73c82010-05-14 22:10:39 -0400701 unsigned int klass1 = (this+classDef1) (c->buffer->info[c->buffer->i].codepoint);
Behdad Esfahbod7e7007a2010-05-14 22:02:37 -0400702 unsigned int klass2 = (this+classDef2) (c->buffer->info[j].codepoint);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400703 if (unlikely (klass1 >= class1Count || klass2 >= class2Count))
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400704 return false;
705
Behdad Esfahbod4b8487d2010-03-16 03:46:17 -0400706 const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
Behdad Esfahbod36b73c82010-05-14 22:10:39 -0400707 valueFormat1.apply_value (c->layout, this, v, c->buffer->pos[c->buffer->i]);
Behdad Esfahbod1b621822010-05-14 22:05:53 -0400708 valueFormat2.apply_value (c->layout, this, v + len1, c->buffer->pos[j]);
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400709
710 if (len2)
711 j++;
Behdad Esfahbod36b73c82010-05-14 22:10:39 -0400712 c->buffer->i = j;
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400713
714 return true;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400715 }
716
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400717 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400718 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400719 if (!(c->check_struct (this)
720 && coverage.sanitize (c, this)
721 && classDef1.sanitize (c, this)
722 && classDef2.sanitize (c, this))) return false;
Behdad Esfahbod815a73e2009-08-14 17:31:16 -0400723
Behdad Esfahbodeba8b4f2010-03-29 00:04:12 -0400724 unsigned int len1 = valueFormat1.get_len ();
725 unsigned int len2 = valueFormat2.get_len ();
726 unsigned int stride = len1 + len2;
Behdad Esfahbod4b8487d2010-03-16 03:46:17 -0400727 unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
Behdad Esfahbodeba8b4f2010-03-29 00:04:12 -0400728 unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400729 return c->check_array (values, record_size, count) &&
730 valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
731 valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400732 }
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400733
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400734 private:
735 USHORT format; /* Format identifier--format = 2 */
736 OffsetTo<Coverage>
737 coverage; /* Offset to Coverage table--from
738 * beginning of subtable */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400739 ValueFormat valueFormat1; /* ValueRecord definition--for the
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400740 * first glyph of the pair--may be zero
741 * (0) */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400742 ValueFormat valueFormat2; /* ValueRecord definition--for the
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400743 * second glyph of the pair--may be
744 * zero (0) */
745 OffsetTo<ClassDef>
746 classDef1; /* Offset to ClassDef table--from
747 * beginning of PairPos subtable--for
748 * the first glyph of the pair */
749 OffsetTo<ClassDef>
750 classDef2; /* Offset to ClassDef table--from
751 * beginning of PairPos subtable--for
752 * the second glyph of the pair */
753 USHORT class1Count; /* Number of classes in ClassDef1
754 * table--includes Class0 */
755 USHORT class2Count; /* Number of classes in ClassDef2
756 * table--includes Class0 */
757 ValueRecord values; /* Matrix of value pairs:
758 * class1-major, class2-minor,
759 * Each entry has value1 and value2 */
Behdad Esfahbod569da922010-05-10 16:38:32 -0400760 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400761 DEFINE_SIZE_ARRAY (16, values);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400762};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400763
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400764struct PairPos
765{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400766 friend struct PosLookupSubTable;
767
768 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400769 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400770 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400771 TRACE_APPLY ();
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400772 switch (u.format) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400773 case 1: return u.format1.apply (c);
774 case 2: return u.format2.apply (c);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400775 default:return false;
776 }
777 }
778
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400779 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400780 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400781 if (!u.format.sanitize (c)) return false;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400782 switch (u.format) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400783 case 1: return u.format1.sanitize (c);
784 case 2: return u.format2.sanitize (c);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400785 default:return true;
786 }
787 }
788
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400789 private:
790 union {
791 USHORT format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -0400792 PairPosFormat1 format1;
793 PairPosFormat2 format2;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400794 } u;
795};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400796
797
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400798struct EntryExitRecord
799{
Behdad Esfahbod569da922010-05-10 16:38:32 -0400800 friend struct CursivePosFormat1;
801
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400802 inline bool sanitize (hb_sanitize_context_t *c, void *base) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400803 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400804 return entryAnchor.sanitize (c, base)
805 && exitAnchor.sanitize (c, base);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400806 }
807
Behdad Esfahbod569da922010-05-10 16:38:32 -0400808 private:
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400809 OffsetTo<Anchor>
810 entryAnchor; /* Offset to EntryAnchor table--from
811 * beginning of CursivePos
812 * subtable--may be NULL */
813 OffsetTo<Anchor>
814 exitAnchor; /* Offset to ExitAnchor table--from
815 * beginning of CursivePos
816 * subtable--may be NULL */
Behdad Esfahbod569da922010-05-10 16:38:32 -0400817 public:
818 DEFINE_SIZE_STATIC (4);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400819};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400820
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400821struct CursivePosFormat1
822{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400823 friend struct CursivePos;
824
825 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400826 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400827 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400828 TRACE_APPLY ();
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400829 /* Now comes the messiest part of the whole OpenType
830 specification. At first glance, cursive connections seem easy
831 to understand, but there are pitfalls! The reason is that
832 the specs don't mention how to compute the advance values
833 resp. glyph offsets. I was told it would be an omission, to
834 be fixed in the next OpenType version... Again many thanks to
835 Andrei Burago <andreib@microsoft.com> for clarifications.
836
837 Consider the following example:
838
839 | xadv1 |
840 +---------+
841 | |
842 +-----+--+ 1 |
843 | | .| |
844 | 0+--+------+
845 | 2 |
846 | |
847 0+--------+
848 | xadv2 |
849
850 glyph1: advance width = 12
851 anchor point = (3,1)
852
853 glyph2: advance width = 11
854 anchor point = (9,4)
855
856 LSB is 1 for both glyphs (so the boxes drawn above are glyph
857 bboxes). Writing direction is R2L; `0' denotes the glyph's
858 coordinate origin.
859
860 Now the surprising part: The advance width of the *left* glyph
861 (resp. of the *bottom* glyph) will be modified, no matter
862 whether the writing direction is L2R or R2L (resp. T2B or
863 B2T)! This assymetry is caused by the fact that the glyph's
864 coordinate origin is always the lower left corner for all
865 writing directions.
866
867 Continuing the above example, we can compute the new
868 (horizontal) advance width of glyph2 as
869
870 9 - 3 = 6 ,
871
872 and the new vertical offset of glyph2 as
873
874 1 - 4 = -3 .
875
876
877 Vertical writing direction is far more complicated:
878
879 a) Assuming that we recompute the advance height of the lower glyph:
880
881 --
882 +---------+
883 -- | |
884 +-----+--+ 1 | yadv1
885 | | .| |
886 yadv2 | 0+--+------+ -- BSB1 --
887 | 2 | -- -- y_offset
888 | |
889 BSB2 -- 0+--------+ --
890 -- --
891
892 glyph1: advance height = 6
893 anchor point = (3,1)
894
895 glyph2: advance height = 7
896 anchor point = (9,4)
897
898 TSB is 1 for both glyphs; writing direction is T2B.
899
900
901 BSB1 = yadv1 - (TSB1 + ymax1)
902 BSB2 = yadv2 - (TSB2 + ymax2)
903 y_offset = y2 - y1
904
905 vertical advance width of glyph2
906 = y_offset + BSB2 - BSB1
907 = (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1))
908 = y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1)
909 = y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1
910
911
912 b) Assuming that we recompute the advance height of the upper glyph:
913
914 -- --
915 +---------+ -- TSB1
916 -- -- | |
917 TSB2 -- +-----+--+ 1 | yadv1 ymax1
918 | | .| |
919 yadv2 | 0+--+------+ -- --
920 ymax2 | 2 | -- y_offset
921 | |
922 -- 0+--------+ --
923 --
924
925 glyph1: advance height = 6
926 anchor point = (3,1)
927
928 glyph2: advance height = 7
929 anchor point = (9,4)
930
931 TSB is 1 for both glyphs; writing direction is T2B.
932
933 y_offset = y2 - y1
934
935 vertical advance width of glyph2
936 = TSB1 + ymax1 + y_offset - (TSB2 + ymax2)
937 = TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2
938
939
940 Comparing a) with b) shows that b) is easier to compute. I'll wait
941 for a reply from Andrei to see what should really be implemented...
942
943 Since horizontal advance widths or vertical advance heights
944 can be used alone but not together, no ambiguity occurs. */
945
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400946 struct hb_ot_layout_context_t::info_t::gpos_t *gpi = &c->layout->info.gpos;
Behdad Esfahbod0f7e6b22009-05-20 04:16:35 -0400947 hb_codepoint_t last_pos = gpi->last;
Behdad Esfahbodc968fc22009-05-25 04:04:24 -0400948 gpi->last = HB_OT_LAYOUT_GPOS_NO_LAST;
Behdad Esfahbod0f7e6b22009-05-20 04:16:35 -0400949
950 /* We don't handle mark glyphs here. */
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400951 if (c->property == HB_OT_LAYOUT_GLYPH_CLASS_MARK)
Behdad Esfahbod0f7e6b22009-05-20 04:16:35 -0400952 return false;
953
Behdad Esfahbod36b73c82010-05-14 22:10:39 -0400954 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400955 if (likely (index == NOT_COVERED))
Behdad Esfahbod0f7e6b22009-05-20 04:16:35 -0400956 return false;
957
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400958 const EntryExitRecord &record = entryExitRecord[index];
959
Behdad Esfahbodc968fc22009-05-25 04:04:24 -0400960 if (last_pos == HB_OT_LAYOUT_GPOS_NO_LAST || !record.entryAnchor)
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400961 goto end;
962
Behdad Esfahbod6c8108c2009-05-26 22:26:08 -0400963 hb_position_t entry_x, entry_y;
Behdad Esfahbod36b73c82010-05-14 22:10:39 -0400964 (this+record.entryAnchor).get_anchor (c->layout, c->buffer->info[c->buffer->i].codepoint, &entry_x, &entry_y);
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400965
Behdad Esfahbodcc83ae12009-05-27 00:17:37 -0400966 /* TODO vertical */
967
Behdad Esfahbod4e4ef242010-07-23 17:22:11 -0400968 if (c->buffer->props.direction == HB_DIRECTION_RTL)
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400969 {
Behdad Esfahbod9db8ad72009-11-06 16:47:31 -0500970 /* advance is absolute, not relative */
Behdad Esfahbod36b73c82010-05-14 22:10:39 -0400971 c->buffer->pos[c->buffer->i].x_advance = entry_x - gpi->anchor_x;
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400972 }
973 else
974 {
Behdad Esfahbod9db8ad72009-11-06 16:47:31 -0500975 /* advance is absolute, not relative */
Behdad Esfahbod1b621822010-05-14 22:05:53 -0400976 c->buffer->pos[last_pos].x_advance = gpi->anchor_x - entry_x;
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400977 }
978
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400979 if (c->lookup_flag & LookupFlag::RightToLeft)
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400980 {
Behdad Esfahbod36b73c82010-05-14 22:10:39 -0400981 c->buffer->pos[last_pos].cursive_chain = last_pos - c->buffer->i;
Behdad Esfahbod1b621822010-05-14 22:05:53 -0400982 c->buffer->pos[last_pos].y_offset = entry_y - gpi->anchor_y;
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400983 }
984 else
985 {
Behdad Esfahbod36b73c82010-05-14 22:10:39 -0400986 c->buffer->pos[c->buffer->i].cursive_chain = c->buffer->i - last_pos;
987 c->buffer->pos[c->buffer->i].y_offset = gpi->anchor_y - entry_y;
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400988 }
989
990 end:
991 if (record.exitAnchor)
Behdad Esfahbod0f7e6b22009-05-20 04:16:35 -0400992 {
Behdad Esfahbod36b73c82010-05-14 22:10:39 -0400993 gpi->last = c->buffer->i;
994 (this+record.exitAnchor).get_anchor (c->layout, c->buffer->info[c->buffer->i].codepoint, &gpi->anchor_x, &gpi->anchor_y);
Behdad Esfahbod0f7e6b22009-05-20 04:16:35 -0400995 }
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400996
Behdad Esfahbod36b73c82010-05-14 22:10:39 -0400997 c->buffer->i++;
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400998 return true;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400999 }
1000
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001001 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001002 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001003 return coverage.sanitize (c, this)
1004 && entryExitRecord.sanitize (c, this);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001005 }
1006
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001007 private:
1008 USHORT format; /* Format identifier--format = 1 */
1009 OffsetTo<Coverage>
1010 coverage; /* Offset to Coverage table--from
1011 * beginning of subtable */
1012 ArrayOf<EntryExitRecord>
1013 entryExitRecord; /* Array of EntryExit records--in
1014 * Coverage Index order */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001015 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04001016 DEFINE_SIZE_ARRAY (6, entryExitRecord);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001017};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001018
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001019struct CursivePos
1020{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001021 friend struct PosLookupSubTable;
1022
1023 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001024 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001025 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001026 TRACE_APPLY ();
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001027 switch (u.format) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001028 case 1: return u.format1.apply (c);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001029 default:return false;
1030 }
1031 }
1032
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001033 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001034 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001035 if (!u.format.sanitize (c)) return false;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001036 switch (u.format) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001037 case 1: return u.format1.sanitize (c);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001038 default:return true;
1039 }
1040 }
1041
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001042 private:
1043 union {
1044 USHORT format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04001045 CursivePosFormat1 format1;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001046 } u;
1047};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001048
1049
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -04001050typedef AnchorMatrix BaseArray; /* base-major--
1051 * in order of BaseCoverage Index--,
1052 * mark-minor--
Behdad Esfahbodfb3b5cc2009-05-21 04:47:05 -04001053 * ordered by class--zero-based. */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001054
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001055struct MarkBasePosFormat1
1056{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001057 friend struct MarkBasePos;
1058
1059 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001060 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001061 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001062 TRACE_APPLY ();
Behdad Esfahbod36b73c82010-05-14 22:10:39 -04001063 unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->i].codepoint);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001064 if (likely (mark_index == NOT_COVERED))
Behdad Esfahbod357ccde2009-05-21 06:32:01 -04001065 return false;
1066
1067 /* now we search backwards for a non-mark glyph */
Behdad Esfahbod1376fb72010-04-29 02:19:21 -04001068 unsigned int property;
Behdad Esfahbod36b73c82010-05-14 22:10:39 -04001069 unsigned int j = c->buffer->i;
Behdad Esfahbod0532ed12009-08-12 15:40:04 -04001070 do
Behdad Esfahbod357ccde2009-05-21 06:32:01 -04001071 {
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001072 if (unlikely (!j))
Behdad Esfahbod80ea5bd2009-05-26 17:58:37 -04001073 return false;
Behdad Esfahbodb2b18ef2009-08-14 19:37:18 -04001074 j--;
Behdad Esfahbod7e7007a2010-05-14 22:02:37 -04001075 } while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], LookupFlag::IgnoreMarks, &property));
Behdad Esfahbod0532ed12009-08-12 15:40:04 -04001076
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001077 /* The following assertion is too strong, so we've disabled it. */
1078 if (false && !(property & HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH))
Behdad Esfahbod357ccde2009-05-21 06:32:01 -04001079 return false;
1080
Behdad Esfahbod7e7007a2010-05-14 22:02:37 -04001081 unsigned int base_index = (this+baseCoverage) (c->buffer->info[j].codepoint);
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001082 if (base_index == NOT_COVERED)
Behdad Esfahbod357ccde2009-05-21 06:32:01 -04001083 return false;
1084
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001085 return (this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, j);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001086 }
1087
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001088 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001089 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001090 return c->check_struct (this)
1091 && markCoverage.sanitize (c, this)
1092 && baseCoverage.sanitize (c, this)
1093 && markArray.sanitize (c, this)
1094 && baseArray.sanitize (c, this, (unsigned int) classCount);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001095 }
1096
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001097 private:
1098 USHORT format; /* Format identifier--format = 1 */
Behdad Esfahbodfb3b5cc2009-05-21 04:47:05 -04001099 OffsetTo<Coverage>
1100 markCoverage; /* Offset to MarkCoverage table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001101 * beginning of MarkBasePos subtable */
Behdad Esfahbodfb3b5cc2009-05-21 04:47:05 -04001102 OffsetTo<Coverage>
1103 baseCoverage; /* Offset to BaseCoverage table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001104 * beginning of MarkBasePos subtable */
1105 USHORT classCount; /* Number of classes defined for marks */
Behdad Esfahbodfb3b5cc2009-05-21 04:47:05 -04001106 OffsetTo<MarkArray>
1107 markArray; /* Offset to MarkArray table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001108 * beginning of MarkBasePos subtable */
Behdad Esfahbodfb3b5cc2009-05-21 04:47:05 -04001109 OffsetTo<BaseArray>
1110 baseArray; /* Offset to BaseArray table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001111 * beginning of MarkBasePos subtable */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001112 public:
1113 DEFINE_SIZE_STATIC (12);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001114};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001115
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001116struct MarkBasePos
1117{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001118 friend struct PosLookupSubTable;
1119
1120 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001121 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001122 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001123 TRACE_APPLY ();
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001124 switch (u.format) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001125 case 1: return u.format1.apply (c);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001126 default:return false;
1127 }
1128 }
1129
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001130 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001131 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001132 if (!u.format.sanitize (c)) return false;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001133 switch (u.format) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001134 case 1: return u.format1.sanitize (c);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001135 default:return true;
1136 }
1137 }
1138
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001139 private:
1140 union {
1141 USHORT format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04001142 MarkBasePosFormat1 format1;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001143 } u;
1144};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001145
1146
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -04001147typedef AnchorMatrix LigatureAttach; /* component-major--
1148 * in order of writing direction--,
1149 * mark-minor--
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001150 * ordered by class--zero-based. */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001151
Behdad Esfahbod3564ee52009-08-14 18:32:56 -04001152typedef OffsetListOf<LigatureAttach> LigatureArray;
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001153 /* Array of LigatureAttach
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001154 * tables ordered by
1155 * LigatureCoverage Index */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001156
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001157struct MarkLigPosFormat1
1158{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001159 friend struct MarkLigPos;
1160
1161 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001162 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001163 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001164 TRACE_APPLY ();
Behdad Esfahbod36b73c82010-05-14 22:10:39 -04001165 unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->i].codepoint);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001166 if (likely (mark_index == NOT_COVERED))
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001167 return false;
1168
1169 /* now we search backwards for a non-mark glyph */
Behdad Esfahbod1376fb72010-04-29 02:19:21 -04001170 unsigned int property;
Behdad Esfahbod36b73c82010-05-14 22:10:39 -04001171 unsigned int j = c->buffer->i;
Behdad Esfahbod0532ed12009-08-12 15:40:04 -04001172 do
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001173 {
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001174 if (unlikely (!j))
Behdad Esfahbod80ea5bd2009-05-26 17:58:37 -04001175 return false;
Behdad Esfahbodb2b18ef2009-08-14 19:37:18 -04001176 j--;
Behdad Esfahbod7e7007a2010-05-14 22:02:37 -04001177 } while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], LookupFlag::IgnoreMarks, &property));
Behdad Esfahbod0532ed12009-08-12 15:40:04 -04001178
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001179 /* The following assertion is too strong, so we've disabled it. */
1180 if (false && !(property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE))
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001181 return false;
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001182
Behdad Esfahbod7e7007a2010-05-14 22:02:37 -04001183 unsigned int lig_index = (this+ligatureCoverage) (c->buffer->info[j].codepoint);
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001184 if (lig_index == NOT_COVERED)
1185 return false;
1186
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001187 const LigatureArray& lig_array = this+ligatureArray;
Behdad Esfahbod3564ee52009-08-14 18:32:56 -04001188 const LigatureAttach& lig_attach = lig_array[lig_index];
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -04001189
1190 /* Find component to attach to */
Behdad Esfahbodb2b18ef2009-08-14 19:37:18 -04001191 unsigned int comp_count = lig_attach.rows;
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001192 if (unlikely (!comp_count))
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001193 return false;
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001194 unsigned int comp_index;
1195 /* We must now check whether the ligature ID of the current mark glyph
1196 * is identical to the ligature ID of the found ligature. If yes, we
1197 * can directly use the component index. If not, we attach the mark
1198 * glyph to the last component of the ligature. */
Behdad Esfahbod36b73c82010-05-14 22:10:39 -04001199 if (c->buffer->info[j].lig_id && c->buffer->info[j].lig_id == c->buffer->info[c->buffer->i].lig_id && c->buffer->info[c->buffer->i].component)
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001200 {
Behdad Esfahbod36b73c82010-05-14 22:10:39 -04001201 comp_index = c->buffer->info[c->buffer->i].component - 1;
Behdad Esfahbodb2b18ef2009-08-14 19:37:18 -04001202 if (comp_index >= comp_count)
1203 comp_index = comp_count - 1;
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001204 }
1205 else
Behdad Esfahbodb2b18ef2009-08-14 19:37:18 -04001206 comp_index = comp_count - 1;
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001207
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001208 return (this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001209 }
1210
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001211 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001212 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001213 return c->check_struct (this)
1214 && markCoverage.sanitize (c, this)
1215 && ligatureCoverage.sanitize (c, this)
1216 && markArray.sanitize (c, this)
1217 && ligatureArray.sanitize (c, this, (unsigned int) classCount);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001218 }
1219
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001220 private:
1221 USHORT format; /* Format identifier--format = 1 */
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001222 OffsetTo<Coverage>
1223 markCoverage; /* Offset to Mark Coverage table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001224 * beginning of MarkLigPos subtable */
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001225 OffsetTo<Coverage>
1226 ligatureCoverage; /* Offset to Ligature Coverage
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001227 * table--from beginning of MarkLigPos
1228 * subtable */
1229 USHORT classCount; /* Number of defined mark classes */
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001230 OffsetTo<MarkArray>
1231 markArray; /* Offset to MarkArray table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001232 * beginning of MarkLigPos subtable */
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001233 OffsetTo<LigatureArray>
1234 ligatureArray; /* Offset to LigatureArray table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001235 * beginning of MarkLigPos subtable */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001236 public:
1237 DEFINE_SIZE_STATIC (12);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001238};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001239
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001240struct MarkLigPos
1241{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001242 friend struct PosLookupSubTable;
1243
1244 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001245 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001246 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001247 TRACE_APPLY ();
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001248 switch (u.format) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001249 case 1: return u.format1.apply (c);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001250 default:return false;
1251 }
1252 }
1253
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001254 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001255 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001256 if (!u.format.sanitize (c)) return false;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001257 switch (u.format) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001258 case 1: return u.format1.sanitize (c);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001259 default:return true;
1260 }
1261 }
1262
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001263 private:
1264 union {
1265 USHORT format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04001266 MarkLigPosFormat1 format1;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001267 } u;
1268};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001269
1270
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -04001271typedef AnchorMatrix Mark2Array; /* mark2-major--
1272 * in order of Mark2Coverage Index--,
1273 * mark1-minor--
1274 * ordered by class--zero-based. */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001275
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001276struct MarkMarkPosFormat1
1277{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001278 friend struct MarkMarkPos;
1279
1280 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001281 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001282 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001283 TRACE_APPLY ();
Behdad Esfahbod36b73c82010-05-14 22:10:39 -04001284 unsigned int mark1_index = (this+mark1Coverage) (c->buffer->info[c->buffer->i].codepoint);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001285 if (likely (mark1_index == NOT_COVERED))
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001286 return false;
1287
1288 /* now we search backwards for a suitable mark glyph until a non-mark glyph */
Behdad Esfahbod1376fb72010-04-29 02:19:21 -04001289 unsigned int property;
Behdad Esfahbod36b73c82010-05-14 22:10:39 -04001290 unsigned int j = c->buffer->i;
Behdad Esfahbod0532ed12009-08-12 15:40:04 -04001291 do
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001292 {
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001293 if (unlikely (!j))
Behdad Esfahbod80ea5bd2009-05-26 17:58:37 -04001294 return false;
Behdad Esfahbodb2b18ef2009-08-14 19:37:18 -04001295 j--;
Behdad Esfahbod7e7007a2010-05-14 22:02:37 -04001296 } while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_flag, &property));
Behdad Esfahbod0532ed12009-08-12 15:40:04 -04001297
Behdad Esfahbod80ea5bd2009-05-26 17:58:37 -04001298 if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
1299 return false;
1300
1301 /* Two marks match only if they belong to the same base, or same component
Behdad Esfahbodc3f9f7e2009-11-05 16:16:14 -05001302 * of the same ligature. That is, the component numbers must match, and
1303 * if those are non-zero, the ligid number should also match. */
Behdad Esfahbod36b73c82010-05-14 22:10:39 -04001304 if ((c->buffer->info[j].component != c->buffer->info[c->buffer->i].component) ||
1305 (c->buffer->info[j].component && c->buffer->info[j].lig_id != c->buffer->info[c->buffer->i].lig_id))
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001306 return false;
1307
Behdad Esfahbod7e7007a2010-05-14 22:02:37 -04001308 unsigned int mark2_index = (this+mark2Coverage) (c->buffer->info[j].codepoint);
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001309 if (mark2_index == NOT_COVERED)
1310 return false;
1311
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001312 return (this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001313 }
1314
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001315 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001316 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001317 return c->check_struct (this)
1318 && mark1Coverage.sanitize (c, this)
1319 && mark2Coverage.sanitize (c, this)
1320 && mark1Array.sanitize (c, this)
1321 && mark2Array.sanitize (c, this, (unsigned int) classCount);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001322 }
1323
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001324 private:
1325 USHORT format; /* Format identifier--format = 1 */
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001326 OffsetTo<Coverage>
1327 mark1Coverage; /* Offset to Combining Mark1 Coverage
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001328 * table--from beginning of MarkMarkPos
1329 * subtable */
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001330 OffsetTo<Coverage>
1331 mark2Coverage; /* Offset to Combining Mark2 Coverage
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001332 * table--from beginning of MarkMarkPos
1333 * subtable */
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001334 USHORT classCount; /* Number of defined mark classes */
1335 OffsetTo<MarkArray>
1336 mark1Array; /* Offset to Mark1Array table--from
1337 * beginning of MarkMarkPos subtable */
1338 OffsetTo<Mark2Array>
1339 mark2Array; /* Offset to Mark2Array table--from
1340 * beginning of MarkMarkPos subtable */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001341 public:
1342 DEFINE_SIZE_STATIC (12);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001343};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001344
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001345struct MarkMarkPos
1346{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001347 friend struct PosLookupSubTable;
1348
1349 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001350 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001351 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001352 TRACE_APPLY ();
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001353 switch (u.format) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001354 case 1: return u.format1.apply (c);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001355 default:return false;
1356 }
1357 }
1358
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001359 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001360 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001361 if (!u.format.sanitize (c)) return false;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001362 switch (u.format) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001363 case 1: return u.format1.sanitize (c);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001364 default:return true;
1365 }
1366 }
1367
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001368 private:
1369 union {
1370 USHORT format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04001371 MarkMarkPosFormat1 format1;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001372 } u;
1373};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001374
1375
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001376HB_BEGIN_DECLS
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001377static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index);
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001378HB_END_DECLS
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001379
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001380struct ContextPos : Context
1381{
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04001382 friend struct PosLookupSubTable;
1383
1384 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001385 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod0535b502009-08-28 17:14:33 -04001386 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001387 TRACE_APPLY ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001388 return Context::apply (c, position_lookup);
Behdad Esfahbod0535b502009-08-28 17:14:33 -04001389 }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001390};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001391
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001392struct ChainContextPos : ChainContext
1393{
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04001394 friend struct PosLookupSubTable;
1395
1396 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001397 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod0535b502009-08-28 17:14:33 -04001398 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001399 TRACE_APPLY ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001400 return ChainContext::apply (c, position_lookup);
Behdad Esfahbod0535b502009-08-28 17:14:33 -04001401 }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001402};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001403
1404
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04001405struct ExtensionPos : Extension
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001406{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001407 friend struct PosLookupSubTable;
1408
1409 private:
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001410 inline const struct PosLookupSubTable& get_subtable (void) const
Behdad Esfahbod3b2c2df2010-04-22 16:51:42 -04001411 {
1412 unsigned int offset = get_offset ();
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001413 if (unlikely (!offset)) return Null(PosLookupSubTable);
Behdad Esfahbod09766b12010-05-10 17:36:03 -04001414 return StructAtOffset<PosLookupSubTable> (this, offset);
Behdad Esfahbod3b2c2df2010-04-22 16:51:42 -04001415 }
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001416
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001417 inline bool apply (hb_apply_context_t *c) const;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001418
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001419 inline bool sanitize (hb_sanitize_context_t *c);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001420};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001421
1422
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04001423
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001424/*
1425 * PosLookup
1426 */
1427
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001428
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001429struct PosLookupSubTable
1430{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001431 friend struct PosLookup;
1432
Behdad Esfahbodff05d252009-05-20 03:53:00 -04001433 enum {
1434 Single = 1,
1435 Pair = 2,
1436 Cursive = 3,
1437 MarkBase = 4,
1438 MarkLig = 5,
1439 MarkMark = 6,
1440 Context = 7,
1441 ChainContext = 8,
Behdad Esfahbod8f034d52009-08-18 16:41:59 -04001442 Extension = 9
Behdad Esfahbodff05d252009-05-20 03:53:00 -04001443 };
1444
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001445 inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001446 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001447 TRACE_APPLY ();
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001448 switch (lookup_type) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001449 case Single: return u.single.apply (c);
1450 case Pair: return u.pair.apply (c);
1451 case Cursive: return u.cursive.apply (c);
1452 case MarkBase: return u.markBase.apply (c);
1453 case MarkLig: return u.markLig.apply (c);
1454 case MarkMark: return u.markMark.apply (c);
1455 case Context: return u.c.apply (c);
1456 case ChainContext: return u.chainContext.apply (c);
1457 case Extension: return u.extension.apply (c);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001458 default:return false;
1459 }
1460 }
1461
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001462 inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001463 TRACE_SANITIZE ();
Behdad Esfahbodfe9bc072010-05-10 21:39:24 -04001464 switch (lookup_type) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001465 case Single: return u.single.sanitize (c);
1466 case Pair: return u.pair.sanitize (c);
1467 case Cursive: return u.cursive.sanitize (c);
1468 case MarkBase: return u.markBase.sanitize (c);
1469 case MarkLig: return u.markLig.sanitize (c);
1470 case MarkMark: return u.markMark.sanitize (c);
1471 case Context: return u.c.sanitize (c);
1472 case ChainContext: return u.chainContext.sanitize (c);
1473 case Extension: return u.extension.sanitize (c);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001474 default:return true;
1475 }
1476 }
1477
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001478 private:
1479 union {
Behdad Esfahbodfe9bc072010-05-10 21:39:24 -04001480 USHORT sub_format;
Behdad Esfahboddacebca2010-05-10 19:45:41 -04001481 SinglePos single;
1482 PairPos pair;
1483 CursivePos cursive;
1484 MarkBasePos markBase;
1485 MarkLigPos markLig;
1486 MarkMarkPos markMark;
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001487 ContextPos c;
Behdad Esfahboddacebca2010-05-10 19:45:41 -04001488 ChainContextPos chainContext;
1489 ExtensionPos extension;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001490 } u;
Behdad Esfahboded074222010-05-10 18:08:46 -04001491 public:
Behdad Esfahbodfe9bc072010-05-10 21:39:24 -04001492 DEFINE_SIZE_UNION (2, sub_format);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001493};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001494
1495
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001496struct PosLookup : Lookup
1497{
1498 inline const PosLookupSubTable& get_subtable (unsigned int i) const
Behdad Esfahbod187454c2010-04-23 16:35:01 -04001499 { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001500
Behdad Esfahbod63493f92010-05-05 01:01:05 -04001501 inline bool apply_once (hb_ot_layout_context_t *layout,
Behdad Esfahbodf7acd8d2010-05-20 17:26:35 +01001502 hb_buffer_t *buffer,
1503 hb_mask_t lookup_mask,
1504 unsigned int context_length,
1505 unsigned int nesting_level_left) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001506 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001507 unsigned int lookup_type = get_type ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001508 hb_apply_context_t c[1] = {{0}};
Behdad Esfahbod923923f2009-05-22 17:58:09 -04001509
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001510 c->layout = layout;
1511 c->buffer = buffer;
Behdad Esfahbodf7acd8d2010-05-20 17:26:35 +01001512 c->lookup_mask = lookup_mask;
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001513 c->context_length = context_length;
1514 c->nesting_level_left = nesting_level_left;
1515 c->lookup_flag = get_flag ();
Behdad Esfahbod1376fb72010-04-29 02:19:21 -04001516
Behdad Esfahbod36b73c82010-05-14 22:10:39 -04001517 if (!_hb_ot_layout_check_glyph_property (c->layout->face, &c->buffer->info[c->buffer->i], c->lookup_flag, &c->property))
Behdad Esfahbod923923f2009-05-22 17:58:09 -04001518 return false;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001519
1520 for (unsigned int i = 0; i < get_subtable_count (); i++)
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001521 if (get_subtable (i).apply (c, lookup_type))
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001522 return true;
1523
1524 return false;
1525 }
1526
Behdad Esfahbod63493f92010-05-05 01:01:05 -04001527 inline bool apply_string (hb_ot_layout_context_t *layout,
Behdad Esfahbod20b035d2009-08-10 19:00:36 -04001528 hb_buffer_t *buffer,
1529 hb_mask_t mask) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001530 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001531 bool ret = false;
1532
Behdad Esfahbod69603502010-05-14 22:07:46 -04001533 if (unlikely (!buffer->len))
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001534 return false;
1535
Behdad Esfahbod63493f92010-05-05 01:01:05 -04001536 layout->info.gpos.last = HB_OT_LAYOUT_GPOS_NO_LAST; /* no last valid glyph for cursive pos. */
Behdad Esfahbod9c42f052009-05-18 17:43:49 -04001537
Behdad Esfahbod36b73c82010-05-14 22:10:39 -04001538 buffer->i = 0;
1539 while (buffer->i < buffer->len)
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001540 {
Behdad Esfahbod9c42f052009-05-18 17:43:49 -04001541 bool done;
Behdad Esfahbod009aad52010-05-20 14:00:57 +01001542 if (buffer->info[buffer->i].mask & mask)
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001543 {
Behdad Esfahbodf7acd8d2010-05-20 17:26:35 +01001544 done = apply_once (layout, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL);
Behdad Esfahbod9c42f052009-05-18 17:43:49 -04001545 ret |= done;
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001546 }
1547 else
1548 {
Behdad Esfahbod9c42f052009-05-18 17:43:49 -04001549 done = false;
1550 /* Contrary to properties defined in GDEF, user-defined properties
1551 will always stop a possible cursive positioning. */
Behdad Esfahbod63493f92010-05-05 01:01:05 -04001552 layout->info.gpos.last = HB_OT_LAYOUT_GPOS_NO_LAST;
Behdad Esfahbod9c42f052009-05-18 17:43:49 -04001553 }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001554
Behdad Esfahbod9c42f052009-05-18 17:43:49 -04001555 if (!done)
Behdad Esfahbod36b73c82010-05-14 22:10:39 -04001556 buffer->i++;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001557 }
1558
1559 return ret;
1560 }
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001561
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001562 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001563 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001564 if (unlikely (!Lookup::sanitize (c))) return false;
Behdad Esfahbod187454c2010-04-23 16:35:01 -04001565 OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable);
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001566 return list.sanitize (c, this, get_type ());
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001567 }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001568};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001569
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001570typedef OffsetListOf<PosLookup> PosLookupList;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001571
1572/*
1573 * GPOS
1574 */
1575
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001576struct GPOS : GSUBGPOS
1577{
Behdad Esfahboda328d662009-08-04 20:27:05 -04001578 static const hb_tag_t Tag = HB_OT_TAG_GPOS;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001579
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001580 inline const PosLookup& get_lookup (unsigned int i) const
Behdad Esfahbod187454c2010-04-23 16:35:01 -04001581 { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001582
Behdad Esfahbod63493f92010-05-05 01:01:05 -04001583 inline bool position_lookup (hb_ot_layout_context_t *layout,
Behdad Esfahbod468769b2009-08-08 16:53:23 -04001584 hb_buffer_t *buffer,
1585 unsigned int lookup_index,
1586 hb_mask_t mask) const
Behdad Esfahbod63493f92010-05-05 01:01:05 -04001587 { return get_lookup (lookup_index).apply_string (layout, buffer, mask); }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001588
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001589 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001590 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001591 if (unlikely (!GSUBGPOS::sanitize (c))) return false;
Behdad Esfahbod187454c2010-04-23 16:35:01 -04001592 OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001593 return list.sanitize (c, this);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001594 }
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001595 public:
1596 DEFINE_SIZE_STATIC (10);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001597};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001598
1599
1600/* Out-of-class implementation for methods recursing */
1601
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001602inline bool ExtensionPos::apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001603{
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001604 TRACE_APPLY ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001605 return get_subtable ().apply (c, get_type ());
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001606}
1607
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001608inline bool ExtensionPos::sanitize (hb_sanitize_context_t *c)
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001609{
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001610 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001611 if (unlikely (!Extension::sanitize (c))) return false;
Behdad Esfahbod3b2c2df2010-04-22 16:51:42 -04001612 unsigned int offset = get_offset ();
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001613 if (unlikely (!offset)) return true;
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001614 return StructAtOffset<PosLookupSubTable> (this, offset).sanitize (c, get_type ());
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001615}
1616
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001617static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index)
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001618{
Behdad Esfahbod0a4399c2010-05-19 15:45:06 -04001619 const GPOS &gpos = *(c->layout->face->ot_layout->gpos);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001620 const PosLookup &l = gpos.get_lookup (lookup_index);
1621
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001622 if (unlikely (c->nesting_level_left == 0))
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001623 return false;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001624
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001625 if (unlikely (c->context_length < 1))
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001626 return false;
1627
Behdad Esfahbodf7acd8d2010-05-20 17:26:35 +01001628 return l.apply_once (c->layout, c->buffer, c->lookup_mask, c->context_length, c->nesting_level_left - 1);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001629}
1630
1631
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001632HB_END_DECLS
1633
Behdad Esfahbod5f5b24f2009-08-02 20:03:12 -04001634#endif /* HB_OT_LAYOUT_GPOS_PRIVATE_HH */