hb-ot-layout.cc revision b9452bfc1696457e156e79037c863903da5454fc
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{ 269 ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX); 270 const GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 271 272 while (*script_tags) 273 { 274 if (g.find_script_index (*script_tags, script_index)) 275 return TRUE; 276 script_tags++; 277 } 278 279 /* try finding 'DFLT' */ 280 if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) 281 return FALSE; 282 283 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */ 284 if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) 285 return FALSE; 286 287 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX; 288 return FALSE; 289} 290 291unsigned int 292hb_ot_layout_table_get_feature_tags (hb_face_t *face, 293 hb_tag_t table_tag, 294 unsigned int start_offset, 295 unsigned int *feature_count /* IN/OUT */, 296 hb_tag_t *feature_tags /* OUT */) 297{ 298 const GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 299 300 return g.get_feature_tags (start_offset, feature_count, feature_tags); 301} 302 303 304unsigned int 305hb_ot_layout_script_get_language_tags (hb_face_t *face, 306 hb_tag_t table_tag, 307 unsigned int script_index, 308 unsigned int start_offset, 309 unsigned int *language_count /* IN/OUT */, 310 hb_tag_t *language_tags /* OUT */) 311{ 312 const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index); 313 314 return s.get_lang_sys_tags (start_offset, language_count, language_tags); 315} 316 317hb_bool_t 318hb_ot_layout_script_find_language (hb_face_t *face, 319 hb_tag_t table_tag, 320 unsigned int script_index, 321 hb_tag_t language_tag, 322 unsigned int *language_index) 323{ 324 ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX); 325 const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index); 326 327 if (s.find_lang_sys_index (language_tag, language_index)) 328 return TRUE; 329 330 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */ 331 if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index)) 332 return FALSE; 333 334 if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX; 335 return FALSE; 336} 337 338hb_bool_t 339hb_ot_layout_language_get_required_feature_index (hb_face_t *face, 340 hb_tag_t table_tag, 341 unsigned int script_index, 342 unsigned int language_index, 343 unsigned int *feature_index) 344{ 345 const LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index); 346 347 if (feature_index) *feature_index = l.get_required_feature_index (); 348 349 return l.has_required_feature (); 350} 351 352unsigned int 353hb_ot_layout_language_get_feature_indexes (hb_face_t *face, 354 hb_tag_t table_tag, 355 unsigned int script_index, 356 unsigned int language_index, 357 unsigned int start_offset, 358 unsigned int *feature_count /* IN/OUT */, 359 unsigned int *feature_indexes /* OUT */) 360{ 361 const GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 362 const LangSys &l = g.get_script (script_index).get_lang_sys (language_index); 363 364 return l.get_feature_indexes (start_offset, feature_count, feature_indexes); 365} 366 367unsigned int 368hb_ot_layout_language_get_feature_tags (hb_face_t *face, 369 hb_tag_t table_tag, 370 unsigned int script_index, 371 unsigned int language_index, 372 unsigned int start_offset, 373 unsigned int *feature_count /* IN/OUT */, 374 hb_tag_t *feature_tags /* OUT */) 375{ 376 const GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 377 const LangSys &l = g.get_script (script_index).get_lang_sys (language_index); 378 379 ASSERT_STATIC (sizeof (unsigned int) == sizeof (hb_tag_t)); 380 unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags); 381 382 if (feature_tags) { 383 unsigned int count = *feature_count; 384 for (unsigned int i = 0; i < count; i++) 385 feature_tags[i] = g.get_feature_tag ((unsigned int) feature_tags[i]); 386 } 387 388 return ret; 389} 390 391 392hb_bool_t 393hb_ot_layout_language_find_feature (hb_face_t *face, 394 hb_tag_t table_tag, 395 unsigned int script_index, 396 unsigned int language_index, 397 hb_tag_t feature_tag, 398 unsigned int *feature_index) 399{ 400 ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX); 401 const GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 402 const LangSys &l = g.get_script (script_index).get_lang_sys (language_index); 403 404 unsigned int num_features = l.get_feature_count (); 405 for (unsigned int i = 0; i < num_features; i++) { 406 unsigned int f_index = l.get_feature_index (i); 407 408 if (feature_tag == g.get_feature_tag (f_index)) { 409 if (feature_index) *feature_index = f_index; 410 return TRUE; 411 } 412 } 413 414 if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX; 415 return FALSE; 416} 417 418unsigned int 419hb_ot_layout_feature_get_lookup_indexes (hb_face_t *face, 420 hb_tag_t table_tag, 421 unsigned int feature_index, 422 unsigned int start_offset, 423 unsigned int *lookup_count /* IN/OUT */, 424 unsigned int *lookup_indexes /* OUT */) 425{ 426 const GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 427 const Feature &f = g.get_feature (feature_index); 428 429 return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes); 430} 431 432 433/* 434 * GSUB 435 */ 436 437hb_bool_t 438hb_ot_layout_has_substitution (hb_face_t *face) 439{ 440 return &_get_gsub (face) != &Null(GSUB); 441} 442 443void 444hb_ot_layout_substitute_start (hb_buffer_t *buffer) 445{ 446 unsigned int count = buffer->len; 447 for (unsigned int i = 0; i < count; i++) 448 buffer->info[i].var1.u32 = buffer->info[i].var2.u32 = 0; 449} 450 451hb_bool_t 452hb_ot_layout_substitute_lookup (hb_face_t *face, 453 hb_buffer_t *buffer, 454 unsigned int lookup_index, 455 hb_mask_t mask) 456{ 457 return _get_gsub (face).substitute_lookup (face, buffer, lookup_index, mask); 458} 459 460void 461hb_ot_layout_substitute_finish (hb_buffer_t *buffer HB_UNUSED) 462{ 463} 464 465 466/* 467 * GPOS 468 */ 469 470hb_bool_t 471hb_ot_layout_has_positioning (hb_face_t *face) 472{ 473 return &_get_gpos (face) != &Null(GPOS); 474} 475 476void 477hb_ot_layout_position_start (hb_buffer_t *buffer) 478{ 479 buffer->clear_positions (); 480} 481 482hb_bool_t 483hb_ot_layout_position_lookup (hb_font_t *font, 484 hb_buffer_t *buffer, 485 unsigned int lookup_index, 486 hb_mask_t mask) 487{ 488 return _get_gpos (font->face).position_lookup (font, buffer, lookup_index, mask); 489} 490 491void 492hb_ot_layout_position_finish (hb_buffer_t *buffer) 493{ 494 GPOS::position_finish (buffer); 495} 496 497 498/* 499 * head 500 */ 501 502unsigned int 503_hb_ot_layout_get_upem (hb_face_t *face) 504{ 505 return _get_head (face).get_upem (); 506} 507 508 509HB_END_DECLS 510