Merge pull request #3759 from googlefonts/update_glyf
[instance] update glyf/hmtx/vmtx/OS2/post tables
This commit is contained in:
commit
82dc23f2a1
|
@ -105,6 +105,29 @@ struct CompositeGlyphRecord
|
|||
}
|
||||
}
|
||||
|
||||
void apply_delta_to_offsets (const contour_point_t &p_delta)
|
||||
{
|
||||
HBINT8 *p = &StructAfter<HBINT8> (flags);
|
||||
#ifndef HB_NO_BEYOND_64K
|
||||
if (flags & GID_IS_24BIT)
|
||||
p += HBGlyphID24::static_size;
|
||||
else
|
||||
#endif
|
||||
p += HBGlyphID16::static_size;
|
||||
|
||||
if (flags & ARG_1_AND_2_ARE_WORDS)
|
||||
{
|
||||
HBINT16 *px = reinterpret_cast<HBINT16 *> (p);
|
||||
px[0] += roundf (p_delta.x);
|
||||
px[1] += roundf (p_delta.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
p[0] += roundf (p_delta.x);
|
||||
p[1] += roundf (p_delta.y);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
bool scaled_offsets () const
|
||||
{ return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; }
|
||||
|
@ -288,6 +311,39 @@ struct CompositeGlyph
|
|||
return;
|
||||
glyph_chain.set_overlaps_flag ();
|
||||
}
|
||||
|
||||
bool compile_bytes_with_deltas (const hb_bytes_t &source_bytes,
|
||||
const contour_point_vector_t &deltas,
|
||||
hb_bytes_t &dest_bytes /* OUT */)
|
||||
{
|
||||
int len = source_bytes.length - GlyphHeader::static_size;
|
||||
if (len <= 0 || header.numberOfContours != -1)
|
||||
{
|
||||
dest_bytes = hb_bytes_t ();
|
||||
return true;
|
||||
}
|
||||
|
||||
char *p = (char *) hb_calloc (len, sizeof (char));
|
||||
if (unlikely (!p)) return false;
|
||||
|
||||
memcpy (p, source_bytes.arrayZ + GlyphHeader::static_size, len);
|
||||
dest_bytes = hb_bytes_t (p, len);
|
||||
|
||||
auto it = composite_iter_t (dest_bytes, (CompositeGlyphRecord *)p);
|
||||
|
||||
unsigned i = 0;
|
||||
for (auto &component : it)
|
||||
{
|
||||
if (!component.is_anchored ())
|
||||
{
|
||||
/* last 4 points in deltas are phantom points and should not be included*/
|
||||
if (i >= deltas.length - 4) return false;
|
||||
const_cast<CompositeGlyphRecord &> (component).apply_delta_to_offsets (deltas[i]);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -72,12 +72,110 @@ struct Glyph
|
|||
}
|
||||
}
|
||||
|
||||
void update_mtx (const hb_subset_plan_t *plan,
|
||||
int xMin, int yMax,
|
||||
const contour_point_vector_t &all_points) const
|
||||
{
|
||||
hb_codepoint_t new_gid = 0;
|
||||
if (!plan->new_gid_for_old_gid (gid, &new_gid))
|
||||
return;
|
||||
|
||||
unsigned len = all_points.length;
|
||||
float leftSideX = all_points[len - 4].x;
|
||||
float rightSideX = all_points[len - 3].x;
|
||||
float topSideY = all_points[len - 2].y;
|
||||
float bottomSideY = all_points[len - 1].y;
|
||||
|
||||
int hori_aw = roundf (rightSideX - leftSideX);
|
||||
if (hori_aw < 0) hori_aw = 0;
|
||||
int lsb = roundf (xMin - leftSideX);
|
||||
plan->hmtx_map->set (new_gid, hb_pair (hori_aw, lsb));
|
||||
|
||||
int vert_aw = roundf (topSideY - bottomSideY);
|
||||
if (vert_aw < 0) vert_aw = 0;
|
||||
int tsb = roundf (topSideY - yMax);
|
||||
plan->vmtx_map->set (new_gid, hb_pair (vert_aw, tsb));
|
||||
}
|
||||
|
||||
bool compile_header_bytes (const hb_subset_plan_t *plan,
|
||||
const contour_point_vector_t &all_points,
|
||||
hb_bytes_t &dest_bytes /* OUT */) const
|
||||
{
|
||||
if (all_points.length == 4) //Empty glyph
|
||||
{
|
||||
dest_bytes = hb_bytes_t ();
|
||||
return true;
|
||||
}
|
||||
|
||||
GlyphHeader *glyph_header = (GlyphHeader *) hb_calloc (1, GlyphHeader::static_size);
|
||||
if (unlikely (!glyph_header)) return false;
|
||||
|
||||
int xMin, xMax;
|
||||
xMin = xMax = roundf (all_points[0].x);
|
||||
|
||||
int yMin, yMax;
|
||||
yMin = yMax = roundf (all_points[0].y);
|
||||
|
||||
for (unsigned i = 1; i < all_points.length - 4; i++)
|
||||
{
|
||||
float rounded_x = roundf (all_points[i].x);
|
||||
float rounded_y = roundf (all_points[i].y);
|
||||
xMin = hb_min (xMin, rounded_x);
|
||||
xMax = hb_max (xMax, rounded_x);
|
||||
yMin = hb_min (yMin, rounded_y);
|
||||
yMax = hb_max (yMax, rounded_y);
|
||||
}
|
||||
|
||||
update_mtx (plan, xMin, yMax, all_points);
|
||||
|
||||
glyph_header->numberOfContours = header->numberOfContours;
|
||||
glyph_header->xMin = xMin;
|
||||
glyph_header->yMin = yMin;
|
||||
glyph_header->xMax = xMax;
|
||||
glyph_header->yMax = yMax;
|
||||
|
||||
dest_bytes = hb_bytes_t ((const char *)glyph_header, GlyphHeader::static_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool compile_bytes_with_deltas (const hb_subset_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
const glyf_accelerator_t &glyf,
|
||||
hb_bytes_t &dest_start, /* IN/OUT */
|
||||
hb_bytes_t &dest_end /* OUT */) const
|
||||
{
|
||||
contour_point_vector_t all_points, deltas;
|
||||
get_points (font, glyf, all_points, &deltas);
|
||||
|
||||
switch (type) {
|
||||
case COMPOSITE:
|
||||
if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start,
|
||||
deltas,
|
||||
dest_end))
|
||||
return false;
|
||||
break;
|
||||
case SIMPLE:
|
||||
if (!SimpleGlyph (*header, bytes).compile_bytes_with_deltas (all_points,
|
||||
plan->flags & HB_SUBSET_FLAGS_NO_HINTING,
|
||||
dest_end))
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
//no need to compile empty glyph (.notdef)
|
||||
return true;
|
||||
}
|
||||
|
||||
return compile_header_bytes (plan, all_points, dest_start);
|
||||
}
|
||||
|
||||
|
||||
/* Note: Recursively calls itself.
|
||||
* all_points includes phantom points
|
||||
*/
|
||||
template <typename accelerator_t>
|
||||
bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
|
||||
contour_point_vector_t &all_points /* OUT */,
|
||||
contour_point_vector_t *deltas = nullptr, /* OUT */
|
||||
bool phantom_only = false,
|
||||
unsigned int depth = 0) const
|
||||
{
|
||||
|
@ -130,10 +228,28 @@ struct Glyph
|
|||
phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
|
||||
}
|
||||
|
||||
if (deltas != nullptr && depth == 0 && type == COMPOSITE)
|
||||
{
|
||||
if (unlikely (!deltas->resize (points.length))) return false;
|
||||
for (unsigned i = 0 ; i < points.length; i++)
|
||||
deltas->arrayZ[i] = points.arrayZ[i];
|
||||
}
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
glyf_accelerator.gvar->apply_deltas_to_points (gid, font, points.as_array ());
|
||||
#endif
|
||||
|
||||
// mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it
|
||||
// with child glyphs' points
|
||||
if (deltas != nullptr && depth == 0 && type == COMPOSITE)
|
||||
{
|
||||
for (unsigned i = 0 ; i < points.length; i++)
|
||||
{
|
||||
deltas->arrayZ[i].x = points.arrayZ[i].x - deltas->arrayZ[i].x;
|
||||
deltas->arrayZ[i].y = points.arrayZ[i].y - deltas->arrayZ[i].y;
|
||||
}
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case SIMPLE:
|
||||
if (!inplace)
|
||||
|
@ -148,7 +264,7 @@ struct Glyph
|
|||
comp_points.reset ();
|
||||
if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
|
||||
.get_points (font, glyf_accelerator, comp_points,
|
||||
phantom_only, depth + 1)))
|
||||
deltas, phantom_only, depth + 1)))
|
||||
return false;
|
||||
|
||||
/* Copy phantom points from component if USE_MY_METRICS flag set */
|
||||
|
|
|
@ -206,6 +206,132 @@ struct SimpleGlyph
|
|||
&& read_points (p, points_, end, &contour_point_t::y,
|
||||
FLAG_Y_SHORT, FLAG_Y_SAME);
|
||||
}
|
||||
|
||||
static void encode_coord (int value,
|
||||
uint8_t &flag,
|
||||
const simple_glyph_flag_t short_flag,
|
||||
const simple_glyph_flag_t same_flag,
|
||||
hb_vector_t<uint8_t> &coords /* OUT */)
|
||||
{
|
||||
if (value == 0)
|
||||
{
|
||||
flag |= same_flag;
|
||||
}
|
||||
else if (value >= -255 && value <= 255)
|
||||
{
|
||||
flag |= short_flag;
|
||||
if (value > 0) flag |= same_flag;
|
||||
else value = -value;
|
||||
|
||||
coords.push ((uint8_t)value);
|
||||
}
|
||||
else
|
||||
{
|
||||
int16_t val = value;
|
||||
coords.push (val >> 8);
|
||||
coords.push (val & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
static void encode_flag (uint8_t &flag,
|
||||
uint8_t &repeat,
|
||||
uint8_t &lastflag,
|
||||
hb_vector_t<uint8_t> &flags /* OUT */)
|
||||
{
|
||||
if (flag == lastflag && repeat != 255)
|
||||
{
|
||||
repeat = repeat + 1;
|
||||
if (repeat == 1)
|
||||
{
|
||||
flags.push(flag);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned len = flags.length;
|
||||
flags[len-2] = flag | FLAG_REPEAT;
|
||||
flags[len-1] = repeat;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
repeat = 0;
|
||||
flags.push (flag);
|
||||
}
|
||||
lastflag = flag;
|
||||
}
|
||||
|
||||
bool compile_bytes_with_deltas (const contour_point_vector_t &all_points,
|
||||
bool no_hinting,
|
||||
hb_bytes_t &dest_bytes /* OUT */)
|
||||
{
|
||||
if (header.numberOfContours == 0 || all_points.length <= 4)
|
||||
{
|
||||
dest_bytes = hb_bytes_t ();
|
||||
return true;
|
||||
}
|
||||
//convert absolute values to relative values
|
||||
unsigned num_points = all_points.length - 4;
|
||||
hb_vector_t<hb_pair_t<int, int>> deltas;
|
||||
deltas.resize (num_points);
|
||||
|
||||
for (unsigned i = 0; i < num_points; i++)
|
||||
{
|
||||
deltas[i].first = i == 0 ? roundf (all_points[i].x) : roundf (all_points[i].x) - roundf (all_points[i-1].x);
|
||||
deltas[i].second = i == 0 ? roundf (all_points[i].y) : roundf (all_points[i].y) - roundf (all_points[i-1].y);
|
||||
}
|
||||
|
||||
hb_vector_t<uint8_t> flags, x_coords, y_coords;
|
||||
flags.alloc (num_points);
|
||||
x_coords.alloc (2*num_points);
|
||||
y_coords.alloc (2*num_points);
|
||||
|
||||
uint8_t lastflag, repeat = 0;
|
||||
|
||||
for (unsigned i = 0; i < num_points; i++)
|
||||
{
|
||||
uint8_t flag = all_points[i].flag;
|
||||
flag &= FLAG_ON_CURVE + FLAG_OVERLAP_SIMPLE;
|
||||
|
||||
encode_coord (deltas[i].first, flag, FLAG_X_SHORT, FLAG_X_SAME, x_coords);
|
||||
encode_coord (deltas[i].second, flag, FLAG_Y_SHORT, FLAG_Y_SAME, y_coords);
|
||||
if (i == 0) lastflag = flag + 1; //make lastflag != flag for the first point
|
||||
encode_flag (flag, repeat, lastflag, flags);
|
||||
}
|
||||
|
||||
unsigned len_before_instrs = 2 * header.numberOfContours + 2;
|
||||
unsigned len_instrs = instructions_length ();
|
||||
unsigned total_len = len_before_instrs + flags.length + x_coords.length + y_coords.length;
|
||||
|
||||
if (!no_hinting)
|
||||
total_len += len_instrs;
|
||||
|
||||
char *p = (char *) hb_calloc (total_len, sizeof (char));
|
||||
if (unlikely (!p)) return false;
|
||||
|
||||
const char *src = bytes.arrayZ + GlyphHeader::static_size;
|
||||
char *cur = p;
|
||||
memcpy (p, src, len_before_instrs);
|
||||
|
||||
cur += len_before_instrs;
|
||||
src += len_before_instrs;
|
||||
|
||||
if (!no_hinting)
|
||||
{
|
||||
memcpy (cur, src, len_instrs);
|
||||
cur += len_instrs;
|
||||
}
|
||||
|
||||
memcpy (cur, flags.arrayZ, flags.length);
|
||||
cur += flags.length;
|
||||
|
||||
memcpy (cur, x_coords.arrayZ, x_coords.length);
|
||||
cur += x_coords.length;
|
||||
|
||||
memcpy (cur, y_coords.arrayZ, y_coords.length);
|
||||
|
||||
dest_bytes = hb_bytes_t (p, total_len);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
|
||||
|
||||
namespace OT {
|
||||
|
||||
struct glyf_accelerator_t;
|
||||
|
||||
namespace glyf_impl {
|
||||
|
||||
|
||||
|
@ -55,6 +58,17 @@ struct SubsetGlyph
|
|||
return_trace (true);
|
||||
}
|
||||
|
||||
bool compile_bytes_with_deltas (const hb_subset_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
const glyf_accelerator_t &glyf)
|
||||
{ return source_glyph.compile_bytes_with_deltas (plan, font, glyf, dest_start, dest_end); }
|
||||
|
||||
void free_compiled_bytes ()
|
||||
{
|
||||
dest_start.fini ();
|
||||
dest_end.fini ();
|
||||
}
|
||||
|
||||
void drop_hints_bytes ()
|
||||
{ source_glyph.drop_hints_bytes (dest_start, dest_end); }
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@ namespace OT {
|
|||
*/
|
||||
#define HB_OT_TAG_glyf HB_TAG('g','l','y','f')
|
||||
|
||||
|
||||
struct glyf
|
||||
{
|
||||
friend struct glyf_accelerator_t;
|
||||
|
@ -75,6 +74,9 @@ struct glyf
|
|||
hb_vector_t<glyf_impl::SubsetGlyph> glyphs;
|
||||
_populate_subset_glyphs (c->plan, &glyphs);
|
||||
|
||||
if (!c->plan->pinned_at_default)
|
||||
_compile_subset_glyphs_with_deltas (c->plan, &glyphs);
|
||||
|
||||
auto padded_offsets =
|
||||
+ hb_iter (glyphs)
|
||||
| hb_map (&glyf_impl::SubsetGlyph::padded_size)
|
||||
|
@ -93,6 +95,8 @@ struct glyf
|
|||
}
|
||||
|
||||
|
||||
if (!c->plan->pinned_at_default)
|
||||
_free_compiled_subset_glyphs (&glyphs);
|
||||
if (unlikely (c->serializer->in_error ())) return_trace (false);
|
||||
return_trace (c->serializer->check_success (glyf_impl::_add_loca_and_head (c->plan,
|
||||
padded_offsets,
|
||||
|
@ -103,6 +107,16 @@ struct glyf
|
|||
_populate_subset_glyphs (const hb_subset_plan_t *plan,
|
||||
hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const;
|
||||
|
||||
void
|
||||
_compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan,
|
||||
hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const;
|
||||
|
||||
void _free_compiled_subset_glyphs (hb_vector_t<glyf_impl::SubsetGlyph> *glyphs) const
|
||||
{
|
||||
for (auto _ : *glyphs)
|
||||
_.free_compiled_bytes ();
|
||||
}
|
||||
|
||||
protected:
|
||||
UnsizedArrayOf<HBUINT8>
|
||||
dataZ; /* Glyphs data. */
|
||||
|
@ -166,7 +180,7 @@ struct glyf_accelerator_t
|
|||
contour_point_vector_t all_points;
|
||||
|
||||
bool phantom_only = !consumer.is_consuming_contour_points ();
|
||||
if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, phantom_only)))
|
||||
if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, phantom_only)))
|
||||
return false;
|
||||
|
||||
if (consumer.is_consuming_contour_points ())
|
||||
|
@ -389,6 +403,30 @@ glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan,
|
|||
;
|
||||
}
|
||||
|
||||
inline void
|
||||
glyf::_compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan,
|
||||
hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const
|
||||
{
|
||||
OT::glyf_accelerator_t glyf (plan->source);
|
||||
hb_font_t *font = hb_font_create (plan->source);
|
||||
|
||||
hb_vector_t<hb_variation_t> vars;
|
||||
vars.alloc (plan->user_axes_location->get_population ());
|
||||
|
||||
for (auto _ : *plan->user_axes_location)
|
||||
{
|
||||
hb_variation_t var;
|
||||
var.tag = _.first;
|
||||
var.value = _.second;
|
||||
vars.push (var);
|
||||
}
|
||||
|
||||
hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location->get_population ());
|
||||
for (auto& subset_glyph : *glyphs)
|
||||
const_cast<glyf_impl::SubsetGlyph &> (subset_glyph).compile_bytes_with_deltas (plan, font, glyf);
|
||||
|
||||
hb_font_destroy (font);
|
||||
}
|
||||
|
||||
|
||||
} /* namespace OT */
|
||||
|
|
|
@ -73,6 +73,8 @@ struct hmtxvmtx
|
|||
return_trace (true);
|
||||
}
|
||||
|
||||
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>>* get_mtx_map (const hb_subset_plan_t *plan) const
|
||||
{ return T::is_horizontal ? plan->hmtx_map : plan->vmtx_map; }
|
||||
|
||||
bool subset_update_header (hb_subset_plan_t *plan,
|
||||
unsigned int num_hmetrics) const
|
||||
|
@ -130,14 +132,15 @@ struct hmtxvmtx
|
|||
|
||||
accelerator_t _mtx (c->plan->source);
|
||||
unsigned num_long_metrics;
|
||||
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *mtx_map = get_mtx_map (c->plan);
|
||||
{
|
||||
/* Determine num_long_metrics to encode. */
|
||||
auto& plan = c->plan;
|
||||
|
||||
num_long_metrics = plan->num_output_glyphs ();
|
||||
hb_codepoint_t old_gid = 0;
|
||||
unsigned int last_advance = plan->old_gid_for_new_gid (num_long_metrics - 1, &old_gid) ? _mtx.get_advance_without_var_unscaled (old_gid) : 0;
|
||||
unsigned int last_advance = get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 1, _mtx);
|
||||
while (num_long_metrics > 1 &&
|
||||
last_advance == (plan->old_gid_for_new_gid (num_long_metrics - 2, &old_gid) ? _mtx.get_advance_without_var_unscaled (old_gid) : 0))
|
||||
last_advance == get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 2, _mtx))
|
||||
{
|
||||
num_long_metrics--;
|
||||
}
|
||||
|
@ -145,14 +148,18 @@ struct hmtxvmtx
|
|||
|
||||
auto it =
|
||||
+ hb_range (c->plan->num_output_glyphs ())
|
||||
| hb_map ([c, &_mtx] (unsigned _)
|
||||
| hb_map ([c, &_mtx, mtx_map] (unsigned _)
|
||||
{
|
||||
hb_codepoint_t old_gid;
|
||||
if (!c->plan->old_gid_for_new_gid (_, &old_gid))
|
||||
return hb_pair (0u, 0);
|
||||
int lsb = 0;
|
||||
(void) _mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb);
|
||||
return hb_pair (_mtx.get_advance_without_var_unscaled (old_gid), +lsb);
|
||||
if (!mtx_map->has (_))
|
||||
{
|
||||
hb_codepoint_t old_gid;
|
||||
if (!c->plan->old_gid_for_new_gid (_, &old_gid))
|
||||
return hb_pair (0u, 0);
|
||||
int lsb = 0;
|
||||
(void) _mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb);
|
||||
return hb_pair (_mtx.get_advance_without_var_unscaled (old_gid), +lsb);
|
||||
}
|
||||
return mtx_map->get (_);
|
||||
})
|
||||
;
|
||||
|
||||
|
@ -330,6 +337,24 @@ struct hmtxvmtx
|
|||
hb_blob_ptr_t<V> var_table;
|
||||
};
|
||||
|
||||
/* get advance: when no variations, call get_advance_without_var_unscaled.
|
||||
* when there're variations, get advance value from mtx_map in subset_plan*/
|
||||
unsigned get_new_gid_advance_unscaled (const hb_subset_plan_t *plan,
|
||||
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *mtx_map,
|
||||
unsigned new_gid,
|
||||
const accelerator_t &_mtx) const
|
||||
{
|
||||
if (mtx_map->is_empty () ||
|
||||
(new_gid == 0 && !mtx_map->has (new_gid)))
|
||||
{
|
||||
hb_codepoint_t old_gid = 0;
|
||||
return plan->old_gid_for_new_gid (new_gid, &old_gid) ?
|
||||
_mtx.get_advance_without_var_unscaled (old_gid) : 0;
|
||||
}
|
||||
else
|
||||
{ return mtx_map->get (new_gid).first; }
|
||||
}
|
||||
|
||||
protected:
|
||||
UnsizedArrayOf<LongMetric>
|
||||
longMetricZ; /* Paired advance width and leading
|
||||
|
|
|
@ -166,6 +166,21 @@ struct OS2
|
|||
}
|
||||
}
|
||||
|
||||
float map_wdth_to_widthclass(float width) const
|
||||
{
|
||||
if (width < 50) return 1.0f;
|
||||
if (width > 200) return 9.0f;
|
||||
|
||||
float ratio = (width - 50) / 12.5f;
|
||||
int a = (int) floorf (ratio);
|
||||
int b = (int) ceilf (ratio);
|
||||
|
||||
float va = 50 + a * 12.5f;
|
||||
float vb = 50 + b * 12.5f;
|
||||
|
||||
return a + 1.0f + (float) (b - a) * (width - va) / (vb - va);
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
|
@ -183,6 +198,26 @@ struct OS2
|
|||
|
||||
_update_unicode_ranges (c->plan->unicodes, os2_prime->ulUnicodeRange);
|
||||
|
||||
if (c->plan->user_axes_location->has (HB_TAG ('w','g','h','t')) &&
|
||||
!c->plan->pinned_at_default)
|
||||
{
|
||||
float weight_class = c->plan->user_axes_location->get (HB_TAG ('w','g','h','t'));
|
||||
if (!c->serializer->check_assign (os2_prime->usWeightClass,
|
||||
roundf (hb_clamp (weight_class, 1.0f, 1000.0f)),
|
||||
HB_SERIALIZE_ERROR_INT_OVERFLOW))
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
if (c->plan->user_axes_location->has (HB_TAG ('w','d','t','h')) &&
|
||||
!c->plan->pinned_at_default)
|
||||
{
|
||||
float width = c->plan->user_axes_location->get (HB_TAG ('w','d','t','h'));
|
||||
if (!c->serializer->check_assign (os2_prime->usWidthClass,
|
||||
roundf (map_wdth_to_widthclass (width)),
|
||||
HB_SERIALIZE_ERROR_INT_OVERFLOW))
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
|
|
|
@ -102,6 +102,14 @@ struct post
|
|||
if (!serialize (c->serializer, glyph_names))
|
||||
return_trace (false);
|
||||
|
||||
if (c->plan->user_axes_location->has (HB_TAG ('s','l','n','t')) &&
|
||||
!c->plan->pinned_at_default)
|
||||
{
|
||||
float italic_angle = c->plan->user_axes_location->get (HB_TAG ('s','l','n','t'));
|
||||
italic_angle = hb_max (-90.f, hb_min (italic_angle, 90.f));
|
||||
post_prime->italicAngle.set_float (italic_angle);
|
||||
}
|
||||
|
||||
if (glyph_names && version.major == 2)
|
||||
return_trace (v2X.subset (c));
|
||||
|
||||
|
|
|
@ -585,12 +585,9 @@ _nameid_closure (hb_face_t *face,
|
|||
|
||||
#ifndef HB_NO_VAR
|
||||
static void
|
||||
_normalize_axes_location (hb_face_t *face,
|
||||
const hb_hashmap_t<hb_tag_t, float> *user_axes_location,
|
||||
hb_hashmap_t<hb_tag_t, int> *normalized_axes_location, /* OUT */
|
||||
bool &all_axes_pinned)
|
||||
_normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
|
||||
{
|
||||
if (user_axes_location->is_empty ())
|
||||
if (plan->user_axes_location->is_empty ())
|
||||
return;
|
||||
|
||||
hb_array_t<const OT::AxisRecord> axes = face->table.fvar->get_axes ();
|
||||
|
@ -605,25 +602,27 @@ _normalize_axes_location (hb_face_t *face,
|
|||
for (const auto& axis : axes)
|
||||
{
|
||||
hb_tag_t axis_tag = axis.get_axis_tag ();
|
||||
if (!user_axes_location->has (axis_tag))
|
||||
if (!plan->user_axes_location->has (axis_tag))
|
||||
{
|
||||
axis_not_pinned = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
int normalized_v = axis.normalize_axis_value (user_axes_location->get (axis_tag));
|
||||
int normalized_v = axis.normalize_axis_value (plan->user_axes_location->get (axis_tag));
|
||||
if (has_avar && axis_count < face->table.avar->get_axis_count ())
|
||||
{
|
||||
normalized_v = seg_maps->map (normalized_v);
|
||||
}
|
||||
normalized_axes_location->set (axis_tag, normalized_v);
|
||||
plan->axes_location->set (axis_tag, normalized_v);
|
||||
if (normalized_v != 0)
|
||||
plan->pinned_at_default = false;
|
||||
}
|
||||
if (has_avar)
|
||||
seg_maps = &StructAfter<OT::SegmentMaps> (*seg_maps);
|
||||
|
||||
axis_count++;
|
||||
}
|
||||
all_axes_pinned = !axis_not_pinned;
|
||||
plan->all_axes_pinned = !axis_not_pinned;
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
|
@ -692,6 +691,10 @@ hb_subset_plan_create_or_fail (hb_face_t *face,
|
|||
if (plan->user_axes_location && input->axes_location)
|
||||
*plan->user_axes_location = *input->axes_location;
|
||||
plan->all_axes_pinned = false;
|
||||
plan->pinned_at_default = true;
|
||||
|
||||
plan->check_success (plan->vmtx_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ());
|
||||
plan->check_success (plan->hmtx_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ());
|
||||
|
||||
if (unlikely (plan->in_error ())) {
|
||||
hb_subset_plan_destroy (plan);
|
||||
|
@ -726,10 +729,7 @@ hb_subset_plan_create_or_fail (hb_face_t *face,
|
|||
}
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
_normalize_axes_location (face,
|
||||
input->axes_location,
|
||||
plan->axes_location,
|
||||
plan->all_axes_pinned);
|
||||
_normalize_axes_location (face, plan);
|
||||
#endif
|
||||
|
||||
_nameid_closure (face, plan->name_ids, plan->all_axes_pinned, plan->user_axes_location);
|
||||
|
|
|
@ -73,6 +73,8 @@ struct hb_subset_plan_t
|
|||
hb_hashmap_destroy (gpos_langsys);
|
||||
hb_hashmap_destroy (axes_location);
|
||||
hb_hashmap_destroy (sanitized_table_cache);
|
||||
hb_hashmap_destroy (hmtx_map);
|
||||
hb_hashmap_destroy (vmtx_map);
|
||||
|
||||
if (user_axes_location)
|
||||
{
|
||||
|
@ -156,6 +158,12 @@ struct hb_subset_plan_t
|
|||
//user specified axes location map
|
||||
hb_hashmap_t<hb_tag_t, float> *user_axes_location;
|
||||
bool all_axes_pinned;
|
||||
bool pinned_at_default;
|
||||
|
||||
//hmtx metrics map: new gid->(advance, lsb)
|
||||
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *hmtx_map;
|
||||
//vmtx metrics map: new gid->(advance, lsb)
|
||||
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *vmtx_map;
|
||||
|
||||
public:
|
||||
|
||||
|
|
|
@ -405,6 +405,27 @@ _passthrough (hb_subset_plan_t *plan, hb_tag_t tag)
|
|||
return result;
|
||||
}
|
||||
|
||||
static bool
|
||||
_dependencies_satisfied (hb_subset_plan_t *plan, hb_tag_t tag,
|
||||
hb_set_t &visited_set, hb_set_t &revisit_set)
|
||||
{
|
||||
switch (tag)
|
||||
{
|
||||
case HB_OT_TAG_hmtx:
|
||||
case HB_OT_TAG_vmtx:
|
||||
if (!plan->pinned_at_default &&
|
||||
!visited_set.has (HB_OT_TAG_glyf))
|
||||
{
|
||||
revisit_set.add (tag);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
_subset_table (hb_subset_plan_t *plan,
|
||||
hb_vector_t<char> &buf,
|
||||
|
@ -514,7 +535,7 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
hb_set_t tags_set;
|
||||
hb_set_t tags_set, revisit_set;
|
||||
bool success = true;
|
||||
hb_tag_t table_tags[32];
|
||||
unsigned offset = 0, num_tables = ARRAY_LENGTH (table_tags);
|
||||
|
@ -527,10 +548,27 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan)
|
|||
{
|
||||
hb_tag_t tag = table_tags[i];
|
||||
if (_should_drop_table (plan, tag) && !tags_set.has (tag)) continue;
|
||||
if (!_dependencies_satisfied (plan, tag, tags_set, revisit_set)) continue;
|
||||
tags_set.add (tag);
|
||||
success = _subset_table (plan, buf, tag);
|
||||
if (unlikely (!success)) goto end;
|
||||
}
|
||||
|
||||
/*delayed subsetting for some tables since they might have dependency on other tables in some cases:
|
||||
e.g: during instantiating glyf tables, hmetrics/vmetrics are updated and saved in subset plan,
|
||||
hmtx/vmtx subsetting need to use these updated metrics values*/
|
||||
while (!revisit_set.is_empty ())
|
||||
{
|
||||
hb_set_t revisit_temp;
|
||||
for (hb_tag_t tag : revisit_set)
|
||||
{
|
||||
if (!_dependencies_satisfied (plan, tag, tags_set, revisit_temp)) continue;
|
||||
tags_set.add (tag);
|
||||
success = _subset_table (plan, buf, tag);
|
||||
if (unlikely (!success)) goto end;
|
||||
}
|
||||
revisit_set = revisit_temp;
|
||||
}
|
||||
offset += num_tables;
|
||||
}
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,13 @@
|
|||
FONTS:
|
||||
Roboto-Variable.ABC.ttf
|
||||
Roboto-Variable.composite.ttf
|
||||
|
||||
PROFILES:
|
||||
default.txt
|
||||
|
||||
SUBSETS:
|
||||
*
|
||||
|
||||
INSTANCES:
|
||||
wght=650,wdth=85
|
||||
wght=200,wdth=90
|
|
@ -50,6 +50,9 @@ tests = [
|
|||
'glyph_names',
|
||||
'post',
|
||||
'32bit_var_store',
|
||||
# instacing tests, enable when --instance is not experimental
|
||||
# 'pin_all_at_default',
|
||||
# 'instantiate_glyf',
|
||||
]
|
||||
|
||||
repack_tests = [
|
||||
|
|
Loading…
Reference in New Issue