/src/harfbuzz/src/hb-ot-layout.cc
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /*  | 
2  |  |  * Copyright © 1998-2004  David Turner and Werner Lemberg  | 
3  |  |  * Copyright © 2006  Behdad Esfahbod  | 
4  |  |  * Copyright © 2007,2008,2009  Red Hat, Inc.  | 
5  |  |  * Copyright © 2012,2013  Google, Inc.  | 
6  |  |  *  | 
7  |  |  *  This is part of HarfBuzz, a text shaping library.  | 
8  |  |  *  | 
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  | 
28  |  |  * Google Author(s): Behdad Esfahbod  | 
29  |  |  */  | 
30  |  |  | 
31  |  | #include "hb.hh"  | 
32  |  |  | 
33  |  | #ifndef HB_NO_OT_LAYOUT  | 
34  |  |  | 
35  |  | #ifdef HB_NO_OT_TAG  | 
36  |  | #error "Cannot compile hb-ot-layout.cc with HB_NO_OT_TAG."  | 
37  |  | #endif  | 
38  |  |  | 
39  |  | #include "hb-open-type.hh"  | 
40  |  | #include "hb-ot-layout.hh"  | 
41  |  | #include "hb-ot-face.hh"  | 
42  |  | #include "hb-ot-map.hh"  | 
43  |  | #include "hb-map.hh"  | 
44  |  |  | 
45  |  | #include "hb-ot-kern-table.hh"  | 
46  |  | #include "hb-ot-layout-gdef-table.hh"  | 
47  |  | #include "hb-ot-layout-gsub-table.hh"  | 
48  |  | #include "hb-ot-layout-gpos-table.hh"  | 
49  |  | #include "hb-ot-layout-base-table.hh"  | 
50  |  | #include "hb-ot-layout-jstf-table.hh" // Just so we compile it; unused otherwise.  | 
51  |  | #include "hb-ot-name-table.hh"  | 
52  |  | #include "hb-ot-os2-table.hh"  | 
53  |  |  | 
54  |  | #include "hb-aat-layout-morx-table.hh"  | 
55  |  | #include "hb-aat-layout-opbd-table.hh" // Just so we compile it; unused otherwise.  | 
56  |  |  | 
57  |  | using OT::Layout::GSUB;  | 
58  |  | using OT::Layout::GPOS;  | 
59  |  |  | 
60  |  | /**  | 
61  |  |  * SECTION:hb-ot-layout  | 
62  |  |  * @title: hb-ot-layout  | 
63  |  |  * @short_description: OpenType Layout  | 
64  |  |  * @include: hb-ot.h  | 
65  |  |  *  | 
66  |  |  * Functions for querying OpenType Layout features in the font face.  | 
67  |  |  **/  | 
68  |  |  | 
69  |  |  | 
70  |  | /*  | 
71  |  |  * kern  | 
72  |  |  */  | 
73  |  |  | 
74  |  | #ifndef HB_NO_OT_KERN  | 
75  |  | /**  | 
76  |  |  * hb_ot_layout_has_kerning:  | 
77  |  |  * @face: The #hb_face_t to work on  | 
78  |  |  *  | 
79  |  |  * Tests whether a face includes any kerning data in the 'kern' table.  | 
80  |  |  * Does NOT test for kerning lookups in the GPOS table.  | 
81  |  |  *  | 
82  |  |  * Return value: `true` if data found, `false` otherwise  | 
83  |  |  *  | 
84  |  |  **/  | 
85  |  | bool  | 
86  |  | hb_ot_layout_has_kerning (hb_face_t *face)  | 
87  | 112k  | { | 
88  | 112k  |   return face->table.kern->has_data ();  | 
89  | 112k  | }  | 
90  |  |  | 
91  |  | /**  | 
92  |  |  * hb_ot_layout_has_machine_kerning:  | 
93  |  |  * @face: The #hb_face_t to work on  | 
94  |  |  *  | 
95  |  |  * Tests whether a face includes any state-machine kerning in the 'kern' table.  | 
96  |  |  * Does NOT examine the GPOS table.  | 
97  |  |  *  | 
98  |  |  * Return value: `true` if data found, `false` otherwise  | 
99  |  |  *  | 
100  |  |  **/  | 
101  |  | bool  | 
102  |  | hb_ot_layout_has_machine_kerning (hb_face_t *face)  | 
103  | 1.07k  | { | 
104  | 1.07k  |   return face->table.kern->has_state_machine ();  | 
105  | 1.07k  | }  | 
106  |  |  | 
107  |  | /**  | 
108  |  |  * hb_ot_layout_has_cross_kerning:  | 
109  |  |  * @face: The #hb_face_t to work on  | 
110  |  |  *  | 
111  |  |  * Tests whether a face has any cross-stream kerning (i.e., kerns  | 
112  |  |  * that make adjustments perpendicular to the direction of the text  | 
113  |  |  * flow: Y adjustments in horizontal text or X adjustments in  | 
114  |  |  * vertical text) in the 'kern' table.  | 
115  |  |  *  | 
116  |  |  * Does NOT examine the GPOS table.  | 
117  |  |  *  | 
118  |  |  * Return value: `true` is data found, `false` otherwise  | 
119  |  |  *  | 
120  |  |  **/  | 
121  |  | bool  | 
122  |  | hb_ot_layout_has_cross_kerning (hb_face_t *face)  | 
123  | 1.07k  | { | 
124  | 1.07k  |   return face->table.kern->has_cross_stream ();  | 
125  | 1.07k  | }  | 
126  |  |  | 
127  |  | void  | 
128  |  | hb_ot_layout_kern (const hb_ot_shape_plan_t *plan,  | 
129  |  |        hb_font_t *font,  | 
130  |  |        hb_buffer_t  *buffer)  | 
131  | 7.61k  | { | 
132  | 7.61k  |   hb_blob_t *blob = font->face->table.kern.get_blob ();  | 
133  | 7.61k  |   const AAT::kern& kern = *blob->as<AAT::kern> ();  | 
134  |  |  | 
135  | 7.61k  |   AAT::hb_aat_apply_context_t c (plan, font, buffer, blob);  | 
136  |  |  | 
137  | 7.61k  |   if (!buffer->message (font, "start table kern")) return;  | 
138  | 7.61k  |   kern.apply (&c);  | 
139  | 7.61k  |   (void) buffer->message (font, "end table kern");  | 
140  | 7.61k  | }  | 
141  |  | #endif  | 
142  |  |  | 
143  |  |  | 
144  |  | /*  | 
145  |  |  * GDEF  | 
146  |  |  */  | 
147  |  |  | 
148  |  | bool  | 
149  |  | OT::GDEF::is_blocklisted (hb_blob_t *blob,  | 
150  |  |         hb_face_t *face) const  | 
151  | 92.7k  | { | 
152  |  | #ifdef HB_NO_OT_LAYOUT_BLOCKLIST  | 
153  |  |   return false;  | 
154  |  | #endif  | 
155  |  |   /* The ugly business of blocklisting individual fonts' tables happen here!  | 
156  |  |    * See this thread for why we finally had to bend in and do this:  | 
157  |  |    * https://lists.freedesktop.org/archives/harfbuzz/2016-February/005489.html  | 
158  |  |    *  | 
159  |  |    * In certain versions of Times New Roman Italic and Bold Italic,  | 
160  |  |    * ASCII double quotation mark U+0022 has wrong glyph class 3 (mark)  | 
161  |  |    * in GDEF.  Many versions of Tahoma have bad GDEF tables that  | 
162  |  |    * incorrectly classify some spacing marks such as certain IPA  | 
163  |  |    * symbols as glyph class 3. So do older versions of Microsoft  | 
164  |  |    * Himalaya, and the version of Cantarell shipped by Ubuntu 16.04.  | 
165  |  |    *  | 
166  |  |    * Nuke the GDEF tables of to avoid unwanted width-zeroing.  | 
167  |  |    *  | 
168  |  |    * See https://bugzilla.mozilla.org/show_bug.cgi?id=1279925  | 
169  |  |    *     https://bugzilla.mozilla.org/show_bug.cgi?id=1279693  | 
170  |  |    *     https://bugzilla.mozilla.org/show_bug.cgi?id=1279875  | 
171  |  |    */  | 
172  | 92.7k  |   switch HB_CODEPOINT_ENCODE3(blob->length,  | 
173  | 92.7k  |             face->table.GSUB->table.get_length (),  | 
174  | 92.7k  |             face->table.GPOS->table.get_length ())  | 
175  | 92.7k  |   { | 
176  |  |     /* sha1sum:c5ee92f0bca4bfb7d06c4d03e8cf9f9cf75d2e8a Windows 7? timesi.ttf */  | 
177  | 0  |     case HB_CODEPOINT_ENCODE3 (442, 2874, 42038):  | 
178  |  |     /* sha1sum:37fc8c16a0894ab7b749e35579856c73c840867b Windows 7? timesbi.ttf */  | 
179  | 0  |     case HB_CODEPOINT_ENCODE3 (430, 2874, 40662):  | 
180  |  |     /* sha1sum:19fc45110ea6cd3cdd0a5faca256a3797a069a80 Windows 7 timesi.ttf */  | 
181  | 0  |     case HB_CODEPOINT_ENCODE3 (442, 2874, 39116):  | 
182  |  |     /* sha1sum:6d2d3c9ed5b7de87bc84eae0df95ee5232ecde26 Windows 7 timesbi.ttf */  | 
183  | 0  |     case HB_CODEPOINT_ENCODE3 (430, 2874, 39374):  | 
184  |  |     /* sha1sum:8583225a8b49667c077b3525333f84af08c6bcd8 OS X 10.11.3 Times New Roman Italic.ttf */  | 
185  | 0  |     case HB_CODEPOINT_ENCODE3 (490, 3046, 41638):  | 
186  |  |     /* sha1sum:ec0f5a8751845355b7c3271d11f9918a966cb8c9 OS X 10.11.3 Times New Roman Bold Italic.ttf */  | 
187  | 0  |     case HB_CODEPOINT_ENCODE3 (478, 3046, 41902):  | 
188  |  |     /* sha1sum:96eda93f7d33e79962451c6c39a6b51ee893ce8c  tahoma.ttf from Windows 8 */  | 
189  | 0  |     case HB_CODEPOINT_ENCODE3 (898, 12554, 46470):  | 
190  |  |     /* sha1sum:20928dc06014e0cd120b6fc942d0c3b1a46ac2bc  tahomabd.ttf from Windows 8 */  | 
191  | 0  |     case HB_CODEPOINT_ENCODE3 (910, 12566, 47732):  | 
192  |  |     /* sha1sum:4f95b7e4878f60fa3a39ca269618dfde9721a79e  tahoma.ttf from Windows 8.1 */  | 
193  | 0  |     case HB_CODEPOINT_ENCODE3 (928, 23298, 59332):  | 
194  |  |     /* sha1sum:6d400781948517c3c0441ba42acb309584b73033  tahomabd.ttf from Windows 8.1 */  | 
195  | 0  |     case HB_CODEPOINT_ENCODE3 (940, 23310, 60732):  | 
196  |  |     /* tahoma.ttf v6.04 from Windows 8.1 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */  | 
197  | 0  |     case HB_CODEPOINT_ENCODE3 (964, 23836, 60072):  | 
198  |  |     /* tahomabd.ttf v6.04 from Windows 8.1 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */  | 
199  | 0  |     case HB_CODEPOINT_ENCODE3 (976, 23832, 61456):  | 
200  |  |     /* sha1sum:e55fa2dfe957a9f7ec26be516a0e30b0c925f846  tahoma.ttf from Windows 10 */  | 
201  | 0  |     case HB_CODEPOINT_ENCODE3 (994, 24474, 60336):  | 
202  |  |     /* sha1sum:7199385abb4c2cc81c83a151a7599b6368e92343  tahomabd.ttf from Windows 10 */  | 
203  | 0  |     case HB_CODEPOINT_ENCODE3 (1006, 24470, 61740):  | 
204  |  |     /* tahoma.ttf v6.91 from Windows 10 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */  | 
205  | 0  |     case HB_CODEPOINT_ENCODE3 (1006, 24576, 61346):  | 
206  |  |     /* tahomabd.ttf v6.91 from Windows 10 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */  | 
207  | 0  |     case HB_CODEPOINT_ENCODE3 (1018, 24572, 62828):  | 
208  |  |     /* sha1sum:b9c84d820c49850d3d27ec498be93955b82772b5  tahoma.ttf from Windows 10 AU */  | 
209  | 0  |     case HB_CODEPOINT_ENCODE3 (1006, 24576, 61352):  | 
210  |  |     /* sha1sum:2bdfaab28174bdadd2f3d4200a30a7ae31db79d2  tahomabd.ttf from Windows 10 AU */  | 
211  | 0  |     case HB_CODEPOINT_ENCODE3 (1018, 24572, 62834):  | 
212  |  |     /* sha1sum:b0d36cf5a2fbe746a3dd277bffc6756a820807a7  Tahoma.ttf from Mac OS X 10.9 */  | 
213  | 0  |     case HB_CODEPOINT_ENCODE3 (832, 7324, 47162):  | 
214  |  |     /* sha1sum:12fc4538e84d461771b30c18b5eb6bd434e30fba  Tahoma Bold.ttf from Mac OS X 10.9 */  | 
215  | 0  |     case HB_CODEPOINT_ENCODE3 (844, 7302, 45474):  | 
216  |  |     /* sha1sum:eb8afadd28e9cf963e886b23a30b44ab4fd83acc  himalaya.ttf from Windows 7 */  | 
217  | 0  |     case HB_CODEPOINT_ENCODE3 (180, 13054, 7254):  | 
218  |  |     /* sha1sum:73da7f025b238a3f737aa1fde22577a6370f77b0  himalaya.ttf from Windows 8 */  | 
219  | 0  |     case HB_CODEPOINT_ENCODE3 (192, 12638, 7254):  | 
220  |  |     /* sha1sum:6e80fd1c0b059bbee49272401583160dc1e6a427  himalaya.ttf from Windows 8.1 */  | 
221  | 0  |     case HB_CODEPOINT_ENCODE3 (192, 12690, 7254):  | 
222  |  |     /* 8d9267aea9cd2c852ecfb9f12a6e834bfaeafe44  cantarell-fonts-0.0.21/otf/Cantarell-Regular.otf */  | 
223  |  |     /* 983988ff7b47439ab79aeaf9a45bd4a2c5b9d371  cantarell-fonts-0.0.21/otf/Cantarell-Oblique.otf */  | 
224  | 0  |     case HB_CODEPOINT_ENCODE3 (188, 248, 3852):  | 
225  |  |     /* 2c0c90c6f6087ffbfea76589c93113a9cbb0e75f  cantarell-fonts-0.0.21/otf/Cantarell-Bold.otf */  | 
226  |  |     /* 55461f5b853c6da88069ffcdf7f4dd3f8d7e3e6b  cantarell-fonts-0.0.21/otf/Cantarell-Bold-Oblique.otf */  | 
227  | 0  |     case HB_CODEPOINT_ENCODE3 (188, 264, 3426):  | 
228  |  |     /* d125afa82a77a6475ac0e74e7c207914af84b37a padauk-2.80/Padauk.ttf RHEL 7.2 */  | 
229  | 0  |     case HB_CODEPOINT_ENCODE3 (1058, 47032, 11818):  | 
230  |  |     /* 0f7b80437227b90a577cc078c0216160ae61b031 padauk-2.80/Padauk-Bold.ttf RHEL 7.2*/  | 
231  | 0  |     case HB_CODEPOINT_ENCODE3 (1046, 47030, 12600):  | 
232  |  |     /* d3dde9aa0a6b7f8f6a89ef1002e9aaa11b882290 padauk-2.80/Padauk.ttf Ubuntu 16.04 */  | 
233  | 0  |     case HB_CODEPOINT_ENCODE3 (1058, 71796, 16770):  | 
234  |  |     /* 5f3c98ccccae8a953be2d122c1b3a77fd805093f padauk-2.80/Padauk-Bold.ttf Ubuntu 16.04 */  | 
235  | 0  |     case HB_CODEPOINT_ENCODE3 (1046, 71790, 17862):  | 
236  |  |     /* 6c93b63b64e8b2c93f5e824e78caca555dc887c7 padauk-2.80/Padauk-book.ttf */  | 
237  | 0  |     case HB_CODEPOINT_ENCODE3 (1046, 71788, 17112):  | 
238  |  |     /* d89b1664058359b8ec82e35d3531931125991fb9 padauk-2.80/Padauk-bookbold.ttf */  | 
239  | 0  |     case HB_CODEPOINT_ENCODE3 (1058, 71794, 17514):  | 
240  |  |     /* 824cfd193aaf6234b2b4dc0cf3c6ef576c0d00ef padauk-3.0/Padauk-book.ttf */  | 
241  | 0  |     case HB_CODEPOINT_ENCODE3 (1330, 109904, 57938):  | 
242  |  |     /* 91fcc10cf15e012d27571e075b3b4dfe31754a8a padauk-3.0/Padauk-bookbold.ttf */  | 
243  | 0  |     case HB_CODEPOINT_ENCODE3 (1330, 109904, 58972):  | 
244  |  |     /* sha1sum: c26e41d567ed821bed997e937bc0c41435689e85  Padauk.ttf  | 
245  |  |      *  "Padauk Regular" "Version 2.5", see https://crbug.com/681813 */  | 
246  | 0  |     case HB_CODEPOINT_ENCODE3 (1004, 59092, 14836):  | 
247  | 0  |       return true;  | 
248  | 92.7k  |   }  | 
249  | 92.7k  |   return false;  | 
250  | 92.7k  | }  | 
251  |  |  | 
252  |  | static void  | 
253  |  | _hb_ot_layout_set_glyph_props (hb_font_t *font,  | 
254  |  |              hb_buffer_t *buffer)  | 
255  | 1.50M  | { | 
256  | 1.50M  |   _hb_buffer_assert_gsubgpos_vars (buffer);  | 
257  |  |  | 
258  | 1.50M  |   const OT::GDEF &gdef = *font->face->table.GDEF->table;  | 
259  | 1.50M  |   unsigned int count = buffer->len;  | 
260  | 5.82M  |   for (unsigned int i = 0; i < count; i++)  | 
261  | 4.31M  |   { | 
262  | 4.31M  |     _hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint));  | 
263  | 4.31M  |     _hb_glyph_info_clear_lig_props (&buffer->info[i]);  | 
264  | 4.31M  |   }  | 
265  | 1.50M  | }  | 
266  |  |  | 
267  |  | /* Public API */  | 
268  |  |  | 
269  |  | /**  | 
270  |  |  * hb_ot_layout_has_glyph_classes:  | 
271  |  |  * @face: #hb_face_t to work upon  | 
272  |  |  *  | 
273  |  |  * Tests whether a face has any glyph classes defined in its GDEF table.  | 
274  |  |  *  | 
275  |  |  * Return value: `true` if data found, `false` otherwise  | 
276  |  |  *  | 
277  |  |  **/  | 
278  |  | hb_bool_t  | 
279  |  | hb_ot_layout_has_glyph_classes (hb_face_t *face)  | 
280  | 218k  | { | 
281  | 218k  |   return face->table.GDEF->table->has_glyph_classes ();  | 
282  | 218k  | }  | 
283  |  |  | 
284  |  | /**  | 
285  |  |  * hb_ot_layout_get_glyph_class:  | 
286  |  |  * @face: The #hb_face_t to work on  | 
287  |  |  * @glyph: The #hb_codepoint_t code point to query  | 
288  |  |  *  | 
289  |  |  * Fetches the GDEF class of the requested glyph in the specified face.  | 
290  |  |  *  | 
291  |  |  * Return value: The #hb_ot_layout_glyph_class_t glyph class of the given code  | 
292  |  |  * point in the GDEF table of the face.  | 
293  |  |  *  | 
294  |  |  * Since: 0.9.7  | 
295  |  |  **/  | 
296  |  | hb_ot_layout_glyph_class_t  | 
297  |  | hb_ot_layout_get_glyph_class (hb_face_t      *face,  | 
298  |  |             hb_codepoint_t  glyph)  | 
299  | 0  | { | 
300  | 0  |   return (hb_ot_layout_glyph_class_t) face->table.GDEF->table->get_glyph_class (glyph);  | 
301  | 0  | }  | 
302  |  |  | 
303  |  | /**  | 
304  |  |  * hb_ot_layout_get_glyphs_in_class:  | 
305  |  |  * @face: The #hb_face_t to work on  | 
306  |  |  * @klass: The #hb_ot_layout_glyph_class_t GDEF class to retrieve  | 
307  |  |  * @glyphs: (out): The #hb_set_t set of all glyphs belonging to the requested  | 
308  |  |  *          class.  | 
309  |  |  *  | 
310  |  |  * Retrieves the set of all glyphs from the face that belong to the requested  | 
311  |  |  * glyph class in the face's GDEF table.  | 
312  |  |  *  | 
313  |  |  * Since: 0.9.7  | 
314  |  |  **/  | 
315  |  | void  | 
316  |  | hb_ot_layout_get_glyphs_in_class (hb_face_t                  *face,  | 
317  |  |           hb_ot_layout_glyph_class_t  klass,  | 
318  |  |           hb_set_t                   *glyphs /* OUT */)  | 
319  | 0  | { | 
320  | 0  |   return face->table.GDEF->table->get_glyphs_in_class (klass, glyphs);  | 
321  | 0  | }  | 
322  |  |  | 
323  |  | #ifndef HB_NO_LAYOUT_UNUSED  | 
324  |  | /**  | 
325  |  |  * hb_ot_layout_get_attach_points:  | 
326  |  |  * @face: The #hb_face_t to work on  | 
327  |  |  * @glyph: The #hb_codepoint_t code point to query  | 
328  |  |  * @start_offset: offset of the first attachment point to retrieve  | 
329  |  |  * @point_count: (inout) (optional): Input = the maximum number of attachment points to return;  | 
330  |  |  *               Output = the actual number of attachment points returned (may be zero)  | 
331  |  |  * @point_array: (out) (array length=point_count): The array of attachment points found for the query  | 
332  |  |  *  | 
333  |  |  * Fetches a list of all attachment points for the specified glyph in the GDEF  | 
334  |  |  * table of the face. The list returned will begin at the offset provided.  | 
335  |  |  *  | 
336  |  |  * Useful if the client program wishes to cache the list.  | 
337  |  |  *  | 
338  |  |  * Return value: Total number of attachment points for @glyph.  | 
339  |  |  *  | 
340  |  |  **/  | 
341  |  | unsigned int  | 
342  |  | hb_ot_layout_get_attach_points (hb_face_t      *face,  | 
343  |  |         hb_codepoint_t  glyph,  | 
344  |  |         unsigned int    start_offset,  | 
345  |  |         unsigned int   *point_count /* IN/OUT */,  | 
346  |  |         unsigned int   *point_array /* OUT */)  | 
347  | 0  | { | 
348  | 0  |   return face->table.GDEF->table->get_attach_points (glyph,  | 
349  | 0  |                  start_offset,  | 
350  | 0  |                  point_count,  | 
351  | 0  |                  point_array);  | 
352  | 0  | }  | 
353  |  | /**  | 
354  |  |  * hb_ot_layout_get_ligature_carets:  | 
355  |  |  * @font: The #hb_font_t to work on  | 
356  |  |  * @direction: The #hb_direction_t text direction to use  | 
357  |  |  * @glyph: The #hb_codepoint_t code point to query  | 
358  |  |  * @start_offset: offset of the first caret position to retrieve  | 
359  |  |  * @caret_count: (inout) (optional): Input = the maximum number of caret positions to return;  | 
360  |  |  *               Output = the actual number of caret positions returned (may be zero)  | 
361  |  |  * @caret_array: (out) (array length=caret_count): The array of caret positions found for the query  | 
362  |  |  *  | 
363  |  |  * Fetches a list of the caret positions defined for a ligature glyph in the GDEF  | 
364  |  |  * table of the font. The list returned will begin at the offset provided.  | 
365  |  |  *  | 
366  |  |  * Note that a ligature that is formed from n characters will have n-1  | 
367  |  |  * caret positions. The first character is not represented in the array,  | 
368  |  |  * since its caret position is the glyph position.  | 
369  |  |  *  | 
370  |  |  * The positions returned by this function are 'unshaped', and will have to  | 
371  |  |  * be fixed up for kerning that may be applied to the ligature glyph.  | 
372  |  |  *  | 
373  |  |  * Return value: Total number of ligature caret positions for @glyph.  | 
374  |  |  *  | 
375  |  |  **/  | 
376  |  | unsigned int  | 
377  |  | hb_ot_layout_get_ligature_carets (hb_font_t      *font,  | 
378  |  |           hb_direction_t  direction,  | 
379  |  |           hb_codepoint_t  glyph,  | 
380  |  |           unsigned int    start_offset,  | 
381  |  |           unsigned int   *caret_count /* IN/OUT */,  | 
382  |  |           hb_position_t  *caret_array /* OUT */)  | 
383  | 94.9k  | { | 
384  | 94.9k  |   return font->face->table.GDEF->table->get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);  | 
385  | 94.9k  | }  | 
386  |  | #endif  | 
387  |  |  | 
388  |  |  | 
389  |  | /*  | 
390  |  |  * GSUB/GPOS  | 
391  |  |  */  | 
392  |  |  | 
393  |  | bool  | 
394  |  | GSUB::is_blocklisted (hb_blob_t *blob HB_UNUSED,  | 
395  |  |         hb_face_t *face) const  | 
396  | 92.7k  | { | 
397  |  | #ifdef HB_NO_OT_LAYOUT_BLOCKLIST  | 
398  |  |   return false;  | 
399  |  | #endif  | 
400  | 92.7k  |   return false;  | 
401  | 92.7k  | }  | 
402  |  |  | 
403  |  | bool  | 
404  |  | GPOS::is_blocklisted (hb_blob_t *blob HB_UNUSED,  | 
405  |  |         hb_face_t *face HB_UNUSED) const  | 
406  | 92.9k  | { | 
407  |  | #ifdef HB_NO_OT_LAYOUT_BLOCKLIST  | 
408  |  |   return false;  | 
409  |  | #endif  | 
410  | 92.9k  |   return false;  | 
411  | 92.9k  | }  | 
412  |  |  | 
413  |  | static const OT::GSUBGPOS&  | 
414  |  | get_gsubgpos_table (hb_face_t *face,  | 
415  |  |         hb_tag_t   table_tag)  | 
416  | 12.1M  | { | 
417  | 12.1M  |   switch (table_tag) { | 
418  | 6.29M  |     case HB_OT_TAG_GSUB: return *face->table.GSUB->table;  | 
419  | 5.90M  |     case HB_OT_TAG_GPOS: return *face->table.GPOS->table;  | 
420  | 0  |     default:             return Null (OT::GSUBGPOS);  | 
421  | 12.1M  |   }  | 
422  | 12.1M  | }  | 
423  |  |  | 
424  |  |  | 
425  |  | /**  | 
426  |  |  * hb_ot_layout_table_get_script_tags:  | 
427  |  |  * @face: #hb_face_t to work upon  | 
428  |  |  * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS  | 
429  |  |  * @start_offset: offset of the first script tag to retrieve  | 
430  |  |  * @script_count: (inout) (optional): Input = the maximum number of script tags to return;  | 
431  |  |  *                Output = the actual number of script tags returned (may be zero)  | 
432  |  |  * @script_tags: (out) (array length=script_count): The array of #hb_tag_t script tags found for the query  | 
433  |  |  *  | 
434  |  |  * Fetches a list of all scripts enumerated in the specified face's GSUB table  | 
435  |  |  * or GPOS table. The list returned will begin at the offset provided.  | 
436  |  |  *  | 
437  |  |  * Return value: Total number of script tags.  | 
438  |  |  *  | 
439  |  |  **/  | 
440  |  | unsigned int  | 
441  |  | hb_ot_layout_table_get_script_tags (hb_face_t    *face,  | 
442  |  |             hb_tag_t      table_tag,  | 
443  |  |             unsigned int  start_offset,  | 
444  |  |             unsigned int *script_count /* IN/OUT */,  | 
445  |  |             hb_tag_t     *script_tags  /* OUT */)  | 
446  | 0  | { | 
447  | 0  |   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);  | 
448  |  | 
  | 
449  | 0  |   return g.get_script_tags (start_offset, script_count, script_tags);  | 
450  | 0  | }  | 
451  |  |  | 
452  | 229k  | #define HB_OT_TAG_LATIN_SCRIPT    HB_TAG ('l', 'a', 't', 'n') | 
453  |  |  | 
454  |  | /**  | 
455  |  |  * hb_ot_layout_table_find_script:  | 
456  |  |  * @face: #hb_face_t to work upon  | 
457  |  |  * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS  | 
458  |  |  * @script_tag: #hb_tag_t of the script tag requested  | 
459  |  |  * @script_index: (out): The index of the requested script tag  | 
460  |  |  *  | 
461  |  |  * Fetches the index if a given script tag in the specified face's GSUB table  | 
462  |  |  * or GPOS table.  | 
463  |  |  *  | 
464  |  |  * Return value: `true` if the script is found, `false` otherwise  | 
465  |  |  *  | 
466  |  |  **/  | 
467  |  | hb_bool_t  | 
468  |  | hb_ot_layout_table_find_script (hb_face_t    *face,  | 
469  |  |         hb_tag_t      table_tag,  | 
470  |  |         hb_tag_t      script_tag,  | 
471  |  |         unsigned int *script_index /* OUT */)  | 
472  | 0  | { | 
473  | 0  |   static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX), "");  | 
474  | 0  |   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);  | 
475  |  | 
  | 
476  | 0  |   if (g.find_script_index (script_tag, script_index))  | 
477  | 0  |     return true;  | 
478  |  |  | 
479  |  |   /* try finding 'DFLT' */  | 
480  | 0  |   if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index))  | 
481  | 0  |     return false;  | 
482  |  |  | 
483  |  |   /* try with 'dflt'; MS site has had typos and many fonts use it now :(.  | 
484  |  |    * including many versions of DejaVu Sans Mono! */  | 
485  | 0  |   if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index))  | 
486  | 0  |     return false;  | 
487  |  |  | 
488  |  |   /* try with 'latn'; some old fonts put their features there even though  | 
489  |  |      they're really trying to support Thai, for example :( */  | 
490  | 0  |   if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index))  | 
491  | 0  |     return false;  | 
492  |  |  | 
493  | 0  |   if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;  | 
494  | 0  |   return false;  | 
495  | 0  | }  | 
496  |  |  | 
497  |  | #ifndef HB_DISABLE_DEPRECATED  | 
498  |  | /**  | 
499  |  |  * hb_ot_layout_table_choose_script:  | 
500  |  |  * @face: #hb_face_t to work upon  | 
501  |  |  * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS  | 
502  |  |  * @script_tags: Array of #hb_tag_t script tags  | 
503  |  |  * @script_index: (out): The index of the chosen script  | 
504  |  |  * @chosen_script: (out): #hb_tag_t of the chosen script  | 
505  |  |  *  | 
506  |  |  * Deprecated since 2.0.0  | 
507  |  |  **/  | 
508  |  | hb_bool_t  | 
509  |  | hb_ot_layout_table_choose_script (hb_face_t      *face,  | 
510  |  |           hb_tag_t        table_tag,  | 
511  |  |           const hb_tag_t *script_tags,  | 
512  |  |           unsigned int   *script_index  /* OUT */,  | 
513  |  |           hb_tag_t       *chosen_script /* OUT */)  | 
514  | 0  | { | 
515  | 0  |   const hb_tag_t *t;  | 
516  | 0  |   for (t = script_tags; *t; t++);  | 
517  | 0  |   return hb_ot_layout_table_select_script (face, table_tag, t - script_tags, script_tags, script_index, chosen_script);  | 
518  | 0  | }  | 
519  |  | #endif  | 
520  |  |  | 
521  |  | /**  | 
522  |  |  * hb_ot_layout_table_select_script:  | 
523  |  |  * @face: #hb_face_t to work upon  | 
524  |  |  * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS  | 
525  |  |  * @script_count: Number of script tags in the array  | 
526  |  |  * @script_tags: Array of #hb_tag_t script tags  | 
527  |  |  * @script_index: (out) (optional): The index of the requested script  | 
528  |  |  * @chosen_script: (out) (optional): #hb_tag_t of the requested script  | 
529  |  |  *  | 
530  |  |  * Selects an OpenType script for @table_tag from the @script_tags array.  | 
531  |  |  *  | 
532  |  |  * If the table does not have any of the requested scripts, then `DFLT`,  | 
533  |  |  * `dflt`, and `latn` tags are tried in that order. If the table still does not  | 
534  |  |  * have any of these scripts, @script_index is set to  | 
535  |  |  * #HB_OT_LAYOUT_NO_SCRIPT_INDEX and @chosen_script is set to #HB_TAG_NONE.  | 
536  |  |  *  | 
537  |  |  * Return value:  | 
538  |  |  * `true` if one of the requested scripts is selected, `false` if a fallback  | 
539  |  |  * script is selected or if no scripts are selected.  | 
540  |  |  *  | 
541  |  |  * Since: 2.0.0  | 
542  |  |  **/  | 
543  |  | hb_bool_t  | 
544  |  | hb_ot_layout_table_select_script (hb_face_t      *face,  | 
545  |  |           hb_tag_t        table_tag,  | 
546  |  |           unsigned int    script_count,  | 
547  |  |           const hb_tag_t *script_tags,  | 
548  |  |           unsigned int   *script_index  /* OUT */,  | 
549  |  |           hb_tag_t       *chosen_script /* OUT */)  | 
550  | 247k  | { | 
551  | 247k  |   static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX), "");  | 
552  | 247k  |   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);  | 
553  | 247k  |   unsigned int i;  | 
554  |  |  | 
555  | 493k  |   for (i = 0; i < script_count; i++)  | 
556  | 265k  |   { | 
557  | 265k  |     if (g.find_script_index (script_tags[i], script_index))  | 
558  | 19.0k  |     { | 
559  | 19.0k  |       if (chosen_script)  | 
560  | 19.0k  |   *chosen_script = script_tags[i];  | 
561  | 19.0k  |       return true;  | 
562  | 19.0k  |     }  | 
563  | 265k  |   }  | 
564  |  |  | 
565  |  |   /* try finding 'DFLT' */  | 
566  | 228k  |   if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) { | 
567  | 5.28k  |     if (chosen_script)  | 
568  | 5.28k  |       *chosen_script = HB_OT_TAG_DEFAULT_SCRIPT;  | 
569  | 5.28k  |     return false;  | 
570  | 5.28k  |   }  | 
571  |  |  | 
572  |  |   /* try with 'dflt'; MS site has had typos and many fonts use it now :( */  | 
573  | 223k  |   if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) { | 
574  | 119  |     if (chosen_script)  | 
575  | 119  |       *chosen_script = HB_OT_TAG_DEFAULT_LANGUAGE;  | 
576  | 119  |     return false;  | 
577  | 119  |   }  | 
578  |  |  | 
579  |  |   /* try with 'latn'; some old fonts put their features there even though  | 
580  |  |      they're really trying to support Thai, for example :( */  | 
581  | 223k  |   if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index)) { | 
582  | 6.14k  |     if (chosen_script)  | 
583  | 6.14k  |       *chosen_script = HB_OT_TAG_LATIN_SCRIPT;  | 
584  | 6.14k  |     return false;  | 
585  | 6.14k  |   }  | 
586  |  |  | 
587  | 217k  |   if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;  | 
588  | 217k  |   if (chosen_script)  | 
589  | 217k  |     *chosen_script = HB_TAG_NONE;  | 
590  | 217k  |   return false;  | 
591  | 223k  | }  | 
592  |  |  | 
593  |  |  | 
594  |  | /**  | 
595  |  |  * hb_ot_layout_table_get_feature_tags:  | 
596  |  |  * @face: #hb_face_t to work upon  | 
597  |  |  * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS  | 
598  |  |  * @start_offset: offset of the first feature tag to retrieve  | 
599  |  |  * @feature_count: (inout) (optional): Input = the maximum number of feature tags to return;  | 
600  |  |  *                 Output = the actual number of feature tags returned (may be zero)  | 
601  |  |  * @feature_tags: (out) (array length=feature_count): Array of feature tags found in the table  | 
602  |  |  *  | 
603  |  |  * Fetches a list of all feature tags in the given face's GSUB or GPOS table.  | 
604  |  |  * Note that there might be duplicate feature tags, belonging to different  | 
605  |  |  * script/language-system pairs of the table.  | 
606  |  |  *  | 
607  |  |  * Return value: Total number of feature tags.  | 
608  |  |  *  | 
609  |  |  * Since: 0.6.0  | 
610  |  |  *  | 
611  |  |  **/  | 
612  |  | unsigned int  | 
613  |  | hb_ot_layout_table_get_feature_tags (hb_face_t    *face,  | 
614  |  |              hb_tag_t      table_tag,  | 
615  |  |              unsigned int  start_offset,  | 
616  |  |              unsigned int *feature_count /* IN/OUT */,  | 
617  |  |              hb_tag_t     *feature_tags  /* OUT */)  | 
618  | 0  | { | 
619  | 0  |   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);  | 
620  |  | 
  | 
621  | 0  |   return g.get_feature_tags (start_offset, feature_count, feature_tags);  | 
622  | 0  | }  | 
623  |  |  | 
624  |  |  | 
625  |  | /**  | 
626  |  |  * hb_ot_layout_table_find_feature:  | 
627  |  |  * @face: #hb_face_t to work upon  | 
628  |  |  * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS  | 
629  |  |  * @feature_tag: The #hb_tag_t of the requested feature tag  | 
630  |  |  * @feature_index: (out): The index of the requested feature  | 
631  |  |  *  | 
632  |  |  * Fetches the index for a given feature tag in the specified face's GSUB table  | 
633  |  |  * or GPOS table.  | 
634  |  |  *  | 
635  |  |  * Return value: `true` if the feature is found, `false` otherwise  | 
636  |  |  *  | 
637  |  |  * Since: 0.6.0  | 
638  |  |  *  | 
639  |  |  **/  | 
640  |  | bool  | 
641  |  | hb_ot_layout_table_find_feature (hb_face_t    *face,  | 
642  |  |          hb_tag_t      table_tag,  | 
643  |  |          hb_tag_t      feature_tag,  | 
644  |  |          unsigned int *feature_index /* OUT */)  | 
645  | 0  | { | 
646  | 0  |   static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX), "");  | 
647  | 0  |   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);  | 
648  |  | 
  | 
