WIP
diff --git a/src/hb-ot-layout-gpos-private.hh b/src/hb-ot-layout-gpos-private.hh
index bd72aae..60eb439 100644
--- a/src/hb-ot-layout-gpos-private.hh
+++ b/src/hb-ot-layout-gpos-private.hh
@@ -52,29 +52,12 @@
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 */
};
- inline unsigned int get_len () 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 *context,
- const char *base,
- const Value *values,
- hb_internal_glyph_position_t *glyph_pos) const
- {
- unsigned int x_ppem, y_ppem;
- hb_16dot16_t x_scale, y_scale;
- unsigned int format = *this;
-
- if (!format)
- return;
-
- /* All fields are options. Only those available advance the value
- * pointer. */
+/* All fields are options. Only those available advance the value pointer. */
#if 0
-struct ValueRecord {
SHORT xPlacement; /* Horizontal adjustment for
* placement--in design units */
SHORT yPlacement; /* Vertical adjustment for
@@ -97,9 +80,24 @@
Offset yAdvDevice; /* Offset to Device table for vertical
* advance--measured from beginning of
* PosTable (may be NULL) */
-};
#endif
+ inline unsigned int get_len () 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 *context,
+ const char *base,
+ const Value *values,
+ hb_internal_glyph_position_t *glyph_pos) const
+ {
+ unsigned int x_ppem, y_ppem;
+ hb_16dot16_t x_scale, y_scale;
+ unsigned int format = *this;
+
+ if (!format) return;
+
x_scale = context->font->x_scale;
y_scale = context->font->y_scale;
/* design units -> fractional pixel */
@@ -124,6 +122,68 @@
if (y_ppem) glyph_pos->y_advance += (base+*(OffsetTo<Device>*)values++).get_delta (y_ppem) << 16; else values++;
}
}
+
+ private:
+ inline bool sanitize_value_devices (SANITIZE_ARG_DEF, void *base, const Value *values) {
+ unsigned int format = *this;
+
+ if (format & xPlacement) values++;
+ if (format & yPlacement) values++;
+ if (format & xAdvance) values++;
+ if (format & yAdvance) values++;
+
+ if ((format & xPlaDevice) && !SANITIZE_BASE (*(OffsetTo<Device>*)values++, base)) return false;
+ if ((format & yPlaDevice) && !SANITIZE_BASE (*(OffsetTo<Device>*)values++, base)) return false;
+ if ((format & xAdvDevice) && !SANITIZE_BASE (*(OffsetTo<Device>*)values++, base)) return false;
+ if ((format & yAdvDevice) && !SANITIZE_BASE (*(OffsetTo<Device>*)values++, base)) return false;
+
+ return true;
+ }
+
+ public:
+
+ inline bool has_device () {
+ unsigned int format = *this;
+ return (format & devices) != 0;
+ }
+
+ inline bool sanitize_value (SANITIZE_ARG_DEF, void *base, const Value *values) {
+ TRACE_SANITIZE ();
+
+ return SANITIZE_MEM (values, get_size ()) &&
+ (!has_device () || sanitize_value_devices (SANITIZE_ARG, base, values));
+ }
+
+ inline bool sanitize_values (SANITIZE_ARG_DEF, void *base, const Value *values, unsigned int count) {
+ TRACE_SANITIZE ();
+ unsigned int len = get_len ();
+
+ if (!SANITIZE_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))
+ return false;
+ values += len;
+ }
+
+ return true;
+ }
+
+ inline bool sanitize_values_stride_unsafe (SANITIZE_ARG_DEF, void *base, const 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))
+ return false;
+ values += stride;
+ }
+
+ return true;
+ }
};
ASSERT_SIZE (ValueFormat, 2);