1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1637 @@ 1.4 +/* 1.5 + * Copyright © 2007,2008,2009,2010 Red Hat, Inc. 1.6 + * Copyright © 2010,2012,2013 Google, Inc. 1.7 + * 1.8 + * This is part of HarfBuzz, a text shaping library. 1.9 + * 1.10 + * Permission is hereby granted, without written agreement and without 1.11 + * license or royalty fees, to use, copy, modify, and distribute this 1.12 + * software and its documentation for any purpose, provided that the 1.13 + * above copyright notice and the following two paragraphs appear in 1.14 + * all copies of this software. 1.15 + * 1.16 + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 1.17 + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 1.18 + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 1.19 + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 1.20 + * DAMAGE. 1.21 + * 1.22 + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 1.23 + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 1.24 + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 1.25 + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 1.26 + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 1.27 + * 1.28 + * Red Hat Author(s): Behdad Esfahbod 1.29 + * Google Author(s): Behdad Esfahbod 1.30 + */ 1.31 + 1.32 +#ifndef HB_OT_LAYOUT_GPOS_TABLE_HH 1.33 +#define HB_OT_LAYOUT_GPOS_TABLE_HH 1.34 + 1.35 +#include "hb-ot-layout-gsubgpos-private.hh" 1.36 + 1.37 + 1.38 +namespace OT { 1.39 + 1.40 + 1.41 +/* buffer **position** var allocations */ 1.42 +#define attach_lookback() var.u16[0] /* number of glyphs to go back to attach this glyph to its base */ 1.43 +#define cursive_chain() var.i16[1] /* character to which this connects, may be positive or negative */ 1.44 + 1.45 + 1.46 +/* Shared Tables: ValueRecord, Anchor Table, and MarkArray */ 1.47 + 1.48 +typedef USHORT Value; 1.49 + 1.50 +typedef Value ValueRecord[VAR]; 1.51 + 1.52 +struct ValueFormat : USHORT 1.53 +{ 1.54 + enum Flags { 1.55 + xPlacement = 0x0001, /* Includes horizontal adjustment for placement */ 1.56 + yPlacement = 0x0002, /* Includes vertical adjustment for placement */ 1.57 + xAdvance = 0x0004, /* Includes horizontal adjustment for advance */ 1.58 + yAdvance = 0x0008, /* Includes vertical adjustment for advance */ 1.59 + xPlaDevice = 0x0010, /* Includes horizontal Device table for placement */ 1.60 + yPlaDevice = 0x0020, /* Includes vertical Device table for placement */ 1.61 + xAdvDevice = 0x0040, /* Includes horizontal Device table for advance */ 1.62 + yAdvDevice = 0x0080, /* Includes vertical Device table for advance */ 1.63 + ignored = 0x0F00, /* Was used in TrueType Open for MM fonts */ 1.64 + reserved = 0xF000, /* For future use */ 1.65 + 1.66 + devices = 0x00F0 /* Mask for having any Device table */ 1.67 + }; 1.68 + 1.69 +/* All fields are options. Only those available advance the value pointer. */ 1.70 +#if 0 1.71 + SHORT xPlacement; /* Horizontal adjustment for 1.72 + * placement--in design units */ 1.73 + SHORT yPlacement; /* Vertical adjustment for 1.74 + * placement--in design units */ 1.75 + SHORT xAdvance; /* Horizontal adjustment for 1.76 + * advance--in design units (only used 1.77 + * for horizontal writing) */ 1.78 + SHORT yAdvance; /* Vertical adjustment for advance--in 1.79 + * design units (only used for vertical 1.80 + * writing) */ 1.81 + Offset xPlaDevice; /* Offset to Device table for 1.82 + * horizontal placement--measured from 1.83 + * beginning of PosTable (may be NULL) */ 1.84 + Offset yPlaDevice; /* Offset to Device table for vertical 1.85 + * placement--measured from beginning 1.86 + * of PosTable (may be NULL) */ 1.87 + Offset xAdvDevice; /* Offset to Device table for 1.88 + * horizontal advance--measured from 1.89 + * beginning of PosTable (may be NULL) */ 1.90 + Offset yAdvDevice; /* Offset to Device table for vertical 1.91 + * advance--measured from beginning of 1.92 + * PosTable (may be NULL) */ 1.93 +#endif 1.94 + 1.95 + inline unsigned int get_len (void) const 1.96 + { return _hb_popcount32 ((unsigned int) *this); } 1.97 + inline unsigned int get_size (void) const 1.98 + { return get_len () * Value::static_size; } 1.99 + 1.100 + void apply_value (hb_font_t *font, 1.101 + hb_direction_t direction, 1.102 + const void *base, 1.103 + const Value *values, 1.104 + hb_glyph_position_t &glyph_pos) const 1.105 + { 1.106 + unsigned int x_ppem, y_ppem; 1.107 + unsigned int format = *this; 1.108 + hb_bool_t horizontal = HB_DIRECTION_IS_HORIZONTAL (direction); 1.109 + 1.110 + if (!format) return; 1.111 + 1.112 + if (format & xPlacement) glyph_pos.x_offset += font->em_scale_x (get_short (values++)); 1.113 + if (format & yPlacement) glyph_pos.y_offset += font->em_scale_y (get_short (values++)); 1.114 + if (format & xAdvance) { 1.115 + if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values)); 1.116 + values++; 1.117 + } 1.118 + /* y_advance values grow downward but font-space grows upward, hence negation */ 1.119 + if (format & yAdvance) { 1.120 + if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values)); 1.121 + values++; 1.122 + } 1.123 + 1.124 + if (!has_device ()) return; 1.125 + 1.126 + x_ppem = font->x_ppem; 1.127 + y_ppem = font->y_ppem; 1.128 + 1.129 + if (!x_ppem && !y_ppem) return; 1.130 + 1.131 + /* pixel -> fractional pixel */ 1.132 + if (format & xPlaDevice) { 1.133 + if (x_ppem) glyph_pos.x_offset += (base + get_device (values)).get_x_delta (font); 1.134 + values++; 1.135 + } 1.136 + if (format & yPlaDevice) { 1.137 + if (y_ppem) glyph_pos.y_offset += (base + get_device (values)).get_y_delta (font); 1.138 + values++; 1.139 + } 1.140 + if (format & xAdvDevice) { 1.141 + if (horizontal && x_ppem) glyph_pos.x_advance += (base + get_device (values)).get_x_delta (font); 1.142 + values++; 1.143 + } 1.144 + if (format & yAdvDevice) { 1.145 + /* y_advance values grow downward but font-space grows upward, hence negation */ 1.146 + if (!horizontal && y_ppem) glyph_pos.y_advance -= (base + get_device (values)).get_y_delta (font); 1.147 + values++; 1.148 + } 1.149 + } 1.150 + 1.151 + private: 1.152 + inline bool sanitize_value_devices (hb_sanitize_context_t *c, void *base, Value *values) { 1.153 + unsigned int format = *this; 1.154 + 1.155 + if (format & xPlacement) values++; 1.156 + if (format & yPlacement) values++; 1.157 + if (format & xAdvance) values++; 1.158 + if (format & yAdvance) values++; 1.159 + 1.160 + if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false; 1.161 + if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false; 1.162 + if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false; 1.163 + if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false; 1.164 + 1.165 + return true; 1.166 + } 1.167 + 1.168 + static inline OffsetTo<Device>& get_device (Value* value) 1.169 + { return *CastP<OffsetTo<Device> > (value); } 1.170 + static inline const OffsetTo<Device>& get_device (const Value* value) 1.171 + { return *CastP<OffsetTo<Device> > (value); } 1.172 + 1.173 + static inline const SHORT& get_short (const Value* value) 1.174 + { return *CastP<SHORT> (value); } 1.175 + 1.176 + public: 1.177 + 1.178 + inline bool has_device (void) const { 1.179 + unsigned int format = *this; 1.180 + return (format & devices) != 0; 1.181 + } 1.182 + 1.183 + inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *values) { 1.184 + TRACE_SANITIZE (this); 1.185 + return TRACE_RETURN (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values))); 1.186 + } 1.187 + 1.188 + inline bool sanitize_values (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count) { 1.189 + TRACE_SANITIZE (this); 1.190 + unsigned int len = get_len (); 1.191 + 1.192 + if (!c->check_array (values, get_size (), count)) return TRACE_RETURN (false); 1.193 + 1.194 + if (!has_device ()) return TRACE_RETURN (true); 1.195 + 1.196 + for (unsigned int i = 0; i < count; i++) { 1.197 + if (!sanitize_value_devices (c, base, values)) 1.198 + return TRACE_RETURN (false); 1.199 + values += len; 1.200 + } 1.201 + 1.202 + return TRACE_RETURN (true); 1.203 + } 1.204 + 1.205 + /* Just sanitize referenced Device tables. Doesn't check the values themselves. */ 1.206 + inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count, unsigned int stride) { 1.207 + TRACE_SANITIZE (this); 1.208 + 1.209 + if (!has_device ()) return TRACE_RETURN (true); 1.210 + 1.211 + for (unsigned int i = 0; i < count; i++) { 1.212 + if (!sanitize_value_devices (c, base, values)) 1.213 + return TRACE_RETURN (false); 1.214 + values += stride; 1.215 + } 1.216 + 1.217 + return TRACE_RETURN (true); 1.218 + } 1.219 +}; 1.220 + 1.221 + 1.222 +struct AnchorFormat1 1.223 +{ 1.224 + inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED, 1.225 + hb_position_t *x, hb_position_t *y) const 1.226 + { 1.227 + *x = font->em_scale_x (xCoordinate); 1.228 + *y = font->em_scale_y (yCoordinate); 1.229 + } 1.230 + 1.231 + inline bool sanitize (hb_sanitize_context_t *c) { 1.232 + TRACE_SANITIZE (this); 1.233 + return TRACE_RETURN (c->check_struct (this)); 1.234 + } 1.235 + 1.236 + protected: 1.237 + USHORT format; /* Format identifier--format = 1 */ 1.238 + SHORT xCoordinate; /* Horizontal value--in design units */ 1.239 + SHORT yCoordinate; /* Vertical value--in design units */ 1.240 + public: 1.241 + DEFINE_SIZE_STATIC (6); 1.242 +}; 1.243 + 1.244 +struct AnchorFormat2 1.245 +{ 1.246 + inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id, 1.247 + hb_position_t *x, hb_position_t *y) const 1.248 + { 1.249 + unsigned int x_ppem = font->x_ppem; 1.250 + unsigned int y_ppem = font->y_ppem; 1.251 + hb_position_t cx, cy; 1.252 + hb_bool_t ret; 1.253 + 1.254 + ret = (x_ppem || y_ppem) && 1.255 + font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy); 1.256 + *x = ret && x_ppem ? cx : font->em_scale_x (xCoordinate); 1.257 + *y = ret && y_ppem ? cy : font->em_scale_y (yCoordinate); 1.258 + } 1.259 + 1.260 + inline bool sanitize (hb_sanitize_context_t *c) { 1.261 + TRACE_SANITIZE (this); 1.262 + return TRACE_RETURN (c->check_struct (this)); 1.263 + } 1.264 + 1.265 + protected: 1.266 + USHORT format; /* Format identifier--format = 2 */ 1.267 + SHORT xCoordinate; /* Horizontal value--in design units */ 1.268 + SHORT yCoordinate; /* Vertical value--in design units */ 1.269 + USHORT anchorPoint; /* Index to glyph contour point */ 1.270 + public: 1.271 + DEFINE_SIZE_STATIC (8); 1.272 +}; 1.273 + 1.274 +struct AnchorFormat3 1.275 +{ 1.276 + inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED, 1.277 + hb_position_t *x, hb_position_t *y) const 1.278 + { 1.279 + *x = font->em_scale_x (xCoordinate); 1.280 + *y = font->em_scale_y (yCoordinate); 1.281 + 1.282 + if (font->x_ppem) 1.283 + *x += (this+xDeviceTable).get_x_delta (font); 1.284 + if (font->y_ppem) 1.285 + *y += (this+yDeviceTable).get_x_delta (font); 1.286 + } 1.287 + 1.288 + inline bool sanitize (hb_sanitize_context_t *c) { 1.289 + TRACE_SANITIZE (this); 1.290 + return TRACE_RETURN (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this)); 1.291 + } 1.292 + 1.293 + protected: 1.294 + USHORT format; /* Format identifier--format = 3 */ 1.295 + SHORT xCoordinate; /* Horizontal value--in design units */ 1.296 + SHORT yCoordinate; /* Vertical value--in design units */ 1.297 + OffsetTo<Device> 1.298 + xDeviceTable; /* Offset to Device table for X 1.299 + * coordinate-- from beginning of 1.300 + * Anchor table (may be NULL) */ 1.301 + OffsetTo<Device> 1.302 + yDeviceTable; /* Offset to Device table for Y 1.303 + * coordinate-- from beginning of 1.304 + * Anchor table (may be NULL) */ 1.305 + public: 1.306 + DEFINE_SIZE_STATIC (10); 1.307 +}; 1.308 + 1.309 +struct Anchor 1.310 +{ 1.311 + inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id, 1.312 + hb_position_t *x, hb_position_t *y) const 1.313 + { 1.314 + *x = *y = 0; 1.315 + switch (u.format) { 1.316 + case 1: u.format1.get_anchor (font, glyph_id, x, y); return; 1.317 + case 2: u.format2.get_anchor (font, glyph_id, x, y); return; 1.318 + case 3: u.format3.get_anchor (font, glyph_id, x, y); return; 1.319 + default: return; 1.320 + } 1.321 + } 1.322 + 1.323 + inline bool sanitize (hb_sanitize_context_t *c) { 1.324 + TRACE_SANITIZE (this); 1.325 + if (!u.format.sanitize (c)) return TRACE_RETURN (false); 1.326 + switch (u.format) { 1.327 + case 1: return TRACE_RETURN (u.format1.sanitize (c)); 1.328 + case 2: return TRACE_RETURN (u.format2.sanitize (c)); 1.329 + case 3: return TRACE_RETURN (u.format3.sanitize (c)); 1.330 + default:return TRACE_RETURN (true); 1.331 + } 1.332 + } 1.333 + 1.334 + protected: 1.335 + union { 1.336 + USHORT format; /* Format identifier */ 1.337 + AnchorFormat1 format1; 1.338 + AnchorFormat2 format2; 1.339 + AnchorFormat3 format3; 1.340 + } u; 1.341 + public: 1.342 + DEFINE_SIZE_UNION (2, format); 1.343 +}; 1.344 + 1.345 + 1.346 +struct AnchorMatrix 1.347 +{ 1.348 + inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols, bool *found) const { 1.349 + *found = false; 1.350 + if (unlikely (row >= rows || col >= cols)) return Null(Anchor); 1.351 + *found = !matrix[row * cols + col].is_null (); 1.352 + return this+matrix[row * cols + col]; 1.353 + } 1.354 + 1.355 + inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) { 1.356 + TRACE_SANITIZE (this); 1.357 + if (!c->check_struct (this)) return TRACE_RETURN (false); 1.358 + if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return TRACE_RETURN (false); 1.359 + unsigned int count = rows * cols; 1.360 + if (!c->check_array (matrix, matrix[0].static_size, count)) return TRACE_RETURN (false); 1.361 + for (unsigned int i = 0; i < count; i++) 1.362 + if (!matrix[i].sanitize (c, this)) return TRACE_RETURN (false); 1.363 + return TRACE_RETURN (true); 1.364 + } 1.365 + 1.366 + USHORT rows; /* Number of rows */ 1.367 + protected: 1.368 + OffsetTo<Anchor> 1.369 + matrix[VAR]; /* Matrix of offsets to Anchor tables-- 1.370 + * from beginning of AnchorMatrix table */ 1.371 + public: 1.372 + DEFINE_SIZE_ARRAY (2, matrix); 1.373 +}; 1.374 + 1.375 + 1.376 +struct MarkRecord 1.377 +{ 1.378 + friend struct MarkArray; 1.379 + 1.380 + inline bool sanitize (hb_sanitize_context_t *c, void *base) { 1.381 + TRACE_SANITIZE (this); 1.382 + return TRACE_RETURN (c->check_struct (this) && markAnchor.sanitize (c, base)); 1.383 + } 1.384 + 1.385 + protected: 1.386 + USHORT klass; /* Class defined for this mark */ 1.387 + OffsetTo<Anchor> 1.388 + markAnchor; /* Offset to Anchor table--from 1.389 + * beginning of MarkArray table */ 1.390 + public: 1.391 + DEFINE_SIZE_STATIC (4); 1.392 +}; 1.393 + 1.394 +struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage order */ 1.395 +{ 1.396 + inline bool apply (hb_apply_context_t *c, 1.397 + unsigned int mark_index, unsigned int glyph_index, 1.398 + const AnchorMatrix &anchors, unsigned int class_count, 1.399 + unsigned int glyph_pos) const 1.400 + { 1.401 + TRACE_APPLY (this); 1.402 + hb_buffer_t *buffer = c->buffer; 1.403 + const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index); 1.404 + unsigned int mark_class = record.klass; 1.405 + 1.406 + const Anchor& mark_anchor = this + record.markAnchor; 1.407 + bool found; 1.408 + const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found); 1.409 + /* If this subtable doesn't have an anchor for this base and this class, 1.410 + * return false such that the subsequent subtables have a chance at it. */ 1.411 + if (unlikely (!found)) return TRACE_RETURN (false); 1.412 + 1.413 + hb_position_t mark_x, mark_y, base_x, base_y; 1.414 + 1.415 + mark_anchor.get_anchor (c->font, buffer->cur().codepoint, &mark_x, &mark_y); 1.416 + glyph_anchor.get_anchor (c->font, buffer->info[glyph_pos].codepoint, &base_x, &base_y); 1.417 + 1.418 + hb_glyph_position_t &o = buffer->cur_pos(); 1.419 + o.x_offset = base_x - mark_x; 1.420 + o.y_offset = base_y - mark_y; 1.421 + o.attach_lookback() = buffer->idx - glyph_pos; 1.422 + 1.423 + buffer->idx++; 1.424 + return TRACE_RETURN (true); 1.425 + } 1.426 + 1.427 + inline bool sanitize (hb_sanitize_context_t *c) { 1.428 + TRACE_SANITIZE (this); 1.429 + return TRACE_RETURN (ArrayOf<MarkRecord>::sanitize (c, this)); 1.430 + } 1.431 +}; 1.432 + 1.433 + 1.434 +/* Lookups */ 1.435 + 1.436 +struct SinglePosFormat1 1.437 +{ 1.438 + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1.439 + { 1.440 + TRACE_COLLECT_GLYPHS (this); 1.441 + (this+coverage).add_coverage (c->input); 1.442 + } 1.443 + 1.444 + inline const Coverage &get_coverage (void) const 1.445 + { 1.446 + return this+coverage; 1.447 + } 1.448 + 1.449 + inline bool apply (hb_apply_context_t *c) const 1.450 + { 1.451 + TRACE_APPLY (this); 1.452 + hb_buffer_t *buffer = c->buffer; 1.453 + unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); 1.454 + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 1.455 + 1.456 + valueFormat.apply_value (c->font, c->direction, this, 1.457 + values, buffer->cur_pos()); 1.458 + 1.459 + buffer->idx++; 1.460 + return TRACE_RETURN (true); 1.461 + } 1.462 + 1.463 + inline bool sanitize (hb_sanitize_context_t *c) { 1.464 + TRACE_SANITIZE (this); 1.465 + return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_value (c, this, values)); 1.466 + } 1.467 + 1.468 + protected: 1.469 + USHORT format; /* Format identifier--format = 1 */ 1.470 + OffsetTo<Coverage> 1.471 + coverage; /* Offset to Coverage table--from 1.472 + * beginning of subtable */ 1.473 + ValueFormat valueFormat; /* Defines the types of data in the 1.474 + * ValueRecord */ 1.475 + ValueRecord values; /* Defines positioning 1.476 + * value(s)--applied to all glyphs in 1.477 + * the Coverage table */ 1.478 + public: 1.479 + DEFINE_SIZE_ARRAY (6, values); 1.480 +}; 1.481 + 1.482 +struct SinglePosFormat2 1.483 +{ 1.484 + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1.485 + { 1.486 + TRACE_COLLECT_GLYPHS (this); 1.487 + (this+coverage).add_coverage (c->input); 1.488 + } 1.489 + 1.490 + inline const Coverage &get_coverage (void) const 1.491 + { 1.492 + return this+coverage; 1.493 + } 1.494 + 1.495 + inline bool apply (hb_apply_context_t *c) const 1.496 + { 1.497 + TRACE_APPLY (this); 1.498 + hb_buffer_t *buffer = c->buffer; 1.499 + unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); 1.500 + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 1.501 + 1.502 + if (likely (index >= valueCount)) return TRACE_RETURN (false); 1.503 + 1.504 + valueFormat.apply_value (c->font, c->direction, this, 1.505 + &values[index * valueFormat.get_len ()], 1.506 + buffer->cur_pos()); 1.507 + 1.508 + buffer->idx++; 1.509 + return TRACE_RETURN (true); 1.510 + } 1.511 + 1.512 + inline bool sanitize (hb_sanitize_context_t *c) { 1.513 + TRACE_SANITIZE (this); 1.514 + return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_values (c, this, values, valueCount)); 1.515 + } 1.516 + 1.517 + protected: 1.518 + USHORT format; /* Format identifier--format = 2 */ 1.519 + OffsetTo<Coverage> 1.520 + coverage; /* Offset to Coverage table--from 1.521 + * beginning of subtable */ 1.522 + ValueFormat valueFormat; /* Defines the types of data in the 1.523 + * ValueRecord */ 1.524 + USHORT valueCount; /* Number of ValueRecords */ 1.525 + ValueRecord values; /* Array of ValueRecords--positioning 1.526 + * values applied to glyphs */ 1.527 + public: 1.528 + DEFINE_SIZE_ARRAY (8, values); 1.529 +}; 1.530 + 1.531 +struct SinglePos 1.532 +{ 1.533 + template <typename context_t> 1.534 + inline typename context_t::return_t dispatch (context_t *c) const 1.535 + { 1.536 + TRACE_DISPATCH (this); 1.537 + switch (u.format) { 1.538 + case 1: return TRACE_RETURN (c->dispatch (u.format1)); 1.539 + case 2: return TRACE_RETURN (c->dispatch (u.format2)); 1.540 + default:return TRACE_RETURN (c->default_return_value ()); 1.541 + } 1.542 + } 1.543 + 1.544 + inline bool sanitize (hb_sanitize_context_t *c) { 1.545 + TRACE_SANITIZE (this); 1.546 + if (!u.format.sanitize (c)) return TRACE_RETURN (false); 1.547 + switch (u.format) { 1.548 + case 1: return TRACE_RETURN (u.format1.sanitize (c)); 1.549 + case 2: return TRACE_RETURN (u.format2.sanitize (c)); 1.550 + default:return TRACE_RETURN (true); 1.551 + } 1.552 + } 1.553 + 1.554 + protected: 1.555 + union { 1.556 + USHORT format; /* Format identifier */ 1.557 + SinglePosFormat1 format1; 1.558 + SinglePosFormat2 format2; 1.559 + } u; 1.560 +}; 1.561 + 1.562 + 1.563 +struct PairValueRecord 1.564 +{ 1.565 + friend struct PairSet; 1.566 + 1.567 + protected: 1.568 + GlyphID secondGlyph; /* GlyphID of second glyph in the 1.569 + * pair--first glyph is listed in the 1.570 + * Coverage table */ 1.571 + ValueRecord values; /* Positioning data for the first glyph 1.572 + * followed by for second glyph */ 1.573 + public: 1.574 + DEFINE_SIZE_ARRAY (2, values); 1.575 +}; 1.576 + 1.577 +struct PairSet 1.578 +{ 1.579 + friend struct PairPosFormat1; 1.580 + 1.581 + inline void collect_glyphs (hb_collect_glyphs_context_t *c, 1.582 + const ValueFormat *valueFormats) const 1.583 + { 1.584 + TRACE_COLLECT_GLYPHS (this); 1.585 + unsigned int len1 = valueFormats[0].get_len (); 1.586 + unsigned int len2 = valueFormats[1].get_len (); 1.587 + unsigned int record_size = USHORT::static_size * (1 + len1 + len2); 1.588 + 1.589 + const PairValueRecord *record = CastP<PairValueRecord> (array); 1.590 + unsigned int count = len; 1.591 + for (unsigned int i = 0; i < count; i++) 1.592 + { 1.593 + c->input->add (record->secondGlyph); 1.594 + record = &StructAtOffset<PairValueRecord> (record, record_size); 1.595 + } 1.596 + } 1.597 + 1.598 + inline bool apply (hb_apply_context_t *c, 1.599 + const ValueFormat *valueFormats, 1.600 + unsigned int pos) const 1.601 + { 1.602 + TRACE_APPLY (this); 1.603 + hb_buffer_t *buffer = c->buffer; 1.604 + unsigned int len1 = valueFormats[0].get_len (); 1.605 + unsigned int len2 = valueFormats[1].get_len (); 1.606 + unsigned int record_size = USHORT::static_size * (1 + len1 + len2); 1.607 + 1.608 + const PairValueRecord *record = CastP<PairValueRecord> (array); 1.609 + unsigned int count = len; 1.610 + for (unsigned int i = 0; i < count; i++) 1.611 + { 1.612 + /* TODO bsearch */ 1.613 + if (buffer->info[pos].codepoint == record->secondGlyph) 1.614 + { 1.615 + valueFormats[0].apply_value (c->font, c->direction, this, 1.616 + &record->values[0], buffer->cur_pos()); 1.617 + valueFormats[1].apply_value (c->font, c->direction, this, 1.618 + &record->values[len1], buffer->pos[pos]); 1.619 + if (len2) 1.620 + pos++; 1.621 + buffer->idx = pos; 1.622 + return TRACE_RETURN (true); 1.623 + } 1.624 + record = &StructAtOffset<PairValueRecord> (record, record_size); 1.625 + } 1.626 + 1.627 + return TRACE_RETURN (false); 1.628 + } 1.629 + 1.630 + struct sanitize_closure_t { 1.631 + void *base; 1.632 + ValueFormat *valueFormats; 1.633 + unsigned int len1; /* valueFormats[0].get_len() */ 1.634 + unsigned int stride; /* 1 + len1 + len2 */ 1.635 + }; 1.636 + 1.637 + inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) { 1.638 + TRACE_SANITIZE (this); 1.639 + if (!(c->check_struct (this) 1.640 + && c->check_array (array, USHORT::static_size * closure->stride, len))) return TRACE_RETURN (false); 1.641 + 1.642 + unsigned int count = len; 1.643 + PairValueRecord *record = CastP<PairValueRecord> (array); 1.644 + return TRACE_RETURN (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride) 1.645 + && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride)); 1.646 + } 1.647 + 1.648 + protected: 1.649 + USHORT len; /* Number of PairValueRecords */ 1.650 + USHORT array[VAR]; /* Array of PairValueRecords--ordered 1.651 + * by GlyphID of the second glyph */ 1.652 + public: 1.653 + DEFINE_SIZE_ARRAY (2, array); 1.654 +}; 1.655 + 1.656 +struct PairPosFormat1 1.657 +{ 1.658 + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1.659 + { 1.660 + TRACE_COLLECT_GLYPHS (this); 1.661 + (this+coverage).add_coverage (c->input); 1.662 + unsigned int count = pairSet.len; 1.663 + for (unsigned int i = 0; i < count; i++) 1.664 + (this+pairSet[i]).collect_glyphs (c, &valueFormat1); 1.665 + } 1.666 + 1.667 + inline const Coverage &get_coverage (void) const 1.668 + { 1.669 + return this+coverage; 1.670 + } 1.671 + 1.672 + inline bool apply (hb_apply_context_t *c) const 1.673 + { 1.674 + TRACE_APPLY (this); 1.675 + hb_buffer_t *buffer = c->buffer; 1.676 + hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1); 1.677 + if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); 1.678 + 1.679 + unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); 1.680 + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 1.681 + 1.682 + if (!skippy_iter.next ()) return TRACE_RETURN (false); 1.683 + 1.684 + return TRACE_RETURN ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx)); 1.685 + } 1.686 + 1.687 + inline bool sanitize (hb_sanitize_context_t *c) { 1.688 + TRACE_SANITIZE (this); 1.689 + 1.690 + unsigned int len1 = valueFormat1.get_len (); 1.691 + unsigned int len2 = valueFormat2.get_len (); 1.692 + PairSet::sanitize_closure_t closure = { 1.693 + this, 1.694 + &valueFormat1, 1.695 + len1, 1.696 + 1 + len1 + len2 1.697 + }; 1.698 + 1.699 + return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure)); 1.700 + } 1.701 + 1.702 + protected: 1.703 + USHORT format; /* Format identifier--format = 1 */ 1.704 + OffsetTo<Coverage> 1.705 + coverage; /* Offset to Coverage table--from 1.706 + * beginning of subtable */ 1.707 + ValueFormat valueFormat1; /* Defines the types of data in 1.708 + * ValueRecord1--for the first glyph 1.709 + * in the pair--may be zero (0) */ 1.710 + ValueFormat valueFormat2; /* Defines the types of data in 1.711 + * ValueRecord2--for the second glyph 1.712 + * in the pair--may be zero (0) */ 1.713 + OffsetArrayOf<PairSet> 1.714 + pairSet; /* Array of PairSet tables 1.715 + * ordered by Coverage Index */ 1.716 + public: 1.717 + DEFINE_SIZE_ARRAY (10, pairSet); 1.718 +}; 1.719 + 1.720 +struct PairPosFormat2 1.721 +{ 1.722 + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1.723 + { 1.724 + TRACE_COLLECT_GLYPHS (this); 1.725 + /* (this+coverage).add_coverage (c->input); // Don't need this. */ 1.726 + 1.727 + unsigned int count1 = class1Count; 1.728 + const ClassDef &klass1 = this+classDef1; 1.729 + for (unsigned int i = 0; i < count1; i++) 1.730 + klass1.add_class (c->input, i); 1.731 + 1.732 + unsigned int count2 = class2Count; 1.733 + const ClassDef &klass2 = this+classDef2; 1.734 + for (unsigned int i = 0; i < count2; i++) 1.735 + klass2.add_class (c->input, i); 1.736 + } 1.737 + 1.738 + inline const Coverage &get_coverage (void) const 1.739 + { 1.740 + return this+coverage; 1.741 + } 1.742 + 1.743 + inline bool apply (hb_apply_context_t *c) const 1.744 + { 1.745 + TRACE_APPLY (this); 1.746 + hb_buffer_t *buffer = c->buffer; 1.747 + hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1); 1.748 + if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); 1.749 + 1.750 + unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); 1.751 + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 1.752 + 1.753 + if (!skippy_iter.next ()) return TRACE_RETURN (false); 1.754 + 1.755 + unsigned int len1 = valueFormat1.get_len (); 1.756 + unsigned int len2 = valueFormat2.get_len (); 1.757 + unsigned int record_len = len1 + len2; 1.758 + 1.759 + unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint); 1.760 + unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint); 1.761 + if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return TRACE_RETURN (false); 1.762 + 1.763 + const Value *v = &values[record_len * (klass1 * class2Count + klass2)]; 1.764 + valueFormat1.apply_value (c->font, c->direction, this, 1.765 + v, buffer->cur_pos()); 1.766 + valueFormat2.apply_value (c->font, c->direction, this, 1.767 + v + len1, buffer->pos[skippy_iter.idx]); 1.768 + 1.769 + buffer->idx = skippy_iter.idx; 1.770 + if (len2) 1.771 + buffer->idx++; 1.772 + 1.773 + return TRACE_RETURN (true); 1.774 + } 1.775 + 1.776 + inline bool sanitize (hb_sanitize_context_t *c) { 1.777 + TRACE_SANITIZE (this); 1.778 + if (!(c->check_struct (this) 1.779 + && coverage.sanitize (c, this) 1.780 + && classDef1.sanitize (c, this) 1.781 + && classDef2.sanitize (c, this))) return TRACE_RETURN (false); 1.782 + 1.783 + unsigned int len1 = valueFormat1.get_len (); 1.784 + unsigned int len2 = valueFormat2.get_len (); 1.785 + unsigned int stride = len1 + len2; 1.786 + unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size (); 1.787 + unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count; 1.788 + return TRACE_RETURN (c->check_array (values, record_size, count) && 1.789 + valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) && 1.790 + valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride)); 1.791 + } 1.792 + 1.793 + protected: 1.794 + USHORT format; /* Format identifier--format = 2 */ 1.795 + OffsetTo<Coverage> 1.796 + coverage; /* Offset to Coverage table--from 1.797 + * beginning of subtable */ 1.798 + ValueFormat valueFormat1; /* ValueRecord definition--for the 1.799 + * first glyph of the pair--may be zero 1.800 + * (0) */ 1.801 + ValueFormat valueFormat2; /* ValueRecord definition--for the 1.802 + * second glyph of the pair--may be 1.803 + * zero (0) */ 1.804 + OffsetTo<ClassDef> 1.805 + classDef1; /* Offset to ClassDef table--from 1.806 + * beginning of PairPos subtable--for 1.807 + * the first glyph of the pair */ 1.808 + OffsetTo<ClassDef> 1.809 + classDef2; /* Offset to ClassDef table--from 1.810 + * beginning of PairPos subtable--for 1.811 + * the second glyph of the pair */ 1.812 + USHORT class1Count; /* Number of classes in ClassDef1 1.813 + * table--includes Class0 */ 1.814 + USHORT class2Count; /* Number of classes in ClassDef2 1.815 + * table--includes Class0 */ 1.816 + ValueRecord values; /* Matrix of value pairs: 1.817 + * class1-major, class2-minor, 1.818 + * Each entry has value1 and value2 */ 1.819 + public: 1.820 + DEFINE_SIZE_ARRAY (16, values); 1.821 +}; 1.822 + 1.823 +struct PairPos 1.824 +{ 1.825 + template <typename context_t> 1.826 + inline typename context_t::return_t dispatch (context_t *c) const 1.827 + { 1.828 + TRACE_DISPATCH (this); 1.829 + switch (u.format) { 1.830 + case 1: return TRACE_RETURN (c->dispatch (u.format1)); 1.831 + case 2: return TRACE_RETURN (c->dispatch (u.format2)); 1.832 + default:return TRACE_RETURN (c->default_return_value ()); 1.833 + } 1.834 + } 1.835 + 1.836 + inline bool sanitize (hb_sanitize_context_t *c) { 1.837 + TRACE_SANITIZE (this); 1.838 + if (!u.format.sanitize (c)) return TRACE_RETURN (false); 1.839 + switch (u.format) { 1.840 + case 1: return TRACE_RETURN (u.format1.sanitize (c)); 1.841 + case 2: return TRACE_RETURN (u.format2.sanitize (c)); 1.842 + default:return TRACE_RETURN (true); 1.843 + } 1.844 + } 1.845 + 1.846 + protected: 1.847 + union { 1.848 + USHORT format; /* Format identifier */ 1.849 + PairPosFormat1 format1; 1.850 + PairPosFormat2 format2; 1.851 + } u; 1.852 +}; 1.853 + 1.854 + 1.855 +struct EntryExitRecord 1.856 +{ 1.857 + friend struct CursivePosFormat1; 1.858 + 1.859 + inline bool sanitize (hb_sanitize_context_t *c, void *base) { 1.860 + TRACE_SANITIZE (this); 1.861 + return TRACE_RETURN (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base)); 1.862 + } 1.863 + 1.864 + protected: 1.865 + OffsetTo<Anchor> 1.866 + entryAnchor; /* Offset to EntryAnchor table--from 1.867 + * beginning of CursivePos 1.868 + * subtable--may be NULL */ 1.869 + OffsetTo<Anchor> 1.870 + exitAnchor; /* Offset to ExitAnchor table--from 1.871 + * beginning of CursivePos 1.872 + * subtable--may be NULL */ 1.873 + public: 1.874 + DEFINE_SIZE_STATIC (4); 1.875 +}; 1.876 + 1.877 +struct CursivePosFormat1 1.878 +{ 1.879 + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1.880 + { 1.881 + TRACE_COLLECT_GLYPHS (this); 1.882 + (this+coverage).add_coverage (c->input); 1.883 + } 1.884 + 1.885 + inline const Coverage &get_coverage (void) const 1.886 + { 1.887 + return this+coverage; 1.888 + } 1.889 + 1.890 + inline bool apply (hb_apply_context_t *c) const 1.891 + { 1.892 + TRACE_APPLY (this); 1.893 + hb_buffer_t *buffer = c->buffer; 1.894 + 1.895 + /* We don't handle mark glyphs here. */ 1.896 + if (unlikely (_hb_glyph_info_is_mark (&buffer->cur()))) return TRACE_RETURN (false); 1.897 + 1.898 + hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1); 1.899 + if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); 1.900 + 1.901 + const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)]; 1.902 + if (!this_record.exitAnchor) return TRACE_RETURN (false); 1.903 + 1.904 + if (!skippy_iter.next ()) return TRACE_RETURN (false); 1.905 + 1.906 + const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)]; 1.907 + if (!next_record.entryAnchor) return TRACE_RETURN (false); 1.908 + 1.909 + unsigned int i = buffer->idx; 1.910 + unsigned int j = skippy_iter.idx; 1.911 + 1.912 + hb_position_t entry_x, entry_y, exit_x, exit_y; 1.913 + (this+this_record.exitAnchor).get_anchor (c->font, buffer->info[i].codepoint, &exit_x, &exit_y); 1.914 + (this+next_record.entryAnchor).get_anchor (c->font, buffer->info[j].codepoint, &entry_x, &entry_y); 1.915 + 1.916 + hb_glyph_position_t *pos = buffer->pos; 1.917 + 1.918 + hb_position_t d; 1.919 + /* Main-direction adjustment */ 1.920 + switch (c->direction) { 1.921 + case HB_DIRECTION_LTR: 1.922 + pos[i].x_advance = exit_x + pos[i].x_offset; 1.923 + 1.924 + d = entry_x + pos[j].x_offset; 1.925 + pos[j].x_advance -= d; 1.926 + pos[j].x_offset -= d; 1.927 + break; 1.928 + case HB_DIRECTION_RTL: 1.929 + d = exit_x + pos[i].x_offset; 1.930 + pos[i].x_advance -= d; 1.931 + pos[i].x_offset -= d; 1.932 + 1.933 + pos[j].x_advance = entry_x + pos[j].x_offset; 1.934 + break; 1.935 + case HB_DIRECTION_TTB: 1.936 + pos[i].y_advance = exit_y + pos[i].y_offset; 1.937 + 1.938 + d = entry_y + pos[j].y_offset; 1.939 + pos[j].y_advance -= d; 1.940 + pos[j].y_offset -= d; 1.941 + break; 1.942 + case HB_DIRECTION_BTT: 1.943 + d = exit_y + pos[i].y_offset; 1.944 + pos[i].y_advance -= d; 1.945 + pos[i].y_offset -= d; 1.946 + 1.947 + pos[j].y_advance = entry_y; 1.948 + break; 1.949 + case HB_DIRECTION_INVALID: 1.950 + default: 1.951 + break; 1.952 + } 1.953 + 1.954 + /* Cross-direction adjustment */ 1.955 + if (c->lookup_props & LookupFlag::RightToLeft) { 1.956 + pos[i].cursive_chain() = j - i; 1.957 + if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction))) 1.958 + pos[i].y_offset = entry_y - exit_y; 1.959 + else 1.960 + pos[i].x_offset = entry_x - exit_x; 1.961 + } else { 1.962 + pos[j].cursive_chain() = i - j; 1.963 + if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction))) 1.964 + pos[j].y_offset = exit_y - entry_y; 1.965 + else 1.966 + pos[j].x_offset = exit_x - entry_x; 1.967 + } 1.968 + 1.969 + buffer->idx = j; 1.970 + return TRACE_RETURN (true); 1.971 + } 1.972 + 1.973 + inline bool sanitize (hb_sanitize_context_t *c) { 1.974 + TRACE_SANITIZE (this); 1.975 + return TRACE_RETURN (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this)); 1.976 + } 1.977 + 1.978 + protected: 1.979 + USHORT format; /* Format identifier--format = 1 */ 1.980 + OffsetTo<Coverage> 1.981 + coverage; /* Offset to Coverage table--from 1.982 + * beginning of subtable */ 1.983 + ArrayOf<EntryExitRecord> 1.984 + entryExitRecord; /* Array of EntryExit records--in 1.985 + * Coverage Index order */ 1.986 + public: 1.987 + DEFINE_SIZE_ARRAY (6, entryExitRecord); 1.988 +}; 1.989 + 1.990 +struct CursivePos 1.991 +{ 1.992 + template <typename context_t> 1.993 + inline typename context_t::return_t dispatch (context_t *c) const 1.994 + { 1.995 + TRACE_DISPATCH (this); 1.996 + switch (u.format) { 1.997 + case 1: return TRACE_RETURN (c->dispatch (u.format1)); 1.998 + default:return TRACE_RETURN (c->default_return_value ()); 1.999 + } 1.1000 + } 1.1001 + 1.1002 + inline bool sanitize (hb_sanitize_context_t *c) { 1.1003 + TRACE_SANITIZE (this); 1.1004 + if (!u.format.sanitize (c)) return TRACE_RETURN (false); 1.1005 + switch (u.format) { 1.1006 + case 1: return TRACE_RETURN (u.format1.sanitize (c)); 1.1007 + default:return TRACE_RETURN (true); 1.1008 + } 1.1009 + } 1.1010 + 1.1011 + protected: 1.1012 + union { 1.1013 + USHORT format; /* Format identifier */ 1.1014 + CursivePosFormat1 format1; 1.1015 + } u; 1.1016 +}; 1.1017 + 1.1018 + 1.1019 +typedef AnchorMatrix BaseArray; /* base-major-- 1.1020 + * in order of BaseCoverage Index--, 1.1021 + * mark-minor-- 1.1022 + * ordered by class--zero-based. */ 1.1023 + 1.1024 +struct MarkBasePosFormat1 1.1025 +{ 1.1026 + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1.1027 + { 1.1028 + TRACE_COLLECT_GLYPHS (this); 1.1029 + (this+markCoverage).add_coverage (c->input); 1.1030 + (this+baseCoverage).add_coverage (c->input); 1.1031 + } 1.1032 + 1.1033 + inline const Coverage &get_coverage (void) const 1.1034 + { 1.1035 + return this+markCoverage; 1.1036 + } 1.1037 + 1.1038 + inline bool apply (hb_apply_context_t *c) const 1.1039 + { 1.1040 + TRACE_APPLY (this); 1.1041 + hb_buffer_t *buffer = c->buffer; 1.1042 + unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint); 1.1043 + if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false); 1.1044 + 1.1045 + /* now we search backwards for a non-mark glyph */ 1.1046 + hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, buffer->idx, 1); 1.1047 + skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); 1.1048 + do { 1.1049 + if (!skippy_iter.prev ()) return TRACE_RETURN (false); 1.1050 + /* We only want to attach to the first of a MultipleSubst sequence. Reject others. */ 1.1051 + if (0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx])) break; 1.1052 + skippy_iter.reject (); 1.1053 + } while (1); 1.1054 + 1.1055 + /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */ 1.1056 + if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { /*return TRACE_RETURN (false);*/ } 1.1057 + 1.1058 + unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[skippy_iter.idx].codepoint); 1.1059 + if (base_index == NOT_COVERED) return TRACE_RETURN (false); 1.1060 + 1.1061 + return TRACE_RETURN ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx)); 1.1062 + } 1.1063 + 1.1064 + inline bool sanitize (hb_sanitize_context_t *c) { 1.1065 + TRACE_SANITIZE (this); 1.1066 + return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && baseCoverage.sanitize (c, this) && 1.1067 + markArray.sanitize (c, this) && baseArray.sanitize (c, this, (unsigned int) classCount)); 1.1068 + } 1.1069 + 1.1070 + protected: 1.1071 + USHORT format; /* Format identifier--format = 1 */ 1.1072 + OffsetTo<Coverage> 1.1073 + markCoverage; /* Offset to MarkCoverage table--from 1.1074 + * beginning of MarkBasePos subtable */ 1.1075 + OffsetTo<Coverage> 1.1076 + baseCoverage; /* Offset to BaseCoverage table--from 1.1077 + * beginning of MarkBasePos subtable */ 1.1078 + USHORT classCount; /* Number of classes defined for marks */ 1.1079 + OffsetTo<MarkArray> 1.1080 + markArray; /* Offset to MarkArray table--from 1.1081 + * beginning of MarkBasePos subtable */ 1.1082 + OffsetTo<BaseArray> 1.1083 + baseArray; /* Offset to BaseArray table--from 1.1084 + * beginning of MarkBasePos subtable */ 1.1085 + public: 1.1086 + DEFINE_SIZE_STATIC (12); 1.1087 +}; 1.1088 + 1.1089 +struct MarkBasePos 1.1090 +{ 1.1091 + template <typename context_t> 1.1092 + inline typename context_t::return_t dispatch (context_t *c) const 1.1093 + { 1.1094 + TRACE_DISPATCH (this); 1.1095 + switch (u.format) { 1.1096 + case 1: return TRACE_RETURN (c->dispatch (u.format1)); 1.1097 + default:return TRACE_RETURN (c->default_return_value ()); 1.1098 + } 1.1099 + } 1.1100 + 1.1101 + inline bool sanitize (hb_sanitize_context_t *c) { 1.1102 + TRACE_SANITIZE (this); 1.1103 + if (!u.format.sanitize (c)) return TRACE_RETURN (false); 1.1104 + switch (u.format) { 1.1105 + case 1: return TRACE_RETURN (u.format1.sanitize (c)); 1.1106 + default:return TRACE_RETURN (true); 1.1107 + } 1.1108 + } 1.1109 + 1.1110 + protected: 1.1111 + union { 1.1112 + USHORT format; /* Format identifier */ 1.1113 + MarkBasePosFormat1 format1; 1.1114 + } u; 1.1115 +}; 1.1116 + 1.1117 + 1.1118 +typedef AnchorMatrix LigatureAttach; /* component-major-- 1.1119 + * in order of writing direction--, 1.1120 + * mark-minor-- 1.1121 + * ordered by class--zero-based. */ 1.1122 + 1.1123 +typedef OffsetListOf<LigatureAttach> LigatureArray; 1.1124 + /* Array of LigatureAttach 1.1125 + * tables ordered by 1.1126 + * LigatureCoverage Index */ 1.1127 + 1.1128 +struct MarkLigPosFormat1 1.1129 +{ 1.1130 + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1.1131 + { 1.1132 + TRACE_COLLECT_GLYPHS (this); 1.1133 + (this+markCoverage).add_coverage (c->input); 1.1134 + (this+ligatureCoverage).add_coverage (c->input); 1.1135 + } 1.1136 + 1.1137 + inline const Coverage &get_coverage (void) const 1.1138 + { 1.1139 + return this+markCoverage; 1.1140 + } 1.1141 + 1.1142 + inline bool apply (hb_apply_context_t *c) const 1.1143 + { 1.1144 + TRACE_APPLY (this); 1.1145 + hb_buffer_t *buffer = c->buffer; 1.1146 + unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint); 1.1147 + if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false); 1.1148 + 1.1149 + /* now we search backwards for a non-mark glyph */ 1.1150 + hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, buffer->idx, 1); 1.1151 + skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); 1.1152 + if (!skippy_iter.prev ()) return TRACE_RETURN (false); 1.1153 + 1.1154 + /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */ 1.1155 + if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { /*return TRACE_RETURN (false);*/ } 1.1156 + 1.1157 + unsigned int j = skippy_iter.idx; 1.1158 + unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[j].codepoint); 1.1159 + if (lig_index == NOT_COVERED) return TRACE_RETURN (false); 1.1160 + 1.1161 + const LigatureArray& lig_array = this+ligatureArray; 1.1162 + const LigatureAttach& lig_attach = lig_array[lig_index]; 1.1163 + 1.1164 + /* Find component to attach to */ 1.1165 + unsigned int comp_count = lig_attach.rows; 1.1166 + if (unlikely (!comp_count)) return TRACE_RETURN (false); 1.1167 + 1.1168 + /* We must now check whether the ligature ID of the current mark glyph 1.1169 + * is identical to the ligature ID of the found ligature. If yes, we 1.1170 + * can directly use the component index. If not, we attach the mark 1.1171 + * glyph to the last component of the ligature. */ 1.1172 + unsigned int comp_index; 1.1173 + unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]); 1.1174 + unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur()); 1.1175 + unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur()); 1.1176 + if (lig_id && lig_id == mark_id && mark_comp > 0) 1.1177 + comp_index = MIN (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1; 1.1178 + else 1.1179 + comp_index = comp_count - 1; 1.1180 + 1.1181 + return TRACE_RETURN ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j)); 1.1182 + } 1.1183 + 1.1184 + inline bool sanitize (hb_sanitize_context_t *c) { 1.1185 + TRACE_SANITIZE (this); 1.1186 + return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && ligatureCoverage.sanitize (c, this) && 1.1187 + markArray.sanitize (c, this) && ligatureArray.sanitize (c, this, (unsigned int) classCount)); 1.1188 + } 1.1189 + 1.1190 + protected: 1.1191 + USHORT format; /* Format identifier--format = 1 */ 1.1192 + OffsetTo<Coverage> 1.1193 + markCoverage; /* Offset to Mark Coverage table--from 1.1194 + * beginning of MarkLigPos subtable */ 1.1195 + OffsetTo<Coverage> 1.1196 + ligatureCoverage; /* Offset to Ligature Coverage 1.1197 + * table--from beginning of MarkLigPos 1.1198 + * subtable */ 1.1199 + USHORT classCount; /* Number of defined mark classes */ 1.1200 + OffsetTo<MarkArray> 1.1201 + markArray; /* Offset to MarkArray table--from 1.1202 + * beginning of MarkLigPos subtable */ 1.1203 + OffsetTo<LigatureArray> 1.1204 + ligatureArray; /* Offset to LigatureArray table--from 1.1205 + * beginning of MarkLigPos subtable */ 1.1206 + public: 1.1207 + DEFINE_SIZE_STATIC (12); 1.1208 +}; 1.1209 + 1.1210 +struct MarkLigPos 1.1211 +{ 1.1212 + template <typename context_t> 1.1213 + inline typename context_t::return_t dispatch (context_t *c) const 1.1214 + { 1.1215 + TRACE_DISPATCH (this); 1.1216 + switch (u.format) { 1.1217 + case 1: return TRACE_RETURN (c->dispatch (u.format1)); 1.1218 + default:return TRACE_RETURN (c->default_return_value ()); 1.1219 + } 1.1220 + } 1.1221 + 1.1222 + inline bool sanitize (hb_sanitize_context_t *c) { 1.1223 + TRACE_SANITIZE (this); 1.1224 + if (!u.format.sanitize (c)) return TRACE_RETURN (false); 1.1225 + switch (u.format) { 1.1226 + case 1: return TRACE_RETURN (u.format1.sanitize (c)); 1.1227 + default:return TRACE_RETURN (true); 1.1228 + } 1.1229 + } 1.1230 + 1.1231 + protected: 1.1232 + union { 1.1233 + USHORT format; /* Format identifier */ 1.1234 + MarkLigPosFormat1 format1; 1.1235 + } u; 1.1236 +}; 1.1237 + 1.1238 + 1.1239 +typedef AnchorMatrix Mark2Array; /* mark2-major-- 1.1240 + * in order of Mark2Coverage Index--, 1.1241 + * mark1-minor-- 1.1242 + * ordered by class--zero-based. */ 1.1243 + 1.1244 +struct MarkMarkPosFormat1 1.1245 +{ 1.1246 + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1.1247 + { 1.1248 + TRACE_COLLECT_GLYPHS (this); 1.1249 + (this+mark1Coverage).add_coverage (c->input); 1.1250 + (this+mark2Coverage).add_coverage (c->input); 1.1251 + } 1.1252 + 1.1253 + inline const Coverage &get_coverage (void) const 1.1254 + { 1.1255 + return this+mark1Coverage; 1.1256 + } 1.1257 + 1.1258 + inline bool apply (hb_apply_context_t *c) const 1.1259 + { 1.1260 + TRACE_APPLY (this); 1.1261 + hb_buffer_t *buffer = c->buffer; 1.1262 + unsigned int mark1_index = (this+mark1Coverage).get_coverage (buffer->cur().codepoint); 1.1263 + if (likely (mark1_index == NOT_COVERED)) return TRACE_RETURN (false); 1.1264 + 1.1265 + /* now we search backwards for a suitable mark glyph until a non-mark glyph */ 1.1266 + hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, buffer->idx, 1); 1.1267 + skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags); 1.1268 + if (!skippy_iter.prev ()) return TRACE_RETURN (false); 1.1269 + 1.1270 + if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return TRACE_RETURN (false); } 1.1271 + 1.1272 + unsigned int j = skippy_iter.idx; 1.1273 + 1.1274 + unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur()); 1.1275 + unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]); 1.1276 + unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur()); 1.1277 + unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]); 1.1278 + 1.1279 + if (likely (id1 == id2)) { 1.1280 + if (id1 == 0) /* Marks belonging to the same base. */ 1.1281 + goto good; 1.1282 + else if (comp1 == comp2) /* Marks belonging to the same ligature component. */ 1.1283 + goto good; 1.1284 + } else { 1.1285 + /* If ligature ids don't match, it may be the case that one of the marks 1.1286 + * itself is a ligature. In which case match. */ 1.1287 + if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2)) 1.1288 + goto good; 1.1289 + } 1.1290 + 1.1291 + /* Didn't match. */ 1.1292 + return TRACE_RETURN (false); 1.1293 + 1.1294 + good: 1.1295 + unsigned int mark2_index = (this+mark2Coverage).get_coverage (buffer->info[j].codepoint); 1.1296 + if (mark2_index == NOT_COVERED) return TRACE_RETURN (false); 1.1297 + 1.1298 + return TRACE_RETURN ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j)); 1.1299 + } 1.1300 + 1.1301 + inline bool sanitize (hb_sanitize_context_t *c) { 1.1302 + TRACE_SANITIZE (this); 1.1303 + return TRACE_RETURN (c->check_struct (this) && mark1Coverage.sanitize (c, this) && 1.1304 + mark2Coverage.sanitize (c, this) && mark1Array.sanitize (c, this) 1.1305 + && mark2Array.sanitize (c, this, (unsigned int) classCount)); 1.1306 + } 1.1307 + 1.1308 + protected: 1.1309 + USHORT format; /* Format identifier--format = 1 */ 1.1310 + OffsetTo<Coverage> 1.1311 + mark1Coverage; /* Offset to Combining Mark1 Coverage 1.1312 + * table--from beginning of MarkMarkPos 1.1313 + * subtable */ 1.1314 + OffsetTo<Coverage> 1.1315 + mark2Coverage; /* Offset to Combining Mark2 Coverage 1.1316 + * table--from beginning of MarkMarkPos 1.1317 + * subtable */ 1.1318 + USHORT classCount; /* Number of defined mark classes */ 1.1319 + OffsetTo<MarkArray> 1.1320 + mark1Array; /* Offset to Mark1Array table--from 1.1321 + * beginning of MarkMarkPos subtable */ 1.1322 + OffsetTo<Mark2Array> 1.1323 + mark2Array; /* Offset to Mark2Array table--from 1.1324 + * beginning of MarkMarkPos subtable */ 1.1325 + public: 1.1326 + DEFINE_SIZE_STATIC (12); 1.1327 +}; 1.1328 + 1.1329 +struct MarkMarkPos 1.1330 +{ 1.1331 + template <typename context_t> 1.1332 + inline typename context_t::return_t dispatch (context_t *c) const 1.1333 + { 1.1334 + TRACE_DISPATCH (this); 1.1335 + switch (u.format) { 1.1336 + case 1: return TRACE_RETURN (c->dispatch (u.format1)); 1.1337 + default:return TRACE_RETURN (c->default_return_value ()); 1.1338 + } 1.1339 + } 1.1340 + 1.1341 + inline bool sanitize (hb_sanitize_context_t *c) { 1.1342 + TRACE_SANITIZE (this); 1.1343 + if (!u.format.sanitize (c)) return TRACE_RETURN (false); 1.1344 + switch (u.format) { 1.1345 + case 1: return TRACE_RETURN (u.format1.sanitize (c)); 1.1346 + default:return TRACE_RETURN (true); 1.1347 + } 1.1348 + } 1.1349 + 1.1350 + protected: 1.1351 + union { 1.1352 + USHORT format; /* Format identifier */ 1.1353 + MarkMarkPosFormat1 format1; 1.1354 + } u; 1.1355 +}; 1.1356 + 1.1357 + 1.1358 +struct ContextPos : Context {}; 1.1359 + 1.1360 +struct ChainContextPos : ChainContext {}; 1.1361 + 1.1362 +struct ExtensionPos : Extension<ExtensionPos> 1.1363 +{ 1.1364 + typedef struct PosLookupSubTable LookupSubTable; 1.1365 +}; 1.1366 + 1.1367 + 1.1368 + 1.1369 +/* 1.1370 + * PosLookup 1.1371 + */ 1.1372 + 1.1373 + 1.1374 +struct PosLookupSubTable 1.1375 +{ 1.1376 + friend struct PosLookup; 1.1377 + 1.1378 + enum Type { 1.1379 + Single = 1, 1.1380 + Pair = 2, 1.1381 + Cursive = 3, 1.1382 + MarkBase = 4, 1.1383 + MarkLig = 5, 1.1384 + MarkMark = 6, 1.1385 + Context = 7, 1.1386 + ChainContext = 8, 1.1387 + Extension = 9 1.1388 + }; 1.1389 + 1.1390 + template <typename context_t> 1.1391 + inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const 1.1392 + { 1.1393 + TRACE_DISPATCH (this); 1.1394 + switch (lookup_type) { 1.1395 + case Single: return TRACE_RETURN (u.single.dispatch (c)); 1.1396 + case Pair: return TRACE_RETURN (u.pair.dispatch (c)); 1.1397 + case Cursive: return TRACE_RETURN (u.cursive.dispatch (c)); 1.1398 + case MarkBase: return TRACE_RETURN (u.markBase.dispatch (c)); 1.1399 + case MarkLig: return TRACE_RETURN (u.markLig.dispatch (c)); 1.1400 + case MarkMark: return TRACE_RETURN (u.markMark.dispatch (c)); 1.1401 + case Context: return TRACE_RETURN (u.context.dispatch (c)); 1.1402 + case ChainContext: return TRACE_RETURN (u.chainContext.dispatch (c)); 1.1403 + case Extension: return TRACE_RETURN (u.extension.dispatch (c)); 1.1404 + default: return TRACE_RETURN (c->default_return_value ()); 1.1405 + } 1.1406 + } 1.1407 + 1.1408 + inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) { 1.1409 + TRACE_SANITIZE (this); 1.1410 + if (!u.header.sub_format.sanitize (c)) 1.1411 + return TRACE_RETURN (false); 1.1412 + switch (lookup_type) { 1.1413 + case Single: return TRACE_RETURN (u.single.sanitize (c)); 1.1414 + case Pair: return TRACE_RETURN (u.pair.sanitize (c)); 1.1415 + case Cursive: return TRACE_RETURN (u.cursive.sanitize (c)); 1.1416 + case MarkBase: return TRACE_RETURN (u.markBase.sanitize (c)); 1.1417 + case MarkLig: return TRACE_RETURN (u.markLig.sanitize (c)); 1.1418 + case MarkMark: return TRACE_RETURN (u.markMark.sanitize (c)); 1.1419 + case Context: return TRACE_RETURN (u.context.sanitize (c)); 1.1420 + case ChainContext: return TRACE_RETURN (u.chainContext.sanitize (c)); 1.1421 + case Extension: return TRACE_RETURN (u.extension.sanitize (c)); 1.1422 + default: return TRACE_RETURN (true); 1.1423 + } 1.1424 + } 1.1425 + 1.1426 + protected: 1.1427 + union { 1.1428 + struct { 1.1429 + USHORT sub_format; 1.1430 + } header; 1.1431 + SinglePos single; 1.1432 + PairPos pair; 1.1433 + CursivePos cursive; 1.1434 + MarkBasePos markBase; 1.1435 + MarkLigPos markLig; 1.1436 + MarkMarkPos markMark; 1.1437 + ContextPos context; 1.1438 + ChainContextPos chainContext; 1.1439 + ExtensionPos extension; 1.1440 + } u; 1.1441 + public: 1.1442 + DEFINE_SIZE_UNION (2, header.sub_format); 1.1443 +}; 1.1444 + 1.1445 + 1.1446 +struct PosLookup : Lookup 1.1447 +{ 1.1448 + inline const PosLookupSubTable& get_subtable (unsigned int i) const 1.1449 + { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; } 1.1450 + 1.1451 + inline bool is_reverse (void) const 1.1452 + { 1.1453 + return false; 1.1454 + } 1.1455 + 1.1456 + inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const 1.1457 + { 1.1458 + TRACE_COLLECT_GLYPHS (this); 1.1459 + c->set_recurse_func (NULL); 1.1460 + return TRACE_RETURN (dispatch (c)); 1.1461 + } 1.1462 + 1.1463 + template <typename set_t> 1.1464 + inline void add_coverage (set_t *glyphs) const 1.1465 + { 1.1466 + hb_get_coverage_context_t c; 1.1467 + const Coverage *last = NULL; 1.1468 + unsigned int count = get_subtable_count (); 1.1469 + for (unsigned int i = 0; i < count; i++) { 1.1470 + const Coverage *coverage = &get_subtable (i).dispatch (&c, get_type ()); 1.1471 + if (coverage != last) { 1.1472 + coverage->add_coverage (glyphs); 1.1473 + last = coverage; 1.1474 + } 1.1475 + } 1.1476 + } 1.1477 + 1.1478 + inline bool apply_once (hb_apply_context_t *c) const 1.1479 + { 1.1480 + TRACE_APPLY (this); 1.1481 + if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props)) 1.1482 + return TRACE_RETURN (false); 1.1483 + return TRACE_RETURN (dispatch (c)); 1.1484 + } 1.1485 + 1.1486 + static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index); 1.1487 + 1.1488 + template <typename context_t> 1.1489 + static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index); 1.1490 + 1.1491 + template <typename context_t> 1.1492 + inline typename context_t::return_t dispatch (context_t *c) const 1.1493 + { 1.1494 + TRACE_DISPATCH (this); 1.1495 + unsigned int lookup_type = get_type (); 1.1496 + unsigned int count = get_subtable_count (); 1.1497 + for (unsigned int i = 0; i < count; i++) { 1.1498 + typename context_t::return_t r = get_subtable (i).dispatch (c, lookup_type); 1.1499 + if (c->stop_sublookup_iteration (r)) 1.1500 + return TRACE_RETURN (r); 1.1501 + } 1.1502 + return TRACE_RETURN (c->default_return_value ()); 1.1503 + } 1.1504 + 1.1505 + inline bool sanitize (hb_sanitize_context_t *c) { 1.1506 + TRACE_SANITIZE (this); 1.1507 + if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false); 1.1508 + OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable); 1.1509 + return TRACE_RETURN (list.sanitize (c, this, get_type ())); 1.1510 + } 1.1511 +}; 1.1512 + 1.1513 +typedef OffsetListOf<PosLookup> PosLookupList; 1.1514 + 1.1515 +/* 1.1516 + * GPOS -- The Glyph Positioning Table 1.1517 + */ 1.1518 + 1.1519 +struct GPOS : GSUBGPOS 1.1520 +{ 1.1521 + static const hb_tag_t tableTag = HB_OT_TAG_GPOS; 1.1522 + 1.1523 + inline const PosLookup& get_lookup (unsigned int i) const 1.1524 + { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); } 1.1525 + 1.1526 + static inline void position_start (hb_font_t *font, hb_buffer_t *buffer); 1.1527 + static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer); 1.1528 + 1.1529 + inline bool sanitize (hb_sanitize_context_t *c) { 1.1530 + TRACE_SANITIZE (this); 1.1531 + if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false); 1.1532 + OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList); 1.1533 + return TRACE_RETURN (list.sanitize (c, this)); 1.1534 + } 1.1535 + public: 1.1536 + DEFINE_SIZE_STATIC (10); 1.1537 +}; 1.1538 + 1.1539 + 1.1540 +static void 1.1541 +fix_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction) 1.1542 +{ 1.1543 + unsigned int j = pos[i].cursive_chain(); 1.1544 + if (likely (!j)) 1.1545 + return; 1.1546 + 1.1547 + j += i; 1.1548 + 1.1549 + pos[i].cursive_chain() = 0; 1.1550 + 1.1551 + fix_cursive_minor_offset (pos, j, direction); 1.1552 + 1.1553 + if (HB_DIRECTION_IS_HORIZONTAL (direction)) 1.1554 + pos[i].y_offset += pos[j].y_offset; 1.1555 + else 1.1556 + pos[i].x_offset += pos[j].x_offset; 1.1557 +} 1.1558 + 1.1559 +static void 1.1560 +fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction) 1.1561 +{ 1.1562 + if (likely (!(pos[i].attach_lookback()))) 1.1563 + return; 1.1564 + 1.1565 + unsigned int j = i - pos[i].attach_lookback(); 1.1566 + 1.1567 + pos[i].x_offset += pos[j].x_offset; 1.1568 + pos[i].y_offset += pos[j].y_offset; 1.1569 + 1.1570 + if (HB_DIRECTION_IS_FORWARD (direction)) 1.1571 + for (unsigned int k = j; k < i; k++) { 1.1572 + pos[i].x_offset -= pos[k].x_advance; 1.1573 + pos[i].y_offset -= pos[k].y_advance; 1.1574 + } 1.1575 + else 1.1576 + for (unsigned int k = j + 1; k < i + 1; k++) { 1.1577 + pos[i].x_offset += pos[k].x_advance; 1.1578 + pos[i].y_offset += pos[k].y_advance; 1.1579 + } 1.1580 +} 1.1581 + 1.1582 +void 1.1583 +GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) 1.1584 +{ 1.1585 + buffer->clear_positions (); 1.1586 + 1.1587 + unsigned int count = buffer->len; 1.1588 + for (unsigned int i = 0; i < count; i++) 1.1589 + buffer->pos[i].attach_lookback() = buffer->pos[i].cursive_chain() = 0; 1.1590 +} 1.1591 + 1.1592 +void 1.1593 +GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) 1.1594 +{ 1.1595 + unsigned int len; 1.1596 + hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len); 1.1597 + hb_direction_t direction = buffer->props.direction; 1.1598 + 1.1599 + /* Handle cursive connections */ 1.1600 + for (unsigned int i = 0; i < len; i++) 1.1601 + fix_cursive_minor_offset (pos, i, direction); 1.1602 + 1.1603 + /* Handle attachments */ 1.1604 + for (unsigned int i = 0; i < len; i++) 1.1605 + fix_mark_attachment (pos, i, direction); 1.1606 + 1.1607 + _hb_buffer_deallocate_gsubgpos_vars (buffer); 1.1608 +} 1.1609 + 1.1610 + 1.1611 +/* Out-of-class implementation for methods recursing */ 1.1612 + 1.1613 +template <typename context_t> 1.1614 +inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index) 1.1615 +{ 1.1616 + const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos); 1.1617 + const PosLookup &l = gpos.get_lookup (lookup_index); 1.1618 + return l.dispatch (c); 1.1619 +} 1.1620 + 1.1621 +inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index) 1.1622 +{ 1.1623 + const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos); 1.1624 + const PosLookup &l = gpos.get_lookup (lookup_index); 1.1625 + unsigned int saved_lookup_props = c->lookup_props; 1.1626 + c->set_lookup (l); 1.1627 + bool ret = l.apply_once (c); 1.1628 + c->lookup_props = saved_lookup_props; 1.1629 + return ret; 1.1630 +} 1.1631 + 1.1632 + 1.1633 +#undef attach_lookback 1.1634 +#undef cursive_chain 1.1635 + 1.1636 + 1.1637 +} /* namespace OT */ 1.1638 + 1.1639 + 1.1640 +#endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */