Index: third_party/harfbuzz-ng/src/hb-ot-font.cc |
diff --git a/third_party/harfbuzz-ng/src/hb-ot-font.cc b/third_party/harfbuzz-ng/src/hb-ot-font.cc |
index df6514dd31f1c91bf490ba9ecea2542f96fb6f6c..3102784e2cad502880d9213b7364451d878a3ff4 100644 |
--- a/third_party/harfbuzz-ng/src/hb-ot-font.cc |
+++ b/third_party/harfbuzz-ng/src/hb-ot-font.cc |
@@ -31,6 +31,8 @@ |
#include "hb-font-private.hh" |
#include "hb-ot-cmap-table.hh" |
+#include "hb-ot-glyf-table.hh" |
+#include "hb-ot-head-table.hh" |
#include "hb-ot-hhea-table.hh" |
#include "hb-ot-hmtx-table.hh" |
@@ -76,8 +78,8 @@ struct hb_ot_face_metrics_accelerator_t |
if (unlikely (glyph >= this->num_metrics)) |
{ |
/* If this->num_metrics is zero, it means we don't have the metrics table |
- * for this direction: return one EM. Otherwise, it means that the glyph |
- * index is out of bound: return zero. */ |
+ * for this direction: return default advance. Otherwise, it means that the |
+ * glyph index is out of bound: return zero. */ |
if (this->num_metrics) |
return 0; |
else |
@@ -91,6 +93,79 @@ struct hb_ot_face_metrics_accelerator_t |
} |
}; |
+struct hb_ot_face_glyf_accelerator_t |
+{ |
+ bool short_offset; |
+ unsigned int num_glyphs; |
+ const OT::loca *loca; |
+ const OT::glyf *glyf; |
+ hb_blob_t *loca_blob; |
+ hb_blob_t *glyf_blob; |
+ unsigned int glyf_len; |
+ |
+ inline void init (hb_face_t *face) |
+ { |
+ hb_blob_t *head_blob = OT::Sanitizer<OT::head>::sanitize (face->reference_table (HB_OT_TAG_head)); |
+ const OT::head *head = OT::Sanitizer<OT::head>::lock_instance (head_blob); |
+ if ((unsigned int) head->indexToLocFormat > 1 || head->glyphDataFormat != 0) |
+ { |
+ /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */ |
+ hb_blob_destroy (head_blob); |
+ return; |
+ } |
+ this->short_offset = 0 == head->indexToLocFormat; |
+ hb_blob_destroy (head_blob); |
+ |
+ this->loca_blob = OT::Sanitizer<OT::loca>::sanitize (face->reference_table (HB_OT_TAG_loca)); |
+ this->loca = OT::Sanitizer<OT::loca>::lock_instance (this->loca_blob); |
+ this->glyf_blob = OT::Sanitizer<OT::glyf>::sanitize (face->reference_table (HB_OT_TAG_glyf)); |
+ this->glyf = OT::Sanitizer<OT::glyf>::lock_instance (this->glyf_blob); |
+ |
+ this->num_glyphs = MAX (1u, hb_blob_get_length (this->loca_blob) / (this->short_offset ? 2 : 4)) - 1; |
+ this->glyf_len = hb_blob_get_length (this->glyf_blob); |
+ } |
+ |
+ inline void fini (void) |
+ { |
+ hb_blob_destroy (this->loca_blob); |
+ hb_blob_destroy (this->glyf_blob); |
+ } |
+ |
+ inline bool get_extents (hb_codepoint_t glyph, |
+ hb_glyph_extents_t *extents) const |
+ { |
+ if (unlikely (glyph >= this->num_glyphs)) |
+ return false; |
+ |
+ unsigned int start_offset, end_offset; |
+ if (this->short_offset) |
+ { |
+ start_offset = 2 * this->loca->u.shortsZ[glyph]; |
+ end_offset = 2 * this->loca->u.shortsZ[glyph + 1]; |
+ } |
+ else |
+ { |
+ start_offset = this->loca->u.longsZ[glyph]; |
+ end_offset = this->loca->u.longsZ[glyph + 1]; |
+ } |
+ |
+ if (start_offset > end_offset || end_offset > this->glyf_len) |
+ return false; |
+ |
+ if (end_offset - start_offset < OT::glyfGlyphHeader::static_size) |
+ return true; /* Empty glyph; zero extents. */ |
+ |
+ const OT::glyfGlyphHeader &glyph_header = OT::StructAtOffset<OT::glyfGlyphHeader> (this->glyf, 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; |
+ |
+ return true; |
+ } |
+}; |
+ |
struct hb_ot_face_cmap_accelerator_t |
{ |
const OT::CmapSubtable *table; |
@@ -158,14 +233,14 @@ struct hb_ot_font_t |
hb_ot_face_cmap_accelerator_t cmap; |
hb_ot_face_metrics_accelerator_t h_metrics; |
hb_ot_face_metrics_accelerator_t v_metrics; |
+ hb_ot_face_glyf_accelerator_t glyf; |
}; |
static hb_ot_font_t * |
-_hb_ot_font_create (hb_font_t *font) |
+_hb_ot_font_create (hb_face_t *face) |
{ |
hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t)); |
- hb_face_t *face = font->face; |
if (unlikely (!ot_font)) |
return NULL; |
@@ -175,6 +250,7 @@ _hb_ot_font_create (hb_font_t *font) |
ot_font->cmap.init (face); |
ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, upem>>1); |
ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, upem); /* TODO Can we do this lazily? */ |
+ ot_font->glyf.init (face); |
return ot_font; |
} |
@@ -185,6 +261,7 @@ _hb_ot_font_destroy (hb_ot_font_t *ot_font) |
ot_font->cmap.fini (); |
ot_font->h_metrics.fini (); |
ot_font->v_metrics.fini (); |
+ ot_font->glyf.fini (); |
free (ot_font); |
} |
@@ -276,8 +353,13 @@ hb_ot_get_glyph_extents (hb_font_t *font HB_UNUSED, |
hb_glyph_extents_t *extents, |
void *user_data HB_UNUSED) |
{ |
- /* TODO */ |
- return false; |
+ const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
+ bool ret = ot_font->glyf.get_extents (glyph, extents); |
+ extents->x_bearing = font->em_scale_x (extents->x_bearing); |
+ extents->y_bearing = font->em_scale_y (extents->y_bearing); |
+ extents->width = font->em_scale_x (extents->width); |
+ extents->height = font->em_scale_y (extents->height); |
+ return ret; |
} |
static hb_bool_t |
@@ -341,7 +423,7 @@ _hb_ot_get_font_funcs (void) |
void |
hb_ot_font_set_funcs (hb_font_t *font) |
{ |
- hb_ot_font_t *ot_font = _hb_ot_font_create (font); |
+ hb_ot_font_t *ot_font = _hb_ot_font_create (font->face); |
if (unlikely (!ot_font)) |
return; |