OLD | NEW |
| (Empty) |
1 /* | |
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 #define HB_SHAPER old | |
28 #define hb_old_shaper_face_data_t HB_FaceRec_ | |
29 #define hb_old_shaper_font_data_t HB_Font_ | |
30 #include "hb-shaper-impl-private.hh" | |
31 | |
32 #include <harfbuzz.h> | |
33 | |
34 | |
35 #ifndef HB_DEBUG_OLD | |
36 #define HB_DEBUG_OLD (HB_DEBUG+0) | |
37 #endif | |
38 | |
39 | |
40 static HB_Script | |
41 hb_old_script_from_script (hb_script_t script) | |
42 { | |
43 switch ((hb_tag_t) script) | |
44 { | |
45 default: | |
46 case HB_SCRIPT_COMMON: return HB_Script_Common; | |
47 case HB_SCRIPT_GREEK: return HB_Script_Greek; | |
48 case HB_SCRIPT_CYRILLIC: return HB_Script_Cyrillic; | |
49 case HB_SCRIPT_ARMENIAN: return HB_Script_Armenian; | |
50 case HB_SCRIPT_HEBREW: return HB_Script_Hebrew; | |
51 case HB_SCRIPT_ARABIC: return HB_Script_Arabic; | |
52 case HB_SCRIPT_SYRIAC: return HB_Script_Syriac; | |
53 case HB_SCRIPT_THAANA: return HB_Script_Thaana; | |
54 case HB_SCRIPT_DEVANAGARI: return HB_Script_Devanagari; | |
55 case HB_SCRIPT_BENGALI: return HB_Script_Bengali; | |
56 case HB_SCRIPT_GURMUKHI: return HB_Script_Gurmukhi; | |
57 case HB_SCRIPT_GUJARATI: return HB_Script_Gujarati; | |
58 case HB_SCRIPT_ORIYA: return HB_Script_Oriya; | |
59 case HB_SCRIPT_TAMIL: return HB_Script_Tamil; | |
60 case HB_SCRIPT_TELUGU: return HB_Script_Telugu; | |
61 case HB_SCRIPT_KANNADA: return HB_Script_Kannada; | |
62 case HB_SCRIPT_MALAYALAM: return HB_Script_Malayalam; | |
63 case HB_SCRIPT_SINHALA: return HB_Script_Sinhala; | |
64 case HB_SCRIPT_THAI: return HB_Script_Thai; | |
65 case HB_SCRIPT_LAO: return HB_Script_Lao; | |
66 case HB_SCRIPT_TIBETAN: return HB_Script_Tibetan; | |
67 case HB_SCRIPT_MYANMAR: return HB_Script_Myanmar; | |
68 case HB_SCRIPT_GEORGIAN: return HB_Script_Georgian; | |
69 case HB_SCRIPT_HANGUL: return HB_Script_Hangul; | |
70 case HB_SCRIPT_OGHAM: return HB_Script_Ogham; | |
71 case HB_SCRIPT_RUNIC: return HB_Script_Runic; | |
72 case HB_SCRIPT_KHMER: return HB_Script_Khmer; | |
73 case HB_SCRIPT_NKO: return HB_Script_Nko; | |
74 case HB_SCRIPT_INHERITED: return HB_Script_Inherited; | |
75 } | |
76 } | |
77 | |
78 | |
79 static HB_Bool | |
80 hb_old_convertStringToGlyphIndices (HB_Font old_font, | |
81 const HB_UChar16 *string, | |
82 hb_uint32 length, | |
83 HB_Glyph *glyphs, | |
84 hb_uint32 *numGlyphs, | |
85 HB_Bool rightToLeft) | |
86 { | |
87 hb_font_t *font = (hb_font_t *) old_font->userData; | |
88 | |
89 for (unsigned int i = 0; i < length; i++) | |
90 { | |
91 hb_codepoint_t u; | |
92 | |
93 /* XXX Handle UTF-16. Ugh */ | |
94 u = string[i]; | |
95 | |
96 if (rightToLeft) | |
97 u = hb_unicode_funcs_get_default ()->mirroring (u); | |
98 | |
99 font->get_glyph (u, 0, &u); /* TODO Variation selectors */ | |
100 | |
101 glyphs[i] = u; | |
102 } | |
103 *numGlyphs = length; /* XXX */ | |
104 | |
105 return true; | |
106 } | |
107 | |
108 static void | |
109 hb_old_getGlyphAdvances (HB_Font old_font, | |
110 const HB_Glyph *glyphs, | |
111 hb_uint32 numGlyphs, | |
112 HB_Fixed *advances, | |
113 int flags /*HB_ShaperFlag*/ HB_UNUSED) | |
114 { | |
115 hb_font_t *font = (hb_font_t *) old_font->userData; | |
116 | |
117 for (unsigned int i = 0; i < numGlyphs; i++) | |
118 advances[i] = font->get_glyph_h_advance (glyphs[i]); | |
119 } | |
120 | |
121 static HB_Bool | |
122 hb_old_canRender (HB_Font old_font, | |
123 const HB_UChar16 *string, | |
124 hb_uint32 length) | |
125 { | |
126 return true; /* TODO */ | |
127 } | |
128 | |
129 static HB_Error | |
130 hb_old_getPointInOutline (HB_Font old_font, | |
131 HB_Glyph glyph, | |
132 int flags /*HB_ShaperFlag*/, | |
133 hb_uint32 point, | |
134 HB_Fixed *xpos, | |
135 HB_Fixed *ypos, | |
136 hb_uint32 *nPoints) | |
137 { | |
138 return HB_Err_Ok; /* TODO */ | |
139 } | |
140 | |
141 static void | |
142 hb_old_getGlyphMetrics (HB_Font old_font, | |
143 HB_Glyph glyph, | |
144 HB_GlyphMetrics *metrics) | |
145 { | |
146 hb_font_t *font = (hb_font_t *) old_font->userData; | |
147 | |
148 hb_glyph_extents_t extents; | |
149 | |
150 font->get_glyph_extents (glyph, &extents); | |
151 | |
152 metrics->x = extents.x_bearing; | |
153 metrics->y = extents.y_bearing; | |
154 metrics->width = extents.width; | |
155 metrics->height = extents.height; | |
156 metrics->xOffset = font->get_glyph_h_advance (glyph); | |
157 metrics->yOffset = 0; | |
158 } | |
159 | |
160 static HB_Fixed | |
161 hb_old_getFontMetric (HB_Font old_font, | |
162 HB_FontMetric metric) | |
163 { | |
164 hb_font_t *font = (hb_font_t *) old_font->userData; | |
165 | |
166 switch (metric) | |
167 { | |
168 case HB_FontAscent: | |
169 return font->y_scale; /* XXX We don't have ascent data yet. */ | |
170 | |
171 default: | |
172 return 0; | |
173 } | |
174 } | |
175 | |
176 static const HB_FontClass hb_old_font_class = { | |
177 hb_old_convertStringToGlyphIndices, | |
178 hb_old_getGlyphAdvances, | |
179 hb_old_canRender, | |
180 hb_old_getPointInOutline, | |
181 hb_old_getGlyphMetrics, | |
182 hb_old_getFontMetric | |
183 }; | |
184 | |
185 | |
186 | |
187 static HB_Error | |
188 table_func (void *font, HB_Tag tag, HB_Byte *buffer, HB_UInt *length) | |
189 { | |
190 hb_face_t *face = (hb_face_t *) font; | |
191 hb_blob_t *blob = face->reference_table ((hb_tag_t) tag); | |
192 unsigned int capacity = *length; | |
193 *length = hb_blob_get_length (blob); | |
194 memcpy (buffer, hb_blob_get_data (blob, NULL), MIN (capacity, *length)); | |
195 hb_blob_destroy (blob); | |
196 return HB_Err_Ok; | |
197 } | |
198 | |
199 | |
200 /* | |
201 * shaper face data | |
202 */ | |
203 | |
204 hb_old_shaper_face_data_t * | |
205 _hb_old_shaper_face_data_create (hb_face_t *face) | |
206 { | |
207 return HB_NewFace (face, table_func); | |
208 } | |
209 | |
210 void | |
211 _hb_old_shaper_face_data_destroy (hb_old_shaper_face_data_t *data) | |
212 { | |
213 HB_FreeFace (data); | |
214 } | |
215 | |
216 | |
217 /* | |
218 * shaper font data | |
219 */ | |
220 | |
221 hb_old_shaper_font_data_t * | |
222 _hb_old_shaper_font_data_create (hb_font_t *font) | |
223 { | |
224 HB_FontRec *data = (HB_FontRec *) calloc (1, sizeof (HB_FontRec)); | |
225 if (unlikely (!data)) { | |
226 DEBUG_MSG (OLD, font, "malloc()ing HB_Font failed"); | |
227 return NULL; | |
228 } | |
229 | |
230 data->klass = &hb_old_font_class; | |
231 data->x_ppem = font->x_ppem; | |
232 data->y_ppem = font->y_ppem; | |
233 data->x_scale = font->x_scale; /* XXX */ | |
234 data->y_scale = font->y_scale; /* XXX */ | |
235 data->userData = font; | |
236 | |
237 return data; | |
238 } | |
239 | |
240 void | |
241 _hb_old_shaper_font_data_destroy (hb_old_shaper_font_data_t *data) | |
242 { | |
243 free (data); | |
244 } | |
245 | |
246 | |
247 /* | |
248 * shaper shape_plan data | |
249 */ | |
250 | |
251 struct hb_old_shaper_shape_plan_data_t {}; | |
252 | |
253 hb_old_shaper_shape_plan_data_t * | |
254 _hb_old_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED, | |
255 const hb_feature_t *user_features HB_UNUS
ED, | |
256 unsigned int num_user_features HB_
UNUSED) | |
257 { | |
258 return (hb_old_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED; | |
259 } | |
260 | |
261 void | |
262 _hb_old_shaper_shape_plan_data_destroy (hb_old_shaper_shape_plan_data_t *data HB
_UNUSED) | |
263 { | |
264 } | |
265 | |
266 | |
267 /* | |
268 * shaper | |
269 */ | |
270 | |
271 hb_bool_t | |
272 _hb_old_shape (hb_shape_plan_t *shape_plan HB_UNUSED, | |
273 hb_font_t *font, | |
274 hb_buffer_t *buffer, | |
275 const hb_feature_t *features, | |
276 unsigned int num_features) | |
277 { | |
278 hb_face_t *face = font->face; | |
279 HB_Face old_face = HB_SHAPER_DATA_GET (face); | |
280 HB_Font old_font = HB_SHAPER_DATA_GET (font); | |
281 | |
282 bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); | |
283 | |
284 retry: | |
285 | |
286 unsigned int scratch_size; | |
287 char *scratch = (char *) buffer->get_scratch_buffer (&scratch_size); | |
288 | |
289 #define utf16_index() var1.u32 | |
290 HB_UChar16 *pchars = (HB_UChar16 *) scratch; | |
291 unsigned int chars_len = 0; | |
292 for (unsigned int i = 0; i < buffer->len; i++) { | |
293 hb_codepoint_t c = buffer->info[i].codepoint; | |
294 buffer->info[i].utf16_index() = chars_len; | |
295 if (likely (c < 0x10000)) | |
296 pchars[chars_len++] = c; | |
297 else if (unlikely (c >= 0x110000)) | |
298 pchars[chars_len++] = 0xFFFD; | |
299 else { | |
300 pchars[chars_len++] = 0xD800 + ((c - 0x10000) >> 10); | |
301 pchars[chars_len++] = 0xDC00 + ((c - 0x10000) & ((1 << 10) - 1)); | |
302 } | |
303 } | |
304 | |
305 | |
306 #define ALLOCATE_ARRAY(Type, name, len) \ | |
307 name = (Type *) scratch; \ | |
308 scratch += (len) * sizeof ((name)[0]); \ | |
309 scratch_size -= (len) * sizeof ((name)[0]); | |
310 | |
311 | |
312 HB_ShaperItem item = {0}; | |
313 | |
314 ALLOCATE_ARRAY (const HB_UChar16, item.string, chars_len); | |
315 ALLOCATE_ARRAY (unsigned short, item.log_clusters, chars_len + 2); | |
316 item.stringLength = chars_len; | |
317 item.item.pos = 0; | |
318 item.item.length = item.stringLength; | |
319 item.item.script = hb_old_script_from_script (buffer->props.script); | |
320 item.item.bidiLevel = backward ? 1 : 0; | |
321 | |
322 item.font = old_font; | |
323 item.face = old_face; | |
324 item.shaperFlags = 0; | |
325 | |
326 item.glyphIndicesPresent = false; | |
327 | |
328 /* TODO Alignment. */ | |
329 unsigned int num_glyphs = scratch_size / (sizeof (HB_Glyph) + | |
330 sizeof (HB_GlyphAttributes) + | |
331 sizeof (HB_Fixed) + | |
332 sizeof (HB_FixedPoint) + | |
333 sizeof (uint32_t)); | |
334 | |
335 item.num_glyphs = num_glyphs; | |
336 ALLOCATE_ARRAY (HB_Glyph, item.glyphs, num_glyphs); | |
337 ALLOCATE_ARRAY (HB_GlyphAttributes, item.attributes, num_glyphs); | |
338 ALLOCATE_ARRAY (HB_Fixed, item.advances, num_glyphs); | |
339 ALLOCATE_ARRAY (HB_FixedPoint, item.offsets, num_glyphs); | |
340 /* Apparently in some cases the offsets array will not be fully assigned to. | |
341 * Clear it. */ | |
342 memset (item.offsets, 0, num_glyphs * sizeof (item.offsets[0])); | |
343 uint32_t *vis_clusters; | |
344 ALLOCATE_ARRAY (uint32_t, vis_clusters, num_glyphs); | |
345 | |
346 #undef ALLOCATE_ARRAY | |
347 | |
348 if (!HB_ShapeItem (&item)) | |
349 { | |
350 if (unlikely (item.num_glyphs > num_glyphs)) | |
351 { | |
352 buffer->ensure (buffer->allocated * 2); | |
353 if (buffer->in_error) | |
354 return false; | |
355 goto retry; | |
356 } | |
357 return false; | |
358 } | |
359 num_glyphs = item.num_glyphs; | |
360 | |
361 /* Ok, we've got everything we need, now compose output buffer, | |
362 * very, *very*, carefully! */ | |
363 | |
364 /* Calculate visual-clusters. That's what we ship. */ | |
365 for (unsigned int i = 0; i < num_glyphs; i++) | |
366 vis_clusters[i] = -1; | |
367 for (unsigned int i = 0; i < buffer->len; i++) { | |
368 uint32_t *p = &vis_clusters[item.log_clusters[buffer->info[i].utf16_index()]
]; | |
369 *p = MIN (*p, buffer->info[i].cluster); | |
370 } | |
371 for (unsigned int i = 1; i < num_glyphs; i++) | |
372 if (vis_clusters[i] == (uint32_t) -1) | |
373 vis_clusters[i] = vis_clusters[i - 1]; | |
374 | |
375 #undef utf16_index | |
376 | |
377 buffer->ensure (num_glyphs); | |
378 if (buffer->in_error) | |
379 return false; | |
380 | |
381 | |
382 buffer->len = num_glyphs; | |
383 hb_glyph_info_t *info = buffer->info; | |
384 for (unsigned int i = 0; i < num_glyphs; i++) | |
385 { | |
386 info[i].codepoint = item.glyphs[i]; | |
387 info[i].cluster = vis_clusters[i]; | |
388 | |
389 info[i].mask = item.advances[i]; | |
390 info[i].var1.u32 = item.offsets[i].x; | |
391 info[i].var2.u32 = item.offsets[i].y; | |
392 } | |
393 | |
394 buffer->clear_positions (); | |
395 | |
396 for (unsigned int i = 0; i < num_glyphs; ++i) { | |
397 hb_glyph_info_t *info = &buffer->info[i]; | |
398 hb_glyph_position_t *pos = &buffer->pos[i]; | |
399 | |
400 /* TODO vertical */ | |
401 pos->x_advance = info->mask; | |
402 pos->x_offset = info->var1.u32; | |
403 pos->y_offset = info->var2.u32; | |
404 } | |
405 | |
406 if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction)) | |
407 buffer->reverse (); | |
408 | |
409 return true; | |
410 } | |
OLD | NEW |