649  | 0  |   unsigned int num_features = g.get_feature_count ();  | 
650  | 0  |   for (unsigned int i = 0; i < num_features; i++)  | 
651  | 0  |   { | 
652  | 0  |     if (feature_tag == g.get_feature_tag (i)) { | 
653  | 0  |       if (feature_index) *feature_index = i;  | 
654  | 0  |       return true;  | 
655  | 0  |     }  | 
656  | 0  |   }  | 
657  |  |  | 
658  | 0  |   if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;  | 
659  | 0  |   return false;  | 
660  | 0  | }  | 
661  |  |  | 
662  |  |  | 
663  |  | /**  | 
664  |  |  * hb_ot_layout_script_get_language_tags:  | 
665  |  |  * @face: #hb_face_t to work upon  | 
666  |  |  * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS  | 
667  |  |  * @script_index: The index of the requested script tag  | 
668  |  |  * @start_offset: offset of the first language tag to retrieve  | 
669  |  |  * @language_count: (inout) (optional): Input = the maximum number of language tags to return;  | 
670  |  |  *                  Output = the actual number of language tags returned (may be zero)  | 
671  |  |  * @language_tags: (out) (array length=language_count): Array of language tags found in the table  | 
672  |  |  *  | 
673  |  |  * Fetches a list of language tags in the given face's GSUB or GPOS table, underneath  | 
674  |  |  * the specified script index. The list returned will begin at the offset provided.  | 
675  |  |  *  | 
676  |  |  * Return value: Total number of language tags.  | 
677  |  |  *  | 
678  |  |  * Since: 0.6.0  | 
679  |  |  *  | 
680  |  |  **/  | 
681  |  | unsigned int  | 
682  |  | hb_ot_layout_script_get_language_tags (hb_face_t    *face,  | 
683  |  |                hb_tag_t      table_tag,  | 
684  |  |                unsigned int  script_index,  | 
685  |  |                unsigned int  start_offset,  | 
686  |  |                unsigned int *language_count /* IN/OUT */,  | 
687  |  |                hb_tag_t     *language_tags  /* OUT */)  | 
688  | 0  | { | 
689  | 0  |   const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);  | 
690  |  | 
  | 
691  | 0  |   return s.get_lang_sys_tags (start_offset, language_count, language_tags);  | 
692  | 0  | }  | 
693  |  |  | 
694  |  |  | 
695  |  | #ifndef HB_DISABLE_DEPRECATED  | 
696  |  | /**  | 
697  |  |  * hb_ot_layout_script_find_language:  | 
698  |  |  * @face: #hb_face_t to work upon  | 
699  |  |  * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS  | 
700  |  |  * @script_index: The index of the requested script tag  | 
701  |  |  * @language_tag: The #hb_tag_t of the requested language  | 
702  |  |  * @language_index: The index of the requested language  | 
703  |  |  *  | 
704  |  |  * Fetches the index of a given language tag in the specified face's GSUB table  | 
705  |  |  * or GPOS table, underneath the specified script tag.  | 
706  |  |  *  | 
707  |  |  * Return value: `true` if the language tag is found, `false` otherwise  | 
708  |  |  *  | 
709  |  |  * Since: 0.6.0  | 
710  |  |  * Deprecated: 2.0.0  | 
711  |  |  **/  | 
712  |  | hb_bool_t  | 
713  |  | hb_ot_layout_script_find_language (hb_face_t    *face,  | 
714  |  |            hb_tag_t      table_tag,  | 
715  |  |            unsigned int  script_index,  | 
716  |  |            hb_tag_t      language_tag,  | 
717  |  |            unsigned int *language_index)  | 
718  | 0  | { | 
719  | 0  |   return hb_ot_layout_script_select_language (face,  | 
720  | 0  |                 table_tag,  | 
721  | 0  |                 script_index,  | 
722  | 0  |                 1,  | 
723  | 0  |                 &language_tag,  | 
724  | 0  |                 language_index);  | 
725  | 0  | }  | 
726  |  | #endif  | 
727  |  |  | 
728  |  |  | 
729  |  | /**  | 
730  |  |  * hb_ot_layout_script_select_language2:  | 
731  |  |  * @face: #hb_face_t to work upon  | 
732  |  |  * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS  | 
733  |  |  * @script_index: The index of the requested script tag  | 
734  |  |  * @language_count: The number of languages in the specified script  | 
735  |  |  * @language_tags: The array of language tags  | 
736  |  |  * @language_index: (out): The index of the chosen language  | 
737  |  |  * @chosen_language: (out): #hb_tag_t of the chosen language  | 
738  |  |  *  | 
739  |  |  * Fetches the index of the first language tag fom @language_tags that is present  | 
740  |  |  * in the specified face's GSUB or GPOS table, underneath the specified script  | 
741  |  |  * index.  | 
742  |  |  *  | 
743  |  |  * If none of the given language tags is found, `false` is returned and  | 
744  |  |  * @language_index is set to #HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX and  | 
745  |  |  * @chosen_language is set to #HB_TAG_NONE.  | 
746  |  |  *  | 
747  |  |  * Return value: `true` if one of the given language tags is found, `false` otherwise  | 
748  |  |  *  | 
749  |  |  * Since: REPLACEME  | 
750  |  |  **/  | 
751  |  | hb_bool_t  | 
752  |  | hb_ot_layout_script_select_language2 (hb_face_t      *face,  | 
753  |  |              hb_tag_t        table_tag,  | 
754  |  |              unsigned int    script_index,  | 
755  |  |              unsigned int    language_count,  | 
756  |  |              const hb_tag_t *language_tags,  | 
757  |  |              unsigned int   *language_index /* OUT */,  | 
758  |  |              hb_tag_t       *chosen_language /* OUT */)  | 
759  | 247k  | { | 
760  | 247k  |   static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX), "");  | 
761  | 247k  |   const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);  | 
762  | 247k  |   unsigned int i;  | 
763  |  |  | 
764  | 247k  |   for (i = 0; i < language_count; i++)  | 
765  | 0  |   { | 
766  | 0  |     if (s.find_lang_sys_index (language_tags[i], language_index))  | 
767  | 0  |     { | 
768  | 0  |       if (chosen_language)  | 
769  | 0  |         *chosen_language = language_tags[i];  | 
770  | 0  |       return true;  | 
771  | 0  |     }  | 
772  | 0  |   }  | 
773  |  |  | 
774  |  |   /* try finding 'dflt' */  | 
775  | 247k  |   if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index))  | 
776  | 26  |   { | 
777  | 26  |     if (chosen_language)  | 
778  | 0  |       *chosen_language = HB_OT_TAG_DEFAULT_LANGUAGE;  | 
779  | 26  |     return false;  | 
780  | 26  |   }  | 
781  |  |  | 
782  | 247k  |   if (language_index)  | 
783  | 247k  |     *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;  | 
784  | 247k  |   if (chosen_language)  | 
785  | 0  |     *chosen_language = HB_TAG_NONE;  | 
786  | 247k  |   return false;  | 
787  | 247k  | }  | 
788  |  |  | 
789  |  | /**  | 
790  |  |  * hb_ot_layout_script_select_language:  | 
791  |  |  * @face: #hb_face_t to work upon  | 
792  |  |  * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS  | 
793  |  |  * @script_index: The index of the requested script tag  | 
794  |  |  * @language_count: The number of languages in the specified script  | 
795  |  |  * @language_tags: The array of language tags  | 
796  |  |  * @language_index: (out): The index of the requested language  | 
797  |  |  *  | 
798  |  |  * Fetches the index of the first language tag fom @language_tags that is present  | 
799  |  |  * in the specified face's GSUB or GPOS table, underneath the specified script  | 
800  |  |  * index.  | 
801  |  |  *  | 
802  |  |  * If none of the given language tags is found, `false` is returned and  | 
803  |  |  * @language_index is set to the default language index.  | 
804  |  |  *  | 
805  |  |  * Return value: `true` if one of the given language tags is found, `false` otherwise  | 
806  |  |  *  | 
807  |  |  * Since: 2.0.0  | 
808  |  |  **/  | 
809  |  | hb_bool_t  | 
810  |  | hb_ot_layout_script_select_language (hb_face_t      *face,  | 
811  |  |              hb_tag_t        table_tag,  | 
812  |  |              unsigned int    script_index,  | 
813  |  |              unsigned int    language_count,  | 
814  |  |              const hb_tag_t *language_tags,  | 
815  |  |              unsigned int   *language_index /* OUT */)  | 
816  | 247k  | { | 
817  | 247k  |   return hb_ot_layout_script_select_language2 (face, table_tag,  | 
818  | 247k  |                  script_index,  | 
819  | 247k  |                  language_count, language_tags,  | 
820  | 247k  |                  language_index, nullptr);  | 
821  | 247k  | }  | 
822  |  |  | 
823  |  | /**  | 
824  |  |  * hb_ot_layout_language_get_required_feature_index:  | 
825  |  |  * @face: #hb_face_t to work upon  | 
826  |  |  * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS  | 
827  |  |  * @script_index: The index of the requested script tag  | 
828  |  |  * @language_index: The index of the requested language tag  | 
829  |  |  * @feature_index: (out): The index of the requested feature  | 
830  |  |  *  | 
831  |  |  * Fetches the index of a requested feature in the given face's GSUB or GPOS table,  | 
832  |  |  * underneath the specified script and language.  | 
833  |  |  *  | 
834  |  |  * Return value: `true` if the feature is found, `false` otherwise  | 
835  |  |  *  | 
836  |  |  * Since: 0.6.0  | 
837  |  |  *  | 
838  |  |  **/  | 
839  |  | hb_bool_t  | 
840  |  | hb_ot_layout_language_get_required_feature_index (hb_face_t    *face,  | 
841  |  |               hb_tag_t      table_tag,  | 
842  |  |               unsigned int  script_index,  | 
843  |  |               unsigned int  language_index,  | 
844  |  |               unsigned int *feature_index /* OUT */)  | 
845  | 0  | { | 
846  | 0  |   return hb_ot_layout_language_get_required_feature (face,  | 
847  | 0  |                  table_tag,  | 
848  | 0  |                  script_index,  | 
849  | 0  |                  language_index,  | 
850  | 0  |                  feature_index,  | 
851  | 0  |                  nullptr);  | 
852  | 0  | }  | 
853  |  |  | 
854  |  |  | 
855  |  | /**  | 
856  |  |  * hb_ot_layout_language_get_required_feature:  | 
857  |  |  * @face: #hb_face_t to work upon  | 
858  |  |  * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS  | 
859  |  |  * @script_index: The index of the requested script tag  | 
860  |  |  * @language_index: The index of the requested language tag  | 
861  |  |  * @feature_index: (out): The index of the requested feature  | 
862  |  |  * @feature_tag: (out): The #hb_tag_t of the requested feature  | 
863  |  |  *  | 
864  |  |  * Fetches the tag of a requested feature index in the given face's GSUB or GPOS table,  | 
865  |  |  * underneath the specified script and language.  | 
866  |  |  *  | 
867  |  |  * Return value: `true` if the feature is found, `false` otherwise  | 
868  |  |  *  | 
869  |  |  * Since: 0.9.30  | 
870  |  |  **/  | 
871  |  | hb_bool_t  | 
872  |  | hb_ot_layout_language_get_required_feature (hb_face_t    *face,  | 
873  |  |               hb_tag_t      table_tag,  | 
874  |  |               unsigned int  script_index,  | 
875  |  |               unsigned int  language_index,  | 
876  |  |               unsigned int *feature_index /* OUT */,  | 
877  |  |               hb_tag_t     *feature_tag   /* OUT */)  | 
878  | 247k  | { | 
879  | 247k  |   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);  | 
880  | 247k  |   const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);  | 
881  |  |  | 
882  | 247k  |   unsigned int index = l.get_required_feature_index ();  | 
883  | 247k  |   if (feature_index) *feature_index = index;  | 
884  | 247k  |   if (feature_tag) *feature_tag = g.get_feature_tag (index);  | 
885  |  |  | 
886  | 247k  |   return l.has_required_feature ();  | 
887  | 247k  | }  | 
888  |  |  | 
889  |  |  | 
890  |  | /**  | 
891  |  |  * hb_ot_layout_language_get_feature_indexes:  | 
892  |  |  * @face: #hb_face_t to work upon  | 
893  |  |  * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS  | 
894  |  |  * @script_index: The index of the requested script tag  | 
895  |  |  * @language_index: The index of the requested language tag  | 
896  |  |  * @start_offset: offset of the first feature tag to retrieve  | 
897  |  |  * @feature_count: (inout) (optional): Input = the maximum number of feature tags to return;  | 
898  |  |  *                 Output: the actual number of feature tags returned (may be zero)  | 
899  |  |  * @feature_indexes: (out) (array length=feature_count): The array of feature indexes found for the query  | 
900  |  |  *  | 
901  |  |  * Fetches a list of all features in the specified face's GSUB table  | 
902  |  |  * or GPOS table, underneath the specified script and language. The list  | 
903  |  |  * returned will begin at the offset provided.  | 
904  |  |  *  | 
905  |  |  * Return value: Total number of features.  | 
906  |  |  *  | 
907  |  |  * Since: 0.6.0  | 
908  |  |  *  | 
909  |  |  **/  | 
910  |  | unsigned int  | 
911  |  | hb_ot_layout_language_get_feature_indexes (hb_face_t    *face,  | 
912  |  |              hb_tag_t      table_tag,  | 
913  |  |              unsigned int  script_index,  | 
914  |  |              unsigned int  language_index,  | 
915  |  |              unsigned int  start_offset,  | 
916  |  |              unsigned int *feature_count   /* IN/OUT */,  | 
917  |  |              unsigned int *feature_indexes /* OUT */)  | 
918  | 94.9k  | { | 
919  | 94.9k  |   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);  | 
920  | 94.9k  |   const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);  | 
921  |  |  | 
922  | 94.9k  |   return l.get_feature_indexes (start_offset, feature_count, feature_indexes);  | 
923  | 94.9k  | }  | 
924  |  |  | 
925  |  |  | 
926  |  | /**  | 
927  |  |  * hb_ot_layout_language_get_feature_tags:  | 
928  |  |  * @face: #hb_face_t to work upon  | 
929  |  |  * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS  | 
930  |  |  * @script_index: The index of the requested script tag  | 
931  |  |  * @language_index: The index of the requested language tag  | 
932  |  |  * @start_offset: offset of the first feature tag to retrieve  | 
933  |  |  * @feature_count: (inout) (optional): Input = the maximum number of feature tags to return;  | 
934  |  |  *                 Output = the actual number of feature tags returned (may be zero)  | 
935  |  |  * @feature_tags: (out) (array length=feature_count): The array of #hb_tag_t feature tags found for the query  | 
936  |  |  *  | 
937  |  |  * Fetches a list of all features in the specified face's GSUB table  | 
938  |  |  * or GPOS table, underneath the specified script and language. The list  | 
939  |  |  * returned will begin at the offset provided.  | 
940  |  |  *  | 
941  |  |  * Return value: Total number of feature tags.  | 
942  |  |  *  | 
943  |  |  * Since: 0.6.0  | 
944  |  |  *  | 
945  |  |  **/  | 
946  |  | unsigned int  | 
947  |  | hb_ot_layout_language_get_feature_tags (hb_face_t    *face,  | 
948  |  |           hb_tag_t      table_tag,  | 
949  |  |           unsigned int  script_index,  | 
950  |  |           unsigned int  language_index,  | 
951  |  |           unsigned int  start_offset,  | 
952  |  |           unsigned int *feature_count /* IN/OUT */,  | 
953  |  |           hb_tag_t     *feature_tags  /* OUT */)  | 
954  | 0  | { | 
955  | 0  |   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);  | 
956  | 0  |   const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);  | 
957  |  | 
  | 
958  | 0  |   static_assert ((sizeof (unsigned int) == sizeof (hb_tag_t)), "");  | 
959  | 0  |   unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags);  | 
960  |  | 
  | 
961  | 0  |   if (feature_tags) { | 
962  | 0  |     unsigned int count = *feature_count;  | 
963  | 0  |     for (unsigned int i = 0; i < count; i++)  | 
964  | 0  |       feature_tags[i] = g.get_feature_tag ((unsigned int) feature_tags[i]);  | 
965  | 0  |   }  | 
966  |  | 
  | 
