[glyf] Move subset related methods inside GlyphHeader

This commit is contained in:
Ebrahim Byagowi 2019-10-08 12:14:14 +03:30
parent 7839e23558
commit ad86806dcb
2 changed files with 214 additions and 218 deletions

View File

@ -208,46 +208,6 @@ struct glyf
glyf.fini ();
}
static void
_fix_component_gids (const hb_subset_plan_t *plan,
hb_bytes_t glyph)
{
for (auto &item : OT::glyf::get_composite_iterator (glyph))
{
hb_codepoint_t new_gid;
if (plan->new_gid_for_old_gid (item.glyphIndex, &new_gid))
((OT::glyf::CompositeGlyphHeader *) &item)->glyphIndex = new_gid;
}
}
static void
_zero_instruction_length (hb_bytes_t glyph)
{
const GlyphHeader &glyph_header = *glyph.as<GlyphHeader> ();
if (!glyph_header.is_simple_glyph ()) return; // only for simple glyphs
unsigned int instruction_len_offset = glyph_header.as_simple ().instruction_len_offset ();
const HBUINT16 &instruction_len = StructAtOffset<HBUINT16> (&glyph, instruction_len_offset);
(HBUINT16 &) instruction_len = 0;
}
static bool _remove_composite_instruction_flag (hb_bytes_t glyph)
{
const GlyphHeader &glyph_header = *glyph.as<GlyphHeader> ();
if (!glyph_header.is_composite_glyph ()) return true; // only for composites
/* remove WE_HAVE_INSTRUCTIONS from flags in dest */
return
+ OT::glyf::get_composite_iterator (glyph)
| hb_reduce ([] (bool _, const OT::glyf::CompositeGlyphHeader &item)
{
OT::HBUINT16 *flags = const_cast<OT::HBUINT16 *> (&item.flags);
*flags = (uint16_t) *flags & ~OT::glyf::CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS;
return true;
}, false)
;
}
static bool
_add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca)
{
@ -266,169 +226,6 @@ struct glyf
return success;
}
struct GlyphHeader
{
struct SimpleHeader
{
const GlyphHeader &header;
SimpleHeader (const GlyphHeader &header_) : header (header_) {}
unsigned int instruction_len_offset () const
{ return static_size + 2 * header.numberOfContours; }
unsigned int length (unsigned int instruction_len) const
{ return instruction_len_offset () + 2 + instruction_len; }
bool get_instruction_length (hb_bytes_t glyph, unsigned int *len) const
{
unsigned int instruction_length_offset = instruction_len_offset ();
if (unlikely (instruction_length_offset + 2 > glyph.length)) return false;
const HBUINT16 &instruction_len = StructAtOffset<HBUINT16> (&glyph, instruction_length_offset);
/* Out of bounds of the current glyph */
if (unlikely (length (instruction_len) > glyph.length)) return false;
*len = instruction_len;
return true;
}
enum simple_glyph_flag_t
{
FLAG_ON_CURVE = 0x01,
FLAG_X_SHORT = 0x02,
FLAG_Y_SHORT = 0x04,
FLAG_REPEAT = 0x08,
FLAG_X_SAME = 0x10,
FLAG_Y_SAME = 0x20,
FLAG_RESERVED1 = 0x40,
FLAG_RESERVED2 = 0x80
};
hb_bytes_t bytes_without_padding (hb_bytes_t glyph_bytes) const
{
/* based on FontTools _g_l_y_f.py::trim */
const char *glyph = glyph_bytes.arrayZ;
const char *glyph_end = glyph + glyph_bytes.length;
/* simple glyph w/contours, possibly trimmable */
glyph += instruction_len_offset ();
if (unlikely (glyph + 2 >= glyph_end)) return hb_bytes_t ();
unsigned int num_coordinates = StructAtOffset<HBUINT16> (glyph - 2, 0) + 1;
unsigned int num_instructions = StructAtOffset<HBUINT16> (glyph, 0);
glyph += 2 + num_instructions;
if (unlikely (glyph + 2 >= glyph_end)) return hb_bytes_t ();
unsigned int coord_bytes = 0;
unsigned int coords_with_flags = 0;
while (glyph < glyph_end)
{
uint8_t flag = *glyph;
glyph++;
unsigned int repeat = 1;
if (flag & FLAG_REPEAT)
{
if (unlikely (glyph >= glyph_end)) return hb_bytes_t ();
repeat = *glyph + 1;
glyph++;
}
unsigned int xBytes, yBytes;
xBytes = yBytes = 0;
if (flag & FLAG_X_SHORT) xBytes = 1;
else if ((flag & FLAG_X_SAME) == 0) xBytes = 2;
if (flag & FLAG_Y_SHORT) yBytes = 1;
else if ((flag & FLAG_Y_SAME) == 0) yBytes = 2;
coord_bytes += (xBytes + yBytes) * repeat;
coords_with_flags += repeat;
if (coords_with_flags >= num_coordinates) break;
}
if (unlikely (coords_with_flags != num_coordinates)) return hb_bytes_t ();
return glyph_bytes.sub_array (0, glyph_bytes.length + coord_bytes - (glyph_end - glyph));
}
};
struct CompositeHeader
{
const GlyphHeader &header;
CompositeHeader (const GlyphHeader &header_) : header (header_) {}
bool get_instruction_length (hb_bytes_t glyph, unsigned int *length) const
{
unsigned int start = glyph.length;
unsigned int end = glyph.length;
const CompositeGlyphHeader *last = nullptr;
for (auto &item : get_composite_iterator (glyph))
last = &item;
if (unlikely (!last)) return false;
if ((uint16_t) last->flags & CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS)
start = (char *) last - &glyph + last->get_size ();
if (unlikely (start > end)) return false;
*length = end - start;
return true;
}
/* Trimming for composites not implemented.
* If removing hints it falls out of that. */
hb_bytes_t bytes_without_padding (hb_bytes_t glyph_bytes) const
{ return glyph_bytes; }
};
const SimpleHeader as_simple () const { return SimpleHeader (*this); }
const CompositeHeader as_composite () const { return CompositeHeader (*this); }
enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE };
glyph_type_t get_type () const
{
if (is_simple_glyph ()) return SIMPLE;
else if (is_composite_glyph ()) return COMPOSITE;
else return EMPTY;
}
bool get_instruction_length (hb_bytes_t glyph, unsigned int *length) const
{
switch (get_type ())
{
case COMPOSITE: return as_composite ().get_instruction_length (glyph, length);
case SIMPLE: return as_simple ().get_instruction_length (glyph, length);
default:
case EMPTY: *length = 0; return glyph.length == 0; /* only 0 byte glyphs are healthy when missing GlyphHeader */
}
}
hb_bytes_t bytes_without_padding (hb_bytes_t glyph_bytes) const
{
switch (get_type ())
{
case COMPOSITE: return as_composite ().bytes_without_padding (glyph_bytes);
case SIMPLE: return as_simple ().bytes_without_padding (glyph_bytes);
default:
case EMPTY: return glyph_bytes;
}
}
bool has_data () const { return numberOfContours; }
bool is_simple_glyph () const { return numberOfContours > 0; }
bool is_composite_glyph () const { return numberOfContours < 0; }
HBINT16 numberOfContours;
/* If the number of contours is
* greater than or equal to zero,
* this is a simple glyph; if negative,
* this is a composite glyph. */
FWORD xMin; /* Minimum x for coordinate data. */
FWORD yMin; /* Minimum y for coordinate data. */
FWORD xMax; /* Maximum x for coordinate data. */
FWORD yMax; /* Maximum y for coordinate data. */
DEFINE_SIZE_STATIC (10);
};
struct CompositeGlyphHeader
{
enum composite_glyph_flag_t
@ -591,14 +388,208 @@ struct glyf
__item_t__ current;
};
static composite_iter_t get_composite_iterator (hb_bytes_t glyph)
struct GlyphHeader
{
const GlyphHeader &glyph_header = *glyph.as<GlyphHeader> ();
if (!glyph_header.is_composite_glyph ()) return composite_iter_t ();
struct SimpleHeader
{
const GlyphHeader &header;
SimpleHeader (const GlyphHeader &header_) : header (header_) {}
return composite_iter_t (glyph, &StructAfter<CompositeGlyphHeader, GlyphHeader> (glyph_header));
unsigned int instruction_len_offset () const
{ return static_size + 2 * header.numberOfContours; }
unsigned int length (unsigned int instruction_len) const
{ return instruction_len_offset () + 2 + instruction_len; }
bool get_instruction_length (hb_bytes_t glyph, unsigned int *len) const
{
unsigned int instruction_length_offset = instruction_len_offset ();
if (unlikely (instruction_length_offset + 2 > glyph.length)) return false;
const HBUINT16 &instructionLength = StructAtOffset<HBUINT16> (&glyph, instruction_length_offset);
/* Out of bounds of the current glyph */
if (unlikely (length (instructionLength) > glyph.length)) return false;
*len = instructionLength;
return true;
}
enum simple_glyph_flag_t
{
FLAG_ON_CURVE = 0x01,
FLAG_X_SHORT = 0x02,
FLAG_Y_SHORT = 0x04,
FLAG_REPEAT = 0x08,
FLAG_X_SAME = 0x10,
FLAG_Y_SAME = 0x20,
FLAG_RESERVED1 = 0x40,
FLAG_RESERVED2 = 0x80
};
hb_bytes_t bytes_without_padding (hb_bytes_t glyph_bytes) const
{
/* based on FontTools _g_l_y_f.py::trim */
const char *glyph = glyph_bytes.arrayZ;
const char *glyph_end = glyph + glyph_bytes.length;
/* simple glyph w/contours, possibly trimmable */
glyph += instruction_len_offset ();
if (unlikely (glyph + 2 >= glyph_end)) return hb_bytes_t ();
unsigned int num_coordinates = StructAtOffset<HBUINT16> (glyph - 2, 0) + 1;
unsigned int num_instructions = StructAtOffset<HBUINT16> (glyph, 0);
glyph += 2 + num_instructions;
if (unlikely (glyph + 2 >= glyph_end)) return hb_bytes_t ();
unsigned int coord_bytes = 0;
unsigned int coords_with_flags = 0;
while (glyph < glyph_end)
{
uint8_t flag = *glyph;
glyph++;
unsigned int repeat = 1;
if (flag & FLAG_REPEAT)
{
if (unlikely (glyph >= glyph_end)) return hb_bytes_t ();
repeat = *glyph + 1;
glyph++;
}
unsigned int xBytes, yBytes;
xBytes = yBytes = 0;
if (flag & FLAG_X_SHORT) xBytes = 1;
else if ((flag & FLAG_X_SAME) == 0) xBytes = 2;
if (flag & FLAG_Y_SHORT) yBytes = 1;
else if ((flag & FLAG_Y_SAME) == 0) yBytes = 2;
coord_bytes += (xBytes + yBytes) * repeat;
coords_with_flags += repeat;
if (coords_with_flags >= num_coordinates) break;
}
if (unlikely (coords_with_flags != num_coordinates)) return hb_bytes_t ();
return glyph_bytes.sub_array (0, glyph_bytes.length + coord_bytes - (glyph_end - glyph));
}
/* zero instruction length */
void drop_hints ()
{
GlyphHeader &glyph_header = const_cast<GlyphHeader &> (header);
(HBUINT16 &) StructAtOffset<HBUINT16> (&glyph_header, instruction_len_offset ()) = 0;
}
};
struct CompositeHeader
{
const GlyphHeader &header;
CompositeHeader (const GlyphHeader &header_) : header (header_) {}
composite_iter_t get_iterator (hb_bytes_t glyph) const
{ return composite_iter_t (glyph, &StructAfter<CompositeGlyphHeader, GlyphHeader> (header)); }
bool get_instruction_length (hb_bytes_t glyph, unsigned int *length) const
{
unsigned int start = glyph.length;
unsigned int end = glyph.length;
const CompositeGlyphHeader *last = nullptr;
for (auto &item : get_iterator (glyph))
last = &item;
if (unlikely (!last)) return false;
if ((uint16_t) last->flags & CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS)
start = (char *) last - &glyph + last->get_size ();
if (unlikely (start > end)) return false;
*length = end - start;
return true;
}
/* Trimming for composites not implemented.
* If removing hints it falls out of that. */
hb_bytes_t bytes_without_padding (hb_bytes_t glyph_bytes) const
{ return glyph_bytes; }
/* remove WE_HAVE_INSTRUCTIONS flag from composite glyph */
void drop_hints (hb_bytes_t glyph_bytes)
{
for (const auto &_ : get_iterator (glyph_bytes))
{
HBUINT16 &flags = *const_cast<OT::HBUINT16 *> (&_.flags);
flags = (uint16_t) flags & ~OT::glyf::CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS;
}
}
};
const SimpleHeader as_simple () const { return SimpleHeader (*this); }
SimpleHeader as_simple () { return SimpleHeader (*this); }
const CompositeHeader as_composite () const { return CompositeHeader (*this); }
CompositeHeader as_composite () { return CompositeHeader (*this); }
enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE };
glyph_type_t get_type () const
{
if (is_simple_glyph ()) return SIMPLE;
else if (is_composite_glyph ()) return COMPOSITE;
else return EMPTY;
}
composite_iter_t get_composite_iterator (hb_bytes_t glyph) const
{
if (!is_composite_glyph ()) return composite_iter_t ();
return as_composite ().get_iterator (glyph);
}
bool get_instruction_length (hb_bytes_t glyph, unsigned int *length) const
{
switch (get_type ())
{
case COMPOSITE: return as_composite ().get_instruction_length (glyph, length);
case SIMPLE: return as_simple ().get_instruction_length (glyph, length);
default:
case EMPTY: *length = 0; return glyph.length == 0; /* only 0 byte glyphs are healthy when missing GlyphHeader */
}
}
hb_bytes_t bytes_without_padding (hb_bytes_t glyph_bytes) const
{
switch (get_type ())
{
case COMPOSITE: return as_composite ().bytes_without_padding (glyph_bytes);
case SIMPLE: return as_simple ().bytes_without_padding (glyph_bytes);
default:
case EMPTY: return glyph_bytes;
}
}
void drop_hints (hb_bytes_t glyph_bytes)
{
switch (get_type ())
{
case COMPOSITE: as_composite ().drop_hints (glyph_bytes); return;
case SIMPLE: as_simple ().drop_hints (); return;
default:
case EMPTY: return;
}
}
bool has_data () const { return numberOfContours; }
bool is_simple_glyph () const { return numberOfContours > 0; }
bool is_composite_glyph () const { return numberOfContours < 0; }
HBINT16 numberOfContours;
/* If the number of contours is
* greater than or equal to zero,
* this is a simple glyph; if negative,
* this is a composite glyph. */
FWORD xMin; /* Minimum x for coordinate data. */
FWORD yMin; /* Minimum y for coordinate data. */
FWORD xMax; /* Maximum x for coordinate data. */
FWORD yMax; /* Maximum y for coordinate data. */
DEFINE_SIZE_STATIC (10);
};
struct accelerator_t
{
void init (hb_face_t *face_)
@ -723,7 +714,7 @@ struct glyf
if (glyph_header.is_composite_glyph ())
{
/* add one pseudo point for each component in composite glyph */
num_points += hb_len (get_composite_iterator (bytes));
num_points += hb_len (glyph_header.get_composite_iterator (bytes));
points_.resize (num_points + PHANTOM_COUNT);
for (unsigned int i = 0; i < points_.length; i++) points_[i].init ();
return true;
@ -821,7 +812,7 @@ struct glyf
all_points.extend (points.as_array ());
else if (glyph_header.is_composite_glyph ())
{
for (auto &item : get_composite_iterator (bytes))
for (auto &item : glyph_header.get_composite_iterator (bytes))
{
contour_point_vector_t comp_points;
if (unlikely (!get_points_var (item.glyphIndex, coords, coord_count,
@ -1051,16 +1042,19 @@ struct glyf
pad_length--;
}
if (dest_glyph.length)
if (!unlikely (dest_glyph.length)) return_trace (true);
/* update components gids */
GlyphHeader &glyph_header = *const_cast<GlyphHeader *> (dest_glyph.as<GlyphHeader> ());
for (auto &_ : glyph_header.get_composite_iterator (dest_glyph))
{
_fix_component_gids (plan, dest_glyph);
if (plan->drop_hints)
{
_zero_instruction_length (dest_glyph);
c->check_success (_remove_composite_instruction_flag (dest_glyph));
}
hb_codepoint_t new_gid;
if (plan->new_gid_for_old_gid (_.glyphIndex, &new_gid))
((OT::glyf::CompositeGlyphHeader *) &_)->glyphIndex = new_gid;
}
if (plan->drop_hints) glyph_header.drop_hints (dest_glyph);
return_trace (true);
}

View File

@ -45,7 +45,9 @@ _add_gid_and_children (const OT::glyf::accelerator_t &glyf,
hb_set_add (gids_to_retain, gid);
for (auto &item : OT::glyf::get_composite_iterator (glyf.bytes_for_glyph (gid)))
hb_bytes_t glyph_bytes = glyf.bytes_for_glyph (gid);
const OT::glyf::GlyphHeader &glyph_header = *glyph_bytes.as<OT::glyf::GlyphHeader> ();
for (auto &item : glyph_header.get_composite_iterator (glyph_bytes))
_add_gid_and_children (glyf, item.glyphIndex, gids_to_retain);
}