hb-ot-layout.cc 13.9 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
 *
 * 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
 */

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

31 32 33 34
#include "hb-ot-layout-gdef-table.hh"
#include "hb-ot-layout-gsub-table.hh"
#include "hb-ot-layout-gpos-table.hh"
#include "hb-ot-maxp-table.hh"
B
Behdad Esfahbod 已提交
35

B
Behdad Esfahbod 已提交
36

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

B
Behdad Esfahbod 已提交
40

B
Behdad Esfahbod 已提交
41

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

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

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

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

  return layout;
B
Behdad Esfahbod 已提交
58 59
}

60
void
61
_hb_ot_layout_destroy (hb_ot_layout_t *layout)
B
Behdad Esfahbod 已提交
62
{
B
Behdad Esfahbod 已提交
63 64 65
  hb_blob_destroy (layout->gdef_blob);
  hb_blob_destroy (layout->gsub_blob);
  hb_blob_destroy (layout->gpos_blob);
B
Behdad Esfahbod 已提交
66

B
Behdad Esfahbod 已提交
67
  free (layout);
68
}
B
Behdad Esfahbod 已提交
69

B
Behdad Esfahbod 已提交
70
static inline const GDEF&
71 72
_get_gdef (hb_face_t *face)
{
B
Behdad Esfahbod 已提交
73
  return likely (face->ot_layout && face->ot_layout->gdef) ? *face->ot_layout->gdef : Null(GDEF);
74
}
B
Behdad Esfahbod 已提交
75
static inline const GSUB&
76
_get_gsub (hb_face_t *face)
B
Behdad Esfahbod 已提交
77
{
B
Behdad Esfahbod 已提交
78
  return likely (face->ot_layout && face->ot_layout->gsub) ? *face->ot_layout->gsub : Null(GSUB);
B
Behdad Esfahbod 已提交
79
}
B
Behdad Esfahbod 已提交
80
static inline const GPOS&
81
_get_gpos (hb_face_t *face)
B
Behdad Esfahbod 已提交
82
{
B
Behdad Esfahbod 已提交
83
  return likely (face->ot_layout && face->ot_layout->gpos) ? *face->ot_layout->gpos : Null(GPOS);
B
Behdad Esfahbod 已提交
84 85
}

86

B
Behdad Esfahbod 已提交
87 88 89 90 91
/*
 * GDEF
 */

hb_bool_t
92
hb_ot_layout_has_glyph_classes (hb_face_t *face)
B
Behdad Esfahbod 已提交
93
{
94
  return _get_gdef (face).has_glyph_classes ();
B
Behdad Esfahbod 已提交
95 96
}

B
Behdad Esfahbod 已提交
97
unsigned int
98 99 100
_hb_ot_layout_get_glyph_property (hb_face_t       *face,
				  hb_glyph_info_t *info)
{
B
Behdad Esfahbod 已提交
101
  if (!info->props_cache())
B
Behdad Esfahbod 已提交
102 103
  {
    const GDEF &gdef = _get_gdef (face);
B
Behdad Esfahbod 已提交
104
    info->props_cache() = gdef.get_glyph_props (info->codepoint);
B
Behdad Esfahbod 已提交
105
  }
106

B
Behdad Esfahbod 已提交
107
  return info->props_cache();
108 109
}

B
Behdad Esfahbod 已提交
110 111 112 113 114
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 已提交
115
{
116
  /* Not covered, if, for example, glyph class is ligature and
117
   * lookup_props includes LookupFlags::IgnoreLigatures
B
Behdad Esfahbod 已提交
118
   */
B
Behdad Esfahbod 已提交
119
  if (glyph_props & lookup_props & LookupFlag::IgnoreFlags)
B
Behdad Esfahbod 已提交
120 121
    return false;

B
Behdad Esfahbod 已提交
122
  if (glyph_props & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
B
Behdad Esfahbod 已提交
123
  {
B
Behdad Esfahbod 已提交
124
    /* If using mark filtering sets, the high short of
125
     * lookup_props has the set index.
B
Behdad Esfahbod 已提交
126
     */
127
    if (lookup_props & LookupFlag::UseMarkFilteringSet)
B
Behdad Esfahbod 已提交
128
      return _get_gdef (face).mark_set_covers (lookup_props >> 16, codepoint);
B
Behdad Esfahbod 已提交
129

130
    /* The second byte of lookup_props has the meaning
B
Behdad Esfahbod 已提交
131 132 133
     * "ignore marks of attachment type different than
     * the attachment type specified."
     */
B
Behdad Esfahbod 已提交
134 135
    if (lookup_props & LookupFlag::MarkAttachmentType && glyph_props & LookupFlag::MarkAttachmentType)
      return (lookup_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
B
Behdad Esfahbod 已提交
136 137
  }

B
Behdad Esfahbod 已提交
138
  return true;
B
Behdad Esfahbod 已提交
139 140
}

B
Behdad Esfahbod 已提交
141 142 143 144 145 146 147 148 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
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 已提交
176
unsigned int
177
hb_ot_layout_get_attach_points (hb_face_t      *face,
B
Behdad Esfahbod 已提交
178
				hb_codepoint_t  glyph,
B
Behdad Esfahbod 已提交
179
				unsigned int    start_offset,
B
Behdad Esfahbod 已提交
180 181 182
				unsigned int   *point_count /* IN/OUT */,
				unsigned int   *point_array /* OUT */)
{
B
Behdad Esfahbod 已提交
183
  return _get_gdef (face).get_attach_points (glyph, start_offset, point_count, point_array);
B
Behdad Esfahbod 已提交
184 185
}

B
Behdad Esfahbod 已提交
186
unsigned int
187 188 189 190 191 192
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 已提交
193
{
194
  return _get_gdef (font->face).get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);
B
Behdad Esfahbod 已提交
195 196
}

197 198 199 200 201
/*
 * GSUB/GPOS
 */

static const GSUBGPOS&
202 203
get_gsubgpos_table (hb_face_t *face,
		    hb_tag_t   table_tag)
204
{
205
  switch (table_tag) {
206 207
    case HB_OT_TAG_GSUB: return _get_gsub (face);
    case HB_OT_TAG_GPOS: return _get_gpos (face);
208
    default:             return Null(GSUBGPOS);
209 210 211 212
  }
}


B
Behdad Esfahbod 已提交
213
unsigned int
214 215
hb_ot_layout_table_get_script_tags (hb_face_t    *face,
				    hb_tag_t      table_tag,
B
Behdad Esfahbod 已提交
216
				    unsigned int  start_offset,
217 218
				    unsigned int *script_count /* IN/OUT */,
				    hb_tag_t     *script_tags /* OUT */)
219
{
220
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
221

B
Behdad Esfahbod 已提交
222
  return g.get_script_tags (start_offset, script_count, script_tags);
223 224 225
}

hb_bool_t
226 227 228 229
hb_ot_layout_table_find_script (hb_face_t    *face,
				hb_tag_t      table_tag,
				hb_tag_t      script_tag,
				unsigned int *script_index)
230
{
B
Behdad Esfahbod 已提交
231
  ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
232
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
233 234 235 236 237

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

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

241 242
  /* try with 'dflt'; MS site has had typos and many fonts use it now :(.
   * including many versions of DejaVu Sans Mono! */
243
  if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index))
B
Behdad Esfahbod 已提交
244 245 246 247 248 249 250 251 252 253
    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,
B
Behdad Esfahbod 已提交
254 255
				  unsigned int   *script_index,
				  hb_tag_t       *chosen_script)
B
Behdad Esfahbod 已提交
256
{
B
Behdad Esfahbod 已提交
257
  ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
B
Behdad Esfahbod 已提交
258 259 260 261
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);

  while (*script_tags)
  {
B
Behdad Esfahbod 已提交
262 263 264
    if (g.find_script_index (*script_tags, script_index)) {
      if (chosen_script)
        *chosen_script = *script_tags;
B
Behdad Esfahbod 已提交
265
      return TRUE;
B
Behdad Esfahbod 已提交
266
    }
B
Behdad Esfahbod 已提交
267 268 269 270
    script_tags++;
  }

  /* try finding 'DFLT' */
B
Behdad Esfahbod 已提交
271 272 273
  if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) {
    if (chosen_script)
      *chosen_script = HB_OT_TAG_DEFAULT_SCRIPT;
B
Behdad Esfahbod 已提交
274
    return FALSE;
B
Behdad Esfahbod 已提交
275
  }
B
Behdad Esfahbod 已提交
276 277

  /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
B
Behdad Esfahbod 已提交
278 279 280
  if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) {
    if (chosen_script)
      *chosen_script = HB_OT_TAG_DEFAULT_LANGUAGE;
281
    return FALSE;
B
Behdad Esfahbod 已提交
282
  }
283 284

  if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
B
Behdad Esfahbod 已提交
285 286
  if (chosen_script)
    *chosen_script = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
287 288 289
  return FALSE;
}

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

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


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

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

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

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

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

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

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

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

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

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

  return ret;
388 389 390 391
}


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

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

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

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

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

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

/*
 * GSUB
 */

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

442 443 444
void
hb_ot_layout_substitute_start (hb_buffer_t  *buffer)
{
B
Behdad Esfahbod 已提交
445
  GSUB::substitute_start (buffer);
446 447
}

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

457
void
458
hb_ot_layout_substitute_finish (hb_buffer_t  *buffer HB_UNUSED)
459
{
B
Behdad Esfahbod 已提交
460
  GSUB::substitute_finish (buffer);
461 462
}

463

464 465 466 467 468
/*
 * GPOS
 */

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

474 475 476
void
hb_ot_layout_position_start (hb_buffer_t  *buffer)
{
B
Behdad Esfahbod 已提交
477
  GPOS::position_start (buffer);
478 479
}

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

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