1/*
2 * Copyright © 2009,2010  Red Hat, Inc.
3 * Copyright © 2010,2011,2012  Google, Inc.
4 *
5 *  This is part of HarfBuzz, a text shaping library.
6 *
7 * Permission is hereby granted, without written agreement and without
8 * license or royalty fees, to use, copy, modify, and distribute this
9 * software and its documentation for any purpose, provided that the
10 * above copyright notice and the following two paragraphs appear in
11 * all copies of this software.
12 *
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17 * DAMAGE.
18 *
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24 *
25 * Red Hat Author(s): Behdad Esfahbod
26 * Google Author(s): Behdad Esfahbod
27 */
28
29#define HB_SHAPER ot
30#define hb_ot_shaper_face_data_t hb_ot_layout_t
31#define hb_ot_shaper_shape_plan_data_t hb_ot_shape_plan_t
32#include "hb-shaper-impl-private.hh"
33
34#include "hb-ot-shape-private.hh"
35#include "hb-ot-shape-complex-private.hh"
36#include "hb-ot-shape-fallback-private.hh"
37#include "hb-ot-shape-normalize-private.hh"
38
39#include "hb-ot-layout-private.hh"
40#include "hb-unicode-private.hh"
41#include "hb-set-private.hh"
42
43
44static hb_tag_t common_features[] = {
45  HB_TAG('c','c','m','p'),
46  HB_TAG('l','o','c','l'),
47  HB_TAG('m','a','r','k'),
48  HB_TAG('m','k','m','k'),
49  HB_TAG('r','l','i','g'),
50};
51
52
53static hb_tag_t horizontal_features[] = {
54  HB_TAG('c','a','l','t'),
55  HB_TAG('c','l','i','g'),
56  HB_TAG('c','u','r','s'),
57  HB_TAG('k','e','r','n'),
58  HB_TAG('l','i','g','a'),
59  HB_TAG('r','c','l','t'),
60};
61
62
63
64static void
65hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
66			      const hb_segment_properties_t  *props,
67			      const hb_feature_t             *user_features,
68			      unsigned int                    num_user_features)
69{
70  hb_ot_map_builder_t *map = &planner->map;
71
72  switch (props->direction) {
73    case HB_DIRECTION_LTR:
74      map->add_global_bool_feature (HB_TAG ('l','t','r','a'));
75      map->add_global_bool_feature (HB_TAG ('l','t','r','m'));
76      break;
77    case HB_DIRECTION_RTL:
78      map->add_global_bool_feature (HB_TAG ('r','t','l','a'));
79      map->add_feature (HB_TAG ('r','t','l','m'), 1, F_NONE);
80      break;
81    case HB_DIRECTION_TTB:
82    case HB_DIRECTION_BTT:
83    case HB_DIRECTION_INVALID:
84    default:
85      break;
86  }
87
88  map->add_feature (HB_TAG ('f','r','a','c'), 1, F_NONE);
89  map->add_feature (HB_TAG ('n','u','m','r'), 1, F_NONE);
90  map->add_feature (HB_TAG ('d','n','o','m'), 1, F_NONE);
91
92  if (planner->shaper->collect_features)
93    planner->shaper->collect_features (planner);
94
95  for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++)
96    map->add_global_bool_feature (common_features[i]);
97
98  if (HB_DIRECTION_IS_HORIZONTAL (props->direction))
99    for (unsigned int i = 0; i < ARRAY_LENGTH (horizontal_features); i++)
100      map->add_feature (horizontal_features[i], 1, F_GLOBAL |
101			(horizontal_features[i] == HB_TAG('k','e','r','n') ?
102			 F_HAS_FALLBACK : F_NONE));
103  else
104  {
105    /* We really want to find a 'vert' feature if there's any in the font, no
106     * matter which script/langsys it is listed (or not) under.
107     * See various bugs referenced from:
108     * https://github.com/behdad/harfbuzz/issues/63 */
109    map->add_feature (HB_TAG ('v','e','r','t'), 1, F_GLOBAL | F_GLOBAL_SEARCH);
110  }
111
112  if (planner->shaper->override_features)
113    planner->shaper->override_features (planner);
114
115  for (unsigned int i = 0; i < num_user_features; i++) {
116    const hb_feature_t *feature = &user_features[i];
117    map->add_feature (feature->tag, feature->value,
118		      (feature->start == 0 && feature->end == (unsigned int) -1) ?
119		       F_GLOBAL : F_NONE);
120  }
121}
122
123
124/*
125 * shaper face data
126 */
127
128hb_ot_shaper_face_data_t *
129_hb_ot_shaper_face_data_create (hb_face_t *face)
130{
131  return _hb_ot_layout_create (face);
132}
133
134void
135_hb_ot_shaper_face_data_destroy (hb_ot_shaper_face_data_t *data)
136{
137  _hb_ot_layout_destroy (data);
138}
139
140
141/*
142 * shaper font data
143 */
144
145struct hb_ot_shaper_font_data_t {};
146
147hb_ot_shaper_font_data_t *
148_hb_ot_shaper_font_data_create (hb_font_t *font HB_UNUSED)
149{
150  return (hb_ot_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
151}
152
153void
154_hb_ot_shaper_font_data_destroy (hb_ot_shaper_font_data_t *data)
155{
156}
157
158
159/*
160 * shaper shape_plan data
161 */
162
163hb_ot_shaper_shape_plan_data_t *
164_hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan,
165				      const hb_feature_t *user_features,
166				      unsigned int        num_user_features)
167{
168  hb_ot_shape_plan_t *plan = (hb_ot_shape_plan_t *) calloc (1, sizeof (hb_ot_shape_plan_t));
169  if (unlikely (!plan))
170    return NULL;
171
172  hb_ot_shape_planner_t planner (shape_plan);
173
174  planner.shaper = hb_ot_shape_complex_categorize (&planner);
175
176  hb_ot_shape_collect_features (&planner, &shape_plan->props, user_features, num_user_features);
177
178  planner.compile (*plan);
179
180  if (plan->shaper->data_create) {
181    plan->data = plan->shaper->data_create (plan);
182    if (unlikely (!plan->data))
183      return NULL;
184  }
185
186  return plan;
187}
188
189void
190_hb_ot_shaper_shape_plan_data_destroy (hb_ot_shaper_shape_plan_data_t *plan)
191{
192  if (plan->shaper->data_destroy)
193    plan->shaper->data_destroy (const_cast<void *> (plan->data));
194
195  plan->finish ();
196
197  free (plan);
198}
199
200
201/*
202 * shaper
203 */
204
205struct hb_ot_shape_context_t
206{
207  hb_ot_shape_plan_t *plan;
208  hb_font_t *font;
209  hb_face_t *face;
210  hb_buffer_t  *buffer;
211  const hb_feature_t *user_features;
212  unsigned int        num_user_features;
213
214  /* Transient stuff */
215  hb_direction_t target_direction;
216};
217
218
219
220/* Main shaper */
221
222
223/* Prepare */
224
225static void
226hb_set_unicode_props (hb_buffer_t *buffer)
227{
228  unsigned int count = buffer->len;
229  hb_glyph_info_t *info = buffer->info;
230  for (unsigned int i = 0; i < count; i++)
231    _hb_glyph_info_set_unicode_props (&info[i], buffer);
232}
233
234static void
235hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
236{
237  if (!(buffer->flags & HB_BUFFER_FLAG_BOT) ||
238      buffer->context_len[0] ||
239      _hb_glyph_info_get_general_category (&buffer->info[0]) !=
240      HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
241    return;
242
243  if (!font->has_glyph (0x25CCu))
244    return;
245
246  hb_glyph_info_t dottedcircle = {0};
247  dottedcircle.codepoint = 0x25CCu;
248  _hb_glyph_info_set_unicode_props (&dottedcircle, buffer);
249
250  buffer->clear_output ();
251
252  buffer->idx = 0;
253  hb_glyph_info_t info = dottedcircle;
254  info.cluster = buffer->cur().cluster;
255  info.mask = buffer->cur().mask;
256  buffer->output_info (info);
257  while (buffer->idx < buffer->len && !buffer->in_error)
258    buffer->next_glyph ();
259
260  buffer->swap_buffers ();
261}
262
263static void
264hb_form_clusters (hb_buffer_t *buffer)
265{
266  if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) ||
267      buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
268    return;
269
270  /* Loop duplicated in hb_ensure_native_direction(), and in _hb-coretext.cc */
271  unsigned int base = 0;
272  unsigned int count = buffer->len;
273  hb_glyph_info_t *info = buffer->info;
274  for (unsigned int i = 1; i < count; i++)
275  {
276    if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])) &&
277		!_hb_glyph_info_is_joiner (&info[i])))
278    {
279      buffer->merge_clusters (base, i);
280      base = i;
281    }
282  }
283  buffer->merge_clusters (base, count);
284}
285
286static void
287hb_ensure_native_direction (hb_buffer_t *buffer)
288{
289  hb_direction_t direction = buffer->props.direction;
290
291  /* TODO vertical:
292   * The only BTT vertical script is Ogham, but it's not clear to me whether OpenType
293   * Ogham fonts are supposed to be implemented BTT or not.  Need to research that
294   * first. */
295  if ((HB_DIRECTION_IS_HORIZONTAL (direction) && direction != hb_script_get_horizontal_direction (buffer->props.script)) ||
296      (HB_DIRECTION_IS_VERTICAL   (direction) && direction != HB_DIRECTION_TTB))
297  {
298    /* Same loop as hb_form_clusters().
299     * Since form_clusters() merged clusters already, we don't merge. */
300    unsigned int base = 0;
301    unsigned int count = buffer->len;
302    hb_glyph_info_t *info = buffer->info;
303    for (unsigned int i = 1; i < count; i++)
304    {
305      if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i]))))
306      {
307	if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
308	  buffer->merge_clusters (base, i);
309	buffer->reverse_range (base, i);
310
311	base = i;
312      }
313    }
314    if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
315      buffer->merge_clusters (base, count);
316    buffer->reverse_range (base, count);
317
318    buffer->reverse ();
319
320    buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction);
321  }
322}
323
324
325/* Substitute */
326
327static inline void
328hb_ot_mirror_chars (hb_ot_shape_context_t *c)
329{
330  if (HB_DIRECTION_IS_FORWARD (c->target_direction))
331    return;
332
333  hb_buffer_t *buffer = c->buffer;
334  hb_unicode_funcs_t *unicode = buffer->unicode;
335  hb_mask_t rtlm_mask = c->plan->rtlm_mask;
336
337  unsigned int count = buffer->len;
338  hb_glyph_info_t *info = buffer->info;
339  for (unsigned int i = 0; i < count; i++) {
340    hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint);
341    if (likely (codepoint == info[i].codepoint || !c->font->has_glyph (codepoint)))
342      info[i].mask |= rtlm_mask;
343    else
344      info[i].codepoint = codepoint;
345  }
346}
347
348static inline void
349hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c)
350{
351  if (!(c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) ||
352      !c->plan->has_frac)
353    return;
354
355  hb_buffer_t *buffer = c->buffer;
356
357  /* TODO look in pre/post context text also. */
358  unsigned int count = buffer->len;
359  hb_glyph_info_t *info = buffer->info;
360  for (unsigned int i = 0; i < count; i++)
361  {
362    if (info[i].codepoint == 0x2044u) /* FRACTION SLASH */
363    {
364      unsigned int start = i, end = i + 1;
365      while (start &&
366	     _hb_glyph_info_get_general_category (&info[start - 1]) ==
367	     HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
368        start--;
369      while (end < count &&
370	     _hb_glyph_info_get_general_category (&info[end]) ==
371	     HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
372        end++;
373
374      for (unsigned int j = start; j < i; j++)
375        info[j].mask |= c->plan->numr_mask | c->plan->frac_mask;
376      info[i].mask |= c->plan->frac_mask;
377      for (unsigned int j = i + 1; j < end; j++)
378        info[j].mask |= c->plan->frac_mask | c->plan->dnom_mask;
379
380      i = end - 1;
381    }
382  }
383}
384
385static inline void
386hb_ot_shape_initialize_masks (hb_ot_shape_context_t *c)
387{
388  hb_ot_map_t *map = &c->plan->map;
389  hb_buffer_t *buffer = c->buffer;
390
391  hb_mask_t global_mask = map->get_global_mask ();
392  buffer->reset_masks (global_mask);
393}
394
395static inline void
396hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
397{
398  hb_ot_map_t *map = &c->plan->map;
399  hb_buffer_t *buffer = c->buffer;
400
401  hb_ot_shape_setup_masks_fraction (c);
402
403  if (c->plan->shaper->setup_masks)
404    c->plan->shaper->setup_masks (c->plan, buffer, c->font);
405
406  for (unsigned int i = 0; i < c->num_user_features; i++)
407  {
408    const hb_feature_t *feature = &c->user_features[i];
409    if (!(feature->start == 0 && feature->end == (unsigned int)-1)) {
410      unsigned int shift;
411      hb_mask_t mask = map->get_mask (feature->tag, &shift);
412      buffer->set_masks (feature->value << shift, mask, feature->start, feature->end);
413    }
414  }
415}
416
417static void
418hb_ot_zero_width_default_ignorables (hb_ot_shape_context_t *c)
419{
420  hb_buffer_t *buffer = c->buffer;
421
422  if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) ||
423      (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES))
424    return;
425
426  unsigned int count = buffer->len;
427  hb_glyph_info_t *info = buffer->info;
428  hb_glyph_position_t *pos = buffer->pos;
429  unsigned int i = 0;
430  for (i = 0; i < count; i++)
431    if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i])))
432      pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0;
433}
434
435static void
436hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
437{
438  hb_buffer_t *buffer = c->buffer;
439
440  if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) ||
441      (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES))
442    return;
443
444  unsigned int count = buffer->len;
445  hb_glyph_info_t *info = buffer->info;
446  hb_glyph_position_t *pos = buffer->pos;
447  unsigned int i = 0;
448  for (i = 0; i < count; i++)
449  {
450    if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i])))
451      break;
452  }
453
454  /* No default-ignorables found; return. */
455  if (i == count)
456    return;
457
458  hb_codepoint_t space;
459  if (c->font->get_nominal_glyph (' ', &space))
460  {
461    /* Replace default-ignorables with a zero-advance space glyph. */
462    for (/*continue*/; i < count; i++)
463    {
464      if (_hb_glyph_info_is_default_ignorable (&info[i]))
465	info[i].codepoint = space;
466    }
467  }
468  else
469  {
470    /* Merge clusters and delete default-ignorables.
471     * NOTE! We can't use out-buffer as we have positioning data. */
472    unsigned int j = i;
473    for (; i < count; i++)
474    {
475      if (_hb_glyph_info_is_default_ignorable (&info[i]))
476      {
477	/* Merge clusters.
478	 * Same logic as buffer->delete_glyph(), but for in-place removal. */
479
480	unsigned int cluster = info[i].cluster;
481	if (i + 1 < count && cluster == info[i + 1].cluster)
482	  continue; /* Cluster survives; do nothing. */
483
484	if (j)
485	{
486	  /* Merge cluster backward. */
487	  if (cluster < info[j - 1].cluster)
488	  {
489	    unsigned int old_cluster = info[j - 1].cluster;
490	    for (unsigned k = j; k && info[k - 1].cluster == old_cluster; k--)
491	      info[k - 1].cluster = cluster;
492	  }
493	  continue;
494	}
495
496	if (i + 1 < count)
497	  buffer->merge_clusters (i, i + 2); /* Merge cluster forward. */
498
499	continue;
500      }
501
502      if (j != i)
503      {
504	info[j] = info[i];
505	pos[j] = pos[i];
506      }
507      j++;
508    }
509    buffer->len = j;
510  }
511}
512
513
514static inline void
515hb_ot_map_glyphs_fast (hb_buffer_t  *buffer)
516{
517  /* Normalization process sets up glyph_index(), we just copy it. */
518  unsigned int count = buffer->len;
519  hb_glyph_info_t *info = buffer->info;
520  for (unsigned int i = 0; i < count; i++)
521    info[i].codepoint = info[i].glyph_index();
522
523  buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
524}
525
526static inline void
527hb_ot_substitute_default (hb_ot_shape_context_t *c)
528{
529  hb_buffer_t *buffer = c->buffer;
530
531  hb_ot_shape_initialize_masks (c);
532
533  hb_ot_mirror_chars (c);
534
535  HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index);
536
537  _hb_ot_shape_normalize (c->plan, buffer, c->font);
538
539  hb_ot_shape_setup_masks (c);
540
541  /* This is unfortunate to go here, but necessary... */
542  if (!hb_ot_layout_has_positioning (c->face))
543    _hb_ot_shape_fallback_position_recategorize_marks (c->plan, c->font, buffer);
544
545  hb_ot_map_glyphs_fast (buffer);
546
547  HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_index);
548}
549
550static inline void
551hb_ot_substitute_complex (hb_ot_shape_context_t *c)
552{
553  hb_buffer_t *buffer = c->buffer;
554
555  hb_ot_layout_substitute_start (c->font, buffer);
556
557  c->plan->substitute (c->font, buffer);
558
559  return;
560}
561
562static inline void
563hb_ot_substitute (hb_ot_shape_context_t *c)
564{
565  hb_ot_substitute_default (c);
566
567  _hb_buffer_allocate_gsubgpos_vars (c->buffer);
568
569  hb_ot_substitute_complex (c);
570}
571
572/* Position */
573
574static inline void
575adjust_mark_offsets (hb_glyph_position_t *pos)
576{
577  pos->x_offset -= pos->x_advance;
578  pos->y_offset -= pos->y_advance;
579}
580
581static inline void
582zero_mark_width (hb_glyph_position_t *pos)
583{
584  pos->x_advance = 0;
585  pos->y_advance = 0;
586}
587
588static inline void
589zero_mark_widths_by_gdef (hb_buffer_t *buffer, bool adjust_offsets)
590{
591  unsigned int count = buffer->len;
592  hb_glyph_info_t *info = buffer->info;
593  for (unsigned int i = 0; i < count; i++)
594    if (_hb_glyph_info_is_mark (&info[i]))
595    {
596      if (adjust_offsets)
597        adjust_mark_offsets (&buffer->pos[i]);
598      zero_mark_width (&buffer->pos[i]);
599    }
600}
601
602static inline void
603hb_ot_position_default (hb_ot_shape_context_t *c)
604{
605  hb_direction_t direction = c->buffer->props.direction;
606  unsigned int count = c->buffer->len;
607  hb_glyph_info_t *info = c->buffer->info;
608  hb_glyph_position_t *pos = c->buffer->pos;
609
610  if (HB_DIRECTION_IS_HORIZONTAL (direction))
611  {
612    for (unsigned int i = 0; i < count; i++)
613      pos[i].x_advance = c->font->get_glyph_h_advance (info[i].codepoint);
614    /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
615    if (c->font->has_glyph_h_origin_func ())
616      for (unsigned int i = 0; i < count; i++)
617	c->font->subtract_glyph_h_origin (info[i].codepoint,
618					  &pos[i].x_offset,
619					  &pos[i].y_offset);
620  }
621  else
622  {
623    for (unsigned int i = 0; i < count; i++)
624    {
625      pos[i].y_advance = c->font->get_glyph_v_advance (info[i].codepoint);
626      c->font->subtract_glyph_v_origin (info[i].codepoint,
627					&pos[i].x_offset,
628					&pos[i].y_offset);
629    }
630  }
631  if (c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK)
632    _hb_ot_shape_fallback_spaces (c->plan, c->font, c->buffer);
633}
634
635static inline bool
636hb_ot_position_complex (hb_ot_shape_context_t *c)
637{
638  hb_ot_layout_position_start (c->font, c->buffer);
639
640  bool ret = false;
641  unsigned int count = c->buffer->len;
642  bool has_positioning = (bool) hb_ot_layout_has_positioning (c->face);
643
644  /* If the font has no GPOS, AND, no fallback positioning will
645   * happen, AND, direction is forward, then when zeroing mark
646   * widths, we shift the mark with it, such that the mark
647   * is positioned hanging over the previous glyph.  When
648   * direction is backward we don't shift and it will end up
649   * hanging over the next glyph after the final reordering.
650   * If fallback positinoing happens or GPOS is present, we don't
651   * care.
652   */
653  bool adjust_offsets_when_zeroing = !(has_positioning || c->plan->shaper->fallback_position ||
654                                       HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction));
655
656  switch (c->plan->shaper->zero_width_marks)
657  {
658    case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
659      zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
660      break;
661
662    default:
663    case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
664    case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
665      break;
666  }
667
668  if (has_positioning)
669  {
670    hb_glyph_info_t *info = c->buffer->info;
671    hb_glyph_position_t *pos = c->buffer->pos;
672
673    /* Change glyph origin to what GPOS expects (horizontal), apply GPOS, change it back. */
674
675    /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
676    if (c->font->has_glyph_h_origin_func ())
677      for (unsigned int i = 0; i < count; i++)
678	c->font->add_glyph_h_origin (info[i].codepoint,
679				     &pos[i].x_offset,
680				     &pos[i].y_offset);
681
682    c->plan->position (c->font, c->buffer);
683
684    /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
685    if (c->font->has_glyph_h_origin_func ())
686      for (unsigned int i = 0; i < count; i++)
687	c->font->subtract_glyph_h_origin (info[i].codepoint,
688					  &pos[i].x_offset,
689					  &pos[i].y_offset);
690
691    ret = true;
692  }
693
694  switch (c->plan->shaper->zero_width_marks)
695  {
696    case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
697      zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
698      break;
699
700    default:
701    case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
702    case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
703      break;
704  }
705
706  /* Finishing off GPOS has to follow a certain order. */
707  hb_ot_layout_position_finish_advances (c->font, c->buffer);
708  hb_ot_zero_width_default_ignorables (c);
709  hb_ot_layout_position_finish_offsets (c->font, c->buffer);
710
711  return ret;
712}
713
714static inline void
715hb_ot_position (hb_ot_shape_context_t *c)
716{
717  c->buffer->clear_positions ();
718
719  hb_ot_position_default (c);
720
721  hb_bool_t fallback = !hb_ot_position_complex (c);
722
723  if (fallback && c->plan->shaper->fallback_position)
724    _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer);
725
726  if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction))
727    hb_buffer_reverse (c->buffer);
728
729  /* Visual fallback goes here. */
730
731  if (fallback)
732    _hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer);
733
734  _hb_buffer_deallocate_gsubgpos_vars (c->buffer);
735}
736
737
738/* Pull it all together! */
739
740static void
741hb_ot_shape_internal (hb_ot_shape_context_t *c)
742{
743  c->buffer->deallocate_var_all ();
744  c->buffer->scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
745  if (likely (!_hb_unsigned_int_mul_overflows (c->buffer->len, HB_BUFFER_MAX_EXPANSION_FACTOR)))
746  {
747    c->buffer->max_len = MAX (c->buffer->len * HB_BUFFER_MAX_EXPANSION_FACTOR,
748			      (unsigned) HB_BUFFER_MAX_LEN_MIN);
749  }
750
751  /* Save the original direction, we use it later. */
752  c->target_direction = c->buffer->props.direction;
753
754  _hb_buffer_allocate_unicode_vars (c->buffer);
755
756  c->buffer->clear_output ();
757
758  hb_set_unicode_props (c->buffer);
759  hb_insert_dotted_circle (c->buffer, c->font);
760  hb_form_clusters (c->buffer);
761
762  hb_ensure_native_direction (c->buffer);
763
764  if (c->plan->shaper->preprocess_text)
765    c->plan->shaper->preprocess_text (c->plan, c->buffer, c->font);
766
767  hb_ot_substitute (c);
768  hb_ot_position (c);
769
770  hb_ot_hide_default_ignorables (c);
771
772  if (c->plan->shaper->postprocess_glyphs)
773    c->plan->shaper->postprocess_glyphs (c->plan, c->buffer, c->font);
774
775  _hb_buffer_deallocate_unicode_vars (c->buffer);
776
777  c->buffer->props.direction = c->target_direction;
778
779  c->buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;
780  c->buffer->deallocate_var_all ();
781}
782
783
784hb_bool_t
785_hb_ot_shape (hb_shape_plan_t    *shape_plan,
786	      hb_font_t          *font,
787	      hb_buffer_t        *buffer,
788	      const hb_feature_t *features,
789	      unsigned int        num_features)
790{
791  hb_ot_shape_context_t c = {HB_SHAPER_DATA_GET (shape_plan), font, font->face, buffer, features, num_features};
792  hb_ot_shape_internal (&c);
793
794  return true;
795}
796
797
798/**
799 * hb_ot_shape_plan_collect_lookups:
800 *
801 * Since: 0.9.7
802 **/
803void
804hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
805				  hb_tag_t         table_tag,
806				  hb_set_t        *lookup_indexes /* OUT */)
807{
808  /* XXX Does the first part always succeed? */
809  HB_SHAPER_DATA_GET (shape_plan)->collect_lookups (table_tag, lookup_indexes);
810}
811
812
813/* TODO Move this to hb-ot-shape-normalize, make it do decompose, and make it public. */
814static void
815add_char (hb_font_t          *font,
816	  hb_unicode_funcs_t *unicode,
817	  hb_bool_t           mirror,
818	  hb_codepoint_t      u,
819	  hb_set_t           *glyphs)
820{
821  hb_codepoint_t glyph;
822  if (font->get_nominal_glyph (u, &glyph))
823    glyphs->add (glyph);
824  if (mirror)
825  {
826    hb_codepoint_t m = unicode->mirroring (u);
827    if (m != u && font->get_nominal_glyph (m, &glyph))
828      glyphs->add (glyph);
829  }
830}
831
832
833/**
834 * hb_ot_shape_glyphs_closure:
835 *
836 * Since: 0.9.2
837 **/
838void
839hb_ot_shape_glyphs_closure (hb_font_t          *font,
840			    hb_buffer_t        *buffer,
841			    const hb_feature_t *features,
842			    unsigned int        num_features,
843			    hb_set_t           *glyphs)
844{
845  hb_ot_shape_plan_t plan;
846
847  const char *shapers[] = {"ot", NULL};
848  hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props,
849							     features, num_features, shapers);
850
851  bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_DIRECTION_RTL;
852
853  unsigned int count = buffer->len;
854  hb_glyph_info_t *info = buffer->info;
855  for (unsigned int i = 0; i < count; i++)
856    add_char (font, buffer->unicode, mirror, info[i].codepoint, glyphs);
857
858  hb_set_t lookups;
859  lookups.init ();
860  hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, &lookups);
861
862  /* And find transitive closure. */
863  hb_set_t copy;
864  copy.init ();
865  do {
866    copy.set (glyphs);
867    for (hb_codepoint_t lookup_index = -1; hb_set_next (&lookups, &lookup_index);)
868      hb_ot_layout_lookup_substitute_closure (font->face, lookup_index, glyphs);
869  } while (!copy.is_equal (glyphs));
870
871  hb_shape_plan_destroy (shape_plan);
872}
873