blob: a3b567974cda9c06575a7f2eace7ac23d032494d [file] [log] [blame]
Behdad Esfahbod8fe4c742012-07-24 21:05:12 -04001/*
2 * Copyright © 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-private.hh"
28
29#include "hb-old-private.hh"
30
31#include "hb-font-private.hh"
32#include "hb-buffer-private.hh"
33
34#include <harfbuzz.h>
35
36
37#ifndef HB_DEBUG_OLD
38#define HB_DEBUG_OLD (HB_DEBUG+0)
39#endif
40
41
42static HB_Script
43hb_old_script_from_script (hb_script_t script)
44{
45 switch ((hb_tag_t) script)
46 {
47 default:
48 case HB_SCRIPT_COMMON: return HB_Script_Common;
49 case HB_SCRIPT_GREEK: return HB_Script_Greek;
50 case HB_SCRIPT_CYRILLIC: return HB_Script_Cyrillic;
51 case HB_SCRIPT_ARMENIAN: return HB_Script_Armenian;
52 case HB_SCRIPT_HEBREW: return HB_Script_Hebrew;
53 case HB_SCRIPT_ARABIC: return HB_Script_Arabic;
54 case HB_SCRIPT_SYRIAC: return HB_Script_Syriac;
55 case HB_SCRIPT_THAANA: return HB_Script_Thaana;
56 case HB_SCRIPT_DEVANAGARI: return HB_Script_Devanagari;
57 case HB_SCRIPT_BENGALI: return HB_Script_Bengali;
58 case HB_SCRIPT_GURMUKHI: return HB_Script_Gurmukhi;
59 case HB_SCRIPT_GUJARATI: return HB_Script_Gujarati;
60 case HB_SCRIPT_ORIYA: return HB_Script_Oriya;
61 case HB_SCRIPT_TAMIL: return HB_Script_Tamil;
62 case HB_SCRIPT_TELUGU: return HB_Script_Telugu;
63 case HB_SCRIPT_KANNADA: return HB_Script_Kannada;
64 case HB_SCRIPT_MALAYALAM: return HB_Script_Malayalam;
65 case HB_SCRIPT_SINHALA: return HB_Script_Sinhala;
66 case HB_SCRIPT_THAI: return HB_Script_Thai;
67 case HB_SCRIPT_LAO: return HB_Script_Lao;
68 case HB_SCRIPT_TIBETAN: return HB_Script_Tibetan;
69 case HB_SCRIPT_MYANMAR: return HB_Script_Myanmar;
70 case HB_SCRIPT_GEORGIAN: return HB_Script_Georgian;
71 case HB_SCRIPT_HANGUL: return HB_Script_Hangul;
72 case HB_SCRIPT_OGHAM: return HB_Script_Ogham;
73 case HB_SCRIPT_RUNIC: return HB_Script_Runic;
74 case HB_SCRIPT_KHMER: return HB_Script_Khmer;
75 case HB_SCRIPT_NKO: return HB_Script_Nko;
76 case HB_SCRIPT_INHERITED: return HB_Script_Inherited;
77 }
78}
79
80
81static HB_Bool
82hb_old_convertStringToGlyphIndices (HB_Font old_font,
83 const HB_UChar16 *string,
84 hb_uint32 length,
85 HB_Glyph *glyphs,
86 hb_uint32 *numGlyphs,
87 HB_Bool rightToLeft)
88{
89 hb_font_t *font = (hb_font_t *) old_font->userData;
90
91 for (unsigned int i = 0; i < length; i++)
92 {
93 hb_codepoint_t u;
94
95 /* TODO Handle UTF-16. Ugh */
96 u = string[i];
97
98 if (rightToLeft)
99 u = hb_unicode_mirroring (hb_unicode_funcs_get_default (), u);
100
101 hb_font_get_glyph (font, u, 0, &u); /* TODO Variation selectors */
102
103 glyphs[i] = u;
104 }
105 *numGlyphs = length; // XXX
106
107 return true;
108}
109
110static void
111hb_old_getGlyphAdvances (HB_Font old_font,
112 const HB_Glyph *glyphs,
113 hb_uint32 numGlyphs,
114 HB_Fixed *advances,
115 int flags /*HB_ShaperFlag*/)
116{
117 hb_font_t *font = (hb_font_t *) old_font->userData;
118
119 for (unsigned int i = 0; i < numGlyphs; i++)
120 advances[i] = hb_font_get_glyph_h_advance (font, glyphs[i]);
121}
122
123static HB_Bool
124hb_old_canRender (HB_Font old_font,
125 const HB_UChar16 *string,
126 hb_uint32 length)
127{
128 return true; // TODO
129}
130
131static HB_Error
132hb_old_getPointInOutline (HB_Font old_font,
133 HB_Glyph glyph,
134 int flags /*HB_ShaperFlag*/,
135 hb_uint32 point,
136 HB_Fixed *xpos,
137 HB_Fixed *ypos,
138 hb_uint32 *nPoints)
139{
140 return HB_Err_Ok; // TODO
141}
142
143static void
144hb_old_getGlyphMetrics (HB_Font old_font,
145 HB_Glyph glyph,
146 HB_GlyphMetrics *metrics)
147{
148 // TODO
149}
150
151static HB_Fixed
152hb_old_getFontMetric (HB_Font old_font,
153 HB_FontMetric metric)
154{
155 return 0; // TODO
156}
157
158static const HB_FontClass hb_old_font_class = {
159 hb_old_convertStringToGlyphIndices,
160 hb_old_getGlyphAdvances,
161 hb_old_canRender,
162 hb_old_getPointInOutline,
163 hb_old_getGlyphMetrics,
164 hb_old_getFontMetric
165};
166
167
168
169static hb_user_data_key_t hb_old_data_key;
170
171static HB_Error
172table_func (void *font, HB_Tag tag, HB_Byte *buffer, HB_UInt *length)
173{
174 hb_face_t *face = (hb_face_t *) font;
175 hb_blob_t *blob = hb_face_reference_table (face, (hb_tag_t) tag);
176 unsigned int capacity = *length;
177 *length = hb_blob_get_length (blob);
178 memcpy (buffer, hb_blob_get_data (blob, NULL), MIN (capacity, *length));
179 hb_blob_destroy (blob);
180 return HB_Err_Ok;
181}
182
183static HB_Face
184_hb_old_face_get (hb_face_t *face)
185{
186 HB_Face data = (HB_Face) hb_face_get_user_data (face, &hb_old_data_key);
187 if (likely (data)) return data;
188
189 data = HB_NewFace (face, table_func);
190
191 if (unlikely (!data)) {
192 DEBUG_MSG (OLD, face, "HB_NewFace failed");
193 return NULL;
194 }
195
196 if (unlikely (!hb_face_set_user_data (face, &hb_old_data_key, data,
197 (hb_destroy_func_t) HB_FreeFace,
198 false)))
199 {
200 HB_FreeFace (data);
201 data = (HB_Face) hb_face_get_user_data (face, &hb_old_data_key);
202 if (data)
203 return data;
204 else
205 return NULL;
206 }
207
208 return data;
209}
210
211
212static HB_Font
213_hb_old_font_get (hb_font_t *font)
214{
215 HB_Font data = (HB_Font) calloc (1, sizeof (HB_FontRec));
216 if (unlikely (!data)) {
217 DEBUG_MSG (OLD, font, "malloc()ing HB_Font failed");
218 return NULL;
219 }
220
221 data->klass = &hb_old_font_class;
222 data->x_ppem = font->x_ppem;
223 data->y_ppem = font->y_ppem;
224 data->x_scale = font->x_scale; // XXX
225 data->y_scale = font->y_scale; // XXX
226 data->userData = font;
227
228 if (unlikely (!hb_font_set_user_data (font, &hb_old_data_key, data,
229 (hb_destroy_func_t) free,
230 false)))
231 {
232 free (data);
233 data = (HB_Font) hb_font_get_user_data (font, &hb_old_data_key);
234 if (data)
235 return data;
236 else
237 return NULL;
238 }
239
240 return data;
241}
242
243hb_bool_t
244_hb_old_shape (hb_font_t *font,
245 hb_buffer_t *buffer,
246 const hb_feature_t *features,
247 unsigned int num_features)
248{
249 if (unlikely (!buffer->len))
250 return true;
251
252 buffer->guess_properties ();
253
254#define FAIL(...) \
255 HB_STMT_START { \
256 DEBUG_MSG (OLD, NULL, __VA_ARGS__); \
257 return false; \
258 } HB_STMT_END;
259
260 HB_Face old_face = _hb_old_face_get (font->face);
261 if (unlikely (!old_face))
262 FAIL ("Couldn't get old face");
263
264 HB_Font old_font = _hb_old_font_get (font);
265 if (unlikely (!old_font))
266 FAIL ("Couldn't get old font");
267
268retry:
269
270 unsigned int scratch_size;
271 char *scratch = (char *) buffer->get_scratch_buffer (&scratch_size);
272
273#define utf16_index() var1.u32
274 HB_UChar16 *pchars = (HB_UChar16 *) scratch;
275 unsigned int chars_len = 0;
276 for (unsigned int i = 0; i < buffer->len; i++) {
277 hb_codepoint_t c = buffer->info[i].codepoint;
278 buffer->info[i].utf16_index() = chars_len;
279 if (likely (c < 0x10000))
280 pchars[chars_len++] = c;
281 else if (unlikely (c >= 0x110000))
282 pchars[chars_len++] = 0xFFFD;
283 else {
284 pchars[chars_len++] = 0xD800 + ((c - 0x10000) >> 10);
285 pchars[chars_len++] = 0xDC00 + ((c - 0x10000) & ((1 << 10) - 1));
286 }
287 }
288#undef utf16_index
289
290
291#define ALLOCATE_ARRAY(Type, name, len) \
292 name = (Type *) scratch; \
293 scratch += len * sizeof (name[0]); \
294 scratch_size -= len * sizeof (name[0]);
295
296
297 HB_ShaperItem item = {0};
298
299 ALLOCATE_ARRAY (const HB_UChar16, item.string, chars_len);
300 item.stringLength = chars_len;
301 item.item.pos = 0;
302 item.item.length = item.stringLength;
303 item.item.script = hb_old_script_from_script (buffer->props.script);
304 item.item.bidiLevel = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
305
306 item.font = old_font;
307 item.face = old_face;
308 item.shaperFlags = 0;
309
310 item.glyphIndicesPresent = false;
311
312 /* TODO Alignment. */
313 unsigned int num_glyphs = scratch_size / (sizeof (HB_Glyph) +
314 sizeof (HB_GlyphAttributes) +
315 sizeof (HB_Fixed) +
316 sizeof (HB_FixedPoint) +
317 sizeof (unsigned short));
318
319 item.num_glyphs = num_glyphs;
320 ALLOCATE_ARRAY (HB_Glyph, item.glyphs, num_glyphs);
321 ALLOCATE_ARRAY (HB_GlyphAttributes, item.attributes, num_glyphs);
322 ALLOCATE_ARRAY (HB_Fixed, item.advances, num_glyphs);
323 ALLOCATE_ARRAY (HB_FixedPoint, item.offsets, num_glyphs);
324 ALLOCATE_ARRAY (unsigned short, item.log_clusters, num_glyphs);
325
326 if (!HB_ShapeItem (&item))
327 return false;
328
329 if (unlikely (item.num_glyphs > num_glyphs))
330 {
331 buffer->ensure (buffer->allocated * 2);
332 if (buffer->in_error)
333 FAIL ("Buffer resize failed");
334 goto retry;
335 }
336 num_glyphs = item.num_glyphs;
337
338#undef ALLOCATE_ARRAY
339
340 hb_glyph_info_t *info = buffer->info;
341 for (unsigned int i = 0; i < num_glyphs; i++)
342 {
343 info[i].codepoint = item.glyphs[i];
344 info[i].cluster = item.log_clusters[i];
345
346 info[i].mask = item.advances[i];
347 info[i].var1.u32 = item.offsets[i].x;
348 info[i].var2.u32 = item.offsets[i].y;
349 }
350 buffer->len = num_glyphs;
351
352 buffer->clear_positions ();
353
354 unsigned int count = buffer->len;
355 for (unsigned int i = 0; i < count; ++i) {
356 hb_glyph_info_t *info = &buffer->info[i];
357 hb_glyph_position_t *pos = &buffer->pos[i];
358
359 /* TODO vertical */
360 pos->x_advance = info->mask;
361 pos->x_offset = info->var1.u32;
362 pos->y_offset = info->var2.u32;
363 }
364
365 if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
366 buffer->reverse ();
367
368 return true;
369}