Merge branch 'master' into cff-more-arrayof-fixes
diff --git a/NEWS b/NEWS
index 890c258..ef87dad 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,10 @@
+Overview of changes leading to 2.3.1
+Wednesday, January 30, 2019
+====================================
+- AAT bug fixes.
+- Misc internal housekeeping cleanup.
+
+
Overview of changes leading to 2.3.0
Thursday, December 20, 2018
====================================
diff --git a/configure.ac b/configure.ac
index 989de12..718f1d0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
AC_PREREQ([2.64])
AC_INIT([HarfBuzz],
- [2.3.0],
+ [2.3.1],
[https://github.com/harfbuzz/harfbuzz/issues/new],
[harfbuzz],
[http://harfbuzz.org/])
@@ -515,6 +515,11 @@
AC_OUTPUT
+echo
+echo "C++ compiler version:"
+$CXX --version
+echo
+
AC_MSG_NOTICE([
Build configuration:
diff --git a/src/hb-ot-hdmx-table.hh b/src/hb-ot-hdmx-table.hh
index 95229c5..953ccab 100644
--- a/src/hb-ot-hdmx-table.hh
+++ b/src/hb-ot-hdmx-table.hh
@@ -57,16 +57,19 @@
}
unsigned int len () const
- { return this->subset_plan->glyphs.length; }
+ { return this->subset_plan->num_output_glyphs (); }
- const HBUINT8* operator [] (unsigned int i) const
+ const HBUINT8* operator [] (unsigned int new_gid) const
{
- if (unlikely (i >= len ())) return nullptr;
- hb_codepoint_t gid = this->subset_plan->glyphs [i];
+ if (unlikely (new_gid >= len ())) return nullptr;
- if (gid >= sizeDeviceRecord - DeviceRecord::min_size)
+ 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[gid]);
+ return &(this->source_device_record->widthsZ[old_gid]);
}
};
@@ -140,7 +143,7 @@
this->version.set (source_hdmx->version);
this->numRecords.set (source_hdmx->numRecords);
- this->sizeDeviceRecord.set (DeviceRecord::get_size (plan->glyphs.length));
+ this->sizeDeviceRecord.set (DeviceRecord::get_size (plan->num_output_glyphs ()));
for (unsigned int i = 0; i < source_hdmx->numRecords; i++)
{
@@ -156,7 +159,7 @@
static size_t get_subsetted_size (const hdmx *source_hdmx, hb_subset_plan_t *plan)
{
- return min_size + source_hdmx->numRecords * DeviceRecord::get_size (plan->glyphs.length);
+ return min_size + source_hdmx->numRecords * DeviceRecord::get_size (plan->num_output_glyphs ());
}
bool subset (hb_subset_plan_t *plan) const
diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh
index a95a56f..9ef1f57 100644
--- a/src/hb-ot-hmtx-table.hh
+++ b/src/hb-ot-hmtx-table.hh
@@ -66,7 +66,7 @@
bool subset_update_header (hb_subset_plan_t *plan,
- unsigned int num_hmetrics) const
+ unsigned int num_hmetrics) const
{
hb_blob_t *src_blob = hb_sanitize_context_t ().reference_table<H> (plan->source, H::tableTag);
hb_blob_t *dest_blob = hb_blob_copy_writable_or_fail (src_blob);
@@ -93,75 +93,49 @@
/* All the trailing glyphs with the same advance can use one LongMetric
* and just keep LSB */
- hb_vector_t<hb_codepoint_t> &gids = plan->glyphs;
- unsigned int num_advances = gids.length;
- unsigned int last_advance = _mtx.get_advance (gids[num_advances - 1]);
- while (num_advances > 1 &&
- last_advance == _mtx.get_advance (gids[num_advances - 2]))
- {
- num_advances--;
- }
+ unsigned int num_output_glyphs = plan->num_output_glyphs ();
+ unsigned int num_advances = _mtx.num_advances_for_subset (plan);
/* alloc the new table */
size_t dest_sz = num_advances * 4
- + (gids.length - num_advances) * 2;
+ + (num_output_glyphs - num_advances) * 2;
void *dest = (void *) malloc (dest_sz);
if (unlikely (!dest))
{
return false;
}
DEBUG_MSG(SUBSET, nullptr, "%c%c%c%c in src has %d advances, %d lsbs", HB_UNTAG(T::tableTag), _mtx.num_advances, _mtx.num_metrics - _mtx.num_advances);
- DEBUG_MSG(SUBSET, nullptr, "%c%c%c%c in dest has %d advances, %d lsbs, %u bytes", HB_UNTAG(T::tableTag), num_advances, gids.length - num_advances, (unsigned int) dest_sz);
+ DEBUG_MSG(SUBSET, nullptr, "%c%c%c%c in dest has %d advances, %d lsbs, %u bytes",
+ HB_UNTAG(T::tableTag), num_advances, num_output_glyphs - num_advances, (unsigned int) dest_sz);
- const char *source_table = hb_blob_get_data (_mtx.table.get_blob (), nullptr);
// Copy everything over
- LongMetric * old_metrics = (LongMetric *) source_table;
- FWORD *lsbs = (FWORD *) (old_metrics + _mtx.num_advances);
char * dest_pos = (char *) dest;
bool failed = false;
- for (unsigned int i = 0; i < gids.length; i++)
+ for (unsigned int i = 0; i < num_output_glyphs; i++)
{
- /* the last metric or the one for gids[i] */
- LongMetric *src_metric = old_metrics + MIN ((hb_codepoint_t) _mtx.num_advances - 1, gids[i]);
- if (gids[i] < _mtx.num_advances)
+ unsigned int side_bearing = 0;
+ unsigned int advance = 0;
+ hb_codepoint_t old_gid;
+ if (plan->old_gid_for_new_gid (i, &old_gid))
{
- /* src is a LongMetric */
- if (i < num_advances)
- {
- /* dest is a LongMetric, copy it */
- *((LongMetric *) dest_pos) = *src_metric;
- }
- else
- {
- /* dest just sb */
- *((FWORD *) dest_pos) = src_metric->sb;
- }
+ // Glyph is not an empty glyph so copy advance and side bearing
+ // from the input font.
+ side_bearing = _mtx.get_side_bearing (old_gid);
+ advance = _mtx.get_advance (old_gid);
+ }
+
+ bool has_advance = i < num_advances;
+ if (has_advance)
+ {
+ ((LongMetric *) dest_pos)->advance.set (advance);
+ ((LongMetric *) dest_pos)->sb.set (side_bearing);
}
else
{
- if (gids[i] >= _mtx.num_metrics)
- {
- DEBUG_MSG(SUBSET, nullptr, "gid %d is >= number of source metrics %d",
- gids[i], _mtx.num_metrics);
- failed = true;
- break;
- }
- FWORD src_sb = *(lsbs + gids[i] - _mtx.num_advances);
- if (i < num_advances)
- {
- /* dest needs a full LongMetric */
- LongMetric *metric = (LongMetric *)dest_pos;
- metric->advance = src_metric->advance;
- metric->sb = src_sb;
- }
- else
- {
- /* dest just needs an sb */
- *((FWORD *) dest_pos) = src_sb;
- }
+ ((FWORD *) dest_pos)->set (side_bearing);
}
- dest_pos += (i < num_advances ? 4 : 2);
+ dest_pos += (has_advance ? 4 : 2);
}
_mtx.fini ();
@@ -187,7 +161,7 @@
friend struct hmtxvmtx;
void init (hb_face_t *face,
- unsigned int default_advance_ = 0)
+ unsigned int default_advance_ = 0)
{
default_advance = default_advance_ ? default_advance_ : hb_face_get_upem (face);
@@ -280,6 +254,32 @@
return advance;
}
+ unsigned int num_advances_for_subset (const hb_subset_plan_t *plan) const
+ {
+ unsigned int num_advances = plan->num_output_glyphs ();
+ unsigned int last_advance = _advance_for_new_gid (plan,
+ num_advances - 1);
+ while (num_advances > 1 &&
+ last_advance == _advance_for_new_gid (plan,
+ num_advances - 2))
+ {
+ num_advances--;
+ }
+
+ return num_advances;
+ }
+
+ private:
+ unsigned int _advance_for_new_gid (const hb_subset_plan_t *plan,
+ hb_codepoint_t new_gid) const
+ {
+ hb_codepoint_t old_gid;
+ if (!plan->old_gid_for_new_gid (new_gid, &old_gid))
+ return 0;
+
+ return get_advance (old_gid);
+ }
+
public:
bool has_font_extents;
int ascender;
diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh
index 39a8bba..9b17225 100644
--- a/src/hb-ot-layout-common.hh
+++ b/src/hb-ot-layout-common.hh
@@ -1222,7 +1222,7 @@
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset;
+ const hb_set_t &glyphset = *c->plan->glyphset ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
hb_vector_t<GlyphID> glyphs;
hb_vector_t<HBUINT16> klasses;
@@ -1369,7 +1369,7 @@
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset;
+ const hb_set_t &glyphset = *c->plan->glyphset ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
hb_vector_t<GlyphID> glyphs;
hb_vector_t<HBUINT16> klasses;
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 33b8f0e..cc10634 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -105,7 +105,7 @@
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset;
+ const hb_set_t &glyphset = *c->plan->glyphset ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
hb_vector_t<GlyphID> from;
hb_vector_t<GlyphID> to;
@@ -202,7 +202,7 @@
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset;
+ const hb_set_t &glyphset = *c->plan->glyphset ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
hb_vector_t<GlyphID> from;
hb_vector_t<GlyphID> to;
diff --git a/src/hb-ot-maxp-table.hh b/src/hb-ot-maxp-table.hh
index e4b67ab..10bd592 100644
--- a/src/hb-ot-maxp-table.hh
+++ b/src/hb-ot-maxp-table.hh
@@ -105,7 +105,7 @@
}
maxp *maxp_prime = (maxp *) hb_blob_get_data (maxp_prime_blob, nullptr);
- maxp_prime->set_num_glyphs (plan->glyphs.length);
+ maxp_prime->set_num_glyphs (plan->num_output_glyphs ());
if (plan->drop_hints)
drop_hint_fields (plan, maxp_prime);
diff --git a/src/hb-ot-vorg-table.hh b/src/hb-ot-vorg-table.hh
index 0202fcc..39073db 100644
--- a/src/hb-ot-vorg-table.hh
+++ b/src/hb-ot-vorg-table.hh
@@ -110,21 +110,29 @@
/* count the number of glyphs to be included in the subset table */
hb_vector_t<VertOriginMetric> subset_metrics;
subset_metrics.init ();
- unsigned int glyph = 0;
+
+
+ hb_codepoint_t old_glyph = HB_SET_VALUE_INVALID;
unsigned int i = 0;
- while ((glyph < plan->glyphs.length) && (i < vertYOrigins.len))
+ while (i < vertYOrigins.len
+ && plan->glyphset ()->next (&old_glyph))
{
- if (plan->glyphs[glyph] > vertYOrigins[i].glyph)
- i++;
- else if (plan->glyphs[glyph] < vertYOrigins[i].glyph)
- glyph++;
- else
+ while (old_glyph > vertYOrigins[i].glyph)
{
- VertOriginMetric *metrics = subset_metrics.push ();
- metrics->glyph.set (glyph);
- metrics->vertOriginY.set (vertYOrigins[i].vertOriginY);
- glyph++;
i++;
+ if (i >= vertYOrigins.len)
+ break;
+ }
+
+ if (old_glyph == vertYOrigins[i].glyph)
+ {
+ hb_codepoint_t new_glyph;
+ if (plan->new_gid_for_old_gid (old_glyph, &new_glyph))
+ {
+ VertOriginMetric *metrics = subset_metrics.push ();
+ metrics->glyph.set (new_glyph);
+ metrics->vertOriginY.set (vertYOrigins[i].vertOriginY);
+ }
}
}
diff --git a/src/hb-subset-cff1.cc b/src/hb-subset-cff1.cc
index 5133a4d..e015eda 100644
--- a/src/hb-subset-cff1.cc
+++ b/src/hb-subset-cff1.cc
@@ -469,11 +469,11 @@
supp_size = 0;
supp_codes.init ();
- subset_enc_num_codes = plan->glyphs.length - 1;
+ subset_enc_num_codes = plan->glyphs_deprecated.length - 1;
unsigned int glyph;
- for (glyph = 1; glyph < plan->glyphs.length; glyph++)
+ for (glyph = 1; glyph < plan->glyphs_deprecated.length; glyph++)
{
- hb_codepoint_t orig_glyph = plan->glyphs[glyph];
+ hb_codepoint_t orig_glyph = plan->glyphs_deprecated[glyph];
code = acc.glyph_to_code (orig_glyph);
if (code == CFF_UNDEF_CODE)
{
@@ -526,9 +526,9 @@
subset_charset_ranges.resize (0);
unsigned int glyph;
- for (glyph = 1; glyph < plan->glyphs.length; glyph++)
+ for (glyph = 1; glyph < plan->glyphs_deprecated.length; glyph++)
{
- hb_codepoint_t orig_glyph = plan->glyphs[glyph];
+ hb_codepoint_t orig_glyph = plan->glyphs_deprecated[glyph];
sid = acc.glyph_to_sid (orig_glyph);
if (!acc.is_CID ())
@@ -544,7 +544,7 @@
bool two_byte = subset_charset_ranges.finalize (glyph);
- size0 = Charset0::min_size + HBUINT16::static_size * (plan->glyphs.length - 1);
+ size0 = Charset0::min_size + HBUINT16::static_size * (plan->glyphs_deprecated.length - 1);
if (!two_byte)
size_ranges = Charset1::min_size + Charset1_Range::static_size * subset_charset_ranges.length;
else
@@ -559,7 +559,7 @@
return Charset::calculate_serialized_size (
subset_charset_format,
- subset_charset_format? subset_charset_ranges.length: plan->glyphs.length);
+ subset_charset_format? subset_charset_ranges.length: plan->glyphs_deprecated.length);
}
bool collect_sids_in_dicts (const OT::cff1::accelerator_subset_t &acc)
@@ -589,19 +589,19 @@
hb_subset_plan_t *plan)
{
/* make sure notdef is first */
- if ((plan->glyphs.length == 0) || (plan->glyphs[0] != 0)) return false;
+ if ((plan->glyphs_deprecated.length == 0) || (plan->glyphs_deprecated[0] != 0)) return false;
final_size = 0;
- num_glyphs = plan->glyphs.length;
+ num_glyphs = plan->glyphs_deprecated.length;
orig_fdcount = acc.fdCount;
drop_hints = plan->drop_hints;
desubroutinize = plan->desubroutinize;
/* check whether the subset renumbers any glyph IDs */
gid_renum = false;
- for (unsigned int glyph = 0; glyph < plan->glyphs.length; glyph++)
+ for (unsigned int glyph = 0; glyph < plan->glyphs_deprecated.length; glyph++)
{
- if (plan->glyphs[glyph] != glyph) {
+ if (plan->glyphs_deprecated[glyph] != glyph) {
gid_renum = true;
break;
}
@@ -644,7 +644,7 @@
/* Determine re-mapping of font index as fdmap among other info */
if (acc.fdSelect != &Null(CFF1FDSelect))
{
- if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs,
+ if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs_deprecated,
orig_fdcount,
*acc.fdSelect,
subset_fdcount,
@@ -681,7 +681,7 @@
{
/* Flatten global & local subrs */
subr_flattener_t<const OT::cff1::accelerator_subset_t, cff1_cs_interp_env_t, cff1_cs_opset_flatten_t>
- flattener(acc, plan->glyphs, plan->drop_hints);
+ flattener(acc, plan->glyphs_deprecated, plan->drop_hints);
if (!flattener.flatten (subset_charstrings))
return false;
@@ -691,11 +691,11 @@
else
{
/* Subset subrs: collect used subroutines, leaving all unused ones behind */
- if (!subr_subsetter.subset (acc, plan->glyphs, plan->drop_hints))
+ if (!subr_subsetter.subset (acc, plan->glyphs_deprecated, plan->drop_hints))
return false;
/* encode charstrings, global subrs, local subrs with new subroutine numbers */
- if (!subr_subsetter.encode_charstrings (acc, plan->glyphs, subset_charstrings))
+ if (!subr_subsetter.encode_charstrings (acc, plan->glyphs_deprecated, subset_charstrings))
return false;
if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs))
@@ -784,7 +784,7 @@
offsets.charStringsInfo.offSize = calcOffSize (dataSize);
if (unlikely (offsets.charStringsInfo.offSize > 4))
return false;
- final_size += CFF1CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs.length, dataSize);
+ final_size += CFF1CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs_deprecated.length, dataSize);
}
/* private dicts & local subrs */
@@ -816,7 +816,7 @@
if (!acc.is_CID ())
offsets.privateDictInfo = fontdicts_mod[0].privateDictInfo;
- return ((subset_charstrings.length == plan->glyphs.length)
+ return ((subset_charstrings.length == plan->glyphs_deprecated.length)
&& (fontdicts_mod.length == subset_fdcount));
}
@@ -1064,7 +1064,7 @@
unsigned int cff_prime_size = cff_plan.get_final_size ();
char *cff_prime_data = (char *) calloc (1, cff_prime_size);
- if (unlikely (!_write_cff1 (cff_plan, acc, plan->glyphs,
+ if (unlikely (!_write_cff1 (cff_plan, acc, plan->glyphs_deprecated,
cff_prime_size, cff_prime_data))) {
DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff.");
free (cff_prime_data);
diff --git a/src/hb-subset-cff2.cc b/src/hb-subset-cff2.cc
index 73a292d..4830b63 100644
--- a/src/hb-subset-cff2.cc
+++ b/src/hb-subset-cff2.cc
@@ -287,7 +287,7 @@
{
/* Flatten global & local subrs */
subr_flattener_t<const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t, cff2_cs_opset_flatten_t>
- flattener(acc, plan->glyphs, plan->drop_hints);
+ flattener(acc, plan->glyphs_deprecated, plan->drop_hints);
if (!flattener.flatten (subset_charstrings))
return false;
@@ -297,11 +297,11 @@
else
{
/* Subset subrs: collect used subroutines, leaving all unused ones behind */
- if (!subr_subsetter.subset (acc, plan->glyphs, plan->drop_hints))
+ if (!subr_subsetter.subset (acc, plan->glyphs_deprecated, plan->drop_hints))
return false;
/* encode charstrings, global subrs, local subrs with new subroutine numbers */
- if (!subr_subsetter.encode_charstrings (acc, plan->glyphs, subset_charstrings))
+ if (!subr_subsetter.encode_charstrings (acc, plan->glyphs_deprecated, subset_charstrings))
return false;
if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs))
@@ -352,7 +352,7 @@
if (acc.fdSelect != &Null(CFF2FDSelect))
{
offsets.FDSelectInfo.offset = final_size;
- if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs,
+ if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs_deprecated,
orig_fdcount,
*(const FDSelect *)acc.fdSelect,
subset_fdcount,
@@ -385,7 +385,7 @@
offsets.charStringsInfo.offset = final_size;
unsigned int dataSize = subset_charstrings.total_size ();
offsets.charStringsInfo.offSize = calcOffSize (dataSize);
- final_size += CFF2CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs.length, dataSize);
+ final_size += CFF2CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs_deprecated.length, dataSize);
}
/* private dicts & local subrs */
@@ -584,7 +584,7 @@
unsigned int cff2_prime_size = cff2_plan.get_final_size ();
char *cff2_prime_data = (char *) calloc (1, cff2_prime_size);
- if (unlikely (!_write_cff2 (cff2_plan, acc, plan->glyphs,
+ if (unlikely (!_write_cff2 (cff2_plan, acc, plan->glyphs_deprecated,
cff2_prime_size, cff2_prime_data))) {
DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff2.");
free (cff2_prime_data);
diff --git a/src/hb-subset-glyf.cc b/src/hb-subset-glyf.cc
index cca364d..ee004ee 100644
--- a/src/hb-subset-glyf.cc
+++ b/src/hb-subset-glyf.cc
@@ -29,97 +29,128 @@
#include "hb-set.h"
#include "hb-subset-glyf.hh"
-static bool
-_calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf,
- hb_vector_t<hb_codepoint_t> &glyph_ids,
- hb_bool_t drop_hints,
- bool *use_short_loca /* OUT */,
- unsigned int *glyf_size /* OUT */,
- unsigned int *loca_size /* OUT */,
- hb_vector_t<unsigned int> *instruction_ranges /* OUT */)
+struct loca_data_t
{
- unsigned int total = 0;
- for (unsigned int i = 0; i < glyph_ids.length; i++)
+ bool is_short;
+ void *data;
+ unsigned int size;
+
+ inline bool
+ _write_loca_entry (unsigned int id,
+ unsigned int offset)
{
- hb_codepoint_t next_glyph = glyph_ids[i];
- if (!instruction_ranges->resize (instruction_ranges->length + 2))
+ unsigned int entry_size = is_short ? sizeof (OT::HBUINT16) : sizeof (OT::HBUINT32);
+ if ((id + 1) * entry_size <= size)
{
- DEBUG_MSG(SUBSET, nullptr, "Failed to resize instruction_ranges.");
+ if (is_short) {
+ ((OT::HBUINT16*) data) [id].set (offset / 2);
+ } else {
+ ((OT::HBUINT32*) data) [id].set (offset);
+ }
+ return true;
+ }
+
+ // Offset was not written because the write is out of bounds.
+ DEBUG_MSG(SUBSET,
+ nullptr,
+ "WARNING: Attempted to write an out of bounds loca entry at index %d. Loca size is %d.",
+ id,
+ size);
+ return false;
+ }
+};
+
+/**
+ * If hints are being dropped find the range which in glyf at which
+ * the hinting instructions are located. Add them to the instruction_ranges
+ * vector.
+ */
+static bool
+_add_instructions_range (const OT::glyf::accelerator_t &glyf,
+ hb_codepoint_t glyph_id,
+ unsigned int glyph_start_offset,
+ unsigned int glyph_end_offset,
+ bool drop_hints,
+ hb_vector_t<unsigned int> *instruction_ranges /* OUT */)
+{
+ if (!instruction_ranges->resize (instruction_ranges->length + 2))
+ {
+ DEBUG_MSG(SUBSET, nullptr, "Failed to resize instruction_ranges.");
+ return false;
+ }
+ unsigned int *instruction_start = &(*instruction_ranges)[instruction_ranges->length - 2];
+ *instruction_start = 0;
+ unsigned int *instruction_end = &(*instruction_ranges)[instruction_ranges->length - 1];
+ *instruction_end = 0;
+
+ if (drop_hints)
+ {
+ if (unlikely (!glyf.get_instruction_offsets (glyph_start_offset, glyph_end_offset,
+ instruction_start, instruction_end)))
+ {
+ DEBUG_MSG(SUBSET, nullptr, "Unable to get instruction offsets for %d", glyph_id);
return false;
}
- unsigned int *instruction_start = &(*instruction_ranges)[instruction_ranges->length - 2];
- *instruction_start = 0;
- unsigned int *instruction_end = &(*instruction_ranges)[instruction_ranges->length - 1];
- *instruction_end = 0;
+ }
+ return true;
+}
+
+static bool
+_calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf,
+ const hb_subset_plan_t *plan,
+ loca_data_t *loca_data, /* OUT */
+ unsigned int *glyf_size /* OUT */,
+ hb_vector_t<unsigned int> *instruction_ranges /* OUT */)
+{
+ unsigned int total = 0;
+
+ hb_codepoint_t next_glyph = HB_SET_VALUE_INVALID;
+ while (plan->glyphset ()->next (&next_glyph))
+ {
unsigned int start_offset, end_offset;
if (unlikely (!(glyf.get_offsets (next_glyph, &start_offset, &end_offset) &&
glyf.remove_padding (start_offset, &end_offset))))
{
DEBUG_MSG(SUBSET, nullptr, "Invalid gid %d", next_glyph);
- continue;
+ start_offset = end_offset = 0;
}
- if (end_offset - start_offset < OT::glyf::GlyphHeader::static_size)
+
+ bool is_zero_length = end_offset - start_offset < OT::glyf::GlyphHeader::static_size;
+ if (!_add_instructions_range (glyf,
+ next_glyph,
+ start_offset,
+ end_offset,
+ plan->drop_hints && !is_zero_length,
+ instruction_ranges))
+ return false;
+
+ if (is_zero_length)
continue; /* 0-length glyph */
- if (drop_hints)
- {
- if (unlikely (!glyf.get_instruction_offsets (start_offset, end_offset,
- instruction_start, instruction_end)))
- {
- DEBUG_MSG(SUBSET, nullptr, "Unable to get instruction offsets for %d", next_glyph);
- return false;
- }
- }
-
- total += end_offset - start_offset - (*instruction_end - *instruction_start);
+ total += end_offset - start_offset
+ - ((*instruction_ranges)[instruction_ranges->length - 1]
+ - (*instruction_ranges)[instruction_ranges->length - 2]);
/* round2 so short loca will work */
total += total % 2;
}
*glyf_size = total;
- *use_short_loca = (total <= 131070);
- *loca_size = (glyph_ids.length + 1)
- * (*use_short_loca ? sizeof (OT::HBUINT16) : sizeof (OT::HBUINT32));
+ loca_data->is_short = (total <= 131070);
+ loca_data->size = (plan->num_output_glyphs () + 1)
+ * (loca_data->is_short ? sizeof (OT::HBUINT16) : sizeof (OT::HBUINT32));
DEBUG_MSG(SUBSET, nullptr, "preparing to subset glyf: final size %d, loca size %d, using %s loca",
total,
- *loca_size,
- *use_short_loca ? "short" : "long");
+ loca_data->size,
+ loca_data->is_short ? "short" : "long");
return true;
}
-static bool
-_write_loca_entry (unsigned int id,
- unsigned int offset,
- bool is_short,
- void *loca_prime,
- unsigned int loca_size)
-{
- unsigned int entry_size = is_short ? sizeof (OT::HBUINT16) : sizeof (OT::HBUINT32);
- if ((id + 1) * entry_size <= loca_size)
- {
- if (is_short) {
- ((OT::HBUINT16*) loca_prime) [id].set (offset / 2);
- } else {
- ((OT::HBUINT32*) loca_prime) [id].set (offset);
- }
- return true;
- }
-
- // Offset was not written because the write is out of bounds.
- DEBUG_MSG(SUBSET,
- nullptr,
- "WARNING: Attempted to write an out of bounds loca entry at index %d. Loca size is %d.",
- id,
- loca_size);
- return false;
-}
-
static void
-_update_components (hb_subset_plan_t * plan,
- char * glyph_start,
- unsigned int length)
+_update_components (const hb_subset_plan_t *plan,
+ char *glyph_start,
+ unsigned int length)
{
OT::glyf::CompositeGlyphHeader::Iterator iterator;
if (OT::glyf::CompositeGlyphHeader::get_iterator (glyph_start,
@@ -153,24 +184,35 @@
}
static bool
-_write_glyf_and_loca_prime (hb_subset_plan_t *plan,
+_write_glyf_and_loca_prime (const hb_subset_plan_t *plan,
const OT::glyf::accelerator_t &glyf,
const char *glyf_data,
- bool use_short_loca,
- hb_vector_t<unsigned int> &instruction_ranges,
+ hb_vector_t<unsigned int> &instruction_ranges,
unsigned int glyf_prime_size,
char *glyf_prime_data /* OUT */,
- unsigned int loca_prime_size,
- char *loca_prime_data /* OUT */)
+ loca_data_t *loca_prime /* OUT */)
{
- hb_vector_t<hb_codepoint_t> &glyph_ids = plan->glyphs;
char *glyf_prime_data_next = glyf_prime_data;
bool success = true;
- for (unsigned int i = 0; i < glyph_ids.length; i++)
+
+
+ unsigned int i = 0;
+ hb_codepoint_t new_gid;
+ for (new_gid = 0; new_gid < plan->num_output_glyphs (); new_gid++)
{
+ hb_codepoint_t old_gid;
+ if (!plan->old_gid_for_new_gid (new_gid, &old_gid))
+ {
+ // Empty glyph, add a loca entry and carry on.
+ loca_prime->_write_loca_entry (new_gid,
+ glyf_prime_data_next - glyf_prime_data);
+ continue;
+ }
+
+
unsigned int start_offset, end_offset;
- if (unlikely (!(glyf.get_offsets (glyph_ids[i], &start_offset, &end_offset) &&
+ if (unlikely (!(glyf.get_offsets (old_gid, &start_offset, &end_offset) &&
glyf.remove_padding (start_offset, &end_offset))))
end_offset = start_offset = 0;
@@ -182,9 +224,9 @@
if (glyf_prime_data_next + length > glyf_prime_data + glyf_prime_size)
{
DEBUG_MSG(SUBSET,
- nullptr,
- "WARNING: Attempted to write an out of bounds glyph entry for gid %d (length %d)",
- i, length);
+ nullptr,
+ "WARNING: Attempted to write an out of bounds glyph entry for gid %d (length %d)",
+ i, length);
return false;
}
@@ -204,22 +246,20 @@
memset (glyf_prime_data_next + instruction_start - start_offset - 2, 0, 2);
}
- success = success && _write_loca_entry (i,
- glyf_prime_data_next - glyf_prime_data,
- use_short_loca,
- loca_prime_data,
- loca_prime_size);
+ success = success && loca_prime->_write_loca_entry (new_gid,
+ glyf_prime_data_next - glyf_prime_data);
_update_components (plan, glyf_prime_data_next, length);
// TODO: don't align to two bytes if using long loca.
glyf_prime_data_next += length + (length % 2); // Align to 2 bytes for short loca.
+
+ i++;
}
- success = success && _write_loca_entry (glyph_ids.length,
- glyf_prime_data_next - glyf_prime_data,
- use_short_loca,
- loca_prime_data,
- loca_prime_size);
+ // loca table has n+1 entries where the last entry signifies the end location of the last
+ // glyph.
+ success = success && loca_prime->_write_loca_entry (new_gid,
+ glyf_prime_data_next - glyf_prime_data);
return success;
}
@@ -228,52 +268,48 @@
const char *glyf_data,
hb_subset_plan_t *plan,
bool *use_short_loca,
- hb_blob_t **glyf_prime /* OUT */,
- hb_blob_t **loca_prime /* OUT */)
+ hb_blob_t **glyf_prime_blob /* OUT */,
+ hb_blob_t **loca_prime_blob /* OUT */)
{
// TODO(grieger): Sanity check allocation size for the new table.
- hb_vector_t<hb_codepoint_t> &glyphs_to_retain = plan->glyphs;
-
+ loca_data_t loca_prime;
unsigned int glyf_prime_size;
- unsigned int loca_prime_size;
hb_vector_t<unsigned int> instruction_ranges;
instruction_ranges.init ();
if (unlikely (!_calculate_glyf_and_loca_prime_size (glyf,
- glyphs_to_retain,
- plan->drop_hints,
- use_short_loca,
+ plan,
+ &loca_prime,
&glyf_prime_size,
- &loca_prime_size,
&instruction_ranges))) {
instruction_ranges.fini ();
return false;
}
+ *use_short_loca = loca_prime.is_short;
char *glyf_prime_data = (char *) calloc (1, glyf_prime_size);
- char *loca_prime_data = (char *) calloc (1, loca_prime_size);
+ loca_prime.data = (void *) calloc (1, loca_prime.size);
if (unlikely (!_write_glyf_and_loca_prime (plan, glyf, glyf_data,
- *use_short_loca,
instruction_ranges,
glyf_prime_size, glyf_prime_data,
- loca_prime_size, loca_prime_data))) {
+ &loca_prime))) {
free (glyf_prime_data);
- free (loca_prime_data);
+ free (loca_prime.data);
instruction_ranges.fini ();
return false;
}
instruction_ranges.fini ();
- *glyf_prime = hb_blob_create (glyf_prime_data,
- glyf_prime_size,
- HB_MEMORY_MODE_READONLY,
- glyf_prime_data,
- free);
- *loca_prime = hb_blob_create (loca_prime_data,
- loca_prime_size,
- HB_MEMORY_MODE_READONLY,
- loca_prime_data,
- free);
+ *glyf_prime_blob = hb_blob_create (glyf_prime_data,
+ glyf_prime_size,
+ HB_MEMORY_MODE_READONLY,
+ glyf_prime_data,
+ free);
+ *loca_prime_blob = hb_blob_create ((char *) loca_prime.data,
+ loca_prime.size,
+ HB_MEMORY_MODE_READONLY,
+ loca_prime.data,
+ free);
return true;
}
diff --git a/src/hb-subset-input.cc b/src/hb-subset-input.cc
index f718a56..693c9c2 100644
--- a/src/hb-subset-input.cc
+++ b/src/hb-subset-input.cc
@@ -44,7 +44,10 @@
input->unicodes = hb_set_create ();
input->glyphs = hb_set_create ();
+ input->drop_hints = false;
input->drop_layout = true;
+ input->desubroutinize = false;
+ input->retain_gids = false;
return input;
}
@@ -144,3 +147,27 @@
{
return subset_input->desubroutinize;
}
+
+/**
+ * hb_subset_input_set_retain_gids:
+ * @subset_input: a subset_input.
+ * @retain_gids: If true the subsetter will not renumber glyph ids.
+ * Since: REPLACEME
+ **/
+HB_EXTERN void
+hb_subset_input_set_retain_gids (hb_subset_input_t *subset_input,
+ hb_bool_t retain_gids)
+{
+ subset_input->retain_gids = retain_gids;
+}
+
+/**
+ * hb_subset_input_get_retain_gids:
+ * Returns: value of retain_gids.
+ * Since: REPLACEME
+ **/
+HB_EXTERN hb_bool_t
+hb_subset_input_get_retain_gids (hb_subset_input_t *subset_input)
+{
+ return subset_input->retain_gids;
+}
diff --git a/src/hb-subset-input.hh b/src/hb-subset-input.hh
index 8dad94f..04d6e12 100644
--- a/src/hb-subset-input.hh
+++ b/src/hb-subset-input.hh
@@ -44,6 +44,7 @@
bool drop_hints : 1;
bool drop_layout : 1;
bool desubroutinize : 1;
+ bool retain_gids : 1;
/* TODO
*
* features
diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc
index cff3426..5702d01 100644
--- a/src/hb-subset-plan.cc
+++ b/src/hb-subset-plan.cc
@@ -156,11 +156,32 @@
}
static void
-_create_old_gid_to_new_gid_map (const hb_vector_t<hb_codepoint_t> &glyphs,
- hb_map_t *glyph_map)
+_create_old_gid_to_new_gid_map (const hb_face_t *face,
+ bool retain_gids,
+ const hb_vector_t<hb_codepoint_t> &glyphs,
+ hb_map_t *glyph_map, /* OUT */
+ hb_map_t *reverse_glyph_map, /* OUT */
+ unsigned int *num_glyphs /* OUT */)
{
for (unsigned int i = 0; i < glyphs.length; i++) {
- glyph_map->set (glyphs[i], i);
+ if (!retain_gids)
+ {
+ glyph_map->set (glyphs[i], i);
+ reverse_glyph_map->set (i, glyphs[i]);
+ }
+ else
+ {
+ glyph_map->set (glyphs[i], glyphs[i]);
+ reverse_glyph_map->set (glyphs[i], glyphs[i]);
+ }
+ }
+ if (!retain_gids || glyphs.length == 0)
+ {
+ *num_glyphs = glyphs.length;
+ }
+ else
+ {
+ *num_glyphs = face->get_num_glyphs ();
}
}
@@ -184,19 +205,25 @@
plan->drop_layout = input->drop_layout;
plan->desubroutinize = input->desubroutinize;
plan->unicodes = hb_set_create();
- plan->glyphs.init();
+ plan->glyphs_deprecated.init();
plan->source = hb_face_reference (face);
plan->dest = hb_face_builder_create ();
plan->codepoint_to_glyph = hb_map_create();
plan->glyph_map = hb_map_create();
- plan->glyphset = _populate_gids_to_retain (face,
- input->unicodes,
- !plan->drop_layout,
- plan->unicodes,
- plan->codepoint_to_glyph,
- &plan->glyphs);
- _create_old_gid_to_new_gid_map (plan->glyphs,
- plan->glyph_map);
+ plan->reverse_glyph_map = hb_map_create();
+ plan->_glyphset = _populate_gids_to_retain (face,
+ input->unicodes,
+ !plan->drop_layout,
+ plan->unicodes,
+ plan->codepoint_to_glyph,
+ &plan->glyphs_deprecated);
+
+ _create_old_gid_to_new_gid_map (face,
+ input->retain_gids,
+ plan->glyphs_deprecated,
+ plan->glyph_map,
+ plan->reverse_glyph_map,
+ &plan->_num_output_glyphs);
return plan;
}
@@ -212,12 +239,13 @@
if (!hb_object_destroy (plan)) return;
hb_set_destroy (plan->unicodes);
- plan->glyphs.fini ();
+ plan->glyphs_deprecated.fini ();
hb_face_destroy (plan->source);
hb_face_destroy (plan->dest);
hb_map_destroy (plan->codepoint_to_glyph);
hb_map_destroy (plan->glyph_map);
- hb_set_destroy (plan->glyphset);
+ hb_map_destroy (plan->reverse_glyph_map);
+ hb_set_destroy (plan->_glyphset);
free (plan);
}
diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh
index a710a4d..32c1999 100644
--- a/src/hb-subset-plan.hh
+++ b/src/hb-subset-plan.hh
@@ -33,6 +33,7 @@
#include "hb-subset-input.hh"
#include "hb-map.hh"
+#include "hb-set.hh"
struct hb_subset_plan_t
{
@@ -45,18 +46,54 @@
// For each cp that we'd like to retain maps to the corresponding gid.
hb_set_t *unicodes;
- hb_vector_t<hb_codepoint_t> glyphs;
- hb_set_t *glyphset;
-
+ // The glyph subset
hb_map_t *codepoint_to_glyph;
+
+ // Old -> New glyph id mapping
hb_map_t *glyph_map;
+ hb_map_t *reverse_glyph_map;
+
+ // Deprecated members:
+ hb_vector_t<hb_codepoint_t> glyphs_deprecated;
// Plan is only good for a specific source/dest so keep them with it
hb_face_t *source;
hb_face_t *dest;
- bool new_gid_for_codepoint (hb_codepoint_t codepoint,
- hb_codepoint_t *new_gid) const
+ unsigned int _num_output_glyphs;
+ hb_set_t *_glyphset;
+
+ public:
+
+ /*
+ * The set of input glyph ids which will be retained in the subset.
+ */
+ inline const hb_set_t *
+ glyphset () const
+ {
+ return _glyphset;
+ }
+
+ /*
+ * The total number of output glyphs in the final subset.
+ */
+ inline unsigned int
+ num_output_glyphs () const
+ {
+ return _num_output_glyphs;
+ }
+
+ /*
+ * Given an output gid , returns true if that glyph id is an empty
+ * glyph (ie. it's a gid that we are dropping all data for).
+ */
+ inline bool is_empty_glyph (hb_codepoint_t gid) const
+ {
+ return !_glyphset->has (gid);
+ }
+
+ inline bool new_gid_for_codepoint (hb_codepoint_t codepoint,
+ hb_codepoint_t *new_gid) const
{
hb_codepoint_t old_gid = codepoint_to_glyph->get (codepoint);
if (old_gid == HB_MAP_VALUE_INVALID)
@@ -65,8 +102,8 @@
return new_gid_for_old_gid (old_gid, new_gid);
}
- bool new_gid_for_old_gid (hb_codepoint_t old_gid,
- hb_codepoint_t *new_gid) const
+ inline bool new_gid_for_old_gid (hb_codepoint_t old_gid,
+ hb_codepoint_t *new_gid) const
{
hb_codepoint_t gid = glyph_map->get (old_gid);
if (gid == HB_MAP_VALUE_INVALID)
@@ -76,7 +113,18 @@
return true;
}
- bool
+ inline bool old_gid_for_new_gid (hb_codepoint_t new_gid,
+ hb_codepoint_t *old_gid) const
+ {
+ hb_codepoint_t gid = reverse_glyph_map->get (new_gid);
+ if (gid == HB_MAP_VALUE_INVALID)
+ return false;
+
+ *old_gid = gid;
+ return true;
+ }
+
+ inline bool
add_table (hb_tag_t tag,
hb_blob_t *contents)
{
diff --git a/src/hb-subset.cc b/src/hb-subset.cc
index 37e7cec..135265f 100644
--- a/src/hb-subset.cc
+++ b/src/hb-subset.cc
@@ -52,7 +52,7 @@
unsigned int table_len)
{
unsigned int src_glyphs = plan->source->get_num_glyphs ();
- unsigned int dst_glyphs = plan->glyphset->get_population ();
+ unsigned int dst_glyphs = plan->glyphset ()->get_population ();
if (unlikely (!src_glyphs))
return 512 + table_len;
diff --git a/src/hb-subset.h b/src/hb-subset.h
index f582e46..657709e 100644
--- a/src/hb-subset.h
+++ b/src/hb-subset.h
@@ -72,6 +72,12 @@
HB_EXTERN hb_bool_t
hb_subset_input_get_desubroutinize (hb_subset_input_t *subset_input);
+HB_EXTERN void
+hb_subset_input_set_retain_gids (hb_subset_input_t *subset_input,
+ hb_bool_t retain_gids);
+HB_EXTERN hb_bool_t
+hb_subset_input_get_retain_gids (hb_subset_input_t *subset_input);
+
/* hb_subset () */
HB_EXTERN hb_face_t *
hb_subset (hb_face_t *source, hb_subset_input_t *input);
diff --git a/src/hb-version.h b/src/hb-version.h
index 0c82d5b..13db8ce 100644
--- a/src/hb-version.h
+++ b/src/hb-version.h
@@ -38,9 +38,9 @@
#define HB_VERSION_MAJOR 2
#define HB_VERSION_MINOR 3
-#define HB_VERSION_MICRO 0
+#define HB_VERSION_MICRO 1
-#define HB_VERSION_STRING "2.3.0"
+#define HB_VERSION_STRING "2.3.1"
#define HB_VERSION_ATLEAST(major,minor,micro) \
((major)*10000+(minor)*100+(micro) <= \
diff --git a/test/api/fonts/Roboto-Regular.ac.retaingids.ttf b/test/api/fonts/Roboto-Regular.ac.retaingids.ttf
new file mode 100644
index 0000000..8606a55
--- /dev/null
+++ b/test/api/fonts/Roboto-Regular.ac.retaingids.ttf
Binary files differ
diff --git a/test/api/test-subset-glyf.c b/test/api/test-subset-glyf.c
index 0e5c293..e8609ca 100644
--- a/test/api/test-subset-glyf.c
+++ b/test/api/test-subset-glyf.c
@@ -257,6 +257,31 @@
hb_face_destroy (face);
}
+static void
+test_subset_glyf_retain_gids (void)
+{
+ hb_face_t *face_abc = hb_test_open_font_file ("fonts/Roboto-Regular.abc.ttf");
+ hb_face_t *face_ac = hb_test_open_font_file ("fonts/Roboto-Regular.ac.retaingids.ttf");
+
+ hb_set_t *codepoints = hb_set_create();
+ hb_face_t *face_abc_subset;
+ hb_set_add (codepoints, 97);
+ hb_set_add (codepoints, 99);
+
+ hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
+ hb_subset_input_set_retain_gids (input, true);
+ face_abc_subset = hb_subset_test_create_subset (face_abc, input);
+ hb_set_destroy (codepoints);
+
+ hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','l','y','f'));
+ hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('l','o','c', 'a'));
+ check_maxp_num_glyphs(face_abc_subset, 4, true);
+
+ hb_face_destroy (face_abc_subset);
+ hb_face_destroy (face_abc);
+ hb_face_destroy (face_ac);
+}
+
// TODO(grieger): test for long loca generation.
int
@@ -272,6 +297,7 @@
hb_test_add (test_subset_glyf_with_components);
hb_test_add (test_subset_glyf_with_gsub);
hb_test_add (test_subset_glyf_without_gsub);
+ hb_test_add (test_subset_glyf_retain_gids);
return hb_test_run();
}
diff --git a/test/fuzzing/hb-subset-fuzzer.cc b/test/fuzzing/hb-subset-fuzzer.cc
index 3a71f22..56ffd22 100644
--- a/test/fuzzing/hb-subset-fuzzer.cc
+++ b/test/fuzzing/hb-subset-fuzzer.cc
@@ -11,11 +11,13 @@
const hb_codepoint_t text[],
int text_length,
bool drop_hints,
- bool drop_layout)
+ bool drop_layout,
+ bool retain_gids)
{
hb_subset_input_t *input = hb_subset_input_create_or_fail ();
hb_subset_input_set_drop_hints (input, drop_hints);
hb_subset_input_set_drop_layout (input, drop_layout);
+ hb_subset_input_set_retain_gids (input, retain_gids);
hb_set_t *codepoints = hb_subset_input_unicode_set (input);
for (int i = 0; i < text_length; i++)
@@ -32,16 +34,14 @@
static void
trySubset (hb_face_t *face,
const hb_codepoint_t text[],
- int text_length)
+ int text_length,
+ const uint8_t flags[1])
{
- for (unsigned int drop_hints = 0; drop_hints < 2; drop_hints++)
- {
- for (unsigned int drop_layout = 0; drop_layout < 2; drop_layout++)
- {
- trySubset (face, text, text_length,
- (bool) drop_hints, (bool) drop_layout);
- }
- }
+ bool drop_hints = flags[0] & (1 << 0);
+ bool drop_layout = flags[0] & (1 << 1);
+ bool retain_gids = flags[0] & (1 << 2);
+ trySubset (face, text, text_length,
+ drop_hints, drop_layout, retain_gids);
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
@@ -55,21 +55,27 @@
hb_face_collect_unicodes (face, output);
hb_set_destroy (output);
+ uint8_t flags[1] = {0};
const hb_codepoint_t text[] =
{
'A', 'B', 'C', 'D', 'E', 'X', 'Y', 'Z', '1', '2',
'3', '@', '_', '%', '&', ')', '*', '$', '!'
};
- trySubset (face, text, sizeof (text) / sizeof (hb_codepoint_t));
+ trySubset (face, text, sizeof (text) / sizeof (hb_codepoint_t), flags);
hb_codepoint_t text_from_data[16];
- if (size > sizeof(text_from_data)) {
+ if (size > sizeof(text_from_data) + sizeof(flags)) {
memcpy (text_from_data,
data + size - sizeof(text_from_data),
sizeof(text_from_data));
+
+ memcpy (flags,
+ data + size - sizeof(text_from_data) - sizeof(flags),
+ sizeof(flags));
unsigned int text_size = sizeof (text_from_data) / sizeof (hb_codepoint_t);
- trySubset (face, text_from_data, text_size);
+
+ trySubset (face, text_from_data, text_size, flags);
}
hb_face_destroy (face);
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,62,63.ttf
new file mode 100644
index 0000000..52dc474
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,63.ttf
new file mode 100644
index 0000000..d6c516e
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61.ttf
new file mode 100644
index 0000000..1a0d5bd
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.62.ttf
new file mode 100644
index 0000000..257184b
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.63.ttf
new file mode 100644
index 0000000..ac735b3
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,62,63.ttf
new file mode 100644
index 0000000..12d9208
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,63.ttf
new file mode 100644
index 0000000..f545375
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61.ttf
new file mode 100644
index 0000000..d3a67ea
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.62.ttf
new file mode 100644
index 0000000..4ff6e33
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.63.ttf
new file mode 100644
index 0000000..efd7c16
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.63.ttf
Binary files differ
diff --git a/test/subset/data/profiles/drop-hints-retain-gids.txt b/test/subset/data/profiles/drop-hints-retain-gids.txt
new file mode 100644
index 0000000..b0409b8
--- /dev/null
+++ b/test/subset/data/profiles/drop-hints-retain-gids.txt
@@ -0,0 +1,2 @@
+--no-hinting
+--retain-gids
diff --git a/test/subset/data/profiles/retain-gids.txt b/test/subset/data/profiles/retain-gids.txt
new file mode 100644
index 0000000..d757487
--- /dev/null
+++ b/test/subset/data/profiles/retain-gids.txt
@@ -0,0 +1 @@
+--retain-gids
diff --git a/test/subset/data/tests/basics.tests b/test/subset/data/tests/basics.tests
index 9725445..4fc3f4e 100644
--- a/test/subset/data/tests/basics.tests
+++ b/test/subset/data/tests/basics.tests
@@ -4,6 +4,8 @@
PROFILES:
default.txt
drop-hints.txt
+drop-hints-retain-gids.txt
+retain-gids.txt
SUBSETS:
abc
diff --git a/util/hb-subset.cc b/util/hb-subset.cc
index b7d9eb9..33e584b 100644
--- a/util/hb-subset.cc
+++ b/util/hb-subset.cc
@@ -91,6 +91,7 @@
{
hb_subset_input_set_drop_layout (input, !subset_options.keep_layout);
hb_subset_input_set_drop_hints (input, subset_options.drop_hints);
+ hb_subset_input_set_retain_gids (input, subset_options.retain_gids);
hb_subset_input_set_desubroutinize (input, subset_options.desubroutinize);
hb_face_t *face = hb_font_get_face (font);
diff --git a/util/options.cc b/util/options.cc
index 04ddcf6..b315c6a 100644
--- a/util/options.cc
+++ b/util/options.cc
@@ -977,6 +977,7 @@
{
{"layout", 0, 0, G_OPTION_ARG_NONE, &this->keep_layout, "Keep OpenType Layout tables", nullptr},
{"no-hinting", 0, 0, G_OPTION_ARG_NONE, &this->drop_hints, "Whether to drop hints", nullptr},
+ {"retain-gids", 0, 0, G_OPTION_ARG_NONE, &this->retain_gids, "If set don't renumber glyph ids in the subset.", nullptr},
{"desubroutinize", 0, 0, G_OPTION_ARG_NONE, &this->desubroutinize, "Remove CFF/CFF2 use of subroutines", nullptr},
{nullptr}
diff --git a/util/options.hh b/util/options.hh
index e846258..84139f5 100644
--- a/util/options.hh
+++ b/util/options.hh
@@ -675,6 +675,7 @@
{
keep_layout = false;
drop_hints = false;
+ retain_gids = false;
desubroutinize = false;
add_options (parser);
@@ -684,6 +685,7 @@
hb_bool_t keep_layout;
hb_bool_t drop_hints;
+ hb_bool_t retain_gids;
hb_bool_t desubroutinize;
};