hb-ot-layout.cc 13.7 KB
Newer Older
B
Behdad Esfahbod 已提交
1
/*
B
Behdad Esfahbod 已提交
2 3 4
 * Copyright © 1998-2004  David Turner and Werner Lemberg
 * Copyright © 2006  Behdad Esfahbod
 * Copyright © 2007,2008,2009  Red Hat, Inc.
B
Behdad Esfahbod 已提交
5
 *
B
Behdad Esfahbod 已提交
6
 *  This is part of HarfBuzz, a text shaping library.
B
Behdad Esfahbod 已提交
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
 *
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that the
 * above copyright notice and the following two paragraphs appear in
 * all copies of this software.
 *
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 *
 * Red Hat Author(s): Behdad Esfahbod
 */

#define HB_OT_LAYOUT_CC

31
#include "hb-ot-layout-private.hh"
B
Behdad Esfahbod 已提交
32

33 34 35
#include "hb-ot-layout-gdef-private.hh"
#include "hb-ot-layout-gsub-private.hh"
#include "hb-ot-layout-gpos-private.hh"
B
Behdad Esfahbod 已提交
36

B
Behdad Esfahbod 已提交
37

B
Behdad Esfahbod 已提交
38
#include <stdlib.h>
B
Behdad Esfahbod 已提交
39 40
#include <string.h>

B
Behdad Esfahbod 已提交
41 42
HB_BEGIN_DECLS

B
Behdad Esfahbod 已提交
43

B
Behdad Esfahbod 已提交
44 45
hb_ot_layout_t *
_hb_ot_layout_new (hb_face_t *face)
46
{
B
Behdad Esfahbod 已提交
47 48
  /* Remove this object altogether */
  hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
49

50
  layout->gdef_blob = Sanitizer<GDEF>::sanitize (hb_face_reference_table (face, HB_OT_TAG_GDEF));
51
  layout->gdef = Sanitizer<GDEF>::lock_instance (layout->gdef_blob);
B
Behdad Esfahbod 已提交
52

53
  layout->gsub_blob = Sanitizer<GSUB>::sanitize (hb_face_reference_table (face, HB_OT_TAG_GSUB));
54
  layout->gsub = Sanitizer<GSUB>::lock_instance (layout->gsub_blob);
B
Behdad Esfahbod 已提交
55

56
  layout->gpos_blob = Sanitizer<GPOS>::sanitize (hb_face_reference_table (face, HB_OT_TAG_GPOS));
57
  layout->gpos = Sanitizer<GPOS>::lock_instance (layout->gpos_blob);
B
Behdad Esfahbod 已提交
58 59

  return layout;
B
Behdad Esfahbod 已提交
60 61
}

62
void
B
Behdad Esfahbod 已提交
63
_hb_ot_layout_free (hb_ot_layout_t *layout)
B
Behdad Esfahbod 已提交
64
{
B
Behdad Esfahbod 已提交
65 66 67 68 69 70 71
  hb_blob_unlock (layout->gdef_blob);
  hb_blob_unlock (layout->gsub_blob);
  hb_blob_unlock (layout->gpos_blob);

  hb_blob_destroy (layout->gdef_blob);
  hb_blob_destroy (layout->gsub_blob);
  hb_blob_destroy (layout->gpos_blob);
B
Behdad Esfahbod 已提交
72

B
Behdad Esfahbod 已提交
73
  free (layout);
74
}
B
Behdad Esfahbod 已提交
75

B
Behdad Esfahbod 已提交
76
static inline const GDEF&
77 78
_get_gdef (hb_face_t *face)
{
B
Behdad Esfahbod 已提交
79
  return likely (face->ot_layout && face->ot_layout->gdef) ? *face->ot_layout->gdef : Null(GDEF);
80
}
B
Behdad Esfahbod 已提交
81

