~ubuntu-branches/ubuntu/trusty/pango1.0/trusty-proposed

« back to all changes in this revision

Viewing changes to pango/opentype/hb-ot-layout.cc

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Dröge
  • Date: 2009-09-09 07:49:30 UTC
  • mfrom: (1.6.1 upstream) (63.1.2 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090909074930-zlgadwz6svi311vh
Tags: 1.25.6-1
New upstream development release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 1998-2004  David Turner and Werner Lemberg
 
3
 * Copyright (C) 2006  Behdad Esfahbod
 
4
 * Copyright (C) 2007,2008,2009  Red Hat, Inc.
 
5
 *
 
6
 *  This is part of HarfBuzz, an OpenType Layout engine library.
 
7
 *
 
8
 * Permission is hereby granted, without written agreement and without
 
9
 * license or royalty fees, to use, copy, modify, and distribute this
 
10
 * software and its documentation for any purpose, provided that the
 
11
 * above copyright notice and the following two paragraphs appear in
 
12
 * all copies of this software.
 
13
 *
 
14
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
 
15
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 
16
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
 
17
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
 
18
 * DAMAGE.
 
19
 *
 
20
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
 
21
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 
22
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 
23
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
 
24
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 
25
 *
 
26
 * Red Hat Author(s): Behdad Esfahbod
 
27
 */
 
28
 
 
29
#define HB_OT_LAYOUT_CC
 
30
 
 
31
#include "hb-ot-layout-private.h"
 
32
 
 
33
#include "hb-ot-layout-gdef-private.hh"
 
34
#include "hb-ot-layout-gsub-private.hh"
 
35
#include "hb-ot-layout-gpos-private.hh"
 
36
 
 
37
 
 
38
#include <stdlib.h>
 
39
#include <string.h>
 
40
 
 
41
 
 
42
void
 
43
_hb_ot_layout_init (hb_face_t *face)
 
44
{
 
45
  hb_ot_layout_t *layout = &face->ot_layout;
 
46
 
 
47
  layout->gdef_blob = Sanitizer<GDEF>::sanitize (hb_face_get_table (face, HB_OT_TAG_GDEF));
 
48
  layout->gdef = &Sanitizer<GDEF>::lock_instance (layout->gdef_blob);
 
49
 
 
50
  layout->gsub_blob = Sanitizer<GSUB>::sanitize (hb_face_get_table (face, HB_OT_TAG_GSUB));
 
51
  layout->gsub = &Sanitizer<GSUB>::lock_instance (layout->gsub_blob);
 
52
 
 
53
  layout->gpos_blob = Sanitizer<GPOS>::sanitize (hb_face_get_table (face, HB_OT_TAG_GPOS));
 
54
  layout->gpos = &Sanitizer<GPOS>::lock_instance (layout->gpos_blob);
 
55
}
 
56
 
 
57
void
 
58
_hb_ot_layout_fini (hb_face_t *face)
 
59
{
 
60
  hb_ot_layout_t *layout = &face->ot_layout;
 
61
 
 
62
  hb_blob_unlock (layout->gdef_blob);
 
63
  hb_blob_unlock (layout->gsub_blob);
 
64
  hb_blob_unlock (layout->gpos_blob);
 
65
 
 
66
  hb_blob_destroy (layout->gdef_blob);
 
67
  hb_blob_destroy (layout->gsub_blob);
 
68
  hb_blob_destroy (layout->gpos_blob);
 
69
 
 
70
  free (layout->new_gdef.klasses);
 
71
}
 
72
 
 
73
static const GDEF&
 
74
_get_gdef (hb_face_t *face)
 
75
{
 
76
  return HB_LIKELY (face->ot_layout.gdef) ? *face->ot_layout.gdef : Null(GDEF);
 
77
}
 
78
 
 
79
static const GSUB&
 
80
_get_gsub (hb_face_t *face)
 
81
{
 
82
  return HB_LIKELY (face->ot_layout.gsub) ? *face->ot_layout.gsub : Null(GSUB);
 
83
}
 
84
 
 
85
static const GPOS&
 
86
_get_gpos (hb_face_t *face)
 
87
{
 
88
  return HB_LIKELY (face->ot_layout.gpos) ? *face->ot_layout.gpos : Null(GPOS);
 
89
}
 
90
 
 
91
 
 
92
/*
 
93
 * GDEF
 
94
 */
 
95
 
 
96
/* TODO the public class_t is a mess */
 
97
 
 
98
hb_bool_t
 
99
hb_ot_layout_has_font_glyph_classes (hb_face_t *face)
 
100
{
 
101
  return _get_gdef (face).has_glyph_classes ();
 
102
}
 
103
 
 
104
hb_bool_t
 
105
_hb_ot_layout_has_new_glyph_classes (hb_face_t *face)
 
106
{
 
107
  return face->ot_layout.new_gdef.len > 0;
 
108
}
 
109
 
 
110
static unsigned int
 
111
_hb_ot_layout_get_glyph_property (hb_face_t      *face,
 
112
                                  hb_codepoint_t  glyph)
 
113
{
 
114
  hb_ot_layout_class_t klass;
 
115
  const GDEF &gdef = _get_gdef (face);
 
116
 
 
117
  klass = gdef.get_glyph_class (glyph);
 
118
 
 
119
  if (!klass && glyph < face->ot_layout.new_gdef.len)
 
120
    klass = face->ot_layout.new_gdef.klasses[glyph];
 
121
 
 
122
  switch (klass) {
 
123
  default:
 
124
  case GDEF::UnclassifiedGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED;
 
125
  case GDEF::BaseGlyph:         return HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
 
126
  case GDEF::LigatureGlyph:     return HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE;
 
127
  case GDEF::ComponentGlyph:    return HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT;
 
128
  case GDEF::MarkGlyph:
 
129
        klass = gdef.get_mark_attachment_type (glyph);
 
130
        return HB_OT_LAYOUT_GLYPH_CLASS_MARK + (klass << 8);
 
131
  }
 
132
}
 
133
 
 
134
hb_bool_t
 
135
_hb_ot_layout_check_glyph_property (hb_face_t    *face,
 
136
                                    hb_internal_glyph_info_t *ginfo,
 
137
                                    unsigned int  lookup_flags,
 
138
                                    unsigned int *property_out)
 
139
{
 
140
  unsigned int property;
 
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
  if (property_out)
 
146
    *property_out = property;
 
147
 
 
148
  /* Not covered, if, for example, glyph class is ligature and
 
149
   * lookup_flags includes LookupFlags::IgnoreLigatures
 
150
   */
 
151
  if (property & lookup_flags)
 
152
    return false;
 
153
 
 
154
  if (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
 
155
  {
 
156
    /* If using mark filtering sets, the high short of
 
157
     * lookup_flags has the set index.
 
158
     */
 
159
    if (lookup_flags & LookupFlag::UseMarkFilteringSet)
 
160
      return _get_gdef (face).mark_set_covers (lookup_flags >> 16, ginfo->codepoint);
 
161
 
 
162
    /* The second byte of lookup_flags has the meaning
 
163
     * "ignore marks of attachment type different than
 
164
     * the attachment type specified."
 
165
     */
 
166
    if (lookup_flags & LookupFlag::MarkAttachmentType && property & LookupFlag::MarkAttachmentType)
 
167
      return (lookup_flags & LookupFlag::MarkAttachmentType) == (property & LookupFlag::MarkAttachmentType);
 
168
  }
 
169
 
 
170
  return true;
 
171
}
 
172
 
 
173
hb_bool_t
 
174
_hb_ot_layout_skip_mark (hb_face_t    *face,
 
175
                         hb_internal_glyph_info_t *ginfo,
 
176
                         unsigned int  lookup_flags,
 
177
                         unsigned int *property_out)
 
178
{
 
179
  unsigned int property;
 
180
 
 
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
  if (property_out)
 
185
    *property_out = property;
 
186
 
 
187
  if (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
 
188
  {
 
189
    /* Skip mark if lookup_flags includes LookupFlags::IgnoreMarks */
 
190
    if (lookup_flags & LookupFlag::IgnoreMarks)
 
191
      return true;
 
192
 
 
193
    /* If using mark filtering sets, the high short of lookup_flags has the set index. */
 
194
    if (lookup_flags & LookupFlag::UseMarkFilteringSet)
 
195
      return !_get_gdef (face).mark_set_covers (lookup_flags >> 16, ginfo->codepoint);
 
196
 
 
197
    /* The second byte of lookup_flags has the meaning "ignore marks of attachment type
 
198
     * different than the attachment type specified." */
 
199
    if (lookup_flags & LookupFlag::MarkAttachmentType && property & LookupFlag::MarkAttachmentType)
 
200
      return (lookup_flags & LookupFlag::MarkAttachmentType) != (property & LookupFlag::MarkAttachmentType);
 
201
  }
 
202
 
 
203
  return false;
 
204
}
 
205
 
 
206
void
 
207
_hb_ot_layout_set_glyph_class (hb_face_t                  *face,
 
208
                               hb_codepoint_t              glyph,
 
209
                               hb_ot_layout_glyph_class_t  klass)
 
210
{
 
211
  if (HB_OBJECT_IS_INERT (face))
 
212
    return;
 
213
 
 
214
  /* TODO optimize this? similar to old harfbuzz code for example */
 
215
 
 
216
  hb_ot_layout_t *layout = &face->ot_layout;
 
217
  hb_ot_layout_class_t gdef_klass;
 
218
  unsigned int len = layout->new_gdef.len;
 
219
 
 
220
  if (HB_UNLIKELY (glyph > 65535))
 
221
    return;
 
222
 
 
223
  /* XXX this is not threadsafe */
 
224
  if (glyph >= len) {
 
225
    unsigned int new_len;
 
226
    unsigned char *new_klasses;
 
227
 
 
228
    new_len = len == 0 ? 120 : 2 * len;
 
229
    while (new_len <= glyph)
 
230
      new_len *= 2;
 
231
 
 
232
    if (new_len > 65536)
 
233
      new_len = 65536;
 
234
    new_klasses = (unsigned char *) realloc (layout->new_gdef.klasses, new_len * sizeof (unsigned char));
 
235
 
 
236
    if (HB_UNLIKELY (!new_klasses))
 
237
      return;
 
238
 
 
239
    memset (new_klasses + len, 0, new_len - len);
 
240
 
 
241
    layout->new_gdef.klasses = new_klasses;
 
242
    layout->new_gdef.len = new_len;
 
243
  }
 
244
 
 
245
  switch (klass) {
 
246
  default:
 
247
  case HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED:   gdef_klass = GDEF::UnclassifiedGlyph;   break;
 
248
  case HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH:     gdef_klass = GDEF::BaseGlyph;           break;
 
249
  case HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE:       gdef_klass = GDEF::LigatureGlyph;       break;
 
250
  case HB_OT_LAYOUT_GLYPH_CLASS_MARK:           gdef_klass = GDEF::MarkGlyph;           break;
 
251
  case HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT:      gdef_klass = GDEF::ComponentGlyph;      break;
 
252
  }
 
253
 
 
254
  layout->new_gdef.klasses[glyph] = gdef_klass;
 
255
  return;
 
256
}
 
257
 
 
258
void
 
259
_hb_ot_layout_set_glyph_property (hb_face_t      *face,
 
260
                                  hb_codepoint_t  glyph,
 
261
                                  unsigned int    property)
 
262
{ _hb_ot_layout_set_glyph_class (face, glyph, (hb_ot_layout_glyph_class_t) (property & 0xff)); }
 
263
 
 
264
 
 
265
hb_ot_layout_glyph_class_t
 
266
hb_ot_layout_get_glyph_class (hb_face_t      *face,
 
267
                              hb_codepoint_t  glyph)
 
268
{
 
269
  return (hb_ot_layout_glyph_class_t) (_hb_ot_layout_get_glyph_property (face, glyph) & 0xff);
 
270
}
 
271
 
 
272
void
 
273
hb_ot_layout_set_glyph_class (hb_face_t                 *face,
 
274
                              hb_codepoint_t             glyph,
 
275
                              hb_ot_layout_glyph_class_t klass)
 
276
{
 
277
  _hb_ot_layout_set_glyph_class (face, glyph, klass);
 
278
}
 
279
 
 
280
void
 
281
hb_ot_layout_build_glyph_classes (hb_face_t      *face,
 
282
                                  uint16_t        num_total_glyphs,
 
283
                                  hb_codepoint_t *glyphs,
 
284
                                  unsigned char  *klasses,
 
285
                                  uint16_t        count)
 
286
{
 
287
  if (HB_OBJECT_IS_INERT (face))
 
288
    return;
 
289
 
 
290
  hb_ot_layout_t *layout = &face->ot_layout;
 
291
 
 
292
  if (HB_UNLIKELY (!count || !glyphs || !klasses))
 
293
    return;
 
294
 
 
295
  if (layout->new_gdef.len == 0) {
 
296
    layout->new_gdef.klasses = (unsigned char *) calloc (num_total_glyphs, sizeof (unsigned char));
 
297
    layout->new_gdef.len = count;
 
298
  }
 
299
 
 
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]);
 
302
}
 
303
 
 
304
hb_bool_t
 
305
hb_ot_layout_get_attach_points (hb_face_t      *face,
 
306
                                hb_codepoint_t  glyph,
 
307
                                unsigned int   *point_count /* IN/OUT */,
 
308
                                unsigned int   *point_array /* OUT */)
 
309
{
 
310
  return _get_gdef (face).get_attach_points (glyph, point_count, point_array);
 
311
}
 
312
 
 
313
hb_bool_t
 
314
hb_ot_layout_get_lig_carets (hb_face_t      *face,
 
315
                             hb_font_t      *font,
 
316
                             hb_codepoint_t  glyph,
 
317
                             unsigned int   *caret_count /* IN/OUT */,
 
318
                             int            *caret_array /* OUT */)
 
319
{
 
320
  hb_ot_layout_context_t context;
 
321
  context.font = font;
 
322
  context.face = face;
 
323
  return _get_gdef (face).get_lig_carets (&context, glyph, caret_count, caret_array);
 
324
}
 
325
 
 
326
/*
 
327
 * GSUB/GPOS
 
328
 */
 
329
 
 
330
static const GSUBGPOS&
 
331
get_gsubgpos_table (hb_face_t *face,
 
332
                    hb_tag_t   table_tag)
 
333
{
 
334
  switch (table_tag) {
 
335
    case HB_OT_TAG_GSUB: return _get_gsub (face);
 
336
    case HB_OT_TAG_GPOS: return _get_gpos (face);
 
337
    default:             return Null(GSUBGPOS);
 
338
  }
 
339
}
 
340
 
 
341
 
 
342
hb_bool_t
 
343
hb_ot_layout_table_get_script_tags (hb_face_t    *face,
 
344
                                    hb_tag_t      table_tag,
 
345
                                    unsigned int *script_count /* IN/OUT */,
 
346
                                    hb_tag_t     *script_tags /* OUT */)
 
347
{
 
348
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
 
349
 
 
350
  return g.get_script_tags (script_count, script_tags);
 
351
}
 
352
 
 
353
hb_bool_t
 
354
hb_ot_layout_table_find_script (hb_face_t    *face,
 
355
                                hb_tag_t      table_tag,
 
356
                                hb_tag_t      script_tag,
 
357
                                unsigned int *script_index)
 
358
{
 
359
  ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
 
360
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
 
361
 
 
362
  if (g.find_script_index (script_tag, script_index))
 
363
    return TRUE;
 
364
 
 
365
  /* try finding 'DFLT' */
 
366
  if (g.find_script_index (HB_OT_LAYOUT_TAG_DEFAULT_SCRIPT, script_index))
 
367
    return FALSE;
 
368
 
 
369
  /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
 
370
  if (g.find_script_index (HB_OT_LAYOUT_TAG_DEFAULT_LANGUAGE, script_index))
 
371
    return FALSE;
 
372
 
 
373
  if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
 
374
  return FALSE;
 
375
}
 
376
 
 
377
hb_bool_t
 
378
hb_ot_layout_table_get_feature_tags (hb_face_t    *face,
 
379
                                     hb_tag_t      table_tag,
 
380
                                     unsigned int *feature_count /* IN/OUT */,
 
381
                                     hb_tag_t     *feature_tags /* OUT */)
 
382
{
 
383
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
 
384
 
 
385
  return g.get_feature_tags (feature_count, feature_tags);
 
386
}
 
387
 
 
388
 
 
389
hb_bool_t
 
390
hb_ot_layout_script_get_language_tags (hb_face_t    *face,
 
391
                                       hb_tag_t      table_tag,
 
392
                                       unsigned int  script_index,
 
393
                                       unsigned int *language_count /* IN/OUT */,
 
394
                                       hb_tag_t     *language_tags /* OUT */)
 
395
{
 
396
  const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
 
397
 
 
398
  return s.get_lang_sys_tags (language_count, language_tags);
 
399
}
 
400
 
 
401
hb_bool_t
 
402
hb_ot_layout_script_find_language (hb_face_t    *face,
 
403
                                   hb_tag_t      table_tag,
 
404
                                   unsigned int  script_index,
 
405
                                   hb_tag_t      language_tag,
 
406
                                   unsigned int *language_index)
 
407
{
 
408
  ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
 
409
  const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
 
410
 
 
411
  if (s.find_lang_sys_index (language_tag, language_index))
 
412
    return TRUE;
 
413
 
 
414
  /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
 
415
  if (s.find_lang_sys_index (HB_OT_LAYOUT_TAG_DEFAULT_LANGUAGE, language_index))
 
416
    return FALSE;
 
417
 
 
418
  if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
 
419
  return FALSE;
 
420
}
 
421
 
 
422
hb_bool_t
 
423
hb_ot_layout_language_get_required_feature_index (hb_face_t    *face,
 
424
                                                  hb_tag_t      table_tag,
 
425
                                                  unsigned int  script_index,
 
426
                                                  unsigned int  language_index,
 
427
                                                  unsigned int *feature_index)
 
428
{
 
429
  const LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index);
 
430
 
 
431
  if (feature_index) *feature_index = l.get_required_feature_index ();
 
432
 
 
433
  return l.has_required_feature ();
 
434
}
 
