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