hb-ot-layout.cc revision 05bd1b63426e07d1df7a1b40bf845dc94ab995a8
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 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-ot-layout-private.hh" 32 33#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" 37 38 39#include <stdlib.h> 40#include <string.h> 41 42 43HB_SHAPER_DATA_ENSURE_DECLARE(ot, face) 44 45static hb_bool_t 46hb_ot_layout_ensure (hb_face_t *face) 47{ 48 return hb_ot_shaper_face_data_ensure (face); 49} 50 51 52hb_ot_layout_t * 53_hb_ot_layout_create (hb_face_t *face) 54{ 55 hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t)); 56 57 layout->gdef_blob = Sanitizer<GDEF>::sanitize (hb_face_reference_table (face, HB_OT_TAG_GDEF)); 58 layout->gdef = Sanitizer<GDEF>::lock_instance (layout->gdef_blob); 59 60 layout->gsub_blob = Sanitizer<GSUB>::sanitize (hb_face_reference_table (face, HB_OT_TAG_GSUB)); 61 layout->gsub = Sanitizer<GSUB>::lock_instance (layout->gsub_blob); 62 63 layout->gpos_blob = Sanitizer<GPOS>::sanitize (hb_face_reference_table (face, HB_OT_TAG_GPOS)); 64 layout->gpos = Sanitizer<GPOS>::lock_instance (layout->gpos_blob); 65 66 return layout; 67} 68 69void 70_hb_ot_layout_destroy (hb_ot_layout_t *layout) 71{ 72 hb_blob_destroy (layout->gdef_blob); 73 hb_blob_destroy (layout->gsub_blob); 74 hb_blob_destroy (layout->gpos_blob); 75 76 free (layout); 77} 78 79static inline const GDEF& 80_get_gdef (hb_face_t *face) 81{ 82 if (unlikely (!hb_ot_layout_ensure (face))) return Null(GDEF); 83 return *hb_ot_layout_from_face (face)->gdef; 84} 85static inline const GSUB& 86_get_gsub (hb_face_t *face) 87{ 88 if (unlikely (!hb_ot_layout_ensure (face))) return Null(GSUB); 89 return *hb_ot_layout_from_face (face)->gsub; 90} 91static inline const GPOS& 92_get_gpos (hb_face_t *face) 93{ 94 if (unlikely (!hb_ot_layout_ensure (face))) return Null(GPOS); 95 return *hb_ot_layout_from_face (face)->gpos; 96} 97 98 99/* 100 * GDEF 101 */ 102 103hb_bool_t 104hb_ot_layout_has_glyph_classes (hb_face_t *face) 105{ 106 return _get_gdef (face).has_glyph_classes (); 107} 108 109 110unsigned int 111hb_ot_layout_get_attach_points (hb_face_t *face, 112 hb_codepoint_t glyph, 113 unsigned int start_offset, 114 unsigned int *point_count /* IN/OUT */, 115 unsigned int *point_array /* OUT */) 116{ 117 return _get_gdef (face).get_attach_points (glyph, start_offset, point_count, point_array); 118} 119 120unsigned int 121hb_ot_layout_get_ligature_carets (hb_font_t *font, 122 hb_direction_t direction, 123 hb_codepoint_t glyph, 124 unsigned int start_offset, 125 unsigned int *caret_count /* IN/OUT */, 126 int *caret_array /* OUT */) 127{ 128 return _get_gdef (font->face).get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array); 129} 130 131 132/* 133 * GSUB/GPOS 134 */ 135 136static const GSUBGPOS& 137get_gsubgpos_table (hb_face_t *face, 138 hb_tag_t table_tag) 139{ 140 switch (table_tag) { 141 case HB_OT_TAG_GSUB: return _get_gsub (face); 142 case HB_OT_TAG_GPOS: return _get_gpos (face); 143 default: return Null(GSUBGPOS); 144 } 145} 146 147 148unsigned int 149hb_ot_layout_table_get_script_tags (hb_face_t *face, 150 hb_tag_t table_tag, 151 unsigned int start_offset, 152 unsigned int *script_count /* IN/OUT */, 153 hb_tag_t *script_tags /* OUT */) 154{ 155 const GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 156 157 return g.get_script_tags (start_offset, script_count, script_tags); 158} 159 160hb_bool_t 161hb_ot_layout_table_find_script (hb_face_t *face, 162 hb_tag_t table_tag, 163 hb_tag_t script_tag, 164 unsigned int *script_index) 165{ 166 ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX); 167 const GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 168 169 if (g.find_script_index (script_tag, script_index)) 170 return true; 171 172 /* try finding 'DFLT' */ 173 if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) 174 return false; 175 176 /* try with 'dflt'; MS site has had typos and many fonts use it now :(. 177 * including many versions of DejaVu Sans Mono! */ 178 if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) 179 return false; 180 181 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX; 182 return false; 183} 184 185hb_bool_t 186hb_ot_layout_table_choose_script (hb_face_t *face, 187 hb_tag_t table_tag, 188 const hb_tag_t *script_tags, 189 unsigned int *script_index, 190 hb_tag_t *chosen_script) 191{ 192 ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX); 193 const GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 194 195 while (*script_tags) 196 { 197 if (g.find_script_index (*script_tags, script_index)) { 198 if (chosen_script) 199 *chosen_script = *script_tags; 200 return true; 201 } 202 script_tags++; 203 } 204 205 /* try finding 'DFLT' */ 206 if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) { 207 if (chosen_script) 208 *chosen_script = HB_OT_TAG_DEFAULT_SCRIPT; 209 return false; 210 } 211 212 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */ 213 if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) { 214 if (chosen_script) 215 *chosen_script = HB_OT_TAG_DEFAULT_LANGUAGE; 216 return false; 217 } 218 219 /* try with 'latn'; some old fonts put their features there even though 220 they're really trying to support Thai, for example :( */ 221#define HB_OT_TAG_LATIN_SCRIPT HB_TAG ('l', 'a', 't', 'n') 222 if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index)) { 223 if (chosen_script) 224 *chosen_script = HB_OT_TAG_LATIN_SCRIPT; 225 return false; 226 } 227 228 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX; 229 if (chosen_script) 230 *chosen_script = HB_OT_LAYOUT_NO_SCRIPT_INDEX; 231 return false; 232} 233 234unsigned int 235hb_ot_layout_table_get_feature_tags (hb_face_t *face, 236 hb_tag_t table_tag, 237 unsigned int start_offset, 238 unsigned int *feature_count /* IN/OUT */, 239 hb_tag_t *feature_tags /* OUT */) 240{ 241 const GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 242 243 return g.get_feature_tags (start_offset, feature_count, feature_tags); 244} 245 246 247unsigned int 248hb_ot_layout_script_get_language_tags (hb_face_t *face, 249 hb_tag_t table_tag, 250 unsigned int script_index, 251 unsigned int start_offset, 252 unsigned int *language_count /* IN/OUT */, 253 hb_tag_t *language_tags /* OUT */) 254{ 255 const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index); 256 257 return s.get_lang_sys_tags (start_offset, language_count, language_tags); 258} 259 260hb_bool_t 261hb_ot_layout_script_find_language (hb_face_t *face, 262 hb_tag_t table_tag, 263 unsigned int script_index, 264 hb_tag_t language_tag, 265 unsigned int *language_index) 266{ 267 ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX); 268 const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index); 269 270 if (s.find_lang_sys_index (language_tag, language_index)) 271 return true; 272 273 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */ 274 if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index)) 275 return false; 276 277 if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX; 278 return false; 279} 280 281hb_bool_t 282hb_ot_layout_language_get_required_feature_index (hb_face_t *face, 283 hb_tag_t table_tag, 284 unsigned int script_index, 285 unsigned int language_index, 286 unsigned int *feature_index) 287{ 288 const LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index); 289 290 if (feature_index) *feature_index = l.get_required_feature_index (); 291 292 return l.has_required_feature (); 293} 294 295unsigned int 296hb_ot_layout_language_get_feature_indexes (hb_face_t *face, 297 hb_tag_t table_tag, 298 unsigned int script_index, 299 unsigned int language_index, 300 unsigned int start_offset, 301 unsigned int *feature_count /* IN/OUT */, 302 unsigned int *feature_indexes /* OUT */) 303{ 304 const GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 305 const LangSys &l = g.get_script (script_index).get_lang_sys (language_index); 306 307 return l.get_feature_indexes (start_offset, feature_count, feature_indexes); 308} 309 310unsigned int 311hb_ot_layout_language_get_feature_tags (hb_face_t *face, 312 hb_tag_t table_tag, 313 unsigned int script_index, 314 unsigned int language_index, 315 unsigned int start_offset, 316 unsigned int *feature_count /* IN/OUT */, 317 hb_tag_t *feature_tags /* OUT */) 318{ 319 const GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 320 const LangSys &l = g.get_script (script_index).get_lang_sys (language_index); 321 322 ASSERT_STATIC (sizeof (unsigned int) == sizeof (hb_tag_t)); 323 unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags); 324 325 if (feature_tags) { 326 unsigned int count = *feature_count; 327 for (unsigned int i = 0; i < count; i++) 328 feature_tags[i] = g.get_feature_tag ((unsigned int) feature_tags[i]); 329 } 330 331 return ret; 332} 333 334 335hb_bool_t 336hb_ot_layout_language_find_feature (hb_face_t *face, 337 hb_tag_t table_tag, 338 unsigned int script_index, 339 unsigned int language_index, 340 hb_tag_t feature_tag, 341 unsigned int *feature_index) 342{ 343 ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX); 344 const GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 345 const LangSys &l = g.get_script (script_index).get_lang_sys (language_index); 346 347 unsigned int num_features = l.get_feature_count (); 348 for (unsigned int i = 0; i < num_features; i++) { 349 unsigned int f_index = l.get_feature_index (i); 350 351 if (feature_tag == g.get_feature_tag (f_index)) { 352 if (feature_index) *feature_index = f_index; 353 return true; 354 } 355 } 356 357 if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX; 358 return false; 359} 360 361unsigned int 362hb_ot_layout_feature_get_lookup_indexes (hb_face_t *face, 363 hb_tag_t table_tag, 364 unsigned int feature_index, 365 unsigned int start_offset, 366 unsigned int *lookup_count /* IN/OUT */, 367 unsigned int *lookup_indexes /* OUT */) 368{ 369 const GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 370 const Feature &f = g.get_feature (feature_index); 371 372 return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes); 373} 374 375 376/* 377 * GSUB 378 */ 379 380hb_bool_t 381hb_ot_layout_has_substitution (hb_face_t *face) 382{ 383 return &_get_gsub (face) != &Null(GSUB); 384} 385 386hb_bool_t 387hb_ot_layout_would_substitute_lookup (hb_face_t *face, 388 const hb_codepoint_t *glyphs, 389 unsigned int glyphs_length, 390 unsigned int lookup_index) 391{ 392 if (unlikely (glyphs_length < 1 || glyphs_length > 2)) return false; 393 hb_would_apply_context_t c (face, glyphs[0], glyphs_length == 2 ? glyphs[1] : -1); 394 return _get_gsub (face).would_substitute_lookup (&c, lookup_index); 395} 396 397hb_bool_t 398hb_ot_layout_would_substitute_lookup_fast (hb_face_t *face, 399 const hb_codepoint_t *glyphs, 400 unsigned int glyphs_length, 401 unsigned int lookup_index) 402{ 403 if (unlikely (glyphs_length < 1 || glyphs_length > 2)) return false; 404 hb_would_apply_context_t c (face, glyphs[0], glyphs_length == 2 ? glyphs[1] : -1); 405 return hb_ot_layout_from_face (face)->gsub->would_substitute_lookup (&c, lookup_index); 406} 407 408void 409hb_ot_layout_substitute_start (hb_face_t *face, hb_buffer_t *buffer) 410{ 411 GSUB::substitute_start (face, buffer); 412} 413 414hb_bool_t 415hb_ot_layout_substitute_lookup (hb_face_t *face, 416 hb_buffer_t *buffer, 417 unsigned int lookup_index, 418 hb_mask_t mask) 419{ 420 hb_apply_context_t c (NULL, face, buffer, mask); 421 return _get_gsub (face).substitute_lookup (&c, lookup_index); 422} 423 424hb_bool_t 425hb_ot_layout_substitute_lookup_fast (hb_face_t *face, 426 hb_buffer_t *buffer, 427 unsigned int lookup_index, 428 hb_mask_t mask) 429{ 430 hb_apply_context_t c (NULL, face, buffer, mask); 431 return hb_ot_layout_from_face (face)->gsub->substitute_lookup (&c, lookup_index); 432} 433 434void 435hb_ot_layout_substitute_finish (hb_face_t *face, hb_buffer_t *buffer) 436{ 437 GSUB::substitute_finish (face, buffer); 438} 439 440void 441hb_ot_layout_substitute_closure_lookup (hb_face_t *face, 442 hb_set_t *glyphs, 443 unsigned int lookup_index) 444{ 445 hb_closure_context_t c (face, glyphs); 446 _get_gsub (face).closure_lookup (&c, lookup_index); 447} 448 449/* 450 * GPOS 451 */ 452 453hb_bool_t 454hb_ot_layout_has_positioning (hb_face_t *face) 455{ 456 return &_get_gpos (face) != &Null(GPOS); 457} 458 459void 460hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer) 461{ 462 GPOS::position_start (font, buffer); 463} 464 465hb_bool_t 466hb_ot_layout_position_lookup (hb_font_t *font, 467 hb_buffer_t *buffer, 468 unsigned int lookup_index, 469 hb_mask_t mask) 470{ 471 hb_apply_context_t c (font, font->face, buffer, mask); 472 return _get_gpos (font->face).position_lookup (&c, lookup_index); 473} 474 475hb_bool_t 476hb_ot_layout_position_lookup_fast (hb_font_t *font, 477 hb_buffer_t *buffer, 478 unsigned int lookup_index, 479 hb_mask_t mask) 480{ 481 hb_apply_context_t c (font, font->face, buffer, mask); 482 return hb_ot_layout_from_face (font->face)->gpos->position_lookup (&c, lookup_index); 483} 484 485void 486hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer) 487{ 488 GPOS::position_finish (font, buffer); 489} 490 491 492