435
 
 
436
hb_bool_t
 
437
hb_ot_layout_language_get_feature_indexes (hb_face_t    *face,
 
438
                                           hb_tag_t      table_tag,
 
439
                                           unsigned int  script_index,
 
440
                                           unsigned int  language_index,
 
441
                                           unsigned int *feature_count /* IN/OUT */,
 
442
                                           unsigned int *feature_indexes /* OUT */)
 
443
{
 
444
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
 
445
  const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
 
446
 
 
447
  return l.get_feature_indexes (feature_count, feature_indexes);
 
448
}
 
449
 
 
450
hb_bool_t
 
451
hb_ot_layout_language_get_feature_tags (hb_face_t    *face,
 
452
                                        hb_tag_t      table_tag,
 
453
                                        unsigned int  script_index,
 
454
                                        unsigned int  language_index,
 
455
                                        unsigned int *feature_count /* IN/OUT */,
 
456
                                        hb_tag_t     *feature_tags /* OUT */)
 
457
{
 
458
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
 
459
  const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
 
460
 
 
461
  ASSERT_STATIC (sizeof (unsigned int) == sizeof (hb_tag_t));
 
462
  hb_bool_t ret = l.get_feature_indexes (feature_count, (unsigned int *) feature_tags);
 
463
 
 
464
  if (feature_tags) {
 
465
    unsigned int count = *feature_count;
 
466
    for (unsigned int i = 0; i < count; i++)
 
467
      feature_tags[i] = g.get_feature_tag ((unsigned int) feature_tags[i]);
 
468
  }
 
469
 
 
470
  return ret;
 
471
}
 
