OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2007,2008,2009,2010 Red Hat, Inc. | |
3 * Copyright (C) 2010 Google, Inc. | |
4 * | |
5 * This is part of HarfBuzz, a text shaping library. | |
6 * | |
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 | |
26 * Google Author(s): Behdad Esfahbod | |
27 */ | |
28 | |
29 #ifndef HB_OT_LAYOUT_GPOS_PRIVATE_HH | |
30 #define HB_OT_LAYOUT_GPOS_PRIVATE_HH | |
31 | |
32 #include "hb-ot-layout-gsubgpos-private.hh" | |
33 | |
34 HB_BEGIN_DECLS | |
35 | |
36 | |
37 /* buffer var allocations */ | |
38 #define attach_lookback() var.u16[0] /* number of glyphs to go back to attach th
is glyph to its base */ | |
39 #define cursive_chain() var.i16[1] /* character to which this connects, may be p
ositive or negative */ | |
40 | |
41 | |
42 /* Shared Tables: ValueRecord, Anchor Table, and MarkArray */ | |
43 | |
44 typedef USHORT Value; | |
45 | |
46 typedef Value ValueRecord[VAR]; | |
47 | |
48 struct ValueFormat : USHORT | |
49 { | |
50 enum | |
51 { | |
52 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 placemen
t */ | |
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 */ | |
60 ignored = 0x0F00, /* Was used in TrueType Open for MM fonts */ | |
61 reserved = 0xF000, /* For future use */ | |
62 | |
63 devices = 0x00F0 /* Mask for having any Device table */ | |
64 }; | |
65 | |
66 /* All fields are options. Only those available advance the value pointer. */ | |
67 #if 0 | |
68 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) */ | |
90 #endif | |
91 | |
92 inline unsigned int get_len (void) const | |
93 { return _hb_popcount32 ((unsigned int) *this); } | |
94 inline unsigned int get_size (void) const | |
95 { return get_len () * Value::static_size; } | |
96 | |
97 void apply_value (hb_ot_layout_context_t *layout, | |
98 const void *base, | |
99 const Value *values, | |
100 hb_glyph_position_t &glyph_pos) const | |
101 { | |
102 unsigned int x_ppem, y_ppem; | |
103 unsigned int format = *this; | |
104 | |
105 if (!format) return; | |
106 | |
107 /* design units -> fractional pixel */ | |
108 if (format & xPlacement) glyph_pos.x_offset += layout->scale_x (get_short (
values++)); | |
109 if (format & yPlacement) glyph_pos.y_offset += layout->scale_y (get_short (
values++)); | |
110 if (format & xAdvance) glyph_pos.x_advance += layout->scale_x (get_short (
values++)); | |
111 if (format & yAdvance) glyph_pos.y_advance += layout->scale_y (get_short (
values++)); | |
112 | |
113 if (!has_device ()) return; | |
114 | |
115 x_ppem = layout->font->x_ppem; | |
116 y_ppem = layout->font->y_ppem; | |
117 | |
118 if (!x_ppem && !y_ppem) return; | |
119 | |
120 /* pixel -> fractional pixel */ | |
121 if (format & xPlaDevice) { | |
122 if (x_ppem) glyph_pos.x_offset += (base + get_device (values++)).get_x_de
lta (layout); else values++; | |
123 } | |
124 if (format & yPlaDevice) { | |
125 if (y_ppem) glyph_pos.y_offset += (base + get_device (values++)).get_y_de
lta (layout); else values++; | |
126 } | |
127 if (format & xAdvDevice) { | |
128 if (x_ppem) glyph_pos.x_advance += (base + get_device (values++)).get_x_de
lta (layout); else values++; | |
129 } | |
130 if (format & yAdvDevice) { | |
131 if (y_ppem) glyph_pos.y_advance += (base + get_device (values++)).get_y_de
lta (layout); else values++; | |
132 } | |
133 } | |
134 | |
135 private: | |
136 inline bool sanitize_value_devices (hb_sanitize_context_t *c, void *base, Valu
e *values) { | |
137 unsigned int format = *this; | |
138 | |
139 if (format & xPlacement) values++; | |
140 if (format & yPlacement) values++; | |
141 if (format & xAdvance) values++; | |
142 if (format & yAdvance) values++; | |
143 | |
144 if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) retu
rn false; | |
145 if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) retu
rn false; | |
146 if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) retu
rn false; | |
147 if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) retu
rn false; | |
148 | |
149 return true; | |
150 } | |
151 | |
152 static inline OffsetTo<Device>& get_device (Value* value) | |
153 { return *CastP<OffsetTo<Device> > (value); } | |
154 static inline const OffsetTo<Device>& get_device (const Value* value) | |
155 { return *CastP<OffsetTo<Device> > (value); } | |
156 | |
157 static inline const SHORT& get_short (const Value* value) | |
158 { return *CastP<SHORT> (value); } | |
159 | |
160 public: | |
161 | |
162 inline bool has_device (void) const { | |
163 unsigned int format = *this; | |
164 return (format & devices) != 0; | |
165 } | |
166 | |
167 inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *value
s) { | |
168 TRACE_SANITIZE (); | |
169 return c->check_range (values, get_size ()) | |
170 && (!has_device () || sanitize_value_devices (c, base, values)); | |
171 } | |
172 | |
173 inline bool sanitize_values (hb_sanitize_context_t *c, void *base, Value *valu
es, unsigned int count) { | |
174 TRACE_SANITIZE (); | |
175 unsigned int len = get_len (); | |
176 | |
177 if (!c->check_array (values, get_size (), count)) return false; | |
178 | |
179 if (!has_device ()) return true; | |
180 | |
181 for (unsigned int i = 0; i < count; i++) { | |
182 if (!sanitize_value_devices (c, base, values)) | |
183 return false; | |
184 values += len; | |
185 } | |
186 | |
187 return true; | |
188 } | |
189 | |
190 /* Just sanitize referenced Device tables. Doesn't check the values themselve
s. */ | |
191 inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, void *bas
e, Value *values, unsigned int count, unsigned int stride) { | |
192 TRACE_SANITIZE (); | |
193 | |
194 if (!has_device ()) return true; | |
195 | |
196 for (unsigned int i = 0; i < count; i++) { | |
197 if (!sanitize_value_devices (c, base, values)) | |
198 return false; | |
199 values += stride; | |
200 } | |
201 | |
202 return true; | |
203 } | |
204 }; | |
205 | |
206 | |
207 struct AnchorFormat1 | |
208 { | |
209 friend struct Anchor; | |
210 | |
211 private: | |
212 inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_i
d HB_UNUSED, | |
213 hb_position_t *x, hb_position_t *y) const | |
214 { | |
215 *x = layout->scale_x (xCoordinate); | |
216 *y = layout->scale_y (yCoordinate); | |
217 } | |
218 | |
219 inline bool sanitize (hb_sanitize_context_t *c) { | |
220 TRACE_SANITIZE (); | |
221 return c->check_struct (this); | |
222 } | |
223 | |
224 private: | |
225 USHORT format; /* Format identifier--format = 1 */ | |
226 SHORT xCoordinate; /* Horizontal value--in design units */ | |
227 SHORT yCoordinate; /* Vertical value--in design units */ | |
228 public: | |
229 DEFINE_SIZE_STATIC (6); | |
230 }; | |
231 | |
232 struct AnchorFormat2 | |
233 { | |
234 friend struct Anchor; | |
235 | |
236 private: | |
237 inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_i
d, | |
238 hb_position_t *x, hb_position_t *y) const | |
239 { | |
240 unsigned int x_ppem = layout->font->x_ppem; | |
241 unsigned int y_ppem = layout->font->y_ppem; | |
242 hb_position_t cx, cy; | |
243 hb_bool_t ret = false; | |
244 | |
245 if (x_ppem || y_ppem) | |
246 ret = hb_font_get_contour_point (layout->font, layout->face, anchorPoint
, glyph_id, &cx, &cy); | |
247 *x = x_ppem && ret ? cx : layout->scale_x (xCoordinate); | |
248 *y = y_ppem && ret ? cy : layout->scale_y (yCoordinate); | |
249 } | |
250 | |
251 inline bool sanitize (hb_sanitize_context_t *c) { | |
252 TRACE_SANITIZE (); | |
253 return c->check_struct (this); | |
254 } | |
255 | |
256 private: | |
257 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 */ | |
261 public: | |
262 DEFINE_SIZE_STATIC (8); | |
263 }; | |
264 | |
265 struct AnchorFormat3 | |
266 { | |
267 friend struct Anchor; | |
268 | |
269 private: | |
270 inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_i
d HB_UNUSED, | |
271 hb_position_t *x, hb_position_t *y) const | |
272 { | |
273 *x = layout->scale_x (xCoordinate); | |
274 *y = layout->scale_y (yCoordinate); | |
275 | |
276 /* pixel -> fractional pixel */ | |
277 if (layout->font->x_ppem) | |
278 *x += (this+xDeviceTable).get_x_delta (layout); | |
279 if (layout->font->y_ppem) | |
280 *y += (this+yDeviceTable).get_x_delta (layout); | |
281 } | |
282 | |
283 inline bool sanitize (hb_sanitize_context_t *c) { | |
284 TRACE_SANITIZE (); | |
285 return c->check_struct (this) | |
286 && xDeviceTable.sanitize (c, this) | |
287 && yDeviceTable.sanitize (c, this); | |
288 } | |
289 | |
290 private: | |
291 USHORT format; /* Format identifier--format = 3 */ | |
292 SHORT xCoordinate; /* Horizontal value--in design units */ | |
293 SHORT yCoordinate; /* Vertical value--in design units */ | |
294 OffsetTo<Device> | |
295 xDeviceTable; /* Offset to Device table for X | |
296 * coordinate-- from beginning of | |
297 * Anchor table (may be NULL) */ | |
298 OffsetTo<Device> | |
299 yDeviceTable; /* Offset to Device table for Y | |
300 * coordinate-- from beginning of | |
301 * Anchor table (may be NULL) */ | |
302 public: | |
303 DEFINE_SIZE_STATIC (10); | |
304 }; | |
305 | |
306 struct Anchor | |
307 { | |
308 inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_i
d, | |
309 hb_position_t *x, hb_position_t *y) const | |
310 { | |
311 *x = *y = 0; | |
312 switch (u.format) { | |
313 case 1: u.format1.get_anchor (layout, glyph_id, x, y); return; | |
314 case 2: u.format2.get_anchor (layout, glyph_id, x, y); return; | |
315 case 3: u.format3.get_anchor (layout, glyph_id, x, y); return; | |
316 default: return; | |
317 } | |
318 } | |
319 | |
320 inline bool sanitize (hb_sanitize_context_t *c) { | |
321 TRACE_SANITIZE (); | |
322 if (!u.format.sanitize (c)) return false; | |
323 switch (u.format) { | |
324 case 1: return u.format1.sanitize (c); | |
325 case 2: return u.format2.sanitize (c); | |
326 case 3: return u.format3.sanitize (c); | |
327 default:return true; | |
328 } | |
329 } | |
330 | |
331 private: | |
332 union { | |
333 USHORT format; /* Format identifier */ | |
334 AnchorFormat1 format1; | |
335 AnchorFormat2 format2; | |
336 AnchorFormat3 format3; | |
337 } u; | |
338 public: | |
339 DEFINE_SIZE_UNION (2, format); | |
340 }; | |
341 | |
342 | |
343 struct AnchorMatrix | |
344 { | |
345 inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned
int cols) const { | |
346 if (unlikely (row >= rows || col >= cols)) return Null(Anchor); | |
347 return this+matrix[row * cols + col]; | |
348 } | |
349 | |
350 inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) { | |
351 TRACE_SANITIZE (); | |
352 if (!c->check_struct (this)) return false; | |
353 if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return false; | |
354 unsigned int count = rows * cols; | |
355 if (!c->check_array (matrix, matrix[0].static_size, count)) return false; | |
356 for (unsigned int i = 0; i < count; i++) | |
357 if (!matrix[i].sanitize (c, this)) return false; | |
358 return true; | |
359 } | |
360 | |
361 USHORT rows; /* Number of rows */ | |
362 private: | |
363 OffsetTo<Anchor> | |
364 matrix[VAR]; /* Matrix of offsets to Anchor tables-- | |
365 * from beginning of AnchorMatrix table
*/ | |
366 public: | |
367 DEFINE_SIZE_ARRAY (2, matrix); | |
368 }; | |
369 | |
370 | |
371 struct MarkRecord | |
372 { | |
373 friend struct MarkArray; | |
374 | |
375 inline bool sanitize (hb_sanitize_context_t *c, void *base) { | |
376 TRACE_SANITIZE (); | |
377 return c->check_struct (this) | |
378 && markAnchor.sanitize (c, base); | |
379 } | |
380 | |
381 private: | |
382 USHORT klass; /* Class defined for this mark */ | |
383 OffsetTo<Anchor> | |
384 markAnchor; /* Offset to Anchor table--from | |
385 * beginning of MarkArray table */ | |
386 public: | |
387 DEFINE_SIZE_STATIC (4); | |
388 }; | |
389 | |
390 struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage ord
er */ | |
391 { | |
392 inline bool apply (hb_apply_context_t *c, | |
393 unsigned int mark_index, unsigned int glyph_index, | |
394 const AnchorMatrix &anchors, unsigned int class_count, | |
395 unsigned int glyph_pos) const | |
396 { | |
397 TRACE_APPLY (); | |
398 const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index); | |
399 unsigned int mark_class = record.klass; | |
400 | |
401 const Anchor& mark_anchor = this + record.markAnchor; | |
402 const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, cl
ass_count); | |
403 | |
404 hb_position_t mark_x, mark_y, base_x, base_y; | |
405 | |
406 mark_anchor.get_anchor (c->layout, c->buffer->info[c->buffer->i].codepoint,
&mark_x, &mark_y); | |
407 glyph_anchor.get_anchor (c->layout, c->buffer->info[glyph_pos].codepoint, &b
ase_x, &base_y); | |
408 | |
409 hb_glyph_position_t &o = c->buffer->pos[c->buffer->i]; | |
410 o.x_offset = base_x - mark_x; | |
411 o.y_offset = base_y - mark_y; | |
412 o.attach_lookback() = c->buffer->i - glyph_pos; | |
413 | |
414 c->buffer->i++; | |
415 return true; | |
416 } | |
417 | |
418 inline bool sanitize (hb_sanitize_context_t *c) { | |
419 TRACE_SANITIZE (); | |
420 return ArrayOf<MarkRecord>::sanitize (c, this); | |
421 } | |
422 }; | |
423 | |
424 | |
425 /* Lookups */ | |
426 | |
427 struct SinglePosFormat1 | |
428 { | |
429 friend struct SinglePos; | |
430 | |
431 private: | |
432 inline bool apply (hb_apply_context_t *c) const | |
433 { | |
434 TRACE_APPLY (); | |
435 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoin
t); | |
436 if (likely (index == NOT_COVERED)) | |
437 return false; | |
438 | |
439 valueFormat.apply_value (c->layout, this, values, c->buffer->pos[c->buffer->
i]); | |
440 | |
441 c->buffer->i++; | |
442 return true; | |
443 } | |
444 | |
445 inline bool sanitize (hb_sanitize_context_t *c) { | |
446 TRACE_SANITIZE (); | |
447 return c->check_struct (this) | |
448 && coverage.sanitize (c, this) | |
449 && valueFormat.sanitize_value (c, this, values); | |
450 } | |
451 | |
452 private: | |
453 USHORT format; /* Format identifier--format = 1 */ | |
454 OffsetTo<Coverage> | |
455 coverage; /* Offset to Coverage table--from | |
456 * beginning of subtable */ | |
457 ValueFormat valueFormat; /* Defines the types of data in the | |
458 * ValueRecord */ | |
459 ValueRecord values; /* Defines positioning | |
460 * value(s)--applied to all glyphs in | |
461 * the Coverage table */ | |
462 public: | |
463 DEFINE_SIZE_ARRAY (6, values); | |
464 }; | |
465 | |
466 struct SinglePosFormat2 | |
467 { | |
468 friend struct SinglePos; | |
469 | |
470 private: | |
471 inline bool apply (hb_apply_context_t *c) const | |
472 { | |
473 TRACE_APPLY (); | |
474 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoin
t); | |
475 if (likely (index == NOT_COVERED)) | |
476 return false; | |
477 | |
478 if (likely (index >= valueCount)) | |
479 return false; | |
480 | |
481 valueFormat.apply_value (c->layout, this, | |
482 &values[index * valueFormat.get_len ()], | |
483 c->buffer->pos[c->buffer->i]); | |
484 | |
485 c->buffer->i++; | |
486 return true; | |
487 } | |
488 | |
489 inline bool sanitize (hb_sanitize_context_t *c) { | |
490 TRACE_SANITIZE (); | |
491 return c->check_struct (this) | |
492 && coverage.sanitize (c, this) | |
493 && valueFormat.sanitize_values (c, this, values, valueCount); | |
494 } | |
495 | |
496 private: | |
497 USHORT format; /* Format identifier--format = 2 */ | |
498 OffsetTo<Coverage> | |
499 coverage; /* Offset to Coverage table--from | |
500 * beginning of subtable */ | |
501 ValueFormat valueFormat; /* Defines the types of data in the | |
502 * ValueRecord */ | |
503 USHORT valueCount; /* Number of ValueRecords */ | |
504 ValueRecord values; /* Array of ValueRecords--positioning | |
505 * values applied to glyphs */ | |
506 public: | |
507 DEFINE_SIZE_ARRAY (8, values); | |
508 }; | |
509 | |
510 struct SinglePos | |
511 { | |
512 friend struct PosLookupSubTable; | |
513 | |
514 private: | |
515 inline bool apply (hb_apply_context_t *c) const | |
516 { | |
517 TRACE_APPLY (); | |
518 switch (u.format) { | |
519 case 1: return u.format1.apply (c); | |
520 case 2: return u.format2.apply (c); | |
521 default:return false; | |
522 } | |
523 } | |
524 | |
525 inline bool sanitize (hb_sanitize_context_t *c) { | |
526 TRACE_SANITIZE (); | |
527 if (!u.format.sanitize (c)) return false; | |
528 switch (u.format) { | |
529 case 1: return u.format1.sanitize (c); | |
530 case 2: return u.format2.sanitize (c); | |
531 default:return true; | |
532 } | |
533 } | |
534 | |
535 private: | |
536 union { | |
537 USHORT format; /* Format identifier */ | |
538 SinglePosFormat1 format1; | |
539 SinglePosFormat2 format2; | |
540 } u; | |
541 }; | |
542 | |
543 | |
544 struct PairValueRecord | |
545 { | |
546 friend struct PairSet; | |
547 | |
548 private: | |
549 GlyphID secondGlyph; /* GlyphID of second glyph in the | |
550 * pair--first glyph is listed in the | |
551 * Coverage table */ | |
552 ValueRecord values; /* Positioning data for the first glyph | |
553 * followed by for second glyph */ | |
554 public: | |
555 DEFINE_SIZE_ARRAY (2, values); | |
556 }; | |
557 | |
558 struct PairSet | |
559 { | |
560 friend struct PairPosFormat1; | |
561 | |
562 inline bool apply (hb_apply_context_t *c, | |
563 const ValueFormat *valueFormats, | |
564 unsigned int pos) const | |
565 { | |
566 TRACE_APPLY (); | |
567 unsigned int len1 = valueFormats[0].get_len (); | |
568 unsigned int len2 = valueFormats[1].get_len (); | |
569 unsigned int record_size = USHORT::static_size * (1 + len1 + len2); | |
570 | |
571 unsigned int count = len; | |
572 const PairValueRecord *record = CastP<PairValueRecord> (array); | |
573 for (unsigned int i = 0; i < count; i++) | |
574 { | |
575 if (c->buffer->info[pos].codepoint == record->secondGlyph) | |
576 { | |
577 valueFormats[0].apply_value (c->layout, this, &record->values[0], c->buf
fer->pos[c->buffer->i]); | |
578 valueFormats[1].apply_value (c->layout, this, &record->values[len1], c->
buffer->pos[pos]); | |
579 if (len2) | |
580 pos++; | |
581 c->buffer->i = pos; | |
582 return true; | |
583 } | |
584 record = &StructAtOffset<PairValueRecord> (record, record_size); | |
585 } | |
586 | |
587 return false; | |
588 } | |
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 | |
597 inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *clos
ure) { | |
598 TRACE_SANITIZE (); | |
599 if (!(c->check_struct (this) | |
600 && c->check_array (array, USHORT::static_size * closure->stride, len))) r
eturn false; | |
601 | |
602 unsigned int count = len; | |
603 PairValueRecord *record = CastP<PairValueRecord> (array); | |
604 return closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->b
ase, &record->values[0], count, closure->stride) | |
605 && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->b
ase, &record->values[closure->len1], count, closure->stride); | |
606 } | |
607 | |
608 private: | |
609 USHORT len; /* Number of PairValueRecords */ | |
610 USHORT array[VAR]; /* Array of PairValueRecords--ordered | |
611 * by GlyphID of the second glyph */ | |
612 public: | |
613 DEFINE_SIZE_ARRAY (2, array); | |
614 }; | |
615 | |
616 struct PairPosFormat1 | |
617 { | |
618 friend struct PairPos; | |
619 | |
620 private: | |
621 inline bool apply (hb_apply_context_t *c) const | |
622 { | |
623 TRACE_APPLY (); | |
624 unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length); | |
625 if (unlikely (c->buffer->i + 2 > end)) | |
626 return false; | |
627 | |
628 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoin
t); | |
629 if (likely (index == NOT_COVERED)) | |
630 return false; | |
631 | |
632 unsigned int j = c->buffer->i + 1; | |
633 while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->loo
kup_props, NULL)) | |
634 { | |
635 if (unlikely (j == end)) | |
636 return false; | |
637 j++; | |
638 } | |
639 | |
640 return (this+pairSet[index]).apply (c, &valueFormat1, j); | |
641 } | |
642 | |
643 inline bool sanitize (hb_sanitize_context_t *c) { | |
644 TRACE_SANITIZE (); | |
645 | |
646 unsigned int len1 = valueFormat1.get_len (); | |
647 unsigned int len2 = valueFormat2.get_len (); | |
648 PairSet::sanitize_closure_t closure = { | |
649 this, | |
650 &valueFormat1, | |
651 len1, | |
652 1 + len1 + len2 | |
653 }; | |
654 | |
655 return c->check_struct (this) | |
656 && coverage.sanitize (c, this) | |
657 && pairSet.sanitize (c, this, &closure); | |
658 } | |
659 | |
660 private: | |
661 USHORT format; /* Format identifier--format = 1 */ | |
662 OffsetTo<Coverage> | |
663 coverage; /* Offset to Coverage table--from | |
664 * beginning of subtable */ | |
665 ValueFormat valueFormat1; /* Defines the types of data in | |
666 * ValueRecord1--for the first glyph | |
667 * in the pair--may be zero (0) */ | |
668 ValueFormat valueFormat2; /* Defines the types of data in | |
669 * ValueRecord2--for the second glyph | |
670 * in the pair--may be zero (0) */ | |
671 OffsetArrayOf<PairSet> | |
672 pairSet; /* Array of PairSet tables | |
673 * ordered by Coverage Index */ | |
674 public: | |
675 DEFINE_SIZE_ARRAY (10, pairSet); | |
676 }; | |
677 | |
678 struct PairPosFormat2 | |
679 { | |
680 friend struct PairPos; | |
681 | |
682 private: | |
683 inline bool apply (hb_apply_context_t *c) const | |
684 { | |
685 TRACE_APPLY (); | |
686 unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length); | |
687 if (unlikely (c->buffer->i + 2 > end)) | |
688 return false; | |
689 | |
690 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoin
t); | |
691 if (likely (index == NOT_COVERED)) | |
692 return false; | |
693 | |
694 unsigned int j = c->buffer->i + 1; | |
695 while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->loo
kup_props, NULL)) | |
696 { | |
697 if (unlikely (j == end)) | |
698 return false; | |
699 j++; | |
700 } | |
701 | |
702 unsigned int len1 = valueFormat1.get_len (); | |
703 unsigned int len2 = valueFormat2.get_len (); | |
704 unsigned int record_len = len1 + len2; | |
705 | |
706 unsigned int klass1 = (this+classDef1) (c->buffer->info[c->buffer->i].codepo
int); | |
707 unsigned int klass2 = (this+classDef2) (c->buffer->info[j].codepoint); | |
708 if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) | |
709 return false; | |
710 | |
711 const Value *v = &values[record_len * (klass1 * class2Count + klass2)]; | |
712 valueFormat1.apply_value (c->layout, this, v, c->buffer->pos[c->buffer->i]); | |
713 valueFormat2.apply_value (c->layout, this, v + len1, c->buffer->pos[j]); | |
714 | |
715 if (len2) | |
716 j++; | |
717 c->buffer->i = j; | |
718 | |
719 return true; | |
720 } | |
721 | |
722 inline bool sanitize (hb_sanitize_context_t *c) { | |
723 TRACE_SANITIZE (); | |
724 if (!(c->check_struct (this) | |
725 && coverage.sanitize (c, this) | |
726 && classDef1.sanitize (c, this) | |
727 && classDef2.sanitize (c, this))) return false; | |
728 | |
729 unsigned int len1 = valueFormat1.get_len (); | |
730 unsigned int len2 = valueFormat2.get_len (); | |
731 unsigned int stride = len1 + len2; | |
732 unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size
(); | |
733 unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count
; | |
734 return c->check_array (values, record_size, count) && | |
735 valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], coun
t, stride) && | |
736 valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], c
ount, stride); | |
737 } | |
738 | |
739 private: | |
740 USHORT format; /* Format identifier--format = 2 */ | |
741 OffsetTo<Coverage> | |
742 coverage; /* Offset to Coverage table--from | |
743 * beginning of subtable */ | |
744 ValueFormat valueFormat1; /* ValueRecord definition--for the | |
745 * first glyph of the pair--may be zero | |
746 * (0) */ | |
747 ValueFormat valueFormat2; /* ValueRecord definition--for the | |
748 * second glyph of the pair--may be | |
749 * zero (0) */ | |
750 OffsetTo<ClassDef> | |
751 classDef1; /* Offset to ClassDef table--from | |
752 * beginning of PairPos subtable--for | |
753 * the first glyph of the pair */ | |
754 OffsetTo<ClassDef> | |
755 classDef2; /* Offset to ClassDef table--from | |
756 * beginning of PairPos subtable--for | |
757 * the second glyph of the pair */ | |
758 USHORT class1Count; /* Number of classes in ClassDef1 | |
759 * table--includes Class0 */ | |
760 USHORT class2Count; /* Number of classes in ClassDef2 | |
761 * table--includes Class0 */ | |
762 ValueRecord values; /* Matrix of value pairs: | |
763 * class1-major, class2-minor, | |
764 * Each entry has value1 and value2 */ | |
765 public: | |
766 DEFINE_SIZE_ARRAY (16, values); | |
767 }; | |
768 | |
769 struct PairPos | |
770 { | |
771 friend struct PosLookupSubTable; | |
772 | |
773 private: | |
774 inline bool apply (hb_apply_context_t *c) const | |
775 { | |
776 TRACE_APPLY (); | |
777 switch (u.format) { | |
778 case 1: return u.format1.apply (c); | |
779 case 2: return u.format2.apply (c); | |
780 default:return false; | |
781 } | |
782 } | |
783 | |
784 inline bool sanitize (hb_sanitize_context_t *c) { | |
785 TRACE_SANITIZE (); | |
786 if (!u.format.sanitize (c)) return false; | |
787 switch (u.format) { | |
788 case 1: return u.format1.sanitize (c); | |
789 case 2: return u.format2.sanitize (c); | |
790 default:return true; | |
791 } | |
792 } | |
793 | |
794 private: | |
795 union { | |
796 USHORT format; /* Format identifier */ | |
797 PairPosFormat1 format1; | |
798 PairPosFormat2 format2; | |
799 } u; | |
800 }; | |
801 | |
802 | |
803 struct EntryExitRecord | |
804 { | |
805 friend struct CursivePosFormat1; | |
806 | |
807 inline bool sanitize (hb_sanitize_context_t *c, void *base) { | |
808 TRACE_SANITIZE (); | |
809 return entryAnchor.sanitize (c, base) | |
810 && exitAnchor.sanitize (c, base); | |
811 } | |
812 | |
813 private: | |
814 OffsetTo<Anchor> | |
815 entryAnchor; /* Offset to EntryAnchor table--from | |
816 * beginning of CursivePos | |
817 * subtable--may be NULL */ | |
818 OffsetTo<Anchor> | |
819 exitAnchor; /* Offset to ExitAnchor table--from | |
820 * beginning of CursivePos | |
821 * subtable--may be NULL */ | |
822 public: | |
823 DEFINE_SIZE_STATIC (4); | |
824 }; | |
825 | |
826 struct CursivePosFormat1 | |
827 { | |
828 friend struct CursivePos; | |
829 | |
830 private: | |
831 inline bool apply (hb_apply_context_t *c) const | |
832 { | |
833 TRACE_APPLY (); | |
834 | |
835 /* We don't handle mark glyphs here. */ | |
836 if (c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK) | |
837 return false; | |
838 | |
839 unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length); | |
840 if (unlikely (c->buffer->i + 2 > end)) | |
841 return false; | |
842 | |
843 const EntryExitRecord &this_record = entryExitRecord[(this+coverage) (c->buf
fer->info[c->buffer->i].codepoint)]; | |
844 if (!this_record.exitAnchor) | |
845 return false; | |
846 | |
847 unsigned int j = c->buffer->i + 1; | |
848 while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->loo
kup_props, NULL)) | |
849 { | |
850 if (unlikely (j == end)) | |
851 return false; | |
852 j++; | |
853 } | |
854 | |
855 const EntryExitRecord &next_record = entryExitRecord[(this+coverage) (c->buf
fer->info[j].codepoint)]; | |
856 if (!next_record.entryAnchor) | |
857 return false; | |
858 | |
859 unsigned int i = c->buffer->i; | |
860 | |
861 hb_position_t entry_x, entry_y, exit_x, exit_y; | |
862 (this+this_record.exitAnchor).get_anchor (c->layout, c->buffer->info[i].code
point, &exit_x, &exit_y); | |
863 (this+next_record.entryAnchor).get_anchor (c->layout, c->buffer->info[j].cod
epoint, &entry_x, &entry_y); | |
864 | |
865 hb_direction_t direction = c->buffer->props.direction; | |
866 | |
867 /* Align the exit anchor of the left/top glyph with the entry anchor of the
right/bottom glyph | |
868 * by adjusting advance of the left/top glyph. */ | |
869 if (HB_DIRECTION_IS_BACKWARD (direction)) | |
870 { | |
871 if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) | |
872 c->buffer->pos[j].x_advance = c->buffer->pos[j].x_offset + entry_x - exi
t_x; | |
873 else | |
874 c->buffer->pos[j].y_advance = c->buffer->pos[j].y_offset + entry_y - exi
t_y; | |
875 } | |
876 else | |
877 { | |
878 if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) | |
879 c->buffer->pos[i].x_advance = c->buffer->pos[i].x_offset + exit_x - entr
y_x; | |
880 else | |
881 c->buffer->pos[i].y_advance = c->buffer->pos[i].y_offset + exit_y - entr
y_y; | |
882 } | |
883 | |
884 if (c->lookup_props & LookupFlag::RightToLeft) | |
885 { | |
886 c->buffer->pos[i].cursive_chain() = j - i; | |
887 if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) | |
888 c->buffer->pos[i].y_offset = entry_y - exit_y; | |
889 else | |
890 c->buffer->pos[i].x_offset = entry_x - exit_x; | |
891 } | |
892 else | |
893 { | |
894 c->buffer->pos[j].cursive_chain() = i - j; | |
895 if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) | |
896 c->buffer->pos[j].y_offset = exit_y - entry_y; | |
897 else | |
898 c->buffer->pos[j].x_offset = exit_x - entry_x; | |
899 } | |
900 | |
901 c->buffer->i = j; | |
902 return true; | |
903 } | |
904 | |
905 inline bool sanitize (hb_sanitize_context_t *c) { | |
906 TRACE_SANITIZE (); | |
907 return coverage.sanitize (c, this) | |
908 && entryExitRecord.sanitize (c, this); | |
909 } | |
910 | |
911 private: | |
912 USHORT format; /* Format identifier--format = 1 */ | |
913 OffsetTo<Coverage> | |
914 coverage; /* Offset to Coverage table--from | |
915 * beginning of subtable */ | |
916 ArrayOf<EntryExitRecord> | |
917 entryExitRecord; /* Array of EntryExit records--in | |
918 * Coverage Index order */ | |
919 public: | |
920 DEFINE_SIZE_ARRAY (6, entryExitRecord); | |
921 }; | |
922 | |
923 struct CursivePos | |
924 { | |
925 friend struct PosLookupSubTable; | |
926 | |
927 private: | |
928 inline bool apply (hb_apply_context_t *c) const | |
929 { | |
930 TRACE_APPLY (); | |
931 switch (u.format) { | |
932 case 1: return u.format1.apply (c); | |
933 default:return false; | |
934 } | |
935 } | |
936 | |
937 inline bool sanitize (hb_sanitize_context_t *c) { | |
938 TRACE_SANITIZE (); | |
939 if (!u.format.sanitize (c)) return false; | |
940 switch (u.format) { | |
941 case 1: return u.format1.sanitize (c); | |
942 default:return true; | |
943 } | |
944 } | |
945 | |
946 private: | |
947 union { | |
948 USHORT format; /* Format identifier */ | |
949 CursivePosFormat1 format1; | |
950 } u; | |
951 }; | |
952 | |
953 | |
954 typedef AnchorMatrix BaseArray; /* base-major-- | |
955 * in order of BaseCoverage Index--, | |
956 * mark-minor-- | |
957 * ordered by class--zero-based. */ | |
958 | |
959 struct MarkBasePosFormat1 | |
960 { | |
961 friend struct MarkBasePos; | |
962 | |
963 private: | |
964 inline bool apply (hb_apply_context_t *c) const | |
965 { | |
966 TRACE_APPLY (); | |
967 unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->i]
.codepoint); | |
968 if (likely (mark_index == NOT_COVERED)) | |
969 return false; | |
970 | |
971 /* now we search backwards for a non-mark glyph */ | |
972 unsigned int property; | |
973 unsigned int j = c->buffer->i; | |
974 do | |
975 { | |
976 if (unlikely (!j)) | |
977 return false; | |
978 j--; | |
979 } while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], Look
upFlag::IgnoreMarks, &property)); | |
980 | |
981 /* The following assertion is too strong, so we've disabled it. */ | |
982 if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH)) | |
983 {/*return false;*/} | |
984 | |
985 unsigned int base_index = (this+baseCoverage) (c->buffer->info[j].codepoint)
; | |
986 if (base_index == NOT_COVERED) | |
987 return false; | |
988 | |
989 return (this+markArray).apply (c, mark_index, base_index, this+baseArray, cl
assCount, j); | |
990 } | |
991 | |
992 inline bool sanitize (hb_sanitize_context_t *c) { | |
993 TRACE_SANITIZE (); | |
994 return c->check_struct (this) | |
995 && markCoverage.sanitize (c, this) | |
996 && baseCoverage.sanitize (c, this) | |
997 && markArray.sanitize (c, this) | |
998 && baseArray.sanitize (c, this, (unsigned int) classCount); | |
999 } | |
1000 | |
1001 private: | |
1002 USHORT format; /* Format identifier--format = 1 */ | |
1003 OffsetTo<Coverage> | |
1004 markCoverage; /* Offset to MarkCoverage table--from | |
1005 * beginning of MarkBasePos subtable */ | |
1006 OffsetTo<Coverage> | |
1007 baseCoverage; /* Offset to BaseCoverage table--from | |
1008 * beginning of MarkBasePos subtable */ | |
1009 USHORT classCount; /* Number of classes defined for marks *
/ | |
1010 OffsetTo<MarkArray> | |
1011 markArray; /* Offset to MarkArray table--from | |
1012 * beginning of MarkBasePos subtable */ | |
1013 OffsetTo<BaseArray> | |
1014 baseArray; /* Offset to BaseArray table--from | |
1015 * beginning of MarkBasePos subtable */ | |
1016 public: | |
1017 DEFINE_SIZE_STATIC (12); | |
1018 }; | |
1019 | |
1020 struct MarkBasePos | |
1021 { | |
1022 friend struct PosLookupSubTable; | |
1023 | |
1024 private: | |
1025 inline bool apply (hb_apply_context_t *c) const | |
1026 { | |
1027 TRACE_APPLY (); | |
1028 switch (u.format) { | |
1029 case 1: return u.format1.apply (c); | |
1030 default:return false; | |
1031 } | |
1032 } | |
1033 | |
1034 inline bool sanitize (hb_sanitize_context_t *c) { | |
1035 TRACE_SANITIZE (); | |
1036 if (!u.format.sanitize (c)) return false; | |
1037 switch (u.format) { | |
1038 case 1: return u.format1.sanitize (c); | |
1039 default:return true; | |
1040 } | |
1041 } | |
1042 | |
1043 private: | |
1044 union { | |
1045 USHORT format; /* Format identifier */ | |
1046 MarkBasePosFormat1 format1; | |
1047 } u; | |
1048 }; | |
1049 | |
1050 | |
1051 typedef AnchorMatrix LigatureAttach; /* component-major-- | |
1052 * in order of writing direction--, | |
1053 * mark-minor-- | |
1054 * ordered by class--zero-based. */ | |
1055 | |
1056 typedef OffsetListOf<LigatureAttach> LigatureArray; | |
1057 /* Array of LigatureAttach | |
1058 * tables ordered by | |
1059 * LigatureCoverage Index */ | |
1060 | |
1061 struct MarkLigPosFormat1 | |
1062 { | |
1063 friend struct MarkLigPos; | |
1064 | |
1065 private: | |
1066 inline bool apply (hb_apply_context_t *c) const | |
1067 { | |
1068 TRACE_APPLY (); | |
1069 unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->i]
.codepoint); | |
1070 if (likely (mark_index == NOT_COVERED)) | |
1071 return false; | |
1072 | |
1073 /* now we search backwards for a non-mark glyph */ | |
1074 unsigned int property; | |
1075 unsigned int j = c->buffer->i; | |
1076 do | |
1077 { | |
1078 if (unlikely (!j)) | |
1079 return false; | |
1080 j--; | |
1081 } while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], Look
upFlag::IgnoreMarks, &property)); | |
1082 | |
1083 /* The following assertion is too strong, so we've disabled it. */ | |
1084 if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE)) | |
1085 {/*return false;*/} | |
1086 | |
1087 unsigned int lig_index = (this+ligatureCoverage) (c->buffer->info[j].codepoi
nt); | |
1088 if (lig_index == NOT_COVERED) | |
1089 return false; | |
1090 | |
1091 const LigatureArray& lig_array = this+ligatureArray; | |
1092 const LigatureAttach& lig_attach = lig_array[lig_index]; | |
1093 | |
1094 /* Find component to attach to */ | |
1095 unsigned int comp_count = lig_attach.rows; | |
1096 if (unlikely (!comp_count)) | |
1097 return false; | |
1098 unsigned int comp_index; | |
1099 /* We must now check whether the ligature ID of the current mark glyph | |
1100 * is identical to the ligature ID of the found ligature. If yes, we | |
1101 * can directly use the component index. If not, we attach the mark | |
1102 * glyph to the last component of the ligature. */ | |
1103 if (c->buffer->info[j].lig_id() && c->buffer->info[j].lig_id() == c->buffer-
>info[c->buffer->i].lig_id() && c->buffer->info[c->buffer->i].lig_comp()) | |
1104 { | |
1105 comp_index = c->buffer->info[c->buffer->i].lig_comp() - 1; | |
1106 if (comp_index >= comp_count) | |
1107 comp_index = comp_count - 1; | |
1108 } | |
1109 else | |
1110 comp_index = comp_count - 1; | |
1111 | |
1112 return (this+markArray).apply (c, mark_index, comp_index, lig_attach, classC
ount, j); | |
1113 } | |
1114 | |
1115 inline bool sanitize (hb_sanitize_context_t *c) { | |
1116 TRACE_SANITIZE (); | |
1117 return c->check_struct (this) | |
1118 && markCoverage.sanitize (c, this) | |
1119 && ligatureCoverage.sanitize (c, this) | |
1120 && markArray.sanitize (c, this) | |
1121 && ligatureArray.sanitize (c, this, (unsigned int) classCount); | |
1122 } | |
1123 | |
1124 private: | |
1125 USHORT format; /* Format identifier--format = 1 */ | |
1126 OffsetTo<Coverage> | |
1127 markCoverage; /* Offset to Mark Coverage table--from | |
1128 * beginning of MarkLigPos subtable */ | |
1129 OffsetTo<Coverage> | |
1130 ligatureCoverage; /* Offset to Ligature Coverage | |
1131 * table--from beginning of MarkLigPos | |
1132 * subtable */ | |
1133 USHORT classCount; /* Number of defined mark classes */ | |
1134 OffsetTo<MarkArray> | |
1135 markArray; /* Offset to MarkArray table--from | |
1136 * beginning of MarkLigPos subtable */ | |
1137 OffsetTo<LigatureArray> | |
1138 ligatureArray; /* Offset to LigatureArray table--from | |
1139 * beginning of MarkLigPos subtable */ | |
1140 public: | |
1141 DEFINE_SIZE_STATIC (12); | |
1142 }; | |
1143 | |
1144 struct MarkLigPos | |
1145 { | |
1146 friend struct PosLookupSubTable; | |
1147 | |
1148 private: | |
1149 inline bool apply (hb_apply_context_t *c) const | |
1150 { | |
1151 TRACE_APPLY (); | |
1152 switch (u.format) { | |
1153 case 1: return u.format1.apply (c); | |
1154 default:return false; | |
1155 } | |
1156 } | |
1157 | |
1158 inline bool sanitize (hb_sanitize_context_t *c) { | |
1159 TRACE_SANITIZE (); | |
1160 if (!u.format.sanitize (c)) return false; | |
1161 switch (u.format) { | |
1162 case 1: return u.format1.sanitize (c); | |
1163 default:return true; | |
1164 } | |
1165 } | |
1166 | |
1167 private: | |
1168 union { | |
1169 USHORT format; /* Format identifier */ | |
1170 MarkLigPosFormat1 format1; | |
1171 } u; | |
1172 }; | |
1173 | |
1174 | |
1175 typedef AnchorMatrix Mark2Array; /* mark2-major-- | |
1176 * in order of Mark2Coverage Index--, | |
1177 * mark1-minor-- | |
1178 * ordered by class--zero-based. */ | |
1179 | |
1180 struct MarkMarkPosFormat1 | |
1181 { | |
1182 friend struct MarkMarkPos; | |
1183 | |
1184 private: | |
1185 inline bool apply (hb_apply_context_t *c) const | |
1186 { | |
1187 TRACE_APPLY (); | |
1188 unsigned int mark1_index = (this+mark1Coverage) (c->buffer->info[c->buffer->
i].codepoint); | |
1189 if (likely (mark1_index == NOT_COVERED)) | |
1190 return false; | |
1191 | |
1192 /* now we search backwards for a suitable mark glyph until a non-mark glyph
*/ | |
1193 unsigned int property; | |
1194 unsigned int j = c->buffer->i; | |
1195 do | |
1196 { | |
1197 if (unlikely (!j)) | |
1198 return false; | |
1199 j--; | |
1200 } while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->l
ookup_props, &property)); | |
1201 | |
1202 if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)) | |
1203 return false; | |
1204 | |
1205 /* Two marks match only if they belong to the same base, or same component | |
1206 * of the same ligature. That is, the component numbers must match, and | |
1207 * if those are non-zero, the ligid number should also match. */ | |
1208 if ((c->buffer->info[j].lig_comp() != c->buffer->info[c->buffer->i].lig_comp
()) || | |
1209 (c->buffer->info[j].lig_comp() && c->buffer->info[j].lig_id() != c->buff
er->info[c->buffer->i].lig_id())) | |
1210 return false; | |
1211 | |
1212 unsigned int mark2_index = (this+mark2Coverage) (c->buffer->info[j].codepoin
t); | |
1213 if (mark2_index == NOT_COVERED) | |
1214 return false; | |
1215 | |
1216 return (this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array
, classCount, j); | |
1217 } | |
1218 | |
1219 inline bool sanitize (hb_sanitize_context_t *c) { | |
1220 TRACE_SANITIZE (); | |
1221 return c->check_struct (this) | |
1222 && mark1Coverage.sanitize (c, this) | |
1223 && mark2Coverage.sanitize (c, this) | |
1224 && mark1Array.sanitize (c, this) | |
1225 && mark2Array.sanitize (c, this, (unsigned int) classCount); | |
1226 } | |
1227 | |
1228 private: | |
1229 USHORT format; /* Format identifier--format = 1 */ | |
1230 OffsetTo<Coverage> | |
1231 mark1Coverage; /* Offset to Combining Mark1 Coverage | |
1232 * table--from beginning of MarkMarkPos | |
1233 * subtable */ | |
1234 OffsetTo<Coverage> | |
1235 mark2Coverage; /* Offset to Combining Mark2 Coverage | |
1236 * table--from beginning of MarkMarkPos | |
1237 * subtable */ | |
1238 USHORT classCount; /* Number of defined mark classes */ | |
1239 OffsetTo<MarkArray> | |
1240 mark1Array; /* Offset to Mark1Array table--from | |
1241 * beginning of MarkMarkPos subtable */ | |
1242 OffsetTo<Mark2Array> | |
1243 mark2Array; /* Offset to Mark2Array table--from | |
1244 * beginning of MarkMarkPos subtable */ | |
1245 public: | |
1246 DEFINE_SIZE_STATIC (12); | |
1247 }; | |
1248 | |
1249 struct MarkMarkPos | |
1250 { | |
1251 friend struct PosLookupSubTable; | |
1252 | |
1253 private: | |
1254 inline bool apply (hb_apply_context_t *c) const | |
1255 { | |
1256 TRACE_APPLY (); | |
1257 switch (u.format) { | |
1258 case 1: return u.format1.apply (c); | |
1259 default:return false; | |
1260 } | |
1261 } | |
1262 | |
1263 inline bool sanitize (hb_sanitize_context_t *c) { | |
1264 TRACE_SANITIZE (); | |
1265 if (!u.format.sanitize (c)) return false; | |
1266 switch (u.format) { | |
1267 case 1: return u.format1.sanitize (c); | |
1268 default:return true; | |
1269 } | |
1270 } | |
1271 | |
1272 private: | |
1273 union { | |
1274 USHORT format; /* Format identifier */ | |
1275 MarkMarkPosFormat1 format1; | |
1276 } u; | |
1277 }; | |
1278 | |
1279 | |
1280 HB_BEGIN_DECLS | |
1281 static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_i
ndex); | |
1282 HB_END_DECLS | |
1283 | |
1284 struct ContextPos : Context | |
1285 { | |
1286 friend struct PosLookupSubTable; | |
1287 | |
1288 private: | |
1289 inline bool apply (hb_apply_context_t *c) const | |
1290 { | |
1291 TRACE_APPLY (); | |
1292 return Context::apply (c, position_lookup); | |
1293 } | |
1294 }; | |
1295 | |
1296 struct ChainContextPos : ChainContext | |
1297 { | |
1298 friend struct PosLookupSubTable; | |
1299 | |
1300 private: | |
1301 inline bool apply (hb_apply_context_t *c) const | |
1302 { | |
1303 TRACE_APPLY (); | |
1304 return ChainContext::apply (c, position_lookup); | |
1305 } | |
1306 }; | |
1307 | |
1308 | |
1309 struct ExtensionPos : Extension | |
1310 { | |
1311 friend struct PosLookupSubTable; | |
1312 | |
1313 private: | |
1314 inline const struct PosLookupSubTable& get_subtable (void) const | |
1315 { | |
1316 unsigned int offset = get_offset (); | |
1317 if (unlikely (!offset)) return Null(PosLookupSubTable); | |
1318 return StructAtOffset<PosLookupSubTable> (this, offset); | |
1319 } | |
1320 | |
1321 inline bool apply (hb_apply_context_t *c) const; | |
1322 | |
1323 inline bool sanitize (hb_sanitize_context_t *c); | |
1324 }; | |
1325 | |
1326 | |
1327 | |
1328 /* | |
1329 * PosLookup | |
1330 */ | |
1331 | |
1332 | |
1333 struct PosLookupSubTable | |
1334 { | |
1335 friend struct PosLookup; | |
1336 | |
1337 enum { | |
1338 Single = 1, | |
1339 Pair = 2, | |
1340 Cursive = 3, | |
1341 MarkBase = 4, | |
1342 MarkLig = 5, | |
1343 MarkMark = 6, | |
1344 Context = 7, | |
1345 ChainContext = 8, | |
1346 Extension = 9 | |
1347 }; | |
1348 | |
1349 inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const | |
1350 { | |
1351 TRACE_APPLY (); | |
1352 switch (lookup_type) { | |
1353 case Single: return u.single.apply (c); | |
1354 case Pair: return u.pair.apply (c); | |
1355 case Cursive: return u.cursive.apply (c); | |
1356 case MarkBase: return u.markBase.apply (c); | |
1357 case MarkLig: return u.markLig.apply (c); | |
1358 case MarkMark: return u.markMark.apply (c); | |
1359 case Context: return u.c.apply (c); | |
1360 case ChainContext: return u.chainContext.apply (c); | |
1361 case Extension: return u.extension.apply (c); | |
1362 default:return false; | |
1363 } | |
1364 } | |
1365 | |
1366 inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) { | |
1367 TRACE_SANITIZE (); | |
1368 switch (lookup_type) { | |
1369 case Single: return u.single.sanitize (c); | |
1370 case Pair: return u.pair.sanitize (c); | |
1371 case Cursive: return u.cursive.sanitize (c); | |
1372 case MarkBase: return u.markBase.sanitize (c); | |
1373 case MarkLig: return u.markLig.sanitize (c); | |
1374 case MarkMark: return u.markMark.sanitize (c); | |
1375 case Context: return u.c.sanitize (c); | |
1376 case ChainContext: return u.chainContext.sanitize (c); | |
1377 case Extension: return u.extension.sanitize (c); | |
1378 default:return true; | |
1379 } | |
1380 } | |
1381 | |
1382 private: | |
1383 union { | |
1384 USHORT sub_format; | |
1385 SinglePos single; | |
1386 PairPos pair; | |
1387 CursivePos cursive; | |
1388 MarkBasePos markBase; | |
1389 MarkLigPos markLig; | |
1390 MarkMarkPos markMark; | |
1391 ContextPos c; | |
1392 ChainContextPos chainContext; | |
1393 ExtensionPos extension; | |
1394 } u; | |
1395 public: | |
1396 DEFINE_SIZE_UNION (2, sub_format); | |
1397 }; | |
1398 | |
1399 | |
1400 struct PosLookup : Lookup | |
1401 { | |
1402 inline const PosLookupSubTable& get_subtable (unsigned int i) const | |
1403 { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; } | |
1404 | |
1405 inline bool apply_once (hb_ot_layout_context_t *layout, | |
1406 hb_buffer_t *buffer, | |
1407 hb_mask_t lookup_mask, | |
1408 unsigned int context_length, | |
1409 unsigned int nesting_level_left) const | |
1410 { | |
1411 unsigned int lookup_type = get_type (); | |
1412 hb_apply_context_t c[1] = {{0}}; | |
1413 | |
1414 c->layout = layout; | |
1415 c->buffer = buffer; | |
1416 c->lookup_mask = lookup_mask; | |
1417 c->context_length = context_length; | |
1418 c->nesting_level_left = nesting_level_left; | |
1419 c->lookup_props = get_props (); | |
1420 | |
1421 if (!_hb_ot_layout_check_glyph_property (c->layout->face, &c->buffer->info[c
->buffer->i], c->lookup_props, &c->property)) | |
1422 return false; | |
1423 | |
1424 for (unsigned int i = 0; i < get_subtable_count (); i++) | |
1425 if (get_subtable (i).apply (c, lookup_type)) | |
1426 return true; | |
1427 | |
1428 return false; | |
1429 } | |
1430 | |
1431 inline bool apply_string (hb_ot_layout_context_t *layout, | |
1432 hb_buffer_t *buffer, | |
1433 hb_mask_t mask) const | |
1434 { | |
1435 bool ret = false; | |
1436 | |
1437 if (unlikely (!buffer->len)) | |
1438 return false; | |
1439 | |
1440 buffer->i = 0; | |
1441 while (buffer->i < buffer->len) | |
1442 { | |
1443 if ((buffer->info[buffer->i].mask & mask) && | |
1444 apply_once (layout, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL)) | |
1445 ret = true; | |
1446 else | |
1447 buffer->i++; | |
1448 } | |
1449 | |
1450 return ret; | |
1451 } | |
1452 | |
1453 inline bool sanitize (hb_sanitize_context_t *c) { | |
1454 TRACE_SANITIZE (); | |
1455 if (unlikely (!Lookup::sanitize (c))) return false; | |
1456 OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTab
le> > (subTable); | |
1457 return list.sanitize (c, this, get_type ()); | |
1458 } | |
1459 }; | |
1460 | |
1461 typedef OffsetListOf<PosLookup> PosLookupList; | |
1462 | |
1463 /* | |
1464 * GPOS | |
1465 */ | |
1466 | |
1467 struct GPOS : GSUBGPOS | |
1468 { | |
1469 static const hb_tag_t Tag = HB_OT_TAG_GPOS; | |
1470 | |
1471 inline const PosLookup& get_lookup (unsigned int i) const | |
1472 { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); } | |
1473 | |
1474 inline bool position_lookup (hb_ot_layout_context_t *layout, | |
1475 hb_buffer_t *buffer, | |
1476 unsigned int lookup_index, | |
1477 hb_mask_t mask) const | |
1478 { return get_lookup (lookup_index).apply_string (layout, buffer, mask); } | |
1479 | |
1480 static inline void position_finish (hb_buffer_t *buffer); | |
1481 | |
1482 inline bool sanitize (hb_sanitize_context_t *c) { | |
1483 TRACE_SANITIZE (); | |
1484 if (unlikely (!GSUBGPOS::sanitize (c))) return false; | |
1485 OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList)
; | |
1486 return list.sanitize (c, this); | |
1487 } | |
1488 public: | |
1489 DEFINE_SIZE_STATIC (10); | |
1490 }; | |
1491 | |
1492 void | |
1493 GPOS::position_finish (hb_buffer_t *buffer) | |
1494 { | |
1495 unsigned int i, j; | |
1496 unsigned int len = hb_buffer_get_length (buffer); | |
1497 hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer); | |
1498 hb_direction_t direction = buffer->props.direction; | |
1499 | |
1500 /* Handle cursive connections: | |
1501 * First handle all chain-back connections, then handle all chain-forward conn
ections. */ | |
1502 if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) | |
1503 { | |
1504 for (j = 0; j < len; j++) { | |
1505 if (pos[j].cursive_chain() < 0) | |
1506 pos[j].y_offset += pos[j + pos[j].cursive_chain()].y_offset; | |
1507 } | |
1508 for (i = len; i > 0; i--) { | |
1509 j = i - 1; | |
1510 if (pos[j].cursive_chain() > 0) | |
1511 pos[j].y_offset += pos[j + pos[j].cursive_chain()].y_offset; | |
1512 } | |
1513 } | |
1514 else | |
1515 { | |
1516 for (j = 0; j < len; j++) { | |
1517 if (pos[j].cursive_chain() < 0) | |
1518 pos[j].x_offset += pos[j + pos[j].cursive_chain()].x_offset; | |
1519 } | |
1520 for (i = len; i > 0; i--) { | |
1521 j = i - 1; | |
1522 if (pos[j].cursive_chain() > 0) | |
1523 pos[j].x_offset += pos[j + pos[j].cursive_chain()].x_offset; | |
1524 } | |
1525 } | |
1526 | |
1527 | |
1528 /* Handle attachments */ | |
1529 for (i = 0; i < len; i++) | |
1530 if (pos[i].attach_lookback()) | |
1531 { | |
1532 unsigned int back = i - pos[i].attach_lookback(); | |
1533 pos[i].x_offset += pos[back].x_offset; | |
1534 pos[i].y_offset += pos[back].y_offset; | |
1535 | |
1536 if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction)) | |
1537 for (j = back + 1; j < i + 1; j++) { | |
1538 pos[i].x_offset += pos[j].x_advance; | |
1539 pos[i].y_offset += pos[j].y_advance; | |
1540 } | |
1541 else | |
1542 for (j = back; j < i; j++) { | |
1543 pos[i].x_offset -= pos[j].x_advance; | |
1544 pos[i].y_offset -= pos[j].y_advance; | |
1545 } | |
1546 } | |
1547 } | |
1548 | |
1549 | |
1550 /* Out-of-class implementation for methods recursing */ | |
1551 | |
1552 inline bool ExtensionPos::apply (hb_apply_context_t *c) const | |
1553 { | |
1554 TRACE_APPLY (); | |
1555 return get_subtable ().apply (c, get_type ()); | |
1556 } | |
1557 | |
1558 inline bool ExtensionPos::sanitize (hb_sanitize_context_t *c) | |
1559 { | |
1560 TRACE_SANITIZE (); | |
1561 if (unlikely (!Extension::sanitize (c))) return false; | |
1562 unsigned int offset = get_offset (); | |
1563 if (unlikely (!offset)) return true; | |
1564 return StructAtOffset<PosLookupSubTable> (this, offset).sanitize (c, get_type
()); | |
1565 } | |
1566 | |
1567 static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_i
ndex) | |
1568 { | |
1569 const GPOS &gpos = *(c->layout->face->ot_layout->gpos); | |
1570 const PosLookup &l = gpos.get_lookup (lookup_index); | |
1571 | |
1572 if (unlikely (c->nesting_level_left == 0)) | |
1573 return false; | |
1574 | |
1575 if (unlikely (c->context_length < 1)) | |
1576 return false; | |
1577 | |
1578 return l.apply_once (c->layout, c->buffer, c->lookup_mask, c->context_length,
c->nesting_level_left - 1); | |
1579 } | |
1580 | |
1581 | |
1582 #undef attach_lookback | |
1583 #undef cursive_chain | |
1584 | |
1585 | |
1586 HB_END_DECLS | |
1587 | |
1588 #endif /* HB_OT_LAYOUT_GPOS_PRIVATE_HH */ | |
OLD | NEW |