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);
- }
-
- 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) &&
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 ());
-
- 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<DeviceRecord> ()->serialize (c, subset_view))
- return_trace (false);
- }
+ using pair_t = decltype (*it);
+ + it
+ | hb_apply ([&] (const pair_t& _) {
+ c->start_embed<DeviceRecord> ()->serialize (c, _.first, _.second);
+ });
- return_trace (true);
+ return_trace (c->successful);
}
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);
}
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)
{
hb_face_t *face_abc = hb_test_open_font_file ("fonts/Roboto-Regular.abc.ttf");
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();