• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "hb-set-digest.hh"
36 
37 
38 static_assert ((sizeof (hb_glyph_info_t) == 20), "");
39 static_assert ((sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t)), "");
40 
41 HB_MARK_AS_FLAG_T (hb_glyph_flags_t);
42 HB_MARK_AS_FLAG_T (hb_buffer_flags_t);
43 HB_MARK_AS_FLAG_T (hb_buffer_serialize_flags_t);
44 HB_MARK_AS_FLAG_T (hb_buffer_diff_flags_t);
45 
46 enum hb_buffer_scratch_flags_t {
47   HB_BUFFER_SCRATCH_FLAG_DEFAULT			= 0x00000000u,
48   HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII			= 0x00000001u,
49   HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES		= 0x00000002u,
50   HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK		= 0x00000004u,
51   HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT		= 0x00000008u,
52   HB_BUFFER_SCRATCH_FLAG_HAS_CGJ			= 0x00000010u,
53   HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS		= 0x00000020u,
54   HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE		= 0x00000040u,
55 
56   /* Reserved for shapers' internal use. */
57   HB_BUFFER_SCRATCH_FLAG_SHAPER0			= 0x01000000u,
58   HB_BUFFER_SCRATCH_FLAG_SHAPER1			= 0x02000000u,
59   HB_BUFFER_SCRATCH_FLAG_SHAPER2			= 0x04000000u,
60   HB_BUFFER_SCRATCH_FLAG_SHAPER3			= 0x08000000u,
61 };
62 HB_MARK_AS_FLAG_T (hb_buffer_scratch_flags_t);
63 
64 
65 /*
66  * hb_buffer_t
67  */
68 
69 struct hb_buffer_t
70 {
71   hb_object_header_t header;
72 
73   /*
74    * Information about how the text in the buffer should be treated.
75    */
76 
77   hb_unicode_funcs_t *unicode; /* Unicode functions */
78   hb_buffer_flags_t flags; /* BOT / EOT / etc. */
79   hb_buffer_cluster_level_t cluster_level;
80   hb_codepoint_t replacement; /* U+FFFD or something else. */
81   hb_codepoint_t invisible; /* 0 or something else. */
82   hb_codepoint_t not_found; /* 0 or something else. */
83 
84   /*
85    * Buffer contents
86    */
87 
88   hb_buffer_content_type_t content_type;
89   hb_segment_properties_t props; /* Script, language, direction */
90 
91   bool successful; /* Allocations successful */
92   bool shaping_failed; /* Shaping failure */
93   bool have_output; /* Whether we have an output buffer going on */
94   bool have_positions; /* Whether we have positions */
95 
96   unsigned int idx; /* Cursor into ->info and ->pos arrays */
97   unsigned int len; /* Length of ->info and ->pos arrays */
98   unsigned int out_len; /* Length of ->out_info array if have_output */
99 
100   unsigned int allocated; /* Length of allocated arrays */
101   hb_glyph_info_t     *info;
102   hb_glyph_info_t     *out_info;
103   hb_glyph_position_t *pos;
104 
105   /* Text before / after the main buffer contents.
106    * Always in Unicode, and ordered outward.
107    * Index 0 is for "pre-context", 1 for "post-context". */
108   static constexpr unsigned CONTEXT_LENGTH = 5u;
109   hb_codepoint_t context[2][CONTEXT_LENGTH];
110   unsigned int context_len[2];
111 
112 
113   /*
114    * Managed by enter / leave
115    */
116 
117   uint8_t allocated_var_bits;
118   uint8_t serial;
119   uint32_t random_state;
120   hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */
121   unsigned int max_len; /* Maximum allowed len. */
122   int max_ops; /* Maximum allowed operations. */
123   /* The bits here reflect current allocations of the bytes in glyph_info_t's var1 and var2. */
124 
125 
126   /*
127    * Messaging callback
128    */
129 
130 #ifndef HB_NO_BUFFER_MESSAGE
131   hb_buffer_message_func_t message_func;
132   void *message_data;
133   hb_destroy_func_t message_destroy;
134   unsigned message_depth; /* How deeply are we inside a message callback? */
135 #else
136   static constexpr unsigned message_depth = 0u;
137 #endif
138 
139 
140 
141   /* Methods */
142 
in_errorhb_buffer_t143   HB_NODISCARD bool in_error () const { return !successful; }
144 
allocate_varhb_buffer_t145   void allocate_var (unsigned int start, unsigned int count)
146   {
147     unsigned int end = start + count;
148     assert (end <= 8);
149     unsigned int bits = (1u<<end) - (1u<<start);
150     assert (0 == (allocated_var_bits & bits));
151     allocated_var_bits |= bits;
152   }
try_allocate_varhb_buffer_t153   bool try_allocate_var (unsigned int start, unsigned int count)
154   {
155     unsigned int end = start + count;
156     assert (end <= 8);
157     unsigned int bits = (1u<<end) - (1u<<start);
158     if (allocated_var_bits & bits)
159       return false;
160     allocated_var_bits |= bits;
161     return true;
162   }
deallocate_varhb_buffer_t163   void deallocate_var (unsigned int start, unsigned int count)
164   {
165     unsigned int end = start + count;
166     assert (end <= 8);
167     unsigned int bits = (1u<<end) - (1u<<start);
168     assert (bits == (allocated_var_bits & bits));
169     allocated_var_bits &= ~bits;
170   }
assert_varhb_buffer_t171   void assert_var (unsigned int start, unsigned int count)
172   {
173     unsigned int end = start + count;
174     assert (end <= 8);
175     HB_UNUSED unsigned int bits = (1u<<end) - (1u<<start);
176     assert (bits == (allocated_var_bits & bits));
177   }
deallocate_var_allhb_buffer_t178   void deallocate_var_all ()
179   {
180     allocated_var_bits = 0;
181   }
182 
curhb_buffer_t183   hb_glyph_info_t &cur (unsigned int i = 0) { return info[idx + i]; }
curhb_buffer_t184   hb_glyph_info_t cur (unsigned int i = 0) const { return info[idx + i]; }
185 
cur_poshb_buffer_t186   hb_glyph_position_t &cur_pos (unsigned int i = 0) { return pos[idx + i]; }
cur_poshb_buffer_t187   hb_glyph_position_t cur_pos (unsigned int i = 0) const { return pos[idx + i]; }
188 
prevhb_buffer_t189   hb_glyph_info_t &prev ()      { return out_info[out_len ? out_len - 1 : 0]; }
prevhb_buffer_t190   hb_glyph_info_t prev () const { return out_info[out_len ? out_len - 1 : 0]; }
191 
digesthb_buffer_t192   hb_set_digest_t digest () const
193   {
194     hb_set_digest_t d;
195     d.init ();
196     d.add_array (&info[0].codepoint, len, sizeof (info[0]));
197     return d;
198   }
199 
200   HB_INTERNAL void similar (const hb_buffer_t &src);
201   HB_INTERNAL void reset ();
202   HB_INTERNAL void clear ();
203 
204   /* Called around shape() */
205   HB_INTERNAL void enter ();
206   HB_INTERNAL void leave ();
207 
208 #ifndef HB_NO_BUFFER_VERIFY
209   HB_INTERNAL
210 #endif
211   bool verify (hb_buffer_t        *text_buffer,
212 	       hb_font_t          *font,
213 	       const hb_feature_t *features,
214 	       unsigned int        num_features,
215 	       const char * const *shapers)
216 #ifndef HB_NO_BUFFER_VERIFY
217   ;
218 #else
219   { return true; }
220 #endif
221 
backtrack_lenhb_buffer_t222   unsigned int backtrack_len () const { return have_output ? out_len : idx; }
lookahead_lenhb_buffer_t223   unsigned int lookahead_len () const { return len - idx; }
next_serialhb_buffer_t224   uint8_t next_serial () { return ++serial ? serial : ++serial; }
225 
226   HB_INTERNAL void add (hb_codepoint_t  codepoint,
227 			unsigned int    cluster);
228   HB_INTERNAL void add_info (const hb_glyph_info_t &glyph_info);
229 
reverse_rangehb_buffer_t230   void reverse_range (unsigned start, unsigned end)
231   {
232     hb_array_t<hb_glyph_info_t> (info, len).reverse (start, end);
233     if (have_positions)
234       hb_array_t<hb_glyph_position_t> (pos, len).reverse (start, end);
235   }
reversehb_buffer_t236   void reverse () { reverse_range (0, len); }
237 
238   template <typename FuncType>
reverse_groupshb_buffer_t239   void reverse_groups (const FuncType& group,
240 		       bool merge_clusters = false)
241   {
242     if (unlikely (!len))
243       return;
244 
245     unsigned start = 0;
246     unsigned i;
247     for (i = 1; i < len; i++)
248     {
249       if (!group (info[i - 1], info[i]))
250       {
251 	if (merge_clusters)
252 	  this->merge_clusters (start, i);
253 	reverse_range (start, i);
254 	start = i;
255       }
256     }
257     if (merge_clusters)
258       this->merge_clusters (start, i);
259     reverse_range (start, i);
260 
261     reverse ();
262   }
263 
264   template <typename FuncType>
group_endhb_buffer_t265   unsigned group_end (unsigned start, const FuncType& group) const
266   {
267     while (++start < len && group (info[start - 1], info[start]))
268       ;
269 
270     return start;
271   }
272 
_cluster_group_funchb_buffer_t273   static bool _cluster_group_func (const hb_glyph_info_t& a,
274 				   const hb_glyph_info_t& b)
275   { return a.cluster == b.cluster; }
276 
reverse_clustershb_buffer_t277   void reverse_clusters () { reverse_groups (_cluster_group_func); }
278 
279   HB_INTERNAL void guess_segment_properties ();
280 
281   HB_INTERNAL bool sync ();
282   HB_INTERNAL int sync_so_far ();
283   HB_INTERNAL void clear_output ();
284   HB_INTERNAL void clear_positions ();
285 
286   template <typename T>
replace_glyphshb_buffer_t287   HB_NODISCARD bool replace_glyphs (unsigned int num_in,
288 				    unsigned int num_out,
289 				    const T *glyph_data)
290   {
291     if (unlikely (!make_room_for (num_in, num_out))) return false;
292 
293     assert (idx + num_in <= len);
294 
295     merge_clusters (idx, idx + num_in);
296 
297     hb_glyph_info_t &orig_info = idx < len ? cur() : prev();
298 
299     hb_glyph_info_t *pinfo = &out_info[out_len];
300     for (unsigned int i = 0; i < num_out; i++)
301     {
302       *pinfo = orig_info;
303       pinfo->codepoint = glyph_data[i];
304       pinfo++;
305     }
306 
307     idx  += num_in;
308     out_len += num_out;
309     return true;
310   }
311 
replace_glyphhb_buffer_t312   HB_NODISCARD bool replace_glyph (hb_codepoint_t glyph_index)
313   { return replace_glyphs (1, 1, &glyph_index); }
314 
315   /* Makes a copy of the glyph at idx to output and replace glyph_index */
output_glyphhb_buffer_t316   HB_NODISCARD bool output_glyph (hb_codepoint_t glyph_index)
317   { return replace_glyphs (0, 1, &glyph_index); }
318 
output_infohb_buffer_t319   HB_NODISCARD bool output_info (const hb_glyph_info_t &glyph_info)
320   {
321     if (unlikely (!make_room_for (0, 1))) return false;
322 
323     out_info[out_len] = glyph_info;
324 
325     out_len++;
326     return true;
327   }
328   /* Copies glyph at idx to output but doesn't advance idx */
copy_glyphhb_buffer_t329   HB_NODISCARD bool copy_glyph ()
330   {
331     /* Extra copy because cur()'s return can be freed within
332      * output_info() call if buffer reallocates. */
333     return output_info (hb_glyph_info_t (cur()));
334   }
335 
336   /* Copies glyph at idx to output and advance idx.
337    * If there's no output, just advance idx. */
next_glyphhb_buffer_t338   HB_NODISCARD bool next_glyph ()
339   {
340     if (have_output)
341     {
342       if (out_info != info || out_len != idx)
343       {
344 	if (unlikely (!make_room_for (1, 1))) return false;
345 	out_info[out_len] = info[idx];
346       }
347       out_len++;
348     }
349 
350     idx++;
351     return true;
352   }
353   /* Copies n glyphs at idx to output and advance idx.
354    * If there's no output, just advance idx. */
next_glyphshb_buffer_t355   HB_NODISCARD bool next_glyphs (unsigned int n)
356   {
357     if (have_output)
358     {
359       if (out_info != info || out_len != idx)
360       {
361 	if (unlikely (!make_room_for (n, n))) return false;
362 	memmove (out_info + out_len, info + idx, n * sizeof (out_info[0]));
363       }
364       out_len += n;
365     }
366 
367     idx += n;
368     return true;
369   }
370   /* Advance idx without copying to output. */
skip_glyphhb_buffer_t371   void skip_glyph () { idx++; }
reset_maskshb_buffer_t372   void reset_masks (hb_mask_t mask)
373   {
374     for (unsigned int j = 0; j < len; j++)
375       info[j].mask = mask;
376   }
add_maskshb_buffer_t377   void add_masks (hb_mask_t mask)
378   {
379     for (unsigned int j = 0; j < len; j++)
380       info[j].mask |= mask;
381   }
382   HB_INTERNAL void set_masks (hb_mask_t value, hb_mask_t mask,
383 			      unsigned int cluster_start, unsigned int cluster_end);
384 
merge_clustershb_buffer_t385   void merge_clusters (unsigned int start, unsigned int end)
386   {
387     if (end - start < 2)
388       return;
389     merge_clusters_impl (start, end);
390   }
391   HB_INTERNAL void merge_clusters_impl (unsigned int start, unsigned int end);
392   HB_INTERNAL void merge_out_clusters (unsigned int start, unsigned int end);
393   /* Merge clusters for deleting current glyph, and skip it. */
394   HB_INTERNAL void delete_glyph ();
395   HB_INTERNAL void delete_glyphs_inplace (bool (*filter) (const hb_glyph_info_t *info));
396 
397 
398 
399   /* Adds glyph flags in mask to infos with clusters between start and end.
400    * The start index will be from out-buffer if from_out_buffer is true.
401    * If interior is true, then the cluster having the minimum value is skipped. */
_set_glyph_flagshb_buffer_t402   void _set_glyph_flags (hb_mask_t mask,
403 			 unsigned start = 0,
404 			 unsigned end = (unsigned) -1,
405 			 bool interior = false,
406 			 bool from_out_buffer = false)
407   {
408     end = hb_min (end, len);
409 
410     if (interior && !from_out_buffer && end - start < 2)
411       return;
412 
413     scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
414 
415     if (!from_out_buffer || !have_output)
416     {
417       if (!interior)
418       {
419 	for (unsigned i = start; i < end; i++)
420 	  info[i].mask |= mask;
421       }
422       else
423       {
424 	unsigned cluster = _infos_find_min_cluster (info, start, end);
425 	_infos_set_glyph_flags (info, start, end, cluster, mask);
426       }
427     }
428     else
429     {
430       assert (start <= out_len);
431       assert (idx <= end);
432 
433       if (!interior)
434       {
435 	for (unsigned i = start; i < out_len; i++)
436 	  out_info[i].mask |= mask;
437 	for (unsigned i = idx; i < end; i++)
438 	  info[i].mask |= mask;
439       }
440       else
441       {
442 	unsigned cluster = _infos_find_min_cluster (info, idx, end);
443 	cluster = _infos_find_min_cluster (out_info, start, out_len, cluster);
444 
445 	_infos_set_glyph_flags (out_info, start, out_len, cluster, mask);
446 	_infos_set_glyph_flags (info, idx, end, cluster, mask);
447       }
448     }
449   }
450 
unsafe_to_breakhb_buffer_t451   void unsafe_to_break (unsigned int start = 0, unsigned int end = -1)
452   {
453     _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_BREAK | HB_GLYPH_FLAG_UNSAFE_TO_CONCAT,
454 		      start, end,
455 		      true);
456   }
safe_to_insert_tatweelhb_buffer_t457   void safe_to_insert_tatweel (unsigned int start = 0, unsigned int end = -1)
458   {
459     if ((flags & HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL) == 0)
460     {
461       unsafe_to_break (start, end);
462       return;
463     }
464     _set_glyph_flags (HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL,
465 		      start, end,
466 		      true);
467   }
468 #ifndef HB_OPTIMIZE_SIZE
469   HB_ALWAYS_INLINE
470 #endif
unsafe_to_concathb_buffer_t471   void unsafe_to_concat (unsigned int start = 0, unsigned int end = -1)
472   {
473     if (likely ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0))
474       return;
475     _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_CONCAT,
476 		      start, end,
477 		      false);
478   }
unsafe_to_break_from_outbufferhb_buffer_t479   void unsafe_to_break_from_outbuffer (unsigned int start = 0, unsigned int end = -1)
480   {
481     _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_BREAK | HB_GLYPH_FLAG_UNSAFE_TO_CONCAT,
482 		      start, end,
483 		      true, true);
484   }
485 #ifndef HB_OPTIMIZE_SIZE
486   HB_ALWAYS_INLINE
487 #endif
unsafe_to_concat_from_outbufferhb_buffer_t488   void unsafe_to_concat_from_outbuffer (unsigned int start = 0, unsigned int end = -1)
489   {
490     if (likely ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0))
491       return;
492     _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_CONCAT,
493 		      start, end,
494 		      false, true);
495   }
496 
497 
498   /* Internal methods */
499   HB_NODISCARD HB_INTERNAL bool move_to (unsigned int i); /* i is output-buffer index. */
500 
501   HB_NODISCARD HB_INTERNAL bool enlarge (unsigned int size);
502 
resizehb_buffer_t503   HB_NODISCARD bool resize (unsigned length)
504   {
505     assert (!have_output);
506     if (unlikely (!ensure (length))) return false;
507     len = length;
508     return true;
509   }
ensurehb_buffer_t510   HB_NODISCARD bool ensure (unsigned int size)
511   { return likely (!size || size < allocated) ? true : enlarge (size); }
512 
ensure_inplacehb_buffer_t513   HB_NODISCARD bool ensure_inplace (unsigned int size)
514   { return likely (!size || size < allocated); }
515 
assert_glyphshb_buffer_t516   void assert_glyphs ()
517   {
518     assert ((content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS) ||
519 	    (!len && (content_type == HB_BUFFER_CONTENT_TYPE_INVALID)));
520   }
assert_unicodehb_buffer_t521   void assert_unicode ()
522   {
523     assert ((content_type == HB_BUFFER_CONTENT_TYPE_UNICODE) ||
524 	    (!len && (content_type == HB_BUFFER_CONTENT_TYPE_INVALID)));
525   }
ensure_glyphshb_buffer_t526   HB_NODISCARD bool ensure_glyphs ()
527   {
528     if (unlikely (content_type != HB_BUFFER_CONTENT_TYPE_GLYPHS))
529     {
530       if (content_type != HB_BUFFER_CONTENT_TYPE_INVALID)
531 	return false;
532       assert (len == 0);
533       content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
534     }
535     return true;
536   }
ensure_unicodehb_buffer_t537   HB_NODISCARD bool ensure_unicode ()
538   {
539     if (unlikely (content_type != HB_BUFFER_CONTENT_TYPE_UNICODE))
540     {
541       if (content_type != HB_BUFFER_CONTENT_TYPE_INVALID)
542 	return false;
543       assert (len == 0);
544       content_type = HB_BUFFER_CONTENT_TYPE_UNICODE;
545     }
546     return true;
547   }
548 
549   HB_NODISCARD HB_INTERNAL bool make_room_for (unsigned int num_in, unsigned int num_out);
550   HB_NODISCARD HB_INTERNAL bool shift_forward (unsigned int count);
551 
552   typedef long scratch_buffer_t;
553   HB_INTERNAL scratch_buffer_t *get_scratch_buffer (unsigned int *size);
554 
clear_contexthb_buffer_t555   void clear_context (unsigned int side) { context_len[side] = 0; }
556 
557   HB_INTERNAL void sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *));
558 
messaginghb_buffer_t559   bool messaging ()
560   {
561 #ifdef HB_NO_BUFFER_MESSAGE
562     return false;
563 #else
564     return unlikely (message_func);
565 #endif
566   }
messagehb_buffer_t567   bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4)
568   {
569 #ifdef HB_NO_BUFFER_MESSAGE
570     return true;
571 #else
572     if (likely (!messaging ()))
573       return true;
574 
575     va_list ap;
576     va_start (ap, fmt);
577     bool ret = message_impl (font, fmt, ap);
578     va_end (ap);
579 
580     return ret;
581 #endif
582   }
583   HB_INTERNAL bool message_impl (hb_font_t *font, const char *fmt, va_list ap) HB_PRINTF_FUNC(3, 0);
584 
585   static void
set_clusterhb_buffer_t586   set_cluster (hb_glyph_info_t &inf, unsigned int cluster, unsigned int mask = 0)
587   {
588     if (inf.cluster != cluster)
589       inf.mask = (inf.mask & ~HB_GLYPH_FLAG_DEFINED) | (mask & HB_GLYPH_FLAG_DEFINED);
590     inf.cluster = cluster;
591   }
592   void
_infos_set_glyph_flagshb_buffer_t593   _infos_set_glyph_flags (hb_glyph_info_t *infos,
594 			  unsigned int start, unsigned int end,
595 			  unsigned int cluster,
596 			  hb_mask_t mask)
597   {
598     if (unlikely (start == end))
599       return;
600 
601     unsigned cluster_first = infos[start].cluster;
602     unsigned cluster_last = infos[end - 1].cluster;
603 
604     if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS ||
605 	(cluster != cluster_first && cluster != cluster_last))
606     {
607       for (unsigned int i = start; i < end; i++)
608 	if (cluster != infos[i].cluster)
609 	{
610 	  scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
611 	  infos[i].mask |= mask;
612 	}
613       return;
614     }
615 
616     /* Monotone clusters */
617 
618     if (cluster == cluster_first)
619     {
620       for (unsigned int i = end; start < i && infos[i - 1].cluster != cluster_first; i--)
621       {
622 	scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
623 	infos[i - 1].mask |= mask;
624       }
625     }
626     else /* cluster == cluster_last */
627     {
628       for (unsigned int i = start; i < end && infos[i].cluster != cluster_last; i++)
629       {
630 	scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
631 	infos[i].mask |= mask;
632       }
633     }
634   }
635   unsigned
_infos_find_min_clusterhb_buffer_t636   _infos_find_min_cluster (const hb_glyph_info_t *infos,
637 			   unsigned start, unsigned end,
638 			   unsigned cluster = UINT_MAX)
639   {
640     if (unlikely (start == end))
641       return cluster;
642 
643     if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
644     {
645       for (unsigned int i = start; i < end; i++)
646 	cluster = hb_min (cluster, infos[i].cluster);
647       return cluster;
648     }
649 
650     return hb_min (cluster, hb_min (infos[start].cluster, infos[end - 1].cluster));
651   }
652 
clear_glyph_flagshb_buffer_t653   void clear_glyph_flags (hb_mask_t mask = 0)
654   {
655     for (unsigned int i = 0; i < len; i++)
656       info[i].mask = (info[i].mask & ~HB_GLYPH_FLAG_DEFINED) | (mask & HB_GLYPH_FLAG_DEFINED);
657   }
658 };
659 DECLARE_NULL_INSTANCE (hb_buffer_t);
660 
661 
662 #define foreach_group(buffer, start, end, group_func) \
663   for (unsigned int \
664        _count = buffer->len, \
665        start = 0, end = _count ? buffer->group_end (0, group_func) : 0; \
666        start < _count; \
667        start = end, end = buffer->group_end (start, group_func))
668 
669 #define foreach_cluster(buffer, start, end) \
670 	foreach_group (buffer, start, end, hb_buffer_t::_cluster_group_func)
671 
672 
673 #define HB_BUFFER_XALLOCATE_VAR(b, func, var) \
674   b->func (offsetof (hb_glyph_info_t, var) - offsetof(hb_glyph_info_t, var1), \
675 	   sizeof (b->info[0].var))
676 #define HB_BUFFER_ALLOCATE_VAR(b, var)		HB_BUFFER_XALLOCATE_VAR (b, allocate_var,     var ())
677 #define HB_BUFFER_TRY_ALLOCATE_VAR(b, var)	HB_BUFFER_XALLOCATE_VAR (b, try_allocate_var, var ())
678 #define HB_BUFFER_DEALLOCATE_VAR(b, var)	HB_BUFFER_XALLOCATE_VAR (b, deallocate_var,   var ())
679 #define HB_BUFFER_ASSERT_VAR(b, var)		HB_BUFFER_XALLOCATE_VAR (b, assert_var,       var ())
680 
681 
682 #endif /* HB_BUFFER_HH */
683