[subset] Fix null pointer deref, tidy up a bit
This commit is contained in:
parent
8a84b540c7
commit
5cedda5e4a
@ -21,7 +21,7 @@
|
|||||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||||
*
|
*
|
||||||
* Google Author(s): Behdad Esfahbod, Garret Reiger, Roderick Sheeter
|
* Google Author(s): Behdad Esfahbod, Garret Rieger, Roderick Sheeter
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef HB_OT_GLYF_TABLE_HH
|
#ifndef HB_OT_GLYF_TABLE_HH
|
||||||
@ -80,6 +80,34 @@ struct glyf
|
|||||||
return_trace (true);
|
return_trace (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Iterator>
|
||||||
|
static void
|
||||||
|
_add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets)
|
||||||
|
{
|
||||||
|
unsigned int max_offset =
|
||||||
|
+ padded_offsets
|
||||||
|
| hb_reduce (hb_max, 0);
|
||||||
|
bool use_short_loca = max_offset <= 131070;
|
||||||
|
unsigned int loca_prime_size = (padded_offsets.len () + 1) * (use_short_loca ? 2 : 4);
|
||||||
|
char *loca_prime_data = (char *) calloc(1, loca_prime_size);
|
||||||
|
|
||||||
|
if (use_short_loca)
|
||||||
|
_write_loca <decltype (padded_offsets), HBUINT16> (padded_offsets, 2, loca_prime_data);
|
||||||
|
else
|
||||||
|
_write_loca <decltype (padded_offsets), HBUINT32> (padded_offsets, 1, loca_prime_data);
|
||||||
|
|
||||||
|
hb_blob_t * loca_blob = hb_blob_create (loca_prime_data,
|
||||||
|
loca_prime_size,
|
||||||
|
HB_MEMORY_MODE_READONLY,
|
||||||
|
loca_prime_data,
|
||||||
|
free);
|
||||||
|
|
||||||
|
plan->add_table (HB_OT_TAG_loca, loca_blob);
|
||||||
|
_add_head_and_set_loca_version(plan, use_short_loca);
|
||||||
|
|
||||||
|
hb_blob_destroy (loca_blob);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Iterator, typename EntryType>
|
template<typename Iterator, typename EntryType>
|
||||||
static void
|
static void
|
||||||
_write_loca (Iterator it, unsigned size_denom, char * dest)
|
_write_loca (Iterator it, unsigned size_denom, char * dest)
|
||||||
@ -100,7 +128,6 @@ struct glyf
|
|||||||
*loca_current = offset / size_denom;
|
*loca_current = offset / size_denom;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO don't pass in plan
|
|
||||||
template <typename Iterator>
|
template <typename Iterator>
|
||||||
bool serialize(hb_serialize_context_t *c,
|
bool serialize(hb_serialize_context_t *c,
|
||||||
Iterator it,
|
Iterator it,
|
||||||
@ -108,33 +135,8 @@ struct glyf
|
|||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
TRACE_SERIALIZE (this);
|
||||||
|
|
||||||
HBUINT8 pad;
|
|
||||||
pad = 0;
|
|
||||||
+ it
|
+ it
|
||||||
| hb_apply ( [&] (hb_pair_t <SubsetGlyph, unsigned int> _) {
|
| hb_apply ( [&] (const SubsetGlyph& _) { _.serialize (c, plan); });
|
||||||
const SubsetGlyph& src_glyph = _.first;
|
|
||||||
unsigned int padded_size = _.second;
|
|
||||||
hb_bytes_t dest_glyph = src_glyph.start.copy(c);
|
|
||||||
src_glyph.end.copy(c);
|
|
||||||
dest_glyph.length += src_glyph.end.length;
|
|
||||||
unsigned int padding = padded_size - dest_glyph.length;
|
|
||||||
DEBUG_MSG(SUBSET, nullptr, "serialize %d byte glyph, width %d pad %d", dest_glyph.length, padded_size, padding);
|
|
||||||
while (padding > 0)
|
|
||||||
{
|
|
||||||
c->embed(pad);
|
|
||||||
padding--;
|
|
||||||
}
|
|
||||||
|
|
||||||
_fix_component_gids (plan, dest_glyph);
|
|
||||||
if (plan->drop_hints)
|
|
||||||
{
|
|
||||||
_zero_instruction_length (dest_glyph);
|
|
||||||
if (unlikely (!_remove_composite_instruction_flag (dest_glyph)))
|
|
||||||
{
|
|
||||||
// TODO signal irreversible failure
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return_trace (true);
|
return_trace (true);
|
||||||
}
|
}
|
||||||
@ -149,102 +151,35 @@ struct glyf
|
|||||||
OT::glyf::accelerator_t glyf;
|
OT::glyf::accelerator_t glyf;
|
||||||
glyf.init (c->plan->source);
|
glyf.init (c->plan->source);
|
||||||
|
|
||||||
// make an iterator of per-glyph hb_bytes_t.
|
// Byte region(s) per glyph to output
|
||||||
// unpadded, hints removed if that was requested.
|
// unpadded, hints removed if so requested
|
||||||
|
// If we fail to process a glyph we produce an empty (0-length) glyph
|
||||||
// TODO hb_sink so we don't redo this work for every + glyphs | ... use.
|
hb_vector_t<SubsetGlyph> glyphs;
|
||||||
auto glyphs =
|
|
||||||
+ hb_range (c->plan->num_output_glyphs ())
|
+ hb_range (c->plan->num_output_glyphs ())
|
||||||
| hb_map ([&] (hb_codepoint_t new_gid) {
|
| hb_map ([&] (hb_codepoint_t new_gid) {
|
||||||
hb_codepoint_t old_gid;
|
|
||||||
|
|
||||||
SubsetGlyph subset_glyph;
|
SubsetGlyph subset_glyph;
|
||||||
|
subset_glyph.new_gid = new_gid;
|
||||||
|
|
||||||
// should never fail, ALL old gids should be mapped
|
// should never fail: all old gids should be mapped
|
||||||
if (!c->plan->old_gid_for_new_gid (new_gid, &old_gid)) return subset_glyph;
|
if (!c->plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid)) return subset_glyph;
|
||||||
|
|
||||||
unsigned int start_offset, end_offset;
|
subset_glyph.source_glyph = glyf.bytes_for_glyph ((const char *) this, subset_glyph.old_gid);
|
||||||
if (unlikely (!(glyf.get_offsets (old_gid, &start_offset, &end_offset) &&
|
if (c->plan->drop_hints) subset_glyph.drop_hints (glyf);
|
||||||
glyf.remove_padding (start_offset, &end_offset))))
|
else subset_glyph.dest_start = subset_glyph.source_glyph;
|
||||||
{
|
|
||||||
// TODO signal fatal error
|
|
||||||
DEBUG_MSG(SUBSET, nullptr, "Unable to get offset or remove padding for new_gid %d", new_gid);
|
|
||||||
return subset_glyph;
|
|
||||||
}
|
|
||||||
subset_glyph.start = hb_bytes_t (((const char *) this) + start_offset, end_offset - start_offset);
|
|
||||||
if (subset_glyph.start.length == 0) return subset_glyph;
|
|
||||||
if (unlikely (subset_glyph.start.length < GlyphHeader::static_size))
|
|
||||||
{
|
|
||||||
// TODO signal fatal error, invalid glyph
|
|
||||||
DEBUG_MSG(SUBSET, nullptr, "Glyph size smaller than minimum header %d", new_gid);
|
|
||||||
return subset_glyph;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!c->plan->drop_hints) return subset_glyph;
|
|
||||||
|
|
||||||
unsigned int instruction_length = 0;
|
|
||||||
if (!glyf.get_instruction_length (subset_glyph.start, &instruction_length))
|
|
||||||
{
|
|
||||||
// TODO signal fatal error
|
|
||||||
DEBUG_MSG(SUBSET, nullptr, "Unable to read instruction length for new_gid %d", new_gid);
|
|
||||||
return subset_glyph;
|
|
||||||
}
|
|
||||||
DEBUG_MSG(SUBSET, nullptr, "new_gid %d drop %d instruction bytes from %d byte glyph", new_gid, instruction_length, subset_glyph.start.length);
|
|
||||||
|
|
||||||
const GlyphHeader& header = StructAtOffset<GlyphHeader> (&subset_glyph.start, 0);
|
|
||||||
if (header.numberOfContours < 0)
|
|
||||||
{
|
|
||||||
// composite, just chop instructions off the end
|
|
||||||
subset_glyph.start = hb_bytes_t (&subset_glyph.start, subset_glyph.start.length - instruction_length);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// simple glyph
|
|
||||||
unsigned start_length = GlyphHeader::static_size + 2 * header.numberOfContours + 2;
|
|
||||||
subset_glyph.end = hb_bytes_t (&subset_glyph.start + start_length + instruction_length,
|
|
||||||
subset_glyph.start.length - start_length - instruction_length);
|
|
||||||
subset_glyph.start = hb_bytes_t (&subset_glyph.start, start_length);
|
|
||||||
}
|
|
||||||
|
|
||||||
return subset_glyph;
|
return subset_glyph;
|
||||||
});
|
})
|
||||||
|
| hb_sink (glyphs);
|
||||||
|
|
||||||
auto padded_offsets =
|
glyf_prime->serialize (c->serializer, hb_iter (glyphs), c->plan);
|
||||||
+ glyphs
|
|
||||||
| hb_map ([&] (SubsetGlyph _) {
|
|
||||||
unsigned length = _.start.length + _.end.length;
|
|
||||||
return length + length % 2;
|
|
||||||
});
|
|
||||||
|
|
||||||
glyf_prime->serialize (c->serializer, hb_zip (glyphs, padded_offsets), c->plan);
|
hb_vector_t<unsigned int> padded_offsets;
|
||||||
|
+ hb_iter (glyphs)
|
||||||
|
| hb_map ([&] (const SubsetGlyph& _) { return _.padded_size(); })
|
||||||
|
| hb_sink (padded_offsets);
|
||||||
|
|
||||||
// TODO whats the right way to serialize loca?
|
_add_loca_and_head (c->plan, hb_iter (padded_offsets));
|
||||||
// _subset2 will think these bytes are part of glyf if we write to serializer
|
|
||||||
unsigned int max_offset = + padded_offsets | hb_reduce (hb_max, 0);
|
|
||||||
bool use_short_loca = max_offset <= 131070;
|
|
||||||
unsigned int loca_prime_size = (c->plan->num_output_glyphs () + 1) * (use_short_loca ? 2 : 4);
|
|
||||||
char *loca_prime_data = (char *) calloc(1, loca_prime_size);
|
|
||||||
DEBUG_MSG(SUBSET, nullptr, "calloc %u for loca", loca_prime_size); // TEMPORARY
|
|
||||||
|
|
||||||
if (use_short_loca)
|
|
||||||
_write_loca <decltype (padded_offsets), HBUINT16> (padded_offsets, 2, loca_prime_data);
|
|
||||||
else
|
|
||||||
_write_loca <decltype (padded_offsets), HBUINT32> (padded_offsets, 1, loca_prime_data);
|
|
||||||
|
|
||||||
hb_blob_t * loca_blob = hb_blob_create (loca_prime_data,
|
|
||||||
loca_prime_size,
|
|
||||||
HB_MEMORY_MODE_READONLY,
|
|
||||||
loca_prime_data,
|
|
||||||
free);
|
|
||||||
if (unlikely (! (c->plan->add_table (HB_OT_TAG_loca, loca_blob)
|
|
||||||
&& _add_head_and_set_loca_version(c->plan, use_short_loca))))
|
|
||||||
{
|
|
||||||
// TODO signal fatal error
|
|
||||||
hb_blob_destroy (loca_blob);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
hb_blob_destroy (loca_blob);
|
|
||||||
return_trace (true);
|
return_trace (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,11 +194,11 @@ DEBUG_MSG(SUBSET, nullptr, "calloc %u for loca", loca_prime_size); // TEMPORARY
|
|||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
hb_codepoint_t new_gid;
|
hb_codepoint_t new_gid;
|
||||||
if (!plan->new_gid_for_old_gid (iterator.current->glyphIndex,
|
if (!plan->new_gid_for_old_gid (iterator.current->glyphIndex,
|
||||||
&new_gid))
|
&new_gid))
|
||||||
continue;
|
continue;
|
||||||
((OT::glyf::CompositeGlyphHeader *) iterator.current)->glyphIndex = new_gid;
|
((OT::glyf::CompositeGlyphHeader *) iterator.current)->glyphIndex = new_gid;
|
||||||
} while (iterator.move_to_next ());
|
} while (iterator.move_to_next ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -314,13 +249,6 @@ DEBUG_MSG(SUBSET, nullptr, "calloc %u for loca", loca_prime_size); // TEMPORARY
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SubsetGlyph
|
|
||||||
{
|
|
||||||
hb_bytes_t start;
|
|
||||||
hb_bytes_t end;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct GlyphHeader
|
struct GlyphHeader
|
||||||
{
|
{
|
||||||
HBINT16 numberOfContours; /* If the number of contours is
|
HBINT16 numberOfContours; /* If the number of contours is
|
||||||
@ -655,6 +583,25 @@ DEBUG_MSG(SUBSET, nullptr, "calloc %u for loca", loca_prime_size); // TEMPORARY
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hb_bytes_t bytes_for_glyph (const char * glyf, hb_codepoint_t gid)
|
||||||
|
{
|
||||||
|
unsigned int start_offset, end_offset;
|
||||||
|
if (unlikely (!(get_offsets (gid, &start_offset, &end_offset) &&
|
||||||
|
remove_padding (start_offset, &end_offset))))
|
||||||
|
{
|
||||||
|
DEBUG_MSG(SUBSET, nullptr, "Unable to get offset or remove padding for %d", gid);
|
||||||
|
return hb_bytes_t ();
|
||||||
|
}
|
||||||
|
hb_bytes_t glyph = hb_bytes_t (glyf + start_offset, end_offset - start_offset);
|
||||||
|
if (glyph.length == 0) return glyph;
|
||||||
|
if (unlikely (glyph.length < GlyphHeader::static_size))
|
||||||
|
{
|
||||||
|
DEBUG_MSG(SUBSET, nullptr, "Glyph size smaller than minimum header %d", gid);
|
||||||
|
return hb_bytes_t ();
|
||||||
|
}
|
||||||
|
return glyph;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool short_offset;
|
bool short_offset;
|
||||||
unsigned int num_glyphs;
|
unsigned int num_glyphs;
|
||||||
@ -662,6 +609,93 @@ DEBUG_MSG(SUBSET, nullptr, "calloc %u for loca", loca_prime_size); // TEMPORARY
|
|||||||
hb_blob_ptr_t<glyf> glyf_table;
|
hb_blob_ptr_t<glyf> glyf_table;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct SubsetGlyph
|
||||||
|
{
|
||||||
|
hb_codepoint_t new_gid;
|
||||||
|
hb_codepoint_t old_gid;
|
||||||
|
hb_bytes_t source_glyph;
|
||||||
|
hb_bytes_t dest_start; // region of source_glyph to copy first
|
||||||
|
hb_bytes_t dest_end; // region of source_glyph to copy second
|
||||||
|
|
||||||
|
|
||||||
|
bool serialize (hb_serialize_context_t *c,
|
||||||
|
const hb_subset_plan_t *plan) const
|
||||||
|
{
|
||||||
|
TRACE_SERIALIZE (this);
|
||||||
|
|
||||||
|
hb_bytes_t dest_glyph = dest_start.copy(c);
|
||||||
|
dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy(c).length);
|
||||||
|
unsigned int pad_length = padding ();
|
||||||
|
DEBUG_MSG(SUBSET, nullptr, "serialize %d byte glyph, width %d pad %d", dest_glyph.length, dest_glyph.length + pad_length, pad_length);
|
||||||
|
|
||||||
|
HBUINT8 pad;
|
||||||
|
pad = 0;
|
||||||
|
while (pad_length > 0)
|
||||||
|
{
|
||||||
|
c->embed(pad);
|
||||||
|
pad_length--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dest_glyph.length)
|
||||||
|
{
|
||||||
|
_fix_component_gids (plan, dest_glyph);
|
||||||
|
if (plan->drop_hints)
|
||||||
|
{
|
||||||
|
_zero_instruction_length (dest_glyph);
|
||||||
|
c->check_success (_remove_composite_instruction_flag (dest_glyph));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return_trace (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drop_hints (const OT::glyf::accelerator_t& glyf)
|
||||||
|
{
|
||||||
|
if (source_glyph.length == 0) return;
|
||||||
|
|
||||||
|
unsigned int instruction_length = 0;
|
||||||
|
if (!glyf.get_instruction_length (source_glyph, &instruction_length))
|
||||||
|
{
|
||||||
|
DEBUG_MSG(SUBSET, nullptr, "Unable to read instruction length for new_gid %d", new_gid);
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GlyphHeader& header = StructAtOffset<GlyphHeader> (&source_glyph, 0);
|
||||||
|
int16_t num_contours = (int16_t) header.numberOfContours;
|
||||||
|
DEBUG_MSG(SUBSET, nullptr, "new_gid %d (%d contours) drop %d instruction bytes from %d byte source glyph", new_gid, num_contours, instruction_length, source_glyph.length);
|
||||||
|
if (num_contours < 0)
|
||||||
|
{
|
||||||
|
// composite, just chop instructions off the end
|
||||||
|
dest_start = hb_bytes_t (&source_glyph, source_glyph.length - instruction_length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// simple glyph
|
||||||
|
dest_start = hb_bytes_t (&source_glyph, GlyphHeader::static_size + 2 * header.numberOfContours + 2);
|
||||||
|
dest_end = hb_bytes_t (&source_glyph + dest_start.length + instruction_length,
|
||||||
|
source_glyph.length - dest_start.length - instruction_length);
|
||||||
|
DEBUG_MSG(SUBSET, nullptr, "source_len %d start len %d instruction_len %d end len %d", source_glyph.length, dest_start.length, instruction_length, dest_end.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int length () const
|
||||||
|
{
|
||||||
|
return dest_start.length + dest_end.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// pad to 2 to ensure 2-byte loca will be ok
|
||||||
|
unsigned int padding () const
|
||||||
|
{
|
||||||
|
return length () % 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int padded_size () const
|
||||||
|
{
|
||||||
|
return length () + padding ();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
UnsizedArrayOf<HBUINT8> dataZ; /* Glyphs data. */
|
UnsizedArrayOf<HBUINT8> dataZ; /* Glyphs data. */
|
||||||
public:
|
public:
|
||||||
|
@ -190,9 +190,9 @@ test_subset_glyf_noop (void)
|
|||||||
face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
|
face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
|
||||||
hb_set_destroy (codepoints);
|
hb_set_destroy (codepoints);
|
||||||
|
|
||||||
hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('g','l','y','f'));
|
|
||||||
hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('l','o','c', 'a'));
|
|
||||||
check_maxp_num_glyphs(face_abc_subset, 4, true);
|
check_maxp_num_glyphs(face_abc_subset, 4, true);
|
||||||
|
hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('l','o','c', 'a'));
|
||||||
|
hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('g','l','y','f'));
|
||||||
|
|
||||||
hb_face_destroy (face_abc_subset);
|
hb_face_destroy (face_abc_subset);
|
||||||
hb_face_destroy (face_abc);
|
hb_face_destroy (face_abc);
|
||||||
@ -214,9 +214,9 @@ test_subset_glyf_strip_hints_simple (void)
|
|||||||
face_abc_subset = hb_subset_test_create_subset (face_abc, input);
|
face_abc_subset = hb_subset_test_create_subset (face_abc, input);
|
||||||
hb_set_destroy (codepoints);
|
hb_set_destroy (codepoints);
|
||||||
|
|
||||||
|
check_maxp_num_glyphs(face_abc_subset, 3, false);
|
||||||
hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('l','o','c', 'a'));
|
hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('l','o','c', 'a'));
|
||||||
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 ('g','l','y','f'));
|
||||||
check_maxp_num_glyphs(face_abc_subset, 3, false);
|
|
||||||
|
|
||||||
hb_face_destroy (face_abc_subset);
|
hb_face_destroy (face_abc_subset);
|
||||||
hb_face_destroy (face_abc);
|
hb_face_destroy (face_abc);
|
||||||
@ -239,9 +239,9 @@ test_subset_glyf_strip_hints_composite (void)
|
|||||||
face_generated_subset = hb_subset_test_create_subset (face_components, input);
|
face_generated_subset = hb_subset_test_create_subset (face_components, input);
|
||||||
hb_set_destroy (codepoints);
|
hb_set_destroy (codepoints);
|
||||||
|
|
||||||
hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('g','l','y','f'));
|
|
||||||
hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('l','o','c', 'a'));
|
|
||||||
check_maxp_num_glyphs(face_generated_subset, 4, false);
|
check_maxp_num_glyphs(face_generated_subset, 4, false);
|
||||||
|
hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('l','o','c', 'a'));
|
||||||
|
hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('g','l','y','f'));
|
||||||
|
|
||||||
hb_face_destroy (face_generated_subset);
|
hb_face_destroy (face_generated_subset);
|
||||||
hb_face_destroy (face_subset);
|
hb_face_destroy (face_subset);
|
||||||
@ -296,9 +296,9 @@ test_subset_glyf_retain_gids (void)
|
|||||||
face_abc_subset = hb_subset_test_create_subset (face_abc, input);
|
face_abc_subset = hb_subset_test_create_subset (face_abc, input);
|
||||||
hb_set_destroy (codepoints);
|
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);
|
check_maxp_num_glyphs(face_abc_subset, 4, true);
|
||||||
|
hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('l','o','c', 'a'));
|
||||||
|
hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','l','y','f'));
|
||||||
|
|
||||||
hb_face_destroy (face_abc_subset);
|
hb_face_destroy (face_abc_subset);
|
||||||
hb_face_destroy (face_abc);
|
hb_face_destroy (face_abc);
|
||||||
@ -320,9 +320,9 @@ test_subset_glyf_retain_gids_truncates (void)
|
|||||||
face_abc_subset = hb_subset_test_create_subset (face_abc, input);
|
face_abc_subset = hb_subset_test_create_subset (face_abc, input);
|
||||||
hb_set_destroy (codepoints);
|
hb_set_destroy (codepoints);
|
||||||
|
|
||||||
hb_subset_test_check (face_a, face_abc_subset, HB_TAG ('g','l','y','f'));
|
|
||||||
hb_subset_test_check (face_a, face_abc_subset, HB_TAG ('l','o','c', 'a'));
|
|
||||||
check_maxp_num_glyphs(face_abc_subset, 2, true);
|
check_maxp_num_glyphs(face_abc_subset, 2, true);
|
||||||
|
hb_subset_test_check (face_a, face_abc_subset, HB_TAG ('l','o','c', 'a'));
|
||||||
|
hb_subset_test_check (face_a, face_abc_subset, HB_TAG ('g','l','y','f'));
|
||||||
|
|
||||||
hb_face_destroy (face_abc_subset);
|
hb_face_destroy (face_abc_subset);
|
||||||
hb_face_destroy (face_abc);
|
hb_face_destroy (face_abc);
|
||||||
|
Loading…
Reference in New Issue
Block a user