1 /*
2  * Copyright © 1998-2004  David Turner and Werner Lemberg
3  * Copyright © 2004,2007,2009,2010  Red Hat, Inc.
4  * Copyright © 2011,2012  Google, Inc.
5  *
6  *  This is part of HarfBuzz, a text shaping library.
7  *
8  * Permission is hereby granted, without written agreement and without
9  * license or royalty fees, to use, copy, modify, and distribute this
10  * software and its documentation for any purpose, provided that the
11  * above copyright notice and the following two paragraphs appear in
12  * all copies of this software.
13  *
14  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
15  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
16  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
17  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
18  * DAMAGE.
19  *
20  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
21  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
22  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
23  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
24  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
25  *
26  * Red Hat Author(s): Owen Taylor, Behdad Esfahbod
27  * Google Author(s): Behdad Esfahbod
28  */
29 
30 #ifndef HB_BUFFER_HH
31 #define HB_BUFFER_HH
32 
33 #include "hb.hh"
34 #include "hb-unicode.hh"
35 
36 
37 #ifndef HB_BUFFER_MAX_LEN_FACTOR
38 #define HB_BUFFER_MAX_LEN_FACTOR 64
39 #endif
40 #ifndef HB_BUFFER_MAX_LEN_MIN
41 #define HB_BUFFER_MAX_LEN_MIN 16384
42 #endif
43 #ifndef HB_BUFFER_MAX_LEN_DEFAULT
44 #define HB_BUFFER_MAX_LEN_DEFAULT 0x3FFFFFFF /* Shaping more than a billion chars? Let us know! */
45 #endif
46 
47 #ifndef HB_BUFFER_MAX_OPS_FACTOR
48 #define HB_BUFFER_MAX_OPS_FACTOR 1024
49 #endif
50 #ifndef HB_BUFFER_MAX_OPS_MIN
51 #define HB_BUFFER_MAX_OPS_MIN 16384
52 #endif
53 #ifndef HB_BUFFER_MAX_OPS_DEFAULT
54 #define HB_BUFFER_MAX_OPS_DEFAULT 0x1FFFFFFF /* Shaping more than a billion operations? Let us know! */
55 #endif
56 
57 static_assert ((sizeof (hb_glyph_info_t) == 20), "");
58 static_assert ((sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t)), "");
59 
60 HB_MARK_AS_FLAG_T (hb_buffer_flags_t);
61 HB_MARK_AS_FLAG_T (hb_buffer_serialize_flags_t);
62 HB_MARK_AS_FLAG_T (hb_buffer_diff_flags_t);
63 
64 enum hb_buffer_scratch_flags_t {
65   HB_BUFFER_SCRATCH_FLAG_DEFAULT			= 0x00000000u,
66   HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII			= 0x00000001u,
67   HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES		= 0x00000002u,
68   HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK		= 0x00000004u,
69   HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT		= 0x00000008u,
70   HB_BUFFER_SCRATCH_FLAG_HAS_CGJ			= 0x00000010u,
71   HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS		= 0x00000020u,
72 
73   /* Reserved for complex shapers' internal use. */
74   HB_BUFFER_SCRATCH_FLAG_COMPLEX0			= 0x01000000u,
75   HB_BUFFER_SCRATCH_FLAG_COMPLEX1			= 0x02000000u,
76   HB_BUFFER_SCRATCH_FLAG_COMPLEX2			= 0x04000000u,
77   HB_BUFFER_SCRATCH_FLAG_COMPLEX3			= 0x08000000u,
78 };
79 HB_MARK_AS_FLAG_T (hb_buffer_scratch_flags_t);
80 
81 
82 /*
83  * hb_buffer_t
84  */
85 
86 struct hb_buffer_t
87 {
88   hb_object_header_t header;
89 
90   /*
91    * Information about how the text in the buffer should be treated.
92    */
93 
94   hb_unicode_funcs_t *unicode; /* Unicode functions */
95   hb_buffer_flags_t flags; /* BOT / EOT / etc. */
96   hb_buffer_cluster_level_t cluster_level;
97   hb_codepoint_t replacement; /* U+FFFD or something else. */
98   hb_codepoint_t invisible; /* 0 or something else. */
99   hb_codepoint_t not_found; /* 0 or something else. */
100 
101   /*
102    * Buffer contents
103    */
104 
105   hb_buffer_content_type_t content_type;
106   hb_segment_properties_t props; /* Script, language, direction */
107 
108   bool successful; /* Allocations successful */
109   bool have_output; /* Whether we have an output buffer going on */
110   bool have_positions; /* Whether we have positions */
111 
112   unsigned int idx; /* Cursor into ->info and ->pos arrays */
113   unsigned int len; /* Length of ->info and ->pos arrays */
114   unsigned int out_len; /* Length of ->out_info array if have_output */
115 
116   unsigned int allocated; /* Length of allocated arrays */
117   hb_glyph_info_t     *info;
118   hb_glyph_info_t     *out_info;
119   hb_glyph_position_t *pos;
120 
121   /* Text before / after the main buffer contents.
122    * Always in Unicode, and ordered outward.
123    * Index 0 is for "pre-context", 1 for "post-context". */
124   static constexpr unsigned CONTEXT_LENGTH = 5u;
125   hb_codepoint_t context[2][CONTEXT_LENGTH];
126   unsigned int context_len[2];
127 
128 
129   /*
130    * Managed by enter / leave
131    */
132 
133 #ifndef HB_NDEBUG
134   uint8_t allocated_var_bits;
135 #endif
136   uint8_t serial;
137   hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */
138   unsigned int max_len; /* Maximum allowed len. */
139   int max_ops; /* Maximum allowed operations. */
140   /* The bits here reflect current allocations of the bytes in glyph_info_t's var1 and var2. */
141 
142 
143   /*
144    * Messaging callback
145    */
146 
147 #ifndef HB_NO_BUFFER_MESSAGE
148   hb_buffer_message_func_t message_func;
149   void *message_data;
150   hb_destroy_func_t message_destroy;
151   unsigned message_depth; /* How deeply are we inside a message callback? */
152 #else
153   static constexpr unsigned message_depth = 0u;
154 #endif
155 
156 
157 
158   /* Methods */
159 
in_errorhb_buffer_t160   HB_NODISCARD bool in_error () const { return !successful; }
161 
allocate_varhb_buffer_t162   void allocate_var (unsigned int start, unsigned int count)
163   {
164 #ifndef HB_NDEBUG
165     unsigned int end = start + count;
166     assert (end <= 8);
167     unsigned int bits = (1u<<end) - (1u<<start);
168     assert (0 == (allocated_var_bits & bits));
169     allocated_var_bits |= bits;
170 #endif
171   }
deallocate_varhb_buffer_t172   void deallocate_var (unsigned int start, unsigned int count)
173   {
174 #ifndef HB_NDEBUG
175     unsigned int end = start + count;
176     assert (end <= 8);
177     unsigned int bits = (1u<<end) - (1u<<start);
178     assert (bits == (allocated_var_bits & bits));
179     allocated_var_bits &= ~bits;
180 #endif
181   }
assert_varhb_buffer_t182   void assert_var (unsigned int start, unsigned int count)
183   {
184 #ifndef HB_NDEBUG
185     unsigned int end = start + count;
186     assert (end <= 8);
187     unsigned int bits = (1u<<end) - (1u<<start);
188     assert (bits == (allocated_var_bits & bits));
189 #endif
190   }
deallocate_var_allhb_buffer_t191   void deallocate_var_all ()
192   {
193 #ifndef HB_NDEBUG
194     allocated_var_bits = 0;
195 #endif
196   }
197 
curhb_buffer_t198   hb_glyph_info_t &cur (unsigned int i = 0) { return info[idx + i]; }
curhb_buffer_t199   hb_glyph_info_t cur (unsigned int i = 0) const { return info[idx + i]; }
200 
cur_poshb_buffer_t201   hb_glyph_position_t &cur_pos (unsigned int i = 0) { return pos[idx + i]; }
cur_poshb_buffer_t202   hb_glyph_position_t cur_pos (unsigned int i = 0) const { return pos[idx + i]; }
203 
prevhb_buffer_t204   hb_glyph_info_t &prev ()      { return out_info[out_len ? out_len - 1 : 0]; }
prevhb_buffer_t205   hb_glyph_info_t prev () const { return out_info[out_len ? out_len - 1 : 0]; }
206 
207   HB_INTERNAL void similar (const hb_buffer_t &src);
208   HB_INTERNAL void reset ();
209   HB_INTERNAL void clear ();
210 
211   /* Called around shape() */
212   HB_INTERNAL void enter ();
213   HB_INTERNAL void leave ();
214 
215 #ifndef HB_NO_BUFFER_VERIFY
216   HB_INTERNAL
217 #endif
218   bool verify (hb_buffer_t        *text_buffer,
219 	       hb_font_t          *font,
220 	       const hb_feature_t *features,
221 	       unsigned int        num_features,
222 	       const char * const *shapers)
223 #ifndef HB_NO_BUFFER_VERIFY
224   ;
225 #else
226   { return true; }
227 #endif
228 
backtrack_lenhb_buffer_t229   unsigned int backtrack_len () const { return have_output ? out_len : idx; }
lookahead_lenhb_buffer_t230   unsigned int lookahead_len () const { return len - idx; }
next_serialhb_buffer_t231   uint8_t next_serial () { return ++serial ? serial : ++serial; }
232 
233   HB_INTERNAL void add (hb_codepoint_t  codepoint,
234 			unsigned int    cluster);
235   HB_INTERNAL void add_info (const hb_glyph_info_t &glyph_info);
236 
reverse_rangehb_buffer_t237   void reverse_range (unsigned start, unsigned end)
238   {
239     hb_array_t<hb_glyph_info_t> (info, len).reverse (start, end);
240     if (have_positions)
241       hb_array_t<hb_glyph_position_t> (pos, len).reverse (start, end);
242   }
reversehb_buffer_t243   void reverse () { reverse_range (0, len); }
244 
245   template <typename FuncType>
reverse_groupshb_buffer_t246   void reverse_groups (const FuncType& group,
247 		       bool merge_clusters = false)
248   {
249     if (unlikely (!len))
250       return;
251 
252     unsigned start = 0;
253     unsigned i;
254     for (i = 1; i < len; i++)
255     {
256       if (!group (info[i - 1], info[i]))
257       {
258 	if (merge_clusters)
259 	  this->merge_clusters (start, i);
260 	reverse_range (start, i);
261 	start = i;
262       }
263     }
264     if (merge_clusters)
265       this->merge_clusters (start, i);
266     reverse_range (start, i);
267 
268     reverse ();
269   }
270 
271   template <typename FuncType>
group_endhb_buffer_t272   unsigned group_end (unsigned start, const FuncType& group) const
273   {
274     while (++start < len && group (info[start - 1], info[start]))
275       ;
276 
277     return start;
278   }
279 
_cluster_group_funchb_buffer_t280   static bool _cluster_group_func (const hb_glyph_info_t& a,
281 				   const hb_glyph_info_t& b)
282   { return a.cluster == b.cluster; }
283 
reverse_clustershb_buffer_t284   void reverse_clusters () { reverse_groups (_cluster_group_func); }
285 
286   HB_INTERNAL void guess_segment_properties ();
287 
288   HB_INTERNAL void sync ();
289   HB_INTERNAL void clear_output ();
290   HB_INTERNAL void clear_positions ();
291 
292   template <typename T>
replace_glyphshb_buffer_t293   HB_NODISCARD bool replace_glyphs (unsigned int num_in,
294 				    unsigned int num_out,
295 				    const T *glyph_data)
296   {
297     if (unlikely (!make_room_for (num_in, num_out))) return false;
298 
299     assert (idx + num_in <= len);
300 
301     merge_clusters (idx, idx + num_in);
302 
303     hb_glyph_info_t &orig_info = idx < len ? cur() : prev();
304 
305     hb_glyph_info_t *pinfo = &out_info[out_len];
306     for (unsigned int i = 0; i < num_out; i++)
307     {
308       *pinfo = orig_info;
309       pinfo->codepoint = glyph_data[i];
310       pinfo++;
311     }
312 
313     idx  += num_in;
314     out_len += num_out;
315     return true;
316   }
317 
replace_glyphhb_buffer_t318   HB_NODISCARD bool replace_glyph (hb_codepoint_t glyph_index)
319   { return replace_glyphs (1, 1, &glyph_index); }
320 
321   /* Makes a copy of the glyph at idx to output and replace glyph_index */
output_glyphhb_buffer_t322   HB_NODISCARD bool output_glyph (hb_codepoint_t glyph_index)
323   { return replace_glyphs (0, 1, &glyph_index); }
324 
output_infohb_buffer_t325   HB_NODISCARD bool output_info (const hb_glyph_info_t &glyph_info)
326   {
327     if (unlikely (!make_room_for (0, 1))) return false;
328 
329     out_info[out_len] = glyph_info;
330 
331     out_len++;
332     return true;
333   }
334   /* Copies glyph at idx to output but doesn't advance idx */
copy_glyphhb_buffer_t335   HB_NODISCARD bool copy_glyph ()
336   {
337     /* Extra copy because cur()'s return can be freed within
338      * output_info() call if buffer reallocates. */
339     return output_info (hb_glyph_info_t (cur()));
340   }
341 
342   /* Copies glyph at idx to output and advance idx.
343    * If there's no output, just advance idx. */
next_glyphhb_buffer_t344   HB_NODISCARD bool next_glyph ()
345   {
346     if (have_output)
347     {
348       if (out_info != info || out_len != idx)
349       {
350 	if (unlikely (!make_room_for (1, 1))) return false;
351 	out_info[out_len] = info[idx];
352       }
353       out_len++;
354     }
355 
356     idx++;
357     return true;
358   }
359   /* Copies n glyphs at idx to output and advance idx.
360    * If there's no output, just advance idx. */
next_glyphshb_buffer_t361   HB_NODISCARD bool next_glyphs (unsigned int n)
362   {
363     if (have_output)
364     {
365       if (out_info != info || out_len != idx)
366       {
367 	if (unlikely (!make_room_for (n, n))) return false;
368 	memmove (out_info + out_len, info + idx, n * sizeof (out_info[0]));
369       }
370       out_len += n;
371     }
372 
373     idx += n;
374     return true;
375   }
376   /* Advance idx without copying to output. */
skip_glyphhb_buffer_t377   void skip_glyph () { idx++; }
reset_maskshb_buffer_t378   void reset_masks (hb_mask_t mask)
379   {
380     for (unsigned int j = 0; j < len; j++)
381       info[j].mask = mask;
382   }
add_maskshb_buffer_t383   void add_masks (hb_mask_t mask)
384   {
385     for (unsigned int j = 0; j < len; j++)
386       info[j].mask |= mask;
387   }
388   HB_INTERNAL void set_masks (hb_mask_t value, hb_mask_t mask,
389 			      unsigned int cluster_start, unsigned int cluster_end);
390 
merge_clustershb_buffer_t391   void merge_clusters (unsigned int start, unsigned int end)
392   {
393     if (end - start < 2)
394       return;
395     merge_clusters_impl (start, end);
396   }
397   HB_INTERNAL void merge_clusters_impl (unsigned int start, unsigned int end);
398   HB_INTERNAL void merge_out_clusters (unsigned int start, unsigned int end);
399   /* Merge clusters for deleting current glyph, and skip it. */
400   HB_INTERNAL void delete_glyph ();
401 
402 
403   /* Adds glyph flags in mask to infos with clusters between start and end.
404    * The start index will be from out-buffer if from_out_buffer is true.
405    * If interior is true, then the cluster having the minimum value is skipped. */
_set_glyph_flagshb_buffer_t406   void _set_glyph_flags (hb_mask_t mask,
407 			 unsigned start = 0,
408 			 unsigned end = (unsigned) -1,
409 			 bool interior = false,
410 			 bool from_out_buffer = false)
411   {
412     end = hb_min (end, len);
413 
414     if (interior && !from_out_buffer && end - start < 2)
415       return;
416 
417     scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
418 
419     if (!from_out_buffer || !have_output)
420     {
421       if (!interior)
422       {
423 	for (unsigned i = start; i < end; i++)
424 	  info[i].mask |= mask;
425       }
426       else
427       {
428 	unsigned cluster = _infos_find_min_cluster (info, start, end);
429 	_infos_set_glyph_flags (info, start, end, cluster, mask);
430       }
431     }
432     else
433     {
434       assert (start <= out_len);
435       assert (idx <= end);
436 
437       if (!interior)
438       {
439 	for (unsigned i = start; i < out_len; i++)
440 	  out_info[i].mask |= mask;
441 	for (unsigned i = idx; i < end; i++)
442 	  info[i].mask |= mask;
443       }
444       else
445       {
446 	unsigned cluster = _infos_find_min_cluster (info, idx, end);
447 	cluster = _infos_find_min_cluster (out_info, start, out_len, cluster);
448 
449 	_infos_set_glyph_flags (out_info, start, out_len, cluster, mask);
450 	_infos_set_glyph_flags (info, idx, end, cluster, mask);
451       }
452     }
453   }
454 
unsafe_to_breakhb_buffer_t455   void unsafe_to_break (unsigned int start = 0, unsigned int end = -1)
456   {
457     _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_BREAK | HB_GLYPH_FLAG_UNSAFE_TO_CONCAT,
458 		      start, end,
459 		      true);
460   }
unsafe_to_concathb_buffer_t461   void unsafe_to_concat (unsigned int start = 0, unsigned int end = -1)
462   {
463     _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_CONCAT,
464 		      start, end,
465 		      true);
466   }
unsafe_to_break_from_outbufferhb_buffer_t467   void unsafe_to_break_from_outbuffer (unsigned int start = 0, unsigned int end = -1)
468   {
469     _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_BREAK | HB_GLYPH_FLAG_UNSAFE_TO_CONCAT,
470 		      start, end,
471 		      true, true);
472   }
unsafe_to_concat_from_outbufferhb_buffer_t473   void unsafe_to_concat_from_outbuffer (unsigned int start = 0, unsigned int end = -1)
474   {
475     _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_CONCAT,
476 		      start, end,
477 		      false, true);
478   }
479 
480 
481   /* Internal methods */
482   HB_NODISCARD HB_INTERNAL bool move_to (unsigned int i); /* i is output-buffer index. */
483 
484   HB_NODISCARD HB_INTERNAL bool enlarge (unsigned int size);
485 
ensurehb_buffer_t486   HB_NODISCARD bool ensure (unsigned int size)
487   { return likely (!size || size < allocated) ? true : enlarge (size); }
488 
ensure_inplacehb_buffer_t489   HB_NODISCARD bool ensure_inplace (unsigned int size)
490   { return likely (!size || size < allocated); }
491 
assert_glyphshb_buffer_t492   void assert_glyphs ()
493   {
494     assert ((content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS) ||
495 	    (!len && (content_type == HB_BUFFER_CONTENT_TYPE_INVALID)));
496   }
assert_unicodehb_buffer_t497   void assert_unicode ()
498   {
499     assert ((content_type == HB_BUFFER_CONTENT_TYPE_UNICODE) ||
500 	    (!len && (content_type == HB_BUFFER_CONTENT_TYPE_INVALID)));
501   }
ensure_glyphshb_buffer_t502   HB_NODISCARD bool ensure_glyphs ()
503   {
504     if (unlikely (content_type != HB_BUFFER_CONTENT_TYPE_GLYPHS))
505     {
506       if (content_type != HB_BUFFER_CONTENT_TYPE_INVALID)
507 	return false;
508       assert (len == 0);
509       content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
510     }
511     return true;
512   }
ensure_unicodehb_buffer_t513   HB_NODISCARD bool ensure_unicode ()
514   {
515     if (unlikely (content_type != HB_BUFFER_CONTENT_TYPE_UNICODE))
516     {
517       if (content_type != HB_BUFFER_CONTENT_TYPE_INVALID)
518 	return false;
519       assert (len == 0);
520       content_type = HB_BUFFER_CONTENT_TYPE_UNICODE;
521     }
522     return true;
523   }
524 
525   HB_NODISCARD HB_INTERNAL bool make_room_for (unsigned int num_in, unsigned int num_out);
526   HB_NODISCARD HB_INTERNAL bool shift_forward (unsigned int count);
527 
528   typedef long scratch_buffer_t;
529   HB_INTERNAL scratch_buffer_t *get_scratch_buffer (unsigned int *size);
530 
clear_contexthb_buffer_t531   void clear_context (unsigned int side) { context_len[side] = 0; }
532 
533   HB_INTERNAL void sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *));
534 
messaginghb_buffer_t535   bool messaging ()
536   {
537 #ifdef HB_NO_BUFFER_MESSAGE
538     return false;
539 #else
540     return unlikely (message_func);
541 #endif
542   }
messagehb_buffer_t543   bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4)
544   {
545 #ifdef HB_NO_BUFFER_MESSAGE
546    return true;
547 #else
548     if (!messaging ())
549       return true;
550 
551     message_depth++;
552 
553     va_list ap;
554     va_start (ap, fmt);
555     bool ret = message_impl (font, fmt, ap);
556     va_end (ap);
557 
558     message_depth--;
559 
560     return ret;
561 #endif
562   }
563   HB_INTERNAL bool message_impl (hb_font_t *font, const char *fmt, va_list ap) HB_PRINTF_FUNC(3, 0);
564 
565   static void
set_clusterhb_buffer_t566   set_cluster (hb_glyph_info_t &inf, unsigned int cluster, unsigned int mask = 0)
567   {
568     if (inf.cluster != cluster)
569       inf.mask = (inf.mask & ~HB_GLYPH_FLAG_DEFINED) | (mask & HB_GLYPH_FLAG_DEFINED);
570     inf.cluster = cluster;
571   }
572   void
_infos_set_glyph_flagshb_buffer_t573   _infos_set_glyph_flags (hb_glyph_info_t *infos,
574 			  unsigned int start, unsigned int end,
575 			  unsigned int cluster,
576 			  hb_mask_t mask)
577   {
578     for (unsigned int i = start; i < end; i++)
579       if (cluster != infos[i].cluster)
580       {
581 	scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
582 	infos[i].mask |= mask;
583       }
584   }
585   static unsigned
_infos_find_min_clusterhb_buffer_t586   _infos_find_min_cluster (const hb_glyph_info_t *infos,
587 			   unsigned start, unsigned end,
588 			   unsigned cluster = UINT_MAX)
589   {
590     for (unsigned int i = start; i < end; i++)
591       cluster = hb_min (cluster, infos[i].cluster);
592     return cluster;
593   }
594 
clear_glyph_flagshb_buffer_t595   void clear_glyph_flags (hb_mask_t mask = 0)
596   {
597     for (unsigned int i = 0; i < len; i++)
598       info[i].mask = (info[i].mask & ~HB_GLYPH_FLAG_DEFINED) | (mask & HB_GLYPH_FLAG_DEFINED);
599   }
600 };
601 DECLARE_NULL_INSTANCE (hb_buffer_t);
602 
603 
604 #define foreach_group(buffer, start, end, group_func) \
605   for (unsigned int \
606        _count = buffer->len, \
607        start = 0, end = _count ? buffer->group_end (0, group_func) : 0; \
608        start < _count; \
609        start = end, end = buffer->group_end (start, group_func))
610 
611 #define foreach_cluster(buffer, start, end) \
612 	foreach_group (buffer, start, end, hb_buffer_t::_cluster_group_func)
613 
614 
615 #define HB_BUFFER_XALLOCATE_VAR(b, func, var) \
616   b->func (offsetof (hb_glyph_info_t, var) - offsetof(hb_glyph_info_t, var1), \
617 	   sizeof (b->info[0].var))
618 #define HB_BUFFER_ALLOCATE_VAR(b, var)		HB_BUFFER_XALLOCATE_VAR (b, allocate_var,   var ())
619 #define HB_BUFFER_DEALLOCATE_VAR(b, var)	HB_BUFFER_XALLOCATE_VAR (b, deallocate_var, var ())
620 #define HB_BUFFER_ASSERT_VAR(b, var)		HB_BUFFER_XALLOCATE_VAR (b, assert_var,     var ())
621 
622 
623 #endif /* HB_BUFFER_HH */
624