hb-ot-layout.cc 14.3 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"
36
#include "hb-ot-head-private.hh"
B
Behdad Esfahbod 已提交
37

B
Behdad Esfahbod 已提交
38

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

B
Behdad Esfahbod 已提交
42 43
HB_BEGIN_DECLS

B
Behdad Esfahbod 已提交
44

B
Behdad Esfahbod 已提交
45
hb_ot_layout_t *
46
_hb_ot_layout_create (hb_face_t *face)
47
{
B
Behdad Esfahbod 已提交
48 49
  /* Remove this object altogether */
  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);
B
Behdad Esfahbod 已提交
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);
B
Behdad Esfahbod 已提交
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);
B
Behdad Esfahbod 已提交
59

60 61 62
  layout->head_blob = Sanitizer<head>::sanitize (hb_face_reference_table (face, HB_OT_TAG_head));
  layout->head = Sanitizer<head>::lock_instance (layout->head_blob);

B
Behdad Esfahbod 已提交
63
  return layout;
B
Behdad Esfahbod 已提交
64 65
}

66
void
67
_hb_ot_layout_destroy (hb_ot_layout_t *layout)
B
Behdad Esfahbod 已提交
68
{
B
Behdad Esfahbod 已提交
69 70 71
  hb_blob_unlock (layout->gdef_blob);
  hb_blob_unlock (layout->gsub_blob);
  hb_blob_unlock (layout->gpos_blob);
72
  hb_blob_unlock (layout->head_blob);
B
Behdad Esfahbod 已提交
73 74 75 76

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

B
Behdad Esfahbod 已提交
79
  free (layout);
80
}
B
Behdad Esfahbod 已提交
81

B
Behdad Esfahbod 已提交
82
static inline const GDEF&
83 84
_get_gdef (hb_face_t *face)
{
B
Behdad Esfahbod 已提交
85
  return likely (face->ot_layout && face->ot_layout->gdef) ? *face->ot_layout->gdef : Null(GDEF);
86
}
B
Behdad Esfahbod 已提交
87
static inline const GSUB&
88
_get_gsub (hb_face_t *face)
B
Behdad Esfahbod 已提交
89
{
B
Behdad Esfahbod 已提交
90
  return likely (face->ot_layout && face->ot_layout->gsub) ? *face->ot_layout->gsub : Null(GSUB);
B
Behdad Esfahbod 已提交
91
}
B
Behdad Esfahbod 已提交
92
static inline const GPOS&
93
_get_gpos (hb_face_t *face)
B
Behdad Esfahbod 已提交
94
{
B
Behdad Esfahbod 已提交
95
  return likely (face->ot_layout && face->ot_layout->gpos) ? *face->ot_layout->gpos : Null(GPOS);
B
Behdad Esfahbod 已提交
96
}
97 98 99 100 101
static inline const head&
_get_head (hb_face_t *face)
{
  return likely (face->ot_layout && face->ot_layout->head) ? *face->ot_layout->head : Null(head);
}
B
Behdad Esfahbod 已提交
102

103

B
Behdad Esfahbod 已提交
104 105 106 107 108
/*
 * GDEF
 */

hb_bool_t
109
hb_ot_layout_has_glyph_classes (hb_face_t *face)
B
Behdad Esfahbod 已提交
110
{
111
  return _get_gdef (face).has_glyph_classes ();
B
Behdad Esfahbod 已提交
112 113
}

B
Behdad Esfahbod 已提交
114
unsigned int
115 116 117
_hb_ot_layout_get_glyph_property (hb_face_t       *face,
				  hb_glyph_info_t *info)
{
B
Behdad Esfahbod 已提交
118
  if (!info->props_cache())
B
Behdad Esfahbod 已提交
119 120
  {
    const GDEF &gdef = _get_gdef (face);
B
Behdad Esfahbod 已提交
121
    info->props_cache() = gdef.get_glyph_props (info->codepoint);
B
Behdad Esfahbod 已提交
122
  }
123

B
Behdad Esfahbod 已提交
124
  return info->props_cache();
125 126
}

B
Behdad Esfahbod 已提交
127 128 129 130 131
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 已提交
132
{
133
  /* Not covered, if, for example, glyph class is ligature and
134
   * lookup_props includes LookupFlags::IgnoreLigatures
B
Behdad Esfahbod 已提交
135
   */
B
Behdad Esfahbod 已提交
136
  if (glyph_props & lookup_props & LookupFlag::IgnoreFlags)
B
Behdad Esfahbod 已提交
137 138
    return false;

B
Behdad Esfahbod 已提交
139
  if (glyph_props & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
B
Behdad Esfahbod 已提交
140
  {
B
Behdad Esfahbod 已提交
141
    /* If using mark filtering sets, the high short of
142
     * lookup_props has the set index.
B
Behdad Esfahbod 已提交
143
     */
144
    if (lookup_props & LookupFlag::UseMarkFilteringSet)
B
Behdad Esfahbod 已提交
145
      return _get_gdef (face).mark_set_covers (lookup_props >> 16, codepoint);
B
Behdad Esfahbod 已提交
146

147
    /* The second byte of lookup_props has the meaning
B
Behdad Esfahbod 已提交
148 149 150
     * "ignore marks of attachment type different than
     * the attachment type specified."
     */
B
Behdad Esfahbod 已提交
151 152
    if (lookup_props & LookupFlag::MarkAttachmentType && glyph_props & LookupFlag::MarkAttachmentType)
      return (lookup_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
B
Behdad Esfahbod 已提交
153 154
  }

B
Behdad Esfahbod 已提交
155
  return true;
B
Behdad Esfahbod 已提交
156 157
}

B
Behdad Esfahbod 已提交
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 184 185 186 187 188 189 190 191 192
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 已提交
193
unsigned int
194
hb_ot_layout_get_attach_points (hb_face_t      *face,
B
Behdad Esfahbod 已提交
195
				hb_codepoint_t  glyph,
B
Behdad Esfahbod 已提交
196
				unsigned int    start_offset,
B
Behdad Esfahbod 已提交
197 198 199
				unsigned int   *point_count /* IN/OUT */,
				unsigned int   *point_array /* OUT */)
{
B
Behdad Esfahbod 已提交
200
  return _get_gdef (face).get_attach_points (glyph, start_offset, point_count, point_array);
B
Behdad Esfahbod 已提交
201 202
}

B
Behdad Esfahbod 已提交
203
unsigned int
204 205 206 207 208 209
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 已提交
210
{
B
Behdad Esfahbod 已提交
211 212
  hb_ot_layout_context_t c;
  c.font = font;
213 214
  c.face = font->face;
  return _get_gdef (c.face).get_lig_carets (&c, direction, glyph, start_offset, caret_count, caret_array);
B
Behdad Esfahbod 已提交
215 216
}

217 218 219 220 221
/*
 * GSUB/GPOS
 */

static const GSUBGPOS&
222 223
get_gsubgpos_table (hb_face_t *face,
		    hb_tag_t   table_tag)
224
{
225
  switch (table_tag) {
226 227
    case HB_OT_TAG_GSUB: return _get_gsub (face);
    case HB_OT_TAG_GPOS: return _get_gpos (face);
228
    default:             return Null(GSUBGPOS);
229 230 231 232
  }
}


B
Behdad Esfahbod 已提交
233
unsigned int
234 235
hb_ot_layout_table_get_script_tags (hb_face_t    *face,
				    hb_tag_t      table_tag,
B
Behdad Esfahbod 已提交
236
				    unsigned int  start_offset,
237 238
				    unsigned int *script_count /* IN/OUT */,
				    hb_tag_t     *script_tags /* OUT */)
239
{
240
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
241

B
Behdad Esfahbod 已提交
242
  return g.get_script_tags (start_offset, script_count, script_tags);
243 244 245
}

hb_bool_t
246 247 248 249
hb_ot_layout_table_find_script (hb_face_t    *face,
				hb_tag_t      table_tag,
				hb_tag_t      script_tag,
				unsigned int *script_index)
250
{
B
Behdad Esfahbod 已提交
251
  ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
252
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
253 254 255 256 257

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

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

261 262
  /* try with 'dflt'; MS site has had typos and many fonts use it now :(.
   * including many versions of DejaVu Sans Mono! */
263
  if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index))
B
Behdad Esfahbod 已提交
264 265 266 267 268 269 270 271 272 273 274 275
    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 已提交
276
  ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
B
Behdad Esfahbod 已提交
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
  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))
292 293 294 295 296 297
    return FALSE;

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

B
Behdad Esfahbod 已提交
298
unsigned int
299 300
hb_ot_layout_table_get_feature_tags (hb_face_t    *face,
				     hb_tag_t      table_tag,
B
Behdad Esfahbod 已提交
301
				     unsigned int  start_offset,
302 303
				     unsigned int *feature_count /* IN/OUT */,
				     hb_tag_t     *feature_tags /* OUT */)
304
{
305
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
306

B
Behdad Esfahbod 已提交
307
  return g.get_feature_tags (start_offset, feature_count, feature_tags);
308 309 310
}


B
Behdad Esfahbod 已提交
311
unsigned int
312 313 314
hb_ot_layout_script_get_language_tags (hb_face_t    *face,
				       hb_tag_t      table_tag,
				       unsigned int  script_index,
B
Behdad Esfahbod 已提交
315
				       unsigned int  start_offset,
316 317
				       unsigned int *language_count /* IN/OUT */,
				       hb_tag_t     *language_tags /* OUT */)
318
{
319
  const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
320

B
Behdad Esfahbod 已提交
321
  return s.get_lang_sys_tags (start_offset, language_count, language_tags);
322 323 324
}

hb_bool_t
325 326 327 328 329
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)
330
{
B
Behdad Esfahbod 已提交
331
  ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
332
  const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
333

334
  if (s.find_lang_sys_index (language_tag, language_index))
335 336 337
    return TRUE;

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

341
  if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
342
  return FALSE;
343
}
344

345
hb_bool_t
346 347 348 349 350
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)
351
{
352
  const LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index);
353

354
  if (feature_index) *feature_index = l.get_required_feature_index ();
355

356 357
  return l.has_required_feature ();
}
358

B
Behdad Esfahbod 已提交
359
unsigned int
360 361 362 363
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 已提交
364
					   unsigned int  start_offset,
365 366
					   unsigned int *feature_count /* IN/OUT */,
					   unsigned int *feature_indexes /* OUT */)
367
{
368
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
369 370
  const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);

B
Behdad Esfahbod 已提交
371
  return l.get_feature_indexes (start_offset, feature_count, feature_indexes);
372 373
}

B
Behdad Esfahbod 已提交
374
unsigned int
375 376 377 378
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 已提交
379
					unsigned int  start_offset,
380 381
					unsigned int *feature_count /* IN/OUT */,
					hb_tag_t     *feature_tags /* OUT */)
382
{
383
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
384
  const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
385

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

B
Behdad Esfahbod 已提交
389 390 391 392 393
  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]);
  }
394 395

  return ret;
396 397 398 399
}


hb_bool_t
400 401 402 403 404 405
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)
406
{
B
Behdad Esfahbod 已提交
407
  ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
408
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
409 410
  const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);

B
Behdad Esfahbod 已提交
411 412
  unsigned int num_features = l.get_feature_count ();
  for (unsigned int i = 0; i < num_features; i++) {
413 414 415 416 417 418 419
    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;
    }
  }
420

421
  if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
422 423
  return FALSE;
}
424

B
Behdad Esfahbod 已提交
425
unsigned int
426 427 428
hb_ot_layout_feature_get_lookup_indexes (hb_face_t    *face,
					 hb_tag_t      table_tag,
					 unsigned int  feature_index,
B
Behdad Esfahbod 已提交
429
					 unsigned int  start_offset,
430 431
					 unsigned int *lookup_count /* IN/OUT */,
					 unsigned int *lookup_indexes /* OUT */)
432
{
433
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
434 435
  const Feature &f = g.get_feature (feature_index);

B
Behdad Esfahbod 已提交
436
  return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
437 438
}

B
Behdad Esfahbod 已提交
439 440 441 442 443 444

/*
 * GSUB
 */

hb_bool_t
445 446
hb_ot_layout_has_substitution (hb_face_t *face)
{
447
  return &_get_gsub (face) != &Null(GSUB);
448 449 450
}

hb_bool_t
451 452 453 454
hb_ot_layout_substitute_lookup (hb_face_t    *face,
				hb_buffer_t  *buffer,
				unsigned int  lookup_index,
				hb_mask_t     mask)
B
Behdad Esfahbod 已提交
455
{
B
Behdad Esfahbod 已提交
456 457 458 459
  hb_ot_layout_context_t c;
  c.font = NULL;
  c.face = face;
  return _get_gsub (face).substitute_lookup (&c, buffer, lookup_index, mask);
460 461
}

462

463 464 465 466 467
/*
 * GPOS
 */

hb_bool_t
468 469
hb_ot_layout_has_positioning (hb_face_t *face)
{
470
  return &_get_gpos (face) != &Null(GPOS);
471 472
}

473 474 475 476 477 478
void
hb_ot_layout_position_start (hb_buffer_t  *buffer)
{
  buffer->clear_positions ();
}

479
hb_bool_t
480
hb_ot_layout_position_lookup   (hb_font_t    *font,
481 482 483
				hb_buffer_t  *buffer,
				unsigned int  lookup_index,
				hb_mask_t     mask)
484
{
B
Behdad Esfahbod 已提交
485 486
  hb_ot_layout_context_t c;
  c.font = font;
487 488
  c.face = font->face;
  return _get_gpos (c.face).position_lookup (&c, buffer, lookup_index, mask);
489
}
490 491

void
B
Behdad Esfahbod 已提交
492
hb_ot_layout_position_finish (hb_buffer_t  *buffer)
493
{
B
Behdad Esfahbod 已提交
494
  GPOS::position_finish (buffer);
495
}
B
Behdad Esfahbod 已提交
496 497


498 499 500 501 502 503 504 505 506 507 508
/*
 * head
 */

unsigned int
_hb_ot_layout_get_upem (hb_face_t *face)
{
  return _get_head (face).get_upem ();
}


B
Behdad Esfahbod 已提交
509
HB_END_DECLS