Remove IN_INFO() and IN_NEXTGLYPH() macros
[framework/uifw/harfbuzz.git] / src / hb-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-private.h"
28
29 #include "hb-shape.h"
30
31 #include "hb-buffer-private.hh"
32
33 #include "hb-ot-shape-private.hh"
34
35
36 /* Prepare */
37
38 static inline hb_bool_t
39 is_variation_selector (hb_codepoint_t unicode)
40 {
41   return unlikely ((unicode >=  0x180B && unicode <=  0x180D) || /* MONGOLIAN FREE VARIATION SELECTOR ONE..THREE */
42                    (unicode >=  0xFE00 && unicode <=  0xFE0F) || /* VARIATION SELECTOR-1..16 */
43                    (unicode >= 0xE0100 && unicode <= 0xE01EF));  /* VARIATION SELECTOR-17..256 */
44 }
45
46 static void
47 hb_form_clusters (hb_buffer_t *buffer)
48 {
49   unsigned int count;
50
51   count = buffer->in_length;
52   for (buffer->in_pos = 1; buffer->in_pos < count; buffer->in_pos++)
53     if (buffer->unicode->get_general_category (IN_CURGLYPH()) == HB_CATEGORY_NON_SPACING_MARK)
54       buffer->in_string[buffer->in_pos].cluster = buffer->in_string[buffer->in_pos - 1].cluster;
55 }
56
57 static hb_direction_t
58 hb_ensure_native_direction (hb_buffer_t *buffer)
59 {
60   hb_direction_t original_direction = buffer->direction;
61
62   /* TODO vertical */
63   if (HB_DIRECTION_IS_HORIZONTAL (original_direction) &&
64       original_direction != _hb_script_get_horizontal_direction (buffer->script))
65   {
66     hb_buffer_reverse_clusters (buffer);
67     buffer->direction = HB_DIRECTION_REVERSE (buffer->direction);
68   }
69
70   return original_direction;
71 }
72
73
74 /* Substitute */
75
76 static void
77 hb_mirror_chars (hb_buffer_t *buffer)
78 {
79   unsigned int count;
80   hb_unicode_get_mirroring_func_t get_mirroring = buffer->unicode->get_mirroring;
81
82   if (HB_DIRECTION_IS_FORWARD (buffer->direction))
83     return;
84
85   count = buffer->in_length;
86   for (buffer->in_pos = 0; buffer->in_pos < count; buffer->in_pos++) {
87       IN_CURGLYPH() = get_mirroring (IN_CURGLYPH());
88   }
89 }
90
91 static void
92 hb_map_glyphs (hb_font_t    *font,
93                hb_face_t    *face,
94                hb_buffer_t  *buffer)
95 {
96   unsigned int count;
97
98   if (unlikely (!buffer->in_length))
99     return;
100   count = buffer->in_length - 1;
101   for (buffer->in_pos = 0; buffer->in_pos < count; buffer->in_pos++) {
102     if (unlikely (is_variation_selector (buffer->in_string[buffer->in_pos + 1].codepoint))) {
103       IN_CURGLYPH() = hb_font_get_glyph (font, face, IN_CURGLYPH(), buffer->in_string[buffer->in_pos + 1].codepoint);
104       buffer->in_pos++;
105     } else {
106       IN_CURGLYPH() = hb_font_get_glyph (font, face, IN_CURGLYPH(), 0);
107     }
108   }
109   IN_CURGLYPH() = hb_font_get_glyph (font, face, IN_CURGLYPH(), 0);
110 }
111
112 static void
113 hb_substitute_default (hb_font_t    *font,
114                        hb_face_t    *face,
115                        hb_buffer_t  *buffer,
116                        hb_feature_t *features HB_UNUSED,
117                        unsigned int  num_features HB_UNUSED)
118 {
119   hb_mirror_chars (buffer);
120   hb_map_glyphs (font, face, buffer);
121 }
122
123 static hb_bool_t
124 hb_substitute_complex (hb_font_t    *font,
125                        hb_face_t    *face,
126                        hb_buffer_t  *buffer,
127                        hb_feature_t *features,
128                        unsigned int  num_features)
129 {
130   return _hb_ot_substitute_complex (font, face, buffer, features, num_features);
131 }
132
133 static void
134 hb_substitute_fallback (hb_font_t    *font HB_UNUSED,
135                         hb_face_t    *face HB_UNUSED,
136                         hb_buffer_t  *buffer HB_UNUSED,
137                         hb_feature_t *features HB_UNUSED,
138                         unsigned int  num_features HB_UNUSED)
139 {
140   /* TODO Arabic */
141 }
142
143
144 /* Position */
145
146 static void
147 hb_position_default (hb_font_t    *font,
148                      hb_face_t    *face,
149                      hb_buffer_t  *buffer,
150                      hb_feature_t *features HB_UNUSED,
151                      unsigned int  num_features HB_UNUSED)
152 {
153   unsigned int count;
154
155   hb_buffer_clear_positions (buffer);
156
157   count = buffer->in_length;
158   for (buffer->in_pos = 0; buffer->in_pos < count; buffer->in_pos++) {
159     hb_glyph_metrics_t metrics;
160     hb_font_get_glyph_metrics (font, face, IN_CURGLYPH(), &metrics);
161     buffer->positions[buffer->in_pos].x_advance = metrics.x_advance;
162     buffer->positions[buffer->in_pos].y_advance = metrics.y_advance;
163   }
164 }
165
166 static hb_bool_t
167 hb_position_complex (hb_font_t    *font,
168                      hb_face_t    *face,
169                      hb_buffer_t  *buffer,
170                      hb_feature_t *features,
171                      unsigned int  num_features)
172 {
173   return _hb_ot_position_complex (font, face, buffer, features, num_features);
174 }
175
176 static void
177 hb_position_fallback (hb_font_t    *font HB_UNUSED,
178                       hb_face_t    *face HB_UNUSED,
179                       hb_buffer_t  *buffer HB_UNUSED,
180                       hb_feature_t *features HB_UNUSED,
181                       unsigned int  num_features HB_UNUSED)
182 {
183   /* TODO Mark pos */
184 }
185
186 static void
187 hb_truetype_kern (hb_font_t    *font,
188                   hb_face_t    *face,
189                   hb_buffer_t  *buffer,
190                   hb_feature_t *features HB_UNUSED,
191                   unsigned int  num_features HB_UNUSED)
192 {
193   unsigned int count;
194
195   /* TODO Check for kern=0 */
196   count = buffer->in_length;
197   for (buffer->in_pos = 1; buffer->in_pos < count; buffer->in_pos++) {
198     hb_position_t kern, kern1, kern2;
199     kern = hb_font_get_kerning (font, face, buffer->in_string[buffer->in_pos - 1].codepoint, IN_CURGLYPH());
200     kern1 = kern >> 1;
201     kern2 = kern - kern1;
202     buffer->positions[buffer->in_pos - 1].x_advance += kern1;
203     buffer->positions[buffer->in_pos].x_advance += kern2;
204     buffer->positions[buffer->in_pos].x_offset += kern2;
205   }
206 }
207
208 static void
209 hb_position_fallback_visual (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   hb_truetype_kern (font, face, buffer, features, num_features);
216 }
217
218
219 /* Shape */
220
221 void
222 hb_shape (hb_font_t    *font,
223           hb_face_t    *face,
224           hb_buffer_t  *buffer,
225           hb_feature_t *features,
226           unsigned int  num_features)
227 {
228   hb_direction_t original_direction;
229   hb_bool_t substitute_fallback, position_fallback;
230
231   hb_form_clusters (buffer);
232
233   hb_substitute_default (font, face, buffer, features, num_features);
234
235   /* We do this after substitute_default because mirroring needs to
236    * see the original direction. */
237   original_direction = hb_ensure_native_direction (buffer);
238
239   substitute_fallback = !hb_substitute_complex (font, face, buffer, features, num_features);
240
241   if (substitute_fallback)
242     hb_substitute_fallback (font, face, buffer, features, num_features);
243
244   hb_position_default (font, face, buffer, features, num_features);
245
246   position_fallback = !hb_position_complex (font, face, buffer, features, num_features);
247
248   if (position_fallback)
249     hb_position_fallback (font, face, buffer, features, num_features);
250
251   if (HB_DIRECTION_IS_BACKWARD (buffer->direction))
252     hb_buffer_reverse (buffer);
253
254   if (position_fallback)
255     hb_position_fallback_visual (font, face, buffer, features, num_features);
256
257   buffer->direction = original_direction;
258 }