B
Behdad Esfahbod 已提交
82
static inline const GSUB&
83
_get_gsub (hb_face_t *face)
B
Behdad Esfahbod 已提交
84
{
B
Behdad Esfahbod 已提交
85
  return likely (face->ot_layout && face->ot_layout->gsub) ? *face->ot_layout->gsub : Null(GSUB);
B
Behdad Esfahbod 已提交
86 87
}

B
Behdad Esfahbod 已提交
88
static inline const GPOS&
89
_get_gpos (hb_face_t *face)
B
Behdad Esfahbod 已提交
90
{
B
Behdad Esfahbod 已提交
91
  return likely (face->ot_layout && face->ot_layout->gpos) ? *face->ot_layout->gpos : Null(GPOS);
B
Behdad Esfahbod 已提交
92 93
}

94

B
Behdad Esfahbod 已提交
95 96 97 98 99
/*
 * GDEF
 */

hb_bool_t
100
hb_ot_layout_has_glyph_classes (hb_face_t *face)
B
Behdad Esfahbod 已提交
101
{
102
  return _get_gdef (face).has_glyph_classes ();
B
Behdad Esfahbod 已提交
103 104
}

B
Behdad Esfahbod 已提交
105
unsigned int
106 107 108
_hb_ot_layout_get_glyph_property (hb_face_t       *face,
				  hb_glyph_info_t *info)
{
B
Behdad Esfahbod 已提交
109
  if (!info->props_cache())
B
Behdad Esfahbod 已提交
110 111
  {
    const GDEF &gdef = _get_gdef (face);
B
Behdad Esfahbod 已提交
112
    info->props_cache() = gdef.get_glyph_props (info->codepoint);
B
Behdad Esfahbod 已提交
113
  }
114

B
Behdad Esfahbod 已提交
115
  return info->props_cache();
116 117
}

B
Behdad Esfahbod 已提交
118 119 120 121 122
static hb_bool_t
_hb_ot_layout_match_properties (hb_face_t      *face,
				hb_codepoint_t  codepoint,
				unsigned int    glyph_props,
				unsigned int    lookup_props)
