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
35namespace OT {
36
37/*
38 * BASE -- Baseline
39 * https://docs.microsoft.com/en-us/typography/opentype/spec/base
40 */
41
42struct 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 (v: coordinate) : font->em_scale_x (v: 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
62struct 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 (v: coordinate) : font->em_scale_x (v: 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
86struct 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 (v: coordinate) + device.get_y_delta (font, store: var_store)
96 : font->em_scale_x (v: coordinate) + device.get_x_delta (font, store: 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
118struct 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
157struct FeatMinMaxRecord
158{
159 int cmp (hb_tag_t key) const { return tag.cmp (a: 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, this) &&
174 maxCoord.sanitize (c, this)));
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
193struct MinMax
194{
195 void get_min_max (hb_tag_t feature_tag,
196 const BaseCoord **min,
197 const BaseCoord **max) const
198 {
199 const FeatMinMaxRecord &minMaxCoord = featMinMaxRecords.bsearch (x: feature_tag);
200 if (minMaxCoord.has_data ())
201 minMaxCoord.get_min_max (min, max);
202 else
203 {
204 if (likely (min)) *min = &(this+minCoord);
205 if (likely (max)) *max = &(this+maxCoord);
206 }
207 }
208
209 bool sanitize (hb_sanitize_context_t *c) const
210 {
211 TRACE_SANITIZE (this);
212 return_trace (likely (c->check_struct (this) &&
213 minCoord.sanitize (c, this) &&
214 maxCoord.sanitize (c, this) &&
215 featMinMaxRecords.sanitize (c, this)));
216 }
217
218 protected:
219 Offset16To<BaseCoord>
220 minCoord; /* Offset to BaseCoord table that defines
221 * minimum extent value, from the beginning
222 * of MinMax table (may be NULL) */
223 Offset16To<BaseCoord>
224 maxCoord; /* Offset to BaseCoord table that defines
225 * maximum extent value, from the beginning
226 * of MinMax table (may be NULL) */
227 SortedArray16Of<FeatMinMaxRecord>
228 featMinMaxRecords;
229 /* Array of FeatMinMaxRecords, in alphabetical
230 * order by featureTableTag */
231 public:
232 DEFINE_SIZE_ARRAY (6, featMinMaxRecords);
233};
234
235struct BaseValues
236{
237 const BaseCoord &get_base_coord (int baseline_tag_index) const
238 {
239 if (baseline_tag_index == -1) baseline_tag_index = defaultIndex;
240 return this+baseCoords[baseline_tag_index];
241 }
242
243 bool sanitize (hb_sanitize_context_t *c) const
244 {
245 TRACE_SANITIZE (this);
246 return_trace (likely (c->check_struct (this) &&
247 baseCoords.sanitize (c, this)));
248 }
249
250 protected:
251 Index defaultIndex; /* Index number of default baseline for this
252 * script — equals index position of baseline tag
253 * in baselineTags array of the BaseTagList */
254 Array16OfOffset16To<BaseCoord>
255 baseCoords; /* Number of BaseCoord tables defined — should equal
256 * baseTagCount in the BaseTagList
257 *
258 * Array of offsets to BaseCoord tables, from beginning of
259 * BaseValues table — order matches baselineTags array in
260 * the BaseTagList */
261 public:
262 DEFINE_SIZE_ARRAY (4, baseCoords);
263};
264
265struct BaseLangSysRecord
266{
267 int cmp (hb_tag_t key) const { return baseLangSysTag.cmp (a: key); }
268
269 bool has_data () const { return baseLangSysTag; }
270
271 const MinMax &get_min_max () const { return this+minMax; }
272
273 bool sanitize (hb_sanitize_context_t *c, const void *base) const
274 {
275 TRACE_SANITIZE (this);
276 return_trace (likely (c->check_struct (this) &&
277 minMax.sanitize (c, this)));
278 }
279
280 protected:
281 Tag baseLangSysTag; /* 4-byte language system identification tag */
282 Offset16To<MinMax>
283 minMax; /* Offset to MinMax table, from beginning
284 * of BaseScript table */
285 public:
286 DEFINE_SIZE_STATIC (6);
287};
288
289struct BaseScript
290{
291 const MinMax &get_min_max (hb_tag_t language_tag) const
292 {
293 const BaseLangSysRecord& record = baseLangSysRecords.bsearch (x: language_tag);
294 return record.has_data () ? record.get_min_max () : this+defaultMinMax;
295 }
296
297 const BaseCoord &get_base_coord (int baseline_tag_index) const
298 { return (this+baseValues).get_base_coord (baseline_tag_index); }
299
300 bool has_data () const { return baseValues; }
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
327struct BaseScriptList;
328struct BaseScriptRecord
329{
330 int cmp (hb_tag_t key) const { return baseScriptTag.cmp (a: 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
354struct BaseScriptList
355{
356 const BaseScript &get_base_script (hb_tag_t script) const
357 {
358 const BaseScriptRecord *record = &baseScriptRecords.bsearch (x: script);
359 if (!record->has_data ()) record = &baseScriptRecords.bsearch (HB_TAG ('D','F','L','T'));
360 return record->has_data () ? record->get_base_script (list: 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
378struct 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: script_tag);
386 if (!base_script.has_data ())
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 (x: baseline_tag, i: &tag_index))
396 {
397 *coord = nullptr;
398 return false;
399 }
400 *coord = &base_script.get_base_coord (baseline_tag_index: 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: script_tag);
413 if (!base_script.has_data ())
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: min_coord, max: 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 (this+baseTagList).sanitize (c) &&
429 (this+baseScriptList).sanitize (c)));
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
448struct 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, var_store: get_var_store (), direction);
472
473 return true;
474 }
475
476 /* TODO: Expose this separately sometime? */
477 bool get_min_max (hb_font_t *font,
478 hb_direction_t direction,
479 hb_tag_t script_tag,
480 hb_tag_t language_tag,
481 hb_tag_t feature_tag,
482 hb_position_t *min,
483 hb_position_t *max)
484 {
485 const BaseCoord *min_coord, *max_coord;
486 if (!get_axis (direction).get_min_max (script_tag, language_tag, feature_tag,
487 min_coord: &min_coord, max_coord: &max_coord))
488 return false;
489
490 const VariationStore &var_store = get_var_store ();
491 if (likely (min && min_coord)) *min = min_coord->get_coord (font, var_store, direction);
492 if (likely (max && max_coord)) *max = max_coord->get_coord (font, var_store, direction);
493 return true;
494 }
495
496 bool sanitize (hb_sanitize_context_t *c) const
497 {
498 TRACE_SANITIZE (this);
499 return_trace (likely (c->check_struct (this) &&
500 likely (version.major == 1) &&
501 hAxis.sanitize (c, this) &&
502 vAxis.sanitize (c, this) &&
503 (version.to_int () < 0x00010001u || varStore.sanitize (c, this))));
504 }
505
506 protected:
507 FixedVersion<>version; /* Version of the BASE table */
508 Offset16To<Axis>hAxis; /* Offset to horizontal Axis table, from beginning
509 * of BASE table (may be NULL) */
510 Offset16To<Axis>vAxis; /* Offset to vertical Axis table, from beginning
511 * of BASE table (may be NULL) */
512 Offset32To<VariationStore>
513 varStore; /* Offset to the table of Item Variation
514 * Store--from beginning of BASE
515 * header (may be NULL). Introduced
516 * in version 0x00010001. */
517 public:
518 DEFINE_SIZE_MIN (8);
519};
520
521
522} /* namespace OT */
523
524
525#endif /* HB_OT_LAYOUT_BASE_TABLE_HH */
526

source code of flutter_engine/third_party/harfbuzz/src/hb-ot-layout-base-table.hh