blob: 0648f6175f7104d4ad1acff641dc2f1d3a6d72d8 [file] [log] [blame]
Ebrahim Byagowia64eacd2018-02-19 23:27:08 +03301/*
Ebrahim Byagowia64eacd2018-02-19 23:27:08 +03302 * Copyright © 2018 Ebrahim Byagowi
Ebrahim Byagowi1ab16f42018-02-24 12:49:42 +03303 * Copyright © 2018 Google, Inc.
Ebrahim Byagowia64eacd2018-02-19 23:27:08 +03304 *
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_AAT_LAYOUT_TRAK_TABLE_HH
29#define HB_AAT_LAYOUT_TRAK_TABLE_HH
30
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070031#include "hb-aat-layout-common.hh"
32#include "hb-ot-layout.hh"
33#include "hb-open-type.hh"
Ebrahim Byagowia64eacd2018-02-19 23:27:08 +033034
Ebrahim Byagowia02c3ee2018-04-12 13:38:19 +043035/*
36 * trak -- Tracking
37 * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6trak.html
38 */
Ebrahim Byagowi158f2812018-03-26 12:04:30 +043039#define HB_AAT_TAG_trak HB_TAG('t','r','a','k')
Ebrahim Byagowia64eacd2018-02-19 23:27:08 +033040
41
42namespace AAT {
43
44
45struct TrackTableEntry
46{
Ebrahim Byagowia47070c2018-04-18 12:09:37 +043047 friend struct TrackData;
48
Ebrahim Byagowie4120082018-12-17 21:31:01 +033049 float get_track_value () const { return track.to_float (); }
Ebrahim Byagowia64eacd2018-02-19 23:27:08 +033050
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +033051 int get_value (const void *base, unsigned int index,
52 unsigned int table_size) const
Ebrahim Byagowi7ee5c522018-12-12 15:14:37 +033053 { return (base+valuesZ).as_array (table_size)[index]; }
Behdad Esfahbod071a2cb2018-10-11 10:18:46 -040054
55 public:
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +033056 bool sanitize (hb_sanitize_context_t *c, const void *base,
57 unsigned int table_size) const
Behdad Esfahbod071a2cb2018-10-11 10:18:46 -040058 {
59 TRACE_SANITIZE (this);
60 return_trace (likely (c->check_struct (this) &&
Ebrahim Byagowi7ee5c522018-12-12 15:14:37 +033061 (valuesZ.sanitize (c, base, table_size))));
Ebrahim Byagowi1ab16f42018-02-24 12:49:42 +033062 }
63
Ebrahim Byagowia64eacd2018-02-19 23:27:08 +033064 protected:
Behdad Esfahboda0dccb62018-03-14 16:31:53 +010065 Fixed track; /* Track value for this record. */
Behdad Esfahbod071a2cb2018-10-11 10:18:46 -040066 NameID trackNameID; /* The 'name' table index for this track.
67 * (a short word or phrase like "loose"
68 * or "very tight") */
Behdad Esfahbod10642b32018-09-15 19:43:33 +020069 OffsetTo<UnsizedArrayOf<FWORD>, HBUINT16, false>
Ebrahim Byagowia47070c2018-04-18 12:09:37 +043070 valuesZ; /* Offset from start of tracking table to
Behdad Esfahboda0dccb62018-03-14 16:31:53 +010071 * per-size tracking values for this track. */
Ebrahim Byagowia64eacd2018-02-19 23:27:08 +033072
73 public:
Behdad Esfahbod6ae40132018-02-20 15:02:25 -080074 DEFINE_SIZE_STATIC (8);
Ebrahim Byagowia64eacd2018-02-19 23:27:08 +033075};
76
77struct TrackData
78{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +033079 float interpolate_at (unsigned int idx,
80 float target_size,
81 const TrackTableEntry &trackTableEntry,
82 const void *base) const
Behdad Esfahbod04f72e82018-10-11 11:25:07 -040083 {
84 unsigned int sizes = nSizes;
Behdad Esfahbodd7865102018-10-22 16:18:34 -070085 hb_array_t<const Fixed> size_table ((base+sizeTable).arrayZ, sizes);
Behdad Esfahbod04f72e82018-10-11 11:25:07 -040086
87 float s0 = size_table[idx].to_float ();
88 float s1 = size_table[idx + 1].to_float ();
89 float t = unlikely (s0 == s1) ? 0.f : (target_size - s0) / (s1 - s0);
Behdad Esfahbod9d42d702018-10-17 17:55:47 -070090 return t * trackTableEntry.get_value (base, idx + 1, sizes) +
91 (1.f - t) * trackTableEntry.get_value (base, idx, sizes);
Behdad Esfahbod04f72e82018-10-11 11:25:07 -040092 }
93
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +033094 int get_tracking (const void *base, float ptem) const
Ebrahim Byagowi1ab16f42018-02-24 12:49:42 +033095 {
96 /* CoreText points are CSS pixels (96 per inch),
97 * NOT typographic points (72 per inch).
98 *
99 * https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html
100 */
101 float csspx = ptem * 96.f / 72.f;
Ebrahim Byagowi1ab16f42018-02-24 12:49:42 +0330102
Behdad Esfahbod3d7dea62018-10-11 10:32:08 -0400103 /*
104 * Choose track.
105 */
Ebrahim Byagowibb82f012018-02-25 12:30:33 +0330106 const TrackTableEntry *trackTableEntry = nullptr;
Behdad Esfahbod451f3de2018-10-11 10:30:32 -0400107 unsigned int count = nTracks;
108 for (unsigned int i = 0; i < count; i++)
Behdad Esfahboda5be3802018-10-11 10:29:02 -0400109 {
110 /* Note: Seems like the track entries are sorted by values. But the
111 * spec doesn't explicitly say that. It just mentions it in the example. */
Ebrahim Byagowibb82f012018-02-25 12:30:33 +0330112
Behdad Esfahboda5be3802018-10-11 10:29:02 -0400113 /* For now we only seek for track entries with zero tracking value */
114
115 if (trackTable[i].get_track_value () == 0.f)
116 {
Behdad Esfahbod9d42d702018-10-17 17:55:47 -0700117 trackTableEntry = &trackTable[i];
Behdad Esfahboda5be3802018-10-11 10:29:02 -0400118 break;
119 }
120 }
Ebrahim Byagowibb82f012018-02-25 12:30:33 +0330121 if (!trackTableEntry) return 0.;
Behdad Esfahbod6dd46fa2018-02-25 18:54:52 -0800122
Behdad Esfahbod3d7dea62018-10-11 10:32:08 -0400123 /*
124 * Choose size.
125 */
Behdad Esfahbod451f3de2018-10-11 10:30:32 -0400126 unsigned int sizes = nSizes;
Behdad Esfahbod3d7dea62018-10-11 10:32:08 -0400127 if (!sizes) return 0.;
128 if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes);
129
Behdad Esfahbodd7865102018-10-22 16:18:34 -0700130 hb_array_t<const Fixed> size_table ((base+sizeTable).arrayZ, sizes);
Behdad Esfahbod04f72e82018-10-11 11:25:07 -0400131 unsigned int size_index;
Behdad Esfahbod79b63562018-10-19 11:00:20 -0700132 for (size_index = 0; size_index < sizes - 1; size_index++)
Behdad Esfahbod04f72e82018-10-11 11:25:07 -0400133 if (size_table[size_index].to_float () >= csspx)
Ebrahim Byagowi1ab16f42018-02-24 12:49:42 +0330134 break;
135
Behdad Esfahbod9d42d702018-10-17 17:55:47 -0700136 return round (interpolate_at (size_index ? size_index - 1 : 0, csspx,
137 *trackTableEntry, base));
Behdad Esfahbod071a2cb2018-10-11 10:18:46 -0400138 }
139
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330140 bool sanitize (hb_sanitize_context_t *c, const void *base) const
Behdad Esfahbod071a2cb2018-10-11 10:18:46 -0400141 {
142 TRACE_SANITIZE (this);
Ebrahim Byagowib9895072018-11-08 20:48:54 +0330143 return_trace (likely (c->check_struct (this) &&
144 sizeTable.sanitize (c, base, nSizes) &&
145 trackTable.sanitize (c, nTracks, base, nSizes)));
Ebrahim Byagowi1ab16f42018-02-24 12:49:42 +0330146 }
147
Ebrahim Byagowia64eacd2018-02-19 23:27:08 +0330148 protected:
Ebrahim Byagowi211da5e2018-04-11 17:41:24 +0430149 HBUINT16 nTracks; /* Number of separate tracks included in this table. */
150 HBUINT16 nSizes; /* Number of point sizes included in this table. */
Behdad Esfahbod10642b32018-09-15 19:43:33 +0200151 LOffsetTo<UnsizedArrayOf<Fixed>, false>
Behdad Esfahbod071a2cb2018-10-11 10:18:46 -0400152 sizeTable; /* Offset from start of the tracking table to
153 * Array[nSizes] of size values.. */
Behdad Esfahbodfa3a69e2018-02-26 00:32:11 -0800154 UnsizedArrayOf<TrackTableEntry>
Ebrahim Byagowi211da5e2018-04-11 17:41:24 +0430155 trackTable; /* Array[nTracks] of TrackTableEntry records. */
Ebrahim Byagowia64eacd2018-02-19 23:27:08 +0330156
157 public:
Behdad Esfahbod6ae40132018-02-20 15:02:25 -0800158 DEFINE_SIZE_ARRAY (8, trackTable);
Ebrahim Byagowia64eacd2018-02-19 23:27:08 +0330159};
160
161struct trak
162{
Behdad Esfahbod5c4fead2018-11-29 15:04:34 -0500163 enum { tableTag = HB_AAT_TAG_trak };
Ebrahim Byagowia64eacd2018-02-19 23:27:08 +0330164
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330165 bool has_data () const { return version.to_int (); }
Behdad Esfahbodd6a12db2018-10-11 11:10:06 -0400166
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330167 bool apply (hb_aat_apply_context_t *c) const
Ebrahim Byagowi1ab16f42018-02-24 12:49:42 +0330168 {
169 TRACE_APPLY (this);
Behdad Esfahbod6dd46fa2018-02-25 18:54:52 -0800170
Behdad Esfahbodcf92d652018-10-23 03:10:56 -0700171 hb_mask_t trak_mask = c->plan->trak_mask;
172
Ebrahim Byagowi1ab16f42018-02-24 12:49:42 +0330173 const float ptem = c->font->ptem;
Ebrahim Byagowia47070c2018-04-18 12:09:37 +0430174 if (unlikely (ptem <= 0.f))
Behdad Esfahbod6dd46fa2018-02-25 18:54:52 -0800175 return_trace (false);
176
177 hb_buffer_t *buffer = c->buffer;
178 if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
Ebrahim Byagowi1ab16f42018-02-24 12:49:42 +0330179 {
Behdad Esfahbod6dd46fa2018-02-25 18:54:52 -0800180 const TrackData &trackData = this+horizData;
Behdad Esfahbod9d42d702018-10-17 17:55:47 -0700181 int tracking = trackData.get_tracking (this, ptem);
Behdad Esfahbodd06c4a82018-10-11 10:22:01 -0400182 hb_position_t offset_to_add = c->font->em_scalef_x (tracking / 2);
183 hb_position_t advance_to_add = c->font->em_scalef_x (tracking);
Behdad Esfahbod6dd46fa2018-02-25 18:54:52 -0800184 foreach_grapheme (buffer, start, end)
Ebrahim Byagowi1ab16f42018-02-24 12:49:42 +0330185 {
Behdad Esfahbodcf92d652018-10-23 03:10:56 -0700186 if (!(buffer->info[start].mask & trak_mask)) continue;
Behdad Esfahbod6dd46fa2018-02-25 18:54:52 -0800187 buffer->pos[start].x_advance += advance_to_add;
Behdad Esfahbodd06c4a82018-10-11 10:22:01 -0400188 buffer->pos[start].x_offset += offset_to_add;
Ebrahim Byagowi1ab16f42018-02-24 12:49:42 +0330189 }
190 }
Behdad Esfahbod6dd46fa2018-02-25 18:54:52 -0800191 else
192 {
193 const TrackData &trackData = this+vertData;
Behdad Esfahbod9d42d702018-10-17 17:55:47 -0700194 int tracking = trackData.get_tracking (this, ptem);
Behdad Esfahbodd06c4a82018-10-11 10:22:01 -0400195 hb_position_t offset_to_add = c->font->em_scalef_y (tracking / 2);
196 hb_position_t advance_to_add = c->font->em_scalef_y (tracking);
Behdad Esfahbod6dd46fa2018-02-25 18:54:52 -0800197 foreach_grapheme (buffer, start, end)
198 {
Behdad Esfahbodcf92d652018-10-23 03:10:56 -0700199 if (!(buffer->info[start].mask & trak_mask)) continue;
Behdad Esfahbod6dd46fa2018-02-25 18:54:52 -0800200 buffer->pos[start].y_advance += advance_to_add;
Behdad Esfahbodd06c4a82018-10-11 10:22:01 -0400201 buffer->pos[start].y_offset += offset_to_add;
Behdad Esfahbod6dd46fa2018-02-25 18:54:52 -0800202 }
203 }
204
205 return_trace (true);
Ebrahim Byagowi1ab16f42018-02-24 12:49:42 +0330206 }
207
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330208 bool sanitize (hb_sanitize_context_t *c) const
Ebrahim Byagowi1d82b472018-11-10 18:08:11 +0330209 {
210 TRACE_SANITIZE (this);
211
212 return_trace (likely (c->check_struct (this) &&
213 version.major == 1 &&
214 horizData.sanitize (c, this, this) &&
215 vertData.sanitize (c, this, this)));
216 }
217
Ebrahim Byagowia64eacd2018-02-19 23:27:08 +0330218 protected:
Ebrahim Byagowi1d82b472018-11-10 18:08:11 +0330219 FixedVersion<>version; /* Version of the tracking table
Behdad Esfahbod071a2cb2018-10-11 10:18:46 -0400220 * (0x00010000u for version 1.0). */
Ebrahim Byagowi1d82b472018-11-10 18:08:11 +0330221 HBUINT16 format; /* Format of the tracking table (set to 0). */
222 OffsetTo<TrackData>
223 horizData; /* Offset from start of tracking table to TrackData
224 * for horizontal text (or 0 if none). */
225 OffsetTo<TrackData>
226 vertData; /* Offset from start of tracking table to TrackData
227 * for vertical text (or 0 if none). */
228 HBUINT16 reserved; /* Reserved. Set to 0. */
Ebrahim Byagowia64eacd2018-02-19 23:27:08 +0330229
230 public:
Behdad Esfahbod071a2cb2018-10-11 10:18:46 -0400231 DEFINE_SIZE_STATIC (12);
Ebrahim Byagowia64eacd2018-02-19 23:27:08 +0330232};
233
234} /* namespace AAT */
235
236
237#endif /* HB_AAT_LAYOUT_TRAK_TABLE_HH */