hb-ot-layout.cc 18.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 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
 *
 *  This is part of HarfBuzz, an OpenType Layout engine library.
 *
 * 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

#include "hb-ot-layout-private.h"

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
void
B
Behdad Esfahbod 已提交
43
_hb_ot_layout_init (hb_face_t *face)
44
{
B
Behdad Esfahbod 已提交
45 46
  hb_ot_layout_t *layout = &face->ot_layout;

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

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

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

57
void
B
Behdad Esfahbod 已提交
58
_hb_ot_layout_fini (hb_face_t *face)
B
Behdad Esfahbod 已提交
59
{
B
Behdad Esfahbod 已提交
60
  hb_ot_layout_t *layout = &face->ot_layout;
B
Behdad Esfahbod 已提交
61

B
Behdad Esfahbod 已提交
62 63 64 65 66 67 68
  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 已提交
69 70

  free (layout->new_gdef.klasses);
71
}
B
Behdad Esfahbod 已提交
72

73 74 75
static const GDEF&
_get_gdef (hb_face_t *face)
{
B
Behdad Esfahbod 已提交
76
  return HB_LIKELY (face->ot_layout.gdef) ? *face->ot_layout.gdef : Null(GDEF);
77
}
B
Behdad Esfahbod 已提交
78

79 80
static const GSUB&
_get_gsub (hb_face_t *face)
B
Behdad Esfahbod 已提交
81
{
B
Behdad Esfahbod 已提交
82
  return HB_LIKELY (face->ot_layout.gsub) ? *face->ot_layout.gsub : Null(GSUB);
B
Behdad Esfahbod 已提交
83 84
}

85 86
static const GPOS&
_get_gpos (hb_face_t *face)
B
Behdad Esfahbod 已提交
87
{
B
Behdad Esfahbod 已提交
88
  return HB_LIKELY (face->ot_layout.gpos) ? *face->ot_layout.gpos : Null(GPOS);
B
Behdad Esfahbod 已提交
89 90
}

91

B
Behdad Esfahbod 已提交
92 93 94 95
/*
 * GDEF
 */

B
Behdad Esfahbod 已提交
96
/* TODO the public class_t is a mess */
B
Behdad Esfahbod 已提交
97

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

B
Behdad Esfahbod 已提交
104
hb_bool_t
105
_hb_ot_layout_has_new_glyph_classes (hb_face_t *face)
B
Behdad Esfahbod 已提交
106
{
107
  return face->ot_layout.new_gdef.len > 0;
B
Behdad Esfahbod 已提交
108 109
}

110 111
static unsigned int
_hb_ot_layout_get_glyph_property (hb_face_t      *face,
B
Behdad Esfahbod 已提交
112
				  hb_codepoint_t  glyph)
B
Behdad Esfahbod 已提交
113
{
B
Behdad Esfahbod 已提交
114
  hb_ot_layout_class_t klass;
115
  const GDEF &gdef = _get_gdef (face);
B
Behdad Esfahbod 已提交
116

117
  klass = gdef.get_glyph_class (glyph);
B
Behdad Esfahbod 已提交
118

119 120
  if (!klass && glyph < face->ot_layout.new_gdef.len)
    klass = face->ot_layout.new_gdef.klasses[glyph];
B
Behdad Esfahbod 已提交
121 122 123 124 125 126 127

  switch (klass) {
  default:
  case GDEF::UnclassifiedGlyph:	return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED;
  case GDEF::BaseGlyph:		return HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
  case GDEF::LigatureGlyph:	return HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE;
  case GDEF::ComponentGlyph:	return HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT;
128
  case GDEF::MarkGlyph:
129
	klass = gdef.get_mark_attachment_type (glyph);
B
Behdad Esfahbod 已提交
130
	return HB_OT_LAYOUT_GLYPH_CLASS_MARK + (klass << 8);
B
Behdad Esfahbod 已提交
131
  }
B
Behdad Esfahbod 已提交
132
}
B
Behdad Esfahbod 已提交
133

B
Behdad Esfahbod 已提交
134
hb_bool_t
135
_hb_ot_layout_check_glyph_property (hb_face_t    *face,
136
				    hb_internal_glyph_info_t *ginfo,
137 138
				    unsigned int  lookup_flags,
				    unsigned int *property_out)
B
Behdad Esfahbod 已提交
139
{
140
  unsigned int property;
B
Behdad Esfahbod 已提交
141

142
  if (ginfo->gproperty == HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN)
143
    ginfo->gproperty = _hb_ot_layout_get_glyph_property (face, ginfo->codepoint);
144
  property = ginfo->gproperty;
145 146
  if (property_out)
    *property_out = property;
B
Behdad Esfahbod 已提交
147

148
  /* Not covered, if, for example, glyph class is ligature and
B
Behdad Esfahbod 已提交
149
   * lookup_flags includes LookupFlags::IgnoreLigatures
B
Behdad Esfahbod 已提交
150
   */
B
Behdad Esfahbod 已提交
151
  if (property & lookup_flags & LookupFlag::IgnoreFlags)
B
Behdad Esfahbod 已提交
152 153
    return false;

154
  if (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
B
Behdad Esfahbod 已提交
155
  {
B
Behdad Esfahbod 已提交
156
    /* If using mark filtering sets, the high short of
157
     * lookup_flags has the set index.
B
Behdad Esfahbod 已提交
158 159
     */
    if (lookup_flags & LookupFlag::UseMarkFilteringSet)
160
      return _get_gdef (face).mark_set_covers (lookup_flags >> 16, ginfo->codepoint);
B
Behdad Esfahbod 已提交
161 162 163 164 165

    /* The second byte of lookup_flags has the meaning
     * "ignore marks of attachment type different than
     * the attachment type specified."
     */
166 167
    if (lookup_flags & LookupFlag::MarkAttachmentType && property & LookupFlag::MarkAttachmentType)
      return (lookup_flags & LookupFlag::MarkAttachmentType) == (property & LookupFlag::MarkAttachmentType);
B
Behdad Esfahbod 已提交
168 169
  }

B
Behdad Esfahbod 已提交
170
  return true;
B
Behdad Esfahbod 已提交
171 172
}

B
Behdad Esfahbod 已提交
173
hb_bool_t
174
_hb_ot_layout_skip_mark (hb_face_t    *face,
175
			 hb_internal_glyph_info_t *ginfo,
176 177
			 unsigned int  lookup_flags,
			 unsigned int *property_out)
178 179 180
{
  unsigned int property;

181
  if (ginfo->gproperty == HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN)
182
    ginfo->gproperty = _hb_ot_layout_get_glyph_property (face, ginfo->codepoint);
183
  property = ginfo->gproperty;
184 185 186 187 188 189 190 191 192 193 194
  if (property_out)
    *property_out = property;

  if (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
  {
    /* Skip mark if lookup_flags includes LookupFlags::IgnoreMarks */
    if (lookup_flags & LookupFlag::IgnoreMarks)
      return true;

    /* If using mark filtering sets, the high short of lookup_flags has the set index. */
    if (lookup_flags & LookupFlag::UseMarkFilteringSet)
195
      return !_get_gdef (face).mark_set_covers (lookup_flags >> 16, ginfo->codepoint);
196 197 198 199 200 201 202 203 204 205

    /* The second byte of lookup_flags has the meaning "ignore marks of attachment type
     * different than the attachment type specified." */
    if (lookup_flags & LookupFlag::MarkAttachmentType && property & LookupFlag::MarkAttachmentType)
      return (lookup_flags & LookupFlag::MarkAttachmentType) != (property & LookupFlag::MarkAttachmentType);
  }

  return false;
}

B
Behdad Esfahbod 已提交
206
void
207
_hb_ot_layout_set_glyph_class (hb_face_t                  *face,
208 209
			       hb_codepoint_t              glyph,
			       hb_ot_layout_glyph_class_t  klass)
B
Behdad Esfahbod 已提交
210
{
211 212 213
  if (HB_OBJECT_IS_INERT (face))
    return;

B
Behdad Esfahbod 已提交
214
  /* TODO optimize this? similar to old harfbuzz code for example */
B
Behdad Esfahbod 已提交
215

216
  hb_ot_layout_t *layout = &face->ot_layout;
B
Behdad Esfahbod 已提交
217
  hb_ot_layout_class_t gdef_klass;
B
Behdad Esfahbod 已提交
218
  unsigned int len = layout->new_gdef.len;
B
Behdad Esfahbod 已提交
219

B
Behdad Esfahbod 已提交
220
  if (HB_UNLIKELY (glyph > 65535))
B
Behdad Esfahbod 已提交
221 222
    return;

B
Behdad Esfahbod 已提交
223
  /* XXX this is not threadsafe */
B
Behdad Esfahbod 已提交
224
  if (glyph >= len) {
B
Behdad Esfahbod 已提交
225
    unsigned int new_len;
B
Behdad Esfahbod 已提交
226
    unsigned char *new_klasses;
B
Behdad Esfahbod 已提交
227 228

    new_len = len == 0 ? 120 : 2 * len;
B
Behdad Esfahbod 已提交
229 230 231
    while (new_len <= glyph)
      new_len *= 2;

B
Behdad Esfahbod 已提交
232 233
    if (new_len > 65536)
      new_len = 65536;
B
Behdad Esfahbod 已提交
234
    new_klasses = (unsigned char *) realloc (layout->new_gdef.klasses, new_len * sizeof (unsigned char));
B
Behdad Esfahbod 已提交
235

B
Behdad Esfahbod 已提交
236
    if (HB_UNLIKELY (!new_klasses))
B
Behdad Esfahbod 已提交
237
      return;
B
Behdad Esfahbod 已提交
238

B
Behdad Esfahbod 已提交
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
    memset (new_klasses + len, 0, new_len - len);

    layout->new_gdef.klasses = new_klasses;
    layout->new_gdef.len = new_len;
  }

  switch (klass) {
  default:
  case HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED:	gdef_klass = GDEF::UnclassifiedGlyph;	break;
  case HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH:	gdef_klass = GDEF::BaseGlyph;		break;
  case HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE:	gdef_klass = GDEF::LigatureGlyph;	break;
  case HB_OT_LAYOUT_GLYPH_CLASS_MARK:		gdef_klass = GDEF::MarkGlyph;		break;
  case HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT:	gdef_klass = GDEF::ComponentGlyph;	break;
  }

  layout->new_gdef.klasses[glyph] = gdef_klass;
  return;
}
B
Behdad Esfahbod 已提交
257

B
Behdad Esfahbod 已提交
258
void
259
_hb_ot_layout_set_glyph_property (hb_face_t      *face,
260 261
				  hb_codepoint_t  glyph,
				  unsigned int    property)
262
{ _hb_ot_layout_set_glyph_class (face, glyph, (hb_ot_layout_glyph_class_t) (property & 0xff)); }
263 264 265 266 267 268


hb_ot_layout_glyph_class_t
hb_ot_layout_get_glyph_class (hb_face_t      *face,
			      hb_codepoint_t  glyph)
{
269
  return (hb_ot_layout_glyph_class_t) (_hb_ot_layout_get_glyph_property (face, glyph) & 0xff);
270 271
}

B
Behdad Esfahbod 已提交
272
void
273 274 275 276
hb_ot_layout_set_glyph_class (hb_face_t                 *face,
			      hb_codepoint_t             glyph,
			      hb_ot_layout_glyph_class_t klass)
{
277
  _hb_ot_layout_set_glyph_class (face, glyph, klass);
278 279 280 281
}

void
hb_ot_layout_build_glyph_classes (hb_face_t      *face,
282
				  uint16_t        num_total_glyphs,
B
Behdad Esfahbod 已提交
283
				  hb_codepoint_t *glyphs,
284 285
				  unsigned char  *klasses,
				  uint16_t        count)
B
Behdad Esfahbod 已提交
286
{
287 288 289 290
  if (HB_OBJECT_IS_INERT (face))
    return;

  hb_ot_layout_t *layout = &face->ot_layout;
291

B
Behdad Esfahbod 已提交
292
  if (HB_UNLIKELY (!count || !glyphs || !klasses))
B
Behdad Esfahbod 已提交
293 294 295 296 297 298 299
    return;

  if (layout->new_gdef.len == 0) {
    layout->new_gdef.klasses = (unsigned char *) calloc (num_total_glyphs, sizeof (unsigned char));
    layout->new_gdef.len = count;
  }

B
Behdad Esfahbod 已提交
300
  for (unsigned int i = 0; i < count; i++)
301
    _hb_ot_layout_set_glyph_class (face, glyphs[i], (hb_ot_layout_glyph_class_t) klasses[i]);
B
Behdad Esfahbod 已提交
302
}
303

B
Behdad Esfahbod 已提交
304
unsigned int
305
hb_ot_layout_get_attach_points (hb_face_t      *face,
B
Behdad Esfahbod 已提交
306
				hb_codepoint_t  glyph,
B
Behdad Esfahbod 已提交
307
				unsigned int    start_offset,
B
Behdad Esfahbod 已提交
308 309 310
				unsigned int   *point_count /* IN/OUT */,
				unsigned int   *point_array /* OUT */)
{
B
Behdad Esfahbod 已提交
311
  return _get_gdef (face).get_attach_points (glyph, start_offset, point_count, point_array);
B
Behdad Esfahbod 已提交
312 313
}

B
Behdad Esfahbod 已提交
314
unsigned int
315 316
hb_ot_layout_get_lig_carets (hb_font_t      *font,
			     hb_face_t      *face,
B
Behdad Esfahbod 已提交
317
			     hb_codepoint_t  glyph,
B
Behdad Esfahbod 已提交
318
			     unsigned int    start_offset,
B
Behdad Esfahbod 已提交
319 320 321
			     unsigned int   *caret_count /* IN/OUT */,
			     int            *caret_array /* OUT */)
{
322 323
  hb_ot_layout_context_t context;
  context.font = font;
324
  context.face = face;
B
Behdad Esfahbod 已提交
325
  return _get_gdef (face).get_lig_carets (&context, glyph, start_offset, caret_count, caret_array);
B
Behdad Esfahbod 已提交
326 327
}

328 329 330 331 332
/*
 * GSUB/GPOS
 */

static const GSUBGPOS&
333 334
get_gsubgpos_table (hb_face_t *face,
		    hb_tag_t   table_tag)
335
{
336
  switch (table_tag) {
337 338
    case HB_OT_TAG_GSUB: return _get_gsub (face);
    case HB_OT_TAG_GPOS: return _get_gpos (face);
339
    default:             return Null(GSUBGPOS);
340 341 342 343
  }
}


B
Behdad Esfahbod 已提交
344
unsigned int
345 346
hb_ot_layout_table_get_script_tags (hb_face_t    *face,
				    hb_tag_t      table_tag,
B
Behdad Esfahbod 已提交
347
				    unsigned int  start_offset,
348 349
				    unsigned int *script_count /* IN/OUT */,
				    hb_tag_t     *script_tags /* OUT */)
350
{
351
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
352

B
Behdad Esfahbod 已提交
353
  return g.get_script_tags (start_offset, script_count, script_tags);
354 355 356
}

hb_bool_t
357 358 359 360
hb_ot_layout_table_find_script (hb_face_t    *face,
				hb_tag_t      table_tag,
				hb_tag_t      script_tag,
				unsigned int *script_index)
361
{
362
  ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
363
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
364 365 366 367 368

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

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

  /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
373
  if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index))
B
Behdad Esfahbod 已提交
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
    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)
{
  ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
  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))
