add option "--instance", store axes_location in subset_plan and drop all
variation tables when all axes are pinned at default
This commit is contained in:
parent
5744e951fc
commit
2a4773e43d
|
@ -19,7 +19,9 @@ symbols = sorted (re.findall (r"^hb_\w+(?= \()", "\n".join (headers_content), re
|
|||
if '--experimental-api' not in sys.argv:
|
||||
# Move these to harfbuzz-sections.txt when got stable
|
||||
experimental_symbols = \
|
||||
"""hb_subset_repack_or_fail""".splitlines ()
|
||||
"""hb_subset_repack_or_fail
|
||||
hb_subset_input_pin_axis_location
|
||||
hb_subset_input_pin_axis_to_default""".splitlines ()
|
||||
symbols = [x for x in symbols if x not in experimental_symbols]
|
||||
symbols = "\n".join (symbols)
|
||||
|
||||
|
|
|
@ -455,4 +455,28 @@ struct hb_map_t : hb_hashmap_t<hb_codepoint_t,
|
|||
hb_map_t (const Iterable &o) : hashmap (o) {}
|
||||
};
|
||||
|
||||
template <typename K, typename V>
|
||||
static inline
|
||||
hb_hashmap_t<K, V>* hb_hashmap_create ()
|
||||
{
|
||||
using hashmap = hb_hashmap_t<K, V>;
|
||||
hashmap* map;
|
||||
if (!(map = hb_object_create<hashmap> ()))
|
||||
return nullptr;
|
||||
|
||||
map->init_shallow ();
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
static inline
|
||||
void hb_hashmap_destroy (hb_hashmap_t<K, V>* map)
|
||||
{
|
||||
if (!hb_object_destroy (map))
|
||||
return;
|
||||
map->fini_shallow ();
|
||||
hb_free (map);
|
||||
}
|
||||
|
||||
#endif /* HB_MAP_HH */
|
||||
|
|
|
@ -106,6 +106,14 @@ struct avar
|
|||
{
|
||||
static constexpr hb_tag_t tableTag = HB_OT_TAG_avar;
|
||||
|
||||
bool has_data () const { return version.to_int (); }
|
||||
|
||||
const SegmentMaps* get_segment_maps () const
|
||||
{ return &firstAxisSegmentMaps; }
|
||||
|
||||
unsigned get_axis_count () const
|
||||
{ return axisCount; }
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
|
|
@ -96,6 +96,8 @@ struct AxisRecord
|
|||
info->reserved = 0;
|
||||
}
|
||||
|
||||
hb_tag_t get_axis_tag () const { return axisTag; }
|
||||
|
||||
int normalize_axis_value (float v) const
|
||||
{
|
||||
float min_value, default_value, max_value;
|
||||
|
|
|
@ -48,7 +48,10 @@ hb_subset_input_create_or_fail (void)
|
|||
for (auto& set : input->sets_iter ())
|
||||
set = hb_set_create ();
|
||||
|
||||
if (input->in_error ())
|
||||
if ((input->axes_location = hb_object_create<hb_hashmap_t<hb_tag_t, float>> ()))
|
||||
input->axes_location->init_shallow ();
|
||||
|
||||
if (!input->axes_location || input->in_error ())
|
||||
{
|
||||
hb_subset_input_destroy (input);
|
||||
return nullptr;
|
||||
|
@ -246,6 +249,13 @@ hb_subset_input_destroy (hb_subset_input_t *input)
|
|||
for (hb_set_t* set : input->sets_iter ())
|
||||
hb_set_destroy (set);
|
||||
|
||||
if (input->axes_location)
|
||||
{
|
||||
hb_object_destroy (input->axes_location);
|
||||
input->axes_location->fini_shallow ();
|
||||
hb_free (input->axes_location);
|
||||
}
|
||||
|
||||
hb_free (input);
|
||||
}
|
||||
|
||||
|
@ -376,3 +386,56 @@ hb_subset_input_get_user_data (const hb_subset_input_t *input,
|
|||
{
|
||||
return hb_object_get_user_data (input, key);
|
||||
}
|
||||
|
||||
#ifdef HB_EXPERIMENTAL_API
|
||||
#ifndef HB_NO_VAR
|
||||
/**
|
||||
* hb_subset_input_pin_axis_to_default: (skip)
|
||||
* @input: a #hb_subset_input_t object.
|
||||
* @axis_tag: Tag of the axis to be pinned
|
||||
*
|
||||
* Pin an axis to its default location in the given subset input object.
|
||||
*
|
||||
* Return value: `true` if success, `false` otherwise
|
||||
*
|
||||
* Since: REPLACEME
|
||||
**/
|
||||
hb_bool_t
|
||||
hb_subset_input_pin_axis_to_default (hb_subset_input_t *input,
|
||||
hb_face_t *face,
|
||||
hb_tag_t axis_tag)
|
||||
{
|
||||
hb_ot_var_axis_info_t axis_info;
|
||||
if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info))
|
||||
return false;
|
||||
|
||||
return input->axes_location->set (axis_tag, axis_info.default_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_subset_input_pin_axis_location: (skip)
|
||||
* @input: a #hb_subset_input_t object.
|
||||
* @axis_tag: Tag of the axis to be pinned
|
||||
* @axis_value: Location on the axis to be pinned at
|
||||
*
|
||||
* Pin an axis to a fixed location in the given subset input object.
|
||||
*
|
||||
* Return value: `true` if success, `false` otherwise
|
||||
*
|
||||
* Since: REPLACEME
|
||||
**/
|
||||
hb_bool_t
|
||||
hb_subset_input_pin_axis_location (hb_subset_input_t *input,
|
||||
hb_face_t *face,
|
||||
hb_tag_t axis_tag,
|
||||
float axis_value)
|
||||
{
|
||||
hb_ot_var_axis_info_t axis_info;
|
||||
if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info))
|
||||
return false;
|
||||
|
||||
float val = hb_clamp(axis_value, axis_info.min_value, axis_info.max_value);
|
||||
return input->axes_location->set (axis_tag, val);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -59,6 +59,7 @@ struct hb_subset_input_t
|
|||
};
|
||||
|
||||
unsigned flags;
|
||||
hb_hashmap_t<hb_tag_t, float> *axes_location;
|
||||
|
||||
inline unsigned num_sets () const
|
||||
{
|
||||
|
@ -77,7 +78,8 @@ struct hb_subset_input_t
|
|||
if (unlikely (set_ptrs[i]->in_error ()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
return axes_location->in_error ();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "hb-ot-color-colr-table.hh"
|
||||
#include "hb-ot-color-colrv1-closure.hh"
|
||||
#include "hb-ot-var-fvar-table.hh"
|
||||
#include "hb-ot-var-avar-table.hh"
|
||||
#include "hb-ot-stat-table.hh"
|
||||
#include "hb-ot-math-table.hh"
|
||||
|
||||
|
@ -585,6 +586,48 @@ _nameid_closure (hb_face_t *face,
|
|||
#endif
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
if (user_axes_location->is_empty ())
|
||||
return;
|
||||
|
||||
hb_array_t<const OT::AxisRecord> axes = face->table.fvar->get_axes ();
|
||||
|
||||
bool has_avar = face->table.avar->has_data ();
|
||||
const OT::SegmentMaps *seg_maps = nullptr;
|
||||
if (has_avar)
|
||||
seg_maps = face->table.avar->get_segment_maps ();
|
||||
|
||||
bool axis_not_pinned = false;
|
||||
unsigned axis_count = 0;
|
||||
for (const auto& axis : axes)
|
||||
{
|
||||
hb_tag_t axis_tag = axis.get_axis_tag ();
|
||||
if (!user_axes_location->has (axis_tag))
|
||||
{
|
||||
axis_not_pinned = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
int normalized_v = axis.normalize_axis_value (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);
|
||||
}
|
||||
if (has_avar)
|
||||
seg_maps = &StructAfter<OT::SegmentMaps> (*seg_maps);
|
||||
|
||||
axis_count++;
|
||||
}
|
||||
all_axes_pinned = !axis_not_pinned;
|
||||
}
|
||||
/**
|
||||
* hb_subset_plan_create_or_fail:
|
||||
* @face: font face to create the plan for.
|
||||
|
@ -636,10 +679,8 @@ hb_subset_plan_create_or_fail (hb_face_t *face,
|
|||
plan->gsub_lookups = hb_map_create ();
|
||||
plan->gpos_lookups = hb_map_create ();
|
||||
|
||||
if (plan->check_success (plan->gsub_langsys = hb_object_create<script_langsys_map> ()))
|
||||
plan->gsub_langsys->init_shallow ();
|
||||
if (plan->check_success (plan->gpos_langsys = hb_object_create<script_langsys_map> ()))
|
||||
plan->gpos_langsys->init_shallow ();
|
||||
plan->check_success (plan->gsub_langsys = hb_hashmap_create<unsigned, hb::unique_ptr<hb_set_t>> ());
|
||||
plan->check_success (plan->gpos_langsys = hb_hashmap_create<unsigned, hb::unique_ptr<hb_set_t>> ());
|
||||
|
||||
plan->gsub_features = hb_map_create ();
|
||||
plan->gpos_features = hb_map_create ();
|
||||
|
@ -648,10 +689,9 @@ hb_subset_plan_create_or_fail (hb_face_t *face,
|
|||
plan->layout_variation_indices = hb_set_create ();
|
||||
plan->layout_variation_idx_map = hb_map_create ();
|
||||
|
||||
|
||||
if ((plan->sanitized_table_cache = hb_object_create<hb_hashmap_t<hb_tag_t, hb::unique_ptr<hb_blob_t>>> ())) {
|
||||
plan->sanitized_table_cache->init_shallow ();
|
||||
}
|
||||
plan->check_success (plan->sanitized_table_cache = hb_hashmap_create<hb_tag_t, hb::unique_ptr<hb_blob_t>> ());
|
||||
plan->check_success (plan->axes_location = hb_hashmap_create<hb_tag_t, int> ());
|
||||
plan->all_axes_pinned = false;
|
||||
|
||||
if (unlikely (plan->in_error ())) {
|
||||
hb_subset_plan_destroy (plan);
|
||||
|
@ -685,6 +725,11 @@ hb_subset_plan_create_or_fail (hb_face_t *face,
|
|||
plan->glyph_map->get(plan->unicode_to_new_gid_list.arrayZ[i].second);
|
||||
}
|
||||
|
||||
_normalize_axes_location (face,
|
||||
input->axes_location,
|
||||
plan->axes_location,
|
||||
plan->all_axes_pinned);
|
||||
|
||||
if (unlikely (plan->in_error ())) {
|
||||
hb_subset_plan_destroy (plan);
|
||||
return nullptr;
|
||||
|
@ -734,25 +779,10 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan)
|
|||
hb_set_destroy (plan->layout_variation_indices);
|
||||
hb_map_destroy (plan->layout_variation_idx_map);
|
||||
|
||||
if (plan->gsub_langsys)
|
||||
{
|
||||
hb_object_destroy (plan->gsub_langsys);
|
||||
plan->gsub_langsys->fini_shallow ();
|
||||
hb_free (plan->gsub_langsys);
|
||||
}
|
||||
|
||||
if (plan->gpos_langsys)
|
||||
{
|
||||
hb_object_destroy (plan->gpos_langsys);
|
||||
plan->gpos_langsys->fini_shallow ();
|
||||
hb_free (plan->gpos_langsys);
|
||||
}
|
||||
|
||||
if (plan->sanitized_table_cache) {
|
||||
hb_object_destroy (plan->sanitized_table_cache);
|
||||
plan->sanitized_table_cache->fini ();
|
||||
hb_free (plan->sanitized_table_cache);
|
||||
}
|
||||
hb_hashmap_destroy (plan->gsub_langsys);
|
||||
hb_hashmap_destroy (plan->gpos_langsys);
|
||||
hb_hashmap_destroy (plan->axes_location);
|
||||
hb_hashmap_destroy (plan->sanitized_table_cache);
|
||||
|
||||
hb_free (plan);
|
||||
}
|
||||
|
|
|
@ -107,6 +107,9 @@ struct hb_subset_plan_t
|
|||
hb_map_t *layout_variation_idx_map;
|
||||
|
||||
hb_hashmap_t<hb_tag_t, hb::unique_ptr<hb_blob_t>>* sanitized_table_cache;
|
||||
//normalized axes location map
|
||||
hb_hashmap_t<hb_tag_t, int> *axes_location;
|
||||
bool all_axes_pinned;
|
||||
|
||||
public:
|
||||
|
||||
|
|
|
@ -361,6 +361,8 @@ _should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag)
|
|||
switch (tag)
|
||||
{
|
||||
case HB_TAG ('c','v','a','r'): /* hint table, fallthrough */
|
||||
return plan->all_axes_pinned || (plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
|
||||
|
||||
case HB_TAG ('c','v','t',' '): /* hint table, fallthrough */
|
||||
case HB_TAG ('f','p','g','m'): /* hint table, fallthrough */
|
||||
case HB_TAG ('p','r','e','p'): /* hint table, fallthrough */
|
||||
|
@ -380,6 +382,14 @@ _should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag)
|
|||
return true;
|
||||
#endif
|
||||
|
||||
case HB_TAG ('a','v','a','r'):
|
||||
case HB_TAG ('f','v','a','r'):
|
||||
case HB_TAG ('g','v','a','r'):
|
||||
case HB_OT_TAG_HVAR:
|
||||
case HB_OT_TAG_VVAR:
|
||||
case HB_TAG ('M','V','A','R'):
|
||||
return plan->all_axes_pinned;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -154,6 +154,21 @@ HB_EXTERN void
|
|||
hb_subset_input_set_flags (hb_subset_input_t *input,
|
||||
unsigned value);
|
||||
|
||||
#ifdef HB_EXPERIMENTAL_API
|
||||
#ifndef HB_NO_VAR
|
||||
HB_EXTERN hb_bool_t
|
||||
hb_subset_input_pin_axis_to_default (hb_subset_input_t *input,
|
||||
hb_face_t *face,
|
||||
hb_tag_t axis_tag);
|
||||
|
||||
HB_EXTERN hb_bool_t
|
||||
hb_subset_input_pin_axis_location (hb_subset_input_t *input,
|
||||
hb_face_t *face,
|
||||
hb_tag_t axis_tag,
|
||||
float axis_value);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
HB_EXTERN hb_face_t *
|
||||
hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input);
|
||||
|
||||
|
|
|
@ -648,6 +648,73 @@ parse_drop_tables (const char *name,
|
|||
return true;
|
||||
}
|
||||
|
||||
#ifdef HB_EXPERIMENTAL_API
|
||||
#ifndef HB_NO_VAR
|
||||
static gboolean
|
||||
parse_instance (const char *name,
|
||||
const char *arg,
|
||||
gpointer data,
|
||||
GError **error)
|
||||
{
|
||||
subset_main_t *subset_main = (subset_main_t *) data;
|
||||
|
||||
char *s = strtok((char *) arg, "=");
|
||||
while (s)
|
||||
{
|
||||
unsigned len = strlen (s);
|
||||
if (len > 4) //Axis tags are 4 bytes.
|
||||
{
|
||||
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
|
||||
"Failed parsing axis tag at: '%s'", s);
|
||||
return false;
|
||||
}
|
||||
|
||||
hb_tag_t axis_tag = hb_tag_from_string (s, len);
|
||||
|
||||
s = strtok(nullptr, ", ");
|
||||
if (!s)
|
||||
{
|
||||
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
|
||||
"Value not specified for axis: %c%c%c%c", HB_UNTAG (axis_tag));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp (s, "drop") == 0)
|
||||
{
|
||||
if (!hb_subset_input_pin_axis_to_default (subset_main->input, subset_main->face, axis_tag))
|
||||
{
|
||||
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
|
||||
"Cannot pin axis: '%c%c%c%c', not present in fvar", HB_UNTAG (axis_tag));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = 0;
|
||||
char *p;
|
||||
float axis_value = strtof (s, &p);
|
||||
if (errno || s == p)
|
||||
{
|
||||
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
|
||||
"Failed parsing axis value at: '%s'", s);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hb_subset_input_pin_axis_location (subset_main->input, subset_main->face, axis_tag, axis_value))
|
||||
{
|
||||
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
|
||||
"Cannot pin axis: '%c%c%c%c', not present in fvar", HB_UNTAG (axis_tag));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
s = strtok(nullptr, "=");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
template <GOptionArgFunc line_parser, bool allow_comments=true>
|
||||
static gboolean
|
||||
parse_file_for (const char *name,
|
||||
|
@ -818,7 +885,18 @@ subset_main_t::add_options ()
|
|||
{"drop-tables", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables, "Drop the specified tables. Use --drop-tables-=... to subtract from the current set.", "list of string table tags or *"},
|
||||
{"drop-tables+", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables, "Drop the specified tables.", "list of string table tags or *"},
|
||||
{"drop-tables-", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables, "Drop the specified tables.", "list of string table tags or *"},
|
||||
#ifdef HB_EXPERIMENTAL_API
|
||||
#ifndef HB_NO_VAR
|
||||
{"instance", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_instance,
|
||||
"(Partially|Fully) Instantiate a variable font. A location consists of the tag of a variation axis, followed by '=', followed by a\n"
|
||||
"number or the literal string 'drop'\n"
|
||||
" "
|
||||
"For example: --instance=\"wdth=100 wght=200\" or --instance=\"wdth=drop\"\n"
|
||||
"Note: currently only fully instancing to the default location is supported\n",
|
||||
"list of comma separated axis-locations"},
|
||||
{nullptr}
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
add_group (other_entries,
|
||||
"subset-other",
|
||||
|
|
Loading…
Reference in New Issue