2 * Copyright © 2007,2008,2009 Red Hat, Inc.
3 * Copyright © 2010,2012 Google, Inc.
5 * This is part of HarfBuzz, a text shaping library.
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.
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
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.
25 * Red Hat Author(s): Behdad Esfahbod
26 * Google Author(s): Behdad Esfahbod
29 #ifndef HB_OT_LAYOUT_COMMON_PRIVATE_HH
30 #define HB_OT_LAYOUT_COMMON_PRIVATE_HH
32 #include "hb-ot-layout-private.hh"
33 #include "hb-open-type-private.hh"
34 #include "hb-set-private.hh"
40 #define NOT_COVERED ((unsigned int) -1)
41 #define MAX_NESTING_LEVEL 8
42 #define MAX_CONTEXT_LENGTH 64
48 * OpenType Layout Common Table Formats
54 * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList
57 template <typename Type
>
60 inline int cmp (hb_tag_t a
) const {
64 struct sanitize_closure_t
{
68 inline bool sanitize (hb_sanitize_context_t
*c
, void *base
) {
69 TRACE_SANITIZE (this);
70 const sanitize_closure_t closure
= {tag
, base
};
71 return TRACE_RETURN (c
->check_struct (this) && offset
.sanitize (c
, base
, &closure
));
74 Tag tag
; /* 4-byte Tag identifier */
76 offset
; /* Offset from beginning of object holding
79 DEFINE_SIZE_STATIC (6);
82 template <typename Type
>
83 struct RecordArrayOf
: SortedArrayOf
<Record
<Type
> > {
84 inline const Tag
& get_tag (unsigned int i
) const
86 /* We cheat slightly and don't define separate Null objects
87 * for Record types. Instead, we return the correct Null(Tag)
89 if (unlikely (i
>= this->len
)) return Null(Tag
);
90 return (*this)[i
].tag
;
92 inline unsigned int get_tags (unsigned int start_offset
,
93 unsigned int *record_count
/* IN/OUT */,
94 hb_tag_t
*record_tags
/* OUT */) const
97 const Record
<Type
> *arr
= this->sub_array (start_offset
, record_count
);
98 unsigned int count
= *record_count
;
99 for (unsigned int i
= 0; i
< count
; i
++)
100 record_tags
[i
] = arr
[i
].tag
;
104 inline bool find_index (hb_tag_t tag
, unsigned int *index
) const
106 /* If we want to allow non-sorted data, we can lsearch(). */
107 int i
= this->/*lsearch*/bsearch (tag
);
109 if (index
) *index
= i
;
112 if (index
) *index
= Index::NOT_FOUND_INDEX
;
118 template <typename Type
>
119 struct RecordListOf
: RecordArrayOf
<Type
>
121 inline const Type
& operator [] (unsigned int i
) const
122 { return this+RecordArrayOf
<Type
>::operator [](i
).offset
; }
124 inline bool sanitize (hb_sanitize_context_t
*c
) {
125 TRACE_SANITIZE (this);
126 return TRACE_RETURN (RecordArrayOf
<Type
>::sanitize (c
, this));
133 inline int cmp (hb_codepoint_t g
) const {
134 return g
< start
? -1 : g
<= end
? 0 : +1 ;
137 inline bool sanitize (hb_sanitize_context_t
*c
) {
138 TRACE_SANITIZE (this);
139 return TRACE_RETURN (c
->check_struct (this));
142 inline bool intersects (const hb_set_t
*glyphs
) const {
143 return glyphs
->intersects (start
, end
);
146 template <typename set_t
>
147 inline void add_coverage (set_t
*glyphs
) const {
148 glyphs
->add_range (start
, end
);
151 GlyphID start
; /* First GlyphID in the range */
152 GlyphID end
; /* Last GlyphID in the range */
153 USHORT value
; /* Value */
155 DEFINE_SIZE_STATIC (6);
157 DEFINE_NULL_DATA (RangeRecord
, "\000\001");
160 struct IndexArray
: ArrayOf
<Index
>
162 inline unsigned int get_indexes (unsigned int start_offset
,
163 unsigned int *_count
/* IN/OUT */,
164 unsigned int *_indexes
/* OUT */) const
167 const USHORT
*arr
= this->sub_array (start_offset
, _count
);
168 unsigned int count
= *_count
;
169 for (unsigned int i
= 0; i
< count
; i
++)
170 _indexes
[i
] = arr
[i
];
184 inline unsigned int get_feature_count (void) const
185 { return featureIndex
.len
; }
186 inline hb_tag_t
get_feature_index (unsigned int i
) const
187 { return featureIndex
[i
]; }
188 inline unsigned int get_feature_indexes (unsigned int start_offset
,
189 unsigned int *feature_count
/* IN/OUT */,
190 unsigned int *feature_indexes
/* OUT */) const
191 { return featureIndex
.get_indexes (start_offset
, feature_count
, feature_indexes
); }
193 inline bool has_required_feature (void) const { return reqFeatureIndex
!= 0xFFFFu
; }
194 inline unsigned int get_required_feature_index (void) const
196 if (reqFeatureIndex
== 0xFFFFu
)
197 return Index::NOT_FOUND_INDEX
;
198 return reqFeatureIndex
;;
201 inline bool sanitize (hb_sanitize_context_t
*c
,
202 const Record
<LangSys
>::sanitize_closure_t
* = NULL
) {
203 TRACE_SANITIZE (this);
204 return TRACE_RETURN (c
->check_struct (this) && featureIndex
.sanitize (c
));
207 Offset
<> lookupOrderZ
; /* = Null (reserved for an offset to a
208 * reordering table) */
209 USHORT reqFeatureIndex
;/* Index of a feature required for this
210 * language system--if no required features
212 IndexArray featureIndex
; /* Array of indices into the FeatureList */
214 DEFINE_SIZE_ARRAY (6, featureIndex
);
216 DEFINE_NULL_DATA (LangSys
, "\0\0\xFF\xFF");
221 inline unsigned int get_lang_sys_count (void) const
222 { return langSys
.len
; }
223 inline const Tag
& get_lang_sys_tag (unsigned int i
) const
224 { return langSys
.get_tag (i
); }
225 inline unsigned int get_lang_sys_tags (unsigned int start_offset
,
226 unsigned int *lang_sys_count
/* IN/OUT */,
227 hb_tag_t
*lang_sys_tags
/* OUT */) const
228 { return langSys
.get_tags (start_offset
, lang_sys_count
, lang_sys_tags
); }
229 inline const LangSys
& get_lang_sys (unsigned int i
) const
231 if (i
== Index::NOT_FOUND_INDEX
) return get_default_lang_sys ();
232 return this+langSys
[i
].offset
;
234 inline bool find_lang_sys_index (hb_tag_t tag
, unsigned int *index
) const
235 { return langSys
.find_index (tag
, index
); }
237 inline bool has_default_lang_sys (void) const { return defaultLangSys
!= 0; }
238 inline const LangSys
& get_default_lang_sys (void) const { return this+defaultLangSys
; }
240 inline bool sanitize (hb_sanitize_context_t
*c
,
241 const Record
<Script
>::sanitize_closure_t
* = NULL
) {
242 TRACE_SANITIZE (this);
243 return TRACE_RETURN (defaultLangSys
.sanitize (c
, this) && langSys
.sanitize (c
, this));
248 defaultLangSys
; /* Offset to DefaultLangSys table--from
249 * beginning of Script table--may be Null */
250 RecordArrayOf
<LangSys
>
251 langSys
; /* Array of LangSysRecords--listed
252 * alphabetically by LangSysTag */
254 DEFINE_SIZE_ARRAY (4, langSys
);
257 typedef RecordListOf
<Script
> ScriptList
;
260 /* http://www.microsoft.com/typography/otspec/features_pt.htm#size */
261 struct FeatureParamsSize
263 inline bool sanitize (hb_sanitize_context_t
*c
) {
264 TRACE_SANITIZE (this);
265 if (unlikely (!c
->check_struct (this))) return TRACE_RETURN (false);
267 /* This subtable has some "history", if you will. Some earlier versions of
268 * Adobe tools calculated the offset of the FeatureParams sutable from the
269 * beginning of the FeatureList table! Now, that is dealt with in the
270 * Feature implementation. But we still need to be able to tell junk from
271 * real data. Note: We don't check that the nameID actually exists.
273 * Read Roberts wrote on 9/15/06 on opentype-list@indx.co.uk :
275 * Yes, it is correct that a new version of the AFDKO (version 2.0) will be
276 * coming out soon, and that the makeotf program will build a font with a
277 * 'size' feature that is correct by the specification.
279 * The specification for this feature tag is in the "OpenType Layout Tag
280 * Registry". You can see a copy of this at:
281 * http://partners.adobe.com/public/developer/opentype/index_tag8.html#size
283 * Here is one set of rules to determine if the 'size' feature is built
284 * correctly, or as by the older versions of MakeOTF. You may be able to do
287 * Assume that the offset to the size feature is according to specification,
288 * and make the following value checks. If it fails, assume the the size
289 * feature is calculated as versions of MakeOTF before the AFDKO 2.0 built it.
290 * If this fails, reject the 'size' feature. The older makeOTF's calculated the
291 * offset from the beginning of the FeatureList table, rather than from the
292 * beginning of the 'size' Feature table.
294 * If "design size" == 0:
297 * Else if ("subfamily identifier" == 0 and
298 * "range start" == 0 and
299 * "range end" == 0 and
300 * "range start" == 0 and
301 * "menu name ID" == 0)
302 * passes check: this is the format used when there is a design size
303 * specified, but there is no recommended size range.
305 * Else if ("design size" < "range start" or
306 * "design size" > "range end" or
307 * "range end" <= "range start" or
308 * "menu name ID" < 256 or
309 * "menu name ID" > 32767 or
310 * menu name ID is not a name ID which is actually in the name table)
317 return TRACE_RETURN (false);
318 else if (subfamilyID
== 0 &&
319 subfamilyNameID
== 0 &&
322 return TRACE_RETURN (true);
323 else if (designSize
< rangeStart
||
324 designSize
> rangeEnd
||
325 subfamilyNameID
< 256 ||
326 subfamilyNameID
> 32767)
327 return TRACE_RETURN (false);
329 return TRACE_RETURN (true);
332 USHORT designSize
; /* Represents the design size in 720/inch
333 * units (decipoints). The design size entry
334 * must be non-zero. When there is a design
335 * size but no recommended size range, the
336 * rest of the array will consist of zeros. */
337 USHORT subfamilyID
; /* Has no independent meaning, but serves
338 * as an identifier that associates fonts
339 * in a subfamily. All fonts which share a
340 * Preferred or Font Family name and which
341 * differ only by size range shall have the
342 * same subfamily value, and no fonts which
343 * differ in weight or style shall have the
344 * same subfamily value. If this value is
345 * zero, the remaining fields in the array
346 * will be ignored. */
347 USHORT subfamilyNameID
;/* If the preceding value is non-zero, this
348 * value must be set in the range 256 - 32767
349 * (inclusive). It records the value of a
350 * field in the name table, which must
351 * contain English-language strings encoded
352 * in Windows Unicode and Macintosh Roman,
353 * and may contain additional strings
354 * localized to other scripts and languages.
355 * Each of these strings is the name an
356 * application should use, in combination
357 * with the family name, to represent the
358 * subfamily in a menu. Applications will
359 * choose the appropriate version based on
360 * their selection criteria. */
361 USHORT rangeStart
; /* Large end of the recommended usage range
362 * (inclusive), stored in 720/inch units
364 USHORT rangeEnd
; /* Small end of the recommended usage range
365 (exclusive), stored in 720/inch units
368 DEFINE_SIZE_STATIC (10);
371 /* http://www.microsoft.com/typography/otspec/features_pt.htm#ssxx */
372 struct FeatureParamsStylisticSet
374 inline bool sanitize (hb_sanitize_context_t
*c
) {
375 TRACE_SANITIZE (this);
376 /* Right now minorVersion is at zero. Which means, any table supports
377 * the uiNameID field. */
378 return TRACE_RETURN (c
->check_struct (this));
381 USHORT version
; /* (set to 0): This corresponds to a “minor”
382 * version number. Additional data may be
383 * added to the end of this Feature Parameters
384 * table in the future. */
386 USHORT uiNameID
; /* The 'name' table name ID that specifies a
387 * string (or strings, for multiple languages)
388 * for a user-interface label for this
389 * feature. The values of uiLabelNameId and
390 * sampleTextNameId are expected to be in the
391 * font-specific name ID range (256-32767),
392 * though that is not a requirement in this
393 * Feature Parameters specification. The
394 * user-interface label for the feature can
395 * be provided in multiple languages. An
396 * English string should be included as a
397 * fallback. The string should be kept to a
398 * minimal length to fit comfortably with
399 * different application interfaces. */
401 DEFINE_SIZE_STATIC (4);
404 /* http://www.microsoft.com/typography/otspec/features_ae.htm#cv01-cv99 */
405 struct FeatureParamsCharacterVariants
407 inline bool sanitize (hb_sanitize_context_t
*c
) {
408 TRACE_SANITIZE (this);
409 return TRACE_RETURN (c
->check_struct (this) &&
410 characters
.sanitize (c
));
413 USHORT format
; /* Format number is set to 0. */
414 USHORT featUILableNameID
; /* The ‘name’ table name ID that
415 * specifies a string (or strings,
416 * for multiple languages) for a
417 * user-interface label for this
418 * feature. (May be NULL.) */
419 USHORT featUITooltipTextNameID
;/* The ‘name’ table name ID that
420 * specifies a string (or strings,
421 * for multiple languages) that an
422 * application can use for tooltip
423 * text for this feature. (May be
425 USHORT sampleTextNameID
; /* The ‘name’ table name ID that
426 * specifies sample text that
427 * illustrates the effect of this
428 * feature. (May be NULL.) */
429 USHORT numNamedParameters
; /* Number of named parameters. (May
431 USHORT firstParamUILabelNameID
;/* The first ‘name’ table name ID
432 * used to specify strings for
433 * user-interface labels for the
434 * feature parameters. (Must be zero
435 * if numParameters is zero.) */
437 characters
; /* Array of the Unicode Scalar Value
438 * of the characters for which this
439 * feature provides glyph variants.
442 DEFINE_SIZE_ARRAY (14, characters
);
447 inline bool sanitize (hb_sanitize_context_t
*c
, hb_tag_t tag
) {
448 TRACE_SANITIZE (this);
449 if (tag
== HB_TAG ('s','i','z','e'))
450 return TRACE_RETURN (u
.size
.sanitize (c
));
451 if ((tag
& 0xFFFF0000u
) == HB_TAG ('s','s','\0','\0')) /* ssXX */
452 return TRACE_RETURN (u
.stylisticSet
.sanitize (c
));
453 if ((tag
& 0xFFFF0000u
) == HB_TAG ('c','v','\0','\0')) /* cvXX */
454 return TRACE_RETURN (u
.characterVariants
.sanitize (c
));
455 return TRACE_RETURN (true);
458 inline const FeatureParamsSize
& get_size_params (hb_tag_t tag
) const
460 if (tag
== HB_TAG ('s','i','z','e'))
462 return Null(FeatureParamsSize
);
467 FeatureParamsSize size
;
468 FeatureParamsStylisticSet stylisticSet
;
469 FeatureParamsCharacterVariants characterVariants
;
471 DEFINE_SIZE_STATIC (17);
476 inline unsigned int get_lookup_count (void) const
477 { return lookupIndex
.len
; }
478 inline hb_tag_t
get_lookup_index (unsigned int i
) const
479 { return lookupIndex
[i
]; }
480 inline unsigned int get_lookup_indexes (unsigned int start_index
,
481 unsigned int *lookup_count
/* IN/OUT */,
482 unsigned int *lookup_tags
/* OUT */) const
483 { return lookupIndex
.get_indexes (start_index
, lookup_count
, lookup_tags
); }
485 inline const FeatureParams
&get_feature_params (void) const
486 { return this+featureParams
; }
488 inline bool sanitize (hb_sanitize_context_t
*c
,
489 const Record
<Feature
>::sanitize_closure_t
*closure
) {
490 TRACE_SANITIZE (this);
491 if (unlikely (!(c
->check_struct (this) && lookupIndex
.sanitize (c
))))
492 return TRACE_RETURN (false);
494 /* Some earlier versions of Adobe tools calculated the offset of the
495 * FeatureParams subtable from the beginning of the FeatureList table!
497 * If sanitizing "failed" for the FeatureParams subtable, try it with the
498 * alternative location. We would know sanitize "failed" if old value
499 * of the offset was non-zero, but it's zeroed now.
501 * Only do this for the 'size' feature, since at the time of the faulty
502 * Adobe tools, only the 'size' feature had FeatureParams defined.
505 OffsetTo
<FeatureParams
> orig_offset
= featureParams
;
506 if (unlikely (!featureParams
.sanitize (c
, this, closure
? closure
->tag
: HB_TAG_NONE
)))
507 return TRACE_RETURN (false);
509 if (likely (orig_offset
.is_null ()))
510 return TRACE_RETURN (true);
512 if (featureParams
== 0 && closure
&&
513 closure
->tag
== HB_TAG ('s','i','z','e') &&
514 closure
->list_base
&& closure
->list_base
< this)
516 unsigned int new_offset_int
= (unsigned int) orig_offset
-
517 (((char *) this) - ((char *) closure
->list_base
));
519 OffsetTo
<FeatureParams
> new_offset
;
520 /* Check that it did not overflow. */
521 new_offset
.set (new_offset_int
);
522 if (new_offset
== new_offset_int
&&
523 c
->try_set (&featureParams
, new_offset
) &&
524 !featureParams
.sanitize (c
, this, closure
? closure
->tag
: HB_TAG_NONE
))
525 return TRACE_RETURN (false);
528 return TRACE_RETURN (true);
531 OffsetTo
<FeatureParams
>
532 featureParams
; /* Offset to Feature Parameters table (if one
533 * has been defined for the feature), relative
534 * to the beginning of the Feature Table; = Null
536 IndexArray lookupIndex
; /* Array of LookupList indices */
538 DEFINE_SIZE_ARRAY (4, lookupIndex
);
541 typedef RecordListOf
<Feature
> FeatureList
;
544 struct LookupFlag
: USHORT
547 RightToLeft
= 0x0001u
,
548 IgnoreBaseGlyphs
= 0x0002u
,
549 IgnoreLigatures
= 0x0004u
,
550 IgnoreMarks
= 0x0008u
,
551 IgnoreFlags
= 0x000Eu
,
552 UseMarkFilteringSet
= 0x0010u
,
554 MarkAttachmentType
= 0xFF00u
557 DEFINE_SIZE_STATIC (2);
562 inline unsigned int get_subtable_count (void) const { return subTable
.len
; }
564 inline unsigned int get_type (void) const { return lookupType
; }
566 /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and
567 * higher 16-bit is mark-filtering-set if the lookup uses one.
568 * Not to be confused with glyph_props which is very similar. */
569 inline uint32_t get_props (void) const
571 unsigned int flag
= lookupFlag
;
572 if (unlikely (flag
& LookupFlag::UseMarkFilteringSet
))
574 const USHORT
&markFilteringSet
= StructAfter
<USHORT
> (subTable
);
575 flag
+= (markFilteringSet
<< 16);
580 inline bool serialize (hb_serialize_context_t
*c
,
581 unsigned int lookup_type
,
582 uint32_t lookup_props
,
583 unsigned int num_subtables
)
585 TRACE_SERIALIZE (this);
586 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
587 lookupType
.set (lookup_type
);
588 lookupFlag
.set (lookup_props
& 0xFFFFu
);
589 if (unlikely (!subTable
.serialize (c
, num_subtables
))) return TRACE_RETURN (false);
590 if (lookupFlag
& LookupFlag::UseMarkFilteringSet
)
592 USHORT
&markFilteringSet
= StructAfter
<USHORT
> (subTable
);
593 markFilteringSet
.set (lookup_props
>> 16);
595 return TRACE_RETURN (true);
598 inline bool sanitize (hb_sanitize_context_t
*c
) {
599 TRACE_SANITIZE (this);
600 /* Real sanitize of the subtables is done by GSUB/GPOS/... */
601 if (!(c
->check_struct (this) && subTable
.sanitize (c
))) return TRACE_RETURN (false);
602 if (lookupFlag
& LookupFlag::UseMarkFilteringSet
)
604 USHORT
&markFilteringSet
= StructAfter
<USHORT
> (subTable
);
605 if (!markFilteringSet
.sanitize (c
)) return TRACE_RETURN (false);
607 return TRACE_RETURN (true);
610 USHORT lookupType
; /* Different enumerations for GSUB and GPOS */
611 USHORT lookupFlag
; /* Lookup qualifiers */
613 subTable
; /* Array of SubTables */
614 USHORT markFilteringSetX
[VAR
]; /* Index (base 0) into GDEF mark glyph sets
615 * structure. This field is only present if bit
616 * UseMarkFilteringSet of lookup flags is set. */
618 DEFINE_SIZE_ARRAY2 (6, subTable
, markFilteringSetX
);
621 typedef OffsetListOf
<Lookup
> LookupList
;
628 struct CoverageFormat1
630 friend struct Coverage
;
633 inline unsigned int get_coverage (hb_codepoint_t glyph_id
) const
635 int i
= glyphArray
.bsearch (glyph_id
);
636 ASSERT_STATIC (((unsigned int) -1) == NOT_COVERED
);
640 inline bool serialize (hb_serialize_context_t
*c
,
641 Supplier
<GlyphID
> &glyphs
,
642 unsigned int num_glyphs
)
644 TRACE_SERIALIZE (this);
645 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
646 glyphArray
.len
.set (num_glyphs
);
647 if (unlikely (!c
->extend (glyphArray
))) return TRACE_RETURN (false);
648 for (unsigned int i
= 0; i
< num_glyphs
; i
++)
649 glyphArray
[i
] = glyphs
[i
];
650 glyphs
.advance (num_glyphs
);
651 return TRACE_RETURN (true);
654 inline bool sanitize (hb_sanitize_context_t
*c
) {
655 TRACE_SANITIZE (this);
656 return TRACE_RETURN (glyphArray
.sanitize (c
));
659 inline bool intersects_coverage (const hb_set_t
*glyphs
, unsigned int index
) const {
660 return glyphs
->has (glyphArray
[index
]);
663 template <typename set_t
>
664 inline void add_coverage (set_t
*glyphs
) const {
665 unsigned int count
= glyphArray
.len
;
666 for (unsigned int i
= 0; i
< count
; i
++)
667 glyphs
->add (glyphArray
[i
]);
671 /* Older compilers need this to be public. */
673 inline void init (const struct CoverageFormat1
&c_
) { c
= &c_
; i
= 0; };
674 inline bool more (void) { return i
< c
->glyphArray
.len
; }
675 inline void next (void) { i
++; }
676 inline uint16_t get_glyph (void) { return c
->glyphArray
[i
]; }
677 inline uint16_t get_coverage (void) { return i
; }
680 const struct CoverageFormat1
*c
;
686 USHORT coverageFormat
; /* Format identifier--format = 1 */
687 SortedArrayOf
<GlyphID
>
688 glyphArray
; /* Array of GlyphIDs--in numerical order */
690 DEFINE_SIZE_ARRAY (4, glyphArray
);
693 struct CoverageFormat2
695 friend struct Coverage
;
698 inline unsigned int get_coverage (hb_codepoint_t glyph_id
) const
700 int i
= rangeRecord
.bsearch (glyph_id
);
702 const RangeRecord
&range
= rangeRecord
[i
];
703 return (unsigned int) range
.value
+ (glyph_id
- range
.start
);
708 inline bool serialize (hb_serialize_context_t
*c
,
709 Supplier
<GlyphID
> &glyphs
,
710 unsigned int num_glyphs
)
712 TRACE_SERIALIZE (this);
713 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
715 if (unlikely (!num_glyphs
)) return TRACE_RETURN (true);
717 unsigned int num_ranges
= 1;
718 for (unsigned int i
= 1; i
< num_glyphs
; i
++)
719 if (glyphs
[i
- 1] + 1 != glyphs
[i
])
721 rangeRecord
.len
.set (num_ranges
);
722 if (unlikely (!c
->extend (rangeRecord
))) return TRACE_RETURN (false);
724 unsigned int range
= 0;
725 rangeRecord
[range
].start
= glyphs
[0];
726 rangeRecord
[range
].value
.set (0);
727 for (unsigned int i
= 1; i
< num_glyphs
; i
++)
728 if (glyphs
[i
- 1] + 1 != glyphs
[i
]) {
730 rangeRecord
[range
].start
= glyphs
[i
];
731 rangeRecord
[range
].value
.set (i
);
732 rangeRecord
[range
].end
= glyphs
[i
];
734 rangeRecord
[range
].end
= glyphs
[i
];
736 glyphs
.advance (num_glyphs
);
737 return TRACE_RETURN (true);
740 inline bool sanitize (hb_sanitize_context_t
*c
) {
741 TRACE_SANITIZE (this);
742 return TRACE_RETURN (rangeRecord
.sanitize (c
));
745 inline bool intersects_coverage (const hb_set_t
*glyphs
, unsigned int index
) const {
747 unsigned int count
= rangeRecord
.len
;
748 for (i
= 0; i
< count
; i
++) {
749 const RangeRecord
&range
= rangeRecord
[i
];
750 if (range
.value
<= index
&&
751 index
< (unsigned int) range
.value
+ (range
.end
- range
.start
) &&
752 range
.intersects (glyphs
))
754 else if (index
< range
.value
)
760 template <typename set_t
>
761 inline void add_coverage (set_t
*glyphs
) const {
762 unsigned int count
= rangeRecord
.len
;
763 for (unsigned int i
= 0; i
< count
; i
++)
764 rangeRecord
[i
].add_coverage (glyphs
);
768 /* Older compilers need this to be public. */
770 inline void init (const CoverageFormat2
&c_
) {
774 j
= c
->rangeRecord
.len
? c_
.rangeRecord
[0].start
: 0;
776 inline bool more (void) { return i
< c
->rangeRecord
.len
; }
777 inline void next (void) {
779 if (j
== c
->rangeRecord
[i
].end
) {
782 j
= c
->rangeRecord
[i
].start
;
787 inline uint16_t get_glyph (void) { return j
; }
788 inline uint16_t get_coverage (void) { return coverage
; }
791 const struct CoverageFormat2
*c
;
792 unsigned int i
, j
, coverage
;
797 USHORT coverageFormat
; /* Format identifier--format = 2 */
798 SortedArrayOf
<RangeRecord
>
799 rangeRecord
; /* Array of glyph ranges--ordered by
800 * Start GlyphID. rangeCount entries
803 DEFINE_SIZE_ARRAY (4, rangeRecord
);
808 inline unsigned int get_coverage (hb_codepoint_t glyph_id
) const
811 case 1: return u
.format1
.get_coverage(glyph_id
);
812 case 2: return u
.format2
.get_coverage(glyph_id
);
813 default:return NOT_COVERED
;
817 inline bool serialize (hb_serialize_context_t
*c
,
818 Supplier
<GlyphID
> &glyphs
,
819 unsigned int num_glyphs
)
821 TRACE_SERIALIZE (this);
822 if (unlikely (!c
->extend_min (*this))) return TRACE_RETURN (false);
823 unsigned int num_ranges
= 1;
824 for (unsigned int i
= 1; i
< num_glyphs
; i
++)
825 if (glyphs
[i
- 1] + 1 != glyphs
[i
])
827 u
.format
.set (num_glyphs
* 2 < num_ranges
* 3 ? 1 : 2);
829 case 1: return TRACE_RETURN (u
.format1
.serialize (c
, glyphs
, num_glyphs
));
830 case 2: return TRACE_RETURN (u
.format2
.serialize (c
, glyphs
, num_glyphs
));
831 default:return TRACE_RETURN (false);
835 inline bool sanitize (hb_sanitize_context_t
*c
) {
836 TRACE_SANITIZE (this);
837 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
839 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
840 case 2: return TRACE_RETURN (u
.format2
.sanitize (c
));
841 default:return TRACE_RETURN (true);
845 inline bool intersects (const hb_set_t
*glyphs
) const {
846 /* TODO speed this up */
848 for (iter
.init (*this); iter
.more (); iter
.next ()) {
849 if (glyphs
->has (iter
.get_glyph ()))
855 inline bool intersects_coverage (const hb_set_t
*glyphs
, unsigned int index
) const {
857 case 1: return u
.format1
.intersects_coverage (glyphs
, index
);
858 case 2: return u
.format2
.intersects_coverage (glyphs
, index
);
859 default:return false;
863 template <typename set_t
>
864 inline void add_coverage (set_t
*glyphs
) const {
866 case 1: u
.format1
.add_coverage (glyphs
); break;
867 case 2: u
.format2
.add_coverage (glyphs
); break;
873 Iter (void) : format (0) {};
874 inline void init (const Coverage
&c_
) {
875 format
= c_
.u
.format
;
877 case 1: u
.format1
.init (c_
.u
.format1
); return;
878 case 2: u
.format2
.init (c_
.u
.format2
); return;
882 inline bool more (void) {
884 case 1: return u
.format1
.more ();
885 case 2: return u
.format2
.more ();
886 default:return false;
889 inline void next (void) {
891 case 1: u
.format1
.next (); break;
892 case 2: u
.format2
.next (); break;
896 inline uint16_t get_glyph (void) {
898 case 1: return u
.format1
.get_glyph ();
899 case 2: return u
.format2
.get_glyph ();
903 inline uint16_t get_coverage (void) {
905 case 1: return u
.format1
.get_coverage ();
906 case 2: return u
.format2
.get_coverage ();
914 CoverageFormat1::Iter format1
;
915 CoverageFormat2::Iter format2
;
921 USHORT format
; /* Format identifier */
922 CoverageFormat1 format1
;
923 CoverageFormat2 format2
;
926 DEFINE_SIZE_UNION (2, format
);
931 * Class Definition Table
934 struct ClassDefFormat1
936 friend struct ClassDef
;
939 inline unsigned int get_class (hb_codepoint_t glyph_id
) const
941 if (unlikely ((unsigned int) (glyph_id
- startGlyph
) < classValue
.len
))
942 return classValue
[glyph_id
- startGlyph
];
946 inline bool sanitize (hb_sanitize_context_t
*c
) {
947 TRACE_SANITIZE (this);
948 return TRACE_RETURN (c
->check_struct (this) && classValue
.sanitize (c
));
951 template <typename set_t
>
952 inline void add_class (set_t
*glyphs
, unsigned int klass
) const {
953 unsigned int count
= classValue
.len
;
954 for (unsigned int i
= 0; i
< count
; i
++)
955 if (classValue
[i
] == klass
)
956 glyphs
->add (startGlyph
+ i
);
959 inline bool intersects_class (const hb_set_t
*glyphs
, unsigned int klass
) const {
960 unsigned int count
= classValue
.len
;
963 /* Match if there's any glyph that is not listed! */
964 hb_codepoint_t g
= -1;
965 if (!hb_set_next (glyphs
, &g
))
969 g
= startGlyph
+ count
- 1;
970 if (hb_set_next (glyphs
, &g
))
974 for (unsigned int i
= 0; i
< count
; i
++)
975 if (classValue
[i
] == klass
&& glyphs
->has (startGlyph
+ i
))
981 USHORT classFormat
; /* Format identifier--format = 1 */
982 GlyphID startGlyph
; /* First GlyphID of the classValueArray */
984 classValue
; /* Array of Class Values--one per GlyphID */
986 DEFINE_SIZE_ARRAY (6, classValue
);
989 struct ClassDefFormat2
991 friend struct ClassDef
;
994 inline unsigned int get_class (hb_codepoint_t glyph_id
) const
996 int i
= rangeRecord
.bsearch (glyph_id
);
998 return rangeRecord
[i
].value
;
1002 inline bool sanitize (hb_sanitize_context_t
*c
) {
1003 TRACE_SANITIZE (this);
1004 return TRACE_RETURN (rangeRecord
.sanitize (c
));
1007 template <typename set_t
>
1008 inline void add_class (set_t
*glyphs
, unsigned int klass
) const {
1009 unsigned int count
= rangeRecord
.len
;
1010 for (unsigned int i
= 0; i
< count
; i
++)
1011 if (rangeRecord
[i
].value
== klass
)
1012 rangeRecord
[i
].add_coverage (glyphs
);
1015 inline bool intersects_class (const hb_set_t
*glyphs
, unsigned int klass
) const {
1016 unsigned int count
= rangeRecord
.len
;
1019 /* Match if there's any glyph that is not listed! */
1020 hb_codepoint_t g
= (hb_codepoint_t
) -1;
1021 for (unsigned int i
= 0; i
< count
; i
++)
1023 if (!hb_set_next (glyphs
, &g
))
1025 if (g
< rangeRecord
[i
].start
)
1027 g
= rangeRecord
[i
].end
;
1029 if (g
!= (hb_codepoint_t
) -1 && hb_set_next (glyphs
, &g
))
1033 for (unsigned int i
= 0; i
< count
; i
++)
1034 if (rangeRecord
[i
].value
== klass
&& rangeRecord
[i
].intersects (glyphs
))
1040 USHORT classFormat
; /* Format identifier--format = 2 */
1041 SortedArrayOf
<RangeRecord
>
1042 rangeRecord
; /* Array of glyph ranges--ordered by
1045 DEFINE_SIZE_ARRAY (4, rangeRecord
);
1050 inline unsigned int get_class (hb_codepoint_t glyph_id
) const
1053 case 1: return u
.format1
.get_class(glyph_id
);
1054 case 2: return u
.format2
.get_class(glyph_id
);
1059 inline bool sanitize (hb_sanitize_context_t
*c
) {
1060 TRACE_SANITIZE (this);
1061 if (!u
.format
.sanitize (c
)) return TRACE_RETURN (false);
1063 case 1: return TRACE_RETURN (u
.format1
.sanitize (c
));
1064 case 2: return TRACE_RETURN (u
.format2
.sanitize (c
));
1065 default:return TRACE_RETURN (true);
1069 inline void add_class (hb_set_t
*glyphs
, unsigned int klass
) const {
1071 case 1: u
.format1
.add_class (glyphs
, klass
); return;
1072 case 2: u
.format2
.add_class (glyphs
, klass
); return;
1077 inline bool intersects_class (const hb_set_t
*glyphs
, unsigned int klass
) const {
1079 case 1: return u
.format1
.intersects_class (glyphs
, klass
);
1080 case 2: return u
.format2
.intersects_class (glyphs
, klass
);
1081 default:return false;
1087 USHORT format
; /* Format identifier */
1088 ClassDefFormat1 format1
;
1089 ClassDefFormat2 format2
;
1092 DEFINE_SIZE_UNION (2, format
);
1103 inline hb_position_t
get_x_delta (hb_font_t
*font
) const
1104 { return get_delta (font
->x_ppem
, font
->x_scale
); }
1106 inline hb_position_t
get_y_delta (hb_font_t
*font
) const
1107 { return get_delta (font
->y_ppem
, font
->y_scale
); }
1109 inline int get_delta (unsigned int ppem
, int scale
) const
1111 if (!ppem
) return 0;
1113 int pixels
= get_delta_pixels (ppem
);
1115 if (!pixels
) return 0;
1117 return (int) (pixels
* (int64_t) scale
/ ppem
);
1121 inline int get_delta_pixels (unsigned int ppem_size
) const
1123 unsigned int f
= deltaFormat
;
1124 if (unlikely (f
< 1 || f
> 3))
1127 if (ppem_size
< startSize
|| ppem_size
> endSize
)
1130 unsigned int s
= ppem_size
- startSize
;
1132 unsigned int byte
= deltaValue
[s
>> (4 - f
)];
1133 unsigned int bits
= (byte
>> (16 - (((s
& ((1 << (4 - f
)) - 1)) + 1) << f
)));
1134 unsigned int mask
= (0xFFFFu
>> (16 - (1 << f
)));
1136 int delta
= bits
& mask
;
1138 if ((unsigned int) delta
>= ((mask
+ 1) >> 1))
1144 inline unsigned int get_size (void) const
1146 unsigned int f
= deltaFormat
;
1147 if (unlikely (f
< 1 || f
> 3 || startSize
> endSize
)) return 3 * USHORT::static_size
;
1148 return USHORT::static_size
* (4 + ((endSize
- startSize
) >> (4 - f
)));
1151 inline bool sanitize (hb_sanitize_context_t
*c
) {
1152 TRACE_SANITIZE (this);
1153 return TRACE_RETURN (c
->check_struct (this) && c
->check_range (this, this->get_size ()));
1157 USHORT startSize
; /* Smallest size to correct--in ppem */
1158 USHORT endSize
; /* Largest size to correct--in ppem */
1159 USHORT deltaFormat
; /* Format of DeltaValue array data: 1, 2, or 3
1160 * 1 Signed 2-bit value, 8 values per uint16
1161 * 2 Signed 4-bit value, 4 values per uint16
1162 * 3 Signed 8-bit value, 2 values per uint16
1164 USHORT deltaValue
[VAR
]; /* Array of compressed data */
1166 DEFINE_SIZE_ARRAY (6, deltaValue
);
1170 } /* namespace OT */
1173 #endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */