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), ¤t_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 } 985