B
Behdad Esfahbod 已提交
123
{
124
  /* Not covered, if, for example, glyph class is ligature and
125
   * lookup_props includes LookupFlags::IgnoreLigatures
B
Behdad Esfahbod 已提交
126
   */
B
Behdad Esfahbod 已提交
127
  if (glyph_props & lookup_props & LookupFlag::IgnoreFlags)
B
Behdad Esfahbod 已提交
128 129
    return false;

B
Behdad Esfahbod 已提交
130
  if (glyph_props & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
B
Behdad Esfahbod 已提交
131
  {
B
Behdad Esfahbod 已提交
132
    /* If using mark filtering sets, the high short of
133
     * lookup_props has the set index.
B
Behdad Esfahbod 已提交
134
     */
135
    if (lookup_props & LookupFlag::UseMarkFilteringSet)
B
Behdad Esfahbod 已提交
136
      return _get_gdef (face).mark_set_covers (lookup_props >> 16, codepoint);
B
Behdad Esfahbod 已提交
137

138
    /* The second byte of lookup_props has the meaning
B
Behdad Esfahbod 已提交
139 140 141
     * "ignore marks of attachment type different than
     * the attachment type specified."
     */
B
Behdad Esfahbod 已提交
142 143
    if (lookup_props & LookupFlag::MarkAttachmentType && glyph_props & LookupFlag::MarkAttachmentType)
      return (lookup_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
B
Behdad Esfahbod 已提交
144 145
  }

B
Behdad Esfahbod 已提交
146
  return true;
B
Behdad Esfahbod 已提交
147 148
}

B
Behdad Esfahbod 已提交
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
hb_bool_t
_hb_ot_layout_check_glyph_property (hb_face_t    *face,
				    hb_glyph_info_t *ginfo,
				    unsigned int  lookup_props,
				    unsigned int *property_out)
{
  unsigned int property;

  property = _hb_ot_layout_get_glyph_property (face, ginfo);
  (void) (property_out && (*property_out = property));

  return _hb_ot_layout_match_properties (face, ginfo->codepoint, property, lookup_props);
}

hb_bool_t
_hb_ot_layout_skip_mark (hb_face_t    *face,
			 hb_glyph_info_t *ginfo,
			 unsigned int  lookup_props,
			 unsigned int *property_out)
{
  unsigned int property;

  property = _hb_ot_layout_get_glyph_property (face, ginfo);
  (void) (property_out && (*property_out = property));

  /* If it's a mark, skip it we don't accept it. */
  if (unlikely (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
    return !_hb_ot_layout_match_properties (face, ginfo->codepoint, property, lookup_props);

  /* If not a mark, don't skip. */
  return false;
}



B
Behdad Esfahbod 已提交
184
unsigned int
185
hb_ot_layout_get_attach_points (hb_face_t      *face,
B
Behdad Esfahbod 已提交
186
				hb_codepoint_t  glyph,
B
Behdad Esfahbod 已提交
187
				unsigned int    start_offset,
B
Behdad Esfahbod 已提交
188 189 190
				unsigned int   *point_count /* IN/OUT */,
				unsigned int   *point_array /* OUT */)
{
B
Behdad Esfahbod 已提交
191
  return _get_gdef (face).get_attach_points (glyph, start_offset, point_count, point_array);
B
Behdad Esfahbod 已提交
192 193
}

B
Behdad Esfahbod 已提交
194
unsigned int
195 196 197 198 199 200
hb_ot_layout_get_ligature_carets (hb_font_t      *font,
				  hb_direction_t  direction,
				  hb_codepoint_t  glyph,
				  unsigned int    start_offset,
				  unsigned int   *caret_count /* IN/OUT */,
				  int            *caret_array /* OUT */)
B
Behdad Esfahbod 已提交
201
{
B
Behdad Esfahbod 已提交
202 203
  hb_ot_layout_context_t c;
  c.font = font;
204 205
  c.face = font->face;
  return _get_gdef (c.face).get_lig_carets (&c, direction, glyph, start_offset, caret_count, caret_array);
B
Behdad Esfahbod 已提交
206 207
}

208 209 210 211 212
/*
 * GSUB/GPOS
 */

static const GSUBGPOS&
213 214
get_gsubgpos_table (hb_face_t *face,
		    hb_tag_t   table_tag)
215
{
216
  switch (table_tag) {
217 218
    case HB_OT_TAG_GSUB: return _get_gsub (face);
    case HB_OT_TAG_GPOS: return _get_gpos (face);
219
    default:             return Null(GSUBGPOS);
220 221 222 223
  }
}


B
Behdad Esfahbod 已提交
224
unsigned int
225 226
hb_ot_layout_table_get_script_tags (hb_face_t    *face,
				    hb_tag_t      table_tag,
B
Behdad Esfahbod 已提交
227
				    unsigned int  start_offset,
228 229
				    unsigned int *script_count /* IN/OUT */,
				    hb_tag_t     *script_tags /* OUT */)
230
{
231
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
232

B
Behdad Esfahbod 已提交
233
  return g.get_script_tags (start_offset, script_count, script_tags);
234 235 236
}

hb_bool_t
237 238 239 240
hb_ot_layout_table_find_script (hb_face_t    *face,
				hb_tag_t      table_tag,
				hb_tag_t      script_tag,
				unsigned int *script_index)
241
{
B
Behdad Esfahbod 已提交
242
  ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
243
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
244 245 246 247 248

  if (g.find_script_index (script_tag, script_index))
    return TRUE;

  /* try finding 'DFLT' */
249
  if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index))
250 251
    return FALSE;

252 253
  /* try with 'dflt'; MS site has had typos and many fonts use it now :(.
   * including many versions of DejaVu Sans Mono! */
254
  if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index))
B
Behdad Esfahbod 已提交
255 256 257 258 259 260 261 262 263 264 265 266
    return FALSE;

  if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
  return FALSE;
}