402 403 404 405 406 407
    return FALSE;

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

B
Behdad Esfahbod 已提交
408
unsigned int
409 410
hb_ot_layout_table_get_feature_tags (hb_face_t    *face,
				     hb_tag_t      table_tag,
B
Behdad Esfahbod 已提交
411
				     unsigned int  start_offset,
412 413
				     unsigned int *feature_count /* IN/OUT */,
				     hb_tag_t     *feature_tags /* OUT */)
414
{
415
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
416

B
Behdad Esfahbod 已提交
417
  return g.get_feature_tags (start_offset, feature_count, feature_tags);
418 419 420
}


B
Behdad Esfahbod 已提交
421
unsigned int
422 423 424
hb_ot_layout_script_get_language_tags (hb_face_t    *face,
				       hb_tag_t      table_tag,
				       unsigned int  script_index,
B
Behdad Esfahbod 已提交
425
				       unsigned int  start_offset,
426 427
				       unsigned int *language_count /* IN/OUT */,
				       hb_tag_t     *language_tags /* OUT */)
428
{
429
  const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
430

B
Behdad Esfahbod 已提交
431
  return s.get_lang_sys_tags (start_offset, language_count, language_tags);
432 433 434
}

hb_bool_t
435 436 437 438 439
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)
440
{
441
  ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
442
  const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
443

444
  if (s.find_lang_sys_index (language_tag, language_index))
445 446 447
    return TRUE;

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

451
  if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
452
  return FALSE;
453
}
454