967  | 0  |   return ret;  | 
968  | 0  | }  | 
969  |  |  | 
970  |  |  | 
971  |  | /**  | 
972  |  |  * hb_ot_layout_language_find_feature:  | 
973  |  |  * @face: #hb_face_t to work upon  | 
974  |  |  * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS  | 
975  |  |  * @script_index: The index of the requested script tag  | 
976  |  |  * @language_index: The index of the requested language tag  | 
977  |  |  * @feature_tag: #hb_tag_t of the feature tag requested  | 
978  |  |  * @feature_index: (out): The index of the requested feature  | 
979  |  |  *  | 
980  |  |  * Fetches the index of a given feature tag in the specified face's GSUB table  | 
981  |  |  * or GPOS table, underneath the specified script and language.  | 
982  |  |  *  | 
983  |  |  * Return value: `true` if the feature is found, `false` otherwise  | 
984  |  |  *  | 
985  |  |  * Since: 0.6.0  | 
986  |  |  *  | 
987  |  |  **/  | 
988  |  | hb_bool_t  | 
989  |  | hb_ot_layout_language_find_feature (hb_face_t    *face,  | 
990  |  |             hb_tag_t      table_tag,  | 
991  |  |             unsigned int  script_index,  | 
992  |  |             unsigned int  language_index,  | 
993  |  |             hb_tag_t      feature_tag,  | 
994  |  |             unsigned int *feature_index /* OUT */)  | 
995  | 6.68M  | { | 
996  | 6.68M  |   static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX), "");  | 
997  | 6.68M  |   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);  | 
998  | 6.68M  |   const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);  | 
999  |  |  | 
1000  | 6.68M  |   unsigned int num_features = l.get_feature_count ();  | 
1001  | 18.8M  |   for (unsigned int i = 0; i < num_features; i++) { | 
1002  | 12.2M  |     unsigned int f_index = l.get_feature_index (i);  | 
1003  |  |  | 
1004  | 12.2M  |     if (feature_tag == g.get_feature_tag (f_index)) { | 
1005  | 30.7k  |       if (feature_index) *feature_index = f_index;  | 
1006  | 30.7k  |       return true;  | 
1007  | 30.7k  |     }  | 
1008  | 12.2M  |   }  | 
1009  |  |  | 
1010  | 6.65M  |   if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;  | 
1011  | 6.65M  |   return false;  | 
1012  | 6.68M  | }  | 
1013  |  |  | 
1014  |  |  | 
1015  |  | /**  | 
1016  |  |  * hb_ot_layout_feature_get_lookups:  | 
1017  |  |  * @face: #hb_face_t to work upon  | 
1018  |  |  * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS  | 
1019  |  |  * @feature_index: The index of the requested feature  | 
1020  |  |  * @start_offset: offset of the first lookup to retrieve  | 
1021  |  |  * @lookup_count: (inout) (optional): Input = the maximum number of lookups to return;  | 
1022  |  |  *                Output = the actual number of lookups returned (may be zero)  | 
1023  |  |  * @lookup_indexes: (out) (array length=lookup_count): The array of lookup indexes found for the query  | 
1024  |  |  *  | 
1025  |  |  * Fetches a list of all lookups enumerated for the specified feature, in  | 
1026  |  |  * the specified face's GSUB table or GPOS table. The list returned will  | 
1027  |  |  * begin at the offset provided.  | 
1028  |  |  *  | 
1029  |  |  * Return value: Total number of lookups.  | 
1030  |  |  *  | 
1031  |  |  * Since: 0.9.7  | 
1032  |  |  **/  | 
1033  |  | unsigned int  | 
1034  |  | hb_ot_layout_feature_get_lookups (hb_face_t    *face,  | 
1035  |  |           hb_tag_t      table_tag,  | 
1036  |  |           unsigned int  feature_index,  | 
1037  |  |           unsigned int  start_offset,  | 
1038  |  |           unsigned int *lookup_count   /* IN/OUT */,  | 
1039  |  |           unsigned int *lookup_indexes /* OUT */)  | 
1040  | 0  | { | 
1041  | 0  |   return hb_ot_layout_feature_with_variations_get_lookups (face,  | 
1042  | 0  |                  table_tag,  | 
1043  | 0  |                  feature_index,  | 
1044  | 0  |                  HB_OT_LAYOUT_NO_VARIATIONS_INDEX,  | 
1045  | 0  |                  start_offset,  | 
1046  | 0  |                  lookup_count,  | 
1047  | 0  |                  lookup_indexes);  | 
1048  | 0  | }  | 
1049  |  |  | 
1050  |  |  | 
1051  |  | /**  | 
1052  |  |  * hb_ot_layout_table_get_lookup_count:  | 
1053  |  |  * @face: #hb_face_t to work upon  | 
1054  |  |  * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS  | 
1055  |  |  *  | 
1056  |  |  * Fetches the total number of lookups enumerated in the specified  | 
1057  |  |  * face's GSUB table or GPOS table.  | 
1058  |  |  *  | 
1059  |  |  * Return value: Total number of lookups.  | 
1060  |  |  *  | 
1061  |  |  * Since: 0.9.22  | 
1062  |  |  **/  | 
1063  |  | unsigned int  | 
1064  |  | hb_ot_layout_table_get_lookup_count (hb_face_t    *face,  | 
1065  |  |              hb_tag_t      table_tag)  | 
1066  | 544k  | { | 
1067  | 544k  |   return get_gsubgpos_table (face, table_tag).get_lookup_count ();  | 
1068  | 544k  | }  | 
1069  |  |  | 
1070  |  |  | 
1071  |  | struct hb_collect_features_context_t  | 
1072  |  | { | 
1073  |  |   hb_collect_features_context_t (hb_face_t *face,  | 
1074  |  |          hb_tag_t   table_tag,  | 
1075  |  |          hb_set_t  *feature_indices_,  | 
1076  |  |          const hb_tag_t *features)  | 
1077  |  |  | 
1078  |  |     : g (get_gsubgpos_table (face, table_tag)),  | 
1079  |  |       feature_indices (feature_indices_),  | 
1080  |  |       has_feature_filter (false),  | 
1081  |  |       script_count (0),langsys_count (0), feature_index_count (0)  | 
1082  | 0  |   { | 
1083  | 0  |     compute_feature_filter (features);  | 
1084  | 0  |   }  | 
1085  |  |  | 
1086  |  |   void compute_feature_filter (const hb_tag_t *features)  | 
1087  | 0  |   { | 
1088  | 0  |     if (features == nullptr)  | 
1089  | 0  |     { | 
1090  | 0  |       has_feature_filter = false;  | 
1091  | 0  |       return;  | 
1092  | 0  |     }  | 
1093  |  |  | 
1094  | 0  |     has_feature_filter = true;  | 
1095  | 0  |     hb_set_t features_set;  | 
1096  | 0  |     for (; *features; features++)  | 
1097  | 0  |       features_set.add (*features);  | 
1098  |  | 
  | 
1099  | 0  |     for (unsigned i = 0; i < g.get_feature_count (); i++)  | 
1100  | 0  |     { | 
1101  | 0  |       hb_tag_t tag = g.get_feature_tag (i);  | 
1102  | 0  |       if (features_set.has (tag))  | 
1103  | 0  |   feature_indices_filter.add(i);  | 
1104  | 0  |     }  | 
1105  | 0  |   }  | 
1106  |  |  | 
1107  |  |   bool visited (const OT::Script &s)  | 
1108  | 0  |   { | 
1109  |  |     /* We might have Null() object here.  Don't want to involve  | 
1110  |  |      * that in the memoize.  So, detect empty objects and return. */  | 
1111  | 0  |     if (unlikely (!s.has_default_lang_sys () &&  | 
1112  | 0  |       !s.get_lang_sys_count ()))  | 
1113  | 0  |       return true;  | 
1114  |  |  | 
1115  | 0  |     if (script_count++ > HB_MAX_SCRIPTS)  | 
1116  | 0  |       return true;  | 
1117  |  |  | 
1118  | 0  |     return visited (s, visited_script);  | 
1119  | 0  |   }  | 
1120  |  |   bool visited (const OT::LangSys &l)  | 
1121  | 0  |   { | 
1122  |  |     /* We might have Null() object here.  Don't want to involve  | 
1123  |  |      * that in the memoize.  So, detect empty objects and return. */  | 
1124  | 0  |     if (unlikely (!l.has_required_feature () &&  | 
1125  | 0  |       !l.get_feature_count ()))  | 
1126  | 0  |       return true;  | 
1127  |  |  | 
1128  | 0  |     if (langsys_count++ > HB_MAX_LANGSYS)  | 
1129  | 0  |       return true;  | 
1130  |  |  | 
1131  | 0  |     return visited (l, visited_langsys);  | 
1132  | 0  |   }  | 
1133  |  |  | 
1134  |  |   bool visited_feature_indices (unsigned count)  | 
1135  | 0  |   { | 
1136  | 0  |     feature_index_count += count;  | 
1137  | 0  |     return feature_index_count > HB_MAX_FEATURE_INDICES;  | 
1138  | 0  |   }  | 
1139  |  |  | 
1140  |  |   private:  | 
1141  |  |   template <typename T>  | 
1142  |  |   bool visited (const T &p, hb_set_t &visited_set)  | 
1143  | 0  |   { | 
1144  | 0  |     hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) &p - (uintptr_t) &g);  | 
1145  | 0  |      if (visited_set.has (delta))  | 
1146  | 0  |       return true;  | 
1147  |  |  | 
1148  | 0  |     visited_set.add (delta);  | 
1149  | 0  |     return false;  | 
1150  | 0  |   } Unexecuted instantiation: bool hb_collect_features_context_t::visited<OT::Script>(OT::Script const&, hb_set_t&) Unexecuted instantiation: bool hb_collect_features_context_t::visited<OT::LangSys>(OT::LangSys const&, hb_set_t&)  | 
1151  |  |  | 
1152  |  |   public:  | 
1153  |  |   const OT::GSUBGPOS &g;  | 
1154  |  |   hb_set_t *feature_indices;  | 
1155  |  |   hb_set_t  feature_indices_filter;  | 
1156  |  |   bool has_feature_filter;  | 
1157  |  |  | 
1158  |  |   private:  | 
1159  |  |   hb_set_t visited_script;  | 
1160  |  |   hb_set_t visited_langsys;  | 
1161  |  |   unsigned int script_count;  | 
1162  |  |   unsigned int langsys_count;  | 
1163  |  |   unsigned int feature_index_count;  | 
1164  |  | };  | 
1165  |  |  | 
1166  |  | static void  | 
1167  |  | langsys_collect_features (hb_collect_features_context_t *c,  | 
1168  |  |         const OT::LangSys  &l)  | 
1169  | 0  | { | 
1170  | 0  |   if (c->visited (l)) return;  | 
1171  |  |  | 
1172  | 0  |   if (!c->has_feature_filter)  | 
1173  | 0  |   { | 
1174  |  |     /* All features. */  | 
1175  | 0  |     if (l.has_required_feature () && !c->visited_feature_indices (1))  | 
1176  | 0  |       c->feature_indices->add (l.get_required_feature_index ());  | 
1177  |  |  | 
1178  |  |     // TODO(garretrieger): filter out indices >= feature count?  | 
1179  | 0  |     if (!c->visited_feature_indices (l.featureIndex.len))  | 
1180  | 0  |       l.add_feature_indexes_to (c->feature_indices);  | 
1181  | 0  |   }  | 
1182  | 0  |   else  | 
1183  | 0  |   { | 
1184  | 0  |     if (c->feature_indices_filter.is_empty()) return;  | 
1185  | 0  |     unsigned int num_features = l.get_feature_count ();  | 
1186  | 0  |     for (unsigned int i = 0; i < num_features; i++)  | 
1187  | 0  |     { | 
1188  | 0  |       unsigned int feature_index = l.get_feature_index (i);  | 
1189  | 0  |       if (!c->feature_indices_filter.has (feature_index)) continue;  | 
1190  |  |  | 
1191  | 0  |       c->feature_indices->add (feature_index);  | 
1192  | 0  |       c->feature_indices_filter.del (feature_index);  | 
1193  | 0  |     }  | 
1194  | 0  |   }  | 
1195  | 0  | }  | 
1196  |  |  | 
1197  |  | static void  | 
1198  |  | script_collect_features (hb_collect_features_context_t *c,  | 
1199  |  |        const OT::Script   &s,  | 
1200  |  |        const hb_tag_t *languages)  | 
1201  | 0  | { | 
1202  | 0  |   if (c->visited (s)) return;  | 
1203  |  |  | 
1204  | 0  |   if (!languages)  | 
1205  | 0  |   { | 
1206  |  |     /* All languages. */  | 
1207  | 0  |     if (s.has_default_lang_sys ())  | 
1208  | 0  |       langsys_collect_features (c,  | 
1209  | 0  |         s.get_default_lang_sys ());  | 
1210  |  |  | 
1211  |  | 
  | 
1212  | 0  |     unsigned int count = s.get_lang_sys_count ();  | 
1213  | 0  |     for (unsigned int language_index = 0; language_index < count; language_index++)  | 
1214  | 0  |       langsys_collect_features (c,  | 
1215  | 0  |         s.get_lang_sys (language_index));  | 
1216  | 0  |   }  | 
1217  | 0  |   else  | 
1218  | 0  |   { | 
1219  | 0  |     for (; *languages; languages++)  | 
1220  | 0  |     { | 
1221  | 0  |       unsigned int language_index;  | 
1222  | 0  |       if (s.find_lang_sys_index (*languages, &language_index))  | 
1223  | 0  |   langsys_collect_features (c,  | 
1224  | 0  |           s.get_lang_sys (language_index));  | 
1225  |  | 
  | 
1226  | 0  |     }  | 
1227  | 0  |   }  | 
1228  | 0  | }  | 
1229  |  |  | 
1230  |  |  | 
1231  |  | /**  | 
1232  |  |  * hb_ot_layout_collect_features:  | 
1233  |  |  * @face: #hb_face_t to work upon  | 
1234  |  |  * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS  | 
1235  |  |  * @scripts: (nullable) (array zero-terminated=1): The array of scripts to collect features for,  | 
1236  |  |  *   terminated by %HB_TAG_NONE  | 
1237  |  |  * @languages: (nullable) (array zero-terminated=1): The array of languages to collect features for,  | 
1238  |  |  *   terminated by %HB_TAG_NONE  | 
1239  |  |  * @features: (nullable) (array zero-terminated=1): The array of features to collect,  | 
1240  |  |  *   terminated by %HB_TAG_NONE  | 
1241  |  |  * @feature_indexes: (out): The array of feature indexes found for the query  | 
1242  |  |  *  | 
1243  |  |  * Fetches a list of all feature indexes in the specified face's GSUB table  | 
1244  |  |  * or GPOS table, underneath the specified scripts, languages, and features.  | 
1245  |  |  * If no list of scripts is provided, all scripts will be queried. If no list  | 
1246  |  |  * of languages is provided, all languages will be queried. If no list of  | 
1247  |  |  * features is provided, all features will be queried.  | 
1248  |  |  *  | 
1249  |  |  * Since: 1.8.5  | 
1250  |  |  **/  | 
1251  |  | void  | 
1252  |  | hb_ot_layout_collect_features (hb_face_t      *face,  | 
1253  |  |              hb_tag_t        table_tag,  | 
1254  |  |              const hb_tag_t *scripts,  | 
1255  |  |              const hb_tag_t *languages,  | 
1256  |  |              const hb_tag_t *features,  | 
1257  |  |              hb_set_t       *feature_indexes /* OUT */)  | 
1258  | 0  | { | 
1259  | 0  |   hb_collect_features_context_t c (face, table_tag, feature_indexes, features);  | 
1260  | 0  |   if (!scripts)  | 
1261  | 0  |   { | 
1262  |  |     /* All scripts. */  | 
1263  | 0  |     unsigned int count = c.g.get_script_count ();  | 
1264  | 0  |     for (unsigned int script_index = 0; script_index < count; script_index++)  | 
1265  | 0  |       script_collect_features (&c,  | 
1266  | 0  |              c.g.get_script (script_index),  | 
1267  | 0  |              languages);  | 
1268  | 0  |   }  | 
1269  | 0  |   else  | 
1270  | 0  |   { | 
1271  | 0  |     for (; *scripts; scripts++)  | 
1272  | 0  |     { | 
1273  | 0  |       unsigned int script_index;  | 
1274  | 0  |       if (c.g.find_script_index (*scripts, &script_index))  | 
1275  | 0  |   script_collect_features (&c,  | 
1276  | 0  |          c.g.get_script (script_index),  | 
1277  | 0  |          languages);  | 
1278  | 0  |     }  | 
1279  | 0  |   }  | 
1280  | 0  | }  | 
1281  |  |  | 
1282  |  |  | 
1283  |  | /**  | 
1284  |  |  * hb_ot_layout_collect_lookups:  | 
1285  |  |  * @face: #hb_face_t to work upon  | 
1286  |  |  * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS  | 
1287  |  |  * @scripts: (nullable) (array zero-terminated=1): The array of scripts to collect lookups for,  | 
1288  |  |  *   terminated by %HB_TAG_NONE  | 
1289  |  |  * @languages: (nullable) (array zero-terminated=1): The array of languages to collect lookups for,  | 
1290  |  |  *   terminated by %HB_TAG_NONE  | 
1291  |  |  * @features: (nullable) (array zero-terminated=1): The array of features to collect lookups for,  | 
1292  |  |  *   terminated by %HB_TAG_NONE  | 
1293  |  |  * @lookup_indexes: (out): The array of lookup indexes found for the query  | 
1294  |  |  *  | 
1295  |  |  * Fetches a list of all feature-lookup indexes in the specified face's GSUB  | 
1296  |  |  * table or GPOS table, underneath the specified scripts, languages, and  | 
1297  |  |  * features. If no list of scripts is provided, all scripts will be queried.  | 
1298  |  |  * If no list of languages is provided, all languages will be queried. If no  | 
1299  |  |  * list of features is provided, all features will be queried.  | 
1300  |  |  *  | 
1301  |  |  * Since: 0.9.8  | 
1302  |  |  **/  | 
1303  |  | void  | 
1304  |  | hb_ot_layout_collect_lookups (hb_face_t      *face,  | 
1305  |  |             hb_tag_t        table_tag,  | 
1306  |  |             const hb_tag_t *scripts,  | 
1307  |  |             const hb_tag_t *languages,  | 
1308  |  |             const hb_tag_t *features,  | 
1309  |  |             hb_set_t       *lookup_indexes /* OUT */)  | 
1310  | 0  | { | 
1311  | 0  |   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);  | 
1312  |  | 
  | 
1313  | 0  |   hb_set_t feature_indexes;  | 
1314  | 0  |   hb_ot_layout_collect_features (face, table_tag, scripts, languages, features, &feature_indexes);  | 
1315  |  | 
  | 
1316  | 0  |   for (hb_codepoint_t feature_index = HB_SET_VALUE_INVALID;  | 
1317  | 0  |        hb_set_next (&feature_indexes, &feature_index);)  | 
1318  | 0  |     g.get_feature (feature_index).add_lookup_indexes_to (lookup_indexes);  | 
1319  |  | 
  | 
1320  | 0  |   g.feature_variation_collect_lookups (&feature_indexes, nullptr, lookup_indexes);  | 
1321  | 0  | }  | 
1322  |  |  | 
1323  |  |  | 
1324  |  | #ifndef HB_NO_LAYOUT_COLLECT_GLYPHS  | 
1325  |  | /**  | 
1326  |  |  * hb_ot_layout_lookup_collect_glyphs:  | 
1327  |  |  * @face: #hb_face_t to work upon  | 
1328  |  |  * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS  | 
1329  |  |  * @lookup_index: The index of the feature lookup to query  | 
1330  |  |  * @glyphs_before: (out): Array of glyphs preceding the substitution range  | 
1331  |  |  * @glyphs_input: (out): Array of input glyphs that would be substituted by the lookup  | 
1332  |  |  * @glyphs_after: (out): Array of glyphs following the substitution range  | 
1333  |  |  * @glyphs_output: (out): Array of glyphs that would be the substituted output of the lookup  | 
1334  |  |  *  | 
1335  |  |  * Fetches a list of all glyphs affected by the specified lookup in the  | 
1336  |  |  * specified face's GSUB table or GPOS table.  | 
1337  |  |  *  | 
1338  |  |  * Since: 0.9.7  | 
1339  |  |  **/  | 
1340  |  | void  | 
1341  |  | hb_ot_layout_lookup_collect_glyphs (hb_face_t    *face,  | 
1342  |  |             hb_tag_t      table_tag,  | 
1343  |  |             unsigned int  lookup_index,  | 
1344  |  |             hb_set_t     *glyphs_before, /* OUT.  May be NULL */  | 
1345  |  |             hb_set_t     *glyphs_input,  /* OUT.  May be NULL */  | 
1346  |  |             hb_set_t     *glyphs_after,  /* OUT.  May be NULL */  | 
1347  |  |             hb_set_t     *glyphs_output  /* OUT.  May be NULL */)  | 
1348  | 0  | { | 
1349  | 0  |   OT::hb_collect_glyphs_context_t c (face,  | 
1350  | 0  |              glyphs_before,  | 
1351  | 0  |              glyphs_input,  | 
1352  | 0  |              glyphs_after,  | 
1353  | 0  |              glyphs_output);  | 
1354  |  | 
  | 
1355  | 0  |   switch (table_tag)  | 
1356  | 0  |   { | 
1357  | 0  |     case HB_OT_TAG_GSUB:  | 
1358  | 0  |     { | 
1359  | 0  |       const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index);  | 
1360  | 0  |       l.collect_glyphs (&c);  | 
1361  | 0  |       return;  | 
1362  | 0  |     }  | 
1363  | 0  |     case HB_OT_TAG_GPOS:  | 
1364  | 0  |     { | 
1365  | 0  |       const OT::PosLookup& l = face->table.GPOS->table->get_lookup (lookup_index);  | 
1366  | 0  |       l.collect_glyphs (&c);  | 
1367  | 0  |       return;  | 
1368  | 0  |     }  | 
1369  | 0  |   }  | 
1370  | 0  | }  | 
1371  |  | #endif  | 
1372  |  |  | 
1373  |  |  | 
1374  |  | /* Variations support */  | 
1375  |  |  | 
1376  |  |  | 
1377  |  | /**  | 
1378  |  |  * hb_ot_layout_table_find_feature_variations:  | 
1379  |  |  * @face: #hb_face_t to work upon  | 
1380  |  |  * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS  | 
1381  |  |  * @coords: The variation coordinates to query  | 
1382  |  |  * @num_coords: The number of variation coordinates  | 
1383  |  |  * @variations_index: (out): The array of feature variations found for the query  | 
1384  |  |  *  | 
1385  |  |  * Fetches a list of feature variations in the specified face's GSUB table  | 
1386  |  |  * or GPOS table, at the specified variation coordinates.  | 
1387  |  |  *  | 
1388  |  |  * Return value: `true` if feature variations were found, `false` otherwise.  | 
1389  |  |  *  | 
1390  |  |  * Since: 1.4.0  | 
1391  |  |  *  | 
1392  |  |  **/  | 
1393  |  | hb_bool_t  | 
1394  |  | hb_ot_layout_table_find_feature_variations (hb_face_t    *face,  | 
1395  |  |               hb_tag_t      table_tag,  | 
1396  |  |               const int    *coords,  | 
1397  |  |               unsigned int  num_coords,  | 
1398  |  |               unsigned int *variations_index /* out */)  | 
1399  | 3.25M  | { | 
1400  | 3.25M  |   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);  | 
1401  |  |  | 
1402  | 3.25M  |   return g.find_variations_index (coords, num_coords, variations_index);  | 
1403  | 3.25M  | }  | 
1404  |  |  | 
1405  |  |  | 
1406  |  | /**  | 
1407  |  |  * hb_ot_layout_feature_with_variations_get_lookups:  | 
1408  |  |  * @face: #hb_face_t to work upon  | 
1409  |  |  * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS  | 
1410  |  |  * @feature_index: The index of the feature to query  | 
1411  |  |  * @variations_index: The index of the feature variation to query  | 
1412  |  |  * @start_offset: offset of the first lookup to retrieve  | 
1413  |  |  * @lookup_count: (inout) (optional): Input = the maximum number of lookups to return;  | 
1414  |  |  *                Output = the actual number of lookups returned (may be zero)  | 
1415  |  |  * @lookup_indexes: (out) (array length=lookup_count): The array of lookups found for the query  | 
1416  |  |  *  | 
1417  |  |  * Fetches a list of all lookups enumerated for the specified feature, in  | 
1418  |  |  * the specified face's GSUB table or GPOS table, enabled at the specified  | 
1419  |  |  * variations index. The list returned will begin at the offset provided.  | 
1420  |  |  *  | 
1421  |  |  * Return value: Total number of lookups.  | 
1422  |  |  *  | 
1423  |  |  * Since: 1.4.0  | 
1424  |  |  *  | 
1425  |  |  **/  | 
1426  |  | unsigned int  | 
1427  |  | hb_ot_layout_feature_with_variations_get_lookups (hb_face_t    *face,  | 
1428  |  |               hb_tag_t      table_tag,  | 
1429  |  |               unsigned int  feature_index,  | 
1430  |  |               unsigned int  variations_index,  | 
1431  |  |               unsigned int  start_offset,  | 
1432  |  |               unsigned int *lookup_count /* IN/OUT */,  | 
1433  |  |               unsigned int *lookup_indexes /* OUT */)  | 
1434  | 688k  | { | 
1435  | 688k  |   static_assert ((OT::FeatureVariations::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_VARIATIONS_INDEX), "");  | 
1436  | 688k  |   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);  | 
1437  |  |  | 
1438  | 688k  |   const OT::Feature &f = g.get_feature_variation (feature_index, variations_index);  | 
1439  |  |  | 
1440  | 688k  |   return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);  | 
1441  | 688k  | }  | 
1442  |  |  | 
1443  |  |  | 
1444  |  | /*  | 
1445  |  |  * OT::GSUB  | 
1446  |  |  */  | 
1447  |  |  | 
1448  |  |  | 
1449  |  | /**  | 
1450  |  |  * hb_ot_layout_has_substitution:  | 
1451  |  |  * @face: #hb_face_t to work upon  | 
1452  |  |  *  | 
1453  |  |  * Tests whether the specified face includes any GSUB substitutions.  | 
1454  |  |  *  | 
1455  |  |  * Return value: `true` if data found, `false` otherwise  | 
1456  |  |  *  | 
1457  |  |  * Since: 0.6.0  | 
1458  |  |  *  | 
1459  |  |  **/  | 
1460  |  | hb_bool_t  | 
1461  |  | hb_ot_layout_has_substitution (hb_face_t *face)  | 
1462  | 215k  | { | 
1463  | 215k  |   return face->table.GSUB->table->has_data ();  | 
1464  | 215k  | }  | 
1465  |  |  | 
1466  |  |  | 
1467  |  | /**  | 
1468  |  |  * hb_ot_layout_lookup_would_substitute:  | 
1469  |  |  * @face: #hb_face_t to work upon  | 
1470  |  |  * @lookup_index: The index of the lookup to query  | 
1471  |  |  * @glyphs: The sequence of glyphs to query for substitution  | 
1472  |  |  * @glyphs_length: The length of the glyph sequence  | 
1473  |  |  * @zero_context: #hb_bool_t indicating whether pre-/post-context are disallowed  | 
1474  |  |  * in substitutions  | 
1475  |  |  *  | 
1476  |  |  * Tests whether a specified lookup in the specified face would  | 
1477  |  |  * trigger a substitution on the given glyph sequence.  | 
1478  |  |  *  | 
1479  |  |  * Return value: `true` if a substitution would be triggered, `false` otherwise  | 
1480  |  |  *  | 
1481  |  |  * Since: 0.9.7  | 
1482  |  |  **/  | 
1483  |  | hb_bool_t  | 
1484  |  | hb_ot_layout_lookup_would_substitute (hb_face_t            *face,  | 
1485  |  |               unsigned int          lookup_index,  | 
1486  |  |               const hb_codepoint_t *glyphs,  | 
1487  |  |               unsigned int          glyphs_length,  | 
1488  |  |               hb_bool_t             zero_context)  | 
1489  | 418k  | { | 
1490  | 418k  |   if (unlikely (lookup_index >= face->table.GSUB->lookup_count)) return false;  | 
1491  | 418k  |   OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, (bool) zero_context);  | 
1492  |  |  | 
1493  | 418k  |   const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index);  | 
1494  | 418k  |   return l.would_apply (&c, &face->table.GSUB->accels[lookup_index]);  | 
1495  | 418k  | }  | 
1496  |  |  | 
1497  |  |  | 
1498  |  | /**  | 
1499  |  |  * hb_ot_layout_substitute_start:  | 
1500  |  |  * @font: #hb_font_t to use  | 
1501  |  |  * @buffer: #hb_buffer_t buffer to work upon  | 
1502  |  |  *  | 
1503  |  |  * Called before substitution lookups are performed, to ensure that glyph  | 
1504  |  |  * class and other properties are set on the glyphs in the buffer.  | 
1505  |  |  *  | 
1506  |  |  **/  | 
1507  |  | void  | 
1508  |  | hb_ot_layout_substitute_start (hb_font_t    *font,  | 
1509  |  |              hb_buffer_t  *buffer)  | 
1510  | 1.50M  | { | 
1511  | 1.50M  |   _hb_ot_layout_set_glyph_props (font, buffer);  | 
1512  | 1.50M  | }  | 
1513  |  |  | 
1514  |  | /**  | 
1515  |  |  * hb_ot_layout_lookup_substitute_closure:  | 
1516  |  |  * @face: #hb_face_t to work upon  | 
1517  |  |  * @lookup_index: index of the feature lookup to query  | 
1518  |  |  * @glyphs: (out): Array of glyphs comprising the transitive closure of the lookup  | 
1519  |  |  *  | 
1520  |  |  * Compute the transitive closure of glyphs needed for a  | 
1521  |  |  * specified lookup.  | 
1522  |  |  *  | 
1523  |  |  * Since: 0.9.7  | 
1524  |  |  **/  | 
1525  |  | void  | 
1526  |  | hb_ot_layout_lookup_substitute_closure (hb_face_t    *face,  | 
1527  |  |           unsigned int  lookup_index,  | 
1528  |  |           hb_set_t     *glyphs /* OUT */)  | 
1529  | 0  | { | 
1530  | 0  |   hb_map_t done_lookups_glyph_count;  | 
1531  | 0  |   hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> done_lookups_glyph_set;  | 
1532  | 0  |   OT::hb_closure_context_t c (face, glyphs, &done_lookups_glyph_count, &done_lookups_glyph_set);  | 
1533  |  | 
  | 
1534  | 0  |   const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index);  | 
1535  |  | 
  | 
