Add buffer serialization / deserialization API

Two output formats for now: TEXT, and JSON.  For example:

  hb-shape --output-format=json

Deserialization API is added, but not implemented yet.
This commit is contained in:
Behdad Esfahbod 2012-11-15 12:14:09 -08:00
parent fd0de881f4
commit f9edf16725
5 changed files with 303 additions and 44 deletions

View File

@ -1023,3 +1023,225 @@ hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
}
normalize_glyphs_cluster (buffer, start, end, backward);
}
/*
* Serialize
*/
static const char *serialize_formats[] = {
"TEXT",
"JSON",
NULL
};
hb_buffer_serialize_format_t
hb_buffer_serialize_format_from_string (const char *str, int len)
{
/* Upper-case it. */
return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020);
}
const char *
hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format)
{
switch (format)
{
case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return serialize_formats[0];
case HB_BUFFER_SERIALIZE_FORMAT_JSON: return serialize_formats[1];
default:
case HB_BUFFER_SERIALIZE_FORMAT_INVALID: return NULL;
}
}
static unsigned int
_hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
unsigned int start,
unsigned int end,
char *buf,
unsigned int buf_size,
unsigned int *buf_consumed,
hb_font_t *font,
hb_buffer_serialize_flags_t flags)
{
hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL);
*buf_consumed = 0;
for (unsigned int i = start; i < end; i++)
{
char b[1024];
char *p = b;
/* In the following code, we know b is large enough that no overflow can happen. */
#define APPEND(s) HB_STMT_START { strcpy (p, s); p += strlen (s); } HB_STMT_END
if (i)
*p++ = ',';
*p++ = '{';
APPEND ("\"g\":");
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES))
{
char g[128];
hb_font_glyph_to_string (font, info[i].codepoint, g, sizeof (g));
*p++ = '"';
for (char *q = g; *q; q++) {
if (*q == '"')
*p++ = '\\';
*p++ = *q;
}
*p++ = '"';
}
else
p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint);
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster);
}
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
{
p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
pos[i].x_offset, pos[i].y_offset);
p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
pos[i].x_advance, pos[i].y_advance);
}
*p++ = '}';
if (buf_size > (p - b))
{
unsigned int l = p - b;
memcpy (buf, b, l);
buf += l;
buf_size -= l;
*buf_consumed += l;
*buf = '\0';
} else
return i - start;
}
return end - start;
}
static unsigned int
_hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
unsigned int start,
unsigned int end,
char *buf,
unsigned int buf_size,
unsigned int *buf_consumed,
hb_font_t *font,
hb_buffer_serialize_flags_t flags)
{
hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL);
hb_direction_t direction = hb_buffer_get_direction (buffer);
*buf_consumed = 0;
for (unsigned int i = start; i < end; i++)
{
char b[1024];
char *p = b;
/* In the following code, we know b is large enough that no overflow can happen. */
if (i)
*p++ = '|';
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES))
{
hb_font_glyph_to_string (font, info[i].codepoint, p, 128);
p += strlen (p);
}
else
p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint);
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster);
}
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
{
if (pos[i].x_offset || pos[i].y_offset)
p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", pos[i].x_offset, pos[i].y_offset);
*p++ = '+';
if (HB_DIRECTION_IS_HORIZONTAL (direction) || pos[i].x_advance)
p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance);
if (HB_DIRECTION_IS_VERTICAL (direction) || pos->y_advance)
p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance);
}
if (buf_size > (p - b))
{
unsigned int l = p - b;
memcpy (buf, b, l);
buf += l;
buf_size -= l;
*buf_consumed += l;
*buf = '\0';
} else
return i - start;
}
return end - start;
}
/* Returns number of items, starting at start, that were serialized. */
unsigned int
hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
unsigned int start,
unsigned int end,
char *buf,
unsigned int buf_size,
unsigned int *buf_consumed,
hb_font_t *font, /* May be NULL */
hb_buffer_serialize_format_t format,
hb_buffer_serialize_flags_t flags)
{
assert (start <= end && end <= buffer->len);
*buf_consumed = 0;
assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
if (unlikely (start == end))
return 0;
if (!font)
font = hb_font_get_empty ();
switch (format)
{
case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
return _hb_buffer_serialize_glyphs_text (buffer, start, end,
buf, buf_size, buf_consumed,
font, flags);
case HB_BUFFER_SERIALIZE_FORMAT_JSON:
return _hb_buffer_serialize_glyphs_json (buffer, start, end,
buf, buf_size, buf_consumed,
font, flags);
default:
case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
return 0;
}
}
hb_bool_t
hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
const char *buf,
unsigned int buf_len,
unsigned int *buf_consumed,
hb_font_t *font, /* May be NULL */
hb_buffer_serialize_format_t format)
{
return false;
}

View File

@ -36,6 +36,7 @@
#include "hb-common.h"
#include "hb-unicode.h"
#include "hb-font.h"
HB_BEGIN_DECLS
@ -238,6 +239,47 @@ hb_buffer_normalize_glyphs (hb_buffer_t *buffer);
*/
typedef enum {
HB_BUFFER_SERIALIZE_FLAGS_DEFAULT = 0x00000000,
HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS = 0x00000001,
HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS = 0x00000002,
HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES = 0x00000004
} hb_buffer_serialize_flags_t;
typedef enum {
HB_BUFFER_SERIALIZE_FORMAT_TEXT = HB_TAG('T','E','X','T'),
HB_BUFFER_SERIALIZE_FORMAT_JSON = HB_TAG('J','S','O','N'),
HB_BUFFER_SERIALIZE_FORMAT_INVALID = HB_TAG_NONE
} hb_buffer_serialize_format_t;
/* len=-1 means str is NUL-terminated. */
hb_buffer_serialize_format_t
hb_buffer_serialize_format_from_string (const char *str, int len);
const char *
hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format);
/* Returns number of items, starting at start, that were serialized. */
unsigned int
hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
unsigned int start,
unsigned int end,
char *buf,
unsigned int buf_size,
unsigned int *buf_consumed,
hb_font_t *font, /* May be NULL */
hb_buffer_serialize_format_t format,
hb_buffer_serialize_flags_t flags);
hb_bool_t
hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
const char *buf,
unsigned int buf_len,
unsigned int *buf_consumed,
hb_font_t *font, /* May be NULL */
hb_buffer_serialize_format_t format);
HB_END_DECLS
#endif /* HB_BUFFER_H */

View File

@ -40,6 +40,20 @@ struct output_buffer_t
gs = g_string_new (NULL);
line_no = 0;
font = hb_font_reference (font_opts->get_font ());
if (!options.output_format)
output_format = HB_BUFFER_SERIALIZE_FORMAT_TEXT;
else
output_format = hb_buffer_serialize_format_from_string (options.output_format, -1);
unsigned int flags = HB_BUFFER_SERIALIZE_FLAGS_DEFAULT;
if (!format.show_glyph_names)
flags |= HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES;
if (!format.show_clusters)
flags |= HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS;
if (!format.show_positions)
flags |= HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS;
format_flags = (hb_buffer_serialize_flags_t) flags;
}
void new_line (void)
{
@ -51,7 +65,7 @@ struct output_buffer_t
hb_bool_t utf8_clusters)
{
g_string_set_size (gs, 0);
format.serialize_buffer_of_text (buffer, line_no, text, text_len, font, utf8_clusters, gs);
format.serialize_buffer_of_text (buffer, line_no, text, text_len, font, gs);
fprintf (options.fp, "%s", gs->str);
}
void shape_failed (hb_buffer_t *buffer,
@ -69,7 +83,8 @@ struct output_buffer_t
hb_bool_t utf8_clusters)
{
g_string_set_size (gs, 0);
format.serialize_buffer_of_glyphs (buffer, line_no, text, text_len, font, utf8_clusters, gs);
format.serialize_buffer_of_glyphs (buffer, line_no, text, text_len, font,
output_format, format_flags, gs);
fprintf (options.fp, "%s", gs->str);
}
void finish (const font_options_t *font_opts)
@ -87,6 +102,8 @@ struct output_buffer_t
GString *gs;
unsigned int line_no;
hb_font_t *font;
hb_buffer_serialize_format_t output_format;
hb_buffer_serialize_flags_t format_flags;
};
int

