hb-ot-shape.cc 15.7 KB
Newer Older
B
Behdad Esfahbod 已提交
1
/*
B
Behdad Esfahbod 已提交
2
 * Copyright (C) 2009,2010  Red Hat, Inc.
B
Behdad Esfahbod 已提交
3
 *
B
Behdad Esfahbod 已提交
4
 *  This is part of HarfBuzz, a text shaping library.
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
 *
 * 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
 */

27
#include "hb-ot-shape-private.h"
B
Behdad Esfahbod 已提交
28

B
Behdad Esfahbod 已提交
29 30
#include "hb-open-type-private.hh"

B
Behdad Esfahbod 已提交
31 32
#include "hb-ot-layout.h"

B
Behdad Esfahbod 已提交
33 34 35
HB_BEGIN_DECLS


B
Behdad Esfahbod 已提交
36
/* XXX vertical */
B
Behdad Esfahbod 已提交
37
hb_tag_t default_features[] = {
38
  HB_TAG('c','a','l','t'),
B
Behdad Esfahbod 已提交
39 40
  HB_TAG('c','c','m','p'),
  HB_TAG('c','l','i','g'),
41 42
  HB_TAG('c','s','w','h'),
  HB_TAG('c','u','r','s'),
B
Behdad Esfahbod 已提交
43
  HB_TAG('k','e','r','n'),
44 45
  HB_TAG('l','i','g','a'),
  HB_TAG('l','o','c','l'),
B
Behdad Esfahbod 已提交
46 47
  HB_TAG('m','a','r','k'),
  HB_TAG('m','k','m','k'),
48
  HB_TAG('r','l','i','g')
B
Behdad Esfahbod 已提交
49 50
};

B
Behdad Esfahbod 已提交
51 52 53 54 55
struct lookup_map {
  unsigned int index;
  hb_mask_t mask;
};

B
Behdad Esfahbod 已提交
56 57 58 59 60

static void
add_feature (hb_face_t    *face,
	     hb_tag_t      table_tag,
	     unsigned int  feature_index,
B
Behdad Esfahbod 已提交
61 62
	     hb_mask_t     mask,
	     lookup_map   *lookups,
B
Behdad Esfahbod 已提交
63 64 65 66
	     unsigned int *num_lookups,
	     unsigned int  room_lookups)
{
  unsigned int i = room_lookups - *num_lookups;
B
Behdad Esfahbod 已提交
67 68 69 70
  lookups += *num_lookups;

  unsigned int *lookup_indices = (unsigned int *) lookups;

B
Behdad Esfahbod 已提交
71 72
  hb_ot_layout_feature_get_lookup_indexes (face, table_tag, feature_index, 0,
					   &i,
B
Behdad Esfahbod 已提交
73 74
					   lookup_indices);

B
Behdad Esfahbod 已提交
75
  *num_lookups += i;
B
Behdad Esfahbod 已提交
76 77 78 79 80

  while (i--) {
    lookups[i].mask = mask;
    lookups[i].index = lookup_indices[i];
  }
B
Behdad Esfahbod 已提交
81 82 83 84 85
}

static int
cmp_lookups (const void *p1, const void *p2)
{
B
Behdad Esfahbod 已提交
86 87
  const lookup_map *a = (const lookup_map *) p1;
  const lookup_map *b = (const lookup_map *) p2;
B
Behdad Esfahbod 已提交
88

B
Behdad Esfahbod 已提交
89
  return a->index - b->index;
B
Behdad Esfahbod 已提交
90 91
}

92

B
Behdad Esfahbod 已提交
93
#define MAX_FEATURES 100 /* FIXME */
94

B
Behdad Esfahbod 已提交
95
struct hb_mask_allocator_t {
96

B
Behdad Esfahbod 已提交
97 98 99
  struct feature_info_t {
    hb_tag_t tag;
    unsigned int value;
B
Behdad Esfahbod 已提交
100
    unsigned int seq;
B
Behdad Esfahbod 已提交
101
    bool global;
102

B
Behdad Esfahbod 已提交
103 104 105
    static int
    cmp (const void *p1, const void *p2)
    {
106 107
      const feature_info_t *a = reinterpret_cast<const feature_info_t *>(p1);
      const feature_info_t *b = reinterpret_cast<const feature_info_t *>(p2);
108

B
Behdad Esfahbod 已提交
109 110
      if (a->tag != b->tag)
        return a->tag < b->tag ? -1 : 1;
111

B
Behdad Esfahbod 已提交
112
      return a->seq < b->seq ? -1 : 1;
B
Behdad Esfahbod 已提交
113 114
    }
  };
115

B
Behdad Esfahbod 已提交
116 117 118 119 120 121 122 123
  struct feature_map_t {
    hb_tag_t tag; /* should be first */
    unsigned int index;
    unsigned int shift;
    hb_mask_t mask;

