w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

hb-ot-shape-complex-arabic.cc
Go to the documentation of this file.
1 /*
2  * Copyright © 2010,2012 Google, Inc.
3  *
4  * This is part of HarfBuzz, a text shaping library.
5  *
6  * Permission is hereby granted, without written agreement and without
7  * license or royalty fees, to use, copy, modify, and distribute this
8  * software and its documentation for any purpose, provided that the
9  * above copyright notice and the following two paragraphs appear in
10  * all copies of this software.
11  *
12  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16  * DAMAGE.
17  *
18  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23  *
24  * Google Author(s): Behdad Esfahbod
25  */
26 
27 #include "hb.hh"
28 
29 #ifndef HB_NO_OT_SHAPE
30 
32 #include "hb-ot-shape.hh"
33 
34 
35 /* buffer var allocations */
36 #define arabic_shaping_action() complex_var_u8_0() /* arabic shaping action */
37 
38 #define HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH HB_BUFFER_SCRATCH_FLAG_COMPLEX0
39 
40 /* See:
41  * https://github.com/harfbuzz/harfbuzz/commit/6e6f82b6f3dde0fc6c3c7d991d9ec6cfff57823d#commitcomment-14248516 */
42 #define HB_ARABIC_GENERAL_CATEGORY_IS_WORD(gen_cat) \
43  (FLAG_UNSAFE (gen_cat) & \
44  (FLAG (HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED) | \
45  FLAG (HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE) | \
46  /*FLAG (HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER) |*/ \
47  FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER) | \
48  FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER) | \
49  /*FLAG (HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER) |*/ \
50  /*FLAG (HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER) |*/ \
51  FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \
52  FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | \
53  FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) | \
54  FLAG (HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) | \
55  FLAG (HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER) | \
56  FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER) | \
57  FLAG (HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL) | \
58  FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL) | \
59  FLAG (HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL) | \
60  FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL)))
61 
62 
63 /*
64  * Joining types:
65  */
66 
67 /*
68  * Bits used in the joining tables
69  */
79 
81  JOINING_TYPE_X = 8 /* means: use general-category to choose between U or T. */
82 };
83 
85 
87 {
88  unsigned int j_type = joining_type(u);
89  if (likely (j_type != JOINING_TYPE_X))
90  return j_type;
91 
92  return (FLAG_UNSAFE(gen_cat) &
97 }
98 
99 #define FEATURE_IS_SYRIAC(tag) hb_in_range<unsigned char> ((unsigned char) (tag), '2', '3')
100 
101 static const hb_tag_t arabic_features[] =
102 {
103  HB_TAG('i','s','o','l'),
104  HB_TAG('f','i','n','a'),
105  HB_TAG('f','i','n','2'),
106  HB_TAG('f','i','n','3'),
107  HB_TAG('m','e','d','i'),
108  HB_TAG('m','e','d','2'),
109  HB_TAG('i','n','i','t'),
111 };
112 
113 
114 /* Same order as the feature array */
123 
125 
127 
128  /* We abuse the same byte for other things... */
131 };
132 
133 static const struct arabic_state_table_entry {
138 {
139  /* jt_U, jt_L, jt_R, jt_D, jg_ALAPH, jg_DALATH_RISH */
140 
141  /* State 0: prev was U, not willing to join. */
142  { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,6}, },
143 
144  /* State 1: prev was R or ISOL/ALAPH, not willing to join. */
145  { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN2,5}, {NONE,ISOL,6}, },
146 
147  /* State 2: prev was D/L in ISOL form, willing to join. */
148  { {NONE,NONE,0}, {NONE,ISOL,2}, {INIT,FINA,1}, {INIT,FINA,3}, {INIT,FINA,4}, {INIT,FINA,6}, },
149 
150  /* State 3: prev was D in FINA form, willing to join. */
151  { {NONE,NONE,0}, {NONE,ISOL,2}, {MEDI,FINA,1}, {MEDI,FINA,3}, {MEDI,FINA,4}, {MEDI,FINA,6}, },
152 
153  /* State 4: prev was FINA ALAPH, not willing to join. */
154  { {NONE,NONE,0}, {NONE,ISOL,2}, {MED2,ISOL,1}, {MED2,ISOL,2}, {MED2,FIN2,5}, {MED2,ISOL,6}, },
155 
156  /* State 5: prev was FIN2/FIN3 ALAPH, not willing to join. */
157  { {NONE,NONE,0}, {NONE,ISOL,2}, {ISOL,ISOL,1}, {ISOL,ISOL,2}, {ISOL,FIN2,5}, {ISOL,ISOL,6}, },
158 
159  /* State 6: prev was DALATH/RISH, not willing to join. */
160  { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN3,5}, {NONE,ISOL,6}, }
161 };
162 
163 
164 static void
166  hb_font_t *font,
168 
169 static void
170 record_stch (const hb_ot_shape_plan_t *plan,
171  hb_font_t *font,
173 
174 static void
176 {
177  hb_ot_map_builder_t *map = &plan->map;
178 
179  /* We apply features according to the Arabic spec, with pauses
180  * in between most.
181  *
182  * The pause between init/medi/... and rlig is required. See eg:
183  * https://bugzilla.mozilla.org/show_bug.cgi?id=644184
184  *
185  * The pauses between init/medi/... themselves are not necessarily
186  * needed as only one of those features is applied to any character.
187  * The only difference it makes is when fonts have contextual
188  * substitutions. We now follow the order of the spec, which makes
189  * for better experience if that's what Uniscribe is doing.
190  *
191  * At least for Arabic, looks like Uniscribe has a pause between
192  * rlig and calt. Otherwise the IranNastaliq's ALLAH ligature won't
193  * work. However, testing shows that rlig and calt are applied
194  * together for Mongolian in Uniscribe. As such, we only add a
195  * pause for Arabic, not other scripts.
196  *
197  * A pause after calt is required to make KFGQPC Uthmanic Script HAFS
198  * work correctly. See https://github.com/harfbuzz/harfbuzz/issues/505
199  */
200 
201 
202  map->enable_feature (HB_TAG('s','t','c','h'));
203  map->add_gsub_pause (record_stch);
204 
205  map->enable_feature (HB_TAG('c','c','m','p'));
206  map->enable_feature (HB_TAG('l','o','c','l'));
207 
208  map->add_gsub_pause (nullptr);
209 
210  for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++)
211  {
212  bool has_fallback = plan->props.script == HB_SCRIPT_ARABIC && !FEATURE_IS_SYRIAC (arabic_features[i]);
213  map->add_feature (arabic_features[i], has_fallback ? F_HAS_FALLBACK : F_NONE);
214  map->add_gsub_pause (nullptr);
215  }
216 
217  /* Normally, Unicode says a ZWNJ means "don't ligate". In Arabic script
218  * however, it says a ZWJ should also mean "don't ligate". So we run
219  * the main ligating features as MANUAL_ZWJ. */
220 
221  map->enable_feature (HB_TAG('r','l','i','g'), F_MANUAL_ZWJ | F_HAS_FALLBACK);
222 
223  if (plan->props.script == HB_SCRIPT_ARABIC)
224  map->add_gsub_pause (arabic_fallback_shape);
225 
226  /* No pause after rclt. See 98460779bae19e4d64d29461ff154b3527bf8420. */
227  map->enable_feature (HB_TAG('r','c','l','t'), F_MANUAL_ZWJ);
228  map->enable_feature (HB_TAG('c','a','l','t'), F_MANUAL_ZWJ);
229  map->add_gsub_pause (nullptr);
230 
231  /* The spec includes 'cswh'. Earlier versions of Windows
232  * used to enable this by default, but testing suggests
233  * that Windows 8 and later do not enable it by default,
234  * and spec now says 'Off by default'.
235  * We disabled this in ae23c24c32.
236  * Note that IranNastaliq uses this feature extensively
237  * to fixup broken glyph sequences. Oh well...
238  * Test case: U+0643,U+0640,U+0631. */
239  //map->enable_feature (HB_TAG('c','s','w','h'));
240  map->enable_feature (HB_TAG('m','s','e','t'));
241 }
242 
244 
245 struct arabic_shape_plan_t
246 {
247  /* The "+ 1" in the next array is to accommodate for the "NONE" command,
248  * which is not an OpenType feature, but this simplifies the code by not
249  * having to do a "if (... < NONE) ..." and just rely on the fact that
250  * mask_array[NONE] == 0. */
252 
254 
255  unsigned int do_fallback : 1;
256  unsigned int has_stch : 1;
257 };
258 
259 void *
261 {
262  arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) calloc (1, sizeof (arabic_shape_plan_t));
263  if (unlikely (!arabic_plan))
264  return nullptr;
265 
266  arabic_plan->do_fallback = plan->props.script == HB_SCRIPT_ARABIC;
267  arabic_plan->has_stch = !!plan->map.get_1_mask (HB_TAG ('s','t','c','h'));
268  for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) {
269  arabic_plan->mask_array[i] = plan->map.get_1_mask (arabic_features[i]);
270  arabic_plan->do_fallback = arabic_plan->do_fallback &&
273  }
274 
275  return arabic_plan;
276 }
277 
278 void
280 {
281  arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) data;
282 
284 
285  free (data);
286 }
287 
288 static void
290 {
291  unsigned int count = buffer->len;
292  hb_glyph_info_t *info = buffer->info;
293  unsigned int prev = UINT_MAX, state = 0;
294 
295  /* Check pre-context */
296  for (unsigned int i = 0; i < buffer->context_len[0]; i++)
297  {
298  unsigned int this_type = get_joining_type (buffer->context[0][i], buffer->unicode->general_category (buffer->context[0][i]));
299 
300  if (unlikely (this_type == JOINING_TYPE_T))
301  continue;
302 
304  state = entry->next_state;
305  break;
306  }
307 
308  for (unsigned int i = 0; i < count; i++)
309  {
310  unsigned int this_type = get_joining_type (info[i].codepoint, _hb_glyph_info_get_general_category (&info[i]));
311 
312  if (unlikely (this_type == JOINING_TYPE_T)) {
313  info[i].arabic_shaping_action() = NONE;
314  continue;
315  }
316 
318 
319  if (entry->prev_action != NONE && prev != UINT_MAX)
320  {
321  info[prev].arabic_shaping_action() = entry->prev_action;
322  buffer->unsafe_to_break (prev, i + 1);
323  }
324 
325  info[i].arabic_shaping_action() = entry->curr_action;
326 
327  prev = i;
328  state = entry->next_state;
329  }
330 
331  for (unsigned int i = 0; i < buffer->context_len[1]; i++)
332  {
333  unsigned int this_type = get_joining_type (buffer->context[1][i], buffer->unicode->general_category (buffer->context[1][i]));
334 
335  if (unlikely (this_type == JOINING_TYPE_T))
336  continue;
337 
339  if (entry->prev_action != NONE && prev != UINT_MAX)
340  info[prev].arabic_shaping_action() = entry->prev_action;
341  break;
342  }
343 }
344 
345 static void
347 {
348  /* Copy arabic_shaping_action() from base to Mongolian variation selectors. */
349  unsigned int count = buffer->len;
350  hb_glyph_info_t *info = buffer->info;
351  for (unsigned int i = 1; i < count; i++)
352  if (unlikely (hb_in_range<hb_codepoint_t> (info[i].codepoint, 0x180Bu, 0x180Du)))
353  info[i].arabic_shaping_action() = info[i - 1].arabic_shaping_action();
354 }
355 
356 void
360 {
362 
366 
367  unsigned int count = buffer->len;
368  hb_glyph_info_t *info = buffer->info;
369  for (unsigned int i = 0; i < count; i++)
370  info[i].mask |= arabic_plan->mask_array[info[i].arabic_shaping_action()];
371 }
372 
373 static void
377 {
378  const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
379  setup_masks_arabic_plan (arabic_plan, buffer, plan->props.script);
380 }
381 
382 static void
384  hb_font_t *font,
386 {
387 #ifdef HB_NO_OT_SHAPE_COMPLEX_ARABIC_FALLBACK
388  return;
389 #endif
390 
391  const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
392 
393  if (!arabic_plan->do_fallback)
394  return;
395 
396 retry:
397  arabic_fallback_plan_t *fallback_plan = arabic_plan->fallback_plan;
398  if (unlikely (!fallback_plan))
399  {
400  /* This sucks. We need a font to build the fallback plan... */
401  fallback_plan = arabic_fallback_plan_create (plan, font);
402  if (unlikely (!arabic_plan->fallback_plan.cmpexch (nullptr, fallback_plan)))
403  {
404  arabic_fallback_plan_destroy (fallback_plan);
405  goto retry;
406  }
407  }
408 
409  arabic_fallback_plan_shape (fallback_plan, font, buffer);
410 }
411 
412 /*
413  * Stretch feature: "stch".
414  * See example here:
415  * https://docs.microsoft.com/en-us/typography/script-development/syriac
416  * We implement this in a generic way, such that the Arabic subtending
417  * marks can use it as well.
418  */
419 
420 static void
424 {
425  const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
426  if (!arabic_plan->has_stch)
427  return;
428 
429  /* 'stch' feature was just applied. Look for anything that multiplied,
430  * and record it for stch treatment later. Note that rtlm, frac, etc
431  * are applied before stch, but we assume that they didn't result in
432  * anything multiplying into 5 pieces, so it's safe-ish... */
433 
434  unsigned int count = buffer->len;
435  hb_glyph_info_t *info = buffer->info;
436  for (unsigned int i = 0; i < count; i++)
438  {
439  unsigned int comp = _hb_glyph_info_get_lig_comp (&info[i]);
440  info[i].arabic_shaping_action() = comp % 2 ? STCH_REPEATING : STCH_FIXED;
442  }
443 }
444 
445 static void
448  hb_font_t *font)
449 {
450  if (likely (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH)))
451  return;
452 
453  /* The Arabic shaper currently always processes in RTL mode, so we should
454  * stretch / position the stretched pieces to the left / preceding glyphs. */
455 
456  /* We do a two pass implementation:
457  * First pass calculates the exact number of extra glyphs we need,
458  * We then enlarge buffer to have that much room,
459  * Second pass applies the stretch, copying things to the end of buffer.
460  */
461 
462  int sign = font->x_scale < 0 ? -1 : +1;
463  unsigned int extra_glyphs_needed = 0; // Set during MEASURE, used during CUT
464  enum { MEASURE, CUT } /* step_t */;
465 
466  for (unsigned int step = MEASURE; step <= CUT; step = step + 1)
467  {
468  unsigned int count = buffer->len;
469  hb_glyph_info_t *info = buffer->info;
471  unsigned int new_len = count + extra_glyphs_needed; // write head during CUT
472  unsigned int j = new_len;
473  for (unsigned int i = count; i; i--)
474  {
475  if (!hb_in_range<uint8_t> (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING))
476  {
477  if (step == CUT)
478  {
479  --j;
480  info[j] = info[i - 1];
481  pos[j] = pos[i - 1];
482  }
483  continue;
484  }
485 
486  /* Yay, justification! */
487 
488  hb_position_t w_total = 0; // Total to be filled
489  hb_position_t w_fixed = 0; // Sum of fixed tiles
490  hb_position_t w_repeating = 0; // Sum of repeating tiles
491  int n_fixed = 0;
492  int n_repeating = 0;
493 
494  unsigned int end = i;
495  while (i &&
496  hb_in_range<uint8_t> (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING))
497  {
498  i--;
499  hb_position_t width = font->get_glyph_h_advance (info[i].codepoint);
501  {
502  w_fixed += width;
503  n_fixed++;
504  }
505  else
506  {
507  w_repeating += width;
508  n_repeating++;
509  }
510  }
511  unsigned int start = i;
512  unsigned int context = i;
513  while (context &&
514  !hb_in_range<uint8_t> (info[context - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING) &&
517  {
518  context--;
519  w_total += pos[context].x_advance;
520  }
521  i++; // Don't touch i again.
522 
523  DEBUG_MSG (ARABIC, nullptr, "%s stretch at (%d,%d,%d)",
524  step == MEASURE ? "measuring" : "cutting", context, start, end);
525  DEBUG_MSG (ARABIC, nullptr, "rest of word: count=%d width %d", start - context, w_total);
526  DEBUG_MSG (ARABIC, nullptr, "fixed tiles: count=%d width=%d", n_fixed, w_fixed);
527  DEBUG_MSG (ARABIC, nullptr, "repeating tiles: count=%d width=%d", n_repeating, w_repeating);
528 
529  /* Number of additional times to repeat each repeating tile. */
530  int n_copies = 0;
531 
532  hb_position_t w_remaining = w_total - w_fixed;
533  if (sign * w_remaining > sign * w_repeating && sign * w_repeating > 0)
534  n_copies = (sign * w_remaining) / (sign * w_repeating) - 1;
535 
536  /* See if we can improve the fit by adding an extra repeat and squeezing them together a bit. */
537  hb_position_t extra_repeat_overlap = 0;
538  hb_position_t shortfall = sign * w_remaining - sign * w_repeating * (n_copies + 1);
539  if (shortfall > 0 && n_repeating > 0)
540  {
541  ++n_copies;
542  hb_position_t excess = (n_copies + 1) * sign * w_repeating - sign * w_remaining;
543  if (excess > 0)
544  extra_repeat_overlap = excess / (n_copies * n_repeating);
545  }
546 
547  if (step == MEASURE)
548  {
549  extra_glyphs_needed += n_copies * n_repeating;
550  DEBUG_MSG (ARABIC, nullptr, "will add extra %d copies of repeating tiles", n_copies);
551  }
552  else
553  {
554  buffer->unsafe_to_break (context, end);
556  for (unsigned int k = end; k > start; k--)
557  {
558  hb_position_t width = font->get_glyph_h_advance (info[k - 1].codepoint);
559 
560  unsigned int repeat = 1;
562  repeat += n_copies;
563 
564  DEBUG_MSG (ARABIC, nullptr, "appending %d copies of glyph %d; j=%d",
565  repeat, info[k - 1].codepoint, j);
566  for (unsigned int n = 0; n < repeat; n++)
567  {
568  x_offset -= width;
569  if (n > 0)
570  x_offset += extra_repeat_overlap;
571  pos[k - 1].x_offset = x_offset;
572  /* Append copy. */
573  --j;
574  info[j] = info[k - 1];
575  pos[j] = pos[k - 1];
576  }
577  }
578  }
579  }
580 
581  if (step == MEASURE)
582  {
583  if (unlikely (!buffer->ensure (count + extra_glyphs_needed)))
584  break;
585  }
586  else
587  {
588  assert (j == 0);
589  buffer->len = new_len;
590  }
591  }
592 }
593 
594 
595 static void
598  hb_font_t *font)
599 {
600  apply_stch (plan, buffer, font);
601 
603 }
604 
605 /* https://www.unicode.org/reports/tr53/ */
606 
607 static hb_codepoint_t
609 {
610  0x0654u, /* ARABIC HAMZA ABOVE */
611  0x0655u, /* ARABIC HAMZA BELOW */
612  0x0658u, /* ARABIC MARK NOON GHUNNA */
613  0x06DCu, /* ARABIC SMALL HIGH SEEN */
614  0x06E3u, /* ARABIC SMALL LOW SEEN */
615  0x06E7u, /* ARABIC SMALL HIGH YEH */
616  0x06E8u, /* ARABIC SMALL HIGH NOON */
617  0x08D3u, /* ARABIC SMALL LOW WAW */
618  0x08F3u, /* ARABIC SMALL HIGH WAW */
619 };
620 
621 static inline bool
623 {
624  hb_codepoint_t u = info.codepoint;
625  for (unsigned int i = 0; i < ARRAY_LENGTH (modifier_combining_marks); i++)
626  if (u == modifier_combining_marks[i])
627  return true;
628  return false;
629 }
630 
631 static void
634  unsigned int start,
635  unsigned int end)
636 {
637  hb_glyph_info_t *info = buffer->info;
638 
639  DEBUG_MSG (ARABIC, buffer, "Reordering marks from %d to %d", start, end);
640 
641  unsigned int i = start;
642  for (unsigned int cc = 220; cc <= 230; cc += 10)
643  {
644  DEBUG_MSG (ARABIC, buffer, "Looking for %d's starting at %d", cc, i);
645  while (i < end && info_cc(info[i]) < cc)
646  i++;
647  DEBUG_MSG (ARABIC, buffer, "Looking for %d's stopped at %d", cc, i);
648 
649  if (i == end)
650  break;
651 
652  if (info_cc(info[i]) > cc)
653  continue;
654 
655  unsigned int j = i;
656  while (j < end && info_cc(info[j]) == cc && info_is_mcm (info[j]))
657  j++;
658 
659  if (i == j)
660  continue;
661 
662  DEBUG_MSG (ARABIC, buffer, "Found %d's from %d to %d", cc, i, j);
663 
664  /* Shift it! */
665  DEBUG_MSG (ARABIC, buffer, "Shifting %d's: %d %d", cc, i, j);
667  assert (j - i <= ARRAY_LENGTH (temp));
668  buffer->merge_clusters (start, j);
669  memmove (temp, &info[i], (j - i) * sizeof (hb_glyph_info_t));
670  memmove (&info[start + j - i], &info[start], (i - start) * sizeof (hb_glyph_info_t));
671  memmove (&info[start], temp, (j - i) * sizeof (hb_glyph_info_t));
672 
673  /* Renumber CC such that the reordered sequence is still sorted.
674  * 22 and 26 are chosen because they are smaller than all Arabic categories,
675  * and are folded back to 220/230 respectively during fallback mark positioning.
676  *
677  * We do this because the CGJ-handling logic in the normalizer relies on
678  * mark sequences having an increasing order even after this reordering.
679  * https://github.com/harfbuzz/harfbuzz/issues/554
680  * This, however, does break some obscure sequences, where the normalizer
681  * might compose a sequence that it should not. For example, in the seequence
682  * ALEF, HAMZAH, MADDAH, we should NOT try to compose ALEF+MADDAH, but with this
683  * renumbering, we will.
684  */
685  unsigned int new_start = start + j - i;
686  unsigned int new_cc = cc == 220 ? HB_MODIFIED_COMBINING_CLASS_CCC22 : HB_MODIFIED_COMBINING_CLASS_CCC26;
687  while (start < new_start)
688  {
690  start++;
691  }
692 
693  i = j;
694  }
695 }
696 
698 {
700  nullptr, /* override_features */
703  nullptr, /* preprocess_text */
706  nullptr, /* decompose */
707  nullptr, /* compose */
709  HB_TAG_NONE, /* gpos_tag */
712  true, /* fallback_position */
713 };
714 
715 
716 #endif
#define state
Definition: aptex-macros.h:996
#define width(a)
Definition: aptex-macros.h:198
#define count(a)
Definition: aptex-macros.h:781
static void step(struct edge *edge)
#define ARRAY_LENGTH(__array)
Definition: cairoint.h:137
#define FLAG(dw, bit,...)
#define n
Definition: t4ht.c:1290
#define free(a)
Definition: decNumber.cpp:310
int excess
char * temp
Definition: dvidvi.c:137
#define info
Definition: dviinfo.c:42
struct rect data
Definition: dvipdfm.c:64
static FIELD_PTR prev
Definition: genind.c:36
#define memmove(d, s, n)
Definition: gsftopk.c:65
assert(pcxLoadImage24((char *)((void *) 0), fp, pinfo, hdr))
#define likely(x)
Definition: jbig2arith.cc:115
#define unlikely(x)
Definition: jbig2arith.cc:116
small capitals from c petite p scientific f u
Definition: afcover.h:88
small capitals from c petite p scientific i
Definition: afcover.h:80
xD9 x84 xD8 xAD xD9 x80 xF0 x90 xAC x9A xE0 xA7 xA6 xE0 xA7 xAA xF0 x91 x84 xA4 xF0 x91 x84 x89 xF0 x91 x84 x9B xF0 x90 x8A xAB xF0 x90 x8B x89 xE2 xB2 x9E xE2 xB2 x9F xD0 xBE xD0 x9E xF0 x90 x90 x84 xF0 x90 x90 xAC xE1 x83 x98 xE1 x83 x94 xE1 x83 x90 xE1 xB2 xBF xE2 xB0 x95 xE2 xB1 x85 xCE xBF xCE x9F xE0 xA8 xA0 xE0 xA8 xB0 xE0 xA9 xA6 Kayah xEA xA4 x8D xEA xA4 x80 Khmer xE1 xA7 xA1 xE1 xA7 xAA xE0 xBB x90 Latin Subscript xE2 x82 x92 xE2 x82 x80 xEA x93 xB3 xF0 x96 xB9 xA1 xF0 x96 xB9 x9B xF0 x96 xB9 xAF xE1 x80 x9D xE1 x80 x84 xE1 x80 x82 no script
Definition: afscript.h:271
HB_SCRIPT_ARABIC
Definition: afscript.h:41
unsigned short uint16_t
Definition: stdint.h:79
unsigned char uint8_t
Definition: stdint.h:78
voidp calloc()
pdf_obj * entry
Definition: pdfdoc.c:64
#define UINT_MAX
Definition: c-minmax.h:56
const int * pos
Definition: combiners.h:905
#define x_offset
Definition: mfluac.c:342
int k
Definition: otp-parser.c:70
#define sign(x)
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro pixld1_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl else error unsupported endif endm macro pixld2_s mem_operand if mov asr add asl add asl mov asr sub UNIT_X add asl mov asr add asl add asl mov asr add UNIT_X add asl else pixld1_s mem_operand pixld1_s mem_operand endif endm macro pixld0_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl endif endm macro pixld_s_internal mem_operand if mem_operand pixld2_s mem_operand pixdeinterleave basereg elseif mem_operand elseif mem_operand elseif mem_operand elseif mem_operand pixld0_s mem_operand else pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else error unsupported mem_operand if bpp mem_operand endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld if[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro fetch_mask_pixblock pixld mask_basereg pixblock_size MASK endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1(dst_w_bpp<=(lowbit *8)) &&((lowbit *8)<(pixblock_size *dst_w_bpp)) .if lowbit< 16 tst DST_R
static int repeat
Definition: pnmtops.c:230
#define map
#define HB_BUFFER_DEALLOCATE_VAR(b, var)
Definition: hb-buffer.hh:480
#define HB_BUFFER_ALLOCATE_VAR(b, var)
Definition: hb-buffer.hh:479
uint32_t hb_codepoint_t
Definition: hb-common.h:106
#define HB_TAG(c1, c2, c3, c4)
Definition: hb-common.h:155
uint32_t hb_mask_t
Definition: hb-common.h:122
int32_t hb_position_t
Definition: hb-common.h:115
hb_script_t
Definition: hb-common.h:448
@ HB_SCRIPT_MONGOLIAN
Definition: hb-common.h:484
uint32_t hb_tag_t
Definition: hb-common.h:147
#define HB_TAG_NONE
Definition: hb-common.h:165
#define DEBUG_MSG(WHAT, OBJ,...)
Definition: hb-debug.hh:232
#define info_cc(info)
static bool _hb_glyph_info_is_default_ignorable(const hb_glyph_info_t *info)
static unsigned int _hb_glyph_info_get_lig_comp(const hb_glyph_info_t *info)
static hb_unicode_general_category_t _hb_glyph_info_get_general_category(const hb_glyph_info_t *info)
static bool _hb_glyph_info_multiplied(const hb_glyph_info_t *info)
static void _hb_glyph_info_set_modified_combining_class(hb_glyph_info_t *info, unsigned int modified_class)
@ F_HAS_FALLBACK
Definition: hb-ot-map.hh:179
@ F_MANUAL_ZWJ
Definition: hb-ot-map.hh:181
@ F_NONE
Definition: hb-ot-map.hh:177
static void arabic_fallback_plan_shape(arabic_fallback_plan_t *fallback_plan, hb_font_t *font, hb_buffer_t *buffer)
static void arabic_fallback_plan_destroy(arabic_fallback_plan_t *fallback_plan)
static arabic_fallback_plan_t * arabic_fallback_plan_create(const hb_ot_shape_plan_t *plan, hb_font_t *font)
static unsigned int joining_type(hb_codepoint_t u)
void data_destroy_arabic(void *data)
void setup_masks_arabic_plan(const arabic_shape_plan_t *arabic_plan, hb_buffer_t *buffer, hb_script_t script)
void * data_create_arabic(const hb_ot_shape_plan_t *plan)
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic
@ JOINING_GROUP_DALATH_RISH
@ NUM_STATE_MACHINE_COLS
@ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE
#define HB_OT_SHAPE_COMPLEX_MAX_COMBINING_MARKS
@ HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT
hb_unicode_general_category_t
Definition: hb-unicode.h:90
@ HB_UNICODE_GENERAL_CATEGORY_FORMAT
Definition: hb-unicode.h:92
@ HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK
Definition: hb-unicode.h:103
@ HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK
Definition: hb-unicode.h:102
#define HB_MODIFIED_COMBINING_CLASS_CCC26
Definition: hb-unicode.hh:300
#define HB_MODIFIED_COMBINING_CLASS_CCC22
Definition: hb-unicode.hh:296
#define HB_UNUSED
Definition: hb.hh:260
#define FLAG_UNSAFE(x)
Definition: hb.hh:501
#define mask(n)
Definition: lbitlib.c:93
static int codepoint(lua_State *L)
Definition: lutf8lib.c:100
static void collect_features_arabic(hb_ot_shape_planner_t *plan)
static void arabic_joining(hb_buffer_t *buffer)
static void setup_masks_arabic(const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, hb_font_t *font)
static bool info_is_mcm(const hb_glyph_info_t &info)
static void mongolian_variation_selectors(hb_buffer_t *buffer)
#define FEATURE_IS_SYRIAC(tag)
#define HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH
#define HB_ARABIC_GENERAL_CATEGORY_IS_WORD(gen_cat)
#define arabic_shaping_action()
static void apply_stch(const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, hb_font_t *font)
static void record_stch(const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer)
static void arabic_fallback_shape(const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer)
static hb_codepoint_t modifier_combining_marks[]
static const hb_tag_t arabic_features[]
static unsigned int get_joining_type(hb_codepoint_t u, hb_unicode_general_category_t gen_cat)
static const struct arabic_state_table_entry arabic_state_table[][NUM_STATE_MACHINE_COLS]
static void postprocess_glyphs_arabic(const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, hb_font_t *font)
static void reorder_marks_arabic(const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, unsigned int start, unsigned int end)
#define ARABIC
Definition: scanst.h:61
hb_mask_t mask_array[ARABIC_NUM_FEATURES+1]
hb_atomic_ptr_t< arabic_fallback_plan_t > fallback_plan
uint8_t curr_action
uint16_t next_state
uint8_t prev_action
Definition: utils.c:300
Definition: funcfont.h:31
Definition: pbmfont.h:11
hb_mask_t get_1_mask(hb_tag_t feature_tag) const
Definition: hb-ot-map.hh:122
bool needs_fallback(hb_tag_t feature_tag) const
Definition: hb-ot-map.hh:116
const void * data
Definition: hb-ot-shape.hh:67
hb_ot_map_t map
Definition: hb-ot-shape.hh:65
hb_segment_properties_t props
Definition: hb-ot-shape.hh:63
hb_segment_properties_t props
Definition: hb-ot-shape.hh:150
hb_ot_map_builder_t map
Definition: hb-ot-shape.hh:151
int j
Definition: t4ht.c:1589
@ start
Definition: preamble.c:52
#define end(cp)
Definition: zic.c:71