blob: d5787607db754d280ed00092c5d473892e73dbd6 [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.
Behdad Esfahbod5b93e8d2012-04-23 22:26:13 -04003 * Copyright © 2010,2012 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 Esfahbod7c8e8442012-08-28 17:57:49 -040035namespace OT {
36
Behdad Esfahbod94a23aa2010-05-05 01:13:09 -040037
Behdad Esfahbodb65c0602011-07-28 16:48:43 -040038/* buffer **position** var allocations */
Behdad Esfahbod194d4562010-10-27 23:09:10 -040039#define attach_lookback() var.u16[0] /* number of glyphs to go back to attach this glyph to its base */
40#define cursive_chain() var.i16[1] /* character to which this connects, may be positive or negative */
41
42
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040043/* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
44
Behdad Esfahbodc2ddfd22010-05-06 13:06:15 -040045typedef USHORT Value;
Behdad Esfahbodc91facd2009-08-26 18:53:43 -040046
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -040047typedef Value ValueRecord[VAR];
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040048
Behdad Esfahbodfca6a0d2009-05-21 04:49:04 -040049struct ValueFormat : USHORT
50{
Behdad Esfahbodc6035cf2012-04-12 13:23:59 -040051 enum Flags {
Behdad Esfahbodfca6a0d2009-05-21 04:49:04 -040052 xPlacement = 0x0001, /* Includes horizontal adjustment for placement */
53 yPlacement = 0x0002, /* Includes vertical adjustment for placement */
54 xAdvance = 0x0004, /* Includes horizontal adjustment for advance */
55 yAdvance = 0x0008, /* Includes vertical adjustment for advance */
56 xPlaDevice = 0x0010, /* Includes horizontal Device table for placement */
57 yPlaDevice = 0x0020, /* Includes vertical Device table for placement */
58 xAdvDevice = 0x0040, /* Includes horizontal Device table for advance */
59 yAdvDevice = 0x0080, /* Includes vertical Device table for advance */
Behdad Esfahbode4b92b82009-05-26 15:38:53 -040060 ignored = 0x0F00, /* Was used in TrueType Open for MM fonts */
Behdad Esfahbodeba8b4f2010-03-29 00:04:12 -040061 reserved = 0xF000, /* For future use */
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -040062
Behdad Esfahbodeba8b4f2010-03-29 00:04:12 -040063 devices = 0x00F0 /* Mask for having any Device table */
Behdad Esfahbodfca6a0d2009-05-21 04:49:04 -040064 };
65
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -040066/* All fields are options. Only those available advance the value pointer. */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040067#if 0
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040068 SHORT xPlacement; /* Horizontal adjustment for
69 * placement--in design units */
70 SHORT yPlacement; /* Vertical adjustment for
71 * placement--in design units */
72 SHORT xAdvance; /* Horizontal adjustment for
73 * advance--in design units (only used
74 * for horizontal writing) */
75 SHORT yAdvance; /* Vertical adjustment for advance--in
76 * design units (only used for vertical
77 * writing) */
78 Offset xPlaDevice; /* Offset to Device table for
79 * horizontal placement--measured from
80 * beginning of PosTable (may be NULL) */
81 Offset yPlaDevice; /* Offset to Device table for vertical
82 * placement--measured from beginning
83 * of PosTable (may be NULL) */
84 Offset xAdvDevice; /* Offset to Device table for
85 * horizontal advance--measured from
86 * beginning of PosTable (may be NULL) */
87 Offset yAdvDevice; /* Offset to Device table for vertical
88 * advance--measured from beginning of
89 * PosTable (may be NULL) */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -040090#endif
91
Behdad Esfahbod7f97d2c2010-10-01 18:58:50 -040092 inline unsigned int get_len (void) const
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -040093 { return _hb_popcount32 ((unsigned int) *this); }
Behdad Esfahbod7f97d2c2010-10-01 18:58:50 -040094 inline unsigned int get_size (void) const
Behdad Esfahbode45d3f82010-05-06 19:33:31 -040095 { return get_len () * Value::static_size; }
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -040096
Behdad Esfahbodabcfe9b2011-05-11 00:02:02 -040097 void apply_value (hb_font_t *font,
Behdad Esfahbod3b0bb852011-05-20 15:59:59 -040098 hb_direction_t direction,
Behdad Esfahbodabcfe9b2011-05-11 00:02:02 -040099 const void *base,
100 const Value *values,
101 hb_glyph_position_t &glyph_pos) const
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400102 {
103 unsigned int x_ppem, y_ppem;
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400104 unsigned int format = *this;
Behdad Esfahbod3b0bb852011-05-20 15:59:59 -0400105 hb_bool_t horizontal = HB_DIRECTION_IS_HORIZONTAL (direction);
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400106
107 if (!format) return;
108
Behdad Esfahbodb6f902a2011-05-11 00:04:15 -0400109 if (format & xPlacement) glyph_pos.x_offset += font->em_scale_x (get_short (values++));
110 if (format & yPlacement) glyph_pos.y_offset += font->em_scale_y (get_short (values++));
Behdad Esfahbod3b0bb852011-05-20 15:59:59 -0400111 if (format & xAdvance) {
112 if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values++)); else values++;
113 }
Behdad Esfahbodcc2086d2011-05-19 19:19:50 -0400114 /* y_advance values grow downward but font-space grows upward, hence negation */
Behdad Esfahbod3b0bb852011-05-20 15:59:59 -0400115 if (format & yAdvance) {
116 if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values++)); else values++;
117 }
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400118
Behdad Esfahboda8d960b2010-04-29 14:31:56 -0400119 if (!has_device ()) return;
120
Behdad Esfahbodabcfe9b2011-05-11 00:02:02 -0400121 x_ppem = font->x_ppem;
122 y_ppem = font->y_ppem;
Behdad Esfahboda8d960b2010-04-29 14:31:56 -0400123
124 if (!x_ppem && !y_ppem) return;
125
Behdad Esfahbod0090dc02009-07-30 16:28:45 -0400126 /* pixel -> fractional pixel */
127 if (format & xPlaDevice) {
Behdad Esfahbodabcfe9b2011-05-11 00:02:02 -0400128 if (x_ppem) glyph_pos.x_offset += (base + get_device (values++)).get_x_delta (font); else values++;
Behdad Esfahbod0090dc02009-07-30 16:28:45 -0400129 }
130 if (format & yPlaDevice) {
Behdad Esfahbodabcfe9b2011-05-11 00:02:02 -0400131 if (y_ppem) glyph_pos.y_offset += (base + get_device (values++)).get_y_delta (font); else values++;
Behdad Esfahbod0090dc02009-07-30 16:28:45 -0400132 }
133 if (format & xAdvDevice) {
Behdad Esfahbod3b0bb852011-05-20 15:59:59 -0400134 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 -0400135 }
136 if (format & yAdvDevice) {
Behdad Esfahbodcc2086d2011-05-19 19:19:50 -0400137 /* y_advance values grow downward but font-space grows upward, hence negation */
Behdad Esfahbod3b0bb852011-05-20 15:59:59 -0400138 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 -0400139 }
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400140 }
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400141
142 private:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400143 inline bool sanitize_value_devices (hb_sanitize_context_t *c, void *base, Value *values) {
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400144 unsigned int format = *this;
145
146 if (format & xPlacement) values++;
147 if (format & yPlacement) values++;
148 if (format & xAdvance) values++;
149 if (format & yAdvance) values++;
150
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400151 if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
152 if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
153 if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
154 if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400155
156 return true;
157 }
158
Behdad Esfahbodc2ddfd22010-05-06 13:06:15 -0400159 static inline OffsetTo<Device>& get_device (Value* value)
160 { return *CastP<OffsetTo<Device> > (value); }
161 static inline const OffsetTo<Device>& get_device (const Value* value)
162 { return *CastP<OffsetTo<Device> > (value); }
163
164 static inline const SHORT& get_short (const Value* value)
165 { return *CastP<SHORT> (value); }
166
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400167 public:
168
Behdad Esfahbod7f97d2c2010-10-01 18:58:50 -0400169 inline bool has_device (void) const {
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400170 unsigned int format = *this;
171 return (format & devices) != 0;
172 }
173
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400174 inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *values) {
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400175 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200176 return TRACE_RETURN (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400177 }
178
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400179 inline bool sanitize_values (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count) {
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400180 TRACE_SANITIZE ();
181 unsigned int len = get_len ();
182
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200183 if (!c->check_array (values, get_size (), count)) return TRACE_RETURN (false);
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400184
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200185 if (!has_device ()) return TRACE_RETURN (true);
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400186
187 for (unsigned int i = 0; i < count; i++) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400188 if (!sanitize_value_devices (c, base, values))
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200189 return TRACE_RETURN (false);
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400190 values += len;
191 }
192
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200193 return TRACE_RETURN (true);
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400194 }
195
Behdad Esfahbod278a91f2010-04-22 13:59:39 -0400196 /* Just sanitize referenced Device tables. Doesn't check the values themselves. */
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400197 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 -0400198 TRACE_SANITIZE ();
199
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200200 if (!has_device ()) return TRACE_RETURN (true);
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400201
202 for (unsigned int i = 0; i < count; i++) {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400203 if (!sanitize_value_devices (c, base, values))
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200204 return TRACE_RETURN (false);
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400205 values += stride;
206 }
207
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200208 return TRACE_RETURN (true);
Behdad Esfahbod673a4ef2010-04-21 02:02:57 -0400209 }
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400210};
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400211
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400212
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400213struct AnchorFormat1
214{
Behdad Esfahbodabcfe9b2011-05-11 00:02:02 -0400215 inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400216 hb_position_t *x, hb_position_t *y) const
217 {
Behdad Esfahbodb6f902a2011-05-11 00:04:15 -0400218 *x = font->em_scale_x (xCoordinate);
219 *y = font->em_scale_y (yCoordinate);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400220 }
221
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400222 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400223 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200224 return TRACE_RETURN (c->check_struct (this));
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400225 }
226
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400227 protected:
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400228 USHORT format; /* Format identifier--format = 1 */
229 SHORT xCoordinate; /* Horizontal value--in design units */
230 SHORT yCoordinate; /* Vertical value--in design units */
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400231 public:
232 DEFINE_SIZE_STATIC (6);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400233};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400234
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400235struct AnchorFormat2
236{
Behdad Esfahbodabcfe9b2011-05-11 00:02:02 -0400237 inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400238 hb_position_t *x, hb_position_t *y) const
239 {
Behdad Esfahbodabcfe9b2011-05-11 00:02:02 -0400240 unsigned int x_ppem = font->x_ppem;
241 unsigned int y_ppem = font->y_ppem;
Behdad Esfahbod6f729b42010-04-29 03:59:06 -0400242 hb_position_t cx, cy;
Behdad Esfahbod03420342010-11-03 15:40:07 -0400243 hb_bool_t ret = false;
Behdad Esfahbod6f729b42010-04-29 03:59:06 -0400244
245 if (x_ppem || y_ppem)
Behdad Esfahbod8fbfda92012-08-01 19:03:46 -0400246 ret = font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
Behdad Esfahbodb6f902a2011-05-11 00:04:15 -0400247 *x = x_ppem && ret ? cx : font->em_scale_x (xCoordinate);
248 *y = y_ppem && ret ? cy : font->em_scale_y (yCoordinate);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400249 }
250
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400251 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400252 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200253 return TRACE_RETURN (c->check_struct (this));
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400254 }
255
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400256 protected:
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400257 USHORT format; /* Format identifier--format = 2 */
258 SHORT xCoordinate; /* Horizontal value--in design units */
259 SHORT yCoordinate; /* Vertical value--in design units */
260 USHORT anchorPoint; /* Index to glyph contour point */
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400261 public:
262 DEFINE_SIZE_STATIC (8);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400263};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400264
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400265struct AnchorFormat3
266{
Behdad Esfahbodabcfe9b2011-05-11 00:02:02 -0400267 inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400268 hb_position_t *x, hb_position_t *y) const
269 {
Behdad Esfahbodb6f902a2011-05-11 00:04:15 -0400270 *x = font->em_scale_x (xCoordinate);
271 *y = font->em_scale_y (yCoordinate);
Behdad Esfahbodc18ec2b2009-05-21 04:54:01 -0400272
Behdad Esfahbodabcfe9b2011-05-11 00:02:02 -0400273 if (font->x_ppem)
274 *x += (this+xDeviceTable).get_x_delta (font);
275 if (font->y_ppem)
276 *y += (this+yDeviceTable).get_x_delta (font);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400277 }
278
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400279 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400280 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200281 return TRACE_RETURN (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400282 }
283
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400284 protected:
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400285 USHORT format; /* Format identifier--format = 3 */
286 SHORT xCoordinate; /* Horizontal value--in design units */
287 SHORT yCoordinate; /* Vertical value--in design units */
288 OffsetTo<Device>
289 xDeviceTable; /* Offset to Device table for X
290 * coordinate-- from beginning of
291 * Anchor table (may be NULL) */
292 OffsetTo<Device>
293 yDeviceTable; /* Offset to Device table for Y
294 * coordinate-- from beginning of
295 * Anchor table (may be NULL) */
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400296 public:
297 DEFINE_SIZE_STATIC (10);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400298};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400299
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400300struct Anchor
301{
Behdad Esfahbodabcfe9b2011-05-11 00:02:02 -0400302 inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400303 hb_position_t *x, hb_position_t *y) const
304 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400305 *x = *y = 0;
306 switch (u.format) {
Behdad Esfahbod60fbb362011-05-19 18:46:15 -0400307 case 1: u.format1.get_anchor (font, glyph_id, x, y); return;
308 case 2: u.format2.get_anchor (font, glyph_id, x, y); return;
309 case 3: u.format3.get_anchor (font, glyph_id, x, y); return;
310 default: return;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400311 }
312 }
313
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400314 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400315 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200316 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400317 switch (u.format) {
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200318 case 1: return TRACE_RETURN (u.format1.sanitize (c));
319 case 2: return TRACE_RETURN (u.format2.sanitize (c));
320 case 3: return TRACE_RETURN (u.format3.sanitize (c));
321 default:return TRACE_RETURN (true);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400322 }
323 }
324
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400325 protected:
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400326 union {
327 USHORT format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -0400328 AnchorFormat1 format1;
329 AnchorFormat2 format2;
330 AnchorFormat3 format3;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400331 } u;
Behdad Esfahboded074222010-05-10 18:08:46 -0400332 public:
Behdad Esfahbod596e4712010-05-10 18:47:48 -0400333 DEFINE_SIZE_UNION (2, format);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400334};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400335
336
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400337struct AnchorMatrix
338{
339 inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols) const {
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400340 if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400341 return this+matrix[row * cols + col];
342 }
343
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400344 inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400345 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200346 if (!c->check_struct (this)) return TRACE_RETURN (false);
347 if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return TRACE_RETURN (false);
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400348 unsigned int count = rows * cols;
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200349 if (!c->check_array (matrix, matrix[0].static_size, count)) return TRACE_RETURN (false);
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400350 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200351 if (!matrix[i].sanitize (c, this)) return TRACE_RETURN (false);
352 return TRACE_RETURN (true);
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400353 }
354
355 USHORT rows; /* Number of rows */
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400356 protected:
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400357 OffsetTo<Anchor>
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -0500358 matrix[VAR]; /* Matrix of offsets to Anchor tables--
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400359 * from beginning of AnchorMatrix table */
Behdad Esfahbod569da922010-05-10 16:38:32 -0400360 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400361 DEFINE_SIZE_ARRAY (2, matrix);
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400362};
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400363
364
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400365struct MarkRecord
366{
Behdad Esfahbod377bfc52009-05-21 04:58:24 -0400367 friend struct MarkArray;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400368
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400369 inline bool sanitize (hb_sanitize_context_t *c, void *base) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400370 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200371 return TRACE_RETURN (c->check_struct (this) && markAnchor.sanitize (c, base));
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400372 }
373
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400374 protected:
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400375 USHORT klass; /* Class defined for this mark */
376 OffsetTo<Anchor>
377 markAnchor; /* Offset to Anchor table--from
378 * beginning of MarkArray table */
Behdad Esfahbod569da922010-05-10 16:38:32 -0400379 public:
380 DEFINE_SIZE_STATIC (4);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400381};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400382
Behdad Esfahbodbea34c72010-05-10 17:28:16 -0400383struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage order */
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400384{
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400385 inline bool apply (hb_apply_context_t *c,
Behdad Esfahbodb41f2102009-08-14 19:33:24 -0400386 unsigned int mark_index, unsigned int glyph_index,
387 const AnchorMatrix &anchors, unsigned int class_count,
388 unsigned int glyph_pos) const
389 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400390 TRACE_APPLY ();
Behdad Esfahbodbea34c72010-05-10 17:28:16 -0400391 const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
Behdad Esfahbodb41f2102009-08-14 19:33:24 -0400392 unsigned int mark_class = record.klass;
393
394 const Anchor& mark_anchor = this + record.markAnchor;
395 const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count);
396
397 hb_position_t mark_x, mark_y, base_x, base_y;
398
Behdad Esfahbod99c26952012-05-13 15:45:18 +0200399 mark_anchor.get_anchor (c->font, c->buffer->cur().codepoint, &mark_x, &mark_y);
Behdad Esfahbod60fbb362011-05-19 18:46:15 -0400400 glyph_anchor.get_anchor (c->font, c->buffer->info[glyph_pos].codepoint, &base_x, &base_y);
Behdad Esfahbodb41f2102009-08-14 19:33:24 -0400401
Behdad Esfahbod99c26952012-05-13 15:45:18 +0200402 hb_glyph_position_t &o = c->buffer->cur_pos();
Behdad Esfahbod194d4562010-10-27 23:09:10 -0400403 o.x_offset = base_x - mark_x;
404 o.y_offset = base_y - mark_y;
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400405 o.attach_lookback() = c->buffer->idx - glyph_pos;
Behdad Esfahbodb41f2102009-08-14 19:33:24 -0400406
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400407 c->buffer->idx++;
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200408 return TRACE_RETURN (true);
Behdad Esfahbodb41f2102009-08-14 19:33:24 -0400409 }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400410
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400411 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400412 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200413 return TRACE_RETURN (ArrayOf<MarkRecord>::sanitize (c, this));
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400414 }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400415};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400416
417
418/* Lookups */
419
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400420struct SinglePosFormat1
421{
Behdad Esfahbod0b994292012-07-28 17:31:01 -0400422 inline const Coverage &get_coverage (void) const
423 {
424 return this+coverage;
425 }
426
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 Esfahbod99c26952012-05-13 15:45:18 +0200430 unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200431 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400432
Behdad Esfahbod3b0bb852011-05-20 15:59:59 -0400433 valueFormat.apply_value (c->font, c->direction, this,
Behdad Esfahbod99c26952012-05-13 15:45:18 +0200434 values, c->buffer->cur_pos());
Behdad Esfahbodf53d4342009-05-30 22:17:32 -0400435
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400436 c->buffer->idx++;
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200437 return TRACE_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 Esfahbod0ab8c862012-05-11 01:25:34 +0200442 return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_value (c, this, values));
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400443 }
444
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400445 protected:
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400446 USHORT format; /* Format identifier--format = 1 */
447 OffsetTo<Coverage>
448 coverage; /* Offset to Coverage table--from
449 * beginning of subtable */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400450 ValueFormat valueFormat; /* Defines the types of data in the
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400451 * ValueRecord */
452 ValueRecord values; /* Defines positioning
453 * value(s)--applied to all glyphs in
454 * the Coverage table */
Behdad Esfahbod569da922010-05-10 16:38:32 -0400455 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400456 DEFINE_SIZE_ARRAY (6, values);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400457};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400458
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400459struct SinglePosFormat2
460{
Behdad Esfahbod0b994292012-07-28 17:31:01 -0400461 inline const Coverage &get_coverage (void) const
462 {
463 return this+coverage;
464 }
465
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 Esfahbod99c26952012-05-13 15:45:18 +0200469 unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200470 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400471
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200472 if (likely (index >= valueCount)) return TRACE_RETURN (false);
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400473
Behdad Esfahbod3b0bb852011-05-20 15:59:59 -0400474 valueFormat.apply_value (c->font, c->direction, this,
Behdad Esfahbod4b8487d2010-03-16 03:46:17 -0400475 &values[index * valueFormat.get_len ()],
Behdad Esfahbod99c26952012-05-13 15:45:18 +0200476 c->buffer->cur_pos());
Behdad Esfahbodf53d4342009-05-30 22:17:32 -0400477
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400478 c->buffer->idx++;
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200479 return TRACE_RETURN (true);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400480 }
481
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400482 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400483 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200484 return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_values (c, this, values, valueCount));
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400485 }
486
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400487 protected:
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400488 USHORT format; /* Format identifier--format = 2 */
489 OffsetTo<Coverage>
490 coverage; /* Offset to Coverage table--from
491 * beginning of subtable */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400492 ValueFormat valueFormat; /* Defines the types of data in the
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400493 * ValueRecord */
494 USHORT valueCount; /* Number of ValueRecords */
495 ValueRecord values; /* Array of ValueRecords--positioning
496 * values applied to glyphs */
Behdad Esfahbod569da922010-05-10 16:38:32 -0400497 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400498 DEFINE_SIZE_ARRAY (8, values);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400499};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400500
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400501struct SinglePos
502{
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500503 template <typename context_t>
504 inline typename context_t::return_t process (context_t *c) const
Behdad Esfahbod0b994292012-07-28 17:31:01 -0400505 {
506 switch (u.format) {
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500507 case 1: return c->process (u.format1);
508 case 2: return c->process (u.format2);
509 default:return c->default_return_value ();
Behdad Esfahbod0b994292012-07-28 17:31:01 -0400510 }
511 }
512
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400513 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400514 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400515 TRACE_APPLY ();
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400516 switch (u.format) {
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200517 case 1: return TRACE_RETURN (u.format1.apply (c));
518 case 2: return TRACE_RETURN (u.format2.apply (c));
519 default:return TRACE_RETURN (false);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400520 }
521 }
522
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400523 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400524 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200525 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400526 switch (u.format) {
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200527 case 1: return TRACE_RETURN (u.format1.sanitize (c));
528 case 2: return TRACE_RETURN (u.format2.sanitize (c));
529 default:return TRACE_RETURN (true);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400530 }
531 }
532
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400533 protected:
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400534 union {
535 USHORT format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -0400536 SinglePosFormat1 format1;
537 SinglePosFormat2 format2;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400538 } u;
539};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400540
541
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400542struct PairValueRecord
543{
Behdad Esfahbod70c9bfd2010-05-11 00:23:50 -0400544 friend struct PairSet;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400545
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400546 protected:
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400547 GlyphID secondGlyph; /* GlyphID of second glyph in the
548 * pair--first glyph is listed in the
549 * Coverage table */
550 ValueRecord values; /* Positioning data for the first glyph
551 * followed by for second glyph */
Behdad Esfahbod569da922010-05-10 16:38:32 -0400552 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400553 DEFINE_SIZE_ARRAY (2, values);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400554};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400555
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400556struct PairSet
557{
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400558 friend struct PairPosFormat1;
559
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400560 inline bool apply (hb_apply_context_t *c,
Behdad Esfahbod70c9bfd2010-05-11 00:23:50 -0400561 const ValueFormat *valueFormats,
562 unsigned int pos) const
563 {
564 TRACE_APPLY ();
565 unsigned int len1 = valueFormats[0].get_len ();
566 unsigned int len2 = valueFormats[1].get_len ();
567 unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
568
569 unsigned int count = len;
570 const PairValueRecord *record = CastP<PairValueRecord> (array);
571 for (unsigned int i = 0; i < count; i++)
572 {
Behdad Esfahbod7e7007a2010-05-14 22:02:37 -0400573 if (c->buffer->info[pos].codepoint == record->secondGlyph)
Behdad Esfahbod70c9bfd2010-05-11 00:23:50 -0400574 {
Behdad Esfahbod3b0bb852011-05-20 15:59:59 -0400575 valueFormats[0].apply_value (c->font, c->direction, this,
Behdad Esfahbod99c26952012-05-13 15:45:18 +0200576 &record->values[0], c->buffer->cur_pos());
Behdad Esfahbod3b0bb852011-05-20 15:59:59 -0400577 valueFormats[1].apply_value (c->font, c->direction, this,
578 &record->values[len1], c->buffer->pos[pos]);
Behdad Esfahbod70c9bfd2010-05-11 00:23:50 -0400579 if (len2)
580 pos++;
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400581 c->buffer->idx = pos;
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200582 return TRACE_RETURN (true);
Behdad Esfahbod70c9bfd2010-05-11 00:23:50 -0400583 }
584 record = &StructAtOffset<PairValueRecord> (record, record_size);
585 }
586
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200587 return TRACE_RETURN (false);
Behdad Esfahbod70c9bfd2010-05-11 00:23:50 -0400588 }
589
590 struct sanitize_closure_t {
591 void *base;
592 ValueFormat *valueFormats;
593 unsigned int len1; /* valueFormats[0].get_len() */
594 unsigned int stride; /* 1 + len1 + len2 */
595 };
596
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400597 inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400598 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400599 if (!(c->check_struct (this)
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200600 && c->check_array (array, USHORT::static_size * closure->stride, len))) return TRACE_RETURN (false);
Behdad Esfahbod70c9bfd2010-05-11 00:23:50 -0400601
602 unsigned int count = len;
603 PairValueRecord *record = CastP<PairValueRecord> (array);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200604 return TRACE_RETURN (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride)
605 && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400606 }
607
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400608 protected:
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400609 USHORT len; /* Number of PairValueRecords */
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400610 USHORT array[VAR]; /* Array of PairValueRecords--ordered
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400611 * by GlyphID of the second glyph */
Behdad Esfahbod569da922010-05-10 16:38:32 -0400612 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400613 DEFINE_SIZE_ARRAY (2, array);
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400614};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400615
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400616struct PairPosFormat1
617{
Behdad Esfahbod0b994292012-07-28 17:31:01 -0400618 inline const Coverage &get_coverage (void) const
619 {
620 return this+coverage;
621 }
622
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400623 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400624 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400625 TRACE_APPLY ();
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500626 hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200627 if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400628
Behdad Esfahbod99c26952012-05-13 15:45:18 +0200629 unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200630 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400631
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200632 if (!skippy_iter.next ()) return TRACE_RETURN (false);
Behdad Esfahbodb24ecba2009-05-19 22:16:04 -0400633
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200634 return TRACE_RETURN ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx));
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400635 }
636
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400637 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400638 TRACE_SANITIZE ();
Behdad Esfahbodeba8b4f2010-03-29 00:04:12 -0400639
640 unsigned int len1 = valueFormat1.get_len ();
641 unsigned int len2 = valueFormat2.get_len ();
Behdad Esfahbod70c9bfd2010-05-11 00:23:50 -0400642 PairSet::sanitize_closure_t closure = {
643 this,
644 &valueFormat1,
645 len1,
646 1 + len1 + len2
647 };
Behdad Esfahbodeba8b4f2010-03-29 00:04:12 -0400648
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200649 return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400650 }
651
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400652 protected:
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400653 USHORT format; /* Format identifier--format = 1 */
654 OffsetTo<Coverage>
655 coverage; /* Offset to Coverage table--from
656 * beginning of subtable */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400657 ValueFormat valueFormat1; /* Defines the types of data in
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400658 * ValueRecord1--for the first glyph
659 * in the pair--may be zero (0) */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400660 ValueFormat valueFormat2; /* Defines the types of data in
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400661 * ValueRecord2--for the second glyph
662 * in the pair--may be zero (0) */
663 OffsetArrayOf<PairSet>
664 pairSet; /* Array of PairSet tables
665 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400666 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400667 DEFINE_SIZE_ARRAY (10, pairSet);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400668};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400669
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400670struct PairPosFormat2
671{
Behdad Esfahbod0b994292012-07-28 17:31:01 -0400672 inline const Coverage &get_coverage (void) const
673 {
674 return this+coverage;
675 }
676
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400677 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400678 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400679 TRACE_APPLY ();
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500680 hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200681 if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400682
Behdad Esfahbod99c26952012-05-13 15:45:18 +0200683 unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200684 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400685
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200686 if (!skippy_iter.next ()) return TRACE_RETURN (false);
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400687
688 unsigned int len1 = valueFormat1.get_len ();
689 unsigned int len2 = valueFormat2.get_len ();
690 unsigned int record_len = len1 + len2;
691
Behdad Esfahbod99c26952012-05-13 15:45:18 +0200692 unsigned int klass1 = (this+classDef1) (c->buffer->cur().codepoint);
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500693 unsigned int klass2 = (this+classDef2) (c->buffer->info[skippy_iter.idx].codepoint);
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200694 if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return TRACE_RETURN (false);
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400695
Behdad Esfahbod4b8487d2010-03-16 03:46:17 -0400696 const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
Behdad Esfahbod3b0bb852011-05-20 15:59:59 -0400697 valueFormat1.apply_value (c->font, c->direction, this,
Behdad Esfahbod99c26952012-05-13 15:45:18 +0200698 v, c->buffer->cur_pos());
Behdad Esfahbod3b0bb852011-05-20 15:59:59 -0400699 valueFormat2.apply_value (c->font, c->direction, this,
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500700 v + len1, c->buffer->pos[skippy_iter.idx]);
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400701
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500702 c->buffer->idx = skippy_iter.idx;
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400703 if (len2)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500704 c->buffer->idx++;
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400705
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200706 return TRACE_RETURN (true);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400707 }
708
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400709 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400710 TRACE_SANITIZE ();
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400711 if (!(c->check_struct (this)
712 && coverage.sanitize (c, this)
713 && classDef1.sanitize (c, this)
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200714 && classDef2.sanitize (c, this))) return TRACE_RETURN (false);
Behdad Esfahbod815a73e2009-08-14 17:31:16 -0400715
Behdad Esfahbodeba8b4f2010-03-29 00:04:12 -0400716 unsigned int len1 = valueFormat1.get_len ();
717 unsigned int len2 = valueFormat2.get_len ();
718 unsigned int stride = len1 + len2;
Behdad Esfahbod4b8487d2010-03-16 03:46:17 -0400719 unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
Behdad Esfahbodeba8b4f2010-03-29 00:04:12 -0400720 unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200721 return TRACE_RETURN (c->check_array (values, record_size, count) &&
722 valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
723 valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400724 }
Behdad Esfahbod70632ad2009-05-19 22:30:09 -0400725
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400726 protected:
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400727 USHORT format; /* Format identifier--format = 2 */
728 OffsetTo<Coverage>
729 coverage; /* Offset to Coverage table--from
730 * beginning of subtable */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400731 ValueFormat valueFormat1; /* ValueRecord definition--for the
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400732 * first glyph of the pair--may be zero
733 * (0) */
Behdad Esfahbod056c7ec2009-05-18 19:47:52 -0400734 ValueFormat valueFormat2; /* ValueRecord definition--for the
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400735 * second glyph of the pair--may be
736 * zero (0) */
737 OffsetTo<ClassDef>
738 classDef1; /* Offset to ClassDef table--from
739 * beginning of PairPos subtable--for
740 * the first glyph of the pair */
741 OffsetTo<ClassDef>
742 classDef2; /* Offset to ClassDef table--from
743 * beginning of PairPos subtable--for
744 * the second glyph of the pair */
745 USHORT class1Count; /* Number of classes in ClassDef1
746 * table--includes Class0 */
747 USHORT class2Count; /* Number of classes in ClassDef2
748 * table--includes Class0 */
749 ValueRecord values; /* Matrix of value pairs:
750 * class1-major, class2-minor,
751 * Each entry has value1 and value2 */
Behdad Esfahbod569da922010-05-10 16:38:32 -0400752 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400753 DEFINE_SIZE_ARRAY (16, values);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400754};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400755
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400756struct PairPos
757{
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500758 template <typename context_t>
759 inline typename context_t::return_t process (context_t *c) const
Behdad Esfahbod0b994292012-07-28 17:31:01 -0400760 {
761 switch (u.format) {
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500762 case 1: return c->process (u.format1);
763 case 2: return c->process (u.format2);
764 default:return c->default_return_value ();
Behdad Esfahbod0b994292012-07-28 17:31:01 -0400765 }
766 }
767
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400768 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400769 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400770 TRACE_APPLY ();
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400771 switch (u.format) {
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200772 case 1: return TRACE_RETURN (u.format1.apply (c));
773 case 2: return TRACE_RETURN (u.format2.apply (c));
774 default:return TRACE_RETURN (false);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400775 }
776 }
777
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400778 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400779 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200780 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400781 switch (u.format) {
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200782 case 1: return TRACE_RETURN (u.format1.sanitize (c));
783 case 2: return TRACE_RETURN (u.format2.sanitize (c));
784 default:return TRACE_RETURN (true);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400785 }
786 }
787
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400788 protected:
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400789 union {
790 USHORT format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -0400791 PairPosFormat1 format1;
792 PairPosFormat2 format2;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400793 } u;
794};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400795
796
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400797struct EntryExitRecord
798{
Behdad Esfahbod569da922010-05-10 16:38:32 -0400799 friend struct CursivePosFormat1;
800
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400801 inline bool sanitize (hb_sanitize_context_t *c, void *base) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400802 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200803 return TRACE_RETURN (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400804 }
805
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400806 protected:
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400807 OffsetTo<Anchor>
808 entryAnchor; /* Offset to EntryAnchor table--from
809 * beginning of CursivePos
810 * subtable--may be NULL */
811 OffsetTo<Anchor>
812 exitAnchor; /* Offset to ExitAnchor table--from
813 * beginning of CursivePos
814 * subtable--may be NULL */
Behdad Esfahbod569da922010-05-10 16:38:32 -0400815 public:
816 DEFINE_SIZE_STATIC (4);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400817};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400818
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400819struct CursivePosFormat1
820{
Behdad Esfahbod0b994292012-07-28 17:31:01 -0400821 inline const Coverage &get_coverage (void) const
822 {
823 return this+coverage;
824 }
825
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 Esfahbod0f7e6b22009-05-20 04:16:35 -0400829
830 /* We don't handle mark glyphs here. */
Behdad Esfahbod5a08ecf2012-11-16 13:34:29 -0800831 if (c->property & HB_OT_LAYOUT_GLYPH_PROPS_MARK) return TRACE_RETURN (false);
Behdad Esfahbod0f7e6b22009-05-20 04:16:35 -0400832
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500833 hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200834 if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
Behdad Esfahbod0f7e6b22009-05-20 04:16:35 -0400835
Behdad Esfahbod99c26952012-05-13 15:45:18 +0200836 const EntryExitRecord &this_record = entryExitRecord[(this+coverage) (c->buffer->cur().codepoint)];
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200837 if (!this_record.exitAnchor) return TRACE_RETURN (false);
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400838
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200839 if (!skippy_iter.next ()) return TRACE_RETURN (false);
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400840
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500841 const EntryExitRecord &next_record = entryExitRecord[(this+coverage) (c->buffer->info[skippy_iter.idx].codepoint)];
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200842 if (!next_record.entryAnchor) return TRACE_RETURN (false);
Behdad Esfahbodaf5d02a2010-10-27 11:54:26 -0400843
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400844 unsigned int i = c->buffer->idx;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500845 unsigned int j = skippy_iter.idx;
Behdad Esfahbodaf5d02a2010-10-27 11:54:26 -0400846
847 hb_position_t entry_x, entry_y, exit_x, exit_y;
Behdad Esfahbod60fbb362011-05-19 18:46:15 -0400848 (this+this_record.exitAnchor).get_anchor (c->font, c->buffer->info[i].codepoint, &exit_x, &exit_y);
849 (this+next_record.entryAnchor).get_anchor (c->font, c->buffer->info[j].codepoint, &entry_x, &entry_y);
Behdad Esfahbodcc83ae12009-05-27 00:17:37 -0400850
Behdad Esfahbod7403e052011-05-24 21:04:15 -0400851 hb_glyph_position_t *pos = c->buffer->pos;
852
853 hb_position_t d;
854 /* Main-direction adjustment */
855 switch (c->direction) {
856 case HB_DIRECTION_LTR:
857 pos[i].x_advance = exit_x + pos[i].x_offset;
858
859 d = entry_x + pos[j].x_offset;
860 pos[j].x_advance -= d;
861 pos[j].x_offset -= d;
862 break;
863 case HB_DIRECTION_RTL:
864 d = exit_x + pos[i].x_offset;
865 pos[i].x_advance -= d;
866 pos[i].x_offset -= d;
867
868 pos[j].x_advance = entry_x + pos[j].x_offset;
869 break;
870 case HB_DIRECTION_TTB:
871 pos[i].y_advance = exit_y + pos[i].y_offset;
872
873 d = entry_y + pos[j].y_offset;
874 pos[j].y_advance -= d;
875 pos[j].y_offset -= d;
876 break;
877 case HB_DIRECTION_BTT:
878 d = exit_y + pos[i].y_offset;
879 pos[i].y_advance -= d;
880 pos[i].y_offset -= d;
881
882 pos[j].y_advance = entry_y;
883 break;
884 case HB_DIRECTION_INVALID:
885 default:
886 break;
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400887 }
888
Behdad Esfahbod7403e052011-05-24 21:04:15 -0400889 /* Cross-direction adjustment */
890 if (c->lookup_props & LookupFlag::RightToLeft) {
891 pos[i].cursive_chain() = j - i;
Behdad Esfahbod744970a2011-05-16 18:15:37 -0400892 if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
Behdad Esfahbod7403e052011-05-24 21:04:15 -0400893 pos[i].y_offset = entry_y - exit_y;
Behdad Esfahbod13528d02010-10-27 14:09:27 -0400894 else
Behdad Esfahbod7403e052011-05-24 21:04:15 -0400895 pos[i].x_offset = entry_x - exit_x;
896 } else {
897 pos[j].cursive_chain() = i - j;
Behdad Esfahbod744970a2011-05-16 18:15:37 -0400898 if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
Behdad Esfahbod7403e052011-05-24 21:04:15 -0400899 pos[j].y_offset = exit_y - entry_y;
Behdad Esfahbod13528d02010-10-27 14:09:27 -0400900 else
Behdad Esfahbod7403e052011-05-24 21:04:15 -0400901 pos[j].x_offset = exit_x - entry_x;
Behdad Esfahbodd18fd8e2009-05-19 23:25:41 -0400902 }
903
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400904 c->buffer->idx = j;
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200905 return TRACE_RETURN (true);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400906 }
907
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400908 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400909 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200910 return TRACE_RETURN (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400911 }
912
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400913 protected:
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400914 USHORT format; /* Format identifier--format = 1 */
915 OffsetTo<Coverage>
916 coverage; /* Offset to Coverage table--from
917 * beginning of subtable */
918 ArrayOf<EntryExitRecord>
919 entryExitRecord; /* Array of EntryExit records--in
920 * Coverage Index order */
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400921 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400922 DEFINE_SIZE_ARRAY (6, entryExitRecord);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400923};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400924
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400925struct CursivePos
926{
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500927 template <typename context_t>
928 inline typename context_t::return_t process (context_t *c) const
Behdad Esfahbod0b994292012-07-28 17:31:01 -0400929 {
930 switch (u.format) {
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500931 case 1: return c->process (u.format1);
932 default:return c->default_return_value ();
Behdad Esfahbod0b994292012-07-28 17:31:01 -0400933 }
934 }
935
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400936 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400937 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400938 TRACE_APPLY ();
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400939 switch (u.format) {
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200940 case 1: return TRACE_RETURN (u.format1.apply (c));
941 default:return TRACE_RETURN (false);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400942 }
943 }
944
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400945 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400946 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200947 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400948 switch (u.format) {
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200949 case 1: return TRACE_RETURN (u.format1.sanitize (c));
950 default:return TRACE_RETURN (true);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400951 }
952 }
953
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400954 protected:
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400955 union {
956 USHORT format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -0400957 CursivePosFormat1 format1;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400958 } u;
959};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400960
961
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -0400962typedef AnchorMatrix BaseArray; /* base-major--
963 * in order of BaseCoverage Index--,
964 * mark-minor--
Behdad Esfahbodfb3b5cc2009-05-21 04:47:05 -0400965 * ordered by class--zero-based. */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400966
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400967struct MarkBasePosFormat1
968{
Behdad Esfahbod0b994292012-07-28 17:31:01 -0400969 inline const Coverage &get_coverage (void) const
970 {
971 return this+markCoverage;
972 }
973
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400974 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400975 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400976 TRACE_APPLY ();
Behdad Esfahbod99c26952012-05-13 15:45:18 +0200977 unsigned int mark_index = (this+markCoverage) (c->buffer->cur().codepoint);
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200978 if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
Behdad Esfahbod357ccde2009-05-21 06:32:01 -0400979
980 /* now we search backwards for a non-mark glyph */
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400981 unsigned int property;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500982 hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
Behdad Esfahbod7b84c532012-06-08 22:04:23 -0400983 do {
984 if (!skippy_iter.prev (&property, LookupFlag::IgnoreMarks)) return TRACE_RETURN (false);
985 /* We only want to attach to the first of a MultipleSubst sequence. Reject others. */
986 if (0 == get_lig_comp (c->buffer->info[skippy_iter.idx])) break;
987 skippy_iter.reject ();
988 } while (1);
Behdad Esfahbod0532ed12009-08-12 15:40:04 -0400989
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400990 /* The following assertion is too strong, so we've disabled it. */
Behdad Esfahbod5a08ecf2012-11-16 13:34:29 -0800991 if (!(property & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH)) {/*return TRACE_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 Esfahbodacea1832012-05-11 02:33:11 +0200994 if (base_index == NOT_COVERED) return TRACE_RETURN (false);
Behdad Esfahbod357ccde2009-05-21 06:32:01 -0400995
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200996 return TRACE_RETURN ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -0400997 }
998
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400999 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001000 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001001 return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && baseCoverage.sanitize (c, this) &&
1002 markArray.sanitize (c, this) && baseArray.sanitize (c, this, (unsigned int) classCount));
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001003 }
1004
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001005 protected:
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001006 USHORT format; /* Format identifier--format = 1 */
Behdad Esfahbodfb3b5cc2009-05-21 04:47:05 -04001007 OffsetTo<Coverage>
1008 markCoverage; /* Offset to MarkCoverage table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001009 * beginning of MarkBasePos subtable */
Behdad Esfahbodfb3b5cc2009-05-21 04:47:05 -04001010 OffsetTo<Coverage>
1011 baseCoverage; /* Offset to BaseCoverage table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001012 * beginning of MarkBasePos subtable */
1013 USHORT classCount; /* Number of classes defined for marks */
Behdad Esfahbodfb3b5cc2009-05-21 04:47:05 -04001014 OffsetTo<MarkArray>
1015 markArray; /* Offset to MarkArray table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001016 * beginning of MarkBasePos subtable */
Behdad Esfahbodfb3b5cc2009-05-21 04:47:05 -04001017 OffsetTo<BaseArray>
1018 baseArray; /* Offset to BaseArray table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001019 * beginning of MarkBasePos subtable */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001020 public:
1021 DEFINE_SIZE_STATIC (12);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001022};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001023
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001024struct MarkBasePos
1025{
Behdad Esfahbod2005fa52012-11-22 14:38:10 -05001026 template <typename context_t>
1027 inline typename context_t::return_t process (context_t *c) const
Behdad Esfahbod0b994292012-07-28 17:31:01 -04001028 {
1029 switch (u.format) {
Behdad Esfahbod2005fa52012-11-22 14:38:10 -05001030 case 1: return c->process (u.format1);
1031 default:return c->default_return_value ();
Behdad Esfahbod0b994292012-07-28 17:31:01 -04001032 }
1033 }
1034
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001035 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001036 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001037 TRACE_APPLY ();
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001038 switch (u.format) {
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001039 case 1: return TRACE_RETURN (u.format1.apply (c));
1040 default:return TRACE_RETURN (false);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001041 }
1042 }
1043
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001044 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001045 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001046 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001047 switch (u.format) {
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001048 case 1: return TRACE_RETURN (u.format1.sanitize (c));
1049 default:return TRACE_RETURN (true);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001050 }
1051 }
1052
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001053 protected:
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001054 union {
1055 USHORT format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04001056 MarkBasePosFormat1 format1;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001057 } u;
1058};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001059
1060
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -04001061typedef AnchorMatrix LigatureAttach; /* component-major--
1062 * in order of writing direction--,
1063 * mark-minor--
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001064 * ordered by class--zero-based. */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001065
Behdad Esfahbod3564ee52009-08-14 18:32:56 -04001066typedef OffsetListOf<LigatureAttach> LigatureArray;
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001067 /* Array of LigatureAttach
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001068 * tables ordered by
1069 * LigatureCoverage Index */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001070
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001071struct MarkLigPosFormat1
1072{
Behdad Esfahbod0b994292012-07-28 17:31:01 -04001073 inline const Coverage &get_coverage (void) const
1074 {
1075 return this+markCoverage;
1076 }
1077
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001078 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001079 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001080 TRACE_APPLY ();
Behdad Esfahbod99c26952012-05-13 15:45:18 +02001081 unsigned int mark_index = (this+markCoverage) (c->buffer->cur().codepoint);
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001082 if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001083
1084 /* now we search backwards for a non-mark glyph */
Behdad Esfahbod1376fb72010-04-29 02:19:21 -04001085 unsigned int property;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -05001086 hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001087 if (!skippy_iter.prev (&property, LookupFlag::IgnoreMarks)) return TRACE_RETURN (false);
Behdad Esfahbod0532ed12009-08-12 15:40:04 -04001088
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001089 /* The following assertion is too strong, so we've disabled it. */
Behdad Esfahbod5a08ecf2012-11-16 13:34:29 -08001090 if (!(property & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE)) {/*return TRACE_RETURN (false);*/}
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001091
Behdad Esfahbod4ab97312012-01-16 22:05:08 -05001092 unsigned int j = skippy_iter.idx;
Behdad Esfahbod7e7007a2010-05-14 22:02:37 -04001093 unsigned int lig_index = (this+ligatureCoverage) (c->buffer->info[j].codepoint);
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001094 if (lig_index == NOT_COVERED) return TRACE_RETURN (false);
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001095
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 Esfahbodacea1832012-05-11 02:33:11 +02001101 if (unlikely (!comp_count)) return TRACE_RETURN (false);
1102
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001103 /* We must now check whether the ligature ID of the current mark glyph
1104 * is identical to the ligature ID of the found ligature. If yes, we
1105 * can directly use the component index. If not, we attach the mark
1106 * glyph to the last component of the ligature. */
Behdad Esfahbod0aef4252012-07-30 00:55:15 -04001107 unsigned int comp_index;
1108 unsigned int lig_id = get_lig_id (c->buffer->info[j]);
1109 unsigned int mark_id = get_lig_id (c->buffer->cur());
1110 unsigned int mark_comp = get_lig_comp (c->buffer->cur());
1111 if (lig_id && lig_id == mark_id && mark_comp > 0)
1112 comp_index = MIN (comp_count, get_lig_comp (c->buffer->cur())) - 1;
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001113 else
Behdad Esfahbodb2b18ef2009-08-14 19:37:18 -04001114 comp_index = comp_count - 1;
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001115
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001116 return TRACE_RETURN ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001117 }
1118
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001119 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001120 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001121 return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && ligatureCoverage.sanitize (c, this) &&
1122 markArray.sanitize (c, this) && ligatureArray.sanitize (c, this, (unsigned int) classCount));
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001123 }
1124
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001125 protected:
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001126 USHORT format; /* Format identifier--format = 1 */
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001127 OffsetTo<Coverage>
1128 markCoverage; /* Offset to Mark Coverage table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001129 * beginning of MarkLigPos subtable */
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001130 OffsetTo<Coverage>
1131 ligatureCoverage; /* Offset to Ligature Coverage
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001132 * table--from beginning of MarkLigPos
1133 * subtable */
1134 USHORT classCount; /* Number of defined mark classes */
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001135 OffsetTo<MarkArray>
1136 markArray; /* Offset to MarkArray table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001137 * beginning of MarkLigPos subtable */
Behdad Esfahbod9b006bc2009-05-22 18:29:45 -04001138 OffsetTo<LigatureArray>
1139 ligatureArray; /* Offset to LigatureArray table--from
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001140 * beginning of MarkLigPos subtable */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001141 public:
1142 DEFINE_SIZE_STATIC (12);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001143};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001144
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001145struct MarkLigPos
1146{
Behdad Esfahbod2005fa52012-11-22 14:38:10 -05001147 template <typename context_t>
1148 inline typename context_t::return_t process (context_t *c) const
Behdad Esfahbod0b994292012-07-28 17:31:01 -04001149 {
1150 switch (u.format) {
Behdad Esfahbod2005fa52012-11-22 14:38:10 -05001151 case 1: return c->process (u.format1);
1152 default:return c->default_return_value ();
Behdad Esfahbod0b994292012-07-28 17:31:01 -04001153 }
1154 }
1155
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001156 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001157 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001158 TRACE_APPLY ();
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001159 switch (u.format) {
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001160 case 1: return TRACE_RETURN (u.format1.apply (c));
1161 default:return TRACE_RETURN (false);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001162 }
1163 }
1164
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001165 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001166 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001167 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001168 switch (u.format) {
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001169 case 1: return TRACE_RETURN (u.format1.sanitize (c));
1170 default:return TRACE_RETURN (true);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001171 }
1172 }
1173
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001174 protected:
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001175 union {
1176 USHORT format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04001177 MarkLigPosFormat1 format1;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001178 } u;
1179};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001180
1181
Behdad Esfahbodcb71a2f2009-08-14 18:14:03 -04001182typedef AnchorMatrix Mark2Array; /* mark2-major--
1183 * in order of Mark2Coverage Index--,
1184 * mark1-minor--
1185 * ordered by class--zero-based. */
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001186
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001187struct MarkMarkPosFormat1
1188{
Behdad Esfahbod0b994292012-07-28 17:31:01 -04001189 inline const Coverage &get_coverage (void) const
1190 {
1191 return this+mark1Coverage;
1192 }
1193
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001194 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001195 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001196 TRACE_APPLY ();
Behdad Esfahbod99c26952012-05-13 15:45:18 +02001197 unsigned int mark1_index = (this+mark1Coverage) (c->buffer->cur().codepoint);
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001198 if (likely (mark1_index == NOT_COVERED)) return TRACE_RETURN (false);
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001199
1200 /* now we search backwards for a suitable mark glyph until a non-mark glyph */
Behdad Esfahbod1376fb72010-04-29 02:19:21 -04001201 unsigned int property;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -05001202 hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001203 if (!skippy_iter.prev (&property)) return TRACE_RETURN (false);
Behdad Esfahbod0532ed12009-08-12 15:40:04 -04001204
Behdad Esfahbod5a08ecf2012-11-16 13:34:29 -08001205 if (!(property & HB_OT_LAYOUT_GLYPH_PROPS_MARK)) return TRACE_RETURN (false);
Behdad Esfahbod80ea5bd2009-05-26 17:58:37 -04001206
Behdad Esfahbod4ab97312012-01-16 22:05:08 -05001207 unsigned int j = skippy_iter.idx;
1208
Behdad Esfahbod5d874d52012-07-28 21:05:25 -04001209 unsigned int id1 = get_lig_id (c->buffer->cur());
1210 unsigned int id2 = get_lig_id (c->buffer->info[j]);
1211 unsigned int comp1 = get_lig_comp (c->buffer->cur());
1212 unsigned int comp2 = get_lig_comp (c->buffer->info[j]);
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001213
Behdad Esfahbod5d874d52012-07-28 21:05:25 -04001214 if (likely (id1 == id2)) {
1215 if (id1 == 0) /* Marks belonging to the same base. */
1216 goto good;
1217 else if (comp1 == comp2) /* Marks belonging to the same ligature component. */
1218 goto good;
1219 } else {
1220 /* If ligature ids don't match, it may be the case that one of the marks
1221 * itself is a ligature. In which case match. */
1222 if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2))
1223 goto good;
1224 }
1225
1226 /* Didn't match. */
1227 return TRACE_RETURN (false);
1228
1229 good:
Behdad Esfahbod7e7007a2010-05-14 22:02:37 -04001230 unsigned int mark2_index = (this+mark2Coverage) (c->buffer->info[j].codepoint);
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001231 if (mark2_index == NOT_COVERED) return TRACE_RETURN (false);
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001232
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001233 return TRACE_RETURN ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001234 }
1235
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001236 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001237 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001238 return TRACE_RETURN (c->check_struct (this) && mark1Coverage.sanitize (c, this) &&
1239 mark2Coverage.sanitize (c, this) && mark1Array.sanitize (c, this)
1240 && mark2Array.sanitize (c, this, (unsigned int) classCount));
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001241 }
1242
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001243 protected:
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001244 USHORT format; /* Format identifier--format = 1 */
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001245 OffsetTo<Coverage>
1246 mark1Coverage; /* Offset to Combining Mark1 Coverage
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001247 * table--from beginning of MarkMarkPos
1248 * subtable */
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001249 OffsetTo<Coverage>
1250 mark2Coverage; /* Offset to Combining Mark2 Coverage
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001251 * table--from beginning of MarkMarkPos
1252 * subtable */
Behdad Esfahbodfe550f42009-05-21 08:27:07 -04001253 USHORT classCount; /* Number of defined mark classes */
1254 OffsetTo<MarkArray>
1255 mark1Array; /* Offset to Mark1Array table--from
1256 * beginning of MarkMarkPos subtable */
1257 OffsetTo<Mark2Array>
1258 mark2Array; /* Offset to Mark2Array table--from
1259 * beginning of MarkMarkPos subtable */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001260 public:
1261 DEFINE_SIZE_STATIC (12);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001262};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001263
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001264struct MarkMarkPos
1265{
Behdad Esfahbod2005fa52012-11-22 14:38:10 -05001266 template <typename context_t>
1267 inline typename context_t::return_t process (context_t *c) const
Behdad Esfahbod0b994292012-07-28 17:31:01 -04001268 {
1269 switch (u.format) {
Behdad Esfahbod2005fa52012-11-22 14:38:10 -05001270 case 1: return c->process (u.format1);
1271 default:return c->default_return_value ();
Behdad Esfahbod0b994292012-07-28 17:31:01 -04001272 }
1273 }
1274
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001275 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001276 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001277 TRACE_APPLY ();
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001278 switch (u.format) {
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001279 case 1: return TRACE_RETURN (u.format1.apply (c));
1280 default:return TRACE_RETURN (false);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001281 }
1282 }
1283
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001284 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001285 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001286 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001287 switch (u.format) {
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001288 case 1: return TRACE_RETURN (u.format1.sanitize (c));
1289 default:return TRACE_RETURN (true);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001290 }
1291 }
1292
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001293 protected:
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001294 union {
1295 USHORT format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04001296 MarkMarkPosFormat1 format1;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001297 } u;
1298};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001299
1300
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001301static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001302
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001303struct ContextPos : Context
1304{
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001305 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod0535b502009-08-28 17:14:33 -04001306 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001307 TRACE_APPLY ();
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001308 return TRACE_RETURN (Context::apply (c, position_lookup));
Behdad Esfahbod0535b502009-08-28 17:14:33 -04001309 }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001310};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001311
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001312struct ChainContextPos : ChainContext
1313{
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001314 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod0535b502009-08-28 17:14:33 -04001315 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001316 TRACE_APPLY ();
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001317 return TRACE_RETURN (ChainContext::apply (c, position_lookup));
Behdad Esfahbod0535b502009-08-28 17:14:33 -04001318 }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001319};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001320
1321
Behdad Esfahbod6d08c7f2012-07-11 18:01:27 -04001322struct ExtensionPos : Extension
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001323{
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001324 inline const struct PosLookupSubTable& get_subtable (void) const
Behdad Esfahbod3b2c2df2010-04-22 16:51:42 -04001325 {
1326 unsigned int offset = get_offset ();
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001327 if (unlikely (!offset)) return Null(PosLookupSubTable);
Behdad Esfahbod09766b12010-05-10 17:36:03 -04001328 return StructAtOffset<PosLookupSubTable> (this, offset);
Behdad Esfahbod3b2c2df2010-04-22 16:51:42 -04001329 }
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001330
Behdad Esfahbod2005fa52012-11-22 14:38:10 -05001331 template <typename context_t>
1332 inline typename context_t::return_t process (context_t *c) const;
Behdad Esfahbod0b994292012-07-28 17:31:01 -04001333
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001334 inline bool apply (hb_apply_context_t *c) const;
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001335
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001336 inline bool sanitize (hb_sanitize_context_t *c);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001337};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001338
1339
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04001340
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001341/*
1342 * PosLookup
1343 */
1344
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001345
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001346struct PosLookupSubTable
1347{
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001348 friend struct PosLookup;
1349
Behdad Esfahbodc6035cf2012-04-12 13:23:59 -04001350 enum Type {
Behdad Esfahbodff05d252009-05-20 03:53:00 -04001351 Single = 1,
1352 Pair = 2,
1353 Cursive = 3,
1354 MarkBase = 4,
1355 MarkLig = 5,
1356 MarkMark = 6,
1357 Context = 7,
1358 ChainContext = 8,
Behdad Esfahbod8f034d52009-08-18 16:41:59 -04001359 Extension = 9
Behdad Esfahbodff05d252009-05-20 03:53:00 -04001360 };
1361
Behdad Esfahbod2005fa52012-11-22 14:38:10 -05001362 template <typename context_t>
1363 inline typename context_t::return_t process (context_t *c, unsigned int lookup_type) const
Behdad Esfahbodfaf0f202012-06-09 03:02:36 -04001364 {
Behdad Esfahbod0b994292012-07-28 17:31:01 -04001365 switch (lookup_type) {
Behdad Esfahbod2005fa52012-11-22 14:38:10 -05001366 case Single: return u.single.process (c);
1367 case Pair: return u.pair.process (c);
1368 case Cursive: return u.cursive.process (c);
1369 case MarkBase: return u.markBase.process (c);
1370 case MarkLig: return u.markLig.process (c);
1371 case MarkMark: return u.markMark.process (c);
1372 case Context: return u.context.process (c);
1373 case ChainContext: return u.chainContext.process (c);
1374 case Extension: return u.extension.process (c);
1375 default: return c->default_return_value ();
Behdad Esfahbod0b994292012-07-28 17:31:01 -04001376 }
Behdad Esfahbodfaf0f202012-06-09 03:02:36 -04001377 }
1378
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001379 inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001380 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001381 TRACE_APPLY ();
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001382 switch (lookup_type) {
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001383 case Single: return TRACE_RETURN (u.single.apply (c));
1384 case Pair: return TRACE_RETURN (u.pair.apply (c));
1385 case Cursive: return TRACE_RETURN (u.cursive.apply (c));
1386 case MarkBase: return TRACE_RETURN (u.markBase.apply (c));
1387 case MarkLig: return TRACE_RETURN (u.markLig.apply (c));
1388 case MarkMark: return TRACE_RETURN (u.markMark.apply (c));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001389 case Context: return TRACE_RETURN (u.context.apply (c));
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001390 case ChainContext: return TRACE_RETURN (u.chainContext.apply (c));
1391 case Extension: return TRACE_RETURN (u.extension.apply (c));
1392 default: return TRACE_RETURN (false);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001393 }
1394 }
1395
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001396 inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001397 TRACE_SANITIZE ();
Behdad Esfahbod0b994292012-07-28 17:31:01 -04001398 if (!u.header.sub_format.sanitize (c))
Behdad Esfahbodfaf0f202012-06-09 03:02:36 -04001399 return TRACE_RETURN (false);
Behdad Esfahbodfe9bc072010-05-10 21:39:24 -04001400 switch (lookup_type) {
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001401 case Single: return TRACE_RETURN (u.single.sanitize (c));
1402 case Pair: return TRACE_RETURN (u.pair.sanitize (c));
1403 case Cursive: return TRACE_RETURN (u.cursive.sanitize (c));
1404 case MarkBase: return TRACE_RETURN (u.markBase.sanitize (c));
1405 case MarkLig: return TRACE_RETURN (u.markLig.sanitize (c));
1406 case MarkMark: return TRACE_RETURN (u.markMark.sanitize (c));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001407 case Context: return TRACE_RETURN (u.context.sanitize (c));
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001408 case ChainContext: return TRACE_RETURN (u.chainContext.sanitize (c));
1409 case Extension: return TRACE_RETURN (u.extension.sanitize (c));
1410 default: return TRACE_RETURN (true);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001411 }
1412 }
1413
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001414 protected:
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001415 union {
Behdad Esfahbod4e766ff2012-06-09 02:53:57 -04001416 struct {
Behdad Esfahbod2005fa52012-11-22 14:38:10 -05001417 USHORT sub_format;
Behdad Esfahbod4e766ff2012-06-09 02:53:57 -04001418 } header;
Behdad Esfahboddacebca2010-05-10 19:45:41 -04001419 SinglePos single;
1420 PairPos pair;
1421 CursivePos cursive;
1422 MarkBasePos markBase;
1423 MarkLigPos markLig;
1424 MarkMarkPos markMark;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001425 ContextPos context;
Behdad Esfahboddacebca2010-05-10 19:45:41 -04001426 ChainContextPos chainContext;
1427 ExtensionPos extension;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001428 } u;
Behdad Esfahboded074222010-05-10 18:08:46 -04001429 public:
Behdad Esfahbod4e766ff2012-06-09 02:53:57 -04001430 DEFINE_SIZE_UNION (2, header.sub_format);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001431};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001432
1433
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001434struct PosLookup : Lookup
1435{
Behdad Esfahbod6d08c7f2012-07-11 18:01:27 -04001436 inline const PosLookupSubTable& get_subtable (unsigned int i) const
1437 { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001438
Behdad Esfahbod2005fa52012-11-22 14:38:10 -05001439 template <typename context_t>
1440 inline typename context_t::return_t process (context_t *c) const
1441 {
1442 unsigned int lookup_type = get_type ();
1443 unsigned int count = get_subtable_count ();
1444 for (unsigned int i = 0; i < count; i++) {
1445 typename context_t::return_t r = get_subtable (i).process (c, lookup_type);
1446 if (c->stop_sublookup_iteration (r))
1447 return r;
1448 }
1449 return c->default_return_value ();
1450 }
1451
Behdad Esfahboda878c582012-08-01 21:18:54 -04001452 template <typename set_t>
1453 inline void add_coverage (set_t *glyphs) const
1454 {
Behdad Esfahbod2005fa52012-11-22 14:38:10 -05001455 hb_get_coverage_context_t c;
Behdad Esfahboda878c582012-08-01 21:18:54 -04001456 const Coverage *last = NULL;
1457 unsigned int count = get_subtable_count ();
1458 for (unsigned int i = 0; i < count; i++) {
Behdad Esfahbod2005fa52012-11-22 14:38:10 -05001459 const Coverage *coverage = &get_subtable (i).process (&c, get_type ());
1460 if (coverage != last) {
1461 coverage->add_coverage (glyphs);
1462 last = coverage;
Behdad Esfahboda878c582012-08-01 21:18:54 -04001463 }
1464 }
1465 }
1466
Behdad Esfahbod41ae6742012-04-11 17:11:05 -04001467 inline bool apply_once (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001468 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001469 unsigned int lookup_type = get_type ();
Behdad Esfahbod1376fb72010-04-29 02:19:21 -04001470
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -04001471 if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props, &c->property))
Behdad Esfahbod923923f2009-05-22 17:58:09 -04001472 return false;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001473
Behdad Esfahbod44b8ee02012-06-09 00:23:24 -04001474 unsigned int count = get_subtable_count ();
1475 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001476 if (get_subtable (i).apply (c, lookup_type))
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001477 return true;
1478
1479 return false;
1480 }
1481
Behdad Esfahbod2bd9fe32012-09-04 15:15:19 -04001482 inline bool apply_string (hb_apply_context_t *c, const hb_set_digest_t *digest) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001483 {
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001484 bool ret = false;
1485
Behdad Esfahbod1d3947a2012-09-04 22:42:17 -04001486 if (unlikely (!c->buffer->len || !c->lookup_mask))
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001487 return false;
1488
Behdad Esfahbod650ac002012-04-23 13:17:09 -04001489 c->set_lookup (*this);
Behdad Esfahbod41ae6742012-04-11 17:11:05 -04001490
Behdad Esfahbod650ac002012-04-23 13:17:09 -04001491 c->buffer->idx = 0;
Behdad Esfahbod0b994292012-07-28 17:31:01 -04001492
Behdad Esfahbod1336ecd2012-08-01 21:46:36 -04001493 while (c->buffer->idx < c->buffer->len)
1494 {
1495 if ((c->buffer->cur().mask & c->lookup_mask) &&
Behdad Esfahbod2bd9fe32012-09-04 15:15:19 -04001496 digest->may_have (c->buffer->cur().codepoint) &&
Behdad Esfahbod1336ecd2012-08-01 21:46:36 -04001497 apply_once (c))
1498 ret = true;
1499 else
1500 c->buffer->idx++;
1501 }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001502
1503 return ret;
1504 }
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001505
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001506 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001507 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001508 if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
Behdad Esfahbod6d08c7f2012-07-11 18:01:27 -04001509 OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001510 return TRACE_RETURN (list.sanitize (c, this, get_type ()));
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001511 }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001512};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001513
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001514typedef OffsetListOf<PosLookup> PosLookupList;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001515
1516/*
Behdad Esfahbodae9877d2011-08-17 14:43:45 +02001517 * GPOS -- The Glyph Positioning Table
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001518 */
1519
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001520struct GPOS : GSUBGPOS
1521{
Behdad Esfahboda328d662009-08-04 20:27:05 -04001522 static const hb_tag_t Tag = HB_OT_TAG_GPOS;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001523
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001524 inline const PosLookup& get_lookup (unsigned int i) const
Behdad Esfahbod187454c2010-04-23 16:35:01 -04001525 { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001526
Behdad Esfahboda878c582012-08-01 21:18:54 -04001527 template <typename set_t>
1528 inline void add_coverage (set_t *glyphs, unsigned int lookup_index) const
1529 { get_lookup (lookup_index).add_coverage (glyphs); }
1530
Behdad Esfahbod05bd1b62012-07-30 19:30:01 -04001531 static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
Behdad Esfahbod1e7d8602012-07-31 23:41:06 -04001532 static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer, hb_bool_t zero_width_attahced_marks);
Behdad Esfahbod1e7c1fc2010-10-27 22:48:31 -04001533
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001534 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001535 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001536 if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
Behdad Esfahbod187454c2010-04-23 16:35:01 -04001537 OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001538 return TRACE_RETURN (list.sanitize (c, this));
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001539 }
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001540 public:
1541 DEFINE_SIZE_STATIC (10);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001542};
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001543
Behdad Esfahbod7403e052011-05-24 21:04:15 -04001544
1545static void
1546fix_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
1547{
Behdad Esfahboddf5d5c62012-08-23 09:33:30 -04001548 unsigned int j = pos[i].cursive_chain();
1549 if (likely (!j))
1550 return;
Behdad Esfahbod7403e052011-05-24 21:04:15 -04001551
Behdad Esfahboddf5d5c62012-08-23 09:33:30 -04001552 j += i;
Behdad Esfahbod7403e052011-05-24 21:04:15 -04001553
Behdad Esfahboddf5d5c62012-08-23 09:33:30 -04001554 pos[i].cursive_chain() = 0;
Behdad Esfahbod7403e052011-05-24 21:04:15 -04001555
Behdad Esfahboddf5d5c62012-08-23 09:33:30 -04001556 fix_cursive_minor_offset (pos, j, direction);
Behdad Esfahbod7403e052011-05-24 21:04:15 -04001557
Behdad Esfahboddf5d5c62012-08-23 09:33:30 -04001558 if (HB_DIRECTION_IS_HORIZONTAL (direction))
1559 pos[i].y_offset += pos[j].y_offset;
1560 else
1561 pos[i].x_offset += pos[j].x_offset;
Behdad Esfahbod7403e052011-05-24 21:04:15 -04001562}
1563
1564static void
Behdad Esfahbod1e7d8602012-07-31 23:41:06 -04001565fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, hb_bool_t zero_width_attached_marks)
Behdad Esfahbod7403e052011-05-24 21:04:15 -04001566{
1567 if (likely (!(pos[i].attach_lookback())))
1568 return;
1569
1570 unsigned int j = i - pos[i].attach_lookback();
1571
Behdad Esfahbod1e7d8602012-07-31 23:41:06 -04001572 if (zero_width_attached_marks) {
1573 pos[i].x_advance = 0;
1574 pos[i].y_advance = 0;
1575 }
Behdad Esfahbod7403e052011-05-24 21:04:15 -04001576 pos[i].x_offset += pos[j].x_offset;
1577 pos[i].y_offset += pos[j].y_offset;
1578
1579 if (HB_DIRECTION_IS_FORWARD (direction))
Behdad Esfahbod21deab22011-05-30 11:08:40 -04001580 for (unsigned int k = j; k < i; k++) {
Behdad Esfahbod7403e052011-05-24 21:04:15 -04001581 pos[i].x_offset -= pos[k].x_advance;
1582 pos[i].y_offset -= pos[k].y_advance;
1583 }
1584 else
Behdad Esfahbod21deab22011-05-30 11:08:40 -04001585 for (unsigned int k = j + 1; k < i + 1; k++) {
Behdad Esfahbod7403e052011-05-24 21:04:15 -04001586 pos[i].x_offset += pos[k].x_advance;
1587 pos[i].y_offset += pos[k].y_advance;
1588 }
1589}
1590
Behdad Esfahbod1e7c1fc2010-10-27 22:48:31 -04001591void
Behdad Esfahbod05bd1b62012-07-30 19:30:01 -04001592GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
Behdad Esfahboda9ad3d32011-07-28 15:42:18 -04001593{
1594 buffer->clear_positions ();
Behdad Esfahbodb65c0602011-07-28 16:48:43 -04001595
1596 unsigned int count = buffer->len;
1597 for (unsigned int i = 0; i < count; i++)
1598 buffer->pos[i].attach_lookback() = buffer->pos[i].cursive_chain() = 0;
Behdad Esfahboda9ad3d32011-07-28 15:42:18 -04001599}
1600
1601void
Behdad Esfahbod1e7d8602012-07-31 23:41:06 -04001602GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer, hb_bool_t zero_width_attached_marks)
Behdad Esfahbod1e7c1fc2010-10-27 22:48:31 -04001603{
Ryan Lortie70566be2011-04-15 18:32:36 -04001604 unsigned int len;
1605 hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
Behdad Esfahbod1e7c1fc2010-10-27 22:48:31 -04001606 hb_direction_t direction = buffer->props.direction;
1607
Behdad Esfahbod7403e052011-05-24 21:04:15 -04001608 /* Handle cursive connections */
1609 for (unsigned int i = 0; i < len; i++)
Behdad Esfahbod7403e052011-05-24 21:04:15 -04001610 fix_cursive_minor_offset (pos, i, direction);
Behdad Esfahbod1e7c1fc2010-10-27 22:48:31 -04001611
1612 /* Handle attachments */
Behdad Esfahbod7403e052011-05-24 21:04:15 -04001613 for (unsigned int i = 0; i < len; i++)
Behdad Esfahbod1e7d8602012-07-31 23:41:06 -04001614 fix_mark_attachment (pos, i, direction, zero_width_attached_marks);
Behdad Esfahbodb65c0602011-07-28 16:48:43 -04001615
Behdad Esfahbodcee71872012-05-11 11:41:39 +02001616 HB_BUFFER_DEALLOCATE_VAR (buffer, syllable);
Behdad Esfahboda9844d42012-05-09 17:53:13 +02001617 HB_BUFFER_DEALLOCATE_VAR (buffer, lig_props);
Behdad Esfahbodc2e42c32012-07-30 19:54:50 -04001618 HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_props);
Behdad Esfahbod1e7c1fc2010-10-27 22:48:31 -04001619}
1620
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001621
1622/* Out-of-class implementation for methods recursing */
1623
Behdad Esfahbod2005fa52012-11-22 14:38:10 -05001624template <typename context_t>
1625inline typename context_t::return_t ExtensionPos::process (context_t *c) const
Behdad Esfahbod0b994292012-07-28 17:31:01 -04001626{
Behdad Esfahbod2005fa52012-11-22 14:38:10 -05001627 return get_subtable ().process (c, get_type ());
Behdad Esfahbod0b994292012-07-28 17:31:01 -04001628}
1629
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001630inline bool ExtensionPos::apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001631{
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001632 TRACE_APPLY ();
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001633 return TRACE_RETURN (get_subtable ().apply (c, get_type ()));
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001634}
1635
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001636inline bool ExtensionPos::sanitize (hb_sanitize_context_t *c)
Behdad Esfahbod42b778f2009-08-04 13:30:49 -04001637{
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001638 TRACE_SANITIZE ();
Behdad Esfahbod6d08c7f2012-07-11 18:01:27 -04001639 if (unlikely (!Extension::sanitize (c))) return TRACE_RETURN (false);
Behdad Esfahbod3b2c2df2010-04-22 16:51:42 -04001640 unsigned int offset = get_offset ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001641 if (unlikely (!offset)) return TRACE_RETURN (true);
Behdad Esfahbod6d08c7f2012-07-11 18:01:27 -04001642 return TRACE_RETURN (StructAtOffset<PosLookupSubTable> (this, offset).sanitize (c, get_type ()));
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001643}
1644
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001645static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index)
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001646{
Behdad Esfahbodea278d32012-07-27 02:12:28 -04001647 const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001648 const PosLookup &l = gpos.get_lookup (lookup_index);
1649
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001650 if (unlikely (c->nesting_level_left == 0))
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001651 return false;
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001652
Behdad Esfahbod650ac002012-04-23 13:17:09 -04001653 hb_apply_context_t new_c (*c);
1654 new_c.nesting_level_left--;
1655 new_c.set_lookup (l);
Behdad Esfahbod41ae6742012-04-11 17:11:05 -04001656 return l.apply_once (&new_c);
Behdad Esfahbod5e5eb052009-05-18 17:09:33 -04001657}
1658
1659
Behdad Esfahbod194d4562010-10-27 23:09:10 -04001660#undef attach_lookback
1661#undef cursive_chain
1662
1663
Behdad Esfahbod7d52e662012-11-16 18:49:54 -08001664} /* namespace OT */
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -04001665
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001666
Behdad Esfahbod7a750ac2011-08-17 14:19:59 +02001667#endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */