Add rtlm
[profile/ivi/org.tizen.video-player.git] / src / hb-ot-shape.cc
1 /*
2  * Copyright (C) 2009  Red Hat, 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  * Red Hat Author(s): Behdad Esfahbod
25  */
26
27 #include "hb-ot-shape.h"
28
29 #include "hb-buffer-private.hh"
30
31 #include "hb-ot-layout.h"
32
33 hb_tag_t default_features[] = {
34   /* GSUB */
35   HB_TAG('c','c','m','p'),
36   HB_TAG('l','o','c','l'),
37   HB_TAG('l','i','g','a'),
38   HB_TAG('c','l','i','g'),
39   /* GPOS */
40   HB_TAG('k','e','r','n'),
41   HB_TAG('m','a','r','k'),
42   HB_TAG('m','k','m','k'),
43 };
44
45 enum {
46   MASK_ALWAYS_ON = 1 << 0,
47   MASK_RTLM      = 1 << 1
48 };
49 #define MASK_BITS_USED 2
50
51 struct lookup_map {
52   unsigned int index;
53   hb_mask_t mask;
54 };
55
56
57 static void
58 add_feature (hb_face_t    *face,
59              hb_tag_t      table_tag,
60              unsigned int  feature_index,
61              hb_mask_t     mask,
62              lookup_map   *lookups,
63              unsigned int *num_lookups,
64              unsigned int  room_lookups)
65 {
66   unsigned int i = room_lookups - *num_lookups;
67   lookups += *num_lookups;
68
69   unsigned int *lookup_indices = (unsigned int *) lookups;
70
71   hb_ot_layout_feature_get_lookup_indexes (face, table_tag, feature_index, 0,
72                                            &i,
73                                            lookup_indices);
74
75   *num_lookups += i;
76
77   while (i--) {
78     lookups[i].mask = mask;
79     lookups[i].index = lookup_indices[i];
80   }
81 }
82
83 static hb_bool_t
84 maybe_add_feature (hb_face_t    *face,
85                    hb_tag_t      table_tag,
86                    unsigned int  script_index,
87                    unsigned int  language_index,
88                    hb_tag_t      feature_tag,
89                    hb_mask_t     mask,
90                    lookup_map   *lookups,
91                    unsigned int *num_lookups,
92                    unsigned int  room_lookups)
93 {
94   unsigned int feature_index;
95   if (hb_ot_layout_language_find_feature (face, table_tag, script_index, language_index,
96                                           feature_tag,
97                                           &feature_index))
98   {
99     add_feature (face, table_tag, feature_index, mask, lookups, num_lookups, room_lookups);
100     return TRUE;
101   }
102   return FALSE;
103 }
104
105 static int
106 cmp_lookups (const void *p1, const void *p2)
107 {
108   const lookup_map *a = (const lookup_map *) p1;
109   const lookup_map *b = (const lookup_map *) p2;
110
111   return a->index - b->index;
112 }
113
114 static void
115 setup_lookups (hb_face_t    *face,
116                hb_buffer_t  *buffer,
117                hb_feature_t *features,
118                unsigned int  num_features,
119                hb_tag_t      table_tag,
120                lookup_map   *lookups,
121                unsigned int *num_lookups,
122                hb_direction_t original_direction)
123 {
124   unsigned int i, j, script_index, language_index, feature_index, room_lookups;
125
126   room_lookups = *num_lookups;
127   *num_lookups = 0;
128
129   hb_ot_layout_table_choose_script (face, table_tag,
130                                     hb_ot_tags_from_script (buffer->script),
131                                     &script_index);
132   hb_ot_layout_script_find_language (face, table_tag, script_index,
133                                      hb_ot_tag_from_language (buffer->language),
134                                      &language_index);
135
136   if (hb_ot_layout_language_get_required_feature_index (face, table_tag, script_index, language_index,
137                                                         &feature_index))
138     add_feature (face, table_tag, feature_index, 1, lookups, num_lookups, room_lookups);
139
140   for (i = 0; i < ARRAY_LENGTH (default_features); i++)
141     maybe_add_feature (face, table_tag, script_index, language_index, default_features[i], 1, lookups, num_lookups, room_lookups);
142
143   switch (original_direction) {
144     case HB_DIRECTION_LTR:
145       maybe_add_feature (face, table_tag, script_index, language_index, HB_TAG ('l','t','r','a'), 1, lookups, num_lookups, room_lookups);
146       maybe_add_feature (face, table_tag, script_index, language_index, HB_TAG ('l','t','r','m'), 1, lookups, num_lookups, room_lookups);
147       break;
148     case HB_DIRECTION_RTL:
149       maybe_add_feature (face, table_tag, script_index, language_index, HB_TAG ('r','t','l','a'), 1, lookups, num_lookups, room_lookups);
150       break;
151     case HB_DIRECTION_TTB:
152     case HB_DIRECTION_BTT:
153     default:
154       break;
155   }
156
157   unsigned int next_bit = MASK_BITS_USED;
158   hb_mask_t global_mask = 0;
159   for (i = 0; i < num_features; i++)
160   {
161     hb_feature_t *feature = &features[i];
162     if (!hb_ot_layout_language_find_feature (face, table_tag, script_index, language_index,
163                                              feature->tag,
164                                              &feature_index))
165       continue;
166
167     if (feature->value == 1 && feature->start == 0 && feature->end == (unsigned int) -1) {
168       add_feature (face, table_tag, feature_index, 1, lookups, num_lookups, room_lookups);
169       continue;
170     }
171
172     /* Allocate bits for the features */
173
174     unsigned int bits_needed = _hb_bit_storage (feature->value);
175     if (!bits_needed)
176       continue; /* Feature disabled */
177
178     if (next_bit + bits_needed > 8 * sizeof (hb_mask_t))
179       continue; /* Oh well... */
180
181     unsigned int mask = (1 << (next_bit + bits_needed)) - (1 << next_bit);
182     unsigned int value = feature->value << next_bit;
183     next_bit += bits_needed;
184
185     add_feature (face, table_tag, feature_index, mask, lookups, num_lookups, room_lookups);
186
187     if (feature->start == 0 && feature->end == (unsigned int) -1)
188       global_mask |= value;
189     else
190       buffer->or_masks (mask, feature->start, feature->end);
191   }
192
193   if (global_mask)
194     buffer->or_masks (global_mask, 0, (unsigned int) -1);
195
196   qsort (lookups, *num_lookups, sizeof (lookups[0]), cmp_lookups);
197
198   if (*num_lookups)
199   {
200     for (i = 1, j = 0; i < *num_lookups; i++)
201       if (lookups[i].index != lookups[j].index)
202         lookups[++j] = lookups[i];
203       else
204         lookups[j].mask |= lookups[i].mask;
205     j++;
206     *num_lookups = j;
207   }
208 }
209
210
211 static hb_bool_t
212 hb_ot_substitute_complex (hb_font_t    *font HB_UNUSED,
213                           hb_face_t    *face,
214                           hb_buffer_t  *buffer,
215                           hb_feature_t *features,
216                           unsigned int  num_features,
217                           hb_direction_t original_direction)
218 {
219   lookup_map lookups[1000];
220   unsigned int num_lookups = ARRAY_LENGTH (lookups);
221   unsigned int i;
222
223   if (!hb_ot_layout_has_substitution (face))
224     return FALSE;
225
226   setup_lookups (face, buffer, features, num_features,
227                  HB_OT_TAG_GSUB,
228                  lookups, &num_lookups,
229                  original_direction);
230
231   for (i = 0; i < num_lookups; i++)
232     hb_ot_layout_substitute_lookup (face, buffer, lookups[i].index, lookups[i].mask);
233
234   return TRUE;
235 }
236
237 static hb_bool_t
238 hb_ot_position_complex (hb_font_t    *font,
239                         hb_face_t    *face,
240                         hb_buffer_t  *buffer,
241                         hb_feature_t *features,
242                         unsigned int  num_features,
243                         hb_direction_t original_direction)
244 {
245   lookup_map lookups[1000];
246   unsigned int num_lookups = ARRAY_LENGTH (lookups);
247   unsigned int i;
248
249   if (!hb_ot_layout_has_positioning (face))
250     return FALSE;
251
252   setup_lookups (face, buffer, features, num_features,
253                  HB_OT_TAG_GPOS,
254                  lookups, &num_lookups,
255                  original_direction);
256
257   for (i = 0; i < num_lookups; i++)
258     hb_ot_layout_position_lookup (font, face, buffer, lookups[i].index, lookups[i].mask);
259
260   hb_ot_layout_position_finish (font, face, buffer);
261
262   return TRUE;
263 }
264
265
266 /* Main shaper */
267
268 /* Prepare */
269
270 static inline hb_bool_t
271 is_variation_selector (hb_codepoint_t unicode)
272 {
273   return unlikely ((unicode >=  0x180B && unicode <=  0x180D) || /* MONGOLIAN FREE VARIATION SELECTOR ONE..THREE */
274                    (unicode >=  0xFE00 && unicode <=  0xFE0F) || /* VARIATION SELECTOR-1..16 */
275                    (unicode >= 0xE0100 && unicode <= 0xE01EF));  /* VARIATION SELECTOR-17..256 */
276 }
277
278 static void
279 hb_form_clusters (hb_buffer_t *buffer)
280 {
281   unsigned int count = buffer->len;
282   for (unsigned int i = 1; i < count; i++)
283     if (buffer->unicode->get_general_category (buffer->info[i].codepoint) == HB_CATEGORY_NON_SPACING_MARK)
284       buffer->info[i].cluster = buffer->info[i - 1].cluster;
285 }
286
287 static hb_direction_t
288 hb_ensure_native_direction (hb_buffer_t *buffer)
289 {
290   hb_direction_t original_direction = buffer->direction;
291
292   /* TODO vertical */
293   if (HB_DIRECTION_IS_HORIZONTAL (original_direction) &&
294       original_direction != _hb_script_get_horizontal_direction (buffer->script))
295   {
296     hb_buffer_reverse_clusters (buffer);
297     buffer->direction = HB_DIRECTION_REVERSE (buffer->direction);
298   }
299
300   return original_direction;
301 }
302
303
304 /* Substitute */
305
306 static void
307 hb_mirror_chars (hb_buffer_t *buffer)
308 {
309   hb_unicode_get_mirroring_func_t get_mirroring = buffer->unicode->get_mirroring;
310
311   if (HB_DIRECTION_IS_FORWARD (buffer->direction))
312     return;
313
314   unsigned int count = buffer->len;
315   for (unsigned int i = 0; i < count; i++) {
316     hb_codepoint_t codepoint = get_mirroring (buffer->info[i].codepoint);
317     if (likely (codepoint == buffer->info[i].codepoint))
318       buffer->info[i].mask |= MASK_RTLM;
319     else
320       buffer->info[i].codepoint = codepoint;
321   }
322 }
323
324 static void
325 hb_map_glyphs (hb_font_t    *font,
326                hb_face_t    *face,
327                hb_buffer_t  *buffer)
328 {
329   if (unlikely (!buffer->len))
330     return;
331
332   unsigned int count = buffer->len - 1;
333   for (unsigned int i = 0; i < count; i++) {
334     if (unlikely (is_variation_selector (buffer->info[i + 1].codepoint))) {
335       buffer->info[i].codepoint = hb_font_get_glyph (font, face, buffer->info[i].codepoint, buffer->info[i + 1].codepoint);
336       i++;
337     } else {
338       buffer->info[i].codepoint = hb_font_get_glyph (font, face, buffer->info[i].codepoint, 0);
339     }
340   }
341   buffer->info[count].codepoint = hb_font_get_glyph (font, face, buffer->info[count].codepoint, 0);
342 }
343
344 static void
345 hb_substitute_default (hb_font_t    *font,
346                        hb_face_t    *face,
347                        hb_buffer_t  *buffer,
348                        hb_feature_t *features HB_UNUSED,
349                        unsigned int  num_features HB_UNUSED)
350 {
351   hb_mirror_chars (buffer);
352   hb_map_glyphs (font, face, buffer);
353 }
354
355 static void
356 hb_substitute_complex_fallback (hb_font_t    *font HB_UNUSED,
357                                 hb_face_t    *face HB_UNUSED,
358                                 hb_buffer_t  *buffer HB_UNUSED,
359                                 hb_feature_t *features HB_UNUSED,
360                                 unsigned int  num_features HB_UNUSED)
361 {
362   /* TODO Arabic */
363 }
364
365
366 /* Position */
367
368 static void
369 hb_position_default (hb_font_t    *font,
370                      hb_face_t    *face,
371                      hb_buffer_t  *buffer,
372                      hb_feature_t *features HB_UNUSED,
373                      unsigned int  num_features HB_UNUSED)
374 {
375   hb_buffer_clear_positions (buffer);
376
377   unsigned int count = buffer->len;
378   for (unsigned int i = 0; i < count; i++) {
379     hb_glyph_metrics_t metrics;
380     hb_font_get_glyph_metrics (font, face, buffer->info[i].codepoint, &metrics);
381     buffer->pos[i].x_advance = metrics.x_advance;
382     buffer->pos[i].y_advance = metrics.y_advance;
383   }
384 }
385
386 static void
387 hb_position_complex_fallback (hb_font_t    *font HB_UNUSED,
388                               hb_face_t    *face HB_UNUSED,
389                               hb_buffer_t  *buffer HB_UNUSED,
390                               hb_feature_t *features HB_UNUSED,
391                               unsigned int  num_features HB_UNUSED)
392 {
393   /* TODO Mark pos */
394 }
395
396 static void
397 hb_truetype_kern (hb_font_t    *font,
398                   hb_face_t    *face,
399                   hb_buffer_t  *buffer,
400                   hb_feature_t *features HB_UNUSED,
401                   unsigned int  num_features HB_UNUSED)
402 {
403   /* TODO Check for kern=0 */
404   unsigned int count = buffer->len;
405   for (unsigned int i = 1; i < count; i++) {
406     hb_position_t kern, kern1, kern2;
407     kern = hb_font_get_kerning (font, face, buffer->info[i - 1].codepoint, buffer->info[i].codepoint);
408     kern1 = kern >> 1;
409     kern2 = kern - kern1;
410     buffer->pos[i - 1].x_advance += kern1;
411     buffer->pos[i].x_advance += kern2;
412     buffer->pos[i].x_offset += kern2;
413   }
414 }
415
416 static void
417 hb_position_complex_fallback_visual (hb_font_t    *font,
418                                      hb_face_t    *face,
419                                      hb_buffer_t  *buffer,
420                                      hb_feature_t *features,
421                                      unsigned int  num_features)
422 {
423   hb_truetype_kern (font, face, buffer, features, num_features);
424 }
425
426
427 /* Do it! */
428
429 void
430 hb_ot_shape (hb_font_t    *font,
431              hb_face_t    *face,
432              hb_buffer_t  *buffer,
433              hb_feature_t *features,
434              unsigned int  num_features)
435 {
436   hb_direction_t original_direction;
437   hb_bool_t substitute_fallback, position_fallback;
438
439   hb_form_clusters (buffer);
440
441   /* SUBSTITUTE */
442
443   buffer->clear_masks ();
444
445   hb_substitute_default (font, face, buffer, features, num_features);
446
447   /* We do this after substitute_default because mirroring needs to
448    * see the original direction. */
449   original_direction = hb_ensure_native_direction (buffer);
450
451   substitute_fallback = !hb_ot_substitute_complex (font, face, buffer, features, num_features, original_direction);
452
453   if (substitute_fallback)
454     hb_substitute_complex_fallback (font, face, buffer, features, num_features);
455
456
457   /* POSITION */
458
459   buffer->clear_masks ();
460
461   hb_position_default (font, face, buffer, features, num_features);
462
463   position_fallback = !hb_ot_position_complex (font, face, buffer, features, num_features, original_direction);
464
465   if (position_fallback)
466     hb_position_complex_fallback (font, face, buffer, features, num_features);
467
468   if (HB_DIRECTION_IS_BACKWARD (buffer->direction))
469     hb_buffer_reverse (buffer);
470
471   if (position_fallback)
472     hb_position_complex_fallback_visual (font, face, buffer, features, num_features);
473
474   buffer->direction = original_direction;
475 }