blob: acc9961584bf3c64871db94999279d7a08c39fb1 [file] [log] [blame]
Behdad Esfahbodfd92a3d2008-01-24 03:11:09 -05001/*
Behdad Esfahbod2409d5f2011-04-21 17:14:28 -04002 * Copyright © 1998-2004 David Turner and Werner Lemberg
3 * Copyright © 2006 Behdad Esfahbod
4 * Copyright © 2007,2008,2009 Red Hat, Inc.
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04005 * Copyright © 2012,2013 Google, Inc.
Behdad Esfahbodfd92a3d2008-01-24 03:11:09 -05006 *
Behdad Esfahbodc755cb32010-04-22 00:11:43 -04007 * This is part of HarfBuzz, a text shaping library.
Behdad Esfahbodfd92a3d2008-01-24 03:11:09 -05008 *
9 * Permission is hereby granted, without written agreement and without
10 * license or royalty fees, to use, copy, modify, and distribute this
11 * software and its documentation for any purpose, provided that the
12 * above copyright notice and the following two paragraphs appear in
13 * all copies of this software.
14 *
15 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
16 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
17 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
18 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
19 * DAMAGE.
20 *
21 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
22 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
23 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
24 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
25 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
26 *
27 * Red Hat Author(s): Behdad Esfahbod
Behdad Esfahbodf8603662012-07-30 02:38:39 -040028 * Google Author(s): Behdad Esfahbod
Behdad Esfahbodfd92a3d2008-01-24 03:11:09 -050029 */
30
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070031#include "hb-open-type.hh"
32#include "hb-ot-layout.hh"
Behdad Esfahbodb9291002018-08-26 01:15:47 -070033#include "hb-ot-face.hh"
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070034#include "hb-ot-map.hh"
35#include "hb-map.hh"
Ebrahim Byagowi5b9c2342018-02-27 22:56:17 +033036
Behdad Esfahbod574d8882018-11-25 16:51:22 -050037#include "hb-ot-kern-table.hh"
Ebrahim Byagowi8f80e532018-12-05 13:51:14 +033038#include "hb-ot-gasp-table.hh" // Just so we compile it; unused otherwise.
Behdad Esfahbod7a750ac2011-08-17 14:19:59 +020039#include "hb-ot-layout-gdef-table.hh"
40#include "hb-ot-layout-gsub-table.hh"
41#include "hb-ot-layout-gpos-table.hh"
Ebrahim Byagowi8f80e532018-12-05 13:51:14 +033042#include "hb-ot-layout-base-table.hh" // Just so we compile it; unused otherwise.
43#include "hb-ot-layout-jstf-table.hh" // Just so we compile it; unused otherwise.
Behdad Esfahbod203dc442018-05-03 21:03:27 -040044#include "hb-ot-name-table.hh"
Behdad Esfahbod574d8882018-11-25 16:51:22 -050045#include "hb-ot-os2-table.hh"
Behdad Esfahbodd2c96812013-05-02 18:18:24 -040046
Ebrahim Byagowib986fea2018-11-05 12:31:58 +033047#include "hb-aat-layout-lcar-table.hh"
Behdad Esfahbod574d8882018-11-25 16:51:22 -050048#include "hb-aat-layout-morx-table.hh"
Ebrahim Byagowib986fea2018-11-05 12:31:58 +033049
Behdad Esfahbodaff831e2008-01-24 06:03:45 -050050
Behdad Esfahbod80d9a422018-10-27 04:58:32 -070051/**
52 * SECTION:hb-ot-layout
53 * @title: hb-ot-layout
54 * @short_description: OpenType Layout
55 * @include: hb-ot.h
56 *
57 * Functions for querying OpenType Layout features in the font face.
58 **/
59
60
Behdad Esfahbod590d55c2008-01-24 19:13:50 -050061/*
Behdad Esfahboda5195882018-10-08 23:57:45 -040062 * kern
63 */
64
Nathan Willis930f6fc2019-03-16 15:10:21 +000065/**
66 * hb_ot_layout_has_kerning:
67 * @face: The #hb_face_t to work on
68 *
Nathan Willisd3178aa2019-03-17 14:27:27 +000069 * Tests whether a face includes any kerning data in the 'kern' table.
70 * Does NOT test for kerning lookups in the GPOS table.
Nathan Willis930f6fc2019-03-16 15:10:21 +000071 *
72 * Return value: true if data found, false otherwise
73 *
74 **/
Behdad Esfahbod385f78b2018-11-07 17:19:21 -050075bool
Behdad Esfahboda5195882018-10-08 23:57:45 -040076hb_ot_layout_has_kerning (hb_face_t *face)
77{
Behdad Esfahboda35c92c2018-11-05 22:58:43 -050078 return face->table.kern->has_data ();
Behdad Esfahboda5195882018-10-08 23:57:45 -040079}
80
Nathan Willis930f6fc2019-03-16 15:10:21 +000081
82/**
83 * hb_ot_layout_has_machine_kerning:
84 * @face: The #hb_face_t to work on
85 *
Nathan Willisd3178aa2019-03-17 14:27:27 +000086 * Tests whether a face includes any state-machine kerning in the 'kern' table.
87 * Does NOT examine the GPOS table.
Nathan Willis930f6fc2019-03-16 15:10:21 +000088 *
89 * Return value: true if data found, false otherwise
90 *
91 **/
Behdad Esfahbod385f78b2018-11-07 17:19:21 -050092bool
Behdad Esfahbod74896222018-11-23 11:10:17 -050093hb_ot_layout_has_machine_kerning (hb_face_t *face)
94{
95 return face->table.kern->has_state_machine ();
96}
97
Nathan Willis930f6fc2019-03-16 15:10:21 +000098
99/**
100 * hb_ot_layout_has_cross_kerning:
101 * @face: The #hb_face_t to work on
102 *
103 * Tests whether a face has any cross-stream kerning (i.e., kerns
104 * that make adjustments perpendicular to the direction of the text
105 * flow: Y adjustments in horizontal text or X adjustments in
Nathan Willisd3178aa2019-03-17 14:27:27 +0000106 * vertical text) in the 'kern' table.
107 *
108 * Does NOT examine the GPOS table.
Nathan Willis930f6fc2019-03-16 15:10:21 +0000109 *
110 * Return value: true is data found, false otherwise
111 *
112 **/
Behdad Esfahbod74896222018-11-23 11:10:17 -0500113bool
Behdad Esfahbodca235672018-11-07 16:19:51 -0500114hb_ot_layout_has_cross_kerning (hb_face_t *face)
115{
116 return face->table.kern->has_cross_stream ();
117}
118
Behdad Esfahboda5195882018-10-08 23:57:45 -0400119void
Behdad Esfahbodc221dc02018-11-14 14:49:34 -0500120hb_ot_layout_kern (const hb_ot_shape_plan_t *plan,
Behdad Esfahbod095f5ad2018-11-02 13:23:54 -0400121 hb_font_t *font,
122 hb_buffer_t *buffer)
Behdad Esfahboda5195882018-10-08 23:57:45 -0400123{
Behdad Esfahboda35c92c2018-11-05 22:58:43 -0500124 hb_blob_t *blob = font->face->table.kern.get_blob ();
Behdad Esfahbodfa3ebf82018-11-05 23:34:07 -0500125 const AAT::kern& kern = *blob->as<AAT::kern> ();
Behdad Esfahbod095f5ad2018-11-02 13:23:54 -0400126
127 AAT::hb_aat_apply_context_t c (plan, font, buffer, blob);
128
129 kern.apply (&c);
Behdad Esfahboda5195882018-10-08 23:57:45 -0400130}
131
132
133/*
Behdad Esfahbod590d55c2008-01-24 19:13:50 -0500134 * GDEF
135 */
136
Behdad Esfahbod4f217032018-11-25 15:59:18 -0500137bool
138OT::GDEF::is_blacklisted (hb_blob_t *blob,
139 hb_face_t *face) const
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700140{
Behdad Esfahbod227d85e2019-05-10 23:15:58 -0700141#ifdef HB_NO_OT_LAYOUT_BLACKLIST
Behdad Esfahbod9ddbfa02019-04-12 09:33:25 -0400142 return false;
143#endif
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700144 /* The ugly business of blacklisting individual fonts' tables happen here!
145 * See this thread for why we finally had to bend in and do this:
146 * https://lists.freedesktop.org/archives/harfbuzz/2016-February/005489.html
147 *
148 * In certain versions of Times New Roman Italic and Bold Italic,
149 * ASCII double quotation mark U+0022 has wrong glyph class 3 (mark)
150 * in GDEF. Many versions of Tahoma have bad GDEF tables that
151 * incorrectly classify some spacing marks such as certain IPA
152 * symbols as glyph class 3. So do older versions of Microsoft
153 * Himalaya, and the version of Cantarell shipped by Ubuntu 16.04.
154 *
155 * Nuke the GDEF tables of to avoid unwanted width-zeroing.
156 *
157 * See https://bugzilla.mozilla.org/show_bug.cgi?id=1279925
158 * https://bugzilla.mozilla.org/show_bug.cgi?id=1279693
159 * https://bugzilla.mozilla.org/show_bug.cgi?id=1279875
160 */
Behdad Esfahbod4ed9fb12018-11-25 15:51:01 -0500161#define ENCODE(x,y,z) (((uint64_t) (x) << 48) | ((uint64_t) (y) << 24) | (uint64_t) (z))
Behdad Esfahbod4f217032018-11-25 15:59:18 -0500162 switch ENCODE(blob->length,
163 face->table.GSUB->table.get_length (),
164 face->table.GPOS->table.get_length ())
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700165 {
166 /* sha1sum:c5ee92f0bca4bfb7d06c4d03e8cf9f9cf75d2e8a Windows 7? timesi.ttf */
167 case ENCODE (442, 2874, 42038):
168 /* sha1sum:37fc8c16a0894ab7b749e35579856c73c840867b Windows 7? timesbi.ttf */
169 case ENCODE (430, 2874, 40662):
170 /* sha1sum:19fc45110ea6cd3cdd0a5faca256a3797a069a80 Windows 7 timesi.ttf */
171 case ENCODE (442, 2874, 39116):
172 /* sha1sum:6d2d3c9ed5b7de87bc84eae0df95ee5232ecde26 Windows 7 timesbi.ttf */
173 case ENCODE (430, 2874, 39374):
174 /* sha1sum:8583225a8b49667c077b3525333f84af08c6bcd8 OS X 10.11.3 Times New Roman Italic.ttf */
175 case ENCODE (490, 3046, 41638):
176 /* sha1sum:ec0f5a8751845355b7c3271d11f9918a966cb8c9 OS X 10.11.3 Times New Roman Bold Italic.ttf */
177 case ENCODE (478, 3046, 41902):
178 /* sha1sum:96eda93f7d33e79962451c6c39a6b51ee893ce8c tahoma.ttf from Windows 8 */
179 case ENCODE (898, 12554, 46470):
180 /* sha1sum:20928dc06014e0cd120b6fc942d0c3b1a46ac2bc tahomabd.ttf from Windows 8 */
181 case ENCODE (910, 12566, 47732):
182 /* sha1sum:4f95b7e4878f60fa3a39ca269618dfde9721a79e tahoma.ttf from Windows 8.1 */
183 case ENCODE (928, 23298, 59332):
184 /* sha1sum:6d400781948517c3c0441ba42acb309584b73033 tahomabd.ttf from Windows 8.1 */
185 case ENCODE (940, 23310, 60732):
186 /* tahoma.ttf v6.04 from Windows 8.1 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
187 case ENCODE (964, 23836, 60072):
188 /* tahomabd.ttf v6.04 from Windows 8.1 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
189 case ENCODE (976, 23832, 61456):
190 /* sha1sum:e55fa2dfe957a9f7ec26be516a0e30b0c925f846 tahoma.ttf from Windows 10 */
191 case ENCODE (994, 24474, 60336):
192 /* sha1sum:7199385abb4c2cc81c83a151a7599b6368e92343 tahomabd.ttf from Windows 10 */
193 case ENCODE (1006, 24470, 61740):
194 /* tahoma.ttf v6.91 from Windows 10 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
195 case ENCODE (1006, 24576, 61346):
196 /* tahomabd.ttf v6.91 from Windows 10 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
197 case ENCODE (1018, 24572, 62828):
198 /* sha1sum:b9c84d820c49850d3d27ec498be93955b82772b5 tahoma.ttf from Windows 10 AU */
199 case ENCODE (1006, 24576, 61352):
200 /* sha1sum:2bdfaab28174bdadd2f3d4200a30a7ae31db79d2 tahomabd.ttf from Windows 10 AU */
201 case ENCODE (1018, 24572, 62834):
202 /* sha1sum:b0d36cf5a2fbe746a3dd277bffc6756a820807a7 Tahoma.ttf from Mac OS X 10.9 */
203 case ENCODE (832, 7324, 47162):
204 /* sha1sum:12fc4538e84d461771b30c18b5eb6bd434e30fba Tahoma Bold.ttf from Mac OS X 10.9 */
205 case ENCODE (844, 7302, 45474):
206 /* sha1sum:eb8afadd28e9cf963e886b23a30b44ab4fd83acc himalaya.ttf from Windows 7 */
207 case ENCODE (180, 13054, 7254):
208 /* sha1sum:73da7f025b238a3f737aa1fde22577a6370f77b0 himalaya.ttf from Windows 8 */
209 case ENCODE (192, 12638, 7254):
210 /* sha1sum:6e80fd1c0b059bbee49272401583160dc1e6a427 himalaya.ttf from Windows 8.1 */
211 case ENCODE (192, 12690, 7254):
212 /* 8d9267aea9cd2c852ecfb9f12a6e834bfaeafe44 cantarell-fonts-0.0.21/otf/Cantarell-Regular.otf */
213 /* 983988ff7b47439ab79aeaf9a45bd4a2c5b9d371 cantarell-fonts-0.0.21/otf/Cantarell-Oblique.otf */
214 case ENCODE (188, 248, 3852):
215 /* 2c0c90c6f6087ffbfea76589c93113a9cbb0e75f cantarell-fonts-0.0.21/otf/Cantarell-Bold.otf */
216 /* 55461f5b853c6da88069ffcdf7f4dd3f8d7e3e6b cantarell-fonts-0.0.21/otf/Cantarell-Bold-Oblique.otf */
217 case ENCODE (188, 264, 3426):
218 /* d125afa82a77a6475ac0e74e7c207914af84b37a padauk-2.80/Padauk.ttf RHEL 7.2 */
219 case ENCODE (1058, 47032, 11818):
220 /* 0f7b80437227b90a577cc078c0216160ae61b031 padauk-2.80/Padauk-Bold.ttf RHEL 7.2*/
221 case ENCODE (1046, 47030, 12600):
222 /* d3dde9aa0a6b7f8f6a89ef1002e9aaa11b882290 padauk-2.80/Padauk.ttf Ubuntu 16.04 */
223 case ENCODE (1058, 71796, 16770):
224 /* 5f3c98ccccae8a953be2d122c1b3a77fd805093f padauk-2.80/Padauk-Bold.ttf Ubuntu 16.04 */
225 case ENCODE (1046, 71790, 17862):
226 /* 6c93b63b64e8b2c93f5e824e78caca555dc887c7 padauk-2.80/Padauk-book.ttf */
227 case ENCODE (1046, 71788, 17112):
228 /* d89b1664058359b8ec82e35d3531931125991fb9 padauk-2.80/Padauk-bookbold.ttf */
229 case ENCODE (1058, 71794, 17514):
230 /* 824cfd193aaf6234b2b4dc0cf3c6ef576c0d00ef padauk-3.0/Padauk-book.ttf */
231 case ENCODE (1330, 109904, 57938):
232 /* 91fcc10cf15e012d27571e075b3b4dfe31754a8a padauk-3.0/Padauk-bookbold.ttf */
233 case ENCODE (1330, 109904, 58972):
234 /* sha1sum: c26e41d567ed821bed997e937bc0c41435689e85 Padauk.ttf
235 * "Padauk Regular" "Version 2.5", see https://crbug.com/681813 */
236 case ENCODE (1004, 59092, 14836):
237 return true;
238#undef ENCODE
239 }
240 return false;
241}
242
Behdad Esfahbodc624e182018-08-26 09:19:20 -0700243static void
244_hb_ot_layout_set_glyph_props (hb_font_t *font,
245 hb_buffer_t *buffer)
246{
247 _hb_buffer_assert_gsubgpos_vars (buffer);
248
Behdad Esfahbod5e68cec2018-11-05 23:23:57 -0500249 const OT::GDEF &gdef = *font->face->table.GDEF->table;
Behdad Esfahbodc624e182018-08-26 09:19:20 -0700250 unsigned int count = buffer->len;
251 for (unsigned int i = 0; i < count; i++)
252 {
253 _hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint));
254 _hb_glyph_info_clear_lig_props (&buffer->info[i]);
255 buffer->info[i].syllable() = 0;
256 }
257}
258
259/* Public API */
260
Nathan Willis930f6fc2019-03-16 15:10:21 +0000261/**
262 * hb_ot_layout_has_glyph_classes:
263 * @face: #hb_face_t to work upon
264 *
265 * Tests whether a face has any glyph classes defined in its GDEF table.
266 *
267 * Return value: true if data found, false otherwise
268 *
269 **/
Behdad Esfahbod590d55c2008-01-24 19:13:50 -0500270hb_bool_t
Behdad Esfahbod52ea4772009-11-06 17:45:38 -0500271hb_ot_layout_has_glyph_classes (hb_face_t *face)
Behdad Esfahbod590d55c2008-01-24 19:13:50 -0500272{
Behdad Esfahbod5e68cec2018-11-05 23:23:57 -0500273 return face->table.GDEF->table->has_glyph_classes ();
Behdad Esfahbod590d55c2008-01-24 19:13:50 -0500274}
275
Sascha Brawer01c3a882015-06-01 13:22:01 +0200276/**
Behdad Esfahbod35d18582015-11-26 19:30:37 -0500277 * hb_ot_layout_get_glyph_class:
Nathan Willis930f6fc2019-03-16 15:10:21 +0000278 * @face: The #hb_face_t to work on
279 * @glyph: The #hb_codepoint_t code point to query
280 *
281 * Fetches the GDEF class of the requested glyph in the specified face.
282 *
Nathan Willisc08ddbd2019-03-24 15:07:07 +0000283 * Return value: The #hb_ot_layout_glyph_class_t glyph class of the given code
284 * point in the GDEF table of the face.
Behdad Esfahbod35d18582015-11-26 19:30:37 -0500285 *
Sascha Brawer01c3a882015-06-01 13:22:01 +0200286 * Since: 0.9.7
287 **/
Behdad Esfahbod5a08ecf2012-11-16 13:34:29 -0800288hb_ot_layout_glyph_class_t
289hb_ot_layout_get_glyph_class (hb_face_t *face,
290 hb_codepoint_t glyph)
291{
Behdad Esfahbod5e68cec2018-11-05 23:23:57 -0500292 return (hb_ot_layout_glyph_class_t) face->table.GDEF->table->get_glyph_class (glyph);
Behdad Esfahbod5a08ecf2012-11-16 13:34:29 -0800293}
Behdad Esfahbod4a2d8442010-11-03 15:28:56 -0400294
Sascha Brawer01c3a882015-06-01 13:22:01 +0200295/**
Behdad Esfahbod35d18582015-11-26 19:30:37 -0500296 * hb_ot_layout_get_glyphs_in_class:
Nathan Willis930f6fc2019-03-16 15:10:21 +0000297 * @face: The #hb_face_t to work on
298 * @klass: The #hb_ot_layout_glyph_class_t GDEF class to retrieve
299 * @glyphs: (out): The #hb_set_t set of all glyphs belonging to the requested
300 * class.
301 *
302 * Retrieves the set of all glyphs from the face that belong to the requested
303 * glyph class in the face's GDEF table.
Behdad Esfahbod35d18582015-11-26 19:30:37 -0500304 *
Sascha Brawer01c3a882015-06-01 13:22:01 +0200305 * Since: 0.9.7
306 **/
Behdad Esfahbod89ca8ee2012-11-16 13:53:40 -0800307void
308hb_ot_layout_get_glyphs_in_class (hb_face_t *face,
309 hb_ot_layout_glyph_class_t klass,
310 hb_set_t *glyphs /* OUT */)
311{
Behdad Esfahbod5e68cec2018-11-05 23:23:57 -0500312 return face->table.GDEF->table->get_glyphs_in_class (klass, glyphs);
Behdad Esfahbod89ca8ee2012-11-16 13:53:40 -0800313}
314
Nathan Willis930f6fc2019-03-16 15:10:21 +0000315
316/**
317 * hb_ot_layout_get_attach_points:
318 * @face: The #hb_face_t to work on
319 * @glyph: The #hb_codepoint_t code point to query
Nathan Willis3db22722019-04-02 18:49:40 +0100320 * @start_offset: offset of the first attachment point to retrieve
321 * @point_count: (inout) (allow-none): Input = the maximum number of attachment points to return;
322 * Output = the actual number of attachment points returned (may be zero)
323 * @point_array: (out) (array length=point_count): The array of attachment points found for the query
Nathan Willis930f6fc2019-03-16 15:10:21 +0000324 *
325 * Fetches a list of all attachment points for the specified glyph in the GDEF
326 * table of the face. The list returned will begin at the offset provided.
327 *
328 * Useful if the client program wishes to cache the list.
329 *
330 **/
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500331unsigned int
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400332hb_ot_layout_get_attach_points (hb_face_t *face,
Behdad Esfahbod79420ad2009-05-26 12:24:16 -0400333 hb_codepoint_t glyph,
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500334 unsigned int start_offset,
Behdad Esfahbod79420ad2009-05-26 12:24:16 -0400335 unsigned int *point_count /* IN/OUT */,
336 unsigned int *point_array /* OUT */)
337{
Behdad Esfahbod5a486112019-05-11 00:19:03 -0700338#ifdef HB_NO_OT_LAYOUT_UNUSED
339 if (point_count)
340 *point_count = 0;
341 return 0;
342#endif
343
Behdad Esfahbod5e68cec2018-11-05 23:23:57 -0500344 return face->table.GDEF->table->get_attach_points (glyph,
345 start_offset,
346 point_count,
347 point_array);
Behdad Esfahbod62964af2009-05-26 12:40:10 -0400348}
349
Nathan Willis930f6fc2019-03-16 15:10:21 +0000350
351/**
352 * hb_ot_layout_get_ligature_carets:
353 * @font: The #hb_font_t to work on
354 * @direction: The #hb_direction_t text direction to use
355 * @glyph: The #hb_codepoint_t code point to query
Nathan Willis3db22722019-04-02 18:49:40 +0100356 * @start_offset: offset of the first caret position to retrieve
357 * @caret_count: (inout) (allow-none): Input = the maximum number of caret positions to return;
358 * Output = the actual number of caret positions returned (may be zero)
359 * @caret_array: (out) (array length=caret_count): The array of caret positions found for the query
Nathan Willis930f6fc2019-03-16 15:10:21 +0000360 *
361 * Fetches a list of the caret positions defined for a ligature glyph in the GDEF
362 * table of the font. The list returned will begin at the offset provided.
363 *
364 **/
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500365unsigned int
Behdad Esfahbode2046742010-10-27 12:32:02 -0400366hb_ot_layout_get_ligature_carets (hb_font_t *font,
Behdad Esfahbode2046742010-10-27 12:32:02 -0400367 hb_direction_t direction,
368 hb_codepoint_t glyph,
369 unsigned int start_offset,
370 unsigned int *caret_count /* IN/OUT */,
Ebrahim Byagowi3b0e47c2017-06-19 14:47:09 +0430371 hb_position_t *caret_array /* OUT */)
Behdad Esfahbod62964af2009-05-26 12:40:10 -0400372{
Behdad Esfahbod5a486112019-05-11 00:19:03 -0700373#ifdef HB_NO_OT_LAYOUT_UNUSED
374 if (caret_count)
375 *caret_count = 0;
376 return 0;
377#endif
378
Ebrahim Byagowib986fea2018-11-05 12:31:58 +0330379 unsigned int result_caret_count = 0;
380 unsigned int result = font->face->table.GDEF->table->get_lig_carets (font, direction, glyph, start_offset, &result_caret_count, caret_array);
381 if (result)
382 {
383 if (caret_count) *caret_count = result_caret_count;
384 }
385 else
386 result = font->face->table.lcar->get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);
387 return result;
Behdad Esfahbod79420ad2009-05-26 12:24:16 -0400388}
389
Behdad Esfahbod05bd1b62012-07-30 19:30:01 -0400390
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500391/*
392 * GSUB/GPOS
393 */
394
Behdad Esfahbod574d8882018-11-25 16:51:22 -0500395bool
396OT::GSUB::is_blacklisted (hb_blob_t *blob HB_UNUSED,
397 hb_face_t *face) const
398{
Behdad Esfahbod227d85e2019-05-10 23:15:58 -0700399#ifdef HB_NO_OT_LAYOUT_BLACKLIST
Behdad Esfahbod9ddbfa02019-04-12 09:33:25 -0400400 return false;
401#endif
Behdad Esfahbod574d8882018-11-25 16:51:22 -0500402 /* Mac OS X prefers morx over GSUB. It also ships with various Indic fonts,
403 * all by 'MUTF' foundry (Tamil MN, Tamil Sangam MN, etc.), that have broken
404 * GSUB/GPOS tables. Some have GSUB with zero scripts, those are ignored by
405 * our morx/GSUB preference code. But if GSUB has non-zero scripts, we tend
406 * to prefer it over morx because we want to be consistent with other OpenType
407 * shapers.
408 *
409 * To work around broken Indic Mac system fonts, we ignore GSUB table if
410 * OS/2 VendorId is 'MUTF' and font has morx table as well.
411 *
412 * https://github.com/harfbuzz/harfbuzz/issues/1410
413 * https://github.com/harfbuzz/harfbuzz/issues/1348
414 * https://github.com/harfbuzz/harfbuzz/issues/1391
415 */
416 if (unlikely (face->table.OS2->achVendID == HB_TAG ('M','U','T','F') &&
417 face->table.morx->has_data ()))
418 return true;
419
420 return false;
421}
422
423bool
424OT::GPOS::is_blacklisted (hb_blob_t *blob HB_UNUSED,
425 hb_face_t *face HB_UNUSED) const
426{
Behdad Esfahbod227d85e2019-05-10 23:15:58 -0700427#ifdef HB_NO_OT_LAYOUT_BLACKLIST
Behdad Esfahbod9ddbfa02019-04-12 09:33:25 -0400428 return false;
429#endif
Behdad Esfahbod574d8882018-11-25 16:51:22 -0500430 return false;
431}
432
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400433static const OT::GSUBGPOS&
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -0400434get_gsubgpos_table (hb_face_t *face,
435 hb_tag_t table_tag)
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500436{
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400437 switch (table_tag) {
Behdad Esfahbod737efbe2018-11-05 23:26:29 -0500438 case HB_OT_TAG_GSUB: return *face->table.GSUB->table;
439 case HB_OT_TAG_GPOS: return *face->table.GPOS->table;
Behdad Esfahbodabc12f72018-05-08 02:23:36 -0700440 default: return Null(OT::GSUBGPOS);
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500441 }
442}
443
444
Nathan Willis930f6fc2019-03-16 15:10:21 +0000445/**
446 * hb_ot_layout_table_get_script_tags:
447 * @face: #hb_face_t to work upon
448 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
Nathan Willis3db22722019-04-02 18:49:40 +0100449 * @start_offset: offset of the first script tag to retrieve
450 * @script_count: (inout) (allow-none): Input = the maximum number of script tags to return;
451 * Output = the actual number of script tags returned (may be zero)
452 * @script_tags: (out) (array length=script_count): The array of #hb_tag_t script tags found for the query
Nathan Willis930f6fc2019-03-16 15:10:21 +0000453 *
454 * Fetches a list of all scripts enumerated in the specified face's GSUB table
455 * or GPOS table. The list returned will begin at the offset provided.
456 *
457 **/
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500458unsigned int
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400459hb_ot_layout_table_get_script_tags (hb_face_t *face,
460 hb_tag_t table_tag,
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500461 unsigned int start_offset,
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400462 unsigned int *script_count /* IN/OUT */,
Ebrahim Byagowi63109432018-10-13 14:00:05 +0330463 hb_tag_t *script_tags /* OUT */)
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500464{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400465 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500466
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500467 return g.get_script_tags (start_offset, script_count, script_tags);
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500468}
469
Behdad Esfahbodeb45c0a2013-01-16 22:07:50 -0600470#define HB_OT_TAG_LATIN_SCRIPT HB_TAG ('l', 'a', 't', 'n')
471
Nathan Willis930f6fc2019-03-16 15:10:21 +0000472/**
473 * hb_ot_layout_table_find_script:
474 * @face: #hb_face_t to work upon
475 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
476 * @script_tag: #hb_tag_t of the script tag requested
Nathan Willis51228052019-03-17 14:43:06 +0000477 * @script_index: (out): The index of the requested script tag
Nathan Willis930f6fc2019-03-16 15:10:21 +0000478 *
479 * Fetches the index if a given script tag in the specified face's GSUB table
480 * or GPOS table.
481 *
482 * Return value: true if the script is found, false otherwise
483 *
484 **/
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500485hb_bool_t
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400486hb_ot_layout_table_find_script (hb_face_t *face,
487 hb_tag_t table_tag,
488 hb_tag_t script_tag,
Nathan Willis930f6fc2019-03-16 15:10:21 +0000489 unsigned int *script_index /* OUT */)
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500490{
Behdad Esfahbod606bf572018-09-16 19:33:48 +0200491 static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX), "");
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400492 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500493
494 if (g.find_script_index (script_tag, script_index))
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400495 return true;
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500496
497 /* try finding 'DFLT' */
Behdad Esfahbod8a3511a2009-11-04 19:45:39 -0500498 if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index))
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400499 return false;
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500500
Behdad Esfahboddca8aff2010-09-28 16:25:23 -0400501 /* try with 'dflt'; MS site has had typos and many fonts use it now :(.
502 * including many versions of DejaVu Sans Mono! */
Behdad Esfahbod8a3511a2009-11-04 19:45:39 -0500503 if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index))
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400504 return false;
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500505
Behdad Esfahbodeb45c0a2013-01-16 22:07:50 -0600506 /* try with 'latn'; some old fonts put their features there even though
507 they're really trying to support Thai, for example :( */
508 if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index))
509 return false;
510
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500511 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400512 return false;
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500513}
514
Behdad Esfahbodfca27862019-05-11 00:37:01 -0700515#ifndef HB_DISABLE_DEPRECATED
Nathan Willis930f6fc2019-03-16 15:10:21 +0000516/**
517 * hb_ot_layout_table_choose_script:
518 * @face: #hb_face_t to work upon
519 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
520 * @script_tags: Array of #hb_tag_t script tags
Nathan Willis6c0a1e82019-03-17 14:50:47 +0000521 * @script_index: (out): The index of the requested script tag
522 * @chosen_script: (out): #hb_tag_t of the script tag requested
Nathan Willis930f6fc2019-03-16 15:10:21 +0000523 *
Nathan Willisc08ddbd2019-03-24 15:07:07 +0000524 * Deprecated since 2.0.0
Nathan Willis930f6fc2019-03-16 15:10:21 +0000525 **/
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100526hb_bool_t
527hb_ot_layout_table_choose_script (hb_face_t *face,
528 hb_tag_t table_tag,
529 const hb_tag_t *script_tags,
Nathan Willis6c0a1e82019-03-17 14:50:47 +0000530 unsigned int *script_index /* OUT */,
531 hb_tag_t *chosen_script /* OUT */)
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100532{
David Corbett91067712017-12-08 11:21:14 -0500533 const hb_tag_t *t;
534 for (t = script_tags; *t; t++);
535 return hb_ot_layout_table_select_script (face, table_tag, t - script_tags, script_tags, script_index, chosen_script);
536}
Behdad Esfahbodfca27862019-05-11 00:37:01 -0700537#endif
David Corbett91067712017-12-08 11:21:14 -0500538
Behdad Esfahbod80616642018-10-11 14:16:55 -0400539/**
540 * hb_ot_layout_table_select_script:
Nathan Willis930f6fc2019-03-16 15:10:21 +0000541 * @face: #hb_face_t to work upon
542 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
543 * @script_count: Number of script tags in the array
544 * @script_tags: Array of #hb_tag_t script tags
Nathan Willis51228052019-03-17 14:43:06 +0000545 * @script_index: (out): The index of the requested script
546 * @chosen_script: (out): #hb_tag_t of the requested script
Behdad Esfahbod80616642018-10-11 14:16:55 -0400547 *
Behdad Esfahbod3d9a0302018-10-18 05:58:17 -0700548 * Since: 2.0.0
Behdad Esfahbod80616642018-10-11 14:16:55 -0400549 **/
David Corbett91067712017-12-08 11:21:14 -0500550hb_bool_t
551hb_ot_layout_table_select_script (hb_face_t *face,
552 hb_tag_t table_tag,
553 unsigned int script_count,
554 const hb_tag_t *script_tags,
Ebrahim Byagowi63109432018-10-13 14:00:05 +0330555 unsigned int *script_index /* OUT */,
David Corbett91067712017-12-08 11:21:14 -0500556 hb_tag_t *chosen_script /* OUT */)
557{
Behdad Esfahbod606bf572018-09-16 19:33:48 +0200558 static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX), "");
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400559 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
David Corbett91067712017-12-08 11:21:14 -0500560 unsigned int i;
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100561
David Corbett91067712017-12-08 11:21:14 -0500562 for (i = 0; i < script_count; i++)
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100563 {
David Corbett91067712017-12-08 11:21:14 -0500564 if (g.find_script_index (script_tags[i], script_index))
565 {
Behdad Esfahbodc47a31f2011-07-30 20:57:01 -0400566 if (chosen_script)
David Corbett91067712017-12-08 11:21:14 -0500567 *chosen_script = script_tags[i];
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400568 return true;
Behdad Esfahbodc47a31f2011-07-30 20:57:01 -0400569 }
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100570 }
571
572 /* try finding 'DFLT' */
Behdad Esfahbodc47a31f2011-07-30 20:57:01 -0400573 if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) {
574 if (chosen_script)
575 *chosen_script = HB_OT_TAG_DEFAULT_SCRIPT;
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400576 return false;
Behdad Esfahbodc47a31f2011-07-30 20:57:01 -0400577 }
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100578
579 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
Behdad Esfahbodc47a31f2011-07-30 20:57:01 -0400580 if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) {
581 if (chosen_script)
582 *chosen_script = HB_OT_TAG_DEFAULT_LANGUAGE;
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400583 return false;
Behdad Esfahbodc47a31f2011-07-30 20:57:01 -0400584 }
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100585
Behdad Esfahbod71632c92012-01-22 15:31:44 -0500586 /* try with 'latn'; some old fonts put their features there even though
587 they're really trying to support Thai, for example :( */
Behdad Esfahbod71632c92012-01-22 15:31:44 -0500588 if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index)) {
589 if (chosen_script)
590 *chosen_script = HB_OT_TAG_LATIN_SCRIPT;
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400591 return false;
Behdad Esfahbod71632c92012-01-22 15:31:44 -0500592 }
593
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100594 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
Behdad Esfahbodc47a31f2011-07-30 20:57:01 -0400595 if (chosen_script)
596 *chosen_script = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400597 return false;
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100598}
599
Nathan Willis930f6fc2019-03-16 15:10:21 +0000600
601/**
602 * hb_ot_layout_table_get_feature_tags:
603 * @face: #hb_face_t to work upon
604 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
Nathan Willis3db22722019-04-02 18:49:40 +0100605 * @start_offset: offset of the first feature tag to retrieve
606 * @feature_count: (inout) (allow-none): Input = the maximum number of feature tags to return;
607 * Output = the actual number of feature tags returned (may be zero)
608 * @feature_tags: (out) (array length=feature_count): Array of feature tags found in the table
Nathan Willis930f6fc2019-03-16 15:10:21 +0000609 *
610 * Fetches a list of all feature tags in the given face's GSUB or GPOS table.
611 *
612 **/
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500613unsigned int
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400614hb_ot_layout_table_get_feature_tags (hb_face_t *face,
615 hb_tag_t table_tag,
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500616 unsigned int start_offset,
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400617 unsigned int *feature_count /* IN/OUT */,
Ebrahim Byagowi63109432018-10-13 14:00:05 +0330618 hb_tag_t *feature_tags /* OUT */)
Behdad Esfahbodc4473352008-02-18 21:14:23 -0500619{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400620 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
Behdad Esfahbodc4473352008-02-18 21:14:23 -0500621
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500622 return g.get_feature_tags (start_offset, feature_count, feature_tags);
Behdad Esfahbodc4473352008-02-18 21:14:23 -0500623}
624
Nathan Willis930f6fc2019-03-16 15:10:21 +0000625
626/**
627 * hb_ot_layout_table_find_feature:
628 * @face: #hb_face_t to work upon
629 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
630 * @feature_tag: The #hb_tag_t og the requested feature tag
Nathan Willis51228052019-03-17 14:43:06 +0000631 * @feature_index: (out): The index of the requested feature
Nathan Willis930f6fc2019-03-16 15:10:21 +0000632 *
633 * Fetches the index for a given feature tag in the specified face's GSUB table
634 * or GPOS table.
635 *
636 * Return value: true if the feature is found, false otherwise
637 **/
Behdad Esfahbod385f78b2018-11-07 17:19:21 -0500638bool
Behdad Esfahbod0f98fe82015-07-23 11:52:11 +0100639hb_ot_layout_table_find_feature (hb_face_t *face,
640 hb_tag_t table_tag,
641 hb_tag_t feature_tag,
Nathan Willis930f6fc2019-03-16 15:10:21 +0000642 unsigned int *feature_index /* OUT */)
Behdad Esfahbod0f98fe82015-07-23 11:52:11 +0100643{
Behdad Esfahbod606bf572018-09-16 19:33:48 +0200644 static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX), "");
Behdad Esfahbod0f98fe82015-07-23 11:52:11 +0100645 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
646
647 unsigned int num_features = g.get_feature_count ();
648 for (unsigned int i = 0; i < num_features; i++)
649 {
650 if (feature_tag == g.get_feature_tag (i)) {
651 if (feature_index) *feature_index = i;
652 return true;
653 }
654 }
655
656 if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
657 return false;
658}
659
Behdad Esfahbodc4473352008-02-18 21:14:23 -0500660
Nathan Willis930f6fc2019-03-16 15:10:21 +0000661/**
662 * hb_ot_layout_script_get_language_tags:
663 * @face: #hb_face_t to work upon
664 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
665 * @script_index: The index of the requested script tag
Nathan Willis3db22722019-04-02 18:49:40 +0100666 * @start_offset: offset of the first language tag to retrieve
667 * @language_count: (inout) (allow-none): Input = the maximum number of language tags to return;
668 * Output = the actual number of language tags returned (may be zero)
669 * @language_tags: (out) (array length=language_count): Array of language tags found in the table
Nathan Willis930f6fc2019-03-16 15:10:21 +0000670 *
671 * Fetches a list of language tags in the given face's GSUB or GPOS table, underneath
672 * the specified script index. The list returned will begin at the offset provided.
673 *
674 **/
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500675unsigned int
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400676hb_ot_layout_script_get_language_tags (hb_face_t *face,
677 hb_tag_t table_tag,
678 unsigned int script_index,
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500679 unsigned int start_offset,
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400680 unsigned int *language_count /* IN/OUT */,
Ebrahim Byagowi63109432018-10-13 14:00:05 +0330681 hb_tag_t *language_tags /* OUT */)
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500682{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400683 const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500684
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500685 return s.get_lang_sys_tags (start_offset, language_count, language_tags);
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500686}
687
Nathan Willis930f6fc2019-03-16 15:10:21 +0000688
Behdad Esfahbodfca27862019-05-11 00:37:01 -0700689#ifndef HB_DISABLE_DEPRECATED
Nathan Willis930f6fc2019-03-16 15:10:21 +0000690/**
691 * hb_ot_layout_script_find_language:
692 * @face: #hb_face_t to work upon
693 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
694 * @script_index: The index of the requested script tag
695 * @language_tag: The #hb_tag_t of the requested language
696 * @language_index: The index of the requested language
697 *
698 * Fetches the index of a given language tag in the specified face's GSUB table
699 * or GPOS table, underneath the specified script tag.
700 *
701 * Return value: true if the language tag is found, false otherwise
702 *
Behdad Esfahbodfca27862019-05-11 00:37:01 -0700703 * Since: ??
704 * Deprecated: ??
Nathan Willis930f6fc2019-03-16 15:10:21 +0000705 **/
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500706hb_bool_t
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400707hb_ot_layout_script_find_language (hb_face_t *face,
708 hb_tag_t table_tag,
709 unsigned int script_index,
710 hb_tag_t language_tag,
711 unsigned int *language_index)
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500712{
Behdad Esfahbod737efbe2018-11-05 23:26:29 -0500713 return hb_ot_layout_script_select_language (face,
714 table_tag,
715 script_index,
716 1,
717 &language_tag,
718 language_index);
David Corbett91067712017-12-08 11:21:14 -0500719}
Behdad Esfahbodfca27862019-05-11 00:37:01 -0700720#endif
David Corbett91067712017-12-08 11:21:14 -0500721
Nathan Willis930f6fc2019-03-16 15:10:21 +0000722
Behdad Esfahbod80616642018-10-11 14:16:55 -0400723/**
724 * hb_ot_layout_script_select_language:
Nathan Willis930f6fc2019-03-16 15:10:21 +0000725 * @face: #hb_face_t to work upon
726 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
727 * @script_index: The index of the requested script tag
728 * @language_count: The number of languages in the specified script
729 * @language_tags: The array of language tags
Nathan Willis51228052019-03-17 14:43:06 +0000730 * @language_index: (out): The index of the requested language
Nathan Willis930f6fc2019-03-16 15:10:21 +0000731 *
732 * Fetches the index of a given language tag in the specified face's GSUB table
733 * or GPOS table, underneath the specified script index.
734 *
735 * Return value: true if the language tag is found, false otherwise
736 *
Behdad Esfahbod3d9a0302018-10-18 05:58:17 -0700737 * Since: 2.0.0
Behdad Esfahbod80616642018-10-11 14:16:55 -0400738 **/
David Corbett91067712017-12-08 11:21:14 -0500739hb_bool_t
Behdad Esfahbodcf975ac2018-10-11 14:07:44 -0400740hb_ot_layout_script_select_language (hb_face_t *face,
741 hb_tag_t table_tag,
742 unsigned int script_index,
743 unsigned int language_count,
744 const hb_tag_t *language_tags,
745 unsigned int *language_index /* OUT */)
David Corbett91067712017-12-08 11:21:14 -0500746{
Behdad Esfahbod606bf572018-09-16 19:33:48 +0200747 static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX), "");
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400748 const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
David Corbett91067712017-12-08 11:21:14 -0500749 unsigned int i;
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500750
David Corbett91067712017-12-08 11:21:14 -0500751 for (i = 0; i < language_count; i++)
752 {
753 if (s.find_lang_sys_index (language_tags[i], language_index))
754 return true;
755 }
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500756
David Corbett91067712017-12-08 11:21:14 -0500757 /* try finding 'dflt' */
Behdad Esfahbod8a3511a2009-11-04 19:45:39 -0500758 if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index))
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400759 return false;
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500760
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500761 if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400762 return false;
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500763}
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500764
Nathan Willis930f6fc2019-03-16 15:10:21 +0000765
766/**
767 * hb_ot_layout_language_get_required_feature_index:
768 * @face: #hb_face_t to work upon
769 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
770 * @script_index: The index of the requested script tag
771 * @language_index: The index of the requested language tag
Nathan Willis51228052019-03-17 14:43:06 +0000772 * @feature_index: (out): The index of the requested feature
Nathan Willis930f6fc2019-03-16 15:10:21 +0000773 *
774 * Fetches the index of a requested feature in the given face's GSUB or GPOS table,
775 * underneath the specified script and language.
776 *
777 * Return value: true if the feature is found, false otherwise
778 *
779 **/
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500780hb_bool_t
Behdad Esfahbod911ca382014-06-24 10:20:36 -0600781hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
782 hb_tag_t table_tag,
783 unsigned int script_index,
784 unsigned int language_index,
785 unsigned int *feature_index)
786{
787 return hb_ot_layout_language_get_required_feature (face,
788 table_tag,
789 script_index,
790 language_index,
791 feature_index,
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200792 nullptr);
Behdad Esfahbod911ca382014-06-24 10:20:36 -0600793}
794
Nathan Willis930f6fc2019-03-16 15:10:21 +0000795
Sascha Brawer01c3a882015-06-01 13:22:01 +0200796/**
Behdad Esfahbod35d18582015-11-26 19:30:37 -0500797 * hb_ot_layout_language_get_required_feature:
Nathan Willis930f6fc2019-03-16 15:10:21 +0000798 * @face: #hb_face_t to work upon
799 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
800 * @script_index: The index of the requested script tag
801 * @language_index: The index of the requested language tag
802 * @feature_index: The index of the requested feature
Nathan Willis51228052019-03-17 14:43:06 +0000803 * @feature_tag: (out): The #hb_tag_t of the requested feature
Nathan Willis930f6fc2019-03-16 15:10:21 +0000804 *
805 * Fetches the tag of a requested feature index in the given face's GSUB or GPOS table,
806 * underneath the specified script and language.
807 *
808 * Return value: true if the feature is found, false otherwise
Behdad Esfahbod35d18582015-11-26 19:30:37 -0500809 *
Sascha Brawer01c3a882015-06-01 13:22:01 +0200810 * Since: 0.9.30
811 **/
Behdad Esfahbod911ca382014-06-24 10:20:36 -0600812hb_bool_t
Jonathan Kewda132932014-04-27 14:05:24 +0100813hb_ot_layout_language_get_required_feature (hb_face_t *face,
814 hb_tag_t table_tag,
815 unsigned int script_index,
816 unsigned int language_index,
817 unsigned int *feature_index,
818 hb_tag_t *feature_tag)
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500819{
Jonathan Kewda132932014-04-27 14:05:24 +0100820 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
821 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500822
Jonathan Kewda132932014-04-27 14:05:24 +0100823 unsigned int index = l.get_required_feature_index ();
824 if (feature_index) *feature_index = index;
825 if (feature_tag) *feature_tag = g.get_feature_tag (index);
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500826
827 return l.has_required_feature ();
828}
829
Nathan Willis930f6fc2019-03-16 15:10:21 +0000830
831/**
832 * hb_ot_layout_language_get_feature_indexes:
833 * @face: #hb_face_t to work upon
834 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
835 * @script_index: The index of the requested script tag
836 * @language_index: The index of the requested language tag
Nathan Willis3db22722019-04-02 18:49:40 +0100837 * @start_offset: offset of the first feature tag to retrieve
838 * @feature_count: (inout) (allow-none): Input = the maximum number of feature tags to return;
839 * Output: the actual number of feature tags returned (may be zero)
840 * @feature_indexes: (out) (array length=feature_count): The array of feature indexes found for the query
Nathan Willis930f6fc2019-03-16 15:10:21 +0000841 *
842 * Fetches a list of all features in the specified face's GSUB table
843 * or GPOS table, underneath the specified script and language. The list
844 * returned will begin at the offset provided.
845 **/
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500846unsigned int
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400847hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
848 hb_tag_t table_tag,
849 unsigned int script_index,
850 unsigned int language_index,
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500851 unsigned int start_offset,
Ebrahim Byagowi63109432018-10-13 14:00:05 +0330852 unsigned int *feature_count /* IN/OUT */,
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400853 unsigned int *feature_indexes /* OUT */)
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500854{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400855 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
856 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500857
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500858 return l.get_feature_indexes (start_offset, feature_count, feature_indexes);
Behdad Esfahbodc4473352008-02-18 21:14:23 -0500859}
860
Nathan Willis930f6fc2019-03-16 15:10:21 +0000861
862/**
863 * hb_ot_layout_language_get_feature_tags:
864 * @face: #hb_face_t to work upon
865 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
866 * @script_index: The index of the requested script tag
867 * @language_index: The index of the requested language tag
Nathan Willis3db22722019-04-02 18:49:40 +0100868 * @start_offset: offset of the first feature tag to retrieve
869 * @feature_count: (inout) (allow-none): Input = the maximum number of feature tags to return;
870 * Output = the actual number of feature tags returned (may be zero)
871 * @feature_tags: (out) (array length=feature_count): The array of #hb_tag_t feature tags found for the query
Nathan Willis930f6fc2019-03-16 15:10:21 +0000872 *
873 * Fetches a list of all features in the specified face's GSUB table
874 * or GPOS table, underneath the specified script and language. The list
875 * returned will begin at the offset provided.
876 *
877 **/
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500878unsigned int
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400879hb_ot_layout_language_get_feature_tags (hb_face_t *face,
880 hb_tag_t table_tag,
881 unsigned int script_index,
882 unsigned int language_index,
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500883 unsigned int start_offset,
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400884 unsigned int *feature_count /* IN/OUT */,
Ebrahim Byagowi63109432018-10-13 14:00:05 +0330885 hb_tag_t *feature_tags /* OUT */)
Behdad Esfahbodc4473352008-02-18 21:14:23 -0500886{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400887 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
888 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500889
Behdad Esfahbod606bf572018-09-16 19:33:48 +0200890 static_assert ((sizeof (unsigned int) == sizeof (hb_tag_t)), "");
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500891 unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags);
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400892
Behdad Esfahbod98977492009-08-27 01:32:17 -0400893 if (feature_tags) {
894 unsigned int count = *feature_count;
895 for (unsigned int i = 0; i < count; i++)
896 feature_tags[i] = g.get_feature_tag ((unsigned int) feature_tags[i]);
897 }
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400898
899 return ret;
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500900}
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500901
902
Nathan Willis930f6fc2019-03-16 15:10:21 +0000903/**
904 * hb_ot_layout_language_find_feature:
905 * @face: #hb_face_t to work upon
906 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
907 * @script_index: The index of the requested script tag
908 * @language_index: The index of the requested language tag
909 * @feature_tag: #hb_tag_t of the feature tag requested
Nathan Willis51228052019-03-17 14:43:06 +0000910 * @feature_index: (out): The index of the requested feature
Nathan Willis930f6fc2019-03-16 15:10:21 +0000911 *
912 * Fetches the index of a given feature tag in the specified face's GSUB table
913 * or GPOS table, underneath the specified script and language.
914 *
915 * Return value: true if the feature is found, false otherwise
916 *
917 **/
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500918hb_bool_t
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400919hb_ot_layout_language_find_feature (hb_face_t *face,
920 hb_tag_t table_tag,
921 unsigned int script_index,
922 unsigned int language_index,
923 hb_tag_t feature_tag,
Nathan Willis930f6fc2019-03-16 15:10:21 +0000924 unsigned int *feature_index /* OUT */)
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500925{
Behdad Esfahbod606bf572018-09-16 19:33:48 +0200926 static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX), "");
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400927 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
928 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500929
Behdad Esfahbodf4c95142009-05-17 04:59:56 -0400930 unsigned int num_features = l.get_feature_count ();
931 for (unsigned int i = 0; i < num_features; i++) {
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500932 unsigned int f_index = l.get_feature_index (i);
933
934 if (feature_tag == g.get_feature_tag (f_index)) {
935 if (feature_index) *feature_index = f_index;
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400936 return true;
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500937 }
938 }
939
940 if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400941 return false;
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500942}
Behdad Esfahbodc4473352008-02-18 21:14:23 -0500943
Nathan Willis930f6fc2019-03-16 15:10:21 +0000944
Sascha Brawer01c3a882015-06-01 13:22:01 +0200945/**
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +0400946 * hb_ot_layout_feature_get_lookups:
Nathan Willis930f6fc2019-03-16 15:10:21 +0000947 * @face: #hb_face_t to work upon
948 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
949 * @feature_index: The index of the requested feature
Nathan Willis3db22722019-04-02 18:49:40 +0100950 * @start_offset: offset of the first lookup to retrieve
951 * @lookup_count: (inout) (allow-none): Input = the maximum number of lookups to return;
952 * Output = the actual number of lookups returned (may be zero)
953 * @lookup_indexes: (out) (array length=lookup_count): The array of lookup indexes found for the query
Nathan Willis930f6fc2019-03-16 15:10:21 +0000954 *
955 * Fetches a list of all lookups enumerated for the specified feature, in
956 * the specified face's GSUB table or GPOS table. The list returned will
957 * begin at the offset provided.
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +0400958 *
Sascha Brawer01c3a882015-06-01 13:22:01 +0200959 * Since: 0.9.7
960 **/
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500961unsigned int
Behdad Esfahbodf3064102012-11-15 18:39:46 -0800962hb_ot_layout_feature_get_lookups (hb_face_t *face,
963 hb_tag_t table_tag,
964 unsigned int feature_index,
965 unsigned int start_offset,
Ebrahim Byagowi63109432018-10-13 14:00:05 +0330966 unsigned int *lookup_count /* IN/OUT */,
Behdad Esfahbodf3064102012-11-15 18:39:46 -0800967 unsigned int *lookup_indexes /* OUT */)
Behdad Esfahbodc4473352008-02-18 21:14:23 -0500968{
Behdad Esfahbodec87ba92016-09-10 03:53:11 -0700969 return hb_ot_layout_feature_with_variations_get_lookups (face,
970 table_tag,
971 feature_index,
972 HB_OT_LAYOUT_NO_VARIATIONS_INDEX,
973 start_offset,
974 lookup_count,
975 lookup_indexes);
Behdad Esfahbodc4473352008-02-18 21:14:23 -0500976}
977
Nathan Willis930f6fc2019-03-16 15:10:21 +0000978
Sascha Brawer01c3a882015-06-01 13:22:01 +0200979/**
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +0400980 * hb_ot_layout_table_get_lookup_count:
Nathan Willis930f6fc2019-03-16 15:10:21 +0000981 * @face: #hb_face_t to work upon
982 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
983 *
984 * Fetches the total number of lookups enumerated in the specified
985 * face's GSUB table or GPOS table.
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +0400986 *
Sascha Brawer01c3a882015-06-01 13:22:01 +0200987 * Since: 0.9.22
988 **/
Behdad Esfahbod27674b42013-10-03 14:54:50 -0400989unsigned int
990hb_ot_layout_table_get_lookup_count (hb_face_t *face,
991 hb_tag_t table_tag)
992{
Behdad Esfahbod96828b92018-10-25 20:34:29 -0700993 return get_gsubgpos_table (face, table_tag).get_lookup_count ();
Behdad Esfahbod27674b42013-10-03 14:54:50 -0400994}
995
Behdad Esfahbod941600a2018-10-25 21:26:08 -0700996
997struct hb_collect_features_context_t
998{
999 hb_collect_features_context_t (hb_face_t *face,
1000 hb_tag_t table_tag,
1001 hb_set_t *feature_indexes_)
1002 : g (get_gsubgpos_table (face, table_tag)),
Garret Rieger0e1ad5a2018-10-30 11:29:58 -07001003 feature_indexes (feature_indexes_),
Behdad Esfahbodbfd549d2018-10-30 14:47:27 -07001004 script_count(0),langsys_count(0) {}
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001005
Ebrahim Byagowid0a706c2018-12-22 19:47:48 +03301006 bool visited (const OT::Script &s)
Behdad Esfahbodeb44bfc2018-10-25 21:42:19 -07001007 {
1008 /* We might have Null() object here. Don't want to involve
1009 * that in the memoize. So, detect empty objects and return. */
1010 if (unlikely (!s.has_default_lang_sys () &&
1011 !s.get_lang_sys_count ()))
1012 return true;
1013
Garret Rieger0e1ad5a2018-10-30 11:29:58 -07001014 if (script_count++ > HB_MAX_SCRIPTS)
1015 return true;
1016
Behdad Esfahbodeb44bfc2018-10-25 21:42:19 -07001017 return visited (s, visited_script);
1018 }
Ebrahim Byagowid0a706c2018-12-22 19:47:48 +03301019 bool visited (const OT::LangSys &l)
Behdad Esfahbodeb44bfc2018-10-25 21:42:19 -07001020 {
1021 /* We might have Null() object here. Don't want to involve
1022 * that in the memoize. So, detect empty objects and return. */
1023 if (unlikely (!l.has_required_feature () &&
1024 !l.get_feature_count ()))
1025 return true;
1026
Garret Rieger0e1ad5a2018-10-30 11:29:58 -07001027 if (langsys_count++ > HB_MAX_LANGSYS)
1028 return true;
1029
Behdad Esfahbodeb44bfc2018-10-25 21:42:19 -07001030 return visited (l, visited_langsys);
1031 }
1032
1033 private:
1034 template <typename T>
Ebrahim Byagowid0a706c2018-12-22 19:47:48 +03301035 bool visited (const T &p, hb_set_t &visited_set)
Behdad Esfahbodeb44bfc2018-10-25 21:42:19 -07001036 {
1037 hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) &p - (uintptr_t) &g);
1038 if (visited_set.has (delta))
1039 return true;
1040
1041 visited_set.add (delta);
1042 return false;
1043 }
1044
1045 public:
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001046 const OT::GSUBGPOS &g;
1047 hb_set_t *feature_indexes;
Behdad Esfahbodeb44bfc2018-10-25 21:42:19 -07001048
1049 private:
Behdad Esfahbod3a4e5dd2018-10-29 18:05:25 -07001050 hb_set_t visited_script;
1051 hb_set_t visited_langsys;
Garret Rieger0e1ad5a2018-10-30 11:29:58 -07001052 unsigned int script_count;
1053 unsigned int langsys_count;
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001054};
1055
Behdad Esfahboda88e7162012-11-24 02:31:02 -05001056static void
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001057langsys_collect_features (hb_collect_features_context_t *c,
Behdad Esfahbode8e67502018-10-25 20:48:20 -07001058 const OT::LangSys &l,
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001059 const hb_tag_t *features)
Behdad Esfahboda88e7162012-11-24 02:31:02 -05001060{
Behdad Esfahbodeb44bfc2018-10-25 21:42:19 -07001061 if (c->visited (l)) return;
1062
Behdad Esfahboda88e7162012-11-24 02:31:02 -05001063 if (!features)
1064 {
Behdad Esfahbode8e67502018-10-25 20:48:20 -07001065 /* All features. */
Behdad Esfahbodeb44bfc2018-10-25 21:42:19 -07001066 if (l.has_required_feature ())
1067 c->feature_indexes->add (l.get_required_feature_index ());
Behdad Esfahbod5f85c802013-06-26 20:14:18 -04001068
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001069 l.add_feature_indexes_to (c->feature_indexes);
Behdad Esfahbod15e9e4e2013-01-03 00:04:40 -06001070 }
1071 else
1072 {
Behdad Esfahbode8e67502018-10-25 20:48:20 -07001073 /* Ugh. Any faster way? */
Behdad Esfahboda88e7162012-11-24 02:31:02 -05001074 for (; *features; features++)
1075 {
Behdad Esfahbode8e67502018-10-25 20:48:20 -07001076 hb_tag_t feature_tag = *features;
Behdad Esfahbode8e67502018-10-25 20:48:20 -07001077 unsigned int num_features = l.get_feature_count ();
1078 for (unsigned int i = 0; i < num_features; i++)
1079 {
1080 unsigned int feature_index = l.get_feature_index (i);
1081
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001082 if (feature_tag == c->g.get_feature_tag (feature_index))
Behdad Esfahbode8e67502018-10-25 20:48:20 -07001083 {
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001084 c->feature_indexes->add (feature_index);
Behdad Esfahbode8e67502018-10-25 20:48:20 -07001085 break;
1086 }
1087 }
Behdad Esfahboda88e7162012-11-24 02:31:02 -05001088 }
1089 }
1090}
1091
1092static void
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001093script_collect_features (hb_collect_features_context_t *c,
Behdad Esfahbodfe5520d2018-10-25 20:58:34 -07001094 const OT::Script &s,
1095 const hb_tag_t *languages,
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001096 const hb_tag_t *features)
Behdad Esfahboda88e7162012-11-24 02:31:02 -05001097{
Behdad Esfahbodeb44bfc2018-10-25 21:42:19 -07001098 if (c->visited (s)) return;
1099
Behdad Esfahboda88e7162012-11-24 02:31:02 -05001100 if (!languages)
1101 {
Behdad Esfahbode8e67502018-10-25 20:48:20 -07001102 /* All languages. */
Behdad Esfahbodeb44bfc2018-10-25 21:42:19 -07001103 if (s.has_default_lang_sys ())
1104 langsys_collect_features (c,
1105 s.get_default_lang_sys (),
1106 features);
Behdad Esfahbode8e67502018-10-25 20:48:20 -07001107
Behdad Esfahbodfe5520d2018-10-25 20:58:34 -07001108 unsigned int count = s.get_lang_sys_count ();
Behdad Esfahboda88e7162012-11-24 02:31:02 -05001109 for (unsigned int language_index = 0; language_index < count; language_index++)
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001110 langsys_collect_features (c,
Behdad Esfahbodfe5520d2018-10-25 20:58:34 -07001111 s.get_lang_sys (language_index),
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001112 features);
Behdad Esfahbod15e9e4e2013-01-03 00:04:40 -06001113 }
1114 else
1115 {
Behdad Esfahboda88e7162012-11-24 02:31:02 -05001116 for (; *languages; languages++)
1117 {
1118 unsigned int language_index;
Behdad Esfahbodfe5520d2018-10-25 20:58:34 -07001119 if (s.find_lang_sys_index (*languages, &language_index))
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001120 langsys_collect_features (c,
Behdad Esfahbodfe5520d2018-10-25 20:58:34 -07001121 s.get_lang_sys (language_index),
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001122 features);
Garret Rieger7d92bef2018-07-30 17:17:43 -07001123 }
1124 }
1125}
1126
Nathan Willis930f6fc2019-03-16 15:10:21 +00001127
Garret Rieger7d92bef2018-07-30 17:17:43 -07001128/**
Garret Rieger89733752018-07-30 18:10:43 -07001129 * hb_ot_layout_collect_features:
Nathan Willis930f6fc2019-03-16 15:10:21 +00001130 * @face: #hb_face_t to work upon
1131 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
1132 * @scripts: The array of scripts to collect features for
1133 * @languages: The array of languages to collect features for
1134 * @features: The array of features to collect
Nathan Willis51228052019-03-17 14:43:06 +00001135 * @feature_indexes: (out): The array of feature indexes found for the query
Nathan Willis930f6fc2019-03-16 15:10:21 +00001136 *
1137 * Fetches a list of all feature indexes in the specified face's GSUB table
1138 * or GPOS table, underneath the specified scripts, languages, and features.
1139 * If no list of scripts is provided, all scripts will be queried. If no list
1140 * of languages is provided, all languages will be queried. If no list of
1141 * features is provided, all features will be queried.
Garret Rieger7d92bef2018-07-30 17:17:43 -07001142 *
Behdad Esfahbod44d1fb32018-08-01 14:51:51 -07001143 * Since: 1.8.5
Garret Rieger7d92bef2018-07-30 17:17:43 -07001144 **/
1145void
1146hb_ot_layout_collect_features (hb_face_t *face,
1147 hb_tag_t table_tag,
1148 const hb_tag_t *scripts,
1149 const hb_tag_t *languages,
1150 const hb_tag_t *features,
1151 hb_set_t *feature_indexes /* OUT */)
1152{
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001153 hb_collect_features_context_t c (face, table_tag, feature_indexes);
Garret Rieger7d92bef2018-07-30 17:17:43 -07001154 if (!scripts)
1155 {
Behdad Esfahbode8e67502018-10-25 20:48:20 -07001156 /* All scripts. */
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001157 unsigned int count = c.g.get_script_count ();
Garret Rieger7d92bef2018-07-30 17:17:43 -07001158 for (unsigned int script_index = 0; script_index < count; script_index++)
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001159 script_collect_features (&c,
1160 c.g.get_script (script_index),
Behdad Esfahbodfe5520d2018-10-25 20:58:34 -07001161 languages,
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001162 features);
Garret Rieger7d92bef2018-07-30 17:17:43 -07001163 }
1164 else
1165 {
1166 for (; *scripts; scripts++)
1167 {
1168 unsigned int script_index;
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001169 if (c.g.find_script_index (*scripts, &script_index))
1170 script_collect_features (&c,
1171 c.g.get_script (script_index),
Behdad Esfahbodfe5520d2018-10-25 20:58:34 -07001172 languages,
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001173 features);
Behdad Esfahboda88e7162012-11-24 02:31:02 -05001174 }
1175 }
1176}
1177
Nathan Willis930f6fc2019-03-16 15:10:21 +00001178
Sascha Brawer01c3a882015-06-01 13:22:01 +02001179/**
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +04001180 * hb_ot_layout_collect_lookups:
Nathan Willis930f6fc2019-03-16 15:10:21 +00001181 * @face: #hb_face_t to work upon
1182 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
1183 * @scripts: The array of scripts to collect lookups for
1184 * @languages: The array of languages to collect lookups for
1185 * @features: The array of features to collect lookups for
Nathan Willis51228052019-03-17 14:43:06 +00001186 * @lookup_indexes: (out): The array of lookup indexes found for the query
Nathan Willis930f6fc2019-03-16 15:10:21 +00001187 *
1188 * Fetches a list of all feature-lookup indexes in the specified face's GSUB
1189 * table or GPOS table, underneath the specified scripts, languages, and
1190 * features. If no list of scripts is provided, all scripts will be queried.
1191 * If no list of languages is provided, all languages will be queried. If no
1192 * list of features is provided, all features will be queried.
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +04001193 *
Sascha Brawer01c3a882015-06-01 13:22:01 +02001194 * Since: 0.9.8
1195 **/
Behdad Esfahboda88e7162012-11-24 02:31:02 -05001196void
1197hb_ot_layout_collect_lookups (hb_face_t *face,
1198 hb_tag_t table_tag,
1199 const hb_tag_t *scripts,
1200 const hb_tag_t *languages,
1201 const hb_tag_t *features,
1202 hb_set_t *lookup_indexes /* OUT */)
1203{
Behdad Esfahbode98af6d2018-10-25 22:25:29 -07001204 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
1205
Behdad Esfahbod3a4e5dd2018-10-29 18:05:25 -07001206 hb_set_t feature_indexes;
Garret Rieger7d92bef2018-07-30 17:17:43 -07001207 hb_ot_layout_collect_features (face, table_tag, scripts, languages, features, &feature_indexes);
Behdad Esfahbode98af6d2018-10-25 22:25:29 -07001208
Behdad Esfahbodc237cdf2018-10-25 21:17:30 -07001209 for (hb_codepoint_t feature_index = HB_SET_VALUE_INVALID;
1210 hb_set_next (&feature_indexes, &feature_index);)
Behdad Esfahbode98af6d2018-10-25 22:25:29 -07001211 g.get_feature (feature_index).add_lookup_indexes_to (lookup_indexes);
Behdad Esfahboda88e7162012-11-24 02:31:02 -05001212}
1213
Nathan Willis930f6fc2019-03-16 15:10:21 +00001214
Sascha Brawer01c3a882015-06-01 13:22:01 +02001215/**
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +04001216 * hb_ot_layout_lookup_collect_glyphs:
Nathan Willis930f6fc2019-03-16 15:10:21 +00001217 * @face: #hb_face_t to work upon
1218 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
1219 * @lookup_index: The index of the feature lookup to query
Nathan Willis51228052019-03-17 14:43:06 +00001220 * @glyphs_before: (out): Array of glyphs preceding the substitution range
1221 * @glyphs_input: (out): Array of input glyphs that would be substituted by the lookup
1222 * @glyphs_after: (out): Array of glyphs following the substition range
1223 * @glyphs_output: (out): Array of glyphs that would be the substitued output of the lookup
Nathan Willis930f6fc2019-03-16 15:10:21 +00001224 *
1225 * Fetches a list of all glyphs affected by the specified lookup in the
1226 * specified face's GSUB table of GPOS table.
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +04001227 *
Sascha Brawer01c3a882015-06-01 13:22:01 +02001228 * Since: 0.9.7
1229 **/
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -08001230void
1231hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
1232 hb_tag_t table_tag,
1233 unsigned int lookup_index,
Ebrahim Byagowi63109432018-10-13 14:00:05 +03301234 hb_set_t *glyphs_before, /* OUT. May be NULL */
1235 hb_set_t *glyphs_input, /* OUT. May be NULL */
1236 hb_set_t *glyphs_after, /* OUT. May be NULL */
1237 hb_set_t *glyphs_output /* OUT. May be NULL */)
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -08001238{
Behdad Esfahbod733e8c02013-01-03 00:00:23 -06001239 OT::hb_collect_glyphs_context_t c (face,
1240 glyphs_before,
1241 glyphs_input,
1242 glyphs_after,
1243 glyphs_output);
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -08001244
Behdad Esfahbod15e9e4e2013-01-03 00:04:40 -06001245 switch (table_tag)
1246 {
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -08001247 case HB_OT_TAG_GSUB:
1248 {
Behdad Esfahbod0fe7a742018-11-05 23:08:33 -05001249 const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index);
Behdad Esfahbod780cd932013-05-03 17:33:16 -04001250 l.collect_glyphs (&c);
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -08001251 return;
1252 }
1253 case HB_OT_TAG_GPOS:
1254 {
Behdad Esfahbod0fe7a742018-11-05 23:08:33 -05001255 const OT::PosLookup& l = face->table.GPOS->table->get_lookup (lookup_index);
Behdad Esfahbod780cd932013-05-03 17:33:16 -04001256 l.collect_glyphs (&c);
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -08001257 return;
1258 }
1259 }
1260}
1261
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001262
Behdad Esfahbod30c42b62016-09-10 03:32:39 -07001263/* Variations support */
1264
Nathan Willis930f6fc2019-03-16 15:10:21 +00001265
1266/**
1267 * hb_ot_layout_table_find_feature_variations:
1268 * @face: #hb_face_t to work upon
1269 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
1270 * @coords: The variation coordinates to query
1271 * @num_coords: The number of variation coorinates
Nathan Willis3db22722019-04-02 18:49:40 +01001272 * @variations_index: (out): The array of feature variations found for the query
Nathan Willis930f6fc2019-03-16 15:10:21 +00001273 *
1274 * Fetches a list of feature variations in the specified face's GSUB table
1275 * or GPOS table, at the specified variation coordinates.
1276 *
1277 **/
Behdad Esfahbod30c42b62016-09-10 03:32:39 -07001278hb_bool_t
1279hb_ot_layout_table_find_feature_variations (hb_face_t *face,
1280 hb_tag_t table_tag,
1281 const int *coords,
1282 unsigned int num_coords,
1283 unsigned int *variations_index /* out */)
1284{
1285 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
1286
1287 return g.find_variations_index (coords, num_coords, variations_index);
1288}
1289
Nathan Willis930f6fc2019-03-16 15:10:21 +00001290
1291/**
1292 * hb_ot_layout_feature_with_variations_get_lookups:
1293 * @face: #hb_face_t to work upon
1294 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
1295 * @feature_index: The index of the feature to query
1296 * @variations_index: The index of the feature variation to query
Nathan Willis3db22722019-04-02 18:49:40 +01001297 * @start_offset: offset of the first lookup to retrieve
1298 * @lookup_count: (inout) (allow-none): Input = the maximum number of lookups to return;
1299 * Output = the actual number of lookups returned (may be zero)
1300 * @lookup_indexes: (out) (array length=lookup_count): The array of lookups found for the query
Nathan Willis930f6fc2019-03-16 15:10:21 +00001301 *
1302 * Fetches a list of all lookups enumerated for the specified feature, in
1303 * the specified face's GSUB table or GPOS table, enabled at the specified
1304 * variations index. The list returned will begin at the offset provided.
1305 *
1306 **/
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07001307unsigned int
1308hb_ot_layout_feature_with_variations_get_lookups (hb_face_t *face,
1309 hb_tag_t table_tag,
1310 unsigned int feature_index,
1311 unsigned int variations_index,
1312 unsigned int start_offset,
1313 unsigned int *lookup_count /* IN/OUT */,
1314 unsigned int *lookup_indexes /* OUT */)
1315{
Behdad Esfahbod606bf572018-09-16 19:33:48 +02001316 static_assert ((OT::FeatureVariations::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_VARIATIONS_INDEX), "");
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07001317 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
1318
1319 const OT::Feature &f = g.get_feature_variation (feature_index, variations_index);
1320
1321 return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
1322}
1323
Behdad Esfahbod30c42b62016-09-10 03:32:39 -07001324
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001325/*
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -04001326 * OT::GSUB
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001327 */
1328
Nathan Willis930f6fc2019-03-16 15:10:21 +00001329
1330/**
1331 * hb_ot_layout_has_substitution:
1332 * @face: #hb_face_t to work upon
1333 *
1334 * Tests whether the specified face includes any GSUB substitutions.
1335 *
1336 * Return value: true if data found, false otherwise
1337 *
1338 **/
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001339hb_bool_t
Behdad Esfahbod0ead4812009-08-02 17:41:36 -04001340hb_ot_layout_has_substitution (hb_face_t *face)
1341{
Behdad Esfahbod737efbe2018-11-05 23:26:29 -05001342 return face->table.GSUB->table->has_data ();
Behdad Esfahbod0ead4812009-08-02 17:41:36 -04001343}
1344
Nathan Willis930f6fc2019-03-16 15:10:21 +00001345
Sascha Brawer01c3a882015-06-01 13:22:01 +02001346/**
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +04001347 * hb_ot_layout_lookup_would_substitute:
Nathan Willis930f6fc2019-03-16 15:10:21 +00001348 * @face: #hb_face_t to work upon
1349 * @lookup_index: The index of the lookup to query
1350 * @glyphs: The sequence of glyphs to query for substitution
1351 * @glyphs_length: The length of the glyph sequence
1352 * @zero_context: #hb_bool_t indicating whether substitutions should be context-free
1353 *
1354 * Tests whether a specified lookup in the specified face would
1355 * trigger a substitution on the given glyph sequence.
1356 *
1357 * Return value: true if a substitution would be triggered, false otherwise
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +04001358 *
Sascha Brawer01c3a882015-06-01 13:22:01 +02001359 * Since: 0.9.7
1360 **/
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001361hb_bool_t
Behdad Esfahbod362a9902012-11-15 14:57:31 -08001362hb_ot_layout_lookup_would_substitute (hb_face_t *face,
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -04001363 unsigned int lookup_index,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001364 const hb_codepoint_t *glyphs,
1365 unsigned int glyphs_length,
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -04001366 hb_bool_t zero_context)
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001367{
Behdad Esfahbod0fe7a742018-11-05 23:08:33 -05001368 if (unlikely (lookup_index >= face->table.GSUB->lookup_count)) return false;
Behdad Esfahbodea512f72015-11-26 19:22:22 -05001369 OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, (bool) zero_context);
Behdad Esfahbod2bd9fe32012-09-04 15:15:19 -04001370
Behdad Esfahbod0fe7a742018-11-05 23:08:33 -05001371 const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index);
Behdad Esfahbod2bd9fe32012-09-04 15:15:19 -04001372
Behdad Esfahbod0fe7a742018-11-05 23:08:33 -05001373 return l.would_apply (&c, &face->table.GSUB->accels[lookup_index]);
Behdad Esfahbodf8603662012-07-30 02:38:39 -04001374}
1375
Nathan Willis930f6fc2019-03-16 15:10:21 +00001376
1377/**
1378 * hb_ot_layout_substitute_start:
1379 * @font: #hb_font_t to use
1380 * @buffer: #hb_buffer_t buffer to work upon
1381 *
Nathan Willis3db22722019-04-02 18:49:40 +01001382 * Called before substitution lookups are performed, to ensure that glyph
1383 * class and other properties are set on the glyphs in the buffer.
Nathan Willis930f6fc2019-03-16 15:10:21 +00001384 *
1385 **/
Behdad Esfahbod46d6a212011-05-11 22:33:13 -04001386void
Behdad Esfahbodc624e182018-08-26 09:19:20 -07001387hb_ot_layout_substitute_start (hb_font_t *font,
1388 hb_buffer_t *buffer)
Behdad Esfahbod46d6a212011-05-11 22:33:13 -04001389{
Behdad Esfahbodc624e182018-08-26 09:19:20 -07001390_hb_ot_layout_set_glyph_props (font, buffer);
Behdad Esfahbod46d6a212011-05-11 22:33:13 -04001391}
1392
Behdad Esfahbod385f78b2018-11-07 17:19:21 -05001393void
1394hb_ot_layout_delete_glyphs_inplace (hb_buffer_t *buffer,
1395 bool (*filter) (const hb_glyph_info_t *info))
1396{
1397 /* Merge clusters and delete filtered glyphs.
1398 * NOTE! We can't use out-buffer as we have positioning data. */
1399 unsigned int j = 0;
1400 unsigned int count = buffer->len;
1401 hb_glyph_info_t *info = buffer->info;
1402 hb_glyph_position_t *pos = buffer->pos;
1403 for (unsigned int i = 0; i < count; i++)
1404 {
1405 if (filter (&info[i]))
1406 {
1407 /* Merge clusters.
1408 * Same logic as buffer->delete_glyph(), but for in-place removal. */
1409
1410 unsigned int cluster = info[i].cluster;
1411 if (i + 1 < count && cluster == info[i + 1].cluster)
1412 continue; /* Cluster survives; do nothing. */
1413
1414 if (j)
1415 {
1416 /* Merge cluster backward. */
1417 if (cluster < info[j - 1].cluster)
1418 {
1419 unsigned int mask = info[i].mask;
1420 unsigned int old_cluster = info[j - 1].cluster;
1421 for (unsigned k = j; k && info[k - 1].cluster == old_cluster; k--)
1422 buffer->set_cluster (info[k - 1], cluster, mask);
1423 }
1424 continue;
1425 }
1426
1427 if (i + 1 < count)
1428 buffer->merge_clusters (i, i + 2); /* Merge cluster forward. */
1429
1430 continue;
1431 }
1432
1433 if (j != i)
1434 {
1435 info[j] = info[i];
1436 pos[j] = pos[i];
1437 }
1438 j++;
1439 }
1440 buffer->len = j;
1441}
1442
Sascha Brawer01c3a882015-06-01 13:22:01 +02001443/**
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +04001444 * hb_ot_layout_lookup_substitute_closure:
Nathan Willis930f6fc2019-03-16 15:10:21 +00001445 * @face: #hb_face_t to work upon
1446 * @lookup_index: index of the feature lookup to query
Nathan Willis51228052019-03-17 14:43:06 +00001447 * @glyphs: (out): Array of glyphs comprising the transitive closure of the lookup
Nathan Willis930f6fc2019-03-16 15:10:21 +00001448 *
1449 * Compute the transitive closure of glyphs needed for a
1450 * specified lookup.
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +04001451 *
Sascha Brawer01c3a882015-06-01 13:22:01 +02001452 * Since: 0.9.7
1453 **/
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001454void
Behdad Esfahbod362a9902012-11-15 14:57:31 -08001455hb_ot_layout_lookup_substitute_closure (hb_face_t *face,
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -04001456 unsigned int lookup_index,
Nathan Willis930f6fc2019-03-16 15:10:21 +00001457 hb_set_t *glyphs /* OUT */)
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001458{
Behdad Esfahbod3a4e5dd2018-10-29 18:05:25 -07001459 hb_map_t done_lookups;
Garret Rieger45186b92018-06-05 17:14:42 -07001460 OT::hb_closure_context_t c (face, glyphs, &done_lookups);
Behdad Esfahbod9b346772012-11-23 17:55:40 -05001461
Behdad Esfahbod737efbe2018-11-05 23:26:29 -05001462 const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index);
Behdad Esfahbod9b346772012-11-23 17:55:40 -05001463
Garret Rieger45186b92018-06-05 17:14:42 -07001464 l.closure (&c, lookup_index);
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001465}
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04001466
Garret Rieger57badad2018-06-06 16:02:51 -07001467/**
1468 * hb_ot_layout_lookups_substitute_closure:
Nathan Willis930f6fc2019-03-16 15:10:21 +00001469 * @face: #hb_face_t to work upon
1470 * @lookups: The set of lookups to query
Nathan Willis51228052019-03-17 14:43:06 +00001471 * @glyphs: (out): Array of glyphs comprising the transitive closure of the lookups
Garret Rieger57badad2018-06-06 16:02:51 -07001472 *
1473 * Compute the transitive closure of glyphs needed for all of the
1474 * provided lookups.
1475 *
1476 * Since: 1.8.1
1477 **/
1478void
1479hb_ot_layout_lookups_substitute_closure (hb_face_t *face,
1480 const hb_set_t *lookups,
Nathan Willis930f6fc2019-03-16 15:10:21 +00001481 hb_set_t *glyphs /* OUT */)
Garret Rieger57badad2018-06-06 16:02:51 -07001482{
Behdad Esfahbod3a4e5dd2018-10-29 18:05:25 -07001483 hb_map_t done_lookups;
Garret Rieger57badad2018-06-06 16:02:51 -07001484 OT::hb_closure_context_t c (face, glyphs, &done_lookups);
Behdad Esfahbod737efbe2018-11-05 23:26:29 -05001485 const OT::GSUB& gsub = *face->table.GSUB->table;
Garret Rieger57badad2018-06-06 16:02:51 -07001486
Garret Rieger85646fd2018-07-23 15:37:18 -07001487 unsigned int iteration_count = 0;
Garret Rieger57badad2018-06-06 16:02:51 -07001488 unsigned int glyphs_length;
1489 do
1490 {
1491 glyphs_length = glyphs->get_population ();
Garret Riegerfeb23892018-06-07 14:32:34 -07001492 if (lookups != nullptr)
1493 {
1494 for (hb_codepoint_t lookup_index = HB_SET_VALUE_INVALID; hb_set_next (lookups, &lookup_index);)
1495 gsub.get_lookup (lookup_index).closure (&c, lookup_index);
Behdad Esfahbodf56cd9d2018-06-11 22:02:38 -04001496 }
1497 else
1498 {
Garret Riegerfeb23892018-06-07 14:32:34 -07001499 for (unsigned int i = 0; i < gsub.get_lookup_count (); i++)
1500 gsub.get_lookup (i).closure (&c, i);
1501 }
Behdad Esfahbode44046e2018-11-10 22:41:35 -05001502 } while (iteration_count++ <= HB_CLOSURE_MAX_STAGES &&
1503 glyphs_length != glyphs->get_population ());
Garret Rieger57badad2018-06-06 16:02:51 -07001504}
1505
Behdad Esfahbod9c42f052009-05-18 17:43:49 -04001506/*
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -04001507 * OT::GPOS
Behdad Esfahbod9c42f052009-05-18 17:43:49 -04001508 */
1509
Nathan Willis930f6fc2019-03-16 15:10:21 +00001510
1511/**
1512 * hb_ot_layout_has_positioning:
1513 * @face: #hb_face_t to work upon
1514 *
1515 * Return value: true if the face has GPOS data, false otherwise
1516 *
1517 **/
Behdad Esfahbod9c42f052009-05-18 17:43:49 -04001518hb_bool_t
Behdad Esfahbod0ead4812009-08-02 17:41:36 -04001519hb_ot_layout_has_positioning (hb_face_t *face)
1520{
Behdad Esfahbod737efbe2018-11-05 23:26:29 -05001521 return face->table.GPOS->table->has_data ();
Behdad Esfahbod0ead4812009-08-02 17:41:36 -04001522}
1523
Nathan Willis930f6fc2019-03-16 15:10:21 +00001524/**
1525 * hb_ot_layout_position_start:
1526 * @font: #hb_font_t to use
1527 * @buffer: #hb_buffer_t buffer to work upon
1528 *
Nathan Willis3db22722019-04-02 18:49:40 +01001529 * Called before positioning lookups are performed, to ensure that glyph
1530 * attachment types and glyph-attachment chains are set for the glyphs in the buffer.
1531 *
Nathan Willis930f6fc2019-03-16 15:10:21 +00001532 **/
Behdad Esfahbod8f0d7e02011-04-15 18:59:56 -04001533void
Behdad Esfahbod05bd1b62012-07-30 19:30:01 -04001534hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
Behdad Esfahbod8f0d7e02011-04-15 18:59:56 -04001535{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -04001536 OT::GPOS::position_start (font, buffer);
Behdad Esfahbod8f0d7e02011-04-15 18:59:56 -04001537}
1538
Nathan Willis930f6fc2019-03-16 15:10:21 +00001539
1540/**
1541 * hb_ot_layout_position_finish_advances:
1542 * @font: #hb_font_t to use
1543 * @buffer: #hb_buffer_t buffer to work upon
1544 *
Nathan Willis3db22722019-04-02 18:49:40 +01001545 * Called after positioning lookups are performed, to finish glyph advances.
1546 *
Nathan Willis930f6fc2019-03-16 15:10:21 +00001547 **/
Behdad Esfahbod9db8ad72009-11-06 16:47:31 -05001548void
Behdad Esfahbod7d8d58a2016-02-11 16:34:28 +07001549hb_ot_layout_position_finish_advances (hb_font_t *font, hb_buffer_t *buffer)
Behdad Esfahbod9db8ad72009-11-06 16:47:31 -05001550{
Behdad Esfahbod7d8d58a2016-02-11 16:34:28 +07001551 OT::GPOS::position_finish_advances (font, buffer);
1552}
1553
Nathan Willis3db22722019-04-02 18:49:40 +01001554/**
1555 * hb_ot_layout_position_finish_offsets:
1556 * @font: #hb_font_t to use
1557 * @buffer: #hb_buffer_t buffer to work upon
1558 *
1559 * Called after positioning lookups are performed, to finish glyph offsets.
1560 *
1561 **/
Behdad Esfahbod7d8d58a2016-02-11 16:34:28 +07001562void
1563hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
1564{
1565 OT::GPOS::position_finish_offsets (font, buffer);
Behdad Esfahbod9db8ad72009-11-06 16:47:31 -05001566}
Behdad Esfahbodf54cce32012-11-26 14:02:31 +02001567
Nathan Willis930f6fc2019-03-16 15:10:21 +00001568
Sascha Brawer01c3a882015-06-01 13:22:01 +02001569/**
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +04001570 * hb_ot_layout_get_size_params:
Nathan Willis930f6fc2019-03-16 15:10:21 +00001571 * @face: #hb_face_t to work upon
Nathan Willis51228052019-03-17 14:43:06 +00001572 * @design_size: (out): The design size of the face
1573 * @subfamily_id: (out): The identifier of the face within the font subfamily
Nathan Willisc08ddbd2019-03-24 15:07:07 +00001574 * @subfamily_name_id: (out): The ‘name’ table name ID of the face within the font subfamily
Nathan Willis3db22722019-04-02 18:49:40 +01001575 * @range_start: (out): The minimum size of the recommended size range for the face
1576 * @range_end: (out): The maximum size of the recommended size range for the face
Nathan Willis930f6fc2019-03-16 15:10:21 +00001577 *
Nathan Willisc08ddbd2019-03-24 15:07:07 +00001578 * Fetches optical-size feature data (i.e., the `size` feature from GPOS). Note that
1579 * the subfamily_id and the subfamily name string (accessible via the subfamily_name_id)
1580 * as used here are defined as pertaining only to fonts within a font family that differ
1581 * specifically in their respective size ranges; other ways to differentiate fonts within
1582 * a subfamily are not covered by the `size` feature.
1583 *
1584 * For more information on this distinction, see the `size` documentation at
1585 * https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#tag-39size39
Nathan Willis930f6fc2019-03-16 15:10:21 +00001586 *
1587 * Return value: true if data found, false otherwise
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +04001588 *
Behdad Esfahbodb8811422015-09-03 15:53:22 +04301589 * Since: 0.9.10
Sascha Brawer01c3a882015-06-01 13:22:01 +02001590 **/
Behdad Esfahbodf54cce32012-11-26 14:02:31 +02001591hb_bool_t
Behdad Esfahboda7aba992018-10-30 14:04:09 -07001592hb_ot_layout_get_size_params (hb_face_t *face,
1593 unsigned int *design_size, /* OUT. May be NULL */
1594 unsigned int *subfamily_id, /* OUT. May be NULL */
1595 hb_ot_name_id_t *subfamily_name_id, /* OUT. May be NULL */
1596 unsigned int *range_start, /* OUT. May be NULL */
1597 unsigned int *range_end /* OUT. May be NULL */)
Behdad Esfahbodf54cce32012-11-26 14:02:31 +02001598{
Behdad Esfahbod737efbe2018-11-05 23:26:29 -05001599 const OT::GPOS &gpos = *face->table.GPOS->table;
Behdad Esfahbodefe252e2012-12-17 23:21:05 -05001600 const hb_tag_t tag = HB_TAG ('s','i','z','e');
Behdad Esfahbodf54cce32012-11-26 14:02:31 +02001601
Behdad Esfahbod0dff11f2012-11-30 08:14:20 +02001602 unsigned int num_features = gpos.get_feature_count ();
1603 for (unsigned int i = 0; i < num_features; i++)
1604 {
Behdad Esfahbodefe252e2012-12-17 23:21:05 -05001605 if (tag == gpos.get_feature_tag (i))
Behdad Esfahbodf54cce32012-11-26 14:02:31 +02001606 {
Behdad Esfahbod0dff11f2012-11-30 08:14:20 +02001607 const OT::Feature &f = gpos.get_feature (i);
Behdad Esfahbodefe252e2012-12-17 23:21:05 -05001608 const OT::FeatureParamsSize &params = f.get_feature_params ().get_size_params (tag);
Behdad Esfahbodf54cce32012-11-26 14:02:31 +02001609
Behdad Esfahbodefe252e2012-12-17 23:21:05 -05001610 if (params.designSize)
Behdad Esfahbod85bc44b2012-12-12 11:38:49 -05001611 {
Ebrahim Byagowi63109432018-10-13 14:00:05 +03301612 if (design_size) *design_size = params.designSize;
1613 if (subfamily_id) *subfamily_id = params.subfamilyID;
Behdad Esfahbod6ce49a92018-10-28 08:26:30 -07001614 if (subfamily_name_id) *subfamily_name_id = params.subfamilyNameID;
Ebrahim Byagowi63109432018-10-13 14:00:05 +03301615 if (range_start) *range_start = params.rangeStart;
1616 if (range_end) *range_end = params.rangeEnd;
Behdad Esfahbodefe252e2012-12-17 23:21:05 -05001617
1618 return true;
1619 }
Behdad Esfahbodf54cce32012-11-26 14:02:31 +02001620 }
1621 }
1622
Ebrahim Byagowi63109432018-10-13 14:00:05 +03301623 if (design_size) *design_size = 0;
1624 if (subfamily_id) *subfamily_id = 0;
Behdad Esfahboda7aba992018-10-30 14:04:09 -07001625 if (subfamily_name_id) *subfamily_name_id = HB_OT_NAME_ID_INVALID;
Ebrahim Byagowi63109432018-10-13 14:00:05 +03301626 if (range_start) *range_start = 0;
1627 if (range_end) *range_end = 0;
Behdad Esfahbodf54cce32012-11-26 14:02:31 +02001628
Behdad Esfahbodefe252e2012-12-17 23:21:05 -05001629 return false;
Behdad Esfahbodf54cce32012-11-26 14:02:31 +02001630}
Behdad Esfahbodd2c96812013-05-02 18:18:24 -04001631
Nathan Willis930f6fc2019-03-16 15:10:21 +00001632
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301633/**
1634 * hb_ot_layout_feature_get_name_ids:
1635 * @face: #hb_face_t to work upon
Behdad Esfahboda5ad8c62018-10-20 16:52:55 -07001636 * @table_tag: table tag to query, "GSUB" or "GPOS".
1637 * @feature_index: index of feature to query.
Nathan Willisaf5230b2019-03-18 14:03:16 +00001638 * @label_id: (out) (allow-none): The ‘name’ table name ID that specifies a string
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301639 * for a user-interface label for this feature. (May be NULL.)
Nathan Willisaf5230b2019-03-18 14:03:16 +00001640 * @tooltip_id: (out) (allow-none): The ‘name’ table name ID that specifies a string
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301641 * that an application can use for tooltip text for this
1642 * feature. (May be NULL.)
Nathan Willisaf5230b2019-03-18 14:03:16 +00001643 * @sample_id: (out) (allow-none): The ‘name’ table name ID that specifies sample text
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301644 * that illustrates the effect of this feature. (May be NULL.)
Nathan Willisaf5230b2019-03-18 14:03:16 +00001645 * @num_named_parameters: (out) (allow-none): Number of named parameters. (May be zero.)
1646 * @first_param_id: (out) (allow-none): The first ‘name’ table name ID used to specify
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301647 * strings for user-interface labels for the feature
1648 * parameters. (Must be zero if numParameters is zero.)
1649 *
Behdad Esfahbodc0a68142018-10-12 16:05:56 -04001650 * Fetches name indices from feature parameters for "Stylistic Set" ('ssXX') or
1651 * "Character Variant" ('cvXX') features.
1652 *
1653 * Return value: true if data found, false otherwise
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301654 *
Behdad Esfahbod3d9a0302018-10-18 05:58:17 -07001655 * Since: 2.0.0
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301656 **/
1657hb_bool_t
Behdad Esfahboda7aba992018-10-30 14:04:09 -07001658hb_ot_layout_feature_get_name_ids (hb_face_t *face,
1659 hb_tag_t table_tag,
1660 unsigned int feature_index,
1661 hb_ot_name_id_t *label_id, /* OUT. May be NULL */
1662 hb_ot_name_id_t *tooltip_id, /* OUT. May be NULL */
1663 hb_ot_name_id_t *sample_id, /* OUT. May be NULL */
1664 unsigned int *num_named_parameters, /* OUT. May be NULL */
1665 hb_ot_name_id_t *first_param_id /* OUT. May be NULL */)
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301666{
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301667 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
1668
Behdad Esfahbodc0a68142018-10-12 16:05:56 -04001669 hb_tag_t feature_tag = g.get_feature_tag (feature_index);
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301670 const OT::Feature &f = g.get_feature (feature_index);
1671
1672 const OT::FeatureParams &feature_params = f.get_feature_params ();
1673 if (&feature_params != &Null (OT::FeatureParams))
1674 {
1675 const OT::FeatureParamsStylisticSet& ss_params =
1676 feature_params.get_stylistic_set_params (feature_tag);
1677 if (&ss_params != &Null (OT::FeatureParamsStylisticSet)) /* ssXX */
1678 {
Behdad Esfahbod6ce49a92018-10-28 08:26:30 -07001679 if (label_id) *label_id = ss_params.uiNameID;
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301680 // ssXX features don't have the rest
Behdad Esfahboda7aba992018-10-30 14:04:09 -07001681 if (tooltip_id) *tooltip_id = HB_OT_NAME_ID_INVALID;
1682 if (sample_id) *sample_id = HB_OT_NAME_ID_INVALID;
Ebrahim Byagowi63109432018-10-13 14:00:05 +03301683 if (num_named_parameters) *num_named_parameters = 0;
Behdad Esfahboda7aba992018-10-30 14:04:09 -07001684 if (first_param_id) *first_param_id = HB_OT_NAME_ID_INVALID;
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301685 return true;
1686 }
1687 const OT::FeatureParamsCharacterVariants& cv_params =
1688 feature_params.get_character_variants_params (feature_tag);
1689 if (&cv_params != &Null (OT::FeatureParamsCharacterVariants)) /* cvXX */
1690 {
Behdad Esfahbod6ce49a92018-10-28 08:26:30 -07001691 if (label_id) *label_id = cv_params.featUILableNameID;
1692 if (tooltip_id) *tooltip_id = cv_params.featUITooltipTextNameID;
1693 if (sample_id) *sample_id = cv_params.sampleTextNameID;
Ebrahim Byagowi63109432018-10-13 14:00:05 +03301694 if (num_named_parameters) *num_named_parameters = cv_params.numNamedParameters;
Behdad Esfahbod6ce49a92018-10-28 08:26:30 -07001695 if (first_param_id) *first_param_id = cv_params.firstParamUILabelNameID;
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301696 return true;
1697 }
1698 }
1699
Behdad Esfahboda7aba992018-10-30 14:04:09 -07001700 if (label_id) *label_id = HB_OT_NAME_ID_INVALID;
1701 if (tooltip_id) *tooltip_id = HB_OT_NAME_ID_INVALID;
1702 if (sample_id) *sample_id = HB_OT_NAME_ID_INVALID;
Ebrahim Byagowi63109432018-10-13 14:00:05 +03301703 if (num_named_parameters) *num_named_parameters = 0;
Behdad Esfahboda7aba992018-10-30 14:04:09 -07001704 if (first_param_id) *first_param_id = HB_OT_NAME_ID_INVALID;
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301705 return false;
1706}
1707
Nathan Willis930f6fc2019-03-16 15:10:21 +00001708
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301709/**
Behdad Esfahboda5ad8c62018-10-20 16:52:55 -07001710 * hb_ot_layout_feature_get_characters:
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301711 * @face: #hb_face_t to work upon
Behdad Esfahboda5ad8c62018-10-20 16:52:55 -07001712 * @table_tag: table tag to query, "GSUB" or "GPOS".
1713 * @feature_index: index of feature to query.
Nathan Willis3db22722019-04-02 18:49:40 +01001714 * @start_offset: offset of the first character to retrieve
1715 * @char_count: (inout) (allow-none): Input = the maximum number of characters to return;
1716 * Output = the actual number of characters returned (may be zero)
1717 * @characters: (out caller-allocates) (array length=char_count): A buffer pointer.
1718 * The Unicode codepoints of the characters for which this feature provides
1719 * glyph variants.
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301720 *
Nathan Willis3db22722019-04-02 18:49:40 +01001721 * Fetches a list of the characters defined as having a variant under the specified
1722 * "Character Variant" ("cvXX") feature tag.
Behdad Esfahbodc0a68142018-10-12 16:05:56 -04001723 *
Nathan Willis3db22722019-04-02 18:49:40 +01001724 * <note>Note: If the char_count output value is equal to its input value, then there
1725 * is a chance there were more characters defined under the feature tag than were
1726 * returned. This function can be called with incrementally larger start_offset
1727 * until the char_count output value is lower than its input value, or the size
1728 * of the characters array can be increased.</note>
1729 *
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301730 * Return value: Number of total sample characters in the cvXX feature.
1731 *
Behdad Esfahbod3d9a0302018-10-18 05:58:17 -07001732 * Since: 2.0.0
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301733 **/
1734unsigned int
1735hb_ot_layout_feature_get_characters (hb_face_t *face,
1736 hb_tag_t table_tag,
1737 unsigned int feature_index,
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301738 unsigned int start_offset,
1739 unsigned int *char_count, /* IN/OUT. May be NULL */
1740 hb_codepoint_t *characters /* OUT. May be NULL */)
1741{
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301742 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
1743
Behdad Esfahbodc0a68142018-10-12 16:05:56 -04001744 hb_tag_t feature_tag = g.get_feature_tag (feature_index);
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301745 const OT::Feature &f = g.get_feature (feature_index);
1746
1747 const OT::FeatureParams &feature_params = f.get_feature_params ();
1748
1749 const OT::FeatureParamsCharacterVariants& cv_params =
1750 feature_params.get_character_variants_params(feature_tag);
Ebrahim Byagowi63109432018-10-13 14:00:05 +03301751
1752 unsigned int len = 0;
1753 if (char_count && characters && start_offset < cv_params.characters.len)
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301754 {
Behdad Esfahbod41248cc2019-05-07 20:54:31 -07001755 len = hb_min (cv_params.characters.len - start_offset, *char_count);
Ebrahim Byagowi63109432018-10-13 14:00:05 +03301756 for (unsigned int i = 0; i < len; ++i)
1757 characters[i] = cv_params.characters[start_offset + i];
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301758 }
Ebrahim Byagowi63109432018-10-13 14:00:05 +03301759 if (char_count) *char_count = len;
1760 return cv_params.characters.len;
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301761}
1762
Behdad Esfahbodd2c96812013-05-02 18:18:24 -04001763
1764/*
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001765 * Parts of different types are implemented here such that they have direct
Behdad Esfahbodd2c96812013-05-02 18:18:24 -04001766 * access to GSUB/GPOS lookups.
1767 */
1768
1769
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001770struct GSUBProxy
1771{
Behdad Esfahbod5d4b0372019-01-22 12:11:24 +01001772 static constexpr unsigned table_index = 0u;
Behdad Esfahbod39e1b6d2019-01-22 12:07:43 +01001773 static constexpr bool inplace = false;
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001774 typedef OT::SubstLookup Lookup;
1775
1776 GSUBProxy (hb_face_t *face) :
Behdad Esfahbod0fe7a742018-11-05 23:08:33 -05001777 table (*face->table.GSUB->table),
1778 accels (face->table.GSUB->accels) {}
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001779
1780 const OT::GSUB &table;
Behdad Esfahbod97e59132018-10-10 11:41:05 -04001781 const OT::hb_ot_layout_lookup_accelerator_t *accels;
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001782};
1783
1784struct GPOSProxy
1785{
Behdad Esfahbod5d4b0372019-01-22 12:11:24 +01001786 static constexpr unsigned table_index = 1u;
Behdad Esfahbod39e1b6d2019-01-22 12:07:43 +01001787 static constexpr bool inplace = true;
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001788 typedef OT::PosLookup Lookup;
1789
1790 GPOSProxy (hb_face_t *face) :
Behdad Esfahbod0fe7a742018-11-05 23:08:33 -05001791 table (*face->table.GPOS->table),
1792 accels (face->table.GPOS->accels) {}
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001793
1794 const OT::GPOS &table;
Behdad Esfahbod97e59132018-10-10 11:41:05 -04001795 const OT::hb_ot_layout_lookup_accelerator_t *accels;
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001796};
1797
1798
Behdad Esfahbode2f50f22015-02-19 17:15:05 +03001799static inline bool
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001800apply_forward (OT::hb_ot_apply_context_t *c,
Behdad Esfahbod78c09bf2018-10-10 11:50:46 -04001801 const OT::hb_ot_layout_lookup_accelerator_t &accel)
Behdad Esfahbode2f50f22015-02-19 17:15:05 +03001802{
1803 bool ret = false;
1804 hb_buffer_t *buffer = c->buffer;
Behdad Esfahbod7185b272018-05-31 20:03:00 -07001805 while (buffer->idx < buffer->len && buffer->successful)
Behdad Esfahbode2f50f22015-02-19 17:15:05 +03001806 {
Behdad Esfahbod3e704522016-01-11 17:38:41 +00001807 bool applied = false;
Behdad Esfahbode2f50f22015-02-19 17:15:05 +03001808 if (accel.may_have (buffer->cur().codepoint) &&
1809 (buffer->cur().mask & c->lookup_mask) &&
Behdad Esfahbod3e704522016-01-11 17:38:41 +00001810 c->check_glyph_property (&buffer->cur(), c->lookup_props))
1811 {
Behdad Esfahbode78549e2018-10-10 11:54:48 -04001812 applied = accel.apply (c);
Behdad Esfahbod3e704522016-01-11 17:38:41 +00001813 }
1814
1815 if (applied)
Behdad Esfahbode2f50f22015-02-19 17:15:05 +03001816 ret = true;
1817 else
1818 buffer->next_glyph ();
1819 }
1820 return ret;
1821}
1822
Behdad Esfahbode2f50f22015-02-19 17:15:05 +03001823static inline bool
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001824apply_backward (OT::hb_ot_apply_context_t *c,
Behdad Esfahbod78c09bf2018-10-10 11:50:46 -04001825 const OT::hb_ot_layout_lookup_accelerator_t &accel)
Behdad Esfahbode2f50f22015-02-19 17:15:05 +03001826{
1827 bool ret = false;
1828 hb_buffer_t *buffer = c->buffer;
1829 do
1830 {
1831 if (accel.may_have (buffer->cur().codepoint) &&
1832 (buffer->cur().mask & c->lookup_mask) &&
Behdad Esfahbod3e704522016-01-11 17:38:41 +00001833 c->check_glyph_property (&buffer->cur(), c->lookup_props))
Behdad Esfahbod9af983a2018-11-07 16:03:09 -05001834 ret |= accel.apply (c);
1835
Behdad Esfahbode2f50f22015-02-19 17:15:05 +03001836 /* The reverse lookup doesn't "advance" cursor (for good reason). */
1837 buffer->idx--;
1838
1839 }
1840 while ((int) buffer->idx >= 0);
1841 return ret;
1842}
1843
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04001844template <typename Proxy>
Behdad Esfahbod1d4a3282015-02-19 11:33:30 +03001845static inline void
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001846apply_string (OT::hb_ot_apply_context_t *c,
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04001847 const typename Proxy::Lookup &lookup,
Behdad Esfahbod97e59132018-10-10 11:41:05 -04001848 const OT::hb_ot_layout_lookup_accelerator_t &accel)
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04001849{
Behdad Esfahbodac8cd512013-10-18 19:33:09 +02001850 hb_buffer_t *buffer = c->buffer;
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04001851
Behdad Esfahbod5337db22015-11-06 16:18:09 -08001852 if (unlikely (!buffer->len || !c->lookup_mask))
Behdad Esfahbod1d4a3282015-02-19 11:33:30 +03001853 return;
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04001854
Behdad Esfahbod2c8b3b22015-08-18 14:36:43 +01001855 c->set_lookup_props (lookup.get_props ());
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04001856
1857 if (likely (!lookup.is_reverse ()))
1858 {
1859 /* in/out forward substitution/positioning */
Behdad Esfahbod271cb7c2019-01-22 12:05:35 +01001860 if (Proxy::table_index == 0u)
Behdad Esfahbodac8cd512013-10-18 19:33:09 +02001861 buffer->clear_output ();
1862 buffer->idx = 0;
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04001863
Behdad Esfahbod640b66c2015-02-19 17:30:05 +03001864 bool ret;
Behdad Esfahbod78c09bf2018-10-10 11:50:46 -04001865 ret = apply_forward (c, accel);
Behdad Esfahbod640b66c2015-02-19 17:30:05 +03001866 if (ret)
Behdad Esfahbod9d9e72e2013-05-03 18:10:10 -04001867 {
Behdad Esfahbod6ffc0072013-10-28 19:26:02 +01001868 if (!Proxy::inplace)
Behdad Esfahbodac8cd512013-10-18 19:33:09 +02001869 buffer->swap_buffers ();
Behdad Esfahbod9d9e72e2013-05-03 18:10:10 -04001870 else
Behdad Esfahbod1d4a3282015-02-19 11:33:30 +03001871 assert (!buffer->has_separate_output ());
Behdad Esfahbod9d9e72e2013-05-03 18:10:10 -04001872 }
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04001873 }
1874 else
1875 {
1876 /* in-place backward substitution/positioning */
Behdad Esfahbod271cb7c2019-01-22 12:05:35 +01001877 if (Proxy::table_index == 0u)
Behdad Esfahbodac8cd512013-10-18 19:33:09 +02001878 buffer->remove_output ();
1879 buffer->idx = buffer->len - 1;
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04001880
Behdad Esfahbod78c09bf2018-10-10 11:50:46 -04001881 apply_backward (c, accel);
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04001882 }
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04001883}
1884
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001885template <typename Proxy>
1886inline void hb_ot_map_t::apply (const Proxy &proxy,
Behdad Esfahbodd2c96812013-05-02 18:18:24 -04001887 const hb_ot_shape_plan_t *plan,
1888 hb_font_t *font,
1889 hb_buffer_t *buffer) const
1890{
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001891 const unsigned int table_index = proxy.table_index;
Behdad Esfahbodd2c96812013-05-02 18:18:24 -04001892 unsigned int i = 0;
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001893 OT::hb_ot_apply_context_t c (table_index, font, buffer);
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04001894 c.set_recurse_func (Proxy::Lookup::apply_recurse_func);
Behdad Esfahbodd2c96812013-05-02 18:18:24 -04001895
Behdad Esfahbod474a1202018-12-21 18:46:51 -05001896 for (unsigned int stage_index = 0; stage_index < stages[table_index].length; stage_index++) {
Behdad Esfahbodd2c96812013-05-02 18:18:24 -04001897 const stage_map_t *stage = &stages[table_index][stage_index];
1898 for (; i < stage->last_lookup; i++)
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001899 {
1900 unsigned int lookup_index = lookups[table_index][i].index;
Behdad Esfahbod0475ef22015-12-18 18:17:07 +00001901 if (!buffer->message (font, "start lookup %d", lookup_index)) continue;
Behdad Esfahbod2c8b3b22015-08-18 14:36:43 +01001902 c.set_lookup_index (lookup_index);
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001903 c.set_lookup_mask (lookups[table_index][i].mask);
1904 c.set_auto_zwj (lookups[table_index][i].auto_zwj);
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +01001905 c.set_auto_zwnj (lookups[table_index][i].auto_zwnj);
David Corbettc2a75e02018-01-25 14:22:03 -05001906 if (lookups[table_index][i].random)
1907 {
David Corbettb545e272018-02-23 12:22:32 -05001908 c.set_random (true);
David Corbettc2a75e02018-01-25 14:22:03 -05001909 buffer->unsafe_to_break_all ();
1910 }
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04001911 apply_string<Proxy> (&c,
1912 proxy.table.get_lookup (lookup_index),
1913 proxy.accels[lookup_index]);
Behdad Esfahbod0475ef22015-12-18 18:17:07 +00001914 (void) buffer->message (font, "end lookup %d", lookup_index);
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001915 }
Behdad Esfahbodd2c96812013-05-02 18:18:24 -04001916
1917 if (stage->pause_func)
1918 {
1919 buffer->clear_output ();
1920 stage->pause_func (plan, font, buffer);
1921 }
1922 }
1923}
1924
1925void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
1926{
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001927 GSUBProxy proxy (font->face);
1928 apply (proxy, plan, font, buffer);
Behdad Esfahbodd2c96812013-05-02 18:18:24 -04001929}
1930
1931void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
1932{
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001933 GPOSProxy proxy (font->face);
1934 apply (proxy, plan, font, buffer);
1935}
1936
Behdad Esfahbodcdab20d2018-02-10 15:45:17 -06001937void
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001938hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001939 const OT::SubstLookup &lookup,
Behdad Esfahbod97e59132018-10-10 11:41:05 -04001940 const OT::hb_ot_layout_lookup_accelerator_t &accel)
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001941{
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04001942 apply_string<GSUBProxy> (c, lookup, accel);
Behdad Esfahbodd2c96812013-05-02 18:18:24 -04001943}
Ebrahim Byagowib8a78ce2018-11-03 22:28:30 +03301944
1945#if 0
1946static const OT::BASE& _get_base (hb_face_t *face)
1947{
Behdad Esfahbod0fe7a742018-11-05 23:08:33 -05001948 return *face->table.BASE;
Ebrahim Byagowib8a78ce2018-11-03 22:28:30 +03301949}
1950
1951hb_bool_t
1952hb_ot_layout_get_baseline (hb_font_t *font,
1953 hb_ot_layout_baseline_t baseline,
1954 hb_direction_t direction,
1955 hb_tag_t script_tag,
1956 hb_tag_t language_tag,
1957 hb_position_t *coord /* OUT. May be NULL. */)
1958{
1959 const OT::BASE &base = _get_base (font->face);
1960 bool result = base.get_baseline (font, baseline, direction, script_tag,
1961 language_tag, coord);
1962
1963 /* TODO: Simulate https://docs.microsoft.com/en-us/typography/opentype/spec/baselinetags#ideographic-em-box */
1964 if (!result && coord) *coord = 0;
1965
1966 if (coord) *coord = font->em_scale_dir (*coord, direction);
1967
1968 return result;
1969}
1970
1971/* To be moved to public header */
1972/*
1973 * BASE
1974 */
1975
1976/**
1977 * hb_ot_layout_baseline_t:
1978 *
1979 * https://docs.microsoft.com/en-us/typography/opentype/spec/baselinetags
1980 *
1981 * Since: DONTREPLACEME
1982 */
1983typedef enum {
1984 HB_OT_LAYOUT_BASELINE_HANG = HB_TAG('h','a','n','g'),
1985 HB_OT_LAYOUT_BASELINE_ICFB = HB_TAG('i','c','f','b'),
1986 HB_OT_LAYOUT_BASELINE_ICFT = HB_TAG('i','c','f','t'),
1987 HB_OT_LAYOUT_BASELINE_IDEO = HB_TAG('i','d','e','o'),
1988 HB_OT_LAYOUT_BASELINE_IDTB = HB_TAG('i','d','t','b'),
1989 HB_OT_LAYOUT_BASELINE_MATH = HB_TAG('m','a','t','h'),
1990 HB_OT_LAYOUT_BASELINE_ROMN = HB_TAG('r','o','m','n')
1991} hb_ot_layout_baseline_t;
1992
Nathan Willis930f6fc2019-03-16 15:10:21 +00001993
1994/**
1995 * hb_ot_layout_get_baseline:
1996 * @font: The #hb_font_t to work upon
1997 * @baseline: The #hb_ot_layout_baseline_t to query
Nathan Willisc08ddbd2019-03-24 15:07:07 +00001998 * @direction: The #hb_direction_t text direction to use (horizontal or vertical)
Nathan Willis930f6fc2019-03-16 15:10:21 +00001999 * @script_tag: #hb_tag_t of the script to use
2000 * @language_tag: #hb_tag_t of the language to use
Nathan Willis51228052019-03-17 14:43:06 +00002001 * @coord: (out): The position of the requested baseline
Nathan Willis930f6fc2019-03-16 15:10:21 +00002002 *
2003 * Fetches the coordinates of the specified baseline in the face, underneath
2004 * the specified script and language and in the specified text direction.
2005 *
2006 * Return value: true if the baseline is found for the settings queried, false otherwise
2007 *
2008 **/
Ebrahim Byagowib8a78ce2018-11-03 22:28:30 +03302009HB_EXTERN hb_bool_t
2010hb_ot_layout_get_baseline (hb_font_t *font,
2011 hb_ot_layout_baseline_t baseline,
2012 hb_direction_t direction,
2013 hb_tag_t script_tag,
2014 hb_tag_t language_tag,
2015 hb_position_t *coord /* OUT. May be NULL. */);
2016
2017#endif