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
#include "hb-ot-maxp-private.hh"
B
Behdad Esfahbod 已提交
38

B
Behdad Esfahbod 已提交
39

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

B
Behdad Esfahbod 已提交
43 44
HB_BEGIN_DECLS

B
Behdad Esfahbod 已提交
45

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

61 62 63
  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 已提交
64
  return layout;
B
Behdad Esfahbod 已提交
65 66
}

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

B
Behdad Esfahbod 已提交
75
  free (layout);
76
}
B
Behdad Esfahbod 已提交
77

B
Behdad Esfahbod 已提交
78
static inline const GDEF&
79 80
_get_gdef (hb_face_t *face)
{
B
Behdad Esfahbod 已提交
81
  return likely (face->ot_layout && face->ot_layout->gdef) ? *face->ot_layout->gdef : Null(GDEF);
82
}
B
Behdad Esfahbod 已提交
83
static inline const GSUB&
84
_get_gsub (hb_face_t *face)
B
Behdad Esfahbod 已提交
85
{
B
Behdad Esfahbod 已提交
86
  return likely (face->ot_layout && face->ot_layout->gsub) ? *face->ot_layout->gsub : Null(GSUB);
B
Behdad Esfahbod 已提交
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 95 96 97
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 已提交
98

99

B
Behdad Esfahbod 已提交
100 101 102 103 104
/*
 * GDEF
 */

hb_bool_t
105
hb_ot_layout_has_glyph_classes (hb_face_t *face)
B
Behdad Esfahbod 已提交
106
{
107
  return _get_gdef (face).has_glyph_classes ();
B
Behdad Esfahbod 已提交
108 109
}

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

B
Behdad Esfahbod 已提交
120
  return info->props_cache();
121 122
}

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

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

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

B
Behdad Esfahbod 已提交
151
  return true;
B
Behdad Esfahbod 已提交
152 153
}

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

B
Behdad Esfahbod 已提交
199
unsigned int
200 201 202 203 204 205
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 已提交
206
{
207
  return _get_gdef (font->face).get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);
B
Behdad Esfahbod 已提交
208 209
}

210 211 212 213 214
/*
 * GSUB/GPOS
 */

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


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

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

hb_bool_t
239 240 241 242
hb_ot_layout_table_find_script (hb_face_t    *face,
				hb_tag_t      table_tag,
				hb_tag_t      script_tag,
				unsigned int *script_index)
243
{
B
Behdad Esfahbod 已提交
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 248 249 250

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

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

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

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

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

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


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

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

hb_bool_t
318 319 320 321 322
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)
323
{
B
Behdad Esfahbod 已提交
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 329 330
    return TRUE;

  /* 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 333
    return FALSE;

334
  if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
335
  return FALSE;
336
}
337

338
hb_bool_t
339 340 341 342 343
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)
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 350
  return l.has_required_feature ();
}
351

B
Behdad Esfahbod 已提交
352
unsigned int
353 354 355 356
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 已提交
357
					   unsigned int  start_offset,
358 359
					   unsigned int *feature_count /* IN/OUT */,
					   unsigned int *feature_indexes /* OUT */)
360
{
361
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
362 363
  const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);

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

B
Behdad Esfahbod 已提交
367
unsigned int
368 369 370 371
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 已提交
372
					unsigned int  start_offset,
373 374
					unsigned int *feature_count /* IN/OUT */,
					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));
B
Behdad Esfahbod 已提交
380
  unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags);
381

B
Behdad Esfahbod 已提交
382 383 384 385 386
  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]);
  }
387 388

  return ret;
389 390 391 392
}


hb_bool_t
393 394 395 396 397 398
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)
399
{
B
Behdad Esfahbod 已提交
400
  ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
401
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
402 403
  const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);

B
Behdad Esfahbod 已提交
404 405
  unsigned int num_features = l.get_feature_count ();
  for (unsigned int i = 0; i < num_features; i++) {
406 407 408 409 410 411 412
    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;
    }
  }
413

414
  if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
415 416
  return FALSE;
}
417

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

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

B
Behdad Esfahbod 已提交
432 433 434 435 436 437

/*
 * GSUB
 */

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

443 444 445 446
void
hb_ot_layout_substitute_start (hb_buffer_t  *buffer)
{
  unsigned int count = buffer->len;
447
  /* XXX */
448 449 450 451
  for (unsigned int i = 0; i < count; i++)
    buffer->info[i].var1.u32 = buffer->info[i].var2.u32 = 0;
}

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

461
void
462
hb_ot_layout_substitute_finish (hb_buffer_t  *buffer HB_UNUSED)
463 464 465
{
}

466

467 468 469 470 471
/*
 * GPOS
 */

hb_bool_t
472 473
hb_ot_layout_has_positioning (hb_face_t *face)
{
474
  return &_get_gpos (face) != &Null(GPOS);
475 476
}

477 478 479 480 481 482
void
hb_ot_layout_position_start (hb_buffer_t  *buffer)
{
  buffer->clear_positions ();
}

483
hb_bool_t
484
hb_ot_layout_position_lookup   (hb_font_t    *font,
485 486 487
				hb_buffer_t  *buffer,
				unsigned int  lookup_index,
				hb_mask_t     mask)
488
{
489
  return _get_gpos (font->face).position_lookup (font, buffer, lookup_index, mask);
490
}
491 492

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


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

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


B
Behdad Esfahbod 已提交
510
HB_END_DECLS