blob: 7a3c117e823ba4f47fbfbf42875087e230935bd6 [file] [log] [blame]
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001/*
Behdad Esfahbod2409d5f2011-04-21 17:14:28 -04002 * Copyright © 2007,2008,2009,2010 Red Hat, Inc.
3 * Copyright © 2010 Google, Inc.
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04004 *
Behdad Esfahbodc755cb32010-04-22 00:11:43 -04005 * This is part of HarfBuzz, a text shaping library.
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04006 *
7 * Permission is hereby granted, without written agreement and without
8 * license or royalty fees, to use, copy, modify, and distribute this
9 * software and its documentation for any purpose, provided that the
10 * above copyright notice and the following two paragraphs appear in
11 * all copies of this software.
12 *
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17 * DAMAGE.
18 *
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24 *
25 * Red Hat Author(s): Behdad Esfahbod
Behdad Esfahbod98370e82010-10-27 17:39:01 -040026 * Google Author(s): Behdad Esfahbod
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040027 */
28
Behdad Esfahbod7a750ac2011-08-17 14:19:59 +020029#ifndef HB_OT_LAYOUT_GPOS_TABLE_HH
30#define HB_OT_LAYOUT_GPOS_TABLE_HH
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040031
Behdad Esfahbod5f5b24f2009-08-02 20:03:12 -040032#include "hb-ot-layout-gsubgpos-private.hh"
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040033
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -040034
Behdad Esfahbod94a23aa2010-05-05 01:13:09 -040035
Behdad Esfahbodb65c0602011-07-28 16:48:43 -040036/* buffer **position** var allocations */
Behdad Esfahbod194d4562010-10-27 23:09:10 -040037#define attach_lookback() var.u16[0] /* number of glyphs to go back to attach this glyph to its base */
38#define cursive_chain() var.i16[1] /* character to which this connects, may be positive or negative */
39
40
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040041/* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
42
Behdad Esfahbodc2ddfd22010-05-06 13:06:15 -040043typedef USHORT Value;
Behdad Esfahbodc91facd2009-08-26 18:53:43 -040044
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -040045typedef Value ValueRecord[VAR];
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040046
Behdad Esfahbodfca6a0d2009-05-21 04:49:04 -040047struct ValueFormat : USHORT
48{
Behdad Esfahbodc6035cf2012-04-12 13:23:59 -040049 enum Flags {
Behdad Esfahbodfca6a0d2009-05-21 04:49:04 -040050 xPlacement = 0x0001, /* Includes horizontal adjustment for placement */
51 yPlacement = 0x0002, /* Includes vertical adjustment for placement */
52 xAdvance = 0x0004, /* Includes horizontal adjustment for advance */
53 yAdvance = 0x0008, /* Includes vertical adjustment for advance */
54 xPlaDevice = 0x0010, /* Includes horizontal Device table for placement */
55 yPlaDevice = 0x0020, /* Includes vertical Device table for placement */
56 xAdvDevice = 0x0040, /* Includes horizontal Device table for advance */
57 yAdvDevice = 0x0080, /* Includes vertical Device table for advance */
Behdad Esfahbode4b92b82009-05-26 15:38:53 -040058 ignored = 0x0F00, /* Was used in TrueType Open for MM fonts */
Behdad Esfahbodeba8b4f2010-03-29 00:04:12 -040059 reserved = 0xF000, /* For future use */
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -040060
Behdad Esfahbodeba8b4f2010-03-29 00:04:12 -040061 devices = 0x00F0 /* Mask for having any Device table */
Behdad Esfahbodfca6a0d2009-05-21 04:49:04 -040062 };
63
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -040064/* All fields are options. Only those available advance the value pointer. */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040065#if 0
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040066 SHORT xPlacement; /* Horizontal adjustment for
67 * placement--in design units */
68 SHORT yPlacement; /* Vertical adjustment for
69 * placement--in design units */
70 SHORT xAdvance; /* Horizontal adjustment for
71 * advance--in design units (only used
72 * for horizontal writing) */
73 SHORT yAdvance; /* Vertical adjustment for advance--in
74 * design units (only used for vertical
75 * writing) */
76 Offset xPlaDevice; /* Offset to Device table for
77 * horizontal placement--measured from
78 * beginning of PosTable (may be NULL) */
79 Offset yPlaDevice; /* Offset to Device table for vertical
80 * placement--measured from beginning
81 * of PosTable (may be NULL) */
82 Offset xAdvDevice; /* Offset to Device table for
83 * horizontal advance--measured from
84 * beginning of PosTable (may be NULL) */
85 Offset yAdvDevice; /* Offset to Device table for vertical
86 * advance--measured from beginning of
87 * PosTable (may be NULL) */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040088#endif
89
Behdad Esfahbod7f97d2c2010-10-01 18:58:50 -040090 inline unsigned int get_len (void) const
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -040091 { return _hb_popcount32 ((unsigned int) *this); }
Behdad Esfahbod7f97d2c2010-10-01 18:58:50 -040092 inline unsigned int get_size (void) const
Behdad Esfahbode45d3f82010-05-06 19:33:31 -040093 { return get_len () * Value::static_size; }
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -040094
Behdad Esfahbodabcfe9b2011-05-11 00:02:02 -040095 void apply_value (hb_font_t *font,
Behdad Esfahbod3b0bb852011-05-20 15:59:59 -040096 hb_direction_t direction,
Behdad Esfahbodabcfe9b2011-05-11 00:02:02 -040097 const void *base,
98 const Value *values,
99 hb_glyph_position_t &glyph_pos) const
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400100 {
101 unsigned int x_ppem, y_ppem;
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400102 unsigned int format = *this;
Behdad Esfahbod3b0bb852011-05-20 15:59:59 -0400103 hb_bool_t horizontal = HB_DIRECTION_IS_HORIZONTAL (direction);
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400104
105 if (!format) return;
106
Behdad Esfahbodb6f902a2011-05-11 00:04:15 -0400107 if (format & xPlacement) glyph_pos.x_offset += font->em_scale_x (get_short (values++));
108 if (format & yPlacement) glyph_pos.y_offset += font->em_scale_y (get_short (values++));
Behdad Esfahbod3b0bb852011-05-20 15:59:59 -0400109 if (format & xAdvance) {
110 if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values++)); else values++;
111 }
Behdad Esfahbodcc2086d2011-05-19 19:19:50 -0400112 /* y_advance values grow downward but font-space grows upward, hence negation */
Behdad Esfahbod3b0bb852011-05-20 15:59:59 -0400113 if (format & yAdvance) {
114 if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values++)); else values++;
115 }
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400116
Behdad Esfahboda8d960b2010-04-29 14:31:56 -0400117 if (!has_device ()) return;
118
Behdad Esfahbodabcfe9b2011-05-11 00:02:02 -0400119 x_ppem = font->x_ppem;
120 y_ppem = font->y_ppem;
Behdad Esfahboda8d960b2010-04-29 14:31:56 -0400121
122 if (!x_ppem && !y_ppem) return;
123
Behdad Esfahbod0090dc02009-07-30 16:28:45 -0400124 /* pixel -> fractional pixel */
125 if (format & xPlaDevice) {
Behdad Esfahbodabcfe9b2011-05-11 00:02:02 -0400126 if (x_ppem) glyph_pos.x_offset += (base + get_device (values++)).get_x_delta (font); else values++;
Behdad Esfahbod0090dc02009-07-30 16:28:45 -0400127 }
128 if (format & yPlaDevice) {
Behdad Esfahbodabcfe9b2011-05-11 00:02:02 -0400129 if (y_ppem) glyph_pos.y_offset += (base + get_device (values++)).get_y_delta (font); else values++;
Behdad Esfahbod0090dc02009-07-30 16:28:45 -0400130 }
131 if (format & xAdvDevice) {
Behdad Esfahbod3b0bb852011-05-20 15:59:59 -0400132 if (horizontal && x_ppem) glyph_pos.x_advance += (base + get_device (values++)).get_x_delta (font); else values++;
Behdad Esfahbod0090dc02009-07-30 16:28:45 -0400133 }
134 if (format & yAdvDevice) {
Behdad Esfahbodcc2086d2011-05-19 19:19:50 -0400135 /* y_advance values grow downward but font-space grows upward, hence negation */
Behdad Esfahbod3b0bb852011-05-20 15:59:59 -0400136 if (!horizontal && y_ppem) glyph_pos.y_advance -= (base + get_device (values++)).get_y_delta (font); else values++;
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400137 }
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400138 }
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400139
140 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400141 inline bool sanitize_value_devices (hb_sanitize_context_t *c, void *base, Value *values) {
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400142 unsigned int format = *this;
143
144 if (format & xPlacement) values++;
145 if (format & yPlacement) values++;
146 if (format & xAdvance) values++;
147 if (format & yAdvance) values++;
148
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400149 if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
150 if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
151 if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
152 if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400153
154 return true;
155 }
156
Behdad Esfahbodc2ddfd22010-05-06 13:06:15 -0400157 static inline OffsetTo<Device>& get_device (Value* value)
158 { return *CastP<OffsetTo<Device> > (value); }
159 static inline const OffsetTo<Device>& get_device (const Value* value)
160 { return *CastP<OffsetTo<Device> > (value); }
161
162 static inline const SHORT& get_short (const Value* value)
163 { return *CastP<SHORT> (value); }
164
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400165 public:
166
Behdad Esfahbod7f97d2c2010-10-01 18:58:50 -0400167 inline bool has_device (void) const {
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400168 unsigned int format = *this;
169 return (format & devices) != 0;
170 }
171
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400172 inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *values) {
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400173 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400174 return c->check_range (values, get_size ())
175 && (!has_device () || sanitize_value_devices (c, base, values));
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400176 }
177
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400178 inline bool sanitize_values (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count) {
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400179 TRACE_SANITIZE ();
180 unsigned int len = get_len ();
181
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400182 if (!c->check_array (values, get_size (), count)) return false;
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400183
184 if (!has_device ()) return true;
185
186 for (unsigned int i = 0; i < count; i++) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400187 if (!sanitize_value_devices (c, base, values))
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400188 return false;
189 values += len;
190 }
191
192 return true;
193 }
194
Behdad Esfahbod278a91f2010-04-22 13:59:39 -0400195 /* Just sanitize referenced Device tables. Doesn't check the values themselves. */
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400196 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 -0400197 TRACE_SANITIZE ();
198
199 if (!has_device ()) return true;
200
201 for (unsigned int i = 0; i < count; i++) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400202 if (!sanitize_value_devices (c, base, values))
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400203 return false;
204 values += stride;
205 }
206
207 return true;
208 }
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400209};
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400210
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400211
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400212struct AnchorFormat1
213{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400214 friend struct Anchor;
215
216 private:
Behdad Esfahbodabcfe9b2011-05-11 00:02:02 -0400217 inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400218 hb_position_t *x, hb_position_t *y) const
219 {
Behdad Esfahbodb6f902a2011-05-11 00:04:15 -0400220 *x = font->em_scale_x (xCoordinate);
221 *y = font->em_scale_y (yCoordinate);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400222 }
223
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400224 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400225 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400226 return c->check_struct (this);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400227 }
228
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400229 private:
230 USHORT format; /* Format identifier--format = 1 */
231 SHORT xCoordinate; /* Horizontal value--in design units */
232 SHORT yCoordinate; /* Vertical value--in design units */
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400233 public:
234 DEFINE_SIZE_STATIC (6);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400235};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400236
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400237struct AnchorFormat2
238{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400239 friend struct Anchor;
240
241 private:
Behdad Esfahbodabcfe9b2011-05-11 00:02:02 -0400242 inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400243 hb_position_t *x, hb_position_t *y) const
244 {
Behdad Esfahbodabcfe9b2011-05-11 00:02:02 -0400245 unsigned int x_ppem = font->x_ppem;
246 unsigned int y_ppem = font->y_ppem;
Behdad Esfahbod6f729b42010-04-29 03:59:06 -0400247 hb_position_t cx, cy;
Behdad Esfahbod03420342010-11-03 15:40:07 -0400248 hb_bool_t ret = false;
Behdad Esfahbod6f729b42010-04-29 03:59:06 -0400249
250 if (x_ppem || y_ppem)
Behdad Esfahbod60fbb362011-05-19 18:46:15 -0400251 ret = hb_font_get_glyph_contour_point_for_origin (font, glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
Behdad Esfahbodb6f902a2011-05-11 00:04:15 -0400252 *x = x_ppem && ret ? cx : font->em_scale_x (xCoordinate);
253 *y = y_ppem && ret ? cy : font->em_scale_y (yCoordinate);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400254 }
255
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400256 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400257 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400258 return c->check_struct (this);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400259 }
260
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400261 private:
262 USHORT format; /* Format identifier--format = 2 */
263 SHORT xCoordinate; /* Horizontal value--in design units */
264 SHORT yCoordinate; /* Vertical value--in design units */
265 USHORT anchorPoint; /* Index to glyph contour point */
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400266 public:
267 DEFINE_SIZE_STATIC (8);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400268};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400269
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400270struct AnchorFormat3
271{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400272 friend struct Anchor;
273
274 private:
Behdad Esfahbodabcfe9b2011-05-11 00:02:02 -0400275 inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400276 hb_position_t *x, hb_position_t *y) const
277 {
Behdad Esfahbodb6f902a2011-05-11 00:04:15 -0400278 *x = font->em_scale_x (xCoordinate);
279 *y = font->em_scale_y (yCoordinate);
Behdad Esfahbodc18ec2b2009-05-21 04:54:01 -0400280
Behdad Esfahbodabcfe9b2011-05-11 00:02:02 -0400281 if (font->x_ppem)
282 *x += (this+xDeviceTable).get_x_delta (font);
283 if (font->y_ppem)
284 *y += (this+yDeviceTable).get_x_delta (font);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400285 }
286
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400287 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400288 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400289 return c->check_struct (this)
290 && xDeviceTable.sanitize (c, this)
291 && yDeviceTable.sanitize (c, this);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400292 }
293
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400294 private:
295 USHORT format; /* Format identifier--format = 3 */
296 SHORT xCoordinate; /* Horizontal value--in design units */
297 SHORT yCoordinate; /* Vertical value--in design units */
298 OffsetTo<Device>
299 xDeviceTable; /* Offset to Device table for X
300 * coordinate-- from beginning of
301 * Anchor table (may be NULL) */
302 OffsetTo<Device>
303 yDeviceTable; /* Offset to Device table for Y
304 * coordinate-- from beginning of
305 * Anchor table (may be NULL) */
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400306 public:
307 DEFINE_SIZE_STATIC (10);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400308};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400309
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400310struct Anchor
311{
Behdad Esfahbodabcfe9b2011-05-11 00:02:02 -0400312 inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400313 hb_position_t *x, hb_position_t *y) const
314 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400315 *x = *y = 0;
316 switch (u.format) {
Behdad Esfahbod60fbb362011-05-19 18:46:15 -0400317 case 1: u.format1.get_anchor (font, glyph_id, x, y); return;
318 case 2: u.format2.get_anchor (font, glyph_id, x, y); return;
319 case 3: u.format3.get_anchor (font, glyph_id, x, y); return;
320 default: return;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400321 }
322 }
323
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400324 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400325 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400326 if (!u.format.sanitize (c)) return false;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400327 switch (u.format) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400328 case 1: return u.format1.sanitize (c);
329 case 2: return u.format2.sanitize (c);
330 case 3: return u.format3.sanitize (c);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400331 default:return true;
332 }
333 }
334
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400335 private:
336 union {
337 USHORT format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -0400338 AnchorFormat1 format1;
339 AnchorFormat2 format2;
340 AnchorFormat3 format3;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400341 } u;
Behdad Esfahboded074222010-05-10 18:08:46 -0400342 public:
Behdad Esfahbod596e4712010-05-10 18:47:48 -0400343 DEFINE_SIZE_UNION (2, format);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400344};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400345
346
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400347struct AnchorMatrix
348{
349 inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols) const {
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400350 if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400351 return this+matrix[row * cols + col];
352 }
353
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400354 inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400355 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400356 if (!c->check_struct (this)) return false;
Behdad Esfahbod258305c2010-08-13 14:10:02 -0400357 if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return false;
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400358 unsigned int count = rows * cols;
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400359 if (!c->check_array (matrix, matrix[0].static_size, count)) return false;
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400360 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400361 if (!matrix[i].sanitize (c, this)) return false;
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400362 return true;
363 }
364
365 USHORT rows; /* Number of rows */
366 private:
367 OffsetTo<Anchor>
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -0500368 matrix[VAR]; /* Matrix of offsets to Anchor tables--
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400369 * from beginning of AnchorMatrix table */
Behdad Esfahbod569da922010-05-10 16:38:32 -0400370 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400371 DEFINE_SIZE_ARRAY (2, matrix);
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400372};
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400373
374
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400375struct MarkRecord
376{
Behdad Esfahbod377bfc52009-05-21 04:58:24 -0400377 friend struct MarkArray;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400378
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400379 inline bool sanitize (hb_sanitize_context_t *c, void *base) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400380 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400381 return c->check_struct (this)
382 && markAnchor.sanitize (c, base);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400383 }
384
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400385 private:
386 USHORT klass; /* Class defined for this mark */
387 OffsetTo<Anchor>
388 markAnchor; /* Offset to Anchor table--from
389 * beginning of MarkArray table */
Behdad Esfahbod569da922010-05-10 16:38:32 -0400390 public:
391 DEFINE_SIZE_STATIC (4);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400392};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400393
Behdad Esfahbodbea34c72010-05-10 17:28:16 -0400394struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage order */
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400395{
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400396 inline bool apply (hb_apply_context_t *c,
Behdad Esfahbodb41f2102009-08-14 19:33:24 -0400397 unsigned int mark_index, unsigned int glyph_index,
398 const AnchorMatrix &anchors, unsigned int class_count,
399 unsigned int glyph_pos) const
400 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400401 TRACE_APPLY ();
Behdad Esfahbodbea34c72010-05-10 17:28:16 -0400402 const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
Behdad Esfahbodb41f2102009-08-14 19:33:24 -0400403 unsigned int mark_class = record.klass;
404
405 const Anchor& mark_anchor = this + record.markAnchor;
406 const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count);
407
408 hb_position_t mark_x, mark_y, base_x, base_y;
409
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400410 mark_anchor.get_anchor (c->font, c->buffer->info[c->buffer->idx].codepoint, &mark_x, &mark_y);
Behdad Esfahbod60fbb362011-05-19 18:46:15 -0400411 glyph_anchor.get_anchor (c->font, c->buffer->info[glyph_pos].codepoint, &base_x, &base_y);
Behdad Esfahbodb41f2102009-08-14 19:33:24 -0400412
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400413 hb_glyph_position_t &o = c->buffer->pos[c->buffer->idx];
Behdad Esfahbod194d4562010-10-27 23:09:10 -0400414 o.x_offset = base_x - mark_x;
415 o.y_offset = base_y - mark_y;
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400416 o.attach_lookback() = c->buffer->idx - glyph_pos;
Behdad Esfahbodb41f2102009-08-14 19:33:24 -0400417
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400418 c->buffer->idx++;
Behdad Esfahbodb41f2102009-08-14 19:33:24 -0400419 return true;
420 }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400421
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400422 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400423 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400424 return ArrayOf<MarkRecord>::sanitize (c, this);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400425 }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400426};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400427
428
429/* Lookups */
430
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400431struct SinglePosFormat1
432{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400433 friend struct SinglePos;
434
435 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400436 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400437 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400438 TRACE_APPLY ();
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400439 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400440 if (likely (index == NOT_COVERED))
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400441 return false;
442
Behdad Esfahbod3b0bb852011-05-20 15:59:59 -0400443 valueFormat.apply_value (c->font, c->direction, this,
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400444 values, c->buffer->pos[c->buffer->idx]);
Behdad Esfahbodf53d4342009-05-30 22:17:32 -0400445
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400446 c->buffer->idx++;
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400447 return true;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400448 }
449
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400450 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400451 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400452 return c->check_struct (this)
453 && coverage.sanitize (c, this)
454 && valueFormat.sanitize_value (c, this, values);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400455 }
456
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400457 private:
458 USHORT format; /* Format identifier--format = 1 */
459 OffsetTo<Coverage>
460 coverage; /* Offset to Coverage table--from
461 * beginning of subtable */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400462 ValueFormat valueFormat; /* Defines the types of data in the
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400463 * ValueRecord */
464 ValueRecord values; /* Defines positioning
465 * value(s)--applied to all glyphs in
466 * the Coverage table */
Behdad Esfahbod569da922010-05-10 16:38:32 -0400467 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400468 DEFINE_SIZE_ARRAY (6, values);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400469};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400470
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400471struct SinglePosFormat2
472{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400473 friend struct SinglePos;
474
475 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400476 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400477 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400478 TRACE_APPLY ();
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400479 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400480 if (likely (index == NOT_COVERED))
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400481 return false;
482
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400483 if (likely (index >= valueCount))
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400484 return false;
485
Behdad Esfahbod3b0bb852011-05-20 15:59:59 -0400486 valueFormat.apply_value (c->font, c->direction, this,
Behdad Esfahbod4b8487d2010-03-16 03:46:17 -0400487 &values[index * valueFormat.get_len ()],
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400488 c->buffer->pos[c->buffer->idx]);
Behdad Esfahbodf53d4342009-05-30 22:17:32 -0400489
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400490 c->buffer->idx++;
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400491 return true;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400492 }
493
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400494 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400495 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400496 return c->check_struct (this)
497 && coverage.sanitize (c, this)
498 && valueFormat.sanitize_values (c, this, values, valueCount);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400499 }
500
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400501 private:
502 USHORT format; /* Format identifier--format = 2 */
503 OffsetTo<Coverage>
504 coverage; /* Offset to Coverage table--from
505 * beginning of subtable */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400506 ValueFormat valueFormat; /* Defines the types of data in the
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400507 * ValueRecord */
508 USHORT valueCount; /* Number of ValueRecords */
509 ValueRecord values; /* Array of ValueRecords--positioning
510 * values applied to glyphs */
Behdad Esfahbod569da922010-05-10 16:38:32 -0400511 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400512 DEFINE_SIZE_ARRAY (8, values);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400513};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400514
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400515struct SinglePos
516{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400517 friend struct PosLookupSubTable;
518
519 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400520 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400521 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400522 TRACE_APPLY ();
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400523 switch (u.format) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400524 case 1: return u.format1.apply (c);
525 case 2: return u.format2.apply (c);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400526 default:return false;
527 }
528 }
529
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400530 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400531 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400532 if (!u.format.sanitize (c)) return false;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400533 switch (u.format) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400534 case 1: return u.format1.sanitize (c);
535 case 2: return u.format2.sanitize (c);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400536 default:return true;
537 }
538 }
539
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400540 private:
541 union {
542 USHORT format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -0400543 SinglePosFormat1 format1;
544 SinglePosFormat2 format2;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400545 } u;
546};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400547
548
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400549struct PairValueRecord
550{
Behdad Esfahbod70c9bfd2010-05-11 00:23:50 -0400551 friend struct PairSet;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400552
553 private:
554 GlyphID secondGlyph; /* GlyphID of second glyph in the
555 * pair--first glyph is listed in the
556 * Coverage table */
557 ValueRecord values; /* Positioning data for the first glyph
558 * followed by for second glyph */
Behdad Esfahbod569da922010-05-10 16:38:32 -0400559 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400560 DEFINE_SIZE_ARRAY (2, values);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400561};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400562
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400563struct PairSet
564{
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400565 friend struct PairPosFormat1;
566
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400567 inline bool apply (hb_apply_context_t *c,
Behdad Esfahbod70c9bfd2010-05-11 00:23:50 -0400568 const ValueFormat *valueFormats,
569 unsigned int pos) const
570 {
571 TRACE_APPLY ();
572 unsigned int len1 = valueFormats[0].get_len ();
573 unsigned int len2 = valueFormats[1].get_len ();
574 unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
575
576 unsigned int count = len;
577 const PairValueRecord *record = CastP<PairValueRecord> (array);
578 for (unsigned int i = 0; i < count; i++)
579 {
Behdad Esfahbod7e7007a2010-05-14 22:02:37 -0400580 if (c->buffer->info[pos].codepoint == record->secondGlyph)
Behdad Esfahbod70c9bfd2010-05-11 00:23:50 -0400581 {
Behdad Esfahbod3b0bb852011-05-20 15:59:59 -0400582 valueFormats[0].apply_value (c->font, c->direction, this,
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400583 &record->values[0], c->buffer->pos[c->buffer->idx]);
Behdad Esfahbod3b0bb852011-05-20 15:59:59 -0400584 valueFormats[1].apply_value (c->font, c->direction, this,
585 &record->values[len1], c->buffer->pos[pos]);
Behdad Esfahbod70c9bfd2010-05-11 00:23:50 -0400586 if (len2)
587 pos++;
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400588 c->buffer->idx = pos;
Behdad Esfahbod70c9bfd2010-05-11 00:23:50 -0400589 return true;
590 }
591 record = &StructAtOffset<PairValueRecord> (record, record_size);
592 }
593
594 return false;
595 }
596
597 struct sanitize_closure_t {
598 void *base;
599 ValueFormat *valueFormats;
600 unsigned int len1; /* valueFormats[0].get_len() */
601 unsigned int stride; /* 1 + len1 + len2 */
602 };
603
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400604 inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400605 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400606 if (!(c->check_struct (this)
607 && c->check_array (array, USHORT::static_size * closure->stride, len))) return false;
Behdad Esfahbod70c9bfd2010-05-11 00:23:50 -0400608
609 unsigned int count = len;
610 PairValueRecord *record = CastP<PairValueRecord> (array);
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400611 return closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride)
612 && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400613 }
614
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400615 private:
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400616 USHORT len; /* Number of PairValueRecords */
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400617 USHORT array[VAR]; /* Array of PairValueRecords--ordered
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400618 * by GlyphID of the second glyph */
Behdad Esfahbod569da922010-05-10 16:38:32 -0400619 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400620 DEFINE_SIZE_ARRAY (2, array);
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400621};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400622
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400623struct PairPosFormat1
624{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400625 friend struct PairPos;
626
627 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400628 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400629 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400630 TRACE_APPLY ();
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500631 hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
632 if (skippy_iter.has_no_chance ())
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400633 return false;
634
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500635 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400636 if (likely (index == NOT_COVERED))
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400637 return false;
638
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500639 if (!skippy_iter.next ())
640 return false;
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400641
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500642 return (this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400643 }
644
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400645 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400646 TRACE_SANITIZE ();
Behdad Esfahbodeba8b4f2010-03-29 00:04:12 -0400647
648 unsigned int len1 = valueFormat1.get_len ();
649 unsigned int len2 = valueFormat2.get_len ();
Behdad Esfahbod70c9bfd2010-05-11 00:23:50 -0400650 PairSet::sanitize_closure_t closure = {
651 this,
652 &valueFormat1,
653 len1,
654 1 + len1 + len2
655 };
Behdad Esfahbodeba8b4f2010-03-29 00:04:12 -0400656
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400657 return c->check_struct (this)
658 && coverage.sanitize (c, this)
659 && pairSet.sanitize (c, this, &closure);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400660 }
661
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400662 private:
663 USHORT format; /* Format identifier--format = 1 */
664 OffsetTo<Coverage>
665 coverage; /* Offset to Coverage table--from
666 * beginning of subtable */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400667 ValueFormat valueFormat1; /* Defines the types of data in
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400668 * ValueRecord1--for the first glyph
669 * in the pair--may be zero (0) */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400670 ValueFormat valueFormat2; /* Defines the types of data in
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400671 * ValueRecord2--for the second glyph
672 * in the pair--may be zero (0) */
673 OffsetArrayOf<PairSet>
674 pairSet; /* Array of PairSet tables
675 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400676 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400677 DEFINE_SIZE_ARRAY (10, pairSet);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400678};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400679
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400680struct PairPosFormat2
681{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400682 friend struct PairPos;
683
684 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400685 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400686 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400687 TRACE_APPLY ();
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500688 hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
689 if (skippy_iter.has_no_chance ())
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400690 return false;
691
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500692 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400693 if (likely (index == NOT_COVERED))
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400694 return false;
695
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500696 if (!skippy_iter.next ())
697 return false;
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400698
699 unsigned int len1 = valueFormat1.get_len ();
700 unsigned int len2 = valueFormat2.get_len ();
701 unsigned int record_len = len1 + len2;
702
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400703 unsigned int klass1 = (this+classDef1) (c->buffer->info[c->buffer->idx].codepoint);
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500704 unsigned int klass2 = (this+classDef2) (c->buffer->info[skippy_iter.idx].codepoint);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400705 if (unlikely (klass1 >= class1Count || klass2 >= class2Count))
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400706 return false;
707
Behdad Esfahbod4b8487d2010-03-16 03:46:17 -0400708 const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
Behdad Esfahbod3b0bb852011-05-20 15:59:59 -0400709 valueFormat1.apply_value (c->font, c->direction, this,
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400710 v, c->buffer->pos[c->buffer->idx]);
Behdad Esfahbod3b0bb852011-05-20 15:59:59 -0400711 valueFormat2.apply_value (c->font, c->direction, this,
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500712 v + len1, c->buffer->pos[skippy_iter.idx]);
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400713
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500714 c->buffer->idx = skippy_iter.idx;
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400715 if (len2)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500716 c->buffer->idx++;
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400717
718 return true;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400719 }
720
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400721 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400722 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400723 if (!(c->check_struct (this)
724 && coverage.sanitize (c, this)
725 && classDef1.sanitize (c, this)
726 && classDef2.sanitize (c, this))) return false;
Behdad Esfahbod815a73e2009-08-14 17:31:16 -0400727
Behdad Esfahbodeba8b4f2010-03-29 00:04:12 -0400728 unsigned int len1 = valueFormat1.get_len ();
729 unsigned int len2 = valueFormat2.get_len ();
730 unsigned int stride = len1 + len2;
Behdad Esfahbod4b8487d2010-03-16 03:46:17 -0400731 unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
Behdad Esfahbodeba8b4f2010-03-29 00:04:12 -0400732 unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400733 return c->check_array (values, record_size, count) &&
734 valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
735 valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400736 }
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400737
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400738 private:
739 USHORT format; /* Format identifier--format = 2 */
740 OffsetTo<Coverage>
741 coverage; /* Offset to Coverage table--from
742 * beginning of subtable */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400743 ValueFormat valueFormat1; /* ValueRecord definition--for the
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400744 * first glyph of the pair--may be zero
745 * (0) */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400746 ValueFormat valueFormat2; /* ValueRecord definition--for the
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400747 * second glyph of the pair--may be
748 * zero (0) */
749 OffsetTo<ClassDef>
750 classDef1; /* Offset to ClassDef table--from
751 * beginning of PairPos subtable--for
752 * the first glyph of the pair */
753 OffsetTo<ClassDef>
754 classDef2; /* Offset to ClassDef table--from
755 * beginning of PairPos subtable--for
756 * the second glyph of the pair */
757 USHORT class1Count; /* Number of classes in ClassDef1
758 * table--includes Class0 */
759 USHORT class2Count; /* Number of classes in ClassDef2
760 * table--includes Class0 */
761 ValueRecord values; /* Matrix of value pairs:
762 * class1-major, class2-minor,
763 * Each entry has value1 and value2 */
Behdad Esfahbod569da922010-05-10 16:38:32 -0400764 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400765 DEFINE_SIZE_ARRAY (16, values);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400766};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400767
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400768struct PairPos
769{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400770 friend struct PosLookupSubTable;
771
772 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400773 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400774 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400775 TRACE_APPLY ();
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400776 switch (u.format) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400777 case 1: return u.format1.apply (c);
778 case 2: return u.format2.apply (c);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400779 default:return false;
780 }
781 }
782
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400783 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400784 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400785 if (!u.format.sanitize (c)) return false;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400786 switch (u.format) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400787 case 1: return u.format1.sanitize (c);
788 case 2: return u.format2.sanitize (c);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400789 default:return true;
790 }
791 }
792
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400793 private:
794 union {
795 USHORT format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -0400796 PairPosFormat1 format1;
797 PairPosFormat2 format2;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400798 } u;
799};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400800
801
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400802struct EntryExitRecord
803{
Behdad Esfahbod569da922010-05-10 16:38:32 -0400804 friend struct CursivePosFormat1;
805
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400806 inline bool sanitize (hb_sanitize_context_t *c, void *base) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400807 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400808 return entryAnchor.sanitize (c, base)
809 && exitAnchor.sanitize (c, base);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400810 }
811
Behdad Esfahbod569da922010-05-10 16:38:32 -0400812 private:
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400813 OffsetTo<Anchor>
814 entryAnchor; /* Offset to EntryAnchor table--from
815 * beginning of CursivePos
816 * subtable--may be NULL */
817 OffsetTo<Anchor>
818 exitAnchor; /* Offset to ExitAnchor table--from
819 * beginning of CursivePos
820 * subtable--may be NULL */
Behdad Esfahbod569da922010-05-10 16:38:32 -0400821 public:
822 DEFINE_SIZE_STATIC (4);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400823};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400824
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400825struct CursivePosFormat1
826{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400827 friend struct CursivePos;
828
829 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400830 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400831 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400832 TRACE_APPLY ();
Behdad Esfahbod0f7e6b22009-05-20 04:16:35 -0400833
834 /* We don't handle mark glyphs here. */
Behdad Esfahbod98370e82010-10-27 17:39:01 -0400835 if (c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
Behdad Esfahbod0f7e6b22009-05-20 04:16:35 -0400836 return false;
837
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500838 hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
839 if (skippy_iter.has_no_chance ())
Behdad Esfahbod0f7e6b22009-05-20 04:16:35 -0400840 return false;
841
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500842 const EntryExitRecord &this_record = entryExitRecord[(this+coverage) (c->buffer->info[c->buffer->idx].codepoint)];
Behdad Esfahbodaf5d02a2010-10-27 11:54:26 -0400843 if (!this_record.exitAnchor)
844 return false;
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400845
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500846 if (!skippy_iter.next ())
847 return false;
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400848
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500849 const EntryExitRecord &next_record = entryExitRecord[(this+coverage) (c->buffer->info[skippy_iter.idx].codepoint)];
Behdad Esfahbodaf5d02a2010-10-27 11:54:26 -0400850 if (!next_record.entryAnchor)
851 return false;
852
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400853 unsigned int i = c->buffer->idx;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500854 unsigned int j = skippy_iter.idx;
Behdad Esfahbodaf5d02a2010-10-27 11:54:26 -0400855
856 hb_position_t entry_x, entry_y, exit_x, exit_y;
Behdad Esfahbod60fbb362011-05-19 18:46:15 -0400857 (this+this_record.exitAnchor).get_anchor (c->font, c->buffer->info[i].codepoint, &exit_x, &exit_y);
858 (this+next_record.entryAnchor).get_anchor (c->font, c->buffer->info[j].codepoint, &entry_x, &entry_y);
Behdad Esfahbodcc83ae12009-05-27 00:17:37 -0400859
Behdad Esfahbod7403e052011-05-24 21:04:15 -0400860 hb_glyph_position_t *pos = c->buffer->pos;
861
862 hb_position_t d;
863 /* Main-direction adjustment */
864 switch (c->direction) {
865 case HB_DIRECTION_LTR:
866 pos[i].x_advance = exit_x + pos[i].x_offset;
867
868 d = entry_x + pos[j].x_offset;
869 pos[j].x_advance -= d;
870 pos[j].x_offset -= d;
871 break;
872 case HB_DIRECTION_RTL:
873 d = exit_x + pos[i].x_offset;
874 pos[i].x_advance -= d;
875 pos[i].x_offset -= d;
876
877 pos[j].x_advance = entry_x + pos[j].x_offset;
878 break;
879 case HB_DIRECTION_TTB:
880 pos[i].y_advance = exit_y + pos[i].y_offset;
881
882 d = entry_y + pos[j].y_offset;
883 pos[j].y_advance -= d;
884 pos[j].y_offset -= d;
885 break;
886 case HB_DIRECTION_BTT:
887 d = exit_y + pos[i].y_offset;
888 pos[i].y_advance -= d;
889 pos[i].y_offset -= d;
890
891 pos[j].y_advance = entry_y;
892 break;
893 case HB_DIRECTION_INVALID:
894 default:
895 break;
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400896 }
897
Behdad Esfahbod7403e052011-05-24 21:04:15 -0400898 /* Cross-direction adjustment */
899 if (c->lookup_props & LookupFlag::RightToLeft) {
900 pos[i].cursive_chain() = j - i;
Behdad Esfahbod744970a2011-05-16 18:15:37 -0400901 if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
Behdad Esfahbod7403e052011-05-24 21:04:15 -0400902 pos[i].y_offset = entry_y - exit_y;
Behdad Esfahbod13528d02010-10-27 14:09:27 -0400903 else
Behdad Esfahbod7403e052011-05-24 21:04:15 -0400904 pos[i].x_offset = entry_x - exit_x;
905 } else {
906 pos[j].cursive_chain() = i - j;
Behdad Esfahbod744970a2011-05-16 18:15:37 -0400907 if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
Behdad Esfahbod7403e052011-05-24 21:04:15 -0400908 pos[j].y_offset = exit_y - entry_y;
Behdad Esfahbod13528d02010-10-27 14:09:27 -0400909 else
Behdad Esfahbod7403e052011-05-24 21:04:15 -0400910 pos[j].x_offset = exit_x - entry_x;
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400911 }
912
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400913 c->buffer->idx = j;
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400914 return true;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400915 }
916
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400917 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400918 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400919 return coverage.sanitize (c, this)
920 && entryExitRecord.sanitize (c, this);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400921 }
922
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400923 private:
924 USHORT format; /* Format identifier--format = 1 */
925 OffsetTo<Coverage>
926 coverage; /* Offset to Coverage table--from
927 * beginning of subtable */
928 ArrayOf<EntryExitRecord>
929 entryExitRecord; /* Array of EntryExit records--in
930 * Coverage Index order */
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400931 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400932 DEFINE_SIZE_ARRAY (6, entryExitRecord);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400933};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400934
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400935struct CursivePos
936{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400937 friend struct PosLookupSubTable;
938
939 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400940 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400941 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400942 TRACE_APPLY ();
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400943 switch (u.format) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400944 case 1: return u.format1.apply (c);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400945 default:return false;
946 }
947 }
948
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400949 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400950 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400951 if (!u.format.sanitize (c)) return false;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400952 switch (u.format) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400953 case 1: return u.format1.sanitize (c);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400954 default:return true;
955 }
956 }
957
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400958 private:
959 union {
960 USHORT format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -0400961 CursivePosFormat1 format1;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400962 } u;
963};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400964
965
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400966typedef AnchorMatrix BaseArray; /* base-major--
967 * in order of BaseCoverage Index--,
968 * mark-minor--
Behdad Esfahbodfb3b5cc2009-05-21 04:47:05 -0400969 * ordered by class--zero-based. */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400970
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400971struct MarkBasePosFormat1
972{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400973 friend struct MarkBasePos;
974
975 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400976 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400977 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400978 TRACE_APPLY ();
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400979 unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->idx].codepoint);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400980 if (likely (mark_index == NOT_COVERED))
Behdad Esfahbod357ccde2009-05-21 06:32:01 -0400981 return false;
982
983 /* now we search backwards for a non-mark glyph */
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400984 unsigned int property;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500985 hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
986 if (!skippy_iter.prev (&property, LookupFlag::IgnoreMarks))
987 return false;
Behdad Esfahbod0532ed12009-08-12 15:40:04 -0400988
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400989 /* The following assertion is too strong, so we've disabled it. */
Behdad Esfahbodb8783c82010-11-03 11:50:21 -0400990 if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH))
991 {/*return false;*/}
Behdad Esfahbod357ccde2009-05-21 06:32:01 -0400992
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500993 unsigned int base_index = (this+baseCoverage) (c->buffer->info[skippy_iter.idx].codepoint);
Behdad Esfahbodfe550f42009-05-21 08:27:07 -0400994 if (base_index == NOT_COVERED)
Behdad Esfahbod357ccde2009-05-21 06:32:01 -0400995 return false;
996
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500997 return (this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400998 }
999
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001000 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001001 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001002 return c->check_struct (this)
1003 && markCoverage.sanitize (c, this)
1004 && baseCoverage.sanitize (c, this)
1005 && markArray.sanitize (c, this)
1006 && baseArray.sanitize (c, this, (unsigned int) classCount);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001007 }
1008
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001009 private:
1010 USHORT format; /* Format identifier--format = 1 */
Behdad Esfahbodfb3b5cc2009-05-21 04:47:05 -04001011 OffsetTo<Coverage>
1012 markCoverage; /* Offset to MarkCoverage table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001013 * beginning of MarkBasePos subtable */
Behdad Esfahbodfb3b5cc2009-05-21 04:47:05 -04001014 OffsetTo<Coverage>
1015 baseCoverage; /* Offset to BaseCoverage table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001016 * beginning of MarkBasePos subtable */
1017 USHORT classCount; /* Number of classes defined for marks */
Behdad Esfahbodfb3b5cc2009-05-21 04:47:05 -04001018 OffsetTo<MarkArray>
1019 markArray; /* Offset to MarkArray table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001020 * beginning of MarkBasePos subtable */
Behdad Esfahbodfb3b5cc2009-05-21 04:47:05 -04001021 OffsetTo<BaseArray>
1022 baseArray; /* Offset to BaseArray table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001023 * beginning of MarkBasePos subtable */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001024 public:
1025 DEFINE_SIZE_STATIC (12);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001026};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001027
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001028struct MarkBasePos
1029{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001030 friend struct PosLookupSubTable;
1031
1032 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001033 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001034 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001035 TRACE_APPLY ();
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001036 switch (u.format) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001037 case 1: return u.format1.apply (c);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001038 default:return false;
1039 }
1040 }
1041
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001042 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001043 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001044 if (!u.format.sanitize (c)) return false;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001045 switch (u.format) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001046 case 1: return u.format1.sanitize (c);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001047 default:return true;
1048 }
1049 }
1050
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001051 private:
1052 union {
1053 USHORT format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04001054 MarkBasePosFormat1 format1;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001055 } u;
1056};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001057
1058
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -04001059typedef AnchorMatrix LigatureAttach; /* component-major--
1060 * in order of writing direction--,
1061 * mark-minor--
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001062 * ordered by class--zero-based. */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001063
Behdad Esfahbod3564ee52009-08-14 18:32:56 -04001064typedef OffsetListOf<LigatureAttach> LigatureArray;
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001065 /* Array of LigatureAttach
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001066 * tables ordered by
1067 * LigatureCoverage Index */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001068
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001069struct MarkLigPosFormat1
1070{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001071 friend struct MarkLigPos;
1072
1073 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001074 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001075 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001076 TRACE_APPLY ();
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -04001077 unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->idx].codepoint);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001078 if (likely (mark_index == NOT_COVERED))
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001079 return false;
1080
1081 /* now we search backwards for a non-mark glyph */
Behdad Esfahbod1376fb72010-04-29 02:19:21 -04001082 unsigned int property;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -05001083 hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
1084 if (!skippy_iter.prev (&property, LookupFlag::IgnoreMarks))
1085 return false;
Behdad Esfahbod0532ed12009-08-12 15:40:04 -04001086
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001087 /* The following assertion is too strong, so we've disabled it. */
Behdad Esfahbodb8783c82010-11-03 11:50:21 -04001088 if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE))
1089 {/*return false;*/}
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001090
Behdad Esfahbod4ab97312012-01-16 22:05:08 -05001091 unsigned int j = skippy_iter.idx;
Behdad Esfahbod7e7007a2010-05-14 22:02:37 -04001092 unsigned int lig_index = (this+ligatureCoverage) (c->buffer->info[j].codepoint);
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001093 if (lig_index == NOT_COVERED)
1094 return false;
1095
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001096 const LigatureArray& lig_array = this+ligatureArray;
Behdad Esfahbod3564ee52009-08-14 18:32:56 -04001097 const LigatureAttach& lig_attach = lig_array[lig_index];
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -04001098
1099 /* Find component to attach to */
Behdad Esfahbodb2b18ef2009-08-14 19:37:18 -04001100 unsigned int comp_count = lig_attach.rows;
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001101 if (unlikely (!comp_count))
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001102 return false;
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001103 unsigned int comp_index;
1104 /* We must now check whether the ligature ID of the current mark glyph
1105 * is identical to the ligature ID of the found ligature. If yes, we
1106 * can directly use the component index. If not, we attach the mark
1107 * glyph to the last component of the ligature. */
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -04001108 if (c->buffer->info[j].lig_id() && c->buffer->info[j].lig_id() == c->buffer->info[c->buffer->idx].lig_id() && c->buffer->info[c->buffer->idx].lig_comp())
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001109 {
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -04001110 comp_index = c->buffer->info[c->buffer->idx].lig_comp() - 1;
Behdad Esfahbodb2b18ef2009-08-14 19:37:18 -04001111 if (comp_index >= comp_count)
1112 comp_index = comp_count - 1;
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001113 }
1114 else
Behdad Esfahbodb2b18ef2009-08-14 19:37:18 -04001115 comp_index = comp_count - 1;
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001116
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001117 return (this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001118 }
1119
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001120 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001121 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001122 return c->check_struct (this)
1123 && markCoverage.sanitize (c, this)
1124 && ligatureCoverage.sanitize (c, this)
1125 && markArray.sanitize (c, this)
1126 && ligatureArray.sanitize (c, this, (unsigned int) classCount);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001127 }
1128
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001129 private:
1130 USHORT format; /* Format identifier--format = 1 */
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001131 OffsetTo<Coverage>
1132 markCoverage; /* Offset to Mark Coverage table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001133 * beginning of MarkLigPos subtable */
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001134 OffsetTo<Coverage>
1135 ligatureCoverage; /* Offset to Ligature Coverage
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001136 * table--from beginning of MarkLigPos
1137 * subtable */
1138 USHORT classCount; /* Number of defined mark classes */
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001139 OffsetTo<MarkArray>
1140 markArray; /* Offset to MarkArray table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001141 * beginning of MarkLigPos subtable */
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001142 OffsetTo<LigatureArray>
1143 ligatureArray; /* Offset to LigatureArray table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001144 * beginning of MarkLigPos subtable */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001145 public:
1146 DEFINE_SIZE_STATIC (12);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001147};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001148
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001149struct MarkLigPos
1150{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001151 friend struct PosLookupSubTable;
1152
1153 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001154 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001155 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001156 TRACE_APPLY ();
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001157 switch (u.format) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001158 case 1: return u.format1.apply (c);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001159 default:return false;
1160 }
1161 }
1162
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001163 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001164 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001165 if (!u.format.sanitize (c)) return false;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001166 switch (u.format) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001167 case 1: return u.format1.sanitize (c);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001168 default:return true;
1169 }
1170 }
1171
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001172 private:
1173 union {
1174 USHORT format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04001175 MarkLigPosFormat1 format1;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001176 } u;
1177};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001178
1179
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -04001180typedef AnchorMatrix Mark2Array; /* mark2-major--
1181 * in order of Mark2Coverage Index--,
1182 * mark1-minor--
1183 * ordered by class--zero-based. */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001184
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001185struct MarkMarkPosFormat1
1186{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001187 friend struct MarkMarkPos;
1188
1189 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001190 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001191 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001192 TRACE_APPLY ();
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -04001193 unsigned int mark1_index = (this+mark1Coverage) (c->buffer->info[c->buffer->idx].codepoint);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001194 if (likely (mark1_index == NOT_COVERED))
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001195 return false;
1196
1197 /* now we search backwards for a suitable mark glyph until a non-mark glyph */
Behdad Esfahbod1376fb72010-04-29 02:19:21 -04001198 unsigned int property;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -05001199 hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
1200 if (!skippy_iter.prev (&property))
1201 return false;
Behdad Esfahbod0532ed12009-08-12 15:40:04 -04001202
Behdad Esfahbod80ea5bd2009-05-26 17:58:37 -04001203 if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
1204 return false;
1205
Behdad Esfahbod4ab97312012-01-16 22:05:08 -05001206 unsigned int j = skippy_iter.idx;
1207
Behdad Esfahbod80ea5bd2009-05-26 17:58:37 -04001208 /* Two marks match only if they belong to the same base, or same component
Behdad Esfahbodc3f9f7e2009-11-05 16:16:14 -05001209 * of the same ligature. That is, the component numbers must match, and
1210 * if those are non-zero, the ligid number should also match. */
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -04001211 if ((c->buffer->info[j].lig_comp() != c->buffer->info[c->buffer->idx].lig_comp()) ||
1212 (c->buffer->info[j].lig_comp() && c->buffer->info[j].lig_id() != c->buffer->info[c->buffer->idx].lig_id()))
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001213 return false;
1214
Behdad Esfahbod7e7007a2010-05-14 22:02:37 -04001215 unsigned int mark2_index = (this+mark2Coverage) (c->buffer->info[j].codepoint);
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001216 if (mark2_index == NOT_COVERED)
1217 return false;
1218
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001219 return (this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001220 }
1221
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001222 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001223 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001224 return c->check_struct (this)
1225 && mark1Coverage.sanitize (c, this)
1226 && mark2Coverage.sanitize (c, this)
1227 && mark1Array.sanitize (c, this)
1228 && mark2Array.sanitize (c, this, (unsigned int) classCount);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001229 }
1230
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001231 private:
1232 USHORT format; /* Format identifier--format = 1 */
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001233 OffsetTo<Coverage>
1234 mark1Coverage; /* Offset to Combining Mark1 Coverage
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001235 * table--from beginning of MarkMarkPos
1236 * subtable */
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001237 OffsetTo<Coverage>
1238 mark2Coverage; /* Offset to Combining Mark2 Coverage
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001239 * table--from beginning of MarkMarkPos
1240 * subtable */
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001241 USHORT classCount; /* Number of defined mark classes */
1242 OffsetTo<MarkArray>
1243 mark1Array; /* Offset to Mark1Array table--from
1244 * beginning of MarkMarkPos subtable */
1245 OffsetTo<Mark2Array>
1246 mark2Array; /* Offset to Mark2Array table--from
1247 * beginning of MarkMarkPos subtable */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001248 public:
1249 DEFINE_SIZE_STATIC (12);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001250};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001251
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001252struct MarkMarkPos
1253{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001254 friend struct PosLookupSubTable;
1255
1256 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001257 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001258 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001259 TRACE_APPLY ();
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001260 switch (u.format) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001261 case 1: return u.format1.apply (c);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001262 default:return false;
1263 }
1264 }
1265
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001266 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001267 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001268 if (!u.format.sanitize (c)) return false;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001269 switch (u.format) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001270 case 1: return u.format1.sanitize (c);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001271 default:return true;
1272 }
1273 }
1274
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001275 private:
1276 union {
1277 USHORT format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04001278 MarkMarkPosFormat1 format1;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001279 } u;
1280};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001281
1282
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001283static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001284
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001285struct ContextPos : Context
1286{
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04001287 friend struct PosLookupSubTable;
1288
1289 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001290 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod0535b502009-08-28 17:14:33 -04001291 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001292 TRACE_APPLY ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001293 return Context::apply (c, position_lookup);
Behdad Esfahbod0535b502009-08-28 17:14:33 -04001294 }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001295};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001296
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001297struct ChainContextPos : ChainContext
1298{
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04001299 friend struct PosLookupSubTable;
1300
1301 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001302 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod0535b502009-08-28 17:14:33 -04001303 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001304 TRACE_APPLY ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001305 return ChainContext::apply (c, position_lookup);
Behdad Esfahbod0535b502009-08-28 17:14:33 -04001306 }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001307};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001308
1309
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04001310struct ExtensionPos : Extension
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001311{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001312 friend struct PosLookupSubTable;
1313
1314 private:
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001315 inline const struct PosLookupSubTable& get_subtable (void) const
Behdad Esfahbod3b2c2df2010-04-22 16:51:42 -04001316 {
1317 unsigned int offset = get_offset ();
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001318 if (unlikely (!offset)) return Null(PosLookupSubTable);
Behdad Esfahbod09766b12010-05-10 17:36:03 -04001319 return StructAtOffset<PosLookupSubTable> (this, offset);
Behdad Esfahbod3b2c2df2010-04-22 16:51:42 -04001320 }
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001321
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001322 inline bool apply (hb_apply_context_t *c) const;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001323
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001324 inline bool sanitize (hb_sanitize_context_t *c);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001325};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001326
1327
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04001328
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001329/*
1330 * PosLookup
1331 */
1332
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001333
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001334struct PosLookupSubTable
1335{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001336 friend struct PosLookup;
1337
Behdad Esfahbodc6035cf2012-04-12 13:23:59 -04001338 enum Type {
Behdad Esfahbodff05d252009-05-20 03:53:00 -04001339 Single = 1,
1340 Pair = 2,
1341 Cursive = 3,
1342 MarkBase = 4,
1343 MarkLig = 5,
1344 MarkMark = 6,
1345 Context = 7,
1346 ChainContext = 8,
Behdad Esfahbod8f034d52009-08-18 16:41:59 -04001347 Extension = 9
Behdad Esfahbodff05d252009-05-20 03:53:00 -04001348 };
1349
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001350 inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) 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 (lookup_type) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001354 case Single: return u.single.apply (c);
1355 case Pair: return u.pair.apply (c);
1356 case Cursive: return u.cursive.apply (c);
1357 case MarkBase: return u.markBase.apply (c);
1358 case MarkLig: return u.markLig.apply (c);
1359 case MarkMark: return u.markMark.apply (c);
1360 case Context: return u.c.apply (c);
1361 case ChainContext: return u.chainContext.apply (c);
1362 case Extension: return u.extension.apply (c);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001363 default:return false;
1364 }
1365 }
1366
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001367 inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001368 TRACE_SANITIZE ();
Behdad Esfahbodfe9bc072010-05-10 21:39:24 -04001369 switch (lookup_type) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001370 case Single: return u.single.sanitize (c);
1371 case Pair: return u.pair.sanitize (c);
1372 case Cursive: return u.cursive.sanitize (c);
1373 case MarkBase: return u.markBase.sanitize (c);
1374 case MarkLig: return u.markLig.sanitize (c);
1375 case MarkMark: return u.markMark.sanitize (c);
1376 case Context: return u.c.sanitize (c);
1377 case ChainContext: return u.chainContext.sanitize (c);
1378 case Extension: return u.extension.sanitize (c);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001379 default:return true;
1380 }
1381 }
1382
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001383 private:
1384 union {
Behdad Esfahbodfe9bc072010-05-10 21:39:24 -04001385 USHORT sub_format;
Behdad Esfahboddacebca2010-05-10 19:45:41 -04001386 SinglePos single;
1387 PairPos pair;
1388 CursivePos cursive;
1389 MarkBasePos markBase;
1390 MarkLigPos markLig;
1391 MarkMarkPos markMark;
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001392 ContextPos c;
Behdad Esfahboddacebca2010-05-10 19:45:41 -04001393 ChainContextPos chainContext;
1394 ExtensionPos extension;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001395 } u;
Behdad Esfahboded074222010-05-10 18:08:46 -04001396 public:
Behdad Esfahbodfe9bc072010-05-10 21:39:24 -04001397 DEFINE_SIZE_UNION (2, sub_format);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001398};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001399
1400
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001401struct PosLookup : Lookup
1402{
1403 inline const PosLookupSubTable& get_subtable (unsigned int i) const
Behdad Esfahbod187454c2010-04-23 16:35:01 -04001404 { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001405
Behdad Esfahbod41ae6742012-04-11 17:11:05 -04001406 inline bool apply_once (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001407 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001408 unsigned int lookup_type = get_type ();
Behdad Esfahbod1376fb72010-04-29 02:19:21 -04001409
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -04001410 if (!_hb_ot_layout_check_glyph_property (c->face, &c->buffer->info[c->buffer->idx], c->lookup_props, &c->property))
Behdad Esfahbod923923f2009-05-22 17:58:09 -04001411 return false;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001412
1413 for (unsigned int i = 0; i < get_subtable_count (); i++)
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001414 if (get_subtable (i).apply (c, lookup_type))
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001415 return true;
1416
1417 return false;
1418 }
1419
Behdad Esfahbodabcfe9b2011-05-11 00:02:02 -04001420 inline bool apply_string (hb_font_t *font,
Behdad Esfahbod20b035d2009-08-10 19:00:36 -04001421 hb_buffer_t *buffer,
1422 hb_mask_t mask) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001423 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001424 bool ret = false;
1425
Behdad Esfahbod69603502010-05-14 22:07:46 -04001426 if (unlikely (!buffer->len))
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001427 return false;
1428
Behdad Esfahbod41ae6742012-04-11 17:11:05 -04001429 hb_apply_context_t c (font, font->face, buffer, mask, *this);
1430
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -04001431 buffer->idx = 0;
1432 while (buffer->idx < buffer->len)
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001433 {
Behdad Esfahbod41ae6742012-04-11 17:11:05 -04001434 if ((buffer->info[buffer->idx].mask & mask) && apply_once (&c))
Behdad Esfahbodaf5d02a2010-10-27 11:54:26 -04001435 ret = true;
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001436 else
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -04001437 buffer->idx++;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001438 }
1439
1440 return ret;
1441 }
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001442
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001443 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001444 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001445 if (unlikely (!Lookup::sanitize (c))) return false;
Behdad Esfahbod187454c2010-04-23 16:35:01 -04001446 OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable);
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001447 return list.sanitize (c, this, get_type ());
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001448 }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001449};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001450
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001451typedef OffsetListOf<PosLookup> PosLookupList;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001452
1453/*
Behdad Esfahbodae9877d2011-08-17 14:43:45 +02001454 * GPOS -- The Glyph Positioning Table
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001455 */
1456
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001457struct GPOS : GSUBGPOS
1458{
Behdad Esfahboda328d662009-08-04 20:27:05 -04001459 static const hb_tag_t Tag = HB_OT_TAG_GPOS;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001460
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001461 inline const PosLookup& get_lookup (unsigned int i) const
Behdad Esfahbod187454c2010-04-23 16:35:01 -04001462 { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001463
Behdad Esfahbodabcfe9b2011-05-11 00:02:02 -04001464 inline bool position_lookup (hb_font_t *font,
Behdad Esfahbod468769b2009-08-08 16:53:23 -04001465 hb_buffer_t *buffer,
1466 unsigned int lookup_index,
1467 hb_mask_t mask) const
Behdad Esfahbodabcfe9b2011-05-11 00:02:02 -04001468 { return get_lookup (lookup_index).apply_string (font, buffer, mask); }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001469
Behdad Esfahboda9ad3d32011-07-28 15:42:18 -04001470 static inline void position_start (hb_buffer_t *buffer);
Behdad Esfahbod1e7c1fc2010-10-27 22:48:31 -04001471 static inline void position_finish (hb_buffer_t *buffer);
1472
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001473 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001474 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001475 if (unlikely (!GSUBGPOS::sanitize (c))) return false;
Behdad Esfahbod187454c2010-04-23 16:35:01 -04001476 OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001477 return list.sanitize (c, this);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001478 }
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001479 public:
1480 DEFINE_SIZE_STATIC (10);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001481};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001482
Behdad Esfahbod7403e052011-05-24 21:04:15 -04001483
1484static void
1485fix_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
1486{
1487 unsigned int j = pos[i].cursive_chain();
1488 if (likely (!j))
1489 return;
1490
1491 j += i;
1492
1493 pos[i].cursive_chain() = 0;
1494
1495 fix_cursive_minor_offset (pos, j, direction);
1496
1497 if (HB_DIRECTION_IS_HORIZONTAL (direction))
1498 pos[i].y_offset += pos[j].y_offset;
1499 else
1500 pos[i].x_offset += pos[j].x_offset;
1501}
1502
1503static void
1504fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
1505{
1506 if (likely (!(pos[i].attach_lookback())))
1507 return;
1508
1509 unsigned int j = i - pos[i].attach_lookback();
1510
1511 pos[i].x_advance = 0;
1512 pos[i].y_advance = 0;
1513 pos[i].x_offset += pos[j].x_offset;
1514 pos[i].y_offset += pos[j].y_offset;
1515
1516 if (HB_DIRECTION_IS_FORWARD (direction))
Behdad Esfahbod21deab22011-05-30 11:08:40 -04001517 for (unsigned int k = j; k < i; k++) {
Behdad Esfahbod7403e052011-05-24 21:04:15 -04001518 pos[i].x_offset -= pos[k].x_advance;
1519 pos[i].y_offset -= pos[k].y_advance;
1520 }
1521 else
Behdad Esfahbod21deab22011-05-30 11:08:40 -04001522 for (unsigned int k = j + 1; k < i + 1; k++) {
Behdad Esfahbod7403e052011-05-24 21:04:15 -04001523 pos[i].x_offset += pos[k].x_advance;
1524 pos[i].y_offset += pos[k].y_advance;
1525 }
1526}
1527
Behdad Esfahbod1e7c1fc2010-10-27 22:48:31 -04001528void
Behdad Esfahboda9ad3d32011-07-28 15:42:18 -04001529GPOS::position_start (hb_buffer_t *buffer)
1530{
1531 buffer->clear_positions ();
Behdad Esfahbodb65c0602011-07-28 16:48:43 -04001532
1533 unsigned int count = buffer->len;
1534 for (unsigned int i = 0; i < count; i++)
1535 buffer->pos[i].attach_lookback() = buffer->pos[i].cursive_chain() = 0;
Behdad Esfahboda9ad3d32011-07-28 15:42:18 -04001536}
1537
1538void
Behdad Esfahbod1e7c1fc2010-10-27 22:48:31 -04001539GPOS::position_finish (hb_buffer_t *buffer)
1540{
Ryan Lortie70566be2011-04-15 18:32:36 -04001541 unsigned int len;
1542 hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
Behdad Esfahbod1e7c1fc2010-10-27 22:48:31 -04001543 hb_direction_t direction = buffer->props.direction;
1544
Behdad Esfahbod7403e052011-05-24 21:04:15 -04001545 /* Handle cursive connections */
1546 for (unsigned int i = 0; i < len; i++)
Behdad Esfahbod7403e052011-05-24 21:04:15 -04001547 fix_cursive_minor_offset (pos, i, direction);
Behdad Esfahbod1e7c1fc2010-10-27 22:48:31 -04001548
1549 /* Handle attachments */
Behdad Esfahbod7403e052011-05-24 21:04:15 -04001550 for (unsigned int i = 0; i < len; i++)
Behdad Esfahbod7403e052011-05-24 21:04:15 -04001551 fix_mark_attachment (pos, i, direction);
Behdad Esfahbodb65c0602011-07-28 16:48:43 -04001552
1553 HB_BUFFER_DEALLOCATE_VAR (buffer, lig_comp);
1554 HB_BUFFER_DEALLOCATE_VAR (buffer, lig_id);
1555 HB_BUFFER_DEALLOCATE_VAR (buffer, props_cache);
Behdad Esfahbod1e7c1fc2010-10-27 22:48:31 -04001556}
1557
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001558
1559/* Out-of-class implementation for methods recursing */
1560
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001561inline bool ExtensionPos::apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001562{
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001563 TRACE_APPLY ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001564 return get_subtable ().apply (c, get_type ());
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001565}
1566
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001567inline bool ExtensionPos::sanitize (hb_sanitize_context_t *c)
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001568{
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001569 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001570 if (unlikely (!Extension::sanitize (c))) return false;
Behdad Esfahbod3b2c2df2010-04-22 16:51:42 -04001571 unsigned int offset = get_offset ();
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001572 if (unlikely (!offset)) return true;
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001573 return StructAtOffset<PosLookupSubTable> (this, offset).sanitize (c, get_type ());
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001574}
1575
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001576static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index)
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001577{
Behdad Esfahbodabcfe9b2011-05-11 00:02:02 -04001578 const GPOS &gpos = *(c->face->ot_layout->gpos);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001579 const PosLookup &l = gpos.get_lookup (lookup_index);
1580
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001581 if (unlikely (c->nesting_level_left == 0))
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001582 return false;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001583
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001584 if (unlikely (c->context_length < 1))
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001585 return false;
1586
Behdad Esfahbod41ae6742012-04-11 17:11:05 -04001587 hb_apply_context_t new_c (*c, l);
1588 return l.apply_once (&new_c);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001589}
1590
1591
Behdad Esfahbod194d4562010-10-27 23:09:10 -04001592#undef attach_lookback
1593#undef cursive_chain
1594
1595
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001596
Behdad Esfahbod7a750ac2011-08-17 14:19:59 +02001597#endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */