Add graphical output to hbtestfont
[framework/uifw/harfbuzz.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-private.hh"
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 struct lookup_map {
46   unsigned int index;
47   hb_mask_t mask;
48 };
49
50
51 static void
52 add_feature (hb_face_t    *face,
53              hb_tag_t      table_tag,
54              unsigned int  feature_index,
55              hb_mask_t     mask,
56              lookup_map   *lookups,
57              unsigned int *num_lookups,
58              unsigned int  room_lookups)
59 {
60   unsigned int i = room_lookups - *num_lookups;
61   lookups += *num_lookups;
62
63   unsigned int *lookup_indices = (unsigned int *) lookups;
64
65   hb_ot_layout_feature_get_lookup_indexes (face, table_tag, feature_index, 0,
66                                            &i,
67                                            lookup_indices);
68
69   *num_lookups += i;
70
71   while (i--) {
72     lookups[i].mask = mask;
73     lookups[i].index = lookup_indices[i];
74   }
75 }
76
77 static int
78 cmp_lookups (const void *p1, const void *p2)
79 {
80   const lookup_map *a = (const lookup_map *) p1;
81   const lookup_map *b = (const lookup_map *) p2;
82
83   return a->index - b->index;
84 }
85
86 static void
87 setup_lookups (hb_face_t    *face,
88                hb_buffer_t  *buffer,
89                hb_feature_t *features,
90                unsigned int  num_features,
91                hb_tag_t      table_tag,
92                lookup_map   *lookups,
93                unsigned int *num_lookups)
94 {
95   unsigned int i, j, script_index, language_index, feature_index, room_lookups;
96
97   room_lookups = *num_lookups;
98   *num_lookups = 0;
99
100   hb_ot_layout_table_choose_script (face, table_tag,
101                                     hb_ot_tags_from_script (buffer->script),
102                                     &script_index);
103   hb_ot_layout_script_find_language (face, table_tag, script_index,
104                                      hb_ot_tag_from_language (buffer->language),
105                                      &language_index);
106
107   if (hb_ot_layout_language_get_required_feature_index (face, table_tag, script_index, language_index,
108                                                         &feature_index))
109     add_feature (face, table_tag, feature_index, 1, lookups, num_lookups, room_lookups);
110
111   for (i = 0; i < ARRAY_LENGTH (default_features); i++)
112   {
113     if (hb_ot_layout_language_find_feature (face, table_tag, script_index, language_index,
114                                             default_features[i],
115                                             &feature_index))
116       add_feature (face, table_tag, feature_index, 1, lookups, num_lookups, room_lookups);
117   }
118
119   /* Clear buffer masks. */
120   unsigned int count = buffer->len;
121   for (unsigned int i = 0; i < count; i++)
122     buffer->info[i].mask = 1;
123
124   unsigned int last_bit_used = 1;
125   unsigned int global_values = 0;
126   for (i = 0; i < num_features; i++)
127   {
128     if (!hb_ot_layout_language_find_feature (face, table_tag, script_index, language_index,
129                                              features[i].tag,
130                                              &feature_index))
131       continue;
132
133     unsigned int bits_needed = _hb_bit_storage (features[i].value);
134     if (!bits_needed)
135       continue;
136     unsigned int mask = (1 << (last_bit_used + bits_needed)) - (1 << last_bit_used);
137     unsigned int value = features[i].value << last_bit_used;
138     last_bit_used += bits_needed;
139
140     add_feature (face, table_tag, feature_index, mask, lookups, num_lookups, room_lookups);
141
142     if (features[i].start == 0 && features[i].end == (unsigned int)-1)
143       global_values |= value;
144     else
145     {
146       unsigned int start = features[i].start, end = features[i].end;
147       unsigned int a = 0, b = buffer->len;
148       while (a < b)
149       {
150         unsigned int h = a + ((b - a) / 2);
151         if (buffer->info[h].cluster < start)
152           a = h + 1;
153         else
154           b = h;
155       }
156       unsigned int count = buffer->len;
157       for (unsigned int j = a; j < count && buffer->info[j].cluster < end; j++)
158         buffer->info[j].mask |= value;
159     }
160   }
161
162   if (global_values)
163   {
164     unsigned int count = buffer->len;
165     for (unsigned int j = 0; j < count; j++)
166       buffer->info[j].mask |= global_values;
167   }
168
169   qsort (lookups, *num_lookups, sizeof (lookups[0]), cmp_lookups);
170
171   if (*num_lookups)
172   {
173     for (i = 1, j = 0; i < *num_lookups; i++)
174       if (lookups[i].index != lookups[j].index)
175         lookups[++j] = lookups[i];
176       else
177         lookups[j].mask |= lookups[i].mask;
178     j++;
179     *num_lookups = j;
180   }
181 }
182
183
184 static hb_bool_t
185 hb_ot_substitute_complex (hb_font_t    *font HB_UNUSED,
186                           hb_face_t    *face,
187                           hb_buffer_t  *buffer,
188                           hb_feature_t *features,
189                           unsigned int  num_features)
190 {
191   lookup_map lookups[1000];
192   unsigned int num_lookups = ARRAY_LENGTH (lookups);
193   unsigned int i;
194
195   if (!hb_ot_layout_has_substitution (face))
196     return FALSE;
197
198   setup_lookups (face, buffer, features, num_features,
199                  HB_OT_TAG_GSUB,
200                  lookups, &num_lookups);
201
202   for (i = 0; i < num_lookups; i++)
203     hb_ot_layout_substitute_lookup (face, buffer, lookups[i].index, lookups[i].mask);
204
205   return TRUE;
206 }
207
208 static hb_bool_t
209 hb_ot_position_complex (hb_font_t    *font,
210                         hb_face_t    *face,
211                         hb_buffer_t  *buffer,
212                         hb_feature_t *features,
213                         unsigned int  num_features)
214 {
215   lookup_map lookups[1000];
216   unsigned int num_lookups = ARRAY_LENGTH (lookups);
217   unsigned int i;
218
219   if (!hb_ot_layout_has_positioning (face))
220     return FALSE;
221
222   setup_lookups (face, buffer, features, num_features,
223                  HB_OT_TAG_GPOS,
224                  lookups, &num_lookups);
225
226   for (i = 0; i < num_lookups; i++)
227     hb_ot_layout_position_lookup (font, face, buffer, lookups[i].index, lookups[i].mask);
228
229   hb_ot_layout_position_finish (font, face, buffer);
230
231   return TRUE;
232 }
233
234
235 /* Main shaper */
236
237 /* Prepare */
238
239 static inline hb_bool_t
240 is_variation_selector (hb_codepoint_t unicode)
241 {
242   return unlikely ((unicode >=  0x180B && unicode <=  0x180D) || /* MONGOLIAN FREE VARIATION SELECTOR ONE..THREE */
243                    (unicode >=  0xFE00 && unicode <=  0xFE0F) || /* VARIATION SELECTOR-1..16 */
244                    (unicode >= 0xE0100 && unicode <= 0xE01EF));  /* VARIATION SELECTOR-17..256 */
245 }
246
247 static void
248 hb_form_clusters (hb_buffer_t *buffer)
249 {
250   unsigned int count = buffer->len;
251   for (unsigned int i = 1; i < count; i++)
252     if (buffer->unicode->get_general_category (buffer->info[i].codepoint) == HB_CATEGORY_NON_SPACING_MARK)
253       buffer->info[i].cluster = buffer->info[i - 1].cluster;
254 }
255
256 static hb_direction_t
257 hb_ensure_native_direction (hb_buffer_t *buffer)
258 {
259   hb_direction_t original_direction = buffer->direction;
260
261   /* TODO vertical */
262   if (HB_DIRECTION_IS_HORIZONTAL (original_direction) &&
263       original_direction != _hb_script_get_horizontal_direction (buffer->script))
264   {
265     hb_buffer_reverse_clusters (buffer);
266     buffer->direction = HB_DIRECTION_REVERSE (buffer->direction);
267   }
268
269   return original_direction;
270 }
271
272
273 /* Substitute */
274
275 static void
276 hb_mirror_chars (hb_buffer_t *buffer)
277 {
278   hb_unicode_get_mirroring_func_t get_mirroring = buffer->unicode->get_mirroring;
279
280   if (HB_DIRECTION_IS_FORWARD (buffer->direction))
281     return;
282
283   unsigned int count = buffer->len;
284   for (unsigned int i = 0; i < count; i++) {
285       buffer->info[i].codepoint = get_mirroring (buffer->info[i].codepoint);
286   }
287 }
288
289 static void
290 hb_map_glyphs (hb_font_t    *font,
291                hb_face_t    *face,
292                hb_buffer_t  *buffer)
293 {
294   if (unlikely (!buffer->len))
295     return;
296
297   unsigned int count = buffer->len - 1;
298   for (unsigned int i = 0; i < count; i++) {
299     if (unlikely (is_variation_selector (buffer->info[i + 1].codepoint))) {
300       buffer->info[i].codepoint = hb_font_get_glyph (font, face, buffer->info[i].codepoint, buffer->info[i + 1].codepoint);
301       i++;
302     } else {
303       buffer->info[i].codepoint = hb_font_get_glyph (font, face, buffer->info[i].codepoint, 0);
304     }
305   }
306   buffer->info[count].codepoint = hb_font_get_glyph (font, face, buffer->info[count].codepoint, 0);
307 }
308
309 static void
310 hb_substitute_default (hb_font_t    *font,
311                        hb_face_t    *face,
312                        hb_buffer_t  *buffer,
313                        hb_feature_t *features HB_UNUSED,
314                        unsigned int  num_features HB_UNUSED)
315 {
316   hb_mirror_chars (buffer);
317   hb_map_glyphs (font, face, buffer);
318 }
319
320 static void
321 hb_substitute_complex_fallback (hb_font_t    *font HB_UNUSED,
322                                 hb_face_t    *face HB_UNUSED,
323                                 hb_buffer_t  *buffer HB_UNUSED,
324                                 hb_feature_t *features HB_UNUSED,
325                                 unsigned int  num_features HB_UNUSED)
326 {
327   /* TODO Arabic */
328 }
329
330
331 /* Position */
332
333 static void
334 hb_position_default (hb_font_t    *font,
335                      hb_face_t    *face,
336                      hb_buffer_t  *buffer,
337                      hb_feature_t *features HB_UNUSED,
338                      unsigned int  num_features HB_UNUSED)
339 {
340   hb_buffer_clear_positions (buffer);
341
342   unsigned int count = buffer->len;
343   for (unsigned int i = 0; i < count; i++) {
344     hb_glyph_metrics_t metrics;
345     hb_font_get_glyph_metrics (font, face, buffer->info[i].codepoint, &metrics);
346     buffer->pos[i].x_advance = metrics.x_advance;
347     buffer->pos[i].y_advance = metrics.y_advance;
348   }
349 }
350
351 static void
352 hb_position_complex_fallback (hb_font_t    *font HB_UNUSED,
353                               hb_face_t    *face HB_UNUSED,
354                               hb_buffer_t  *buffer HB_UNUSED,
355                               hb_feature_t *features HB_UNUSED,
356                               unsigned int  num_features HB_UNUSED)
357 {
358   /* TODO Mark pos */
359 }
360
361 static void
362 hb_truetype_kern (hb_font_t    *font,
363                   hb_face_t    *face,
364                   hb_buffer_t  *buffer,
365                   hb_feature_t *features HB_UNUSED,
366                   unsigned int  num_features HB_UNUSED)
367 {
368   /* TODO Check for kern=0 */
369   unsigned int count = buffer->len;
370   for (unsigned int i = 1; i < count; i++) {
371     hb_position_t kern, kern1, kern2;
372     kern = hb_font_get_kerning (font, face, buffer->info[i - 1].codepoint, buffer->info[i].codepoint);
373     kern1 = kern >> 1;
374     kern2 = kern - kern1;
375     buffer->pos[i - 1].x_advance += kern1;
376     buffer->pos[i].x_advance += kern2;
377     buffer->pos[i].x_offset += kern2;
378   }
379 }
380
381 static void
382 hb_position_complex_fallback_visual (hb_font_t    *font,
383                                      hb_face_t    *face,
384                                      hb_buffer_t  *buffer,
385                                      hb_feature_t *features,
386                                      unsigned int  num_features)
387 {
388   hb_truetype_kern (font, face, buffer, features, num_features);
389 }
390
391
392 /* Do it! */
393
394 void
395 hb_ot_shape (hb_font_t    *font,
396              hb_face_t    *face,
397              hb_buffer_t  *buffer,
398              hb_feature_t *features,
399              unsigned int  num_features)
400 {
401   hb_direction_t original_direction;
402   hb_bool_t substitute_fallback, position_fallback;
403
404   hb_form_clusters (buffer);
405
406   hb_substitute_default (font, face, buffer, features, num_features);
407
408   /* We do this after substitute_default because mirroring needs to
409    * see the original direction. */
410   original_direction = hb_ensure_native_direction (buffer);
411
412   substitute_fallback = !hb_ot_substitute_complex (font, face, buffer, features, num_features);
413
414   if (substitute_fallback)
415     hb_substitute_complex_fallback (font, face, buffer, features, num_features);
416
417   hb_position_default (font, face, buffer, features, num_features);
418
419   position_fallback = !hb_ot_position_complex (font, face, buffer, features, num_features);
420
421   if (position_fallback)
422     hb_position_complex_fallback (font, face, buffer, features, num_features);
423
424   if (HB_DIRECTION_IS_BACKWARD (buffer->direction))
425     hb_buffer_reverse (buffer);
426
427   if (position_fallback)
428     hb_position_complex_fallback_visual (font, face, buffer, features, num_features);
429
430   buffer->direction = original_direction;
431 }