1 | /* |
2 | * Copyright © 2012,2013 Google, Inc. |
3 | * |
4 | * This is part of HarfBuzz, a text shaping library. |
5 | * |
6 | * Permission is hereby granted, without written agreement and without |
7 | * license or royalty fees, to use, copy, modify, and distribute this |
8 | * software and its documentation for any purpose, provided that the |
9 | * above copyright notice and the following two paragraphs appear in |
10 | * all copies of this software. |
11 | * |
12 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
13 | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
14 | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
15 | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
16 | * DAMAGE. |
17 | * |
18 | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
19 | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
20 | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
21 | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
22 | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
23 | * |
24 | * Google Author(s): Behdad Esfahbod |
25 | */ |
26 | |
27 | #include "hb-buffer.hh" |
28 | |
29 | |
30 | static const char *serialize_formats[] = { |
31 | "text" , |
32 | "json" , |
33 | nullptr |
34 | }; |
35 | |
36 | /** |
37 | * hb_buffer_serialize_list_formats: |
38 | * |
39 | * Returns a list of supported buffer serialization formats. |
40 | * |
41 | * Return value: (transfer none): |
42 | * A string array of buffer serialization formats. Should not be freed. |
43 | * |
44 | * Since: 0.9.7 |
45 | **/ |
46 | const char ** |
47 | hb_buffer_serialize_list_formats (void) |
48 | { |
49 | return serialize_formats; |
50 | } |
51 | |
52 | /** |
53 | * hb_buffer_serialize_format_from_string: |
54 | * @str: (array length=len) (element-type uint8_t): a string to parse |
55 | * @len: length of @str, or -1 if string is %NULL terminated |
56 | * |
57 | * Parses a string into an #hb_buffer_serialize_format_t. Does not check if |
58 | * @str is a valid buffer serialization format, use |
59 | * hb_buffer_serialize_list_formats() to get the list of supported formats. |
60 | * |
61 | * Return value: |
62 | * The parsed #hb_buffer_serialize_format_t. |
63 | * |
64 | * Since: 0.9.7 |
65 | **/ |
66 | hb_buffer_serialize_format_t |
67 | hb_buffer_serialize_format_from_string (const char *str, int len) |
68 | { |
69 | /* Upper-case it. */ |
70 | return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020u); |
71 | } |
72 | |
73 | /** |
74 | * hb_buffer_serialize_format_to_string: |
75 | * @format: an #hb_buffer_serialize_format_t to convert. |
76 | * |
77 | * Converts @format to the string corresponding it, or %NULL if it is not a valid |
78 | * #hb_buffer_serialize_format_t. |
79 | * |
80 | * Return value: (transfer none): |
81 | * A %NULL terminated string corresponding to @format. Should not be freed. |
82 | * |
83 | * Since: 0.9.7 |
84 | **/ |
85 | const char * |
86 | hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format) |
87 | { |
88 | switch (format) |
89 | { |
90 | case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return serialize_formats[0]; |
91 | case HB_BUFFER_SERIALIZE_FORMAT_JSON: return serialize_formats[1]; |
92 | default: |
93 | case HB_BUFFER_SERIALIZE_FORMAT_INVALID: return nullptr; |
94 | } |
95 | } |
96 | |
97 | static unsigned int |
98 | _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer, |
99 | unsigned int start, |
100 | unsigned int end, |
101 | char *buf, |
102 | unsigned int buf_size, |
103 | unsigned int *buf_consumed, |
104 | hb_font_t *font, |
105 | hb_buffer_serialize_flags_t flags) |
106 | { |
107 | hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr); |
108 | hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ? |
109 | nullptr : hb_buffer_get_glyph_positions (buffer, nullptr); |
110 | |
111 | *buf_consumed = 0; |
112 | hb_position_t x = 0, y = 0; |
113 | for (unsigned int i = start; i < end; i++) |
114 | { |
115 | char b[1024]; |
116 | char *p = b; |
117 | |
118 | /* In the following code, we know b is large enough that no overflow can happen. */ |
119 | |
120 | #define APPEND(s) HB_STMT_START { strcpy (p, s); p += strlen (s); } HB_STMT_END |
121 | |
122 | if (i) |
123 | *p++ = ','; |
124 | |
125 | *p++ = '{'; |
126 | |
127 | APPEND ("\"g\":" ); |
128 | if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES)) |
129 | { |
130 | char g[128]; |
131 | hb_font_glyph_to_string (font, info[i].codepoint, g, sizeof (g)); |
132 | *p++ = '"'; |
133 | for (char *q = g; *q; q++) { |
134 | if (*q == '"') |
135 | *p++ = '\\'; |
136 | *p++ = *q; |
137 | } |
138 | *p++ = '"'; |
139 | } |
140 | else |
141 | p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u" , info[i].codepoint)); |
142 | |
143 | if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) { |
144 | p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u" , info[i].cluster)); |
145 | } |
146 | |
147 | if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) |
148 | { |
149 | p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d" , |
150 | x+pos[i].x_offset, y+pos[i].y_offset)); |
151 | if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES)) |
152 | p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d" , |
153 | pos[i].x_advance, pos[i].y_advance)); |
154 | } |
155 | |
156 | if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS) |
157 | { |
158 | if (info[i].mask & HB_GLYPH_FLAG_DEFINED) |
159 | p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"fl\":%u" , info[i].mask & HB_GLYPH_FLAG_DEFINED)); |
160 | } |
161 | |
162 | if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS) |
163 | { |
164 | hb_glyph_extents_t extents; |
165 | hb_font_get_glyph_extents(font, info[i].codepoint, &extents); |
166 | p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d" , |
167 | extents.x_bearing, extents.y_bearing)); |
168 | p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d" , |
169 | extents.width, extents.height)); |
170 | } |
171 | |
172 | *p++ = '}'; |
173 | |
174 | unsigned int l = p - b; |
175 | if (buf_size > l) |
176 | { |
177 | memcpy (buf, b, l); |
178 | buf += l; |
179 | buf_size -= l; |
180 | *buf_consumed += l; |
181 | *buf = '\0'; |
182 | } else |
183 | return i - start; |
184 | |
185 | if (pos && (flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES)) |
186 | { |
187 | x += pos[i].x_advance; |
188 | y += pos[i].y_advance; |
189 | } |
190 | } |
191 | |
192 | return end - start; |
193 | } |
194 | |
195 | static unsigned int |
196 | _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, |
197 | unsigned int start, |
198 | unsigned int end, |
199 | char *buf, |
200 | unsigned int buf_size, |
201 | unsigned int *buf_consumed, |
202 | hb_font_t *font, |
203 | hb_buffer_serialize_flags_t flags) |
204 | { |
205 | hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr); |
206 | hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ? |
207 | nullptr : hb_buffer_get_glyph_positions (buffer, nullptr); |
208 | |
209 | *buf_consumed = 0; |
210 | hb_position_t x = 0, y = 0; |
211 | for (unsigned int i = start; i < end; i++) |
212 | { |
213 | char b[1024]; |
214 | char *p = b; |
215 | |
216 | /* In the following code, we know b is large enough that no overflow can happen. */ |
217 | |
218 | if (i) |
219 | *p++ = '|'; |
220 | |
221 | if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES)) |
222 | { |
223 | hb_font_glyph_to_string (font, info[i].codepoint, p, 128); |
224 | p += strlen (p); |
225 | } |
226 | else |
227 | p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u" , info[i].codepoint)); |
228 | |
229 | if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) { |
230 | p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u" , info[i].cluster)); |
231 | } |
232 | |
233 | if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) |
234 | { |
235 | if (x+pos[i].x_offset || y+pos[i].y_offset) |
236 | p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d" , x+pos[i].x_offset, y+pos[i].y_offset)); |
237 | |
238 | if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES)) |
239 | { |
240 | *p++ = '+'; |
241 | p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d" , pos[i].x_advance)); |
242 | if (pos[i].y_advance) |
243 | p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d" , pos[i].y_advance)); |
244 | } |
245 | } |
246 | |
247 | if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS) |
248 | { |
249 | if (info[i].mask &HB_GLYPH_FLAG_DEFINED) |
250 | p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "#%X" , info[i].mask &HB_GLYPH_FLAG_DEFINED)); |
251 | } |
252 | |
253 | if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS) |
254 | { |
255 | hb_glyph_extents_t extents; |
256 | hb_font_get_glyph_extents(font, info[i].codepoint, &extents); |
257 | p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>" , extents.x_bearing, extents.y_bearing, extents.width, extents.height)); |
258 | } |
259 | |
260 | unsigned int l = p - b; |
261 | if (buf_size > l) |
262 | { |
263 | memcpy (buf, b, l); |
264 | buf += l; |
265 | buf_size -= l; |
266 | *buf_consumed += l; |
267 | *buf = '\0'; |
268 | } else |
269 | return i - start; |
270 | |
271 | if (pos && (flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES)) |
272 | { |
273 | x += pos[i].x_advance; |
274 | y += pos[i].y_advance; |
275 | } |
276 | } |
277 | |
278 | return end - start; |
279 | } |
280 | |
281 | /** |
282 | * hb_buffer_serialize_glyphs: |
283 | * @buffer: an #hb_buffer_t buffer. |
284 | * @start: the first item in @buffer to serialize. |
285 | * @end: the last item in @buffer to serialize. |
286 | * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to |
287 | * write serialized buffer into. |
288 | * @buf_size: the size of @buf. |
289 | * @buf_consumed: (out) (allow-none): if not %NULL, will be set to the number of byes written into @buf. |
290 | * @font: (allow-none): the #hb_font_t used to shape this buffer, needed to |
291 | * read glyph names and extents. If %NULL, and empty font will be used. |
292 | * @format: the #hb_buffer_serialize_format_t to use for formatting the output. |
293 | * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties |
294 | * to serialize. |
295 | * |
296 | * Serializes @buffer into a textual representation of its glyph content, |
297 | * useful for showing the contents of the buffer, for example during debugging. |
298 | * There are currently two supported serialization formats: |
299 | * |
300 | * ## text |
301 | * A human-readable, plain text format. |
302 | * The serialized glyphs will look something like: |
303 | * |
304 | * ``` |
305 | * [uni0651=0@518,0+0|uni0628=0+1897] |
306 | * ``` |
307 | * - The serialized glyphs are delimited with `[` and `]`. |
308 | * - Glyphs are separated with `|` |
309 | * - Each glyph starts with glyph name, or glyph index if |
310 | * #HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES flag is set. Then, |
311 | * - If #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set, `=` then #hb_glyph_info_t.cluster. |
312 | * - If #HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS is not set, the #hb_glyph_position_t in the format: |
313 | * - If both #hb_glyph_position_t.x_offset and #hb_glyph_position_t.y_offset are not 0, `@x_offset,y_offset`. Then, |
314 | * - `+x_advance`, then `,y_advance` if #hb_glyph_position_t.y_advance is not 0. Then, |
315 | * - If #HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS is set, the |
316 | * #hb_glyph_extents_t in the format |
317 | * `<x_bearing,y_bearing,width,height>` |
318 | * |
319 | * ## json |
320 | * TODO. |
321 | * |
322 | * Return value: |
323 | * The number of serialized items. |
324 | * |
325 | * Since: 0.9.7 |
326 | **/ |
327 | unsigned int |
328 | hb_buffer_serialize_glyphs (hb_buffer_t *buffer, |
329 | unsigned int start, |
330 | unsigned int end, |
331 | char *buf, |
332 | unsigned int buf_size, |
333 | unsigned int *buf_consumed, |
334 | hb_font_t *font, |
335 | hb_buffer_serialize_format_t format, |
336 | hb_buffer_serialize_flags_t flags) |
337 | { |
338 | assert (start <= end && end <= buffer->len); |
339 | |
340 | unsigned int sconsumed; |
341 | if (!buf_consumed) |
342 | buf_consumed = &sconsumed; |
343 | *buf_consumed = 0; |
344 | if (buf_size) |
345 | *buf = '\0'; |
346 | |
347 | assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) || |
348 | buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS); |
349 | |
350 | if (!buffer->have_positions) |
351 | flags |= HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS; |
352 | |
353 | if (unlikely (start == end)) |
354 | return 0; |
355 | |
356 | if (!font) |
357 | font = hb_font_get_empty (); |
358 | |
359 | switch (format) |
360 | { |
361 | case HB_BUFFER_SERIALIZE_FORMAT_TEXT: |
362 | return _hb_buffer_serialize_glyphs_text (buffer, start, end, |
363 | buf, buf_size, buf_consumed, |
364 | font, flags); |
365 | |
366 | case HB_BUFFER_SERIALIZE_FORMAT_JSON: |
367 | return _hb_buffer_serialize_glyphs_json (buffer, start, end, |
368 | buf, buf_size, buf_consumed, |
369 | font, flags); |
370 | |
371 | default: |
372 | case HB_BUFFER_SERIALIZE_FORMAT_INVALID: |
373 | return 0; |
374 | |
375 | } |
376 | } |
377 | |
378 | |
379 | static hb_bool_t |
380 | parse_uint (const char *pp, const char *end, uint32_t *pv) |
381 | { |
382 | char buf[32]; |
383 | unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp)); |
384 | strncpy (buf, pp, len); |
385 | buf[len] = '\0'; |
386 | |
387 | char *p = buf; |
388 | char *pend = p; |
389 | uint32_t v; |
390 | |
391 | errno = 0; |
392 | v = strtol (p, &pend, 10); |
393 | if (errno || p == pend || pend - p != end - pp) |
394 | return false; |
395 | |
396 | *pv = v; |
397 | return true; |
398 | } |
399 | |
400 | static hb_bool_t |
401 | parse_int (const char *pp, const char *end, int32_t *pv) |
402 | { |
403 | char buf[32]; |
404 | unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp)); |
405 | strncpy (buf, pp, len); |
406 | buf[len] = '\0'; |
407 | |
408 | char *p = buf; |
409 | char *pend = p; |
410 | int32_t v; |
411 | |
412 | errno = 0; |
413 | v = strtol (p, &pend, 10); |
414 | if (errno || p == pend || pend - p != end - pp) |
415 | return false; |
416 | |
417 | *pv = v; |
418 | return true; |
419 | } |
420 | |
421 | #include "hb-buffer-deserialize-json.hh" |
422 | #include "hb-buffer-deserialize-text.hh" |
423 | |
424 | /** |
425 | * hb_buffer_deserialize_glyphs: |
426 | * @buffer: an #hb_buffer_t buffer. |
427 | * @buf: (array length=buf_len): |
428 | * @buf_len: |
429 | * @end_ptr: (out): |
430 | * @font: |
431 | * @format: |
432 | * |
433 | * |
434 | * |
435 | * Return value: |
436 | * |
437 | * Since: 0.9.7 |
438 | **/ |
439 | hb_bool_t |
440 | hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, |
441 | const char *buf, |
442 | int buf_len, /* -1 means nul-terminated */ |
443 | const char **end_ptr, /* May be nullptr */ |
444 | hb_font_t *font, /* May be nullptr */ |
445 | hb_buffer_serialize_format_t format) |
446 | { |
447 | const char *end; |
448 | if (!end_ptr) |
449 | end_ptr = &end; |
450 | *end_ptr = buf; |
451 | |
452 | assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) || |
453 | buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS); |
454 | |
455 | if (buf_len == -1) |
456 | buf_len = strlen (buf); |
457 | |
458 | if (!buf_len) |
459 | { |
460 | *end_ptr = buf; |
461 | return false; |
462 | } |
463 | |
464 | hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_GLYPHS); |
465 | |
466 | if (!font) |
467 | font = hb_font_get_empty (); |
468 | |
469 | switch (format) |
470 | { |
471 | case HB_BUFFER_SERIALIZE_FORMAT_TEXT: |
472 | return _hb_buffer_deserialize_glyphs_text (buffer, |
473 | buf, buf_len, end_ptr, |
474 | font); |
475 | |
476 | case HB_BUFFER_SERIALIZE_FORMAT_JSON: |
477 | return _hb_buffer_deserialize_glyphs_json (buffer, |
478 | buf, buf_len, end_ptr, |
479 | font); |
480 | |
481 | default: |
482 | case HB_BUFFER_SERIALIZE_FORMAT_INVALID: |
483 | return false; |
484 | |
485 | } |
486 | } |
487 | |