View File

@ -615,46 +615,23 @@ format_options_t::serialize_unicode (hb_buffer_t *buffer,
void
format_options_t::serialize_glyphs (hb_buffer_t *buffer,
hb_font_t *font,
hb_bool_t utf8_clusters,
hb_buffer_serialize_format_t output_format,
hb_buffer_serialize_flags_t flags,
GString *gs)
{
unsigned int num_glyphs = hb_buffer_get_length (buffer);
hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL);
hb_direction_t direction = hb_buffer_get_direction (buffer);
g_string_append_c (gs, '[');
for (unsigned int i = 0; i < num_glyphs; i++)
{
if (i)
g_string_append_c (gs, '|');
unsigned int num_glyphs = hb_buffer_get_length (buffer);
unsigned int start = 0;
char glyph_name[128];
if (show_glyph_names) {
hb_font_glyph_to_string (font, info->codepoint, glyph_name, sizeof (glyph_name));
g_string_append_printf (gs, "%s", glyph_name);
} else
g_string_append_printf (gs, "%u", info->codepoint);
if (show_clusters) {
g_string_append_printf (gs, "=%u", info->cluster);
if (utf8_clusters)
g_string_append (gs, "u8");
}
if (show_positions && (pos->x_offset || pos->y_offset)) {
g_string_append_printf (gs, "@%d,%d", pos->x_offset, pos->y_offset);
}
if (show_positions) {
g_string_append_c (gs, '+');
if (HB_DIRECTION_IS_HORIZONTAL (direction) || pos->x_advance)
g_string_append_printf (gs, "%d", pos->x_advance);
if (HB_DIRECTION_IS_VERTICAL (direction) || pos->y_advance)
g_string_append_printf (gs, ",%d", pos->y_advance);
}
info++;
pos++;
while (start < num_glyphs) {
char buf[1024];
unsigned int consumed;
start += hb_buffer_serialize_glyphs (buffer, start, num_glyphs,
buf, sizeof (buf), &consumed,
font, output_format, flags);
if (!consumed)
break;
g_string_append (gs, buf);
}
g_string_append_c (gs, ']');
}
@ -671,7 +648,6 @@ format_options_t::serialize_buffer_of_text (hb_buffer_t *buffer,
const char *text,
unsigned int text_len,
hb_font_t *font,
hb_bool_t utf8_clusters,
GString *gs)
{
if (show_text) {
@ -703,10 +679,11 @@ format_options_t::serialize_buffer_of_glyphs (hb_buffer_t *buffer,
const char *text,
unsigned int text_len,
hb_font_t *font,
hb_bool_t utf8_clusters,
hb_buffer_serialize_format_t output_format,
hb_buffer_serialize_flags_t format_flags,
GString *gs)
{
serialize_line_no (line_no, gs);
serialize_glyphs (buffer, font, utf8_clusters, gs);
serialize_glyphs (buffer, font, output_format, format_flags, gs);
g_string_append_c (gs, '\n');
}

View File

@ -364,7 +364,8 @@ struct format_options_t : option_group_t
GString *gs);
void serialize_glyphs (hb_buffer_t *buffer,
hb_font_t *font,
hb_bool_t utf8_clusters,
hb_buffer_serialize_format_t format,
hb_buffer_serialize_flags_t flags,
GString *gs);
void serialize_line_no (unsigned int line_no,
GString *gs);
@ -373,7 +374,6 @@ struct format_options_t : option_group_t
const char *text,
unsigned int text_len,
hb_font_t *font,
hb_bool_t utf8_clusters,
GString *gs);
void serialize_message (unsigned int line_no,
const char *msg,
@ -383,7 +383,8 @@ struct format_options_t : option_group_t
const char *text,
unsigned int text_len,
hb_font_t *font,
hb_bool_t utf8_clusters,
hb_buffer_serialize_format_t output_format,
hb_buffer_serialize_flags_t format_flags,
GString *gs);