#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,
const hb_vector_t<hb_codepoint_pair_t> new_to_old_gid_list,
unsigned num_glyphs)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend (this, num_glyphs))) return_trace (false);
this->pixelSize = pixelSize;
this->maxWidth =
+ it
| hb_reduce (hb_max, 0u);
for (auto &_ : new_to_old_gid_list)
widthsZ[_.first] = *it++;
return_trace (true);
}
bool sanitize (hb_sanitize_context_t *c, unsigned sizeDeviceRecord) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
hb_barrier () &&
c->check_range (this, sizeDeviceRecord)));
}
HBUINT8 pixelSize;
HBUINT8 maxWidth;
UnsizedArrayOf<HBUINT8> widthsZ;
public:
DEFINE_SIZE_UNBOUNDED (2);
};
struct hdmx
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_hdmx;
unsigned int get_size () const
{ return min_size + numRecords * sizeDeviceRecord; }
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
bool serialize (hb_serialize_context_t *c,
unsigned version,
Iterator it,
const hb_vector_t<hb_codepoint_pair_t> &new_to_old_gid_list,
unsigned num_glyphs)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min ((*this)))) return_trace (false);
this->version = version;
this->numRecords = it.len ();
this->sizeDeviceRecord = DeviceRecord::get_size (num_glyphs);
for (const hb_item_type<Iterator>& _ : +it)
c->start_embed<DeviceRecord> ()->serialize (c, _.first, _.second, new_to_old_gid_list, num_glyphs);
return_trace (c->successful ());
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *hdmx_prime = c->serializer->start_embed <hdmx> ();
unsigned num_input_glyphs = get_num_glyphs ();
auto it =
+ hb_range ((unsigned) numRecords)
| hb_map ([c, num_input_glyphs, this] (unsigned _)
{
const DeviceRecord *device_record =
&StructAtOffset<DeviceRecord> (&firstDeviceRecord,
_ * sizeDeviceRecord);
auto row =
+ hb_iter (c->plan->new_to_old_gid_list)
| hb_map ([num_input_glyphs, device_record] (hb_codepoint_pair_t _)
{
return device_record->widthsZ.as_array (num_input_glyphs) [_.second];
})
;
return hb_pair ((unsigned) device_record->pixelSize, +row);
})
;
hdmx_prime->serialize (c->serializer, version, it,
c->plan->new_to_old_gid_list,
c->plan->num_output_glyphs ());
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_barrier () &&
!hb_unsigned_mul_overflows (numRecords, sizeDeviceRecord) &&
min_size + numRecords * sizeDeviceRecord > 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