Fix build error
[platform/upstream/harfbuzz.git] / src / hb-ot-layout-base-table.hh
1 /*
2  * Copyright © 2016  Elie Roux <elie.roux@telecom-bretagne.eu>
3  * Copyright © 2018  Google, Inc.
4  * Copyright © 2018-2019  Ebrahim Byagowi
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  * Google Author(s): Behdad Esfahbod
27  */
28
29 #ifndef HB_OT_LAYOUT_BASE_TABLE_HH
30 #define HB_OT_LAYOUT_BASE_TABLE_HH
31
32 #include "hb-open-type.hh"
33 #include "hb-ot-layout-common.hh"
34
35 namespace OT {
36
37 /*
38  * BASE -- Baseline
39  * https://docs.microsoft.com/en-us/typography/opentype/spec/base
40  */
41
42 struct BaseCoordFormat1
43 {
44   hb_position_t get_coord (hb_font_t *font, hb_direction_t direction) const
45   {
46     return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (coordinate) : font->em_scale_x (coordinate);
47   }
48
49   bool sanitize (hb_sanitize_context_t *c) const
50   {
51     TRACE_SANITIZE (this);
52     return_trace (c->check_struct (this));
53   }
54
55   protected:
56   HBUINT16      format;         /* Format identifier--format = 1 */
57   FWORD         coordinate;     /* X or Y value, in design units */
58   public:
59   DEFINE_SIZE_STATIC (4);
60 };
61
62 struct BaseCoordFormat2
63 {
64   hb_position_t get_coord (hb_font_t *font, hb_direction_t direction) const
65   {
66     /* TODO */
67     return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (coordinate) : font->em_scale_x (coordinate);
68   }
69
70   bool sanitize (hb_sanitize_context_t *c) const
71   {
72     TRACE_SANITIZE (this);
73     return_trace (c->check_struct (this));
74   }
75
76   protected:
77   HBUINT16      format;         /* Format identifier--format = 2 */
78   FWORD         coordinate;     /* X or Y value, in design units */
79   HBGlyphID16   referenceGlyph; /* Glyph ID of control glyph */
80   HBUINT16      coordPoint;     /* Index of contour point on the
81                                  * reference glyph */
82   public:
83   DEFINE_SIZE_STATIC (8);
84 };
85
86 struct BaseCoordFormat3
87 {
88   hb_position_t get_coord (hb_font_t *font,
89                            const VariationStore &var_store,
90                            hb_direction_t direction) const
91   {
92     const Device &device = this+deviceTable;
93
94     return HB_DIRECTION_IS_HORIZONTAL (direction)
95          ? font->em_scale_y (coordinate) + device.get_y_delta (font, var_store)
96          : font->em_scale_x (coordinate) + device.get_x_delta (font, var_store);
97   }
98
99
100   bool sanitize (hb_sanitize_context_t *c) const
101   {
102     TRACE_SANITIZE (this);
103     return_trace (likely (c->check_struct (this) &&
104                           deviceTable.sanitize (c, this)));
105   }
106
107   protected:
108   HBUINT16      format;         /* Format identifier--format = 3 */
109   FWORD         coordinate;     /* X or Y value, in design units */
110   Offset16To<Device>
111                 deviceTable;    /* Offset to Device table for X or
112                                  * Y value, from beginning of
113                                  * BaseCoord table (may be NULL). */
114   public:
115   DEFINE_SIZE_STATIC (6);
116 };
117
118 struct BaseCoord
119 {
120   bool has_data () const { return u.format; }
121
122   hb_position_t get_coord (hb_font_t            *font,
123                            const VariationStore &var_store,
124                            hb_direction_t        direction) const
125   {
126     switch (u.format) {
127     case 1: return u.format1.get_coord (font, direction);
128     case 2: return u.format2.get_coord (font, direction);
129     case 3: return u.format3.get_coord (font, var_store, direction);
130     default:return 0;
131     }
132   }
133
134   bool sanitize (hb_sanitize_context_t *c) const
135   {
136     TRACE_SANITIZE (this);
137     if (unlikely (!u.format.sanitize (c))) return_trace (false);
138     switch (u.format) {
139     case 1: return_trace (u.format1.sanitize (c));
140     case 2: return_trace (u.format2.sanitize (c));
141     case 3: return_trace (u.format3.sanitize (c));
142     default:return_trace (false);
143     }
144   }
145
146   protected:
147   union {
148   HBUINT16              format;
149   BaseCoordFormat1      format1;
150   BaseCoordFormat2      format2;
151   BaseCoordFormat3      format3;
152   } u;
153   public:
154   DEFINE_SIZE_UNION (2, format);
155 };
156
157 struct FeatMinMaxRecord
158 {
159   int cmp (hb_tag_t key) const { return tag.cmp (key); }
160
161   bool has_data () const { return tag; }
162
163   void get_min_max (const BaseCoord **min, const BaseCoord **max) const
164   {
165     if (likely (min)) *min = &(this+minCoord);
166     if (likely (max)) *max = &(this+maxCoord);
167   }
168
169   bool sanitize (hb_sanitize_context_t *c, const void *base) const
170   {
171     TRACE_SANITIZE (this);
172     return_trace (likely (c->check_struct (this) &&
173                           minCoord.sanitize (c, base) &&
174                           maxCoord.sanitize (c, base)));
175   }
176
177   protected:
178   Tag           tag;            /* 4-byte feature identification tag--must
179                                  * match feature tag in FeatureList */
180   Offset16To<BaseCoord>
181                 minCoord;       /* Offset to BaseCoord table that defines
182                                  * the minimum extent value, from beginning
183                                  * of MinMax table (may be NULL) */
184   Offset16To<BaseCoord>
185                 maxCoord;       /* Offset to BaseCoord table that defines
186                                  * the maximum extent value, from beginning
187                                  * of MinMax table (may be NULL) */
188   public:
189   DEFINE_SIZE_STATIC (8);
190 };
191
192 struct MinMax
193 {
194   void get_min_max (hb_tag_t          feature_tag,
195                     const BaseCoord **min,
196                     const BaseCoord **max) const
197   {
198     const FeatMinMaxRecord &minMaxCoord = featMinMaxRecords.bsearch (feature_tag);
199     if (minMaxCoord.has_data ())
200       minMaxCoord.get_min_max (min, max);
201     else
202     {
203       if (likely (min)) *min = &(this+minCoord);
204       if (likely (max)) *max = &(this+maxCoord);
205     }
206   }
207
208   bool sanitize (hb_sanitize_context_t *c) const
209   {
210     TRACE_SANITIZE (this);
211     return_trace (likely (c->check_struct (this) &&
212                           minCoord.sanitize (c, this) &&
213                           maxCoord.sanitize (c, this) &&
214                           featMinMaxRecords.sanitize (c, this)));
215   }
216
217   protected:
218   Offset16To<BaseCoord>
219                 minCoord;       /* Offset to BaseCoord table that defines
220                                  * minimum extent value, from the beginning
221                                  * of MinMax table (may be NULL) */
222   Offset16To<BaseCoord>
223                 maxCoord;       /* Offset to BaseCoord table that defines
224                                  * maximum extent value, from the beginning
225                                  * of MinMax table (may be NULL) */
226   SortedArray16Of<FeatMinMaxRecord>
227                 featMinMaxRecords;
228                                 /* Array of FeatMinMaxRecords, in alphabetical
229                                  * order by featureTableTag */
230   public:
231   DEFINE_SIZE_ARRAY (6, featMinMaxRecords);
232 };
233
234 struct BaseValues
235 {
236   const BaseCoord &get_base_coord (int baseline_tag_index) const
237   {
238     if (baseline_tag_index == -1) baseline_tag_index = defaultIndex;
239     return this+baseCoords[baseline_tag_index];
240   }
241
242   bool sanitize (hb_sanitize_context_t *c) const
243   {
244     TRACE_SANITIZE (this);
245     return_trace (likely (c->check_struct (this) &&
246                           baseCoords.sanitize (c, this)));
247   }
248
249   protected:
250   Index         defaultIndex;   /* Index number of default baseline for this
251                                  * script — equals index position of baseline tag
252                                  * in baselineTags array of the BaseTagList */
253   Array16OfOffset16To<BaseCoord>
254                 baseCoords;     /* Number of BaseCoord tables defined — should equal
255                                  * baseTagCount in the BaseTagList
256                                  *
257                                  * Array of offsets to BaseCoord tables, from beginning of
258                                  * BaseValues table — order matches baselineTags array in
259                                  * the BaseTagList */
260   public:
261   DEFINE_SIZE_ARRAY (4, baseCoords);
262 };
263
264 struct BaseLangSysRecord
265 {
266   int cmp (hb_tag_t key) const { return baseLangSysTag.cmp (key); }
267
268   bool has_data () const { return baseLangSysTag; }
269
270   const MinMax &get_min_max () const { return this+minMax; }
271
272   bool sanitize (hb_sanitize_context_t *c, const void *base) const
273   {
274     TRACE_SANITIZE (this);
275     return_trace (likely (c->check_struct (this) &&
276                           minMax.sanitize (c, base)));
277   }
278
279   protected:
280   Tag           baseLangSysTag; /* 4-byte language system identification tag */
281   Offset16To<MinMax>
282                 minMax;         /* Offset to MinMax table, from beginning
283                                  * of BaseScript table */
284   public:
285   DEFINE_SIZE_STATIC (6);
286 };
287
288 struct BaseScript
289 {
290   const MinMax &get_min_max (hb_tag_t language_tag) const
291   {
292     const BaseLangSysRecord& record = baseLangSysRecords.bsearch (language_tag);
293     return record.has_data () ? record.get_min_max () : this+defaultMinMax;
294   }
295
296   const BaseCoord &get_base_coord (int baseline_tag_index) const
297   { return (this+baseValues).get_base_coord (baseline_tag_index); }
298
299   bool has_values () const { return baseValues; }
300   bool has_min_max () const { return defaultMinMax; /* TODO What if only per-language is present? */ }
301
302   bool sanitize (hb_sanitize_context_t *c) const
303   {
304     TRACE_SANITIZE (this);
305     return_trace (likely (c->check_struct (this) &&
306                           baseValues.sanitize (c, this) &&
307                           defaultMinMax.sanitize (c, this) &&
308                           baseLangSysRecords.sanitize (c, this)));
309   }
310
311   protected:
312   Offset16To<BaseValues>
313                 baseValues;     /* Offset to BaseValues table, from beginning
314                                  * of BaseScript table (may be NULL) */
315   Offset16To<MinMax>
316                 defaultMinMax;  /* Offset to MinMax table, from beginning of
317                                  * BaseScript table (may be NULL) */
318   SortedArray16Of<BaseLangSysRecord>
319                 baseLangSysRecords;
320                                 /* Number of BaseLangSysRecords
321                                  * defined — may be zero (0) */
322
323   public:
324   DEFINE_SIZE_ARRAY (6, baseLangSysRecords);
325 };
326
327 struct BaseScriptList;
328 struct BaseScriptRecord
329 {
330   int cmp (hb_tag_t key) const { return baseScriptTag.cmp (key); }
331
332   bool has_data () const { return baseScriptTag; }
333
334   const BaseScript &get_base_script (const BaseScriptList *list) const
335   { return list+baseScript; }
336
337   bool sanitize (hb_sanitize_context_t *c, const void *base) const
338   {
339     TRACE_SANITIZE (this);
340     return_trace (likely (c->check_struct (this) &&
341                           baseScript.sanitize (c, base)));
342   }
343
344   protected:
345   Tag           baseScriptTag;  /* 4-byte script identification tag */
346   Offset16To<BaseScript>
347                 baseScript;     /* Offset to BaseScript table, from beginning
348                                  * of BaseScriptList */
349
350   public:
351   DEFINE_SIZE_STATIC (6);
352 };
353
354 struct BaseScriptList
355 {
356   const BaseScript &get_base_script (hb_tag_t script) const
357   {
358     const BaseScriptRecord *record = &baseScriptRecords.bsearch (script);
359     if (!record->has_data ()) record = &baseScriptRecords.bsearch (HB_TAG ('D','F','L','T'));
360     return record->has_data () ? record->get_base_script (this) : Null (BaseScript);
361   }
362
363   bool sanitize (hb_sanitize_context_t *c) const
364   {
365     TRACE_SANITIZE (this);
366     return_trace (c->check_struct (this) &&
367                   baseScriptRecords.sanitize (c, this));
368   }
369
370   protected:
371   SortedArray16Of<BaseScriptRecord>
372                         baseScriptRecords;
373
374   public:
375   DEFINE_SIZE_ARRAY (2, baseScriptRecords);
376 };
377
378 struct Axis
379 {
380   bool get_baseline (hb_tag_t          baseline_tag,
381                      hb_tag_t          script_tag,
382                      hb_tag_t          language_tag,
383                      const BaseCoord **coord) const
384   {
385     const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag);
386     if (!base_script.has_values ())
387     {
388       *coord = nullptr;
389       return false;
390     }
391
392     if (likely (coord))
393     {
394       unsigned int tag_index = 0;
395       if (!(this+baseTagList).bfind (baseline_tag, &tag_index))
396       {
397         *coord = nullptr;
398         return false;
399       }
400       *coord = &base_script.get_base_coord (tag_index);
401     }
402
403     return true;
404   }
405
406   bool get_min_max (hb_tag_t          script_tag,
407                     hb_tag_t          language_tag,
408                     hb_tag_t          feature_tag,
409                     const BaseCoord **min_coord,
410                     const BaseCoord **max_coord) const
411   {
412     const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag);
413     if (!base_script.has_min_max ())
414     {
415       *min_coord = *max_coord = nullptr;
416       return false;
417     }
418
419     base_script.get_min_max (language_tag).get_min_max (feature_tag, min_coord, max_coord);
420
421     return true;
422   }
423
424   bool sanitize (hb_sanitize_context_t *c) const
425   {
426     TRACE_SANITIZE (this);
427     return_trace (likely (c->check_struct (this) &&
428                           baseTagList.sanitize (c, this) &&
429                           baseScriptList.sanitize (c, this)));
430   }
431
432   protected:
433   Offset16To<SortedArray16Of<Tag>>
434                 baseTagList;    /* Offset to BaseTagList table, from beginning
435                                  * of Axis table (may be NULL)
436                                  * Array of 4-byte baseline identification tags — must
437                                  * be in alphabetical order */
438   Offset16To<BaseScriptList>
439                 baseScriptList; /* Offset to BaseScriptList table, from beginning
440                                  * of Axis table
441                                  * Array of BaseScriptRecords, in alphabetical order
442                                  * by baseScriptTag */
443
444   public:
445   DEFINE_SIZE_STATIC (4);
446 };
447
448 struct BASE
449 {
450   static constexpr hb_tag_t tableTag = HB_OT_TAG_BASE;
451
452   const Axis &get_axis (hb_direction_t direction) const
453   { return HB_DIRECTION_IS_VERTICAL (direction) ? this+vAxis : this+hAxis; }
454
455   const VariationStore &get_var_store () const
456   { return version.to_int () < 0x00010001u ? Null (VariationStore) : this+varStore; }
457
458   bool get_baseline (hb_font_t      *font,
459                      hb_tag_t        baseline_tag,
460                      hb_direction_t  direction,
461                      hb_tag_t        script_tag,
462                      hb_tag_t        language_tag,
463                      hb_position_t  *base) const
464   {
465     const BaseCoord *base_coord = nullptr;
466     if (unlikely (!get_axis (direction).get_baseline (baseline_tag, script_tag, language_tag, &base_coord) ||
467                   !base_coord || !base_coord->has_data ()))
468       return false;
469
470     if (likely (base))
471       *base = base_coord->get_coord (font, get_var_store (), direction);
472
473     return true;
474   }
475
476   bool get_min_max (hb_font_t      *font,
477                     hb_direction_t  direction,
478                     hb_tag_t        script_tag,
479                     hb_tag_t        language_tag,
480                     hb_tag_t        feature_tag,
481                     hb_position_t  *min,
482                     hb_position_t  *max) const
483   {
484     const BaseCoord *min_coord, *max_coord;
485     if (!get_axis (direction).get_min_max (script_tag, language_tag, feature_tag,
486                                            &min_coord, &max_coord))
487       return false;
488
489     const VariationStore &var_store = get_var_store ();
490     if (likely (min && min_coord)) *min = min_coord->get_coord (font, var_store, direction);
491     if (likely (max && max_coord)) *max = max_coord->get_coord (font, var_store, direction);
492     return true;
493   }
494
495   bool sanitize (hb_sanitize_context_t *c) const
496   {
497     TRACE_SANITIZE (this);
498     return_trace (likely (c->check_struct (this) &&
499                           likely (version.major == 1) &&
500                           hAxis.sanitize (c, this) &&
501                           vAxis.sanitize (c, this) &&
502                           (version.to_int () < 0x00010001u || varStore.sanitize (c, this))));
503   }
504
505   protected:
506   FixedVersion<>version;        /* Version of the BASE table */
507   Offset16To<Axis>hAxis;                /* Offset to horizontal Axis table, from beginning
508                                  * of BASE table (may be NULL) */
509   Offset16To<Axis>vAxis;                /* Offset to vertical Axis table, from beginning
510                                  * of BASE table (may be NULL) */
511   Offset32To<VariationStore>
512                 varStore;       /* Offset to the table of Item Variation
513                                  * Store--from beginning of BASE
514                                  * header (may be NULL).  Introduced
515                                  * in version 0x00010001. */
516   public:
517   DEFINE_SIZE_MIN (8);
518 };
519
520
521 } /* namespace OT */
522
523
524 #endif /* HB_OT_LAYOUT_BASE_TABLE_HH */