summaryrefslogtreecommitdiff
path: root/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-glyf-table.hh
diff options
context:
space:
mode:
authorAkira Kakuto <kakuto@fuk.kindai.ac.jp>2019-05-24 23:03:55 +0000
committerAkira Kakuto <kakuto@fuk.kindai.ac.jp>2019-05-24 23:03:55 +0000
commit77ba432cf7f046d3f5c29d738279e898bdd02a5c (patch)
tree92d5078972de2b02a7af1d7ef72cf99a16a441b4 /Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-glyf-table.hh
parent676d0c444418989d8c0c8d1c60ed3d52f9290c80 (diff)
harfbuzz-2.5.0
git-svn-id: svn://tug.org/texlive/trunk@51218 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-glyf-table.hh')
-rw-r--r--Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-glyf-table.hh349
1 files changed, 296 insertions, 53 deletions
diff --git a/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-glyf-table.hh b/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-glyf-table.hh
index c2b38b05bae..6113dbcf89a 100644
--- a/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-glyf-table.hh
+++ b/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-glyf-table.hh
@@ -21,7 +21,7 @@
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
- * Google Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod, Garret Rieger, Roderick Sheeter
*/
#ifndef HB_OT_GLYF_TABLE_HH
@@ -29,7 +29,6 @@
#include "hb-open-type.hh"
#include "hb-ot-head-table.hh"
-#include "hb-subset-glyf.hh"
namespace OT {
@@ -58,7 +57,7 @@ struct loca
public:
DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always
* check the size externally, allow Null() object of it by
- * defining it MIN() instead. */
+ * defining it _MIN instead. */
};
@@ -81,26 +80,169 @@ struct glyf
return_trace (true);
}
- bool subset (hb_subset_plan_t *plan) const
+ template<typename Iterator,
+ hb_requires (hb_is_source_of (Iterator, unsigned int))>
+ static bool
+ _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets)
+ {
+ unsigned int max_offset = + padded_offsets | hb_reduce (hb_max, 0);
+ unsigned num_offsets = padded_offsets.len () + 1;
+ bool use_short_loca = max_offset < 0x1FFFF;
+ unsigned entry_size = use_short_loca ? 2 : 4;
+ char *loca_prime_data = (char *) calloc (entry_size, num_offsets);
+
+ if (unlikely (!loca_prime_data)) return false;
+
+ if (use_short_loca)
+ _write_loca (padded_offsets, 1, hb_array ((HBUINT16*) loca_prime_data, num_offsets));
+ else
+ _write_loca (padded_offsets, 0, hb_array ((HBUINT32*) loca_prime_data, num_offsets));
+
+ hb_blob_t * loca_blob = hb_blob_create (loca_prime_data,
+ entry_size * num_offsets,
+ HB_MEMORY_MODE_WRITABLE,
+ loca_prime_data,
+ free);
+
+ bool result = plan->add_table (HB_OT_TAG_loca, loca_blob)
+ && _add_head_and_set_loca_version(plan, use_short_loca);
+
+ hb_blob_destroy (loca_blob);
+ return result;
+ }
+
+ template<typename IteratorIn, typename IteratorOut,
+ hb_requires (hb_is_source_of (IteratorIn, unsigned int)),
+ hb_requires (hb_is_sink_of (IteratorOut, unsigned))>
+ static void
+ _write_loca (IteratorIn it, unsigned right_shift, IteratorOut dest)
+ {
+ unsigned int offset = 0;
+ dest << 0;
+ + it
+ | hb_map ([=, &offset] (unsigned int padded_size) {
+ offset += padded_size;
+ DEBUG_MSG(SUBSET, nullptr, "loca entry offset %d", offset);
+ return offset >> right_shift;
+ })
+ | hb_sink (dest)
+ ;
+ }
+
+ // requires source of SubsetGlyph complains the identifier isn't declared
+ template <typename Iterator>
+ bool serialize(hb_serialize_context_t *c,
+ Iterator it,
+ const hb_subset_plan_t *plan)
+ {
+ TRACE_SERIALIZE (this);
+
+ + it
+ | hb_apply ([=] (const SubsetGlyph& _) { _.serialize (c, plan); })
+ ;
+
+ return_trace (true);
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+
+ glyf *glyf_prime = c->serializer->start_embed <glyf> ();
+ if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false);
+
+ // Byte region(s) per glyph to output
+ // unpadded, hints removed if so requested
+ // If we fail to process a glyph we produce an empty (0-length) glyph
+ hb_vector_t<SubsetGlyph> glyphs;
+ _populate_subset_glyphs (c->plan, &glyphs);
+
+ glyf_prime->serialize (c->serializer, hb_iter (glyphs), c->plan);
+
+ auto padded_offsets =
+ + hb_iter (glyphs)
+ | hb_map (&SubsetGlyph::padded_size)
+ ;
+
+ return_trace (c->serializer->check_success (_add_loca_and_head (c->plan, padded_offsets)));
+ }
+
+ template <typename SubsetGlyph>
+ void
+ _populate_subset_glyphs (const hb_subset_plan_t * plan,
+ hb_vector_t<SubsetGlyph> * glyphs /* OUT */) const
+ {
+ OT::glyf::accelerator_t glyf;
+ glyf.init (plan->source);
+
+ + hb_range (plan->num_output_glyphs ())
+ | hb_map ([&] (hb_codepoint_t new_gid) {
+ SubsetGlyph subset_glyph;
+ subset_glyph.new_gid = new_gid;
+
+ // 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;
+
+ subset_glyph.source_glyph = glyf.bytes_for_glyph ((const char *) this, subset_glyph.old_gid);
+ if (plan->drop_hints) subset_glyph.drop_hints (glyf);
+ else subset_glyph.dest_start = subset_glyph.source_glyph;
+
+ return subset_glyph;
+ })
+ | hb_sink (glyphs)
+ ;
+
+ glyf.fini();
+ }
+
+ static void
+ _fix_component_gids (const hb_subset_plan_t *plan,
+ hb_bytes_t glyph)
{
- hb_blob_t *glyf_prime = nullptr;
- hb_blob_t *loca_prime = nullptr;
-
- bool success = true;
- bool use_short_loca = false;
- if (hb_subset_glyf_and_loca (plan, &use_short_loca, &glyf_prime, &loca_prime)) {
- success = success && plan->add_table (HB_OT_TAG_glyf, glyf_prime);
- success = success && plan->add_table (HB_OT_TAG_loca, loca_prime);
- success = success && _add_head_and_set_loca_version (plan, use_short_loca);
- } else {
- success = false;
+ OT::glyf::CompositeGlyphHeader::Iterator iterator;
+ if (OT::glyf::CompositeGlyphHeader::get_iterator (&glyph,
+ glyph.length,
+ &iterator))
+ {
+ do
+ {
+ hb_codepoint_t new_gid;
+ if (!plan->new_gid_for_old_gid (iterator.current->glyphIndex,
+ &new_gid))
+ continue;
+ ((OT::glyf::CompositeGlyphHeader *) iterator.current)->glyphIndex = new_gid;
+ } while (iterator.move_to_next ());
}
- hb_blob_destroy (loca_prime);
- hb_blob_destroy (glyf_prime);
+ }
- return success;
+ static void
+ _zero_instruction_length (hb_bytes_t glyph)
+ {
+ const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (&glyph, 0);
+ int16_t num_contours = (int16_t) glyph_header.numberOfContours;
+ if (num_contours <= 0) return; // only for simple glyphs
+
+ const HBUINT16 &instruction_length = StructAtOffset<HBUINT16> (&glyph, GlyphHeader::static_size + 2 * num_contours);
+ (HBUINT16 &) instruction_length = 0;
}
+ static bool _remove_composite_instruction_flag (hb_bytes_t glyph)
+ {
+ const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (&glyph, 0);
+ if (glyph_header.numberOfContours >= 0) return true; // only for composites
+
+ /* remove WE_HAVE_INSTRUCTIONS from flags in dest */
+ OT::glyf::CompositeGlyphHeader::Iterator composite_it;
+ if (unlikely (!OT::glyf::CompositeGlyphHeader::get_iterator (&glyph, glyph.length, &composite_it))) return false;
+ const OT::glyf::CompositeGlyphHeader *composite_header;
+ do {
+ composite_header = composite_it.current;
+ OT::HBUINT16 *flags = const_cast<OT::HBUINT16 *> (&composite_header->flags);
+ *flags = (uint16_t) *flags & ~OT::glyf::CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS;
+ } while (composite_it.move_to_next ());
+ return true;
+}
+
static bool
_add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca)
{
@@ -112,7 +254,7 @@ struct glyf
return false;
head *head_prime = (head *) hb_blob_get_data_writable (head_prime_blob, nullptr);
- head_prime->indexToLocFormat.set (use_short_loca ? 0 : 1);
+ head_prime->indexToLocFormat = use_short_loca ? 0 : 1;
bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob);
hb_blob_destroy (head_prime_blob);
@@ -171,6 +313,7 @@ struct glyf
return size;
}
+ // TODO rewrite using new iterator framework if possible
struct Iterator
{
const char *glyph_start;
@@ -241,7 +384,7 @@ struct glyf
loca_table = hb_sanitize_context_t ().reference_table<loca> (face);
glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face);
- num_glyphs = MAX (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1;
+ num_glyphs = hb_max (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1;
}
void fini ()
@@ -283,7 +426,7 @@ struct glyf
/* based on FontTools _g_l_y_f.py::trim */
bool remove_padding (unsigned int start_offset,
- unsigned int *end_offset) const
+ unsigned int *end_offset) const
{
if (*end_offset - start_offset < GlyphHeader::static_size) return true;
@@ -381,61 +524,55 @@ 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.length < GlyphHeader::static_size)
{
- *instruction_start = 0;
- *instruction_end = 0;
- return true; /* Empty glyph; no instructions. */
+ *length = 0;
+ // only 0 byte glyphs are healthy when missing GlyphHeader
+ return glyph.length == 0;
}
- const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyf_table, start_offset);
+ const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (&glyph, 0);
int16_t num_contours = (int16_t) glyph_header.numberOfContours;
if (num_contours < 0)
{
+ unsigned int start = glyph.length;
+ unsigned int end = glyph.length;
+ unsigned int glyph_offset = &glyph - glyf_table;
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 () - glyph_offset;
+ 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;
}
+ *length = end - start;
}
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;
}
- 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
+ const HBUINT16 &instruction_length = StructAtOffset<HBUINT16> (&glyph, instruction_length_offset);
+ if (unlikely (instruction_length_offset + instruction_length > 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 = (uint16_t) instruction_length;
}
return true;
}
@@ -451,14 +588,33 @@ struct glyf
const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyf_table, start_offset);
- extents->x_bearing = MIN (glyph_header.xMin, glyph_header.xMax);
- extents->y_bearing = MAX (glyph_header.yMin, glyph_header.yMax);
- extents->width = MAX (glyph_header.xMin, glyph_header.xMax) - extents->x_bearing;
- extents->height = MIN (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing;
+ extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax);
+ 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->height = hb_min (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing;
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:
bool short_offset;
unsigned int num_glyphs;
@@ -466,12 +622,99 @@ struct glyf
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:
UnsizedArrayOf<HBUINT8> dataZ; /* Glyphs data. */
public:
DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always
* check the size externally, allow Null() object of it by
- * defining it MIN() instead. */
+ * defining it _MIN instead. */
};
struct glyf_accelerator_t : glyf::accelerator_t {};