1536  | 0  |   l.closure (&c, lookup_index);  | 
1537  | 0  | }  | 
1538  |  |  | 
1539  |  | /**  | 
1540  |  |  * hb_ot_layout_lookups_substitute_closure:  | 
1541  |  |  * @face: #hb_face_t to work upon  | 
1542  |  |  * @lookups: The set of lookups to query  | 
1543  |  |  * @glyphs: (out): Array of glyphs comprising the transitive closure of the lookups  | 
1544  |  |  *  | 
1545  |  |  * Compute the transitive closure of glyphs needed for all of the  | 
1546  |  |  * provided lookups.  | 
1547  |  |  *  | 
1548  |  |  * Since: 1.8.1  | 
1549  |  |  **/  | 
1550  |  | void  | 
1551  |  | hb_ot_layout_lookups_substitute_closure (hb_face_t      *face,  | 
1552  |  |            const hb_set_t *lookups,  | 
1553  |  |            hb_set_t       *glyphs /* OUT */)  | 
1554  | 0  | { | 
1555  | 0  |   hb_map_t done_lookups_glyph_count;  | 
1556  | 0  |   hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> done_lookups_glyph_set;  | 
1557  | 0  |   OT::hb_closure_context_t c (face, glyphs, &done_lookups_glyph_count, &done_lookups_glyph_set);  | 
1558  | 0  |   const GSUB& gsub = *face->table.GSUB->table;  | 
1559  |  | 
  | 
1560  | 0  |   unsigned int iteration_count = 0;  | 
1561  | 0  |   unsigned int glyphs_length;  | 
1562  | 0  |   do  | 
1563  | 0  |   { | 
1564  | 0  |     c.reset_lookup_visit_count ();  | 
1565  | 0  |     glyphs_length = glyphs->get_population ();  | 
1566  | 0  |     if (lookups)  | 
1567  | 0  |     { | 
1568  | 0  |       for (hb_codepoint_t lookup_index = HB_SET_VALUE_INVALID; hb_set_next (lookups, &lookup_index);)  | 
1569  | 0  |   gsub.get_lookup (lookup_index).closure (&c, lookup_index);  | 
1570  | 0  |     }  | 
1571  | 0  |     else  | 
1572  | 0  |     { | 
1573  | 0  |       for (unsigned int i = 0; i < gsub.get_lookup_count (); i++)  | 
1574  | 0  |   gsub.get_lookup (i).closure (&c, i);  | 
1575  | 0  |     }  | 
1576  | 0  |   } while (iteration_count++ <= HB_CLOSURE_MAX_STAGES &&  | 
1577  | 0  |      glyphs_length != glyphs->get_population ());  | 
1578  | 0  | }  | 
1579  |  |  | 
1580  |  | /*  | 
1581  |  |  * GPOS  | 
1582  |  |  */  | 
1583  |  |  | 
1584  |  |  | 
1585  |  | /**  | 
1586  |  |  * hb_ot_layout_has_positioning:  | 
1587  |  |  * @face: #hb_face_t to work upon  | 
1588  |  |  *  | 
1589  |  |  * Tests whether the specified face includes any GPOS positioning.  | 
1590  |  |  *  | 
1591  |  |  * Return value: `true` if the face has GPOS data, `false` otherwise  | 
1592  |  |  *  | 
1593  |  |  **/  | 
1594  |  | hb_bool_t  | 
1595  |  | hb_ot_layout_has_positioning (hb_face_t *face)  | 
1596  | 218k  | { | 
1597  | 218k  |   return face->table.GPOS->table->has_data ();  | 
1598  | 218k  | }  | 
1599  |  |  | 
1600  |  | /**  | 
1601  |  |  * hb_ot_layout_position_start:  | 
1602  |  |  * @font: #hb_font_t to use  | 
1603  |  |  * @buffer: #hb_buffer_t buffer to work upon  | 
1604  |  |  *  | 
1605  |  |  * Called before positioning lookups are performed, to ensure that glyph  | 
1606  |  |  * attachment types and glyph-attachment chains are set for the glyphs in the buffer.  | 
1607  |  |  *  | 
1608  |  |  **/  | 
1609  |  | void  | 
1610  |  | hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)  | 
1611  | 1.50M  | { | 
1612  | 1.50M  |   GPOS::position_start (font, buffer);  | 
1613  | 1.50M  | }  | 
1614  |  |  | 
1615  |  |  | 
1616  |  | /**  | 
1617  |  |  * hb_ot_layout_position_finish_advances:  | 
1618  |  |  * @font: #hb_font_t to use  | 
1619  |  |  * @buffer: #hb_buffer_t buffer to work upon  | 
1620  |  |  *  | 
1621  |  |  * Called after positioning lookups are performed, to finish glyph advances.  | 
1622  |  |  *  | 
1623  |  |  **/  | 
1624  |  | void  | 
1625  |  | hb_ot_layout_position_finish_advances (hb_font_t *font, hb_buffer_t *buffer)  | 
1626  | 1.50M  | { | 
1627  | 1.50M  |   GPOS::position_finish_advances (font, buffer);  | 
1628  | 1.50M  | }  | 
1629  |  |  | 
1630  |  | /**  | 
1631  |  |  * hb_ot_layout_position_finish_offsets:  | 
1632  |  |  * @font: #hb_font_t to use  | 
1633  |  |  * @buffer: #hb_buffer_t buffer to work upon  | 
1634  |  |  *  | 
1635  |  |  * Called after positioning lookups are performed, to finish glyph offsets.  | 
1636  |  |  *  | 
1637  |  |  **/  | 
1638  |  | void  | 
1639  |  | hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)  | 
1640  | 1.50M  | { | 
1641  | 1.50M  |   GPOS::position_finish_offsets (font, buffer);  | 
1642  | 1.50M  | }  | 
1643  |  |  | 
1644  |  |  | 
1645  |  | #ifndef HB_NO_LAYOUT_FEATURE_PARAMS  | 
1646  |  | /**  | 
1647  |  |  * hb_ot_layout_get_size_params:  | 
1648  |  |  * @face: #hb_face_t to work upon  | 
1649  |  |  * @design_size: (out): The design size of the face  | 
1650  |  |  * @subfamily_id: (out): The identifier of the face within the font subfamily  | 
1651  |  |  * @subfamily_name_id: (out): The ‘name’ table name ID of the face within the font subfamily  | 
1652  |  |  * @range_start: (out): The minimum size of the recommended size range for the face  | 
1653  |  |  * @range_end: (out): The maximum size of the recommended size range for the face  | 
1654  |  |  *  | 
1655  |  |  * Fetches optical-size feature data (i.e., the `size` feature from GPOS). Note that  | 
1656  |  |  * the subfamily_id and the subfamily name string (accessible via the subfamily_name_id)  | 
1657  |  |  * as used here are defined as pertaining only to fonts within a font family that differ  | 
1658  |  |  * specifically in their respective size ranges; other ways to differentiate fonts within  | 
1659  |  |  * a subfamily are not covered by the `size` feature.  | 
1660  |  |  *  | 
1661  |  |  * For more information on this distinction, see the [`size` feature documentation](  | 
1662  |  |  * https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#tag-size).  | 
1663  |  |  *  | 
1664  |  |  * Return value: `true` if data found, `false` otherwise  | 
1665  |  |  *  | 
1666  |  |  * Since: 0.9.10  | 
1667  |  |  **/  | 
1668  |  | hb_bool_t  | 
1669  |  | hb_ot_layout_get_size_params (hb_face_t       *face,  | 
1670  |  |             unsigned int    *design_size,       /* OUT.  May be NULL */  | 
1671  |  |             unsigned int    *subfamily_id,      /* OUT.  May be NULL */  | 
1672  |  |             hb_ot_name_id_t *subfamily_name_id, /* OUT.  May be NULL */  | 
1673  |  |             unsigned int    *range_start,       /* OUT.  May be NULL */  | 
1674  |  |             unsigned int    *range_end          /* OUT.  May be NULL */)  | 
1675  | 94.9k  | { | 
1676  | 94.9k  |   const GPOS &gpos = *face->table.GPOS->table;  | 
1677  | 94.9k  |   const hb_tag_t tag = HB_TAG ('s','i','z','e'); | 
1678  |  |  | 
1679  | 94.9k  |   unsigned int num_features = gpos.get_feature_count ();  | 
1680  | 123k  |   for (unsigned int i = 0; i < num_features; i++)  | 
1681  | 28.8k  |   { | 
1682  | 28.8k  |     if (tag == gpos.get_feature_tag (i))  | 
1683  | 219  |     { | 
1684  | 219  |       const OT::Feature &f = gpos.get_feature (i);  | 
1685  | 219  |       const OT::FeatureParamsSize ¶ms = f.get_feature_params ().get_size_params (tag);  | 
1686  |  |  | 
1687  | 219  |       if (params.designSize)  | 
1688  | 39  |       { | 
1689  | 39  |   if (design_size) *design_size = params.designSize;  | 
1690  | 39  |   if (subfamily_id) *subfamily_id = params.subfamilyID;  | 
1691  | 39  |   if (subfamily_name_id) *subfamily_name_id = params.subfamilyNameID;  | 
1692  | 39  |   if (range_start) *range_start = params.rangeStart;  | 
1693  | 39  |   if (range_end) *range_end = params.rangeEnd;  | 
1694  |  |  | 
1695  | 39  |   return true;  | 
1696  | 39  |       }  | 
1697  | 219  |     }  | 
1698  | 28.8k  |   }  | 
1699  |  |  | 
1700  | 94.8k  |   if (design_size) *design_size = 0;  | 
1701  | 94.8k  |   if (subfamily_id) *subfamily_id = 0;  | 
1702  | 94.8k  |   if (subfamily_name_id) *subfamily_name_id = HB_OT_NAME_ID_INVALID;  | 
1703  | 94.8k  |   if (range_start) *range_start = 0;  | 
1704  | 94.8k  |   if (range_end) *range_end = 0;  | 
1705  |  |  | 
1706  | 94.8k  |   return false;  | 
1707  | 94.9k  | }  | 
1708  |  |  | 
1709  |  |  | 
1710  |  | /**  | 
1711  |  |  * hb_ot_layout_feature_get_name_ids:  | 
1712  |  |  * @face: #hb_face_t to work upon  | 
1713  |  |  * @table_tag: table tag to query, "GSUB" or "GPOS".  | 
1714  |  |  * @feature_index: index of feature to query.  | 
1715  |  |  * @label_id: (out) (optional): The ‘name’ table name ID that specifies a string  | 
1716  |  |  *            for a user-interface label for this feature. (May be NULL.)  | 
1717  |  |  * @tooltip_id: (out) (optional): The ‘name’ table name ID that specifies a string  | 
1718  |  |  *              that an application can use for tooltip text for this  | 
1719  |  |  *              feature. (May be NULL.)  | 
1720  |  |  * @sample_id: (out) (optional): The ‘name’ table name ID that specifies sample text  | 
1721  |  |  *             that illustrates the effect of this feature. (May be NULL.)  | 
1722  |  |  * @num_named_parameters: (out) (optional):  Number of named parameters. (May be zero.)  | 
1723  |  |  * @first_param_id: (out) (optional): The first ‘name’ table name ID used to specify  | 
1724  |  |  *                  strings for user-interface labels for the feature  | 
1725  |  |  *                  parameters. (Must be zero if numParameters is zero.)  | 
1726  |  |  *  | 
1727  |  |  * Fetches name indices from feature parameters for "Stylistic Set" ('ssXX') or | 
1728  |  |  * "Character Variant" ('cvXX') features. | 
1729  |  |  *  | 
1730  |  |  * Return value: `true` if data found, `false` otherwise  | 
1731  |  |  *  | 
1732  |  |  * Since: 2.0.0  | 
1733  |  |  **/  | 
1734  |  | hb_bool_t  | 
1735  |  | hb_ot_layout_feature_get_name_ids (hb_face_t       *face,  | 
1736  |  |            hb_tag_t         table_tag,  | 
1737  |  |            unsigned int     feature_index,  | 
1738  |  |            hb_ot_name_id_t *label_id,             /* OUT.  May be NULL */  | 
1739  |  |            hb_ot_name_id_t *tooltip_id,           /* OUT.  May be NULL */  | 
1740  |  |            hb_ot_name_id_t *sample_id,            /* OUT.  May be NULL */  | 
1741  |  |            unsigned int    *num_named_parameters, /* OUT.  May be NULL */  | 
1742  |  |            hb_ot_name_id_t *first_param_id        /* OUT.  May be NULL */)  | 
1743  | 94.9k  | { | 
1744  | 94.9k  |   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);  | 
1745  |  |  | 
1746  | 94.9k  |   hb_tag_t feature_tag = g.get_feature_tag (feature_index);  | 
1747  | 94.9k  |   const OT::Feature &f = g.get_feature (feature_index);  | 
1748  |  |  | 
1749  | 94.9k  |   const OT::FeatureParams &feature_params = f.get_feature_params ();  | 
1750  | 94.9k  |   if (&feature_params != &Null (OT::FeatureParams))  | 
1751  | 44  |   { | 
1752  | 44  |     const OT::FeatureParamsStylisticSet& ss_params =  | 
1753  | 44  |       feature_params.get_stylistic_set_params (feature_tag);  | 
1754  | 44  |     if (&ss_params != &Null (OT::FeatureParamsStylisticSet)) /* ssXX */  | 
1755  | 0  |     { | 
1756  | 0  |       if (label_id) *label_id = ss_params.uiNameID;  | 
1757  |  |       // ssXX features don't have the rest  | 
1758  | 0  |       if (tooltip_id) *tooltip_id = HB_OT_NAME_ID_INVALID;  | 
1759  | 0  |       if (sample_id) *sample_id = HB_OT_NAME_ID_INVALID;  | 
1760  | 0  |       if (num_named_parameters) *num_named_parameters = 0;  | 
1761  | 0  |       if (first_param_id) *first_param_id = HB_OT_NAME_ID_INVALID;  | 
1762  | 0  |       return true;  | 
1763  | 0  |     }  | 
1764  | 44  |     const OT::FeatureParamsCharacterVariants& cv_params =  | 
1765  | 44  |       feature_params.get_character_variants_params (feature_tag);  | 
1766  | 44  |     if (&cv_params != &Null (OT::FeatureParamsCharacterVariants)) /* cvXX */  | 
1767  | 44  |     { | 
1768  | 44  |       if (label_id) *label_id = cv_params.featUILableNameID;  | 
1769  | 44  |       if (tooltip_id) *tooltip_id = cv_params.featUITooltipTextNameID;  | 
1770  | 44  |       if (sample_id) *sample_id = cv_params.sampleTextNameID;  | 
1771  | 44  |       if (num_named_parameters) *num_named_parameters = cv_params.numNamedParameters;  | 
1772  | 44  |       if (first_param_id) *first_param_id = cv_params.firstParamUILabelNameID;  | 
1773  | 44  |       return true;  | 
1774  | 44  |     }  | 
1775  | 44  |   }  | 
1776  |  |  | 
1777  | 94.8k  |   if (label_id) *label_id = HB_OT_NAME_ID_INVALID;  | 
1778  | 94.8k  |   if (tooltip_id) *tooltip_id = HB_OT_NAME_ID_INVALID;  | 
1779  | 94.8k  |   if (sample_id) *sample_id = HB_OT_NAME_ID_INVALID;  | 
1780  | 94.8k  |   if (num_named_parameters) *num_named_parameters = 0;  | 
1781  | 94.8k  |   if (first_param_id) *first_param_id = HB_OT_NAME_ID_INVALID;  | 
1782  | 94.8k  |   return false;  | 
1783  | 94.9k  | }  | 
1784  |  | /**  | 
1785  |  |  * hb_ot_layout_feature_get_characters:  | 
1786  |  |  * @face: #hb_face_t to work upon  | 
1787  |  |  * @table_tag: table tag to query, "GSUB" or "GPOS".  | 
1788  |  |  * @feature_index: index of feature to query.  | 
1789  |  |  * @start_offset: offset of the first character to retrieve  | 
1790  |  |  * @char_count: (inout) (optional): Input = the maximum number of characters to return;  | 
1791  |  |  *              Output = the actual number of characters returned (may be zero)  | 
1792  |  |  * @characters: (out caller-allocates) (array length=char_count): A buffer pointer.  | 
1793  |  |  *              The Unicode codepoints of the characters for which this feature provides  | 
1794  |  |  *               glyph variants.  | 
1795  |  |  *  | 
1796  |  |  * Fetches a list of the characters defined as having a variant under the specified  | 
1797  |  |  * "Character Variant" ("cvXX") feature tag. | 
1798  |  |  *  | 
1799  |  |  * Return value: Number of total sample characters in the cvXX feature.  | 
1800  |  |  *  | 
1801  |  |  * Since: 2.0.0  | 
1802  |  |  **/  | 
1803  |  | unsigned int  | 
1804  |  | hb_ot_layout_feature_get_characters (hb_face_t      *face,  | 
1805  |  |              hb_tag_t        table_tag,  | 
1806  |  |              unsigned int    feature_index,  | 
1807  |  |              unsigned int    start_offset,  | 
1808  |  |              unsigned int   *char_count, /* IN/OUT.  May be NULL */  | 
1809  |  |              hb_codepoint_t *characters  /* OUT.     May be NULL */)  | 
1810  | 94.9k  | { | 
1811  | 94.9k  |   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);  | 
1812  | 94.9k  |   return g.get_feature (feature_index)  | 
1813  | 94.9k  |     .get_feature_params ()  | 
1814  | 94.9k  |     .get_character_variants_params(g.get_feature_tag (feature_index))  | 
1815  | 94.9k  |     .get_characters (start_offset, char_count, characters);  | 
1816  | 94.9k  | }  | 
1817  |  | #endif  | 
1818  |  |  | 
1819  |  |  | 
1820  |  | /*  | 
1821  |  |  * Parts of different types are implemented here such that they have direct  | 
1822  |  |  * access to GSUB/GPOS lookups.  | 
1823  |  |  */  | 
1824  |  |  | 
1825  |  |  | 
1826  |  | struct GSUBProxy  | 
1827  |  | { | 
1828  |  |   static constexpr unsigned table_index = 0u;  | 
1829  |  |   static constexpr bool always_inplace = false;  | 
1830  |  |   typedef OT::SubstLookup Lookup;  | 
1831  |  |  | 
1832  |  |   GSUBProxy (hb_face_t *face) :  | 
1833  |  |     table (*face->table.GSUB->table),  | 
1834  | 1.47M  |     accels (face->table.GSUB->accels) {} | 
1835  |  |  | 
1836  |  |   const GSUB &table;  | 
1837  |  |   const OT::hb_ot_layout_lookup_accelerator_t *accels;  | 
1838  |  | };  | 
1839  |  |  | 
1840  |  | struct GPOSProxy  | 
1841  |  | { | 
1842  |  |   static constexpr unsigned table_index = 1u;  | 
1843  |  |   static constexpr bool always_inplace = true;  | 
1844  |  |   typedef OT::PosLookup Lookup;  | 
1845  |  |  | 
1846  |  |   GPOSProxy (hb_face_t *face) :  | 
1847  |  |     table (*face->table.GPOS->table),  | 
1848  | 289k  |     accels (face->table.GPOS->accels) {} | 
1849  |  |  | 
1850  |  |   const GPOS &table;  | 
1851  |  |   const OT::hb_ot_layout_lookup_accelerator_t *accels;  | 
1852  |  | };  | 
1853  |  |  | 
1854  |  |  | 
1855  |  | static inline bool  | 
1856  |  | apply_forward (OT::hb_ot_apply_context_t *c,  | 
1857  |  |          const OT::hb_ot_layout_lookup_accelerator_t &accel)  | 
1858  | 145k  | { | 
1859  | 145k  |   bool use_cache = accel.cache_enter (c);  | 
1860  |  |  | 
1861  | 145k  |   bool ret = false;  | 
1862  | 145k  |   hb_buffer_t *buffer = c->buffer;  | 
1863  | 8.56M  |   while (buffer->idx < buffer->len && buffer->successful)  | 
1864  | 8.41M  |   { | 
1865  | 8.41M  |     bool applied = false;  | 
1866  | 8.41M  |     if (accel.digest.may_have (buffer->cur().codepoint) &&  | 
1867  | 8.41M  |   (buffer->cur().mask & c->lookup_mask) &&  | 
1868  | 8.41M  |   c->check_glyph_property (&buffer->cur(), c->lookup_props))  | 
1869  | 2.83M  |      { | 
1870  | 2.83M  |        applied = accel.apply (c, use_cache);  | 
1871  | 2.83M  |      }  | 
1872  |  |  | 
1873  | 8.41M  |     if (applied)  | 
1874  | 921k  |       ret = true;  | 
1875  | 7.49M  |     else  | 
1876  | 7.49M  |       (void) buffer->next_glyph ();  | 
1877  | 8.41M  |   }  | 
1878  |  |  | 
1879  | 145k  |   if (use_cache)  | 
1880  | 2.99k  |     accel.cache_leave (c);  | 
1881  |  |  | 
1882  | 145k  |   return ret;  | 
1883  | 145k  | }  | 
1884  |  |  | 
1885  |  | static inline bool  | 
1886  |  | apply_backward (OT::hb_ot_apply_context_t *c,  | 
1887  |  |          const OT::hb_ot_layout_lookup_accelerator_t &accel)  | 
1888  | 8.20k  | { | 
1889  | 8.20k  |   bool ret = false;  | 
1890  | 8.20k  |   hb_buffer_t *buffer = c->buffer;  | 
1891  | 8.20k  |   do  | 
1892  | 447k  |   { | 
1893  | 447k  |     if (accel.digest.may_have (buffer->cur().codepoint) &&  | 
1894  | 447k  |   (buffer->cur().mask & c->lookup_mask) &&  | 
1895  | 447k  |   c->check_glyph_property (&buffer->cur(), c->lookup_props))  | 
1896  | 163k  |      ret |= accel.apply (c, false);  | 
1897  |  |  | 
1898  |  |     /* The reverse lookup doesn't "advance" cursor (for good reason). */  | 
1899  | 447k  |     buffer->idx--;  | 
1900  |  |  | 
1901  | 447k  |   }  | 
1902  | 447k  |   while ((int) buffer->idx >= 0);  | 
1903  | 8.20k  |   return ret;  | 
1904  | 8.20k  | }  | 
1905  |  |  | 
1906  |  | template <typename Proxy>  | 
1907  |  | static inline bool  | 
1908  |  | apply_string (OT::hb_ot_apply_context_t *c,  | 
1909  |  |         const typename Proxy::Lookup &lookup,  | 
1910  |  |         const OT::hb_ot_layout_lookup_accelerator_t &accel)  | 
1911  | 153k  | { | 
1912  | 153k  |   bool ret = false;  | 
1913  | 153k  |   hb_buffer_t *buffer = c->buffer;  | 
1914  |  |  | 
1915  | 153k  |   if (unlikely (!buffer->len || !c->lookup_mask))  | 
1916  | 280  |     return ret;  | 
1917  |  |  | 
1918  | 153k  |   c->set_lookup_props (lookup.get_props ());  | 
1919  |  |  | 
1920  | 153k  |   if (likely (!lookup.is_reverse ()))  | 
1921  | 145k  |   { | 
1922  |  |     /* in/out forward substitution/positioning */  | 
1923  | 145k  |     if (!Proxy::always_inplace)  | 
1924  | 82.8k  |       buffer->clear_output ();  | 
1925  |  |  | 
1926  | 145k  |     buffer->idx = 0;  | 
1927  | 145k  |     ret = apply_forward (c, accel);  | 
1928  |  |  | 
1929  | 145k  |     if (!Proxy::always_inplace)  | 
1930  | 82.8k  |       buffer->sync ();  | 
1931  | 145k  |   }  | 
1932  | 8.20k  |   else  | 
1933  | 8.20k  |   { | 
1934  |  |     /* in-place backward substitution/positioning */  | 
1935  | 8.20k  |     assert (!buffer->have_output);  | 
1936  | 0  |     buffer->idx = buffer->len - 1;  | 
1937  | 8.20k  |     ret = apply_backward (c, accel);  | 
1938  | 8.20k  |   }  | 
1939  |  |  | 
1940  | 0  |   return ret;  | 
1941  | 153k  | } hb-ot-layout.cc:bool apply_string<GPOSProxy>(OT::hb_ot_apply_context_t*, GPOSProxy::Lookup const&, OT::hb_ot_layout_lookup_accelerator_t const&) Line  | Count  | Source  |  1911  | 62.3k  | { |  1912  | 62.3k  |   bool ret = false;  |  1913  | 62.3k  |   hb_buffer_t *buffer = c->buffer;  |  1914  |  |  |  1915  | 62.3k  |   if (unlikely (!buffer->len || !c->lookup_mask))  |  1916  | 0  |     return ret;  |  1917  |  |  |  1918  | 62.3k  |   c->set_lookup_props (lookup.get_props ());  |  1919  |  |  |  1920  | 62.3k  |   if (likely (!lookup.is_reverse ()))  |  1921  | 62.3k  |   { |  1922  |  |     /* in/out forward substitution/positioning */  |  1923  | 62.3k  |     if (!Proxy::always_inplace)  |  1924  | 0  |       buffer->clear_output ();  |  1925  |  |  |  1926  | 62.3k  |     buffer->idx = 0;  |  1927  | 62.3k  |     ret = apply_forward (c, accel);  |  1928  |  |  |  1929  | 62.3k  |     if (!Proxy::always_inplace)  |  1930  | 0  |       buffer->sync ();  |  1931  | 62.3k  |   }  |  1932  | 0  |   else  |  1933  | 0  |   { |  1934  |  |     /* in-place backward substitution/positioning */  |  1935  | 0  |     assert (!buffer->have_output);  |  1936  | 0  |     buffer->idx = buffer->len - 1;  |  1937  | 0  |     ret = apply_backward (c, accel);  |  1938  | 0  |   }  |  1939  |  |  |  1940  | 0  |   return ret;  |  1941  | 62.3k  | }  |  
 hb-ot-layout.cc:bool apply_string<GSUBProxy>(OT::hb_ot_apply_context_t*, GSUBProxy::Lookup const&, OT::hb_ot_layout_lookup_accelerator_t const&) Line  | Count  | Source  |  1911  | 91.3k  | { |  1912  | 91.3k  |   bool ret = false;  |  1913  | 91.3k  |   hb_buffer_t *buffer = c->buffer;  |  1914  |  |  |  1915  | 91.3k  |   if (unlikely (!buffer->len || !c->lookup_mask))  |  1916  | 280  |     return ret;  |  1917  |  |  |  1918  | 91.0k  |   c->set_lookup_props (lookup.get_props ());  |  1919  |  |  |  1920  | 91.0k  |   if (likely (!lookup.is_reverse ()))  |  1921  | 82.8k  |   { |  1922  |  |     /* in/out forward substitution/positioning */  |  1923  | 82.8k  |     if (!Proxy::always_inplace)  |  1924  | 82.8k  |       buffer->clear_output ();  |  1925  |  |  |  1926  | 82.8k  |     buffer->idx = 0;  |  1927  | 82.8k  |     ret = apply_forward (c, accel);  |  1928  |  |  |  1929  | 82.8k  |     if (!Proxy::always_inplace)  |  1930  | 82.8k  |       buffer->sync ();  |  1931  | 82.8k  |   }  |  1932  | 8.20k  |   else  |  1933  | 8.20k  |   { |  1934  |  |     /* in-place backward substitution/positioning */  |  1935  | 8.20k  |     assert (!buffer->have_output);  |  1936  | 0  |     buffer->idx = buffer->len - 1;  |  1937  | 8.20k  |     ret = apply_backward (c, accel);  |  1938  | 8.20k  |   }  |  1939  |  |  |  1940  | 0  |   return ret;  |  1941  | 91.3k  | }  |  
  | 