hb_bool_t
hb_ot_layout_table_choose_script (hb_face_t      *face,
				  hb_tag_t        table_tag,
				  const hb_tag_t *script_tags,
				  unsigned int   *script_index)
{
B
Behdad Esfahbod 已提交
267
  ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
B
Behdad Esfahbod 已提交
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);

  while (*script_tags)
  {
    if (g.find_script_index (*script_tags, script_index))
      return TRUE;
    script_tags++;
  }

  /* try finding 'DFLT' */
  if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index))
    return FALSE;

  /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
  if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index))
283 284 285 286 287 288
    return FALSE;

  if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
  return FALSE;
}

B
Behdad Esfahbod 已提交
289
unsigned int
290 291
hb_ot_layout_table_get_feature_tags (hb_face_t    *face,
				     hb_tag_t      table_tag,
B
Behdad Esfahbod 已提交
292
				     unsigned int  start_offset,
293 294
				     unsigned int *feature_count /* IN/OUT */,
				     hb_tag_t     *feature_tags /* OUT */)
295
{
296
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
297

B
Behdad Esfahbod 已提交
298
  return g.get_feature_tags (start_offset, feature_count, feature_tags);
299 300 301
}


B
Behdad Esfahbod 已提交
302
unsigned int
303 304 305
hb_ot_layout_script_get_language_tags (hb_face_t    *face,
				       hb_tag_t      table_tag,
				       unsigned int  script_index,
B
Behdad Esfahbod 已提交
306
				       unsigned int  start_offset,
307 308
				       unsigned int *language_count /* IN/OUT */,
				       hb_tag_t     *language_tags /* OUT */)
309
{
310
  const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
311

B
Behdad Esfahbod 已提交
312
  return s.get_lang_sys_tags (start_offset, language_count, language_tags);
313 314 315
}

hb_bool_t
316 317 318 319 320
hb_ot_layout_script_find_language (hb_face_t    *face,
				   hb_tag_t      table_tag,
				   unsigned int  script_index,
				   hb_tag_t      language_tag,
				   unsigned int *language_index)
321
{
B
Behdad Esfahbod 已提交
322
  ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
323
  const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
324

325
  if (s.find_lang_sys_index (language_tag, language_index))
326 327 328
    return TRUE;

  /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
329
  if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index))
330 331
    return FALSE;

332
  if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
333
  return FALSE;
334
}
335

336
hb_bool_t
337 338 339 340 341
hb_ot_layout_language_get_required_feature_index (hb_face_t    *face,
						  hb_tag_t      table_tag,
						  unsigned int  script_index,
						  unsigned int  language_index,
						  unsigned int *feature_index)
342
{
343
  const LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index);
344

345
  if (feature_index) *feature_index = l.get_required_feature_index ();
346

347 348
  return l.has_required_feature ();
}
349

B
Behdad Esfahbod 已提交
350
unsigned int
351 352 353 354
hb_ot_layout_language_get_feature_indexes (hb_face_t    *face,
					   hb_tag_t      table_tag,
					   unsigned int  script_index,
					   unsigned int  language_index,
B
Behdad Esfahbod 已提交
355
					   unsigned int  start_offset,
356 357
					   unsigned int *feature_count /* IN/OUT */,
					   unsigned int *feature_indexes /* OUT */)
358
{
359
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
360 361
  const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);

B
Behdad Esfahbod 已提交
362
  return l.get_feature_indexes (start_offset, feature_count, feature_indexes);
363 364
}

B
Behdad Esfahbod 已提交
365
unsigned int
366 367 368 369
hb_ot_layout_language_get_feature_tags (hb_face_t    *face,
					hb_tag_t      table_tag,
					unsigned int  script_index,
					unsigned int  language_index,
B
Behdad Esfahbod 已提交
370
					unsigned int  start_offset,
371 372
					unsigned int *feature_count /* IN/OUT */,
					hb_tag_t     *feature_tags /* OUT */)
