hb-ot-layout.cc revision c47a31fb4793b825f4be57e9cb1b10db352b9512
1/* 2 * Copyright © 1998-2004 David Turner and Werner Lemberg 3 * Copyright © 2006 Behdad Esfahbod 4 * Copyright © 2007,2008,2009 Red Hat, Inc. 5 * 6 * This is part of HarfBuzz, a text shaping library. 7 * 8 * Permission is hereby granted, without written agreement and without 9 * license or royalty fees, to use, copy, modify, and distribute this 10 * software and its documentation for any purpose, provided that the 11 * above copyright notice and the following two paragraphs appear in 12 * all copies of this software. 13 * 14 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 15 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 16 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 17 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 18 * DAMAGE. 19 * 20 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 21 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 22 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 23 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 24 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 25 * 26 * Red Hat Author(s): Behdad Esfahbod 27 */ 28 29#define HB_OT_LAYOUT_CC 30 31#include "hb-ot-layout-private.hh" 32 33#include "hb-ot-layout-gdef-private.hh" 34#include "hb-ot-layout-gsub-private.hh" 35#include "hb-ot-layout-gpos-private.hh" 36#include "hb-ot-head-private.hh" 37#include "hb-ot-maxp-private.hh" 38 39 40#include <stdlib.h> 41#include <string.h> 42 43HB_BEGIN_DECLS 44 45 46hb_ot_layout_t * 47_hb_ot_layout_create (hb_face_t *face) 48{ 49 /* TODO Remove this object altogether */ 50 hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t)); 51 52 layout->gdef_blob = Sanitizer<GDEF>::sanitize (hb_face_reference_table (face, HB_OT_TAG_GDEF)); 53 layout->gdef = Sanitizer<GDEF>::lock_instance (layout->gdef_blob); 54 55 layout->gsub_blob = Sanitizer<GSUB>::sanitize (hb_face_reference_table (face, HB_OT_TAG_GSUB)); 56 layout->gsub = Sanitizer<GSUB>::lock_instance (layout->gsub_blob); 57 58 layout->gpos_blob = Sanitizer<GPOS>::sanitize (hb_face_reference_table (face, HB_OT_TAG_GPOS)); 59 layout->gpos = Sanitizer<GPOS>::lock_instance (layout->gpos_blob); 60 61 layout->head_blob = Sanitizer<head>::sanitize (hb_face_reference_table (face, HB_OT_TAG_head)); 62 layout->head = Sanitizer<head>::lock_instance (layout->head_blob); 63 64 return layout; 65} 66 67void 68_hb_ot_layout_destroy (hb_ot_layout_t *layout) 69{ 70 hb_blob_destroy (layout->gdef_blob); 71 hb_blob_destroy (layout->gsub_blob); 72 hb_blob_destroy (layout->gpos_blob); 73 hb_blob_destroy (layout->head_blob); 74 75 free (layout); 76} 77 78static inline const GDEF& 79_get_gdef (hb_face_t *face) 80{ 81 return likely (face->ot_layout && face->ot_layout->gdef) ? *face->ot_layout->gdef : Null(GDEF); 82} 83static inline const GSUB& 84_get_gsub (hb_face_t *face) 85{ 86 return likely (face->ot_layout && face->ot_layout->gsub) ? *face->ot_layout->gsub : Null(GSUB); 87} 88static inline const GPOS& 89_get_gpos (hb_face_t *face) 90{ 91 return likely (face->ot_layout && face->ot_layout->gpos) ? *face->ot_layout->gpos : Null(GPOS); 92} 93static inline const head& 94_get_head (hb_face_t *face) 95{ 96 return likely (face->ot_layout && face->ot_layout->head) ? *face->ot_layout->head : Null(head); 97} 98 99 100/* 101 * GDEF 102 */ 103 104hb_bool_t 105hb_ot_layout_has_glyph_classes (hb_face_t *face) 106{ 107 return _get_gdef (face).has_glyph_classes (); 108} 109 110unsigned int 111_hb_ot_layout_get_glyph_property (hb_face_t *face, 112 hb_glyph_info_t *info) 113{ 114 if (!info->props_cache()) 115 { 116 const GDEF &gdef = _get_gdef (face); 117 info->props_cache() = gdef.get_glyph_props (info->codepoint); 118 } 119 120 return info->props_cache(); 121} 122 123static hb_bool_t 124_hb_ot_layout_match_properties (hb_face_t *face, 125 hb_codepoint_t codepoint, 126 unsigned int glyph_props, 127 unsigned int lookup_props) 128{ 129 /* Not covered, if, for example, glyph class is ligature and 130 * lookup_props includes LookupFlags::IgnoreLigatures 131 */ 132 if (glyph_props & lookup_props & LookupFlag::IgnoreFlags) 133 return false; 134 135 if (glyph_props & HB_OT_LAYOUT_GLYPH_CLASS_MARK) 136 { 137 /* If using mark filtering sets, the high short of 138 * lookup_props has the set index. 139 */ 140 if (lookup_props & LookupFlag::UseMarkFilteringSet) 141 return _get_gdef (face).mark_set_covers (lookup_props >> 16, codepoint); 142 143 /* The second byte of lookup_props has the meaning 144 * "ignore marks of attachment type different than 145 * the attachment type specified." 146 */ 147 if (lookup_props & LookupFlag::MarkAttachmentType && glyph_props & LookupFlag::MarkAttachmentType) 148 return (lookup_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType); 149 } 150 151 return true; 152} 153 154hb_bool_t 155_hb_ot_layout_check_glyph_property (hb_face_t *face, 156 hb_glyph_info_t *ginfo, 157 unsigned int lookup_props, 158 unsigned int *property_out) 159{ 160 unsigned int property; 161 162 property = _hb_ot_layout_get_glyph_property (face, ginfo); 163 (void) (property_out && (*property_out = property)); 164 165 return _hb_ot_layout_match_properties (face, ginfo->codepoint, property, lookup_props); 166} 167 168hb_bool_t 169_hb_ot_layout_skip_mark (hb_face_t *face, 170 hb_glyph_info_t *ginfo, 171 unsigned int lookup_props, 172 unsigned int *property_out) 173{ 174 unsigned int property; 175 176 property = _hb_ot_layout_get_glyph_property (face, ginfo); 177 (void) (property_out && (*property_out = property)); 178 179 /* If it's a mark, skip it we don't accept it. */ 180 if (unlikely (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)) 181 return !_hb_ot_layout_match_properties (face, ginfo->codepoint, property, lookup_props); 182 183 /* If not a mark, don't skip. */ 184 return false; 185} 186 187 188 189unsigned int 190hb_ot_layout_get_attach_points (hb_face_t *face, 191 hb_codepoint_t glyph, 192 unsigned int start_offset, 193 unsigned int *point_count /* IN/OUT */, 194 unsigned int *point_array /* OUT */) 195{ 196 return _get_gdef (face).get_attach_points (glyph, start_offset, point_count, point_array); 197} 198 199unsigned int 200hb_ot_layout_get_ligature_carets (hb_font_t *font, 201 hb_direction_t direction, 202 hb_codepoint_t glyph, 203 unsigned int start_offset, 204 unsigned int *caret_count /* IN/OUT */, 205 int *caret_array /* OUT */) 206{ 207 return _get_gdef (font->face).get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array); 208} 209 210/* 211 * GSUB/GPOS 212 */ 213 214static const GSUBGPOS& 215get_gsubgpos_table (hb_face_t *face, 216 hb_tag_t table_tag) 217{ 218 switch (table_tag) { 219 case HB_OT_TAG_GSUB: return _get_gsub (face); 220 case HB_OT_TAG_GPOS: return _get_gpos (face); 221 default: return Null(GSUBGPOS); 222 } 223} 224 225 226unsigned int 227hb_ot_layout_table_get_script_tags (hb_face_t *face, 228 hb_tag_t table_tag, 229 unsigned int start_offset, 230 unsigned int *script_count /* IN/OUT */, 231 hb_tag_t *script_tags /* OUT */) 232{ 233 const GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 234 235 return g.get_script_tags (start_offset, script_count, script_tags); 236} 237 238hb_bool_t 239hb_ot_layout_table_find_script (hb_face_t *face, 240 hb_tag_t table_tag, 241 hb_tag_t script_tag, 242 unsigned int *script_index) 243{ 244 ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX); 245 const GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 246 247 if (g.find_script_index (script_tag, script_index)) 248 return TRUE; 249 250 /* try finding 'DFLT' */ 251 if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) 252 return FALSE; 253 254 /* try with 'dflt'; MS site has had typos and many fonts use it now :(. 255 * including many versions of DejaVu Sans Mono! */ 256 if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) 257 return FALSE; 258 259 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX; 260 return FALSE; 261} 262 263hb_bool_t 264hb_ot_layout_table_choose_script (hb_face_t *face, 265 hb_tag_t table_tag, 266 const hb_tag_t *script_tags, 267 unsigned int *script_index, 268 hb_tag_t *chosen_script) 269{ 270 ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX); 271 const GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 272 273 while (*script_tags) 274 { 275 if (g.find_script_index (*script_tags, script_index)) { 276 if (chosen_script) 277 *chosen_script = *script_tags; 278 return TRUE; 279 } 280 script_tags++; 281 } 282 283 /* try finding 'DFLT' */ 284 if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) { 285 if (chosen_script) 286 *chosen_script = HB_OT_TAG_DEFAULT_SCRIPT; 287 return FALSE; 288 } 289 290 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */ 291 if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) { 292 if (chosen_script) 293 *chosen_script = HB_OT_TAG_DEFAULT_LANGUAGE; 294 return FALSE; 295 } 296 297 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX; 298 if (chosen_script) 299 *chosen_script = HB_OT_LAYOUT_NO_SCRIPT_INDEX; 300 return FALSE; 301} 302 303unsigned int 304hb_ot_layout_table_get_feature_tags (hb_face_t *face, 305 hb_tag_t table_tag, 306 unsigned int start_offset, 307 unsigned int *feature_count /* IN/OUT */, 308 hb_tag_t *feature_tags /* OUT */) 309{ 310 const GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 311 312 return g.get_feature_tags (start_offset, feature_count, feature_tags); 313} 314 315 316unsigned int 317hb_ot_layout_script_get_language_tags (hb_face_t *face, 318 hb_tag_t table_tag, 319 unsigned int script_index, 320 unsigned int start_offset, 321 unsigned int *language_count /* IN/OUT */, 322 hb_tag_t *language_tags /* OUT */) 323{ 324 const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index); 325 326 return s.get_lang_sys_tags (start_offset, language_count, language_tags); 327} 328 329hb_bool_t 330hb_ot_layout_script_find_language (hb_face_t *face, 331 hb_tag_t table_tag, 332 unsigned int script_index, 333 hb_tag_t language_tag, 334 unsigned int *language_index) 335{ 336 ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX); 337 const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index); 338 339 if (s.find_lang_sys_index (language_tag, language_index)) 340 return TRUE; 341 342 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */ 343 if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index)) 344 return FALSE; 345 346 if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX; 347 return FALSE; 348} 349 350hb_bool_t 351hb_ot_layout_language_get_required_feature_index (hb_face_t *face, 352 hb_tag_t table_tag, 353 unsigned int script_index, 354 unsigned int language_index, 355 unsigned int *feature_index) 356{ 357 const LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index); 358 359 if (feature_index) *feature_index = l.get_required_feature_index (); 360 361 return l.has_required_feature (); 362} 363 364unsigned int 365hb_ot_layout_language_get_feature_indexes (hb_face_t *face, 366 hb_tag_t table_tag, 367 unsigned int script_index, 368 unsigned int language_index, 369 unsigned int start_offset, 370 unsigned int *feature_count /* IN/OUT */, 371 unsigned int *feature_indexes /* OUT */) 372{ 373 const GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 374 const LangSys &l = g.get_script (script_index).get_lang_sys (language_index); 375 376 return l.get_feature_indexes (start_offset, feature_count, feature_indexes); 377} 378 379unsigned int 380hb_ot_layout_language_get_feature_tags (hb_face_t *face, 381 hb_tag_t table_tag, 382 unsigned int script_index, 383 unsigned int language_index, 384 unsigned int start_offset, 385 unsigned int *feature_count /* IN/OUT */, 386 hb_tag_t *feature_tags /* OUT */) 387{ 388 const GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 389 const LangSys &l = g.get_script (script_index).get_lang_sys (language_index); 390 391 ASSERT_STATIC (sizeof (unsigned int) == sizeof (hb_tag_t)); 392 unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags); 393 394 if (feature_tags) { 395 unsigned int count = *feature_count; 396 for (unsigned int i = 0; i < count; i++) 397 feature_tags[i] = g.get_feature_tag ((unsigned int) feature_tags[i]); 398 } 399 400 return ret; 401} 402 403 404hb_bool_t 405hb_ot_layout_language_find_feature (hb_face_t *face, 406 hb_tag_t table_tag, 407 unsigned int script_index, 408 unsigned int language_index, 409 hb_tag_t feature_tag, 410 unsigned int *feature_index) 411{ 412 ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX); 413 const GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 414 const LangSys &l = g.get_script (script_index).get_lang_sys (language_index); 415 416 unsigned int num_features = l.get_feature_count (); 417 for (unsigned int i = 0; i < num_features; i++) { 418 unsigned int f_index = l.get_feature_index (i); 419 420 if (feature_tag == g.get_feature_tag (f_index)) { 421 if (feature_index) *feature_index = f_index; 422 return TRUE; 423 } 424 } 425 426 if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX; 427 return FALSE; 428} 429 430unsigned int 431hb_ot_layout_feature_get_lookup_indexes (hb_face_t *face, 432 hb_tag_t table_tag, 433 unsigned int feature_index, 434 unsigned int start_offset, 435 unsigned int *lookup_count /* IN/OUT */, 436 unsigned int *lookup_indexes /* OUT */) 437{ 438 const GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 439 const Feature &f = g.get_feature (feature_index); 440 441 return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes); 442} 443 444 445/* 446 * GSUB 447 */ 448 449hb_bool_t 450hb_ot_layout_has_substitution (hb_face_t *face) 451{ 452 return &_get_gsub (face) != &Null(GSUB); 453} 454 455void 456hb_ot_layout_substitute_start (hb_buffer_t *buffer) 457{ 458 GSUB::substitute_start (buffer); 459} 460 461hb_bool_t 462hb_ot_layout_substitute_lookup (hb_face_t *face, 463 hb_buffer_t *buffer, 464 unsigned int lookup_index, 465 hb_mask_t mask) 466{ 467 return _get_gsub (face).substitute_lookup (face, buffer, lookup_index, mask); 468} 469 470void 471hb_ot_layout_substitute_finish (hb_buffer_t *buffer HB_UNUSED) 472{ 473 GSUB::substitute_finish (buffer); 474} 475 476 477/* 478 * GPOS 479 */ 480 481hb_bool_t 482hb_ot_layout_has_positioning (hb_face_t *face) 483{ 484 return &_get_gpos (face) != &Null(GPOS); 485} 486 487void 488hb_ot_layout_position_start (hb_buffer_t *buffer) 489{ 490 GPOS::position_start (buffer); 491} 492 493hb_bool_t 494hb_ot_layout_position_lookup (hb_font_t *font, 495 hb_buffer_t *buffer, 496 unsigned int lookup_index, 497 hb_mask_t mask) 498{ 499 return _get_gpos (font->face).position_lookup (font, buffer, lookup_index, mask); 500} 501 502void 503hb_ot_layout_position_finish (hb_buffer_t *buffer) 504{ 505 GPOS::position_finish (buffer); 506} 507 508 509/* 510 * head 511 */ 512 513unsigned int 514_hb_ot_layout_get_upem (hb_face_t *face) 515{ 516 return _get_head (face).get_upem (); 517} 518 519 520HB_END_DECLS 521