X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fhb-ot-layout-gpos-private.hh;h=59750ab1a78aae10e899d8ea53dfdda02e338301;hb=7b08b0a7f2057937dfc3ab2ec191656bf2386463;hp=c13969235d7bee061c4d4710b9d672c4e22999b5;hpb=33d13fdda99acaeffa9600737e8870278d053ebe;p=framework%2Fuifw%2Fharfbuzz.git diff --git a/src/hb-ot-layout-gpos-private.hh b/src/hb-ot-layout-gpos-private.hh index c139692..59750ab 100644 --- a/src/hb-ot-layout-gpos-private.hh +++ b/src/hb-ot-layout-gpos-private.hh @@ -1,5 +1,6 @@ /* - * Copyright (C) 2007,2008,2009 Red Hat, Inc. + * Copyright © 2007,2008,2009,2010 Red Hat, Inc. + * Copyright © 2010 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -22,6 +23,7 @@ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod */ #ifndef HB_OT_LAYOUT_GPOS_PRIVATE_HH @@ -29,14 +31,19 @@ #include "hb-ot-layout-gsubgpos-private.hh" -#define HB_OT_LAYOUT_GPOS_NO_LAST ((unsigned int) -1) +HB_BEGIN_DECLS + + +/* buffer var allocations */ +#define attach_lookback() var.u16[0] /* number of glyphs to go back to attach this glyph to its base */ +#define cursive_chain() var.i16[1] /* character to which this connects, may be positive or negative */ + /* Shared Tables: ValueRecord, Anchor Table, and MarkArray */ -typedef SHORT Value; +typedef USHORT Value; -typedef Value ValueRecord[VAR0]; -ASSERT_SIZE_VAR (ValueRecord, 0, Value); +typedef Value ValueRecord[VAR]; struct ValueFormat : USHORT { @@ -82,49 +89,58 @@ struct ValueFormat : USHORT * PosTable (may be NULL) */ #endif - inline unsigned int get_len () const + inline unsigned int get_len (void) const { return _hb_popcount32 ((unsigned int) *this); } - inline unsigned int get_size () const - { return get_len () * Value::get_size (); } - - void apply_value (hb_ot_layout_context_t *layout_context, - const char *base, - const Value *values, - hb_internal_glyph_position_t *glyph_pos) const + inline unsigned int get_size (void) const + { return get_len () * Value::static_size; } + + void apply_value (hb_font_t *font, + hb_direction_t direction, + const void *base, + const Value *values, + hb_glyph_position_t &glyph_pos) const { unsigned int x_ppem, y_ppem; - hb_16dot16_t x_scale, y_scale; unsigned int format = *this; + hb_bool_t horizontal = HB_DIRECTION_IS_HORIZONTAL (direction); if (!format) return; - x_scale = layout_context->font->x_scale; - y_scale = layout_context->font->y_scale; - /* design units -> fractional pixel */ - if (format & xPlacement) glyph_pos->x_offset += _hb_16dot16_mul_round (x_scale, *(SHORT*)values++); - if (format & yPlacement) glyph_pos->y_offset += _hb_16dot16_mul_round (y_scale, *(SHORT*)values++); - if (format & xAdvance) glyph_pos->x_advance += _hb_16dot16_mul_round (x_scale, *(SHORT*)values++); - if (format & yAdvance) glyph_pos->y_advance += _hb_16dot16_mul_round (y_scale, *(SHORT*)values++); + if (format & xPlacement) glyph_pos.x_offset += font->em_scale_x (get_short (values++)); + if (format & yPlacement) glyph_pos.y_offset += font->em_scale_y (get_short (values++)); + if (format & xAdvance) { + if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values++)); else values++; + } + /* y_advance values grow downward but font-space grows upward, hence negation */ + if (format & yAdvance) { + if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values++)); else values++; + } + + if (!has_device ()) return; + + x_ppem = font->x_ppem; + y_ppem = font->y_ppem; + + if (!x_ppem && !y_ppem) return; - x_ppem = layout_context->font->x_ppem; - y_ppem = layout_context->font->y_ppem; /* pixel -> fractional pixel */ if (format & xPlaDevice) { - if (x_ppem) glyph_pos->x_offset += (base+*(OffsetTo*)values++).get_delta (x_ppem) << 16; else values++; + if (x_ppem) glyph_pos.x_offset += (base + get_device (values++)).get_x_delta (font); else values++; } if (format & yPlaDevice) { - if (y_ppem) glyph_pos->y_offset += (base+*(OffsetTo*)values++).get_delta (y_ppem) << 16; else values++; + if (y_ppem) glyph_pos.y_offset += (base + get_device (values++)).get_y_delta (font); else values++; } if (format & xAdvDevice) { - if (x_ppem) glyph_pos->x_advance += (base+*(OffsetTo*)values++).get_delta (x_ppem) << 16; else values++; + if (horizontal && x_ppem) glyph_pos.x_advance += (base + get_device (values++)).get_x_delta (font); else values++; } if (format & yAdvDevice) { - if (y_ppem) glyph_pos->y_advance += (base+*(OffsetTo*)values++).get_delta (y_ppem) << 16; else values++; + /* y_advance values grow downward but font-space grows upward, hence negation */ + if (!horizontal && y_ppem) glyph_pos.y_advance -= (base + get_device (values++)).get_y_delta (font); else values++; } } private: - inline bool sanitize_value_devices (SANITIZE_ARG_DEF, void *base, const Value *values) { + inline bool sanitize_value_devices (hb_sanitize_context_t *c, void *base, Value *values) { unsigned int format = *this; if (format & xPlacement) values++; @@ -132,38 +148,45 @@ struct ValueFormat : USHORT if (format & xAdvance) values++; if (format & yAdvance) values++; - if ((format & xPlaDevice) && !SANITIZE_BASE (*(OffsetTo*)values++, base)) return false; - if ((format & yPlaDevice) && !SANITIZE_BASE (*(OffsetTo*)values++, base)) return false; - if ((format & xAdvDevice) && !SANITIZE_BASE (*(OffsetTo*)values++, base)) return false; - if ((format & yAdvDevice) && !SANITIZE_BASE (*(OffsetTo*)values++, base)) return false; + if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false; + if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false; + if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false; + if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false; return true; } + static inline OffsetTo& get_device (Value* value) + { return *CastP > (value); } + static inline const OffsetTo& get_device (const Value* value) + { return *CastP > (value); } + + static inline const SHORT& get_short (const Value* value) + { return *CastP (value); } + public: - inline bool has_device () { + inline bool has_device (void) const { unsigned int format = *this; return (format & devices) != 0; } - inline bool sanitize_value (SANITIZE_ARG_DEF, void *base, const Value *values) { + inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *values) { TRACE_SANITIZE (); - - return SANITIZE_MEM (values, get_size ()) && - (!has_device () || sanitize_value_devices (SANITIZE_ARG, base, values)); + return c->check_range (values, get_size ()) + && (!has_device () || sanitize_value_devices (c, base, values)); } - inline bool sanitize_values (SANITIZE_ARG_DEF, void *base, const Value *values, unsigned int count) { + inline bool sanitize_values (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count) { TRACE_SANITIZE (); unsigned int len = get_len (); - if (!SANITIZE_ARRAY (values, get_size (), count)) return false; + if (!c->check_array (values, get_size (), count)) return false; if (!has_device ()) return true; for (unsigned int i = 0; i < count; i++) { - if (!sanitize_value_devices (SANITIZE_ARG, base, values)) + if (!sanitize_value_devices (c, base, values)) return false; values += len; } @@ -172,13 +195,13 @@ struct ValueFormat : USHORT } /* Just sanitize referenced Device tables. Doesn't check the values themselves. */ - inline bool sanitize_values_stride_unsafe (SANITIZE_ARG_DEF, void *base, const Value *values, unsigned int count, unsigned int stride) { + inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count, unsigned int stride) { TRACE_SANITIZE (); if (!has_device ()) return true; for (unsigned int i = 0; i < count; i++) { - if (!sanitize_value_devices (SANITIZE_ARG, base, values)) + if (!sanitize_value_devices (c, base, values)) return false; values += stride; } @@ -186,7 +209,6 @@ struct ValueFormat : USHORT return true; } }; -ASSERT_SIZE (ValueFormat, 2); struct AnchorFormat1 @@ -194,47 +216,48 @@ struct AnchorFormat1 friend struct Anchor; private: - inline void get_anchor (hb_ot_layout_context_t *layout_context, hb_codepoint_t glyph_id HB_UNUSED, + inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED, hb_position_t *x, hb_position_t *y) const { - *x = _hb_16dot16_mul_round (layout_context->font->x_scale, xCoordinate); - *y = _hb_16dot16_mul_round (layout_context->font->y_scale, yCoordinate); + *x = font->em_scale_x (xCoordinate); + *y = font->em_scale_y (yCoordinate); } - inline bool sanitize (SANITIZE_ARG_DEF) { + inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return SANITIZE_SELF (); + return c->check_struct (this); } private: USHORT format; /* Format identifier--format = 1 */ SHORT xCoordinate; /* Horizontal value--in design units */ SHORT yCoordinate; /* Vertical value--in design units */ + public: + DEFINE_SIZE_STATIC (6); }; -ASSERT_SIZE (AnchorFormat1, 6); struct AnchorFormat2 { friend struct Anchor; private: - inline void get_anchor (hb_ot_layout_context_t *layout_context, hb_codepoint_t glyph_id, + inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id, hb_position_t *x, hb_position_t *y) const { - unsigned int x_ppem = layout_context->font->x_ppem; - unsigned int y_ppem = layout_context->font->y_ppem; + unsigned int x_ppem = font->x_ppem; + unsigned int y_ppem = font->y_ppem; hb_position_t cx, cy; - hb_bool_t ret; + hb_bool_t ret = false; if (x_ppem || y_ppem) - ret = hb_font_get_contour_point (layout_context->font, layout_context->face, anchorPoint, glyph_id, &cx, &cy); - *x = x_ppem && ret ? cx : _hb_16dot16_mul_round (layout_context->font->x_scale, xCoordinate); - *y = y_ppem && ret ? cy : _hb_16dot16_mul_round (layout_context->font->y_scale, yCoordinate); + ret = hb_font_get_glyph_contour_point_for_origin (font, glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy); + *x = x_ppem && ret ? cx : font->em_scale_x (xCoordinate); + *y = y_ppem && ret ? cy : font->em_scale_y (yCoordinate); } - inline bool sanitize (SANITIZE_ARG_DEF) { + inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return SANITIZE_SELF (); + return c->check_struct (this); } private: @@ -242,30 +265,32 @@ struct AnchorFormat2 SHORT xCoordinate; /* Horizontal value--in design units */ SHORT yCoordinate; /* Vertical value--in design units */ USHORT anchorPoint; /* Index to glyph contour point */ + public: + DEFINE_SIZE_STATIC (8); }; -ASSERT_SIZE (AnchorFormat2, 8); struct AnchorFormat3 { friend struct Anchor; private: - inline void get_anchor (hb_ot_layout_context_t *layout_context, hb_codepoint_t glyph_id HB_UNUSED, + inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED, hb_position_t *x, hb_position_t *y) const { - *x = _hb_16dot16_mul_round (layout_context->font->x_scale, xCoordinate); - *y = _hb_16dot16_mul_round (layout_context->font->y_scale, yCoordinate); - - /* pixel -> fractional pixel */ - if (layout_context->font->x_ppem) - *x += (this+xDeviceTable).get_delta (layout_context->font->x_ppem) << 16; - if (layout_context->font->y_ppem) - *y += (this+yDeviceTable).get_delta (layout_context->font->y_ppem) << 16; + *x = font->em_scale_x (xCoordinate); + *y = font->em_scale_y (yCoordinate); + + if (font->x_ppem) + *x += (this+xDeviceTable).get_x_delta (font); + if (font->y_ppem) + *y += (this+yDeviceTable).get_x_delta (font); } - inline bool sanitize (SANITIZE_ARG_DEF) { + inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return SANITIZE_SELF () && SANITIZE_THIS2 (xDeviceTable, yDeviceTable); + return c->check_struct (this) + && xDeviceTable.sanitize (c, this) + && yDeviceTable.sanitize (c, this); } private: @@ -280,30 +305,31 @@ struct AnchorFormat3 yDeviceTable; /* Offset to Device table for Y * coordinate-- from beginning of * Anchor table (may be NULL) */ + public: + DEFINE_SIZE_STATIC (10); }; -ASSERT_SIZE (AnchorFormat3, 10); struct Anchor { - inline void get_anchor (hb_ot_layout_context_t *layout_context, hb_codepoint_t glyph_id, + inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id, hb_position_t *x, hb_position_t *y) const { *x = *y = 0; switch (u.format) { - case 1: u.format1->get_anchor (layout_context, glyph_id, x, y); return; - case 2: u.format2->get_anchor (layout_context, glyph_id, x, y); return; - case 3: u.format3->get_anchor (layout_context, glyph_id, x, y); return; - default: return; + case 1: u.format1.get_anchor (font, glyph_id, x, y); return; + case 2: u.format2.get_anchor (font, glyph_id, x, y); return; + case 3: u.format3.get_anchor (font, glyph_id, x, y); return; + default: return; } } - inline bool sanitize (SANITIZE_ARG_DEF) { + inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!SANITIZE (u.format)) return false; + if (!u.format.sanitize (c)) return false; switch (u.format) { - case 1: return u.format1->sanitize (SANITIZE_ARG); - case 2: return u.format2->sanitize (SANITIZE_ARG); - case 3: return u.format3->sanitize (SANITIZE_ARG); + case 1: return u.format1.sanitize (c); + case 2: return u.format2.sanitize (c); + case 3: return u.format3.sanitize (c); default:return true; } } @@ -311,28 +337,30 @@ struct Anchor private: union { USHORT format; /* Format identifier */ - AnchorFormat1 format1[VAR]; - AnchorFormat2 format2[VAR]; - AnchorFormat3 format3[VAR]; + AnchorFormat1 format1; + AnchorFormat2 format2; + AnchorFormat3 format3; } u; + public: + DEFINE_SIZE_UNION (2, format); }; struct AnchorMatrix { inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols) const { - if (HB_UNLIKELY (row >= rows || col >= cols)) return Null(Anchor); + if (unlikely (row >= rows || col >= cols)) return Null(Anchor); return this+matrix[row * cols + col]; } - inline bool sanitize (SANITIZE_ARG_DEF, unsigned int cols) { + inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) { TRACE_SANITIZE (); - if (!SANITIZE_SELF ()) return false; - if (HB_UNLIKELY (cols >= ((unsigned int) -1) / rows)) return false; + if (!c->check_struct (this)) return false; + if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return false; unsigned int count = rows * cols; - if (!SANITIZE_ARRAY (matrix, matrix[0].get_size (), count)) return false; + if (!c->check_array (matrix, matrix[0].static_size, count)) return false; for (unsigned int i = 0; i < count; i++) - if (!SANITIZE_THIS (matrix[i])) return false; + if (!matrix[i].sanitize (c, this)) return false; return true; } @@ -341,19 +369,19 @@ struct AnchorMatrix OffsetTo matrix[VAR]; /* Matrix of offsets to Anchor tables-- * from beginning of AnchorMatrix table */ + public: + DEFINE_SIZE_ARRAY (2, matrix); }; -ASSERT_SIZE_VAR (AnchorMatrix, 2, OffsetTo); struct MarkRecord { friend struct MarkArray; - static inline unsigned int get_size () { return sizeof (MarkRecord); } - - inline bool sanitize (SANITIZE_ARG_DEF, void *base) { + inline bool sanitize (hb_sanitize_context_t *c, void *base) { TRACE_SANITIZE (); - return SANITIZE_SELF () && SANITIZE_BASE (markAnchor, base); + return c->check_struct (this) + && markAnchor.sanitize (c, base); } private: @@ -361,18 +389,19 @@ struct MarkRecord OffsetTo markAnchor; /* Offset to Anchor table--from * beginning of MarkArray table */ + public: + DEFINE_SIZE_STATIC (4); }; -ASSERT_SIZE (MarkRecord, 4); -struct MarkArray +struct MarkArray : ArrayOf /* Array of MarkRecords--in Coverage order */ { - inline bool apply (APPLY_ARG_DEF, + inline bool apply (hb_apply_context_t *c, unsigned int mark_index, unsigned int glyph_index, const AnchorMatrix &anchors, unsigned int class_count, unsigned int glyph_pos) const { TRACE_APPLY (); - const MarkRecord &record = markRecord[mark_index]; + const MarkRecord &record = ArrayOf::operator[](mark_index); unsigned int mark_class = record.klass; const Anchor& mark_anchor = this + record.markAnchor; @@ -380,30 +409,23 @@ struct MarkArray hb_position_t mark_x, mark_y, base_x, base_y; - mark_anchor.get_anchor (layout_context, IN_CURGLYPH (), &mark_x, &mark_y); - glyph_anchor.get_anchor (layout_context, IN_GLYPH (glyph_pos), &base_x, &base_y); + mark_anchor.get_anchor (c->font, c->buffer->info[c->buffer->i].codepoint, &mark_x, &mark_y); + glyph_anchor.get_anchor (c->font, c->buffer->info[glyph_pos].codepoint, &base_x, &base_y); - hb_internal_glyph_position_t *o = POSITION (buffer->in_pos); - o->x_advance = 0; - o->y_advance = 0; - o->x_offset = base_x - mark_x; - o->y_offset = base_y - mark_y; - o->back = buffer->in_pos - glyph_pos; + hb_glyph_position_t &o = c->buffer->pos[c->buffer->i]; + o.x_offset = base_x - mark_x; + o.y_offset = base_y - mark_y; + o.attach_lookback() = c->buffer->i - glyph_pos; - buffer->in_pos++; + c->buffer->i++; return true; } - inline bool sanitize (SANITIZE_ARG_DEF) { + inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return SANITIZE_THIS (markRecord); + return ArrayOf::sanitize (c, this); } - - private: - ArrayOf - markRecord; /* Array of MarkRecords--in Coverage order */ }; -ASSERT_SIZE (MarkArray, 2); /* Lookups */ @@ -413,23 +435,25 @@ struct SinglePosFormat1 friend struct SinglePos; private: - inline bool apply (APPLY_ARG_DEF) const + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - unsigned int index = (this+coverage) (IN_CURGLYPH ()); - if (HB_LIKELY (index == NOT_COVERED)) + unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint); + if (likely (index == NOT_COVERED)) return false; - valueFormat.apply_value (layout_context, CharP(this), values, CURPOSITION ()); + valueFormat.apply_value (c->font, c->direction, this, + values, c->buffer->pos[c->buffer->i]); - buffer->in_pos++; + c->buffer->i++; return true; } - inline bool sanitize (SANITIZE_ARG_DEF) { + inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return SANITIZE_SELF () && SANITIZE_THIS (coverage) && - valueFormat.sanitize_value (SANITIZE_ARG, CharP(this), values); + return c->check_struct (this) + && coverage.sanitize (c, this) + && valueFormat.sanitize_value (c, this, values); } private: @@ -442,36 +466,38 @@ struct SinglePosFormat1 ValueRecord values; /* Defines positioning * value(s)--applied to all glyphs in * the Coverage table */ + public: + DEFINE_SIZE_ARRAY (6, values); }; -ASSERT_SIZE_VAR (SinglePosFormat1, 6, ValueRecord); struct SinglePosFormat2 { friend struct SinglePos; private: - inline bool apply (APPLY_ARG_DEF) const + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - unsigned int index = (this+coverage) (IN_CURGLYPH ()); - if (HB_LIKELY (index == NOT_COVERED)) + unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint); + if (likely (index == NOT_COVERED)) return false; - if (HB_LIKELY (index >= valueCount)) + if (likely (index >= valueCount)) return false; - valueFormat.apply_value (layout_context, CharP(this), + valueFormat.apply_value (c->font, c->direction, this, &values[index * valueFormat.get_len ()], - CURPOSITION ()); + c->buffer->pos[c->buffer->i]); - buffer->in_pos++; + c->buffer->i++; return true; } - inline bool sanitize (SANITIZE_ARG_DEF) { + inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return SANITIZE_SELF () && SANITIZE_THIS (coverage) && - valueFormat.sanitize_values (SANITIZE_ARG, CharP(this), values, valueCount); + return c->check_struct (this) + && coverage.sanitize (c, this) + && valueFormat.sanitize_values (c, this, values, valueCount); } private: @@ -484,30 +510,31 @@ struct SinglePosFormat2 USHORT valueCount; /* Number of ValueRecords */ ValueRecord values; /* Array of ValueRecords--positioning * values applied to glyphs */ + public: + DEFINE_SIZE_ARRAY (8, values); }; -ASSERT_SIZE_VAR (SinglePosFormat2, 8, ValueRecord); struct SinglePos { friend struct PosLookupSubTable; private: - inline bool apply (APPLY_ARG_DEF) const + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); switch (u.format) { - case 1: return u.format1->apply (APPLY_ARG); - case 2: return u.format2->apply (APPLY_ARG); + case 1: return u.format1.apply (c); + case 2: return u.format2.apply (c); default:return false; } } - inline bool sanitize (SANITIZE_ARG_DEF) { + inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!SANITIZE (u.format)) return false; + if (!u.format.sanitize (c)) return false; switch (u.format) { - case 1: return u.format1->sanitize (SANITIZE_ARG); - case 2: return u.format2->sanitize (SANITIZE_ARG); + case 1: return u.format1.sanitize (c); + case 2: return u.format2.sanitize (c); default:return true; } } @@ -515,15 +542,15 @@ struct SinglePos private: union { USHORT format; /* Format identifier */ - SinglePosFormat1 format1[VAR]; - SinglePosFormat2 format2[VAR]; + SinglePosFormat1 format1; + SinglePosFormat2 format2; } u; }; struct PairValueRecord { - friend struct PairPosFormat1; + friend struct PairSet; private: GlyphID secondGlyph; /* GlyphID of second glyph in the @@ -531,102 +558,112 @@ struct PairValueRecord * Coverage table */ ValueRecord values; /* Positioning data for the first glyph * followed by for second glyph */ + public: + DEFINE_SIZE_ARRAY (2, values); }; -ASSERT_SIZE_VAR (PairValueRecord, 2, ValueRecord); struct PairSet { friend struct PairPosFormat1; - /* Note: Doesn't sanitize the Device entries in the ValueRecord */ - inline bool sanitize (SANITIZE_ARG_DEF, unsigned int format_len) { + inline bool apply (hb_apply_context_t *c, + const ValueFormat *valueFormats, + unsigned int pos) const + { + TRACE_APPLY (); + unsigned int len1 = valueFormats[0].get_len (); + unsigned int len2 = valueFormats[1].get_len (); + unsigned int record_size = USHORT::static_size * (1 + len1 + len2); + + unsigned int count = len; + const PairValueRecord *record = CastP (array); + for (unsigned int i = 0; i < count; i++) + { + if (c->buffer->info[pos].codepoint == record->secondGlyph) + { + valueFormats[0].apply_value (c->font, c->direction, this, + &record->values[0], c->buffer->pos[c->buffer->i]); + valueFormats[1].apply_value (c->font, c->direction, this, + &record->values[len1], c->buffer->pos[pos]); + if (len2) + pos++; + c->buffer->i = pos; + return true; + } + record = &StructAtOffset (record, record_size); + } + + return false; + } + + struct sanitize_closure_t { + void *base; + ValueFormat *valueFormats; + unsigned int len1; /* valueFormats[0].get_len() */ + unsigned int stride; /* 1 + len1 + len2 */ + }; + + inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) { TRACE_SANITIZE (); - if (!SANITIZE_SELF ()) return false; - unsigned int count = (1 + format_len) * len; - return SANITIZE_ARRAY (array, USHORT::get_size (), count); + if (!(c->check_struct (this) + && c->check_array (array, USHORT::static_size * closure->stride, len))) return false; + + unsigned int count = len; + PairValueRecord *record = CastP (array); + return closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride) + && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride); } private: USHORT len; /* Number of PairValueRecords */ - PairValueRecord - array[VAR]; /* Array of PairValueRecords--ordered + USHORT array[VAR]; /* Array of PairValueRecords--ordered * by GlyphID of the second glyph */ + public: + DEFINE_SIZE_ARRAY (2, array); }; -ASSERT_SIZE_VAR (PairSet, 2, PairValueRecord); struct PairPosFormat1 { friend struct PairPos; private: - inline bool apply (APPLY_ARG_DEF) const + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - unsigned int end = MIN (buffer->in_length, buffer->in_pos + context_length); - if (HB_UNLIKELY (buffer->in_pos + 2 > end)) + unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length); + if (unlikely (c->buffer->i + 2 > end)) return false; - unsigned int index = (this+coverage) (IN_CURGLYPH ()); - if (HB_LIKELY (index == NOT_COVERED)) + unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint); + if (likely (index == NOT_COVERED)) return false; - unsigned int j = buffer->in_pos + 1; - while (_hb_ot_layout_skip_mark (layout_context->face, IN_INFO (j), context->lookup_flag, NULL)) + unsigned int j = c->buffer->i + 1; + while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[j], c->lookup_props, NULL)) { - if (HB_UNLIKELY (j == end)) + if (unlikely (j == end)) return false; j++; } - unsigned int len1 = valueFormat1.get_len (); - unsigned int len2 = valueFormat2.get_len (); - unsigned int record_size = USHORT::get_size () * (1 + len1 + len2); - - const PairSet &pair_set = this+pairSet[index]; - unsigned int count = pair_set.len; - const PairValueRecord *record = pair_set.array; - for (unsigned int i = 0; i < count; i++) - { - if (IN_GLYPH (j) == record->secondGlyph) - { - valueFormat1.apply_value (layout_context, CharP(this), &record->values[0], CURPOSITION ()); - valueFormat2.apply_value (layout_context, CharP(this), &record->values[len1], POSITION (j)); - if (len2) - j++; - buffer->in_pos = j; - return true; - } - record = &StructAtOffset (*record, record_size); - } - - return false; + return (this+pairSet[index]).apply (c, &valueFormat1, j); } - inline bool sanitize (SANITIZE_ARG_DEF) { + inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); unsigned int len1 = valueFormat1.get_len (); unsigned int len2 = valueFormat2.get_len (); - - if (!(SANITIZE_SELF () && SANITIZE_THIS (coverage) && - HB_LIKELY (pairSet.sanitize (SANITIZE_ARG, CharP(this), len1 + len2)))) return false; - - if (!(valueFormat1.has_device () || valueFormat2.has_device ())) return true; - - unsigned int stride = 1 + len1 + len2; - unsigned int count1 = pairSet.len; - for (unsigned int i = 0; i < count1; i++) - { - const PairSet &pair_set = this+pairSet[i]; - - unsigned int count2 = pair_set.len; - const PairValueRecord *record = pair_set.array; - if (!(valueFormat1.sanitize_values_stride_unsafe (SANITIZE_ARG, CharP(this), &record->values[0], count2, stride) && - valueFormat2.sanitize_values_stride_unsafe (SANITIZE_ARG, CharP(this), &record->values[len1], count2, stride))) - return false; - } - - return true; + PairSet::sanitize_closure_t closure = { + this, + &valueFormat1, + len1, + 1 + len1 + len2 + }; + + return c->check_struct (this) + && coverage.sanitize (c, this) + && pairSet.sanitize (c, this, &closure); } private: @@ -643,29 +680,30 @@ struct PairPosFormat1 OffsetArrayOf pairSet; /* Array of PairSet tables * ordered by Coverage Index */ + public: + DEFINE_SIZE_ARRAY (10, pairSet); }; -ASSERT_SIZE (PairPosFormat1, 10); struct PairPosFormat2 { friend struct PairPos; private: - inline bool apply (APPLY_ARG_DEF) const + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - unsigned int end = MIN (buffer->in_length, buffer->in_pos + context_length); - if (HB_UNLIKELY (buffer->in_pos + 2 > end)) + unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length); + if (unlikely (c->buffer->i + 2 > end)) return false; - unsigned int index = (this+coverage) (IN_CURGLYPH ()); - if (HB_LIKELY (index == NOT_COVERED)) + unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint); + if (likely (index == NOT_COVERED)) return false; - unsigned int j = buffer->in_pos + 1; - while (_hb_ot_layout_skip_mark (layout_context->face, IN_INFO (j), context->lookup_flag, NULL)) + unsigned int j = c->buffer->i + 1; + while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[j], c->lookup_props, NULL)) { - if (HB_UNLIKELY (j == end)) + if (unlikely (j == end)) return false; j++; } @@ -674,35 +712,39 @@ struct PairPosFormat2 unsigned int len2 = valueFormat2.get_len (); unsigned int record_len = len1 + len2; - unsigned int klass1 = (this+classDef1) (IN_CURGLYPH ()); - unsigned int klass2 = (this+classDef2) (IN_GLYPH (j)); - if (HB_UNLIKELY (klass1 >= class1Count || klass2 >= class2Count)) + unsigned int klass1 = (this+classDef1) (c->buffer->info[c->buffer->i].codepoint); + unsigned int klass2 = (this+classDef2) (c->buffer->info[j].codepoint); + if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return false; const Value *v = &values[record_len * (klass1 * class2Count + klass2)]; - valueFormat1.apply_value (layout_context, CharP(this), v, CURPOSITION ()); - valueFormat2.apply_value (layout_context, CharP(this), v + len1, POSITION (j)); + valueFormat1.apply_value (c->font, c->direction, this, + v, c->buffer->pos[c->buffer->i]); + valueFormat2.apply_value (c->font, c->direction, this, + v + len1, c->buffer->pos[j]); if (len2) j++; - buffer->in_pos = j; + c->buffer->i = j; return true; } - inline bool sanitize (SANITIZE_ARG_DEF) { + inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!(SANITIZE_SELF () && SANITIZE_THIS (coverage) && - SANITIZE_THIS2 (classDef1, classDef2))) return false; + if (!(c->check_struct (this) + && coverage.sanitize (c, this) + && classDef1.sanitize (c, this) + && classDef2.sanitize (c, this))) return false; unsigned int len1 = valueFormat1.get_len (); unsigned int len2 = valueFormat2.get_len (); unsigned int stride = len1 + len2; unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size (); unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count; - return SANITIZE_ARRAY (values, record_size, count) && - valueFormat1.sanitize_values_stride_unsafe (SANITIZE_ARG, CharP(this), &values[0], count, stride) && - valueFormat2.sanitize_values_stride_unsafe (SANITIZE_ARG, CharP(this), &values[len1], count, stride); + return c->check_array (values, record_size, count) && + valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) && + valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride); } private: @@ -731,30 +773,31 @@ struct PairPosFormat2 ValueRecord values; /* Matrix of value pairs: * class1-major, class2-minor, * Each entry has value1 and value2 */ + public: + DEFINE_SIZE_ARRAY (16, values); }; -ASSERT_SIZE_VAR (PairPosFormat2, 16, ValueRecord); struct PairPos { friend struct PosLookupSubTable; private: - inline bool apply (APPLY_ARG_DEF) const + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); switch (u.format) { - case 1: return u.format1->apply (APPLY_ARG); - case 2: return u.format2->apply (APPLY_ARG); + case 1: return u.format1.apply (c); + case 2: return u.format2.apply (c); default:return false; } } - inline bool sanitize (SANITIZE_ARG_DEF) { + inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!SANITIZE (u.format)) return false; + if (!u.format.sanitize (c)) return false; switch (u.format) { - case 1: return u.format1->sanitize (SANITIZE_ARG); - case 2: return u.format2->sanitize (SANITIZE_ARG); + case 1: return u.format1.sanitize (c); + case 2: return u.format2.sanitize (c); default:return true; } } @@ -762,21 +805,23 @@ struct PairPos private: union { USHORT format; /* Format identifier */ - PairPosFormat1 format1[VAR]; - PairPosFormat2 format2[VAR]; + PairPosFormat1 format1; + PairPosFormat2 format2; } u; }; struct EntryExitRecord { - static inline unsigned int get_size () { return sizeof (EntryExitRecord); } + friend struct CursivePosFormat1; - inline bool sanitize (SANITIZE_ARG_DEF, void *base) { + inline bool sanitize (hb_sanitize_context_t *c, void *base) { TRACE_SANITIZE (); - return SANITIZE_BASE2 (entryAnchor, exitAnchor, base); + return entryAnchor.sanitize (c, base) + && exitAnchor.sanitize (c, base); } + private: OffsetTo entryAnchor; /* Offset to EntryAnchor table--from * beginning of CursivePos @@ -785,192 +830,110 @@ struct EntryExitRecord exitAnchor; /* Offset to ExitAnchor table--from * beginning of CursivePos * subtable--may be NULL */ + public: + DEFINE_SIZE_STATIC (4); }; -ASSERT_SIZE (EntryExitRecord, 4); struct CursivePosFormat1 { friend struct CursivePos; private: - inline bool apply (APPLY_ARG_DEF) const + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - /* Now comes the messiest part of the whole OpenType - specification. At first glance, cursive connections seem easy - to understand, but there are pitfalls! The reason is that - the specs don't mention how to compute the advance values - resp. glyph offsets. I was told it would be an omission, to - be fixed in the next OpenType version... Again many thanks to - Andrei Burago for clarifications. - - Consider the following example: - - | xadv1 | - +---------+ - | | - +-----+--+ 1 | - | | .| | - | 0+--+------+ - | 2 | - | | - 0+--------+ - | xadv2 | - - glyph1: advance width = 12 - anchor point = (3,1) - - glyph2: advance width = 11 - anchor point = (9,4) - - LSB is 1 for both glyphs (so the boxes drawn above are glyph - bboxes). Writing direction is R2L; `0' denotes the glyph's - coordinate origin. - - Now the surprising part: The advance width of the *left* glyph - (resp. of the *bottom* glyph) will be modified, no matter - whether the writing direction is L2R or R2L (resp. T2B or - B2T)! This assymetry is caused by the fact that the glyph's - coordinate origin is always the lower left corner for all - writing directions. - - Continuing the above example, we can compute the new - (horizontal) advance width of glyph2 as - - 9 - 3 = 6 , - - and the new vertical offset of glyph2 as - - 1 - 4 = -3 . - - - Vertical writing direction is far more complicated: - - a) Assuming that we recompute the advance height of the lower glyph: - - -- - +---------+ - -- | | - +-----+--+ 1 | yadv1 - | | .| | - yadv2 | 0+--+------+ -- BSB1 -- - | 2 | -- -- y_offset - | | - BSB2 -- 0+--------+ -- - -- -- - - glyph1: advance height = 6 - anchor point = (3,1) - - glyph2: advance height = 7 - anchor point = (9,4) - - TSB is 1 for both glyphs; writing direction is T2B. - - - BSB1 = yadv1 - (TSB1 + ymax1) - BSB2 = yadv2 - (TSB2 + ymax2) - y_offset = y2 - y1 - - vertical advance width of glyph2 - = y_offset + BSB2 - BSB1 - = (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1)) - = y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1) - = y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1 - - - b) Assuming that we recompute the advance height of the upper glyph: - - -- -- - +---------+ -- TSB1 - -- -- | | - TSB2 -- +-----+--+ 1 | yadv1 ymax1 - | | .| | - yadv2 | 0+--+------+ -- -- - ymax2 | 2 | -- y_offset - | | - -- 0+--------+ -- - -- - - glyph1: advance height = 6 - anchor point = (3,1) - - glyph2: advance height = 7 - anchor point = (9,4) - - TSB is 1 for both glyphs; writing direction is T2B. - - y_offset = y2 - y1 - - vertical advance width of glyph2 - = TSB1 + ymax1 + y_offset - (TSB2 + ymax2) - = TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2 - - - Comparing a) with b) shows that b) is easier to compute. I'll wait - for a reply from Andrei to see what should really be implemented... - - Since horizontal advance widths or vertical advance heights - can be used alone but not together, no ambiguity occurs. */ - - struct hb_ot_layout_context_t::info_t::gpos_t *gpi = &layout_context->info.gpos; - hb_codepoint_t last_pos = gpi->last; - gpi->last = HB_OT_LAYOUT_GPOS_NO_LAST; /* We don't handle mark glyphs here. */ - if (context->property == HB_OT_LAYOUT_GLYPH_CLASS_MARK) + if (c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK) return false; - unsigned int index = (this+coverage) (IN_CURGLYPH ()); - if (HB_LIKELY (index == NOT_COVERED)) + unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length); + if (unlikely (c->buffer->i + 2 > end)) return false; - const EntryExitRecord &record = entryExitRecord[index]; - - if (last_pos == HB_OT_LAYOUT_GPOS_NO_LAST || !record.entryAnchor) - goto end; - - hb_position_t entry_x, entry_y; - (this+record.entryAnchor).get_anchor (layout_context, IN_CURGLYPH (), &entry_x, &entry_y); - - /* TODO vertical */ + const EntryExitRecord &this_record = entryExitRecord[(this+coverage) (c->buffer->info[c->buffer->i].codepoint)]; + if (!this_record.exitAnchor) + return false; - if (buffer->direction == HB_DIRECTION_RTL) - { - /* advance is absolute, not relative */ - POSITION (buffer->in_pos)->x_advance = entry_x - gpi->anchor_x; - } - else + unsigned int j = c->buffer->i + 1; + while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[j], c->lookup_props, NULL)) { - /* advance is absolute, not relative */ - POSITION (last_pos)->x_advance = gpi->anchor_x - entry_x; + if (unlikely (j == end)) + return false; + j++; } - if (context->lookup_flag & LookupFlag::RightToLeft) - { - POSITION (last_pos)->cursive_chain = last_pos - buffer->in_pos; - POSITION (last_pos)->y_offset = entry_y - gpi->anchor_y; - } - else - { - POSITION (buffer->in_pos)->cursive_chain = buffer->in_pos - last_pos; - POSITION (buffer->in_pos)->y_offset = gpi->anchor_y - entry_y; + const EntryExitRecord &next_record = entryExitRecord[(this+coverage) (c->buffer->info[j].codepoint)]; + if (!next_record.entryAnchor) + return false; + + unsigned int i = c->buffer->i; + + hb_position_t entry_x, entry_y, exit_x, exit_y; + (this+this_record.exitAnchor).get_anchor (c->font, c->buffer->info[i].codepoint, &exit_x, &exit_y); + (this+next_record.entryAnchor).get_anchor (c->font, c->buffer->info[j].codepoint, &entry_x, &entry_y); + + hb_glyph_position_t *pos = c->buffer->pos; + + hb_position_t d; + /* Main-direction adjustment */ + switch (c->direction) { + case HB_DIRECTION_LTR: + pos[i].x_advance = exit_x + pos[i].x_offset; + + d = entry_x + pos[j].x_offset; + pos[j].x_advance -= d; + pos[j].x_offset -= d; + break; + case HB_DIRECTION_RTL: + d = exit_x + pos[i].x_offset; + pos[i].x_advance -= d; + pos[i].x_offset -= d; + + pos[j].x_advance = entry_x + pos[j].x_offset; + break; + case HB_DIRECTION_TTB: + pos[i].y_advance = exit_y + pos[i].y_offset; + + d = entry_y + pos[j].y_offset; + pos[j].y_advance -= d; + pos[j].y_offset -= d; + break; + case HB_DIRECTION_BTT: + d = exit_y + pos[i].y_offset; + pos[i].y_advance -= d; + pos[i].y_offset -= d; + + pos[j].y_advance = entry_y; + break; + case HB_DIRECTION_INVALID: + default: + break; } - end: - if (record.exitAnchor) - { - gpi->last = buffer->in_pos; - (this+record.exitAnchor).get_anchor (layout_context, IN_CURGLYPH (), &gpi->anchor_x, &gpi->anchor_y); + /* Cross-direction adjustment */ + if (c->lookup_props & LookupFlag::RightToLeft) { + pos[i].cursive_chain() = j - i; + if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction))) + pos[i].y_offset = entry_y - exit_y; + else + pos[i].x_offset = entry_x - exit_x; + } else { + pos[j].cursive_chain() = i - j; + if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction))) + pos[j].y_offset = exit_y - entry_y; + else + pos[j].x_offset = exit_x - entry_x; } - buffer->in_pos++; + c->buffer->i = j; return true; } - inline bool sanitize (SANITIZE_ARG_DEF) { + inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return SANITIZE_THIS2 (coverage, entryExitRecord); + return coverage.sanitize (c, this) + && entryExitRecord.sanitize (c, this); } private: @@ -981,28 +944,29 @@ struct CursivePosFormat1 ArrayOf entryExitRecord; /* Array of EntryExit records--in * Coverage Index order */ + public: + DEFINE_SIZE_ARRAY (6, entryExitRecord); }; -ASSERT_SIZE (CursivePosFormat1, 6); struct CursivePos { friend struct PosLookupSubTable; private: - inline bool apply (APPLY_ARG_DEF) const + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); switch (u.format) { - case 1: return u.format1->apply (APPLY_ARG); + case 1: return u.format1.apply (c); default:return false; } } - inline bool sanitize (SANITIZE_ARG_DEF) { + inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!SANITIZE (u.format)) return false; + if (!u.format.sanitize (c)) return false; switch (u.format) { - case 1: return u.format1->sanitize (SANITIZE_ARG); + case 1: return u.format1.sanitize (c); default:return true; } } @@ -1010,7 +974,7 @@ struct CursivePos private: union { USHORT format; /* Format identifier */ - CursivePosFormat1 format1[VAR]; + CursivePosFormat1 format1; } u; }; @@ -1025,40 +989,41 @@ struct MarkBasePosFormat1 friend struct MarkBasePos; private: - inline bool apply (APPLY_ARG_DEF) const + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - unsigned int mark_index = (this+markCoverage) (IN_CURGLYPH ()); - if (HB_LIKELY (mark_index == NOT_COVERED)) + unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->i].codepoint); + if (likely (mark_index == NOT_COVERED)) return false; /* now we search backwards for a non-mark glyph */ unsigned int property; - unsigned int j = buffer->in_pos; + unsigned int j = c->buffer->i; do { - if (HB_UNLIKELY (!j)) + if (unlikely (!j)) return false; j--; - } while (_hb_ot_layout_skip_mark (layout_context->face, IN_INFO (j), LookupFlag::IgnoreMarks, &property)); + } while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[j], LookupFlag::IgnoreMarks, &property)); -#if 0 - /* The following assertion is too strong. */ + /* The following assertion is too strong, so we've disabled it. */ if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH)) - return false; -#endif + {/*return false;*/} - unsigned int base_index = (this+baseCoverage) (IN_GLYPH (j)); + unsigned int base_index = (this+baseCoverage) (c->buffer->info[j].codepoint); if (base_index == NOT_COVERED) return false; - return (this+markArray).apply (APPLY_ARG, mark_index, base_index, this+baseArray, classCount, j); + return (this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, j); } - inline bool sanitize (SANITIZE_ARG_DEF) { + inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return SANITIZE_SELF () && SANITIZE_THIS3 (markCoverage, baseCoverage, markArray) && - HB_LIKELY (baseArray.sanitize (SANITIZE_ARG, CharP(this), classCount)); + return c->check_struct (this) + && markCoverage.sanitize (c, this) + && baseCoverage.sanitize (c, this) + && markArray.sanitize (c, this) + && baseArray.sanitize (c, this, (unsigned int) classCount); } private: @@ -1076,28 +1041,29 @@ struct MarkBasePosFormat1 OffsetTo baseArray; /* Offset to BaseArray table--from * beginning of MarkBasePos subtable */ + public: + DEFINE_SIZE_STATIC (12); }; -ASSERT_SIZE (MarkBasePosFormat1, 12); struct MarkBasePos { friend struct PosLookupSubTable; private: - inline bool apply (APPLY_ARG_DEF) const + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); switch (u.format) { - case 1: return u.format1->apply (APPLY_ARG); + case 1: return u.format1.apply (c); default:return false; } } - inline bool sanitize (SANITIZE_ARG_DEF) { + inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!SANITIZE (u.format)) return false; + if (!u.format.sanitize (c)) return false; switch (u.format) { - case 1: return u.format1->sanitize (SANITIZE_ARG); + case 1: return u.format1.sanitize (c); default:return true; } } @@ -1105,7 +1071,7 @@ struct MarkBasePos private: union { USHORT format; /* Format identifier */ - MarkBasePosFormat1 format1[VAR]; + MarkBasePosFormat1 format1; } u; }; @@ -1125,30 +1091,28 @@ struct MarkLigPosFormat1 friend struct MarkLigPos; private: - inline bool apply (APPLY_ARG_DEF) const + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - unsigned int mark_index = (this+markCoverage) (IN_CURGLYPH ()); - if (HB_LIKELY (mark_index == NOT_COVERED)) + unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->i].codepoint); + if (likely (mark_index == NOT_COVERED)) return false; /* now we search backwards for a non-mark glyph */ unsigned int property; - unsigned int j = buffer->in_pos; + unsigned int j = c->buffer->i; do { - if (HB_UNLIKELY (!j)) + if (unlikely (!j)) return false; j--; - } while (_hb_ot_layout_skip_mark (layout_context->face, IN_INFO (j), LookupFlag::IgnoreMarks, &property)); + } while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[j], LookupFlag::IgnoreMarks, &property)); -#if 0 - /* The following assertion is too strong. */ + /* The following assertion is too strong, so we've disabled it. */ if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE)) - return false; -#endif + {/*return false;*/} - unsigned int lig_index = (this+ligatureCoverage) (IN_GLYPH (j)); + unsigned int lig_index = (this+ligatureCoverage) (c->buffer->info[j].codepoint); if (lig_index == NOT_COVERED) return false; @@ -1157,29 +1121,32 @@ struct MarkLigPosFormat1 /* Find component to attach to */ unsigned int comp_count = lig_attach.rows; - if (HB_UNLIKELY (!comp_count)) + if (unlikely (!comp_count)) return false; unsigned int comp_index; /* We must now check whether the ligature ID of the current mark glyph * is identical to the ligature ID of the found ligature. If yes, we * can directly use the component index. If not, we attach the mark * glyph to the last component of the ligature. */ - if (IN_LIGID (j) && IN_LIGID (j) == IN_LIGID (buffer->in_pos) && IN_COMPONENT (buffer->in_pos)) + 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()) { - comp_index = IN_COMPONENT (buffer->in_pos) - 1; + comp_index = c->buffer->info[c->buffer->i].lig_comp() - 1; if (comp_index >= comp_count) comp_index = comp_count - 1; } else comp_index = comp_count - 1; - return (this+markArray).apply (APPLY_ARG, mark_index, comp_index, lig_attach, classCount, j); + return (this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j); } - inline bool sanitize (SANITIZE_ARG_DEF) { + inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return SANITIZE_SELF () && SANITIZE_THIS3 (markCoverage, ligatureCoverage, markArray) && - HB_LIKELY (ligatureArray.sanitize (SANITIZE_ARG, CharP(this), classCount)); + return c->check_struct (this) + && markCoverage.sanitize (c, this) + && ligatureCoverage.sanitize (c, this) + && markArray.sanitize (c, this) + && ligatureArray.sanitize (c, this, (unsigned int) classCount); } private: @@ -1198,28 +1165,29 @@ struct MarkLigPosFormat1 OffsetTo ligatureArray; /* Offset to LigatureArray table--from * beginning of MarkLigPos subtable */ + public: + DEFINE_SIZE_STATIC (12); }; -ASSERT_SIZE (MarkLigPosFormat1, 12); struct MarkLigPos { friend struct PosLookupSubTable; private: - inline bool apply (APPLY_ARG_DEF) const + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); switch (u.format) { - case 1: return u.format1->apply (APPLY_ARG); + case 1: return u.format1.apply (c); default:return false; } } - inline bool sanitize (SANITIZE_ARG_DEF) { + inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!SANITIZE (u.format)) return false; + if (!u.format.sanitize (c)) return false; switch (u.format) { - case 1: return u.format1->sanitize (SANITIZE_ARG); + case 1: return u.format1.sanitize (c); default:return true; } } @@ -1227,7 +1195,7 @@ struct MarkLigPos private: union { USHORT format; /* Format identifier */ - MarkLigPosFormat1 format1[VAR]; + MarkLigPosFormat1 format1; } u; }; @@ -1242,22 +1210,22 @@ struct MarkMarkPosFormat1 friend struct MarkMarkPos; private: - inline bool apply (APPLY_ARG_DEF) const + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - unsigned int mark1_index = (this+mark1Coverage) (IN_CURGLYPH ()); - if (HB_LIKELY (mark1_index == NOT_COVERED)) + unsigned int mark1_index = (this+mark1Coverage) (c->buffer->info[c->buffer->i].codepoint); + if (likely (mark1_index == NOT_COVERED)) return false; /* now we search backwards for a suitable mark glyph until a non-mark glyph */ unsigned int property; - unsigned int j = buffer->in_pos; + unsigned int j = c->buffer->i; do { - if (HB_UNLIKELY (!j)) + if (unlikely (!j)) return false; j--; - } while (_hb_ot_layout_skip_mark (layout_context->face, IN_INFO (j), context->lookup_flag, &property)); + } while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[j], c->lookup_props, &property)); if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)) return false; @@ -1265,21 +1233,24 @@ struct MarkMarkPosFormat1 /* Two marks match only if they belong to the same base, or same component * of the same ligature. That is, the component numbers must match, and * if those are non-zero, the ligid number should also match. */ - if ((IN_COMPONENT (j) != IN_COMPONENT (buffer->in_pos)) || - (IN_COMPONENT (j) && IN_LIGID (j) != IN_LIGID (buffer->in_pos))) + if ((c->buffer->info[j].lig_comp() != c->buffer->info[c->buffer->i].lig_comp()) || + (c->buffer->info[j].lig_comp() && c->buffer->info[j].lig_id() != c->buffer->info[c->buffer->i].lig_id())) return false; - unsigned int mark2_index = (this+mark2Coverage) (IN_GLYPH (j)); + unsigned int mark2_index = (this+mark2Coverage) (c->buffer->info[j].codepoint); if (mark2_index == NOT_COVERED) return false; - return (this+mark1Array).apply (APPLY_ARG, mark1_index, mark2_index, this+mark2Array, classCount, j); + return (this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j); } - inline bool sanitize (SANITIZE_ARG_DEF) { + inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return SANITIZE_SELF () && SANITIZE_THIS3 (mark1Coverage, mark2Coverage, mark1Array) && - HB_LIKELY (mark2Array.sanitize (SANITIZE_ARG, CharP(this), classCount)); + return c->check_struct (this) + && mark1Coverage.sanitize (c, this) + && mark2Coverage.sanitize (c, this) + && mark1Array.sanitize (c, this) + && mark2Array.sanitize (c, this, (unsigned int) classCount); } private: @@ -1299,28 +1270,29 @@ struct MarkMarkPosFormat1 OffsetTo mark2Array; /* Offset to Mark2Array table--from * beginning of MarkMarkPos subtable */ + public: + DEFINE_SIZE_STATIC (12); }; -ASSERT_SIZE (MarkMarkPosFormat1, 12); struct MarkMarkPos { friend struct PosLookupSubTable; private: - inline bool apply (APPLY_ARG_DEF) const + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); switch (u.format) { - case 1: return u.format1->apply (APPLY_ARG); + case 1: return u.format1.apply (c); default:return false; } } - inline bool sanitize (SANITIZE_ARG_DEF) { + inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!SANITIZE (u.format)) return false; + if (!u.format.sanitize (c)) return false; switch (u.format) { - case 1: return u.format1->sanitize (SANITIZE_ARG); + case 1: return u.format1.sanitize (c); default:return true; } } @@ -1328,22 +1300,24 @@ struct MarkMarkPos private: union { USHORT format; /* Format identifier */ - MarkMarkPosFormat1 format1[VAR]; + MarkMarkPosFormat1 format1; } u; }; -static inline bool position_lookup (APPLY_ARG_DEF, unsigned int lookup_index); +HB_BEGIN_DECLS +static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index); +HB_END_DECLS struct ContextPos : Context { friend struct PosLookupSubTable; private: - inline bool apply (APPLY_ARG_DEF) const + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - return Context::apply (APPLY_ARG, position_lookup); + return Context::apply (c, position_lookup); } }; @@ -1352,10 +1326,10 @@ struct ChainContextPos : ChainContext friend struct PosLookupSubTable; private: - inline bool apply (APPLY_ARG_DEF) const + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - return ChainContext::apply (APPLY_ARG, position_lookup); + return ChainContext::apply (c, position_lookup); } }; @@ -1368,13 +1342,13 @@ struct ExtensionPos : Extension inline const struct PosLookupSubTable& get_subtable (void) const { unsigned int offset = get_offset (); - if (HB_UNLIKELY (!offset)) return Null(PosLookupSubTable); - return StructAtOffset (*this, offset); + if (unlikely (!offset)) return Null(PosLookupSubTable); + return StructAtOffset (this, offset); } - inline bool apply (APPLY_ARG_DEF) const; + inline bool apply (hb_apply_context_t *c) const; - inline bool sanitize (SANITIZE_ARG_DEF); + inline bool sanitize (hb_sanitize_context_t *c); }; @@ -1400,53 +1374,54 @@ struct PosLookupSubTable Extension = 9 }; - inline bool apply (APPLY_ARG_DEF, unsigned int lookup_type) const + inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const { TRACE_APPLY (); switch (lookup_type) { - case Single: return u.single->apply (APPLY_ARG); - case Pair: return u.pair->apply (APPLY_ARG); - case Cursive: return u.cursive->apply (APPLY_ARG); - case MarkBase: return u.markBase->apply (APPLY_ARG); - case MarkLig: return u.markLig->apply (APPLY_ARG); - case MarkMark: return u.markMark->apply (APPLY_ARG); - case Context: return u.context->apply (APPLY_ARG); - case ChainContext: return u.chainContext->apply (APPLY_ARG); - case Extension: return u.extension->apply (APPLY_ARG); + case Single: return u.single.apply (c); + case Pair: return u.pair.apply (c); + case Cursive: return u.cursive.apply (c); + case MarkBase: return u.markBase.apply (c); + case MarkLig: return u.markLig.apply (c); + case MarkMark: return u.markMark.apply (c); + case Context: return u.c.apply (c); + case ChainContext: return u.chainContext.apply (c); + case Extension: return u.extension.apply (c); default:return false; } } - inline bool sanitize (SANITIZE_ARG_DEF) { + inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) { TRACE_SANITIZE (); - if (!SANITIZE (u.format)) return false; - switch (u.format) { - case Single: return u.single->sanitize (SANITIZE_ARG); - case Pair: return u.pair->sanitize (SANITIZE_ARG); - case Cursive: return u.cursive->sanitize (SANITIZE_ARG); - case MarkBase: return u.markBase->sanitize (SANITIZE_ARG); - case MarkLig: return u.markLig->sanitize (SANITIZE_ARG); - case MarkMark: return u.markMark->sanitize (SANITIZE_ARG); - case Context: return u.context->sanitize (SANITIZE_ARG); - case ChainContext: return u.chainContext->sanitize (SANITIZE_ARG); - case Extension: return u.extension->sanitize (SANITIZE_ARG); + switch (lookup_type) { + case Single: return u.single.sanitize (c); + case Pair: return u.pair.sanitize (c); + case Cursive: return u.cursive.sanitize (c); + case MarkBase: return u.markBase.sanitize (c); + case MarkLig: return u.markLig.sanitize (c); + case MarkMark: return u.markMark.sanitize (c); + case Context: return u.c.sanitize (c); + case ChainContext: return u.chainContext.sanitize (c); + case Extension: return u.extension.sanitize (c); default:return true; } } private: union { - USHORT format; - SinglePos single[VAR]; - PairPos pair[VAR]; - CursivePos cursive[VAR]; - MarkBasePos markBase[VAR]; - MarkLigPos markLig[VAR]; - MarkMarkPos markMark[VAR]; - ContextPos context[VAR]; - ChainContextPos chainContext[VAR]; - ExtensionPos extension[VAR]; + USHORT sub_format; + SinglePos single; + PairPos pair; + CursivePos cursive; + MarkBasePos markBase; + MarkLigPos markLig; + MarkMarkPos markMark; + ContextPos c; + ChainContextPos chainContext; + ExtensionPos extension; } u; + public: + DEFINE_SIZE_UNION (2, sub_format); }; @@ -1455,73 +1430,65 @@ struct PosLookup : Lookup inline const PosLookupSubTable& get_subtable (unsigned int i) const { return this+CastR > (subTable)[i]; } - inline bool apply_once (hb_ot_layout_context_t *layout_context, - hb_buffer_t *buffer, - unsigned int context_length, - unsigned int nesting_level_left, - unsigned int apply_depth) const + inline bool apply_once (hb_font_t *font, + hb_buffer_t *buffer, + hb_mask_t lookup_mask, + unsigned int context_length, + unsigned int nesting_level_left) const { unsigned int lookup_type = get_type (); - hb_apply_context_t context[1]; - - context->nesting_level_left = nesting_level_left; - context->lookup_flag = get_flag (); - - if (!_hb_ot_layout_check_glyph_property (layout_context->face, IN_CURINFO (), context->lookup_flag, &context->property)) + hb_apply_context_t c[1] = {{0}}; + + c->font = font; + c->face = font->face; + c->buffer = buffer; + c->direction = buffer->props.direction; + c->lookup_mask = lookup_mask; + c->context_length = context_length; + c->nesting_level_left = nesting_level_left; + c->lookup_props = get_props (); + + if (!_hb_ot_layout_check_glyph_property (c->face, &c->buffer->info[c->buffer->i], c->lookup_props, &c->property)) return false; for (unsigned int i = 0; i < get_subtable_count (); i++) - if (get_subtable (i).apply (APPLY_ARG, lookup_type)) + if (get_subtable (i).apply (c, lookup_type)) return true; return false; } - inline bool apply_string (hb_ot_layout_context_t *layout_context, + inline bool apply_string (hb_font_t *font, hb_buffer_t *buffer, hb_mask_t mask) const { bool ret = false; - if (HB_UNLIKELY (!buffer->in_length)) + if (unlikely (!buffer->len)) return false; - layout_context->info.gpos.last = HB_OT_LAYOUT_GPOS_NO_LAST; /* no last valid glyph for cursive pos. */ - - buffer->in_pos = 0; - while (buffer->in_pos < buffer->in_length) + buffer->i = 0; + while (buffer->i < buffer->len) { - bool done; - if (~IN_MASK (buffer->in_pos) & mask) - { - done = apply_once (layout_context, buffer, NO_CONTEXT, MAX_NESTING_LEVEL, 0); - ret |= done; - } + if ((buffer->info[buffer->i].mask & mask) && + apply_once (font, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL)) + ret = true; else - { - done = false; - /* Contrary to properties defined in GDEF, user-defined properties - will always stop a possible cursive positioning. */ - layout_context->info.gpos.last = HB_OT_LAYOUT_GPOS_NO_LAST; - } - - if (!done) - buffer->in_pos++; + buffer->i++; } return ret; } - inline bool sanitize (SANITIZE_ARG_DEF) { + inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (HB_UNLIKELY (!Lookup::sanitize (SANITIZE_ARG))) return false; + if (unlikely (!Lookup::sanitize (c))) return false; OffsetArrayOf &list = CastR > (subTable); - return SANITIZE_THIS (list); + return list.sanitize (c, this, get_type ()); } }; typedef OffsetListOf PosLookupList; -ASSERT_SIZE (PosLookupList, 2); /* * GPOS @@ -1534,52 +1501,126 @@ struct GPOS : GSUBGPOS inline const PosLookup& get_lookup (unsigned int i) const { return CastR (GSUBGPOS::get_lookup (i)); } - inline bool position_lookup (hb_ot_layout_context_t *layout_context, + inline bool position_lookup (hb_font_t *font, hb_buffer_t *buffer, unsigned int lookup_index, hb_mask_t mask) const - { return get_lookup (lookup_index).apply_string (layout_context, buffer, mask); } + { return get_lookup (lookup_index).apply_string (font, buffer, mask); } - inline bool sanitize (SANITIZE_ARG_DEF) { + static inline void position_finish (hb_buffer_t *buffer); + + inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (HB_UNLIKELY (!GSUBGPOS::sanitize (SANITIZE_ARG))) return false; + if (unlikely (!GSUBGPOS::sanitize (c))) return false; OffsetTo &list = CastR > (lookupList); - return SANITIZE_THIS (list); + return list.sanitize (c, this); } + public: + DEFINE_SIZE_STATIC (10); }; -ASSERT_SIZE (GPOS, 10); + + +static void +fix_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction) +{ + unsigned int j = pos[i].cursive_chain(); + if (likely (!j)) + return; + + j += i; + + pos[i].cursive_chain() = 0; + + fix_cursive_minor_offset (pos, j, direction); + + if (HB_DIRECTION_IS_HORIZONTAL (direction)) + pos[i].y_offset += pos[j].y_offset; + else + pos[i].x_offset += pos[j].x_offset; +} + +static void +fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction) +{ + if (likely (!(pos[i].attach_lookback()))) + return; + + unsigned int j = i - pos[i].attach_lookback(); + + pos[i].x_advance = 0; + pos[i].y_advance = 0; + pos[i].x_offset += pos[j].x_offset; + pos[i].y_offset += pos[j].y_offset; + + if (HB_DIRECTION_IS_FORWARD (direction)) + for (unsigned int k = j; k < i; k++) { + pos[i].x_offset -= pos[k].x_advance; + pos[i].y_offset -= pos[k].y_advance; + } + else + for (unsigned int k = j + 1; k < i + 1; k++) { + pos[i].x_offset += pos[k].x_advance; + pos[i].y_offset += pos[k].y_advance; + } +} + +void +GPOS::position_finish (hb_buffer_t *buffer) +{ + unsigned int len; + hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len); + hb_direction_t direction = buffer->props.direction; + + /* Handle cursive connections */ + for (unsigned int i = 0; i < len; i++) + { + fix_cursive_minor_offset (pos, i, direction); + } + + /* Handle attachments */ + for (unsigned int i = 0; i < len; i++) + { + fix_mark_attachment (pos, i, direction); + } +} /* Out-of-class implementation for methods recursing */ -inline bool ExtensionPos::apply (APPLY_ARG_DEF) const +inline bool ExtensionPos::apply (hb_apply_context_t *c) const { TRACE_APPLY (); - return get_subtable ().apply (APPLY_ARG, get_type ()); + return get_subtable ().apply (c, get_type ()); } -inline bool ExtensionPos::sanitize (SANITIZE_ARG_DEF) +inline bool ExtensionPos::sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (HB_UNLIKELY (!Extension::sanitize (SANITIZE_ARG))) return false; + if (unlikely (!Extension::sanitize (c))) return false; unsigned int offset = get_offset (); - if (HB_UNLIKELY (!offset)) return true; - return SANITIZE (StructAtOffset (*this, offset)); + if (unlikely (!offset)) return true; + return StructAtOffset (this, offset).sanitize (c, get_type ()); } -static inline bool position_lookup (APPLY_ARG_DEF, unsigned int lookup_index) +static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index) { - const GPOS &gpos = *(layout_context->face->ot_layout.gpos); + const GPOS &gpos = *(c->face->ot_layout->gpos); const PosLookup &l = gpos.get_lookup (lookup_index); - if (HB_UNLIKELY (context->nesting_level_left == 0)) + if (unlikely (c->nesting_level_left == 0)) return false; - if (HB_UNLIKELY (context_length < 1)) + if (unlikely (c->context_length < 1)) return false; - return l.apply_once (layout_context, buffer, context_length, context->nesting_level_left - 1, apply_depth + 1); + return l.apply_once (c->font, c->buffer, c->lookup_mask, c->context_length, c->nesting_level_left - 1); } +#undef attach_lookback +#undef cursive_chain + + +HB_END_DECLS + #endif /* HB_OT_LAYOUT_GPOS_PRIVATE_HH */