From e8ef0e627c493af700e254bdd2767f8955f2d03f Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Tue, 7 May 2019 17:23:02 -0700 Subject: [PATCH] [subset] WIP convert hdmx subsetting to use iterators. --- src/hb-ot-hdmx-table.hh | 121 +++++++++++++++--------------------- test/api/test-subset-hdmx.c | 23 ------- 2 files changed, 51 insertions(+), 93 deletions(-) diff --git a/src/hb-ot-hdmx-table.hh b/src/hb-ot-hdmx-table.hh index abf4440a..560fb14d 100644 --- a/src/hb-ot-hdmx-table.hh +++ b/src/hb-ot-hdmx-table.hh @@ -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 + 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 (size))) - { - DEBUG_MSG(SUBSET, nullptr, "Couldn't allocate enough space for DeviceRecord: %d.", - size); - return_trace (false); - } - - this->pixelSize = subset_view.source_device_record->pixelSize; - this->maxWidth = subset_view.source_device_record->maxWidth; - - 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; - } + 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 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 (&this->firstDeviceRecord, i * sizeDeviceRecord); } - bool serialize (hb_serialize_context_t *c, const hdmx *source_hdmx, hb_subset_plan_t *plan) + template + 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 ()); - - for (unsigned int i = 0; i < source_hdmx->numRecords; i++) - { - DeviceRecord::SubsetView subset_view; - subset_view.init (&(*source_hdmx)[i], source_hdmx->sizeDeviceRecord, plan); + this->version = version; + this->numRecords = it.len (); + this->sizeDeviceRecord = + it ? DeviceRecord::get_size ((*it).second.len ()) : DeviceRecord::get_size (0); - if (!c->start_embed ()->serialize (c, subset_view)) - return_trace (false); - } + using pair_t = decltype (*it); + + it + | hb_apply ([&] (const pair_t& _) { + c->start_embed ()->serialize (c, _.first, _.second); + }); - return_trace (true); + return_trace (c->successful); } @@ -165,10 +123,33 @@ struct hdmx hdmx *hdmx_prime = c->serializer->start_embed (); 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 (&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); diff --git a/test/api/test-subset-hdmx.c b/test/api/test-subset-hdmx.c index 44e579ac..7178833b 100644 --- a/test/api/test-subset-hdmx.c +++ b/test/api/test-subset-hdmx.c @@ -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(); -- GitLab