• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 **
hb_buffer_serialize_list_formats()47 hb_buffer_serialize_list_formats ()
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
hb_buffer_serialize_format_from_string(const char * str,int len)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 *
hb_buffer_serialize_format_to_string(hb_buffer_serialize_format_t format)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
_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)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
_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)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  *     `&lt;x_bearing,y_bearing,width,height&gt;`
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
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,hb_buffer_serialize_format_t format,hb_buffer_serialize_flags_t flags)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
parse_uint(const char * pp,const char * end,uint32_t * pv)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
parse_int(const char * pp,const char * end,int32_t * pv)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
hb_buffer_deserialize_glyphs(hb_buffer_t * buffer,const char * buf,int buf_len,const char ** end_ptr,hb_font_t * font,hb_buffer_serialize_format_t format)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 NULL */
444 			      hb_font_t *font, /* May be NULL */
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