    static int
    cmp (const void *p1, const void *p2)
124
    {
125 126
      const feature_map_t *a = reinterpret_cast<const feature_map_t *>(p1);
      const feature_map_t *b = reinterpret_cast<const feature_map_t *>(p2);
B
Behdad Esfahbod 已提交
127 128 129 130 131

      return a->tag < b->tag ? -1 : a->tag > b->tag ? 1 : 0;
    }
  };

132
  hb_mask_allocator_t (void) : count (0) {}
B
Behdad Esfahbod 已提交
133

B
Behdad Esfahbod 已提交
134 135 136
  void add_feature (hb_tag_t tag,
		    unsigned int value,
		    bool global)
137
  {
B
Behdad Esfahbod 已提交
138 139
    feature_info_t *info = &infos[count++];
    info->tag = tag;
B
Behdad Esfahbod 已提交
140
    info->value = value;
B
Behdad Esfahbod 已提交
141
    info->seq = count;
B
Behdad Esfahbod 已提交
142
    info->global = global;
143 144
  }

145 146 147 148
  void compile (hb_face_t *face,
		hb_tag_t table_tag,
		unsigned int script_index,
		unsigned int language_index)
149
  {
B
Behdad Esfahbod 已提交
150
    global_mask = 0;
151
    unsigned int next_bit = 1;
B
Behdad Esfahbod 已提交
152 153 154 155 156 157 158 159 160 161 162

    if (!count)
      return;

    qsort (infos, count, sizeof (infos[0]), feature_info_t::cmp);

    unsigned int j = 0;
    for (unsigned int i = 1; i < count; i++)
      if (infos[i].tag != infos[j].tag)
	infos[++j] = infos[i];
      else {
B
Behdad Esfahbod 已提交
163 164 165 166
	if (infos[i].global)
	  infos[j] = infos[i];
	else {
	  infos[j].global = infos[j].global && (infos[j].value == infos[i].value);
B
Behdad Esfahbod 已提交
167
	  infos[j].value = MAX (infos[j].value, infos[i].value);
B
Behdad Esfahbod 已提交
168
	}
B
Behdad Esfahbod 已提交
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
      }
    count = j + 1;

    /* Allocate bits now */
    j = 0;
    for (unsigned int i = 0; i < count; i++) {
      const feature_info_t *info = &infos[i];

      unsigned int bits_needed;

      if (info->global && info->value == 1)
        /* Uses the global bit */
        bits_needed = 0;
      else
        bits_needed = _hb_bit_storage (info->value);

      if (!info->value || next_bit + bits_needed > 8 * sizeof (hb_mask_t))
        continue; /* Feature disabled, or not enough bits. */

      unsigned int feature_index;
      if (!hb_ot_layout_language_find_feature (face, table_tag, script_index, language_index,
					       info->tag, &feature_index))
        continue;

      feature_map_t *map = &maps[j++];

      map->tag = info->tag;
      map->index = feature_index;
      if (info->global && info->value == 1) {
B
Minor  
Behdad Esfahbod 已提交
198
        /* Use the global bit */
B
Behdad Esfahbod 已提交
199 200 201 202 203 204 205 206 207 208 209 210
        map->shift = 0;
	map->mask = 1;
      } else {
	map->shift = next_bit;
	map->mask = (1 << (next_bit + bits_needed)) - (1 << next_bit);
	next_bit += bits_needed;
      }

      if (info->global && map->mask != 1)
        global_mask |= map->mask;
    }
    count = j;
211 212
  }

B
Behdad Esfahbod 已提交
213 214 215 216 217
  hb_mask_t get_global_mask (void) { return global_mask; }
  const feature_map_t *find_feature (hb_tag_t tag) const {
    static const feature_map_t off_map = { HB_TAG_NONE, Index::NOT_FOUND_INDEX, 0, 0 };
    const feature_map_t *map = (const feature_map_t *) bsearch (&tag, maps, count, sizeof (maps[0]), feature_map_t::cmp);
    return map ? map : &off_map;
218 219
  }

B
Behdad Esfahbod 已提交
220 221 222 223 224 225

