[subset] Dinner time, checkpoint

This commit is contained in:
rsheeter 2019-05-08 16:52:00 -07:00 committed by Rod Sheeter
parent 723d054dcb
commit 8f174870e9
1 changed files with 58 additions and 39 deletions

View File

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