[hb-cairo] Make hb_cairo_glyphs_from_buffer public

This commit is contained in:
Behdad Esfahbod 2022-12-25 16:09:26 -07:00
parent bf52386cfa
commit 20a50acc91
4 changed files with 166 additions and 122 deletions

View File

@ -30,6 +30,8 @@
#include "hb-cairo-utils.hh" #include "hb-cairo-utils.hh"
#include "hb-utf.hh"
static void static void
move_to (hb_draw_funcs_t *dfuncs, move_to (hb_draw_funcs_t *dfuncs,
cairo_t *cr, 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); 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<hb_utf8_t> ((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<hb_utf8_t> ((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;
}
}
}

View File

@ -39,6 +39,18 @@ hb_cairo_font_face_create (hb_font_t *font);
HB_EXTERN hb_font_t * HB_EXTERN hb_font_t *
hb_cairo_font_face_get_font (cairo_font_face_t *font_face); 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 HB_END_DECLS
#endif /* HB_CAIRO_H */ #endif /* HB_CAIRO_H */

View File

@ -35,6 +35,7 @@
struct hb_utf8_t struct hb_utf8_t
{ {
typedef uint8_t codepoint_t; typedef uint8_t codepoint_t;
static constexpr unsigned max_len = 4;
static const codepoint_t * static const codepoint_t *
next (const codepoint_t *text, next (const codepoint_t *text,
@ -182,6 +183,7 @@ struct hb_utf16_xe_t
{ {
static_assert (sizeof (TCodepoint) == 2, ""); static_assert (sizeof (TCodepoint) == 2, "");
typedef TCodepoint codepoint_t; typedef TCodepoint codepoint_t;
static constexpr unsigned max_len = 2;
static const codepoint_t * static const codepoint_t *
next (const codepoint_t *text, next (const codepoint_t *text,
@ -290,6 +292,7 @@ struct hb_utf32_xe_t
{ {
static_assert (sizeof (TCodepoint) == 4, ""); static_assert (sizeof (TCodepoint) == 4, "");
typedef TCodepoint codepoint_t; typedef TCodepoint codepoint_t;
static constexpr unsigned max_len = 1;
static const TCodepoint * static const TCodepoint *
next (const TCodepoint *text, next (const TCodepoint *text,
@ -348,6 +351,7 @@ typedef hb_utf32_xe_t<uint32_t, false> hb_utf32_novalidate_t;
struct hb_latin1_t struct hb_latin1_t
{ {
typedef uint8_t codepoint_t; typedef uint8_t codepoint_t;
static constexpr unsigned max_len = 1;
static const codepoint_t * static const codepoint_t *
next (const codepoint_t *text, next (const codepoint_t *text,
@ -399,12 +403,13 @@ struct hb_latin1_t
struct hb_ascii_t struct hb_ascii_t
{ {
typedef uint8_t codepoint_t; typedef uint8_t codepoint_t;
static constexpr unsigned max_len = 1;
static const codepoint_t * static const codepoint_t *
next (const codepoint_t *text, next (const codepoint_t *text,
const codepoint_t *end HB_UNUSED, const codepoint_t *end HB_UNUSED,
hb_codepoint_t *unicode, hb_codepoint_t *unicode,
hb_codepoint_t replacement HB_UNUSED) hb_codepoint_t replacement)
{ {
*unicode = *text++; *unicode = *text++;
if (*unicode >= 0x0080u) if (*unicode >= 0x0080u)
@ -450,4 +455,27 @@ struct hb_ascii_t
} }
}; };
template <typename utf_t>
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 */ #endif /* HB_UTF_HH */

View File

@ -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 static inline void
helper_cairo_line_from_buffer (helper_cairo_line_t *l, helper_cairo_line_from_buffer (helper_cairo_line_t *l,
hb_buffer_t *buffer, hb_buffer_t *buffer,