QtBase  v6.3.1
hb-ot-shape-complex-arabic-fallback.hh
Go to the documentation of this file.
1 /*
2  * Copyright © 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 #ifndef HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH
28 #define HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH
29 
30 #include "hb.hh"
31 
32 #include "hb-ot-shape.hh"
34 
35 
36 /* Features ordered the same as the entries in shaping_table rows,
37  * followed by rlig. Don't change. */
38 static const hb_tag_t arabic_fallback_features[] =
39 {
40  HB_TAG('i','n','i','t'),
41  HB_TAG('m','e','d','i'),
42  HB_TAG('f','i','n','a'),
43  HB_TAG('i','s','o','l'),
44  HB_TAG('r','l','i','g'),
45 };
46 
47 static OT::SubstLookup *
48 arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan HB_UNUSED,
49  hb_font_t *font,
50  unsigned int feature_index)
51 {
54  unsigned int num_glyphs = 0;
55 
56  /* Populate arrays */
58  {
59  hb_codepoint_t s = shaping_table[u - SHAPING_TABLE_FIRST][feature_index];
60  hb_codepoint_t u_glyph, s_glyph;
61 
62  if (!s ||
63  !hb_font_get_glyph (font, u, 0, &u_glyph) ||
64  !hb_font_get_glyph (font, s, 0, &s_glyph) ||
65  u_glyph == s_glyph ||
66  u_glyph > 0xFFFFu || s_glyph > 0xFFFFu)
67  continue;
68 
69  glyphs[num_glyphs] = u_glyph;
70  substitutes[num_glyphs] = s_glyph;
71 
72  num_glyphs++;
73  }
74 
75  if (!num_glyphs)
76  return nullptr;
77 
78  /* Bubble-sort or something equally good!
79  * May not be good-enough for presidential candidate interviews, but good-enough for us... */
80  hb_stable_sort (&glyphs[0], num_glyphs,
81  (int(*)(const OT::HBUINT16*, const OT::HBUINT16 *)) OT::HBGlyphID16::cmp,
82  &substitutes[0]);
83 
84 
85  /* Each glyph takes four bytes max, and there's some overhead. */
86  char buf[(SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1) * 4 + 128];
87  hb_serialize_context_t c (buf, sizeof (buf));
88  OT::SubstLookup *lookup = c.start_serialize<OT::SubstLookup> ();
89  bool ret = lookup->serialize_single (&c,
91  hb_sorted_array (glyphs, num_glyphs),
92  hb_array (substitutes, num_glyphs));
93  c.end_serialize ();
94 
95  return ret && !c.in_error () ? c.copy<OT::SubstLookup> () : nullptr;
96 }
97 
98 static OT::SubstLookup *
99 arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UNUSED,
100  hb_font_t *font)
101 {
102  OT::HBGlyphID16 first_glyphs[ARRAY_LENGTH_CONST (ligature_table)];
103  unsigned int first_glyphs_indirection[ARRAY_LENGTH_CONST (ligature_table)];
104  unsigned int ligature_per_first_glyph_count_list[ARRAY_LENGTH_CONST (first_glyphs)];
105  unsigned int num_first_glyphs = 0;
106 
107  /* We know that all our ligatures are 2-component */
108  OT::HBGlyphID16 ligature_list[ARRAY_LENGTH_CONST (first_glyphs) * ARRAY_LENGTH_CONST(ligature_table[0].ligatures)];
109  unsigned int component_count_list[ARRAY_LENGTH_CONST (ligature_list)];
110  OT::HBGlyphID16 component_list[ARRAY_LENGTH_CONST (ligature_list) * 1/* One extra component per ligature */];
111  unsigned int num_ligatures = 0;
112 
113  /* Populate arrays */
114 
115  /* Sort out the first-glyphs */
116  for (unsigned int first_glyph_idx = 0; first_glyph_idx < ARRAY_LENGTH (first_glyphs); first_glyph_idx++)
117  {
118  hb_codepoint_t first_u = ligature_table[first_glyph_idx].first;
119  hb_codepoint_t first_glyph;
120  if (!hb_font_get_glyph (font, first_u, 0, &first_glyph))
121  continue;
122  first_glyphs[num_first_glyphs] = first_glyph;
123  ligature_per_first_glyph_count_list[num_first_glyphs] = 0;
124  first_glyphs_indirection[num_first_glyphs] = first_glyph_idx;
125  num_first_glyphs++;
126  }
127  hb_stable_sort (&first_glyphs[0], num_first_glyphs,
128  (int(*)(const OT::HBUINT16*, const OT::HBUINT16 *)) OT::HBGlyphID16::cmp,
129  &first_glyphs_indirection[0]);
130 
131  /* Now that the first-glyphs are sorted, walk again, populate ligatures. */
132  for (unsigned int i = 0; i < num_first_glyphs; i++)
133  {
134  unsigned int first_glyph_idx = first_glyphs_indirection[i];
135 
136  for (unsigned int second_glyph_idx = 0; second_glyph_idx < ARRAY_LENGTH (ligature_table[0].ligatures); second_glyph_idx++)
137  {
138  hb_codepoint_t second_u = ligature_table[first_glyph_idx].ligatures[second_glyph_idx].second;
139  hb_codepoint_t ligature_u = ligature_table[first_glyph_idx].ligatures[second_glyph_idx].ligature;
140  hb_codepoint_t second_glyph, ligature_glyph;
141  if (!second_u ||
142  !hb_font_get_glyph (font, second_u, 0, &second_glyph) ||
143  !hb_font_get_glyph (font, ligature_u, 0, &ligature_glyph))
144  continue;
145 
146  ligature_per_first_glyph_count_list[i]++;
147 
148  ligature_list[num_ligatures] = ligature_glyph;
149  component_count_list[num_ligatures] = 2;
150  component_list[num_ligatures] = second_glyph;
151  num_ligatures++;
152  }
153  }
154 
155  if (!num_ligatures)
156  return nullptr;
157 
158 
159  /* 16 bytes per ligature ought to be enough... */
160  char buf[ARRAY_LENGTH_CONST (ligature_list) * 16 + 128];
161  hb_serialize_context_t c (buf, sizeof (buf));
162  OT::SubstLookup *lookup = c.start_serialize<OT::SubstLookup> ();
163  bool ret = lookup->serialize_ligature (&c,
165  hb_sorted_array (first_glyphs, num_first_glyphs),
166  hb_array (ligature_per_first_glyph_count_list, num_first_glyphs),
167  hb_array (ligature_list, num_ligatures),
168  hb_array (component_count_list, num_ligatures),
169  hb_array (component_list, num_ligatures));
170  c.end_serialize ();
171  /* TODO sanitize the results? */
172 
173  return ret && !c.in_error () ? c.copy<OT::SubstLookup> () : nullptr;
174 }
175 
176 static OT::SubstLookup *
177 arabic_fallback_synthesize_lookup (const hb_ot_shape_plan_t *plan,
178  hb_font_t *font,
179  unsigned int feature_index)
180 {
181  if (feature_index < 4)
182  return arabic_fallback_synthesize_lookup_single (plan, font, feature_index);
183  else
184  return arabic_fallback_synthesize_lookup_ligature (plan, font);
185 }
186 
187 #define ARABIC_FALLBACK_MAX_LOOKUPS 5
188 
190 {
191  unsigned int num_lookups;
193 
197 };
198 
199 #if defined(_WIN32) && !defined(HB_NO_WIN1256)
200 #define HB_WITH_WIN1256
201 #endif
202 
203 #ifdef HB_WITH_WIN1256
205 #endif
206 
208 {
209  public:
212  public:
214 };
216 
217 static bool
218 arabic_fallback_plan_init_win1256 (arabic_fallback_plan_t *fallback_plan HB_UNUSED,
219  const hb_ot_shape_plan_t *plan HB_UNUSED,
221 {
222 #ifdef HB_WITH_WIN1256
223  /* Does this font look like it's Windows-1256-encoded? */
225  if (!(hb_font_get_glyph (font, 0x0627u, 0, &g) && g == 199 /* ALEF */ &&
226  hb_font_get_glyph (font, 0x0644u, 0, &g) && g == 225 /* LAM */ &&
227  hb_font_get_glyph (font, 0x0649u, 0, &g) && g == 236 /* ALEF MAKSURA */ &&
228  hb_font_get_glyph (font, 0x064Au, 0, &g) && g == 237 /* YEH */ &&
229  hb_font_get_glyph (font, 0x0652u, 0, &g) && g == 250 /* SUKUN */))
230  return false;
231 
232  const Manifest &manifest = reinterpret_cast<const Manifest&> (arabic_win1256_gsub_lookups.manifest);
233  static_assert (sizeof (arabic_win1256_gsub_lookups.manifestData) ==
235  /* TODO sanitize the table? */
236 
237  unsigned j = 0;
238  unsigned int count = manifest.len;
239  for (unsigned int i = 0; i < count; i++)
240  {
241  fallback_plan->mask_array[j] = plan->map.get_1_mask (manifest[i].tag);
242  if (fallback_plan->mask_array[j])
243  {
244  fallback_plan->lookup_array[j] = const_cast<OT::SubstLookup*> (&(&manifest+manifest[i].lookupOffset));
245  if (fallback_plan->lookup_array[j])
246  {
247  fallback_plan->accel_array[j].init (*fallback_plan->lookup_array[j]);
248  j++;
249  }
250  }
251  }
252 
253  fallback_plan->num_lookups = j;
254  fallback_plan->free_lookups = false;
255 
256  return j > 0;
257 #else
258  return false;
259 #endif
260 }
261 
262 static bool
263 arabic_fallback_plan_init_unicode (arabic_fallback_plan_t *fallback_plan,
264  const hb_ot_shape_plan_t *plan,
265  hb_font_t *font)
266 {
267  static_assert ((ARRAY_LENGTH_CONST(arabic_fallback_features) <= ARABIC_FALLBACK_MAX_LOOKUPS), "");
268  unsigned int j = 0;
269  for (unsigned int i = 0; i < ARRAY_LENGTH(arabic_fallback_features) ; i++)
270  {
271  fallback_plan->mask_array[j] = plan->map.get_1_mask (arabic_fallback_features[i]);
272  if (fallback_plan->mask_array[j])
273  {
274  fallback_plan->lookup_array[j] = arabic_fallback_synthesize_lookup (plan, font, i);
275  if (fallback_plan->lookup_array[j])
276  {
277  fallback_plan->accel_array[j].init (*fallback_plan->lookup_array[j]);
278  j++;
279  }
280  }
281  }
282 
283  fallback_plan->num_lookups = j;
284  fallback_plan->free_lookups = true;
285 
286  return j > 0;
287 }
288 
289 static arabic_fallback_plan_t *
290 arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan,
291  hb_font_t *font)
292 {
294  if (unlikely (!fallback_plan))
295  return const_cast<arabic_fallback_plan_t *> (&Null (arabic_fallback_plan_t));
296 
297  fallback_plan->num_lookups = 0;
298  fallback_plan->free_lookups = false;
299 
300  /* Try synthesizing GSUB table using Unicode Arabic Presentation Forms,
301  * in case the font has cmap entries for the presentation-forms characters. */
302  if (arabic_fallback_plan_init_unicode (fallback_plan, plan, font))
303  return fallback_plan;
304 
305  /* See if this looks like a Windows-1256-encoded font. If it does, use a
306  * hand-coded GSUB table. */
307  if (arabic_fallback_plan_init_win1256 (fallback_plan, plan, font))
308  return fallback_plan;
309 
310  assert (fallback_plan->num_lookups == 0);
311  hb_free (fallback_plan);
312  return const_cast<arabic_fallback_plan_t *> (&Null (arabic_fallback_plan_t));
313 }
314 
315 static void
316 arabic_fallback_plan_destroy (arabic_fallback_plan_t *fallback_plan)
317 {
318  if (!fallback_plan || fallback_plan->num_lookups == 0)
319  return;
320 
321  for (unsigned int i = 0; i < fallback_plan->num_lookups; i++)
322  if (fallback_plan->lookup_array[i])
323  {
324  fallback_plan->accel_array[i].fini ();
325  if (fallback_plan->free_lookups)
326  hb_free (fallback_plan->lookup_array[i]);
327  }
328 
329  hb_free (fallback_plan);
330 }
331 
332 static void
333 arabic_fallback_plan_shape (arabic_fallback_plan_t *fallback_plan,
334  hb_font_t *font,
336 {
338  for (unsigned int i = 0; i < fallback_plan->num_lookups; i++)
339  if (fallback_plan->lookup_array[i]) {
340  c.set_lookup_mask (fallback_plan->mask_array[i]);
342  *fallback_plan->lookup_array[i],
343  fallback_plan->accel_array[i]);
344  }
345 }
346 
347 
348 #endif /* HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH */
small capitals from c petite p scientific f u
Definition: afcover.h:88
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
sizeof(AF_ModuleRec)
#define ARRAY_LENGTH_CONST(__array)
Definition: hb-algs.hh:795
hb_array_t< T > hb_array(T *array, unsigned int length)
Definition: hb-array.hh:295
hb_sorted_array_t< T > hb_sorted_array(T *array, unsigned int length)
Definition: hb-array.hh:399
void const void *obj HB_UNUSED
Definition: hb-debug.hh:180
hb_bool_t hb_font_get_glyph(hb_font_t *font, hb_codepoint_t unicode, hb_codepoint_t variation_selector, hb_codepoint_t *glyph)
Definition: hb-font.cc:938
#define Null(Type)
Definition: hb-null.hh:106
void hb_ot_layout_substitute_lookup(OT::hb_ot_apply_context_t *c, const OT::SubstLookup &lookup, const OT::hb_ot_layout_lookup_accelerator_t &accel)
OT::Array16Of< ManifestLookup > Manifest
#define ARABIC_FALLBACK_MAX_LOOKUPS
#define SHAPING_TABLE_FIRST
#define SHAPING_TABLE_LAST
#define hb_calloc
Definition: hb.hh:236
#define unlikely(expr)
Definition: hb.hh:251
#define hb_free
Definition: hb.hh:238
#define assert
Definition: qcborcommon_p.h:63
#define ARRAY_LENGTH(a)
Definition: qkmsdevice.cpp:52
GLenum GLenum GLsizei count
GLenum GLuint buffer
GLenum GLuint GLenum GLsizei const GLchar * buf
GLboolean GLboolean g
const GLubyte * c
Definition: qopenglext.h:12701
GLdouble s
[6]
Definition: qopenglext.h:235
uint32_t hb_codepoint_t
Definition: hb-common.h:106
#define HB_TAG(c1, c2, c3, c4)
Definition: hb-common.h:169
uint32_t hb_mask_t
Definition: hb-common.h:122
uint32_t hb_tag_t
Definition: hb-common.h:157
OT::Offset16To< OT::SubstLookup > lookupOffset
Definition: hb-null.hh:93
static HB_INTERNAL int cmp(const IntType *a, const IntType *b)
Definition: hb-open-type.hh:79
bool serialize_ligature(hb_serialize_context_t *c, uint32_t lookup_props, hb_sorted_array_t< const HBGlyphID16 > first_glyphs, hb_array_t< const unsigned int > ligature_per_first_glyph_count_list, hb_array_t< const HBGlyphID16 > ligatures_list, hb_array_t< const unsigned int > component_count_list, hb_array_t< const HBGlyphID16 > component_list)
Definition: SubstLookup.hh:164
bool serialize_single(hb_serialize_context_t *c, uint32_t lookup_props, hb_sorted_array_t< const HBGlyphID16 > glyphs, hb_array_t< const HBGlyphID16 > substitutes)
Definition: SubstLookup.hh:105
OT::SubstLookup * lookup_array[ARABIC_FALLBACK_MAX_LOOKUPS]
OT::hb_ot_layout_lookup_accelerator_t accel_array[ARABIC_FALLBACK_MAX_LOOKUPS]
hb_mask_t mask_array[ARABIC_FALLBACK_MAX_LOOKUPS]
hb_mask_t get_1_mask(hb_tag_t feature_tag) const
Definition: hb-ot-map.hh:124
hb_ot_map_t map
Definition: hb-ot-shape.hh:65
XmlOutput::xml_output tag(const QString &name)
Definition: xmloutput.h:154