373
{
374
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
375
  const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
376

377
  ASSERT_STATIC (sizeof (unsigned int) == sizeof (hb_tag_t));
B
Behdad Esfahbod 已提交
378
  unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags);
379

B
Behdad Esfahbod 已提交
380 381 382 383 384
  if (feature_tags) {
    unsigned int count = *feature_count;
    for (unsigned int i = 0; i < count; i++)
      feature_tags[i] = g.get_feature_tag ((unsigned int) feature_tags[i]);
  }
385 386

  return ret;
387 388 389 390
}


hb_bool_t
391 392 393 394 395 396
hb_ot_layout_language_find_feature (hb_face_t    *face,
				    hb_tag_t      table_tag,
				    unsigned int  script_index,
				    unsigned int  language_index,
				    hb_tag_t      feature_tag,
				    unsigned int *feature_index)
397
{
B
Behdad Esfahbod 已提交
398
  ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
399
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
400 401
  const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);

B
Behdad Esfahbod 已提交
402 403
  unsigned int num_features = l.get_feature_count ();
  for (unsigned int i = 0; i < num_features; i++) {
404 405 406 407 408 409 410
    unsigned int f_index = l.get_feature_index (i);

    if (feature_tag == g.get_feature_tag (f_index)) {
      if (feature_index) *feature_index = f_index;
      return TRUE;
    }
  }
411

412
  if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
413 414
  return FALSE;
}
415

B
Behdad Esfahbod 已提交
416
unsigned int
417 418 419
hb_ot_layout_feature_get_lookup_indexes (hb_face_t    *face,
					 hb_tag_t      table_tag,
					 unsigned int  feature_index,
B
Behdad Esfahbod 已提交
420
					 unsigned int  start_offset,
421 422
					 unsigned int *lookup_count /* IN/OUT */,
					 unsigned int *lookup_indexes /* OUT */)
423
{
424
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
425 426
  const Feature &f = g.get_feature (feature_index);

B
Behdad Esfahbod 已提交
427
  return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
428 429
}

B
Behdad Esfahbod 已提交
430 431 432 433 434 435

/*
 * GSUB
 */

hb_bool_t
436 437
hb_ot_layout_has_substitution (hb_face_t *face)
{
438
  return &_get_gsub (face) != &Null(GSUB);
439 440 441
}

hb_bool_t
442 443 444 445
hb_ot_layout_substitute_lookup (hb_face_t    *face,
				hb_buffer_t  *buffer,
				unsigned int  lookup_index,
				hb_mask_t     mask)
B
Behdad Esfahbod 已提交
446
{
B
Behdad Esfahbod 已提交
447 448 449 450
  hb_ot_layout_context_t c;
  c.font = NULL;
  c.face = face;
  return _get_gsub (face).substitute_lookup (&c, buffer, lookup_index, mask);
451 452
}

453

454 455 456 457 458
/*
 * GPOS
 */

hb_bool_t
459 460
hb_ot_layout_has_positioning (hb_face_t *face)
{
461
  return &_get_gpos (face) != &Null(GPOS);
462 463
}

464 465 466 467 468 469
void
hb_ot_layout_position_start (hb_buffer_t  *buffer)
{
  buffer->clear_positions ();
}

470
hb_bool_t
471
hb_ot_layout_position_lookup   (hb_font_t    *font,
472 473 474
				hb_buffer_t  *buffer,
				unsigned int  lookup_index,
				hb_mask_t     mask)
475
{
B
Behdad Esfahbod 已提交
476 477
  hb_ot_layout_context_t c;
  c.font = font;
478 479
  c.face = font->face;
  return _get_gpos (c.face).position_lookup (&c, buffer, lookup_index, mask);
480
}
481 482

void
B
Behdad Esfahbod 已提交
483
hb_ot_layout_position_finish (hb_buffer_t  *buffer)
484
{
B
Behdad Esfahbod 已提交
485
  GPOS::position_finish (buffer);
486
}
B
Behdad Esfahbod 已提交
487 488 489


HB_END_DECLS