From 832f2b599b3d4fad5eea6d0eeef77377d3e0bad0 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Tue, 10 Nov 2020 16:15:37 -0800 Subject: [PATCH] [subset] Refactor _subset () to reduce nesting and eliminate the use of 'goto'. --- src/hb-serialize.hh | 9 +++ src/hb-subset.cc | 138 ++++++++++++++++++++++++++------------------ src/meson.build | 1 + 3 files changed, 92 insertions(+), 56 deletions(-) diff --git a/src/hb-serialize.hh b/src/hb-serialize.hh index 7afe61710..c8a209d67 100644 --- a/src/hb-serialize.hh +++ b/src/hb-serialize.hh @@ -119,6 +119,14 @@ struct hb_serialize_context_t bool in_error () const { return !this->successful; } + void reset (void *start_, unsigned int size) + { + start = (char*) start_; + end = start + size; + reset (); + current = nullptr; + } + void reset () { this->successful = true; @@ -129,6 +137,7 @@ struct hb_serialize_context_t fini (); this->packed.push (nullptr); + this->packed_map.init (); } bool check_success (bool success) diff --git a/src/hb-subset.cc b/src/hb-subset.cc index 46cfbe9d0..0d64de1c8 100644 --- a/src/hb-subset.cc +++ b/src/hb-subset.cc @@ -94,74 +94,100 @@ _repack (hb_tag_t tag, const hb_serialize_context_t& c) return repacked.copy_blob (); } +template +static +bool +_try_subset (const TableType *table, + hb_vector_t* buf, + unsigned buf_size, + hb_subset_context_t* c /* OUT */) +{ + c->serializer->start_serialize (); + + bool needed = table->subset (c); + if (!c->serializer->ran_out_of_room) + { + c->serializer->end_serialize (); + return needed; + } + + buf_size += (buf_size >> 1) + 32; + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.", + HB_UNTAG (c->table_tag), buf_size); + + if (unlikely (!buf->alloc (buf_size))) + { + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.", + HB_UNTAG (c->table_tag), buf_size); + return needed; + } + + c->serializer->reset (buf->arrayZ, buf_size); + return _try_subset (table, buf, buf_size, c); +} + template static bool _subset (hb_subset_plan_t *plan) { - bool result = false; hb_blob_t *source_blob = hb_sanitize_context_t ().reference_table (plan->source); const TableType *table = source_blob->as (); hb_tag_t tag = TableType::tableTag; - if (source_blob->data) + if (!source_blob->data) { - hb_vector_t buf; - /* TODO Not all tables are glyph-related. 'name' table size for example should not be - * affected by number of glyphs. Accommodate that. */ - unsigned buf_size = _plan_estimate_subset_table_size (plan, source_blob->length); - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG (tag), buf_size); - if (unlikely (!buf.alloc (buf_size))) - { - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG (tag), buf_size); - hb_blob_destroy (source_blob); - return false; - } - retry: - hb_serialize_context_t serializer ((void *) buf, buf_size); - serializer.start_serialize (); - hb_subset_context_t c (source_blob, plan, &serializer, tag); - bool needed = table->subset (&c); - if (serializer.ran_out_of_room) - { - buf_size += (buf_size >> 1) + 32; - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.", HB_UNTAG (tag), buf_size); - if (unlikely (!buf.alloc (buf_size))) - { - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.", HB_UNTAG (tag), buf_size); - hb_blob_destroy (source_blob); - return false; - } - goto retry; - } - serializer.end_serialize (); - - result = !serializer.in_error (); - - if (result) - { - if (needed) - { - hb_blob_t *dest_blob = _repack (tag, serializer); - if (dest_blob) - { - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c final subset table size: %u bytes.", HB_UNTAG (tag), dest_blob->length); - result = c.plan->add_table (tag, dest_blob); - hb_blob_destroy (dest_blob); - } else { - result = false; - } - } - else - { - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG (tag)); - } - } + DEBUG_MSG (SUBSET, nullptr, + "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag)); + hb_blob_destroy (source_blob); + return false; } - else - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag)); + hb_vector_t buf; + /* TODO Not all tables are glyph-related. 'name' table size for example should not be + * affected by number of glyphs. Accommodate that. */ + unsigned buf_size = _plan_estimate_subset_table_size (plan, source_blob->length); + DEBUG_MSG (SUBSET, nullptr, + "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG (tag), buf_size); + if (unlikely (!buf.alloc (buf_size))) + { + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG (tag), buf_size); + hb_blob_destroy (source_blob); + return false; + } + + bool needed = false; + hb_serialize_context_t serializer (buf.arrayZ, buf_size); + { + hb_subset_context_t c (source_blob, plan, &serializer, tag); + needed = _try_subset (table, &buf, buf_size, &c); + } hb_blob_destroy (source_blob); - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset %s", HB_UNTAG (tag), result ? "success" : "FAILED!"); + + if (serializer.ran_out_of_room || serializer.in_error ()) + { + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset FAILED!", HB_UNTAG (tag)); + return false; + } + + if (!needed) + { + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG (tag)); + return true; + } + + bool result = false; + hb_blob_t *dest_blob = _repack (tag, serializer); + if (dest_blob) + { + DEBUG_MSG (SUBSET, nullptr, + "OT::%c%c%c%c final subset table size: %u bytes.", + HB_UNTAG (tag), dest_blob->length); + result = plan->add_table (tag, dest_blob); + hb_blob_destroy (dest_blob); + } + + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset %s", + HB_UNTAG (tag), result ? "success" : "FAILED!"); return result; } diff --git a/src/meson.build b/src/meson.build index 280ddb521..dddafe9c2 100644 --- a/src/meson.build +++ b/src/meson.build @@ -478,6 +478,7 @@ if get_option('tests').enabled() 'test-algs': ['test-algs.cc', 'hb-static.cc'], 'test-array': ['test-array.cc'], 'test-repacker': ['test-repacker.cc', 'hb-static.cc'], + 'test-priority-queue': ['test-priority-queue.cc', 'hb-static.cc'], 'test-iter': ['test-iter.cc', 'hb-static.cc'], 'test-meta': ['test-meta.cc', 'hb-static.cc'], 'test-number': ['test-number.cc', 'hb-number.cc'],