hb-uniscribe.cc revision 02aeca985b570763342c35e99af90025bfa088d5
1/* 2 * Copyright © 2011 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 0x0500 28 29#include "hb-private.hh" 30 31#include "hb-uniscribe.h" 32 33#include "hb-ot-tag.h" 34 35#include "hb-font-private.hh" 36 37#include "hb-buffer-private.hh" 38 39#include <windows.h> 40#include <usp10.h> 41 42 43 44#ifndef HB_DEBUG_UNISCRIBE 45#define HB_DEBUG_UNISCRIBE (HB_DEBUG+0) 46#endif 47 48 49/* 50DWORD GetFontData( 51 __in HDC hdc, 52 __in DWORD dwTable, 53 __in DWORD dwOffset, 54 __out LPVOID lpvBuffer, 55 __in DWORD cbData 56); 57*/ 58 59static void 60populate_log_font (LOGFONTW *lf, 61 HDC hdc, 62 hb_font_t *font, 63 hb_blob_t *blob) 64{ 65 memset (lf, 0, sizeof (*lf)); 66 int dpi = GetDeviceCaps (hdc, LOGPIXELSY); 67 lf->lfHeight = MulDiv (font->x_scale, dpi, 72); 68 69 WCHAR family_name[] = {'n','a','z','l','i'}; 70 for (unsigned int i = 0; family_name[i] && i < LF_FACESIZE - 1; i++) 71 lf->lfFaceName[i] = family_name[i]; 72} 73 74hb_bool_t 75hb_uniscribe_shape (hb_font_t *font, 76 hb_buffer_t *buffer, 77 const hb_feature_t *features, 78 unsigned int num_features, 79 const char *shaper_options) 80{ 81 buffer->guess_properties (); 82 83 HRESULT hr; 84 85 if (unlikely (!buffer->len)) 86 return TRUE; 87 88retry: 89 90 unsigned int scratch_size; 91 char *scratch = (char *) buffer->get_scratch_buffer (&scratch_size); 92 93 /* Allocate char buffers; they all fit */ 94 95#define ALLOCATE_ARRAY(Type, name, len) \ 96 Type *name = (Type *) scratch; \ 97 scratch += len * sizeof (name[0]); \ 98 scratch_size -= len * sizeof (name[0]); 99 100#define utf16_index() var1.u32 101 102 WCHAR *pchars = (WCHAR *) scratch; 103 unsigned int chars_len = 0; 104 for (unsigned int i = 0; i < buffer->len; i++) { 105 hb_codepoint_t c = buffer->info[i].codepoint; 106 buffer->info[i].utf16_index() = chars_len; 107 if (likely (c < 0x10000)) 108 pchars[chars_len++] = c; 109 else if (unlikely (c >= 0x110000)) 110 pchars[chars_len++] = 0xFFFD; 111 else { 112 pchars[chars_len++] = 0xD800 + ((c - 0x10000) >> 10); 113 pchars[chars_len++] = 0xDC00 + ((c - 0x10000) & ((1 << 10) - 1)); 114 } 115 } 116 117 ALLOCATE_ARRAY (WCHAR, wchars, chars_len); 118 ALLOCATE_ARRAY (WORD, log_clusters, chars_len); 119 ALLOCATE_ARRAY (SCRIPT_CHARPROP, char_props, chars_len); 120 121 /* On Windows, we don't care about alignment...*/ 122 unsigned int glyphs_size = scratch_size / (sizeof (WORD) + 123 sizeof (SCRIPT_GLYPHPROP) + 124 sizeof (int) + 125 sizeof (GOFFSET) + 126 sizeof (uint32_t)); 127 128 ALLOCATE_ARRAY (WORD, glyphs, glyphs_size); 129 ALLOCATE_ARRAY (SCRIPT_GLYPHPROP, glyph_props, glyphs_size); 130 ALLOCATE_ARRAY (int, advances, glyphs_size); 131 ALLOCATE_ARRAY (GOFFSET, offsets, glyphs_size); 132 ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size); 133 134 135#define FAIL(...) \ 136 HB_STMT_START { \ 137 DEBUG_MSG (UNISCRIBE, NULL, __VA_ARGS__); \ 138 return FALSE; \ 139 } HB_STMT_END; 140 141 142#define MAX_ITEMS 10 143 144 SCRIPT_ITEM items[MAX_ITEMS + 1]; 145 SCRIPT_STATE bidi_state = {0}; 146 ULONG script_tags[MAX_ITEMS]; 147 int item_count; 148 149 bidi_state.uBidiLevel = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1; 150 bidi_state.fOverrideDirection = 1; 151 152 hr = ScriptItemizeOpenType (wchars, 153 chars_len, 154 MAX_ITEMS, 155 NULL, 156 &bidi_state, 157 items, 158 script_tags, 159 &item_count); 160 if (unlikely (FAILED (hr))) 161 FAIL ("ScriptItemizeOpenType() failed: %d", hr); 162 163#undef MAX_ITEMS 164 165 int *range_char_counts = NULL; 166 TEXTRANGE_PROPERTIES **range_properties = NULL; 167 int range_count = 0; 168 if (num_features) { 169 /* XXX setup ranges */ 170 } 171 172 hb_blob_t *blob = hb_face_get_blob (font->face); 173 unsigned int blob_length; 174 const char *blob_data = hb_blob_get_data (blob, &blob_length); 175 if (unlikely (!blob_length)) 176 FAIL ("Empty font blob"); 177 178 DWORD num_fonts_installed; 179 HANDLE fh = AddFontMemResourceEx ((void *) blob_data, blob_length, 0, &num_fonts_installed); 180 if (unlikely (!fh)) 181 FAIL ("AddFontMemResourceEx() failed"); 182 183 /* FREE stuff, specially when taking fallback... */ 184 185 HDC hdc = GetDC (NULL); /* XXX The DC should be cached on the face I guess? */ 186 187 LOGFONTW log_font; 188 populate_log_font (&log_font, hdc, font, blob); 189 190 HFONT hfont = CreateFontIndirectW (&log_font); 191 SelectObject (hdc, hfont); 192 193 SCRIPT_CACHE script_cache = NULL; 194 OPENTYPE_TAG language_tag = hb_ot_tag_from_language (buffer->props.language); 195 196 unsigned int glyphs_offset = 0; 197 unsigned int glyphs_len; 198 for (unsigned int i = 0; i < item_count; i++) 199 { 200 unsigned int chars_offset = items[i].iCharPos; 201 unsigned int item_chars_len = items[i + 1].iCharPos - chars_offset; 202 OPENTYPE_TAG script_tag = script_tags[i]; /* XXX buffer->props.script */ 203 204 hr = ScriptShapeOpenType (hdc, 205 &script_cache, 206 &items[i].a, 207 script_tag, 208 language_tag, 209 range_char_counts, 210 range_properties, 211 range_count, 212 wchars + chars_offset, 213 item_chars_len, 214 glyphs_size - glyphs_offset, 215 /* out */ 216 log_clusters + chars_offset, 217 char_props + chars_offset, 218 glyphs + glyphs_offset, 219 glyph_props + glyphs_offset, 220 (int *) &glyphs_len); 221 222 if (unlikely (items[i].a.fNoGlyphIndex)) 223 FAIL ("ScriptShapeOpenType() set fNoGlyphIndex"); 224 if (unlikely (hr == E_OUTOFMEMORY)) 225 { 226 buffer->ensure (buffer->allocated * 2); 227 if (buffer->in_error) 228 FAIL ("Buffer resize failed"); 229 goto retry; 230 } 231 if (unlikely (FAILED (hr))) 232 FAIL ("ScriptShapeOpenType() failed: %d", hr); 233 234 hr = ScriptPlaceOpenType (hdc, 235 &script_cache, 236 &items[i].a, 237 script_tag, 238 language_tag, 239 range_char_counts, 240 range_properties, 241 range_count, 242 wchars + chars_offset, 243 log_clusters + chars_offset, 244 char_props + chars_offset, 245 item_chars_len, 246 glyphs + glyphs_offset, 247 glyph_props + glyphs_offset, 248 glyphs_len, 249 /* out */ 250 advances + glyphs_offset, 251 offsets + glyphs_offset, 252 NULL); 253 if (unlikely (FAILED (hr))) 254 FAIL ("ScriptPlaceOpenType() failed: %d", hr); 255 256 glyphs_offset += glyphs_len; 257 } 258 glyphs_len = glyphs_offset; 259 260 ReleaseDC (NULL, hdc); 261 DeleteObject (hfont); 262 RemoveFontMemResourceEx (fh); 263 264 /* Ok, we've got everything we need, now compose output buffer, 265 * very, *very*, carefully! */ 266 267 /* Calculate visual-clusters. That's what we ship. */ 268 for (unsigned int i = 0; i < buffer->len; i++) 269 vis_clusters[log_clusters[buffer->info[i].utf16_index()]] = buffer->info[i].cluster; 270 for (unsigned int i = 1; i < glyphs_len; i++) 271 if (!glyph_props[i].sva.fClusterStart) 272 vis_clusters[i] = vis_clusters[i - 1]; 273 274#undef utf16_index 275 276 buffer->ensure (glyphs_len); 277 if (buffer->in_error) 278 FAIL ("Buffer in error"); 279 280#undef FAIL 281 282 /* Set glyph infos */ 283 for (unsigned int i = 0; i < glyphs_len; i++) 284 { 285 hb_glyph_info_t *info = &buffer->info[i]; 286 287 info->codepoint = glyphs[i]; 288 info->cluster = vis_clusters[i]; 289 290 /* The rest is crap. Let's store position info there for now. */ 291 info->mask = advances[i]; 292 info->var1.u32 = offsets[i].du; 293 info->var2.u32 = offsets[i].dv; 294 } 295 296 /* Set glyph positions */ 297 buffer->clear_positions (); 298 for (unsigned int i = 0; i < glyphs_len; i++) 299 { 300 hb_glyph_info_t *info = &buffer->info[i]; 301 hb_glyph_position_t *pos = &buffer->pos[i]; 302 303 /* TODO vertical */ 304 pos->x_advance = info->mask; 305 pos->x_offset = info->var1.u32; 306 pos->y_offset = info->var2.u32; 307 } 308 309 /* Wow, done! */ 310 return TRUE; 311} 312 313 314