  private:

  unsigned int count;
  feature_info_t infos[MAX_FEATURES];

226
  feature_map_t maps[MAX_FEATURES];
B
Behdad Esfahbod 已提交
227 228
  hb_mask_t global_mask;
};
229

B
Behdad Esfahbod 已提交
230
static void
B
Behdad Esfahbod 已提交
231 232 233
hb_ot_shape_setup_lookups (hb_ot_shape_context_t *c,
			   lookup_map            *lookups,
			   unsigned int          *num_lookups)
B
Behdad Esfahbod 已提交
234 235 236 237 238 239
{
  unsigned int i, j, script_index, language_index, feature_index, room_lookups;

  room_lookups = *num_lookups;
  *num_lookups = 0;

240
  hb_ot_layout_table_choose_script (c->face, c->table_tag,
241
				    hb_ot_tags_from_script (c->buffer->props.script),
B
Behdad Esfahbod 已提交
242
				    &script_index);
243
  hb_ot_layout_script_find_language (c->face, c->table_tag, script_index,
244
				     hb_ot_tag_from_language (c->buffer->props.language),
B
Behdad Esfahbod 已提交
245 246
				     &language_index);

247

248
  hb_mask_allocator_t allocator;
B
Behdad Esfahbod 已提交
249

250
  switch (c->original_direction) {
B
Behdad Esfahbod 已提交
251
    case HB_DIRECTION_LTR:
B
Behdad Esfahbod 已提交
252 253
      allocator.add_feature (HB_TAG ('l','t','r','a'), 1, true);
      allocator.add_feature (HB_TAG ('l','t','r','m'), 1, true);
B
Behdad Esfahbod 已提交
254 255
      break;
    case HB_DIRECTION_RTL:
B
Behdad Esfahbod 已提交
256
      allocator.add_feature (HB_TAG ('r','t','l','a'), 1, true);
257
      allocator.add_feature (HB_TAG ('r','t','l','m'), 1, false);
B
Behdad Esfahbod 已提交
258 259 260 261 262 263 264 265
      break;
    case HB_DIRECTION_TTB:
    case HB_DIRECTION_BTT:
    default:
      break;
  }

  for (i = 0; i < ARRAY_LENGTH (default_features); i++)
B
Behdad Esfahbod 已提交
266 267 268 269
    allocator.add_feature (default_features[i], 1, true);

  /* XXX complex-shaper features go here */

270 271
  for (unsigned int i = 0; i < c->num_features; i++) {
    const hb_feature_t *feature = &c->features[i];
B
Behdad Esfahbod 已提交
272 273
    allocator.add_feature (feature->tag, feature->value, (feature->start == 0 && feature->end == (unsigned int) -1));
  }
B
Behdad Esfahbod 已提交
274 275 276


  /* Compile features */
277
  allocator.compile (c->face, c->table_tag, script_index, language_index);
B
Behdad Esfahbod 已提交
278 279 280 281


  /* Gather lookup indices for features and set buffer masks at the same time */

282
  if (hb_ot_layout_language_get_required_feature_index (c->face, c->table_tag, script_index, language_index,
283
							&feature_index))
284
    add_feature (c->face, c->table_tag, feature_index, 1, lookups, num_lookups, room_lookups);
285

B
Behdad Esfahbod 已提交
286
  const hb_mask_allocator_t::feature_map_t *map;
287

B
Behdad Esfahbod 已提交
288 289
  hb_mask_t global_mask = allocator.get_global_mask ();
  if (global_mask)
290
    c->buffer->set_masks (global_mask, global_mask, 0, (unsigned int) -1);
291

292
  switch (c->original_direction) {
293
    case HB_DIRECTION_LTR:
B
Behdad Esfahbod 已提交
294
      map = allocator.find_feature (HB_TAG ('l','t','r','a'));
295
      add_feature (c->face, c->table_tag, map->index, map->mask, lookups, num_lookups, room_lookups);
B
Behdad Esfahbod 已提交
296
      map = allocator.find_feature (HB_TAG ('l','t','r','m'));
297
      add_feature (c->face, c->table_tag, map->index, map->mask, lookups, num_lookups, room_lookups);
298 299
      break;
    case HB_DIRECTION_RTL:
B
Behdad Esfahbod 已提交
300
      map = allocator.find_feature (HB_TAG ('r','t','l','a'));
301
      add_feature (c->face, c->table_tag, map->index, map->mask, lookups, num_lookups, room_lookups);
302
      map = allocator.find_feature (HB_TAG ('r','t','l','m'));
303
      add_feature (c->face, c->table_tag, map->index, map->mask, lookups, num_lookups, room_lookups);
304 305 306 307 308
      break;
    case HB_DIRECTION_TTB:
    case HB_DIRECTION_BTT:
    default:
      break;
B
Behdad Esfahbod 已提交
309 310
  }

311
  for (i = 0; i < ARRAY_LENGTH (default_features); i++)
B
Behdad Esfahbod 已提交
312
  {
B
Behdad Esfahbod 已提交
313
    map = allocator.find_feature (default_features[i]);
314
    add_feature (c->face, c->table_tag, map->index, map->mask, lookups, num_lookups, room_lookups);
315
  }
B
Behdad Esfahbod 已提交
316

317
  for (i = 0; i < c->num_features; i++)
318
  {
319
    hb_feature_t *feature = &c->features[i];
B
Behdad Esfahbod 已提交
320
    map = allocator.find_feature (feature->tag);
321
    add_feature (c->face, c->table_tag, map->index, map->mask, lookups, num_lookups, room_lookups);
B
Behdad Esfahbod 已提交
322
    if (!(feature->start == 0 && feature->end == (unsigned int)-1))
323
      c->buffer->set_masks (feature->value << map->shift, map->mask, feature->start, feature->end);
B
Behdad Esfahbod 已提交
324 325
  }

326

B
Behdad Esfahbod 已提交
327
  /* Sort lookups and merge duplicates */
B
Behdad Esfahbod 已提交
328

B
Behdad Esfahbod 已提交
329 330 331 332 333
  qsort (lookups, *num_lookups, sizeof (lookups[0]), cmp_lookups);

  if (*num_lookups)
  {
    for (i = 1, j = 0; i < *num_lookups; i++)
B
Behdad Esfahbod 已提交
334
      if (lookups[i].index != lookups[j].index)
B
Behdad Esfahbod 已提交
335
	lookups[++j] = lookups[i];
B
Behdad Esfahbod 已提交
336 337 338
      else
        lookups[j].mask |= lookups[i].mask;
    j++;
B
Behdad Esfahbod 已提交
339 340 341 342 343
    *num_lookups = j;
  }
}


