hb-ot-layout.cc 18.0 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_font_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_face_t      *face,
			     hb_font_t      *font,
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))
374 375 376 377 378 379
    return FALSE;

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

B
Behdad Esfahbod 已提交
380
unsigned int
381 382
hb_ot_layout_table_get_feature_tags (hb_face_t    *face,
				     hb_tag_t      table_tag,
B
Behdad Esfahbod 已提交
383
				     unsigned int  start_offset,
384 385
				     unsigned int *feature_count /* IN/OUT */,
				     hb_tag_t     *feature_tags /* OUT */)
386
{
387
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
388

B
Behdad Esfahbod 已提交
389
  return g.get_feature_tags (start_offset, feature_count, feature_tags);
390 391 392
}


B
Behdad Esfahbod 已提交
393
unsigned int
394 395 396
hb_ot_layout_script_get_language_tags (hb_face_t    *face,
				       hb_tag_t      table_tag,
				       unsigned int  script_index,
B
Behdad Esfahbod 已提交
397
				       unsigned int  start_offset,
398 399
				       unsigned int *language_count /* IN/OUT */,
				       hb_tag_t     *language_tags /* OUT */)
400
{
401
  const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
402

B
Behdad Esfahbod 已提交
403
  return s.get_lang_sys_tags (start_offset, language_count, language_tags);
404 405 406
}

hb_bool_t
407 408 409 410 411
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)
412
{
413
  ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
414
  const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
415

416
  if (s.find_lang_sys_index (language_tag, language_index))
417 418 419
    return TRUE;

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

423
  if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
424
  return FALSE;
425
}
426

427
hb_bool_t
428 429 430 431 432
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)
433
{
434
  const LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index);
435

436
  if (feature_index) *feature_index = l.get_required_feature_index ();
437

438 439
  return l.has_required_feature ();
}
440

B
Behdad Esfahbod 已提交
441
unsigned int
442 443 444 445
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 已提交
446
					   unsigned int  start_offset,
447 448
					   unsigned int *feature_count /* IN/OUT */,
					   unsigned int *feature_indexes /* OUT */)
449
{
450
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
451 452
  const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);

B
Behdad Esfahbod 已提交
453
  return l.get_feature_indexes (start_offset, feature_count, feature_indexes);
454 455
}

B
Behdad Esfahbod 已提交
456
unsigned int
457 458 459 460
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 已提交
461
					unsigned int  start_offset,
462 463
					unsigned int *feature_count /* IN/OUT */,
					hb_tag_t     *feature_tags /* OUT */)
464
{
465
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
466
  const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
467

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

B
Behdad Esfahbod 已提交
471 472 473 474 475
  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]);
  }
476 477

  return ret;
478 479 480 481
}


hb_bool_t
482 483 484 485 486 487
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)
488 489
{
  ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
490
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
491 492
  const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);

B
Behdad Esfahbod 已提交
493 494
  unsigned int num_features = l.get_feature_count ();
  for (unsigned int i = 0; i < num_features; i++) {
495 496 497 498 499 500 501
    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;
    }
  }
502

503
  if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
504 505
  return FALSE;
}
506

B
Behdad Esfahbod 已提交
507
unsigned int
508 509 510
hb_ot_layout_feature_get_lookup_indexes (hb_face_t    *face,
					 hb_tag_t      table_tag,
					 unsigned int  feature_index,
B
Behdad Esfahbod 已提交
511
					 unsigned int  start_offset,
512 513
					 unsigned int *lookup_count /* IN/OUT */,
					 unsigned int *lookup_indexes /* OUT */)
514
{
515
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
516 517
  const Feature &f = g.get_feature (feature_index);

B
Behdad Esfahbod 已提交
518
  return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
519 520
}

B
Behdad Esfahbod 已提交
521 522 523 524 525 526

/*
 * GSUB
 */

hb_bool_t
527 528
hb_ot_layout_has_substitution (hb_face_t *face)
{
529
  return &_get_gsub (face) != &Null(GSUB);
530 531 532
}

hb_bool_t
533 534 535 536
hb_ot_layout_substitute_lookup (hb_face_t    *face,
				hb_buffer_t  *buffer,
				unsigned int  lookup_index,
				hb_mask_t     mask)
B
Behdad Esfahbod 已提交
537
{
538 539
  hb_ot_layout_context_t context;
  context.font = NULL;
540 541
  context.face = face;
  return _get_gsub (face).substitute_lookup (&context, buffer, lookup_index, mask);
542 543
}

544

545 546 547 548 549
/*
 * GPOS
 */

hb_bool_t
550 551
hb_ot_layout_has_positioning (hb_face_t *face)
{
552
  return &_get_gpos (face) != &Null(GPOS);
553 554 555
}

hb_bool_t
556 557 558 559 560
hb_ot_layout_position_lookup   (hb_face_t    *face,
				hb_font_t    *font,
				hb_buffer_t  *buffer,
				unsigned int  lookup_index,
				hb_mask_t     mask)
561
{
562 563
  hb_ot_layout_context_t context;
  context.font = font;
564 565
  context.face = face;
  return _get_gpos (face).position_lookup (&context, buffer, lookup_index, mask);
566
}
567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616

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