455
hb_bool_t
456 457 458 459 460
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)
461
{
462
  const LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index);
463

464
  if (feature_index) *feature_index = l.get_required_feature_index ();
465

466 467
  return l.has_required_feature ();
}
468

B
Behdad Esfahbod 已提交
469
unsigned int
470 471 472 473
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 已提交
474
					   unsigned int  start_offset,
475 476
					   unsigned int *feature_count /* IN/OUT */,
					   unsigned int *feature_indexes /* OUT */)
477
{
478
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
479 480
  const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);

B
Behdad Esfahbod 已提交
481
  return l.get_feature_indexes (start_offset, feature_count, feature_indexes);
482 483
}

B
Behdad Esfahbod 已提交
484
unsigned int
485 486 487 488
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 已提交
489
					unsigned int  start_offset,
490 491
					unsigned int *feature_count /* IN/OUT */,
					hb_tag_t     *feature_tags /* OUT */)
492
{
493
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
494
  const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
495

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

B
Behdad Esfahbod 已提交
499 500 501 502 503
  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]);
  }
504 505

  return ret;
506 507 508 509
}


hb_bool_t
510 511 512 513 514 515
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)
516 517
{
  ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
518
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
519 520
  const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);

B
Behdad Esfahbod 已提交
521 522
  unsigned int num_features = l.get_feature_count ();
  for (unsigned int i = 0; i < num_features; i++) {
523 524 525 526 527 528 529
    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;
    }
  }