344 345
static void
hb_ot_substitute_complex (hb_ot_shape_context_t *c)
B
Behdad Esfahbod 已提交
346
{
347
  lookup_map lookups[1000]; /* FIXME */
B
Behdad Esfahbod 已提交
348 349 350
  unsigned int num_lookups = ARRAY_LENGTH (lookups);
  unsigned int i;

351 352
  if (!hb_ot_layout_has_substitution (c->face))
    return;
B
Behdad Esfahbod 已提交
353

354 355
  c->table_tag = HB_OT_TAG_GSUB;

B
Behdad Esfahbod 已提交
356
  hb_ot_shape_setup_lookups (c, lookups, &num_lookups);
B
Behdad Esfahbod 已提交
357 358

  for (i = 0; i < num_lookups; i++)
359
    hb_ot_layout_substitute_lookup (c->face, c->buffer, lookups[i].index, lookups[i].mask);
B
Behdad Esfahbod 已提交
360

361 362
  c->applied_substitute_complex = TRUE;
  return;
B
Behdad Esfahbod 已提交
363 364
}

365 366
static void
hb_ot_position_complex (hb_ot_shape_context_t *c)
B
Behdad Esfahbod 已提交
367
{
368
  lookup_map lookups[1000]; /* FIXME */
B
Behdad Esfahbod 已提交
369 370 371
  unsigned int num_lookups = ARRAY_LENGTH (lookups);
  unsigned int i;

372 373
  if (!hb_ot_layout_has_positioning (c->face))
    return;
B
Behdad Esfahbod 已提交
374

375 376
  c->table_tag = HB_OT_TAG_GPOS;

B
Behdad Esfahbod 已提交
377
  hb_ot_shape_setup_lookups (c, lookups, &num_lookups);
B
Behdad Esfahbod 已提交
378 379

  for (i = 0; i < num_lookups; i++)
380
    hb_ot_layout_position_lookup (c->font, c->face, c->buffer, lookups[i].index, lookups[i].mask);
B
Behdad Esfahbod 已提交
381

382
  hb_ot_layout_position_finish (c->font, c->face, c->buffer);
B
Behdad Esfahbod 已提交
383

384 385
  c->applied_position_complex = TRUE;
  return;
B
Behdad Esfahbod 已提交
386
}
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405


