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