472
 
 
473
 
 
474
hb_bool_t
 
475
hb_ot_layout_language_find_feature (hb_face_t    *face,
 
476
                                    hb_tag_t      table_tag,
 
477
                                    unsigned int  script_index,
 
478
                                    unsigned int  language_index,
 
479
                                    hb_tag_t      feature_tag,
 
480
                                    unsigned int *feature_index)
 
481
{
 
482
  ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
 
483
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
 
484
  const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
 
485
 
 
486
  unsigned int num_features = l.get_feature_count ();
 
487
  for (unsigned int i = 0; i < num_features; i++) {
 
488
    unsigned int f_index = l.get_feature_index (i);
 
489
 
 
490
    if (feature_tag == g.get_feature_tag (f_index)) {
 
491
      if (feature_index) *feature_index = f_index;
 
492
      return TRUE;
 
493
    }
 
494
  }
 
495
 
 
496
  if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
 
497
  return FALSE;
 
498
}
 
499
 
 
500
hb_bool_t
 
501
hb_ot_layout_feature_get_lookup_indexes (hb_face_t    *face,
 
502
                                         hb_tag_t      table_tag,
 
503
                                         unsigned int  feature_index,
 
504
                                         unsigned int *lookup_count /* IN/OUT */,
 
505
                                         unsigned int *lookup_indexes /* OUT */)
 
