[glyf] format source

This commit is contained in:
Ebrahim Byagowi 2019-08-24 16:26:42 +04:30
parent 2aef3013f3
commit d57819cbdb
1 changed files with 152 additions and 126 deletions

View File

@ -1,5 +1,6 @@
/* /*
* Copyright © 2015 Google, Inc. * Copyright © 2015 Google, Inc.
* Copyright © 2019 Ebrahim Byagowi
* *
* This is part of HarfBuzz, a text shaping library. * This is part of HarfBuzz, a text shaping library.
* *
@ -53,7 +54,8 @@ struct loca
} }
protected: protected:
UnsizedArrayOf<HBUINT8> dataZ; /* Location data. */ UnsizedArrayOf<HBUINT8>
dataZ; /* Location data. */
public: public:
DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always
* check the size externally, allow Null() object of it by * check the size externally, allow Null() object of it by
@ -93,7 +95,9 @@ struct glyf
if (unlikely (!loca_prime_data)) return false; if (unlikely (!loca_prime_data)) return false;
DEBUG_MSG(SUBSET, nullptr, "loca entry_size %d num_offsets %d max_offset %d size %d", entry_size, num_offsets, max_offset, entry_size * num_offsets); DEBUG_MSG (SUBSET, nullptr, "loca entry_size %d num_offsets %d "
"max_offset %d size %d",
entry_size, num_offsets, max_offset, entry_size * num_offsets);
if (use_short_loca) if (use_short_loca)
_write_loca (padded_offsets, 1, hb_array ((HBUINT16*) loca_prime_data, num_offsets)); _write_loca (padded_offsets, 1, hb_array ((HBUINT16*) loca_prime_data, num_offsets));
@ -122,7 +126,8 @@ struct glyf
unsigned int offset = 0; unsigned int offset = 0;
dest << 0; dest << 0;
+ it + it
| hb_map ([=, &offset] (unsigned int padded_size) { | hb_map ([=, &offset] (unsigned int padded_size)
{
offset += padded_size; offset += padded_size;
DEBUG_MSG (SUBSET, nullptr, "loca entry offset %d", offset); DEBUG_MSG (SUBSET, nullptr, "loca entry offset %d", offset);
return offset >> right_shift; return offset >> right_shift;
@ -167,7 +172,8 @@ struct glyf
; ;
if (c->serializer->in_error ()) return_trace (false); if (c->serializer->in_error ()) return_trace (false);
return_trace (c->serializer->check_success (_add_loca_and_head (c->plan, padded_offsets))); return_trace (c->serializer->check_success (_add_loca_and_head (c->plan,
padded_offsets)));
} }
template <typename SubsetGlyph> template <typename SubsetGlyph>
@ -179,14 +185,17 @@ struct glyf
glyf.init (plan->source); glyf.init (plan->source);
+ hb_range (plan->num_output_glyphs ()) + hb_range (plan->num_output_glyphs ())
| hb_map ([&] (hb_codepoint_t new_gid) { | hb_map ([&] (hb_codepoint_t new_gid)
{
SubsetGlyph subset_glyph = {0}; SubsetGlyph subset_glyph = {0};
subset_glyph.new_gid = new_gid; 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 (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid)) return subset_glyph; if (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid))
return subset_glyph;
subset_glyph.source_glyph = glyf.bytes_for_glyph ((const char *) this, subset_glyph.old_gid); subset_glyph.source_glyph = glyf.bytes_for_glyph ((const char *) this,
subset_glyph.old_gid);
if (plan->drop_hints) subset_glyph.drop_hints (glyf); if (plan->drop_hints) subset_glyph.drop_hints (glyf);
else subset_glyph.dest_start = subset_glyph.source_glyph; else subset_glyph.dest_start = subset_glyph.source_glyph;
@ -225,7 +234,9 @@ struct glyf
int16_t num_contours = (int16_t) glyph_header.numberOfContours; int16_t num_contours = (int16_t) glyph_header.numberOfContours;
if (num_contours <= 0) return; // only for simple glyphs if (num_contours <= 0) return; // only for simple glyphs
const HBUINT16 &instruction_length = StructAtOffset<HBUINT16> (&glyph, GlyphHeader::static_size + 2 * num_contours); unsigned int contours_length = GlyphHeader::static_size + 2 * num_contours;
const HBUINT16 &instruction_length = StructAtOffset<HBUINT16> (&glyph,
contours_length);
(HBUINT16 &) instruction_length = 0; (HBUINT16 &) instruction_length = 0;
} }
@ -236,9 +247,12 @@ struct glyf
/* remove WE_HAVE_INSTRUCTIONS from flags in dest */ /* remove WE_HAVE_INSTRUCTIONS from flags in dest */
OT::glyf::CompositeGlyphHeader::Iterator composite_it; OT::glyf::CompositeGlyphHeader::Iterator composite_it;
if (unlikely (!OT::glyf::CompositeGlyphHeader::get_iterator (&glyph, glyph.length, &composite_it))) return false; if (unlikely (!OT::glyf::CompositeGlyphHeader::get_iterator (&glyph, glyph.length,
&composite_it)))
return false;
const OT::glyf::CompositeGlyphHeader *composite_header; const OT::glyf::CompositeGlyphHeader *composite_header;
do { do
{
composite_header = composite_it.current; composite_header = composite_it.current;
OT::HBUINT16 *flags = const_cast<OT::HBUINT16 *> (&composite_header->flags); OT::HBUINT16 *flags = const_cast<OT::HBUINT16 *> (&composite_header->flags);
*flags = (uint16_t) *flags & ~OT::glyf::CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS; *flags = (uint16_t) *flags & ~OT::glyf::CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS;
@ -257,7 +271,7 @@ struct glyf
return false; return false;
head *head_prime = (head *) hb_blob_get_data_writable (head_prime_blob, nullptr); head *head_prime = (head *) hb_blob_get_data_writable (head_prime_blob, nullptr);
head_prime->indexToLocFormat = use_short_loca ? 0 : 1; head_prime->indexToLocFormat = !use_short_loca;
bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob); bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob);
hb_blob_destroy (head_prime_blob); hb_blob_destroy (head_prime_blob);
@ -280,7 +294,8 @@ struct glyf
struct CompositeGlyphHeader struct CompositeGlyphHeader
{ {
enum composite_glyph_flag_t { enum composite_glyph_flag_t
{
ARG_1_AND_2_ARE_WORDS = 0x0001, ARG_1_AND_2_ARE_WORDS = 0x0001,
ARGS_ARE_XY_VALUES = 0x0002, ARGS_ARE_XY_VALUES = 0x0002,
ROUND_XY_TO_GRID = 0x0004, ROUND_XY_TO_GRID = 0x0004,
@ -416,7 +431,8 @@ struct glyf
composite); composite);
} }
enum simple_glyph_flag_t { enum simple_glyph_flag_t
{
FLAG_ON_CURVE = 0x01, FLAG_ON_CURVE = 0x01,
FLAG_X_SHORT = 0x02, FLAG_X_SHORT = 0x02,
FLAG_Y_SHORT = 0x04, FLAG_Y_SHORT = 0x04,
@ -489,7 +505,8 @@ struct glyf
if (coordsWithFlags != nCoordinates) if (coordsWithFlags != nCoordinates)
{ {
DEBUG_MSG(SUBSET, nullptr, "Expect %d coords to have flags, got flags for %d", nCoordinates, coordsWithFlags); DEBUG_MSG (SUBSET, nullptr, "Expect %d coords to have flags, got flags for %d",
nCoordinates, coordsWithFlags);
return false; return false;
} }
glyph += coordBytes; glyph += coordBytes;
@ -546,38 +563,47 @@ struct glyf
unsigned int end = glyph.length; unsigned int end = glyph.length;
unsigned int glyph_offset = &glyph - glyf_table; unsigned int glyph_offset = &glyph - glyf_table;
CompositeGlyphHeader::Iterator composite_it; CompositeGlyphHeader::Iterator composite_it;
if (unlikely (!CompositeGlyphHeader::get_iterator (&glyph, glyph.length, &composite_it))) return false; if (unlikely (!CompositeGlyphHeader::get_iterator (&glyph, glyph.length,
&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)
start = ((char *) last - (char *) glyf_table->dataZ.arrayZ) + last->get_size () - glyph_offset; start = ((char *) last - (char *) glyf_table->dataZ.arrayZ)
+ last->get_size () - glyph_offset;
if (unlikely (start > end)) if (unlikely (start > end))
{ {
DEBUG_MSG(SUBSET, nullptr, "Invalid instruction offset, %d is outside %d byte buffer", start, glyph.length); DEBUG_MSG (SUBSET, nullptr, "Invalid instruction offset, %d is outside "
"%d byte buffer", start, glyph.length);
return false; return false;
} }
*length = end - start; *length = end - start;
} }
else else
{ {
// simple glyph /* simple glyph */
unsigned int instruction_length_offset = GlyphHeader::static_size + 2 * num_contours; unsigned int instruction_len_offset = GlyphHeader::static_size + 2 * num_contours;
if (unlikely (instruction_length_offset + 2 > glyph.length)) if (unlikely (instruction_len_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;
} }
const HBUINT16 &instruction_length = StructAtOffset<HBUINT16> (&glyph, instruction_length_offset); const HBUINT16 &instruction_len = StructAtOffset<HBUINT16> (&glyph,
if (unlikely (instruction_length_offset + 2 + instruction_length > glyph.length)) // Out of bounds of the current glyph instruction_len_offset);
/* Out of bounds of the current glyph */
if (unlikely (instruction_len_offset + 2 + instruction_len > glyph.length))
{ {
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;
} }
*length = (uint16_t) instruction_length; *length = (uint16_t) instruction_len;
} }
return true; return true;
} }
@ -591,12 +617,15 @@ struct glyf
if (end_offset - start_offset < GlyphHeader::static_size) if (end_offset - start_offset < GlyphHeader::static_size)
return true; /* Empty glyph; zero extents. */ return true; /* Empty glyph; zero extents. */
const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyf_table, start_offset); const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyf_table,
start_offset);
extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax);
extents->y_bearing = hb_max (glyph_header.yMin, glyph_header.yMax); extents->y_bearing = hb_max (glyph_header.yMin, glyph_header.yMax);
extents->width = hb_max (glyph_header.xMin, glyph_header.xMax) - extents->x_bearing; extents->width = hb_max (glyph_header.xMin, glyph_header.xMax)
extents->height = hb_min (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing; - extents->x_bearing;
extents->height = hb_min (glyph_header.yMin, glyph_header.yMax)
- extents->y_bearing;
return true; return true;
} }
@ -627,15 +656,13 @@ struct glyf
hb_blob_ptr_t<glyf> glyf_table; hb_blob_ptr_t<glyf> glyf_table;
}; };
struct SubsetGlyph struct SubsetGlyph
{ {
hb_codepoint_t new_gid; hb_codepoint_t new_gid;
hb_codepoint_t old_gid; hb_codepoint_t old_gid;
hb_bytes_t source_glyph; hb_bytes_t source_glyph;
hb_bytes_t dest_start; // region of source_glyph to copy first hb_bytes_t dest_start; /* region of source_glyph to copy first */
hb_bytes_t dest_end; // region of source_glyph to copy second hb_bytes_t dest_end; /* region of source_glyph to copy second */
bool serialize (hb_serialize_context_t *c, bool serialize (hb_serialize_context_t *c,
const hb_subset_plan_t *plan) const const hb_subset_plan_t *plan) const
@ -645,7 +672,8 @@ struct glyf
hb_bytes_t dest_glyph = dest_start.copy (c); hb_bytes_t dest_glyph = dest_start.copy (c);
dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length); dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length);
unsigned int pad_length = padding (); 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); DEBUG_MSG (SUBSET, nullptr, "serialize %d byte glyph, width %d pad %d",
dest_glyph.length, dest_glyph.length + pad_length, pad_length);
HBUINT8 pad; HBUINT8 pad;
pad = 0; pad = 0;
@ -672,50 +700,48 @@ struct glyf
{ {
if (source_glyph.length == 0) return; if (source_glyph.length == 0) return;
unsigned int instruction_length = 0; unsigned int instruction_len = 0;
if (!glyf.get_instruction_length (source_glyph, &instruction_length)) if (!glyf.get_instruction_length (source_glyph, &instruction_len))
{ {
DEBUG_MSG(SUBSET, nullptr, "Unable to read instruction length for new_gid %d", new_gid); DEBUG_MSG (SUBSET, nullptr, "Unable to read instruction length for new_gid %d",
new_gid);
return ; return ;
} }
const GlyphHeader& header = StructAtOffset<GlyphHeader> (&source_glyph, 0); const GlyphHeader& header = StructAtOffset<GlyphHeader> (&source_glyph, 0);
int16_t num_contours = (int16_t) header.numberOfContours; 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); DEBUG_MSG (SUBSET, nullptr, "new_gid %d (%d contours) drop %d instruction bytes "
"from %d byte source glyph",
new_gid, num_contours, instruction_len, source_glyph.length);
if (num_contours < 0) if (num_contours < 0)
{ {
// composite, just chop instructions off the end /* composite, just chop instructions off the end */
dest_start = hb_bytes_t (&source_glyph, source_glyph.length - instruction_length); dest_start = hb_bytes_t (&source_glyph, source_glyph.length - instruction_len);
} }
else else
{ {
// simple glyph /* simple glyph */
dest_start = hb_bytes_t (&source_glyph, GlyphHeader::static_size + 2 * header.numberOfContours + 2); unsigned int glyph_length = GlyphHeader::static_size + 2 * header.numberOfContours
dest_end = hb_bytes_t (&source_glyph + dest_start.length + instruction_length, + 2 + instruction_len;
source_glyph.length - dest_start.length - instruction_length); dest_start = hb_bytes_t (&source_glyph, glyph_length - instruction_len);
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); dest_end = hb_bytes_t (&source_glyph + glyph_length,
source_glyph.length - glyph_length);
DEBUG_MSG (SUBSET, nullptr, "source_len %d start len %d glyph_len %d "
"instruction_len %d end len %d",
source_glyph.length, dest_start.length, glyph_length,
instruction_len, dest_end.length);
} }
} }
unsigned int length () const unsigned int length () const { return dest_start.length + dest_end.length; }
{ /* pad to 2 to ensure 2-byte loca will be ok */
return dest_start.length + dest_end.length; unsigned int padding () const { return length () % 2; }
} unsigned int padded_size () const { return length () + padding (); }
// 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:
DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always
* check the size externally, allow Null() object of it by * check the size externally, allow Null() object of it by