530

531
  if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
532 533
  return FALSE;
}
534

B
Behdad Esfahbod 已提交
535
unsigned int
536 537 538
hb_ot_layout_feature_get_lookup_indexes (hb_face_t    *face,
					 hb_tag_t      table_tag,
					 unsigned int  feature_index,
B
Behdad Esfahbod 已提交
539
					 unsigned int  start_offset,
540 541
					 unsigned int *lookup_count /* IN/OUT */,
					 unsigned int *lookup_indexes /* OUT */)
542
{
543
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
544 545
  const Feature &f = g.get_feature (feature_index);

B
Behdad Esfahbod 已提交
546
  return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
547 548
}

B
Behdad Esfahbod 已提交
549 550 551 552 553 554

/*
 * GSUB
 */

hb_bool_t
555 556
hb_ot_layout_has_substitution (hb_face_t *face)
{
557
  return &_get_gsub (face) != &Null(GSUB);
558 559 560
}

hb_bool_t
561 562 563 564
hb_ot_layout_substitute_lookup (hb_face_t    *face,
				hb_buffer_t  *buffer,
				unsigned int  lookup_index,
				hb_mask_t     mask)
B
Behdad Esfahbod 已提交
565
{
566 567
  hb_ot_layout_context_t context;
  context.font = NULL;
568 569
  context.face = face;
  return _get_gsub (face).substitute_lookup (&context, buffer, lookup_index, mask);
570 571
}

