HarfBuzz text shaping engine http://harfbuzz.github.io/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1632 lines
47 KiB

16 years ago
/*
* Copyright (C) 2007,2008,2009,2010 Red Hat, Inc.
16 years ago
*
* This is part of HarfBuzz, a text shaping library.
16 years ago
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_LAYOUT_GPOS_PRIVATE_HH
#define HB_OT_LAYOUT_GPOS_PRIVATE_HH
16 years ago
#include "hb-ot-layout-gsubgpos-private.hh"
16 years ago
#define HB_OT_LAYOUT_GPOS_NO_LAST ((unsigned int) -1)
16 years ago
/* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
typedef USHORT Value;
typedef Value ValueRecord[VAR];
16 years ago
16 years ago
struct ValueFormat : USHORT
{
enum
{
xPlacement = 0x0001, /* Includes horizontal adjustment for placement */
yPlacement = 0x0002, /* Includes vertical adjustment for placement */
xAdvance = 0x0004, /* Includes horizontal adjustment for advance */
yAdvance = 0x0008, /* Includes vertical adjustment for advance */
xPlaDevice = 0x0010, /* Includes horizontal Device table for placement */
yPlaDevice = 0x0020, /* Includes vertical Device table for placement */
xAdvDevice = 0x0040, /* Includes horizontal Device table for advance */
yAdvDevice = 0x0080, /* Includes vertical Device table for advance */
ignored = 0x0F00, /* Was used in TrueType Open for MM fonts */
reserved = 0xF000, /* For future use */
devices = 0x00F0 /* Mask for having any Device table */
15 years ago
};
15 years ago
/* All fields are options. Only those available advance the value pointer. */
#if 0
SHORT xPlacement; /* Horizontal adjustment for
* placement--in design units */
SHORT yPlacement; /* Vertical adjustment for
* placement--in design units */
SHORT xAdvance; /* Horizontal adjustment for
* advance--in design units (only used
* for horizontal writing) */
SHORT yAdvance; /* Vertical adjustment for advance--in
* design units (only used for vertical
* writing) */
Offset xPlaDevice; /* Offset to Device table for
* horizontal placement--measured from
* beginning of PosTable (may be NULL) */
Offset yPlaDevice; /* Offset to Device table for vertical
* placement--measured from beginning
* of PosTable (may be NULL) */
Offset xAdvDevice; /* Offset to Device table for
* horizontal advance--measured from
* beginning of PosTable (may be NULL) */
Offset yAdvDevice; /* Offset to Device table for vertical
* advance--measured from beginning of
* PosTable (may be NULL) */
#endif
15 years ago
inline unsigned int get_len () const
{ return _hb_popcount32 ((unsigned int) *this); }
inline unsigned int get_size () const
{ return get_len () * Value::static_size; }
15 years ago
void apply_value (hb_ot_layout_context_t *layout,
const void *base,
15 years ago
const Value *values,
hb_internal_glyph_position_t &glyph_pos) const
15 years ago
{
unsigned int x_ppem, y_ppem;
hb_16dot16_t x_scale, y_scale;
unsigned int format = *this;
if (!format) return;
x_scale = layout->font->x_scale;
y_scale = layout->font->y_scale;
/* design units -> fractional pixel */
if (format & xPlacement) glyph_pos.x_offset += _hb_16dot16_mul_round (x_scale, get_short (values++));
if (format & yPlacement) glyph_pos.y_offset += _hb_16dot16_mul_round (y_scale, get_short (values++));
if (format & xAdvance) glyph_pos.x_advance += _hb_16dot16_mul_round (x_scale, get_short (values++));
if (format & yAdvance) glyph_pos.y_advance += _hb_16dot16_mul_round (y_scale, get_short (values++));
if (!has_device ()) return;
x_ppem = layout->font->x_ppem;
y_ppem = layout->font->y_ppem;
if (!x_ppem && !y_ppem) return;
/* pixel -> fractional pixel */
if (format & xPlaDevice) {
if (x_ppem) glyph_pos.x_offset += (base + get_device (values++)).get_delta (x_ppem) << 16; else values++;
}
if (format & yPlaDevice) {
if (y_ppem) glyph_pos.y_offset += (base + get_device (values++)).get_delta (y_ppem) << 16; else values++;
}
if (format & xAdvDevice) {
if (x_ppem) glyph_pos.x_advance += (base + get_device (values++)).get_delta (x_ppem) << 16; else values++;
}
if (format & yAdvDevice) {
if (y_ppem) glyph_pos.y_advance += (base + get_device (values++)).get_delta (y_ppem) << 16; else values++;
}
}
15 years ago
private:
15 years ago
inline bool sanitize_value_devices (hb_sanitize_context_t *c, void *base, Value *values) {
15 years ago
unsigned int format = *this;
if (format & xPlacement) values++;
if (format & yPlacement) values++;
if (format & xAdvance) values++;
if (format & yAdvance) values++;
15 years ago
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;
15 years ago
return true;
}
static inline OffsetTo<Device>& get_device (Value* value)
{ return *CastP<OffsetTo<Device> > (value); }
static inline const OffsetTo<Device>& get_device (const Value* value)
{ return *CastP<OffsetTo<Device> > (value); }
static inline const SHORT& get_short (const Value* value)
{ return *CastP<SHORT> (value); }
15 years ago
public:
inline bool has_device () const {
15 years ago
unsigned int format = *this;
return (format & devices) != 0;
}
15 years ago
inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *values) {
15 years ago
TRACE_SANITIZE ();
15 years ago
return c->check_range (values, get_size ())
&& (!has_device () || sanitize_value_devices (c, base, values));
15 years ago
}
15 years ago
inline bool sanitize_values (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count) {
15 years ago
TRACE_SANITIZE ();
unsigned int len = get_len ();
15 years ago
if (!c->check_array (values, get_size (), count)) return false;
15 years ago
if (!has_device ()) return true;
for (unsigned int i = 0; i < count; i++) {
15 years ago
if (!sanitize_value_devices (c, base, values))
15 years ago
return false;
values += len;
}
return true;
}
/* Just sanitize referenced Device tables. Doesn't check the values themselves. */
15 years ago
inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count, unsigned int stride) {
15 years ago
TRACE_SANITIZE ();
if (!has_device ()) return true;
for (unsigned int i = 0; i < count; i++) {
15 years ago
if (!sanitize_value_devices (c, base, values))
15 years ago
return false;
values += stride;
}
return true;
}
16 years ago
};
16 years ago
struct AnchorFormat1
{
16 years ago
friend struct Anchor;
private:
inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id HB_UNUSED,
hb_position_t *x, hb_position_t *y) const
{
*x = _hb_16dot16_mul_round (layout->font->x_scale, xCoordinate);
*y = _hb_16dot16_mul_round (layout->font->y_scale, yCoordinate);
16 years ago
}
15 years ago
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
15 years ago
return c->check_struct (this);
}
16 years ago
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);
16 years ago
};
16 years ago
struct AnchorFormat2
{
16 years ago
friend struct Anchor;
private:
inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id,
hb_position_t *x, hb_position_t *y) const
{
unsigned int x_ppem = layout->font->x_ppem;
unsigned int y_ppem = layout->font->y_ppem;
hb_position_t cx, cy;
hb_bool_t ret;
if (x_ppem || y_ppem)
ret = hb_font_get_contour_point (layout->font, layout->face, anchorPoint, glyph_id, &cx, &cy);
*x = x_ppem && ret ? cx : _hb_16dot16_mul_round (layout->font->x_scale, xCoordinate);
*y = y_ppem && ret ? cy : _hb_16dot16_mul_round (layout->font->y_scale, yCoordinate);
16 years ago
}
15 years ago
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
15 years ago
return c->check_struct (this);
}
16 years ago
private:
USHORT format; /* Format identifier--format = 2 */
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);
16 years ago
};
16 years ago
struct AnchorFormat3
{
16 years ago
friend struct Anchor;
private:
inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id HB_UNUSED,
hb_position_t *x, hb_position_t *y) const
{
*x = _hb_16dot16_mul_round (layout->font->x_scale, xCoordinate);
*y = _hb_16dot16_mul_round (layout->font->y_scale, yCoordinate);
/* pixel -> fractional pixel */
if (layout->font->x_ppem)
*x += (this+xDeviceTable).get_delta (layout->font->x_ppem) << 16;
if (layout->font->y_ppem)
*y += (this+yDeviceTable).get_delta (layout->font->y_ppem) << 16;
16 years ago
}
15 years ago
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
15 years ago
return c->check_struct (this)
&& xDeviceTable.sanitize (c, this)
&& yDeviceTable.sanitize (c, this);
}
16 years ago
private:
USHORT format; /* Format identifier--format = 3 */
SHORT xCoordinate; /* Horizontal value--in design units */
SHORT yCoordinate; /* Vertical value--in design units */
OffsetTo<Device>
xDeviceTable; /* Offset to Device table for X
* coordinate-- from beginning of
* Anchor table (may be NULL) */
OffsetTo<Device>
yDeviceTable; /* Offset to Device table for Y
* coordinate-- from beginning of
* Anchor table (may be NULL) */
public:
DEFINE_SIZE_STATIC (10);
16 years ago
};
16 years ago
struct Anchor
{
inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id,
hb_position_t *x, hb_position_t *y) const
{
16 years ago
*x = *y = 0;
switch (u.format) {
15 years ago
case 1: u.format1.get_anchor (layout, glyph_id, x, y); return;
case 2: u.format2.get_anchor (layout, glyph_id, x, y); return;
case 3: u.format3.get_anchor (layout, glyph_id, x, y); return;
default: return;
16 years ago
}
}
15 years ago
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
15 years ago
if (!u.format.sanitize (c)) return false;
switch (u.format) {
15 years ago
case 1: return u.format1.sanitize (c);
case 2: return u.format2.sanitize (c);
case 3: return u.format3.sanitize (c);
default:return true;
}
}
16 years ago
private:
union {
USHORT format; /* Format identifier */
15 years ago
AnchorFormat1 format1;
AnchorFormat2 format2;
AnchorFormat3 format3;
16 years ago
} u;
public:
DEFINE_SIZE_UNION (2, format);
16 years ago
};
struct AnchorMatrix
{
inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols) const {
if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
return this+matrix[row * cols + col];
}
15 years ago
inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) {
TRACE_SANITIZE ();
15 years ago
if (!c->check_struct (this)) return false;
if (unlikely (cols >= ((unsigned int) -1) / rows)) return false;
unsigned int count = rows * cols;
15 years ago
if (!c->check_array (matrix, matrix[0].static_size, count)) return false;
for (unsigned int i = 0; i < count; i++)
15 years ago
if (!matrix[i].sanitize (c, this)) return false;
return true;
}
USHORT rows; /* Number of rows */
private:
OffsetTo<Anchor>
matrix[VAR]; /* Matrix of offsets to Anchor tables--
* from beginning of AnchorMatrix table */
public:
DEFINE_SIZE_ARRAY (2, matrix);
};
16 years ago
struct MarkRecord
{
friend struct MarkArray;
16 years ago
15 years ago
inline bool sanitize (hb_sanitize_context_t *c, void *base) {
TRACE_SANITIZE ();
15 years ago
return c->check_struct (this)
&& markAnchor.sanitize (c, base);
}
16 years ago
private:
USHORT klass; /* Class defined for this mark */
OffsetTo<Anchor>
markAnchor; /* Offset to Anchor table--from
* beginning of MarkArray table */
public:
DEFINE_SIZE_STATIC (4);
16 years ago
};
struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage order */
16 years ago
{
15 years ago
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 = ArrayOf<MarkRecord>::operator[](mark_index);
unsigned int mark_class = record.klass;
const Anchor& mark_anchor = this + record.markAnchor;
const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count);
hb_position_t mark_x, mark_y, base_x, base_y;
mark_anchor.get_anchor (c->layout, c->buffer->info[c->buffer->in_pos].codepoint, &mark_x, &mark_y);
glyph_anchor.get_anchor (c->layout, c->buffer->info[glyph_pos].codepoint, &base_x, &base_y);
hb_internal_glyph_position_t &o = c->buffer->positions[c->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 = c->buffer->in_pos - glyph_pos;
15 years ago
c->buffer->in_pos++;
return true;
}
16 years ago
15 years ago
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
15 years ago
return ArrayOf<MarkRecord>::sanitize (c, this);
}
16 years ago
};
/* Lookups */
16 years ago
struct SinglePosFormat1
{
16 years ago
friend struct SinglePos;
private:
15 years ago
inline bool apply (hb_apply_context_t *c) const
{
TRACE_APPLY ();
unsigned int index = (this+coverage) (c->buffer->info[c->buffer->in_pos].codepoint);
if (likely (index == NOT_COVERED))
return false;
valueFormat.apply_value (c->layout, this, values, c->buffer->positions[c->buffer->in_pos]);
15 years ago
c->buffer->in_pos++;
return true;
16 years ago
}
15 years ago
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
15 years ago
return c->check_struct (this)
&& coverage.sanitize (c, this)
&& valueFormat.sanitize_value (c, this, values);
}
16 years ago
private:
USHORT format; /* Format identifier--format = 1 */
OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of subtable */
ValueFormat valueFormat; /* Defines the types of data in the
16 years ago
* ValueRecord */
ValueRecord values; /* Defines positioning
* value(s)--applied to all glyphs in
* the Coverage table */
public:
DEFINE_SIZE_ARRAY (6, values);
16 years ago
};
16 years ago
struct SinglePosFormat2
{
16 years ago
friend struct SinglePos;
private:
15 years ago
inline bool apply (hb_apply_context_t *c) const
{
TRACE_APPLY ();
unsigned int index = (this+coverage) (c->buffer->info[c->buffer->in_pos].codepoint);
if (likely (index == NOT_COVERED))
return false;
if (likely (index >= valueCount))
return false;
15 years ago
valueFormat.apply_value (c->layout, this,
&values[index * valueFormat.get_len ()],
c->buffer->positions[c->buffer->in_pos]);
15 years ago
c->buffer->in_pos++;
return true;
16 years ago
}
15 years ago
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
15 years ago
return c->check_struct (this)
&& coverage.sanitize (c, this)
&& valueFormat.sanitize_values (c, this, values, valueCount);
}
16 years ago
private:
USHORT format; /* Format identifier--format = 2 */
OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of subtable */
ValueFormat valueFormat; /* Defines the types of data in the
16 years ago
* ValueRecord */
USHORT valueCount; /* Number of ValueRecords */
ValueRecord values; /* Array of ValueRecords--positioning
* values applied to glyphs */
public:
DEFINE_SIZE_ARRAY (8, values);
16 years ago
};
16 years ago
struct SinglePos
{
16 years ago
friend struct PosLookupSubTable;
private:
15 years ago
inline bool apply (hb_apply_context_t *c) const
{
TRACE_APPLY ();
16 years ago
switch (u.format) {
15 years ago
case 1: return u.format1.apply (c);
case 2: return u.format2.apply (c);
16 years ago
default:return false;
}
}
15 years ago
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
15 years ago
if (!u.format.sanitize (c)) return false;
switch (u.format) {
15 years ago
case 1: return u.format1.sanitize (c);
case 2: return u.format2.sanitize (c);
default:return true;
}
}
16 years ago
private:
union {
USHORT format; /* Format identifier */
15 years ago
SinglePosFormat1 format1;
SinglePosFormat2 format2;
16 years ago
} u;
};
16 years ago
struct PairValueRecord
{
15 years ago
friend struct PairSet;
16 years ago
private:
GlyphID secondGlyph; /* GlyphID of second glyph in the
* pair--first glyph is listed in the
* Coverage table */
ValueRecord values; /* Positioning data for the first glyph
* followed by for second glyph */
public:
DEFINE_SIZE_ARRAY (2, values);
16 years ago
};
16 years ago
struct PairSet
{
friend struct PairPosFormat1;
15 years ago
inline bool apply (hb_apply_context_t *c,
15 years ago
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<PairValueRecord> (array);
for (unsigned int i = 0; i < count; i++)
{
if (c->buffer->info[pos].codepoint == record->secondGlyph)
15 years ago
{
valueFormats[0].apply_value (c->layout, this, &record->values[0], c->buffer->positions[c->buffer->in_pos]);
valueFormats[1].apply_value (c->layout, this, &record->values[len1], c->buffer->positions[pos]);
15 years ago
if (len2)
pos++;
15 years ago
c->buffer->in_pos = pos;
15 years ago
return true;
}
record = &StructAtOffset<PairValueRecord> (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 */
};
15 years ago
inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) {
TRACE_SANITIZE ();
15 years ago
if (!(c->check_struct (this)
&& c->check_array (array, USHORT::static_size * closure->stride, len))) return false;
15 years ago
unsigned int count = len;
PairValueRecord *record = CastP<PairValueRecord> (array);
15 years ago
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 */
USHORT array[VAR]; /* Array of PairValueRecords--ordered
* by GlyphID of the second glyph */
public:
DEFINE_SIZE_ARRAY (2, array);
};
16 years ago
16 years ago
struct PairPosFormat1
{
16 years ago
friend struct PairPos;
private:
15 years ago
inline bool apply (hb_apply_context_t *c) const
{
TRACE_APPLY ();
15 years ago
unsigned int end = MIN (c->buffer->in_length, c->buffer->in_pos + c->context_length);
if (unlikely (c->buffer->in_pos + 2 > end))
return false;
unsigned int index = (this+coverage) (c->buffer->info[c->buffer->in_pos].codepoint);
if (likely (index == NOT_COVERED))
return false;
15 years ago
unsigned int j = c->buffer->in_pos + 1;
while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_flag, NULL))
16 years ago
{
if (unlikely (j == end))
return false;
j++;
}
15 years ago
return (this+pairSet[index]).apply (c, &valueFormat1, j);
16 years ago
}
15 years ago
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
unsigned int len1 = valueFormat1.get_len ();
unsigned int len2 = valueFormat2.get_len ();
15 years ago
PairSet::sanitize_closure_t closure = {
this,
&valueFormat1,
len1,
1 + len1 + len2
};
15 years ago
return c->check_struct (this)
&& coverage.sanitize (c, this)
&& pairSet.sanitize (c, this, &closure);
}
16 years ago
private:
USHORT format; /* Format identifier--format = 1 */
OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of subtable */
ValueFormat valueFormat1; /* Defines the types of data in
16 years ago
* ValueRecord1--for the first glyph
* in the pair--may be zero (0) */
ValueFormat valueFormat2; /* Defines the types of data in
16 years ago
* ValueRecord2--for the second glyph
* in the pair--may be zero (0) */
OffsetArrayOf<PairSet>
pairSet; /* Array of PairSet tables
* ordered by Coverage Index */
public:
DEFINE_SIZE_ARRAY (10, pairSet);
16 years ago
};
16 years ago
struct PairPosFormat2
{
16 years ago
friend struct PairPos;
private:
15 years ago
inline bool apply (hb_apply_context_t *c) const
{
TRACE_APPLY ();
15 years ago
unsigned int end = MIN (c->buffer->in_length, c->buffer->in_pos + c->context_length);
if (unlikely (c->buffer->in_pos + 2 > end))
return false;
unsigned int index = (this+coverage) (c->buffer->info[c->buffer->in_pos].codepoint);
if (likely (index == NOT_COVERED))
return false;
15 years ago
unsigned int j = c->buffer->in_pos + 1;
while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_flag, NULL))
16 years ago
{
if (unlikely (j == end))
return false;
j++;
}
unsigned int len1 = valueFormat1.get_len ();
unsigned int len2 = valueFormat2.get_len ();
unsigned int record_len = len1 + len2;
unsigned int klass1 = (this+classDef1) (c->buffer->info[c->buffer->in_pos].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 (c->layout, this, v, c->buffer->positions[c->buffer->in_pos]);
valueFormat2.apply_value (c->layout, this, v + len1, c->buffer->positions[j]);
if (len2)
j++;
15 years ago
c->buffer->in_pos = j;
return true;
16 years ago
}
15 years ago
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
15 years ago
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;
15 years ago
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);
}
16 years ago
private:
USHORT format; /* Format identifier--format = 2 */
OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of subtable */
ValueFormat valueFormat1; /* ValueRecord definition--for the
16 years ago
* first glyph of the pair--may be zero
* (0) */
ValueFormat valueFormat2; /* ValueRecord definition--for the
16 years ago
* second glyph of the pair--may be
* zero (0) */
OffsetTo<ClassDef>
classDef1; /* Offset to ClassDef table--from
* beginning of PairPos subtable--for
* the first glyph of the pair */
OffsetTo<ClassDef>
classDef2; /* Offset to ClassDef table--from
* beginning of PairPos subtable--for
* the second glyph of the pair */
USHORT class1Count; /* Number of classes in ClassDef1
* table--includes Class0 */
USHORT class2Count; /* Number of classes in ClassDef2
* table--includes Class0 */
ValueRecord values; /* Matrix of value pairs:
* class1-major, class2-minor,
* Each entry has value1 and value2 */
public:
DEFINE_SIZE_ARRAY (16, values);
16 years ago
};
16 years ago
struct PairPos
{
16 years ago
friend struct PosLookupSubTable;
private:
15 years ago
inline bool apply (hb_apply_context_t *c) const
16 years ago
{
TRACE_APPLY ();
16 years ago
switch (u.format) {
15 years ago
case 1: return u.format1.apply (c);
case 2: return u.format2.apply (c);
16 years ago
default:return false;
}
}
15 years ago
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
15 years ago
if (!u.format.sanitize (c)) return false;
switch (u.format) {
15 years ago
case 1: return u.format1.sanitize (c);
case 2: return u.format2.sanitize (c);
default:return true;
}
}
16 years ago
private:
union {
USHORT format; /* Format identifier */
15 years ago
PairPosFormat1 format1;
PairPosFormat2 format2;
16 years ago
} u;
};
16 years ago
struct EntryExitRecord
{
friend struct CursivePosFormat1;
15 years ago
inline bool sanitize (hb_sanitize_context_t *c, void *base) {
TRACE_SANITIZE ();
15 years ago
return entryAnchor.sanitize (c, base)
&& exitAnchor.sanitize (c, base);
}
private:
16 years ago
OffsetTo<Anchor>
entryAnchor; /* Offset to EntryAnchor table--from
* beginning of CursivePos
* subtable--may be NULL */
OffsetTo<Anchor>
exitAnchor; /* Offset to ExitAnchor table--from
* beginning of CursivePos
* subtable--may be NULL */
public:
DEFINE_SIZE_STATIC (4);
16 years ago
};
16 years ago
struct CursivePosFormat1
{
16 years ago
friend struct CursivePos;
private:
15 years ago
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 <andreib@microsoft.com> 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. */
15 years ago
struct hb_ot_layout_context_t::info_t::gpos_t *gpi = &c->layout->info.gpos;
hb_codepoint_t last_pos = gpi->last;
gpi->last = HB_OT_LAYOUT_GPOS_NO_LAST;
/* We don't handle mark glyphs here. */
15 years ago
if (c->property == HB_OT_LAYOUT_GLYPH_CLASS_MARK)
return false;
unsigned int index = (this+coverage) (c->buffer->info[c->buffer->in_pos].codepoint);
if (likely (index == NOT_COVERED))
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 (c->layout, c->buffer->info[c->buffer->in_pos].codepoint, &entry_x, &entry_y);
/* TODO vertical */
15 years ago
if (c->buffer->direction == HB_DIRECTION_RTL)
{
/* advance is absolute, not relative */
c->buffer->positions[c->buffer->in_pos].x_advance = entry_x - gpi->anchor_x;
}
else
{
/* advance is absolute, not relative */
c->buffer->positions[last_pos].x_advance = gpi->anchor_x - entry_x;
}
15 years ago
if (c->lookup_flag & LookupFlag::RightToLeft)
{
c->buffer->positions[last_pos].cursive_chain = last_pos - c->buffer->in_pos;
c->buffer->positions[last_pos].y_offset = entry_y - gpi->anchor_y;
}
else
{
c->buffer->positions[c->buffer->in_pos].cursive_chain = c->buffer->in_pos - last_pos;
c->buffer->positions[c->buffer->in_pos].y_offset = gpi->anchor_y - entry_y;
}
end:
if (record.exitAnchor)
{
15 years ago
gpi->last = c->buffer->in_pos;
(this+record.exitAnchor).get_anchor (c->layout, c->buffer->info[c->buffer->in_pos].codepoint, &gpi->anchor_x, &gpi->anchor_y);
}
15 years ago
c->buffer->in_pos++;
return true;
16 years ago
}
15 years ago
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
15 years ago
return coverage.sanitize (c, this)
&& entryExitRecord.sanitize (c, this);
}
16 years ago
private:
USHORT format; /* Format identifier--format = 1 */
OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of subtable */
ArrayOf<EntryExitRecord>
entryExitRecord; /* Array of EntryExit records--in
* Coverage Index order */
public:
DEFINE_SIZE_ARRAY (6, entryExitRecord);
16 years ago
};
16 years ago
struct CursivePos
{
16 years ago
friend struct PosLookupSubTable;
private:
15 years ago
inline bool apply (hb_apply_context_t *c) const
16 years ago
{
TRACE_APPLY ();
16 years ago
switch (u.format) {
15 years ago
case 1: return u.format1.apply (c);
16 years ago
default:return false;
}
}
15 years ago
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
15 years ago
if (!u.format.sanitize (c)) return false;
switch (u.format) {
15 years ago
case 1: return u.format1.sanitize (c);
default:return true;
}
}
16 years ago
private:
union {
USHORT format; /* Format identifier */
15 years ago
CursivePosFormat1 format1;
16 years ago
} u;
};
typedef AnchorMatrix BaseArray; /* base-major--
* in order of BaseCoverage Index--,
* mark-minor--
* ordered by class--zero-based. */
16 years ago
16 years ago
struct MarkBasePosFormat1
{
16 years ago
friend struct MarkBasePos;
private:
15 years ago
inline bool apply (hb_apply_context_t *c) const
16 years ago
{
TRACE_APPLY ();
unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->in_pos].codepoint);
if (likely (mark_index == NOT_COVERED))
return false;
/* now we search backwards for a non-mark glyph */
unsigned int property;
15 years ago
unsigned int j = c->buffer->in_pos;
do
{
if (unlikely (!j))
return false;
j--;
} while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], LookupFlag::IgnoreMarks, &property));
/* The following assertion is too strong, so we've disabled it. */
if (false && !(property & HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH))
return false;
unsigned int base_index = (this+baseCoverage) (c->buffer->info[j].codepoint);
if (base_index == NOT_COVERED)
return false;
15 years ago
return (this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, j);
16 years ago
}
15 years ago
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
15 years ago
return c->check_struct (this)
&& markCoverage.sanitize (c, this)
&& baseCoverage.sanitize (c, this)
&& markArray.sanitize (c, this)
&& baseArray.sanitize (c, this, (unsigned int) classCount);
}
16 years ago
private:
USHORT format; /* Format identifier--format = 1 */
OffsetTo<Coverage>
markCoverage; /* Offset to MarkCoverage table--from
16 years ago
* beginning of MarkBasePos subtable */
OffsetTo<Coverage>
baseCoverage; /* Offset to BaseCoverage table--from
16 years ago
* beginning of MarkBasePos subtable */
USHORT classCount; /* Number of classes defined for marks */
OffsetTo<MarkArray>
markArray; /* Offset to MarkArray table--from
16 years ago
* beginning of MarkBasePos subtable */
OffsetTo<BaseArray>
baseArray; /* Offset to BaseArray table--from
16 years ago
* beginning of MarkBasePos subtable */
public:
DEFINE_SIZE_STATIC (12);
16 years ago
};
16 years ago
struct MarkBasePos
{
16 years ago
friend struct PosLookupSubTable;
private:
15 years ago
inline bool apply (hb_apply_context_t *c) const
16 years ago
{
TRACE_APPLY ();
16 years ago
switch (u.format) {
15 years ago
case 1: return u.format1.apply (c);
16 years ago
default:return false;
}
}
15 years ago
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
15 years ago
if (!u.format.sanitize (c)) return false;
switch (u.format) {
15 years ago
case 1: return u.format1.sanitize (c);
default:return true;
}
}
16 years ago
private:
union {
USHORT format; /* Format identifier */
15 years ago
MarkBasePosFormat1 format1;
16 years ago
} u;
};
typedef AnchorMatrix LigatureAttach; /* component-major--
* in order of writing direction--,
* mark-minor--
* ordered by class--zero-based. */
16 years ago
typedef OffsetListOf<LigatureAttach> LigatureArray;
/* Array of LigatureAttach
16 years ago
* tables ordered by
* LigatureCoverage Index */
16 years ago
struct MarkLigPosFormat1
{
16 years ago
friend struct MarkLigPos;
private:
15 years ago
inline bool apply (hb_apply_context_t *c) const
16 years ago
{
TRACE_APPLY ();
unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->in_pos].codepoint);
if (likely (mark_index == NOT_COVERED))
return false;
/* now we search backwards for a non-mark glyph */
unsigned int property;
15 years ago
unsigned int j = c->buffer->in_pos;
do
{
if (unlikely (!j))
return false;
j--;
} while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], LookupFlag::IgnoreMarks, &property));
/* The following assertion is too strong, so we've disabled it. */
if (false && !(property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE))
return false;
unsigned int lig_index = (this+ligatureCoverage) (c->buffer->info[j].codepoint);
if (lig_index == NOT_COVERED)
return false;
const LigatureArray& lig_array = this+ligatureArray;
const LigatureAttach& lig_attach = lig_array[lig_index];
/* Find component to attach to */
unsigned int comp_count = lig_attach.rows;
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 (c->buffer->info[j].lig_id && c->buffer->info[j].lig_id == c->buffer->info[c->buffer->in_pos].lig_id && c->buffer->info[c->buffer->in_pos].component)
{
comp_index = c->buffer->info[c->buffer->in_pos].component - 1;
if (comp_index >= comp_count)
comp_index = comp_count - 1;
}
else
comp_index = comp_count - 1;
15 years ago
return (this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j);
16 years ago
}
15 years ago
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
15 years ago
return c->check_struct (this)
&& markCoverage.sanitize (c, this)
&& ligatureCoverage.sanitize (c, this)
&& markArray.sanitize (c, this)
&& ligatureArray.sanitize (c, this, (unsigned int) classCount);
}
16 years ago
private:
USHORT format; /* Format identifier--format = 1 */
OffsetTo<Coverage>
markCoverage; /* Offset to Mark Coverage table--from
16 years ago
* beginning of MarkLigPos subtable */
OffsetTo<Coverage>
ligatureCoverage; /* Offset to Ligature Coverage
16 years ago
* table--from beginning of MarkLigPos
* subtable */
USHORT classCount; /* Number of defined mark classes */
OffsetTo<MarkArray>
markArray; /* Offset to MarkArray table--from
16 years ago
* beginning of MarkLigPos subtable */
OffsetTo<LigatureArray>
ligatureArray; /* Offset to LigatureArray table--from
16 years ago
* beginning of MarkLigPos subtable */
public:
DEFINE_SIZE_STATIC (12);
16 years ago
};
16 years ago
struct MarkLigPos
{
16 years ago
friend struct PosLookupSubTable;
private:
15 years ago
inline bool apply (hb_apply_context_t *c) const
16 years ago
{
TRACE_APPLY ();
16 years ago
switch (u.format) {
15 years ago
case 1: return u.format1.apply (c);
16 years ago
default:return false;
}
}
15 years ago
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
15 years ago
if (!u.format.sanitize (c)) return false;
switch (u.format) {
15 years ago
case 1: return u.format1.sanitize (c);
default:return true;
}
}
16 years ago
private:
union {
USHORT format; /* Format identifier */
15 years ago
MarkLigPosFormat1 format1;
16 years ago
} u;
};
typedef AnchorMatrix Mark2Array; /* mark2-major--
* in order of Mark2Coverage Index--,
* mark1-minor--
* ordered by class--zero-based. */
16 years ago
16 years ago
struct MarkMarkPosFormat1
{
16 years ago
friend struct MarkMarkPos;
private:
15 years ago
inline bool apply (hb_apply_context_t *c) const
16 years ago
{
TRACE_APPLY ();
unsigned int mark1_index = (this+mark1Coverage) (c->buffer->info[c->buffer->in_pos].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;
15 years ago
unsigned int j = c->buffer->in_pos;
do
{
if (unlikely (!j))
return false;
j--;
} while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_flag, &property));
if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
return false;
/* 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 ((c->buffer->info[j].component != c->buffer->info[c->buffer->in_pos].component) ||
(c->buffer->info[j].component && c->buffer->info[j].lig_id != c->buffer->info[c->buffer->in_pos].lig_id))
return false;
unsigned int mark2_index = (this+mark2Coverage) (c->buffer->info[j].codepoint);
if (mark2_index == NOT_COVERED)
return false;
15 years ago
return (this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j);
16 years ago
}
15 years ago
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
15 years ago
return c->check_struct (this)
&& mark1Coverage.sanitize (c, this)
&& mark2Coverage.sanitize (c, this)
&& mark1Array.sanitize (c, this)
&& mark2Array.sanitize (c, this, (unsigned int) classCount);
}
16 years ago
private:
USHORT format; /* Format identifier--format = 1 */
OffsetTo<Coverage>
mark1Coverage; /* Offset to Combining Mark1 Coverage
16 years ago
* table--from beginning of MarkMarkPos
* subtable */
OffsetTo<Coverage>
mark2Coverage; /* Offset to Combining Mark2 Coverage
16 years ago
* table--from beginning of MarkMarkPos
* subtable */
USHORT classCount; /* Number of defined mark classes */
OffsetTo<MarkArray>
mark1Array; /* Offset to Mark1Array table--from
* beginning of MarkMarkPos subtable */
OffsetTo<Mark2Array>
mark2Array; /* Offset to Mark2Array table--from
* beginning of MarkMarkPos subtable */
public:
DEFINE_SIZE_STATIC (12);
16 years ago
};
16 years ago
struct MarkMarkPos
{
16 years ago
friend struct PosLookupSubTable;
private:
15 years ago
inline bool apply (hb_apply_context_t *c) const
16 years ago
{
TRACE_APPLY ();
16 years ago
switch (u.format) {
15 years ago
case 1: return u.format1.apply (c);
16 years ago
default:return false;
}
}
15 years ago
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
15 years ago
if (!u.format.sanitize (c)) return false;
switch (u.format) {
15 years ago
case 1: return u.format1.sanitize (c);
default:return true;
}
}
16 years ago
private:
union {
USHORT format; /* Format identifier */
15 years ago
MarkMarkPosFormat1 format1;
16 years ago
} u;
};
15 years ago
static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index);
16 years ago
16 years ago
struct ContextPos : Context
{
friend struct PosLookupSubTable;
private:
15 years ago
inline bool apply (hb_apply_context_t *c) const
{
TRACE_APPLY ();
15 years ago
return Context::apply (c, position_lookup);
}
16 years ago
};
16 years ago
struct ChainContextPos : ChainContext
{
friend struct PosLookupSubTable;
private:
15 years ago
inline bool apply (hb_apply_context_t *c) const
{
TRACE_APPLY ();
15 years ago
return ChainContext::apply (c, position_lookup);
}
16 years ago
};
struct ExtensionPos : Extension
16 years ago
{
16 years ago
friend struct PosLookupSubTable;
private:
inline const struct PosLookupSubTable& get_subtable (void) const
{
unsigned int offset = get_offset ();
if (unlikely (!offset)) return Null(PosLookupSubTable);
return StructAtOffset<PosLookupSubTable> (this, offset);
}
15 years ago
inline bool apply (hb_apply_context_t *c) const;
15 years ago
inline bool sanitize (hb_sanitize_context_t *c);
16 years ago
};
16 years ago
/*
* PosLookup
*/
16 years ago
struct PosLookupSubTable
{
16 years ago
friend struct PosLookup;
enum {
Single = 1,
Pair = 2,
Cursive = 3,
MarkBase = 4,
MarkLig = 5,
MarkMark = 6,
Context = 7,
ChainContext = 8,
Extension = 9
};
15 years ago
inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
16 years ago
{
TRACE_APPLY ();
16 years ago
switch (lookup_type) {
15 years ago
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);
16 years ago
default:return false;
}
}
15 years ago
inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
TRACE_SANITIZE ();
switch (lookup_type) {
15 years ago
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;
}
}
16 years ago
private:
union {
USHORT sub_format;
15 years ago
SinglePos single;
PairPos pair;
CursivePos cursive;
MarkBasePos markBase;
MarkLigPos markLig;
MarkMarkPos markMark;
15 years ago
ContextPos c;
15 years ago
ChainContextPos chainContext;
ExtensionPos extension;
16 years ago
} u;
public:
DEFINE_SIZE_UNION (2, sub_format);
16 years ago
};
16 years ago
struct PosLookup : Lookup
{
inline const PosLookupSubTable& get_subtable (unsigned int i) const
{ return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
16 years ago
inline bool apply_once (hb_ot_layout_context_t *layout,
hb_buffer_t *buffer,
unsigned int context_length,
unsigned int nesting_level_left) const
16 years ago
{
16 years ago
unsigned int lookup_type = get_type ();
15 years ago
hb_apply_context_t c[1] = {{0}};
15 years ago
c->layout = layout;
c->buffer = buffer;
c->context_length = context_length;
c->nesting_level_left = nesting_level_left;
c->lookup_flag = get_flag ();
if (!_hb_ot_layout_check_glyph_property (c->layout->face, &c->buffer->info[c->buffer->in_pos], c->lookup_flag, &c->property))
return false;
16 years ago
for (unsigned int i = 0; i < get_subtable_count (); i++)
15 years ago
if (get_subtable (i).apply (c, lookup_type))
16 years ago
return true;
return false;
}
inline bool apply_string (hb_ot_layout_context_t *layout,
hb_buffer_t *buffer,
hb_mask_t mask) const
16 years ago
{
16 years ago
bool ret = false;
if (unlikely (!buffer->in_length))
16 years ago
return false;
layout->info.gpos.last = HB_OT_LAYOUT_GPOS_NO_LAST; /* no last valid glyph for cursive pos. */
16 years ago
buffer->in_pos = 0;
16 years ago
while (buffer->in_pos < buffer->in_length)
{
bool done;
if (~buffer->info[buffer->in_pos].mask & mask)
16 years ago
{
done = apply_once (layout, buffer, NO_CONTEXT, MAX_NESTING_LEVEL);
ret |= done;
16 years ago
}
else
{
done = false;
/* Contrary to properties defined in GDEF, user-defined properties
will always stop a possible cursive positioning. */
layout->info.gpos.last = HB_OT_LAYOUT_GPOS_NO_LAST;
}
if (!done)
buffer->in_pos++;
16 years ago
}
return ret;
}
15 years ago
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
15 years ago
if (unlikely (!Lookup::sanitize (c))) return false;
OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable);
15 years ago
return list.sanitize (c, this, get_type ());
}
16 years ago
};
typedef OffsetListOf<PosLookup> PosLookupList;
16 years ago
/*
* GPOS
*/
16 years ago
struct GPOS : GSUBGPOS
{
static const hb_tag_t Tag = HB_OT_TAG_GPOS;
16 years ago
16 years ago
inline const PosLookup& get_lookup (unsigned int i) const
{ return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
16 years ago
inline bool position_lookup (hb_ot_layout_context_t *layout,
hb_buffer_t *buffer,
unsigned int lookup_index,
hb_mask_t mask) const
{ return get_lookup (lookup_index).apply_string (layout, buffer, mask); }
16 years ago
15 years ago
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE ();
15 years ago
if (unlikely (!GSUBGPOS::sanitize (c))) return false;
OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
15 years ago
return list.sanitize (c, this);
}
public:
DEFINE_SIZE_STATIC (10);
16 years ago
};
/* Out-of-class implementation for methods recursing */
15 years ago
inline bool ExtensionPos::apply (hb_apply_context_t *c) const
16 years ago
{
TRACE_APPLY ();
15 years ago
return get_subtable ().apply (c, get_type ());
}
15 years ago
inline bool ExtensionPos::sanitize (hb_sanitize_context_t *c)
{
TRACE_SANITIZE ();
15 years ago
if (unlikely (!Extension::sanitize (c))) return false;
unsigned int offset = get_offset ();
if (unlikely (!offset)) return true;
15 years ago
return StructAtOffset<PosLookupSubTable> (this, offset).sanitize (c, get_type ());
16 years ago
}
15 years ago
static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index)
16 years ago
{
15 years ago
const GPOS &gpos = *(c->layout->face->ot_layout.gpos);
16 years ago
const PosLookup &l = gpos.get_lookup (lookup_index);
15 years ago
if (unlikely (c->nesting_level_left == 0))
16 years ago
return false;
15 years ago
if (unlikely (c->context_length < 1))
16 years ago
return false;
15 years ago
return l.apply_once (c->layout, c->buffer, c->context_length, c->nesting_level_left - 1);
16 years ago
}
#endif /* HB_OT_LAYOUT_GPOS_PRIVATE_HH */