blob: 5accbcf086261ca2add3510a16543c76a0fb30ab [file] [log] [blame]
Behdad Esfahbodfd92a3d2008-01-24 03:11:09 -05001/*
Behdad Esfahbod2409d5f2011-04-21 17:14:28 -04002 * Copyright © 1998-2004 David Turner and Werner Lemberg
3 * Copyright © 2006 Behdad Esfahbod
4 * Copyright © 2007,2008,2009 Red Hat, Inc.
Behdad Esfahbodf8603662012-07-30 02:38:39 -04005 * Copyright © 2012 Google, Inc.
Behdad Esfahbodfd92a3d2008-01-24 03:11:09 -05006 *
Behdad Esfahbodc755cb32010-04-22 00:11:43 -04007 * This is part of HarfBuzz, a text shaping library.
Behdad Esfahbodfd92a3d2008-01-24 03:11:09 -05008 *
9 * Permission is hereby granted, without written agreement and without
10 * license or royalty fees, to use, copy, modify, and distribute this
11 * software and its documentation for any purpose, provided that the
12 * above copyright notice and the following two paragraphs appear in
13 * all copies of this software.
14 *
15 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
16 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
17 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
18 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
19 * DAMAGE.
20 *
21 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
22 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
23 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
24 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
25 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
26 *
27 * Red Hat Author(s): Behdad Esfahbod
Behdad Esfahbodf8603662012-07-30 02:38:39 -040028 * Google Author(s): Behdad Esfahbod
Behdad Esfahbodfd92a3d2008-01-24 03:11:09 -050029 */
30
Behdad Esfahbod22da7fd2010-05-12 18:23:21 -040031#include "hb-ot-layout-private.hh"
Behdad Esfahbodfd92a3d2008-01-24 03:11:09 -050032
Behdad Esfahbod7a750ac2011-08-17 14:19:59 +020033#include "hb-ot-layout-gdef-table.hh"
34#include "hb-ot-layout-gsub-table.hh"
35#include "hb-ot-layout-gpos-table.hh"
36#include "hb-ot-maxp-table.hh"
Behdad Esfahbodfd92a3d2008-01-24 03:11:09 -050037
38#include <stdlib.h>
Behdad Esfahbodaff831e2008-01-24 06:03:45 -050039#include <string.h>
40
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -040041
Behdad Esfahbodcfe98822012-07-27 03:06:30 -040042HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
Behdad Esfahbod11f4c872012-07-30 02:36:46 -040043
Behdad Esfahbod0a4399c2010-05-19 15:45:06 -040044hb_ot_layout_t *
Behdad Esfahbod266b3442011-05-03 00:35:53 -040045_hb_ot_layout_create (hb_face_t *face)
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -050046{
Behdad Esfahbod0a4399c2010-05-19 15:45:06 -040047 hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
Behdad Esfahbod3dcbdc22012-07-30 19:31:17 -040048 if (unlikely (!layout))
49 return NULL;
Behdad Esfahbod555d1122010-01-26 12:58:59 -050050
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -040051 layout->gdef_blob = OT::Sanitizer<OT::GDEF>::sanitize (face->reference_table (HB_OT_TAG_GDEF));
52 layout->gdef = OT::Sanitizer<OT::GDEF>::lock_instance (layout->gdef_blob);
Behdad Esfahbod70e0f2a2009-08-03 22:01:47 -040053
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -040054 layout->gsub_blob = OT::Sanitizer<OT::GSUB>::sanitize (face->reference_table (HB_OT_TAG_GSUB));
55 layout->gsub = OT::Sanitizer<OT::GSUB>::lock_instance (layout->gsub_blob);
Behdad Esfahbod70e0f2a2009-08-03 22:01:47 -040056
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -040057 layout->gpos_blob = OT::Sanitizer<OT::GPOS>::sanitize (face->reference_table (HB_OT_TAG_GPOS));
58 layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob);
Behdad Esfahbod0a4399c2010-05-19 15:45:06 -040059
Behdad Esfahbod6f761132012-08-02 04:00:31 -040060 layout->gsub_lookup_count = layout->gsub->get_lookup_count ();
61 layout->gpos_lookup_count = layout->gpos->get_lookup_count ();
62
Behdad Esfahbod1336ecd2012-08-01 21:46:36 -040063 layout->gsub_digests = (hb_set_digest_t *) calloc (layout->gsub->get_lookup_count (), sizeof (hb_set_digest_t));
64 layout->gpos_digests = (hb_set_digest_t *) calloc (layout->gpos->get_lookup_count (), sizeof (hb_set_digest_t));
65
Behdad Esfahbod6f761132012-08-02 04:00:31 -040066 if (unlikely ((layout->gsub_lookup_count && !layout->gsub_digests) ||
67 (layout->gpos_lookup_count && !layout->gpos_digests)))
Behdad Esfahbod1336ecd2012-08-01 21:46:36 -040068 {
69 _hb_ot_layout_destroy (layout);
70 return NULL;
71 }
72
Behdad Esfahbod6f761132012-08-02 04:00:31 -040073 for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
Behdad Esfahbod1336ecd2012-08-01 21:46:36 -040074 layout->gsub->add_coverage (&layout->gsub_digests[i], i);
Behdad Esfahbod6f761132012-08-02 04:00:31 -040075 for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
Behdad Esfahbod1336ecd2012-08-01 21:46:36 -040076 layout->gpos->add_coverage (&layout->gpos_digests[i], i);
77
Behdad Esfahbod0a4399c2010-05-19 15:45:06 -040078 return layout;
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -050079}
80
Behdad Esfahbodfd92a3d2008-01-24 03:11:09 -050081void
Behdad Esfahbod266b3442011-05-03 00:35:53 -040082_hb_ot_layout_destroy (hb_ot_layout_t *layout)
Behdad Esfahbodfd92a3d2008-01-24 03:11:09 -050083{
Behdad Esfahbod70e0f2a2009-08-03 22:01:47 -040084 hb_blob_destroy (layout->gdef_blob);
85 hb_blob_destroy (layout->gsub_blob);
86 hb_blob_destroy (layout->gpos_blob);
Behdad Esfahbod679f41f2009-08-04 21:32:06 -040087
Behdad Esfahbod1336ecd2012-08-01 21:46:36 -040088 free (layout->gsub_digests);
89 free (layout->gpos_digests);
90
Behdad Esfahbod9ea73682010-09-22 17:38:44 -040091 free (layout);
Behdad Esfahbod2ebb89d2009-07-25 19:09:01 -040092}
93
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -040094static inline const OT::GDEF&
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -040095_get_gdef (hb_face_t *face)
96{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -040097 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GDEF);
Behdad Esfahbodea278d32012-07-27 02:12:28 -040098 return *hb_ot_layout_from_face (face)->gdef;
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -040099}
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400100static inline const OT::GSUB&
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -0400101_get_gsub (hb_face_t *face)
102{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400103 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GSUB);
Behdad Esfahbodea278d32012-07-27 02:12:28 -0400104 return *hb_ot_layout_from_face (face)->gsub;
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -0400105}
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400106static inline const OT::GPOS&
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -0400107_get_gpos (hb_face_t *face)
108{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400109 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GPOS);
Behdad Esfahbodea278d32012-07-27 02:12:28 -0400110 return *hb_ot_layout_from_face (face)->gpos;
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -0400111}
112
113
Behdad Esfahbod590d55c2008-01-24 19:13:50 -0500114/*
115 * GDEF
116 */
117
118hb_bool_t
Behdad Esfahbod52ea4772009-11-06 17:45:38 -0500119hb_ot_layout_has_glyph_classes (hb_face_t *face)
Behdad Esfahbod590d55c2008-01-24 19:13:50 -0500120{
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -0400121 return _get_gdef (face).has_glyph_classes ();
Behdad Esfahbod590d55c2008-01-24 19:13:50 -0500122}
123
Behdad Esfahbod5a08ecf2012-11-16 13:34:29 -0800124hb_ot_layout_glyph_class_t
125hb_ot_layout_get_glyph_class (hb_face_t *face,
126 hb_codepoint_t glyph)
127{
128 return (hb_ot_layout_glyph_class_t) _get_gdef (face).get_glyph_class (glyph);
129}
Behdad Esfahbod4a2d8442010-11-03 15:28:56 -0400130
Behdad Esfahbod89ca8ee2012-11-16 13:53:40 -0800131void
132hb_ot_layout_get_glyphs_in_class (hb_face_t *face,
133 hb_ot_layout_glyph_class_t klass,
134 hb_set_t *glyphs /* OUT */)
135{
136 return _get_gdef (face).get_glyphs_in_class (klass, glyphs);
137}
138
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500139unsigned int
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400140hb_ot_layout_get_attach_points (hb_face_t *face,
Behdad Esfahbod79420ad2009-05-26 12:24:16 -0400141 hb_codepoint_t glyph,
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500142 unsigned int start_offset,
Behdad Esfahbod79420ad2009-05-26 12:24:16 -0400143 unsigned int *point_count /* IN/OUT */,
144 unsigned int *point_array /* OUT */)
145{
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500146 return _get_gdef (face).get_attach_points (glyph, start_offset, point_count, point_array);
Behdad Esfahbod62964af2009-05-26 12:40:10 -0400147}
148
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500149unsigned int
Behdad Esfahbode2046742010-10-27 12:32:02 -0400150hb_ot_layout_get_ligature_carets (hb_font_t *font,
Behdad Esfahbode2046742010-10-27 12:32:02 -0400151 hb_direction_t direction,
152 hb_codepoint_t glyph,
153 unsigned int start_offset,
154 unsigned int *caret_count /* IN/OUT */,
155 int *caret_array /* OUT */)
Behdad Esfahbod62964af2009-05-26 12:40:10 -0400156{
Behdad Esfahbodabcfe9b2011-05-11 00:02:02 -0400157 return _get_gdef (font->face).get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);
Behdad Esfahbod79420ad2009-05-26 12:24:16 -0400158}
159
Behdad Esfahbod05bd1b62012-07-30 19:30:01 -0400160
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500161/*
162 * GSUB/GPOS
163 */
164
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400165static const OT::GSUBGPOS&
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -0400166get_gsubgpos_table (hb_face_t *face,
167 hb_tag_t table_tag)
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500168{
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400169 switch (table_tag) {
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -0400170 case HB_OT_TAG_GSUB: return _get_gsub (face);
171 case HB_OT_TAG_GPOS: return _get_gpos (face);
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400172 default: return OT::Null(OT::GSUBGPOS);
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500173 }
174}
175
176
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500177unsigned int
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400178hb_ot_layout_table_get_script_tags (hb_face_t *face,
179 hb_tag_t table_tag,
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500180 unsigned int start_offset,
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400181 unsigned int *script_count /* IN/OUT */,
182 hb_tag_t *script_tags /* OUT */)
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500183{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400184 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500185
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500186 return g.get_script_tags (start_offset, script_count, script_tags);
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500187}
188
189hb_bool_t
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400190hb_ot_layout_table_find_script (hb_face_t *face,
191 hb_tag_t table_tag,
192 hb_tag_t script_tag,
193 unsigned int *script_index)
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500194{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400195 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
196 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500197
198 if (g.find_script_index (script_tag, script_index))
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400199 return true;
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500200
201 /* try finding 'DFLT' */
Behdad Esfahbod8a3511a2009-11-04 19:45:39 -0500202 if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index))
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400203 return false;
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500204
Behdad Esfahboddca8aff2010-09-28 16:25:23 -0400205 /* try with 'dflt'; MS site has had typos and many fonts use it now :(.
206 * including many versions of DejaVu Sans Mono! */
Behdad Esfahbod8a3511a2009-11-04 19:45:39 -0500207 if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index))
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400208 return false;
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500209
210 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400211 return false;
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500212}
213
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100214hb_bool_t
215hb_ot_layout_table_choose_script (hb_face_t *face,
216 hb_tag_t table_tag,
217 const hb_tag_t *script_tags,
Behdad Esfahbodc47a31f2011-07-30 20:57:01 -0400218 unsigned int *script_index,
219 hb_tag_t *chosen_script)
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100220{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400221 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
222 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100223
224 while (*script_tags)
225 {
Behdad Esfahbodc47a31f2011-07-30 20:57:01 -0400226 if (g.find_script_index (*script_tags, script_index)) {
227 if (chosen_script)
228 *chosen_script = *script_tags;
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400229 return true;
Behdad Esfahbodc47a31f2011-07-30 20:57:01 -0400230 }
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100231 script_tags++;
232 }
233
234 /* try finding 'DFLT' */
Behdad Esfahbodc47a31f2011-07-30 20:57:01 -0400235 if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) {
236 if (chosen_script)
237 *chosen_script = HB_OT_TAG_DEFAULT_SCRIPT;
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400238 return false;
Behdad Esfahbodc47a31f2011-07-30 20:57:01 -0400239 }
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100240
241 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
Behdad Esfahbodc47a31f2011-07-30 20:57:01 -0400242 if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) {
243 if (chosen_script)
244 *chosen_script = HB_OT_TAG_DEFAULT_LANGUAGE;
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400245 return false;
Behdad Esfahbodc47a31f2011-07-30 20:57:01 -0400246 }
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100247
Behdad Esfahbod71632c92012-01-22 15:31:44 -0500248 /* try with 'latn'; some old fonts put their features there even though
249 they're really trying to support Thai, for example :( */
250#define HB_OT_TAG_LATIN_SCRIPT HB_TAG ('l', 'a', 't', 'n')
251 if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index)) {
252 if (chosen_script)
253 *chosen_script = HB_OT_TAG_LATIN_SCRIPT;
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400254 return false;
Behdad Esfahbod71632c92012-01-22 15:31:44 -0500255 }
256
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100257 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
Behdad Esfahbodc47a31f2011-07-30 20:57:01 -0400258 if (chosen_script)
259 *chosen_script = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400260 return false;
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100261}
262
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500263unsigned int
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400264hb_ot_layout_table_get_feature_tags (hb_face_t *face,
265 hb_tag_t table_tag,
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500266 unsigned int start_offset,
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400267 unsigned int *feature_count /* IN/OUT */,
268 hb_tag_t *feature_tags /* OUT */)
Behdad Esfahbodc4473352008-02-18 21:14:23 -0500269{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400270 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
Behdad Esfahbodc4473352008-02-18 21:14:23 -0500271
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500272 return g.get_feature_tags (start_offset, feature_count, feature_tags);
Behdad Esfahbodc4473352008-02-18 21:14:23 -0500273}
274
Behdad Esfahbodc4473352008-02-18 21:14:23 -0500275
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500276unsigned int
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400277hb_ot_layout_script_get_language_tags (hb_face_t *face,
278 hb_tag_t table_tag,
279 unsigned int script_index,
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500280 unsigned int start_offset,
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400281 unsigned int *language_count /* IN/OUT */,
282 hb_tag_t *language_tags /* OUT */)
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500283{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400284 const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500285
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500286 return s.get_lang_sys_tags (start_offset, language_count, language_tags);
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500287}
288
289hb_bool_t
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400290hb_ot_layout_script_find_language (hb_face_t *face,
291 hb_tag_t table_tag,
292 unsigned int script_index,
293 hb_tag_t language_tag,
294 unsigned int *language_index)
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500295{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400296 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
297 const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500298
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500299 if (s.find_lang_sys_index (language_tag, language_index))
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400300 return true;
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500301
302 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
Behdad Esfahbod8a3511a2009-11-04 19:45:39 -0500303 if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index))
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400304 return false;
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500305
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500306 if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400307 return false;
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500308}
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500309
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500310hb_bool_t
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400311hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
312 hb_tag_t table_tag,
313 unsigned int script_index,
314 unsigned int language_index,
315 unsigned int *feature_index)
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500316{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400317 const OT::LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index);
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500318
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500319 if (feature_index) *feature_index = l.get_required_feature_index ();
320
321 return l.has_required_feature ();
322}
323
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500324unsigned int
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400325hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
326 hb_tag_t table_tag,
327 unsigned int script_index,
328 unsigned int language_index,
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500329 unsigned int start_offset,
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400330 unsigned int *feature_count /* IN/OUT */,
331 unsigned int *feature_indexes /* OUT */)
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500332{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400333 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
334 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500335
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500336 return l.get_feature_indexes (start_offset, feature_count, feature_indexes);
Behdad Esfahbodc4473352008-02-18 21:14:23 -0500337}
338
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500339unsigned int
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400340hb_ot_layout_language_get_feature_tags (hb_face_t *face,
341 hb_tag_t table_tag,
342 unsigned int script_index,
343 unsigned int language_index,
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500344 unsigned int start_offset,
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400345 unsigned int *feature_count /* IN/OUT */,
346 hb_tag_t *feature_tags /* OUT */)
Behdad Esfahbodc4473352008-02-18 21:14:23 -0500347{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400348 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
349 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500350
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400351 ASSERT_STATIC (sizeof (unsigned int) == sizeof (hb_tag_t));
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500352 unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags);
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400353
Behdad Esfahbod98977492009-08-27 01:32:17 -0400354 if (feature_tags) {
355 unsigned int count = *feature_count;
356 for (unsigned int i = 0; i < count; i++)
357 feature_tags[i] = g.get_feature_tag ((unsigned int) feature_tags[i]);
358 }
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400359
360 return ret;
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500361}
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500362
363
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500364hb_bool_t
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400365hb_ot_layout_language_find_feature (hb_face_t *face,
366 hb_tag_t table_tag,
367 unsigned int script_index,
368 unsigned int language_index,
369 hb_tag_t feature_tag,
370 unsigned int *feature_index)
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500371{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400372 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
373 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
374 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500375
Behdad Esfahbodf4c95142009-05-17 04:59:56 -0400376 unsigned int num_features = l.get_feature_count ();
377 for (unsigned int i = 0; i < num_features; i++) {
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500378 unsigned int f_index = l.get_feature_index (i);
379
380 if (feature_tag == g.get_feature_tag (f_index)) {
381 if (feature_index) *feature_index = f_index;
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400382 return true;
Behdad Esfahbod4a26ea42008-01-28 07:40:10 -0500383 }
384 }
385
386 if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400387 return false;
Behdad Esfahbod706ab252008-01-28 05:58:50 -0500388}
Behdad Esfahbodc4473352008-02-18 21:14:23 -0500389
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500390unsigned int
Behdad Esfahbodf3064102012-11-15 18:39:46 -0800391hb_ot_layout_feature_get_lookups (hb_face_t *face,
392 hb_tag_t table_tag,
393 unsigned int feature_index,
394 unsigned int start_offset,
395 unsigned int *lookup_count /* IN/OUT */,
396 unsigned int *lookup_indexes /* OUT */)
Behdad Esfahbodc4473352008-02-18 21:14:23 -0500397{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400398 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
399 const OT::Feature &f = g.get_feature (feature_index);
Behdad Esfahbodc4473352008-02-18 21:14:23 -0500400
Behdad Esfahbode21899b2009-11-04 16:36:14 -0500401 return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
Behdad Esfahbodc4473352008-02-18 21:14:23 -0500402}
403
Behdad Esfahboda88e7162012-11-24 02:31:02 -0500404static void
405_hb_ot_layout_collect_lookups_lookups (hb_face_t *face,
406 hb_tag_t table_tag,
407 unsigned int feature_index,
408 hb_set_t *lookup_indexes /* OUT */)
409{
410 unsigned int lookup_indices[32];
411 unsigned int offset, len;
412
413 offset = 0;
414 do {
415 len = ARRAY_LENGTH (lookup_indices);
416 hb_ot_layout_feature_get_lookups (face,
417 table_tag,
418 feature_index,
419 offset, &len,
420 lookup_indices);
421
422 for (unsigned int i = 0; i < len; i++)
423 lookup_indexes->add (lookup_indices[i]);
424
425 offset += len;
426 } while (len == ARRAY_LENGTH (lookup_indices));
427}
428
429static void
430_hb_ot_layout_collect_lookups_features (hb_face_t *face,
431 hb_tag_t table_tag,
432 unsigned int script_index,
433 unsigned int language_index,
434 const hb_tag_t *features,
435 hb_set_t *lookup_indexes /* OUT */)
436{
437 if (!features)
438 {
439 /* All features */
440 unsigned int count = hb_ot_layout_language_get_feature_tags (face, table_tag, script_index, language_index, 0, NULL, NULL);
441 for (unsigned int feature_index = 0; feature_index < count; feature_index++)
442 _hb_ot_layout_collect_lookups_lookups (face, table_tag, feature_index, lookup_indexes);
443 } else {
444 for (; *features; features++)
445 {
446 unsigned int feature_index;
447 if (hb_ot_layout_language_find_feature (face, table_tag, script_index, language_index, *features, &feature_index))
448 _hb_ot_layout_collect_lookups_lookups (face, table_tag, feature_index, lookup_indexes);
449 }
450 }
451}
452
453static void
454_hb_ot_layout_collect_lookups_languages (hb_face_t *face,
455 hb_tag_t table_tag,
456 unsigned int script_index,
457 const hb_tag_t *languages,
458 const hb_tag_t *features,
459 hb_set_t *lookup_indexes /* OUT */)
460{
461 if (!languages)
462 {
463 /* All languages */
464 unsigned int count = hb_ot_layout_script_get_language_tags (face, table_tag, script_index, 0, NULL, NULL);
465 for (unsigned int language_index = 0; language_index < count; language_index++)
466 _hb_ot_layout_collect_lookups_features (face, table_tag, script_index, language_index, features, lookup_indexes);
467 } else {
468 for (; *languages; languages++)
469 {
470 unsigned int language_index;
471 if (hb_ot_layout_script_find_language (face, table_tag, script_index, *languages, &language_index))
472 _hb_ot_layout_collect_lookups_features (face, table_tag, script_index, language_index, features, lookup_indexes);
473 }
474 }
475}
476
477void
478hb_ot_layout_collect_lookups (hb_face_t *face,
479 hb_tag_t table_tag,
480 const hb_tag_t *scripts,
481 const hb_tag_t *languages,
482 const hb_tag_t *features,
483 hb_set_t *lookup_indexes /* OUT */)
484{
485 if (!scripts)
486 {
487 /* All scripts */
488 unsigned int count = hb_ot_layout_table_get_script_tags (face, table_tag, 0, NULL, NULL);
489 for (unsigned int script_index = 0; script_index < count; script_index++)
490 _hb_ot_layout_collect_lookups_languages (face, table_tag, script_index, languages, features, lookup_indexes);
491 } else {
492 for (; *scripts; scripts++)
493 {
494 unsigned int script_index;
495 if (hb_ot_layout_table_find_script (face, table_tag, *scripts, &script_index))
496 _hb_ot_layout_collect_lookups_languages (face, table_tag, script_index, languages, features, lookup_indexes);
497 }
498 }
499}
500
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800501void
502hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
503 hb_tag_t table_tag,
504 unsigned int lookup_index,
505 hb_set_t *glyphs_before, /* OUT. May be NULL */
506 hb_set_t *glyphs_input, /* OUT. May be NULL */
507 hb_set_t *glyphs_after, /* OUT. May be NULL */
508 hb_set_t *glyphs_output /* OUT. May be NULL */)
509{
510 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
511
Behdad Esfahbodcdd756b2012-11-24 01:38:41 -0500512 OT::hb_collect_glyphs_context_t c (face, glyphs_before, glyphs_input, glyphs_after, glyphs_output);
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800513
514 switch (table_tag) {
515 case HB_OT_TAG_GSUB:
516 {
Behdad Esfahbodcdd756b2012-11-24 01:38:41 -0500517 const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
518 l.collect_glyphs_lookup (&c);
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800519 return;
520 }
521 case HB_OT_TAG_GPOS:
522 {
Behdad Esfahbodcdd756b2012-11-24 01:38:41 -0500523 const OT::PosLookup& l = hb_ot_layout_from_face (face)->gpos->get_lookup (lookup_index);
524 l.collect_glyphs_lookup (&c);
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800525 return;
526 }
527 }
528}
529
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400530
531/*
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400532 * OT::GSUB
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400533 */
534
535hb_bool_t
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400536hb_ot_layout_has_substitution (hb_face_t *face)
537{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400538 return &_get_gsub (face) != &OT::Null(OT::GSUB);
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400539}
540
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400541hb_bool_t
Behdad Esfahbod362a9902012-11-15 14:57:31 -0800542hb_ot_layout_lookup_would_substitute (hb_face_t *face,
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -0400543 unsigned int lookup_index,
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400544 const hb_codepoint_t *glyphs,
545 unsigned int glyphs_length,
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -0400546 hb_bool_t zero_context)
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400547{
Behdad Esfahbod6f761132012-08-02 04:00:31 -0400548 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return false;
Behdad Esfahbod362a9902012-11-15 14:57:31 -0800549 return hb_ot_layout_lookup_would_substitute_fast (face, lookup_index, glyphs, glyphs_length, zero_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400550}
551
Behdad Esfahbodf8603662012-07-30 02:38:39 -0400552hb_bool_t
Behdad Esfahbod362a9902012-11-15 14:57:31 -0800553hb_ot_layout_lookup_would_substitute_fast (hb_face_t *face,
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -0400554 unsigned int lookup_index,
Behdad Esfahbodf8603662012-07-30 02:38:39 -0400555 const hb_codepoint_t *glyphs,
556 unsigned int glyphs_length,
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -0400557 hb_bool_t zero_context)
Behdad Esfahbodf8603662012-07-30 02:38:39 -0400558{
Behdad Esfahbod6f761132012-08-02 04:00:31 -0400559 if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false;
Behdad Esfahbod2bd9fe32012-09-04 15:15:19 -0400560 OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, zero_context);
561
562 const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
563
564 return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_digests[lookup_index]);
Behdad Esfahbodf8603662012-07-30 02:38:39 -0400565}
566
Behdad Esfahbod46d6a212011-05-11 22:33:13 -0400567void
Behdad Esfahbodafbcc242012-08-02 08:36:40 -0400568hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer)
Behdad Esfahbod46d6a212011-05-11 22:33:13 -0400569{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400570 OT::GSUB::substitute_start (font, buffer);
Behdad Esfahbod46d6a212011-05-11 22:33:13 -0400571}
572
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400573hb_bool_t
Behdad Esfahbodafbcc242012-08-02 08:36:40 -0400574hb_ot_layout_substitute_lookup (hb_font_t *font,
Behdad Esfahbod468769b2009-08-08 16:53:23 -0400575 hb_buffer_t *buffer,
576 unsigned int lookup_index,
577 hb_mask_t mask)
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400578{
Behdad Esfahbodafbcc242012-08-02 08:36:40 -0400579 if (unlikely (lookup_index >= hb_ot_layout_from_face (font->face)->gsub_lookup_count)) return false;
Behdad Esfahbod2bd9fe32012-09-04 15:15:19 -0400580
581 OT::hb_apply_context_t c (font, buffer, mask);
582
583 const OT::SubstLookup& l = hb_ot_layout_from_face (font->face)->gsub->get_lookup (lookup_index);
584
585 return l.apply_string (&c, &hb_ot_layout_from_face (font->face)->gsub_digests[lookup_index]);
Behdad Esfahbodf8603662012-07-30 02:38:39 -0400586}
587
Behdad Esfahbod46d6a212011-05-11 22:33:13 -0400588void
Behdad Esfahbodafbcc242012-08-02 08:36:40 -0400589hb_ot_layout_substitute_finish (hb_font_t *font, hb_buffer_t *buffer)
Behdad Esfahbod46d6a212011-05-11 22:33:13 -0400590{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400591 OT::GSUB::substitute_finish (font, buffer);
Behdad Esfahbod46d6a212011-05-11 22:33:13 -0400592}
593
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400594void
Behdad Esfahbod362a9902012-11-15 14:57:31 -0800595hb_ot_layout_lookup_substitute_closure (hb_face_t *face,
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -0400596 unsigned int lookup_index,
597 hb_set_t *glyphs)
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400598{
Behdad Esfahbod9b346772012-11-23 17:55:40 -0500599 OT::hb_closure_context_t c (face, glyphs);
600
601 const OT::SubstLookup& l = _get_gsub (face).get_lookup (lookup_index);
602
603 l.closure (&c);
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400604}
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400605
Behdad Esfahbod9c42f052009-05-18 17:43:49 -0400606/*
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400607 * OT::GPOS
Behdad Esfahbod9c42f052009-05-18 17:43:49 -0400608 */
609
610hb_bool_t
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400611hb_ot_layout_has_positioning (hb_face_t *face)
612{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400613 return &_get_gpos (face) != &OT::Null(OT::GPOS);
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400614}
615
Behdad Esfahbod8f0d7e02011-04-15 18:59:56 -0400616void
Behdad Esfahbod05bd1b62012-07-30 19:30:01 -0400617hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
Behdad Esfahbod8f0d7e02011-04-15 18:59:56 -0400618{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400619 OT::GPOS::position_start (font, buffer);
Behdad Esfahbod8f0d7e02011-04-15 18:59:56 -0400620}
621
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400622hb_bool_t
Behdad Esfahbodf8603662012-07-30 02:38:39 -0400623hb_ot_layout_position_lookup (hb_font_t *font,
624 hb_buffer_t *buffer,
625 unsigned int lookup_index,
626 hb_mask_t mask)
Behdad Esfahbod9c42f052009-05-18 17:43:49 -0400627{
Behdad Esfahbod6f761132012-08-02 04:00:31 -0400628 if (unlikely (lookup_index >= hb_ot_layout_from_face (font->face)->gpos_lookup_count)) return false;
Behdad Esfahbod2bd9fe32012-09-04 15:15:19 -0400629
630 OT::hb_apply_context_t c (font, buffer, mask);
631
632 const OT::PosLookup& l = hb_ot_layout_from_face (font->face)->gpos->get_lookup (lookup_index);
633
634 return l.apply_string (&c, &hb_ot_layout_from_face (font->face)->gpos_digests[lookup_index]);
Behdad Esfahbodf8603662012-07-30 02:38:39 -0400635}
636
Behdad Esfahbod9db8ad72009-11-06 16:47:31 -0500637void
Behdad Esfahbod1e7d8602012-07-31 23:41:06 -0400638hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer, hb_bool_t zero_width_attached_marks)
Behdad Esfahbod9db8ad72009-11-06 16:47:31 -0500639{
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -0400640 OT::GPOS::position_finish (font, buffer, zero_width_attached_marks);
Behdad Esfahbod9db8ad72009-11-06 16:47:31 -0500641}
Behdad Esfahbodf54cce32012-11-26 14:02:31 +0200642
643hb_bool_t
Behdad Esfahbode9ad71d2012-11-30 08:10:26 +0200644hb_ot_layout_get_size_params (hb_face_t *face,
645 uint16_t *data /* OUT, 5 items */)
Behdad Esfahbodf54cce32012-11-26 14:02:31 +0200646{
647 const OT::GPOS &gpos = _get_gpos (face);
Behdad Esfahbodf54cce32012-11-26 14:02:31 +0200648
Behdad Esfahbod0dff11f2012-11-30 08:14:20 +0200649 unsigned int num_features = gpos.get_feature_count ();
650 for (unsigned int i = 0; i < num_features; i++)
651 {
652 if (HB_TAG ('s','i','z','e') == gpos.get_feature_tag (i))
Behdad Esfahbodf54cce32012-11-26 14:02:31 +0200653 {
Behdad Esfahbod0dff11f2012-11-30 08:14:20 +0200654 const OT::Feature &f = gpos.get_feature (i);
Behdad Esfahbodf54cce32012-11-26 14:02:31 +0200655 const OT::FeatureParams &params = f.get_feature_params ();
656
657 for (unsigned int i = 0; i < 5; i++)
658 data[i] = params.u.size.params[i];
659
660 return true;
661 }
662 }
663
664 for (unsigned int i = 0; i < 5; i++)
665 data[i] = 0;
666
667 return false;
668}