blob: 63ccab885d5608014b251cfebfe513d0c0ab4f7c [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 Esfahbodbb4bbe62019-06-26 13:29:58 -070031#include "hb.hh"
32
33#ifndef HB_NO_OT_LAYOUT
34
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070035#include "hb-open-type.hh"
36#include "hb-ot-layout.hh"
Behdad Esfahbodb9291002018-08-26 01:15:47 -070037#include "hb-ot-face.hh"
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070038#include "hb-ot-map.hh"
39#include "hb-map.hh"
Ebrahim Byagowi5b9c2342018-02-27 22:56:17 +033040
Behdad Esfahbod574d8882018-11-25 16:51:22 -050041#include "hb-ot-kern-table.hh"
Ebrahim Byagowi8f80e532018-12-05 13:51:14 +033042#include "hb-ot-gasp-table.hh" // Just so we compile it; unused otherwise.
Behdad Esfahbod7a750ac2011-08-17 14:19:59 +020043#include "hb-ot-layout-gdef-table.hh"
44#include "hb-ot-layout-gsub-table.hh"
45#include "hb-ot-layout-gpos-table.hh"
Ebrahim Byagowi8f80e532018-12-05 13:51:14 +033046#include "hb-ot-layout-base-table.hh" // Just so we compile it; unused otherwise.
47#include "hb-ot-layout-jstf-table.hh" // Just so we compile it; unused otherwise.
Behdad Esfahbod203dc442018-05-03 21:03:27 -040048#include "hb-ot-name-table.hh"
Behdad Esfahbod574d8882018-11-25 16:51:22 -050049#include "hb-ot-os2-table.hh"
Behdad Esfahbodd2c96812013-05-02 18:18:24 -040050
Ebrahim Byagowib986fea2018-11-05 12:31:58 +033051#include "hb-aat-layout-lcar-table.hh"
Behdad Esfahbod574d8882018-11-25 16:51:22 -050052#include "hb-aat-layout-morx-table.hh"
Ebrahim Byagowib986fea2018-11-05 12:31:58 +033053
Behdad Esfahbodaff831e2008-01-24 06:03:45 -050054
Behdad Esfahbod80d9a422018-10-27 04:58:32 -070055/**
56 * SECTION:hb-ot-layout
57 * @title: hb-ot-layout
58 * @short_description: OpenType Layout
59 * @include: hb-ot.h
60 *
61 * Functions for querying OpenType Layout features in the font face.
62 **/
63
64
Behdad Esfahbod590d55c2008-01-24 19:13:50 -050065/*
Behdad Esfahboda5195882018-10-08 23:57:45 -040066 * kern
67 */
68
Behdad Esfahbod588697a2019-06-19 16:24:51 -070069#ifndef HB_NO_OT_KERN
Nathan Willis930f6fc2019-03-16 15:10:21 +000070/**
71 * hb_ot_layout_has_kerning:
72 * @face: The #hb_face_t to work on
73 *
Nathan Willisd3178aa2019-03-17 14:27:27 +000074 * Tests whether a face includes any kerning data in the 'kern' table.
75 * Does NOT test for kerning lookups in the GPOS table.
Nathan Willis930f6fc2019-03-16 15:10:21 +000076 *
77 * Return value: true if data found, false otherwise
78 *
79 **/
Behdad Esfahbod385f78b2018-11-07 17:19:21 -050080bool
Behdad Esfahboda5195882018-10-08 23:57:45 -040081hb_ot_layout_has_kerning (hb_face_t *face)
82{
Behdad Esfahboda35c92c2018-11-05 22:58:43 -050083 return face->table.kern->has_data ();
Behdad Esfahboda5195882018-10-08 23:57:45 -040084}
85
Nathan Willis930f6fc2019-03-16 15:10:21 +000086/**
87 * hb_ot_layout_has_machine_kerning:
88 * @face: The #hb_face_t to work on
89 *
Nathan Willisd3178aa2019-03-17 14:27:27 +000090 * Tests whether a face includes any state-machine kerning in the 'kern' table.
91 * Does NOT examine the GPOS table.
Nathan Willis930f6fc2019-03-16 15:10:21 +000092 *
93 * Return value: true if data found, false otherwise
94 *
95 **/
Behdad Esfahbod385f78b2018-11-07 17:19:21 -050096bool
Behdad Esfahbod74896222018-11-23 11:10:17 -050097hb_ot_layout_has_machine_kerning (hb_face_t *face)
98{
99 return face->table.kern->has_state_machine ();
100}
101
Nathan Willis930f6fc2019-03-16 15:10:21 +0000102/**
103 * hb_ot_layout_has_cross_kerning:
104 * @face: The #hb_face_t to work on
105 *
106 * Tests whether a face has any cross-stream kerning (i.e., kerns
107 * that make adjustments perpendicular to the direction of the text
108 * flow: Y adjustments in horizontal text or X adjustments in
Nathan Willisd3178aa2019-03-17 14:27:27 +0000109 * vertical text) in the 'kern' table.
110 *
111 * Does NOT examine the GPOS table.
Nathan Willis930f6fc2019-03-16 15:10:21 +0000112 *
113 * Return value: true is data found, false otherwise
114 *
115 **/
Behdad Esfahbod74896222018-11-23 11:10:17 -0500116bool
Behdad Esfahbodca235672018-11-07 16:19:51 -0500117hb_ot_layout_has_cross_kerning (hb_face_t *face)
118{
119 return face->table.kern->has_cross_stream ();
120}
121
Behdad Esfahboda5195882018-10-08 23:57:45 -0400122void
Behdad Esfahbodc221dc02018-11-14 14:49:34 -0500123hb_ot_layout_kern (const hb_ot_shape_plan_t *plan,
Behdad Esfahbod095f5ad2018-11-02 13:23:54 -0400124 hb_font_t *font,
125 hb_buffer_t *buffer)
Behdad Esfahboda5195882018-10-08 23:57:45 -0400126{
Behdad Esfahboda35c92c2018-11-05 22:58:43 -0500127 hb_blob_t *blob = font->face->table.kern.get_blob ();
Behdad Esfahbodfa3ebf82018-11-05 23:34:07 -0500128 const AAT::kern& kern = *blob->as<AAT::kern> ();
Behdad Esfahbod095f5ad2018-11-02 13:23:54 -0400129
130 AAT::hb_aat_apply_context_t c (plan, font, buffer, blob);
131
132 kern.apply (&c);
Behdad Esfahboda5195882018-10-08 23:57:45 -0400133}
Behdad Esfahbod588697a2019-06-19 16:24:51 -0700134#endif
Behdad Esfahboda5195882018-10-08 23:57:45 -0400135
136
137/*
Behdad Esfahbod590d55c2008-01-24 19:13:50 -0500138 * GDEF
139 */
140
Behdad Esfahbod4f217032018-11-25 15:59:18 -0500141bool
142OT::GDEF::is_blacklisted (hb_blob_t *blob,
143 hb_face_t *face) const
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700144{
Behdad Esfahbod227d85e2019-05-10 23:15:58 -0700145#ifdef HB_NO_OT_LAYOUT_BLACKLIST
Behdad Esfahbod9ddbfa02019-04-12 09:33:25 -0400146 return false;
147#endif
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700148 /* The ugly business of blacklisting individual fonts' tables happen here!
149 * See this thread for why we finally had to bend in and do this:
150 * https://lists.freedesktop.org/archives/harfbuzz/2016-February/005489.html
151 *
152 * In certain versions of Times New Roman Italic and Bold Italic,
153 * ASCII double quotation mark U+0022 has wrong glyph class 3 (mark)
154 * in GDEF. Many versions of Tahoma have bad GDEF tables that
155 * incorrectly classify some spacing marks such as certain IPA
156 * symbols as glyph class 3. So do older versions of Microsoft
157 * Himalaya, and the version of Cantarell shipped by Ubuntu 16.04.
158 *
159 * Nuke the GDEF tables of to avoid unwanted width-zeroing.
160 *
161 * See https://bugzilla.mozilla.org/show_bug.cgi?id=1279925
162 * https://bugzilla.mozilla.org/show_bug.cgi?id=1279693
163 * https://bugzilla.mozilla.org/show_bug.cgi?id=1279875
164 */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400165 switch HB_CODEPOINT_ENCODE3(blob->length,
166 face->table.GSUB->table.get_length (),
167 face->table.GPOS->table.get_length ())
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700168 {
169 /* sha1sum:c5ee92f0bca4bfb7d06c4d03e8cf9f9cf75d2e8a Windows 7? timesi.ttf */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400170 case HB_CODEPOINT_ENCODE3 (442, 2874, 42038):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700171 /* sha1sum:37fc8c16a0894ab7b749e35579856c73c840867b Windows 7? timesbi.ttf */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400172 case HB_CODEPOINT_ENCODE3 (430, 2874, 40662):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700173 /* sha1sum:19fc45110ea6cd3cdd0a5faca256a3797a069a80 Windows 7 timesi.ttf */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400174 case HB_CODEPOINT_ENCODE3 (442, 2874, 39116):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700175 /* sha1sum:6d2d3c9ed5b7de87bc84eae0df95ee5232ecde26 Windows 7 timesbi.ttf */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400176 case HB_CODEPOINT_ENCODE3 (430, 2874, 39374):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700177 /* sha1sum:8583225a8b49667c077b3525333f84af08c6bcd8 OS X 10.11.3 Times New Roman Italic.ttf */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400178 case HB_CODEPOINT_ENCODE3 (490, 3046, 41638):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700179 /* sha1sum:ec0f5a8751845355b7c3271d11f9918a966cb8c9 OS X 10.11.3 Times New Roman Bold Italic.ttf */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400180 case HB_CODEPOINT_ENCODE3 (478, 3046, 41902):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700181 /* sha1sum:96eda93f7d33e79962451c6c39a6b51ee893ce8c tahoma.ttf from Windows 8 */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400182 case HB_CODEPOINT_ENCODE3 (898, 12554, 46470):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700183 /* sha1sum:20928dc06014e0cd120b6fc942d0c3b1a46ac2bc tahomabd.ttf from Windows 8 */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400184 case HB_CODEPOINT_ENCODE3 (910, 12566, 47732):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700185 /* sha1sum:4f95b7e4878f60fa3a39ca269618dfde9721a79e tahoma.ttf from Windows 8.1 */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400186 case HB_CODEPOINT_ENCODE3 (928, 23298, 59332):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700187 /* sha1sum:6d400781948517c3c0441ba42acb309584b73033 tahomabd.ttf from Windows 8.1 */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400188 case HB_CODEPOINT_ENCODE3 (940, 23310, 60732):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700189 /* tahoma.ttf v6.04 from Windows 8.1 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400190 case HB_CODEPOINT_ENCODE3 (964, 23836, 60072):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700191 /* tahomabd.ttf v6.04 from Windows 8.1 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400192 case HB_CODEPOINT_ENCODE3 (976, 23832, 61456):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700193 /* sha1sum:e55fa2dfe957a9f7ec26be516a0e30b0c925f846 tahoma.ttf from Windows 10 */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400194 case HB_CODEPOINT_ENCODE3 (994, 24474, 60336):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700195 /* sha1sum:7199385abb4c2cc81c83a151a7599b6368e92343 tahomabd.ttf from Windows 10 */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400196 case HB_CODEPOINT_ENCODE3 (1006, 24470, 61740):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700197 /* tahoma.ttf v6.91 from Windows 10 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400198 case HB_CODEPOINT_ENCODE3 (1006, 24576, 61346):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700199 /* tahomabd.ttf v6.91 from Windows 10 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400200 case HB_CODEPOINT_ENCODE3 (1018, 24572, 62828):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700201 /* sha1sum:b9c84d820c49850d3d27ec498be93955b82772b5 tahoma.ttf from Windows 10 AU */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400202 case HB_CODEPOINT_ENCODE3 (1006, 24576, 61352):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700203 /* sha1sum:2bdfaab28174bdadd2f3d4200a30a7ae31db79d2 tahomabd.ttf from Windows 10 AU */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400204 case HB_CODEPOINT_ENCODE3 (1018, 24572, 62834):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700205 /* sha1sum:b0d36cf5a2fbe746a3dd277bffc6756a820807a7 Tahoma.ttf from Mac OS X 10.9 */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400206 case HB_CODEPOINT_ENCODE3 (832, 7324, 47162):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700207 /* sha1sum:12fc4538e84d461771b30c18b5eb6bd434e30fba Tahoma Bold.ttf from Mac OS X 10.9 */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400208 case HB_CODEPOINT_ENCODE3 (844, 7302, 45474):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700209 /* sha1sum:eb8afadd28e9cf963e886b23a30b44ab4fd83acc himalaya.ttf from Windows 7 */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400210 case HB_CODEPOINT_ENCODE3 (180, 13054, 7254):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700211 /* sha1sum:73da7f025b238a3f737aa1fde22577a6370f77b0 himalaya.ttf from Windows 8 */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400212 case HB_CODEPOINT_ENCODE3 (192, 12638, 7254):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700213 /* sha1sum:6e80fd1c0b059bbee49272401583160dc1e6a427 himalaya.ttf from Windows 8.1 */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400214 case HB_CODEPOINT_ENCODE3 (192, 12690, 7254):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700215 /* 8d9267aea9cd2c852ecfb9f12a6e834bfaeafe44 cantarell-fonts-0.0.21/otf/Cantarell-Regular.otf */
216 /* 983988ff7b47439ab79aeaf9a45bd4a2c5b9d371 cantarell-fonts-0.0.21/otf/Cantarell-Oblique.otf */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400217 case HB_CODEPOINT_ENCODE3 (188, 248, 3852):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700218 /* 2c0c90c6f6087ffbfea76589c93113a9cbb0e75f cantarell-fonts-0.0.21/otf/Cantarell-Bold.otf */
219 /* 55461f5b853c6da88069ffcdf7f4dd3f8d7e3e6b cantarell-fonts-0.0.21/otf/Cantarell-Bold-Oblique.otf */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400220 case HB_CODEPOINT_ENCODE3 (188, 264, 3426):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700221 /* d125afa82a77a6475ac0e74e7c207914af84b37a padauk-2.80/Padauk.ttf RHEL 7.2 */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400222 case HB_CODEPOINT_ENCODE3 (1058, 47032, 11818):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700223 /* 0f7b80437227b90a577cc078c0216160ae61b031 padauk-2.80/Padauk-Bold.ttf RHEL 7.2*/
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400224 case HB_CODEPOINT_ENCODE3 (1046, 47030, 12600):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700225 /* d3dde9aa0a6b7f8f6a89ef1002e9aaa11b882290 padauk-2.80/Padauk.ttf Ubuntu 16.04 */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400226 case HB_CODEPOINT_ENCODE3 (1058, 71796, 16770):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700227 /* 5f3c98ccccae8a953be2d122c1b3a77fd805093f padauk-2.80/Padauk-Bold.ttf Ubuntu 16.04 */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400228 case HB_CODEPOINT_ENCODE3 (1046, 71790, 17862):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700229 /* 6c93b63b64e8b2c93f5e824e78caca555dc887c7 padauk-2.80/Padauk-book.ttf */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400230 case HB_CODEPOINT_ENCODE3 (1046, 71788, 17112):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700231 /* d89b1664058359b8ec82e35d3531931125991fb9 padauk-2.80/Padauk-bookbold.ttf */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400232 case HB_CODEPOINT_ENCODE3 (1058, 71794, 17514):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700233 /* 824cfd193aaf6234b2b4dc0cf3c6ef576c0d00ef padauk-3.0/Padauk-book.ttf */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400234 case HB_CODEPOINT_ENCODE3 (1330, 109904, 57938):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700235 /* 91fcc10cf15e012d27571e075b3b4dfe31754a8a padauk-3.0/Padauk-bookbold.ttf */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400236 case HB_CODEPOINT_ENCODE3 (1330, 109904, 58972):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700237 /* sha1sum: c26e41d567ed821bed997e937bc0c41435689e85 Padauk.ttf
238 * "Padauk Regular" "Version 2.5", see https://crbug.com/681813 */
Behdad Esfahbod65392b72019-05-22 16:21:21 -0400239 case HB_CODEPOINT_ENCODE3 (1004, 59092, 14836):
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700240 return true;
Behdad Esfahbodd8c57e82018-08-26 09:03:31 -0700241 }
242 return false;
243}
244
Behdad Esfahbodc624e182018-08-26 09:19:20 -0700245static void
246_hb_ot_layout_set_glyph_props (hb_font_t *font,
247 hb_buffer_t *buffer)
248{
249 _hb_buffer_assert_gsubgpos_vars (buffer);
250
Behdad Esfahbod5e68cec2018-11-05 23:23:57 -0500251 const OT::GDEF &gdef = *font->face->table.GDEF->table;
Behdad Esfahbodc624e182018-08-26 09:19:20 -0700252 unsigned int count = buffer->len;
253 for (unsigned int i = 0; i < count; i++)
254 {
255 _hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint));
256 _hb_glyph_info_clear_lig_props (&buffer->info[i]);
257 buffer->info[i].syllable() = 0;
258 }
259}
260
261/* Public API */
262
Nathan Willis930f6fc2019-03-16 15:10:21 +0000263/**
264 * hb_ot_layout_has_glyph_classes:
265 * @face: #hb_face_t to work upon
266 *
267 * Tests whether a face has any glyph classes defined in its GDEF table.
268 *
269 * Return value: true if data found, false otherwise
270 *
271 **/
Behdad Esfahbod590d55c2008-01-24 19:13:50 -0500272hb_bool_t
Behdad Esfahbod52ea4772009-11-06 17:45:38 -0500273hb_ot_layout_has_glyph_classes (hb_face_t *face)
Behdad Esfahbod590d55c2008-01-24 19:13:50 -0500274{
Behdad Esfahbod5e68cec2018-11-05 23:23:57 -0500275 return face->table.GDEF->table->has_glyph_classes ();
Behdad Esfahbod590d55c2008-01-24 19:13:50 -0500276}
277
Sascha Brawer01c3a882015-06-01 13:22:01 +0200278/**
Behdad Esfahbod35d18582015-11-26 19:30:37 -0500279 * hb_ot_layout_get_glyph_class:
Nathan Willis930f6fc2019-03-16 15:10:21 +0000280 * @face: The #hb_face_t to work on
281 * @glyph: The #hb_codepoint_t code point to query
282 *
283 * Fetches the GDEF class of the requested glyph in the specified face.
284 *
Nathan Willisc08ddbd2019-03-24 15:07:07 +0000285 * Return value: The #hb_ot_layout_glyph_class_t glyph class of the given code
286 * point in the GDEF table of the face.
Behdad Esfahbod35d18582015-11-26 19:30:37 -0500287 *
Sascha Brawer01c3a882015-06-01 13:22:01 +0200288 * Since: 0.9.7
289 **/
Behdad Esfahbod5a08ecf2012-11-16 13:34:29 -0800290hb_ot_layout_glyph_class_t
291hb_ot_layout_get_glyph_class (hb_face_t *face,
292 hb_codepoint_t glyph)
293{
Behdad Esfahbod5e68cec2018-11-05 23:23:57 -0500294 return (hb_ot_layout_glyph_class_t) face->table.GDEF->table->get_glyph_class (glyph);
Behdad Esfahbod5a08ecf2012-11-16 13:34:29 -0800295}
Behdad Esfahbod4a2d8442010-11-03 15:28:56 -0400296
Sascha Brawer01c3a882015-06-01 13:22:01 +0200297/**
Behdad Esfahbod35d18582015-11-26 19:30:37 -0500298 * hb_ot_layout_get_glyphs_in_class:
Nathan Willis930f6fc2019-03-16 15:10:21 +0000299 * @face: The #hb_face_t to work on
300 * @klass: The #hb_ot_layout_glyph_class_t GDEF class to retrieve
301 * @glyphs: (out): The #hb_set_t set of all glyphs belonging to the requested
302 * class.
303 *
304 * Retrieves the set of all glyphs from the face that belong to the requested
305 * glyph class in the face's GDEF table.
Behdad Esfahbod35d18582015-11-26 19:30:37 -0500306 *
Sascha Brawer01c3a882015-06-01 13:22:01 +0200307 * Since: 0.9.7
308 **/
Behdad Esfahbod89ca8ee2012-11-16 13:53:40 -0800309void
310hb_ot_layout_get_glyphs_in_class (hb_face_t *face,
311 hb_ot_layout_glyph_class_t klass,
312 hb_set_t *glyphs /* OUT */)
313{
Behdad Esfahbod5e68cec2018-11-05 23:23:57 -0500314 return face->table.GDEF->table->get_glyphs_in_class (klass, glyphs);
Behdad Esfahbod89ca8ee2012-11-16 13:53:40 -0800315}
316
Nathan Willis930f6fc2019-03-16 15:10:21 +0000317
Behdad Esfahbodbf9424a2019-06-18 13:31:35 -0700318#ifndef HB_NO_LAYOUT_UNUSED
Nathan Willis930f6fc2019-03-16 15:10:21 +0000319/**
320 * hb_ot_layout_get_attach_points:
321 * @face: The #hb_face_t to work on
322 * @glyph: The #hb_codepoint_t code point to query
Nathan Willis3db22722019-04-02 18:49:40 +0100323 * @start_offset: offset of the first attachment point to retrieve
324 * @point_count: (inout) (allow-none): Input = the maximum number of attachment points to return;
325 * Output = the actual number of attachment points returned (may be zero)
326 * @point_array: (out) (array length=point_count): The array of attachment points found for the query
Nathan Willis930f6fc2019-03-16 15:10:21 +0000327 *
328 * Fetches a list of all attachment points for the specified glyph in the GDEF
329 * table of the face. The list returned will begin at the offset provided.
330 *
331 * Useful if the client program wishes to cache the list.
332 *
333 **/
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500334unsigned int
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400335hb_ot_layout_get_attach_points (hb_face_t *face,
Behdad Esfahbod79420ad2009-05-26 12:24:16 -0400336 hb_codepoint_t glyph,
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500337 unsigned int start_offset,
Behdad Esfahbod79420ad2009-05-26 12:24:16 -0400338 unsigned int *point_count /* IN/OUT */,
339 unsigned int *point_array /* OUT */)
340{
Behdad Esfahbod5e68cec2018-11-05 23:23:57 -0500341 return face->table.GDEF->table->get_attach_points (glyph,
342 start_offset,
343 point_count,
344 point_array);
Behdad Esfahbod62964af2009-05-26 12:40:10 -0400345}
Nathan Willis930f6fc2019-03-16 15:10:21 +0000346/**
347 * hb_ot_layout_get_ligature_carets:
348 * @font: The #hb_font_t to work on
349 * @direction: The #hb_direction_t text direction to use
350 * @glyph: The #hb_codepoint_t code point to query
Nathan Willis3db22722019-04-02 18:49:40 +0100351 * @start_offset: offset of the first caret position to retrieve
352 * @caret_count: (inout) (allow-none): Input = the maximum number of caret positions to return;
353 * Output = the actual number of caret positions returned (may be zero)
354 * @caret_array: (out) (array length=caret_count): The array of caret positions found for the query
Nathan Willis930f6fc2019-03-16 15:10:21 +0000355 *
356 * Fetches a list of the caret positions defined for a ligature glyph in the GDEF
357 * table of the font. The list returned will begin at the offset provided.
358 *
359 **/
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500360unsigned int
Behdad Esfahbode2046742010-10-27 12:32:02 -0400361hb_ot_layout_get_ligature_carets (hb_font_t *font,
Behdad Esfahbode2046742010-10-27 12:32:02 -0400362 hb_direction_t direction,
363 hb_codepoint_t glyph,
364 unsigned int start_offset,
365 unsigned int *caret_count /* IN/OUT */,
Ebrahim Byagowi3b0e47c2017-06-19 14:47:09 +0430366 hb_position_t *caret_array /* OUT */)
Behdad Esfahbod62964af2009-05-26 12:40:10 -0400367{
Ebrahim Byagowib986fea2018-11-05 12:31:58 +0330368 unsigned int result_caret_count = 0;
369 unsigned int result = font->face->table.GDEF->table->get_lig_carets (font, direction, glyph, start_offset, &result_caret_count, caret_array);
370 if (result)
371 {
372 if (caret_count) *caret_count = result_caret_count;
373 }
Behdad Esfahbod631da9d2019-06-19 15:36:14 -0700374#ifndef HB_NO_AAT
Ebrahim Byagowib986fea2018-11-05 12:31:58 +0330375 else
376 result = font->face->table.lcar->get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);
Behdad Esfahbod631da9d2019-06-19 15:36:14 -0700377#endif
Ebrahim Byagowib986fea2018-11-05 12:31:58 +0330378 return result;
Behdad Esfahbod79420ad2009-05-26 12:24:16 -0400379}
Behdad Esfahbodbf9424a2019-06-18 13:31:35 -0700380#endif
Behdad Esfahbod79420ad2009-05-26 12:24:16 -0400381
Behdad Esfahbod05bd1b62012-07-30 19:30:01 -0400382
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500383/*
384 * GSUB/GPOS
385 */
386
Behdad Esfahbod574d8882018-11-25 16:51:22 -0500387bool
388OT::GSUB::is_blacklisted (hb_blob_t *blob HB_UNUSED,
389 hb_face_t *face) const
390{
Behdad Esfahbod227d85e2019-05-10 23:15:58 -0700391#ifdef HB_NO_OT_LAYOUT_BLACKLIST
Behdad Esfahbod9ddbfa02019-04-12 09:33:25 -0400392 return false;
393#endif
Behdad Esfahbodf08066c2019-06-18 14:29:27 -0700394
Behdad Esfahbod12092a42019-06-26 13:31:01 -0700395#ifndef HB_NO_AAT_SHAPE
Behdad Esfahbod574d8882018-11-25 16:51:22 -0500396 /* Mac OS X prefers morx over GSUB. It also ships with various Indic fonts,
397 * all by 'MUTF' foundry (Tamil MN, Tamil Sangam MN, etc.), that have broken
398 * GSUB/GPOS tables. Some have GSUB with zero scripts, those are ignored by
399 * our morx/GSUB preference code. But if GSUB has non-zero scripts, we tend
400 * to prefer it over morx because we want to be consistent with other OpenType
401 * shapers.
402 *
403 * To work around broken Indic Mac system fonts, we ignore GSUB table if
404 * OS/2 VendorId is 'MUTF' and font has morx table as well.
405 *
406 * https://github.com/harfbuzz/harfbuzz/issues/1410
407 * https://github.com/harfbuzz/harfbuzz/issues/1348
408 * https://github.com/harfbuzz/harfbuzz/issues/1391
409 */
410 if (unlikely (face->table.OS2->achVendID == HB_TAG ('M','U','T','F') &&
411 face->table.morx->has_data ()))
412 return true;
Behdad Esfahbodf08066c2019-06-18 14:29:27 -0700413#endif
Behdad Esfahbod574d8882018-11-25 16:51:22 -0500414
415 return false;
416}
417
418bool
419OT::GPOS::is_blacklisted (hb_blob_t *blob HB_UNUSED,
420 hb_face_t *face HB_UNUSED) const
421{
Behdad Esfahbod227d85e2019-05-10 23:15:58 -0700422#ifdef HB_NO_OT_LAYOUT_BLACKLIST
Behdad Esfahbod9ddbfa02019-04-12 09:33:25 -0400423 return false;
424#endif
Behdad Esfahbod574d8882018-11-25 16:51:22 -0500425 return false;
426}
427
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400428static const OT::GSUBGPOS&
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -0400429get_gsubgpos_table (hb_face_t *face,
430 hb_tag_t table_tag)
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500431{
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400432 switch (table_tag) {
Behdad Esfahbod737efbe2018-11-05 23:26:29 -0500433 case HB_OT_TAG_GSUB: return *face->table.GSUB->table;
434 case HB_OT_TAG_GPOS: return *face->table.GPOS->table;
Behdad Esfahbodabc12f72018-05-08 02:23:36 -0700435 default: return Null(OT::GSUBGPOS);
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500436 }
437}
438
439
Nathan Willis930f6fc2019-03-16 15:10:21 +0000440/**
441 * hb_ot_layout_table_get_script_tags:
442 * @face: #hb_face_t to work upon
443 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
Nathan Willis3db22722019-04-02 18:49:40 +0100444 * @start_offset: offset of the first script tag to retrieve
445 * @script_count: (inout) (allow-none): Input = the maximum number of script tags to return;
446 * Output = the actual number of script tags returned (may be zero)
447 * @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 +0000448 *
449 * Fetches a list of all scripts enumerated in the specified face's GSUB table
450 * or GPOS table. The list returned will begin at the offset provided.
451 *
452 **/
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500453unsigned int
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400454hb_ot_layout_table_get_script_tags (hb_face_t *face,
455 hb_tag_t table_tag,
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500456 unsigned int start_offset,
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400457 unsigned int *script_count /* IN/OUT */,
Ebrahim Byagowi63109432018-10-13 14:00:05 +0330458 hb_tag_t *script_tags /* OUT */)
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500459{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400460 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500461
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500462 return g.get_script_tags (start_offset, script_count, script_tags);
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500463}
464
Behdad Esfahbodeb45c0a2013-01-16 22:07:50 -0600465#define HB_OT_TAG_LATIN_SCRIPT HB_TAG ('l', 'a', 't', 'n')
466
Nathan Willis930f6fc2019-03-16 15:10:21 +0000467/**
468 * hb_ot_layout_table_find_script:
469 * @face: #hb_face_t to work upon
470 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
471 * @script_tag: #hb_tag_t of the script tag requested
Nathan Willis51228052019-03-17 14:43:06 +0000472 * @script_index: (out): The index of the requested script tag
Nathan Willis930f6fc2019-03-16 15:10:21 +0000473 *
474 * Fetches the index if a given script tag in the specified face's GSUB table
475 * or GPOS table.
476 *
477 * Return value: true if the script is found, false otherwise
478 *
479 **/
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500480hb_bool_t
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400481hb_ot_layout_table_find_script (hb_face_t *face,
482 hb_tag_t table_tag,
483 hb_tag_t script_tag,
Nathan Willis930f6fc2019-03-16 15:10:21 +0000484 unsigned int *script_index /* OUT */)
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500485{
Behdad Esfahbod606bf572018-09-16 19:33:48 +0200486 static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX), "");
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400487 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500488
489 if (g.find_script_index (script_tag, script_index))
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400490 return true;
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500491
492 /* try finding 'DFLT' */
Behdad Esfahbod8a3511a2009-11-04 19:45:39 -0500493 if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index))
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400494 return false;
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500495
Behdad Esfahboddca8aff2010-09-28 16:25:23 -0400496 /* try with 'dflt'; MS site has had typos and many fonts use it now :(.
497 * including many versions of DejaVu Sans Mono! */
Behdad Esfahbod8a3511a2009-11-04 19:45:39 -0500498 if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index))
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400499 return false;
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500500
Behdad Esfahbodeb45c0a2013-01-16 22:07:50 -0600501 /* try with 'latn'; some old fonts put their features there even though
502 they're really trying to support Thai, for example :( */
503 if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index))
504 return false;
505
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500506 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400507 return false;
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500508}
509
Behdad Esfahbodfca27862019-05-11 00:37:01 -0700510#ifndef HB_DISABLE_DEPRECATED
Nathan Willis930f6fc2019-03-16 15:10:21 +0000511/**
512 * hb_ot_layout_table_choose_script:
513 * @face: #hb_face_t to work upon
514 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
515 * @script_tags: Array of #hb_tag_t script tags
Nathan Willis6c0a1e82019-03-17 14:50:47 +0000516 * @script_index: (out): The index of the requested script tag
517 * @chosen_script: (out): #hb_tag_t of the script tag requested
Nathan Willis930f6fc2019-03-16 15:10:21 +0000518 *
Nathan Willisc08ddbd2019-03-24 15:07:07 +0000519 * Deprecated since 2.0.0
Nathan Willis930f6fc2019-03-16 15:10:21 +0000520 **/
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100521hb_bool_t
522hb_ot_layout_table_choose_script (hb_face_t *face,
523 hb_tag_t table_tag,
524 const hb_tag_t *script_tags,
Nathan Willis6c0a1e82019-03-17 14:50:47 +0000525 unsigned int *script_index /* OUT */,
526 hb_tag_t *chosen_script /* OUT */)
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100527{
David Corbett91067712017-12-08 11:21:14 -0500528 const hb_tag_t *t;
529 for (t = script_tags; *t; t++);
530 return hb_ot_layout_table_select_script (face, table_tag, t - script_tags, script_tags, script_index, chosen_script);
531}
Behdad Esfahbodfca27862019-05-11 00:37:01 -0700532#endif
David Corbett91067712017-12-08 11:21:14 -0500533
Behdad Esfahbod80616642018-10-11 14:16:55 -0400534/**
535 * hb_ot_layout_table_select_script:
Nathan Willis930f6fc2019-03-16 15:10:21 +0000536 * @face: #hb_face_t to work upon
537 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
538 * @script_count: Number of script tags in the array
539 * @script_tags: Array of #hb_tag_t script tags
Nathan Willis51228052019-03-17 14:43:06 +0000540 * @script_index: (out): The index of the requested script
541 * @chosen_script: (out): #hb_tag_t of the requested script
Behdad Esfahbod80616642018-10-11 14:16:55 -0400542 *
Behdad Esfahbod3d9a0302018-10-18 05:58:17 -0700543 * Since: 2.0.0
Behdad Esfahbod80616642018-10-11 14:16:55 -0400544 **/
David Corbett91067712017-12-08 11:21:14 -0500545hb_bool_t
546hb_ot_layout_table_select_script (hb_face_t *face,
547 hb_tag_t table_tag,
548 unsigned int script_count,
549 const hb_tag_t *script_tags,
Ebrahim Byagowi63109432018-10-13 14:00:05 +0330550 unsigned int *script_index /* OUT */,
David Corbett91067712017-12-08 11:21:14 -0500551 hb_tag_t *chosen_script /* OUT */)
552{
Behdad Esfahbod606bf572018-09-16 19:33:48 +0200553 static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX), "");
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400554 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
David Corbett91067712017-12-08 11:21:14 -0500555 unsigned int i;
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100556
David Corbett91067712017-12-08 11:21:14 -0500557 for (i = 0; i < script_count; i++)
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100558 {
David Corbett91067712017-12-08 11:21:14 -0500559 if (g.find_script_index (script_tags[i], script_index))
560 {
Behdad Esfahbodc47a31f2011-07-30 20:57:01 -0400561 if (chosen_script)
David Corbett91067712017-12-08 11:21:14 -0500562 *chosen_script = script_tags[i];
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400563 return true;
Behdad Esfahbodc47a31f2011-07-30 20:57:01 -0400564 }
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100565 }
566
567 /* try finding 'DFLT' */
Behdad Esfahbodc47a31f2011-07-30 20:57:01 -0400568 if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) {
569 if (chosen_script)
570 *chosen_script = HB_OT_TAG_DEFAULT_SCRIPT;
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400571 return false;
Behdad Esfahbodc47a31f2011-07-30 20:57:01 -0400572 }
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100573
574 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
Behdad Esfahbodc47a31f2011-07-30 20:57:01 -0400575 if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) {
576 if (chosen_script)
577 *chosen_script = HB_OT_TAG_DEFAULT_LANGUAGE;
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400578 return false;
Behdad Esfahbodc47a31f2011-07-30 20:57:01 -0400579 }
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100580
Behdad Esfahbod71632c92012-01-22 15:31:44 -0500581 /* try with 'latn'; some old fonts put their features there even though
582 they're really trying to support Thai, for example :( */
Behdad Esfahbod71632c92012-01-22 15:31:44 -0500583 if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index)) {
584 if (chosen_script)
585 *chosen_script = HB_OT_TAG_LATIN_SCRIPT;
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400586 return false;
Behdad Esfahbod71632c92012-01-22 15:31:44 -0500587 }
588
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100589 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
Behdad Esfahbodc47a31f2011-07-30 20:57:01 -0400590 if (chosen_script)
591 *chosen_script = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400592 return false;
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100593}
594
Nathan Willis930f6fc2019-03-16 15:10:21 +0000595
596/**
597 * hb_ot_layout_table_get_feature_tags:
598 * @face: #hb_face_t to work upon
599 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
Nathan Willis3db22722019-04-02 18:49:40 +0100600 * @start_offset: offset of the first feature tag to retrieve
601 * @feature_count: (inout) (allow-none): Input = the maximum number of feature tags to return;
602 * Output = the actual number of feature tags returned (may be zero)
603 * @feature_tags: (out) (array length=feature_count): Array of feature tags found in the table
Nathan Willis930f6fc2019-03-16 15:10:21 +0000604 *
605 * Fetches a list of all feature tags in the given face's GSUB or GPOS table.
606 *
607 **/
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500608unsigned int
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400609hb_ot_layout_table_get_feature_tags (hb_face_t *face,
610 hb_tag_t table_tag,
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500611 unsigned int start_offset,
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400612 unsigned int *feature_count /* IN/OUT */,
Ebrahim Byagowi63109432018-10-13 14:00:05 +0330613 hb_tag_t *feature_tags /* OUT */)
Behdad Esfahbodc4473352008-02-18 21:14:23 -0500614{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400615 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
Behdad Esfahbodc4473352008-02-18 21:14:23 -0500616
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500617 return g.get_feature_tags (start_offset, feature_count, feature_tags);
Behdad Esfahbodc4473352008-02-18 21:14:23 -0500618}
619
Nathan Willis930f6fc2019-03-16 15:10:21 +0000620
621/**
622 * hb_ot_layout_table_find_feature:
623 * @face: #hb_face_t to work upon
624 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
625 * @feature_tag: The #hb_tag_t og the requested feature tag
Nathan Willis51228052019-03-17 14:43:06 +0000626 * @feature_index: (out): The index of the requested feature
Nathan Willis930f6fc2019-03-16 15:10:21 +0000627 *
628 * Fetches the index for a given feature tag in the specified face's GSUB table
629 * or GPOS table.
630 *
631 * Return value: true if the feature is found, false otherwise
632 **/
Behdad Esfahbod385f78b2018-11-07 17:19:21 -0500633bool
Behdad Esfahbod0f98fe82015-07-23 11:52:11 +0100634hb_ot_layout_table_find_feature (hb_face_t *face,
635 hb_tag_t table_tag,
636 hb_tag_t feature_tag,
Nathan Willis930f6fc2019-03-16 15:10:21 +0000637 unsigned int *feature_index /* OUT */)
Behdad Esfahbod0f98fe82015-07-23 11:52:11 +0100638{
Behdad Esfahbod606bf572018-09-16 19:33:48 +0200639 static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX), "");
Behdad Esfahbod0f98fe82015-07-23 11:52:11 +0100640 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
641
642 unsigned int num_features = g.get_feature_count ();
643 for (unsigned int i = 0; i < num_features; i++)
644 {
645 if (feature_tag == g.get_feature_tag (i)) {
646 if (feature_index) *feature_index = i;
647 return true;
648 }
649 }
650
651 if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
652 return false;
653}
654
Behdad Esfahbodc4473352008-02-18 21:14:23 -0500655
Nathan Willis930f6fc2019-03-16 15:10:21 +0000656/**
657 * hb_ot_layout_script_get_language_tags:
658 * @face: #hb_face_t to work upon
659 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
660 * @script_index: The index of the requested script tag
Nathan Willis3db22722019-04-02 18:49:40 +0100661 * @start_offset: offset of the first language tag to retrieve
662 * @language_count: (inout) (allow-none): Input = the maximum number of language tags to return;
663 * Output = the actual number of language tags returned (may be zero)
664 * @language_tags: (out) (array length=language_count): Array of language tags found in the table
Nathan Willis930f6fc2019-03-16 15:10:21 +0000665 *
666 * Fetches a list of language tags in the given face's GSUB or GPOS table, underneath
667 * the specified script index. The list returned will begin at the offset provided.
668 *
669 **/
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500670unsigned int
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400671hb_ot_layout_script_get_language_tags (hb_face_t *face,
672 hb_tag_t table_tag,
673 unsigned int script_index,
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500674 unsigned int start_offset,
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400675 unsigned int *language_count /* IN/OUT */,
Ebrahim Byagowi63109432018-10-13 14:00:05 +0330676 hb_tag_t *language_tags /* OUT */)
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500677{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400678 const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500679
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500680 return s.get_lang_sys_tags (start_offset, language_count, language_tags);
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500681}
682
Nathan Willis930f6fc2019-03-16 15:10:21 +0000683
Behdad Esfahbodfca27862019-05-11 00:37:01 -0700684#ifndef HB_DISABLE_DEPRECATED
Nathan Willis930f6fc2019-03-16 15:10:21 +0000685/**
686 * hb_ot_layout_script_find_language:
687 * @face: #hb_face_t to work upon
688 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
689 * @script_index: The index of the requested script tag
690 * @language_tag: The #hb_tag_t of the requested language
691 * @language_index: The index of the requested language
692 *
693 * Fetches the index of a given language tag in the specified face's GSUB table
694 * or GPOS table, underneath the specified script tag.
695 *
696 * Return value: true if the language tag is found, false otherwise
697 *
Behdad Esfahbodfca27862019-05-11 00:37:01 -0700698 * Since: ??
699 * Deprecated: ??
Nathan Willis930f6fc2019-03-16 15:10:21 +0000700 **/
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500701hb_bool_t
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400702hb_ot_layout_script_find_language (hb_face_t *face,
703 hb_tag_t table_tag,
704 unsigned int script_index,
705 hb_tag_t language_tag,
706 unsigned int *language_index)
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500707{
Behdad Esfahbod737efbe2018-11-05 23:26:29 -0500708 return hb_ot_layout_script_select_language (face,
709 table_tag,
710 script_index,
711 1,
712 &language_tag,
713 language_index);
David Corbett91067712017-12-08 11:21:14 -0500714}
Behdad Esfahbodfca27862019-05-11 00:37:01 -0700715#endif
David Corbett91067712017-12-08 11:21:14 -0500716
Nathan Willis930f6fc2019-03-16 15:10:21 +0000717
Behdad Esfahbod80616642018-10-11 14:16:55 -0400718/**
719 * hb_ot_layout_script_select_language:
Nathan Willis930f6fc2019-03-16 15:10:21 +0000720 * @face: #hb_face_t to work upon
721 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
722 * @script_index: The index of the requested script tag
723 * @language_count: The number of languages in the specified script
724 * @language_tags: The array of language tags
Nathan Willis51228052019-03-17 14:43:06 +0000725 * @language_index: (out): The index of the requested language
Nathan Willis930f6fc2019-03-16 15:10:21 +0000726 *
727 * Fetches the index of a given language tag in the specified face's GSUB table
728 * or GPOS table, underneath the specified script index.
729 *
730 * Return value: true if the language tag is found, false otherwise
731 *
Behdad Esfahbod3d9a0302018-10-18 05:58:17 -0700732 * Since: 2.0.0
Behdad Esfahbod80616642018-10-11 14:16:55 -0400733 **/
David Corbett91067712017-12-08 11:21:14 -0500734hb_bool_t
Behdad Esfahbodcf975ac2018-10-11 14:07:44 -0400735hb_ot_layout_script_select_language (hb_face_t *face,
736 hb_tag_t table_tag,
737 unsigned int script_index,
738 unsigned int language_count,
739 const hb_tag_t *language_tags,
740 unsigned int *language_index /* OUT */)
David Corbett91067712017-12-08 11:21:14 -0500741{
Behdad Esfahbod606bf572018-09-16 19:33:48 +0200742 static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX), "");
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400743 const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
David Corbett91067712017-12-08 11:21:14 -0500744 unsigned int i;
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500745
David Corbett91067712017-12-08 11:21:14 -0500746 for (i = 0; i < language_count; i++)
747 {
748 if (s.find_lang_sys_index (language_tags[i], language_index))
749 return true;
750 }
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500751
David Corbett91067712017-12-08 11:21:14 -0500752 /* try finding 'dflt' */
Behdad Esfahbod8a3511a2009-11-04 19:45:39 -0500753 if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index))
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400754 return false;
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500755
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500756 if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400757 return false;
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500758}
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500759
Nathan Willis930f6fc2019-03-16 15:10:21 +0000760
761/**
762 * hb_ot_layout_language_get_required_feature_index:
763 * @face: #hb_face_t to work upon
764 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
765 * @script_index: The index of the requested script tag
766 * @language_index: The index of the requested language tag
Nathan Willis51228052019-03-17 14:43:06 +0000767 * @feature_index: (out): The index of the requested feature
Nathan Willis930f6fc2019-03-16 15:10:21 +0000768 *
769 * Fetches the index of a requested feature in the given face's GSUB or GPOS table,
770 * underneath the specified script and language.
771 *
772 * Return value: true if the feature is found, false otherwise
773 *
774 **/
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500775hb_bool_t
Behdad Esfahbod911ca382014-06-24 10:20:36 -0600776hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
777 hb_tag_t table_tag,
778 unsigned int script_index,
779 unsigned int language_index,
780 unsigned int *feature_index)
781{
782 return hb_ot_layout_language_get_required_feature (face,
783 table_tag,
784 script_index,
785 language_index,
786 feature_index,
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200787 nullptr);
Behdad Esfahbod911ca382014-06-24 10:20:36 -0600788}
789
Nathan Willis930f6fc2019-03-16 15:10:21 +0000790
Sascha Brawer01c3a882015-06-01 13:22:01 +0200791/**
Behdad Esfahbod35d18582015-11-26 19:30:37 -0500792 * hb_ot_layout_language_get_required_feature:
Nathan Willis930f6fc2019-03-16 15:10:21 +0000793 * @face: #hb_face_t to work upon
794 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
795 * @script_index: The index of the requested script tag
796 * @language_index: The index of the requested language tag
797 * @feature_index: The index of the requested feature
Nathan Willis51228052019-03-17 14:43:06 +0000798 * @feature_tag: (out): The #hb_tag_t of the requested feature
Nathan Willis930f6fc2019-03-16 15:10:21 +0000799 *
800 * Fetches the tag of a requested feature index in the given face's GSUB or GPOS table,
801 * underneath the specified script and language.
802 *
803 * Return value: true if the feature is found, false otherwise
Behdad Esfahbod35d18582015-11-26 19:30:37 -0500804 *
Sascha Brawer01c3a882015-06-01 13:22:01 +0200805 * Since: 0.9.30
806 **/
Behdad Esfahbod911ca382014-06-24 10:20:36 -0600807hb_bool_t
Jonathan Kewda132932014-04-27 14:05:24 +0100808hb_ot_layout_language_get_required_feature (hb_face_t *face,
809 hb_tag_t table_tag,
810 unsigned int script_index,
811 unsigned int language_index,
812 unsigned int *feature_index,
813 hb_tag_t *feature_tag)
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500814{
Jonathan Kewda132932014-04-27 14:05:24 +0100815 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
816 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500817
Jonathan Kewda132932014-04-27 14:05:24 +0100818 unsigned int index = l.get_required_feature_index ();
819 if (feature_index) *feature_index = index;
820 if (feature_tag) *feature_tag = g.get_feature_tag (index);
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500821
822 return l.has_required_feature ();
823}
824
Nathan Willis930f6fc2019-03-16 15:10:21 +0000825
826/**
827 * hb_ot_layout_language_get_feature_indexes:
828 * @face: #hb_face_t to work upon
829 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
830 * @script_index: The index of the requested script tag
831 * @language_index: The index of the requested language tag
Nathan Willis3db22722019-04-02 18:49:40 +0100832 * @start_offset: offset of the first feature tag to retrieve
833 * @feature_count: (inout) (allow-none): Input = the maximum number of feature tags to return;
834 * Output: the actual number of feature tags returned (may be zero)
835 * @feature_indexes: (out) (array length=feature_count): The array of feature indexes found for the query
Nathan Willis930f6fc2019-03-16 15:10:21 +0000836 *
837 * Fetches a list of all features in the specified face's GSUB table
838 * or GPOS table, underneath the specified script and language. The list
839 * returned will begin at the offset provided.
840 **/
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500841unsigned int
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400842hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
843 hb_tag_t table_tag,
844 unsigned int script_index,
845 unsigned int language_index,
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500846 unsigned int start_offset,
Ebrahim Byagowi63109432018-10-13 14:00:05 +0330847 unsigned int *feature_count /* IN/OUT */,
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400848 unsigned int *feature_indexes /* OUT */)
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500849{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400850 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
851 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500852
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500853 return l.get_feature_indexes (start_offset, feature_count, feature_indexes);
Behdad Esfahbodc4473352008-02-18 21:14:23 -0500854}
855
Nathan Willis930f6fc2019-03-16 15:10:21 +0000856
857/**
858 * hb_ot_layout_language_get_feature_tags:
859 * @face: #hb_face_t to work upon
860 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
861 * @script_index: The index of the requested script tag
862 * @language_index: The index of the requested language tag
Nathan Willis3db22722019-04-02 18:49:40 +0100863 * @start_offset: offset of the first feature tag to retrieve
864 * @feature_count: (inout) (allow-none): Input = the maximum number of feature tags to return;
865 * Output = the actual number of feature tags returned (may be zero)
866 * @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 +0000867 *
868 * Fetches a list of all features in the specified face's GSUB table
869 * or GPOS table, underneath the specified script and language. The list
870 * returned will begin at the offset provided.
871 *
872 **/
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500873unsigned int
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400874hb_ot_layout_language_get_feature_tags (hb_face_t *face,
875 hb_tag_t table_tag,
876 unsigned int script_index,
877 unsigned int language_index,
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500878 unsigned int start_offset,
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400879 unsigned int *feature_count /* IN/OUT */,
Ebrahim Byagowi63109432018-10-13 14:00:05 +0330880 hb_tag_t *feature_tags /* OUT */)
Behdad Esfahbodc4473352008-02-18 21:14:23 -0500881{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400882 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
883 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500884
Behdad Esfahbod606bf572018-09-16 19:33:48 +0200885 static_assert ((sizeof (unsigned int) == sizeof (hb_tag_t)), "");
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500886 unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags);
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400887
Behdad Esfahbod98977492009-08-27 01:32:17 -0400888 if (feature_tags) {
889 unsigned int count = *feature_count;
890 for (unsigned int i = 0; i < count; i++)
891 feature_tags[i] = g.get_feature_tag ((unsigned int) feature_tags[i]);
892 }
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400893
894 return ret;
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500895}
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500896
897
Nathan Willis930f6fc2019-03-16 15:10:21 +0000898/**
899 * hb_ot_layout_language_find_feature:
900 * @face: #hb_face_t to work upon
901 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
902 * @script_index: The index of the requested script tag
903 * @language_index: The index of the requested language tag
904 * @feature_tag: #hb_tag_t of the feature tag requested
Nathan Willis51228052019-03-17 14:43:06 +0000905 * @feature_index: (out): The index of the requested feature
Nathan Willis930f6fc2019-03-16 15:10:21 +0000906 *
907 * Fetches the index of a given feature tag in the specified face's GSUB table
908 * or GPOS table, underneath the specified script and language.
909 *
910 * Return value: true if the feature is found, false otherwise
911 *
912 **/
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500913hb_bool_t
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400914hb_ot_layout_language_find_feature (hb_face_t *face,
915 hb_tag_t table_tag,
916 unsigned int script_index,
917 unsigned int language_index,
918 hb_tag_t feature_tag,
Nathan Willis930f6fc2019-03-16 15:10:21 +0000919 unsigned int *feature_index /* OUT */)
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500920{
Behdad Esfahbod606bf572018-09-16 19:33:48 +0200921 static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX), "");
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400922 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
923 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500924
Behdad Esfahbodf4c95142009-05-17 04:59:56 -0400925 unsigned int num_features = l.get_feature_count ();
926 for (unsigned int i = 0; i < num_features; i++) {
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500927 unsigned int f_index = l.get_feature_index (i);
928
929 if (feature_tag == g.get_feature_tag (f_index)) {
930 if (feature_index) *feature_index = f_index;
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400931 return true;
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500932 }
933 }
934
935 if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400936 return false;
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500937}
Behdad Esfahbodc4473352008-02-18 21:14:23 -0500938
Nathan Willis930f6fc2019-03-16 15:10:21 +0000939
Sascha Brawer01c3a882015-06-01 13:22:01 +0200940/**
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +0400941 * hb_ot_layout_feature_get_lookups:
Nathan Willis930f6fc2019-03-16 15:10:21 +0000942 * @face: #hb_face_t to work upon
943 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
944 * @feature_index: The index of the requested feature
Nathan Willis3db22722019-04-02 18:49:40 +0100945 * @start_offset: offset of the first lookup to retrieve
946 * @lookup_count: (inout) (allow-none): Input = the maximum number of lookups to return;
947 * Output = the actual number of lookups returned (may be zero)
948 * @lookup_indexes: (out) (array length=lookup_count): The array of lookup indexes found for the query
Nathan Willis930f6fc2019-03-16 15:10:21 +0000949 *
950 * Fetches a list of all lookups enumerated for the specified feature, in
951 * the specified face's GSUB table or GPOS table. The list returned will
952 * begin at the offset provided.
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +0400953 *
Sascha Brawer01c3a882015-06-01 13:22:01 +0200954 * Since: 0.9.7
955 **/
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500956unsigned int
Behdad Esfahbodf3064102012-11-15 18:39:46 -0800957hb_ot_layout_feature_get_lookups (hb_face_t *face,
958 hb_tag_t table_tag,
959 unsigned int feature_index,
960 unsigned int start_offset,
Ebrahim Byagowi63109432018-10-13 14:00:05 +0330961 unsigned int *lookup_count /* IN/OUT */,
Behdad Esfahbodf3064102012-11-15 18:39:46 -0800962 unsigned int *lookup_indexes /* OUT */)
Behdad Esfahbodc4473352008-02-18 21:14:23 -0500963{
Behdad Esfahbodec87ba92016-09-10 03:53:11 -0700964 return hb_ot_layout_feature_with_variations_get_lookups (face,
965 table_tag,
966 feature_index,
967 HB_OT_LAYOUT_NO_VARIATIONS_INDEX,
968 start_offset,
969 lookup_count,
970 lookup_indexes);
Behdad Esfahbodc4473352008-02-18 21:14:23 -0500971}
972
Nathan Willis930f6fc2019-03-16 15:10:21 +0000973
Sascha Brawer01c3a882015-06-01 13:22:01 +0200974/**
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +0400975 * hb_ot_layout_table_get_lookup_count:
Nathan Willis930f6fc2019-03-16 15:10:21 +0000976 * @face: #hb_face_t to work upon
977 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
978 *
979 * Fetches the total number of lookups enumerated in the specified
980 * face's GSUB table or GPOS table.
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +0400981 *
Sascha Brawer01c3a882015-06-01 13:22:01 +0200982 * Since: 0.9.22
983 **/
Behdad Esfahbod27674b42013-10-03 14:54:50 -0400984unsigned int
985hb_ot_layout_table_get_lookup_count (hb_face_t *face,
986 hb_tag_t table_tag)
987{
Behdad Esfahbod96828b92018-10-25 20:34:29 -0700988 return get_gsubgpos_table (face, table_tag).get_lookup_count ();
Behdad Esfahbod27674b42013-10-03 14:54:50 -0400989}
990
Behdad Esfahbod941600a2018-10-25 21:26:08 -0700991
992struct hb_collect_features_context_t
993{
994 hb_collect_features_context_t (hb_face_t *face,
995 hb_tag_t table_tag,
996 hb_set_t *feature_indexes_)
997 : g (get_gsubgpos_table (face, table_tag)),
Garret Rieger0e1ad5a2018-10-30 11:29:58 -0700998 feature_indexes (feature_indexes_),
Behdad Esfahbodbfd549d2018-10-30 14:47:27 -0700999 script_count(0),langsys_count(0) {}
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001000
Ebrahim Byagowid0a706c2018-12-22 19:47:48 +03301001 bool visited (const OT::Script &s)
Behdad Esfahbodeb44bfc2018-10-25 21:42:19 -07001002 {
1003 /* We might have Null() object here. Don't want to involve
1004 * that in the memoize. So, detect empty objects and return. */
1005 if (unlikely (!s.has_default_lang_sys () &&
1006 !s.get_lang_sys_count ()))
1007 return true;
1008
Garret Rieger0e1ad5a2018-10-30 11:29:58 -07001009 if (script_count++ > HB_MAX_SCRIPTS)
1010 return true;
1011
Behdad Esfahbodeb44bfc2018-10-25 21:42:19 -07001012 return visited (s, visited_script);
1013 }
Ebrahim Byagowid0a706c2018-12-22 19:47:48 +03301014 bool visited (const OT::LangSys &l)
Behdad Esfahbodeb44bfc2018-10-25 21:42:19 -07001015 {
1016 /* We might have Null() object here. Don't want to involve
1017 * that in the memoize. So, detect empty objects and return. */
1018 if (unlikely (!l.has_required_feature () &&
1019 !l.get_feature_count ()))
1020 return true;
1021
Garret Rieger0e1ad5a2018-10-30 11:29:58 -07001022 if (langsys_count++ > HB_MAX_LANGSYS)
1023 return true;
1024
Behdad Esfahbodeb44bfc2018-10-25 21:42:19 -07001025 return visited (l, visited_langsys);
1026 }
1027
1028 private:
1029 template <typename T>
Ebrahim Byagowid0a706c2018-12-22 19:47:48 +03301030 bool visited (const T &p, hb_set_t &visited_set)
Behdad Esfahbodeb44bfc2018-10-25 21:42:19 -07001031 {
1032 hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) &p - (uintptr_t) &g);
1033 if (visited_set.has (delta))
1034 return true;
1035
1036 visited_set.add (delta);
1037 return false;
1038 }
1039
1040 public:
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001041 const OT::GSUBGPOS &g;
1042 hb_set_t *feature_indexes;
Behdad Esfahbodeb44bfc2018-10-25 21:42:19 -07001043
1044 private:
Behdad Esfahbod3a4e5dd2018-10-29 18:05:25 -07001045 hb_set_t visited_script;
1046 hb_set_t visited_langsys;
Garret Rieger0e1ad5a2018-10-30 11:29:58 -07001047 unsigned int script_count;
1048 unsigned int langsys_count;
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001049};
1050
Behdad Esfahboda88e7162012-11-24 02:31:02 -05001051static void
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001052langsys_collect_features (hb_collect_features_context_t *c,
Behdad Esfahbode8e67502018-10-25 20:48:20 -07001053 const OT::LangSys &l,
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001054 const hb_tag_t *features)
Behdad Esfahboda88e7162012-11-24 02:31:02 -05001055{
Behdad Esfahbodeb44bfc2018-10-25 21:42:19 -07001056 if (c->visited (l)) return;
1057
Behdad Esfahboda88e7162012-11-24 02:31:02 -05001058 if (!features)
1059 {
Behdad Esfahbode8e67502018-10-25 20:48:20 -07001060 /* All features. */
Behdad Esfahbodeb44bfc2018-10-25 21:42:19 -07001061 if (l.has_required_feature ())
1062 c->feature_indexes->add (l.get_required_feature_index ());
Behdad Esfahbod5f85c802013-06-26 20:14:18 -04001063
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001064 l.add_feature_indexes_to (c->feature_indexes);
Behdad Esfahbod15e9e4e2013-01-03 00:04:40 -06001065 }
1066 else
1067 {
Behdad Esfahbode8e67502018-10-25 20:48:20 -07001068 /* Ugh. Any faster way? */
Behdad Esfahboda88e7162012-11-24 02:31:02 -05001069 for (; *features; features++)
1070 {
Behdad Esfahbode8e67502018-10-25 20:48:20 -07001071 hb_tag_t feature_tag = *features;
Behdad Esfahbode8e67502018-10-25 20:48:20 -07001072 unsigned int num_features = l.get_feature_count ();
1073 for (unsigned int i = 0; i < num_features; i++)
1074 {
1075 unsigned int feature_index = l.get_feature_index (i);
1076
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001077 if (feature_tag == c->g.get_feature_tag (feature_index))
Behdad Esfahbode8e67502018-10-25 20:48:20 -07001078 {
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001079 c->feature_indexes->add (feature_index);
Behdad Esfahbode8e67502018-10-25 20:48:20 -07001080 break;
1081 }
1082 }
Behdad Esfahboda88e7162012-11-24 02:31:02 -05001083 }
1084 }
1085}
1086
1087static void
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001088script_collect_features (hb_collect_features_context_t *c,
Behdad Esfahbodfe5520d2018-10-25 20:58:34 -07001089 const OT::Script &s,
1090 const hb_tag_t *languages,
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001091 const hb_tag_t *features)
Behdad Esfahboda88e7162012-11-24 02:31:02 -05001092{
Behdad Esfahbodeb44bfc2018-10-25 21:42:19 -07001093 if (c->visited (s)) return;
1094
Behdad Esfahboda88e7162012-11-24 02:31:02 -05001095 if (!languages)
1096 {
Behdad Esfahbode8e67502018-10-25 20:48:20 -07001097 /* All languages. */
Behdad Esfahbodeb44bfc2018-10-25 21:42:19 -07001098 if (s.has_default_lang_sys ())
1099 langsys_collect_features (c,
1100 s.get_default_lang_sys (),
1101 features);
Behdad Esfahbode8e67502018-10-25 20:48:20 -07001102
Behdad Esfahbodfe5520d2018-10-25 20:58:34 -07001103 unsigned int count = s.get_lang_sys_count ();
Behdad Esfahboda88e7162012-11-24 02:31:02 -05001104 for (unsigned int language_index = 0; language_index < count; language_index++)
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001105 langsys_collect_features (c,
Behdad Esfahbodfe5520d2018-10-25 20:58:34 -07001106 s.get_lang_sys (language_index),
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001107 features);
Behdad Esfahbod15e9e4e2013-01-03 00:04:40 -06001108 }
1109 else
1110 {
Behdad Esfahboda88e7162012-11-24 02:31:02 -05001111 for (; *languages; languages++)
1112 {
1113 unsigned int language_index;
Behdad Esfahbodfe5520d2018-10-25 20:58:34 -07001114 if (s.find_lang_sys_index (*languages, &language_index))
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001115 langsys_collect_features (c,
Behdad Esfahbodfe5520d2018-10-25 20:58:34 -07001116 s.get_lang_sys (language_index),
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001117 features);
Garret Rieger7d92bef2018-07-30 17:17:43 -07001118 }
1119 }
1120}
1121
Nathan Willis930f6fc2019-03-16 15:10:21 +00001122
Garret Rieger7d92bef2018-07-30 17:17:43 -07001123/**
Garret Rieger89733752018-07-30 18:10:43 -07001124 * hb_ot_layout_collect_features:
Nathan Willis930f6fc2019-03-16 15:10:21 +00001125 * @face: #hb_face_t to work upon
1126 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
1127 * @scripts: The array of scripts to collect features for
1128 * @languages: The array of languages to collect features for
1129 * @features: The array of features to collect
Nathan Willis51228052019-03-17 14:43:06 +00001130 * @feature_indexes: (out): The array of feature indexes found for the query
Nathan Willis930f6fc2019-03-16 15:10:21 +00001131 *
1132 * Fetches a list of all feature indexes in the specified face's GSUB table
1133 * or GPOS table, underneath the specified scripts, languages, and features.
1134 * If no list of scripts is provided, all scripts will be queried. If no list
1135 * of languages is provided, all languages will be queried. If no list of
1136 * features is provided, all features will be queried.
Garret Rieger7d92bef2018-07-30 17:17:43 -07001137 *
Behdad Esfahbod44d1fb32018-08-01 14:51:51 -07001138 * Since: 1.8.5
Garret Rieger7d92bef2018-07-30 17:17:43 -07001139 **/
1140void
1141hb_ot_layout_collect_features (hb_face_t *face,
1142 hb_tag_t table_tag,
1143 const hb_tag_t *scripts,
1144 const hb_tag_t *languages,
1145 const hb_tag_t *features,
1146 hb_set_t *feature_indexes /* OUT */)
1147{
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001148 hb_collect_features_context_t c (face, table_tag, feature_indexes);
Garret Rieger7d92bef2018-07-30 17:17:43 -07001149 if (!scripts)
1150 {
Behdad Esfahbode8e67502018-10-25 20:48:20 -07001151 /* All scripts. */
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001152 unsigned int count = c.g.get_script_count ();
Garret Rieger7d92bef2018-07-30 17:17:43 -07001153 for (unsigned int script_index = 0; script_index < count; script_index++)
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001154 script_collect_features (&c,
1155 c.g.get_script (script_index),
Behdad Esfahbodfe5520d2018-10-25 20:58:34 -07001156 languages,
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001157 features);
Garret Rieger7d92bef2018-07-30 17:17:43 -07001158 }
1159 else
1160 {
1161 for (; *scripts; scripts++)
1162 {
1163 unsigned int script_index;
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001164 if (c.g.find_script_index (*scripts, &script_index))
1165 script_collect_features (&c,
1166 c.g.get_script (script_index),
Behdad Esfahbodfe5520d2018-10-25 20:58:34 -07001167 languages,
Behdad Esfahbod941600a2018-10-25 21:26:08 -07001168 features);
Behdad Esfahboda88e7162012-11-24 02:31:02 -05001169 }
1170 }
1171}
1172
Nathan Willis930f6fc2019-03-16 15:10:21 +00001173
Sascha Brawer01c3a882015-06-01 13:22:01 +02001174/**
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +04001175 * hb_ot_layout_collect_lookups:
Nathan Willis930f6fc2019-03-16 15:10:21 +00001176 * @face: #hb_face_t to work upon
1177 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
1178 * @scripts: The array of scripts to collect lookups for
1179 * @languages: The array of languages to collect lookups for
1180 * @features: The array of features to collect lookups for
Nathan Willis51228052019-03-17 14:43:06 +00001181 * @lookup_indexes: (out): The array of lookup indexes found for the query
Nathan Willis930f6fc2019-03-16 15:10:21 +00001182 *
1183 * Fetches a list of all feature-lookup indexes in the specified face's GSUB
1184 * table or GPOS table, underneath the specified scripts, languages, and
1185 * features. If no list of scripts is provided, all scripts will be queried.
1186 * If no list of languages is provided, all languages will be queried. If no
1187 * list of features is provided, all features will be queried.
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +04001188 *
Sascha Brawer01c3a882015-06-01 13:22:01 +02001189 * Since: 0.9.8
1190 **/
Behdad Esfahboda88e7162012-11-24 02:31:02 -05001191void
1192hb_ot_layout_collect_lookups (hb_face_t *face,
1193 hb_tag_t table_tag,
1194 const hb_tag_t *scripts,
1195 const hb_tag_t *languages,
1196 const hb_tag_t *features,
1197 hb_set_t *lookup_indexes /* OUT */)
1198{
Behdad Esfahbode98af6d2018-10-25 22:25:29 -07001199 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
1200
Behdad Esfahbod3a4e5dd2018-10-29 18:05:25 -07001201 hb_set_t feature_indexes;
Garret Rieger7d92bef2018-07-30 17:17:43 -07001202 hb_ot_layout_collect_features (face, table_tag, scripts, languages, features, &feature_indexes);
Behdad Esfahbode98af6d2018-10-25 22:25:29 -07001203
Behdad Esfahbodc237cdf2018-10-25 21:17:30 -07001204 for (hb_codepoint_t feature_index = HB_SET_VALUE_INVALID;
1205 hb_set_next (&feature_indexes, &feature_index);)
Behdad Esfahbode98af6d2018-10-25 22:25:29 -07001206 g.get_feature (feature_index).add_lookup_indexes_to (lookup_indexes);
Behdad Esfahboda88e7162012-11-24 02:31:02 -05001207}
1208
Nathan Willis930f6fc2019-03-16 15:10:21 +00001209
Behdad Esfahbodfce3bf82019-06-19 20:34:29 -07001210#ifndef HB_NO_LAYOUT_COLLECT_GLYPHS
Sascha Brawer01c3a882015-06-01 13:22:01 +02001211/**
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +04001212 * hb_ot_layout_lookup_collect_glyphs:
Nathan Willis930f6fc2019-03-16 15:10:21 +00001213 * @face: #hb_face_t to work upon
1214 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
1215 * @lookup_index: The index of the feature lookup to query
Nathan Willis51228052019-03-17 14:43:06 +00001216 * @glyphs_before: (out): Array of glyphs preceding the substitution range
1217 * @glyphs_input: (out): Array of input glyphs that would be substituted by the lookup
1218 * @glyphs_after: (out): Array of glyphs following the substition range
1219 * @glyphs_output: (out): Array of glyphs that would be the substitued output of the lookup
Nathan Willis930f6fc2019-03-16 15:10:21 +00001220 *
1221 * Fetches a list of all glyphs affected by the specified lookup in the
1222 * specified face's GSUB table of GPOS table.
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +04001223 *
Sascha Brawer01c3a882015-06-01 13:22:01 +02001224 * Since: 0.9.7
1225 **/
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -08001226void
1227hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
1228 hb_tag_t table_tag,
1229 unsigned int lookup_index,
Ebrahim Byagowi63109432018-10-13 14:00:05 +03301230 hb_set_t *glyphs_before, /* OUT. May be NULL */
1231 hb_set_t *glyphs_input, /* OUT. May be NULL */
1232 hb_set_t *glyphs_after, /* OUT. May be NULL */
1233 hb_set_t *glyphs_output /* OUT. May be NULL */)
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -08001234{
Behdad Esfahbod733e8c02013-01-03 00:00:23 -06001235 OT::hb_collect_glyphs_context_t c (face,
1236 glyphs_before,
1237 glyphs_input,
1238 glyphs_after,
1239 glyphs_output);
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -08001240
Behdad Esfahbod15e9e4e2013-01-03 00:04:40 -06001241 switch (table_tag)
1242 {
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -08001243 case HB_OT_TAG_GSUB:
1244 {
Behdad Esfahbod0fe7a742018-11-05 23:08:33 -05001245 const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index);
Behdad Esfahbod780cd932013-05-03 17:33:16 -04001246 l.collect_glyphs (&c);
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -08001247 return;
1248 }
1249 case HB_OT_TAG_GPOS:
1250 {
Behdad Esfahbod0fe7a742018-11-05 23:08:33 -05001251 const OT::PosLookup& l = face->table.GPOS->table->get_lookup (lookup_index);
Behdad Esfahbod780cd932013-05-03 17:33:16 -04001252 l.collect_glyphs (&c);
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -08001253 return;
1254 }
1255 }
1256}
Behdad Esfahbodfce3bf82019-06-19 20:34:29 -07001257#endif
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -08001258
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001259
Behdad Esfahbod30c42b62016-09-10 03:32:39 -07001260/* Variations support */
1261
Nathan Willis930f6fc2019-03-16 15:10:21 +00001262
1263/**
1264 * hb_ot_layout_table_find_feature_variations:
1265 * @face: #hb_face_t to work upon
1266 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
1267 * @coords: The variation coordinates to query
1268 * @num_coords: The number of variation coorinates
Nathan Willis3db22722019-04-02 18:49:40 +01001269 * @variations_index: (out): The array of feature variations found for the query
Nathan Willis930f6fc2019-03-16 15:10:21 +00001270 *
1271 * Fetches a list of feature variations in the specified face's GSUB table
1272 * or GPOS table, at the specified variation coordinates.
1273 *
1274 **/
Behdad Esfahbod30c42b62016-09-10 03:32:39 -07001275hb_bool_t
1276hb_ot_layout_table_find_feature_variations (hb_face_t *face,
1277 hb_tag_t table_tag,
1278 const int *coords,
1279 unsigned int num_coords,
1280 unsigned int *variations_index /* out */)
1281{
1282 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
1283
1284 return g.find_variations_index (coords, num_coords, variations_index);
1285}
1286
Nathan Willis930f6fc2019-03-16 15:10:21 +00001287
1288/**
1289 * hb_ot_layout_feature_with_variations_get_lookups:
1290 * @face: #hb_face_t to work upon
1291 * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
1292 * @feature_index: The index of the feature to query
1293 * @variations_index: The index of the feature variation to query
Nathan Willis3db22722019-04-02 18:49:40 +01001294 * @start_offset: offset of the first lookup to retrieve
1295 * @lookup_count: (inout) (allow-none): Input = the maximum number of lookups to return;
1296 * Output = the actual number of lookups returned (may be zero)
1297 * @lookup_indexes: (out) (array length=lookup_count): The array of lookups found for the query
Nathan Willis930f6fc2019-03-16 15:10:21 +00001298 *
1299 * Fetches a list of all lookups enumerated for the specified feature, in
1300 * the specified face's GSUB table or GPOS table, enabled at the specified
1301 * variations index. The list returned will begin at the offset provided.
1302 *
1303 **/
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07001304unsigned int
1305hb_ot_layout_feature_with_variations_get_lookups (hb_face_t *face,
1306 hb_tag_t table_tag,
1307 unsigned int feature_index,
1308 unsigned int variations_index,
1309 unsigned int start_offset,
1310 unsigned int *lookup_count /* IN/OUT */,
1311 unsigned int *lookup_indexes /* OUT */)
1312{
Behdad Esfahbod606bf572018-09-16 19:33:48 +02001313 static_assert ((OT::FeatureVariations::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_VARIATIONS_INDEX), "");
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07001314 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
1315
1316 const OT::Feature &f = g.get_feature_variation (feature_index, variations_index);
1317
1318 return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
1319}
1320
Behdad Esfahbod30c42b62016-09-10 03:32:39 -07001321
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001322/*
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -04001323 * OT::GSUB
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001324 */
1325
Nathan Willis930f6fc2019-03-16 15:10:21 +00001326
1327/**
1328 * hb_ot_layout_has_substitution:
1329 * @face: #hb_face_t to work upon
1330 *
1331 * Tests whether the specified face includes any GSUB substitutions.
1332 *
1333 * Return value: true if data found, false otherwise
1334 *
1335 **/
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001336hb_bool_t
Behdad Esfahbod0ead4812009-08-02 17:41:36 -04001337hb_ot_layout_has_substitution (hb_face_t *face)
1338{
Behdad Esfahbod737efbe2018-11-05 23:26:29 -05001339 return face->table.GSUB->table->has_data ();
Behdad Esfahbod0ead4812009-08-02 17:41:36 -04001340}
1341
Nathan Willis930f6fc2019-03-16 15:10:21 +00001342
Sascha Brawer01c3a882015-06-01 13:22:01 +02001343/**
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +04001344 * hb_ot_layout_lookup_would_substitute:
Nathan Willis930f6fc2019-03-16 15:10:21 +00001345 * @face: #hb_face_t to work upon
1346 * @lookup_index: The index of the lookup to query
1347 * @glyphs: The sequence of glyphs to query for substitution
1348 * @glyphs_length: The length of the glyph sequence
1349 * @zero_context: #hb_bool_t indicating whether substitutions should be context-free
1350 *
1351 * Tests whether a specified lookup in the specified face would
1352 * trigger a substitution on the given glyph sequence.
1353 *
1354 * Return value: true if a substitution would be triggered, false otherwise
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +04001355 *
Sascha Brawer01c3a882015-06-01 13:22:01 +02001356 * Since: 0.9.7
1357 **/
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001358hb_bool_t
Behdad Esfahbod362a9902012-11-15 14:57:31 -08001359hb_ot_layout_lookup_would_substitute (hb_face_t *face,
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -04001360 unsigned int lookup_index,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001361 const hb_codepoint_t *glyphs,
1362 unsigned int glyphs_length,
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -04001363 hb_bool_t zero_context)
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001364{
Behdad Esfahbod0fe7a742018-11-05 23:08:33 -05001365 if (unlikely (lookup_index >= face->table.GSUB->lookup_count)) return false;
Behdad Esfahbodea512f72015-11-26 19:22:22 -05001366 OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, (bool) zero_context);
Behdad Esfahbod2bd9fe32012-09-04 15:15:19 -04001367
Behdad Esfahbod0fe7a742018-11-05 23:08:33 -05001368 const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index);
Behdad Esfahbod2bd9fe32012-09-04 15:15:19 -04001369
Behdad Esfahbod0fe7a742018-11-05 23:08:33 -05001370 return l.would_apply (&c, &face->table.GSUB->accels[lookup_index]);
Behdad Esfahbodf8603662012-07-30 02:38:39 -04001371}
1372
Nathan Willis930f6fc2019-03-16 15:10:21 +00001373
1374/**
1375 * hb_ot_layout_substitute_start:
1376 * @font: #hb_font_t to use
1377 * @buffer: #hb_buffer_t buffer to work upon
1378 *
Nathan Willis3db22722019-04-02 18:49:40 +01001379 * Called before substitution lookups are performed, to ensure that glyph
1380 * class and other properties are set on the glyphs in the buffer.
Nathan Willis930f6fc2019-03-16 15:10:21 +00001381 *
1382 **/
Behdad Esfahbod46d6a212011-05-11 22:33:13 -04001383void
Behdad Esfahbodc624e182018-08-26 09:19:20 -07001384hb_ot_layout_substitute_start (hb_font_t *font,
1385 hb_buffer_t *buffer)
Behdad Esfahbod46d6a212011-05-11 22:33:13 -04001386{
Behdad Esfahbodc624e182018-08-26 09:19:20 -07001387_hb_ot_layout_set_glyph_props (font, buffer);
Behdad Esfahbod46d6a212011-05-11 22:33:13 -04001388}
1389
Behdad Esfahbod385f78b2018-11-07 17:19:21 -05001390void
1391hb_ot_layout_delete_glyphs_inplace (hb_buffer_t *buffer,
1392 bool (*filter) (const hb_glyph_info_t *info))
1393{
1394 /* Merge clusters and delete filtered glyphs.
1395 * NOTE! We can't use out-buffer as we have positioning data. */
1396 unsigned int j = 0;
1397 unsigned int count = buffer->len;
1398 hb_glyph_info_t *info = buffer->info;
1399 hb_glyph_position_t *pos = buffer->pos;
1400 for (unsigned int i = 0; i < count; i++)
1401 {
1402 if (filter (&info[i]))
1403 {
1404 /* Merge clusters.
1405 * Same logic as buffer->delete_glyph(), but for in-place removal. */
1406
1407 unsigned int cluster = info[i].cluster;
1408 if (i + 1 < count && cluster == info[i + 1].cluster)
1409 continue; /* Cluster survives; do nothing. */
1410
1411 if (j)
1412 {
1413 /* Merge cluster backward. */
1414 if (cluster < info[j - 1].cluster)
1415 {
1416 unsigned int mask = info[i].mask;
1417 unsigned int old_cluster = info[j - 1].cluster;
1418 for (unsigned k = j; k && info[k - 1].cluster == old_cluster; k--)
1419 buffer->set_cluster (info[k - 1], cluster, mask);
1420 }
1421 continue;
1422 }
1423
1424 if (i + 1 < count)
1425 buffer->merge_clusters (i, i + 2); /* Merge cluster forward. */
1426
1427 continue;
1428 }
1429
1430 if (j != i)
1431 {
1432 info[j] = info[i];
1433 pos[j] = pos[i];
1434 }
1435 j++;
1436 }
1437 buffer->len = j;
1438}
1439
Sascha Brawer01c3a882015-06-01 13:22:01 +02001440/**
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +04001441 * hb_ot_layout_lookup_substitute_closure:
Nathan Willis930f6fc2019-03-16 15:10:21 +00001442 * @face: #hb_face_t to work upon
1443 * @lookup_index: index of the feature lookup to query
Nathan Willis51228052019-03-17 14:43:06 +00001444 * @glyphs: (out): Array of glyphs comprising the transitive closure of the lookup
Nathan Willis930f6fc2019-03-16 15:10:21 +00001445 *
1446 * Compute the transitive closure of glyphs needed for a
1447 * specified lookup.
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +04001448 *
Sascha Brawer01c3a882015-06-01 13:22:01 +02001449 * Since: 0.9.7
1450 **/
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001451void
Behdad Esfahbod362a9902012-11-15 14:57:31 -08001452hb_ot_layout_lookup_substitute_closure (hb_face_t *face,
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -04001453 unsigned int lookup_index,
Nathan Willis930f6fc2019-03-16 15:10:21 +00001454 hb_set_t *glyphs /* OUT */)
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001455{
Behdad Esfahbod3a4e5dd2018-10-29 18:05:25 -07001456 hb_map_t done_lookups;
Garret Rieger45186b92018-06-05 17:14:42 -07001457 OT::hb_closure_context_t c (face, glyphs, &done_lookups);
Behdad Esfahbod9b346772012-11-23 17:55:40 -05001458
Behdad Esfahbod737efbe2018-11-05 23:26:29 -05001459 const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index);
Behdad Esfahbod9b346772012-11-23 17:55:40 -05001460
Garret Rieger45186b92018-06-05 17:14:42 -07001461 l.closure (&c, lookup_index);
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001462}
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04001463
Garret Rieger57badad2018-06-06 16:02:51 -07001464/**
1465 * hb_ot_layout_lookups_substitute_closure:
Nathan Willis930f6fc2019-03-16 15:10:21 +00001466 * @face: #hb_face_t to work upon
1467 * @lookups: The set of lookups to query
Nathan Willis51228052019-03-17 14:43:06 +00001468 * @glyphs: (out): Array of glyphs comprising the transitive closure of the lookups
Garret Rieger57badad2018-06-06 16:02:51 -07001469 *
1470 * Compute the transitive closure of glyphs needed for all of the
1471 * provided lookups.
1472 *
1473 * Since: 1.8.1
1474 **/
1475void
1476hb_ot_layout_lookups_substitute_closure (hb_face_t *face,
1477 const hb_set_t *lookups,
Nathan Willis930f6fc2019-03-16 15:10:21 +00001478 hb_set_t *glyphs /* OUT */)
Garret Rieger57badad2018-06-06 16:02:51 -07001479{
Behdad Esfahbod3a4e5dd2018-10-29 18:05:25 -07001480 hb_map_t done_lookups;
Garret Rieger57badad2018-06-06 16:02:51 -07001481 OT::hb_closure_context_t c (face, glyphs, &done_lookups);
Behdad Esfahbod737efbe2018-11-05 23:26:29 -05001482 const OT::GSUB& gsub = *face->table.GSUB->table;
Garret Rieger57badad2018-06-06 16:02:51 -07001483
Garret Rieger85646fd2018-07-23 15:37:18 -07001484 unsigned int iteration_count = 0;
Garret Rieger57badad2018-06-06 16:02:51 -07001485 unsigned int glyphs_length;
1486 do
1487 {
1488 glyphs_length = glyphs->get_population ();
Garret Riegerfeb23892018-06-07 14:32:34 -07001489 if (lookups != nullptr)
1490 {
1491 for (hb_codepoint_t lookup_index = HB_SET_VALUE_INVALID; hb_set_next (lookups, &lookup_index);)
1492 gsub.get_lookup (lookup_index).closure (&c, lookup_index);
Behdad Esfahbodf56cd9d2018-06-11 22:02:38 -04001493 }
1494 else
1495 {
Garret Riegerfeb23892018-06-07 14:32:34 -07001496 for (unsigned int i = 0; i < gsub.get_lookup_count (); i++)
1497 gsub.get_lookup (i).closure (&c, i);
1498 }
Behdad Esfahbode44046e2018-11-10 22:41:35 -05001499 } while (iteration_count++ <= HB_CLOSURE_MAX_STAGES &&
1500 glyphs_length != glyphs->get_population ());
Garret Rieger57badad2018-06-06 16:02:51 -07001501}
1502
Behdad Esfahbod9c42f052009-05-18 17:43:49 -04001503/*
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -04001504 * OT::GPOS
Behdad Esfahbod9c42f052009-05-18 17:43:49 -04001505 */
1506
Nathan Willis930f6fc2019-03-16 15:10:21 +00001507
1508/**
1509 * hb_ot_layout_has_positioning:
1510 * @face: #hb_face_t to work upon
1511 *
1512 * Return value: true if the face has GPOS data, false otherwise
1513 *
1514 **/
Behdad Esfahbod9c42f052009-05-18 17:43:49 -04001515hb_bool_t
Behdad Esfahbod0ead4812009-08-02 17:41:36 -04001516hb_ot_layout_has_positioning (hb_face_t *face)
1517{
Behdad Esfahbod737efbe2018-11-05 23:26:29 -05001518 return face->table.GPOS->table->has_data ();
Behdad Esfahbod0ead4812009-08-02 17:41:36 -04001519}
1520
Nathan Willis930f6fc2019-03-16 15:10:21 +00001521/**
1522 * hb_ot_layout_position_start:
1523 * @font: #hb_font_t to use
1524 * @buffer: #hb_buffer_t buffer to work upon
1525 *
Nathan Willis3db22722019-04-02 18:49:40 +01001526 * Called before positioning lookups are performed, to ensure that glyph
1527 * attachment types and glyph-attachment chains are set for the glyphs in the buffer.
1528 *
Nathan Willis930f6fc2019-03-16 15:10:21 +00001529 **/
Behdad Esfahbod8f0d7e02011-04-15 18:59:56 -04001530void
Behdad Esfahbod05bd1b62012-07-30 19:30:01 -04001531hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
Behdad Esfahbod8f0d7e02011-04-15 18:59:56 -04001532{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -04001533 OT::GPOS::position_start (font, buffer);
Behdad Esfahbod8f0d7e02011-04-15 18:59:56 -04001534}
1535
Nathan Willis930f6fc2019-03-16 15:10:21 +00001536
1537/**
1538 * hb_ot_layout_position_finish_advances:
1539 * @font: #hb_font_t to use
1540 * @buffer: #hb_buffer_t buffer to work upon
1541 *
Nathan Willis3db22722019-04-02 18:49:40 +01001542 * Called after positioning lookups are performed, to finish glyph advances.
1543 *
Nathan Willis930f6fc2019-03-16 15:10:21 +00001544 **/
Behdad Esfahbod9db8ad72009-11-06 16:47:31 -05001545void
Behdad Esfahbod7d8d58a2016-02-11 16:34:28 +07001546hb_ot_layout_position_finish_advances (hb_font_t *font, hb_buffer_t *buffer)
Behdad Esfahbod9db8ad72009-11-06 16:47:31 -05001547{
Behdad Esfahbod7d8d58a2016-02-11 16:34:28 +07001548 OT::GPOS::position_finish_advances (font, buffer);
1549}
1550
Nathan Willis3db22722019-04-02 18:49:40 +01001551/**
1552 * hb_ot_layout_position_finish_offsets:
1553 * @font: #hb_font_t to use
1554 * @buffer: #hb_buffer_t buffer to work upon
1555 *
1556 * Called after positioning lookups are performed, to finish glyph offsets.
1557 *
1558 **/
Behdad Esfahbod7d8d58a2016-02-11 16:34:28 +07001559void
1560hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
1561{
1562 OT::GPOS::position_finish_offsets (font, buffer);
Behdad Esfahbod9db8ad72009-11-06 16:47:31 -05001563}
Behdad Esfahbodf54cce32012-11-26 14:02:31 +02001564
Nathan Willis930f6fc2019-03-16 15:10:21 +00001565
Behdad Esfahbod6c725c72019-06-19 20:12:25 -07001566#ifndef HB_NO_LAYOUT_FEATURE_PARAMS
Sascha Brawer01c3a882015-06-01 13:22:01 +02001567/**
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +04001568 * hb_ot_layout_get_size_params:
Nathan Willis930f6fc2019-03-16 15:10:21 +00001569 * @face: #hb_face_t to work upon
Nathan Willis51228052019-03-17 14:43:06 +00001570 * @design_size: (out): The design size of the face
1571 * @subfamily_id: (out): The identifier of the face within the font subfamily
Nathan Willisc08ddbd2019-03-24 15:07:07 +00001572 * @subfamily_name_id: (out): The ‘name’ table name ID of the face within the font subfamily
Nathan Willis3db22722019-04-02 18:49:40 +01001573 * @range_start: (out): The minimum size of the recommended size range for the face
1574 * @range_end: (out): The maximum size of the recommended size range for the face
Nathan Willis930f6fc2019-03-16 15:10:21 +00001575 *
Nathan Willisc08ddbd2019-03-24 15:07:07 +00001576 * Fetches optical-size feature data (i.e., the `size` feature from GPOS). Note that
1577 * the subfamily_id and the subfamily name string (accessible via the subfamily_name_id)
1578 * as used here are defined as pertaining only to fonts within a font family that differ
1579 * specifically in their respective size ranges; other ways to differentiate fonts within
1580 * a subfamily are not covered by the `size` feature.
1581 *
1582 * For more information on this distinction, see the `size` documentation at
1583 * https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#tag-39size39
Nathan Willis930f6fc2019-03-16 15:10:21 +00001584 *
1585 * Return value: true if data found, false otherwise
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +04001586 *
Behdad Esfahbodb8811422015-09-03 15:53:22 +04301587 * Since: 0.9.10
Sascha Brawer01c3a882015-06-01 13:22:01 +02001588 **/
Behdad Esfahbodf54cce32012-11-26 14:02:31 +02001589hb_bool_t
Behdad Esfahboda7aba992018-10-30 14:04:09 -07001590hb_ot_layout_get_size_params (hb_face_t *face,
1591 unsigned int *design_size, /* OUT. May be NULL */
1592 unsigned int *subfamily_id, /* OUT. May be NULL */
1593 hb_ot_name_id_t *subfamily_name_id, /* OUT. May be NULL */
1594 unsigned int *range_start, /* OUT. May be NULL */
1595 unsigned int *range_end /* OUT. May be NULL */)
Behdad Esfahbodf54cce32012-11-26 14:02:31 +02001596{
Behdad Esfahbod737efbe2018-11-05 23:26:29 -05001597 const OT::GPOS &gpos = *face->table.GPOS->table;
Behdad Esfahbodefe252e2012-12-17 23:21:05 -05001598 const hb_tag_t tag = HB_TAG ('s','i','z','e');
Behdad Esfahbodf54cce32012-11-26 14:02:31 +02001599
Behdad Esfahbod0dff11f2012-11-30 08:14:20 +02001600 unsigned int num_features = gpos.get_feature_count ();
1601 for (unsigned int i = 0; i < num_features; i++)
1602 {
Behdad Esfahbodefe252e2012-12-17 23:21:05 -05001603 if (tag == gpos.get_feature_tag (i))
Behdad Esfahbodf54cce32012-11-26 14:02:31 +02001604 {
Behdad Esfahbod0dff11f2012-11-30 08:14:20 +02001605 const OT::Feature &f = gpos.get_feature (i);
Behdad Esfahbodefe252e2012-12-17 23:21:05 -05001606 const OT::FeatureParamsSize &params = f.get_feature_params ().get_size_params (tag);
Behdad Esfahbodf54cce32012-11-26 14:02:31 +02001607
Behdad Esfahbodefe252e2012-12-17 23:21:05 -05001608 if (params.designSize)
Behdad Esfahbod85bc44b2012-12-12 11:38:49 -05001609 {
Ebrahim Byagowi63109432018-10-13 14:00:05 +03301610 if (design_size) *design_size = params.designSize;
1611 if (subfamily_id) *subfamily_id = params.subfamilyID;
Behdad Esfahbod6ce49a92018-10-28 08:26:30 -07001612 if (subfamily_name_id) *subfamily_name_id = params.subfamilyNameID;
Ebrahim Byagowi63109432018-10-13 14:00:05 +03301613 if (range_start) *range_start = params.rangeStart;
1614 if (range_end) *range_end = params.rangeEnd;
Behdad Esfahbodefe252e2012-12-17 23:21:05 -05001615
1616 return true;
1617 }
Behdad Esfahbodf54cce32012-11-26 14:02:31 +02001618 }
1619 }
1620
Ebrahim Byagowi63109432018-10-13 14:00:05 +03301621 if (design_size) *design_size = 0;
1622 if (subfamily_id) *subfamily_id = 0;
Behdad Esfahboda7aba992018-10-30 14:04:09 -07001623 if (subfamily_name_id) *subfamily_name_id = HB_OT_NAME_ID_INVALID;
Ebrahim Byagowi63109432018-10-13 14:00:05 +03301624 if (range_start) *range_start = 0;
1625 if (range_end) *range_end = 0;
Behdad Esfahbodf54cce32012-11-26 14:02:31 +02001626
Behdad Esfahbodefe252e2012-12-17 23:21:05 -05001627 return false;
Behdad Esfahbodf54cce32012-11-26 14:02:31 +02001628}
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301629/**
1630 * hb_ot_layout_feature_get_name_ids:
1631 * @face: #hb_face_t to work upon
Behdad Esfahboda5ad8c62018-10-20 16:52:55 -07001632 * @table_tag: table tag to query, "GSUB" or "GPOS".
1633 * @feature_index: index of feature to query.
Nathan Willisaf5230b2019-03-18 14:03:16 +00001634 * @label_id: (out) (allow-none): The ‘name’ table name ID that specifies a string
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301635 * for a user-interface label for this feature. (May be NULL.)
Nathan Willisaf5230b2019-03-18 14:03:16 +00001636 * @tooltip_id: (out) (allow-none): The ‘name’ table name ID that specifies a string
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301637 * that an application can use for tooltip text for this
1638 * feature. (May be NULL.)
Nathan Willisaf5230b2019-03-18 14:03:16 +00001639 * @sample_id: (out) (allow-none): The ‘name’ table name ID that specifies sample text
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301640 * that illustrates the effect of this feature. (May be NULL.)
Nathan Willisaf5230b2019-03-18 14:03:16 +00001641 * @num_named_parameters: (out) (allow-none): Number of named parameters. (May be zero.)
1642 * @first_param_id: (out) (allow-none): The first ‘name’ table name ID used to specify
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301643 * strings for user-interface labels for the feature
1644 * parameters. (Must be zero if numParameters is zero.)
1645 *
Behdad Esfahbodc0a68142018-10-12 16:05:56 -04001646 * Fetches name indices from feature parameters for "Stylistic Set" ('ssXX') or
1647 * "Character Variant" ('cvXX') features.
1648 *
1649 * Return value: true if data found, false otherwise
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301650 *
Behdad Esfahbod3d9a0302018-10-18 05:58:17 -07001651 * Since: 2.0.0
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301652 **/
1653hb_bool_t
Behdad Esfahboda7aba992018-10-30 14:04:09 -07001654hb_ot_layout_feature_get_name_ids (hb_face_t *face,
1655 hb_tag_t table_tag,
1656 unsigned int feature_index,
1657 hb_ot_name_id_t *label_id, /* OUT. May be NULL */
1658 hb_ot_name_id_t *tooltip_id, /* OUT. May be NULL */
1659 hb_ot_name_id_t *sample_id, /* OUT. May be NULL */
1660 unsigned int *num_named_parameters, /* OUT. May be NULL */
1661 hb_ot_name_id_t *first_param_id /* OUT. May be NULL */)
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301662{
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301663 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
1664
Behdad Esfahbodc0a68142018-10-12 16:05:56 -04001665 hb_tag_t feature_tag = g.get_feature_tag (feature_index);
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301666 const OT::Feature &f = g.get_feature (feature_index);
1667
1668 const OT::FeatureParams &feature_params = f.get_feature_params ();
1669 if (&feature_params != &Null (OT::FeatureParams))
1670 {
1671 const OT::FeatureParamsStylisticSet& ss_params =
1672 feature_params.get_stylistic_set_params (feature_tag);
1673 if (&ss_params != &Null (OT::FeatureParamsStylisticSet)) /* ssXX */
1674 {
Behdad Esfahbod6ce49a92018-10-28 08:26:30 -07001675 if (label_id) *label_id = ss_params.uiNameID;
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301676 // ssXX features don't have the rest
Behdad Esfahboda7aba992018-10-30 14:04:09 -07001677 if (tooltip_id) *tooltip_id = HB_OT_NAME_ID_INVALID;
1678 if (sample_id) *sample_id = HB_OT_NAME_ID_INVALID;
Ebrahim Byagowi63109432018-10-13 14:00:05 +03301679 if (num_named_parameters) *num_named_parameters = 0;
Behdad Esfahboda7aba992018-10-30 14:04:09 -07001680 if (first_param_id) *first_param_id = HB_OT_NAME_ID_INVALID;
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301681 return true;
1682 }
1683 const OT::FeatureParamsCharacterVariants& cv_params =
1684 feature_params.get_character_variants_params (feature_tag);
1685 if (&cv_params != &Null (OT::FeatureParamsCharacterVariants)) /* cvXX */
1686 {
Behdad Esfahbod6ce49a92018-10-28 08:26:30 -07001687 if (label_id) *label_id = cv_params.featUILableNameID;
1688 if (tooltip_id) *tooltip_id = cv_params.featUITooltipTextNameID;
1689 if (sample_id) *sample_id = cv_params.sampleTextNameID;
Ebrahim Byagowi63109432018-10-13 14:00:05 +03301690 if (num_named_parameters) *num_named_parameters = cv_params.numNamedParameters;
Behdad Esfahbod6ce49a92018-10-28 08:26:30 -07001691 if (first_param_id) *first_param_id = cv_params.firstParamUILabelNameID;
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301692 return true;
1693 }
1694 }
1695
Behdad Esfahboda7aba992018-10-30 14:04:09 -07001696 if (label_id) *label_id = HB_OT_NAME_ID_INVALID;
1697 if (tooltip_id) *tooltip_id = HB_OT_NAME_ID_INVALID;
1698 if (sample_id) *sample_id = HB_OT_NAME_ID_INVALID;
Ebrahim Byagowi63109432018-10-13 14:00:05 +03301699 if (num_named_parameters) *num_named_parameters = 0;
Behdad Esfahboda7aba992018-10-30 14:04:09 -07001700 if (first_param_id) *first_param_id = HB_OT_NAME_ID_INVALID;
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301701 return false;
1702}
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301703/**
Behdad Esfahboda5ad8c62018-10-20 16:52:55 -07001704 * hb_ot_layout_feature_get_characters:
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301705 * @face: #hb_face_t to work upon
Behdad Esfahboda5ad8c62018-10-20 16:52:55 -07001706 * @table_tag: table tag to query, "GSUB" or "GPOS".
1707 * @feature_index: index of feature to query.
Nathan Willis3db22722019-04-02 18:49:40 +01001708 * @start_offset: offset of the first character to retrieve
1709 * @char_count: (inout) (allow-none): Input = the maximum number of characters to return;
1710 * Output = the actual number of characters returned (may be zero)
1711 * @characters: (out caller-allocates) (array length=char_count): A buffer pointer.
1712 * The Unicode codepoints of the characters for which this feature provides
1713 * glyph variants.
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301714 *
Nathan Willis3db22722019-04-02 18:49:40 +01001715 * Fetches a list of the characters defined as having a variant under the specified
1716 * "Character Variant" ("cvXX") feature tag.
Behdad Esfahbodc0a68142018-10-12 16:05:56 -04001717 *
Nathan Willis3db22722019-04-02 18:49:40 +01001718 * <note>Note: If the char_count output value is equal to its input value, then there
1719 * is a chance there were more characters defined under the feature tag than were
1720 * returned. This function can be called with incrementally larger start_offset
1721 * until the char_count output value is lower than its input value, or the size
1722 * of the characters array can be increased.</note>
1723 *
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301724 * Return value: Number of total sample characters in the cvXX feature.
1725 *
Behdad Esfahbod3d9a0302018-10-18 05:58:17 -07001726 * Since: 2.0.0
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301727 **/
1728unsigned int
1729hb_ot_layout_feature_get_characters (hb_face_t *face,
1730 hb_tag_t table_tag,
1731 unsigned int feature_index,
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301732 unsigned int start_offset,
1733 unsigned int *char_count, /* IN/OUT. May be NULL */
1734 hb_codepoint_t *characters /* OUT. May be NULL */)
1735{
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301736 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
1737
Behdad Esfahbodc0a68142018-10-12 16:05:56 -04001738 hb_tag_t feature_tag = g.get_feature_tag (feature_index);
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301739 const OT::Feature &f = g.get_feature (feature_index);
1740
1741 const OT::FeatureParams &feature_params = f.get_feature_params ();
1742
1743 const OT::FeatureParamsCharacterVariants& cv_params =
1744 feature_params.get_character_variants_params(feature_tag);
Ebrahim Byagowi63109432018-10-13 14:00:05 +03301745
1746 unsigned int len = 0;
1747 if (char_count && characters && start_offset < cv_params.characters.len)
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301748 {
Behdad Esfahbod41248cc2019-05-07 20:54:31 -07001749 len = hb_min (cv_params.characters.len - start_offset, *char_count);
Ebrahim Byagowi63109432018-10-13 14:00:05 +03301750 for (unsigned int i = 0; i < len; ++i)
1751 characters[i] = cv_params.characters[start_offset + i];
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301752 }
Ebrahim Byagowi63109432018-10-13 14:00:05 +03301753 if (char_count) *char_count = len;
1754 return cv_params.characters.len;
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301755}
Behdad Esfahbod6c725c72019-06-19 20:12:25 -07001756#endif
Ebrahim Byagowidc49bd82018-10-12 03:00:59 +03301757
Behdad Esfahbodd2c96812013-05-02 18:18:24 -04001758
1759/*
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001760 * Parts of different types are implemented here such that they have direct
Behdad Esfahbodd2c96812013-05-02 18:18:24 -04001761 * access to GSUB/GPOS lookups.
1762 */
1763
1764
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001765struct GSUBProxy
1766{
Behdad Esfahbod5d4b0372019-01-22 12:11:24 +01001767 static constexpr unsigned table_index = 0u;
Behdad Esfahbod39e1b6d2019-01-22 12:07:43 +01001768 static constexpr bool inplace = false;
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001769 typedef OT::SubstLookup Lookup;
1770
1771 GSUBProxy (hb_face_t *face) :
Behdad Esfahbod0fe7a742018-11-05 23:08:33 -05001772 table (*face->table.GSUB->table),
1773 accels (face->table.GSUB->accels) {}
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001774
1775 const OT::GSUB &table;
Behdad Esfahbod97e59132018-10-10 11:41:05 -04001776 const OT::hb_ot_layout_lookup_accelerator_t *accels;
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001777};
1778
1779struct GPOSProxy
1780{
Behdad Esfahbod5d4b0372019-01-22 12:11:24 +01001781 static constexpr unsigned table_index = 1u;
Behdad Esfahbod39e1b6d2019-01-22 12:07:43 +01001782 static constexpr bool inplace = true;
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001783 typedef OT::PosLookup Lookup;
1784
1785 GPOSProxy (hb_face_t *face) :
Behdad Esfahbod0fe7a742018-11-05 23:08:33 -05001786 table (*face->table.GPOS->table),
1787 accels (face->table.GPOS->accels) {}
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001788
1789 const OT::GPOS &table;
Behdad Esfahbod97e59132018-10-10 11:41:05 -04001790 const OT::hb_ot_layout_lookup_accelerator_t *accels;
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001791};
1792
1793
Behdad Esfahbode2f50f22015-02-19 17:15:05 +03001794static inline bool
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001795apply_forward (OT::hb_ot_apply_context_t *c,
Behdad Esfahbod78c09bf2018-10-10 11:50:46 -04001796 const OT::hb_ot_layout_lookup_accelerator_t &accel)
Behdad Esfahbode2f50f22015-02-19 17:15:05 +03001797{
1798 bool ret = false;
1799 hb_buffer_t *buffer = c->buffer;
Behdad Esfahbod7185b272018-05-31 20:03:00 -07001800 while (buffer->idx < buffer->len && buffer->successful)
Behdad Esfahbode2f50f22015-02-19 17:15:05 +03001801 {
Behdad Esfahbod3e704522016-01-11 17:38:41 +00001802 bool applied = false;
Behdad Esfahbode2f50f22015-02-19 17:15:05 +03001803 if (accel.may_have (buffer->cur().codepoint) &&
1804 (buffer->cur().mask & c->lookup_mask) &&
Behdad Esfahbod3e704522016-01-11 17:38:41 +00001805 c->check_glyph_property (&buffer->cur(), c->lookup_props))
1806 {
Behdad Esfahbode78549e2018-10-10 11:54:48 -04001807 applied = accel.apply (c);
Behdad Esfahbod3e704522016-01-11 17:38:41 +00001808 }
1809
1810 if (applied)
Behdad Esfahbode2f50f22015-02-19 17:15:05 +03001811 ret = true;
1812 else
1813 buffer->next_glyph ();
1814 }
1815 return ret;
1816}
1817
Behdad Esfahbode2f50f22015-02-19 17:15:05 +03001818static inline bool
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001819apply_backward (OT::hb_ot_apply_context_t *c,
Behdad Esfahbod78c09bf2018-10-10 11:50:46 -04001820 const OT::hb_ot_layout_lookup_accelerator_t &accel)
Behdad Esfahbode2f50f22015-02-19 17:15:05 +03001821{
1822 bool ret = false;
1823 hb_buffer_t *buffer = c->buffer;
1824 do
1825 {
1826 if (accel.may_have (buffer->cur().codepoint) &&
1827 (buffer->cur().mask & c->lookup_mask) &&
Behdad Esfahbod3e704522016-01-11 17:38:41 +00001828 c->check_glyph_property (&buffer->cur(), c->lookup_props))
Behdad Esfahbod9af983a2018-11-07 16:03:09 -05001829 ret |= accel.apply (c);
1830
Behdad Esfahbode2f50f22015-02-19 17:15:05 +03001831 /* The reverse lookup doesn't "advance" cursor (for good reason). */
1832 buffer->idx--;
1833
1834 }
1835 while ((int) buffer->idx >= 0);
1836 return ret;
1837}
1838
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04001839template <typename Proxy>
Behdad Esfahbod1d4a3282015-02-19 11:33:30 +03001840static inline void
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001841apply_string (OT::hb_ot_apply_context_t *c,
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04001842 const typename Proxy::Lookup &lookup,
Behdad Esfahbod97e59132018-10-10 11:41:05 -04001843 const OT::hb_ot_layout_lookup_accelerator_t &accel)
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04001844{
Behdad Esfahbodac8cd512013-10-18 19:33:09 +02001845 hb_buffer_t *buffer = c->buffer;
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04001846
Behdad Esfahbod5337db22015-11-06 16:18:09 -08001847 if (unlikely (!buffer->len || !c->lookup_mask))
Behdad Esfahbod1d4a3282015-02-19 11:33:30 +03001848 return;
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04001849
Behdad Esfahbod2c8b3b22015-08-18 14:36:43 +01001850 c->set_lookup_props (lookup.get_props ());
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04001851
1852 if (likely (!lookup.is_reverse ()))
1853 {
1854 /* in/out forward substitution/positioning */
Behdad Esfahbod271cb7c2019-01-22 12:05:35 +01001855 if (Proxy::table_index == 0u)
Behdad Esfahbodac8cd512013-10-18 19:33:09 +02001856 buffer->clear_output ();
1857 buffer->idx = 0;
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04001858
Behdad Esfahbod640b66c2015-02-19 17:30:05 +03001859 bool ret;
Behdad Esfahbod78c09bf2018-10-10 11:50:46 -04001860 ret = apply_forward (c, accel);
Behdad Esfahbod640b66c2015-02-19 17:30:05 +03001861 if (ret)
Behdad Esfahbod9d9e72e2013-05-03 18:10:10 -04001862 {
Behdad Esfahbod6ffc0072013-10-28 19:26:02 +01001863 if (!Proxy::inplace)
Behdad Esfahbodac8cd512013-10-18 19:33:09 +02001864 buffer->swap_buffers ();
Behdad Esfahbod9d9e72e2013-05-03 18:10:10 -04001865 else
Behdad Esfahbod1d4a3282015-02-19 11:33:30 +03001866 assert (!buffer->has_separate_output ());
Behdad Esfahbod9d9e72e2013-05-03 18:10:10 -04001867 }
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04001868 }
1869 else
1870 {
1871 /* in-place backward substitution/positioning */
Behdad Esfahbod271cb7c2019-01-22 12:05:35 +01001872 if (Proxy::table_index == 0u)
Behdad Esfahbodac8cd512013-10-18 19:33:09 +02001873 buffer->remove_output ();
1874 buffer->idx = buffer->len - 1;
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04001875
Behdad Esfahbod78c09bf2018-10-10 11:50:46 -04001876 apply_backward (c, accel);
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04001877 }
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04001878}
1879
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001880template <typename Proxy>
1881inline void hb_ot_map_t::apply (const Proxy &proxy,
Behdad Esfahbodd2c96812013-05-02 18:18:24 -04001882 const hb_ot_shape_plan_t *plan,
1883 hb_font_t *font,
1884 hb_buffer_t *buffer) const
1885{
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001886 const unsigned int table_index = proxy.table_index;
Behdad Esfahbodd2c96812013-05-02 18:18:24 -04001887 unsigned int i = 0;
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001888 OT::hb_ot_apply_context_t c (table_index, font, buffer);
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04001889 c.set_recurse_func (Proxy::Lookup::apply_recurse_func);
Behdad Esfahbodd2c96812013-05-02 18:18:24 -04001890
Behdad Esfahbod474a1202018-12-21 18:46:51 -05001891 for (unsigned int stage_index = 0; stage_index < stages[table_index].length; stage_index++) {
Behdad Esfahbodd2c96812013-05-02 18:18:24 -04001892 const stage_map_t *stage = &stages[table_index][stage_index];
1893 for (; i < stage->last_lookup; i++)
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001894 {
1895 unsigned int lookup_index = lookups[table_index][i].index;
Behdad Esfahbod0475ef22015-12-18 18:17:07 +00001896 if (!buffer->message (font, "start lookup %d", lookup_index)) continue;
Behdad Esfahbod2c8b3b22015-08-18 14:36:43 +01001897 c.set_lookup_index (lookup_index);
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001898 c.set_lookup_mask (lookups[table_index][i].mask);
1899 c.set_auto_zwj (lookups[table_index][i].auto_zwj);
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +01001900 c.set_auto_zwnj (lookups[table_index][i].auto_zwnj);
David Corbettc2a75e02018-01-25 14:22:03 -05001901 if (lookups[table_index][i].random)
1902 {
David Corbettb545e272018-02-23 12:22:32 -05001903 c.set_random (true);
David Corbettc2a75e02018-01-25 14:22:03 -05001904 buffer->unsafe_to_break_all ();
1905 }
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04001906 apply_string<Proxy> (&c,
1907 proxy.table.get_lookup (lookup_index),
1908 proxy.accels[lookup_index]);
Behdad Esfahbod0475ef22015-12-18 18:17:07 +00001909 (void) buffer->message (font, "end lookup %d", lookup_index);
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001910 }
Behdad Esfahbodd2c96812013-05-02 18:18:24 -04001911
1912 if (stage->pause_func)
1913 {
1914 buffer->clear_output ();
1915 stage->pause_func (plan, font, buffer);
1916 }
1917 }
1918}
1919
1920void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
1921{
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001922 GSUBProxy proxy (font->face);
1923 apply (proxy, plan, font, buffer);
Behdad Esfahbodd2c96812013-05-02 18:18:24 -04001924}
1925
1926void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
1927{
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001928 GPOSProxy proxy (font->face);
1929 apply (proxy, plan, font, buffer);
1930}
1931
Behdad Esfahbodcdab20d2018-02-10 15:45:17 -06001932void
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001933hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001934 const OT::SubstLookup &lookup,
Behdad Esfahbod97e59132018-10-10 11:41:05 -04001935 const OT::hb_ot_layout_lookup_accelerator_t &accel)
Behdad Esfahbodbac1dd62013-05-02 18:52:24 -04001936{
Behdad Esfahbod45f3d982013-05-03 17:49:44 -04001937 apply_string<GSUBProxy> (c, lookup, accel);
Behdad Esfahbodd2c96812013-05-02 18:18:24 -04001938}
Ebrahim Byagowib8a78ce2018-11-03 22:28:30 +03301939
1940#if 0
Ebrahim Byagowib8a78ce2018-11-03 22:28:30 +03301941hb_bool_t
1942hb_ot_layout_get_baseline (hb_font_t *font,
1943 hb_ot_layout_baseline_t baseline,
1944 hb_direction_t direction,
1945 hb_tag_t script_tag,
1946 hb_tag_t language_tag,
1947 hb_position_t *coord /* OUT. May be NULL. */)
1948{
Behdad Esfahbodf0b0fd42019-06-18 14:40:24 -07001949 bool result = font->face->table.BASE->get_baseline (font, baseline, direction, script_tag,
1950 language_tag, coord);
Ebrahim Byagowib8a78ce2018-11-03 22:28:30 +03301951
1952 /* TODO: Simulate https://docs.microsoft.com/en-us/typography/opentype/spec/baselinetags#ideographic-em-box */
1953 if (!result && coord) *coord = 0;
1954
1955 if (coord) *coord = font->em_scale_dir (*coord, direction);
1956
1957 return result;
1958}
1959
1960/* To be moved to public header */
1961/*
1962 * BASE
1963 */
1964
1965/**
1966 * hb_ot_layout_baseline_t:
1967 *
1968 * https://docs.microsoft.com/en-us/typography/opentype/spec/baselinetags
1969 *
1970 * Since: DONTREPLACEME
1971 */
1972typedef enum {
1973 HB_OT_LAYOUT_BASELINE_HANG = HB_TAG('h','a','n','g'),
1974 HB_OT_LAYOUT_BASELINE_ICFB = HB_TAG('i','c','f','b'),
1975 HB_OT_LAYOUT_BASELINE_ICFT = HB_TAG('i','c','f','t'),
1976 HB_OT_LAYOUT_BASELINE_IDEO = HB_TAG('i','d','e','o'),
1977 HB_OT_LAYOUT_BASELINE_IDTB = HB_TAG('i','d','t','b'),
1978 HB_OT_LAYOUT_BASELINE_MATH = HB_TAG('m','a','t','h'),
1979 HB_OT_LAYOUT_BASELINE_ROMN = HB_TAG('r','o','m','n')
1980} hb_ot_layout_baseline_t;
1981
Nathan Willis930f6fc2019-03-16 15:10:21 +00001982
1983/**
1984 * hb_ot_layout_get_baseline:
1985 * @font: The #hb_font_t to work upon
1986 * @baseline: The #hb_ot_layout_baseline_t to query
Nathan Willisc08ddbd2019-03-24 15:07:07 +00001987 * @direction: The #hb_direction_t text direction to use (horizontal or vertical)
Nathan Willis930f6fc2019-03-16 15:10:21 +00001988 * @script_tag: #hb_tag_t of the script to use
1989 * @language_tag: #hb_tag_t of the language to use
Nathan Willis51228052019-03-17 14:43:06 +00001990 * @coord: (out): The position of the requested baseline
Nathan Willis930f6fc2019-03-16 15:10:21 +00001991 *
1992 * Fetches the coordinates of the specified baseline in the face, underneath
1993 * the specified script and language and in the specified text direction.
1994 *
1995 * Return value: true if the baseline is found for the settings queried, false otherwise
1996 *
1997 **/
Ebrahim Byagowib8a78ce2018-11-03 22:28:30 +03301998HB_EXTERN hb_bool_t
1999hb_ot_layout_get_baseline (hb_font_t *font,
2000 hb_ot_layout_baseline_t baseline,
2001 hb_direction_t direction,
2002 hb_tag_t script_tag,
2003 hb_tag_t language_tag,
2004 hb_position_t *coord /* OUT. May be NULL. */);
2005
2006#endif
Behdad Esfahbodbb4bbe62019-06-26 13:29:58 -07002007
2008
2009#endif