572

573 574 575 576 577
/*
 * GPOS
 */

hb_bool_t
578 579
hb_ot_layout_has_positioning (hb_face_t *face)
{
580
  return &_get_gpos (face) != &Null(GPOS);
581 582 583
}

hb_bool_t
584 585
hb_ot_layout_position_lookup   (hb_font_t    *font,
				hb_face_t    *face,
586 587 588
				hb_buffer_t  *buffer,
				unsigned int  lookup_index,
				hb_mask_t     mask)
589
{
590 591
  hb_ot_layout_context_t context;
  context.font = font;
592 593
  context.face = face;
  return _get_gpos (face).position_lookup (&context, buffer, lookup_index, mask);
594
}
595 596

void
597 598
hb_ot_layout_position_finish (hb_font_t    *font,
			      hb_face_t    *face,
599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644
			      hb_buffer_t  *buffer)
{
  unsigned int i, j;
  unsigned int len = hb_buffer_get_length (buffer);
  hb_internal_glyph_position_t *positions = (hb_internal_glyph_position_t *) hb_buffer_get_glyph_positions (buffer);

  /* TODO: Vertical */

  /* Handle cursive connections */
  /* First handle all left-to-right connections */
  for (j = 0; j < len; j++) {
    if (positions[j].cursive_chain > 0) {
      positions[j].y_offset += positions[j - positions[j].cursive_chain].y_offset;
      positions[j].cursive_chain = 0;
    }
  }
  /* Then handle all right-to-left connections */
  for (i = len; i > 0; i--) {
    j = i - 1;
    if (positions[j].cursive_chain < 0) {
      positions[j].y_offset += positions[j - positions[j].cursive_chain].y_offset;
      positions[j].cursive_chain = 0;
    }
  }

  /* Handle attachments */
  for (i = 0; i < len; i++)
    if (positions[i].back)
      {
	unsigned int back = i - positions[i].back;
	positions[i].back = 0;
	positions[i].x_offset += positions[back].x_offset;
	positions[i].y_offset += positions[back].y_offset;

	if (buffer->direction == HB_DIRECTION_RTL)
	  for (j = back + 1; j < i + 1; j++) {
	    positions[i].x_offset += positions[j].x_advance;
	    positions[i].y_offset += positions[j].y_advance;
	  }
	else
	  for (j = back; j < i; j++) {
	    positions[i].x_offset -= positions[j].x_advance;
	    positions[i].y_offset -= positions[j].y_advance;
	  }
      }
}