3fa9f7989c00f146b1d2741e3a13be73b8aa4d45
[framework/uifw/harfbuzz.git] / src / hb-graphite2.cc
1 /*
2  * Copyright © 2011  Martin Hosken
3  * Copyright © 2011  SIL International
4  * Copyright © 2011  Google, Inc.
5  *
6  *  This is part of HarfBuzz, a text shaping library.
7  *
8  * Permission is hereby granted, without written agreement and without
9  * license or royalty fees, to use, copy, modify, and distribute this
10  * software and its documentation for any purpose, provided that the
11  * above copyright notice and the following two paragraphs appear in
12  * all copies of this software.
13  *
14  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
15  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
16  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
17  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
18  * DAMAGE.
19  *
20  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
21  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
22  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
23  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
24  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
25  *
26  * Google Author(s): Behdad Esfahbod
27  */
28
29 #include "hb-private.hh"
30
31 #include "hb-graphite2.h"
32
33 #include "hb-buffer-private.hh"
34 #include "hb-font-private.hh"
35 #include "hb-ot-tag.h"
36
37 #include <graphite2/Font.h>
38 #include <graphite2/Segment.h>
39
40
41 struct hb_gr_cluster_t {
42   unsigned int base_char;
43   unsigned int num_chars;
44   unsigned int base_glyph;
45   unsigned int num_glyphs;
46 };
47
48
49 typedef struct hb_gr_tablelist_t {
50   hb_blob_t   *blob;
51   struct hb_gr_tablelist_t *next;
52   unsigned int tag;
53 } hb_gr_tablelist_t;
54
55 static struct hb_gr_face_data_t {
56   hb_face_t         *face;
57   gr_face           *grface;
58   hb_gr_tablelist_t *tlist;
59 } _hb_gr_face_data_nil = {NULL, NULL};
60
61 static struct hb_gr_font_data_t {
62   gr_font   *grfont;
63   gr_face   *grface;
64 } _hb_gr_font_data_nil = {NULL, NULL};
65
66
67 static const void *hb_gr_get_table (const void *data, unsigned int tag, size_t *len)
68 {
69   hb_gr_tablelist_t *pl = NULL, *p;
70   hb_gr_face_data_t *face = (hb_gr_face_data_t *) data;
71   hb_gr_tablelist_t *tlist = face->tlist;
72
73   for (p = tlist; p; p = p->next)
74     if (p->tag == tag ) {
75       unsigned int tlen;
76       const char *d = hb_blob_get_data (p->blob, &tlen);
77       *len = tlen;
78       return d;
79     } else
80       pl = p;
81
82   if (!face->face)
83     return NULL;
84   hb_blob_t *blob = hb_face_reference_table (face->face, tag);
85
86   if (!pl || pl->blob)
87   {
88     p = (hb_gr_tablelist_t *) malloc (sizeof (hb_gr_tablelist_t));
89     if (!p) {
90       hb_blob_destroy (blob);
91       return NULL;
92     }
93     p->next = NULL;
94     if (pl)
95       pl->next = p;
96     else
97       face->tlist = p;
98     pl = p;
99   }
100   pl->blob = blob;
101   pl->tag = tag;
102
103   unsigned int tlen;
104   const char *d = hb_blob_get_data (blob, &tlen);
105   *len = tlen;
106   return d;
107 }
108
109 static float hb_gr_get_advance (const void *hb_font, unsigned short gid)
110 {
111   return hb_font_get_glyph_h_advance ((hb_font_t *) hb_font, gid);
112 }
113
114 static void _hb_gr_face_data_destroy (void *data)
115 {
116   hb_gr_face_data_t *f = (hb_gr_face_data_t *) data;
117   hb_gr_tablelist_t *tlist = f->tlist;
118   while (tlist)
119   {
120     hb_gr_tablelist_t *old = tlist;
121     hb_blob_destroy (tlist->blob);
122     tlist = tlist->next;
123     free (old);
124   }
125   gr_face_destroy (f->grface);
126 }
127
128 static void _hb_gr_font_data_destroy (void *data)
129 {
130   hb_gr_font_data_t *f = (hb_gr_font_data_t *) data;
131
132   gr_font_destroy (f->grfont);
133   free (f);
134 }
135
136 static hb_user_data_key_t hb_gr_data_key;
137
138 static hb_gr_face_data_t *
139 _hb_gr_face_get_data (hb_face_t *face)
140 {
141   hb_gr_face_data_t *data = (hb_gr_face_data_t *) hb_face_get_user_data (face, &hb_gr_data_key);
142   if (likely (data)) return data;
143
144   data = (hb_gr_face_data_t *) calloc (1, sizeof (hb_gr_face_data_t));
145   if (unlikely (!data))
146     return &_hb_gr_face_data_nil;
147
148
149   hb_blob_t *silf_blob = hb_face_reference_table (face, HB_GRAPHITE_TAG_Silf);
150   if (!hb_blob_get_length (silf_blob))
151   {
152     hb_blob_destroy (silf_blob);
153     return &_hb_gr_face_data_nil;
154   }
155
156   data->face = face;
157   data->grface = gr_make_face (data, &hb_gr_get_table, gr_face_default);
158
159
160   if (unlikely (!hb_face_set_user_data (face, &hb_gr_data_key, data,
161                                         (hb_destroy_func_t) _hb_gr_face_data_destroy,
162                                         false)))
163   {
164     _hb_gr_face_data_destroy (data);
165     data = (hb_gr_face_data_t *) hb_face_get_user_data (face, &hb_gr_data_key);
166     if (data)
167       return data;
168     else
169       return &_hb_gr_face_data_nil;
170   }
171
172   return data;
173 }
174
175 static hb_gr_font_data_t *
176 _hb_gr_font_get_data (hb_font_t *font)
177 {
178   hb_gr_font_data_t *data = (hb_gr_font_data_t *) hb_font_get_user_data (font, &hb_gr_data_key);
179   if (likely (data)) return data;
180
181   data = (hb_gr_font_data_t *) calloc (1, sizeof (hb_gr_font_data_t));
182   if (unlikely (!data))
183     return &_hb_gr_font_data_nil;
184
185
186   hb_blob_t *silf_blob = hb_face_reference_table (font->face, HB_GRAPHITE_TAG_Silf);
187   if (!hb_blob_get_length (silf_blob))
188   {
189     hb_blob_destroy (silf_blob);
190     return &_hb_gr_font_data_nil;
191   }
192
193   data->grface = _hb_gr_face_get_data (font->face)->grface;
194   int scale;
195   hb_font_get_scale (font, &scale, NULL);
196   data->grfont = gr_make_font_with_advance_fn (scale, font, &hb_gr_get_advance, data->grface);
197
198
199   if (unlikely (!hb_font_set_user_data (font, &hb_gr_data_key, data,
200                                         (hb_destroy_func_t) _hb_gr_font_data_destroy,
201                                         false)))
202   {
203     _hb_gr_font_data_destroy (data);
204     data = (hb_gr_font_data_t *) hb_font_get_user_data (font, &hb_gr_data_key);
205     if (data)
206       return data;
207     else
208       return &_hb_gr_font_data_nil;
209   }
210
211   return data;
212 }
213
214
215 hb_bool_t
216 _hb_graphite_shape (hb_font_t          *font,
217                    hb_buffer_t        *buffer,
218                    const hb_feature_t *features,
219                    unsigned int        num_features)
220 {
221
222   buffer->guess_properties ();
223
224   /* XXX We do a hell of a lot of stuff just to figure out this font
225    * is not graphite!  Shouldn't do. */
226
227   hb_gr_font_data_t *data = _hb_gr_font_get_data (font);
228   if (!data->grface) return false;
229
230   unsigned int charlen;
231   hb_glyph_info_t *bufferi = hb_buffer_get_glyph_infos (buffer, &charlen);
232
233   int success = 0;
234
235   if (!charlen) return true;
236
237   const char *lang = hb_language_to_string (hb_buffer_get_language (buffer));
238   const char *lang_end = strchr (lang, '-');
239   int lang_len = lang_end ? lang_end - lang : -1;
240   gr_feature_val *feats = gr_face_featureval_for_lang (data->grface, lang ? hb_tag_from_string (lang, lang_len) : 0);
241
242   while (num_features--)
243   {
244     const gr_feature_ref *fref = gr_face_find_fref (data->grface, features->tag);
245     if (fref)
246       gr_fref_set_feature_value (fref, features->value, feats);
247     features++;
248   }
249
250   hb_codepoint_t *gids = NULL, *pg;
251   hb_gr_cluster_t *clusters = NULL;
252   gr_segment *seg = NULL;
253   uint32_t *text = NULL;
254   const gr_slot *is;
255   unsigned int ci = 0, ic = 0;
256   float curradvx = 0., curradvy = 0.;
257   unsigned int glyphlen = 0;
258   unsigned int *p;
259
260   text = (uint32_t *) malloc ((charlen + 1) * sizeof (uint32_t));
261   if (!text) goto dieout;
262
263   p = text;
264   for (unsigned int i = 0; i < charlen; ++i)
265     *p++ = bufferi++->codepoint;
266   *p = 0;
267
268   hb_tag_t script_tag[2];
269   hb_ot_tags_from_script (hb_buffer_get_script (buffer), &script_tag[0], &script_tag[1]);
270
271   seg = gr_make_seg (data->grfont, data->grface,
272                      script_tag[1] == HB_TAG_NONE ? script_tag[0] : script_tag[1],
273                      feats,
274                      gr_utf32, text, charlen,
275                      2 | (hb_buffer_get_direction (buffer) == HB_DIRECTION_RTL ? 1 : 0));
276   if (!seg) goto dieout;
277
278   glyphlen = gr_seg_n_slots (seg);
279   clusters = (hb_gr_cluster_t *) calloc (charlen, sizeof (hb_gr_cluster_t));
280   if (!glyphlen || !clusters) goto dieout;
281
282   gids = (hb_codepoint_t *) malloc (glyphlen * sizeof (hb_codepoint_t));
283   if (!gids) goto dieout;
284
285   pg = gids;
286   for (is = gr_seg_first_slot (seg), ic = 0; is; is = gr_slot_next_in_segment (is), ic++)
287   {
288     unsigned int before = gr_slot_before (is);
289     unsigned int after = gr_slot_after (is);
290     *pg = gr_slot_gid (is);
291     pg++;
292     while (clusters[ci].base_char > before && ci)
293     {
294       clusters[ci-1].num_chars += clusters[ci].num_chars;
295       clusters[ci-1].num_glyphs += clusters[ci].num_glyphs;
296       ci--;
297     }
298
299     if (gr_slot_can_insert_before (is) && clusters[ci].num_chars && before >= clusters[ci].base_char + clusters[ci].num_chars)
300     {
301       hb_gr_cluster_t *c = clusters + ci + 1;
302       c->base_char = clusters[ci].base_char + clusters[ci].num_chars;
303       c->num_chars = before - c->base_char;
304       c->base_glyph = ic;
305       c->num_glyphs = 0;
306       ci++;
307     }
308     clusters[ci].num_glyphs++;
309
310     if (clusters[ci].base_char + clusters[ci].num_chars < after + 1)
311         clusters[ci].num_chars = after + 1 - clusters[ci].base_char;
312   }
313   ci++;
314
315   buffer->clear_output ();
316   for (unsigned int i = 0; i < ci; ++i)
317     buffer->replace_glyphs (clusters[i].num_chars, clusters[i].num_glyphs, gids + clusters[i].base_glyph);
318   buffer->swap_buffers ();
319
320   hb_glyph_position_t *pPos;
321   for (pPos = hb_buffer_get_glyph_positions (buffer, NULL), is = gr_seg_first_slot (seg);
322        is; pPos++, is = gr_slot_next_in_segment (is))
323   {
324     pPos->x_offset = gr_slot_origin_X(is) - curradvx;
325     pPos->y_offset = gr_slot_origin_Y(is) - curradvy;
326     pPos->x_advance = gr_slot_advance_X(is, data->grface, data->grfont);
327     pPos->y_advance = gr_slot_advance_Y(is, data->grface, data->grfont);
328 //    if (pPos->x_advance < 0 && gr_slot_attached_to(is))
329 //      pPos->x_advance = 0;
330     curradvx += pPos->x_advance;
331     curradvy += pPos->y_advance;
332   }
333   pPos[-1].x_advance += gr_seg_advance_X(seg) - curradvx;
334
335   /* TODO(behdad):
336    * This shaper is badly broken with RTL text.  It returns glyphs
337    * in the logical order!
338    */
339 //  if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
340 //    hb_buffer_reverse (buffer);
341
342   success = 1;
343
344 dieout:
345   if (gids) free (gids);
346   if (clusters) free (clusters);
347   if (seg) gr_seg_destroy (seg);
348   if (text) free (text);
349   return success;
350 }