/* Main shaper */

/* Prepare */

static inline hb_bool_t
is_variation_selector (hb_codepoint_t unicode)
{
  return unlikely ((unicode >=  0x180B && unicode <=  0x180D) || /* MONGOLIAN FREE VARIATION SELECTOR ONE..THREE */
		   (unicode >=  0xFE00 && unicode <=  0xFE0F) || /* VARIATION SELECTOR-1..16 */
		   (unicode >= 0xE0100 && unicode <= 0xE01EF));  /* VARIATION SELECTOR-17..256 */
}

static void
hb_form_clusters (hb_buffer_t *buffer)
{
  unsigned int count = buffer->len;
  for (unsigned int i = 1; i < count; i++)
406
    if (buffer->unicode->v.get_general_category (buffer->info[i].codepoint) == HB_CATEGORY_NON_SPACING_MARK)
407 408 409
      buffer->info[i].cluster = buffer->info[i - 1].cluster;
}

410
static void
411 412
hb_ensure_native_direction (hb_buffer_t *buffer)
{
413
  hb_direction_t direction = buffer->props.direction;
414 415

  /* TODO vertical */
416 417
  if (HB_DIRECTION_IS_HORIZONTAL (direction) &&
      direction != _hb_script_get_horizontal_direction (buffer->props.script))
418 419
  {
    hb_buffer_reverse_clusters (buffer);
420
    buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction);
421 422 423 424 425 426 427 428 429
  }
}


/* Substitute */

static void
hb_mirror_chars (hb_buffer_t *buffer)
{
430
  hb_unicode_get_mirroring_func_t get_mirroring = buffer->unicode->v.get_mirroring;
431

432
  if (HB_DIRECTION_IS_FORWARD (buffer->props.direction))
433 434
    return;

435 436
//  map = allocator.find_feature (HB_TAG ('r','t','l','m'));

437 438
  unsigned int count = buffer->len;
  for (unsigned int i = 0; i < count; i++) {
B
Behdad Esfahbod 已提交
439 440
    hb_codepoint_t codepoint = get_mirroring (buffer->info[i].codepoint);
    if (likely (codepoint == buffer->info[i].codepoint))
441
;//      buffer->info[i].mask |= map->mask;
B
Behdad Esfahbod 已提交
442 443
    else
      buffer->info[i].codepoint = codepoint;
444 445 446 447 448 449 450 451 452 453 454
  }
}

static void
hb_map_glyphs (hb_font_t    *font,
	       hb_face_t    *face,
	       hb_buffer_t  *buffer)
{
  if (unlikely (!buffer->len))
    return;

455
  buffer->clear_output ();
456
  unsigned int count = buffer->len - 1;
457 458 459 460
  for (buffer->i = 0; buffer->i < count;) {
    if (unlikely (is_variation_selector (buffer->info[buffer->i + 1].codepoint))) {
      buffer->add_output_glyph (hb_font_get_glyph (font, face, buffer->info[buffer->i].codepoint, buffer->info[buffer->i + 1].codepoint));
      buffer->i++;
461
    } else {
462
      buffer->add_output_glyph (hb_font_get_glyph (font, face, buffer->info[buffer->i].codepoint, 0));
463 464
    }
  }
465 466
  if (likely (buffer->i < buffer->len))
    buffer->add_output_glyph (hb_font_get_glyph (font, face, buffer->info[buffer->i].codepoint, 0));
467
  buffer->swap ();
468 469 470
}

