1/*
2 * Copyright © 2016 Elie Roux <elie.roux@telecom-bretagne.eu>
3 * Copyright © 2018 Google, Inc.
4 *
5 * This is part of HarfBuzz, a text shaping library.
6 *
7 * Permission is hereby granted, without written agreement and without
8 * license or royalty fees, to use, copy, modify, and distribute this
9 * software and its documentation for any purpose, provided that the
10 * above copyright notice and the following two paragraphs appear in
11 * all copies of this software.
12 *
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17 * DAMAGE.
18 *
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24 *
25 * Google Author(s): Behdad Esfahbod
26 */
27
28#ifndef HB_OT_LAYOUT_BASE_TABLE_HH
29#define HB_OT_LAYOUT_BASE_TABLE_HH
30
31#include "hb-open-type.hh"
32#include "hb-ot-layout-common.hh"
33
34namespace OT {
35
36/*
37 * BASE -- Baseline
38 * https://docs.microsoft.com/en-us/typography/opentype/spec/base
39 */
40
41
42/* XXX Review this. */
43#define NOT_INDEXED ((unsigned int) -1)
44
45
46struct BaseCoordFormat1
47{
48 inline int get_coord (void) const { return coordinate; }
49
50 inline bool sanitize (hb_sanitize_context_t *c) const
51 {
52 TRACE_SANITIZE (this);
53 return_trace (c->check_struct (this));
54 }
55
56 protected:
57 HBUINT16 format; /* Format identifier--format = 1 */
58 FWORD coordinate; /* X or Y value, in design units */
59 public:
60 DEFINE_SIZE_STATIC (4);
61};
62
63struct BaseCoordFormat2
64{
65 inline int get_coord (void) const
66 {
67 /* TODO */
68 return coordinate;
69 }
70
71 inline bool sanitize (hb_sanitize_context_t *c) const
72 {
73 TRACE_SANITIZE (this);
74 return_trace (c->check_struct (this));
75 }
76
77 protected:
78 HBUINT16 format; /* Format identifier--format = 2 */
79 FWORD coordinate; /* X or Y value, in design units */
80 GlyphID referenceGlyph; /* Glyph ID of control glyph */
81 HBUINT16 coordPoint; /* Index of contour point on the
82 * reference glyph */
83 public:
84 DEFINE_SIZE_STATIC (8);
85};
86
87struct BaseCoordFormat3
88{
89 inline int get_coord (void) const
90 {
91 /* TODO */
92 return coordinate;
93 }
94
95 inline bool sanitize (hb_sanitize_context_t *c) const
96 {
97 TRACE_SANITIZE (this);
98 return_trace (c->check_struct (this) && deviceTable.sanitize (c, this));
99 }
100
101 protected:
102 HBUINT16 format; /* Format identifier--format = 3 */
103 FWORD coordinate; /* X or Y value, in design units */
104 OffsetTo<Device> deviceTable; /* Offset to Device table for X or
105 * Y value, from beginning of
106 * BaseCoord table (may be NULL). */
107 public:
108 DEFINE_SIZE_STATIC (6);
109};
110
111struct BaseCoord
112{
113 inline int get_coord (void) const
114 {
115 /* XXX wire up direction and font. */
116 switch (u.format) {
117 case 1: return u.format1.get_coord ();
118 case 2: return u.format2.get_coord ();
119 case 3: return u.format3.get_coord ();
120 default:return 0;
121 }
122 }
123
124 inline bool sanitize (hb_sanitize_context_t *c) const
125 {
126 TRACE_SANITIZE (this);
127 if (!u.format.sanitize (c)) return_trace (false);
128 switch (u.format) {
129 case 1: return_trace (u.format1.sanitize (c));
130 case 2: return_trace (u.format2.sanitize (c));
131 case 3: return_trace (u.format3.sanitize (c));
132 default:return_trace (false);
133 }
134 }
135
136 protected:
137 union {
138 HBUINT16 format;
139 BaseCoordFormat1 format1;
140 BaseCoordFormat2 format2;
141 BaseCoordFormat3 format3;
142 } u;
143 public:
144 DEFINE_SIZE_UNION (2, format);
145};
146
147struct FeatMinMaxRecord
148{
149 inline int get_min_value (void) const { return (this+minCoord).get_coord(); }
150 inline int get_max_value (void) const { return (this+maxCoord).get_coord(); }
151
152 inline const Tag& get_tag () const { return tag; }
153
154 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
155 {
156 TRACE_SANITIZE (this);
157 return_trace (c->check_struct (this) &&
158 minCoord.sanitize (c, base) &&
159 maxCoord.sanitize (c, base));
160 }
161
162 protected:
163 Tag tag; /* 4-byte feature identification tag--must
164 * match feature tag in FeatureList */
165 OffsetTo<BaseCoord> minCoord; /* Offset to BaseCoord table that defines
166 * the minimum extent value, from beginning
167 * of MinMax table (may be NULL) */
168 OffsetTo<BaseCoord> maxCoord; /* Offset to BaseCoord table that defines
169 * the maximum extent value, from beginning
170 * of MinMax table (may be NULL) */
171 public:
172 DEFINE_SIZE_STATIC (8);
173
174};
175
176struct MinMax
177{
178 inline unsigned int get_feature_tag_index (Tag featureTableTag) const
179 {
180 /* TODO bsearch */
181 unsigned int count = featMinMaxRecords.len;
182 for (unsigned int i = 0; i < count; i++)
183 {
184 Tag tag = featMinMaxRecords[i].get_tag ();
185 int cmp = tag.cmp(featureTableTag);
186 if (cmp == 0) return i;
187 if (cmp > 0) return NOT_INDEXED;
188 }
189 return NOT_INDEXED;
190 }
191
192 inline int get_min_value (unsigned int featureTableTagIndex) const
193 {
194 if (featureTableTagIndex == NOT_INDEXED)
195 return (this+minCoord).get_coord();
196 return featMinMaxRecords[featureTableTagIndex].get_min_value();
197 }
198
199 inline int get_max_value (unsigned int featureTableTagIndex) const
200 {
201 if (featureTableTagIndex == NOT_INDEXED)
202 return (this+maxCoord).get_coord();
203 return featMinMaxRecords[featureTableTagIndex].get_max_value();
204 }
205
206 inline bool sanitize (hb_sanitize_context_t *c) const
207 {
208 TRACE_SANITIZE (this);
209 return_trace (c->check_struct (this) &&
210 minCoord.sanitize (c, this) &&
211 maxCoord.sanitize (c, this) &&
212 featMinMaxRecords.sanitize (c, this));
213 }
214
215 protected:
216 OffsetTo<BaseCoord> minCoord; /* Offset to BaseCoord table that defines
217 * minimum extent value, from the beginning
218 * of MinMax table (may be NULL) */
219 OffsetTo<BaseCoord> maxCoord; /* Offset to BaseCoord table that defines
220 * maximum extent value, from the beginning
221 * of MinMax table (may be NULL) */
222 ArrayOf<FeatMinMaxRecord>
223 featMinMaxRecords; /* Array of FeatMinMaxRecords, in alphabetical
224 * order by featureTableTag */
225 public:
226 DEFINE_SIZE_ARRAY (6, featMinMaxRecords);
227};
228
229/* TODO... */
230struct BaseLangSysRecord
231{
232 inline const Tag& get_tag(void) const
233 { return baseLangSysTag; }
234
235 inline unsigned int get_feature_tag_index (Tag featureTableTag) const
236 { return (this+minMax).get_feature_tag_index( featureTableTag); }
237
238 inline int get_min_value (unsigned int featureTableTagIndex) const
239 { return (this+minMax).get_min_value( featureTableTagIndex); }
240
241 inline int get_max_value (unsigned int featureTableTagIndex) const
242 { return (this+minMax).get_max_value (featureTableTagIndex); }
243
244 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
245 {
246 TRACE_SANITIZE (this);
247 return_trace (c->check_struct (this) &&
248 minMax.sanitize (c, base));
249 }
250
251 protected:
252 Tag baseLangSysTag;
253 OffsetTo<MinMax> minMax;
254 public:
255 DEFINE_SIZE_STATIC (6);
256
257};
258
259struct BaseValues
260{
261 inline unsigned int get_default_base_tag_index (void) const
262 { return defaultIndex; }
263
264 inline int get_base_coord (unsigned int baselineTagIndex) const
265 {
266 return (this+baseCoords[baselineTagIndex]).get_coord ();
267 }
268
269 inline bool sanitize (hb_sanitize_context_t *c) const
270 {
271 TRACE_SANITIZE (this);
272 return_trace (c->check_struct (this) &&
273 baseCoords.sanitize (c, this));
274 }
275
276 protected:
277 Index defaultIndex;
278 OffsetArrayOf<BaseCoord> baseCoords;
279 public:
280 DEFINE_SIZE_ARRAY (4, baseCoords);
281};
282
283struct BaseScript {
284
285 inline unsigned int get_lang_tag_index (Tag baseLangSysTag) const
286 {
287 /* XXX bsearch */
288 Tag tag;
289 int cmp;
290 unsigned int count = baseLangSysRecords.len;
291 for (unsigned int i = 0; i < count; i++)
292 {
293 tag = baseLangSysRecords[i].get_tag ();
294 // taking advantage of alphabetical order
295 cmp = tag.cmp(baseLangSysTag);
296 if (cmp == 0) return i;
297 if (cmp > 0) return NOT_INDEXED;
298 }
299 return NOT_INDEXED;
300 }
301
302 inline unsigned int get_feature_tag_index (unsigned int baseLangSysIndex, Tag featureTableTag) const
303 {
304 if (baseLangSysIndex == NOT_INDEXED)
305 {
306 if (unlikely(defaultMinMax)) return NOT_INDEXED;
307 return (this+defaultMinMax).get_feature_tag_index (featureTableTag);
308 }
309 return baseLangSysRecords[baseLangSysIndex].get_feature_tag_index (featureTableTag);
310 }
311
312 inline int get_min_value (unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
313 {
314 if (baseLangSysIndex == NOT_INDEXED)
315 return (this+defaultMinMax).get_min_value (featureTableTagIndex);
316 return baseLangSysRecords[baseLangSysIndex].get_max_value (featureTableTagIndex);
317 }
318
319 inline int get_max_value (unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
320 {
321 if (baseLangSysIndex == NOT_INDEXED)
322 return (this+defaultMinMax).get_min_value (featureTableTagIndex);
323 return baseLangSysRecords[baseLangSysIndex].get_max_value (featureTableTagIndex);
324 }
325
326 inline unsigned int get_default_base_tag_index (void) const
327 { return (this+baseValues).get_default_base_tag_index (); }
328
329 inline int get_base_coord (unsigned int baselineTagIndex) const
330 { return (this+baseValues).get_base_coord (baselineTagIndex); }
331
332 inline bool sanitize (hb_sanitize_context_t *c) const
333 {
334 TRACE_SANITIZE (this);
335 return_trace (c->check_struct (this) &&
336 baseValues.sanitize (c, this) &&
337 defaultMinMax.sanitize (c, this) &&
338 baseLangSysRecords.sanitize (c, this));
339 }
340
341 protected:
342 OffsetTo<BaseValues> baseValues;
343 OffsetTo<MinMax> defaultMinMax;
344 ArrayOf<BaseLangSysRecord> baseLangSysRecords;
345
346 public:
347 DEFINE_SIZE_ARRAY (6, baseLangSysRecords);
348};
349
350
351struct BaseScriptRecord {
352
353 inline const Tag& get_tag (void) const
354 { return baseScriptTag; }
355
356 inline unsigned int get_default_base_tag_index(void) const
357 { return (this+baseScript).get_default_base_tag_index (); }
358
359 inline int get_base_coord(unsigned int baselineTagIndex) const
360 { return (this+baseScript).get_base_coord (baselineTagIndex); }
361
362 inline unsigned int get_lang_tag_index (Tag baseLangSysTag) const
363 { return (this+baseScript).get_lang_tag_index (baseLangSysTag); }
364
365 inline unsigned int get_feature_tag_index (unsigned int baseLangSysIndex, Tag featureTableTag) const
366 { return (this+baseScript).get_feature_tag_index (baseLangSysIndex, featureTableTag); }
367
368 inline int get_max_value (unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
369 { return (this+baseScript).get_max_value (baseLangSysIndex, featureTableTagIndex); }
370
371 inline int get_min_value (unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
372 { return (this+baseScript).get_min_value (baseLangSysIndex, featureTableTagIndex); }
373
374 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
375 {
376 TRACE_SANITIZE (this);
377 return_trace (c->check_struct (this) &&
378 baseScript.sanitize (c, base));
379 }
380
381 protected:
382 Tag baseScriptTag;
383 OffsetTo<BaseScript> baseScript;
384
385 public:
386 DEFINE_SIZE_STATIC (6);
387};
388
389struct BaseScriptList {
390
391 inline unsigned int get_base_script_index (Tag baseScriptTag) const
392 {
393 /* XXX bsearch? */
394 unsigned int count = baseScriptRecords.len;
395 for (unsigned int i = 0; i < count; i++)
396 if (baseScriptRecords[i].get_tag() == baseScriptTag)
397 return i;
398 return NOT_INDEXED;
399 }
400
401 inline unsigned int get_default_base_tag_index (unsigned int baseScriptIndex) const
402 {
403 return baseScriptRecords[baseScriptIndex].get_default_base_tag_index();
404 }
405
406 inline int get_base_coord(unsigned int baseScriptIndex, unsigned int baselineTagIndex) const
407 {
408 return baseScriptRecords[baseScriptIndex].get_base_coord(baselineTagIndex);
409 }
410
411 inline unsigned int get_lang_tag_index (unsigned int baseScriptIndex, Tag baseLangSysTag) const
412 {
413 return baseScriptRecords[baseScriptIndex].get_lang_tag_index(baseLangSysTag);
414 }
415
416 inline unsigned int get_feature_tag_index (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, Tag featureTableTag) const
417 {
418 return baseScriptRecords[baseScriptIndex].get_feature_tag_index(baseLangSysIndex, featureTableTag);
419 }
420
421 inline int get_max_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
422 {
423 return baseScriptRecords[baseScriptIndex].get_max_value(baseLangSysIndex, featureTableTagIndex);
424 }
425
426 inline int get_min_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
427 {
428 return baseScriptRecords[baseScriptIndex].get_min_value(baseLangSysIndex, featureTableTagIndex);
429 }
430
431 inline bool sanitize (hb_sanitize_context_t *c) const
432 {
433 TRACE_SANITIZE (this);
434 return_trace (c->check_struct (this) &&
435 baseScriptRecords.sanitize (c, this));
436 }
437
438 protected:
439 ArrayOf<BaseScriptRecord> baseScriptRecords;
440
441 public:
442 DEFINE_SIZE_ARRAY (2, baseScriptRecords);
443};
444
445struct BaseTagList
446{
447 inline unsigned int get_tag_index (Tag baselineTag) const
448 {
449 /* TODO bsearch? */
450 unsigned int count = baselineTags.len;
451 for (unsigned int i = 0; i < count; i++)
452 if (baselineTags[i] == baselineTag)
453 return i;
454 return NOT_INDEXED;
455 }
456
457 inline bool sanitize (hb_sanitize_context_t *c) const
458 {
459 TRACE_SANITIZE (this);
460 return_trace (c->check_struct (this));
461 }
462
463 protected:
464 SortedArrayOf<Tag> baselineTags;
465
466 public:
467 DEFINE_SIZE_ARRAY (2, baselineTags);
468};
469
470struct Axis
471{
472
473 inline unsigned int get_base_tag_index (Tag baselineTag) const
474 {
475 return (this+baseTagList).get_tag_index(baselineTag);
476 }
477
478 inline unsigned int get_default_base_tag_index_for_script_index (unsigned int baseScriptIndex) const
479 {
480 return (this+baseScriptList).get_default_base_tag_index(baseScriptIndex);
481 }
482
483 inline int get_base_coord (unsigned int baseScriptIndex, unsigned int baselineTagIndex) const
484 {
485 return (this+baseScriptList).get_base_coord(baseScriptIndex, baselineTagIndex);
486 }
487
488 inline unsigned int get_lang_tag_index (unsigned int baseScriptIndex, Tag baseLangSysTag) const
489 {
490 return (this+baseScriptList).get_lang_tag_index(baseScriptIndex, baseLangSysTag);
491 }
492
493 inline unsigned int get_feature_tag_index (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, Tag featureTableTag) const
494 {
495 return (this+baseScriptList).get_feature_tag_index(baseScriptIndex, baseLangSysIndex, featureTableTag);
496 }
497
498 inline int get_max_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
499 {
500 return (this+baseScriptList).get_max_value(baseScriptIndex, baseLangSysIndex, featureTableTagIndex);
501 }
502
503 inline int get_min_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
504 {
505 return (this+baseScriptList).get_min_value(baseScriptIndex, baseLangSysIndex, featureTableTagIndex);
506 }
507
508 inline bool sanitize (hb_sanitize_context_t *c) const
509 {
510 TRACE_SANITIZE (this);
511 return_trace (c->check_struct (this) &&
512 baseTagList.sanitize (c, this) &&
513 baseScriptList.sanitize (c, this));
514 }
515
516 protected:
517 OffsetTo<BaseTagList> baseTagList;
518 OffsetTo<BaseScriptList> baseScriptList;
519
520 public:
521 DEFINE_SIZE_STATIC (4);
522};
523
524struct BASE
525{
526 static const hb_tag_t tableTag = HB_OT_TAG_BASE;
527
528 inline bool has_v_axis(void) { return vAxis != 0; }
529
530 inline bool has_h_axis(void) { return hAxis != 0; }
531
532 inline unsigned int get_h_base_tag_index (Tag baselineTag) const
533 {
534 return (this+hAxis).get_base_tag_index(baselineTag);
535 }
536
537 inline unsigned int get_h_default_base_tag_index_for_script_index (unsigned int baseScriptIndex) const
538 {
539 return (this+hAxis).get_default_base_tag_index_for_script_index(baseScriptIndex);
540 }
541
542 inline int get_h_base_coord(unsigned int baseScriptIndex, unsigned int baselineTagIndex) const
543 {
544 return (this+hAxis).get_base_coord(baseScriptIndex, baselineTagIndex);
545 }
546
547 inline unsigned int get_v_base_tag_index(Tag baselineTag) const
548 {
549 return (this+vAxis).get_base_tag_index(baselineTag);
550 }
551
552 inline unsigned int get_v_default_base_tag_index_for_script_index (unsigned int baseScriptIndex) const
553 {
554 return (this+vAxis).get_default_base_tag_index_for_script_index(baseScriptIndex);
555 }
556
557 inline int get_v_base_coord(unsigned int baseScriptIndex, unsigned int baselineTagIndex) const
558 {
559 return (this+vAxis).get_base_coord(baseScriptIndex, baselineTagIndex);
560 }
561
562 inline unsigned int get_h_lang_tag_index (unsigned int baseScriptIndex, Tag baseLangSysTag) const
563 {
564 return (this+hAxis).get_lang_tag_index (baseScriptIndex, baseLangSysTag);
565 }
566
567 inline unsigned int get_h_feature_tag_index (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, Tag featureTableTag) const
568 {
569 return (this+hAxis).get_feature_tag_index (baseScriptIndex, baseLangSysIndex, featureTableTag);
570 }
571
572 inline int get_h_max_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
573 {
574 return (this+hAxis).get_max_value (baseScriptIndex, baseLangSysIndex, featureTableTagIndex);
575 }
576
577 inline int get_h_min_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
578 {
579 return (this+hAxis).get_min_value (baseScriptIndex, baseLangSysIndex, featureTableTagIndex);
580 }
581
582 inline unsigned int get_v_lang_tag_index (unsigned int baseScriptIndex, Tag baseLangSysTag) const
583 {
584 return (this+vAxis).get_lang_tag_index (baseScriptIndex, baseLangSysTag);
585 }
586
587 inline unsigned int get_v_feature_tag_index (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, Tag featureTableTag) const
588 {
589 return (this+vAxis).get_feature_tag_index (baseScriptIndex, baseLangSysIndex, featureTableTag);
590 }
591
592 inline int get_v_max_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
593 {
594 return (this+vAxis).get_max_value (baseScriptIndex, baseLangSysIndex, featureTableTagIndex);
595 }
596
597 inline int get_v_min_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
598 {
599 return (this+vAxis).get_min_value (baseScriptIndex, baseLangSysIndex, featureTableTagIndex);
600 }
601
602 inline bool sanitize (hb_sanitize_context_t *c) const
603 {
604 TRACE_SANITIZE (this);
605 return_trace (c->check_struct (this) &&
606 likely (version.major == 1) &&
607 hAxis.sanitize (c, this) &&
608 vAxis.sanitize (c, this) &&
609 (version.to_int () < 0x00010001u || varStore.sanitize (c, this)));
610 }
611
612 protected:
613 FixedVersion<> version;
614 OffsetTo<Axis> hAxis;
615 OffsetTo<Axis> vAxis;
616 LOffsetTo<VariationStore>
617 varStore; /* Offset to the table of Item Variation
618 * Store--from beginning of BASE
619 * header (may be NULL). Introduced
620 * in version 0x00010001. */
621 public:
622 DEFINE_SIZE_MIN (8);
623};
624
625
626} /* namespace OT */
627
628
629#endif /* HB_OT_LAYOUT_BASE_TABLE_HH */
630