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