[API] Add hb_buffer_[sg]et_not_found_glyph() and --not-found-glyph
Instead of using gid=0 when a character is not found in the font,
client can now set a custom value. This is useful for shaper-driven
font fallback and to differentiate that from .notdef glyph.
Fixes https://github.com/harfbuzz/harfbuzz/issues/1360
diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt
index bb8040f..f2c7593 100644
--- a/docs/harfbuzz-sections.txt
+++ b/docs/harfbuzz-sections.txt
@@ -85,6 +85,8 @@
hb_buffer_has_positions
hb_buffer_get_invisible_glyph
hb_buffer_set_invisible_glyph
+hb_buffer_get_not_found_glyph
+hb_buffer_set_not_found_glyph
hb_buffer_set_replacement_codepoint
hb_buffer_get_replacement_codepoint
hb_buffer_normalize_glyphs
diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc
index c6591ca..caa5629 100644
--- a/src/hb-buffer.cc
+++ b/src/hb-buffer.cc
@@ -224,6 +224,7 @@
flags = HB_BUFFER_FLAG_DEFAULT;
replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
invisible = 0;
+ not_found = 0;
clear ();
}
@@ -608,6 +609,7 @@
HB_BUFFER_CLUSTER_LEVEL_DEFAULT,
HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
0, /* invisible */
+ 0, /* not_found */
HB_BUFFER_SCRATCH_FLAG_DEFAULT,
HB_BUFFER_MAX_LEN_DEFAULT,
HB_BUFFER_MAX_OPS_DEFAULT,
@@ -1158,6 +1160,46 @@
return buffer->invisible;
}
+/**
+ * hb_buffer_set_not_found_glyph:
+ * @buffer: An #hb_buffer_t
+ * @not_found: the not-found #hb_codepoint_t
+ *
+ * Sets the #hb_codepoint_t that replaces characters not found in
+ * the font during shaping.
+ *
+ * The not-found glyph defaults to zero, sometimes knows as the
+ * ".notdef" glyph. This API allows for differentiating the two.
+ *
+ * Since: REPLACEME
+ **/
+void
+hb_buffer_set_not_found_glyph (hb_buffer_t *buffer,
+ hb_codepoint_t not_found)
+{
+ if (unlikely (hb_object_is_immutable (buffer)))
+ return;
+
+ buffer->not_found = not_found;
+}
+
+/**
+ * hb_buffer_get_not_found_glyph:
+ * @buffer: An #hb_buffer_t
+ *
+ * See hb_buffer_set_not_found_glyph().
+ *
+ * Return value:
+ * The @buffer not-found #hb_codepoint_t
+ *
+ * Since: REPLACEME
+ **/
+hb_codepoint_t
+hb_buffer_get_not_found_glyph (hb_buffer_t *buffer)
+{
+ return buffer->not_found;
+}
+
/**
* hb_buffer_reset:
diff --git a/src/hb-buffer.h b/src/hb-buffer.h
index 865ccb2..a183cb9 100644
--- a/src/hb-buffer.h
+++ b/src/hb-buffer.h
@@ -383,6 +383,13 @@
HB_EXTERN hb_codepoint_t
hb_buffer_get_invisible_glyph (hb_buffer_t *buffer);
+HB_EXTERN void
+hb_buffer_set_not_found_glyph (hb_buffer_t *buffer,
+ hb_codepoint_t not_found);
+
+HB_EXTERN hb_codepoint_t
+hb_buffer_get_not_found_glyph (hb_buffer_t *buffer);
+
HB_EXTERN void
hb_buffer_reset (hb_buffer_t *buffer);
diff --git a/src/hb-buffer.hh b/src/hb-buffer.hh
index 8635ebd..bde2893 100644
--- a/src/hb-buffer.hh
+++ b/src/hb-buffer.hh
@@ -93,6 +93,7 @@
hb_buffer_cluster_level_t cluster_level;
hb_codepoint_t replacement; /* U+FFFD or something else. */
hb_codepoint_t invisible; /* 0 or something else. */
+ hb_codepoint_t not_found; /* 0 or something else. */
hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */
unsigned int max_len; /* Maximum allowed len. */
int max_ops; /* Maximum allowed operations. */
diff --git a/src/hb-font.hh b/src/hb-font.hh
index 8fc7f44..dd5cd13 100644
--- a/src/hb-font.hh
+++ b/src/hb-font.hh
@@ -217,9 +217,10 @@
}
hb_bool_t get_nominal_glyph (hb_codepoint_t unicode,
- hb_codepoint_t *glyph)
+ hb_codepoint_t *glyph,
+ hb_codepoint_t not_found = 0)
{
- *glyph = 0;
+ *glyph = not_found;
return klass->get.f.nominal_glyph (this, user_data,
unicode, glyph,
klass->user_data.nominal_glyph);
@@ -238,9 +239,10 @@
}
hb_bool_t get_variation_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
- hb_codepoint_t *glyph)
+ hb_codepoint_t *glyph,
+ hb_codepoint_t not_found = 0)
{
- *glyph = 0;
+ *glyph = not_found;
return klass->get.f.variation_glyph (this, user_data,
unicode, variation_selector, glyph,
klass->user_data.variation_glyph);
diff --git a/src/hb-ot-shape-normalize.cc b/src/hb-ot-shape-normalize.cc
index 778b5b8..839cc91 100644
--- a/src/hb-ot-shape-normalize.cc
+++ b/src/hb-ot-shape-normalize.cc
@@ -171,7 +171,7 @@
hb_codepoint_t u = buffer->cur().codepoint;
hb_codepoint_t glyph = 0;
- if (shortest && c->font->get_nominal_glyph (u, &glyph))
+ if (shortest && c->font->get_nominal_glyph (u, &glyph, c->not_found))
{
next_char (buffer, glyph);
return;
@@ -183,7 +183,7 @@
return;
}
- if (!shortest && c->font->get_nominal_glyph (u, &glyph))
+ if (!shortest && c->font->get_nominal_glyph (u, &glyph, c->not_found))
{
next_char (buffer, glyph);
return;
@@ -312,6 +312,7 @@
buffer,
font,
buffer->unicode,
+ buffer->not_found,
plan->shaper->decompose ? plan->shaper->decompose : decompose_unicode,
plan->shaper->compose ? plan->shaper->compose : compose_unicode
};
diff --git a/src/hb-ot-shape-normalize.hh b/src/hb-ot-shape-normalize.hh
index 04f1a80..12c78a2 100644
--- a/src/hb-ot-shape-normalize.hh
+++ b/src/hb-ot-shape-normalize.hh
@@ -56,6 +56,7 @@
hb_buffer_t *buffer;
hb_font_t *font;
hb_unicode_funcs_t *unicode;
+ const hb_codepoint_t not_found;
bool (*decompose) (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t ab,
hb_codepoint_t *a,
diff --git a/util/shape-options.hh b/util/shape-options.hh
index 6484085..8d33184 100644
--- a/util/shape-options.hh
+++ b/util/shape-options.hh
@@ -55,6 +55,7 @@
(remove_default_ignorables ? HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES : 0) |
0));
hb_buffer_set_invisible_glyph (buffer, invisible_glyph);
+ hb_buffer_set_not_found_glyph (buffer, not_found_glyph);
hb_buffer_set_cluster_level (buffer, cluster_level);
hb_buffer_guess_segment_properties (buffer);
}
@@ -305,6 +306,7 @@
char **shapers = nullptr;
hb_bool_t utf8_clusters = false;
hb_codepoint_t invisible_glyph = 0;
+ hb_codepoint_t not_found_glyph = 0;
hb_buffer_cluster_level_t cluster_level = HB_BUFFER_CLUSTER_LEVEL_DEFAULT;
hb_bool_t normalize_glyphs = false;
hb_bool_t verify = false;
@@ -427,6 +429,7 @@
{"preserve-default-ignorables",0, 0, G_OPTION_ARG_NONE, &this->preserve_default_ignorables, "Preserve Default-Ignorable characters", nullptr},
{"remove-default-ignorables",0, 0, G_OPTION_ARG_NONE, &this->remove_default_ignorables, "Remove Default-Ignorable characters", nullptr},
{"invisible-glyph", 0, 0, G_OPTION_ARG_INT, &this->invisible_glyph, "Glyph value to replace Default-Ignorables with", nullptr},
+ {"not-found-glyph", 0, 0, G_OPTION_ARG_INT, &this->not_found_glyph, "Glyph value to replace not-found characters with", nullptr},
{"utf8-clusters", 0, 0, G_OPTION_ARG_NONE, &this->utf8_clusters, "Use UTF8 byte indices, not char indices", nullptr},
{"cluster-level", 0, 0, G_OPTION_ARG_INT, &this->cluster_level, "Cluster merging level (default: 0)", "0/1/2"},
{"normalize-glyphs",0, 0, G_OPTION_ARG_NONE, &this->normalize_glyphs, "Rearrange glyph clusters in nominal order", nullptr},