[subset] Dinner time, checkpoint

This commit is contained in:
rsheeter 2019-05-08 16:52:00 -07:00 committed by Rod Sheeter
parent 240bc86e3a
commit 0d7fef2d50
1 changed files with 58 additions and 39 deletions

View File

@ -86,9 +86,13 @@ struct glyf
{
TRACE_SERIALIZE (this);
// TODO actually copy glyph
// TODO worry about instructions
// TODO capture dest locations for loca
// pad glyphs to 2-byte boundaries to permit short loca
HBUINT8 pad;
+ it
| hb_apply ( [&] (hb_bytes_t glyph) {
glyph.copy(c);
if (glyph.length % 2) c->extend(pad);
});
return_trace (true);
}
@ -103,32 +107,54 @@ struct glyf
OT::glyf::accelerator_t glyf;
glyf.init (c->plan->source);
// stream new-gids => pair of start/end offsets
// can now copy glyph from <prev>=>end
// TODO(instructions)
// stream new-gids => glyph to keep
// if dropping hints the glyph to keep doesn't have them anymore
auto it =
+ hb_iota (c->plan->num_output_glyphs ())
| hb_map ([&] (hb_codepoint_t new_gid) {
unsigned int start_offset = 0, end_offset = 0;
hb_codepoint_t old_gid;
// should never happen, ALL old gids should be mapped
if (!c->plan->old_gid_for_new_gid (new_gid, &old_gid)) return hb_pair (start_offset, end_offset);
// being empty is perfectly normal
if (c->plan->is_empty_glyph (old_gid)) return hb_pair (start_offset, end_offset);
// should never happen fail, ALL old gids should be mapped
if (!c->plan->old_gid_for_new_gid (new_gid, &old_gid)) return hb_bytes_t ();
unsigned int start_offset, end_offset;
if (unlikely (!(glyf.get_offsets (old_gid, &start_offset, &end_offset) &&
glyf.remove_padding (start_offset, &end_offset))))
{
// TODO signal irreversible error
return hb_pair (start_offset, end_offset);
return hb_bytes_t ();
}
return hb_pair (start_offset, end_offset);
hb_bytes_t glyph ((const char *) this, end_offset - start_offset);
// if dropping hints, find hints region and subtract it
if (c->plan->drop_hints) {
unsigned int instruction_length;
if (!glyf.get_instruction_length (glyph, &instruction_length))
{
// TODO signal irreversible failure
return hb_bytes_t ();
}
glyph = hb_bytes_t (&glyph, glyph.length - instruction_length);
}
return glyph;
});
glyf_prime->serialize (c->serializer, it);
// we know enough to write loca
// TODO calculate size, do we need two or four byte loca entries
unsigned int offset = 0;
HBUINT16 loca_entry;
loca *loca_prime = c->serializer->start_embed <loca> ();
+ hb_enumerate (it)
| hb_apply ([&] (hb_pair_t<unsigned, hb_bytes_t> p) {
offset += p.second.length;
loca_entry = offset / 2;
c->serializer->embed(loca_entry);
});
// one for the road
c->serializer->embed(loca_entry);
return_trace (true);
}
@ -412,45 +438,40 @@ struct glyf
return true;
}
bool get_instruction_offsets (unsigned int start_offset,
unsigned int end_offset,
unsigned int *instruction_start /* OUT */,
unsigned int *instruction_end /* OUT */) const
bool get_instruction_length (hb_bytes_t glyph,
unsigned int * length /* OUT */) const
{
if (end_offset - start_offset < GlyphHeader::static_size)
/* Empty glyph; no instructions. */
if (glyph.get_size() < GlyphHeader::static_size)
{
*instruction_start = 0;
*instruction_end = 0;
return true; /* Empty glyph; no instructions. */
*length = 0;
return true;
}
const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyf_table, start_offset);
unsigned int start = glyph.length;
unsigned int end = glyph.length;
const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (&glyph, 0);
int16_t num_contours = (int16_t) glyph_header.numberOfContours;
if (num_contours < 0)
{
CompositeGlyphHeader::Iterator composite_it;
if (unlikely (!CompositeGlyphHeader::get_iterator (
(const char*) this->glyf_table + start_offset,
end_offset - start_offset, &composite_it))) return false;
if (unlikely (!CompositeGlyphHeader::get_iterator (&glyph, glyph.length, &composite_it))) return false;
const CompositeGlyphHeader *last;
do {
last = composite_it.current;
} while (composite_it.move_to_next ());
if ((uint16_t) last->flags & CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS)
*instruction_start = ((char *) last - (char *) glyf_table->dataZ.arrayZ) + last->get_size ();
else
*instruction_start = end_offset;
*instruction_end = end_offset;
if (unlikely (*instruction_start > *instruction_end))
start = ((char *) last - (char *) glyf_table->dataZ.arrayZ) + last->get_size ();
if (unlikely (start > end))
{
DEBUG_MSG(SUBSET, nullptr, "Invalid instruction offset, %d is outside [%d, %d]", *instruction_start, start_offset, end_offset);
DEBUG_MSG(SUBSET, nullptr, "Invalid instruction offset, %d is outside %d byte buffer", start, glyph.length);
return false;
}
}
else
{
unsigned int instruction_length_offset = start_offset + GlyphHeader::static_size + 2 * num_contours;
if (unlikely (instruction_length_offset + 2 > end_offset))
unsigned int instruction_length_offset = GlyphHeader::static_size + 2 * num_contours;
if (unlikely (instruction_length_offset + 2 > glyph.length))
{
DEBUG_MSG(SUBSET, nullptr, "Glyph size is too short, missing field instructionLength.");
return false;
@ -459,15 +480,13 @@ struct glyf
const HBUINT16 &instruction_length = StructAtOffset<HBUINT16> (glyf_table, instruction_length_offset);
unsigned int start = instruction_length_offset + 2;
unsigned int end = start + (uint16_t) instruction_length;
if (unlikely (end > end_offset)) // Out of bounds of the current glyph
if (unlikely (end > glyph.length)) // Out of bounds of the current glyph
{
DEBUG_MSG(SUBSET, nullptr, "The instructions array overruns the glyph's boundaries.");
return false;
}
*instruction_start = start;
*instruction_end = end;
}
*length = end - start;
return true;
}