Merge branch 'master' into iter
This commit is contained in:
commit
cbe2118c58
7
NEWS
7
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
|
Overview of changes leading to 2.3.0
|
||||||
Thursday, December 20, 2018
|
Thursday, December 20, 2018
|
||||||
====================================
|
====================================
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
AC_PREREQ([2.64])
|
AC_PREREQ([2.64])
|
||||||
AC_INIT([HarfBuzz],
|
AC_INIT([HarfBuzz],
|
||||||
[2.3.0],
|
[2.3.1],
|
||||||
[https://github.com/harfbuzz/harfbuzz/issues/new],
|
[https://github.com/harfbuzz/harfbuzz/issues/new],
|
||||||
[harfbuzz],
|
[harfbuzz],
|
||||||
[http://harfbuzz.org/])
|
[http://harfbuzz.org/])
|
||||||
|
|
|
@ -57,16 +57,19 @@ struct DeviceRecord
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int len () const
|
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;
|
if (unlikely (new_gid >= len ())) return nullptr;
|
||||||
hb_codepoint_t gid = this->subset_plan->glyphs [i];
|
|
||||||
|
|
||||||
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 nullptr;
|
||||||
return &(this->source_device_record->widthsZ[gid]);
|
return &(this->source_device_record->widthsZ[old_gid]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -140,7 +143,7 @@ struct hdmx
|
||||||
|
|
||||||
this->version.set (source_hdmx->version);
|
this->version.set (source_hdmx->version);
|
||||||
this->numRecords.set (source_hdmx->numRecords);
|
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++)
|
for (unsigned int i = 0; i < source_hdmx->numRecords; i++)
|
||||||
{
|
{
|
||||||
|
@ -156,7 +159,7 @@ struct hdmx
|
||||||
|
|
||||||
static size_t get_subsetted_size (const hdmx *source_hdmx, hb_subset_plan_t *plan)
|
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
|
bool subset (hb_subset_plan_t *plan) const
|
||||||
|
|
|
@ -93,75 +93,49 @@ struct hmtxvmtx
|
||||||
|
|
||||||
/* All the trailing glyphs with the same advance can use one LongMetric
|
/* All the trailing glyphs with the same advance can use one LongMetric
|
||||||
* and just keep LSB */
|
* and just keep LSB */
|
||||||
hb_vector_t<hb_codepoint_t> &gids = plan->glyphs;
|
unsigned int num_output_glyphs = plan->num_output_glyphs ();
|
||||||
unsigned int num_advances = gids.length;
|
unsigned int num_advances = _mtx.num_advances_for_subset (plan);
|
||||||
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--;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* alloc the new table */
|
/* alloc the new table */
|
||||||
size_t dest_sz = num_advances * 4
|
size_t dest_sz = num_advances * 4
|
||||||
+ (gids.length - num_advances) * 2;
|
+ (num_output_glyphs - num_advances) * 2;
|
||||||
void *dest = (void *) malloc (dest_sz);
|
void *dest = (void *) malloc (dest_sz);
|
||||||
if (unlikely (!dest))
|
if (unlikely (!dest))
|
||||||
{
|
{
|
||||||
return false;
|
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 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
|
// Copy everything over
|
||||||
LongMetric * old_metrics = (LongMetric *) source_table;
|
|
||||||
FWORD *lsbs = (FWORD *) (old_metrics + _mtx.num_advances);
|
|
||||||
char * dest_pos = (char *) dest;
|
char * dest_pos = (char *) dest;
|
||||||
|
|
||||||
bool failed = false;
|
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] */
|
unsigned int side_bearing = 0;
|
||||||
LongMetric *src_metric = old_metrics + MIN ((hb_codepoint_t) _mtx.num_advances - 1, gids[i]);
|
unsigned int advance = 0;
|
||||||
if (gids[i] < _mtx.num_advances)
|
hb_codepoint_t old_gid;
|
||||||
|
if (plan->old_gid_for_new_gid (i, &old_gid))
|
||||||
{
|
{
|
||||||
/* src is a LongMetric */
|
// Glyph is not an empty glyph so copy advance and side bearing
|
||||||
if (i < num_advances)
|
// 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)
|
||||||
{
|
{
|
||||||
/* dest is a LongMetric, copy it */
|
((LongMetric *) dest_pos)->advance.set (advance);
|
||||||
*((LongMetric *) dest_pos) = *src_metric;
|
((LongMetric *) dest_pos)->sb.set (side_bearing);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* dest just sb */
|
((FWORD *) dest_pos)->set (side_bearing);
|
||||||
*((FWORD *) dest_pos) = src_metric->sb;
|
|
||||||
}
|
}
|
||||||
}
|
dest_pos += (has_advance ? 4 : 2);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dest_pos += (i < num_advances ? 4 : 2);
|
|
||||||
}
|
}
|
||||||
_mtx.fini ();
|
_mtx.fini ();
|
||||||
|
|
||||||
|
@ -280,6 +254,32 @@ struct hmtxvmtx
|
||||||
return advance;
|
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:
|
public:
|
||||||
bool has_font_extents;
|
bool has_font_extents;
|
||||||
int ascender;
|
int ascender;
|
||||||
|
|
|
@ -1233,7 +1233,7 @@ struct ClassDefFormat1
|
||||||
bool subset (hb_subset_context_t *c) const
|
bool subset (hb_subset_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SUBSET (this);
|
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;
|
const hb_map_t &glyph_map = *c->plan->glyph_map;
|
||||||
hb_sorted_vector_t<GlyphID> glyphs;
|
hb_sorted_vector_t<GlyphID> glyphs;
|
||||||
hb_vector_t<HBUINT16> klasses;
|
hb_vector_t<HBUINT16> klasses;
|
||||||
|
@ -1380,7 +1380,7 @@ struct ClassDefFormat2
|
||||||
bool subset (hb_subset_context_t *c) const
|
bool subset (hb_subset_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SUBSET (this);
|
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;
|
const hb_map_t &glyph_map = *c->plan->glyph_map;
|
||||||
hb_vector_t<GlyphID> glyphs;
|
hb_vector_t<GlyphID> glyphs;
|
||||||
hb_vector_t<HBUINT16> klasses;
|
hb_vector_t<HBUINT16> klasses;
|
||||||
|
|
|
@ -95,7 +95,7 @@ struct SingleSubstFormat1
|
||||||
bool subset (hb_subset_context_t *c) const
|
bool subset (hb_subset_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SUBSET (this);
|
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;
|
const hb_map_t &glyph_map = *c->plan->glyph_map;
|
||||||
hb_sorted_vector_t<GlyphID> from;
|
hb_sorted_vector_t<GlyphID> from;
|
||||||
hb_vector_t<GlyphID> to;
|
hb_vector_t<GlyphID> to;
|
||||||
|
@ -184,7 +184,7 @@ struct SingleSubstFormat2
|
||||||
bool subset (hb_subset_context_t *c) const
|
bool subset (hb_subset_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SUBSET (this);
|
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;
|
const hb_map_t &glyph_map = *c->plan->glyph_map;
|
||||||
hb_sorted_vector_t<GlyphID> from;
|
hb_sorted_vector_t<GlyphID> from;
|
||||||
hb_vector_t<GlyphID> to;
|
hb_vector_t<GlyphID> to;
|
||||||
|
|
|
@ -105,7 +105,7 @@ struct maxp
|
||||||
}
|
}
|
||||||
maxp *maxp_prime = (maxp *) hb_blob_get_data (maxp_prime_blob, nullptr);
|
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)
|
if (plan->drop_hints)
|
||||||
drop_hint_fields (plan, maxp_prime);
|
drop_hint_fields (plan, maxp_prime);
|
||||||
|
|
||||||
|
|
|
@ -110,21 +110,29 @@ struct VORG
|
||||||
/* count the number of glyphs to be included in the subset table */
|
/* count the number of glyphs to be included in the subset table */
|
||||||
hb_vector_t<VertOriginMetric> subset_metrics;
|
hb_vector_t<VertOriginMetric> subset_metrics;
|
||||||
subset_metrics.init ();
|
subset_metrics.init ();
|
||||||
unsigned int glyph = 0;
|
|
||||||
|
|
||||||
|
hb_codepoint_t old_glyph = HB_SET_VALUE_INVALID;
|
||||||
unsigned int i = 0;
|
unsigned int i = 0;
|
||||||
while ((glyph < plan->glyphs.length) && (i < vertYOrigins.len))
|
while (i < vertYOrigins.len
|
||||||
|
&& plan->glyphset ()->next (&old_glyph))
|
||||||
|
{
|
||||||
|
while (old_glyph > vertYOrigins[i].glyph)
|
||||||
{
|
{
|
||||||
if (plan->glyphs[glyph] > vertYOrigins[i].glyph)
|
|
||||||
i++;
|
i++;
|
||||||
else if (plan->glyphs[glyph] < vertYOrigins[i].glyph)
|
if (i >= vertYOrigins.len)
|
||||||
glyph++;
|
break;
|
||||||
else
|
}
|
||||||
|
|
||||||
|
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 ();
|
VertOriginMetric *metrics = subset_metrics.push ();
|
||||||
metrics->glyph.set (glyph);
|
metrics->glyph.set (new_glyph);
|
||||||
metrics->vertOriginY.set (vertYOrigins[i].vertOriginY);
|
metrics->vertOriginY.set (vertYOrigins[i].vertOriginY);
|
||||||
glyph++;
|
}
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -469,11 +469,11 @@ struct cff_subset_plan {
|
||||||
supp_size = 0;
|
supp_size = 0;
|
||||||
supp_codes.init ();
|
supp_codes.init ();
|
||||||
|
|
||||||
subset_enc_num_codes = plan->glyphs.length - 1;
|
subset_enc_num_codes = plan->glyphs_deprecated.length - 1;
|
||||||
unsigned int glyph;
|
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);
|
code = acc.glyph_to_code (orig_glyph);
|
||||||
if (code == CFF_UNDEF_CODE)
|
if (code == CFF_UNDEF_CODE)
|
||||||
{
|
{
|
||||||
|
@ -526,9 +526,9 @@ struct cff_subset_plan {
|
||||||
|
|
||||||
subset_charset_ranges.resize (0);
|
subset_charset_ranges.resize (0);
|
||||||
unsigned int glyph;
|
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);
|
sid = acc.glyph_to_sid (orig_glyph);
|
||||||
|
|
||||||
if (!acc.is_CID ())
|
if (!acc.is_CID ())
|
||||||
|
@ -544,7 +544,7 @@ struct cff_subset_plan {
|
||||||
|
|
||||||
bool two_byte = subset_charset_ranges.finalize (glyph);
|
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)
|
if (!two_byte)
|
||||||
size_ranges = Charset1::min_size + Charset1_Range::static_size * subset_charset_ranges.length;
|
size_ranges = Charset1::min_size + Charset1_Range::static_size * subset_charset_ranges.length;
|
||||||
else
|
else
|
||||||
|
@ -559,7 +559,7 @@ struct cff_subset_plan {
|
||||||
|
|
||||||
return Charset::calculate_serialized_size (
|
return Charset::calculate_serialized_size (
|
||||||
subset_charset_format,
|
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)
|
bool collect_sids_in_dicts (const OT::cff1::accelerator_subset_t &acc)
|
||||||
|
@ -589,19 +589,19 @@ struct cff_subset_plan {
|
||||||
hb_subset_plan_t *plan)
|
hb_subset_plan_t *plan)
|
||||||
{
|
{
|
||||||
/* make sure notdef is first */
|
/* 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;
|
final_size = 0;
|
||||||
num_glyphs = plan->glyphs.length;
|
num_glyphs = plan->glyphs_deprecated.length;
|
||||||
orig_fdcount = acc.fdCount;
|
orig_fdcount = acc.fdCount;
|
||||||
drop_hints = plan->drop_hints;
|
drop_hints = plan->drop_hints;
|
||||||
desubroutinize = plan->desubroutinize;
|
desubroutinize = plan->desubroutinize;
|
||||||
|
|
||||||
/* check whether the subset renumbers any glyph IDs */
|
/* check whether the subset renumbers any glyph IDs */
|
||||||
gid_renum = false;
|
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;
|
gid_renum = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -644,7 +644,7 @@ struct cff_subset_plan {
|
||||||
/* Determine re-mapping of font index as fdmap among other info */
|
/* Determine re-mapping of font index as fdmap among other info */
|
||||||
if (acc.fdSelect != &Null(CFF1FDSelect))
|
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,
|
orig_fdcount,
|
||||||
*acc.fdSelect,
|
*acc.fdSelect,
|
||||||
subset_fdcount,
|
subset_fdcount,
|
||||||
|
@ -681,7 +681,7 @@ struct cff_subset_plan {
|
||||||
{
|
{
|
||||||
/* Flatten global & local subrs */
|
/* Flatten global & local subrs */
|
||||||
subr_flattener_t<const OT::cff1::accelerator_subset_t, cff1_cs_interp_env_t, cff1_cs_opset_flatten_t>
|
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))
|
if (!flattener.flatten (subset_charstrings))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -691,11 +691,11 @@ struct cff_subset_plan {
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Subset subrs: collect used subroutines, leaving all unused ones behind */
|
/* 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;
|
return false;
|
||||||
|
|
||||||
/* encode charstrings, global subrs, local subrs with new subroutine numbers */
|
/* 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;
|
return false;
|
||||||
|
|
||||||
if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs))
|
if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs))
|
||||||
|
@ -784,7 +784,7 @@ struct cff_subset_plan {
|
||||||
offsets.charStringsInfo.offSize = calcOffSize (dataSize);
|
offsets.charStringsInfo.offSize = calcOffSize (dataSize);
|
||||||
if (unlikely (offsets.charStringsInfo.offSize > 4))
|
if (unlikely (offsets.charStringsInfo.offSize > 4))
|
||||||
return false;
|
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 */
|
/* private dicts & local subrs */
|
||||||
|
@ -816,7 +816,7 @@ struct cff_subset_plan {
|
||||||
if (!acc.is_CID ())
|
if (!acc.is_CID ())
|
||||||
offsets.privateDictInfo = fontdicts_mod[0].privateDictInfo;
|
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));
|
&& (fontdicts_mod.length == subset_fdcount));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1064,7 +1064,7 @@ _hb_subset_cff1 (const OT::cff1::accelerator_subset_t &acc,
|
||||||
unsigned int cff_prime_size = cff_plan.get_final_size ();
|
unsigned int cff_prime_size = cff_plan.get_final_size ();
|
||||||
char *cff_prime_data = (char *) calloc (1, cff_prime_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))) {
|
cff_prime_size, cff_prime_data))) {
|
||||||
DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff.");
|
DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff.");
|
||||||
free (cff_prime_data);
|
free (cff_prime_data);
|
||||||
|
|
|
@ -287,7 +287,7 @@ struct cff2_subset_plan {
|
||||||
{
|
{
|
||||||
/* Flatten global & local subrs */
|
/* Flatten global & local subrs */
|
||||||
subr_flattener_t<const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t, cff2_cs_opset_flatten_t>
|
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))
|
if (!flattener.flatten (subset_charstrings))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -297,11 +297,11 @@ struct cff2_subset_plan {
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Subset subrs: collect used subroutines, leaving all unused ones behind */
|
/* 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;
|
return false;
|
||||||
|
|
||||||
/* encode charstrings, global subrs, local subrs with new subroutine numbers */
|
/* 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;
|
return false;
|
||||||
|
|
||||||
if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs))
|
if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs))
|
||||||
|
@ -352,7 +352,7 @@ struct cff2_subset_plan {
|
||||||
if (acc.fdSelect != &Null(CFF2FDSelect))
|
if (acc.fdSelect != &Null(CFF2FDSelect))
|
||||||
{
|
{
|
||||||
offsets.FDSelectInfo.offset = final_size;
|
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,
|
orig_fdcount,
|
||||||
*(const FDSelect *)acc.fdSelect,
|
*(const FDSelect *)acc.fdSelect,
|
||||||
subset_fdcount,
|
subset_fdcount,
|
||||||
|
@ -385,7 +385,7 @@ struct cff2_subset_plan {
|
||||||
offsets.charStringsInfo.offset = final_size;
|
offsets.charStringsInfo.offset = final_size;
|
||||||
unsigned int dataSize = subset_charstrings.total_size ();
|
unsigned int dataSize = subset_charstrings.total_size ();
|
||||||
offsets.charStringsInfo.offSize = calcOffSize (dataSize);
|
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 */
|
/* private dicts & local subrs */
|
||||||
|
@ -584,7 +584,7 @@ _hb_subset_cff2 (const OT::cff2::accelerator_subset_t &acc,
|
||||||
unsigned int cff2_prime_size = cff2_plan.get_final_size ();
|
unsigned int cff2_prime_size = cff2_plan.get_final_size ();
|
||||||
char *cff2_prime_data = (char *) calloc (1, cff2_prime_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))) {
|
cff2_prime_size, cff2_prime_data))) {
|
||||||
DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff2.");
|
DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff2.");
|
||||||
free (cff2_prime_data);
|
free (cff2_prime_data);
|
||||||
|
|
|
@ -29,19 +29,50 @@
|
||||||
#include "hb-set.h"
|
#include "hb-set.h"
|
||||||
#include "hb-subset-glyf.hh"
|
#include "hb-subset-glyf.hh"
|
||||||
|
|
||||||
|
struct loca_data_t
|
||||||
|
{
|
||||||
|
bool is_short;
|
||||||
|
void *data;
|
||||||
|
unsigned int size;
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
_write_loca_entry (unsigned int id,
|
||||||
|
unsigned int offset)
|
||||||
|
{
|
||||||
|
unsigned int entry_size = is_short ? sizeof (OT::HBUINT16) : sizeof (OT::HBUINT32);
|
||||||
|
if ((id + 1) * entry_size <= size)
|
||||||
|
{
|
||||||
|
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
|
static bool
|
||||||
_calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf,
|
_add_instructions_range (const OT::glyf::accelerator_t &glyf,
|
||||||
hb_vector_t<hb_codepoint_t> &glyph_ids,
|
hb_codepoint_t glyph_id,
|
||||||
hb_bool_t drop_hints,
|
unsigned int glyph_start_offset,
|
||||||
bool *use_short_loca /* OUT */,
|
unsigned int glyph_end_offset,
|
||||||
unsigned int *glyf_size /* OUT */,
|
bool drop_hints,
|
||||||
unsigned int *loca_size /* OUT */,
|
|
||||||
hb_vector_t<unsigned int> *instruction_ranges /* OUT */)
|
hb_vector_t<unsigned int> *instruction_ranges /* OUT */)
|
||||||
{
|
{
|
||||||
unsigned int total = 0;
|
|
||||||
for (unsigned int i = 0; i < glyph_ids.length; i++)
|
|
||||||
{
|
|
||||||
hb_codepoint_t next_glyph = glyph_ids[i];
|
|
||||||
if (!instruction_ranges->resize (instruction_ranges->length + 2))
|
if (!instruction_ranges->resize (instruction_ranges->length + 2))
|
||||||
{
|
{
|
||||||
DEBUG_MSG(SUBSET, nullptr, "Failed to resize instruction_ranges.");
|
DEBUG_MSG(SUBSET, nullptr, "Failed to resize instruction_ranges.");
|
||||||
|
@ -52,73 +83,73 @@ _calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf,
|
||||||
unsigned int *instruction_end = &(*instruction_ranges)[instruction_ranges->length - 1];
|
unsigned int *instruction_end = &(*instruction_ranges)[instruction_ranges->length - 1];
|
||||||
*instruction_end = 0;
|
*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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
unsigned int start_offset, end_offset;
|
||||||
if (unlikely (!(glyf.get_offsets (next_glyph, &start_offset, &end_offset) &&
|
if (unlikely (!(glyf.get_offsets (next_glyph, &start_offset, &end_offset) &&
|
||||||
glyf.remove_padding (start_offset, &end_offset))))
|
glyf.remove_padding (start_offset, &end_offset))))
|
||||||
{
|
{
|
||||||
DEBUG_MSG(SUBSET, nullptr, "Invalid gid %d", next_glyph);
|
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 */
|
continue; /* 0-length glyph */
|
||||||
|
|
||||||
if (drop_hints)
|
total += end_offset - start_offset
|
||||||
{
|
- ((*instruction_ranges)[instruction_ranges->length - 1]
|
||||||
if (unlikely (!glyf.get_instruction_offsets (start_offset, end_offset,
|
- (*instruction_ranges)[instruction_ranges->length - 2]);
|
||||||
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);
|
|
||||||
/* round2 so short loca will work */
|
/* round2 so short loca will work */
|
||||||
total += total % 2;
|
total += total % 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
*glyf_size = total;
|
*glyf_size = total;
|
||||||
*use_short_loca = (total <= 131070);
|
loca_data->is_short = (total <= 131070);
|
||||||
*loca_size = (glyph_ids.length + 1)
|
loca_data->size = (plan->num_output_glyphs () + 1)
|
||||||
* (*use_short_loca ? sizeof (OT::HBUINT16) : sizeof (OT::HBUINT32));
|
* (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",
|
DEBUG_MSG(SUBSET, nullptr, "preparing to subset glyf: final size %d, loca size %d, using %s loca",
|
||||||
total,
|
total,
|
||||||
*loca_size,
|
loca_data->size,
|
||||||
*use_short_loca ? "short" : "long");
|
loca_data->is_short ? "short" : "long");
|
||||||
return true;
|
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
|
static void
|
||||||
_update_components (hb_subset_plan_t * plan,
|
_update_components (const hb_subset_plan_t *plan,
|
||||||
char * glyph_start,
|
char *glyph_start,
|
||||||
unsigned int length)
|
unsigned int length)
|
||||||
{
|
{
|
||||||
OT::glyf::CompositeGlyphHeader::Iterator iterator;
|
OT::glyf::CompositeGlyphHeader::Iterator iterator;
|
||||||
|
@ -153,24 +184,35 @@ static bool _remove_composite_instruction_flag (char *glyf_prime, unsigned int l
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
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 OT::glyf::accelerator_t &glyf,
|
||||||
const char *glyf_data,
|
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,
|
unsigned int glyf_prime_size,
|
||||||
char *glyf_prime_data /* OUT */,
|
char *glyf_prime_data /* OUT */,
|
||||||
unsigned int loca_prime_size,
|
loca_data_t *loca_prime /* OUT */)
|
||||||
char *loca_prime_data /* OUT */)
|
|
||||||
{
|
{
|
||||||
hb_vector_t<hb_codepoint_t> &glyph_ids = plan->glyphs;
|
|
||||||
char *glyf_prime_data_next = glyf_prime_data;
|
char *glyf_prime_data_next = glyf_prime_data;
|
||||||
|
|
||||||
bool success = true;
|
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;
|
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))))
|
glyf.remove_padding (start_offset, &end_offset))))
|
||||||
end_offset = start_offset = 0;
|
end_offset = start_offset = 0;
|
||||||
|
|
||||||
|
@ -204,22 +246,20 @@ _write_glyf_and_loca_prime (hb_subset_plan_t *plan,
|
||||||
memset (glyf_prime_data_next + instruction_start - start_offset - 2, 0, 2);
|
memset (glyf_prime_data_next + instruction_start - start_offset - 2, 0, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
success = success && _write_loca_entry (i,
|
success = success && loca_prime->_write_loca_entry (new_gid,
|
||||||
glyf_prime_data_next - glyf_prime_data,
|
glyf_prime_data_next - glyf_prime_data);
|
||||||
use_short_loca,
|
|
||||||
loca_prime_data,
|
|
||||||
loca_prime_size);
|
|
||||||
_update_components (plan, glyf_prime_data_next, length);
|
_update_components (plan, glyf_prime_data_next, length);
|
||||||
|
|
||||||
// TODO: don't align to two bytes if using long loca.
|
// 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.
|
glyf_prime_data_next += length + (length % 2); // Align to 2 bytes for short loca.
|
||||||
|
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
success = success && _write_loca_entry (glyph_ids.length,
|
// loca table has n+1 entries where the last entry signifies the end location of the last
|
||||||
glyf_prime_data_next - glyf_prime_data,
|
// glyph.
|
||||||
use_short_loca,
|
success = success && loca_prime->_write_loca_entry (new_gid,
|
||||||
loca_prime_data,
|
glyf_prime_data_next - glyf_prime_data);
|
||||||
loca_prime_size);
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,51 +268,47 @@ _hb_subset_glyf_and_loca (const OT::glyf::accelerator_t &glyf,
|
||||||
const char *glyf_data,
|
const char *glyf_data,
|
||||||
hb_subset_plan_t *plan,
|
hb_subset_plan_t *plan,
|
||||||
bool *use_short_loca,
|
bool *use_short_loca,
|
||||||
hb_blob_t **glyf_prime /* OUT */,
|
hb_blob_t **glyf_prime_blob /* OUT */,
|
||||||
hb_blob_t **loca_prime /* OUT */)
|
hb_blob_t **loca_prime_blob /* OUT */)
|
||||||
{
|
{
|
||||||
// TODO(grieger): Sanity check allocation size for the new table.
|
// 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 glyf_prime_size;
|
||||||
unsigned int loca_prime_size;
|
|
||||||
hb_vector_t<unsigned int> instruction_ranges;
|
hb_vector_t<unsigned int> instruction_ranges;
|
||||||
instruction_ranges.init ();
|
instruction_ranges.init ();
|
||||||
|
|
||||||
if (unlikely (!_calculate_glyf_and_loca_prime_size (glyf,
|
if (unlikely (!_calculate_glyf_and_loca_prime_size (glyf,
|
||||||
glyphs_to_retain,
|
plan,
|
||||||
plan->drop_hints,
|
&loca_prime,
|
||||||
use_short_loca,
|
|
||||||
&glyf_prime_size,
|
&glyf_prime_size,
|
||||||
&loca_prime_size,
|
|
||||||
&instruction_ranges))) {
|
&instruction_ranges))) {
|
||||||
instruction_ranges.fini ();
|
instruction_ranges.fini ();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
*use_short_loca = loca_prime.is_short;
|
||||||
|
|
||||||
char *glyf_prime_data = (char *) calloc (1, glyf_prime_size);
|
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,
|
if (unlikely (!_write_glyf_and_loca_prime (plan, glyf, glyf_data,
|
||||||
*use_short_loca,
|
|
||||||
instruction_ranges,
|
instruction_ranges,
|
||||||
glyf_prime_size, glyf_prime_data,
|
glyf_prime_size, glyf_prime_data,
|
||||||
loca_prime_size, loca_prime_data))) {
|
&loca_prime))) {
|
||||||
free (glyf_prime_data);
|
free (glyf_prime_data);
|
||||||
free (loca_prime_data);
|
free (loca_prime.data);
|
||||||
instruction_ranges.fini ();
|
instruction_ranges.fini ();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
instruction_ranges.fini ();
|
instruction_ranges.fini ();
|
||||||
|
|
||||||
*glyf_prime = hb_blob_create (glyf_prime_data,
|
*glyf_prime_blob = hb_blob_create (glyf_prime_data,
|
||||||
glyf_prime_size,
|
glyf_prime_size,
|
||||||
HB_MEMORY_MODE_READONLY,
|
HB_MEMORY_MODE_READONLY,
|
||||||
glyf_prime_data,
|
glyf_prime_data,
|
||||||
free);
|
free);
|
||||||
*loca_prime = hb_blob_create (loca_prime_data,
|
*loca_prime_blob = hb_blob_create ((char *) loca_prime.data,
|
||||||
loca_prime_size,
|
loca_prime.size,
|
||||||
HB_MEMORY_MODE_READONLY,
|
HB_MEMORY_MODE_READONLY,
|
||||||
loca_prime_data,
|
loca_prime.data,
|
||||||
free);
|
free);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,10 @@ hb_subset_input_create_or_fail ()
|
||||||
|
|
||||||
input->unicodes = hb_set_create ();
|
input->unicodes = hb_set_create ();
|
||||||
input->glyphs = hb_set_create ();
|
input->glyphs = hb_set_create ();
|
||||||
|
input->drop_hints = false;
|
||||||
input->drop_layout = true;
|
input->drop_layout = true;
|
||||||
|
input->desubroutinize = false;
|
||||||
|
input->retain_gids = false;
|
||||||
|
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
@ -144,3 +147,27 @@ hb_subset_input_get_desubroutinize (hb_subset_input_t *subset_input)
|
||||||
{
|
{
|
||||||
return subset_input->desubroutinize;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ struct hb_subset_input_t
|
||||||
bool drop_hints : 1;
|
bool drop_hints : 1;
|
||||||
bool drop_layout : 1;
|
bool drop_layout : 1;
|
||||||
bool desubroutinize : 1;
|
bool desubroutinize : 1;
|
||||||
|
bool retain_gids : 1;
|
||||||
/* TODO
|
/* TODO
|
||||||
*
|
*
|
||||||
* features
|
* features
|
||||||
|
|
|
@ -156,11 +156,32 @@ _populate_gids_to_retain (hb_face_t *face,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_create_old_gid_to_new_gid_map (const hb_vector_t<hb_codepoint_t> &glyphs,
|
_create_old_gid_to_new_gid_map (const hb_face_t *face,
|
||||||
hb_map_t *glyph_map)
|
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++) {
|
for (unsigned int i = 0; i < glyphs.length; i++) {
|
||||||
|
if (!retain_gids)
|
||||||
|
{
|
||||||
glyph_map->set (glyphs[i], i);
|
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 @@ hb_subset_plan_create (hb_face_t *face,
|
||||||
plan->drop_layout = input->drop_layout;
|
plan->drop_layout = input->drop_layout;
|
||||||
plan->desubroutinize = input->desubroutinize;
|
plan->desubroutinize = input->desubroutinize;
|
||||||
plan->unicodes = hb_set_create();
|
plan->unicodes = hb_set_create();
|
||||||
plan->glyphs.init();
|
plan->glyphs_deprecated.init();
|
||||||
plan->source = hb_face_reference (face);
|
plan->source = hb_face_reference (face);
|
||||||
plan->dest = hb_face_builder_create ();
|
plan->dest = hb_face_builder_create ();
|
||||||
plan->codepoint_to_glyph = hb_map_create();
|
plan->codepoint_to_glyph = hb_map_create();
|
||||||
plan->glyph_map = hb_map_create();
|
plan->glyph_map = hb_map_create();
|
||||||
plan->glyphset = _populate_gids_to_retain (face,
|
plan->reverse_glyph_map = hb_map_create();
|
||||||
|
plan->_glyphset = _populate_gids_to_retain (face,
|
||||||
input->unicodes,
|
input->unicodes,
|
||||||
!plan->drop_layout,
|
!plan->drop_layout,
|
||||||
plan->unicodes,
|
plan->unicodes,
|
||||||
plan->codepoint_to_glyph,
|
plan->codepoint_to_glyph,
|
||||||
&plan->glyphs);
|
&plan->glyphs_deprecated);
|
||||||
_create_old_gid_to_new_gid_map (plan->glyphs,
|
|
||||||
plan->glyph_map);
|
_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;
|
return plan;
|
||||||
}
|
}
|
||||||
|
@ -212,12 +239,13 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan)
|
||||||
if (!hb_object_destroy (plan)) return;
|
if (!hb_object_destroy (plan)) return;
|
||||||
|
|
||||||
hb_set_destroy (plan->unicodes);
|
hb_set_destroy (plan->unicodes);
|
||||||
plan->glyphs.fini ();
|
plan->glyphs_deprecated.fini ();
|
||||||
hb_face_destroy (plan->source);
|
hb_face_destroy (plan->source);
|
||||||
hb_face_destroy (plan->dest);
|
hb_face_destroy (plan->dest);
|
||||||
hb_map_destroy (plan->codepoint_to_glyph);
|
hb_map_destroy (plan->codepoint_to_glyph);
|
||||||
hb_map_destroy (plan->glyph_map);
|
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);
|
free (plan);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "hb-subset-input.hh"
|
#include "hb-subset-input.hh"
|
||||||
|
|
||||||
#include "hb-map.hh"
|
#include "hb-map.hh"
|
||||||
|
#include "hb-set.hh"
|
||||||
|
|
||||||
struct hb_subset_plan_t
|
struct hb_subset_plan_t
|
||||||
{
|
{
|
||||||
|
@ -45,17 +46,53 @@ struct hb_subset_plan_t
|
||||||
// For each cp that we'd like to retain maps to the corresponding gid.
|
// For each cp that we'd like to retain maps to the corresponding gid.
|
||||||
hb_set_t *unicodes;
|
hb_set_t *unicodes;
|
||||||
|
|
||||||
hb_vector_t<hb_codepoint_t> glyphs;
|
// The glyph subset
|
||||||
hb_set_t *glyphset;
|
|
||||||
|
|
||||||
hb_map_t *codepoint_to_glyph;
|
hb_map_t *codepoint_to_glyph;
|
||||||
|
|
||||||
|
// Old -> New glyph id mapping
|
||||||
hb_map_t *glyph_map;
|
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
|
// Plan is only good for a specific source/dest so keep them with it
|
||||||
hb_face_t *source;
|
hb_face_t *source;
|
||||||
hb_face_t *dest;
|
hb_face_t *dest;
|
||||||
|
|
||||||
bool new_gid_for_codepoint (hb_codepoint_t codepoint,
|
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 *new_gid) const
|
||||||
{
|
{
|
||||||
hb_codepoint_t old_gid = codepoint_to_glyph->get (codepoint);
|
hb_codepoint_t old_gid = codepoint_to_glyph->get (codepoint);
|
||||||
|
@ -65,7 +102,7 @@ struct hb_subset_plan_t
|
||||||
return new_gid_for_old_gid (old_gid, new_gid);
|
return new_gid_for_old_gid (old_gid, new_gid);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool new_gid_for_old_gid (hb_codepoint_t old_gid,
|
inline bool new_gid_for_old_gid (hb_codepoint_t old_gid,
|
||||||
hb_codepoint_t *new_gid) const
|
hb_codepoint_t *new_gid) const
|
||||||
{
|
{
|
||||||
hb_codepoint_t gid = glyph_map->get (old_gid);
|
hb_codepoint_t gid = glyph_map->get (old_gid);
|
||||||
|
@ -76,7 +113,18 @@ struct hb_subset_plan_t
|
||||||
return true;
|
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,
|
add_table (hb_tag_t tag,
|
||||||
hb_blob_t *contents)
|
hb_blob_t *contents)
|
||||||
{
|
{
|
||||||
|
|
|
@ -52,7 +52,7 @@ _plan_estimate_subset_table_size (hb_subset_plan_t *plan,
|
||||||
unsigned int table_len)
|
unsigned int table_len)
|
||||||
{
|
{
|
||||||
unsigned int src_glyphs = plan->source->get_num_glyphs ();
|
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))
|
if (unlikely (!src_glyphs))
|
||||||
return 512 + table_len;
|
return 512 + table_len;
|
||||||
|
|
|
@ -72,6 +72,12 @@ hb_subset_input_set_desubroutinize (hb_subset_input_t *subset_input,
|
||||||
HB_EXTERN hb_bool_t
|
HB_EXTERN hb_bool_t
|
||||||
hb_subset_input_get_desubroutinize (hb_subset_input_t *subset_input);
|
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_subset () */
|
||||||
HB_EXTERN hb_face_t *
|
HB_EXTERN hb_face_t *
|
||||||
hb_subset (hb_face_t *source, hb_subset_input_t *input);
|
hb_subset (hb_face_t *source, hb_subset_input_t *input);
|
||||||
|
|
|
@ -38,9 +38,9 @@ HB_BEGIN_DECLS
|
||||||
|
|
||||||
#define HB_VERSION_MAJOR 2
|
#define HB_VERSION_MAJOR 2
|
||||||
#define HB_VERSION_MINOR 3
|
#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) \
|
#define HB_VERSION_ATLEAST(major,minor,micro) \
|
||||||
((major)*10000+(minor)*100+(micro) <= \
|
((major)*10000+(minor)*100+(micro) <= \
|
||||||
|
|
Binary file not shown.
|
@ -257,6 +257,31 @@ test_subset_glyf_strip_hints_invalid (void)
|
||||||
hb_face_destroy (face);
|
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.
|
// TODO(grieger): test for long loca generation.
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -272,6 +297,7 @@ main (int argc, char **argv)
|
||||||
hb_test_add (test_subset_glyf_with_components);
|
hb_test_add (test_subset_glyf_with_components);
|
||||||
hb_test_add (test_subset_glyf_with_gsub);
|
hb_test_add (test_subset_glyf_with_gsub);
|
||||||
hb_test_add (test_subset_glyf_without_gsub);
|
hb_test_add (test_subset_glyf_without_gsub);
|
||||||
|
hb_test_add (test_subset_glyf_retain_gids);
|
||||||
|
|
||||||
return hb_test_run();
|
return hb_test_run();
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,2 @@
|
||||||
|
--no-hinting
|
||||||
|
--retain-gids
|
|
@ -0,0 +1 @@
|
||||||
|
--retain-gids
|
|
@ -4,6 +4,8 @@ Roboto-Regular.abc.ttf
|
||||||
PROFILES:
|
PROFILES:
|
||||||
default.txt
|
default.txt
|
||||||
drop-hints.txt
|
drop-hints.txt
|
||||||
|
drop-hints-retain-gids.txt
|
||||||
|
retain-gids.txt
|
||||||
|
|
||||||
SUBSETS:
|
SUBSETS:
|
||||||
abc
|
abc
|
||||||
|
|
|
@ -91,6 +91,7 @@ struct subset_consumer_t
|
||||||
{
|
{
|
||||||
hb_subset_input_set_drop_layout (input, !subset_options.keep_layout);
|
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_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_subset_input_set_desubroutinize (input, subset_options.desubroutinize);
|
||||||
|
|
||||||
hb_face_t *face = hb_font_get_face (font);
|
hb_face_t *face = hb_font_get_face (font);
|
||||||
|
|
|
@ -977,6 +977,7 @@ subset_options_t::add_options (option_parser_t *parser)
|
||||||
{
|
{
|
||||||
{"layout", 0, 0, G_OPTION_ARG_NONE, &this->keep_layout, "Keep OpenType Layout tables", nullptr},
|
{"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},
|
{"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},
|
{"desubroutinize", 0, 0, G_OPTION_ARG_NONE, &this->desubroutinize, "Remove CFF/CFF2 use of subroutines", nullptr},
|
||||||
|
|
||||||
{nullptr}
|
{nullptr}
|
||||||
|
|
|
@ -675,6 +675,7 @@ struct subset_options_t : option_group_t
|
||||||
{
|
{
|
||||||
keep_layout = false;
|
keep_layout = false;
|
||||||
drop_hints = false;
|
drop_hints = false;
|
||||||
|
retain_gids = false;
|
||||||
desubroutinize = false;
|
desubroutinize = false;
|
||||||
|
|
||||||
add_options (parser);
|
add_options (parser);
|
||||||
|
@ -684,6 +685,7 @@ struct subset_options_t : option_group_t
|
||||||
|
|
||||||
hb_bool_t keep_layout;
|
hb_bool_t keep_layout;
|
||||||
hb_bool_t drop_hints;
|
hb_bool_t drop_hints;
|
||||||
|
hb_bool_t retain_gids;
|
||||||
hb_bool_t desubroutinize;
|
hb_bool_t desubroutinize;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue