hb-ot-layout.cc 13.7 KB
Newer Older
B
Behdad Esfahbod 已提交
1
/*
B
Behdad Esfahbod 已提交
2 3
 * Copyright (C) 1998-2004  David Turner and Werner Lemberg
 * Copyright (C) 2006  Behdad Esfahbod
B
Behdad Esfahbod 已提交
4
 * Copyright (C) 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_get_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_get_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_get_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 201
hb_ot_layout_get_ligature_carets (hb_font_t      *font,
				  hb_face_t      *face,
				  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 已提交
202
{
B
Behdad Esfahbod 已提交
203 204 205
  hb_ot_layout_context_t c;
  c.font = font;
  c.face = face;
206
  return _get_gdef (face).get_lig_carets (&c, direction, glyph, start_offset, caret_count, caret_array);
B
Behdad Esfahbod 已提交
207 208
}

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

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


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

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

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

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

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

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

  if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
  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
}

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

454

455 456 457 458 459
/*
 * GPOS
 */

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

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

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

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


HB_END_DECLS