1942  |  |  | 
1943  |  | template <typename Proxy>  | 
1944  |  | inline void hb_ot_map_t::apply (const Proxy &proxy,  | 
1945  |  |         const hb_ot_shape_plan_t *plan,  | 
1946  |  |         hb_font_t *font,  | 
1947  |  |         hb_buffer_t *buffer) const  | 
1948  | 1.76M  | { | 
1949  | 1.76M  |   const unsigned int table_index = proxy.table_index;  | 
1950  | 1.76M  |   unsigned int i = 0;  | 
1951  | 1.76M  |   OT::hb_ot_apply_context_t c (table_index, font, buffer);  | 
1952  | 1.76M  |   c.set_recurse_func (Proxy::Lookup::template dispatch_recurse_func<OT::hb_ot_apply_context_t>);  | 
1953  |  |  | 
1954  | 5.09M  |   for (unsigned int stage_index = 0; stage_index < stages[table_index].length; stage_index++)  | 
1955  | 3.32M  |   { | 
1956  | 3.32M  |     const stage_map_t *stage = &stages[table_index][stage_index];  | 
1957  | 4.01M  |     for (; i < stage->last_lookup; i++)  | 
1958  | 696k  |     { | 
1959  | 696k  |       auto &lookup = lookups[table_index][i];  | 
1960  |  |  | 
1961  | 696k  |       unsigned int lookup_index = lookup.index;  | 
1962  | 696k  |       if (buffer->messaging () &&  | 
1963  | 696k  |     !buffer->message (font, "start lookup %u feature '%c%c%c%c'", lookup_index, HB_UNTAG (lookup.feature_tag))) continue;  | 
1964  |  |  | 
1965  |  |       /* c.digest is a digest of all the current glyphs in the buffer  | 
1966  |  |        * (plus some past glyphs).  | 
1967  |  |        *  | 
1968  |  |        * Only try applying the lookup if there is any overlap. */  | 
1969  | 696k  |       if (proxy.accels[lookup_index].digest.may_have (c.digest))  | 
1970  | 151k  |       { | 
1971  | 151k  |   c.set_lookup_index (lookup_index);  | 
1972  | 151k  |   c.set_lookup_mask (lookup.mask);  | 
1973  | 151k  |   c.set_auto_zwj (lookup.auto_zwj);  | 
1974  | 151k  |   c.set_auto_zwnj (lookup.auto_zwnj);  | 
1975  | 151k  |   c.set_random (lookup.random);  | 
1976  | 151k  |   c.set_per_syllable (lookup.per_syllable);  | 
1977  |  |  | 
1978  | 151k  |   apply_string<Proxy> (&c,  | 
1979  | 151k  |            proxy.table.get_lookup (lookup_index),  | 
1980  | 151k  |            proxy.accels[lookup_index]);  | 
1981  | 151k  |       }  | 
1982  | 544k  |       else if (buffer->messaging ())  | 
1983  | 0  |   (void) buffer->message (font, "skipped lookup %u feature '%c%c%c%c' because no glyph matches", lookup_index, HB_UNTAG (lookup.feature_tag));  | 
1984  |  |  | 
1985  | 696k  |       if (buffer->messaging ())  | 
1986  | 0  |   (void) buffer->message (font, "end lookup %u feature '%c%c%c%c'", lookup_index, HB_UNTAG (lookup.feature_tag));  | 
1987  | 696k  |     }  | 
1988  |  |  | 
1989  | 3.32M  |     if (stage->pause_func)  | 
1990  | 40.7k  |     { | 
1991  | 40.7k  |       if (stage->pause_func (plan, font, buffer))  | 
1992  | 2.55k  |       { | 
1993  |  |   /* Refresh working buffer digest since buffer changed. */  | 
1994  | 2.55k  |   c.digest = buffer->digest ();  | 
1995  | 2.55k  |       }  | 
1996  | 40.7k  |     }  | 
1997  | 3.32M  |   }  | 
1998  | 1.76M  | } void hb_ot_map_t::apply<GSUBProxy>(GSUBProxy const&, hb_ot_shape_plan_t const*, hb_font_t*, hb_buffer_t*) const Line  | Count  | Source  |  1948  | 1.47M  | { |  1949  | 1.47M  |   const unsigned int table_index = proxy.table_index;  |  1950  | 1.47M  |   unsigned int i = 0;  |  1951  | 1.47M  |   OT::hb_ot_apply_context_t c (table_index, font, buffer);  |  1952  | 1.47M  |   c.set_recurse_func (Proxy::Lookup::template dispatch_recurse_func<OT::hb_ot_apply_context_t>);  |  1953  |  |  |  1954  | 4.51M  |   for (unsigned int stage_index = 0; stage_index < stages[table_index].length; stage_index++)  |  1955  | 3.03M  |   { |  1956  | 3.03M  |     const stage_map_t *stage = &stages[table_index][stage_index];  |  1957  | 3.38M  |     for (; i < stage->last_lookup; i++)  |  1958  | 345k  |     { |  1959  | 345k  |       auto &lookup = lookups[table_index][i];  |  1960  |  |  |  1961  | 345k  |       unsigned int lookup_index = lookup.index;  |  1962  | 345k  |       if (buffer->messaging () &&  |  1963  | 345k  |     !buffer->message (font, "start lookup %u feature '%c%c%c%c'", lookup_index, HB_UNTAG (lookup.feature_tag))) continue;  |  1964  |  |  |  1965  |  |       /* c.digest is a digest of all the current glyphs in the buffer  |  1966  |  |        * (plus some past glyphs).  |  1967  |  |        *  |  1968  |  |        * Only try applying the lookup if there is any overlap. */  |  1969  | 345k  |       if (proxy.accels[lookup_index].digest.may_have (c.digest))  |  1970  | 89.0k  |       { |  1971  | 89.0k  |   c.set_lookup_index (lookup_index);  |  1972  | 89.0k  |   c.set_lookup_mask (lookup.mask);  |  1973  | 89.0k  |   c.set_auto_zwj (lookup.auto_zwj);  |  1974  | 89.0k  |   c.set_auto_zwnj (lookup.auto_zwnj);  |  1975  | 89.0k  |   c.set_random (lookup.random);  |  1976  | 89.0k  |   c.set_per_syllable (lookup.per_syllable);  |  1977  |  |  |  1978  | 89.0k  |   apply_string<Proxy> (&c,  |  1979  | 89.0k  |            proxy.table.get_lookup (lookup_index),  |  1980  | 89.0k  |            proxy.accels[lookup_index]);  |  1981  | 89.0k  |       }  |  1982  | 256k  |       else if (buffer->messaging ())  |  1983  | 0  |   (void) buffer->message (font, "skipped lookup %u feature '%c%c%c%c' because no glyph matches", lookup_index, HB_UNTAG (lookup.feature_tag));  |  1984  |  |  |  1985  | 345k  |       if (buffer->messaging ())  |  1986  | 0  |   (void) buffer->message (font, "end lookup %u feature '%c%c%c%c'", lookup_index, HB_UNTAG (lookup.feature_tag));  |  1987  | 345k  |     }  |  1988  |  |  |  1989  | 3.03M  |     if (stage->pause_func)  |  1990  | 40.7k  |     { |  1991  | 40.7k  |       if (stage->pause_func (plan, font, buffer))  |  1992  | 2.55k  |       { |  1993  |  |   /* Refresh working buffer digest since buffer changed. */  |  1994  | 2.55k  |   c.digest = buffer->digest ();  |  1995  | 2.55k  |       }  |  1996  | 40.7k  |     }  |  1997  | 3.03M  |   }  |  1998  | 1.47M  | }  |  
 void hb_ot_map_t::apply<GPOSProxy>(GPOSProxy const&, hb_ot_shape_plan_t const*, hb_font_t*, hb_buffer_t*) const Line  | Count  | Source  |  1948  | 289k  | { |  1949  | 289k  |   const unsigned int table_index = proxy.table_index;  |  1950  | 289k  |   unsigned int i = 0;  |  1951  | 289k  |   OT::hb_ot_apply_context_t c (table_index, font, buffer);  |  1952  | 289k  |   c.set_recurse_func (Proxy::Lookup::template dispatch_recurse_func<OT::hb_ot_apply_context_t>);  |  1953  |  |  |  1954  | 575k  |   for (unsigned int stage_index = 0; stage_index < stages[table_index].length; stage_index++)  |  1955  | 285k  |   { |  1956  | 285k  |     const stage_map_t *stage = &stages[table_index][stage_index];  |  1957  | 636k  |     for (; i < stage->last_lookup; i++)  |  1958  | 350k  |     { |  1959  | 350k  |       auto &lookup = lookups[table_index][i];  |  1960  |  |  |  1961  | 350k  |       unsigned int lookup_index = lookup.index;  |  1962  | 350k  |       if (buffer->messaging () &&  |  1963  | 350k  |     !buffer->message (font, "start lookup %u feature '%c%c%c%c'", lookup_index, HB_UNTAG (lookup.feature_tag))) continue;  |  1964  |  |  |  1965  |  |       /* c.digest is a digest of all the current glyphs in the buffer  |  1966  |  |        * (plus some past glyphs).  |  1967  |  |        *  |  1968  |  |        * Only try applying the lookup if there is any overlap. */  |  1969  | 350k  |       if (proxy.accels[lookup_index].digest.may_have (c.digest))  |  1970  | 62.3k  |       { |  1971  | 62.3k  |   c.set_lookup_index (lookup_index);  |  1972  | 62.3k  |   c.set_lookup_mask (lookup.mask);  |  1973  | 62.3k  |   c.set_auto_zwj (lookup.auto_zwj);  |  1974  | 62.3k  |   c.set_auto_zwnj (lookup.auto_zwnj);  |  1975  | 62.3k  |   c.set_random (lookup.random);  |  1976  | 62.3k  |   c.set_per_syllable (lookup.per_syllable);  |  1977  |  |  |  1978  | 62.3k  |   apply_string<Proxy> (&c,  |  1979  | 62.3k  |            proxy.table.get_lookup (lookup_index),  |  1980  | 62.3k  |            proxy.accels[lookup_index]);  |  1981  | 62.3k  |       }  |  1982  | 288k  |       else if (buffer->messaging ())  |  1983  | 0  |   (void) buffer->message (font, "skipped lookup %u feature '%c%c%c%c' because no glyph matches", lookup_index, HB_UNTAG (lookup.feature_tag));  |  1984  |  |  |  1985  | 350k  |       if (buffer->messaging ())  |  1986  | 0  |   (void) buffer->message (font, "end lookup %u feature '%c%c%c%c'", lookup_index, HB_UNTAG (lookup.feature_tag));  |  1987  | 350k  |     }  |  1988  |  |  |  1989  | 285k  |     if (stage->pause_func)  |  1990  | 0  |     { |  1991  | 0  |       if (stage->pause_func (plan, font, buffer))  |  1992  | 0  |       { |  1993  |  |   /* Refresh working buffer digest since buffer changed. */  |  1994  | 0  |   c.digest = buffer->digest ();  |  1995  | 0  |       }  |  1996  | 0  |     }  |  1997  | 285k  |   }  |  1998  | 289k  | }  |  
  | 
