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
 *
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 31 32
 *
 * 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
  memset (layout, 0, sizeof (*layout));

49
  layout->gdef_blob = Sanitizer<GDEF>::sanitize (hb_face_get_table (face, HB_OT_TAG_GDEF));
B
Behdad Esfahbod 已提交
50
  layout->gdef = CastP<GDEF> (hb_blob_lock (layout->gdef_blob));
B
Behdad Esfahbod 已提交
51

52
  layout->gsub_blob = Sanitizer<GSUB>::sanitize (hb_face_get_table (face, HB_OT_TAG_GSUB));
B
Behdad Esfahbod 已提交
53
  layout->gsub = CastP<GSUB> (hb_blob_lock (layout->gsub_blob));
B
Behdad Esfahbod 已提交
54

55
  layout->gpos_blob = Sanitizer<GPOS>::sanitize (hb_face_get_table (face, HB_OT_TAG_GPOS));
B
Behdad Esfahbod 已提交
56
  layout->gpos = CastP<GPOS> (hb_blob_lock (layout->gpos_blob));
B
Behdad Esfahbod 已提交
57 58
}

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

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

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

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

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

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

93

B
Behdad Esfahbod 已提交
94 95 96 97
/*
 * GDEF
 */

B
Behdad Esfahbod 已提交
98
/* TODO the public class_t is a mess */
B
Behdad Esfahbod 已提交
99

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

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

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

119
  klass = gdef.get_glyph_class (glyph);
B
Behdad Esfahbod 已提交
120

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

  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;
130
  case GDEF::MarkGlyph:
131
	klass = gdef.get_mark_attachment_type (glyph);
B
Behdad Esfahbod 已提交
132
	return HB_OT_LAYOUT_GLYPH_CLASS_MARK + (klass << 8);
B
Behdad Esfahbod 已提交
133
  }
B
Behdad Esfahbod 已提交
134
}
B
Behdad Esfahbod 已提交
135

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

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

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

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

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

B
Behdad Esfahbod 已提交
172
  return true;
B
Behdad Esfahbod 已提交
173 174
}

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

183
  if (ginfo->gproperty == HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN)
184
    ginfo->gproperty = _hb_ot_layout_get_glyph_property (face, ginfo->codepoint);
185
  property = ginfo->gproperty;
186 187 188 189 190 191 192 193 194 195 196
  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)
197
      return !_get_gdef (face).mark_set_covers (lookup_flags >> 16, ginfo->codepoint);
198 199 200 201 202 203 204 205 206 207

    /* 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 已提交
208
void
209
_hb_ot_layout_set_glyph_class (hb_face_t                  *face,
210 211
			       hb_codepoint_t              glyph,
			       hb_ot_layout_glyph_class_t  klass)
B
Behdad Esfahbod 已提交
212
{
213 214 215
  if (HB_OBJECT_IS_INERT (face))
    return;

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

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

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

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

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

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

B
Behdad Esfahbod 已提交
238
    if (HB_UNLIKELY (!new_klasses))
B
Behdad Esfahbod 已提交
239
      return;
B
Behdad Esfahbod 已提交
240

B
Behdad Esfahbod 已提交
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
    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 已提交
259

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


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

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

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

  hb_ot_layout_t *layout = &face->ot_layout;
292

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

  if (layout->new_gdef.len == 0) {
297
    layout->new_gdef.klasses = (unsigned char *) calloc (count, sizeof (unsigned char));
B
Behdad Esfahbod 已提交
298 299 300
    layout->new_gdef.len = count;
  }

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

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

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

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

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


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

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

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

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

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

  /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
374
  if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index))
B
Behdad Esfahbod 已提交
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 402
    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))
403 404 405 406 407 408
    return FALSE;

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

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

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


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

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

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

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

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

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

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

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

467 468
  return l.has_required_feature ();
}
469

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

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

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

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

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

  return ret;
507 508 509 510
}


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

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

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

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

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

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

/*
 * GSUB
 */

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

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

573

574 575 576 577 578
/*
 * GPOS
 */

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

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

void
598 599
hb_ot_layout_position_finish (hb_font_t    *font HB_UNUSED,
			      hb_face_t    *face HB_UNUSED,
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 645
			      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;
	  }
      }
}