2f01c28778f89da66fc2c76c9fa6a80c9203ebe9
[platform/upstream/harfbuzz.git] / src / hb-uniscribe.cc
1 /*
2  * Copyright © 2011,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 _WIN32_WINNT 0x0600
28 #define WIN32_LEAN_AND_MEAN
29
30 #define HB_SHAPER uniscribe
31 #include "hb-shaper-impl-private.hh"
32
33 #include <windows.h>
34 #include <usp10.h>
35
36 #include "hb-uniscribe.h"
37
38 #include "hb-ot-name-table.hh"
39 #include "hb-ot-tag.h"
40
41
42 #ifndef HB_DEBUG_UNISCRIBE
43 #define HB_DEBUG_UNISCRIBE (HB_DEBUG+0)
44 #endif
45
46
47 /*
48 DWORD GetFontData(
49   __in   HDC hdc,
50   __in   DWORD dwTable,
51   __in   DWORD dwOffset,
52   __out  LPVOID lpvBuffer,
53   __in   DWORD cbData
54 );
55 */
56
57
58 HB_SHAPER_DATA_ENSURE_DECLARE(uniscribe, face)
59 HB_SHAPER_DATA_ENSURE_DECLARE(uniscribe, font)
60
61
62 /*
63  * shaper face data
64  */
65
66 struct hb_uniscribe_shaper_face_data_t {
67   HANDLE fh;
68 };
69
70 hb_uniscribe_shaper_face_data_t *
71 _hb_uniscribe_shaper_face_data_create (hb_face_t *face)
72 {
73   hb_uniscribe_shaper_face_data_t *data = (hb_uniscribe_shaper_face_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_face_data_t));
74   if (unlikely (!data))
75     return NULL;
76
77   hb_blob_t *blob = hb_face_reference_blob (face);
78   unsigned int blob_length;
79   const char *blob_data = hb_blob_get_data (blob, &blob_length);
80   if (unlikely (!blob_length))
81     DEBUG_MSG (UNISCRIBE, face, "Face has empty blob");
82
83   DWORD num_fonts_installed;
84   data->fh = AddFontMemResourceEx ((void *) blob_data, blob_length, 0, &num_fonts_installed);
85   hb_blob_destroy (blob);
86   if (unlikely (!data->fh)) {
87     DEBUG_MSG (UNISCRIBE, face, "Face AddFontMemResourceEx() failed");
88     free (data);
89     return NULL;
90   }
91
92   return data;
93 }
94
95 void
96 _hb_uniscribe_shaper_face_data_destroy (hb_uniscribe_shaper_face_data_t *data)
97 {
98   RemoveFontMemResourceEx (data->fh);
99   free (data);
100 }
101
102
103 /*
104  * shaper font data
105  */
106
107 struct hb_uniscribe_shaper_font_data_t {
108   HDC hdc;
109   LOGFONTW log_font;
110   HFONT hfont;
111   SCRIPT_CACHE script_cache;
112 };
113
114 static bool
115 populate_log_font (LOGFONTW  *lf,
116                    hb_font_t *font)
117 {
118   memset (lf, 0, sizeof (*lf));
119   lf->lfHeight = -font->y_scale;
120   lf->lfCharSet = DEFAULT_CHARSET;
121
122   hb_blob_t *blob = OT::Sanitizer<OT::name>::sanitize (hb_face_reference_table (font->face, HB_TAG ('n','a','m','e')));
123   const OT::name *name_table = OT::Sanitizer<OT::name>::lock_instance (blob);
124   unsigned int len = name_table->get_name (3, 1, 0x409, 4,
125                                            lf->lfFaceName,
126                                            sizeof (lf->lfFaceName[0]) * LF_FACESIZE)
127                                           / sizeof (lf->lfFaceName[0]);
128   hb_blob_destroy (blob);
129
130   if (unlikely (!len)) {
131     DEBUG_MSG (UNISCRIBE, NULL, "Didn't find English name table entry");
132     return false;
133   }
134   if (unlikely (len >= LF_FACESIZE)) {
135     DEBUG_MSG (UNISCRIBE, NULL, "Font name too long");
136     return false;
137   }
138
139   for (unsigned int i = 0; i < len; i++)
140     lf->lfFaceName[i] = hb_be_uint16 (lf->lfFaceName[i]);
141   lf->lfFaceName[len] = 0;
142
143   return true;
144 }
145
146 hb_uniscribe_shaper_font_data_t *
147 _hb_uniscribe_shaper_font_data_create (hb_font_t *font)
148 {
149   if (unlikely (!hb_uniscribe_shaper_face_data_ensure (font->face))) return NULL;
150
151   hb_uniscribe_shaper_font_data_t *data = (hb_uniscribe_shaper_font_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_font_data_t));
152   if (unlikely (!data))
153     return NULL;
154
155   data->hdc = GetDC (NULL);
156
157   if (unlikely (!populate_log_font (&data->log_font, font))) {
158     DEBUG_MSG (UNISCRIBE, font, "Font populate_log_font() failed");
159     _hb_uniscribe_shaper_font_data_destroy (data);
160     return NULL;
161   }
162
163   data->hfont = CreateFontIndirectW (&data->log_font);
164   if (unlikely (!data->hfont)) {
165     DEBUG_MSG (UNISCRIBE, font, "Font CreateFontIndirectW() failed");
166     _hb_uniscribe_shaper_font_data_destroy (data);
167      return NULL;
168   }
169
170   if (!SelectObject (data->hdc, data->hfont)) {
171     DEBUG_MSG (UNISCRIBE, font, "Font SelectObject() failed");
172     _hb_uniscribe_shaper_font_data_destroy (data);
173      return NULL;
174   }
175
176   return data;
177 }
178
179 void
180 _hb_uniscribe_shaper_font_data_destroy (hb_uniscribe_shaper_font_data_t *data)
181 {
182   if (data->hdc)
183     ReleaseDC (NULL, data->hdc);
184   if (data->hfont)
185     DeleteObject (data->hfont);
186   if (data->script_cache)
187     ScriptFreeCache (&data->script_cache);
188   free (data);
189 }
190
191 LOGFONTW *
192 hb_uniscribe_font_get_logfontw (hb_font_t *font)
193 {
194   if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return NULL;
195   hb_uniscribe_shaper_font_data_t *font_data =  HB_SHAPER_DATA_GET (font);
196   return &font_data->log_font;
197 }
198
199 HFONT
200 hb_uniscribe_font_get_hfont (hb_font_t *font)
201 {
202   if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return NULL;
203   hb_uniscribe_shaper_font_data_t *font_data =  HB_SHAPER_DATA_GET (font);
204   return font_data->hfont;
205 }
206
207
208 /*
209  * shaper shape_plan data
210  */
211
212 struct hb_uniscribe_shaper_shape_plan_data_t {};
213
214 hb_uniscribe_shaper_shape_plan_data_t *
215 _hb_uniscribe_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
216                                              const hb_feature_t *user_features HB_UNUSED,
217                                              unsigned int        num_user_features HB_UNUSED)
218 {
219   return (hb_uniscribe_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
220 }
221
222 void
223 _hb_uniscribe_shaper_shape_plan_data_destroy (hb_uniscribe_shaper_shape_plan_data_t *data HB_UNUSED)
224 {
225 }
226
227
228 /*
229  * shaper
230  */
231
232
233 hb_bool_t
234 _hb_uniscribe_shape (hb_shape_plan_t    *shape_plan,
235                      hb_font_t          *font,
236                      hb_buffer_t        *buffer,
237                      const hb_feature_t *features,
238                      unsigned int        num_features)
239 {
240   hb_face_t *face = font->face;
241   hb_uniscribe_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
242   hb_uniscribe_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
243
244 #define FAIL(...) \
245   HB_STMT_START { \
246     DEBUG_MSG (UNISCRIBE, NULL, __VA_ARGS__); \
247     return false; \
248   } HB_STMT_END;
249
250   HRESULT hr;
251
252 retry:
253
254   unsigned int scratch_size;
255   char *scratch = (char *) buffer->get_scratch_buffer (&scratch_size);
256
257   /* Allocate char buffers; they all fit */
258
259 #define ALLOCATE_ARRAY(Type, name, len) \
260   Type *name = (Type *) scratch; \
261   scratch += (len) * sizeof ((name)[0]); \
262   scratch_size -= (len) * sizeof ((name)[0]);
263
264 #define utf16_index() var1.u32
265
266   WCHAR *pchars = (WCHAR *) scratch;
267   unsigned int chars_len = 0;
268   for (unsigned int i = 0; i < buffer->len; i++) {
269     hb_codepoint_t c = buffer->info[i].codepoint;
270     buffer->info[i].utf16_index() = chars_len;
271     if (likely (c < 0x10000))
272       pchars[chars_len++] = c;
273     else if (unlikely (c >= 0x110000))
274       pchars[chars_len++] = 0xFFFD;
275     else {
276       pchars[chars_len++] = 0xD800 + ((c - 0x10000) >> 10);
277       pchars[chars_len++] = 0xDC00 + ((c - 0x10000) & ((1 << 10) - 1));
278     }
279   }
280
281   ALLOCATE_ARRAY (WCHAR, wchars, chars_len);
282   ALLOCATE_ARRAY (WORD, log_clusters, chars_len);
283   ALLOCATE_ARRAY (SCRIPT_CHARPROP, char_props, chars_len);
284
285   /* On Windows, we don't care about alignment...*/
286   unsigned int glyphs_size = scratch_size / (sizeof (WORD) +
287                                              sizeof (SCRIPT_GLYPHPROP) +
288                                              sizeof (int) +
289                                              sizeof (GOFFSET) +
290                                              sizeof (uint32_t));
291
292   ALLOCATE_ARRAY (WORD, glyphs, glyphs_size);
293   ALLOCATE_ARRAY (SCRIPT_GLYPHPROP, glyph_props, glyphs_size);
294   ALLOCATE_ARRAY (int, advances, glyphs_size);
295   ALLOCATE_ARRAY (GOFFSET, offsets, glyphs_size);
296   ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size);
297
298 #undef ALLOCATE_ARRAY
299
300 #define MAX_ITEMS 256
301
302   SCRIPT_ITEM items[MAX_ITEMS + 1];
303   SCRIPT_CONTROL bidi_control = {0};
304   SCRIPT_STATE bidi_state = {0};
305   ULONG script_tags[MAX_ITEMS];
306   int item_count;
307
308   /* MinGW32 doesn't define fMergeNeutralItems, so we bruteforce */
309   //bidi_control.fMergeNeutralItems = true;
310   *(uint32_t*)&bidi_control |= 1<<24;
311
312   bidi_state.uBidiLevel = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
313   bidi_state.fOverrideDirection = 1;
314
315   hr = ScriptItemizeOpenType (wchars,
316                               chars_len,
317                               MAX_ITEMS,
318                               &bidi_control,
319                               &bidi_state,
320                               items,
321                               script_tags,
322                               &item_count);
323   if (unlikely (FAILED (hr)))
324     FAIL ("ScriptItemizeOpenType() failed: 0x%08xL", hr);
325
326 #undef MAX_ITEMS
327
328   int *range_char_counts = NULL;
329   TEXTRANGE_PROPERTIES **range_properties = NULL;
330   int range_count = 0;
331   if (num_features) {
332     /* TODO setup ranges */
333   }
334
335   OPENTYPE_TAG language_tag = hb_uint32_swap (hb_ot_tag_from_language (buffer->props.language));
336
337   unsigned int glyphs_offset = 0;
338   unsigned int glyphs_len;
339   bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
340   for (unsigned int j = 0; j < item_count; j++)
341   {
342     unsigned int i = backward ? item_count - 1 - j : j;
343     unsigned int chars_offset = items[i].iCharPos;
344     unsigned int item_chars_len = items[i + 1].iCharPos - chars_offset;
345
346   retry_shape:
347     hr = ScriptShapeOpenType (font_data->hdc,
348                               &font_data->script_cache,
349                               &items[i].a,
350                               script_tags[i],
351                               language_tag,
352                               range_char_counts,
353                               range_properties,
354                               range_count,
355                               wchars + chars_offset,
356                               item_chars_len,
357                               glyphs_size - glyphs_offset,
358                               /* out */
359                               log_clusters + chars_offset,
360                               char_props + chars_offset,
361                               glyphs + glyphs_offset,
362                               glyph_props + glyphs_offset,
363                               (int *) &glyphs_len);
364
365     if (unlikely (items[i].a.fNoGlyphIndex))
366       FAIL ("ScriptShapeOpenType() set fNoGlyphIndex");
367     if (unlikely (hr == E_OUTOFMEMORY))
368     {
369       buffer->ensure (buffer->allocated * 2);
370       if (buffer->in_error)
371         FAIL ("Buffer resize failed");
372       goto retry;
373     }
374     if (unlikely (hr == USP_E_SCRIPT_NOT_IN_FONT))
375     {
376       if (items[i].a.eScript == SCRIPT_UNDEFINED)
377         FAIL ("ScriptShapeOpenType() failed: Font doesn't support script");
378       items[i].a.eScript = SCRIPT_UNDEFINED;
379       goto retry_shape;
380     }
381     if (unlikely (FAILED (hr)))
382     {
383       FAIL ("ScriptShapeOpenType() failed: 0x%08xL", hr);
384     }
385
386     for (unsigned int j = chars_offset; j < chars_offset + item_chars_len; j++)
387       log_clusters[j] += glyphs_offset;
388
389     hr = ScriptPlaceOpenType (font_data->hdc,
390                               &font_data->script_cache,
391                               &items[i].a,
392                               script_tags[i],
393                               language_tag,
394                               range_char_counts,
395                               range_properties,
396                               range_count,
397                               wchars + chars_offset,
398                               log_clusters + chars_offset,
399                               char_props + chars_offset,
400                               item_chars_len,
401                               glyphs + glyphs_offset,
402                               glyph_props + glyphs_offset,
403                               glyphs_len,
404                               /* out */
405                               advances + glyphs_offset,
406                               offsets + glyphs_offset,
407                               NULL);
408     if (unlikely (FAILED (hr)))
409       FAIL ("ScriptPlaceOpenType() failed: 0x%08xL", hr);
410
411     glyphs_offset += glyphs_len;
412   }
413   glyphs_len = glyphs_offset;
414
415   /* Ok, we've got everything we need, now compose output buffer,
416    * very, *very*, carefully! */
417
418   /* Calculate visual-clusters.  That's what we ship. */
419   for (unsigned int i = 0; i < glyphs_len; i++)
420     vis_clusters[i] = -1;
421   for (unsigned int i = 0; i < buffer->len; i++) {
422     uint32_t *p = &vis_clusters[log_clusters[buffer->info[i].utf16_index()]];
423     *p = MIN (*p, buffer->info[i].cluster);
424   }
425   if (!backward) {
426     for (unsigned int i = 1; i < glyphs_len; i++)
427       if (vis_clusters[i] == -1)
428         vis_clusters[i] = vis_clusters[i - 1];
429   } else {
430     for (int i = glyphs_len - 2; i >= 0; i--)
431       if (vis_clusters[i] == -1)
432         vis_clusters[i] = vis_clusters[i + 1];
433   }
434
435 #undef utf16_index
436
437   buffer->ensure (glyphs_len);
438   if (buffer->in_error)
439     FAIL ("Buffer in error");
440
441 #undef FAIL
442
443   /* Set glyph infos */
444   buffer->len = 0;
445   for (unsigned int i = 0; i < glyphs_len; i++)
446   {
447     hb_glyph_info_t *info = &buffer->info[buffer->len++];
448
449     info->codepoint = glyphs[i];
450     info->cluster = vis_clusters[i];
451
452     /* The rest is crap.  Let's store position info there for now. */
453     info->mask = advances[i];
454     info->var1.u32 = offsets[i].du;
455     info->var2.u32 = offsets[i].dv;
456   }
457
458   /* Set glyph positions */
459   buffer->clear_positions ();
460   for (unsigned int i = 0; i < glyphs_len; i++)
461   {
462     hb_glyph_info_t *info = &buffer->info[i];
463     hb_glyph_position_t *pos = &buffer->pos[i];
464
465     /* TODO vertical */
466     pos->x_advance = info->mask;
467     pos->x_offset = info->var1.u32;
468     pos->y_offset = info->var2.u32;
469   }
470
471   /* Wow, done! */
472   return true;
473 }
474
475