summaryrefslogtreecommitdiff
path: root/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.cc
diff options
context:
space:
mode:
authorAkira Kakuto <kakuto@fuk.kindai.ac.jp>2018-10-19 23:02:01 +0000
committerAkira Kakuto <kakuto@fuk.kindai.ac.jp>2018-10-19 23:02:01 +0000
commit4ca29e7f53a6b8a57f2f64c3c3e9a0b423e76429 (patch)
treed9b59fe0f8f0a178fc2f4aac4f26ddca36434038 /Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.cc
parentbd0c56dddccc51f470df742260cb6137223d1dda (diff)
harfbuzz 2.0.0
git-svn-id: svn://tug.org/texlive/trunk@48949 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.cc')
-rw-r--r--Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.cc392
1 files changed, 244 insertions, 148 deletions
diff --git a/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.cc b/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.cc
index a1220f4dd3b..fb1d9b11f25 100644
--- a/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.cc
+++ b/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-ot-layout.cc
@@ -45,17 +45,15 @@
#include "hb-ot-color-cpal-table.hh"
#include "hb-ot-color-sbix-table.hh"
#include "hb-ot-color-svg-table.hh"
+#include "hb-ot-kern-table.hh"
#include "hb-ot-name-table.hh"
-// static inline const OT::BASE&
-// _get_base (hb_face_t *face)
-// {
-// if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::BASE);
-// hb_ot_face_data_t *data = hb_ot_face_data (face);
-// return *(data->base.get ());
-// }
-
+static const OT::kern::accelerator_t& _get_kern (hb_face_t *face)
+{
+ if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::kern::accelerator_t);
+ return *hb_ot_face_data (face)->kern;
+}
const OT::GDEF& _get_gdef (hb_face_t *face)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::GDEF);
@@ -92,6 +90,25 @@ const OT::GPOS& _get_gpos_relaxed (hb_face_t *face)
/*
+ * kern
+ */
+
+hb_bool_t
+hb_ot_layout_has_kerning (hb_face_t *face)
+{
+ return _get_kern (face).has_data ();
+}
+
+void
+hb_ot_layout_kern (hb_font_t *font,
+ hb_buffer_t *buffer,
+ hb_mask_t kern_mask)
+{
+ _get_kern (font->face).apply (font, buffer, kern_mask);
+}
+
+
+/*
* GDEF
*/
@@ -305,7 +322,7 @@ hb_ot_layout_table_get_script_tags (hb_face_t *face,
hb_tag_t table_tag,
unsigned int start_offset,
unsigned int *script_count /* IN/OUT */,
- hb_tag_t *script_tags /* OUT */)
+ hb_tag_t *script_tags /* OUT */)
{
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
@@ -351,17 +368,36 @@ hb_ot_layout_table_choose_script (hb_face_t *face,
unsigned int *script_index,
hb_tag_t *chosen_script)
{
+ const hb_tag_t *t;
+ for (t = script_tags; *t; t++);
+ return hb_ot_layout_table_select_script (face, table_tag, t - script_tags, script_tags, script_index, chosen_script);
+}
+
+/**
+ * hb_ot_layout_table_select_script:
+ *
+ * Since: 2.0.0
+ **/
+hb_bool_t
+hb_ot_layout_table_select_script (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int script_count,
+ const hb_tag_t *script_tags,
+ unsigned int *script_index /* OUT */,
+ hb_tag_t *chosen_script /* OUT */)
+{
static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX), "");
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+ unsigned int i;
- while (*script_tags)
+ for (i = 0; i < script_count; i++)
{
- if (g.find_script_index (*script_tags, script_index)) {
+ if (g.find_script_index (script_tags[i], script_index))
+ {
if (chosen_script)
- *chosen_script = *script_tags;
+ *chosen_script = script_tags[i];
return true;
}
- script_tags++;
}
/* try finding 'DFLT' */
@@ -397,7 +433,7 @@ hb_ot_layout_table_get_feature_tags (hb_face_t *face,
hb_tag_t table_tag,
unsigned int start_offset,
unsigned int *feature_count /* IN/OUT */,
- hb_tag_t *feature_tags /* OUT */)
+ hb_tag_t *feature_tags /* OUT */)
{
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
@@ -433,7 +469,7 @@ hb_ot_layout_script_get_language_tags (hb_face_t *face,
unsigned int script_index,
unsigned int start_offset,
unsigned int *language_count /* IN/OUT */,
- hb_tag_t *language_tags /* OUT */)
+ hb_tag_t *language_tags /* OUT */)
{
const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
@@ -447,13 +483,33 @@ hb_ot_layout_script_find_language (hb_face_t *face,
hb_tag_t language_tag,
unsigned int *language_index)
{
+ return hb_ot_layout_script_select_language (face, table_tag, script_index, 1, &language_tag, language_index);
+}
+
+/**
+ * hb_ot_layout_script_select_language:
+ *
+ * Since: 2.0.0
+ **/
+hb_bool_t
+hb_ot_layout_script_select_language (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int script_index,
+ unsigned int language_count,
+ const hb_tag_t *language_tags,
+ unsigned int *language_index /* OUT */)
+{
static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX), "");
const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
+ unsigned int i;
- if (s.find_lang_sys_index (language_tag, language_index))
- return true;
+ for (i = 0; i < language_count; i++)
+ {
+ if (s.find_lang_sys_index (language_tags[i], language_index))
+ return true;
+ }
- /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
+ /* try finding 'dflt' */
if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index))
return false;
@@ -518,7 +574,7 @@ hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
unsigned int script_index,
unsigned int language_index,
unsigned int start_offset,
- unsigned int *feature_count /* IN/OUT */,
+ unsigned int *feature_count /* IN/OUT */,
unsigned int *feature_indexes /* OUT */)
{
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
@@ -534,7 +590,7 @@ hb_ot_layout_language_get_feature_tags (hb_face_t *face,
unsigned int language_index,
unsigned int start_offset,
unsigned int *feature_count /* IN/OUT */,
- hb_tag_t *feature_tags /* OUT */)
+ hb_tag_t *feature_tags /* OUT */)
{
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
@@ -588,7 +644,7 @@ hb_ot_layout_feature_get_lookups (hb_face_t *face,
hb_tag_t table_tag,
unsigned int feature_index,
unsigned int start_offset,
- unsigned int *lookup_count /* IN/OUT */,
+ unsigned int *lookup_count /* IN/OUT */,
unsigned int *lookup_indexes /* OUT */)
{
return hb_ot_layout_feature_with_variations_get_lookups (face,
@@ -726,11 +782,12 @@ _hb_ot_layout_collect_features_languages (hb_face_t *face,
for (; *languages; languages++)
{
unsigned int language_index;
- if (hb_ot_layout_script_find_language (face,
- table_tag,
- script_index,
- *languages,
- &language_index))
+ if (hb_ot_layout_script_select_language (face,
+ table_tag,
+ script_index,
+ 1,
+ languages,
+ &language_index))
_hb_ot_layout_collect_features_features (face,
table_tag,
script_index,
@@ -815,10 +872,10 @@ void
hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
hb_tag_t table_tag,
unsigned int lookup_index,
- hb_set_t *glyphs_before, /* OUT. May be nullptr */
- hb_set_t *glyphs_input, /* OUT. May be nullptr */
- hb_set_t *glyphs_after, /* OUT. May be nullptr */
- hb_set_t *glyphs_output /* OUT. May be nullptr */)
+ hb_set_t *glyphs_before, /* OUT. May be NULL */
+ hb_set_t *glyphs_input, /* OUT. May be NULL */
+ hb_set_t *glyphs_after, /* OUT. May be NULL */
+ hb_set_t *glyphs_output /* OUT. May be NULL */)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
@@ -1016,11 +1073,11 @@ hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
**/
hb_bool_t
hb_ot_layout_get_size_params (hb_face_t *face,
- unsigned int *design_size, /* OUT. May be nullptr */
- unsigned int *subfamily_id, /* OUT. May be nullptr */
- unsigned int *subfamily_name_id, /* OUT. May be nullptr */
- unsigned int *range_start, /* OUT. May be nullptr */
- unsigned int *range_end /* OUT. May be nullptr */)
+ unsigned int *design_size, /* OUT. May be NULL */
+ unsigned int *subfamily_id, /* OUT. May be NULL */
+ unsigned int *subfamily_name_id, /* OUT. May be NULL */
+ unsigned int *range_start, /* OUT. May be NULL */
+ unsigned int *range_end /* OUT. May be NULL */)
{
const OT::GPOS &gpos = _get_gpos (face);
const hb_tag_t tag = HB_TAG ('s','i','z','e');
@@ -1035,30 +1092,152 @@ hb_ot_layout_get_size_params (hb_face_t *face,
if (params.designSize)
{
-#define PARAM(a, A) if (a) *a = params.A
- PARAM (design_size, designSize);
- PARAM (subfamily_id, subfamilyID);
- PARAM (subfamily_name_id, subfamilyNameID);
- PARAM (range_start, rangeStart);
- PARAM (range_end, rangeEnd);
-#undef PARAM
+ if (design_size) *design_size = params.designSize;
+ if (subfamily_id) *subfamily_id = params.subfamilyID;
+ if (subfamily_name_id) *subfamily_name_id = params.subfamilyNameID;
+ if (range_start) *range_start = params.rangeStart;
+ if (range_end) *range_end = params.rangeEnd;
return true;
}
}
}
-#define PARAM(a, A) if (a) *a = 0
- PARAM (design_size, designSize);
- PARAM (subfamily_id, subfamilyID);
- PARAM (subfamily_name_id, subfamilyNameID);
- PARAM (range_start, rangeStart);
- PARAM (range_end, rangeEnd);
-#undef PARAM
+ if (design_size) *design_size = 0;
+ if (subfamily_id) *subfamily_id = 0;
+ if (subfamily_name_id) *subfamily_name_id = 0;
+ if (range_start) *range_start = 0;
+ if (range_end) *range_end = 0;
+
+ return false;
+}
+
+/**
+ * hb_ot_layout_feature_get_name_ids:
+ * @face: #hb_face_t to work upon
+ * @table_tag:
+ * @feature_index:
+ * @label_id: (out) (allow-none): The ‘name’ table name ID that specifies a string
+ * for a user-interface label for this feature. (May be NULL.)
+ * @tooltip_id: (out) (allow-none): The ‘name’ table name ID that specifies a string
+ * that an application can use for tooltip text for this
+ * feature. (May be NULL.)
+ * @sample_id: (out) (allow-none): The ‘name’ table name ID that specifies sample text
+ * that illustrates the effect of this feature. (May be NULL.)
+ * @num_named_parameters: (out) (allow-none): Number of named parameters. (May be zero.)
+ * @first_param_id: (out) (allow-none): The first ‘name’ table name ID used to specify
+ * strings for user-interface labels for the feature
+ * parameters. (Must be zero if numParameters is zero.)
+ *
+ * Fetches name indices from feature parameters for "Stylistic Set" ('ssXX') or
+ * "Character Variant" ('cvXX') features.
+ *
+ * Return value: true if data found, false otherwise
+ *
+ * Since: 2.0.0
+ **/
+hb_bool_t
+hb_ot_layout_feature_get_name_ids (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int feature_index,
+ hb_name_id_t *label_id, /* OUT. May be NULL */
+ hb_name_id_t *tooltip_id, /* OUT. May be NULL */
+ hb_name_id_t *sample_id, /* OUT. May be NULL */
+ unsigned int *num_named_parameters, /* OUT. May be NULL */
+ hb_name_id_t *first_param_id /* OUT. May be NULL */)
+{
+ const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+
+ hb_tag_t feature_tag = g.get_feature_tag (feature_index);
+ const OT::Feature &f = g.get_feature (feature_index);
+
+ const OT::FeatureParams &feature_params = f.get_feature_params ();
+ if (&feature_params != &Null (OT::FeatureParams))
+ {
+ const OT::FeatureParamsStylisticSet& ss_params =
+ feature_params.get_stylistic_set_params (feature_tag);
+ if (&ss_params != &Null (OT::FeatureParamsStylisticSet)) /* ssXX */
+ {
+ if (label_id) *label_id = ss_params.uiNameID;
+ // ssXX features don't have the rest
+ if (tooltip_id) *tooltip_id = HB_NAME_ID_INVALID;
+ if (sample_id) *sample_id = HB_NAME_ID_INVALID;
+ if (num_named_parameters) *num_named_parameters = 0;
+ if (first_param_id) *first_param_id = HB_NAME_ID_INVALID;
+ return true;
+ }
+ const OT::FeatureParamsCharacterVariants& cv_params =
+ feature_params.get_character_variants_params (feature_tag);
+ if (&cv_params != &Null (OT::FeatureParamsCharacterVariants)) /* cvXX */
+ {
+ if (label_id) *label_id = cv_params.featUILableNameID;
+ if (tooltip_id) *tooltip_id = cv_params.featUITooltipTextNameID;
+ if (sample_id) *sample_id = cv_params.sampleTextNameID;
+ if (num_named_parameters) *num_named_parameters = cv_params.numNamedParameters;
+ if (first_param_id) *first_param_id = cv_params.firstParamUILabelNameID;
+ return true;
+ }
+ }
+ if (label_id) *label_id = HB_NAME_ID_INVALID;
+ if (tooltip_id) *tooltip_id = HB_NAME_ID_INVALID;
+ if (sample_id) *sample_id = HB_NAME_ID_INVALID;
+ if (num_named_parameters) *num_named_parameters = 0;
+ if (first_param_id) *first_param_id = HB_NAME_ID_INVALID;
return false;
}
+/**
+ * hb_ot_layout_feature_get_characters::
+ * @face: #hb_face_t to work upon
+ * @table_tag:
+ * @feature_index:
+ * @start_offset: In case the resulting char_count was equal to its input value, there
+ * is a chance there were more characters on the tag so this API can be
+ * called with an offset till resulting char_count gets to a number
+ * lower than input buffer (or consider using just a bigger buffer for
+ * one shot copying).
+ * @char_count: (inout) (allow-none): The count of characters for which this feature
+ * provides glyph variants. (May be zero.)
+ * @characters: (out) (allow-none): A buffer pointer. The Unicode Scalar Value
+ * of the characters for which this feature provides glyph variants.
+ *
+ * Fetches characters listed by designer under feature parameters for "Character
+ * Variant" ("cvXX") features.
+ *
+ * Return value: Number of total sample characters in the cvXX feature.
+ *
+ * Since: 2.0.0
+ **/
+unsigned int
+hb_ot_layout_feature_get_characters (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int feature_index,
+ unsigned int start_offset,
+ unsigned int *char_count, /* IN/OUT. May be NULL */
+ hb_codepoint_t *characters /* OUT. May be NULL */)
+{
+ const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+
+ hb_tag_t feature_tag = g.get_feature_tag (feature_index);
+ const OT::Feature &f = g.get_feature (feature_index);
+
+ const OT::FeatureParams &feature_params = f.get_feature_params ();
+
+ const OT::FeatureParamsCharacterVariants& cv_params =
+ feature_params.get_character_variants_params(feature_tag);
+
+ unsigned int len = 0;
+ if (char_count && characters && start_offset < cv_params.characters.len)
+ {
+ len = MIN (cv_params.characters.len - start_offset, *char_count);
+ for (unsigned int i = 0; i < len; ++i)
+ characters[i] = cv_params.characters[start_offset + i];
+ }
+ if (char_count) *char_count = len;
+ return cv_params.characters.len;
+}
+
/*
* Parts of different types are implemented here such that they have direct
@@ -1077,7 +1256,7 @@ struct GSUBProxy
accels (hb_ot_face_data (face)->GSUB->accels) {}
const OT::GSUB &table;
- const hb_ot_layout_lookup_accelerator_t *accels;
+ const OT::hb_ot_layout_lookup_accelerator_t *accels;
};
struct GPOSProxy
@@ -1091,63 +1270,13 @@ struct GPOSProxy
accels (hb_ot_face_data (face)->GPOS->accels) {}
const OT::GPOS &table;
- const hb_ot_layout_lookup_accelerator_t *accels;
+ const OT::hb_ot_layout_lookup_accelerator_t *accels;
};
-struct hb_get_subtables_context_t :
- hb_dispatch_context_t<hb_get_subtables_context_t, hb_void_t, HB_DEBUG_APPLY>
-{
- template <typename Type>
- static inline bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
- {
- const Type *typed_obj = (const Type *) obj;
- return typed_obj->apply (c);
- }
-
- typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_ot_apply_context_t *c);
-
- struct hb_applicable_t
- {
- inline void init (const void *obj_, hb_apply_func_t apply_func_)
- {
- obj = obj_;
- apply_func = apply_func_;
- }
-
- inline bool apply (OT::hb_ot_apply_context_t *c) const { return apply_func (obj, c); }
-
- private:
- const void *obj;
- hb_apply_func_t apply_func;
- };
-
- typedef hb_auto_t<hb_vector_t<hb_applicable_t> > array_t;
-
- /* Dispatch interface. */
- inline const char *get_name (void) { return "GET_SUBTABLES"; }
- template <typename T>
- inline return_t dispatch (const T &obj)
- {
- hb_applicable_t *entry = array.push();
- entry->init (&obj, apply_to<T>);
- return HB_VOID;
- }
- static return_t default_return_value (void) { return HB_VOID; }
- bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
-
- hb_get_subtables_context_t (array_t &array_) :
- array (array_),
- debug_depth (0) {}
-
- array_t &array;
- unsigned int debug_depth;
-};
-
static inline bool
apply_forward (OT::hb_ot_apply_context_t *c,
- const hb_ot_layout_lookup_accelerator_t &accel,
- const hb_get_subtables_context_t::array_t &subtables)
+ const OT::hb_ot_layout_lookup_accelerator_t &accel)
{
bool ret = false;
hb_buffer_t *buffer = c->buffer;
@@ -1158,12 +1287,7 @@ apply_forward (OT::hb_ot_apply_context_t *c,
(buffer->cur().mask & c->lookup_mask) &&
c->check_glyph_property (&buffer->cur(), c->lookup_props))
{
- for (unsigned int i = 0; i < subtables.len; i++)
- if (subtables[i].apply (c))
- {
- applied = true;
- break;
- }
+ applied = accel.apply (c);
}
if (applied)
@@ -1176,8 +1300,7 @@ apply_forward (OT::hb_ot_apply_context_t *c,
static inline bool
apply_backward (OT::hb_ot_apply_context_t *c,
- const hb_ot_layout_lookup_accelerator_t &accel,
- const hb_get_subtables_context_t::array_t &subtables)
+ const OT::hb_ot_layout_lookup_accelerator_t &accel)
{
bool ret = false;
hb_buffer_t *buffer = c->buffer;
@@ -1187,12 +1310,8 @@ apply_backward (OT::hb_ot_apply_context_t *c,
(buffer->cur().mask & c->lookup_mask) &&
c->check_glyph_property (&buffer->cur(), c->lookup_props))
{
- for (unsigned int i = 0; i < subtables.len; i++)
- if (subtables[i].apply (c))
- {
- ret = true;
- break;
- }
+ if (accel.apply (c))
+ ret = true;
}
/* The reverse lookup doesn't "advance" cursor (for good reason). */
buffer->idx--;
@@ -1206,7 +1325,7 @@ template <typename Proxy>
static inline void
apply_string (OT::hb_ot_apply_context_t *c,
const typename Proxy::Lookup &lookup,
- const hb_ot_layout_lookup_accelerator_t &accel)
+ const OT::hb_ot_layout_lookup_accelerator_t &accel)
{
hb_buffer_t *buffer = c->buffer;
@@ -1215,10 +1334,6 @@ apply_string (OT::hb_ot_apply_context_t *c,
c->set_lookup_props (lookup.get_props ());
- hb_get_subtables_context_t::array_t subtables;
- hb_get_subtables_context_t c_get_subtables (subtables);
- lookup.dispatch (&c_get_subtables);
-
if (likely (!lookup.is_reverse ()))
{
/* in/out forward substitution/positioning */
@@ -1227,7 +1342,7 @@ apply_string (OT::hb_ot_apply_context_t *c,
buffer->idx = 0;
bool ret;
- ret = apply_forward (c, accel, subtables);
+ ret = apply_forward (c, accel);
if (ret)
{
if (!Proxy::inplace)
@@ -1243,7 +1358,7 @@ apply_string (OT::hb_ot_apply_context_t *c,
buffer->remove_output ();
buffer->idx = buffer->len - 1;
- apply_backward (c, accel, subtables);
+ apply_backward (c, accel);
}
}
@@ -1268,6 +1383,11 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
c.set_lookup_mask (lookups[table_index][i].mask);
c.set_auto_zwj (lookups[table_index][i].auto_zwj);
c.set_auto_zwnj (lookups[table_index][i].auto_zwnj);
+ if (lookups[table_index][i].random)
+ {
+ c.set_random (true);
+ buffer->unsafe_to_break_all ();
+ }
apply_string<Proxy> (&c,
proxy.table.get_lookup (lookup_index),
proxy.accels[lookup_index]);
@@ -1297,31 +1417,7 @@ void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_
void
hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
const OT::SubstLookup &lookup,
- const hb_ot_layout_lookup_accelerator_t &accel)
+ const OT::hb_ot_layout_lookup_accelerator_t &accel)
{
apply_string<GSUBProxy> (c, lookup, accel);
}
-
-
-
-
-/*
- * OT::BASE
- */
-
-// /**
-// * hb_ot_base_has_data:
-// * @face: #hb_face_t to test
-// *
-// * This function allows to verify the presence of an OpenType BASE table on the
-// * face.
-// *
-// * Return value: true if face has a BASE table, false otherwise
-// *
-// * Since: XXX
-// **/
-// hb_bool_t
-// hb_ot_base_has_data (hb_face_t *face)
-// {
-// return _get_base (face).has_data ();
-// }