summaryrefslogtreecommitdiff
path: root/thirdparty/harfbuzz/src/hb-ot-shape.cc
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/harfbuzz/src/hb-ot-shape.cc')
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape.cc194
1 files changed, 121 insertions, 73 deletions
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape.cc b/thirdparty/harfbuzz/src/hb-ot-shape.cc
index 7d90558458..2ada84b8a3 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape.cc
@@ -37,7 +37,7 @@
#include "hb-shaper-impl.hh"
#include "hb-ot-shape.hh"
-#include "hb-ot-shape-complex.hh"
+#include "hb-ot-shaper.hh"
#include "hb-ot-shape-fallback.hh"
#include "hb-ot-shape-normalize.hh"
@@ -47,14 +47,17 @@
#include "hb-aat-layout.hh"
+static inline bool
+_hb_codepoint_is_regional_indicator (hb_codepoint_t u)
+{ return hb_in_range<hb_codepoint_t> (u, 0x1F1E6u, 0x1F1FFu); }
#ifndef HB_NO_AAT_SHAPE
static inline bool
-_hb_apply_morx (hb_face_t *face, const hb_segment_properties_t *props)
+_hb_apply_morx (hb_face_t *face, const hb_segment_properties_t &props)
{
/* https://github.com/harfbuzz/harfbuzz/issues/2124 */
return hb_aat_layout_has_substitution (face) &&
- (HB_DIRECTION_IS_HORIZONTAL (props->direction) || !hb_ot_layout_has_substitution (face));
+ (HB_DIRECTION_IS_HORIZONTAL (props.direction) || !hb_ot_layout_has_substitution (face));
}
#endif
@@ -74,23 +77,23 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
unsigned int num_user_features);
hb_ot_shape_planner_t::hb_ot_shape_planner_t (hb_face_t *face,
- const hb_segment_properties_t *props) :
+ const hb_segment_properties_t &props) :
face (face),
- props (*props),
+ props (props),
map (face, props),
aat_map (face, props)
#ifndef HB_NO_AAT_SHAPE
, apply_morx (_hb_apply_morx (face, props))
#endif
{
- shaper = hb_ot_shape_complex_categorize (this);
+ shaper = hb_ot_shaper_categorize (this);
script_zero_marks = shaper->zero_width_marks != HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE;
script_fallback_mark_positioning = shaper->fallback_position;
/* https://github.com/harfbuzz/harfbuzz/issues/1528 */
- if (apply_morx && shaper != &_hb_ot_complex_shaper_default)
- shaper = &_hb_ot_complex_shaper_dumber;
+ if (apply_morx && shaper != &_hb_ot_shaper_default)
+ shaper = &_hb_ot_shaper_dumber;
}
void
@@ -149,20 +152,26 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
* Decide who does positioning. GPOS, kerx, kern, or fallback.
*/
- if (0)
+#ifndef HB_NO_AAT_SHAPE
+ bool has_kerx = hb_aat_layout_has_positioning (face);
+ bool has_gsub = !apply_morx && hb_ot_layout_has_substitution (face);
+#endif
+ bool has_gpos = !disable_gpos && hb_ot_layout_has_positioning (face);
+ if (false)
;
#ifndef HB_NO_AAT_SHAPE
- else if (hb_aat_layout_has_positioning (face))
+ /* Prefer GPOS over kerx if GSUB is present;
+ * https://github.com/harfbuzz/harfbuzz/issues/3008 */
+ else if (has_kerx && !(has_gsub && has_gpos))
plan.apply_kerx = true;
#endif
- else if (!apply_morx && !disable_gpos && hb_ot_layout_has_positioning (face))
+ else if (has_gpos)
plan.apply_gpos = true;
if (!plan.apply_kerx && (!has_gpos_kern || !plan.apply_gpos))
{
- /* Apparently Apple applies kerx if GPOS kern was not applied. */
#ifndef HB_NO_AAT_SHAPE
- if (hb_aat_layout_has_positioning (face))
+ if (has_kerx)
plan.apply_kerx = true;
else
#endif
@@ -172,6 +181,8 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
#endif
}
+ plan.apply_fallback_kern = !(plan.apply_gpos || plan.apply_kerx || plan.apply_kern);
+
plan.zero_marks = script_zero_marks &&
!plan.apply_kerx &&
(!plan.apply_kern
@@ -193,6 +204,12 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
script_fallback_mark_positioning;
#ifndef HB_NO_AAT_SHAPE
+ /* If we're using morx shaping, we cancel mark position adjustment because
+ Apple Color Emoji assumes this will NOT be done when forming emoji sequences;
+ https://github.com/harfbuzz/harfbuzz/issues/2967. */
+ if (plan.apply_morx)
+ plan.adjust_mark_positioning_when_zeroing = false;
+
/* Currently we always apply trak. */
plan.apply_trak = plan.requested_tracking && hb_aat_layout_has_tracking (face);
#endif
@@ -208,7 +225,7 @@ hb_ot_shape_plan_t::init0 (hb_face_t *face,
#endif
hb_ot_shape_planner_t planner (face,
- &key->props);
+ key->props);
hb_ot_shape_collect_features (&planner,
key->user_features,
@@ -266,11 +283,12 @@ hb_ot_shape_plan_t::position (hb_font_t *font,
else if (this->apply_kerx)
hb_aat_layout_position (this, font, buffer);
#endif
+
#ifndef HB_NO_OT_KERN
- else if (this->apply_kern)
+ if (this->apply_kern)
hb_ot_layout_kern (this, font, buffer);
#endif
- else
+ else if (this->apply_fallback_kern)
_hb_ot_shape_fallback_kern (this, font, buffer);
#ifndef HB_NO_AAT_SHAPE
@@ -306,16 +324,17 @@ horizontal_features[] =
};
static void
-hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
- const hb_feature_t *user_features,
- unsigned int num_user_features)
+hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
+ const hb_feature_t *user_features,
+ unsigned int num_user_features)
{
hb_ot_map_builder_t *map = &planner->map;
map->enable_feature (HB_TAG('r','v','r','n'));
map->add_gsub_pause (nullptr);
- switch (planner->props.direction) {
+ switch (planner->props.direction)
+ {
case HB_DIRECTION_LTR:
map->enable_feature (HB_TAG ('l','t','r','a'));
map->enable_feature (HB_TAG ('l','t','r','m'));
@@ -348,12 +367,14 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
map->enable_feature (HB_TAG ('t','r','a','k'), F_HAS_FALLBACK);
#endif
- map->enable_feature (HB_TAG ('H','A','R','F'));
+ map->enable_feature (HB_TAG ('H','a','r','f')); /* Considered required. */
+ map->enable_feature (HB_TAG ('H','A','R','F')); /* Considered discretionary. */
if (planner->shaper->collect_features)
planner->shaper->collect_features (planner);
- map->enable_feature (HB_TAG ('B','U','Z','Z'));
+ map->enable_feature (HB_TAG ('B','u','z','z')); /* Considered required. */
+ map->enable_feature (HB_TAG ('B','U','Z','Z')); /* Considered discretionary. */
for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++)
map->add_feature (common_features[i]);
@@ -363,6 +384,10 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
map->add_feature (horizontal_features[i]);
else
{
+ /* We only apply `vert` feature. See:
+ * https://github.com/harfbuzz/harfbuzz/commit/d71c0df2d17f4590d5611239577a6cb532c26528
+ * https://lists.freedesktop.org/archives/harfbuzz/2013-August/003490.html */
+
/* We really want to find a 'vert' feature if there's any in the font, no
* matter which script/langsys it is listed (or not) under.
* See various bugs referenced from:
@@ -478,6 +503,14 @@ hb_set_unicode_props (hb_buffer_t *buffer)
if (unlikely (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL &&
hb_in_range<hb_codepoint_t> (info[i].codepoint, 0x1F3FBu, 0x1F3FFu)))
{
+ _hb_glyph_info_set_continuation (&info[i]);
+ }
+ /* Regional_Indicators are hairy as hell...
+ * https://github.com/harfbuzz/harfbuzz/issues/2265 */
+ else if (unlikely (i && _hb_codepoint_is_regional_indicator (info[i].codepoint)))
+ {
+ if (_hb_codepoint_is_regional_indicator (info[i - 1].codepoint) &&
+ !_hb_glyph_info_is_continuation (&info[i - 1]))
_hb_glyph_info_set_continuation (&info[i]);
}
#ifndef HB_NO_EMOJI_SEQUENCES
@@ -534,10 +567,9 @@ hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
hb_glyph_info_t info = dottedcircle;
info.cluster = buffer->cur().cluster;
info.mask = buffer->cur().mask;
- buffer->output_info (info);
- while (buffer->idx < buffer->len && buffer->successful)
- buffer->next_glyph ();
- buffer->swap_buffers ();
+ (void) buffer->output_info (info);
+
+ buffer->sync ();
}
static void
@@ -560,6 +592,45 @@ hb_ensure_native_direction (hb_buffer_t *buffer)
hb_direction_t direction = buffer->props.direction;
hb_direction_t horiz_dir = hb_script_get_horizontal_direction (buffer->props.script);
+ /* Numeric runs in natively-RTL scripts are actually native-LTR, so we reset
+ * the horiz_dir if the run contains at least one decimal-number char, and no
+ * letter chars (ideally we should be checking for chars with strong
+ * directionality but hb-unicode currently lacks bidi categories).
+ *
+ * This allows digit sequences in Arabic etc to be shaped in "native"
+ * direction, so that features like ligatures will work as intended.
+ *
+ * https://github.com/harfbuzz/harfbuzz/issues/501
+ *
+ * Similar thing about Regional_Indicators; They are bidi=L, but Script=Common.
+ * If they are present in a run of natively-RTL text, they get assigned a script
+ * with natively RTL direction, which would result in wrong shaping if we
+ * assign such native RTL direction to them then. Detect that as well.
+ *
+ * https://github.com/harfbuzz/harfbuzz/issues/3314
+ */
+ if (unlikely (horiz_dir == HB_DIRECTION_RTL && direction == HB_DIRECTION_LTR))
+ {
+ bool found_number = false, found_letter = false, found_ri = false;
+ const auto* info = buffer->info;
+ const auto count = buffer->len;
+ for (unsigned i = 0; i < count; i++)
+ {
+ auto gc = _hb_glyph_info_get_general_category (&info[i]);
+ if (gc == HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
+ found_number = true;
+ else if (HB_UNICODE_GENERAL_CATEGORY_IS_LETTER (gc))
+ {
+ found_letter = true;
+ break;
+ }
+ else if (_hb_codepoint_is_regional_indicator (info[i].codepoint))
+ found_ri = true;
+ }
+ if ((found_number || found_ri) && !found_letter)
+ horiz_dir = HB_DIRECTION_LTR;
+ }
+
/* TODO vertical:
* The only BTT vertical script is Ogham, but it's not clear to me whether OpenType
* Ogham fonts are supposed to be implemented BTT or not. Need to research that
@@ -569,20 +640,7 @@ hb_ensure_native_direction (hb_buffer_t *buffer)
(HB_DIRECTION_IS_VERTICAL (direction) &&
direction != HB_DIRECTION_TTB))
{
-
- if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
- foreach_grapheme (buffer, start, end)
- {
- buffer->merge_clusters (start, end);
- buffer->reverse_range (start, end);
- }
- else
- foreach_grapheme (buffer, start, end)
- /* form_clusters() merged clusters already, we don't merge. */
- buffer->reverse_range (start, end);
-
- buffer->reverse ();
-
+ _hb_ot_layout_reverse_graphemes (buffer);
buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction);
}
}
@@ -592,6 +650,7 @@ hb_ensure_native_direction (hb_buffer_t *buffer)
* Substitute
*/
+#ifndef HB_NO_VERTICAL
static hb_codepoint_t
hb_vert_char_for (hb_codepoint_t u)
{
@@ -642,6 +701,7 @@ hb_vert_char_for (hb_codepoint_t u)
return u;
}
+#endif
static inline void
hb_ot_rotate_chars (const hb_ot_shape_context_t *c)
@@ -664,6 +724,7 @@ hb_ot_rotate_chars (const hb_ot_shape_context_t *c)
}
}
+#ifndef HB_NO_VERTICAL
if (HB_DIRECTION_IS_VERTICAL (c->target_direction) && !c->plan->has_vert)
{
for (unsigned int i = 0; i < count; i++) {
@@ -672,6 +733,7 @@ hb_ot_rotate_chars (const hb_ot_shape_context_t *c)
info[i].codepoint = codepoint;
}
}
+#endif
}
static inline void
@@ -865,7 +927,7 @@ hb_ot_substitute_default (const hb_ot_shape_context_t *c)
}
static inline void
-hb_ot_substitute_complex (const hb_ot_shape_context_t *c)
+hb_ot_substitute_plan (const hb_ot_shape_context_t *c)
{
hb_buffer_t *buffer = c->buffer;
@@ -884,18 +946,24 @@ hb_ot_substitute_pre (const hb_ot_shape_context_t *c)
_hb_buffer_allocate_gsubgpos_vars (c->buffer);
- hb_ot_substitute_complex (c);
+ hb_ot_substitute_plan (c);
+
+#ifndef HB_NO_AAT_SHAPE
+ if (c->plan->apply_morx && c->plan->apply_gpos)
+ hb_aat_layout_remove_deleted_glyphs (c->buffer);
+#endif
}
static inline void
hb_ot_substitute_post (const hb_ot_shape_context_t *c)
{
- hb_ot_hide_default_ignorables (c->buffer, c->font);
#ifndef HB_NO_AAT_SHAPE
- if (c->plan->apply_morx)
+ if (c->plan->apply_morx && !c->plan->apply_gpos)
hb_aat_layout_remove_deleted_glyphs (c->buffer);
#endif
+ hb_ot_hide_default_ignorables (c->buffer, c->font);
+
if (c->plan->shaper->postprocess_glyphs &&
c->buffer->message(c->font, "start postprocess-glyphs")) {
c->plan->shaper->postprocess_glyphs (c->plan, c->buffer, c->font);
@@ -971,7 +1039,7 @@ hb_ot_position_default (const hb_ot_shape_context_t *c)
}
static inline void
-hb_ot_position_complex (const hb_ot_shape_context_t *c)
+hb_ot_position_plan (const hb_ot_shape_context_t *c)
{
unsigned int count = c->buffer->len;
hb_glyph_info_t *info = c->buffer->info;
@@ -984,7 +1052,7 @@ hb_ot_position_complex (const hb_ot_shape_context_t *c)
* hanging over the next glyph after the final reordering.
*
* Note: If fallback positinoing happens, we don't care about
- * this as it will be overriden.
+ * this as it will be overridden.
*/
bool adjust_offsets_when_zeroing = c->plan->adjust_mark_positioning_when_zeroing &&
HB_DIRECTION_IS_FORWARD (c->buffer->props.direction);
@@ -1056,7 +1124,7 @@ hb_ot_position (const hb_ot_shape_context_t *c)
hb_ot_position_default (c);
- hb_ot_position_complex (c);
+ hb_ot_position_plan (c);
if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction))
hb_buffer_reverse (c->buffer);
@@ -1070,7 +1138,7 @@ hb_propagate_flags (hb_buffer_t *buffer)
/* Propagate cluster-level glyph flags to be the same on all cluster glyphs.
* Simplifies using them. */
- if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK))
+ if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS))
return;
hb_glyph_info_t *info = buffer->info;
@@ -1079,11 +1147,7 @@ hb_propagate_flags (hb_buffer_t *buffer)
{
unsigned int mask = 0;
for (unsigned int i = start; i < end; i++)
- if (info[i].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK)
- {
- mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
- break;
- }
+ mask |= info[i].mask & HB_GLYPH_FLAG_DEFINED;
if (mask)
for (unsigned int i = start; i < end; i++)
info[i].mask |= mask;
@@ -1095,26 +1159,11 @@ hb_propagate_flags (hb_buffer_t *buffer)
static void
hb_ot_shape_internal (hb_ot_shape_context_t *c)
{
- c->buffer->deallocate_var_all ();
- c->buffer->scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
- if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_LEN_FACTOR)))
- {
- c->buffer->max_len = hb_max (c->buffer->len * HB_BUFFER_MAX_LEN_FACTOR,
- (unsigned) HB_BUFFER_MAX_LEN_MIN);
- }
- if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_OPS_FACTOR)))
- {
- c->buffer->max_ops = hb_max (c->buffer->len * HB_BUFFER_MAX_OPS_FACTOR,
- (unsigned) HB_BUFFER_MAX_OPS_MIN);
- }
-
/* Save the original direction, we use it later. */
c->target_direction = c->buffer->props.direction;
_hb_buffer_allocate_unicode_vars (c->buffer);
- c->buffer->clear_output ();
-
hb_ot_shape_initialize_masks (c);
hb_set_unicode_props (c->buffer);
hb_insert_dotted_circle (c->buffer, c->font);
@@ -1124,7 +1173,8 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c)
hb_ensure_native_direction (c->buffer);
if (c->plan->shaper->preprocess_text &&
- c->buffer->message(c->font, "start preprocess-text")) {
+ c->buffer->message(c->font, "start preprocess-text"))
+ {
c->plan->shaper->preprocess_text (c->plan, c->buffer, c->font);
(void) c->buffer->message(c->font, "end preprocess-text");
}
@@ -1139,9 +1189,7 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c)
c->buffer->props.direction = c->target_direction;
- c->buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;
- c->buffer->max_ops = HB_BUFFER_MAX_OPS_DEFAULT;
- c->buffer->deallocate_var_all ();
+ c->buffer->leave ();
}
@@ -1166,7 +1214,7 @@ _hb_ot_shape (hb_shape_plan_t *shape_plan,
* @lookup_indexes: (out): The #hb_set_t set of lookups returned
*
* Computes the complete set of GSUB or GPOS lookups that are applicable
- * under a given @shape_plan.
+ * under a given @shape_plan.
*
* Since: 0.9.7
**/