From 20a50acc91946f1ae3421dd7dd5657b81e1ffd24 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 25 Dec 2022 16:09:26 -0700 Subject: [PATCH] [hb-cairo] Make hb_cairo_glyphs_from_buffer public --- src/hb-cairo.cc | 125 +++++++++++++++++++++++++++++++++++++++++++ src/hb-cairo.h | 12 +++++ src/hb-utf.hh | 30 ++++++++++- util/helper-cairo.hh | 121 ----------------------------------------- 4 files changed, 166 insertions(+), 122 deletions(-) diff --git a/src/hb-cairo.cc b/src/hb-cairo.cc index ed7c4ae90..4bb45bbaf 100644 --- a/src/hb-cairo.cc +++ b/src/hb-cairo.cc @@ -30,6 +30,8 @@ #include "hb-cairo-utils.hh" +#include "hb-utf.hh" + static void move_to (hb_draw_funcs_t *dfuncs, cairo_t *cr, @@ -395,3 +397,126 @@ hb_cairo_font_face_get_font (cairo_font_face_t *font_face) { return (hb_font_t *) cairo_font_face_get_user_data (font_face, &hb_cairo_font_user_data_key); } + + +void +hb_cairo_glyphs_from_buffer (hb_buffer_t *buffer, + const char *text, + int text_len, + hb_bool_t utf8_clusters, + int scale_factor, + cairo_glyph_t **glyphs, + unsigned int *num_glyphs, + cairo_text_cluster_t **clusters, + unsigned int *num_clusters, + cairo_text_cluster_flags_t *cluster_flags) +{ + if (text && text_len < 0) + text_len = strlen (text); + + *num_glyphs = hb_buffer_get_length (buffer); + hb_glyph_info_t *hb_glyph = hb_buffer_get_glyph_infos (buffer, nullptr); + hb_glyph_position_t *hb_position = hb_buffer_get_glyph_positions (buffer, nullptr); + *glyphs = cairo_glyph_allocate (*num_glyphs + 1); + + if (text) + { + *num_clusters = *num_glyphs ? 1 : 0; + for (unsigned int i = 1; i < *num_glyphs; i++) + if (hb_glyph[i].cluster != hb_glyph[i-1].cluster) + (*num_clusters)++; + *clusters = cairo_text_cluster_allocate (*num_clusters); + } + else if (clusters) + { + *clusters = nullptr; + *num_clusters = 0; + *cluster_flags = (cairo_text_cluster_flags_t) 0; + } + + if ((*num_glyphs && !*glyphs) || + (clusters && *num_clusters && !*clusters)) + { + if (*glyphs) + { + cairo_glyph_free (*glyphs); + *glyphs = nullptr; + *num_glyphs = 0; + } + if (clusters && *clusters) + { + cairo_text_cluster_free (*clusters); + *clusters = nullptr; + *num_clusters = 0; + *cluster_flags = (cairo_text_cluster_flags_t) 0; + } + return; + } + + double iscale = scale_factor ? 1. / scale_factor : 0.; + hb_position_t x = 0, y = 0; + int i; + for (i = 0; i < (int) *num_glyphs; i++) + { + (*glyphs)[i].index = hb_glyph[i].codepoint; + (*glyphs)[i].x = (+hb_position->x_offset + x) * iscale; + (*glyphs)[i].y = (-hb_position->y_offset + y) * iscale; + x += hb_position->x_advance; + y += -hb_position->y_advance; + + hb_position++; + } + (*glyphs)[i].index = -1; + (*glyphs)[i].x = x * iscale; + (*glyphs)[i].y = y * iscale; + + if (*num_clusters) + { + memset ((void *) *clusters, 0, *num_clusters * sizeof ((*clusters)[0])); + hb_bool_t backward = HB_DIRECTION_IS_BACKWARD (hb_buffer_get_direction (buffer)); + *cluster_flags = backward ? CAIRO_TEXT_CLUSTER_FLAG_BACKWARD : (cairo_text_cluster_flags_t) 0; + unsigned int cluster = 0; + const char *start = text, *end; + (*clusters)[cluster].num_glyphs++; + if (backward) + { + for (i = *num_glyphs - 2; i >= 0; i--) + { + if (hb_glyph[i].cluster != hb_glyph[i+1].cluster) + { + assert (hb_glyph[i].cluster > hb_glyph[i+1].cluster); + if (utf8_clusters) + end = start + hb_glyph[i].cluster - hb_glyph[i+1].cluster; + else + end = (const char *) hb_utf_offset_to_pointer ((const uint8_t *) start, + (signed) (hb_glyph[i].cluster - hb_glyph[i+1].cluster)); + (*clusters)[cluster].num_bytes = end - start; + start = end; + cluster++; + } + (*clusters)[cluster].num_glyphs++; + } + (*clusters)[cluster].num_bytes = text + text_len - start; + } + else + { + for (i = 1; i < (int) *num_glyphs; i++) + { + if (hb_glyph[i].cluster != hb_glyph[i-1].cluster) + { + assert (hb_glyph[i].cluster > hb_glyph[i-1].cluster); + if (utf8_clusters) + end = start + hb_glyph[i].cluster - hb_glyph[i-1].cluster; + else + end = (const char *) hb_utf_offset_to_pointer ((const uint8_t *) start, + (signed) (hb_glyph[i].cluster - hb_glyph[i-1].cluster)); + (*clusters)[cluster].num_bytes = end - start; + start = end; + cluster++; + } + (*clusters)[cluster].num_glyphs++; + } + (*clusters)[cluster].num_bytes = text + text_len - start; + } + } +} diff --git a/src/hb-cairo.h b/src/hb-cairo.h index 31940c416..2732350e0 100644 --- a/src/hb-cairo.h +++ b/src/hb-cairo.h @@ -39,6 +39,18 @@ hb_cairo_font_face_create (hb_font_t *font); HB_EXTERN hb_font_t * hb_cairo_font_face_get_font (cairo_font_face_t *font_face); +HB_EXTERN void +hb_cairo_glyphs_from_buffer (hb_buffer_t *buffer, + const char *text, + int text_len, + hb_bool_t utf8_clusters, + int scale_factor, + cairo_glyph_t **glyphs, + unsigned int *num_glyphs, + cairo_text_cluster_t **clusters, + unsigned int *num_clusters, + cairo_text_cluster_flags_t *cluster_flags); + HB_END_DECLS #endif /* HB_CAIRO_H */ diff --git a/src/hb-utf.hh b/src/hb-utf.hh index ff5712d16..1120bd1cc 100644 --- a/src/hb-utf.hh +++ b/src/hb-utf.hh @@ -35,6 +35,7 @@ struct hb_utf8_t { typedef uint8_t codepoint_t; + static constexpr unsigned max_len = 4; static const codepoint_t * next (const codepoint_t *text, @@ -182,6 +183,7 @@ struct hb_utf16_xe_t { static_assert (sizeof (TCodepoint) == 2, ""); typedef TCodepoint codepoint_t; + static constexpr unsigned max_len = 2; static const codepoint_t * next (const codepoint_t *text, @@ -290,6 +292,7 @@ struct hb_utf32_xe_t { static_assert (sizeof (TCodepoint) == 4, ""); typedef TCodepoint codepoint_t; + static constexpr unsigned max_len = 1; static const TCodepoint * next (const TCodepoint *text, @@ -348,6 +351,7 @@ typedef hb_utf32_xe_t hb_utf32_novalidate_t; struct hb_latin1_t { typedef uint8_t codepoint_t; + static constexpr unsigned max_len = 1; static const codepoint_t * next (const codepoint_t *text, @@ -399,12 +403,13 @@ struct hb_latin1_t struct hb_ascii_t { typedef uint8_t codepoint_t; + static constexpr unsigned max_len = 1; static const codepoint_t * next (const codepoint_t *text, const codepoint_t *end HB_UNUSED, hb_codepoint_t *unicode, - hb_codepoint_t replacement HB_UNUSED) + hb_codepoint_t replacement) { *unicode = *text++; if (*unicode >= 0x0080u) @@ -450,4 +455,27 @@ struct hb_ascii_t } }; +template +static inline const typename utf_t::codepoint_t * +hb_utf_offset_to_pointer (const typename utf_t::codepoint_t *start, + signed offset) +{ + hb_codepoint_t unicode; + + while (offset-- > 0) + start = utf_t::next (start, + start + utf_t::max_len, + &unicode, + HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT); + + while (offset++ < 0) + start = utf_t::prev (start, + start - utf_t::max_len, + &unicode, + HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT); + + return start; +} + + #endif /* HB_UTF_HH */ diff --git a/util/helper-cairo.hh b/util/helper-cairo.hh index b9b8cf0e8..6c330998b 100644 --- a/util/helper-cairo.hh +++ b/util/helper-cairo.hh @@ -592,127 +592,6 @@ struct helper_cairo_line_t { } }; -static inline void -hb_cairo_glyphs_from_buffer (hb_buffer_t *buffer, - const char *text, - int text_len, - hb_bool_t utf8_clusters, - int scale, - cairo_glyph_t **glyphs, - unsigned int *num_glyphs, - cairo_text_cluster_t **clusters, - unsigned int *num_clusters, - cairo_text_cluster_flags_t *cluster_flags) -{ - if (text && text_len < 0) - text_len = strlen (text); - - *num_glyphs = hb_buffer_get_length (buffer); - hb_glyph_info_t *hb_glyph = hb_buffer_get_glyph_infos (buffer, nullptr); - hb_glyph_position_t *hb_position = hb_buffer_get_glyph_positions (buffer, nullptr); - *glyphs = cairo_glyph_allocate (*num_glyphs + 1); - - if (text) - { - *num_clusters = *num_glyphs ? 1 : 0; - for (unsigned int i = 1; i < *num_glyphs; i++) - if (hb_glyph[i].cluster != hb_glyph[i-1].cluster) - (*num_clusters)++; - *clusters = cairo_text_cluster_allocate (*num_clusters); - } - else if (clusters) - { - *clusters = nullptr; - *num_clusters = 0; - *cluster_flags = (cairo_text_cluster_flags_t) 0; - } - - if ((*num_glyphs && !*glyphs) || - (clusters && *num_clusters && !*clusters)) - { - if (*glyphs) - { - cairo_glyph_free (*glyphs); - *glyphs = nullptr; - *num_glyphs = 0; - } - if (clusters && *clusters) - { - cairo_text_cluster_free (*clusters); - *clusters = nullptr; - *num_clusters = 0; - *cluster_flags = (cairo_text_cluster_flags_t) 0; - } - return; - } - - double iscale = scale ? 1. / scale : 0.; - hb_position_t x = 0, y = 0; - int i; - for (i = 0; i < (int) *num_glyphs; i++) - { - (*glyphs)[i].index = hb_glyph[i].codepoint; - (*glyphs)[i].x = (+hb_position->x_offset + x) * iscale; - (*glyphs)[i].y = (-hb_position->y_offset + y) * iscale; - x += hb_position->x_advance; - y += -hb_position->y_advance; - - hb_position++; - } - (*glyphs)[i].index = -1; - (*glyphs)[i].x = x * iscale; - (*glyphs)[i].y = y * iscale; - - if (*num_clusters) - { - memset ((void *) *clusters, 0, *num_clusters * sizeof ((*clusters)[0])); - hb_bool_t backward = HB_DIRECTION_IS_BACKWARD (hb_buffer_get_direction (buffer)); - *cluster_flags = backward ? CAIRO_TEXT_CLUSTER_FLAG_BACKWARD : (cairo_text_cluster_flags_t) 0; - unsigned int cluster = 0; - const char *start = text, *end; - (*clusters)[cluster].num_glyphs++; - if (backward) - { - for (i = *num_glyphs - 2; i >= 0; i--) - { - if (hb_glyph[i].cluster != hb_glyph[i+1].cluster) - { - assert (hb_glyph[i].cluster > hb_glyph[i+1].cluster); - if (utf8_clusters) - end = start + hb_glyph[i].cluster - hb_glyph[i+1].cluster; - else - end = g_utf8_offset_to_pointer (start, hb_glyph[i].cluster - hb_glyph[i+1].cluster); - (*clusters)[cluster].num_bytes = end - start; - start = end; - cluster++; - } - (*clusters)[cluster].num_glyphs++; - } - (*clusters)[cluster].num_bytes = text + text_len - start; - } - else - { - for (i = 1; i < (int) *num_glyphs; i++) - { - if (hb_glyph[i].cluster != hb_glyph[i-1].cluster) - { - assert (hb_glyph[i].cluster > hb_glyph[i-1].cluster); - if (utf8_clusters) - end = start + hb_glyph[i].cluster - hb_glyph[i-1].cluster; - else - end = g_utf8_offset_to_pointer (start, hb_glyph[i].cluster - hb_glyph[i-1].cluster); - (*clusters)[cluster].num_bytes = end - start; - start = end; - cluster++; - } - (*clusters)[cluster].num_glyphs++; - } - (*clusters)[cluster].num_bytes = text + text_len - start; - } - } -} - - static inline void helper_cairo_line_from_buffer (helper_cairo_line_t *l, hb_buffer_t *buffer,