Imported Upstream version 0.9.12
[platform/upstream/harfbuzz.git] / src / hb-ot-shape-fallback.cc
1 /*
2  * Copyright © 2011,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-ot-shape-fallback-private.hh"
28
29 static unsigned int
30 recategorize_combining_class (hb_codepoint_t u,
31                               unsigned int klass)
32 {
33   if (klass >= 200)
34     return klass;
35
36   /* Thai / Lao need some per-character work. */
37   if ((u & ~0xFF) == 0x0E00)
38   {
39     if (unlikely (klass == 0))
40     {
41       switch (u)
42       {
43         case 0x0E31:
44         case 0x0E34:
45         case 0x0E35:
46         case 0x0E36:
47         case 0x0E37:
48         case 0x0E47:
49         case 0x0E4C:
50         case 0x0E4D:
51         case 0x0E4E:
52           klass = HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
53           break;
54
55         case 0x0EB1:
56         case 0x0EB4:
57         case 0x0EB5:
58         case 0x0EB6:
59         case 0x0EB7:
60         case 0x0EBB:
61         case 0x0ECC:
62         case 0x0ECD:
63           klass = HB_UNICODE_COMBINING_CLASS_ABOVE;
64           break;
65
66         case 0x0EBC:
67           klass = HB_UNICODE_COMBINING_CLASS_BELOW;
68           break;
69       }
70     } else {
71       /* Thai virama is below-right */
72       if (u == 0x0E3A)
73         klass = HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT;
74     }
75   }
76
77   switch (klass)
78   {
79
80     /* Hebrew */
81
82     case HB_MODIFIED_COMBINING_CLASS_CCC10: /* sheva */
83     case HB_MODIFIED_COMBINING_CLASS_CCC11: /* hataf segol */
84     case HB_MODIFIED_COMBINING_CLASS_CCC12: /* hataf patah */
85     case HB_MODIFIED_COMBINING_CLASS_CCC13: /* hataf qamats */
86     case HB_MODIFIED_COMBINING_CLASS_CCC14: /* hiriq */
87     case HB_MODIFIED_COMBINING_CLASS_CCC15: /* tsere */
88     case HB_MODIFIED_COMBINING_CLASS_CCC16: /* segol */
89     case HB_MODIFIED_COMBINING_CLASS_CCC17: /* patah */
90     case HB_MODIFIED_COMBINING_CLASS_CCC18: /* qamats */
91     case HB_MODIFIED_COMBINING_CLASS_CCC20: /* qubuts */
92     case HB_MODIFIED_COMBINING_CLASS_CCC22: /* meteg */
93       return HB_UNICODE_COMBINING_CLASS_BELOW;
94
95     case HB_MODIFIED_COMBINING_CLASS_CCC23: /* rafe */
96       return HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE;
97
98     case HB_MODIFIED_COMBINING_CLASS_CCC24: /* shin dot */
99       return HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
100
101     case HB_MODIFIED_COMBINING_CLASS_CCC25: /* sin dot */
102     case HB_MODIFIED_COMBINING_CLASS_CCC19: /* holam */
103       return HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT;
104
105     case HB_MODIFIED_COMBINING_CLASS_CCC26: /* point varika */
106       return HB_UNICODE_COMBINING_CLASS_ABOVE;
107
108     case HB_MODIFIED_COMBINING_CLASS_CCC21: /* dagesh */
109       break;
110
111
112     /* Arabic and Syriac */
113
114     case HB_MODIFIED_COMBINING_CLASS_CCC27: /* fathatan */
115     case HB_MODIFIED_COMBINING_CLASS_CCC28: /* dammatan */
116     case HB_MODIFIED_COMBINING_CLASS_CCC30: /* fatha */
117     case HB_MODIFIED_COMBINING_CLASS_CCC31: /* damma */
118     case HB_MODIFIED_COMBINING_CLASS_CCC33: /* shadda */
119     case HB_MODIFIED_COMBINING_CLASS_CCC34: /* sukun */
120     case HB_MODIFIED_COMBINING_CLASS_CCC35: /* superscript alef */
121     case HB_MODIFIED_COMBINING_CLASS_CCC36: /* superscript alaph */
122       return HB_UNICODE_COMBINING_CLASS_ABOVE;
123
124     case HB_MODIFIED_COMBINING_CLASS_CCC29: /* kasratan */
125     case HB_MODIFIED_COMBINING_CLASS_CCC32: /* kasra */
126       return HB_UNICODE_COMBINING_CLASS_BELOW;
127
128
129     /* Thai */
130
131     case HB_MODIFIED_COMBINING_CLASS_CCC103: /* sara u / sara uu */
132       return HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT;
133
134     case HB_MODIFIED_COMBINING_CLASS_CCC107: /* mai */
135       return HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
136
137
138     /* Lao */
139
140     case HB_MODIFIED_COMBINING_CLASS_CCC118: /* sign u / sign uu */
141       return HB_UNICODE_COMBINING_CLASS_BELOW;
142
143     case HB_MODIFIED_COMBINING_CLASS_CCC122: /* mai */
144       return HB_UNICODE_COMBINING_CLASS_ABOVE;
145
146
147     /* Tibetan */
148
149     case HB_MODIFIED_COMBINING_CLASS_CCC129: /* sign aa */
150       return HB_UNICODE_COMBINING_CLASS_BELOW;
151
152     case HB_MODIFIED_COMBINING_CLASS_CCC130: /* sign i*/
153       return HB_UNICODE_COMBINING_CLASS_ABOVE;
154
155     case HB_MODIFIED_COMBINING_CLASS_CCC132: /* sign u */
156       return HB_UNICODE_COMBINING_CLASS_BELOW;
157
158   }
159
160   return klass;
161 }
162
163 void
164 _hb_ot_shape_fallback_position_recategorize_marks (const hb_ot_shape_plan_t *plan HB_UNUSED,
165                                                    hb_font_t *font HB_UNUSED,
166                                                    hb_buffer_t  *buffer)
167 {
168   unsigned int count = buffer->len;
169   for (unsigned int i = 0; i < count; i++)
170     if (_hb_glyph_info_get_general_category (&buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) {
171       unsigned int combining_class = _hb_glyph_info_get_modified_combining_class (&buffer->info[i]);
172       combining_class = recategorize_combining_class (buffer->info[i].codepoint, combining_class);
173       _hb_glyph_info_set_modified_combining_class (&buffer->info[i], combining_class);
174     }
175 }
176
177
178 static void
179 zero_mark_advances (hb_buffer_t *buffer,
180                     unsigned int start,
181                     unsigned int end)
182 {
183   for (unsigned int i = start; i < end; i++)
184     if (_hb_glyph_info_get_general_category (&buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
185     {
186       buffer->pos[i].x_advance = 0;
187       buffer->pos[i].y_advance = 0;
188     }
189 }
190
191 static inline void
192 position_mark (const hb_ot_shape_plan_t *plan,
193                hb_font_t *font,
194                hb_buffer_t  *buffer,
195                hb_glyph_extents_t &base_extents,
196                unsigned int i,
197                unsigned int combining_class)
198 {
199   hb_glyph_extents_t mark_extents;
200   if (!font->get_glyph_extents (buffer->info[i].codepoint,
201                                 &mark_extents))
202     return;
203
204   hb_position_t y_gap = font->y_scale / 16;
205
206   hb_glyph_position_t &pos = buffer->pos[i];
207   pos.x_offset = pos.y_offset = 0;
208
209
210   /* We dont position LEFT and RIGHT marks. */
211
212   /* X positioning */
213   switch (combining_class)
214   {
215     case HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW:
216     case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE:
217       if (buffer->props.direction == HB_DIRECTION_LTR) {
218         pos.x_offset += base_extents.x_bearing - mark_extents.width / 2 - mark_extents.x_bearing;
219         break;
220       } else if (buffer->props.direction == HB_DIRECTION_RTL) {
221         pos.x_offset += base_extents.x_bearing + base_extents.width - mark_extents.width / 2 - mark_extents.x_bearing;
222         break;
223       }
224       /* Fall through */
225
226     default:
227     case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW:
228     case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE:
229     case HB_UNICODE_COMBINING_CLASS_BELOW:
230     case HB_UNICODE_COMBINING_CLASS_ABOVE:
231       /* Center align. */
232       pos.x_offset += base_extents.x_bearing + (base_extents.width - mark_extents.width) / 2 - mark_extents.x_bearing;
233       break;
234
235     case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT:
236     case HB_UNICODE_COMBINING_CLASS_BELOW_LEFT:
237     case HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT:
238       /* Left align. */
239       pos.x_offset += base_extents.x_bearing - mark_extents.x_bearing;
240       break;
241
242     case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT:
243     case HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT:
244     case HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT:
245       /* Right align. */
246       pos.x_offset += base_extents.x_bearing + base_extents.width - mark_extents.width - mark_extents.x_bearing;
247       break;
248   }
249
250   /* Y positioning */
251   switch (combining_class)
252   {
253     case HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW:
254     case HB_UNICODE_COMBINING_CLASS_BELOW_LEFT:
255     case HB_UNICODE_COMBINING_CLASS_BELOW:
256     case HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT:
257       /* Add gap, fall-through. */
258       base_extents.height -= y_gap;
259
260     case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT:
261     case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW:
262       pos.y_offset += base_extents.y_bearing + base_extents.height - mark_extents.y_bearing;
263       base_extents.height += mark_extents.height;
264       break;
265
266     case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE:
267     case HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT:
268     case HB_UNICODE_COMBINING_CLASS_ABOVE:
269     case HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT:
270       /* Add gap, fall-through. */
271       base_extents.y_bearing += y_gap;
272       base_extents.height -= y_gap;
273
274     case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE:
275     case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT:
276       pos.y_offset += base_extents.y_bearing - (mark_extents.y_bearing + mark_extents.height);
277       base_extents.y_bearing -= mark_extents.height;
278       base_extents.height += mark_extents.height;
279       break;
280   }
281 }
282
283 static inline void
284 position_around_base (const hb_ot_shape_plan_t *plan,
285                       hb_font_t *font,
286                       hb_buffer_t  *buffer,
287                       unsigned int base,
288                       unsigned int end)
289 {
290   hb_direction_t horiz_dir = HB_DIRECTION_INVALID;
291   hb_glyph_extents_t base_extents;
292   if (!font->get_glyph_extents (buffer->info[base].codepoint,
293                                 &base_extents))
294   {
295     /* If extents don't work, zero marks and go home. */
296     zero_mark_advances (buffer, base + 1, end);
297     return;
298   }
299   base_extents.x_bearing += buffer->pos[base].x_offset;
300   base_extents.y_bearing += buffer->pos[base].y_offset;
301
302   unsigned int lig_id = get_lig_id (buffer->info[base]);
303   unsigned int num_lig_components = get_lig_num_comps (buffer->info[base]);
304
305   hb_position_t x_offset = 0, y_offset = 0;
306   if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
307     x_offset -= buffer->pos[base].x_advance;
308     y_offset -= buffer->pos[base].y_advance;
309   }
310
311   hb_glyph_extents_t component_extents = base_extents;
312   unsigned int last_lig_component = (unsigned int) -1;
313   unsigned int last_combining_class = 255;
314   hb_glyph_extents_t cluster_extents = base_extents; /* Initialization is just to shut gcc up. */
315   for (unsigned int i = base + 1; i < end; i++)
316     if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i]))
317     {
318       if (num_lig_components > 1) {
319         unsigned int this_lig_id = get_lig_id (buffer->info[i]);
320         unsigned int this_lig_component = get_lig_comp (buffer->info[i]) - 1;
321         /* Conditions for attaching to the last component. */
322         if (!lig_id || lig_id != this_lig_id || this_lig_component >= num_lig_components)
323           this_lig_component = num_lig_components - 1;
324         if (last_lig_component != this_lig_component)
325         {
326           last_lig_component = this_lig_component;
327           last_combining_class = 255;
328           component_extents = base_extents;
329           if (unlikely (horiz_dir == HB_DIRECTION_INVALID)) {
330             if (HB_DIRECTION_IS_HORIZONTAL (plan->props.direction))
331               horiz_dir = plan->props.direction;
332             else
333               horiz_dir = hb_script_get_horizontal_direction (plan->props.script);
334           }
335           if (horiz_dir == HB_DIRECTION_LTR)
336             component_extents.x_bearing += (this_lig_component * component_extents.width) / num_lig_components;
337           else
338             component_extents.x_bearing += ((num_lig_components - 1 - this_lig_component) * component_extents.width) / num_lig_components;
339           component_extents.width /= num_lig_components;
340         }
341       }
342
343       unsigned int this_combining_class = _hb_glyph_info_get_modified_combining_class (&buffer->info[i]);
344       if (last_combining_class != this_combining_class)
345       {
346         last_combining_class = this_combining_class;
347         cluster_extents = component_extents;
348       }
349
350       position_mark (plan, font, buffer, cluster_extents, i, this_combining_class);
351
352       buffer->pos[i].x_advance = 0;
353       buffer->pos[i].y_advance = 0;
354       buffer->pos[i].x_offset += x_offset;
355       buffer->pos[i].y_offset += y_offset;
356
357     } else {
358       if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
359         x_offset -= buffer->pos[i].x_advance;
360         y_offset -= buffer->pos[i].y_advance;
361       } else {
362         x_offset += buffer->pos[i].x_advance;
363         y_offset += buffer->pos[i].y_advance;
364       }
365     }
366 }
367
368 static inline void
369 position_cluster (const hb_ot_shape_plan_t *plan,
370                   hb_font_t *font,
371                   hb_buffer_t  *buffer,
372                   unsigned int start,
373                   unsigned int end)
374 {
375   if (end - start < 2)
376     return;
377
378   /* Find the base glyph */
379   for (unsigned int i = start; i < end; i++)
380     if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[i])))
381     {
382       /* Find mark glyphs */
383       unsigned int j;
384       for (j = i + 1; j < end; j++)
385         if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[j])))
386           break;
387
388       position_around_base (plan, font, buffer, i, j);
389
390       i = j - 1;
391     }
392 }
393
394 void
395 _hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan,
396                                 hb_font_t *font,
397                                 hb_buffer_t  *buffer)
398 {
399   unsigned int start = 0;
400   unsigned int last_cluster = buffer->info[0].cluster;
401   unsigned int count = buffer->len;
402   for (unsigned int i = 1; i < count; i++)
403     if (buffer->info[i].cluster != last_cluster) {
404       position_cluster (plan, font, buffer, start, i);
405       start = i;
406       last_cluster = buffer->info[i].cluster;
407     }
408   position_cluster (plan, font, buffer, start, count);
409 }