[subset] WIP convert hdmx subsetting to use iterators.

This commit is contained in:
Garret Rieger 2019-05-07 17:23:02 -07:00 committed by Behdad Esfahbod
parent d5decf9bf7
commit e8ef0e627c
2 changed files with 49 additions and 91 deletions

View File

@ -41,71 +41,30 @@ namespace OT {
struct DeviceRecord
{
struct SubsetView
{
const DeviceRecord *source_device_record;
unsigned int sizeDeviceRecord;
hb_subset_plan_t *subset_plan;
void init (const DeviceRecord *source_device_record,
unsigned int sizeDeviceRecord,
hb_subset_plan_t *subset_plan)
{
this->source_device_record = source_device_record;
this->sizeDeviceRecord = sizeDeviceRecord;
this->subset_plan = subset_plan;
}
unsigned int len () const
{ return this->subset_plan->num_output_glyphs (); }
const HBUINT8* operator [] (unsigned int new_gid) const
{
if (unlikely (new_gid >= len ())) return nullptr;
hb_codepoint_t old_gid;
if (!this->subset_plan->old_gid_for_new_gid (new_gid, &old_gid))
return &Null(HBUINT8);
if (old_gid >= sizeDeviceRecord - DeviceRecord::min_size)
return nullptr;
return &(this->source_device_record->widthsZ[old_gid]);
}
};
static unsigned int get_size (unsigned int count)
static unsigned int get_size (unsigned count)
{ return hb_ceil_to_4 (min_size + count * HBUINT8::static_size); }
bool serialize (hb_serialize_context_t *c, const SubsetView &subset_view)
template<typename Iterator>
bool serialize (hb_serialize_context_t *c, unsigned pixelSize, Iterator it)
{
TRACE_SERIALIZE (this);
unsigned int size = get_size (subset_view.len ());
if (unlikely (!c->allocate_size<DeviceRecord> (size)))
{
DEBUG_MSG(SUBSET, nullptr, "Couldn't allocate enough space for DeviceRecord: %d.",
size);
return_trace (false);
}
unsigned length = it.len ();
this->pixelSize = subset_view.source_device_record->pixelSize;
this->maxWidth = subset_view.source_device_record->maxWidth;
if (unlikely (!c->extend (*this, length))) return_trace (false);
for (unsigned int i = 0; i < subset_view.len (); i++)
{
const HBUINT8 *width = subset_view[i];
if (!width)
{
DEBUG_MSG(SUBSET, nullptr, "HDMX width for new gid %d is missing.", i);
return_trace (false);
}
widthsZ[i] = *width;
}
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 int sizeDeviceRecord) const
bool sanitize (hb_sanitize_context_t *c, unsigned sizeDeviceRecord) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
@ -135,26 +94,25 @@ struct hdmx
return StructAtOffset<DeviceRecord> (&this->firstDeviceRecord, i * sizeDeviceRecord);
}
bool serialize (hb_serialize_context_t *c, const hdmx *source_hdmx, hb_subset_plan_t *plan)
template<typename 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 = source_hdmx->version;
this->numRecords = source_hdmx->numRecords;
this->sizeDeviceRecord = DeviceRecord::get_size (plan->num_output_glyphs ());
this->version = version;
this->numRecords = it.len ();
this->sizeDeviceRecord =
it ? DeviceRecord::get_size ((*it).second.len ()) : DeviceRecord::get_size (0);
for (unsigned int i = 0; i < source_hdmx->numRecords; i++)
{
DeviceRecord::SubsetView subset_view;
subset_view.init (&(*source_hdmx)[i], source_hdmx->sizeDeviceRecord, plan);
using pair_t = decltype (*it);
+ it
| hb_apply ([&] (const pair_t& _) {
c->start_embed<DeviceRecord> ()->serialize (c, _.first, _.second);
});
if (!c->start_embed<DeviceRecord> ()->serialize (c, subset_view))
return_trace (false);
}
return_trace (true);
return_trace (c->successful);
}
@ -165,10 +123,33 @@ struct hdmx
hdmx *hdmx_prime = c->serializer->start_embed <hdmx> ();
if (unlikely (!hdmx_prime)) return_trace (false);
hdmx_prime->serialize (c->serializer, this, c->plan);
auto it =
+ hb_iota ((unsigned) numRecords)
| hb_map ([&] (unsigned _) {
const DeviceRecord *device_record =
&StructAtOffset<DeviceRecord> (&firstDeviceRecord,
_ * sizeDeviceRecord);
auto row =
+ hb_iota (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);

View File

@ -91,28 +91,6 @@ test_subset_hdmx_invalid (void)
hb_face_destroy (face);
}
static void
test_subset_hdmx_fails_sanitize (void)
{
hb_face_t *face = hb_test_open_font_file ("../fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5609911946838016");
hb_subset_input_t *input = hb_subset_input_create_or_fail ();
hb_set_t *codepoints = hb_subset_input_unicode_set (input);
hb_face_t *subset;
hb_set_add (codepoints, 'a');
hb_set_add (codepoints, 'b');
hb_set_add (codepoints, 'c');
subset = hb_subset (face, input);
g_assert (subset);
g_assert (subset == hb_face_get_empty ());
hb_subset_input_destroy (input);
hb_face_destroy (subset);
hb_face_destroy (face);
}
static void
test_subset_hdmx_noop (void)
{
@ -140,7 +118,6 @@ main (int argc, char **argv)
hb_test_add (test_subset_hdmx_simple_subset);
hb_test_add (test_subset_hdmx_multiple_device_records);
hb_test_add (test_subset_hdmx_invalid);
hb_test_add (test_subset_hdmx_fails_sanitize);
hb_test_add (test_subset_hdmx_noop);
return hb_test_run();