1999  |  |  | 
2000  |  | void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const  | 
2001  | 1.47M  | { | 
2002  | 1.47M  |   GSUBProxy proxy (font->face);  | 
2003  | 1.47M  |   if (buffer->messaging () &&  | 
2004  | 1.47M  |       !buffer->message (font, "start table GSUB")) return;  | 
2005  | 1.47M  |   apply (proxy, plan, font, buffer);  | 
2006  | 1.47M  |   if (buffer->messaging ())  | 
2007  | 0  |     (void) buffer->message (font, "end table GSUB");  | 
2008  | 1.47M  | }  | 
2009  |  |  | 
2010  |  | void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const  | 
2011  | 289k  | { | 
2012  | 289k  |   GPOSProxy proxy (font->face);  | 
2013  | 289k  |   if (buffer->messaging () &&  | 
2014  | 289k  |       !buffer->message (font, "start table GPOS")) return;  | 
2015  | 289k  |   apply (proxy, plan, font, buffer);  | 
2016  | 289k  |   if (buffer->messaging ())  | 
2017  | 0  |     (void) buffer->message (font, "end table GPOS");  | 
2018  | 289k  | }  | 
2019  |  |  | 
2020  |  | void  | 
2021  |  | hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,  | 
2022  |  |         const OT::SubstLookup &lookup,  | 
2023  |  |         const OT::hb_ot_layout_lookup_accelerator_t &accel)  | 
2024  | 2.32k  | { | 
2025  | 2.32k  |   apply_string<GSUBProxy> (c, lookup, accel);  | 
2026  | 2.32k  | }  | 
2027  |  |  | 
2028  |  | #ifndef HB_NO_BASE  | 
2029  |  | /**  | 
2030  |  |  * hb_ot_layout_get_horizontal_baseline_tag_for_script:  | 
2031  |  |  * @script: a script tag.  | 
2032  |  |  *  | 
2033  |  |  * Fetches the dominant horizontal baseline tag used by @script.  | 
2034  |  |  *  | 
2035  |  |  * Return value: dominant baseline tag for the @script.  | 
2036  |  |  *  | 
2037  |  |  * Since: 4.0.0  | 
2038  |  |  **/  | 
2039  |  | hb_ot_layout_baseline_tag_t  | 
2040  |  | hb_ot_layout_get_horizontal_baseline_tag_for_script (hb_script_t script)  | 
2041  | 0  | { | 
2042  |  |   /* Keep in sync with hb_ot_layout_get_baseline_with_fallback */  | 
2043  | 0  |   switch ((int) script)  | 
2044  | 0  |   { | 
2045  |  |     /* Unicode-1.1 additions */  | 
2046  | 0  |     case HB_SCRIPT_BENGALI:  | 
2047  | 0  |     case HB_SCRIPT_DEVANAGARI:  | 
2048  | 0  |     case HB_SCRIPT_GUJARATI:  | 
2049  | 0  |     case HB_SCRIPT_GURMUKHI:  | 
2050  |  |     /* Unicode-2.0 additions */  | 
2051  | 0  |     case HB_SCRIPT_TIBETAN:  | 
2052  |  |     /* Unicode-4.0 additions */  | 
2053  | 0  |     case HB_SCRIPT_LIMBU:  | 
2054  |  |     /* Unicode-4.1 additions */  | 
2055  | 0  |     case HB_SCRIPT_SYLOTI_NAGRI:  | 
2056  |  |     /* Unicode-5.0 additions */  | 
2057  | 0  |     case HB_SCRIPT_PHAGS_PA:  | 
2058  |  |     /* Unicode-5.2 additions */  | 
2059  | 0  |     case HB_SCRIPT_MEETEI_MAYEK:  | 
2060  |  |     /* Unicode-6.1 additions */  | 
2061  | 0  |     case HB_SCRIPT_SHARADA:  | 
2062  | 0  |     case HB_SCRIPT_TAKRI:  | 
2063  |  |     /* Unicode-7.0 additions */  | 
2064  | 0  |     case HB_SCRIPT_MODI:  | 
2065  | 0  |     case HB_SCRIPT_SIDDHAM:  | 
2066  | 0  |     case HB_SCRIPT_TIRHUTA:  | 
2067  |  |     /* Unicode-9.0 additions */  | 
2068  | 0  |     case HB_SCRIPT_MARCHEN:  | 
2069  | 0  |     case HB_SCRIPT_NEWA:  | 
2070  |  |     /* Unicode-10.0 additions */  | 
2071  | 0  |     case HB_SCRIPT_SOYOMBO:  | 
2072  | 0  |     case HB_SCRIPT_ZANABAZAR_SQUARE:  | 
2073  |  |     /* Unicode-11.0 additions */  | 
2074  | 0  |     case HB_SCRIPT_DOGRA:  | 
2075  | 0  |     case HB_SCRIPT_GUNJALA_GONDI:  | 
2076  |  |     /* Unicode-12.0 additions */  | 
2077  | 0  |     case HB_SCRIPT_NANDINAGARI:  | 
2078  | 0  |       return HB_OT_LAYOUT_BASELINE_TAG_HANGING;  | 
2079  |  |  | 
2080  |  |     /* Unicode-1.1 additions */  | 
2081  | 0  |     case HB_SCRIPT_HANGUL:  | 
2082  | 0  |     case HB_SCRIPT_HAN:  | 
2083  | 0  |     case HB_SCRIPT_HIRAGANA:  | 
2084  | 0  |     case HB_SCRIPT_KATAKANA:  | 
2085  |  |     /* Unicode-3.0 additions */  | 
2086  | 0  |     case HB_SCRIPT_BOPOMOFO:  | 
2087  |  |     /* Unicode-9.0 additions */  | 
2088  | 0  |     case HB_SCRIPT_TANGUT:  | 
2089  |  |     /* Unicode-10.0 additions */  | 
2090  | 0  |     case HB_SCRIPT_NUSHU:  | 
2091  |  |     /* Unicode-13.0 additions */  | 
2092  | 0  |     case HB_SCRIPT_KHITAN_SMALL_SCRIPT:  | 
2093  | 0  |       return HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT;  | 
2094  |  |  | 
2095  | 0  |     default:  | 
2096  | 0  |       return HB_OT_LAYOUT_BASELINE_TAG_ROMAN;  | 
2097  | 0  |   }  | 
2098  | 0  | }  | 
2099  |  |  | 
2100  |  | /**  | 
2101  |  |  * hb_ot_layout_get_baseline:  | 
2102  |  |  * @font: a font  | 
2103  |  |  * @baseline_tag: a baseline tag  | 
2104  |  |  * @direction: text direction.  | 
2105  |  |  * @script_tag:  script tag.  | 
2106  |  |  * @language_tag: language tag, currently unused.  | 
2107  |  |  * @coord: (out) (nullable): baseline value if found.  | 
2108  |  |  *  | 
2109  |  |  * Fetches a baseline value from the face.  | 
2110  |  |  *  | 
2111  |  |  * Return value: `true` if found baseline value in the font.  | 
2112  |  |  *  | 
2113  |  |  * Since: 2.6.0  | 
2114  |  |  **/  | 
2115  |  | hb_bool_t  | 
2116  |  | hb_ot_layout_get_baseline (hb_font_t                   *font,  | 
2117  |  |          hb_ot_layout_baseline_tag_t  baseline_tag,  | 
2118  |  |          hb_direction_t               direction,  | 
2119  |  |          hb_tag_t                     script_tag,  | 
2120  |  |          hb_tag_t                     language_tag,  | 
2121  |  |          hb_position_t               *coord        /* OUT.  May be NULL. */)  | 
2122  | 94.9k  | { | 
2123  | 94.9k  |   return font->face->table.BASE->get_baseline (font, baseline_tag, direction, script_tag, language_tag, coord);  | 
2124  | 94.9k  | }  | 
2125  |  |  | 
2126  |  | /**  | 
2127  |  |  * hb_ot_layout_get_baseline_with_fallback:  | 
2128  |  |  * @font: a font  | 
2129  |  |  * @baseline_tag: a baseline tag  | 
2130  |  |  * @direction: text direction.  | 
2131  |  |  * @script_tag:  script tag.  | 
2132  |  |  * @language_tag: language tag, currently unused.  | 
2133  |  |  * @coord: (out): baseline value if found.  | 
2134  |  |  *  | 
2135  |  |  * Fetches a baseline value from the face, and synthesizes  | 
2136  |  |  * it if the font does not have it.  | 
2137  |  |  *  | 
2138  |  |  * Since: 4.0.0  | 
2139  |  |  **/  | 
2140  |  | void  | 
2141  |  | hb_ot_layout_get_baseline_with_fallback (hb_font_t                   *font,  | 
2142  |  |            hb_ot_layout_baseline_tag_t  baseline_tag,  | 
2143  |  |            hb_direction_t               direction,  | 
2144  |  |            hb_tag_t                     script_tag,  | 
2145  |  |            hb_tag_t                     language_tag,  | 
2146  |  |            hb_position_t               *coord /* OUT */)  | 
2147  | 0  | { | 
2148  | 0  |   if (hb_ot_layout_get_baseline (font,  | 
2149  | 0  |          baseline_tag,  | 
2150  | 0  |          direction,  | 
2151  | 0  |          script_tag,  | 
2152  | 0  |          language_tag,  | 
2153  | 0  |          coord))  | 
2154  | 0  |     return;  | 
2155  |  |  | 
2156  |  |   /* Synthesize missing baselines.  | 
2157  |  |    * See https://www.w3.org/TR/css-inline-3/#baseline-synthesis-fonts  | 
2158  |  |    */  | 
2159  | 0  |   switch (baseline_tag)  | 
2160  | 0  |   { | 
2161  | 0  |   case HB_OT_LAYOUT_BASELINE_TAG_ROMAN:  | 
2162  | 0  |     *coord = 0; // FIXME origin ?  | 
2163  | 0  |     break;  | 
2164  |  |  | 
2165  | 0  |   case HB_OT_LAYOUT_BASELINE_TAG_MATH:  | 
2166  | 0  |     { | 
2167  | 0  |       hb_codepoint_t glyph;  | 
2168  | 0  |       hb_glyph_extents_t extents;  | 
2169  | 0  |       if (HB_DIRECTION_IS_HORIZONTAL (direction) &&  | 
2170  | 0  |     (hb_font_get_nominal_glyph (font, 0x2212u, &glyph) ||  | 
2171  | 0  |      hb_font_get_nominal_glyph (font, '-', &glyph)) &&  | 
2172  | 0  |     hb_font_get_glyph_extents (font, glyph, &extents))  | 
2173  | 0  |       { | 
2174  | 0  |   *coord = extents.y_bearing + extents.height / 2;  | 
2175  | 0  |       }  | 
2176  | 0  |       else  | 
2177  | 0  |       { | 
2178  | 0  |   hb_position_t x_height = font->y_scale / 2;  | 
2179  | 0  | #ifndef HB_NO_METRICS  | 
2180  | 0  |   hb_ot_metrics_get_position_with_fallback (font, HB_OT_METRICS_TAG_X_HEIGHT, &x_height);  | 
2181  | 0  | #endif  | 
2182  | 0  |   *coord = x_height / 2;  | 
2183  | 0  |       }  | 
2184  | 0  |     }  | 
2185  | 0  |     break;  | 
2186  |  |  | 
2187  | 0  |   case HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT:  | 
2188  | 0  |   case HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT:  | 
2189  | 0  |     { | 
2190  | 0  |       hb_position_t embox_top, embox_bottom;  | 
2191  |  | 
  | 
2192  | 0  |       hb_ot_layout_get_baseline_with_fallback (font,  | 
2193  | 0  |                  HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT,  | 
2194  | 0  |                  direction,  | 
2195  | 0  |                  script_tag,  | 
2196  | 0  |                  language_tag,  | 
2197  | 0  |                  &embox_top);  | 
2198  | 0  |       hb_ot_layout_get_baseline_with_fallback (font,  | 
2199  | 0  |                  HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,  | 
2200  | 0  |                  direction,  | 
2201  | 0  |                  script_tag,  | 
2202  | 0  |                  language_tag,  | 
2203  | 0  |                  &embox_bottom);  | 
2204  |  | 
  | 
2205  | 0  |       if (baseline_tag == HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT)  | 
2206  | 0  |   *coord = embox_top + (embox_bottom - embox_top) / 10;  | 
2207  | 0  |       else  | 
2208  | 0  |   *coord = embox_bottom + (embox_top - embox_bottom) / 10;  | 
2209  | 0  |     }  | 
2210  | 0  |     break;  | 
2211  |  |  | 
2212  | 0  |   case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT:  | 
2213  | 0  |     if (hb_ot_layout_get_baseline (font,  | 
2214  | 0  |            HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,  | 
2215  | 0  |            direction,  | 
2216  | 0  |            script_tag,  | 
2217  | 0  |            language_tag,  | 
2218  | 0  |            coord))  | 
2219  | 0  |       *coord += HB_DIRECTION_IS_HORIZONTAL (direction) ? font->y_scale : font->x_scale;  | 
2220  | 0  |     else  | 
2221  | 0  |     { | 
2222  | 0  |       hb_font_extents_t font_extents;  | 
2223  | 0  |       hb_font_get_extents_for_direction (font, direction, &font_extents);  | 
2224  | 0  |       *coord = font_extents.ascender;  | 
2225  | 0  |     }  | 
2226  | 0  |     break;  | 
2227  |  |  | 
2228  | 0  |   case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT:  | 
2229  | 0  |     if (hb_ot_layout_get_baseline (font,  | 
2230  | 0  |            HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT,  | 
2231  | 0  |            direction,  | 
2232  | 0  |            script_tag,  | 
2233  | 0  |            language_tag,  | 
2234  | 0  |            coord))  | 
2235  | 0  |       *coord -= HB_DIRECTION_IS_HORIZONTAL (direction) ? font->y_scale : font->x_scale;  | 
2236  | 0  |     else  | 
2237  | 0  |     { | 
2238  | 0  |       hb_font_extents_t font_extents;  | 
2239  | 0  |       hb_font_get_extents_for_direction (font, direction, &font_extents);  | 
2240  | 0  |       *coord = font_extents.descender;  | 
2241  | 0  |     }  | 
2242  | 0  |     break;  | 
2243  |  |  | 
2244  | 0  |   case HB_OT_LAYOUT_BASELINE_TAG_HANGING:  | 
2245  | 0  |     if (HB_DIRECTION_IS_HORIZONTAL (direction))  | 
2246  | 0  |     { | 
2247  | 0  |       hb_codepoint_t ch;  | 
2248  | 0  |       hb_codepoint_t glyph;  | 
2249  | 0  |       hb_glyph_extents_t extents;  | 
2250  |  |  | 
2251  |  |       /* Keep in sync with hb_ot_layout_get_horizontal_baseline_for_script */  | 
2252  | 0  |       switch ((int) script_tag)  | 
2253  | 0  |       { | 
2254  |  |       /* Unicode-1.1 additions */  | 
2255  | 0  |       case HB_SCRIPT_BENGALI:          ch = 0x0995u; break;  | 
2256  | 0  |       case HB_SCRIPT_DEVANAGARI:       ch = 0x0915u; break;  | 
2257  | 0  |       case HB_SCRIPT_GUJARATI:         ch = 0x0a95u; break;  | 
2258  | 0  |       case HB_SCRIPT_GURMUKHI:         ch = 0x0a15u; break;  | 
2259  |  |       /* Unicode-2.0 additions */  | 
2260  | 0  |       case HB_SCRIPT_TIBETAN:          ch = 0x0f40u; break;  | 
2261  |  |       /* Unicode-4.0 additions */  | 
2262  | 0  |       case HB_SCRIPT_LIMBU:            ch = 0x1901u; break;  | 
2263  |  |       /* Unicode-4.1 additions */  | 
2264  | 0  |       case HB_SCRIPT_SYLOTI_NAGRI:     ch = 0xa807u; break;  | 
2265  |  |       /* Unicode-5.0 additions */  | 
2266  | 0  |       case HB_SCRIPT_PHAGS_PA:         ch = 0xa840u; break;  | 
2267  |  |       /* Unicode-5.2 additions */  | 
2268  | 0  |       case HB_SCRIPT_MEETEI_MAYEK:     ch = 0xabc0u; break;  | 
2269  |  |       /* Unicode-6.1 additions */  | 
2270  | 0  |       case HB_SCRIPT_SHARADA:          ch = 0x11191u; break;  | 
2271  | 0  |       case HB_SCRIPT_TAKRI:            ch = 0x1168cu; break;  | 
2272  |  |       /* Unicode-7.0 additions */  | 
2273  | 0  |       case HB_SCRIPT_MODI:             ch = 0x1160eu;break;  | 
2274  | 0  |       case HB_SCRIPT_SIDDHAM:          ch = 0x11590u; break;  | 
2275  | 0  |       case HB_SCRIPT_TIRHUTA:          ch = 0x1148fu; break;  | 
2276  |  |       /* Unicode-9.0 additions */  | 
2277  | 0  |       case HB_SCRIPT_MARCHEN:          ch = 0x11c72u; break;  | 
2278  | 0  |       case HB_SCRIPT_NEWA:             ch = 0x1140eu; break;  | 
2279  |  |       /* Unicode-10.0 additions */  | 
2280  | 0  |       case HB_SCRIPT_SOYOMBO:          ch = 0x11a5cu; break;  | 
2281  | 0  |       case HB_SCRIPT_ZANABAZAR_SQUARE: ch = 0x11a0bu; break;  | 
2282  |  |       /* Unicode-11.0 additions */  | 
2283  | 0  |       case HB_SCRIPT_DOGRA:            ch = 0x1180au; break;  | 
2284  | 0  |       case HB_SCRIPT_GUNJALA_GONDI:    ch = 0x11d6cu; break;  | 
2285  |  |       /* Unicode-12.0 additions */  | 
2286  | 0  |       case HB_SCRIPT_NANDINAGARI:      ch = 0x119b0u; break;  | 
2287  | 0  |       default:                         ch = 0;        break;  | 
2288  | 0  |       }  | 
2289  |  |  | 
2290  | 0  |       if (ch &&  | 
2291  | 0  |     hb_font_get_nominal_glyph (font, ch, &glyph) &&  | 
2292  | 0  |     hb_font_get_glyph_extents (font, glyph, &extents))  | 
2293  | 0  |   *coord = extents.y_bearing;  | 
2294  | 0  |       else  | 
2295  | 0  |   *coord = font->y_scale * 6 / 10; // FIXME makes assumptions about origin  | 
2296  | 0  |     }  | 
2297  | 0  |     else  | 
2298  | 0  |       *coord = font->x_scale * 6 / 10; // FIXME makes assumptions about origin  | 
2299  | 0  |     break;  | 
2300  |  |  | 
2301  | 0  |   case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_CENTRAL:  | 
2302  | 0  |     { | 
2303  | 0  |       hb_position_t top, bottom;  | 
2304  | 0  |       hb_ot_layout_get_baseline_with_fallback (font,  | 
2305  | 0  |                  HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT,  | 
2306  | 0  |                  direction,  | 
2307  | 0  |                  script_tag,  | 
2308  | 0  |                  language_tag,  | 
2309  | 0  |                  &top);  | 
2310  | 0  |       hb_ot_layout_get_baseline_with_fallback (font,  | 
2311  | 0  |                  HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,  | 
2312  | 0  |                  direction,  | 
2313  | 0  |                  script_tag,  | 
2314  | 0  |                  language_tag,  | 
2315  | 0  |                  &bottom);  | 
2316  | 0  |       *coord = (top + bottom) / 2;  | 
2317  |  | 
  | 
2318  | 0  |     }  | 
2319  | 0  |     break;  | 
2320  |  |  | 
2321  | 0  |   case HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_CENTRAL:  | 
2322  | 0  |     { | 
2323  | 0  |       hb_position_t top, bottom;  | 
2324  | 0  |       hb_ot_layout_get_baseline_with_fallback (font,  | 
2325  | 0  |                  HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT,  | 
2326  | 0  |                  direction,  | 
2327  | 0  |                  script_tag,  | 
2328  | 0  |                  language_tag,  | 
2329  | 0  |                  &top);  | 
2330  | 0  |       hb_ot_layout_get_baseline_with_fallback (font,  | 
2331  | 0  |                  HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT,  | 
2332  | 0  |                  direction,  | 
2333  | 0  |                  script_tag,  | 
2334  | 0  |                  language_tag,  | 
2335  | 0  |                  &bottom);  | 
2336  | 0  |       *coord = (top + bottom) / 2;  | 
2337  |  | 
  | 
2338  | 0  |     }  | 
2339  | 0  |     break;  | 
2340  |  |  | 
2341  | 0  |   case _HB_OT_LAYOUT_BASELINE_TAG_MAX_VALUE:  | 
2342  | 0  |   default:  | 
2343  | 0  |     *coord = 0;  | 
2344  | 0  |     break;  | 
2345  | 0  |   }  | 
2346  | 0  | }  | 
2347  |  |  | 
2348  |  | #endif  | 
2349  |  |  | 
2350  |  |  | 
2351  |  | struct hb_get_glyph_alternates_dispatch_t :  | 
2352  |  |        hb_dispatch_context_t<hb_get_glyph_alternates_dispatch_t, unsigned>  | 
2353  |  | { | 
2354  | 0  |   static return_t default_return_value () { return 0; } | 
2355  | 0  |   bool stop_sublookup_iteration (return_t r) const { return r; } | 
2356  |  |  | 
2357  |  |   private:  | 
2358  |  |   template <typename T, typename ...Ts> auto  | 
2359  |  |   _dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN  | 
2360  |  |   ( obj.get_glyph_alternates (std::forward<Ts> (ds)...) )  | 
2361  |  |   template <typename T, typename ...Ts> auto  | 
2362  |  |   _dispatch (const T &obj, hb_priority<0>, Ts&&... ds) HB_AUTO_RETURN  | 
2363  |  |   ( default_return_value () )  | 
2364  |  |   public:  | 
2365  |  |   template <typename T, typename ...Ts> auto  | 
2366  |  |   dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN  | 
2367  |  |   ( _dispatch (obj, hb_prioritize, std::forward<Ts> (ds)...) )  | 
2368  |  | };  | 
2369  |  |  | 
2370  |  | #ifndef HB_NO_LAYOUT_RARELY_USED  | 
2371  |  | /**  | 
2372  |  |  * hb_ot_layout_lookup_get_glyph_alternates:  | 
2373  |  |  * @face: a face.  | 
2374  |  |  * @lookup_index: index of the feature lookup to query.  | 
2375  |  |  * @glyph: a glyph id.  | 
2376  |  |  * @start_offset: starting offset.  | 
2377  |  |  * @alternate_count: (inout) (optional): Input = the maximum number of alternate glyphs to return;  | 
2378  |  |  *                   Output = the actual number of alternate glyphs returned (may be zero).  | 
2379  |  |  * @alternate_glyphs: (out caller-allocates) (array length=alternate_count): A glyphs buffer.  | 
2380  |  |  *                    Alternate glyphs associated with the glyph id.  | 
2381  |  |  *  | 
2382  |  |  * Fetches alternates of a glyph from a given GSUB lookup index.  | 
2383  |  |  *  | 
2384  |  |  * Return value: Total number of alternates found in the specific lookup index for the given glyph id.  | 
2385  |  |  *  | 
2386  |  |  * Since: 2.6.8  | 
2387  |  |  **/  | 
2388  |  | HB_EXTERN unsigned  | 
2389  |  | hb_ot_layout_lookup_get_glyph_alternates (hb_face_t      *face,  | 
2390  |  |             unsigned        lookup_index,  | 
2391  |  |             hb_codepoint_t  glyph,  | 
2392  |  |             unsigned        start_offset,  | 
2393  |  |             unsigned       *alternate_count  /* IN/OUT.  May be NULL. */,  | 
2394  |  |             hb_codepoint_t *alternate_glyphs /* OUT.     May be NULL. */)  | 
2395  | 0  | { | 
2396  | 0  |   hb_get_glyph_alternates_dispatch_t c;  | 
2397  | 0  |   const OT::SubstLookup &lookup = face->table.GSUB->table->get_lookup (lookup_index);  | 
2398  | 0  |   auto ret = lookup.dispatch (&c, glyph, start_offset, alternate_count, alternate_glyphs);  | 
2399  | 0  |   if (!ret && alternate_count) *alternate_count = 0;  | 
2400  | 0  |   return ret;  | 
2401  | 0  | }  | 
2402  |  |  | 
2403  |  |  | 
2404  |  | struct hb_position_single_dispatch_t :  | 
2405  |  |        hb_dispatch_context_t<hb_position_single_dispatch_t, bool>  | 
2406  |  | { | 
2407  | 0  |   static return_t default_return_value () { return false; } | 
2408  | 0  |   bool stop_sublookup_iteration (return_t r) const { return r; } | 
2409  |  |  | 
2410  |  |   private:  | 
2411  |  |   template <typename T, typename ...Ts> auto  | 
2412  |  |   _dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN  | 
2413  |  |   ( obj.position_single (std::forward<Ts> (ds)...) )  | 
2414  |  |   template <typename T, typename ...Ts> auto  | 
2415  |  |   _dispatch (const T &obj, hb_priority<0>, Ts&&... ds) HB_AUTO_RETURN  | 
2416  |  |   ( default_return_value () )  | 
2417  |  |   public:  | 
2418  |  |   template <typename T, typename ...Ts> auto  | 
2419  |  |   dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN  | 
2420  |  |   ( _dispatch (obj, hb_prioritize, std::forward<Ts> (ds)...) )  | 
2421  |  | };  | 
2422  |  |  | 
2423  |  | /**  | 
2424  |  |  * hb_ot_layout_lookup_get_optical_bound:  | 
2425  |  |  * @font: a font.  | 
2426  |  |  * @lookup_index: index of the feature lookup to query.  | 
2427  |  |  * @direction: edge of the glyph to query.  | 
2428  |  |  * @glyph: a glyph id.  | 
2429  |  |  *  | 
2430  |  |  * Fetches the optical bound of a glyph positioned at the margin of text.  | 
2431  |  |  * The direction identifies which edge of the glyph to query.  | 
2432  |  |  *  | 
2433  |  |  * Return value: Adjustment value. Negative values mean the glyph will stick out of the margin.  | 
2434  |  |  *  | 
2435  |  |  * Since: 5.3.0  | 
2436  |  |  **/  | 
2437  |  | hb_position_t  | 
2438  |  | hb_ot_layout_lookup_get_optical_bound (hb_font_t      *font,  | 
2439  |  |                unsigned        lookup_index,  | 
2440  |  |                hb_direction_t  direction,  | 
2441  |  |                hb_codepoint_t  glyph)  | 
2442  | 0  | { | 
2443  | 0  |   const OT::PosLookup &lookup = font->face->table.GPOS->table->get_lookup (lookup_index);  | 
2444  | 0  |   hb_glyph_position_t pos = {0}; | 
2445  | 0  |   hb_position_single_dispatch_t c;  | 
2446  | 0  |   lookup.dispatch (&c, font, direction, glyph, pos);  | 
2447  | 0  |   hb_position_t ret = 0;  | 
2448  | 0  |   switch (direction)  | 
2449  | 0  |   { | 
2450  | 0  |     case HB_DIRECTION_LTR:  | 
2451  | 0  |       ret = pos.x_offset;  | 
2452  | 0  |       break;  | 
2453  | 0  |     case HB_DIRECTION_RTL:  | 
2454  | 0  |       ret = pos.x_advance - pos.x_offset;  | 
2455  | 0  |       break;  | 
2456  | 0  |     case HB_DIRECTION_TTB:  | 
2457  | 0  |       ret = pos.y_offset;  | 
2458  | 0  |       break;  | 
2459  | 0  |     case HB_DIRECTION_BTT:  | 
2460  | 0  |       ret = pos.y_advance - pos.y_offset;  | 
2461  | 0  |       break;  | 
2462  | 0  |     case HB_DIRECTION_INVALID:  | 
2463  | 0  |     default:  | 
2464  | 0  |       break;  | 
2465  | 0  |   }  | 
2466  | 0  |   return ret;  | 
2467  | 0  | }  | 
2468  |  | #endif  | 
2469  |  |  | 
2470  |  |  | 
2471  |  | #endif  |