xref: /aosp_15_r20/external/harfbuzz_ng/src/hb-aat-layout-trak-table.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1*2d1272b8SAndroid Build Coastguard Worker /*
2*2d1272b8SAndroid Build Coastguard Worker  * Copyright © 2018  Ebrahim Byagowi
3*2d1272b8SAndroid Build Coastguard Worker  * Copyright © 2018  Google, Inc.
4*2d1272b8SAndroid Build Coastguard Worker  *
5*2d1272b8SAndroid Build Coastguard Worker  *  This is part of HarfBuzz, a text shaping library.
6*2d1272b8SAndroid Build Coastguard Worker  *
7*2d1272b8SAndroid Build Coastguard Worker  * Permission is hereby granted, without written agreement and without
8*2d1272b8SAndroid Build Coastguard Worker  * license or royalty fees, to use, copy, modify, and distribute this
9*2d1272b8SAndroid Build Coastguard Worker  * software and its documentation for any purpose, provided that the
10*2d1272b8SAndroid Build Coastguard Worker  * above copyright notice and the following two paragraphs appear in
11*2d1272b8SAndroid Build Coastguard Worker  * all copies of this software.
12*2d1272b8SAndroid Build Coastguard Worker  *
13*2d1272b8SAndroid Build Coastguard Worker  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14*2d1272b8SAndroid Build Coastguard Worker  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15*2d1272b8SAndroid Build Coastguard Worker  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16*2d1272b8SAndroid Build Coastguard Worker  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17*2d1272b8SAndroid Build Coastguard Worker  * DAMAGE.
18*2d1272b8SAndroid Build Coastguard Worker  *
19*2d1272b8SAndroid Build Coastguard Worker  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20*2d1272b8SAndroid Build Coastguard Worker  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21*2d1272b8SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
22*2d1272b8SAndroid Build Coastguard Worker  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23*2d1272b8SAndroid Build Coastguard Worker  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24*2d1272b8SAndroid Build Coastguard Worker  *
25*2d1272b8SAndroid Build Coastguard Worker  * Google Author(s): Behdad Esfahbod
26*2d1272b8SAndroid Build Coastguard Worker  */
27*2d1272b8SAndroid Build Coastguard Worker 
28*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_AAT_LAYOUT_TRAK_TABLE_HH
29*2d1272b8SAndroid Build Coastguard Worker #define HB_AAT_LAYOUT_TRAK_TABLE_HH
30*2d1272b8SAndroid Build Coastguard Worker 
31*2d1272b8SAndroid Build Coastguard Worker #include "hb-aat-layout-common.hh"
32*2d1272b8SAndroid Build Coastguard Worker #include "hb-ot-layout.hh"
33*2d1272b8SAndroid Build Coastguard Worker #include "hb-open-type.hh"
34*2d1272b8SAndroid Build Coastguard Worker 
35*2d1272b8SAndroid Build Coastguard Worker /*
36*2d1272b8SAndroid Build Coastguard Worker  * trak -- Tracking
37*2d1272b8SAndroid Build Coastguard Worker  * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6trak.html
38*2d1272b8SAndroid Build Coastguard Worker  */
39*2d1272b8SAndroid Build Coastguard Worker #define HB_AAT_TAG_trak HB_TAG('t','r','a','k')
40*2d1272b8SAndroid Build Coastguard Worker 
41*2d1272b8SAndroid Build Coastguard Worker 
42*2d1272b8SAndroid Build Coastguard Worker namespace AAT {
43*2d1272b8SAndroid Build Coastguard Worker 
44*2d1272b8SAndroid Build Coastguard Worker 
45*2d1272b8SAndroid Build Coastguard Worker struct TrackTableEntry
46*2d1272b8SAndroid Build Coastguard Worker {
47*2d1272b8SAndroid Build Coastguard Worker   friend struct TrackData;
48*2d1272b8SAndroid Build Coastguard Worker 
get_track_valueAAT::TrackTableEntry49*2d1272b8SAndroid Build Coastguard Worker   float get_track_value () const { return track.to_float (); }
50*2d1272b8SAndroid Build Coastguard Worker 
get_valueAAT::TrackTableEntry51*2d1272b8SAndroid Build Coastguard Worker   int get_value (const void *base, unsigned int index,
52*2d1272b8SAndroid Build Coastguard Worker 		 unsigned int table_size) const
53*2d1272b8SAndroid Build Coastguard Worker   { return (base+valuesZ).as_array (table_size)[index]; }
54*2d1272b8SAndroid Build Coastguard Worker 
55*2d1272b8SAndroid Build Coastguard Worker   public:
sanitizeAAT::TrackTableEntry56*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c, const void *base,
57*2d1272b8SAndroid Build Coastguard Worker 		 unsigned int table_size) const
58*2d1272b8SAndroid Build Coastguard Worker   {
59*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
60*2d1272b8SAndroid Build Coastguard Worker     return_trace (likely (c->check_struct (this) &&
61*2d1272b8SAndroid Build Coastguard Worker 			  (valuesZ.sanitize (c, base, table_size))));
62*2d1272b8SAndroid Build Coastguard Worker   }
63*2d1272b8SAndroid Build Coastguard Worker 
64*2d1272b8SAndroid Build Coastguard Worker   protected:
65*2d1272b8SAndroid Build Coastguard Worker   F16DOT16	track;		/* Track value for this record. */
66*2d1272b8SAndroid Build Coastguard Worker   NameID	trackNameID;	/* The 'name' table index for this track.
67*2d1272b8SAndroid Build Coastguard Worker 				 * (a short word or phrase like "loose"
68*2d1272b8SAndroid Build Coastguard Worker 				 * or "very tight") */
69*2d1272b8SAndroid Build Coastguard Worker   NNOffset16To<UnsizedArrayOf<FWORD>>
70*2d1272b8SAndroid Build Coastguard Worker 		valuesZ;	/* Offset from start of tracking table to
71*2d1272b8SAndroid Build Coastguard Worker 				 * per-size tracking values for this track. */
72*2d1272b8SAndroid Build Coastguard Worker 
73*2d1272b8SAndroid Build Coastguard Worker   public:
74*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC (8);
75*2d1272b8SAndroid Build Coastguard Worker };
76*2d1272b8SAndroid Build Coastguard Worker 
77*2d1272b8SAndroid Build Coastguard Worker struct TrackData
78*2d1272b8SAndroid Build Coastguard Worker {
interpolate_atAAT::TrackData79*2d1272b8SAndroid Build Coastguard Worker   float interpolate_at (unsigned int idx,
80*2d1272b8SAndroid Build Coastguard Worker 			float target_size,
81*2d1272b8SAndroid Build Coastguard Worker 			const TrackTableEntry &trackTableEntry,
82*2d1272b8SAndroid Build Coastguard Worker 			const void *base) const
83*2d1272b8SAndroid Build Coastguard Worker   {
84*2d1272b8SAndroid Build Coastguard Worker     unsigned int sizes = nSizes;
85*2d1272b8SAndroid Build Coastguard Worker     hb_array_t<const F16DOT16> size_table ((base+sizeTable).arrayZ, sizes);
86*2d1272b8SAndroid Build Coastguard Worker 
87*2d1272b8SAndroid Build Coastguard Worker     float s0 = size_table[idx].to_float ();
88*2d1272b8SAndroid Build Coastguard Worker     float s1 = size_table[idx + 1].to_float ();
89*2d1272b8SAndroid Build Coastguard Worker     float t = unlikely (s0 == s1) ? 0.f : (target_size - s0) / (s1 - s0);
90*2d1272b8SAndroid Build Coastguard Worker     return t * trackTableEntry.get_value (base, idx + 1, sizes) +
91*2d1272b8SAndroid Build Coastguard Worker 	   (1.f - t) * trackTableEntry.get_value (base, idx, sizes);
92*2d1272b8SAndroid Build Coastguard Worker   }
93*2d1272b8SAndroid Build Coastguard Worker 
get_trackingAAT::TrackData94*2d1272b8SAndroid Build Coastguard Worker   int get_tracking (const void *base, float ptem) const
95*2d1272b8SAndroid Build Coastguard Worker   {
96*2d1272b8SAndroid Build Coastguard Worker     /*
97*2d1272b8SAndroid Build Coastguard Worker      * Choose track.
98*2d1272b8SAndroid Build Coastguard Worker      */
99*2d1272b8SAndroid Build Coastguard Worker     const TrackTableEntry *trackTableEntry = nullptr;
100*2d1272b8SAndroid Build Coastguard Worker     unsigned int count = nTracks;
101*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < count; i++)
102*2d1272b8SAndroid Build Coastguard Worker     {
103*2d1272b8SAndroid Build Coastguard Worker       /* Note: Seems like the track entries are sorted by values.  But the
104*2d1272b8SAndroid Build Coastguard Worker        * spec doesn't explicitly say that.  It just mentions it in the example. */
105*2d1272b8SAndroid Build Coastguard Worker 
106*2d1272b8SAndroid Build Coastguard Worker       /* For now we only seek for track entries with zero tracking value */
107*2d1272b8SAndroid Build Coastguard Worker 
108*2d1272b8SAndroid Build Coastguard Worker       if (trackTable[i].get_track_value () == 0.f)
109*2d1272b8SAndroid Build Coastguard Worker       {
110*2d1272b8SAndroid Build Coastguard Worker 	trackTableEntry = &trackTable[i];
111*2d1272b8SAndroid Build Coastguard Worker 	break;
112*2d1272b8SAndroid Build Coastguard Worker       }
113*2d1272b8SAndroid Build Coastguard Worker     }
114*2d1272b8SAndroid Build Coastguard Worker     if (!trackTableEntry) return 0;
115*2d1272b8SAndroid Build Coastguard Worker 
116*2d1272b8SAndroid Build Coastguard Worker     /*
117*2d1272b8SAndroid Build Coastguard Worker      * Choose size.
118*2d1272b8SAndroid Build Coastguard Worker      */
119*2d1272b8SAndroid Build Coastguard Worker     unsigned int sizes = nSizes;
120*2d1272b8SAndroid Build Coastguard Worker     if (!sizes) return 0;
121*2d1272b8SAndroid Build Coastguard Worker     if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes);
122*2d1272b8SAndroid Build Coastguard Worker 
123*2d1272b8SAndroid Build Coastguard Worker     hb_array_t<const F16DOT16> size_table ((base+sizeTable).arrayZ, sizes);
124*2d1272b8SAndroid Build Coastguard Worker     unsigned int size_index;
125*2d1272b8SAndroid Build Coastguard Worker     for (size_index = 0; size_index < sizes - 1; size_index++)
126*2d1272b8SAndroid Build Coastguard Worker       if (size_table[size_index].to_float () >= ptem)
127*2d1272b8SAndroid Build Coastguard Worker 	break;
128*2d1272b8SAndroid Build Coastguard Worker 
129*2d1272b8SAndroid Build Coastguard Worker     return roundf (interpolate_at (size_index ? size_index - 1 : 0, ptem,
130*2d1272b8SAndroid Build Coastguard Worker 				   *trackTableEntry, base));
131*2d1272b8SAndroid Build Coastguard Worker   }
132*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::TrackData133*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c, const void *base) const
134*2d1272b8SAndroid Build Coastguard Worker   {
135*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
136*2d1272b8SAndroid Build Coastguard Worker     return_trace (likely (c->check_struct (this) &&
137*2d1272b8SAndroid Build Coastguard Worker 			  hb_barrier () &&
138*2d1272b8SAndroid Build Coastguard Worker 			  sizeTable.sanitize (c, base, nSizes) &&
139*2d1272b8SAndroid Build Coastguard Worker 			  trackTable.sanitize (c, nTracks, base, nSizes)));
140*2d1272b8SAndroid Build Coastguard Worker   }
141*2d1272b8SAndroid Build Coastguard Worker 
142*2d1272b8SAndroid Build Coastguard Worker   protected:
143*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	nTracks;	/* Number of separate tracks included in this table. */
144*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	nSizes;		/* Number of point sizes included in this table. */
145*2d1272b8SAndroid Build Coastguard Worker   NNOffset32To<UnsizedArrayOf<F16DOT16>>
146*2d1272b8SAndroid Build Coastguard Worker 		sizeTable;	/* Offset from start of the tracking table to
147*2d1272b8SAndroid Build Coastguard Worker 				 * Array[nSizes] of size values.. */
148*2d1272b8SAndroid Build Coastguard Worker   UnsizedArrayOf<TrackTableEntry>
149*2d1272b8SAndroid Build Coastguard Worker 		trackTable;	/* Array[nTracks] of TrackTableEntry records. */
150*2d1272b8SAndroid Build Coastguard Worker 
151*2d1272b8SAndroid Build Coastguard Worker   public:
152*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_ARRAY (8, trackTable);
153*2d1272b8SAndroid Build Coastguard Worker };
154*2d1272b8SAndroid Build Coastguard Worker 
155*2d1272b8SAndroid Build Coastguard Worker struct trak
156*2d1272b8SAndroid Build Coastguard Worker {
157*2d1272b8SAndroid Build Coastguard Worker   static constexpr hb_tag_t tableTag = HB_AAT_TAG_trak;
158*2d1272b8SAndroid Build Coastguard Worker 
has_dataAAT::trak159*2d1272b8SAndroid Build Coastguard Worker   bool has_data () const { return version.to_int (); }
160*2d1272b8SAndroid Build Coastguard Worker 
applyAAT::trak161*2d1272b8SAndroid Build Coastguard Worker   bool apply (hb_aat_apply_context_t *c) const
162*2d1272b8SAndroid Build Coastguard Worker   {
163*2d1272b8SAndroid Build Coastguard Worker     TRACE_APPLY (this);
164*2d1272b8SAndroid Build Coastguard Worker 
165*2d1272b8SAndroid Build Coastguard Worker     hb_mask_t trak_mask = c->plan->trak_mask;
166*2d1272b8SAndroid Build Coastguard Worker 
167*2d1272b8SAndroid Build Coastguard Worker     const float ptem = c->font->ptem;
168*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (ptem <= 0.f))
169*2d1272b8SAndroid Build Coastguard Worker       return_trace (false);
170*2d1272b8SAndroid Build Coastguard Worker 
171*2d1272b8SAndroid Build Coastguard Worker     hb_buffer_t *buffer = c->buffer;
172*2d1272b8SAndroid Build Coastguard Worker     if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
173*2d1272b8SAndroid Build Coastguard Worker     {
174*2d1272b8SAndroid Build Coastguard Worker       const TrackData &trackData = this+horizData;
175*2d1272b8SAndroid Build Coastguard Worker       int tracking = trackData.get_tracking (this, ptem);
176*2d1272b8SAndroid Build Coastguard Worker       hb_position_t offset_to_add = c->font->em_scalef_x (tracking / 2);
177*2d1272b8SAndroid Build Coastguard Worker       hb_position_t advance_to_add = c->font->em_scalef_x (tracking);
178*2d1272b8SAndroid Build Coastguard Worker       foreach_grapheme (buffer, start, end)
179*2d1272b8SAndroid Build Coastguard Worker       {
180*2d1272b8SAndroid Build Coastguard Worker 	if (!(buffer->info[start].mask & trak_mask)) continue;
181*2d1272b8SAndroid Build Coastguard Worker 	buffer->pos[start].x_advance += advance_to_add;
182*2d1272b8SAndroid Build Coastguard Worker 	buffer->pos[start].x_offset += offset_to_add;
183*2d1272b8SAndroid Build Coastguard Worker       }
184*2d1272b8SAndroid Build Coastguard Worker     }
185*2d1272b8SAndroid Build Coastguard Worker     else
186*2d1272b8SAndroid Build Coastguard Worker     {
187*2d1272b8SAndroid Build Coastguard Worker       const TrackData &trackData = this+vertData;
188*2d1272b8SAndroid Build Coastguard Worker       int tracking = trackData.get_tracking (this, ptem);
189*2d1272b8SAndroid Build Coastguard Worker       hb_position_t offset_to_add = c->font->em_scalef_y (tracking / 2);
190*2d1272b8SAndroid Build Coastguard Worker       hb_position_t advance_to_add = c->font->em_scalef_y (tracking);
191*2d1272b8SAndroid Build Coastguard Worker       foreach_grapheme (buffer, start, end)
192*2d1272b8SAndroid Build Coastguard Worker       {
193*2d1272b8SAndroid Build Coastguard Worker 	if (!(buffer->info[start].mask & trak_mask)) continue;
194*2d1272b8SAndroid Build Coastguard Worker 	buffer->pos[start].y_advance += advance_to_add;
195*2d1272b8SAndroid Build Coastguard Worker 	buffer->pos[start].y_offset += offset_to_add;
196*2d1272b8SAndroid Build Coastguard Worker       }
197*2d1272b8SAndroid Build Coastguard Worker     }
198*2d1272b8SAndroid Build Coastguard Worker 
199*2d1272b8SAndroid Build Coastguard Worker     return_trace (true);
200*2d1272b8SAndroid Build Coastguard Worker   }
201*2d1272b8SAndroid Build Coastguard Worker 
sanitizeAAT::trak202*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
203*2d1272b8SAndroid Build Coastguard Worker   {
204*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
205*2d1272b8SAndroid Build Coastguard Worker 
206*2d1272b8SAndroid Build Coastguard Worker     return_trace (likely (c->check_struct (this) &&
207*2d1272b8SAndroid Build Coastguard Worker 			  hb_barrier () &&
208*2d1272b8SAndroid Build Coastguard Worker 			  version.major == 1 &&
209*2d1272b8SAndroid Build Coastguard Worker 			  horizData.sanitize (c, this, this) &&
210*2d1272b8SAndroid Build Coastguard Worker 			  vertData.sanitize (c, this, this)));
211*2d1272b8SAndroid Build Coastguard Worker   }
212*2d1272b8SAndroid Build Coastguard Worker 
213*2d1272b8SAndroid Build Coastguard Worker   protected:
214*2d1272b8SAndroid Build Coastguard Worker   FixedVersion<>version;	/* Version of the tracking table
215*2d1272b8SAndroid Build Coastguard Worker 				 * (0x00010000u for version 1.0). */
216*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	format;		/* Format of the tracking table (set to 0). */
217*2d1272b8SAndroid Build Coastguard Worker   Offset16To<TrackData>
218*2d1272b8SAndroid Build Coastguard Worker 		horizData;	/* Offset from start of tracking table to TrackData
219*2d1272b8SAndroid Build Coastguard Worker 				 * for horizontal text (or 0 if none). */
220*2d1272b8SAndroid Build Coastguard Worker   Offset16To<TrackData>
221*2d1272b8SAndroid Build Coastguard Worker 		vertData;	/* Offset from start of tracking table to TrackData
222*2d1272b8SAndroid Build Coastguard Worker 				 * for vertical text (or 0 if none). */
223*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	reserved;	/* Reserved. Set to 0. */
224*2d1272b8SAndroid Build Coastguard Worker 
225*2d1272b8SAndroid Build Coastguard Worker   public:
226*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC (12);
227*2d1272b8SAndroid Build Coastguard Worker };
228*2d1272b8SAndroid Build Coastguard Worker 
229*2d1272b8SAndroid Build Coastguard Worker } /* namespace AAT */
230*2d1272b8SAndroid Build Coastguard Worker 
231*2d1272b8SAndroid Build Coastguard Worker 
232*2d1272b8SAndroid Build Coastguard Worker #endif /* HB_AAT_LAYOUT_TRAK_TABLE_HH */
233