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:
|
protected:
|
||||||
bool scaled_offsets () const
|
bool scaled_offsets () const
|
||||||
{ return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; }
|
{ return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; }
|
||||||
|
@ -288,6 +311,39 @@ struct CompositeGlyph
|
||||||
return;
|
return;
|
||||||
glyph_chain.set_overlaps_flag ();
|
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.
|
/* Note: Recursively calls itself.
|
||||||
* all_points includes phantom points
|
* all_points includes phantom points
|
||||||
*/
|
*/
|
||||||
template <typename accelerator_t>
|
template <typename accelerator_t>
|
||||||
bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
|
bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
|
||||||
contour_point_vector_t &all_points /* OUT */,
|
contour_point_vector_t &all_points /* OUT */,
|
||||||
|
contour_point_vector_t *deltas = nullptr, /* OUT */
|
||||||
bool phantom_only = false,
|
bool phantom_only = false,
|
||||||
unsigned int depth = 0) const
|
unsigned int depth = 0) const
|
||||||
{
|
{
|
||||||
|
@ -130,10 +228,28 @@ struct Glyph
|
||||||
phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
|
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
|
#ifndef HB_NO_VAR
|
||||||
glyf_accelerator.gvar->apply_deltas_to_points (gid, font, points.as_array ());
|
glyf_accelerator.gvar->apply_deltas_to_points (gid, font, points.as_array ());
|
||||||
#endif
|
#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) {
|
switch (type) {
|
||||||
case SIMPLE:
|
case SIMPLE:
|
||||||
if (!inplace)
|
if (!inplace)
|
||||||
|
@ -148,7 +264,7 @@ struct Glyph
|
||||||
comp_points.reset ();
|
comp_points.reset ();
|
||||||
if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
|
if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
|
||||||
.get_points (font, glyf_accelerator, comp_points,
|
.get_points (font, glyf_accelerator, comp_points,
|
||||||
phantom_only, depth + 1)))
|
deltas, phantom_only, depth + 1)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Copy phantom points from component if USE_MY_METRICS flag set */
|
/* 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,
|
&& read_points (p, points_, end, &contour_point_t::y,
|
||||||
FLAG_Y_SHORT, FLAG_Y_SAME);
|
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 {
|
namespace OT {
|
||||||
|
|
||||||
|
struct glyf_accelerator_t;
|
||||||
|
|
||||||
namespace glyf_impl {
|
namespace glyf_impl {
|
||||||
|
|
||||||
|
|
||||||
|
@ -55,6 +58,17 @@ struct SubsetGlyph
|
||||||
return_trace (true);
|
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 ()
|
void drop_hints_bytes ()
|
||||||
{ source_glyph.drop_hints_bytes (dest_start, dest_end); }
|
{ 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')
|
#define HB_OT_TAG_glyf HB_TAG('g','l','y','f')
|
||||||
|
|
||||||
|
|
||||||
struct glyf
|
struct glyf
|
||||||
{
|
{
|
||||||
friend struct glyf_accelerator_t;
|
friend struct glyf_accelerator_t;
|
||||||
|
@ -75,6 +74,9 @@ struct glyf
|
||||||
hb_vector_t<glyf_impl::SubsetGlyph> glyphs;
|
hb_vector_t<glyf_impl::SubsetGlyph> glyphs;
|
||||||
_populate_subset_glyphs (c->plan, &glyphs);
|
_populate_subset_glyphs (c->plan, &glyphs);
|
||||||
|
|
||||||
|
if (!c->plan->pinned_at_default)
|
||||||
|
_compile_subset_glyphs_with_deltas (c->plan, &glyphs);
|
||||||
|
|
||||||
auto padded_offsets =
|
auto padded_offsets =
|
||||||
+ hb_iter (glyphs)
|
+ hb_iter (glyphs)
|
||||||
| hb_map (&glyf_impl::SubsetGlyph::padded_size)
|
| 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);
|
if (unlikely (c->serializer->in_error ())) return_trace (false);
|
||||||
return_trace (c->serializer->check_success (glyf_impl::_add_loca_and_head (c->plan,
|
return_trace (c->serializer->check_success (glyf_impl::_add_loca_and_head (c->plan,
|
||||||
padded_offsets,
|
padded_offsets,
|
||||||
|
@ -103,6 +107,16 @@ struct glyf
|
||||||
_populate_subset_glyphs (const hb_subset_plan_t *plan,
|
_populate_subset_glyphs (const hb_subset_plan_t *plan,
|
||||||
hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const;
|
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:
|
protected:
|
||||||
UnsizedArrayOf<HBUINT8>
|
UnsizedArrayOf<HBUINT8>
|
||||||
dataZ; /* Glyphs data. */
|
dataZ; /* Glyphs data. */
|
||||||
|
@ -166,7 +180,7 @@ struct glyf_accelerator_t
|
||||||
contour_point_vector_t all_points;
|
contour_point_vector_t all_points;
|
||||||
|
|
||||||
bool phantom_only = !consumer.is_consuming_contour_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;
|
return false;
|
||||||
|
|
||||||
if (consumer.is_consuming_contour_points ())
|
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 */
|
} /* namespace OT */
|
||||||
|
|
|
@ -73,6 +73,8 @@ struct hmtxvmtx
|
||||||
return_trace (true);
|
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,
|
bool subset_update_header (hb_subset_plan_t *plan,
|
||||||
unsigned int num_hmetrics) const
|
unsigned int num_hmetrics) const
|
||||||
|
@ -130,14 +132,15 @@ struct hmtxvmtx
|
||||||
|
|
||||||
accelerator_t _mtx (c->plan->source);
|
accelerator_t _mtx (c->plan->source);
|
||||||
unsigned num_long_metrics;
|
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. */
|
/* Determine num_long_metrics to encode. */
|
||||||
auto& plan = c->plan;
|
auto& plan = c->plan;
|
||||||
|
|
||||||
num_long_metrics = plan->num_output_glyphs ();
|
num_long_metrics = plan->num_output_glyphs ();
|
||||||
hb_codepoint_t old_gid = 0;
|
unsigned int last_advance = get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 1, _mtx);
|
||||||
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;
|
|
||||||
while (num_long_metrics > 1 &&
|
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--;
|
num_long_metrics--;
|
||||||
}
|
}
|
||||||
|
@ -145,7 +148,9 @@ struct hmtxvmtx
|
||||||
|
|
||||||
auto it =
|
auto it =
|
||||||
+ hb_range (c->plan->num_output_glyphs ())
|
+ hb_range (c->plan->num_output_glyphs ())
|
||||||
| hb_map ([c, &_mtx] (unsigned _)
|
| hb_map ([c, &_mtx, mtx_map] (unsigned _)
|
||||||
|
{
|
||||||
|
if (!mtx_map->has (_))
|
||||||
{
|
{
|
||||||
hb_codepoint_t old_gid;
|
hb_codepoint_t old_gid;
|
||||||
if (!c->plan->old_gid_for_new_gid (_, &old_gid))
|
if (!c->plan->old_gid_for_new_gid (_, &old_gid))
|
||||||
|
@ -153,6 +158,8 @@ struct hmtxvmtx
|
||||||
int lsb = 0;
|
int lsb = 0;
|
||||||
(void) _mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb);
|
(void) _mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb);
|
||||||
return hb_pair (_mtx.get_advance_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;
|
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:
|
protected:
|
||||||
UnsizedArrayOf<LongMetric>
|
UnsizedArrayOf<LongMetric>
|
||||||
longMetricZ; /* Paired advance width and leading
|
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
|
bool subset (hb_subset_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SUBSET (this);
|
TRACE_SUBSET (this);
|
||||||
|
@ -183,6 +198,26 @@ struct OS2
|
||||||
|
|
||||||
_update_unicode_ranges (c->plan->unicodes, os2_prime->ulUnicodeRange);
|
_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);
|
return_trace (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -102,6 +102,14 @@ struct post
|
||||||
if (!serialize (c->serializer, glyph_names))
|
if (!serialize (c->serializer, glyph_names))
|
||||||
return_trace (false);
|
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)
|
if (glyph_names && version.major == 2)
|
||||||
return_trace (v2X.subset (c));
|
return_trace (v2X.subset (c));
|
||||||
|
|
||||||
|
|
|
@ -585,12 +585,9 @@ _nameid_closure (hb_face_t *face,
|
||||||
|
|
||||||
#ifndef HB_NO_VAR
|
#ifndef HB_NO_VAR
|
||||||
static void
|
static void
|
||||||
_normalize_axes_location (hb_face_t *face,
|
_normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
if (user_axes_location->is_empty ())
|
if (plan->user_axes_location->is_empty ())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
hb_array_t<const OT::AxisRecord> axes = face->table.fvar->get_axes ();
|
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)
|
for (const auto& axis : axes)
|
||||||
{
|
{
|
||||||
hb_tag_t axis_tag = axis.get_axis_tag ();
|
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;
|
axis_not_pinned = true;
|
||||||
}
|
}
|
||||||
else
|
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 ())
|
if (has_avar && axis_count < face->table.avar->get_axis_count ())
|
||||||
{
|
{
|
||||||
normalized_v = seg_maps->map (normalized_v);
|
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)
|
if (has_avar)
|
||||||
seg_maps = &StructAfter<OT::SegmentMaps> (*seg_maps);
|
seg_maps = &StructAfter<OT::SegmentMaps> (*seg_maps);
|
||||||
|
|
||||||
axis_count++;
|
axis_count++;
|
||||||
}
|
}
|
||||||
all_axes_pinned = !axis_not_pinned;
|
plan->all_axes_pinned = !axis_not_pinned;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/**
|
/**
|
||||||
|
@ -692,6 +691,10 @@ hb_subset_plan_create_or_fail (hb_face_t *face,
|
||||||
if (plan->user_axes_location && input->axes_location)
|
if (plan->user_axes_location && input->axes_location)
|
||||||
*plan->user_axes_location = *input->axes_location;
|
*plan->user_axes_location = *input->axes_location;
|
||||||
plan->all_axes_pinned = false;
|
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 ())) {
|
if (unlikely (plan->in_error ())) {
|
||||||
hb_subset_plan_destroy (plan);
|
hb_subset_plan_destroy (plan);
|
||||||
|
@ -726,10 +729,7 @@ hb_subset_plan_create_or_fail (hb_face_t *face,
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef HB_NO_VAR
|
#ifndef HB_NO_VAR
|
||||||
_normalize_axes_location (face,
|
_normalize_axes_location (face, plan);
|
||||||
input->axes_location,
|
|
||||||
plan->axes_location,
|
|
||||||
plan->all_axes_pinned);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_nameid_closure (face, plan->name_ids, plan->all_axes_pinned, plan->user_axes_location);
|
_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 (gpos_langsys);
|
||||||
hb_hashmap_destroy (axes_location);
|
hb_hashmap_destroy (axes_location);
|
||||||
hb_hashmap_destroy (sanitized_table_cache);
|
hb_hashmap_destroy (sanitized_table_cache);
|
||||||
|
hb_hashmap_destroy (hmtx_map);
|
||||||
|
hb_hashmap_destroy (vmtx_map);
|
||||||
|
|
||||||
if (user_axes_location)
|
if (user_axes_location)
|
||||||
{
|
{
|
||||||
|
@ -156,6 +158,12 @@ struct hb_subset_plan_t
|
||||||
//user specified axes location map
|
//user specified axes location map
|
||||||
hb_hashmap_t<hb_tag_t, float> *user_axes_location;
|
hb_hashmap_t<hb_tag_t, float> *user_axes_location;
|
||||||
bool all_axes_pinned;
|
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:
|
public:
|
||||||
|
|
||||||
|
|
|
@ -405,6 +405,27 @@ _passthrough (hb_subset_plan_t *plan, hb_tag_t tag)
|
||||||
return result;
|
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
|
static bool
|
||||||
_subset_table (hb_subset_plan_t *plan,
|
_subset_table (hb_subset_plan_t *plan,
|
||||||
hb_vector_t<char> &buf,
|
hb_vector_t<char> &buf,
|
||||||
|
@ -514,7 +535,7 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
hb_set_t tags_set;
|
hb_set_t tags_set, revisit_set;
|
||||||
bool success = true;
|
bool success = true;
|
||||||
hb_tag_t table_tags[32];
|
hb_tag_t table_tags[32];
|
||||||
unsigned offset = 0, num_tables = ARRAY_LENGTH (table_tags);
|
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];
|
hb_tag_t tag = table_tags[i];
|
||||||
if (_should_drop_table (plan, tag) && !tags_set.has (tag)) continue;
|
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);
|
tags_set.add (tag);
|
||||||
success = _subset_table (plan, buf, tag);
|
success = _subset_table (plan, buf, tag);
|
||||||
if (unlikely (!success)) goto end;
|
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;
|
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',
|
'glyph_names',
|
||||||
'post',
|
'post',
|
||||||
'32bit_var_store',
|
'32bit_var_store',
|
||||||
|
# instacing tests, enable when --instance is not experimental
|
||||||
|
# 'pin_all_at_default',
|
||||||
|
# 'instantiate_glyf',
|
||||||
]
|
]
|
||||||
|
|
||||||
repack_tests = [
|
repack_tests = [
|
||||||
|
|
Loading…
Reference in New Issue