[COMCTL32] Pt.rc: Place accelerator FIXMEs
[reactos.git] / dll / directx / wine / d3dx9_36 / font.c
1 #ifdef __REACTOS__
2 #include "precomp.h"
3 #else
4 /*
5 * Copyright (C) 2008 Tony Wasserka
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 *
21 */
22
23
24 #include "d3dx9_private.h"
25
26 #include "usp10.h"
27 #endif /* __REACTOS__ */
28
29 WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
30
31 struct d3dx_glyph
32 {
33 unsigned int id;
34 RECT black_box;
35 POINT cell_inc;
36 IDirect3DTexture9 *texture;
37
38 struct wine_rb_entry entry;
39 };
40
41 struct d3dx_font
42 {
43 ID3DXFont ID3DXFont_iface;
44 LONG ref;
45
46 IDirect3DDevice9 *device;
47 D3DXFONT_DESCW desc;
48 TEXTMETRICW metrics;
49
50 HDC hdc;
51 HFONT hfont;
52
53 struct wine_rb_tree glyph_tree;
54
55 IDirect3DTexture9 **textures;
56 unsigned int texture_count, texture_pos;
57
58 unsigned int texture_size, glyph_size, glyphs_per_texture;
59 };
60
61 static int glyph_rb_compare(const void *key, const struct wine_rb_entry *entry)
62 {
63 struct d3dx_glyph *glyph = WINE_RB_ENTRY_VALUE(entry, struct d3dx_glyph, entry);
64 unsigned int id = (UINT_PTR)key;
65
66 return id - glyph->id;
67 }
68
69 static void glyph_rb_free(struct wine_rb_entry *entry, void *context)
70 {
71 struct d3dx_glyph *glyph = WINE_RB_ENTRY_VALUE(entry, struct d3dx_glyph, entry);
72
73 heap_free(glyph);
74 }
75
76 static inline struct d3dx_font *impl_from_ID3DXFont(ID3DXFont *iface)
77 {
78 return CONTAINING_RECORD(iface, struct d3dx_font, ID3DXFont_iface);
79 }
80
81 static HRESULT WINAPI ID3DXFontImpl_QueryInterface(ID3DXFont *iface, REFIID riid, void **out)
82 {
83 TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
84
85 if (IsEqualGUID(riid, &IID_ID3DXFont)
86 || IsEqualGUID(riid, &IID_IUnknown))
87 {
88 IUnknown_AddRef(iface);
89 *out = iface;
90 return S_OK;
91 }
92
93 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
94
95 *out = NULL;
96 return E_NOINTERFACE;
97 }
98
99 static ULONG WINAPI ID3DXFontImpl_AddRef(ID3DXFont *iface)
100 {
101 struct d3dx_font *font = impl_from_ID3DXFont(iface);
102 ULONG ref = InterlockedIncrement(&font->ref);
103
104 TRACE("%p increasing refcount to %u\n", iface, ref);
105 return ref;
106 }
107
108 static ULONG WINAPI ID3DXFontImpl_Release(ID3DXFont *iface)
109 {
110 struct d3dx_font *font = impl_from_ID3DXFont(iface);
111 ULONG ref = InterlockedDecrement(&font->ref);
112 unsigned int i;
113
114 TRACE("%p decreasing refcount to %u\n", iface, ref);
115
116 if (!ref)
117 {
118 for (i = 0; i < font->texture_count; ++i)
119 IDirect3DTexture9_Release(font->textures[i]);
120
121 heap_free(font->textures);
122
123 wine_rb_destroy(&font->glyph_tree, glyph_rb_free, NULL);
124
125 DeleteObject(font->hfont);
126 DeleteDC(font->hdc);
127 IDirect3DDevice9_Release(font->device);
128 heap_free(font);
129 }
130 return ref;
131 }
132
133 static HRESULT WINAPI ID3DXFontImpl_GetDevice(ID3DXFont *iface, IDirect3DDevice9 **device)
134 {
135 struct d3dx_font *font = impl_from_ID3DXFont(iface);
136
137 TRACE("iface %p, device %p\n", iface, device);
138
139 if( !device ) return D3DERR_INVALIDCALL;
140 *device = font->device;
141 IDirect3DDevice9_AddRef(font->device);
142
143 return D3D_OK;
144 }
145
146 static HRESULT WINAPI ID3DXFontImpl_GetDescA(ID3DXFont *iface, D3DXFONT_DESCA *desc)
147 {
148 struct d3dx_font *font = impl_from_ID3DXFont(iface);
149
150 TRACE("iface %p, desc %p\n", iface, desc);
151
152 if( !desc ) return D3DERR_INVALIDCALL;
153 memcpy(desc, &font->desc, FIELD_OFFSET(D3DXFONT_DESCA, FaceName));
154 WideCharToMultiByte(CP_ACP, 0, font->desc.FaceName, -1, desc->FaceName, ARRAY_SIZE(desc->FaceName), NULL, NULL);
155
156 return D3D_OK;
157 }
158
159 static HRESULT WINAPI ID3DXFontImpl_GetDescW(ID3DXFont *iface, D3DXFONT_DESCW *desc)
160 {
161 struct d3dx_font *font = impl_from_ID3DXFont(iface);
162
163 TRACE("iface %p, desc %p\n", iface, desc);
164
165 if( !desc ) return D3DERR_INVALIDCALL;
166 *desc = font->desc;
167
168 return D3D_OK;
169 }
170
171 static BOOL WINAPI ID3DXFontImpl_GetTextMetricsA(ID3DXFont *iface, TEXTMETRICA *metrics)
172 {
173 struct d3dx_font *font = impl_from_ID3DXFont(iface);
174 TRACE("iface %p, metrics %p\n", iface, metrics);
175 return GetTextMetricsA(font->hdc, metrics);
176 }
177
178 static BOOL WINAPI ID3DXFontImpl_GetTextMetricsW(ID3DXFont *iface, TEXTMETRICW *metrics)
179 {
180 struct d3dx_font *font = impl_from_ID3DXFont(iface);
181 TRACE("iface %p, metrics %p\n", iface, metrics);
182 return GetTextMetricsW(font->hdc, metrics);
183 }
184
185 static HDC WINAPI ID3DXFontImpl_GetDC(ID3DXFont *iface)
186 {
187 struct d3dx_font *font = impl_from_ID3DXFont(iface);
188 TRACE("iface %p\n", iface);
189 return font->hdc;
190 }
191
192 static HRESULT WINAPI ID3DXFontImpl_GetGlyphData(ID3DXFont *iface, UINT glyph,
193 IDirect3DTexture9 **texture, RECT *black_box, POINT *cell_inc)
194 {
195 struct d3dx_font *font = impl_from_ID3DXFont(iface);
196 struct wine_rb_entry *entry;
197 HRESULT hr;
198
199 TRACE("iface %p, glyph %#x, texture %p, black_box %p, cell_inc %p.\n",
200 iface, glyph, texture, black_box, cell_inc);
201
202 hr = ID3DXFont_PreloadGlyphs(iface, glyph, glyph);
203 if (FAILED(hr))
204 return hr;
205
206 entry = wine_rb_get(&font->glyph_tree, ULongToPtr(glyph));
207 if (entry)
208 {
209 struct d3dx_glyph *current_glyph = WINE_RB_ENTRY_VALUE(entry, struct d3dx_glyph, entry);
210
211 if (cell_inc)
212 *cell_inc = current_glyph->cell_inc;
213 if (black_box)
214 *black_box = current_glyph->black_box;
215 if (texture)
216 {
217 *texture = current_glyph->texture;
218 if (*texture)
219 IDirect3DTexture9_AddRef(current_glyph->texture);
220 }
221 return D3D_OK;
222 }
223
224 return D3DXERR_INVALIDDATA;
225 }
226
227 static HRESULT WINAPI ID3DXFontImpl_PreloadCharacters(ID3DXFont *iface, UINT first, UINT last)
228 {
229 struct d3dx_font *font = impl_from_ID3DXFont(iface);
230 unsigned int i, count, start, end;
231 WORD *indices;
232 WCHAR *chars;
233
234 TRACE("iface %p, first %u, last %u.\n", iface, first, last);
235
236 if (last < first)
237 return D3D_OK;
238
239 count = last - first + 1;
240 indices = heap_alloc(count * sizeof(*indices));
241 if (!indices)
242 return E_OUTOFMEMORY;
243
244 chars = heap_alloc(count * sizeof(*chars));
245 if (!chars)
246 {
247 heap_free(indices);
248 return E_OUTOFMEMORY;
249 }
250
251 for (i = 0; i < count; ++i)
252 chars[i] = first + i;
253
254 GetGlyphIndicesW(font->hdc, chars, count, indices, 0);
255
256 start = end = indices[0];
257 for (i = 1; i < count; ++i)
258 {
259 if (indices[i] == end + 1)
260 {
261 end = indices[i];
262 continue;
263 }
264 ID3DXFont_PreloadGlyphs(iface, start, end);
265 start = end = indices[i];
266 }
267 ID3DXFont_PreloadGlyphs(iface, start, end);
268
269 heap_free(chars);
270 heap_free(indices);
271
272 return D3D_OK;
273 }
274
275 static uint32_t morton_decode(uint32_t x)
276 {
277 x &= 0x55555555;
278 x = (x ^ (x >> 1)) & 0x33333333;
279 x = (x ^ (x >> 2)) & 0x0f0f0f0f;
280 x = (x ^ (x >> 4)) & 0x00ff00ff;
281 x = (x ^ (x >> 8)) & 0x0000ffff;
282 return x;
283 }
284
285 /* The glyphs are stored in a grid. Cell sizes vary between different font
286 * sizes.
287 *
288 * The grid is filled in Morton order:
289 * 1 2 5 6 17 18 21 22
290 * 3 4 7 8 19 20 23 24
291 * 9 10 13 14 25 26 29 30
292 * 11 12 15 16 27 28 31 32
293 * 33 34 ...
294 * ...
295 *
296 * i.e. we try to fill one small square, then three equal-sized squares so
297 * that we get one big square, etc.
298 *
299 * The glyphs are positioned around their baseline, which is located at y
300 * position glyph_size * i + tmAscent. Concerning the x position, the glyphs
301 * are centered around glyph_size * (i + 0.5). */
302 static HRESULT WINAPI ID3DXFontImpl_PreloadGlyphs(ID3DXFont *iface, UINT first, UINT last)
303 {
304 static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
305 struct d3dx_font *font = impl_from_ID3DXFont(iface);
306 IDirect3DTexture9 *current_texture = NULL;
307 unsigned int size, stride, glyph, x, y;
308 struct d3dx_glyph *current_glyph;
309 D3DLOCKED_RECT lockrect;
310 GLYPHMETRICS metrics;
311 BOOL mapped = FALSE;
312 DWORD *pixel_data;
313 BYTE *buffer;
314 HRESULT hr;
315
316 TRACE("iface %p, first %u, last %u.\n", iface, first, last);
317
318 if (last < first)
319 return D3D_OK;
320
321 if (font->texture_count)
322 current_texture = font->textures[font->texture_count - 1];
323
324 for (glyph = first; glyph <= last; ++glyph)
325 {
326 if (wine_rb_get(&font->glyph_tree, ULongToPtr(glyph)))
327 continue;
328
329 current_glyph = heap_alloc(sizeof(*current_glyph));
330 if (!current_glyph)
331 {
332 if (mapped)
333 IDirect3DTexture9_UnlockRect(current_texture, 0);
334 return E_OUTOFMEMORY;
335 }
336
337 current_glyph->id = glyph;
338 current_glyph->texture = NULL;
339 wine_rb_put(&font->glyph_tree, ULongToPtr(current_glyph->id), &current_glyph->entry);
340
341 size = GetGlyphOutlineW(font->hdc, glyph, GGO_GLYPH_INDEX | GGO_GRAY8_BITMAP, &metrics, 0, NULL, &mat);
342 if (size == GDI_ERROR)
343 {
344 WARN("GetGlyphOutlineW failed.\n");
345 continue;
346 }
347 if (!size)
348 continue;
349
350 buffer = heap_alloc(size);
351 if (!buffer)
352 {
353 if (mapped)
354 IDirect3DTexture9_UnlockRect(current_texture, 0);
355 return E_OUTOFMEMORY;
356 }
357
358 GetGlyphOutlineW(font->hdc, glyph, GGO_GLYPH_INDEX | GGO_GRAY8_BITMAP, &metrics, size, buffer, &mat);
359
360 if (font->texture_pos == font->glyphs_per_texture)
361 {
362 unsigned int new_texture_count = font->texture_count + 1;
363 IDirect3DTexture9 **new_textures;
364
365 if (mapped)
366 IDirect3DTexture9_UnlockRect(current_texture, 0);
367 mapped = FALSE;
368 new_textures = heap_realloc(font->textures, new_texture_count * sizeof(*new_textures));
369 if (!new_textures)
370 {
371 heap_free(buffer);
372 return E_OUTOFMEMORY;
373 }
374 font->textures = new_textures;
375
376 if (FAILED(hr = IDirect3DDevice9_CreateTexture(font->device, font->texture_size,
377 font->texture_size, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED,
378 &font->textures[font->texture_count], NULL)))
379 {
380 heap_free(buffer);
381 return hr;
382 }
383
384 current_texture = font->textures[font->texture_count++];
385 font->texture_pos = 0;
386 }
387
388 if (!mapped)
389 {
390 if (FAILED(hr = IDirect3DTexture9_LockRect(current_texture, 0, &lockrect, NULL, 0)))
391 {
392 heap_free(buffer);
393 return hr;
394 }
395 mapped = TRUE;
396 }
397
398 x = morton_decode(font->texture_pos) * font->glyph_size;
399 y = morton_decode(font->texture_pos >> 1) * font->glyph_size;
400
401 current_glyph->black_box.left = x - metrics.gmptGlyphOrigin.x + font->glyph_size / 2
402 - metrics.gmBlackBoxX / 2;
403 current_glyph->black_box.top = y - metrics.gmptGlyphOrigin.y + font->metrics.tmAscent + 1;
404 current_glyph->black_box.right = current_glyph->black_box.left + metrics.gmBlackBoxX;
405 current_glyph->black_box.bottom = current_glyph->black_box.top + metrics.gmBlackBoxY;
406 current_glyph->cell_inc.x = metrics.gmptGlyphOrigin.x - 1;
407 current_glyph->cell_inc.y = font->metrics.tmAscent - metrics.gmptGlyphOrigin.y - 1;
408 current_glyph->texture = current_texture;
409
410 pixel_data = lockrect.pBits;
411 stride = (metrics.gmBlackBoxX + 3) & ~3;
412 for (y = 0; y < metrics.gmBlackBoxY; ++y)
413 for (x = 0; x < metrics.gmBlackBoxX; ++x)
414 pixel_data[(current_glyph->black_box.top + y) * lockrect.Pitch / 4
415 + current_glyph->black_box.left + x] =
416 (buffer[y * stride + x] * 255 / 64 << 24) | 0x00ffffffu;
417
418 heap_free(buffer);
419 ++font->texture_pos;
420 }
421 if (mapped)
422 IDirect3DTexture9_UnlockRect(current_texture, 0);
423
424 return D3D_OK;
425 }
426
427 static HRESULT WINAPI ID3DXFontImpl_PreloadTextA(ID3DXFont *iface, const char *string, INT count)
428 {
429 WCHAR *wstr;
430 HRESULT hr;
431 int countW;
432
433 TRACE("iface %p, string %s, count %d.\n", iface, debugstr_an(string, count), count);
434
435 if (!string && !count)
436 return D3D_OK;
437
438 if (!string)
439 return D3DERR_INVALIDCALL;
440
441 countW = MultiByteToWideChar(CP_ACP, 0, string, count < 0 ? -1 : count, NULL, 0);
442
443 wstr = heap_alloc(countW * sizeof(*wstr));
444 if (!wstr)
445 return E_OUTOFMEMORY;
446
447 MultiByteToWideChar(CP_ACP, 0, string, count < 0 ? -1 : count, wstr, countW);
448
449 hr = ID3DXFont_PreloadTextW(iface, wstr, count < 0 ? countW - 1 : countW);
450
451 heap_free(wstr);
452
453 return hr;
454 }
455
456 static HRESULT WINAPI ID3DXFontImpl_PreloadTextW(ID3DXFont *iface, const WCHAR *string, INT count)
457 {
458 struct d3dx_font *font = impl_from_ID3DXFont(iface);
459 WORD *indices;
460 int i;
461
462 TRACE("iface %p, string %s, count %d.\n", iface, debugstr_wn(string, count), count);
463
464 if (!string && !count)
465 return D3D_OK;
466
467 if (!string)
468 return D3DERR_INVALIDCALL;
469
470 if (count < 0)
471 count = lstrlenW(string);
472
473 indices = heap_alloc(count * sizeof(*indices));
474 if (!indices)
475 return E_OUTOFMEMORY;
476
477 GetGlyphIndicesW(font->hdc, string, count, indices, 0);
478
479 for (i = 0; i < count; ++i)
480 ID3DXFont_PreloadGlyphs(iface, indices[i], indices[i]);
481
482 heap_free(indices);
483
484 return D3D_OK;
485 }
486
487 static INT WINAPI ID3DXFontImpl_DrawTextA(ID3DXFont *iface, ID3DXSprite *sprite,
488 const char *string, INT count, RECT *rect, DWORD format, D3DCOLOR color)
489 {
490 int ret, countW;
491 WCHAR *wstr;
492
493 TRACE("iface %p, sprite %p, string %s, count %d, rect %s, format %#x, color 0x%08x.\n",
494 iface, sprite, debugstr_an(string, count), count, wine_dbgstr_rect(rect), format, color);
495
496 if (!string || !count)
497 return 0;
498
499 countW = MultiByteToWideChar(CP_ACP, 0, string, count < 0 ? -1 : count, NULL, 0);
500
501 if (!countW)
502 return 0;
503
504 wstr = heap_alloc_zero(countW * sizeof(*wstr));
505 if (!wstr)
506 return 0;
507
508 MultiByteToWideChar(CP_ACP, 0, string, count < 0 ? -1 : count, wstr, countW);
509
510 ret = ID3DXFont_DrawTextW(iface, sprite, wstr, count < 0 ? countW - 1 : countW,
511 rect, format, color);
512
513 heap_free(wstr);
514
515 return ret;
516 }
517
518 static void word_break(HDC hdc, const WCHAR *str, unsigned int *str_len,
519 unsigned int chars_fit, unsigned int *chars_used, SIZE *size)
520 {
521 SCRIPT_LOGATTR *sla;
522 SCRIPT_ANALYSIS sa;
523 unsigned int i;
524
525 *chars_used = 0;
526
527 sla = heap_alloc(*str_len * sizeof(*sla));
528 if (!sla)
529 return;
530
531 memset(&sa, 0, sizeof(sa));
532 sa.eScript = SCRIPT_UNDEFINED;
533
534 ScriptBreak(str, *str_len, &sa, sla);
535
536 /* Work back from the last character that did fit to a place where we can break */
537 i = chars_fit;
538 while (i > 0 && !sla[i].fSoftBreak) /* chars_fit < *str_len so this is valid */
539 --i;
540
541 /* If the there is no word that fits put in all characters that do fit */
542 if (!sla[i].fSoftBreak)
543 i = chars_fit;
544
545 *chars_used = i;
546 if (sla[i].fWhiteSpace)
547 ++(*chars_used);
548
549 /* Remove extra spaces */
550 while (i > 0 && sla[i-1].fWhiteSpace)
551 --i;
552 *str_len = i;
553
554 /* Remeasure the string */
555 GetTextExtentExPointW(hdc, str, *str_len, 0, NULL, NULL, size);
556 heap_free(sla);
557 }
558
559 static const WCHAR *read_line(HDC hdc, const WCHAR *str, unsigned int *count,
560 WCHAR *dest, unsigned int *dest_len, int width, DWORD format, SIZE *size)
561 {
562 unsigned int orig_count = *count;
563 unsigned int i = 0;
564 int num_fit;
565
566 *dest_len = 0;
567 while (*count && (str[i] != '\n' || (format & DT_SINGLELINE)))
568 {
569 --(*count);
570 if (str[i] != '\r' && str[i] != '\n')
571 dest[(*dest_len)++] = str[i];
572 ++i;
573 }
574
575 num_fit = 0;
576 GetTextExtentExPointW(hdc, dest, *dest_len, width, &num_fit, NULL, size);
577
578 if (num_fit < *dest_len && (format & DT_WORDBREAK))
579 {
580 unsigned int chars_used;
581
582 word_break(hdc, dest, dest_len, num_fit, &chars_used, size);
583 *count = orig_count - chars_used;
584 i = chars_used;
585 }
586
587 if (*count && str[i] == '\n')
588 {
589 --(*count);
590 ++i;
591 }
592
593 if (*count)
594 return str + i;
595 return NULL;
596 }
597
598 static int compute_rect(struct d3dx_font *font, const WCHAR *string, unsigned int count,
599 WCHAR *line, RECT *rect, DWORD format)
600 {
601 int y, lh, width, top = rect->top;
602 int max_width = 0;
603 SIZE size;
604
605 y = rect->top;
606 lh = font->metrics.tmHeight;
607 width = rect->right - rect->left;
608
609 while (string)
610 {
611 unsigned int line_len;
612
613 string = read_line(font->hdc, string, &count, line, &line_len, width, format, &size);
614
615 if (size.cx > max_width)
616 max_width = size.cx;
617
618 y += lh;
619 if (!(format & DT_NOCLIP) && (y > rect->bottom))
620 break;
621 }
622
623 if (format & DT_CENTER)
624 {
625 rect->left += (rect->right - rect->left - max_width) / 2;
626 rect->right = rect->left + max_width;
627 }
628 else if (format & DT_RIGHT)
629 {
630 rect->left = rect->right - max_width;
631 }
632 else
633 {
634 rect->right = rect->left + max_width;
635 }
636
637 if (format & DT_VCENTER)
638 {
639 rect->top += (rect->bottom - y) / 2;
640 rect->bottom = rect->top + y - top;
641 }
642 else if (format & DT_BOTTOM)
643 {
644 rect->top += rect->bottom - y;
645 }
646 else
647 {
648 rect->bottom = y;
649 }
650
651 return rect->bottom - top;
652 }
653
654 static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite,
655 const WCHAR *string, INT in_count, RECT *rect, DWORD format, D3DCOLOR color)
656 {
657 struct d3dx_font *font = impl_from_ID3DXFont(iface);
658 int lh, x, y, width, top, ret = 0;
659 ID3DXSprite *target = sprite;
660 unsigned int count;
661 RECT r = {0};
662 WCHAR *line;
663 SIZE size;
664
665 TRACE("iface %p, sprite %p, string %s, in_count %d, rect %s, format %#x, color 0x%08x.\n",
666 iface, sprite, debugstr_wn(string, in_count), in_count, wine_dbgstr_rect(rect), format, color);
667
668 if (!string)
669 return 0;
670
671 count = in_count < 0 ? lstrlenW(string) : in_count;
672
673 if (!count)
674 return 0;
675
676 if (format & DT_CALCRECT)
677 format |= DT_NOCLIP;
678
679 if (format & DT_SINGLELINE)
680 format &= ~DT_WORDBREAK;
681
682 line = heap_alloc(count * sizeof(*line));
683 if (!line)
684 return 0;
685
686 if (!rect || format & (DT_CALCRECT | DT_VCENTER | DT_BOTTOM))
687 {
688 if (!rect)
689 {
690 rect = &r;
691 format |= DT_NOCLIP;
692 }
693 else if (!(format & DT_CALCRECT))
694 {
695 r = *rect;
696 rect = &r;
697 }
698
699 top = rect->top;
700
701 ret = compute_rect(font, string, count, line, rect, format);
702
703 if (format & DT_CALCRECT)
704 goto cleanup;
705 }
706 else
707 {
708 top = rect->top;
709 }
710
711 y = rect->top;
712 lh = font->metrics.tmHeight;
713 width = rect->right - rect->left;
714
715 if (!sprite)
716 {
717 D3DXCreateSprite(font->device, &target);
718 ID3DXSprite_Begin(target, 0);
719 }
720
721 while (string)
722 {
723 unsigned int line_len, i;
724 GCP_RESULTSW results;
725
726 string = read_line(font->hdc, string, &count, line, &line_len, width, format, &size);
727
728 if (format & DT_CENTER)
729 x = (rect->left + rect->right - size.cx) / 2;
730 else if (format & DT_RIGHT)
731 x = rect->right - size.cx;
732 else
733 x = rect->left;
734
735 memset(&results, 0, sizeof(results));
736 results.nGlyphs = line_len;
737
738 results.lpCaretPos = heap_alloc(line_len * sizeof(*results.lpCaretPos));
739 if (!results.lpCaretPos)
740 goto cleanup;
741
742 results.lpGlyphs = heap_alloc(line_len * sizeof(*results.lpGlyphs));
743 if (!results.lpGlyphs)
744 {
745 heap_free(results.lpCaretPos);
746 goto cleanup;
747 }
748
749 GetCharacterPlacementW(font->hdc, line, line_len, 0, &results, 0);
750
751 for (i = 0; i < results.nGlyphs; ++i)
752 {
753 IDirect3DTexture9 *texture;
754 D3DXVECTOR3 pos;
755 POINT cell_inc;
756 RECT black_box;
757
758 ID3DXFont_GetGlyphData(iface, results.lpGlyphs[i], &texture, &black_box, &cell_inc);
759
760 if (!texture)
761 continue;
762
763 pos.x = cell_inc.x + x + results.lpCaretPos[i];
764 pos.y = cell_inc.y + y;
765 pos.z = 0;
766
767 if (!(format & DT_NOCLIP))
768 {
769 if (pos.x > rect->right)
770 {
771 IDirect3DTexture9_Release(texture);
772 continue;
773 }
774
775 if (pos.x + black_box.right - black_box.left > rect->right)
776 black_box.right = black_box.left + rect->right - pos.x;
777
778 if (pos.y + black_box.bottom - black_box.top > rect->bottom)
779 black_box.bottom = black_box.top + rect->bottom - pos.y;
780 }
781
782 ID3DXSprite_Draw(target, texture, &black_box, NULL, &pos, color);
783 IDirect3DTexture9_Release(texture);
784 }
785
786 heap_free(results.lpCaretPos);
787 heap_free(results.lpGlyphs);
788
789 y += lh;
790 if (!(DT_NOCLIP & format) && (y > rect->bottom))
791 break;
792 }
793
794 ret = y - top;
795
796 cleanup:
797 if (target != sprite)
798 {
799 ID3DXSprite_End(target);
800 ID3DXSprite_Release(target);
801 }
802
803 heap_free(line);
804
805 return ret;
806 }
807
808 static HRESULT WINAPI ID3DXFontImpl_OnLostDevice(ID3DXFont *iface)
809 {
810 FIXME("iface %p stub!\n", iface);
811 return D3D_OK;
812 }
813
814 static HRESULT WINAPI ID3DXFontImpl_OnResetDevice(ID3DXFont *iface)
815 {
816 FIXME("iface %p stub\n", iface);
817 return D3D_OK;
818 }
819
820 static const ID3DXFontVtbl D3DXFont_Vtbl =
821 {
822 /*** IUnknown methods ***/
823 ID3DXFontImpl_QueryInterface,
824 ID3DXFontImpl_AddRef,
825 ID3DXFontImpl_Release,
826 /*** ID3DXFont methods ***/
827 ID3DXFontImpl_GetDevice,
828 ID3DXFontImpl_GetDescA,
829 ID3DXFontImpl_GetDescW,
830 ID3DXFontImpl_GetTextMetricsA,
831 ID3DXFontImpl_GetTextMetricsW,
832 ID3DXFontImpl_GetDC,
833 ID3DXFontImpl_GetGlyphData,
834 ID3DXFontImpl_PreloadCharacters,
835 ID3DXFontImpl_PreloadGlyphs,
836 ID3DXFontImpl_PreloadTextA,
837 ID3DXFontImpl_PreloadTextW,
838 ID3DXFontImpl_DrawTextA,
839 ID3DXFontImpl_DrawTextW,
840 ID3DXFontImpl_OnLostDevice,
841 ID3DXFontImpl_OnResetDevice
842 };
843
844 HRESULT WINAPI D3DXCreateFontA(struct IDirect3DDevice9 *device, INT height, UINT width,
845 UINT weight, UINT miplevels, BOOL italic, DWORD charset, DWORD precision, DWORD quality,
846 DWORD pitchandfamily, const char *facename, struct ID3DXFont **font)
847 {
848 D3DXFONT_DESCA desc;
849
850 if( !device || !font ) return D3DERR_INVALIDCALL;
851
852 desc.Height=height;
853 desc.Width=width;
854 desc.Weight=weight;
855 desc.MipLevels=miplevels;
856 desc.Italic=italic;
857 desc.CharSet=charset;
858 desc.OutputPrecision=precision;
859 desc.Quality=quality;
860 desc.PitchAndFamily=pitchandfamily;
861 if(facename != NULL) lstrcpyA(desc.FaceName, facename);
862 else desc.FaceName[0] = '\0';
863
864 return D3DXCreateFontIndirectA(device, &desc, font);
865 }
866
867 HRESULT WINAPI D3DXCreateFontW(IDirect3DDevice9 *device, INT height, UINT width, UINT weight, UINT miplevels, BOOL italic, DWORD charset,
868 DWORD precision, DWORD quality, DWORD pitchandfamily, const WCHAR *facename, ID3DXFont **font)
869 {
870 D3DXFONT_DESCW desc;
871
872 if( !device || !font ) return D3DERR_INVALIDCALL;
873
874 desc.Height=height;
875 desc.Width=width;
876 desc.Weight=weight;
877 desc.MipLevels=miplevels;
878 desc.Italic=italic;
879 desc.CharSet=charset;
880 desc.OutputPrecision=precision;
881 desc.Quality=quality;
882 desc.PitchAndFamily=pitchandfamily;
883 if(facename != NULL) lstrcpyW(desc.FaceName, facename);
884 else desc.FaceName[0] = '\0';
885
886 return D3DXCreateFontIndirectW(device, &desc, font);
887 }
888
889 /***********************************************************************
890 * D3DXCreateFontIndirectA (D3DX9_36.@)
891 */
892 HRESULT WINAPI D3DXCreateFontIndirectA(IDirect3DDevice9 *device, const D3DXFONT_DESCA *desc, ID3DXFont **font)
893 {
894 D3DXFONT_DESCW widedesc;
895
896 if( !device || !desc || !font ) return D3DERR_INVALIDCALL;
897
898 /* Copy everything but the last structure member. This requires the
899 two D3DXFONT_DESC structures to be equal until the FaceName member */
900 memcpy(&widedesc, desc, FIELD_OFFSET(D3DXFONT_DESCA, FaceName));
901 MultiByteToWideChar(CP_ACP, 0, desc->FaceName, -1, widedesc.FaceName, ARRAY_SIZE(widedesc.FaceName));
902 return D3DXCreateFontIndirectW(device, &widedesc, font);
903 }
904
905 /***********************************************************************
906 * D3DXCreateFontIndirectW (D3DX9_36.@)
907 */
908 HRESULT WINAPI D3DXCreateFontIndirectW(IDirect3DDevice9 *device, const D3DXFONT_DESCW *desc, ID3DXFont **font)
909 {
910 D3DDEVICE_CREATION_PARAMETERS cpars;
911 struct d3dx_font *object;
912 D3DDISPLAYMODE mode;
913 IDirect3D9 *d3d;
914 HRESULT hr;
915
916 TRACE("(%p, %p, %p)\n", device, desc, font);
917
918 if( !device || !desc || !font ) return D3DERR_INVALIDCALL;
919
920 /* the device MUST support D3DFMT_A8R8G8B8 */
921 IDirect3DDevice9_GetDirect3D(device, &d3d);
922 IDirect3DDevice9_GetCreationParameters(device, &cpars);
923 IDirect3DDevice9_GetDisplayMode(device, 0, &mode);
924 hr = IDirect3D9_CheckDeviceFormat(d3d, cpars.AdapterOrdinal, cpars.DeviceType, mode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_A8R8G8B8);
925 if (FAILED(hr))
926 {
927 IDirect3D9_Release(d3d);
928 return D3DXERR_INVALIDDATA;
929 }
930 IDirect3D9_Release(d3d);
931
932 object = heap_alloc_zero(sizeof(*object));
933 if (!object)
934 {
935 *font = NULL;
936 return E_OUTOFMEMORY;
937 }
938 object->ID3DXFont_iface.lpVtbl = &D3DXFont_Vtbl;
939 object->ref = 1;
940 object->device = device;
941 object->desc = *desc;
942
943 object->hdc = CreateCompatibleDC(NULL);
944 if (!object->hdc)
945 {
946 heap_free(object);
947 return D3DXERR_INVALIDDATA;
948 }
949
950 object->hfont = CreateFontW(desc->Height, desc->Width, 0, 0, desc->Weight, desc->Italic, FALSE, FALSE, desc->CharSet,
951 desc->OutputPrecision, CLIP_DEFAULT_PRECIS, desc->Quality, desc->PitchAndFamily, desc->FaceName);
952 if (!object->hfont)
953 {
954 DeleteDC(object->hdc);
955 heap_free(object);
956 return D3DXERR_INVALIDDATA;
957 }
958 SelectObject(object->hdc, object->hfont);
959
960 wine_rb_init(&object->glyph_tree, glyph_rb_compare);
961
962 if (!GetTextMetricsW(object->hdc, &object->metrics))
963 {
964 DeleteObject(object->hfont);
965 DeleteDC(object->hdc);
966 heap_free(object);
967 return D3DXERR_INVALIDDATA;
968 }
969
970 object->glyph_size = make_pow2(object->metrics.tmHeight);
971
972 object->texture_size = object->glyph_size;
973 if (object->glyph_size < 256)
974 object->texture_size = min(256, object->texture_size * 16);
975
976 object->glyphs_per_texture = object->texture_size * object->texture_size
977 / (object->glyph_size * object->glyph_size);
978 object->texture_pos = object->glyphs_per_texture;
979
980 IDirect3DDevice9_AddRef(device);
981 *font = &object->ID3DXFont_iface;
982
983 return D3D_OK;
984 }