From d73cdcf3612ae6114a0f828e0f667d447ed1a964 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sun, 6 Oct 2019 18:09:14 +0330 Subject: [PATCH 01/26] [ot-font] Apply font scaling before turning to int --- src/hb-ot-cff1-table.cc | 12 +++---- src/hb-ot-cff1-table.hh | 2 +- src/hb-ot-cff2-table.cc | 8 ++--- src/hb-ot-color-cbdt-table.hh | 14 ++++---- src/hb-ot-color-sbix-table.hh | 8 ++--- src/hb-ot-font.cc | 12 +++---- src/hb-ot-glyf-table.hh | 58 ++++++++++++++++------------------ src/hb-ot-hmtx-table.hh | 2 +- src/hb-ot-var-hvar-table.hh | 5 ++- test/api/test-ot-extents-cff.c | 20 ++++++------ 10 files changed, 66 insertions(+), 75 deletions(-) diff --git a/src/hb-ot-cff1-table.cc b/src/hb-ot-cff1-table.cc index 5e09af4e5..54bfe5dff 100644 --- a/src/hb-ot-cff1-table.cc +++ b/src/hb-ot-cff1-table.cc @@ -306,14 +306,14 @@ bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, boun return true; } -bool OT::cff1::accelerator_t::get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const +bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const { #ifdef HB_NO_OT_FONT_CFF /* XXX Remove check when this code moves to .hh file. */ return true; #endif - bounds_t bounds; + bounds_t bounds; if (!_get_bounds (this, glyph, bounds)) return false; @@ -325,8 +325,8 @@ bool OT::cff1::accelerator_t::get_extents (hb_codepoint_t glyph, hb_glyph_extent } else { - extents->x_bearing = (int32_t)bounds.min.x.floor (); - extents->width = (int32_t)bounds.max.x.ceil () - extents->x_bearing; + extents->x_bearing = font->em_scalef_x (bounds.min.x.to_real ()); + extents->width = font->em_scalef_x (bounds.max.x.to_real () - extents->x_bearing); } if (bounds.min.y >= bounds.max.y) { @@ -335,8 +335,8 @@ bool OT::cff1::accelerator_t::get_extents (hb_codepoint_t glyph, hb_glyph_extent } else { - extents->y_bearing = (int32_t)bounds.max.y.ceil (); - extents->height = (int32_t)bounds.min.y.floor () - extents->y_bearing; + extents->y_bearing = font->em_scalef_y (bounds.max.y.to_real ()); + extents->height = font->em_scalef_x (bounds.min.y.to_real () - extents->y_bearing); } return true; diff --git a/src/hb-ot-cff1-table.hh b/src/hb-ot-cff1-table.hh index cd98c4477..ad206511c 100644 --- a/src/hb-ot-cff1-table.hh +++ b/src/hb-ot-cff1-table.hh @@ -1196,7 +1196,7 @@ struct cff1 struct accelerator_t : accelerator_templ_t { - HB_INTERNAL bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; + HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const; }; diff --git a/src/hb-ot-cff2-table.cc b/src/hb-ot-cff2-table.cc index b28055036..e69070e18 100644 --- a/src/hb-ot-cff2-table.cc +++ b/src/hb-ot-cff2-table.cc @@ -125,8 +125,8 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, } else { - extents->x_bearing = (int32_t)param.min_x.floor (); - extents->width = (int32_t)param.max_x.ceil () - extents->x_bearing; + extents->x_bearing = font->em_scalef_x (param.min_x.to_real ()); + extents->width = font->em_scalef_x (param.max_x.to_real () - extents->x_bearing); } if (param.min_y >= param.max_y) { @@ -135,8 +135,8 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, } else { - extents->y_bearing = (int32_t)param.max_y.ceil (); - extents->height = (int32_t)param.min_y.floor () - extents->y_bearing; + extents->y_bearing = font->em_scalef_y (param.max_y.to_real ()); + extents->height = font->em_scalef_y (param.min_y.to_real () - extents->y_bearing); } return true; diff --git a/src/hb-ot-color-cbdt-table.hh b/src/hb-ot-color-cbdt-table.hh index 06da55600..3498d3b36 100644 --- a/src/hb-ot-color-cbdt-table.hh +++ b/src/hb-ot-color-cbdt-table.hh @@ -51,12 +51,12 @@ struct SmallGlyphMetrics return_trace (c->check_struct (this)); } - void get_extents (hb_glyph_extents_t *extents) const + void get_extents (hb_font_t *font, hb_glyph_extents_t *extents) const { - extents->x_bearing = bearingX; - extents->y_bearing = bearingY; - extents->width = width; - extents->height = - (hb_position_t) height; + extents->x_bearing = font->em_scale_x (bearingX); + extents->y_bearing = font->em_scale_y (bearingY); + extents->width = font->em_scale_x (width); + extents->height = font->em_scale_y (-height); } HBUINT8 height; @@ -424,7 +424,7 @@ struct CBDT return false; const GlyphBitmapDataFormat17& glyphFormat17 = StructAtOffset (this->cbdt, image_offset); - glyphFormat17.glyphMetrics.get_extents (extents); + glyphFormat17.glyphMetrics.get_extents (font, extents); break; } case 18: { @@ -432,7 +432,7 @@ struct CBDT return false; const GlyphBitmapDataFormat18& glyphFormat18 = StructAtOffset (this->cbdt, image_offset); - glyphFormat18.glyphMetrics.get_extents (extents); + glyphFormat18.glyphMetrics.get_extents (font, extents); break; } default: diff --git a/src/hb-ot-color-sbix-table.hh b/src/hb-ot-color-sbix-table.hh index 6089027f8..6008e7e3d 100644 --- a/src/hb-ot-color-sbix-table.hh +++ b/src/hb-ot-color-sbix-table.hh @@ -243,10 +243,10 @@ struct sbix if (strike_ppem) { float scale = font->face->get_upem () / (float) strike_ppem; - extents->x_bearing = roundf (extents->x_bearing * scale); - extents->y_bearing = roundf (extents->y_bearing * scale); - extents->width = roundf (extents->width * scale); - extents->height = roundf (extents->height * scale); + extents->x_bearing = font->em_scalef_x (extents->x_bearing * scale); + extents->y_bearing = font->em_scalef_y (extents->y_bearing * scale); + extents->width = font->em_scalef_x (extents->width * scale); + extents->height = font->em_scalef_y (extents->height * scale); } hb_blob_destroy (blob); diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc index 303cd4c68..6924955ba 100644 --- a/src/hb-ot-font.cc +++ b/src/hb-ot-font.cc @@ -164,7 +164,7 @@ hb_ot_get_glyph_v_origin (hb_font_t *font, { const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx; hb_position_t tsb = vmtx.get_side_bearing (font, glyph); - *y = font->em_scale_y (extents.y_bearing + tsb); + *y = extents.y_bearing + font->em_scale_y (tsb); return true; } @@ -190,7 +190,7 @@ hb_ot_get_glyph_extents (hb_font_t *font, #endif if (!ret) ret = ot_face->glyf->get_extents (font, glyph, extents); #ifndef HB_NO_OT_FONT_CFF - if (!ret) ret = ot_face->cff1->get_extents (glyph, extents); + if (!ret) ret = ot_face->cff1->get_extents (font, glyph, extents); if (!ret) ret = ot_face->cff2->get_extents (font, glyph, extents); #endif #if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR) @@ -198,10 +198,6 @@ hb_ot_get_glyph_extents (hb_font_t *font, #endif // TODO Hook up side-bearings variations. - 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; } @@ -319,13 +315,13 @@ hb_ot_font_set_funcs (hb_font_t *font) int hb_ot_get_side_bearing_var_tt (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical) { - return font->face->table.glyf->get_side_bearing_var (glyph, font->coords, font->num_coords, is_vertical); + return font->face->table.glyf->get_side_bearing_var (font, glyph, is_vertical); } unsigned hb_ot_get_advance_var_tt (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical) { - return font->face->table.glyf->get_advance_var (glyph, font->coords, font->num_coords, is_vertical); + return font->face->table.glyf->get_advance_var (font, glyph, is_vertical); } #endif diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index 48ee387c6..0443ea01f 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -803,13 +803,12 @@ struct glyf return true; } - bool get_var_extents_and_phantoms (hb_codepoint_t glyph, - const int *coords, unsigned int coord_count, - hb_glyph_extents_t *extents=nullptr /* OUt */, + bool get_var_extents_and_phantoms (hb_font_t *font, hb_codepoint_t glyph, + hb_glyph_extents_t *extents=nullptr /* OUT */, contour_point_vector_t *phantoms=nullptr /* OUT */) const { contour_point_vector_t all_points; - if (unlikely (!get_points_var (glyph, coords, coord_count, all_points) || + if (unlikely (!get_points_var (glyph, font->coords, font->num_coords, all_points) || all_points.length < PHANTOM_COUNT)) return false; /* Undocumented rasterizer behavior: @@ -832,8 +831,8 @@ struct glyf } else { - extents->x_bearing = (int) floor (bounds.min.x); - extents->width = (int) ceil (bounds.max.x) - extents->x_bearing; + extents->x_bearing = font->em_scalef_x (bounds.min.x); + extents->width = font->em_scalef_x (bounds.max.x) - extents->x_bearing; } if (bounds.min.y > bounds.max.y) { @@ -842,8 +841,8 @@ struct glyf } else { - extents->y_bearing = (int) ceil (bounds.max.y); - extents->height = (int) floor (bounds.min.y) - extents->y_bearing; + extents->y_bearing = font->em_scalef_y (bounds.max.y); + extents->height = font->em_scalef_y (bounds.min.y) - extents->y_bearing; } } if (phantoms != nullptr) @@ -854,15 +853,13 @@ struct glyf return true; } - bool get_var_metrics (hb_codepoint_t glyph, - const int *coords, unsigned int coord_count, + bool get_var_metrics (hb_font_t *font, hb_codepoint_t glyph, contour_point_vector_t &phantoms) const - { return get_var_extents_and_phantoms (glyph, coords, coord_count, nullptr, &phantoms); } + { return get_var_extents_and_phantoms (font, glyph, nullptr, &phantoms); } - bool get_extents_var (hb_codepoint_t glyph, - const int *coords, unsigned int coord_count, + bool get_extents_var (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const - { return get_var_extents_and_phantoms (glyph, coords, coord_count, extents); } + { return get_var_extents_and_phantoms (font, glyph, extents); } #endif public: @@ -966,36 +963,35 @@ struct glyf } #ifndef HB_NO_VAR - unsigned int get_advance_var (hb_codepoint_t glyph, - const int *coords, unsigned int coord_count, - bool vertical) const + unsigned int get_advance_var (hb_font_t *font, hb_codepoint_t glyph, + bool is_vertical) const { bool success = false; contour_point_vector_t phantoms; phantoms.resize (PHANTOM_COUNT); - if (likely (coord_count == face->table.gvar->get_axis_count ())) - success = get_var_metrics (glyph, coords, coord_count, phantoms); + if (likely (font->num_coords == face->table.gvar->get_axis_count ())) + success = get_var_metrics (font, glyph, phantoms); if (unlikely (!success)) - return vertical ? face->table.vmtx->get_advance (glyph) : face->table.hmtx->get_advance (glyph); + return is_vertical ? face->table.vmtx->get_advance (glyph) : face->table.hmtx->get_advance (glyph); - if (vertical) + if (is_vertical) return roundf (phantoms[PHANTOM_TOP].y - phantoms[PHANTOM_BOTTOM].y); else return roundf (phantoms[PHANTOM_RIGHT].x - phantoms[PHANTOM_LEFT].x); } - int get_side_bearing_var (hb_codepoint_t glyph, const int *coords, unsigned int coord_count, bool vertical) const + int get_side_bearing_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical) const { hb_glyph_extents_t extents; - contour_point_vector_t phantoms; + contour_point_vector_t phantoms; phantoms.resize (PHANTOM_COUNT); - if (unlikely (!get_var_extents_and_phantoms (glyph, coords, coord_count, &extents, &phantoms))) - return vertical ? face->table.vmtx->get_side_bearing (glyph) : face->table.hmtx->get_side_bearing (glyph); + if (unlikely (!get_var_extents_and_phantoms (font, glyph, &extents, &phantoms))) + return is_vertical ? face->table.vmtx->get_side_bearing (glyph) : face->table.hmtx->get_side_bearing (glyph); - return vertical ? ceil (phantoms[PHANTOM_TOP].y) - extents.y_bearing : floor (phantoms[PHANTOM_LEFT].x); + return is_vertical ? ceil (phantoms[PHANTOM_TOP].y) - extents.y_bearing : floor (phantoms[PHANTOM_LEFT].x); } #endif @@ -1005,7 +1001,7 @@ struct glyf unsigned int coord_count; const int *coords = hb_font_get_var_coords_normalized (font, &coord_count); if (coords && coord_count > 0 && coord_count == face->table.gvar->get_axis_count ()) - return get_extents_var (glyph, coords, coord_count, extents); + return get_extents_var (font, glyph, extents); #endif unsigned int start_offset, end_offset; @@ -1019,10 +1015,10 @@ struct glyf /* Undocumented rasterizer behavior: shift glyph to the left by (lsb - xMin), i.e., xMin = lsb */ /* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */ - extents->x_bearing = face->table.hmtx->get_side_bearing (glyph); - extents->y_bearing = hb_max (glyph_header.yMin, glyph_header.yMax); - extents->width = hb_max (glyph_header.xMin, glyph_header.xMax) - hb_min (glyph_header.xMin, glyph_header.xMax); - extents->height = hb_min (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing; + extents->x_bearing = font->em_scale_x (face->table.hmtx->get_side_bearing (glyph)); + extents->y_bearing = font->em_scale_x (hb_max (glyph_header.yMin, glyph_header.yMax)); + extents->width = font->em_scale_x (hb_max (glyph_header.xMin, glyph_header.xMax) - hb_min (glyph_header.xMin, glyph_header.xMax)); + extents->height = font->em_scale_x (hb_min (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing); return true; } diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh index 9d179330c..ce8f261bc 100644 --- a/src/hb-ot-hmtx-table.hh +++ b/src/hb-ot-hmtx-table.hh @@ -252,7 +252,7 @@ struct hmtxvmtx if (var_table.get_blob () == &Null (hb_blob_t)) return hb_ot_get_advance_var_tt (font, glyph, T::tableTag == HB_OT_TAG_vmtx); - return advance + roundf (var_table->get_advance_var (glyph, font->coords, font->num_coords)); // TODO Optimize?! + return advance + roundf (var_table->get_advance_var (font, glyph)); // TODO Optimize?! #else return advance; #endif diff --git a/src/hb-ot-var-hvar-table.hh b/src/hb-ot-var-hvar-table.hh index ba1f2dac2..223430fb8 100644 --- a/src/hb-ot-var-hvar-table.hh +++ b/src/hb-ot-var-hvar-table.hh @@ -114,11 +114,10 @@ struct HVARVVAR rsbMap.sanitize (c, this)); } - float get_advance_var (hb_codepoint_t glyph, - const int *coords, unsigned int coord_count) const + float get_advance_var (hb_font_t *font, hb_codepoint_t glyph) const { unsigned int varidx = (this+advMap).map (glyph); - return (this+varStore).get_delta (varidx, coords, coord_count); + return (this+varStore).get_delta (varidx, font->coords, font->num_coords); } float get_side_bearing_var (hb_codepoint_t glyph, diff --git a/test/api/test-ot-extents-cff.c b/test/api/test-ot-extents-cff.c index 6810ea457..e6aeb0d6e 100644 --- a/test/api/test-ot-extents-cff.c +++ b/test/api/test-ot-extents-cff.c @@ -146,8 +146,8 @@ test_extents_cff2 (void) g_assert_cmpint (extents.x_bearing, ==, 38); g_assert_cmpint (extents.y_bearing, ==, 493); - g_assert_cmpint (extents.width, ==, 481); - g_assert_cmpint (extents.height, ==, -508); + g_assert_cmpint (extents.width, ==, 480); + g_assert_cmpint (extents.height, ==, -507); hb_font_destroy (font); } @@ -168,17 +168,17 @@ test_extents_cff2_vsindex (void) hb_bool_t result = hb_font_get_glyph_extents (font, 1, &extents); g_assert (result); - g_assert_cmpint (extents.x_bearing, ==, 11); - g_assert_cmpint (extents.y_bearing, ==, 656); - g_assert_cmpint (extents.width, ==, 653); - g_assert_cmpint (extents.height, ==, -656); + g_assert_cmpint (extents.x_bearing, ==, 12); + g_assert_cmpint (extents.y_bearing, ==, 655); + g_assert_cmpint (extents.width, ==, 651); + g_assert_cmpint (extents.height, ==, -655); result = hb_font_get_glyph_extents (font, 2, &extents); g_assert (result); - g_assert_cmpint (extents.x_bearing, ==, 7); + g_assert_cmpint (extents.x_bearing, ==, 8); g_assert_cmpint (extents.y_bearing, ==, 669); - g_assert_cmpint (extents.width, ==, 650); + g_assert_cmpint (extents.width, ==, 648); g_assert_cmpint (extents.height, ==, -669); hb_font_destroy (font); @@ -199,9 +199,9 @@ test_extents_cff2_vsindex_named_instance (void) hb_bool_t result = hb_font_get_glyph_extents (font, 1, &extents); g_assert (result); - g_assert_cmpint (extents.x_bearing, ==, 12); + g_assert_cmpint (extents.x_bearing, ==, 13); g_assert_cmpint (extents.y_bearing, ==, 652); - g_assert_cmpint (extents.width, ==, 653); + g_assert_cmpint (extents.width, ==, 652); g_assert_cmpint (extents.height, ==, -652); result = hb_font_get_glyph_extents (font, 2, &extents); From 5179b96958f2db71c315c1d8c224bab87e2f4ae8 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Tue, 8 Oct 2019 11:09:12 +0330 Subject: [PATCH 02/26] [cff] minor on number_t --- src/hb-cff-interp-common.hh | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/hb-cff-interp-common.hh b/src/hb-cff-interp-common.hh index fdc5c683a..780f61892 100644 --- a/src/hb-cff-interp-common.hh +++ b/src/hb-cff-interp-common.hh @@ -220,18 +220,15 @@ struct number_t void init () { set_real (0.0); } void fini () {} - void set_int (int v) { value = (double) v; } - int to_int () const { return (int) value; } + void set_int (int v) { value = v; } + int to_int () const { return value; } void set_fixed (int32_t v) { value = v / 65536.0; } - int32_t to_fixed () const { return (int32_t) (value * 65536.0); } + int32_t to_fixed () const { return value * 65536.0; } void set_real (double v) { value = v; } double to_real () const { return value; } - int ceil () const { return (int) ::ceil (value); } - int floor () const { return (int) ::floor (value); } - bool in_int_range () const { return ((double) (int16_t) to_int () == value); } @@ -248,7 +245,7 @@ struct number_t } protected: - double value; + double value; }; /* byte string */ From 13fb5612ad545b419ca217f031864dde1b71c43f Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sun, 6 Oct 2019 23:24:06 +0330 Subject: [PATCH 03/26] [glyf] Aggregate get_offsets uses --- src/hb-ot-glyf-table.hh | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index 0443ea01f..0820bc60a 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -570,15 +570,6 @@ struct glyf }; protected: - const GlyphHeader &get_header (hb_codepoint_t glyph) const - { - unsigned int start_offset, end_offset; - if (!get_offsets (glyph, &start_offset, &end_offset) || end_offset - start_offset < GlyphHeader::static_size) - return Null (GlyphHeader); - - return StructAtOffset (glyf_table, start_offset); - } - struct x_setter_t { void set (contour_point_t &point, float v) const { point.x = v; } @@ -627,7 +618,7 @@ struct glyf void init_phantom_points (hb_codepoint_t glyph, hb_array_t &phantoms /* IN/OUT */) const { - const GlyphHeader &header = get_header (glyph); + const GlyphHeader &header = *bytes_for_glyph (glyph).as (); int h_delta = (int) header.xMin - face->table.hmtx->get_side_bearing (glyph); int v_orig = (int) header.yMax + face->table.vmtx->get_side_bearing (glyph); unsigned int h_adv = face->table.hmtx->get_advance (glyph); @@ -673,7 +664,7 @@ struct glyf points_.resize (num_points + PHANTOM_COUNT); for (unsigned int i = 0; i < points_.length; i++) points_[i].init (); - if (!glyph_header.is_simple_glyph () || phantom_only) return true; + if (phantom_only) return true; /* Read simple glyph points if !phantom_only */ end_points_.resize (num_contours); @@ -749,10 +740,7 @@ struct glyf if (unlikely (!face->table.gvar->apply_deltas_to_points (glyph, coords, coord_count, points.as_array (), end_points.as_array ()))) return false; unsigned int comp_index = 0; - unsigned int start_offset, end_offset; - if (unlikely (!get_offsets (glyph, &start_offset, &end_offset))) return false; - hb_bytes_t bytes ((const char *) this->glyf_table + start_offset, - end_offset - start_offset); + hb_bytes_t bytes = bytes_for_glyph (glyph); const GlyphHeader &glyph_header = *bytes.as (); if (glyph_header.is_simple_glyph ()) all_points.extend (points.as_array ()); @@ -1004,15 +992,12 @@ struct glyf return get_extents_var (font, glyph, extents); #endif - unsigned int start_offset, end_offset; - if (!get_offsets (glyph, &start_offset, &end_offset)) - return false; + if (unlikely (glyph >= num_glyphs)) return false; - if (end_offset - start_offset < GlyphHeader::static_size) + const GlyphHeader &glyph_header = *bytes_for_glyph (glyph).as (); + if (unlikely (!glyph_header.has_data ())) return true; /* Empty glyph; zero extents. */ - const GlyphHeader &glyph_header = StructAtOffset (glyf_table, start_offset); - /* Undocumented rasterizer behavior: shift glyph to the left by (lsb - xMin), i.e., xMin = lsb */ /* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */ extents->x_bearing = font->em_scale_x (face->table.hmtx->get_side_bearing (glyph)); @@ -1030,7 +1015,7 @@ struct glyf if (unlikely (!get_offsets (gid, &start_offset, &end_offset))) return hb_bytes_t (); - /* couldn't remove padding, needed for subset */ + /* Remove padding, needed for subset */ if (needs_padding_removal) if (unlikely (!remove_padding (start_offset, &end_offset))) return hb_bytes_t (); From 1ab8f9aa7a182fa078f6c6a5a78ef95686b1ac54 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Mon, 7 Oct 2019 08:24:12 +0330 Subject: [PATCH 04/26] [glyf] minor --- src/hb-ot-glyf-table.hh | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index 0820bc60a..6d5992cf2 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -226,7 +226,7 @@ struct glyf const GlyphHeader &glyph_header = *glyph.as (); if (!glyph_header.is_simple_glyph ()) return; // only for simple glyphs - unsigned int instruction_len_offset = GlyphHeader::SimpleHeader (glyph_header).instruction_len_offset (); + unsigned int instruction_len_offset = glyph_header.as_simple ().instruction_len_offset (); const HBUINT16 &instruction_len = StructAtOffset (&glyph, instruction_len_offset); (HBUINT16 &) instruction_len = 0; } @@ -297,7 +297,7 @@ struct glyf const GlyphHeader &header; CompositeHeader (const GlyphHeader &header_) : header (header_) {} - bool get_instruction_length (hb_bytes_t glyph, unsigned int *length) + bool get_instruction_length (hb_bytes_t glyph, unsigned int *length) const { unsigned int start = glyph.length; unsigned int end = glyph.length; @@ -314,6 +314,9 @@ struct glyf } }; + 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 @@ -327,8 +330,8 @@ struct glyf { switch (get_type ()) { - case COMPOSITE: return CompositeHeader (*this).get_instruction_length (glyph, length); - case SIMPLE: return SimpleHeader (*this).get_instruction_length (glyph, length); + 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 */ } @@ -495,7 +498,7 @@ struct glyf if (!(current->flags & CompositeGlyphHeader::MORE_COMPONENTS)) { current = nullptr; return; } const CompositeGlyphHeader *possible = &StructAfter (*current); + CompositeGlyphHeader> (*current); if (!in_range (possible)) { current = nullptr; return; } current = possible; } @@ -868,7 +871,7 @@ struct glyf else { /* simple glyph w/contours, possibly trimmable */ - glyph += GlyphHeader::SimpleHeader (glyph_header).instruction_len_offset (); + glyph += glyph_header.as_simple ().instruction_len_offset (); if (unlikely (glyph + 2 >= glyph_end)) return false; uint16_t nCoordinates = (uint16_t) StructAtOffset (glyph - 2, 0) + 1; From cbefbb2439c1a2f4c20877e611f8986b3933234e Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Mon, 7 Oct 2019 10:15:18 +0330 Subject: [PATCH 05/26] [glyf] Move padding removal logic to GlyphHeader --- src/hb-ot-glyf-table.hh | 219 +++++++++++++++++++--------------------- 1 file changed, 105 insertions(+), 114 deletions(-) diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index 6d5992cf2..0250c2cac 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -290,6 +290,70 @@ struct glyf *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 + { + unsigned int end_offset = glyph_bytes.length; + /* 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 nCoordinates = StructAtOffset (glyph - 2, 0) + 1; + unsigned int nInstructions = StructAtOffset (glyph, 0); + + glyph += 2 + nInstructions; + if (unlikely (glyph + 2 >= glyph_end)) return hb_bytes_t (); + + unsigned int coordBytes = 0; + unsigned int coordsWithFlags = 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; + + coordBytes += (xBytes + yBytes) * repeat; + coordsWithFlags += repeat; + if (coordsWithFlags >= nCoordinates) break; + } + + if (unlikely (coordsWithFlags != nCoordinates)) return hb_bytes_t (); + glyph += coordBytes; + + if (glyph < glyph_end) + end_offset -= glyph_end - glyph; + return glyph_bytes.sub_array (0, end_offset); + } }; struct CompositeHeader @@ -312,6 +376,11 @@ struct glyf *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); } @@ -337,6 +406,17 @@ struct glyf } } + 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; } @@ -656,10 +736,7 @@ struct glyf else if (glyph_header.is_simple_glyph ()) { const HBUINT16 *end_pts = &StructAfter (glyph_header); - - unsigned int start_offset, end_offset; - if (unlikely (!get_offsets (glyph, &start_offset, &end_offset))) return false; - range_checker_t checker (glyf_table, start_offset, end_offset); + range_checker_t checker (bytes.arrayZ, 0, bytes.length); num_points = 0; int num_contours = glyph_header.numberOfContours; if (unlikely (!checker.in_range (&end_pts[num_contours + 1]))) return false; @@ -854,105 +931,6 @@ struct glyf #endif public: - /* based on FontTools _g_l_y_f.py::trim */ - bool remove_padding (unsigned int start_offset, - unsigned int *end_offset) const - { - unsigned int glyph_length = *end_offset - start_offset; - const char *glyph = ((const char *) glyf_table) + start_offset; - const GlyphHeader &glyph_header = *hb_bytes_t (glyph, glyph_length).as (); - if (!glyph_header.has_data ()) return true; - - const char *glyph_end = glyph + glyph_length; - if (glyph_header.is_composite_glyph ()) - /* Trimming for composites not implemented. - * If removing hints it falls out of that. */ - return true; - else - { - /* simple glyph w/contours, possibly trimmable */ - glyph += glyph_header.as_simple ().instruction_len_offset (); - - if (unlikely (glyph + 2 >= glyph_end)) return false; - uint16_t nCoordinates = (uint16_t) StructAtOffset (glyph - 2, 0) + 1; - uint16_t nInstructions = (uint16_t) StructAtOffset (glyph, 0); - - glyph += 2 + nInstructions; - if (unlikely (glyph + 2 >= glyph_end)) return false; - - unsigned int coordBytes = 0; - unsigned int coordsWithFlags = 0; - while (glyph < glyph_end) - { - uint8_t flag = (uint8_t) *glyph; - glyph++; - - unsigned int repeat = 1; - if (flag & FLAG_REPEAT) - { - if (glyph >= glyph_end) - { - DEBUG_MSG (SUBSET, nullptr, "Bad flag"); - return false; - } - repeat = ((uint8_t) *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; - - coordBytes += (xBytes + yBytes) * repeat; - coordsWithFlags += repeat; - if (coordsWithFlags >= nCoordinates) - break; - } - - if (coordsWithFlags != nCoordinates) - { - DEBUG_MSG (SUBSET, nullptr, "Expect %d coords to have flags, got flags for %d", - nCoordinates, coordsWithFlags); - return false; - } - glyph += coordBytes; - - if (glyph < glyph_end) - *end_offset -= glyph_end - glyph; - } - return true; - } - - bool get_offsets (hb_codepoint_t glyph, - unsigned int *start_offset /* OUT */, - unsigned int *end_offset /* OUT */) const - { - if (unlikely (glyph >= num_glyphs)) return false; - - if (short_offset) - { - const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ; - *start_offset = 2 * offsets[glyph]; - *end_offset = 2 * offsets[glyph + 1]; - } - else - { - const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ; - - *start_offset = offsets[glyph]; - *end_offset = offsets[glyph + 1]; - } - - if (*start_offset > *end_offset || *end_offset > glyf_table.get_length ()) - return false; - - return true; - } - #ifndef HB_NO_VAR unsigned int get_advance_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical) const @@ -1015,22 +993,35 @@ struct glyf bool needs_padding_removal = false) const { unsigned int start_offset, end_offset; - if (unlikely (!get_offsets (gid, &start_offset, &end_offset))) + if (unlikely (gid >= num_glyphs)) return hb_bytes_t (); + + if (short_offset) + { + const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ; + start_offset = 2 * offsets[gid]; + end_offset = 2 * offsets[gid + 1]; + } + else + { + const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ; + start_offset = offsets[gid]; + end_offset = offsets[gid + 1]; + } + + if (unlikely (start_offset > end_offset || end_offset > glyf_table.get_length ())) return hb_bytes_t (); - /* Remove padding, needed for subset */ - if (needs_padding_removal) - if (unlikely (!remove_padding (start_offset, &end_offset))) - return hb_bytes_t (); + hb_bytes_t glyph_bytes ((const char *) this->glyf_table + start_offset, + end_offset - start_offset); - hb_bytes_t glyph_bytes = hb_bytes_t ((const char *) this->glyf_table + start_offset, - end_offset - start_offset); + const GlyphHeader &glyph_header = *glyph_bytes.as (); - /* Glyph size smaller than minimum header */ - if (!glyph_bytes.as ()->has_data ()) - return hb_bytes_t (); + /* Empty glyph or its size is smaller than minimum header */ + if (!glyph_header.has_data ()) return hb_bytes_t (); + + if (!needs_padding_removal) return glyph_bytes; - return glyph_bytes; + return glyph_header.bytes_without_padding (glyph_bytes); } private: From 7839e23558344f206175b5a798149e0f04f38266 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Mon, 7 Oct 2019 11:14:26 +0330 Subject: [PATCH 06/26] [glyf] minor --- src/hb-ot-glyf-table.hh | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index 0250c2cac..f48173013 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -305,22 +305,21 @@ struct glyf hb_bytes_t bytes_without_padding (hb_bytes_t glyph_bytes) const { - unsigned int end_offset = glyph_bytes.length; - /* based on FontTools _g_l_y_f.py::trim */ - const char *glyph = glyph_bytes.arrayZ; - const char *glyph_end = glyph + glyph_bytes.length; + /* 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 nCoordinates = StructAtOffset (glyph - 2, 0) + 1; - unsigned int nInstructions = StructAtOffset (glyph, 0); + unsigned int num_coordinates = StructAtOffset (glyph - 2, 0) + 1; + unsigned int num_instructions = StructAtOffset (glyph, 0); - glyph += 2 + nInstructions; + glyph += 2 + num_instructions; if (unlikely (glyph + 2 >= glyph_end)) return hb_bytes_t (); - unsigned int coordBytes = 0; - unsigned int coordsWithFlags = 0; + unsigned int coord_bytes = 0; + unsigned int coords_with_flags = 0; while (glyph < glyph_end) { uint8_t flag = *glyph; @@ -342,17 +341,13 @@ struct glyf if (flag & FLAG_Y_SHORT) yBytes = 1; else if ((flag & FLAG_Y_SAME) == 0) yBytes = 2; - coordBytes += (xBytes + yBytes) * repeat; - coordsWithFlags += repeat; - if (coordsWithFlags >= nCoordinates) break; + coord_bytes += (xBytes + yBytes) * repeat; + coords_with_flags += repeat; + if (coords_with_flags >= num_coordinates) break; } - if (unlikely (coordsWithFlags != nCoordinates)) return hb_bytes_t (); - glyph += coordBytes; - - if (glyph < glyph_end) - end_offset -= glyph_end - glyph; - return glyph_bytes.sub_array (0, end_offset); + 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)); } }; @@ -380,7 +375,7 @@ struct glyf /* 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; } + { return glyph_bytes; } }; const SimpleHeader as_simple () const { return SimpleHeader (*this); } @@ -913,11 +908,9 @@ struct glyf extents->height = font->em_scalef_y (bounds.min.y) - extents->y_bearing; } } - if (phantoms != nullptr) - { + if (phantoms) for (unsigned int i = 0; i < PHANTOM_COUNT; i++) (*phantoms)[i] = all_points[all_points.length - PHANTOM_COUNT + i]; - } return true; } @@ -1032,7 +1025,6 @@ struct glyf hb_face_t *face; }; - struct SubsetGlyph { hb_codepoint_t new_gid; From ad86806dcb702b25fac6a3364cf0f85e1b8f4b2a Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Tue, 8 Oct 2019 12:14:14 +0330 Subject: [PATCH 07/26] [glyf] Move subset related methods inside GlyphHeader --- src/hb-ot-glyf-table.hh | 428 ++++++++++++++++++++-------------------- src/hb-subset-plan.cc | 4 +- 2 files changed, 214 insertions(+), 218 deletions(-) diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index f48173013..e7e9dad8f 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -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 (); - 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 (&glyph, instruction_len_offset); - (HBUINT16 &) instruction_len = 0; - } - - static bool _remove_composite_instruction_flag (hb_bytes_t glyph) - { - const GlyphHeader &glyph_header = *glyph.as (); - 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 (&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 (&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 (glyph - 2, 0) + 1; - unsigned int num_instructions = StructAtOffset (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,13 +388,207 @@ struct glyf __item_t__ current; }; - static composite_iter_t get_composite_iterator (hb_bytes_t glyph) + struct GlyphHeader { - const GlyphHeader &glyph_header = *glyph.as (); - 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 (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 (&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 (glyph - 2, 0) + 1; + unsigned int num_instructions = StructAtOffset (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 (header); + (HBUINT16 &) StructAtOffset (&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 (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 (&_.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 { @@ -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 (dest_glyph.as ()); + 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); } diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index 6851f68f6..9a52c55e2 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -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 (); + for (auto &item : glyph_header.get_composite_iterator (glyph_bytes)) _add_gid_and_children (glyf, item.glyphIndex, gids_to_retain); } From c7621cf21115aa563ee4fb9d2fcb601984848494 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Tue, 8 Oct 2019 13:24:26 +0330 Subject: [PATCH 08/26] Minor, replace hb_set_add with private API --- src/hb-ot-map.cc | 2 +- src/hb-subset-cff-common.hh | 2 +- src/hb-subset-cff1.cc | 2 +- src/hb-subset-cff2.cc | 2 +- src/hb-subset-plan.cc | 10 +++++----- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc index d40c67af9..e4bb4b636 100644 --- a/src/hb-ot-map.cc +++ b/src/hb-ot-map.cc @@ -38,7 +38,7 @@ void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_out) const { for (unsigned int i = 0; i < lookups[table_index].length; i++) - hb_set_add (lookups_out, lookups[table_index][i].index); + lookups_out->add (lookups[table_index][i].index); } diff --git a/src/hb-subset-cff-common.hh b/src/hb-subset-cff-common.hh index 7388f4fd4..3c6611960 100644 --- a/src/hb-subset-cff-common.hh +++ b/src/hb-subset-cff-common.hh @@ -916,7 +916,7 @@ struct subr_subsetter_t hb_set_t *closure, const subr_subset_param_t ¶m) { - hb_set_add (closure, subr_num); + closure->add (subr_num); collect_subr_refs_in_str (subrs[subr_num], param); } diff --git a/src/hb-subset-cff1.cc b/src/hb-subset-cff1.cc index 21bd97fbb..e9e075749 100644 --- a/src/hb-subset-cff1.cc +++ b/src/hb-subset-cff1.cc @@ -389,7 +389,7 @@ struct cff1_cs_opset_subr_subset_t : cff1_cs_opset_tadd_call_op (op, str_ref, env.context.subr_num); - hb_set_add (closure, env.context.subr_num); + closure->add (env.context.subr_num); param.set_current_str (env, true); } diff --git a/src/hb-subset-cff2.cc b/src/hb-subset-cff2.cc index 9bdd0ee7d..7edc3f515 100644 --- a/src/hb-subset-cff2.cc +++ b/src/hb-subset-cff2.cc @@ -219,7 +219,7 @@ struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_tadd_call_op (op, str_ref, env.context.subr_num); - hb_set_add (closure, env.context.subr_num); + closure->add (env.context.subr_num); param.set_current_str (env, true); } diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index 9a52c55e2..147d7f076 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -43,7 +43,7 @@ _add_gid_and_children (const OT::glyf::accelerator_t &glyf, // Already visited this gid, ignore. return; - hb_set_add (gids_to_retain, gid); + gids_to_retain->add (gid); hb_bytes_t glyph_bytes = glyf.bytes_for_glyph (gid); const OT::glyf::GlyphHeader &glyph_header = *glyph_bytes.as (); @@ -54,14 +54,14 @@ _add_gid_and_children (const OT::glyf::accelerator_t &glyf, #ifndef HB_NO_SUBSET_CFF static inline void _add_cff_seac_components (const OT::cff1::accelerator_t &cff, - hb_codepoint_t gid, - hb_set_t *gids_to_retain) + hb_codepoint_t gid, + hb_set_t *gids_to_retain) { hb_codepoint_t base_gid, accent_gid; if (cff.get_seac_components (gid, &base_gid, &accent_gid)) { - hb_set_add (gids_to_retain, base_gid); - hb_set_add (gids_to_retain, accent_gid); + gids_to_retain->add (base_gid); + gids_to_retain->add (accent_gid); } } #endif From be0eddd41896824cb093024c2b4929b612ee1fae Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Tue, 8 Oct 2019 13:46:55 +0330 Subject: [PATCH 09/26] [glyf] Move add_gid_and_children to glyf table --- src/hb-ot-glyf-table.hh | 14 ++++++++++++++ src/hb-subset-plan.cc | 19 +------------------ 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index e7e9dad8f..124a7d7b0 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -1008,6 +1008,20 @@ struct glyf return glyph_header.bytes_without_padding (glyph_bytes); } + void + add_gid_and_children (hb_codepoint_t gid, hb_set_t *gids_to_retain) const + { + /* Check if is already visited */ + if (gids_to_retain->has (gid)) return; + + gids_to_retain->add (gid); + + hb_bytes_t glyph_bytes = bytes_for_glyph (gid); + const GlyphHeader &glyph_header = *glyph_bytes.as (); + for (auto &item : glyph_header.get_composite_iterator (glyph_bytes)) + add_gid_and_children (item.glyphIndex, gids_to_retain); + } + private: bool short_offset; unsigned int num_glyphs; diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index 147d7f076..e537772c0 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -34,23 +34,6 @@ #include "hb-ot-var-fvar-table.hh" #include "hb-ot-stat-table.hh" -static inline void -_add_gid_and_children (const OT::glyf::accelerator_t &glyf, - hb_codepoint_t gid, - hb_set_t *gids_to_retain) -{ - if (gids_to_retain->has (gid)) - // Already visited this gid, ignore. - return; - - gids_to_retain->add (gid); - - hb_bytes_t glyph_bytes = glyf.bytes_for_glyph (gid); - const OT::glyf::GlyphHeader &glyph_header = *glyph_bytes.as (); - for (auto &item : glyph_header.get_composite_iterator (glyph_bytes)) - _add_gid_and_children (glyf, item.glyphIndex, gids_to_retain); -} - #ifndef HB_NO_SUBSET_CFF static inline void _add_cff_seac_components (const OT::cff1::accelerator_t &cff, @@ -147,7 +130,7 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, hb_codepoint_t gid = HB_SET_VALUE_INVALID; while (plan->_glyphset_gsub->next (&gid)) { - _add_gid_and_children (glyf, gid, plan->_glyphset); + glyf.add_gid_and_children (gid, plan->_glyphset); #ifndef HB_NO_SUBSET_CFF if (cff.is_valid ()) _add_cff_seac_components (cff, gid, plan->_glyphset); From 1fb9c3b6463fdee9eb4dac697beab4d3d7a5fdcf Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Tue, 8 Oct 2019 13:50:16 +0330 Subject: [PATCH 10/26] [glyf] Implement depth limit for add_gid_and_children --- src/hb-ot-glyf-table.hh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index 124a7d7b0..0bb9aca13 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -795,7 +795,7 @@ struct glyf bool get_points_var (hb_codepoint_t glyph, const int *coords, unsigned int coord_count, contour_point_vector_t &all_points /* OUT */, - unsigned int depth=0) const + unsigned int depth = 0) const { if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return false; contour_point_vector_t points; @@ -1009,8 +1009,10 @@ struct glyf } void - add_gid_and_children (hb_codepoint_t gid, hb_set_t *gids_to_retain) const + add_gid_and_children (hb_codepoint_t gid, hb_set_t *gids_to_retain, + unsigned int depth = 0) const { + if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return; /* Check if is already visited */ if (gids_to_retain->has (gid)) return; @@ -1019,7 +1021,7 @@ struct glyf hb_bytes_t glyph_bytes = bytes_for_glyph (gid); const GlyphHeader &glyph_header = *glyph_bytes.as (); for (auto &item : glyph_header.get_composite_iterator (glyph_bytes)) - add_gid_and_children (item.glyphIndex, gids_to_retain); + add_gid_and_children (item.glyphIndex, gids_to_retain, depth); } private: From b2628f1a3e3a6875dcdf7cb89f5b10a4ae76e6f9 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Tue, 8 Oct 2019 15:09:09 +0330 Subject: [PATCH 11/26] [glyf] Move glyph bytes drop hints logic to GlyphHeader --- src/hb-ot-glyf-table.hh | 92 +++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 55 deletions(-) diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index 0bb9aca13..a4e49d003 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -197,7 +197,7 @@ struct glyf return subset_glyph; subset_glyph.source_glyph = glyf.bytes_for_glyph (subset_glyph.old_gid, true); - if (plan->drop_hints) subset_glyph.drop_hints (glyf); + if (plan->drop_hints) subset_glyph.drop_hints_bytes (); else subset_glyph.dest_start = subset_glyph.source_glyph; return subset_glyph; @@ -401,16 +401,15 @@ struct glyf 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 instructions_length (hb_bytes_t glyph) const { unsigned int instruction_length_offset = instruction_len_offset (); - if (unlikely (instruction_length_offset + 2 > glyph.length)) return false; + if (unlikely (instruction_length_offset + 2 > glyph.length)) return 0; const HBUINT16 &instructionLength = StructAtOffset (&glyph, instruction_length_offset); /* Out of bounds of the current glyph */ - if (unlikely (length (instructionLength) > glyph.length)) return false; - *len = instructionLength; - return true; + if (unlikely (length (instructionLength) > glyph.length)) return 0; + return instructionLength; } enum simple_glyph_flag_t @@ -478,6 +477,14 @@ struct glyf GlyphHeader &glyph_header = const_cast (header); (HBUINT16 &) StructAtOffset (&glyph_header, instruction_len_offset ()) = 0; } + + void drop_hints_bytes (hb_bytes_t source_glyph, hb_bytes_t &dest_start, hb_bytes_t &dest_end) const + { + unsigned int instructions_len = instructions_length (source_glyph); + unsigned int glyph_length = length (instructions_len); + dest_start = source_glyph.sub_array (0, glyph_length - instructions_len); + dest_end = source_glyph.sub_array (glyph_length, source_glyph.length - glyph_length); + } }; struct CompositeHeader @@ -488,20 +495,19 @@ struct glyf composite_iter_t get_iterator (hb_bytes_t glyph) const { return composite_iter_t (glyph, &StructAfter (header)); } - bool get_instruction_length (hb_bytes_t glyph, unsigned int *length) const + unsigned int instructions_length (hb_bytes_t glyph) 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 (unlikely (!last)) return 0; 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; + if (unlikely (start > end)) return 0; + return end - start; } /* Trimming for composites not implemented. @@ -518,16 +524,15 @@ struct glyf 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); } + /* Chop instructions off the end */ + void drop_hints_bytes (hb_bytes_t source_glyph, hb_bytes_t &dest_start) const + { dest_start = source_glyph.sub_array (0, source_glyph.length - instructions_length (source_glyph)); } + }; enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE }; - glyph_type_t get_type () const + unsigned get_type () const { if (is_simple_glyph ()) return SIMPLE; else if (is_composite_glyph ()) return COMPOSITE; @@ -537,39 +542,36 @@ struct glyf 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); + return CompositeHeader (*this).get_iterator (glyph); } - bool get_instruction_length (hb_bytes_t glyph, unsigned int *length) const + hb_bytes_t bytes_without_padding (hb_bytes_t glyph_bytes) 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 */ + case COMPOSITE: return CompositeHeader (*this).bytes_without_padding (glyph_bytes); + case SIMPLE: return SimpleHeader (*this).bytes_without_padding (glyph_bytes); + default: return glyph_bytes; } } - hb_bytes_t bytes_without_padding (hb_bytes_t glyph_bytes) const + void drop_hints (hb_bytes_t glyph_bytes) { 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; + case COMPOSITE: CompositeHeader (*this).drop_hints (glyph_bytes); return; + case SIMPLE: SimpleHeader (*this).drop_hints (); return; + default: return; } } - void drop_hints (hb_bytes_t glyph_bytes) + void drop_hints_bytes (hb_bytes_t source_glyph, hb_bytes_t &dest_start, hb_bytes_t &dest_end) const { switch (get_type ()) { - case COMPOSITE: as_composite ().drop_hints (glyph_bytes); return; - case SIMPLE: as_simple ().drop_hints (); return; - default: - case EMPTY: return; + case COMPOSITE: CompositeHeader (*this).drop_hints_bytes (source_glyph, dest_start); return; + case SIMPLE: SimpleHeader (*this).drop_hints_bytes (source_glyph, dest_start, dest_end); return; + default: return; } } @@ -1074,28 +1076,8 @@ struct glyf return_trace (true); } - void drop_hints (const OT::glyf::accelerator_t& glyf) - { - if (source_glyph.length == 0) return; - - unsigned int instruction_len = 0; - - const GlyphHeader& header = *source_glyph.as (); - if (!header.get_instruction_length (source_glyph, &instruction_len)) - /* Unable to read instruction length */ - return; - - if (header.is_composite_glyph ()) - /* just chop instructions off the end for composite glyphs */ - dest_start = hb_bytes_t (&source_glyph, source_glyph.length - instruction_len); - else - { - unsigned int glyph_length = GlyphHeader::SimpleHeader (header).length (instruction_len); - dest_start = hb_bytes_t (&source_glyph, glyph_length - instruction_len); - dest_end = hb_bytes_t (&source_glyph + glyph_length, - source_glyph.length - glyph_length); - } - } + void drop_hints_bytes () + { source_glyph.as ()->drop_hints_bytes (source_glyph, dest_start, dest_end); } unsigned int length () const { return dest_start.length + dest_end.length; } /* pad to 2 to ensure 2-byte loca will be ok */ From 0527fda4c75e4354198df79275526d4726a3aacc Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Tue, 8 Oct 2019 16:19:39 +0330 Subject: [PATCH 12/26] minor --- src/hb-subset-cff-common.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/hb-subset-cff-common.cc b/src/hb-subset-cff-common.cc index b71ac57cc..c9a880ad5 100644 --- a/src/hb-subset-cff-common.cc +++ b/src/hb-subset-cff-common.cc @@ -68,8 +68,7 @@ hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan, { /* use hb_set to determine the subset of font dicts */ hb_set_t *set = hb_set_create (); - if (set == &Null (hb_set_t)) - return false; + if (unlikely (set == &Null (hb_set_t))) return false; hb_codepoint_t prev_fd = CFF_UNDEF_CODE; for (hb_codepoint_t i = 0; i < subset_num_glyphs; i++) { From 6961766db2c53ea813079c61e4d996234ae8be4f Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Tue, 8 Oct 2019 16:26:48 +0330 Subject: [PATCH 13/26] [glyf] fix scaling direction --- src/hb-ot-glyf-table.hh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index a4e49d003..9cb1a26fb 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -968,9 +968,9 @@ struct glyf /* Undocumented rasterizer behavior: shift glyph to the left by (lsb - xMin), i.e., xMin = lsb */ /* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */ extents->x_bearing = font->em_scale_x (face->table.hmtx->get_side_bearing (glyph)); - extents->y_bearing = font->em_scale_x (hb_max (glyph_header.yMin, glyph_header.yMax)); + extents->y_bearing = font->em_scale_y (hb_max (glyph_header.yMin, glyph_header.yMax)); extents->width = font->em_scale_x (hb_max (glyph_header.xMin, glyph_header.xMax) - hb_min (glyph_header.xMin, glyph_header.xMax)); - extents->height = font->em_scale_x (hb_min (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing); + extents->height = font->em_scale_y (hb_min (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing); return true; } From b068e25f8f89d9b07963dddd5d5e14f61539556f Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Tue, 8 Oct 2019 16:29:15 +0330 Subject: [PATCH 14/26] [glyf] Address Behdad's reviews Addresses https://github.com/harfbuzz/harfbuzz/pull/1999#issuecomment-539298559 * Don't check against Null pool * Remove cryptic _tt suffix --- src/hb-ot-font.cc | 4 ++-- src/hb-ot-hmtx-table.hh | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc index 6924955ba..96f94e4a9 100644 --- a/src/hb-ot-font.cc +++ b/src/hb-ot-font.cc @@ -313,13 +313,13 @@ hb_ot_font_set_funcs (hb_font_t *font) #ifndef HB_NO_VAR int -hb_ot_get_side_bearing_var_tt (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical) +_glyf_get_side_bearing_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical) { return font->face->table.glyf->get_side_bearing_var (font, glyph, is_vertical); } unsigned -hb_ot_get_advance_var_tt (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical) +_glyf_get_advance_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical) { return font->face->table.glyf->get_advance_var (font, glyph, is_vertical); } diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh index ce8f261bc..e20b37262 100644 --- a/src/hb-ot-hmtx-table.hh +++ b/src/hb-ot-hmtx-table.hh @@ -43,10 +43,10 @@ HB_INTERNAL int -hb_ot_get_side_bearing_var_tt (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical); +_glyf_get_side_bearing_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical); HB_INTERNAL unsigned -hb_ot_get_advance_var_tt (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical); +_glyf_get_advance_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical); namespace OT { @@ -215,10 +215,10 @@ struct hmtxvmtx if (unlikely (glyph >= num_metrics) || !font->num_coords) return side_bearing; - if (var_table.get_blob () == &Null (hb_blob_t)) - return hb_ot_get_side_bearing_var_tt (font, glyph, T::tableTag == HB_OT_TAG_vmtx); + if (var_table.get_length ()) + return side_bearing + var_table->get_side_bearing_var (glyph, font->coords, font->num_coords); // TODO Optimize?! - return side_bearing + var_table->get_side_bearing_var (glyph, font->coords, font->num_coords); // TODO Optimize?! + return _glyf_get_side_bearing_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx); #else return side_bearing; #endif @@ -249,10 +249,10 @@ struct hmtxvmtx if (unlikely (glyph >= num_metrics) || !font->num_coords) return advance; - if (var_table.get_blob () == &Null (hb_blob_t)) - return hb_ot_get_advance_var_tt (font, glyph, T::tableTag == HB_OT_TAG_vmtx); + if (var_table.get_length ()) + return advance + roundf (var_table->get_advance_var (font, glyph)); // TODO Optimize?! - return advance + roundf (var_table->get_advance_var (font, glyph)); // TODO Optimize?! + return _glyf_get_advance_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx); #else return advance; #endif From dc45f225212da7b8eca0ddcb3c9cd66e65983605 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Tue, 8 Oct 2019 23:27:37 +0330 Subject: [PATCH 15/26] [ot-metrics] Don't use mixed scaled and not scaled for generating extents --- src/hb-ot-cff1-table.cc | 4 ++-- src/hb-ot-cff2-table.cc | 4 ++-- src/hb-ot-color-sbix-table.hh | 7 +++++++ src/hb-ot-glyf-table.hh | 6 +++--- test/api/test-ot-extents-cff.c | 6 +++--- 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/hb-ot-cff1-table.cc b/src/hb-ot-cff1-table.cc index 54bfe5dff..d1e462562 100644 --- a/src/hb-ot-cff1-table.cc +++ b/src/hb-ot-cff1-table.cc @@ -326,7 +326,7 @@ bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph else { extents->x_bearing = font->em_scalef_x (bounds.min.x.to_real ()); - extents->width = font->em_scalef_x (bounds.max.x.to_real () - extents->x_bearing); + extents->width = font->em_scalef_x (bounds.max.x.to_real () - bounds.min.x.to_real ()); } if (bounds.min.y >= bounds.max.y) { @@ -336,7 +336,7 @@ bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph else { extents->y_bearing = font->em_scalef_y (bounds.max.y.to_real ()); - extents->height = font->em_scalef_x (bounds.min.y.to_real () - extents->y_bearing); + extents->height = font->em_scalef_x (bounds.min.y.to_real () - bounds.max.y.to_real ()); } return true; diff --git a/src/hb-ot-cff2-table.cc b/src/hb-ot-cff2-table.cc index e69070e18..a2242b76f 100644 --- a/src/hb-ot-cff2-table.cc +++ b/src/hb-ot-cff2-table.cc @@ -126,7 +126,7 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, else { extents->x_bearing = font->em_scalef_x (param.min_x.to_real ()); - extents->width = font->em_scalef_x (param.max_x.to_real () - extents->x_bearing); + extents->width = font->em_scalef_x (param.max_x.to_real () - param.min_x.to_real ()); } if (param.min_y >= param.max_y) { @@ -136,7 +136,7 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, else { extents->y_bearing = font->em_scalef_y (param.max_y.to_real ()); - extents->height = font->em_scalef_y (param.min_y.to_real () - extents->y_bearing); + extents->height = font->em_scalef_y (param.min_y.to_real () - param.max_y.to_real ()); } return true; diff --git a/src/hb-ot-color-sbix-table.hh b/src/hb-ot-color-sbix-table.hh index 6008e7e3d..35d3fd510 100644 --- a/src/hb-ot-color-sbix-table.hh +++ b/src/hb-ot-color-sbix-table.hh @@ -248,6 +248,13 @@ struct sbix extents->width = font->em_scalef_x (extents->width * scale); extents->height = font->em_scalef_y (extents->height * scale); } + else + { + 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); + } hb_blob_destroy (blob); diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index 9cb1a26fb..cd350f504 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -888,7 +888,7 @@ struct glyf else { extents->x_bearing = font->em_scalef_x (bounds.min.x); - extents->width = font->em_scalef_x (bounds.max.x) - extents->x_bearing; + extents->width = font->em_scalef_x (bounds.max.x - bounds.min.x); } if (bounds.min.y > bounds.max.y) { @@ -898,7 +898,7 @@ struct glyf else { extents->y_bearing = font->em_scalef_y (bounds.max.y); - extents->height = font->em_scalef_y (bounds.min.y) - extents->y_bearing; + extents->height = font->em_scalef_y (bounds.min.y - bounds.max.y); } } if (phantoms) @@ -970,7 +970,7 @@ struct glyf extents->x_bearing = font->em_scale_x (face->table.hmtx->get_side_bearing (glyph)); extents->y_bearing = font->em_scale_y (hb_max (glyph_header.yMin, glyph_header.yMax)); extents->width = font->em_scale_x (hb_max (glyph_header.xMin, glyph_header.xMax) - hb_min (glyph_header.xMin, glyph_header.xMax)); - extents->height = font->em_scale_y (hb_min (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing); + extents->height = font->em_scale_y (hb_min (glyph_header.yMin, glyph_header.yMax) - hb_max (glyph_header.yMin, glyph_header.yMax)); return true; } diff --git a/test/api/test-ot-extents-cff.c b/test/api/test-ot-extents-cff.c index e6aeb0d6e..7109e302e 100644 --- a/test/api/test-ot-extents-cff.c +++ b/test/api/test-ot-extents-cff.c @@ -170,7 +170,7 @@ test_extents_cff2_vsindex (void) g_assert_cmpint (extents.x_bearing, ==, 12); g_assert_cmpint (extents.y_bearing, ==, 655); - g_assert_cmpint (extents.width, ==, 651); + g_assert_cmpint (extents.width, ==, 652); g_assert_cmpint (extents.height, ==, -655); result = hb_font_get_glyph_extents (font, 2, &extents); @@ -178,7 +178,7 @@ test_extents_cff2_vsindex (void) g_assert_cmpint (extents.x_bearing, ==, 8); g_assert_cmpint (extents.y_bearing, ==, 669); - g_assert_cmpint (extents.width, ==, 648); + g_assert_cmpint (extents.width, ==, 649); g_assert_cmpint (extents.height, ==, -669); hb_font_destroy (font); @@ -201,7 +201,7 @@ test_extents_cff2_vsindex_named_instance (void) g_assert_cmpint (extents.x_bearing, ==, 13); g_assert_cmpint (extents.y_bearing, ==, 652); - g_assert_cmpint (extents.width, ==, 652); + g_assert_cmpint (extents.width, ==, 653); g_assert_cmpint (extents.height, ==, -652); result = hb_font_get_glyph_extents (font, 2, &extents); From 36f18cecbbaf8635a2179a827242ca99d5283666 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Mon, 7 Oct 2019 14:02:31 -0700 Subject: [PATCH 16/26] Add subset_offset_array helper function which simplifies subsetting offset arrays during stream operations. --- src/hb-ot-layout-common.hh | 54 ++++++++++++++++++++++++++++++++++ src/hb-ot-layout-gsub-table.hh | 15 +--------- 2 files changed, 55 insertions(+), 14 deletions(-) diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh index 051bfda69..f2f3b05f2 100644 --- a/src/hb-ot-layout-common.hh +++ b/src/hb-ot-layout-common.hh @@ -66,6 +66,60 @@ namespace OT { #define NOT_COVERED ((unsigned int) -1) +template +struct subset_offset_array_t +{ + subset_offset_array_t + (hb_subset_context_t *subset_context, + OutputArray& out, + const void *src_base, + const void *dest_base) + : _subset_context(subset_context), _out (out), _src_base (src_base), _dest_base (dest_base) {} + + template + bool + operator () + (T&& offset) + { + auto *o = _out.serialize_append (_subset_context->serializer); + if (unlikely (!o)) return false; + auto snap = _subset_context->serializer->snapshot (); + bool ret = o->serialize_subset (_subset_context, offset, _src_base, _dest_base); + if (!ret) + { + _out.pop (); + _subset_context->serializer->revert (snap); + } + return ret; + } + + private: + hb_subset_context_t *_subset_context; + OutputArray &_out; + const void *_src_base; + const void *_dest_base; +}; + +/* + * Helper to subset an array of offsets. Subsets the thing pointed to by each offset + * and discards the offset in the array if the subset operation results in an empty + * thing. + */ +struct +{ + template + subset_offset_array_t + operator () + (hb_subset_context_t *subset_context, + OutputArray& out, + const void *src_base, + const void *dest_base) const + { + return subset_offset_array_t (subset_context, out, src_base, dest_base); + } +} +HB_FUNCOBJ (subset_offset_array); + /* * diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh index a2722ade9..f080d682a 100644 --- a/src/hb-ot-layout-gsub-table.hh +++ b/src/hb-ot-layout-gsub-table.hh @@ -1074,20 +1074,7 @@ struct LigatureSubstFormat1 hb_sorted_vector_t new_coverage; + hb_zip (this+coverage, ligatureSet) | hb_filter (glyphset, hb_first) - | hb_filter ([this, c, out] (const OffsetTo& _) - { - auto *o = out->ligatureSet.serialize_append (c->serializer); - if (unlikely (!o)) return false; - auto snap = c->serializer->snapshot (); - bool ret = o->serialize_subset (c, _, this, out); - if (!ret) - { - out->ligatureSet.pop (); - c->serializer->revert (snap); - } - return ret; - }, - hb_second) + | hb_filter (subset_offset_array (c, out->ligatureSet, this, out), hb_second) | hb_map (hb_first) | hb_map (glyph_map) | hb_sink (new_coverage) From e17e7443007fc0debc4a26e5cf37d5d76c747fbf Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Wed, 9 Oct 2019 11:45:42 -0700 Subject: [PATCH 17/26] Convert existing uses of serialize_append in gsub subsetting to use subset_offset_array. --- src/hb-ot-layout-gsub-table.hh | 44 +++------------------------------- 1 file changed, 3 insertions(+), 41 deletions(-) diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh index f080d682a..fc21cb056 100644 --- a/src/hb-ot-layout-gsub-table.hh +++ b/src/hb-ot-layout-gsub-table.hh @@ -452,20 +452,7 @@ struct MultipleSubstFormat1 hb_sorted_vector_t new_coverage; + hb_zip (this+coverage, sequence) | hb_filter (glyphset, hb_first) - | hb_filter ([this, c, out] (const OffsetTo& _) - { - auto *o = out->sequence.serialize_append (c->serializer); - if (unlikely (!o)) return false; - auto snap = c->serializer->snapshot (); - bool ret = o->serialize_subset (c, _, this, out); - if (!ret) - { - out->sequence.pop (); - c->serializer->revert (snap); - } - return ret; - }, - hb_second) + | hb_filter (subset_offset_array (c, out->sequence, this, out), hb_second) | hb_map (hb_first) | hb_map (glyph_map) | hb_sink (new_coverage) @@ -675,20 +662,7 @@ struct AlternateSubstFormat1 hb_sorted_vector_t new_coverage; + hb_zip (this+coverage, alternateSet) | hb_filter (glyphset, hb_first) - | hb_filter ([this, c, out] (const OffsetTo& _) - { - auto *o = out->alternateSet.serialize_append (c->serializer); - if (unlikely (!o)) return false; - auto snap = c->serializer->snapshot (); - bool ret = o->serialize_subset (c, _, this, out); - if (!ret) - { - out->alternateSet.pop (); - c->serializer->revert (snap); - } - return ret; - }, - hb_second) + | hb_filter (subset_offset_array (c, out->alternateSet, this, out), hb_second) | hb_map (hb_first) | hb_map (glyph_map) | hb_sink (new_coverage) @@ -948,19 +922,7 @@ struct LigatureSet if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + hb_iter (ligature) - | hb_filter ([this, c, out] (const OffsetTo& _) - { - auto *o = out->ligature.serialize_append (c->serializer); - if (unlikely (!o)) return false; - auto snap = c->serializer->snapshot (); - bool ret = o->serialize_subset (c, _, this, out); - if (!ret) - { - out->ligature.pop (); - c->serializer->revert (snap); - } - return ret; - }) + | hb_filter (subset_offset_array (c, out->ligature, this, out)) | hb_drain ; return_trace (bool (out->ligature)); From e4464f4484009b4efe7144570384d836cb6bbac8 Mon Sep 17 00:00:00 2001 From: David Corbett Date: Wed, 9 Oct 2019 20:55:52 -0400 Subject: [PATCH 18/26] Reorder U+1C29 LEPCHA VOWEL SIGN OO --- src/gen-use-table.py | 3 +++ src/hb-ot-shape-complex-use-table.cc | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/gen-use-table.py b/src/gen-use-table.py index a8a03a77b..4523fb8ed 100755 --- a/src/gen-use-table.py +++ b/src/gen-use-table.py @@ -383,6 +383,9 @@ def map_to_use(data): # TODO: In USE's override list but not in Unicode 12.0 if U == 0x103C: UIPC = Left + # TODO: https://github.com/harfbuzz/harfbuzz/pull/2012 + if U == 0x1C29: UIPC = Left + # TODO: These are not in USE's override list that we have, nor are they in Unicode 12.0 if 0xA926 <= U <= 0xA92A: UIPC = Top # TODO: https://github.com/harfbuzz/harfbuzz/pull/1037 diff --git a/src/hb-ot-shape-complex-use-table.cc b/src/hb-ot-shape-complex-use-table.cc index 4c5d687c7..e3889b3e6 100644 --- a/src/hb-ot-shape-complex-use-table.cc +++ b/src/hb-ot-shape-complex-use-table.cc @@ -347,7 +347,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 1C00 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1C10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 1C20 */ B, B, B, B, SUB, SUB, VPst, VPre, VPre, VPst, VPst, VPst, VBlw, FAbv, FAbv, FAbv, + /* 1C20 */ B, B, B, B, SUB, SUB, VPst, VPre, VPre, VPre, VPst, VPst, VBlw, FAbv, FAbv, FAbv, /* 1C30 */ FAbv, FAbv, FAbv, FAbv, VMPre, VMPre, FMAbv, CMBlw, O, O, O, O, O, O, O, O, /* 1C40 */ B, B, B, B, B, B, B, B, B, B, O, O, O, B, B, B, From 670fec231d31bf7417de590efd3485f337a7330f Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Thu, 10 Oct 2019 09:21:08 +0330 Subject: [PATCH 19/26] Minor, add a zero length tolerant memset, hb_memset --- src/hb-algs.hh | 10 +++++++++- src/hb-buffer.cc | 3 +-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/hb-algs.hh b/src/hb-algs.hh index c57481bfe..042e1c20d 100644 --- a/src/hb-algs.hh +++ b/src/hb-algs.hh @@ -588,10 +588,18 @@ hb_memcmp (const void *a, const void *b, unsigned int len) /* It's illegal to pass NULL to memcmp(), even if len is zero. * So, wrap it. * https://sourceware.org/bugzilla/show_bug.cgi?id=23878 */ - if (!len) return 0; + if (unlikely (!len)) return 0; return memcmp (a, b, len); } +static inline void * +hb_memset (void *s, int c, unsigned int n) +{ + /* It's illegal to pass NULL to memset(), even if n is zero. */ + if (unlikely (!n)) return 0; + return memset (s, c, n); +} + static inline bool hb_unsigned_mul_overflows (unsigned int count, unsigned int size) { diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc index bb7f3c7c1..40ac55c1c 100644 --- a/src/hb-buffer.cc +++ b/src/hb-buffer.cc @@ -324,8 +324,7 @@ hb_buffer_t::clear_positions () out_len = 0; out_info = info; - if (likely (len)) - memset (pos, 0, sizeof (pos[0]) * len); + hb_memset (pos, 0, sizeof (pos[0]) * len); } void From b918cd8c76a6333e43b9be23178afc9e74e17024 Mon Sep 17 00:00:00 2001 From: Ben Wagner Date: Thu, 10 Oct 2019 15:30:48 -0400 Subject: [PATCH 20/26] Document hb_feature_t. This documents hb_feature_t. This is motivated mostly by the ambiguity of the units for 'start' and 'end' (clusters) and whether they are inclusive or exclusive. This also documents that for lookup type 3 the value is the one based index into the alternates and that in a list of features later feature values override previous feature values with the same tag. --- src/hb-common.h | 15 +++++++++++++++ src/hb-shape.cc | 4 +++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/hb-common.h b/src/hb-common.h index 9f1764bdc..9cfaab11b 100644 --- a/src/hb-common.h +++ b/src/hb-common.h @@ -425,6 +425,21 @@ typedef void (*hb_destroy_func_t) (void *user_data); */ #define HB_FEATURE_GLOBAL_END ((unsigned int) -1) +/** + * hb_feature_t: + * @tag: a feature tag + * @value: 0 disables the feature, non-zero (usually 1) enables the feature. + * For features implemented as lookup type 3 (like 'salt') the @value is a one + * based index into the alternates. + * @start: the cluster to start applying this feature setting (inclusive). + * @end: the cluster to end applying this feature setting (exclusive). + * + * The hb_feature_t is the structure that holds information about requested + * feature application. The feature will be applied with the given value to all + * glyphs which are in clusters between @start (inclusive) and @end (exclusive). + * Setting start to @HB_FEATURE_GLOBAL_START and end to @HB_FEATURE_GLOBAL_END + * specifies that the feature always applies to the entire buffer. + */ typedef struct hb_feature_t { hb_tag_t tag; uint32_t value; diff --git a/src/hb-shape.cc b/src/hb-shape.cc index deff77bed..cf4e1525a 100644 --- a/src/hb-shape.cc +++ b/src/hb-shape.cc @@ -154,7 +154,9 @@ hb_shape_full (hb_font_t *font, * * Shapes @buffer using @font turning its Unicode characters content to * positioned glyphs. If @features is not %NULL, it will be used to control the - * features applied during shaping. + * features applied during shaping. If two @features have the same tag but + * overlapping ranges the value of the feature with the higher index takes + * precedence. * * Since: 0.9.2 **/ From 4299ea266e03b64db4e8a132983fed9fd0a967ee Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sat, 12 Oct 2019 09:51:27 +0330 Subject: [PATCH 21/26] [glyf] Move get_contour_points to GlyphHeader --- src/hb-ot-glyf-table.hh | 260 ++++++++++++++++++++++------------------ 1 file changed, 141 insertions(+), 119 deletions(-) diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index cd350f504..488b186ed 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -485,6 +485,53 @@ struct glyf dest_start = source_glyph.sub_array (0, glyph_length - instructions_len); dest_end = source_glyph.sub_array (glyph_length, source_glyph.length - glyph_length); } + + bool get_contour_points (hb_bytes_t bytes, + contour_point_vector_t &points_ /* OUT */, + hb_vector_t &end_points_ /* OUT */, + const bool phantom_only=false) const + { + unsigned int num_points = 0; + const HBUINT16 *end_pts = &StructAfter (header); + range_checker_t checker (bytes.arrayZ, 0, bytes.length); + num_points = 0; + int num_contours = header.numberOfContours; + if (unlikely (!checker.in_range (&end_pts[num_contours + 1]))) return false; + num_points = end_pts[num_contours - 1] + 1; + + points_.resize (num_points + PHANTOM_COUNT); + for (unsigned int i = 0; i < points_.length; i++) points_[i].init (); + if (phantom_only) return true; + + /* Read simple glyph points if !phantom_only */ + end_points_.resize (num_contours); + + for (int i = 0; i < num_contours; i++) + end_points_[i] = end_pts[i]; + + /* Skip instructions */ + const HBUINT8 *p = &StructAtOffset (&end_pts[num_contours + 1], + end_pts[num_contours]); + + /* Read flags */ + for (unsigned int i = 0; i < num_points; i++) + { + if (unlikely (!checker.in_range (p))) return false; + uint8_t flag = *p++; + points_[i].flag = flag; + if ((flag & SimpleHeader::FLAG_REPEAT) != 0) + { + if (unlikely (!checker.in_range (p))) return false; + unsigned int repeat_count = *p++; + while ((repeat_count-- > 0) && (++i < num_points)) + points_[i].flag = flag; + } + } + + /* Read x & y coordinates */ + return (read_points (p, points_, checker) && + read_points (p, points_, checker)); + } }; struct CompositeHeader @@ -528,6 +575,19 @@ struct glyf /* Chop instructions off the end */ void drop_hints_bytes (hb_bytes_t source_glyph, hb_bytes_t &dest_start) const { dest_start = source_glyph.sub_array (0, source_glyph.length - instructions_length (source_glyph)); } + + bool get_contour_points (hb_bytes_t bytes, + contour_point_vector_t &points_ /* OUT */, + hb_vector_t &end_points_ /* OUT */, + const bool phantom_only=false) const + { + unsigned int num_points = 0; + /* add one pseudo point for each component in composite glyph */ + num_points += hb_len (get_iterator (bytes)); + points_.resize (num_points + PHANTOM_COUNT); + for (unsigned int i = 0; i < points_.length; i++) points_[i].init (); + return true; + } }; enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE }; @@ -575,6 +635,84 @@ struct glyf } } + enum phantom_point_index_t + { + PHANTOM_LEFT = 0, + PHANTOM_RIGHT = 1, + PHANTOM_TOP = 2, + PHANTOM_BOTTOM = 3, + PHANTOM_COUNT = 4 + }; + + struct x_setter_t + { + void set (contour_point_t &point, float v) const { point.x = v; } + bool is_short (uint8_t flag) const { return flag & SimpleHeader::FLAG_X_SHORT; } + bool is_same (uint8_t flag) const { return flag & SimpleHeader::FLAG_X_SAME; } + }; + + struct y_setter_t + { + void set (contour_point_t &point, float v) const { point.y = v; } + bool is_short (uint8_t flag) const { return flag & SimpleHeader::FLAG_Y_SHORT; } + bool is_same (uint8_t flag) const { return flag & SimpleHeader::FLAG_Y_SAME; } + }; + + template + static bool read_points (const HBUINT8 *&p /* IN/OUT */, + contour_point_vector_t &points_ /* IN/OUT */, + const range_checker_t &checker) + { + T coord_setter; + float v = 0; + for (unsigned int i = 0; i < points_.length - PHANTOM_COUNT; i++) + { + uint8_t flag = points_[i].flag; + if (coord_setter.is_short (flag)) + { + if (unlikely (!checker.in_range (p))) return false; + if (coord_setter.is_same (flag)) + v += *p++; + else + v -= *p++; + } + else + { + if (!coord_setter.is_same (flag)) + { + if (unlikely (!checker.in_range ((const HBUINT16 *) p))) return false; + v += *(const HBINT16 *) p; + p += HBINT16::static_size; + } + } + coord_setter.set (points_[i], v); + } + return true; + } + + /* for a simple glyph, return contour end points, flags, along with coordinate points + * for a composite glyph, return pseudo component points + * in both cases points trailed with four phantom points + */ + bool get_contour_points (hb_bytes_t bytes, + contour_point_vector_t &points_ /* OUT */, + hb_vector_t &end_points_ /* OUT */, + const bool phantom_only=false) const + { + switch (get_type ()) + { + case COMPOSITE: return CompositeHeader (*this).get_contour_points (bytes, points_, end_points_, phantom_only); + case SIMPLE: return SimpleHeader (*this).get_contour_points (bytes, points_, end_points_, phantom_only); + default: + { + /* empty glyph */ + points_.resize (PHANTOM_COUNT); + for (unsigned int i = 0; i < points_.length; i++) points_[i].init (); + return true; + } + } + } + bool has_data () const { return numberOfContours; } bool is_simple_glyph () const { return numberOfContours > 0; } bool is_composite_glyph () const { return numberOfContours < 0; } @@ -641,51 +779,6 @@ struct glyf }; protected: - struct x_setter_t - { - void set (contour_point_t &point, float v) const { point.x = v; } - bool is_short (uint8_t flag) const { return flag & FLAG_X_SHORT; } - bool is_same (uint8_t flag) const { return flag & FLAG_X_SAME; } - }; - - struct y_setter_t - { - void set (contour_point_t &point, float v) const { point.y = v; } - bool is_short (uint8_t flag) const { return flag & FLAG_Y_SHORT; } - bool is_same (uint8_t flag) const { return flag & FLAG_Y_SAME; } - }; - - template - static bool read_points (const HBUINT8 *&p /* IN/OUT */, - contour_point_vector_t &points_ /* IN/OUT */, - const range_checker_t &checker) - { - T coord_setter; - float v = 0; - for (unsigned int i = 0; i < points_.length - PHANTOM_COUNT; i++) - { - uint8_t flag = points_[i].flag; - if (coord_setter.is_short (flag)) - { - if (unlikely (!checker.in_range (p))) return false; - if (coord_setter.is_same (flag)) - v += *p++; - else - v -= *p++; - } - else - { - if (!coord_setter.is_same (flag)) - { - if (unlikely (!checker.in_range ((const HBUINT16 *)p))) return false; - v += *(const HBINT16 *) p; - p += HBINT16::static_size; - } - } - coord_setter.set (points_[i], v); - } - return true; - } void init_phantom_points (hb_codepoint_t glyph, hb_array_t &phantoms /* IN/OUT */) const { @@ -701,77 +794,6 @@ struct glyf phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv; } - /* for a simple glyph, return contour end points, flags, along with coordinate points - * for a composite glyph, return pseudo component points - * in both cases points trailed with four phantom points - */ - bool get_contour_points (hb_codepoint_t glyph, - contour_point_vector_t &points_ /* OUT */, - hb_vector_t &end_points_ /* OUT */, - const bool phantom_only=false) const - { - unsigned int num_points = 0; - hb_bytes_t bytes = bytes_for_glyph (glyph); - const GlyphHeader &glyph_header = *bytes.as (); - if (glyph_header.is_composite_glyph ()) - { - /* add one pseudo point for each component in composite glyph */ - 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; - } - else if (glyph_header.is_simple_glyph ()) - { - const HBUINT16 *end_pts = &StructAfter (glyph_header); - range_checker_t checker (bytes.arrayZ, 0, bytes.length); - num_points = 0; - int num_contours = glyph_header.numberOfContours; - if (unlikely (!checker.in_range (&end_pts[num_contours + 1]))) return false; - num_points = end_pts[glyph_header.numberOfContours - 1] + 1; - - points_.resize (num_points + PHANTOM_COUNT); - for (unsigned int i = 0; i < points_.length; i++) points_[i].init (); - if (phantom_only) return true; - - /* Read simple glyph points if !phantom_only */ - end_points_.resize (num_contours); - - for (int i = 0; i < num_contours; i++) - end_points_[i] = end_pts[i]; - - /* Skip instructions */ - const HBUINT8 *p = &StructAtOffset (&end_pts[num_contours + 1], - end_pts[num_contours]); - - /* Read flags */ - for (unsigned int i = 0; i < num_points; i++) - { - if (unlikely (!checker.in_range (p))) return false; - uint8_t flag = *p++; - points_[i].flag = flag; - if ((flag & FLAG_REPEAT) != 0) - { - if (unlikely (!checker.in_range (p))) return false; - unsigned int repeat_count = *p++; - while ((repeat_count-- > 0) && (++i < num_points)) - points_[i].flag = flag; - } - } - - /* Read x & y coordinates */ - return (read_points (p, points_, checker) && - read_points (p, points_, checker)); - } - else - { - /* empty glyph */ - points_.resize (PHANTOM_COUNT); - for (unsigned int i = 0; i < points_.length; i++) points_[i].init (); - return true; - } - } - struct contour_bounds_t { contour_bounds_t () { min.x = min.y = FLT_MAX; max.x = max.y = -FLT_MAX; } @@ -802,14 +824,14 @@ struct glyf if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return false; contour_point_vector_t points; hb_vector_t end_points; - if (unlikely (!get_contour_points (glyph, points, end_points))) return false; + hb_bytes_t bytes = bytes_for_glyph (glyph); + const GlyphHeader &glyph_header = *bytes.as (); + if (unlikely (!glyph_header.get_contour_points (bytes, points, end_points))) return false; hb_array_t phantoms = points.sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT); init_phantom_points (glyph, phantoms); if (unlikely (!face->table.gvar->apply_deltas_to_points (glyph, coords, coord_count, points.as_array (), end_points.as_array ()))) return false; unsigned int comp_index = 0; - hb_bytes_t bytes = bytes_for_glyph (glyph); - const GlyphHeader &glyph_header = *bytes.as (); if (glyph_header.is_simple_glyph ()) all_points.extend (points.as_array ()); else if (glyph_header.is_composite_glyph ()) From 546ffc9faf869b4971765e9a4fd232cfe0eecaea Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sat, 12 Oct 2019 09:51:57 +0330 Subject: [PATCH 22/26] [glyf] minor --- src/hb-ot-glyf-table.hh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index 488b186ed..0f4ffdde3 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -265,7 +265,8 @@ struct glyf return size; } - bool is_anchored () const { return (flags & ARGS_ARE_XY_VALUES) == 0; } + bool is_use_my_metrics () const { return flags & USE_MY_METRICS; } + bool is_anchored () const { return (flags & ARGS_ARE_XY_VALUES) == 0; } void get_anchor_points (unsigned int &point1, unsigned int &point2) const { const HBUINT8 *p = &StructAfter (glyphIndex); @@ -845,7 +846,7 @@ struct glyf return false; /* Copy phantom points from component if USE_MY_METRICS flag set */ - if (item.flags & CompositeGlyphHeader::USE_MY_METRICS) + if (item.is_use_my_metrics ()) for (unsigned int i = 0; i < PHANTOM_COUNT; i++) phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i]; From e7aa8c5d22b034f3d7bcf187a63cdec27732fa8a Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sat, 12 Oct 2019 11:25:32 +0330 Subject: [PATCH 23/26] [glyf] Introduce glyf::Glyph, a hb_bytes_t/GlyphHeader pair --- src/hb-ot-glyf-table.hh | 177 +++++++++++++++++++++------------------- 1 file changed, 91 insertions(+), 86 deletions(-) diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index 0f4ffdde3..6ffd3f40d 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -180,8 +180,8 @@ struct glyf template void - _populate_subset_glyphs (const hb_subset_plan_t * plan, - hb_vector_t * glyphs /* OUT */) const + _populate_subset_glyphs (const hb_subset_plan_t *plan, + hb_vector_t *glyphs /* OUT */) const { OT::glyf::accelerator_t glyf; glyf.init (plan->source); @@ -198,7 +198,7 @@ struct glyf subset_glyph.source_glyph = glyf.bytes_for_glyph (subset_glyph.old_gid, true); if (plan->drop_hints) subset_glyph.drop_hints_bytes (); - else subset_glyph.dest_start = subset_glyph.source_glyph; + else subset_glyph.dest_start = subset_glyph.source_glyph.bytes; return subset_glyph; }) @@ -226,7 +226,7 @@ struct glyf return success; } - struct CompositeGlyphHeader + struct CompositeGlyphChain { enum composite_glyph_flag_t { @@ -357,31 +357,31 @@ struct glyf DEFINE_SIZE_MIN (4); }; - struct composite_iter_t : hb_iter_with_fallback_t + struct composite_iter_t : hb_iter_with_fallback_t { - typedef const CompositeGlyphHeader *__item_t__; + typedef const CompositeGlyphChain *__item_t__; composite_iter_t (hb_bytes_t glyph_, __item_t__ current_) : glyph (glyph_), current (current_) { if (!in_range (current)) current = nullptr; } composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr) {} - const CompositeGlyphHeader &__item__ () const { return *current; } + const CompositeGlyphChain &__item__ () const { return *current; } bool __more__ () const { return current; } void __next__ () { - if (!(current->flags & CompositeGlyphHeader::MORE_COMPONENTS)) { current = nullptr; return; } + if (!(current->flags & CompositeGlyphChain::MORE_COMPONENTS)) { current = nullptr; return; } - const CompositeGlyphHeader *possible = &StructAfter (*current); + const CompositeGlyphChain *possible = &StructAfter (*current); if (!in_range (possible)) { current = nullptr; return; } current = possible; } bool operator != (const composite_iter_t& o) const { return glyph != o.glyph || current != o.current; } - bool in_range (const CompositeGlyphHeader *composite) const + bool in_range (const CompositeGlyphChain *composite) const { return glyph.sub_array ((const char *) composite - (const char *) &glyph, - CompositeGlyphHeader::min_size).as () != &Null (CompositeGlyphHeader); + CompositeGlyphChain::min_size).as () != &Null (CompositeGlyphChain); } private: @@ -389,15 +389,32 @@ struct glyf __item_t__ current; }; - struct GlyphHeader + struct Glyph { - struct SimpleHeader + struct GlyphHeader + { + bool has_data () const { return numberOfContours; } + + 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 SimpleGlyph { const GlyphHeader &header; - SimpleHeader (const GlyphHeader &header_) : header (header_) {} + SimpleGlyph (const GlyphHeader &header_) : header (header_) {} unsigned int instruction_len_offset () const - { return static_size + 2 * header.numberOfContours; } + { return GlyphHeader::static_size + 2 * header.numberOfContours; } unsigned int length (unsigned int instruction_len) const { return instruction_len_offset () + 2 + instruction_len; } @@ -520,7 +537,7 @@ struct glyf if (unlikely (!checker.in_range (p))) return false; uint8_t flag = *p++; points_[i].flag = flag; - if ((flag & SimpleHeader::FLAG_REPEAT) != 0) + if ((flag & SimpleGlyph::FLAG_REPEAT) != 0) { if (unlikely (!checker.in_range (p))) return false; unsigned int repeat_count = *p++; @@ -535,24 +552,24 @@ struct glyf } }; - struct CompositeHeader + struct CompositeGlyph { const GlyphHeader &header; - CompositeHeader (const GlyphHeader &header_) : header (header_) {} + CompositeGlyph (const GlyphHeader &header_) : header (header_) {} composite_iter_t get_iterator (hb_bytes_t glyph) const - { return composite_iter_t (glyph, &StructAfter (header)); } + { return composite_iter_t (glyph, &StructAfter (header)); } unsigned int instructions_length (hb_bytes_t glyph) const { unsigned int start = glyph.length; unsigned int end = glyph.length; - const CompositeGlyphHeader *last = nullptr; + const CompositeGlyphChain *last = nullptr; for (auto &item : get_iterator (glyph)) last = &item; if (unlikely (!last)) return 0; - if ((uint16_t) last->flags & CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS) + if ((uint16_t) last->flags & CompositeGlyphChain::WE_HAVE_INSTRUCTIONS) start = (char *) last - &glyph + last->get_size (); if (unlikely (start > end)) return 0; return end - start; @@ -569,7 +586,7 @@ struct glyf for (const auto &_ : get_iterator (glyph_bytes)) { HBUINT16 &flags = *const_cast (&_.flags); - flags = (uint16_t) flags & ~OT::glyf::CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS; + flags = (uint16_t) flags & ~OT::glyf::CompositeGlyphChain::WE_HAVE_INSTRUCTIONS; } } @@ -600,38 +617,38 @@ struct glyf else return EMPTY; } - composite_iter_t get_composite_iterator (hb_bytes_t glyph) const + composite_iter_t get_composite_iterator () const { if (!is_composite_glyph ()) return composite_iter_t (); - return CompositeHeader (*this).get_iterator (glyph); + return CompositeGlyph (*header).get_iterator (bytes); } - hb_bytes_t bytes_without_padding (hb_bytes_t glyph_bytes) const + hb_bytes_t bytes_without_padding () const { switch (get_type ()) { - case COMPOSITE: return CompositeHeader (*this).bytes_without_padding (glyph_bytes); - case SIMPLE: return SimpleHeader (*this).bytes_without_padding (glyph_bytes); - default: return glyph_bytes; + case COMPOSITE: return CompositeGlyph (*header).bytes_without_padding (bytes); + case SIMPLE: return SimpleGlyph (*header).bytes_without_padding (bytes); + default: return bytes; } } - void drop_hints (hb_bytes_t glyph_bytes) + void drop_hints () { switch (get_type ()) { - case COMPOSITE: CompositeHeader (*this).drop_hints (glyph_bytes); return; - case SIMPLE: SimpleHeader (*this).drop_hints (); return; + case COMPOSITE: CompositeGlyph (*header).drop_hints (bytes); return; + case SIMPLE: SimpleGlyph (*header).drop_hints (); return; default: return; } } - void drop_hints_bytes (hb_bytes_t source_glyph, hb_bytes_t &dest_start, hb_bytes_t &dest_end) const + void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const { switch (get_type ()) { - case COMPOSITE: CompositeHeader (*this).drop_hints_bytes (source_glyph, dest_start); return; - case SIMPLE: SimpleHeader (*this).drop_hints_bytes (source_glyph, dest_start, dest_end); return; + case COMPOSITE: CompositeGlyph (*header).drop_hints_bytes (bytes, dest_start); return; + case SIMPLE: SimpleGlyph (*header).drop_hints_bytes (bytes, dest_start, dest_end); return; default: return; } } @@ -648,15 +665,15 @@ struct glyf struct x_setter_t { void set (contour_point_t &point, float v) const { point.x = v; } - bool is_short (uint8_t flag) const { return flag & SimpleHeader::FLAG_X_SHORT; } - bool is_same (uint8_t flag) const { return flag & SimpleHeader::FLAG_X_SAME; } + bool is_short (uint8_t flag) const { return flag & SimpleGlyph::FLAG_X_SHORT; } + bool is_same (uint8_t flag) const { return flag & SimpleGlyph::FLAG_X_SAME; } }; struct y_setter_t { void set (contour_point_t &point, float v) const { point.y = v; } - bool is_short (uint8_t flag) const { return flag & SimpleHeader::FLAG_Y_SHORT; } - bool is_same (uint8_t flag) const { return flag & SimpleHeader::FLAG_Y_SAME; } + bool is_short (uint8_t flag) const { return flag & SimpleGlyph::FLAG_Y_SHORT; } + bool is_same (uint8_t flag) const { return flag & SimpleGlyph::FLAG_Y_SAME; } }; template @@ -695,15 +712,14 @@ struct glyf * for a composite glyph, return pseudo component points * in both cases points trailed with four phantom points */ - bool get_contour_points (hb_bytes_t bytes, - contour_point_vector_t &points_ /* OUT */, + bool get_contour_points (contour_point_vector_t &points_ /* OUT */, hb_vector_t &end_points_ /* OUT */, const bool phantom_only=false) const { switch (get_type ()) { - case COMPOSITE: return CompositeHeader (*this).get_contour_points (bytes, points_, end_points_, phantom_only); - case SIMPLE: return SimpleHeader (*this).get_contour_points (bytes, points_, end_points_, phantom_only); + case COMPOSITE: return CompositeGlyph (*header).get_contour_points (bytes, points_, end_points_, phantom_only); + case SIMPLE: return SimpleGlyph (*header).get_contour_points (bytes, points_, end_points_, phantom_only); default: { /* empty glyph */ @@ -714,21 +730,14 @@ struct glyf } } - bool has_data () const { return numberOfContours; } - bool is_simple_glyph () const { return numberOfContours > 0; } - bool is_composite_glyph () const { return numberOfContours < 0; } + bool is_simple_glyph () const { return header->numberOfContours > 0; } + bool is_composite_glyph () const { return header->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. */ + const GlyphHeader *header; + hb_bytes_t bytes; - DEFINE_SIZE_STATIC (10); + Glyph (hb_bytes_t bytes_ = hb_bytes_t ()) + { bytes = bytes_; header = bytes.as (); } }; struct accelerator_t @@ -781,13 +790,13 @@ struct glyf protected: - void init_phantom_points (hb_codepoint_t glyph, hb_array_t &phantoms /* IN/OUT */) const + void init_phantom_points (hb_codepoint_t gid, hb_array_t &phantoms /* IN/OUT */) const { - const GlyphHeader &header = *bytes_for_glyph (glyph).as (); - int h_delta = (int) header.xMin - face->table.hmtx->get_side_bearing (glyph); - int v_orig = (int) header.yMax + face->table.vmtx->get_side_bearing (glyph); - unsigned int h_adv = face->table.hmtx->get_advance (glyph); - unsigned int v_adv = face->table.vmtx->get_advance (glyph); + const Glyph &glyph = bytes_for_glyph (gid); + int h_delta = (int) glyph.header->xMin - face->table.hmtx->get_side_bearing (gid); + int v_orig = (int) glyph.header->yMax + face->table.vmtx->get_side_bearing (gid); + unsigned int h_adv = face->table.hmtx->get_advance (gid); + unsigned int v_adv = face->table.vmtx->get_advance (gid); phantoms[PHANTOM_LEFT].x = h_delta; phantoms[PHANTOM_RIGHT].x = h_adv + h_delta; @@ -825,19 +834,18 @@ struct glyf if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return false; contour_point_vector_t points; hb_vector_t end_points; - hb_bytes_t bytes = bytes_for_glyph (glyph); - const GlyphHeader &glyph_header = *bytes.as (); - if (unlikely (!glyph_header.get_contour_points (bytes, points, end_points))) return false; + Glyph bytes = bytes_for_glyph (glyph); + if (unlikely (!bytes.get_contour_points (points, end_points))) return false; hb_array_t phantoms = points.sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT); init_phantom_points (glyph, phantoms); if (unlikely (!face->table.gvar->apply_deltas_to_points (glyph, coords, coord_count, points.as_array (), end_points.as_array ()))) return false; unsigned int comp_index = 0; - if (glyph_header.is_simple_glyph ()) + if (bytes.is_simple_glyph ()) all_points.extend (points.as_array ()); - else if (glyph_header.is_composite_glyph ()) + else if (bytes.is_composite_glyph ()) { - for (auto &item : glyph_header.get_composite_iterator (bytes)) + for (auto &item : bytes.get_composite_iterator ()) { contour_point_vector_t comp_points; if (unlikely (!get_points_var (item.glyphIndex, coords, coord_count, @@ -984,7 +992,7 @@ struct glyf if (unlikely (glyph >= num_glyphs)) return false; - const GlyphHeader &glyph_header = *bytes_for_glyph (glyph).as (); + const Glyph::GlyphHeader &glyph_header = *bytes_for_glyph (glyph).header; if (unlikely (!glyph_header.has_data ())) return true; /* Empty glyph; zero extents. */ @@ -998,11 +1006,11 @@ struct glyf return true; } - hb_bytes_t bytes_for_glyph (hb_codepoint_t gid, - bool needs_padding_removal = false) const + const Glyph + bytes_for_glyph (hb_codepoint_t gid, bool needs_padding_removal = false) const { unsigned int start_offset, end_offset; - if (unlikely (gid >= num_glyphs)) return hb_bytes_t (); + if (unlikely (gid >= num_glyphs)) return Glyph (); if (short_offset) { @@ -1018,19 +1026,19 @@ struct glyf } if (unlikely (start_offset > end_offset || end_offset > glyf_table.get_length ())) - return hb_bytes_t (); + return Glyph (); hb_bytes_t glyph_bytes ((const char *) this->glyf_table + start_offset, end_offset - start_offset); - const GlyphHeader &glyph_header = *glyph_bytes.as (); + const Glyph::GlyphHeader &glyph_header = *glyph_bytes.as (); /* Empty glyph or its size is smaller than minimum header */ - if (!glyph_header.has_data ()) return hb_bytes_t (); + if (!glyph_header.has_data ()) return Glyph (); - if (!needs_padding_removal) return glyph_bytes; + if (!needs_padding_removal) return Glyph (glyph_bytes); - return glyph_header.bytes_without_padding (glyph_bytes); + return Glyph (Glyph (glyph_bytes).bytes_without_padding ()); } void @@ -1043,9 +1051,7 @@ struct glyf gids_to_retain->add (gid); - hb_bytes_t glyph_bytes = bytes_for_glyph (gid); - const GlyphHeader &glyph_header = *glyph_bytes.as (); - for (auto &item : glyph_header.get_composite_iterator (glyph_bytes)) + for (auto &item : bytes_for_glyph (gid).get_composite_iterator ()) add_gid_and_children (item.glyphIndex, gids_to_retain, depth); } @@ -1061,7 +1067,7 @@ struct glyf { hb_codepoint_t new_gid; hb_codepoint_t old_gid; - hb_bytes_t source_glyph; + Glyph 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 */ @@ -1086,21 +1092,20 @@ struct glyf if (!unlikely (dest_glyph.length)) return_trace (true); /* update components gids */ - GlyphHeader &glyph_header = *const_cast (dest_glyph.as ()); - for (auto &_ : glyph_header.get_composite_iterator (dest_glyph)) + for (auto &_ : Glyph (dest_glyph).get_composite_iterator ()) { hb_codepoint_t new_gid; if (plan->new_gid_for_old_gid (_.glyphIndex, &new_gid)) - ((OT::glyf::CompositeGlyphHeader *) &_)->glyphIndex = new_gid; + ((OT::glyf::CompositeGlyphChain *) &_)->glyphIndex = new_gid; } - if (plan->drop_hints) glyph_header.drop_hints (dest_glyph); + if (plan->drop_hints) Glyph (dest_glyph).drop_hints (); return_trace (true); } void drop_hints_bytes () - { source_glyph.as ()->drop_hints_bytes (source_glyph, dest_start, dest_end); } + { source_glyph.drop_hints_bytes (dest_start, dest_end); } unsigned int length () const { return dest_start.length + dest_end.length; } /* pad to 2 to ensure 2-byte loca will be ok */ From d13bb4bd94a6ba8cdd4a03d40d8089a8f8b3a7ec Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sat, 12 Oct 2019 12:13:57 +0330 Subject: [PATCH 24/26] [glyf] other cleanups --- src/hb-ot-glyf-table.hh | 338 +++++++++++++++++++--------------------- 1 file changed, 160 insertions(+), 178 deletions(-) diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index 6ffd3f40d..59f9f6a51 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -196,9 +196,9 @@ struct glyf if (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid)) return subset_glyph; - subset_glyph.source_glyph = glyf.bytes_for_glyph (subset_glyph.old_gid, true); + subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true); if (plan->drop_hints) subset_glyph.drop_hints_bytes (); - else subset_glyph.dest_start = subset_glyph.source_glyph.bytes; + else subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes (); return subset_glyph; }) @@ -391,10 +391,23 @@ struct glyf struct Glyph { + private: struct GlyphHeader { bool has_data () const { return numberOfContours; } + bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const + { + /* Undocumented rasterizer behavior: shift glyph to the left by (lsb - xMin), i.e., xMin = lsb */ + /* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */ + extents->x_bearing = font->em_scale_x (font->face->table.hmtx->get_side_bearing (gid)); + extents->y_bearing = font->em_scale_y (hb_max (yMin, yMax)); + extents->width = font->em_scale_x (hb_max (xMin, xMax) - hb_min (xMin, xMax)); + extents->height = font->em_scale_y (hb_min (yMin, yMax) - hb_max (yMin, yMax)); + + return true; + } + HBINT16 numberOfContours; /* If the number of contours is * greater than or equal to zero, @@ -411,7 +424,9 @@ struct glyf struct SimpleGlyph { const GlyphHeader &header; - SimpleGlyph (const GlyphHeader &header_) : header (header_) {} + hb_bytes_t bytes; + SimpleGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) : + header (header_), bytes (bytes_) {} unsigned int instruction_len_offset () const { return GlyphHeader::static_size + 2 * header.numberOfContours; } @@ -419,14 +434,14 @@ struct glyf unsigned int length (unsigned int instruction_len) const { return instruction_len_offset () + 2 + instruction_len; } - unsigned int instructions_length (hb_bytes_t glyph) const + unsigned int instructions_length () const { unsigned int instruction_length_offset = instruction_len_offset (); - if (unlikely (instruction_length_offset + 2 > glyph.length)) return 0; + if (unlikely (instruction_length_offset + 2 > bytes.length)) return 0; - const HBUINT16 &instructionLength = StructAtOffset (&glyph, instruction_length_offset); + const HBUINT16 &instructionLength = StructAtOffset (&bytes, instruction_length_offset); /* Out of bounds of the current glyph */ - if (unlikely (length (instructionLength) > glyph.length)) return 0; + if (unlikely (length (instructionLength) > bytes.length)) return 0; return instructionLength; } @@ -442,11 +457,11 @@ struct glyf FLAG_RESERVED2 = 0x80 }; - hb_bytes_t bytes_without_padding (hb_bytes_t glyph_bytes) const + hb_bytes_t bytes_without_padding () const { /* based on FontTools _g_l_y_f.py::trim */ - const char *glyph = glyph_bytes.arrayZ; - const char *glyph_end = glyph + glyph_bytes.length; + const char *glyph = bytes.arrayZ; + const char *glyph_end = glyph + bytes.length; /* simple glyph w/contours, possibly trimmable */ glyph += instruction_len_offset (); @@ -486,7 +501,7 @@ struct glyf } 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)); + return bytes.sub_array (0, bytes.length + coord_bytes - (glyph_end - glyph)); } /* zero instruction length */ @@ -496,23 +511,67 @@ struct glyf (HBUINT16 &) StructAtOffset (&glyph_header, instruction_len_offset ()) = 0; } - void drop_hints_bytes (hb_bytes_t source_glyph, hb_bytes_t &dest_start, hb_bytes_t &dest_end) const + void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const { - unsigned int instructions_len = instructions_length (source_glyph); + unsigned int instructions_len = instructions_length (); unsigned int glyph_length = length (instructions_len); - dest_start = source_glyph.sub_array (0, glyph_length - instructions_len); - dest_end = source_glyph.sub_array (glyph_length, source_glyph.length - glyph_length); + dest_start = bytes.sub_array (0, glyph_length - instructions_len); + dest_end = bytes.sub_array (glyph_length, bytes.length - glyph_length); + } + + struct x_setter_t + { + void set (contour_point_t &point, float v) const { point.x = v; } + bool is_short (uint8_t flag) const { return flag & FLAG_X_SHORT; } + bool is_same (uint8_t flag) const { return flag & FLAG_X_SAME; } + }; + + struct y_setter_t + { + void set (contour_point_t &point, float v) const { point.y = v; } + bool is_short (uint8_t flag) const { return flag & FLAG_Y_SHORT; } + bool is_same (uint8_t flag) const { return flag & FLAG_Y_SAME; } + }; + + template + static bool read_points (const HBUINT8 *&p /* IN/OUT */, + contour_point_vector_t &points_ /* IN/OUT */, + const range_checker_t &checker) + { + T coord_setter; + float v = 0; + for (unsigned int i = 0; i < points_.length - PHANTOM_COUNT; i++) + { + uint8_t flag = points_[i].flag; + if (coord_setter.is_short (flag)) + { + if (unlikely (!checker.in_range (p))) return false; + if (coord_setter.is_same (flag)) + v += *p++; + else + v -= *p++; + } + else + { + if (!coord_setter.is_same (flag)) + { + if (unlikely (!checker.in_range ((const HBUINT16 *) p))) return false; + v += *(const HBINT16 *) p; + p += HBINT16::static_size; + } + } + coord_setter.set (points_[i], v); + } + return true; } - bool get_contour_points (hb_bytes_t bytes, - contour_point_vector_t &points_ /* OUT */, + bool get_contour_points (contour_point_vector_t &points_ /* OUT */, hb_vector_t &end_points_ /* OUT */, const bool phantom_only=false) const { - unsigned int num_points = 0; - const HBUINT16 *end_pts = &StructAfter (header); + const HBUINT16 *end_pts = &StructAfter (header); range_checker_t checker (bytes.arrayZ, 0, bytes.length); - num_points = 0; + unsigned int num_points = 0; int num_contours = header.numberOfContours; if (unlikely (!checker.in_range (&end_pts[num_contours + 1]))) return false; num_points = end_pts[num_contours - 1] + 1; @@ -537,7 +596,7 @@ struct glyf if (unlikely (!checker.in_range (p))) return false; uint8_t flag = *p++; points_[i].flag = flag; - if ((flag & SimpleGlyph::FLAG_REPEAT) != 0) + if ((flag & FLAG_REPEAT) != 0) { if (unlikely (!checker.in_range (p))) return false; unsigned int repeat_count = *p++; @@ -555,53 +614,49 @@ struct glyf struct CompositeGlyph { const GlyphHeader &header; - CompositeGlyph (const GlyphHeader &header_) : header (header_) {} + hb_bytes_t bytes; + CompositeGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) : + header (header_), bytes (bytes_) {} - composite_iter_t get_iterator (hb_bytes_t glyph) const - { return composite_iter_t (glyph, &StructAfter (header)); } + composite_iter_t get_iterator () const + { return composite_iter_t (bytes, &StructAfter (header)); } - unsigned int instructions_length (hb_bytes_t glyph) const + unsigned int instructions_length (hb_bytes_t bytes) const { - unsigned int start = glyph.length; - unsigned int end = glyph.length; + unsigned int start = bytes.length; + unsigned int end = bytes.length; const CompositeGlyphChain *last = nullptr; - for (auto &item : get_iterator (glyph)) + for (auto &item : get_iterator ()) last = &item; if (unlikely (!last)) return 0; if ((uint16_t) last->flags & CompositeGlyphChain::WE_HAVE_INSTRUCTIONS) - start = (char *) last - &glyph + last->get_size (); + start = (char *) last - &bytes + last->get_size (); if (unlikely (start > end)) return 0; return end - start; } /* 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; } + hb_bytes_t bytes_without_padding () const { return bytes; } /* remove WE_HAVE_INSTRUCTIONS flag from composite glyph */ - void drop_hints (hb_bytes_t glyph_bytes) + void drop_hints () { - for (const auto &_ : get_iterator (glyph_bytes)) - { - HBUINT16 &flags = *const_cast (&_.flags); - flags = (uint16_t) flags & ~OT::glyf::CompositeGlyphChain::WE_HAVE_INSTRUCTIONS; - } + for (const auto &_ : get_iterator ()) + *const_cast (&_.flags) = (uint16_t) _.flags & ~OT::glyf::CompositeGlyphChain::WE_HAVE_INSTRUCTIONS; } /* Chop instructions off the end */ - void drop_hints_bytes (hb_bytes_t source_glyph, hb_bytes_t &dest_start) const - { dest_start = source_glyph.sub_array (0, source_glyph.length - instructions_length (source_glyph)); } + void drop_hints_bytes (hb_bytes_t &dest_start) const + { dest_start = bytes.sub_array (0, bytes.length - instructions_length (bytes)); } - bool get_contour_points (hb_bytes_t bytes, - contour_point_vector_t &points_ /* OUT */, + bool get_contour_points (contour_point_vector_t &points_ /* OUT */, hb_vector_t &end_points_ /* OUT */, const bool phantom_only=false) const { - unsigned int num_points = 0; /* add one pseudo point for each component in composite glyph */ - num_points += hb_len (get_iterator (bytes)); + unsigned int num_points = hb_len (get_iterator ()); points_.resize (num_points + PHANTOM_COUNT); for (unsigned int i = 0; i < points_.length; i++) points_[i].init (); return true; @@ -610,104 +665,49 @@ struct glyf enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE }; - unsigned get_type () const + enum phantom_point_index_t { - if (is_simple_glyph ()) return SIMPLE; - else if (is_composite_glyph ()) return COMPOSITE; - else return EMPTY; - } + PHANTOM_LEFT = 0, + PHANTOM_RIGHT = 1, + PHANTOM_TOP = 2, + PHANTOM_BOTTOM = 3, + PHANTOM_COUNT = 4 + }; + public: composite_iter_t get_composite_iterator () const { - if (!is_composite_glyph ()) return composite_iter_t (); - return CompositeGlyph (*header).get_iterator (bytes); + if (type != COMPOSITE) return composite_iter_t (); + return CompositeGlyph (*header, bytes).get_iterator (); } hb_bytes_t bytes_without_padding () const { - switch (get_type ()) - { - case COMPOSITE: return CompositeGlyph (*header).bytes_without_padding (bytes); - case SIMPLE: return SimpleGlyph (*header).bytes_without_padding (bytes); + switch (type) { + case COMPOSITE: return CompositeGlyph (*header, bytes).bytes_without_padding (); + case SIMPLE: return SimpleGlyph (*header, bytes).bytes_without_padding (); default: return bytes; } } void drop_hints () { - switch (get_type ()) - { - case COMPOSITE: CompositeGlyph (*header).drop_hints (bytes); return; - case SIMPLE: SimpleGlyph (*header).drop_hints (); return; + switch (type) { + case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return; + case SIMPLE: SimpleGlyph (*header, bytes).drop_hints (); return; default: return; } } void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const { - switch (get_type ()) - { - case COMPOSITE: CompositeGlyph (*header).drop_hints_bytes (bytes, dest_start); return; - case SIMPLE: SimpleGlyph (*header).drop_hints_bytes (bytes, dest_start, dest_end); return; + switch (type) { + case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return; + case SIMPLE: SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return; default: return; } } - enum phantom_point_index_t - { - PHANTOM_LEFT = 0, - PHANTOM_RIGHT = 1, - PHANTOM_TOP = 2, - PHANTOM_BOTTOM = 3, - PHANTOM_COUNT = 4 - }; - - struct x_setter_t - { - void set (contour_point_t &point, float v) const { point.x = v; } - bool is_short (uint8_t flag) const { return flag & SimpleGlyph::FLAG_X_SHORT; } - bool is_same (uint8_t flag) const { return flag & SimpleGlyph::FLAG_X_SAME; } - }; - - struct y_setter_t - { - void set (contour_point_t &point, float v) const { point.y = v; } - bool is_short (uint8_t flag) const { return flag & SimpleGlyph::FLAG_Y_SHORT; } - bool is_same (uint8_t flag) const { return flag & SimpleGlyph::FLAG_Y_SAME; } - }; - - template - static bool read_points (const HBUINT8 *&p /* IN/OUT */, - contour_point_vector_t &points_ /* IN/OUT */, - const range_checker_t &checker) - { - T coord_setter; - float v = 0; - for (unsigned int i = 0; i < points_.length - PHANTOM_COUNT; i++) - { - uint8_t flag = points_[i].flag; - if (coord_setter.is_short (flag)) - { - if (unlikely (!checker.in_range (p))) return false; - if (coord_setter.is_same (flag)) - v += *p++; - else - v -= *p++; - } - else - { - if (!coord_setter.is_same (flag)) - { - if (unlikely (!checker.in_range ((const HBUINT16 *) p))) return false; - v += *(const HBINT16 *) p; - p += HBINT16::static_size; - } - } - coord_setter.set (points_[i], v); - } - return true; - } - /* for a simple glyph, return contour end points, flags, along with coordinate points * for a composite glyph, return pseudo component points * in both cases points trailed with four phantom points @@ -716,28 +716,41 @@ struct glyf hb_vector_t &end_points_ /* OUT */, const bool phantom_only=false) const { - switch (get_type ()) - { - case COMPOSITE: return CompositeGlyph (*header).get_contour_points (bytes, points_, end_points_, phantom_only); - case SIMPLE: return SimpleGlyph (*header).get_contour_points (bytes, points_, end_points_, phantom_only); + switch (type) { + case COMPOSITE: return CompositeGlyph (*header, bytes).get_contour_points (points_, end_points_, phantom_only); + case SIMPLE: return SimpleGlyph (*header, bytes).get_contour_points (points_, end_points_, phantom_only); default: - { /* empty glyph */ points_.resize (PHANTOM_COUNT); for (unsigned int i = 0; i < points_.length; i++) points_[i].init (); return true; } - } } bool is_simple_glyph () const { return header->numberOfContours > 0; } bool is_composite_glyph () const { return header->numberOfContours < 0; } - const GlyphHeader *header; - hb_bytes_t bytes; + bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const + { + if (type == EMPTY) return true; /* Empty glyph; zero extents. */ + return header->get_extents (font, gid, extents); + } - Glyph (hb_bytes_t bytes_ = hb_bytes_t ()) - { bytes = bytes_; header = bytes.as (); } + hb_bytes_t get_bytes () const { return bytes; } + const GlyphHeader &get_header () const { return *header; } + + Glyph (hb_bytes_t bytes_ = hb_bytes_t ()) : + bytes (bytes_), header (bytes.as ()) + { + if (is_simple_glyph ()) type = SIMPLE; + else if (is_composite_glyph ()) type = COMPOSITE; + else type = EMPTY; + } + + protected: + hb_bytes_t bytes; + const GlyphHeader *header; + unsigned type; }; struct accelerator_t @@ -767,18 +780,6 @@ struct glyf glyf_table.destroy (); } - 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 - }; - enum phantom_point_index_t { PHANTOM_LEFT = 0, @@ -792,9 +793,9 @@ struct glyf void init_phantom_points (hb_codepoint_t gid, hb_array_t &phantoms /* IN/OUT */) const { - const Glyph &glyph = bytes_for_glyph (gid); - int h_delta = (int) glyph.header->xMin - face->table.hmtx->get_side_bearing (gid); - int v_orig = (int) glyph.header->yMax + face->table.vmtx->get_side_bearing (gid); + const Glyph &glyph = glyph_for_gid (gid); + int h_delta = (int) glyph.get_header ().xMin - face->table.hmtx->get_side_bearing (gid); + int v_orig = (int) glyph.get_header ().yMax + face->table.vmtx->get_side_bearing (gid); unsigned int h_adv = face->table.hmtx->get_advance (gid); unsigned int v_adv = face->table.vmtx->get_advance (gid); @@ -826,7 +827,7 @@ struct glyf /* Note: Recursively calls itself. * all_points includes phantom points */ - bool get_points_var (hb_codepoint_t glyph, + bool get_points_var (hb_codepoint_t gid, const int *coords, unsigned int coord_count, contour_point_vector_t &all_points /* OUT */, unsigned int depth = 0) const @@ -834,18 +835,18 @@ struct glyf if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return false; contour_point_vector_t points; hb_vector_t end_points; - Glyph bytes = bytes_for_glyph (glyph); - if (unlikely (!bytes.get_contour_points (points, end_points))) return false; + const Glyph &glyph = glyph_for_gid (gid); + if (unlikely (!glyph.get_contour_points (points, end_points))) return false; hb_array_t phantoms = points.sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT); - init_phantom_points (glyph, phantoms); - if (unlikely (!face->table.gvar->apply_deltas_to_points (glyph, coords, coord_count, points.as_array (), end_points.as_array ()))) return false; + init_phantom_points (gid, phantoms); + if (unlikely (!face->table.gvar->apply_deltas_to_points (gid, coords, coord_count, points.as_array (), end_points.as_array ()))) return false; unsigned int comp_index = 0; - if (bytes.is_simple_glyph ()) + if (glyph.is_simple_glyph ()) all_points.extend (points.as_array ()); - else if (bytes.is_composite_glyph ()) + else if (glyph.is_composite_glyph ()) { - for (auto &item : bytes.get_composite_iterator ()) + for (auto &item : glyph.get_composite_iterator ()) { contour_point_vector_t comp_points; if (unlikely (!get_points_var (item.glyphIndex, coords, coord_count, @@ -981,33 +982,22 @@ struct glyf } #endif - bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const + bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const { #ifndef HB_NO_VAR unsigned int coord_count; const int *coords = hb_font_get_var_coords_normalized (font, &coord_count); if (coords && coord_count > 0 && coord_count == face->table.gvar->get_axis_count ()) - return get_extents_var (font, glyph, extents); + return get_extents_var (font, gid, extents); #endif - if (unlikely (glyph >= num_glyphs)) return false; - - const Glyph::GlyphHeader &glyph_header = *bytes_for_glyph (glyph).header; - if (unlikely (!glyph_header.has_data ())) - return true; /* Empty glyph; zero extents. */ - - /* Undocumented rasterizer behavior: shift glyph to the left by (lsb - xMin), i.e., xMin = lsb */ - /* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */ - extents->x_bearing = font->em_scale_x (face->table.hmtx->get_side_bearing (glyph)); - extents->y_bearing = font->em_scale_y (hb_max (glyph_header.yMin, glyph_header.yMax)); - extents->width = font->em_scale_x (hb_max (glyph_header.xMin, glyph_header.xMax) - hb_min (glyph_header.xMin, glyph_header.xMax)); - extents->height = font->em_scale_y (hb_min (glyph_header.yMin, glyph_header.yMax) - hb_max (glyph_header.yMin, glyph_header.yMax)); + if (unlikely (gid >= num_glyphs)) return false; - return true; + return glyph_for_gid (gid).get_extents (font, gid, extents); } const Glyph - bytes_for_glyph (hb_codepoint_t gid, bool needs_padding_removal = false) const + glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const { unsigned int start_offset, end_offset; if (unlikely (gid >= num_glyphs)) return Glyph (); @@ -1028,17 +1018,9 @@ struct glyf if (unlikely (start_offset > end_offset || end_offset > glyf_table.get_length ())) return Glyph (); - hb_bytes_t glyph_bytes ((const char *) this->glyf_table + start_offset, - end_offset - start_offset); - - const Glyph::GlyphHeader &glyph_header = *glyph_bytes.as (); - - /* Empty glyph or its size is smaller than minimum header */ - if (!glyph_header.has_data ()) return Glyph (); - - if (!needs_padding_removal) return Glyph (glyph_bytes); - - return Glyph (Glyph (glyph_bytes).bytes_without_padding ()); + Glyph glyph (hb_bytes_t ((const char *) this->glyf_table + start_offset, + end_offset - start_offset)); + return needs_padding_removal ? Glyph (glyph.bytes_without_padding ()) : glyph; } void @@ -1051,7 +1033,7 @@ struct glyf gids_to_retain->add (gid); - for (auto &item : bytes_for_glyph (gid).get_composite_iterator ()) + for (auto &item : glyph_for_gid (gid).get_composite_iterator ()) add_gid_and_children (item.glyphIndex, gids_to_retain, depth); } From 06e35ce052388e7ce079c0250db62428ae0c5bc8 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sat, 12 Oct 2019 15:16:31 +0330 Subject: [PATCH 25/26] [glyf] minor --- src/hb-ot-glyf-table.hh | 128 +++++++++++++++++++++------------------- 1 file changed, 67 insertions(+), 61 deletions(-) diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index 59f9f6a51..fd54bd396 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -83,8 +83,7 @@ struct glyf bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const { TRACE_SANITIZE (this); - /* We don't check for anything specific here. The users of the - * struct do all the hard work... */ + /* Runtime checks as eager sanitizing each glyph is costy */ return_trace (true); } @@ -142,7 +141,7 @@ struct glyf ; } - // requires source of SubsetGlyph complains the identifier isn't declared + /* requires source of SubsetGlyph complains the identifier isn't declared */ template bool serialize (hb_serialize_context_t *c, Iterator it, @@ -153,6 +152,9 @@ struct glyf return_trace (true); } + /* 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 */ bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); @@ -160,9 +162,6 @@ struct glyf glyf *glyf_prime = c->serializer->start_embed (); 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 glyphs; _populate_subset_glyphs (c->plan, &glyphs); @@ -192,7 +191,7 @@ struct glyf SubsetGlyph subset_glyph = {0}; 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; @@ -244,29 +243,26 @@ struct glyf UNSCALED_COMPONENT_OFFSET = 0x1000 }; - HBUINT16 flags; - HBGlyphID glyphIndex; - unsigned int get_size () const { unsigned int size = min_size; - // arg1 and 2 are int16 + /* arg1 and 2 are int16 */ if (flags & ARG_1_AND_2_ARE_WORDS) size += 4; - // arg1 and 2 are int8 + /* arg1 and 2 are int8 */ else size += 2; - // One x 16 bit (scale) + /* One x 16 bit (scale) */ if (flags & WE_HAVE_A_SCALE) size += 2; - // Two x 16 bit (xscale, yscale) + /* Two x 16 bit (xscale, yscale) */ else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) size += 4; - // Four x 16 bit (xscale, scale01, scale10, yscale) + /* Four x 16 bit (xscale, scale01, scale10, yscale) */ else if (flags & WE_HAVE_A_TWO_BY_TWO) size += 8; return size; } - bool is_use_my_metrics () const { return flags & USE_MY_METRICS; } - bool is_anchored () const { return (flags & ARGS_ARE_XY_VALUES) == 0; } + bool is_use_my_metrics () const { return flags & USE_MY_METRICS; } + bool is_anchored () const { return !(flags & ARGS_ARE_XY_VALUES); } void get_anchor_points (unsigned int &point1, unsigned int &point2) const { const HBUINT8 *p = &StructAfter (glyphIndex); @@ -353,6 +349,9 @@ struct glyf return tx || ty; } + public: + HBUINT16 flags; + HBGlyphID glyphIndex; public: DEFINE_SIZE_MIN (4); }; @@ -371,7 +370,7 @@ struct glyf if (!(current->flags & CompositeGlyphChain::MORE_COMPONENTS)) { current = nullptr; return; } const CompositeGlyphChain *possible = &StructAfter (*current); + CompositeGlyphChain> (*current); if (!in_range (possible)) { current = nullptr; return; } current = possible; } @@ -417,7 +416,7 @@ struct glyf FWORD yMin; /* Minimum y for coordinate data. */ FWORD xMax; /* Maximum x for coordinate data. */ FWORD yMax; /* Maximum y for coordinate data. */ - + public: DEFINE_SIZE_STATIC (10); }; @@ -457,7 +456,7 @@ struct glyf FLAG_RESERVED2 = 0x80 }; - hb_bytes_t bytes_without_padding () const + const Glyph trim_padding () const { /* based on FontTools _g_l_y_f.py::trim */ const char *glyph = bytes.arrayZ; @@ -465,12 +464,12 @@ struct glyf /* simple glyph w/contours, possibly trimmable */ glyph += instruction_len_offset (); - if (unlikely (glyph + 2 >= glyph_end)) return hb_bytes_t (); + if (unlikely (glyph + 2 >= glyph_end)) return Glyph (); unsigned int num_coordinates = StructAtOffset (glyph - 2, 0) + 1; unsigned int num_instructions = StructAtOffset (glyph, 0); glyph += 2 + num_instructions; - if (unlikely (glyph + 2 >= glyph_end)) return hb_bytes_t (); + if (unlikely (glyph + 2 >= glyph_end)) return Glyph (); unsigned int coord_bytes = 0; unsigned int coords_with_flags = 0; @@ -482,7 +481,7 @@ struct glyf unsigned int repeat = 1; if (flag & FLAG_REPEAT) { - if (unlikely (glyph >= glyph_end)) return hb_bytes_t (); + if (unlikely (glyph >= glyph_end)) return Glyph (); repeat = *glyph + 1; glyph++; } @@ -500,8 +499,8 @@ struct glyf if (coords_with_flags >= num_coordinates) break; } - if (unlikely (coords_with_flags != num_coordinates)) return hb_bytes_t (); - return bytes.sub_array (0, bytes.length + coord_bytes - (glyph_end - glyph)); + if (unlikely (coords_with_flags != num_coordinates)) return Glyph (); + return Glyph (bytes.sub_array (0, bytes.length + coord_bytes - (glyph_end - glyph))); } /* zero instruction length */ @@ -569,12 +568,11 @@ struct glyf hb_vector_t &end_points_ /* OUT */, const bool phantom_only=false) const { - const HBUINT16 *end_pts = &StructAfter (header); + const HBUINT16 *endPtsOfContours = &StructAfter (header); range_checker_t checker (bytes.arrayZ, 0, bytes.length); - unsigned int num_points = 0; int num_contours = header.numberOfContours; - if (unlikely (!checker.in_range (&end_pts[num_contours + 1]))) return false; - num_points = end_pts[num_contours - 1] + 1; + if (unlikely (!checker.in_range (&endPtsOfContours[num_contours + 1]))) return false; + unsigned int num_points = endPtsOfContours[num_contours - 1] + 1; points_.resize (num_points + PHANTOM_COUNT); for (unsigned int i = 0; i < points_.length; i++) points_[i].init (); @@ -584,11 +582,11 @@ struct glyf end_points_.resize (num_contours); for (int i = 0; i < num_contours; i++) - end_points_[i] = end_pts[i]; + end_points_[i] = endPtsOfContours[i]; /* Skip instructions */ - const HBUINT8 *p = &StructAtOffset (&end_pts[num_contours + 1], - end_pts[num_contours]); + const HBUINT8 *p = &StructAtOffset (&endPtsOfContours[num_contours + 1], + endPtsOfContours[num_contours]); /* Read flags */ for (unsigned int i = 0; i < num_points; i++) @@ -596,7 +594,7 @@ struct glyf if (unlikely (!checker.in_range (p))) return false; uint8_t flag = *p++; points_[i].flag = flag; - if ((flag & FLAG_REPEAT) != 0) + if (flag & FLAG_REPEAT) { if (unlikely (!checker.in_range (p))) return false; unsigned int repeat_count = *p++; @@ -638,7 +636,7 @@ struct glyf /* Trimming for composites not implemented. * If removing hints it falls out of that. */ - hb_bytes_t bytes_without_padding () const { return bytes; } + const Glyph trim_padding () const { return Glyph (bytes); } /* remove WE_HAVE_INSTRUCTIONS flag from composite glyph */ void drop_hints () @@ -681,11 +679,11 @@ struct glyf return CompositeGlyph (*header, bytes).get_iterator (); } - hb_bytes_t bytes_without_padding () const + const Glyph trim_padding () const { switch (type) { - case COMPOSITE: return CompositeGlyph (*header, bytes).bytes_without_padding (); - case SIMPLE: return SimpleGlyph (*header, bytes).bytes_without_padding (); + case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding (); + case SIMPLE: return SimpleGlyph (*header, bytes).trim_padding (); default: return bytes; } } @@ -727,8 +725,8 @@ struct glyf } } - bool is_simple_glyph () const { return header->numberOfContours > 0; } - bool is_composite_glyph () const { return header->numberOfContours < 0; } + bool is_simple_glyph () const { return type == SIMPLE; } + bool is_composite_glyph () const { return type == COMPOSITE; } bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const { @@ -742,9 +740,10 @@ struct glyf Glyph (hb_bytes_t bytes_ = hb_bytes_t ()) : bytes (bytes_), header (bytes.as ()) { - if (is_simple_glyph ()) type = SIMPLE; - else if (is_composite_glyph ()) type = COMPOSITE; - else type = EMPTY; + int num_contours = header->numberOfContours; + if (unlikely (num_contours == 0)) type = EMPTY; + else if (num_contours > 0) type = SIMPLE; + else type = COMPOSITE; /* negative numbers */ } protected: @@ -763,7 +762,7 @@ struct glyf glyf_table = nullptr; face = face_; const OT::head &head = *face->table.head; - if (head.indexToLocFormat > 1 || head.glyphDataFormat != 0) + if (head.indexToLocFormat > 1 || head.glyphDataFormat > 0) /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */ return; short_offset = 0 == head.indexToLocFormat; @@ -891,12 +890,9 @@ struct glyf return true; } - bool get_var_extents_and_phantoms (hb_font_t *font, hb_codepoint_t glyph, - hb_glyph_extents_t *extents=nullptr /* OUT */, - contour_point_vector_t *phantoms=nullptr /* OUT */) const + bool get_points_bearing_applied (hb_font_t *font, hb_codepoint_t gid, contour_point_vector_t &all_points) const { - contour_point_vector_t all_points; - if (unlikely (!get_points_var (glyph, font->coords, font->num_coords, all_points) || + if (unlikely (!get_points_var (gid, font->coords, font->num_coords, all_points) || all_points.length < PHANTOM_COUNT)) return false; /* Undocumented rasterizer behavior: @@ -904,9 +900,19 @@ struct glyf */ contour_point_t delta; delta.init (-all_points[all_points.length - PHANTOM_COUNT + PHANTOM_LEFT].x, 0.f); - if (delta.x != 0.f) all_points.translate (delta); + if (delta.x) all_points.translate (delta); + return true; + } + + protected: - if (extents != nullptr) + bool get_var_extents_and_phantoms (hb_font_t *font, hb_codepoint_t gid, + hb_glyph_extents_t *extents=nullptr /* OUT */, + contour_point_vector_t *phantoms=nullptr /* OUT */) const + { + contour_point_vector_t all_points; + if (!unlikely (get_points_bearing_applied (font, gid, all_points))) return false; + if (extents) { contour_bounds_t bounds; for (unsigned int i = 0; i + PHANTOM_COUNT < all_points.length; i++) @@ -939,18 +945,18 @@ struct glyf return true; } - bool get_var_metrics (hb_font_t *font, hb_codepoint_t glyph, + bool get_var_metrics (hb_font_t *font, hb_codepoint_t gid, contour_point_vector_t &phantoms) const - { return get_var_extents_and_phantoms (font, glyph, nullptr, &phantoms); } + { return get_var_extents_and_phantoms (font, gid, nullptr, &phantoms); } - bool get_extents_var (hb_font_t *font, hb_codepoint_t glyph, + bool get_extents_var (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const - { return get_var_extents_and_phantoms (font, glyph, extents); } + { return get_var_extents_and_phantoms (font, gid, extents); } #endif public: #ifndef HB_NO_VAR - unsigned int get_advance_var (hb_font_t *font, hb_codepoint_t glyph, + unsigned int get_advance_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const { bool success = false; @@ -958,10 +964,10 @@ struct glyf phantoms.resize (PHANTOM_COUNT); if (likely (font->num_coords == face->table.gvar->get_axis_count ())) - success = get_var_metrics (font, glyph, phantoms); + success = get_var_metrics (font, gid, phantoms); if (unlikely (!success)) - return is_vertical ? face->table.vmtx->get_advance (glyph) : face->table.hmtx->get_advance (glyph); + return is_vertical ? face->table.vmtx->get_advance (gid) : face->table.hmtx->get_advance (gid); if (is_vertical) return roundf (phantoms[PHANTOM_TOP].y - phantoms[PHANTOM_BOTTOM].y); @@ -969,14 +975,14 @@ struct glyf return roundf (phantoms[PHANTOM_RIGHT].x - phantoms[PHANTOM_LEFT].x); } - int get_side_bearing_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical) const + int get_side_bearing_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const { hb_glyph_extents_t extents; contour_point_vector_t phantoms; phantoms.resize (PHANTOM_COUNT); - if (unlikely (!get_var_extents_and_phantoms (font, glyph, &extents, &phantoms))) - return is_vertical ? face->table.vmtx->get_side_bearing (glyph) : face->table.hmtx->get_side_bearing (glyph); + if (unlikely (!get_var_extents_and_phantoms (font, gid, &extents, &phantoms))) + return is_vertical ? face->table.vmtx->get_side_bearing (gid) : face->table.hmtx->get_side_bearing (gid); return is_vertical ? ceil (phantoms[PHANTOM_TOP].y) - extents.y_bearing : floor (phantoms[PHANTOM_LEFT].x); } @@ -1020,7 +1026,7 @@ struct glyf Glyph glyph (hb_bytes_t ((const char *) this->glyf_table + start_offset, end_offset - start_offset)); - return needs_padding_removal ? Glyph (glyph.bytes_without_padding ()) : glyph; + return needs_padding_removal ? glyph.trim_padding () : glyph; } void From b0b8551afc2ff86d027fdb380210601cb465af41 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sat, 12 Oct 2019 21:12:19 +0330 Subject: [PATCH 26/26] [glyf] Use range_checker_t in composite_iter_t --- src/hb-ot-glyf-table.hh | 12 +++++++----- src/hb-ot-var-gvar-table.hh | 19 +++++++++---------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index fd54bd396..f5a64b050 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -359,9 +359,10 @@ struct glyf struct composite_iter_t : hb_iter_with_fallback_t { typedef const CompositeGlyphChain *__item_t__; - composite_iter_t (hb_bytes_t glyph_, __item_t__ current_) : glyph (glyph_), current (current_) + composite_iter_t (hb_bytes_t glyph_, __item_t__ current_) : + glyph (glyph_), current (current_), checker (range_checker_t (glyph.arrayZ, glyph.length)) { if (!in_range (current)) current = nullptr; } - composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr) {} + composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr), checker (range_checker_t (nullptr, 0)) {} const CompositeGlyphChain &__item__ () const { return *current; } bool __more__ () const { return current; } @@ -379,13 +380,14 @@ struct glyf bool in_range (const CompositeGlyphChain *composite) const { - return glyph.sub_array ((const char *) composite - (const char *) &glyph, - CompositeGlyphChain::min_size).as () != &Null (CompositeGlyphChain); + return checker.in_range (composite, CompositeGlyphChain::min_size) + && checker.in_range (composite, composite->get_size ()); } private: hb_bytes_t glyph; __item_t__ current; + range_checker_t checker; }; struct Glyph @@ -569,7 +571,7 @@ struct glyf const bool phantom_only=false) const { const HBUINT16 *endPtsOfContours = &StructAfter (header); - range_checker_t checker (bytes.arrayZ, 0, bytes.length); + range_checker_t checker (bytes.arrayZ, bytes.length); int num_contours = header.numberOfContours; if (unlikely (!checker.in_range (&endPtsOfContours[num_contours + 1]))) return false; unsigned int num_points = endPtsOfContours[num_contours - 1] + 1; diff --git a/src/hb-ot-var-gvar-table.hh b/src/hb-ot-var-gvar-table.hh index 510174c35..666b30895 100644 --- a/src/hb-ot-var-gvar-table.hh +++ b/src/hb-ot-var-gvar-table.hh @@ -80,20 +80,19 @@ struct contour_point_vector_t : hb_vector_t struct range_checker_t { - range_checker_t (const void *table_, unsigned int start_offset_, unsigned int end_offset_) - : table ((const char*) table_), start_offset (start_offset_), end_offset (end_offset_) {} + range_checker_t (const void *data_, unsigned int length_) + : data ((const char *) data_), length (length_) {} template - bool in_range (const T *p) const + bool in_range (const T *p, unsigned int size = T::static_size) const { - return ((const char *) p) >= table + start_offset - && ((const char *) p + T::static_size) <= table + end_offset; + return ((const char *) p) >= data + && ((const char *) p + size) <= data + length; } protected: - const char *table; - const unsigned int start_offset; - const unsigned int end_offset; + const char *data; + const unsigned int length; }; struct Tuple : UnsizedArrayOf {}; @@ -234,7 +233,7 @@ struct GlyphVarData { if (var_data->has_shared_point_numbers ()) { - range_checker_t checker (var_data, 0, length); + range_checker_t checker (var_data, length); const HBUINT8 *base = &(var_data+var_data->data); const HBUINT8 *p = base; if (!unpack_points (p, shared_indices, checker)) return false; @@ -612,7 +611,7 @@ struct gvar if (unlikely (!iterator.in_range (p, length))) return false; - range_checker_t checker (p, 0, length); + range_checker_t checker (p, length); hb_vector_t private_indices; if (iterator.current_tuple->has_private_points () && !GlyphVarData::unpack_points (p, private_indices, checker))