#ifndef HB_OT_HDMX_TABLE_HH
#define HB_OT_HDMX_TABLE_HH
#include "hb-open-type.hh"
#define HB_OT_TAG_hdmx HB_TAG('h','d','m','x')
namespace OT {
struct DeviceRecord
{
static unsigned int get_size (unsigned count)
{ return hb_ceil_to_4 (min_size + count * HBUINT8::static_size); }
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
bool serialize (hb_serialize_context_t *c, unsigned pixelSize, Iterator it)
{
TRACE_SERIALIZE (this);
unsigned length = it.len ();
if (unlikely (!c->extend (*this, length))) return_trace (false);
this->pixelSize = pixelSize;
this->maxWidth =
+ it
| hb_reduce (hb_max, 0u);
+ it
| hb_sink (widthsZ.as_array (length));
return_trace (true);
}
bool sanitize (hb_sanitize_context_t *c, unsigned sizeDeviceRecord) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
c->check_range (this, sizeDeviceRecord)));
}
HBUINT8 pixelSize;
HBUINT8 maxWidth;
UnsizedArrayOf<HBUINT8> widthsZ;
public:
DEFINE_SIZE_ARRAY (2, widthsZ);
};
struct hdmx
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_hdmx;
unsigned int get_size () const
{ return min_size + numRecords * sizeDeviceRecord; }
const DeviceRecord& operator [] (unsigned int i) const
{
if (unlikely (i >= numRecords)) return Null (DeviceRecord);
return StructAtOffset<DeviceRecord> (&this->firstDeviceRecord, i * sizeDeviceRecord);
}
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
bool serialize (hb_serialize_context_t *c, unsigned version, Iterator it)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min ((*this)))) return_trace (false);
this->version = version;
this->numRecords = it.len ();
this->sizeDeviceRecord = DeviceRecord::get_size (it ? (*it).second.len () : 0);
+ it
| hb_apply ([c] (const hb_item_type<Iterator>& _) {
c->start_embed<DeviceRecord> ()->serialize (c, _.first, _.second);
})
;
return_trace (c->successful);
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
hdmx *hdmx_prime = c->serializer->start_embed <hdmx> ();
if (unlikely (!hdmx_prime)) return_trace (false);
auto it =
+ hb_range ((unsigned) numRecords)
| hb_map ([c, this] (unsigned _)
{
const DeviceRecord *device_record =
&StructAtOffset<DeviceRecord> (&firstDeviceRecord,
_ * sizeDeviceRecord);
auto row =
+ hb_range (c->plan->num_output_glyphs ())
| hb_map (c->plan->reverse_glyph_map)
| hb_map ([=] (hb_codepoint_t _)
{
if (c->plan->is_empty_glyph (_))
return Null(HBUINT8);
return device_record->widthsZ.as_array (get_num_glyphs ()) [_];
})
;
return hb_pair ((unsigned) device_record->pixelSize, +row);
})
;
hdmx_prime->serialize (c->serializer, version, it);
return_trace (true);
}
unsigned get_num_glyphs () const
{
return sizeDeviceRecord - DeviceRecord::min_size;
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
!hb_unsigned_mul_overflows (numRecords, sizeDeviceRecord) &&
sizeDeviceRecord >= DeviceRecord::min_size &&
c->check_range (this, get_size ()));
}
protected:
HBUINT16 version;
HBUINT16 numRecords;
HBUINT32 sizeDeviceRecord;
DeviceRecord firstDeviceRecord;
public:
DEFINE_SIZE_MIN (8);
};
}
#endif