xref: /aosp_15_r20/external/harfbuzz_ng/src/hb-aat-layout-common.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1 /*
2  * Copyright © 2017  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 #ifndef HB_AAT_LAYOUT_COMMON_HH
28 #define HB_AAT_LAYOUT_COMMON_HH
29 
30 #include "hb-aat-layout.hh"
31 #include "hb-aat-map.hh"
32 #include "hb-open-type.hh"
33 
34 namespace OT {
35 struct GDEF;
36 };
37 
38 namespace AAT {
39 
40 using namespace OT;
41 
42 #define HB_AAT_BUFFER_DIGEST_THRESHOLD 32
43 
44 struct ankr;
45 
46 struct hb_aat_apply_context_t :
47        hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
48 {
get_nameAAT::hb_aat_apply_context_t49   const char *get_name () { return "APPLY"; }
50   template <typename T, typename ...Ts>
dispatchAAT::hb_aat_apply_context_t51   return_t dispatch (const T &obj, Ts&&... ds)
52   { return obj.apply (this, std::forward<Ts> (ds)...); }
default_return_valueAAT::hb_aat_apply_context_t53   static return_t default_return_value () { return false; }
stop_sublookup_iterationAAT::hb_aat_apply_context_t54   bool stop_sublookup_iteration (return_t r) const { return r; }
55 
56   const hb_ot_shape_plan_t *plan;
57   hb_font_t *font;
58   hb_face_t *face;
59   hb_buffer_t *buffer;
60   hb_sanitize_context_t sanitizer;
61   const ankr *ankr_table;
62   const OT::GDEF *gdef_table;
63   const hb_sorted_vector_t<hb_aat_map_t::range_flags_t> *range_flags = nullptr;
64   hb_set_digest_t buffer_digest = hb_set_digest_t::full ();
65   hb_set_digest_t machine_glyph_set = hb_set_digest_t::full ();
66   hb_set_digest_t left_set = hb_set_digest_t::full ();
67   hb_set_digest_t right_set = hb_set_digest_t::full ();
68   hb_mask_t subtable_flags = 0;
69 
70   /* Unused. For debug tracing only. */
71   unsigned int lookup_index;
72 
73   HB_INTERNAL hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_,
74 				      hb_font_t *font_,
75 				      hb_buffer_t *buffer_,
76 				      hb_blob_t *blob = const_cast<hb_blob_t *> (&Null (hb_blob_t)));
77 
78   HB_INTERNAL ~hb_aat_apply_context_t ();
79 
80   HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_);
81 
set_lookup_indexAAT::hb_aat_apply_context_t82   void set_lookup_index (unsigned int i) { lookup_index = i; }
83 };
84 
85 
86 /*
87  * Lookup Table
88  */
89 
90 enum { DELETED_GLYPH = 0xFFFF };
91 
92 template <typename T> struct Lookup;
93 
94 template <typename T>
95 struct LookupFormat0
96 {
97   friend struct Lookup<T>;
98 
99   private:
get_valueAAT::LookupFormat0100   const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
101   {
102     if (unlikely (glyph_id >= num_glyphs)) return nullptr;
103     return &arrayZ[glyph_id];
104   }
105 
106   template <typename set_t>
collect_glyphsAAT::LookupFormat0107   void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const
108   {
109     glyphs.add_range (0, num_glyphs - 1);
110   }
111 
sanitizeAAT::LookupFormat0112   bool sanitize (hb_sanitize_context_t *c) const
113   {
114     TRACE_SANITIZE (this);
115     return_trace (arrayZ.sanitize (c, c->get_num_glyphs ()));
116   }
sanitizeAAT::LookupFormat0117   bool sanitize (hb_sanitize_context_t *c, const void *base) const
118   {
119     TRACE_SANITIZE (this);
120     return_trace (arrayZ.sanitize (c, c->get_num_glyphs (), base));
121   }
122 
123   protected:
124   HBUINT16	format;		/* Format identifier--format = 0 */
125   UnsizedArrayOf<T>
126 		arrayZ;		/* Array of lookup values, indexed by glyph index. */
127   public:
128   DEFINE_SIZE_UNBOUNDED (2);
129 };
130 
131 
132 template <typename T>
133 struct LookupSegmentSingle
134 {
135   static constexpr unsigned TerminationWordCount = 2u;
136 
cmpAAT::LookupSegmentSingle137   int cmp (hb_codepoint_t g) const
138   { return g < first ? -1 : g <= last ? 0 : +1 ; }
139 
140   template <typename set_t>
collect_glyphsAAT::LookupSegmentSingle141   void collect_glyphs (set_t &glyphs) const
142   {
143     if (first == DELETED_GLYPH)
144       return;
145     glyphs.add_range (first, last);
146   }
147 
sanitizeAAT::LookupSegmentSingle148   bool sanitize (hb_sanitize_context_t *c) const
149   {
150     TRACE_SANITIZE (this);
151     return_trace (c->check_struct (this) && value.sanitize (c));
152   }
sanitizeAAT::LookupSegmentSingle153   bool sanitize (hb_sanitize_context_t *c, const void *base) const
154   {
155     TRACE_SANITIZE (this);
156     return_trace (c->check_struct (this) && value.sanitize (c, base));
157   }
158 
159   HBGlyphID16	last;		/* Last GlyphID in this segment */
160   HBGlyphID16	first;		/* First GlyphID in this segment */
161   T		value;		/* The lookup value (only one) */
162   public:
163   DEFINE_SIZE_STATIC (4 + T::static_size);
164 };
165 
166 template <typename T>
167 struct LookupFormat2
168 {
169   friend struct Lookup<T>;
170 
171   private:
get_valueAAT::LookupFormat2172   const T* get_value (hb_codepoint_t glyph_id) const
173   {
174     const LookupSegmentSingle<T> *v = segments.bsearch (glyph_id);
175     return v ? &v->value : nullptr;
176   }
177 
178   template <typename set_t>
collect_glyphsAAT::LookupFormat2179   void collect_glyphs (set_t &glyphs) const
180   {
181     unsigned count = segments.get_length ();
182     for (unsigned int i = 0; i < count; i++)
183       segments[i].collect_glyphs (glyphs);
184   }
185 
sanitizeAAT::LookupFormat2186   bool sanitize (hb_sanitize_context_t *c) const
187   {
188     TRACE_SANITIZE (this);
189     return_trace (segments.sanitize (c));
190   }
sanitizeAAT::LookupFormat2191   bool sanitize (hb_sanitize_context_t *c, const void *base) const
192   {
193     TRACE_SANITIZE (this);
194     return_trace (segments.sanitize (c, base));
195   }
196 
197   protected:
198   HBUINT16	format;		/* Format identifier--format = 2 */
199   VarSizedBinSearchArrayOf<LookupSegmentSingle<T>>
200 		segments;	/* The actual segments. These must already be sorted,
201 				 * according to the first word in each one (the last
202 				 * glyph in each segment). */
203   public:
204   DEFINE_SIZE_ARRAY (8, segments);
205 };
206 
207 template <typename T>
208 struct LookupSegmentArray
209 {
210   static constexpr unsigned TerminationWordCount = 2u;
211 
get_valueAAT::LookupSegmentArray212   const T* get_value (hb_codepoint_t glyph_id, const void *base) const
213   {
214     return first <= glyph_id && glyph_id <= last ? &(base+valuesZ)[glyph_id - first] : nullptr;
215   }
216 
217   template <typename set_t>
collect_glyphsAAT::LookupSegmentArray218   void collect_glyphs (set_t &glyphs) const
219   {
220     if (first == DELETED_GLYPH)
221       return;
222     glyphs.add_range (first, last);
223   }
224 
cmpAAT::LookupSegmentArray225   int cmp (hb_codepoint_t g) const
226   { return g < first ? -1 : g <= last ? 0 : +1; }
227 
sanitizeAAT::LookupSegmentArray228   bool sanitize (hb_sanitize_context_t *c, const void *base) const
229   {
230     TRACE_SANITIZE (this);
231     return_trace (c->check_struct (this) &&
232 		  hb_barrier () &&
233 		  first <= last &&
234 		  valuesZ.sanitize (c, base, last - first + 1));
235   }
236   template <typename ...Ts>
sanitizeAAT::LookupSegmentArray237   bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const
238   {
239     TRACE_SANITIZE (this);
240     return_trace (c->check_struct (this) &&
241 		  hb_barrier () &&
242 		  first <= last &&
243 		  valuesZ.sanitize (c, base, last - first + 1, std::forward<Ts> (ds)...));
244   }
245 
246   HBGlyphID16	last;		/* Last GlyphID in this segment */
247   HBGlyphID16	first;		/* First GlyphID in this segment */
248   NNOffset16To<UnsizedArrayOf<T>>
249 		valuesZ;	/* A 16-bit offset from the start of
250 				 * the table to the data. */
251   public:
252   DEFINE_SIZE_STATIC (6);
253 };
254 
255 template <typename T>
256 struct LookupFormat4
257 {
258   friend struct Lookup<T>;
259 
260   private:
get_valueAAT::LookupFormat4261   const T* get_value (hb_codepoint_t glyph_id) const
262   {
263     const LookupSegmentArray<T> *v = segments.bsearch (glyph_id);
264     return v ? v->get_value (glyph_id, this) : nullptr;
265   }
266 
267   template <typename set_t>
collect_glyphsAAT::LookupFormat4268   void collect_glyphs (set_t &glyphs) const
269   {
270     unsigned count = segments.get_length ();
271     for (unsigned i = 0; i < count; i++)
272       segments[i].collect_glyphs (glyphs);
273   }
274 
sanitizeAAT::LookupFormat4275   bool sanitize (hb_sanitize_context_t *c) const
276   {
277     TRACE_SANITIZE (this);
278     return_trace (segments.sanitize (c, this));
279   }
sanitizeAAT::LookupFormat4280   bool sanitize (hb_sanitize_context_t *c, const void *base) const
281   {
282     TRACE_SANITIZE (this);
283     return_trace (segments.sanitize (c, this, base));
284   }
285 
286   protected:
287   HBUINT16	format;		/* Format identifier--format = 4 */
288   VarSizedBinSearchArrayOf<LookupSegmentArray<T>>
289 		segments;	/* The actual segments. These must already be sorted,
290 				 * according to the first word in each one (the last
291 				 * glyph in each segment). */
292   public:
293   DEFINE_SIZE_ARRAY (8, segments);
294 };
295 
296 template <typename T>
297 struct LookupSingle
298 {
299   static constexpr unsigned TerminationWordCount = 1u;
300 
cmpAAT::LookupSingle301   int cmp (hb_codepoint_t g) const { return glyph.cmp (g); }
302 
303   template <typename set_t>
collect_glyphsAAT::LookupSingle304   void collect_glyphs (set_t &glyphs) const
305   {
306     if (glyph == DELETED_GLYPH)
307       return;
308     glyphs.add (glyph);
309   }
310 
sanitizeAAT::LookupSingle311   bool sanitize (hb_sanitize_context_t *c) const
312   {
313     TRACE_SANITIZE (this);
314     return_trace (c->check_struct (this) && value.sanitize (c));
315   }
sanitizeAAT::LookupSingle316   bool sanitize (hb_sanitize_context_t *c, const void *base) const
317   {
318     TRACE_SANITIZE (this);
319     return_trace (c->check_struct (this) && value.sanitize (c, base));
320   }
321 
322   HBGlyphID16	glyph;		/* Last GlyphID */
323   T		value;		/* The lookup value (only one) */
324   public:
325   DEFINE_SIZE_STATIC (2 + T::static_size);
326 };
327 
328 template <typename T>
329 struct LookupFormat6
330 {
331   friend struct Lookup<T>;
332 
333   private:
get_valueAAT::LookupFormat6334   const T* get_value (hb_codepoint_t glyph_id) const
335   {
336     const LookupSingle<T> *v = entries.bsearch (glyph_id);
337     return v ? &v->value : nullptr;
338   }
339 
340   template <typename set_t>
collect_glyphsAAT::LookupFormat6341   void collect_glyphs (set_t &glyphs) const
342   {
343     unsigned count = entries.get_length ();
344     for (unsigned i = 0; i < count; i++)
345       entries[i].collect_glyphs (glyphs);
346   }
347 
sanitizeAAT::LookupFormat6348   bool sanitize (hb_sanitize_context_t *c) const
349   {
350     TRACE_SANITIZE (this);
351     return_trace (entries.sanitize (c));
352   }
sanitizeAAT::LookupFormat6353   bool sanitize (hb_sanitize_context_t *c, const void *base) const
354   {
355     TRACE_SANITIZE (this);
356     return_trace (entries.sanitize (c, base));
357   }
358 
359   protected:
360   HBUINT16	format;		/* Format identifier--format = 6 */
361   VarSizedBinSearchArrayOf<LookupSingle<T>>
362 		entries;	/* The actual entries, sorted by glyph index. */
363   public:
364   DEFINE_SIZE_ARRAY (8, entries);
365 };
366 
367 template <typename T>
368 struct LookupFormat8
369 {
370   friend struct Lookup<T>;
371 
372   private:
get_valueAAT::LookupFormat8373   const T* get_value (hb_codepoint_t glyph_id) const
374   {
375     return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ?
376 	   &valueArrayZ[glyph_id - firstGlyph] : nullptr;
377   }
378 
379   template <typename set_t>
collect_glyphsAAT::LookupFormat8380   void collect_glyphs (set_t &glyphs) const
381   {
382     if (unlikely (!glyphCount))
383       return;
384     if (firstGlyph == DELETED_GLYPH)
385       return;
386     glyphs.add_range (firstGlyph, firstGlyph + glyphCount - 1);
387   }
388 
sanitizeAAT::LookupFormat8389   bool sanitize (hb_sanitize_context_t *c) const
390   {
391     TRACE_SANITIZE (this);
392     return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount));
393   }
sanitizeAAT::LookupFormat8394   bool sanitize (hb_sanitize_context_t *c, const void *base) const
395   {
396     TRACE_SANITIZE (this);
397     return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount, base));
398   }
399 
400   protected:
401   HBUINT16	format;		/* Format identifier--format = 8 */
402   HBGlyphID16	firstGlyph;	/* First glyph index included in the trimmed array. */
403   HBUINT16	glyphCount;	/* Total number of glyphs (equivalent to the last
404 				 * glyph minus the value of firstGlyph plus 1). */
405   UnsizedArrayOf<T>
406 		valueArrayZ;	/* The lookup values (indexed by the glyph index
407 				 * minus the value of firstGlyph). */
408   public:
409   DEFINE_SIZE_ARRAY (6, valueArrayZ);
410 };
411 
412 template <typename T>
413 struct LookupFormat10
414 {
415   friend struct Lookup<T>;
416 
417   private:
get_value_or_nullAAT::LookupFormat10418   const typename T::type get_value_or_null (hb_codepoint_t glyph_id) const
419   {
420     if (!(firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount))
421       return Null (T);
422 
423     const HBUINT8 *p = &valueArrayZ[(glyph_id - firstGlyph) * valueSize];
424 
425     unsigned int v = 0;
426     unsigned int count = valueSize;
427     for (unsigned int i = 0; i < count; i++)
428       v = (v << 8) | *p++;
429 
430     return v;
431   }
432 
433   template <typename set_t>
collect_glyphsAAT::LookupFormat10434   void collect_glyphs (set_t &glyphs) const
435   {
436     if (unlikely (!glyphCount))
437       return;
438     if (firstGlyph == DELETED_GLYPH)
439       return;
440     glyphs.add_range (firstGlyph, firstGlyph + glyphCount - 1);
441   }
442 
sanitizeAAT::LookupFormat10443   bool sanitize (hb_sanitize_context_t *c) const
444   {
445     TRACE_SANITIZE (this);
446     return_trace (c->check_struct (this) &&
447 		  hb_barrier () &&
448 		  valueSize <= 4 &&
449 		  valueArrayZ.sanitize (c, glyphCount * valueSize));
450   }
451 
452   protected:
453   HBUINT16	format;		/* Format identifier--format = 8 */
454   HBUINT16	valueSize;	/* Byte size of each value. */
455   HBGlyphID16	firstGlyph;	/* First glyph index included in the trimmed array. */
456   HBUINT16	glyphCount;	/* Total number of glyphs (equivalent to the last
457 				 * glyph minus the value of firstGlyph plus 1). */
458   UnsizedArrayOf<HBUINT8>
459 		valueArrayZ;	/* The lookup values (indexed by the glyph index
460 				 * minus the value of firstGlyph). */
461   public:
462   DEFINE_SIZE_ARRAY (8, valueArrayZ);
463 };
464 
465 template <typename T>
466 struct Lookup
467 {
get_valueAAT::Lookup468   const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
469   {
470     switch (u.format) {
471     case 0: hb_barrier (); return u.format0.get_value (glyph_id, num_glyphs);
472     case 2: hb_barrier (); return u.format2.get_value (glyph_id);
473     case 4: hb_barrier (); return u.format4.get_value (glyph_id);
474     case 6: hb_barrier (); return u.format6.get_value (glyph_id);
475     case 8: hb_barrier (); return u.format8.get_value (glyph_id);
476     default:return nullptr;
477     }
478   }
479 
get_value_or_nullAAT::Lookup480   const typename T::type get_value_or_null (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
481   {
482     switch (u.format) {
483       /* Format 10 cannot return a pointer. */
484       case 10: hb_barrier (); return u.format10.get_value_or_null (glyph_id);
485       default:
486       const T *v = get_value (glyph_id, num_glyphs);
487       return v ? *v : Null (T);
488     }
489   }
490 
491   template <typename set_t>
collect_glyphsAAT::Lookup492   void collect_glyphs (set_t &glyphs, unsigned int num_glyphs) const
493   {
494     switch (u.format) {
495     case 0: hb_barrier (); u.format0.collect_glyphs (glyphs, num_glyphs); return;
496     case 2: hb_barrier (); u.format2.collect_glyphs (glyphs); return;
497     case 4: hb_barrier (); u.format4.collect_glyphs (glyphs); return;
498     case 6: hb_barrier (); u.format6.collect_glyphs (glyphs); return;
499     case 8: hb_barrier (); u.format8.collect_glyphs (glyphs); return;
500     case 10: hb_barrier (); u.format10.collect_glyphs (glyphs); return;
501     default:return;
502     }
503   }
504 
get_classAAT::Lookup505   typename T::type get_class (hb_codepoint_t glyph_id,
506 			      unsigned int num_glyphs,
507 			      unsigned int outOfRange) const
508   {
509     const T *v = get_value (glyph_id, num_glyphs);
510     return v ? *v : outOfRange;
511   }
512 
sanitizeAAT::Lookup513   bool sanitize (hb_sanitize_context_t *c) const
514   {
515     TRACE_SANITIZE (this);
516     if (!u.format.sanitize (c)) return_trace (false);
517     hb_barrier ();
518     switch (u.format) {
519     case 0: hb_barrier (); return_trace (u.format0.sanitize (c));
520     case 2: hb_barrier (); return_trace (u.format2.sanitize (c));
521     case 4: hb_barrier (); return_trace (u.format4.sanitize (c));
522     case 6: hb_barrier (); return_trace (u.format6.sanitize (c));
523     case 8: hb_barrier (); return_trace (u.format8.sanitize (c));
524     case 10: hb_barrier (); return_trace (u.format10.sanitize (c));
525     default:return_trace (true);
526     }
527   }
sanitizeAAT::Lookup528   bool sanitize (hb_sanitize_context_t *c, const void *base) const
529   {
530     TRACE_SANITIZE (this);
531     if (!u.format.sanitize (c)) return_trace (false);
532     hb_barrier ();
533     switch (u.format) {
534     case 0: hb_barrier (); return_trace (u.format0.sanitize (c, base));
535     case 2: hb_barrier (); return_trace (u.format2.sanitize (c, base));
536     case 4: hb_barrier (); return_trace (u.format4.sanitize (c, base));
537     case 6: hb_barrier (); return_trace (u.format6.sanitize (c, base));
538     case 8: hb_barrier (); return_trace (u.format8.sanitize (c, base));
539     case 10: return_trace (false); /* We don't support format10 here currently. */
540     default:return_trace (true);
541     }
542   }
543 
544   protected:
545   union {
546   HBUINT16		format;		/* Format identifier */
547   LookupFormat0<T>	format0;
548   LookupFormat2<T>	format2;
549   LookupFormat4<T>	format4;
550   LookupFormat6<T>	format6;
551   LookupFormat8<T>	format8;
552   LookupFormat10<T>	format10;
553   } u;
554   public:
555   DEFINE_SIZE_UNION (2, format);
556 };
557 DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (AAT, Lookup, 2);
558 
559 /*
560  * (Extended) State Table
561  */
562 
563 template <typename T>
564 struct Entry
565 {
566   // This does seem like it's ever called.
sanitizeAAT::Entry567   bool sanitize (hb_sanitize_context_t *c) const
568   {
569     TRACE_SANITIZE (this);
570     /* Note, we don't recurse-sanitize data because we don't access it.
571      * That said, in our DEFINE_SIZE_STATIC we access T::static_size,
572      * which ensures that data has a simple sanitize(). To be determined
573      * if I need to remove that as well.
574      *
575      * HOWEVER! Because we are a template, our DEFINE_SIZE_STATIC
576      * assertion wouldn't be checked, hence the line below. */
577     static_assert (T::static_size, "");
578 
579     return_trace (c->check_struct (this));
580   }
581 
582   public:
583   HBUINT16	newState;	/* Byte offset from beginning of state table
584 				 * to the new state. Really?!?! Or just state
585 				 * number?  The latter in morx for sure. */
586   HBUINT16	flags;		/* Table specific. */
587   T		data;		/* Optional offsets to per-glyph tables. */
588   public:
589   DEFINE_SIZE_STATIC (4 + T::static_size);
590 };
591 
592 template <>
593 struct Entry<void>
594 {
595   // This does seem like it's ever called.
sanitizeAAT::Entry596   bool sanitize (hb_sanitize_context_t *c) const
597   {
598     TRACE_SANITIZE (this);
599     return_trace (c->check_struct (this));
600   }
601 
602   public:
603   HBUINT16	newState;	/* Byte offset from beginning of state table to the new state. */
604   HBUINT16	flags;		/* Table specific. */
605   public:
606   DEFINE_SIZE_STATIC (4);
607 };
608 
609 enum Class
610 {
611   CLASS_END_OF_TEXT = 0,
612   CLASS_OUT_OF_BOUNDS = 1,
613   CLASS_DELETED_GLYPH = 2,
614   CLASS_END_OF_LINE = 3,
615 };
616 
617 template <typename Types, typename Extra>
618 struct StateTable
619 {
620   typedef typename Types::HBUINT HBUINT;
621   typedef typename Types::HBUSHORT HBUSHORT;
622   typedef typename Types::ClassTypeNarrow ClassType;
623 
624   enum State
625   {
626     STATE_START_OF_TEXT = 0,
627     STATE_START_OF_LINE = 1,
628   };
629 
630   template <typename set_t>
collect_glyphsAAT::StateTable631   void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const
632   {
633     (this+classTable).collect_glyphs (glyphs, num_glyphs);
634   }
635 
new_stateAAT::StateTable636   int new_state (unsigned int newState) const
637   { return Types::extended ? newState : ((int) newState - (int) stateArrayTable) / (int) nClasses; }
638 
639   template <typename set_t>
get_classAAT::StateTable640   unsigned int get_class (hb_codepoint_t glyph_id,
641 			  unsigned int num_glyphs,
642 			  const set_t &glyphs) const
643   {
644     if (unlikely (glyph_id == DELETED_GLYPH)) return CLASS_DELETED_GLYPH;
645     if (!glyphs[glyph_id]) return CLASS_OUT_OF_BOUNDS;
646     return (this+classTable).get_class (glyph_id, num_glyphs, CLASS_OUT_OF_BOUNDS);
647   }
648 
get_entriesAAT::StateTable649   const Entry<Extra> *get_entries () const
650   { return (this+entryTable).arrayZ; }
651 
get_entryAAT::StateTable652   const Entry<Extra> &get_entry (int state, unsigned int klass) const
653   {
654     if (unlikely (klass >= nClasses))
655       klass = CLASS_OUT_OF_BOUNDS;
656 
657     const HBUSHORT *states = (this+stateArrayTable).arrayZ;
658     const Entry<Extra> *entries = (this+entryTable).arrayZ;
659 
660     unsigned int entry = states[state * nClasses + klass];
661     DEBUG_MSG (APPLY, nullptr, "e%u", entry);
662 
663     return entries[entry];
664   }
665 
sanitizeAAT::StateTable666   bool sanitize (hb_sanitize_context_t *c,
667 		 unsigned int *num_entries_out = nullptr) const
668   {
669     TRACE_SANITIZE (this);
670     if (unlikely (!(c->check_struct (this) &&
671 		    hb_barrier () &&
672 		    nClasses >= 4 /* Ensure pre-defined classes fit.  */ &&
673 		    classTable.sanitize (c, this)))) return_trace (false);
674 
675     const HBUSHORT *states = (this+stateArrayTable).arrayZ;
676     const Entry<Extra> *entries = (this+entryTable).arrayZ;
677 
678     unsigned int num_classes = nClasses;
679     if (unlikely (hb_unsigned_mul_overflows (num_classes, states[0].static_size)))
680       return_trace (false);
681     unsigned int row_stride = num_classes * states[0].static_size;
682 
683     /* Apple 'kern' table has this peculiarity:
684      *
685      * "Because the stateTableOffset in the state table header is (strictly
686      * speaking) redundant, some 'kern' tables use it to record an initial
687      * state where that should not be StartOfText. To determine if this is
688      * done, calculate what the stateTableOffset should be. If it's different
689      * from the actual stateTableOffset, use it as the initial state."
690      *
691      * We implement this by calling the initial state zero, but allow *negative*
692      * states if the start state indeed was not the first state.  Since the code
693      * is shared, this will also apply to 'mort' table.  The 'kerx' / 'morx'
694      * tables are not affected since those address states by index, not offset.
695      */
696 
697     int min_state = 0;
698     int max_state = 0;
699     unsigned int num_entries = 0;
700 
701     int state_pos = 0;
702     int state_neg = 0;
703     unsigned int entry = 0;
704     while (min_state < state_neg || state_pos <= max_state)
705     {
706       if (min_state < state_neg)
707       {
708 	/* Negative states. */
709 	if (unlikely (hb_unsigned_mul_overflows (min_state, num_classes)))
710 	  return_trace (false);
711 	if (unlikely (!c->check_range (&states[min_state * num_classes],
712 				       -min_state,
713 				       row_stride)))
714 	  return_trace (false);
715 	if ((c->max_ops -= state_neg - min_state) <= 0)
716 	  return_trace (false);
717 	{ /* Sweep new states. */
718 	  const HBUSHORT *stop = &states[min_state * num_classes];
719 	  if (unlikely (stop > states))
720 	    return_trace (false);
721 	  for (const HBUSHORT *p = states; stop < p; p--)
722 	    num_entries = hb_max (num_entries, *(p - 1) + 1u);
723 	  state_neg = min_state;
724 	}
725       }
726 
727       if (state_pos <= max_state)
728       {
729 	/* Positive states. */
730 	if (unlikely (!c->check_range (states,
731 				       max_state + 1,
732 				       row_stride)))
733 	  return_trace (false);
734 	if ((c->max_ops -= max_state - state_pos + 1) <= 0)
735 	  return_trace (false);
736 	{ /* Sweep new states. */
737 	  if (unlikely (hb_unsigned_mul_overflows ((max_state + 1), num_classes)))
738 	    return_trace (false);
739 	  const HBUSHORT *stop = &states[(max_state + 1) * num_classes];
740 	  if (unlikely (stop < states))
741 	    return_trace (false);
742 	  for (const HBUSHORT *p = &states[state_pos * num_classes]; p < stop; p++)
743 	    num_entries = hb_max (num_entries, *p + 1u);
744 	  state_pos = max_state + 1;
745 	}
746       }
747 
748       if (unlikely (!c->check_array (entries, num_entries)))
749 	return_trace (false);
750       if ((c->max_ops -= num_entries - entry) <= 0)
751 	return_trace (false);
752       { /* Sweep new entries. */
753 	const Entry<Extra> *stop = &entries[num_entries];
754 	for (const Entry<Extra> *p = &entries[entry]; p < stop; p++)
755 	{
756 	  int newState = new_state (p->newState);
757 	  min_state = hb_min (min_state, newState);
758 	  max_state = hb_max (max_state, newState);
759 	}
760 	entry = num_entries;
761       }
762     }
763 
764     if (num_entries_out)
765       *num_entries_out = num_entries;
766 
767     return_trace (true);
768   }
769 
770   protected:
771   HBUINT	nClasses;	/* Number of classes, which is the number of indices
772 				 * in a single line in the state array. */
773   NNOffsetTo<ClassType, HBUINT>
774 		classTable;	/* Offset to the class table. */
775   NNOffsetTo<UnsizedArrayOf<HBUSHORT>, HBUINT>
776 		stateArrayTable;/* Offset to the state array. */
777   NNOffsetTo<UnsizedArrayOf<Entry<Extra>>, HBUINT>
778 		entryTable;	/* Offset to the entry array. */
779 
780   public:
781   DEFINE_SIZE_STATIC (4 * sizeof (HBUINT));
782 };
783 
784 template <typename HBUCHAR>
785 struct ClassTable
786 {
get_classAAT::ClassTable787   unsigned int get_class (hb_codepoint_t glyph_id, unsigned int outOfRange) const
788   {
789     unsigned int i = glyph_id - firstGlyph;
790     return i >= classArray.len ? outOfRange : classArray.arrayZ[i];
791   }
get_classAAT::ClassTable792   unsigned int get_class (hb_codepoint_t glyph_id,
793 			  unsigned int num_glyphs HB_UNUSED,
794 			  unsigned int outOfRange) const
795   {
796     return get_class (glyph_id, outOfRange);
797   }
798 
799   template <typename set_t>
collect_glyphsAAT::ClassTable800   void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const
801   {
802     for (unsigned i = 0; i < classArray.len; i++)
803       if (classArray.arrayZ[i] != CLASS_OUT_OF_BOUNDS)
804 	glyphs.add (firstGlyph + i);
805   }
806 
sanitizeAAT::ClassTable807   bool sanitize (hb_sanitize_context_t *c) const
808   {
809     TRACE_SANITIZE (this);
810     return_trace (c->check_struct (this) && classArray.sanitize (c));
811   }
812   protected:
813   HBGlyphID16		firstGlyph;	/* First glyph index included in the trimmed array. */
814   Array16Of<HBUCHAR>	classArray;	/* The class codes (indexed by glyph index minus
815 					 * firstGlyph). */
816   public:
817   DEFINE_SIZE_ARRAY (4, classArray);
818 };
819 
820 struct SubtableGlyphCoverage
821 {
sanitizeAAT::SubtableGlyphCoverage822   bool sanitize (hb_sanitize_context_t *c, unsigned subtable_count) const
823   {
824     TRACE_SANITIZE (this);
825 
826     if (unlikely (!c->check_array (&subtableOffsets, subtable_count)))
827       return_trace (false);
828 
829     unsigned bytes = (c->get_num_glyphs () + CHAR_BIT - 1) / CHAR_BIT;
830     for (unsigned i = 0; i < subtable_count; i++)
831     {
832       uint32_t offset = (uint32_t) subtableOffsets[i];
833       if (offset == 0 || offset == 0xFFFFFFFF)
834         continue;
835       if (unlikely (!subtableOffsets[i].sanitize (c, this, bytes)))
836         return_trace (false);
837     }
838 
839     return_trace (true);
840   }
841   protected:
842   UnsizedArrayOf<NNOffset32To<UnsizedArrayOf<HBUINT8>>> subtableOffsets;
843 					    /* Array of offsets from the beginning of the
844 					     * subtable glyph coverage table to the glyph
845 					     * coverage bitfield for a given subtable; there
846 					     * is one offset for each subtable in the chain */
847   /* UnsizedArrayOf<HBUINT8> coverageBitfields; *//* The individual coverage bitfields. */
848   public:
849   DEFINE_SIZE_ARRAY (0, subtableOffsets);
850 };
851 
852 struct ObsoleteTypes
853 {
854   static constexpr bool extended = false;
855   typedef HBUINT16 HBUINT;
856   typedef HBUINT8 HBUSHORT;
857   typedef ClassTable<HBUINT8> ClassTypeNarrow;
858   typedef ClassTable<HBUINT16> ClassTypeWide;
859 
860   template <typename T>
offsetToIndexAAT::ObsoleteTypes861   static unsigned int offsetToIndex (unsigned int offset,
862 				     const void *base,
863 				     const T *array)
864   {
865     /* https://github.com/harfbuzz/harfbuzz/issues/3483 */
866     /* If offset is less than base, return an offset that would
867      * result in an address half a 32bit address-space away,
868      * to make sure sanitize fails even on 32bit builds. */
869     if (unlikely (offset < unsigned ((const char *) array - (const char *) base)))
870       return INT_MAX / T::static_size;
871 
872     /* https://github.com/harfbuzz/harfbuzz/issues/2816 */
873     return (offset - unsigned ((const char *) array - (const char *) base)) / T::static_size;
874   }
875   template <typename T>
byteOffsetToIndexAAT::ObsoleteTypes876   static unsigned int byteOffsetToIndex (unsigned int offset,
877 					 const void *base,
878 					 const T *array)
879   {
880     return offsetToIndex (offset, base, array);
881   }
882   template <typename T>
wordOffsetToIndexAAT::ObsoleteTypes883   static unsigned int wordOffsetToIndex (unsigned int offset,
884 					 const void *base,
885 					 const T *array)
886   {
887     return offsetToIndex (2 * offset, base, array);
888   }
889 };
890 struct ExtendedTypes
891 {
892   static constexpr bool extended = true;
893   typedef HBUINT32 HBUINT;
894   typedef HBUINT16 HBUSHORT;
895   typedef Lookup<HBUINT16> ClassTypeNarrow;
896   typedef Lookup<HBUINT16> ClassTypeWide;
897 
898   template <typename T>
offsetToIndexAAT::ExtendedTypes899   static unsigned int offsetToIndex (unsigned int offset,
900 				     const void *base HB_UNUSED,
901 				     const T *array HB_UNUSED)
902   {
903     return offset;
904   }
905   template <typename T>
byteOffsetToIndexAAT::ExtendedTypes906   static unsigned int byteOffsetToIndex (unsigned int offset,
907 					 const void *base HB_UNUSED,
908 					 const T *array HB_UNUSED)
909   {
910     return offset / 2;
911   }
912   template <typename T>
wordOffsetToIndexAAT::ExtendedTypes913   static unsigned int wordOffsetToIndex (unsigned int offset,
914 					 const void *base HB_UNUSED,
915 					 const T *array HB_UNUSED)
916   {
917     return offset;
918   }
919 };
920 
921 template <typename Types, typename EntryData>
922 struct StateTableDriver
923 {
924   using StateTableT = StateTable<Types, EntryData>;
925   using EntryT = Entry<EntryData>;
926 
StateTableDriverAAT::StateTableDriver927   StateTableDriver (const StateTableT &machine_,
928 		    hb_face_t *face_) :
929 	      machine (machine_),
930 	      num_glyphs (face_->get_num_glyphs ()) {}
931 
932   template <typename context_t>
is_idempotent_on_all_out_of_boundsAAT::StateTableDriver933   bool is_idempotent_on_all_out_of_bounds (context_t *c, hb_aat_apply_context_t *ac)
934   {
935     const auto entry = machine.get_entry (StateTableT::STATE_START_OF_TEXT, CLASS_OUT_OF_BOUNDS);
936     return !c->is_actionable (ac->buffer, this, entry) &&
937 	    machine.new_state (entry.newState) == StateTableT::STATE_START_OF_TEXT;
938   }
939 
940   template <typename context_t>
driveAAT::StateTableDriver941   void drive (context_t *c, hb_aat_apply_context_t *ac)
942   {
943     hb_buffer_t *buffer = ac->buffer;
944 
945     if (!c->in_place)
946       buffer->clear_output ();
947 
948     int state = StateTableT::STATE_START_OF_TEXT;
949     // If there's only one range, we already checked the flag.
950     auto *last_range = ac->range_flags && (ac->range_flags->length > 1) ? &(*ac->range_flags)[0] : nullptr;
951     for (buffer->idx = 0; buffer->successful;)
952     {
953       /* This block is copied in NoncontextualSubtable::apply. Keep in sync. */
954       if (last_range)
955       {
956 	auto *range = last_range;
957 	if (buffer->idx < buffer->len)
958 	{
959 	  unsigned cluster = buffer->cur().cluster;
960 	  while (cluster < range->cluster_first)
961 	    range--;
962 	  while (cluster > range->cluster_last)
963 	    range++;
964 
965 
966 	  last_range = range;
967 	}
968 	if (!(range->flags & ac->subtable_flags))
969 	{
970 	  if (buffer->idx == buffer->len || unlikely (!buffer->successful))
971 	    break;
972 
973 	  state = StateTableT::STATE_START_OF_TEXT;
974 	  (void) buffer->next_glyph ();
975 	  continue;
976 	}
977       }
978 
979       unsigned int klass = likely (buffer->idx < buffer->len) ?
980 			   machine.get_class (buffer->cur().codepoint, num_glyphs, ac->machine_glyph_set) :
981 			   (unsigned) CLASS_END_OF_TEXT;
982       DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
983       const EntryT &entry = machine.get_entry (state, klass);
984       const int next_state = machine.new_state (entry.newState);
985 
986       /* Conditions under which it's guaranteed safe-to-break before current glyph:
987        *
988        * 1. There was no action in this transition; and
989        *
990        * 2. If we break before current glyph, the results will be the same. That
991        *    is guaranteed if:
992        *
993        *    2a. We were already in start-of-text state; or
994        *
995        *    2b. We are epsilon-transitioning to start-of-text state; or
996        *
997        *    2c. Starting from start-of-text state seeing current glyph:
998        *
999        *        2c'. There won't be any actions; and
1000        *
1001        *        2c". We would end up in the same state that we were going to end up
1002        *             in now, including whether epsilon-transitioning.
1003        *
1004        *    and
1005        *
1006        * 3. If we break before current glyph, there won't be any end-of-text action
1007        *    after previous glyph.
1008        *
1009        * This triples the transitions we need to look up, but is worth returning
1010        * granular unsafe-to-break results. See eg.:
1011        *
1012        *   https://github.com/harfbuzz/harfbuzz/issues/2860
1013        */
1014 
1015       const auto is_safe_to_break_extra = [&]()
1016       {
1017           /* 2c. */
1018           const auto &wouldbe_entry = machine.get_entry(StateTableT::STATE_START_OF_TEXT, klass);
1019 
1020           /* 2c'. */
1021           if (c->is_actionable (buffer, this, wouldbe_entry))
1022 	    return false;
1023 
1024           /* 2c". */
1025           return next_state == machine.new_state(wouldbe_entry.newState)
1026               && (entry.flags & context_t::DontAdvance) == (wouldbe_entry.flags & context_t::DontAdvance);
1027       };
1028 
1029       const auto is_safe_to_break = [&]()
1030       {
1031           /* 1. */
1032           if (c->is_actionable (buffer, this, entry))
1033               return false;
1034 
1035           /* 2. */
1036           // This one is meh, I know...
1037           const auto ok =
1038                  state == StateTableT::STATE_START_OF_TEXT
1039               || ((entry.flags & context_t::DontAdvance) && next_state == StateTableT::STATE_START_OF_TEXT)
1040               || is_safe_to_break_extra();
1041           if (!ok)
1042               return false;
1043 
1044           /* 3. */
1045           return !c->is_actionable (buffer, this, machine.get_entry (state, CLASS_END_OF_TEXT));
1046       };
1047 
1048       if (!is_safe_to_break () && buffer->backtrack_len () && buffer->idx < buffer->len)
1049 	buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
1050 
1051       c->transition (buffer, this, entry);
1052 
1053       state = next_state;
1054       DEBUG_MSG (APPLY, nullptr, "s%d", state);
1055 
1056       if (buffer->idx == buffer->len || unlikely (!buffer->successful))
1057 	break;
1058 
1059       if (!(entry.flags & context_t::DontAdvance) || buffer->max_ops-- <= 0)
1060 	(void) buffer->next_glyph ();
1061     }
1062 
1063     if (!c->in_place)
1064       buffer->sync ();
1065   }
1066 
1067   public:
1068   const StateTableT &machine;
1069   unsigned int num_glyphs;
1070 };
1071 
1072 
1073 } /* namespace AAT */
1074 
1075 
1076 #endif /* HB_AAT_LAYOUT_COMMON_HH */
1077