static void
471
hb_substitute_default (hb_ot_shape_context_t *c)
472
{
473
  hb_map_glyphs (c->font, c->face, c->buffer);
474 475 476
}

static void
477
hb_substitute_complex_fallback (hb_ot_shape_context_t *c HB_UNUSED)
478 479 480 481 482 483 484 485
{
  /* TODO Arabic */
}


/* Position */

static void
486
hb_position_default (hb_ot_shape_context_t *c)
487
{
488
  hb_buffer_clear_positions (c->buffer);
489

490
  unsigned int count = c->buffer->len;
491 492
  for (unsigned int i = 0; i < count; i++) {
    hb_glyph_metrics_t metrics;
493 494 495
    hb_font_get_glyph_metrics (c->font, c->face, c->buffer->info[i].codepoint, &metrics);
    c->buffer->pos[i].x_advance = metrics.x_advance;
    c->buffer->pos[i].y_advance = metrics.y_advance;
496 497 498 499
  }
}

static void
500
hb_position_complex_fallback (hb_ot_shape_context_t *c HB_UNUSED)
501 502 503 504 505
{
  /* TODO Mark pos */
}

static void
506
hb_truetype_kern (hb_ot_shape_context_t *c)
507 508
{
  /* TODO Check for kern=0 */
509
  unsigned int count = c->buffer->len;
510 511
  for (unsigned int i = 1; i < count; i++) {
    hb_position_t kern, kern1, kern2;
512
    kern = hb_font_get_kerning (c->font, c->face, c->buffer->info[i - 1].codepoint, c->buffer->info[i].codepoint);
513 514
    kern1 = kern >> 1;
    kern2 = kern - kern1;
515 516 517
    c->buffer->pos[i - 1].x_advance += kern1;
    c->buffer->pos[i].x_advance += kern2;
    c->buffer->pos[i].x_offset += kern2;
518 519 520 521
  }
}

static void
522
hb_position_complex_fallback_visual (hb_ot_shape_context_t *c)
523
{
524
  hb_truetype_kern (c);
525 526 527 528 529
}


/* Do it! */

530 531
static void
hb_ot_shape_internal (hb_ot_shape_context_t *c)
532
{
533
  hb_form_clusters (c->buffer);
534

B
Behdad Esfahbod 已提交
535
  /* SUBSTITUTE */
B
Minor  
Behdad Esfahbod 已提交
536
  {
537
    c->buffer->clear_masks ();
B
Behdad Esfahbod 已提交
538

B
Minor  
Behdad Esfahbod 已提交
539
    /* Mirroring needs to see the original direction */
540
    hb_mirror_chars (c->buffer);
541

542
    hb_ensure_native_direction (c->buffer);
543

544
    hb_substitute_default (c);
B
Behdad Esfahbod 已提交
545

546
    hb_ot_substitute_complex (c);
547

548 549
    if (!c->applied_substitute_complex)
      hb_substitute_complex_fallback (c);
B
Minor  
Behdad Esfahbod 已提交
550
  }
B
Behdad Esfahbod 已提交
551 552

  /* POSITION */
B
Minor  
Behdad Esfahbod 已提交
553
  {
554
    c->buffer->clear_masks ();
B
Behdad Esfahbod 已提交
555

556
    hb_position_default (c);
557

558
    hb_ot_position_complex (c);
559

560
    hb_bool_t position_fallback = !c->applied_position_complex;
B
Minor  
Behdad Esfahbod 已提交
561
    if (position_fallback)
562
      hb_position_complex_fallback (c);
563

564 565
    if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction))
      hb_buffer_reverse (c->buffer);
566

B
Minor  
Behdad Esfahbod 已提交
567
    if (position_fallback)
568
      hb_position_complex_fallback_visual (c);
B
Minor  
Behdad Esfahbod 已提交
569
  }
570

571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586
  c->buffer->props.direction = c->original_direction;
}

void
hb_ot_shape (hb_font_t    *font,
	     hb_face_t    *face,
	     hb_buffer_t  *buffer,
	     hb_feature_t *features,
	     unsigned int  num_features)
{
  hb_ot_shape_context_t c = {font, face, buffer, features, num_features};

  /* Setup transient context members */
  c.original_direction = buffer->props.direction;

  hb_ot_shape_internal (&c);
587
}
B
Behdad Esfahbod 已提交
588 589 590


HB_END_DECLS