506
{
 
507
  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
 
508
  const Feature &f = g.get_feature (feature_index);
 
509
 
 
510
  return f.get_lookup_indexes (lookup_count, lookup_indexes);
 
511
}
 
512
 
 
513
 
 
514
/*
 
515
 * GSUB
 
516
 */
 
517
 
 
518
hb_bool_t
 
519
hb_ot_layout_has_substitution (hb_face_t *face)
 
520
{
 
521
  return &_get_gsub (face) != &Null(GSUB);
 
522
}
 
523
 
 
524
hb_bool_t
 
525
hb_ot_layout_substitute_lookup (hb_face_t    *face,
 
526
                                hb_buffer_t  *buffer,
 
527
                                unsigned int  lookup_index,
 
528
                                hb_mask_t     mask)
 
529
{
 
530
  hb_ot_layout_context_t context;
 
531
  context.font = NULL;
 
532
  context.face = face;
 
533
  return _get_gsub (face).substitute_lookup (&context, buffer, lookup_index, mask);
 
534
}
 
535
 
 
536
 
 
537
/*
 
538
 * GPOS
 
539
 */
 
540
 
 
541
hb_bool_t
 
542
hb_ot_layout_has_positioning (hb_face_t *face)
 
543
{
 
544
  return &_get_gpos (face) != &Null(GPOS);
 
545
}
 
546
 
 
547
hb_bool_t
 
548
hb_ot_layout_position_lookup   (hb_face_t    *face,
 
549
                                hb_font_t    *font,
 
550
                                hb_buffer_t  *buffer,
 
551
                                unsigned int  lookup_index,
 
552
                                hb_mask_t     mask)
 
553
{
 
554
  hb_ot_layout_context_t context;
 
555
  context.font = font;
 
556
  context.face = face;
 
557
  return _get_gpos (face).position_lookup (&context, buffer, lookup_index, mask);
 
558
}