|  | /* | 
|  | * Copyright © 2017  Google, Inc. | 
|  | * | 
|  | *  This is part of HarfBuzz, a text shaping library. | 
|  | * | 
|  | * Permission is hereby granted, without written agreement and without | 
|  | * license or royalty fees, to use, copy, modify, and distribute this | 
|  | * software and its documentation for any purpose, provided that the | 
|  | * above copyright notice and the following two paragraphs appear in | 
|  | * all copies of this software. | 
|  | * | 
|  | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR | 
|  | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES | 
|  | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN | 
|  | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH | 
|  | * DAMAGE. | 
|  | * | 
|  | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, | 
|  | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | 
|  | * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS | 
|  | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO | 
|  | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | 
|  | * | 
|  | * Google Author(s): Behdad Esfahbod | 
|  | */ | 
|  |  | 
|  | #ifndef HB_OT_KERN_TABLE_HH | 
|  | #define HB_OT_KERN_TABLE_HH | 
|  |  | 
|  | #include "hb-aat-layout-kerx-table.hh" | 
|  |  | 
|  |  | 
|  | /* | 
|  | * kern -- Kerning | 
|  | * https://docs.microsoft.com/en-us/typography/opentype/spec/kern | 
|  | * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kern.html | 
|  | */ | 
|  | #define HB_OT_TAG_kern HB_TAG('k','e','r','n') | 
|  |  | 
|  |  | 
|  | namespace OT { | 
|  |  | 
|  |  | 
|  | template <typename KernSubTableHeader> | 
|  | struct KernSubTableFormat3 | 
|  | { | 
|  | int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const | 
|  | { | 
|  | hb_array_t<const FWORD> kernValue = kernValueZ.as_array (kernValueCount); | 
|  | hb_array_t<const HBUINT8> leftClass = StructAfter<const UnsizedArrayOf<HBUINT8>> (kernValue).as_array (glyphCount); | 
|  | hb_array_t<const HBUINT8> rightClass = StructAfter<const UnsizedArrayOf<HBUINT8>> (leftClass).as_array (glyphCount); | 
|  | hb_array_t<const HBUINT8> kernIndex = StructAfter<const UnsizedArrayOf<HBUINT8>> (rightClass).as_array (leftClassCount * rightClassCount); | 
|  |  | 
|  | unsigned int leftC = leftClass[left]; | 
|  | unsigned int rightC = rightClass[right]; | 
|  | if (unlikely (leftC >= leftClassCount || rightC >= rightClassCount)) | 
|  | return 0; | 
|  | unsigned int i = leftC * rightClassCount + rightC; | 
|  | return kernValue[kernIndex[i]]; | 
|  | } | 
|  |  | 
|  | bool apply (AAT::hb_aat_apply_context_t *c) const | 
|  | { | 
|  | TRACE_APPLY (this); | 
|  |  | 
|  | if (!c->plan->requested_kerning) | 
|  | return false; | 
|  |  | 
|  | if (header.coverage & header.Backwards) | 
|  | return false; | 
|  |  | 
|  | hb_kern_machine_t<KernSubTableFormat3> machine (*this, header.coverage & header.CrossStream); | 
|  | machine.kern (c->font, c->buffer, c->plan->kern_mask); | 
|  |  | 
|  | return_trace (true); | 
|  | } | 
|  |  | 
|  | bool sanitize (hb_sanitize_context_t *c) const | 
|  | { | 
|  | TRACE_SANITIZE (this); | 
|  | return_trace (c->check_struct (this) && | 
|  | c->check_range (kernValueZ, | 
|  | kernValueCount * sizeof (FWORD) + | 
|  | glyphCount * 2 + | 
|  | leftClassCount * rightClassCount)); | 
|  | } | 
|  |  | 
|  | protected: | 
|  | KernSubTableHeader	header; | 
|  | HBUINT16		glyphCount;	/* The number of glyphs in this font. */ | 
|  | HBUINT8		kernValueCount;	/* The number of kerning values. */ | 
|  | HBUINT8		leftClassCount;	/* The number of left-hand classes. */ | 
|  | HBUINT8		rightClassCount;/* The number of right-hand classes. */ | 
|  | HBUINT8		flags;		/* Set to zero (reserved for future use). */ | 
|  | UnsizedArrayOf<FWORD>	kernValueZ;	/* The kerning values. | 
|  | * Length kernValueCount. */ | 
|  | #if 0 | 
|  | UnsizedArrayOf<HBUINT8>leftClass;	/* The left-hand classes. | 
|  | * Length glyphCount. */ | 
|  | UnsizedArrayOf<HBUINT8>rightClass;	/* The right-hand classes. | 
|  | * Length glyphCount. */ | 
|  | UnsizedArrayOf<HBUINT8>kernIndex;	/* The indices into the kernValue array. | 
|  | * Length leftClassCount * rightClassCount */ | 
|  | #endif | 
|  | public: | 
|  | DEFINE_SIZE_ARRAY (KernSubTableHeader::static_size + 6, kernValueZ); | 
|  | }; | 
|  |  | 
|  | template <typename KernSubTableHeader> | 
|  | struct KernSubTable | 
|  | { | 
|  | unsigned int get_size () const { return u.header.length; } | 
|  | unsigned int get_type () const { return u.header.format; } | 
|  |  | 
|  | int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const | 
|  | { | 
|  | switch (get_type ()) { | 
|  | /* This method hooks up to hb_font_t's get_h_kerning.  Only support Format0. */ | 
|  | case 0: return u.format0.get_kerning (left, right); | 
|  | default:return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | template <typename context_t, typename ...Ts> | 
|  | typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const | 
|  | { | 
|  | unsigned int subtable_type = get_type (); | 
|  | TRACE_DISPATCH (this, subtable_type); | 
|  | switch (subtable_type) { | 
|  | case 0:	return_trace (c->dispatch (u.format0)); | 
|  | #ifndef HB_NO_AAT_SHAPE | 
|  | case 1:	return_trace (u.header.apple ? c->dispatch (u.format1, hb_forward<Ts> (ds)...) : c->default_return_value ()); | 
|  | #endif | 
|  | case 2:	return_trace (c->dispatch (u.format2)); | 
|  | #ifndef HB_NO_AAT_SHAPE | 
|  | case 3:	return_trace (u.header.apple ? c->dispatch (u.format3, hb_forward<Ts> (ds)...) : c->default_return_value ()); | 
|  | #endif | 
|  | default:	return_trace (c->default_return_value ()); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool sanitize (hb_sanitize_context_t *c) const | 
|  | { | 
|  | TRACE_SANITIZE (this); | 
|  | if (unlikely (!u.header.sanitize (c) || | 
|  | u.header.length < u.header.min_size || | 
|  | !c->check_range (this, u.header.length))) return_trace (false); | 
|  |  | 
|  | return_trace (dispatch (c)); | 
|  | } | 
|  |  | 
|  | public: | 
|  | union { | 
|  | KernSubTableHeader				header; | 
|  | AAT::KerxSubTableFormat0<KernSubTableHeader>	format0; | 
|  | AAT::KerxSubTableFormat1<KernSubTableHeader>	format1; | 
|  | AAT::KerxSubTableFormat2<KernSubTableHeader>	format2; | 
|  | KernSubTableFormat3<KernSubTableHeader>	format3; | 
|  | } u; | 
|  | public: | 
|  | DEFINE_SIZE_MIN (KernSubTableHeader::static_size); | 
|  | }; | 
|  |  | 
|  |  | 
|  | struct KernOTSubTableHeader | 
|  | { | 
|  | static constexpr bool apple = false; | 
|  | typedef AAT::ObsoleteTypes Types; | 
|  |  | 
|  | unsigned   tuple_count () const { return 0; } | 
|  | bool     is_horizontal () const { return (coverage & Horizontal); } | 
|  |  | 
|  | enum Coverage | 
|  | { | 
|  | Horizontal	= 0x01u, | 
|  | Minimum	= 0x02u, | 
|  | CrossStream	= 0x04u, | 
|  | Override	= 0x08u, | 
|  |  | 
|  | /* Not supported: */ | 
|  | Backwards	= 0x00u, | 
|  | Variation	= 0x00u, | 
|  | }; | 
|  |  | 
|  | bool sanitize (hb_sanitize_context_t *c) const | 
|  | { | 
|  | TRACE_SANITIZE (this); | 
|  | return_trace (c->check_struct (this)); | 
|  | } | 
|  |  | 
|  | public: | 
|  | HBUINT16	versionZ;	/* Unused. */ | 
|  | HBUINT16	length;		/* Length of the subtable (including this header). */ | 
|  | HBUINT8	format;		/* Subtable format. */ | 
|  | HBUINT8	coverage;	/* Coverage bits. */ | 
|  | public: | 
|  | DEFINE_SIZE_STATIC (6); | 
|  | }; | 
|  |  | 
|  | struct KernOT : AAT::KerxTable<KernOT> | 
|  | { | 
|  | friend struct AAT::KerxTable<KernOT>; | 
|  |  | 
|  | static constexpr hb_tag_t tableTag = HB_OT_TAG_kern; | 
|  | static constexpr unsigned minVersion = 0u; | 
|  |  | 
|  | typedef KernOTSubTableHeader SubTableHeader; | 
|  | typedef SubTableHeader::Types Types; | 
|  | typedef KernSubTable<SubTableHeader> SubTable; | 
|  |  | 
|  | protected: | 
|  | HBUINT16	version;	/* Version--0x0000u */ | 
|  | HBUINT16	tableCount;	/* Number of subtables in the kerning table. */ | 
|  | SubTable	firstSubTable;	/* Subtables. */ | 
|  | public: | 
|  | DEFINE_SIZE_MIN (4); | 
|  | }; | 
|  |  | 
|  |  | 
|  | struct KernAATSubTableHeader | 
|  | { | 
|  | static constexpr bool apple = true; | 
|  | typedef AAT::ObsoleteTypes Types; | 
|  |  | 
|  | unsigned   tuple_count () const { return 0; } | 
|  | bool     is_horizontal () const { return !(coverage & Vertical); } | 
|  |  | 
|  | enum Coverage | 
|  | { | 
|  | Vertical	= 0x80u, | 
|  | CrossStream	= 0x40u, | 
|  | Variation	= 0x20u, | 
|  |  | 
|  | /* Not supported: */ | 
|  | Backwards	= 0x00u, | 
|  | }; | 
|  |  | 
|  | bool sanitize (hb_sanitize_context_t *c) const | 
|  | { | 
|  | TRACE_SANITIZE (this); | 
|  | return_trace (c->check_struct (this)); | 
|  | } | 
|  |  | 
|  | public: | 
|  | HBUINT32	length;		/* Length of the subtable (including this header). */ | 
|  | HBUINT8	coverage;	/* Coverage bits. */ | 
|  | HBUINT8	format;		/* Subtable format. */ | 
|  | HBUINT16	tupleIndex;	/* The tuple index (used for variations fonts). | 
|  | * This value specifies which tuple this subtable covers. | 
|  | * Note: We don't implement. */ | 
|  | public: | 
|  | DEFINE_SIZE_STATIC (8); | 
|  | }; | 
|  |  | 
|  | struct KernAAT : AAT::KerxTable<KernAAT> | 
|  | { | 
|  | friend struct AAT::KerxTable<KernAAT>; | 
|  |  | 
|  | static constexpr hb_tag_t tableTag = HB_OT_TAG_kern; | 
|  | static constexpr unsigned minVersion = 0x00010000u; | 
|  |  | 
|  | typedef KernAATSubTableHeader SubTableHeader; | 
|  | typedef SubTableHeader::Types Types; | 
|  | typedef KernSubTable<SubTableHeader> SubTable; | 
|  |  | 
|  | protected: | 
|  | HBUINT32	version;	/* Version--0x00010000u */ | 
|  | HBUINT32	tableCount;	/* Number of subtables in the kerning table. */ | 
|  | SubTable	firstSubTable;	/* Subtables. */ | 
|  | public: | 
|  | DEFINE_SIZE_MIN (8); | 
|  | }; | 
|  |  | 
|  | struct kern | 
|  | { | 
|  | static constexpr hb_tag_t tableTag = HB_OT_TAG_kern; | 
|  |  | 
|  | bool     has_data () const { return u.version32; } | 
|  | unsigned get_type () const { return u.major; } | 
|  |  | 
|  | bool has_state_machine () const | 
|  | { | 
|  | switch (get_type ()) { | 
|  | case 0: return u.ot.has_state_machine (); | 
|  | #ifndef HB_NO_AAT_SHAPE | 
|  | case 1: return u.aat.has_state_machine (); | 
|  | #endif | 
|  | default:return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | bool has_cross_stream () const | 
|  | { | 
|  | switch (get_type ()) { | 
|  | case 0: return u.ot.has_cross_stream (); | 
|  | #ifndef HB_NO_AAT_SHAPE | 
|  | case 1: return u.aat.has_cross_stream (); | 
|  | #endif | 
|  | default:return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const | 
|  | { | 
|  | switch (get_type ()) { | 
|  | case 0: return u.ot.get_h_kerning (left, right); | 
|  | #ifndef HB_NO_AAT_SHAPE | 
|  | case 1: return u.aat.get_h_kerning (left, right); | 
|  | #endif | 
|  | default:return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | bool apply (AAT::hb_aat_apply_context_t *c) const | 
|  | { return dispatch (c); } | 
|  |  | 
|  | template <typename context_t, typename ...Ts> | 
|  | typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const | 
|  | { | 
|  | unsigned int subtable_type = get_type (); | 
|  | TRACE_DISPATCH (this, subtable_type); | 
|  | switch (subtable_type) { | 
|  | case 0:	return_trace (c->dispatch (u.ot, hb_forward<Ts> (ds)...)); | 
|  | #ifndef HB_NO_AAT_SHAPE | 
|  | case 1:	return_trace (c->dispatch (u.aat, hb_forward<Ts> (ds)...)); | 
|  | #endif | 
|  | default:	return_trace (c->default_return_value ()); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool sanitize (hb_sanitize_context_t *c) const | 
|  | { | 
|  | TRACE_SANITIZE (this); | 
|  | if (!u.version32.sanitize (c)) return_trace (false); | 
|  | return_trace (dispatch (c)); | 
|  | } | 
|  |  | 
|  | protected: | 
|  | union { | 
|  | HBUINT32		version32; | 
|  | HBUINT16		major; | 
|  | KernOT		ot; | 
|  | #ifndef HB_NO_AAT_SHAPE | 
|  | KernAAT		aat; | 
|  | #endif | 
|  | } u; | 
|  | public: | 
|  | DEFINE_SIZE_UNION (4, version32); | 
|  | }; | 
|  |  | 
|  | } /* namespace OT */ | 
|  |  | 
|  |  | 
|  | #endif /* HB_OT_KERN_TABLE_HH */ |