[buffer] Add HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES

https://github.com/harfbuzz/harfbuzz/discussions/5026#discussioncomment-12168668
This commit is contained in:
Behdad Esfahbod 2025-02-12 11:39:14 +00:00
parent bcbd1df3dd
commit 7518718671
8 changed files with 44 additions and 33 deletions

View file

@ -63,24 +63,25 @@ static bool
buffer_verify_monotone (hb_buffer_t *buffer,
hb_font_t *font)
{
/* Check that clusters are monotone. */
if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES ||
buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (buffer->cluster_level))
{
bool is_forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
unsigned int num_glyphs;
hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
for (unsigned int i = 1; i < num_glyphs; i++)
if (info[i-1].cluster != info[i].cluster &&
(info[i-1].cluster < info[i].cluster) != is_forward)
{
buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "clusters are not monotone.");
return false;
}
/* Cannot perform this check without monotone clusters. */
return true;
}
bool is_forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
unsigned int num_glyphs;
hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
for (unsigned int i = 1; i < num_glyphs; i++)
if (info[i-1].cluster != info[i].cluster &&
(info[i-1].cluster < info[i].cluster) != is_forward)
{
buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "clusters are not monotone.");
return false;
}
return true;
}
@ -92,8 +93,7 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer,
unsigned int num_features,
const char * const *shapers)
{
if (buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES &&
buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (buffer->cluster_level))
{
/* Cannot perform this check without monotone clusters. */
return true;
@ -207,8 +207,7 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer,
unsigned int num_features,
const char * const *shapers)
{
if (buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES &&
buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (buffer->cluster_level))
{
/* Cannot perform this check without monotone clusters. */
return true;

View file

@ -518,7 +518,7 @@ void
hb_buffer_t::merge_clusters_impl (unsigned int start,
unsigned int end)
{
if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (cluster_level))
{
unsafe_to_break (start, end);
return;
@ -551,7 +551,7 @@ void
hb_buffer_t::merge_out_clusters (unsigned int start,
unsigned int end)
{
if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (cluster_level))
return;
if (unlikely (end - start < 2))

View file

@ -422,9 +422,9 @@ hb_buffer_get_flags (const hb_buffer_t *buffer);
* @HB_BUFFER_CLUSTER_LEVEL_CHARACTERS: Don't group cluster values.
* @HB_BUFFER_CLUSTER_LEVEL_DEFAULT: Default cluster level,
* equal to @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES.
*
*
* Data type for holding HarfBuzz's clustering behavior options. The cluster level
* dictates one aspect of how HarfBuzz will treat non-base characters
* dictates one aspect of how HarfBuzz will treat non-base characters
* during shaping.
*
* In @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES, non-base
@ -446,9 +446,23 @@ typedef enum {
HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES = 0,
HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS = 1,
HB_BUFFER_CLUSTER_LEVEL_CHARACTERS = 2,
HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES = 3,
HB_BUFFER_CLUSTER_LEVEL_DEFAULT = HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES
} hb_buffer_cluster_level_t;
#define HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE(level) \
((bool) ((1u << (unsigned) (level)) & \
((1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) | \
(1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS))))
#define HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES(level) \
((bool) ((1u << (unsigned) (level)) & \
((1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) | \
(1u << HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES))))
#define HB_BUFFER_CLUSTER_LEVEL_IS_CHARACTERS(level) \
((bool) ((1u << (unsigned) (level)) & \
((1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARCATERS) | \
(1u << HB_BUFFER_CLUSTER_LEVEL_CHARACTERS))))
HB_EXTERN void
hb_buffer_set_cluster_level (hb_buffer_t *buffer,
hb_buffer_cluster_level_t cluster_level);

View file

@ -646,7 +646,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
* B1 M1 B2 M2, and B1-B2 form a ligature, M2's cluster will
* continue pointing to B2 even though B2 was merged into B1's
* cluster... */
if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
if (HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES (buffer->cluster_level))
{
hb_unicode_funcs_t *unicode = buffer->unicode;
unsigned int count = buffer->len;
@ -1292,7 +1292,7 @@ resize_and_retry:
* or the native OT backend, only that the cluster indices will be
* monotonic in the output buffer. */
if (count > 1 && (status_or & kCTRunStatusNonMonotonic) &&
buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (buffer->cluster_level))
{
hb_glyph_info_t *info = buffer->info;
if (HB_DIRECTION_IS_FORWARD (buffer->props.direction))

View file

@ -387,7 +387,7 @@ static inline void
_hb_ot_layout_reverse_graphemes (hb_buffer_t *buffer)
{
buffer->reverse_groups (_hb_grapheme_group_func,
buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (buffer->cluster_level));
}
static inline bool

View file

@ -551,7 +551,7 @@ hb_form_clusters (hb_buffer_t *buffer)
if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII))
return;
if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
if (HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES (buffer->cluster_level))
foreach_grapheme (buffer, start, end)
buffer->merge_clusters (start, end);
else
@ -609,7 +609,7 @@ hb_ensure_native_direction (hb_buffer_t *buffer)
* Ogham fonts are supposed to be implemented BTT or not. Need to research that
* first. */
if ((HB_DIRECTION_IS_HORIZONTAL (direction) &&
direction != horiz_dir && horiz_dir != HB_DIRECTION_INVALID) ||
direction != horiz_dir && HB_DIRECTION_IS_VALID (horiz_dir)) ||
(HB_DIRECTION_IS_VERTICAL (direction) &&
direction != HB_DIRECTION_TTB))
{

View file

@ -298,8 +298,7 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED,
end = start + 2;
if (unlikely (!buffer->successful))
break;
if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
buffer->merge_out_clusters (start, end);
buffer->merge_out_clusters (start, end);
continue;
}
}
@ -372,8 +371,7 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED,
if (i < end)
info[i++].hangul_shaping_feature() = TJMO;
if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
buffer->merge_out_clusters (start, end);
buffer->merge_out_clusters (start, end);
continue;
}
else if ((!tindex && buffer->idx + 1 < count && isT (buffer->cur(+1).codepoint)))

View file

@ -360,7 +360,7 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan,
{
/* Since we decomposed, and NIKHAHIT is combining, merge clusters with the
* previous cluster. */
if (start && buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
if (start)
buffer->merge_out_clusters (start - 1, end);
}
}