1 /* 2 * Copyright (C) 2007 Google (Evan Stade) 3 * Copyright (C) 2012 Dmitry Timoshkov 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 18 */ 19 20 #include <stdarg.h> 21 22 #include "windef.h" 23 #include "winbase.h" 24 #include "wingdi.h" 25 #include "winnls.h" 26 #include "winreg.h" 27 #include "wine/debug.h" 28 #include "wine/unicode.h" 29 30 WINE_DEFAULT_DEBUG_CHANNEL (gdiplus); 31 32 #include "objbase.h" 33 34 #include "gdiplus.h" 35 #include "gdiplus_private.h" 36 37 /* PANOSE is 10 bytes in size, need to pack the structure properly */ 38 #include "pshpack2.h" 39 typedef struct 40 { 41 USHORT version; 42 SHORT xAvgCharWidth; 43 USHORT usWeightClass; 44 USHORT usWidthClass; 45 SHORT fsType; 46 SHORT ySubscriptXSize; 47 SHORT ySubscriptYSize; 48 SHORT ySubscriptXOffset; 49 SHORT ySubscriptYOffset; 50 SHORT ySuperscriptXSize; 51 SHORT ySuperscriptYSize; 52 SHORT ySuperscriptXOffset; 53 SHORT ySuperscriptYOffset; 54 SHORT yStrikeoutSize; 55 SHORT yStrikeoutPosition; 56 SHORT sFamilyClass; 57 PANOSE panose; 58 ULONG ulUnicodeRange1; 59 ULONG ulUnicodeRange2; 60 ULONG ulUnicodeRange3; 61 ULONG ulUnicodeRange4; 62 CHAR achVendID[4]; 63 USHORT fsSelection; 64 USHORT usFirstCharIndex; 65 USHORT usLastCharIndex; 66 /* According to the Apple spec, original version didn't have the below fields, 67 * version numbers were taken from the OpenType spec. 68 */ 69 /* version 0 (TrueType 1.5) */ 70 USHORT sTypoAscender; 71 USHORT sTypoDescender; 72 USHORT sTypoLineGap; 73 USHORT usWinAscent; 74 USHORT usWinDescent; 75 /* version 1 (TrueType 1.66) */ 76 ULONG ulCodePageRange1; 77 ULONG ulCodePageRange2; 78 /* version 2 (OpenType 1.2) */ 79 SHORT sxHeight; 80 SHORT sCapHeight; 81 USHORT usDefaultChar; 82 USHORT usBreakChar; 83 USHORT usMaxContext; 84 } TT_OS2_V2; 85 86 typedef struct 87 { 88 ULONG Version; 89 SHORT Ascender; 90 SHORT Descender; 91 SHORT LineGap; 92 USHORT advanceWidthMax; 93 SHORT minLeftSideBearing; 94 SHORT minRightSideBearing; 95 SHORT xMaxExtent; 96 SHORT caretSlopeRise; 97 SHORT caretSlopeRun; 98 SHORT caretOffset; 99 SHORT reserved[4]; 100 SHORT metricDataFormat; 101 USHORT numberOfHMetrics; 102 } TT_HHEA; 103 #include "poppack.h" 104 105 #ifdef WORDS_BIGENDIAN 106 #define GET_BE_WORD(x) (x) 107 #define GET_BE_DWORD(x) (x) 108 #else 109 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x)) 110 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x))); 111 #endif 112 113 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \ 114 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \ 115 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24)) 116 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2') 117 #define MS_HHEA_TAG MS_MAKE_TAG('h','h','e','a') 118 119 static GpStatus clone_font_family(const GpFontFamily *, GpFontFamily **); 120 121 static GpFontCollection installedFontCollection = {0}; 122 123 /******************************************************************************* 124 * GdipCreateFont [GDIPLUS.@] 125 * 126 * Create a new font based off of a FontFamily 127 * 128 * PARAMS 129 * *fontFamily [I] Family to base the font off of 130 * emSize [I] Size of the font 131 * style [I] Bitwise OR of FontStyle enumeration 132 * unit [I] Unit emSize is measured in 133 * **font [I] the resulting Font object 134 * 135 * RETURNS 136 * SUCCESS: Ok 137 * FAILURE: InvalidParameter if fontfamily or font is NULL. 138 * FAILURE: FontFamilyNotFound if an invalid FontFamily is given 139 * 140 * NOTES 141 * UnitDisplay is unsupported. 142 * emSize is stored separately from lfHeight, to hold the fraction. 143 */ 144 GpStatus WINGDIPAPI GdipCreateFont(GDIPCONST GpFontFamily *fontFamily, 145 REAL emSize, INT style, Unit unit, GpFont **font) 146 { 147 HFONT hfont; 148 OUTLINETEXTMETRICW otm; 149 LOGFONTW lfw; 150 HDC hdc; 151 GpStatus stat; 152 int ret; 153 154 if (!fontFamily || !font || emSize < 0.0) 155 return InvalidParameter; 156 157 TRACE("%p (%s), %f, %d, %d, %p\n", fontFamily, 158 debugstr_w(fontFamily->FamilyName), emSize, style, unit, font); 159 160 memset(&lfw, 0, sizeof(lfw)); 161 162 stat = GdipGetFamilyName(fontFamily, lfw.lfFaceName, LANG_NEUTRAL); 163 if (stat != Ok) return stat; 164 165 lfw.lfHeight = -units_to_pixels(emSize, unit, fontFamily->dpi); 166 lfw.lfWeight = style & FontStyleBold ? FW_BOLD : FW_REGULAR; 167 lfw.lfItalic = style & FontStyleItalic; 168 lfw.lfUnderline = style & FontStyleUnderline; 169 lfw.lfStrikeOut = style & FontStyleStrikeout; 170 171 hfont = CreateFontIndirectW(&lfw); 172 hdc = CreateCompatibleDC(0); 173 SelectObject(hdc, hfont); 174 otm.otmSize = sizeof(otm); 175 ret = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm); 176 DeleteDC(hdc); 177 DeleteObject(hfont); 178 179 if (!ret) return NotTrueTypeFont; 180 181 *font = heap_alloc_zero(sizeof(GpFont)); 182 if (!*font) return OutOfMemory; 183 184 (*font)->unit = unit; 185 (*font)->emSize = emSize; 186 (*font)->otm = otm; 187 188 stat = clone_font_family(fontFamily, &(*font)->family); 189 if (stat != Ok) 190 { 191 heap_free(*font); 192 return stat; 193 } 194 195 TRACE("<-- %p\n", *font); 196 197 return Ok; 198 } 199 200 /******************************************************************************* 201 * GdipCreateFontFromLogfontW [GDIPLUS.@] 202 */ 203 GpStatus WINGDIPAPI GdipCreateFontFromLogfontW(HDC hdc, 204 GDIPCONST LOGFONTW *logfont, GpFont **font) 205 { 206 HFONT hfont, oldfont; 207 OUTLINETEXTMETRICW otm; 208 WCHAR facename[LF_FACESIZE]; 209 GpStatus stat; 210 int ret; 211 212 TRACE("(%p, %p, %p)\n", hdc, logfont, font); 213 214 if (!hdc || !logfont || !font) 215 return InvalidParameter; 216 217 hfont = CreateFontIndirectW(logfont); 218 oldfont = SelectObject(hdc, hfont); 219 otm.otmSize = sizeof(otm); 220 ret = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm); 221 GetTextFaceW(hdc, LF_FACESIZE, facename); 222 SelectObject(hdc, oldfont); 223 DeleteObject(hfont); 224 225 if (!ret) return NotTrueTypeFont; 226 227 *font = heap_alloc_zero(sizeof(GpFont)); 228 if (!*font) return OutOfMemory; 229 230 (*font)->unit = UnitWorld; 231 (*font)->emSize = otm.otmTextMetrics.tmAscent; 232 (*font)->otm = otm; 233 234 stat = GdipCreateFontFamilyFromName(facename, NULL, &(*font)->family); 235 if (stat != Ok) 236 { 237 heap_free(*font); 238 return NotTrueTypeFont; 239 } 240 241 TRACE("<-- %p\n", *font); 242 243 return Ok; 244 } 245 246 /******************************************************************************* 247 * GdipCreateFontFromLogfontA [GDIPLUS.@] 248 */ 249 GpStatus WINGDIPAPI GdipCreateFontFromLogfontA(HDC hdc, 250 GDIPCONST LOGFONTA *lfa, GpFont **font) 251 { 252 LOGFONTW lfw; 253 254 TRACE("(%p, %p, %p)\n", hdc, lfa, font); 255 256 if(!lfa || !font) 257 return InvalidParameter; 258 259 memcpy(&lfw, lfa, FIELD_OFFSET(LOGFONTA,lfFaceName) ); 260 261 if(!MultiByteToWideChar(CP_ACP, 0, lfa->lfFaceName, -1, lfw.lfFaceName, LF_FACESIZE)) 262 return GenericError; 263 264 return GdipCreateFontFromLogfontW(hdc, &lfw, font); 265 } 266 267 /******************************************************************************* 268 * GdipDeleteFont [GDIPLUS.@] 269 */ 270 GpStatus WINGDIPAPI GdipDeleteFont(GpFont* font) 271 { 272 TRACE("(%p)\n", font); 273 274 if(!font) 275 return InvalidParameter; 276 277 GdipDeleteFontFamily(font->family); 278 heap_free(font); 279 280 return Ok; 281 } 282 283 /******************************************************************************* 284 * GdipCreateFontFromDC [GDIPLUS.@] 285 */ 286 GpStatus WINGDIPAPI GdipCreateFontFromDC(HDC hdc, GpFont **font) 287 { 288 HFONT hfont; 289 LOGFONTW lfw; 290 291 TRACE("(%p, %p)\n", hdc, font); 292 293 if(!font) 294 return InvalidParameter; 295 296 hfont = GetCurrentObject(hdc, OBJ_FONT); 297 if(!hfont) 298 return GenericError; 299 300 if(!GetObjectW(hfont, sizeof(LOGFONTW), &lfw)) 301 return GenericError; 302 303 return GdipCreateFontFromLogfontW(hdc, &lfw, font); 304 } 305 306 /******************************************************************************* 307 * GdipGetFamily [GDIPLUS.@] 308 * 309 * Returns the FontFamily for the specified Font 310 * 311 * PARAMS 312 * font [I] Font to request from 313 * family [O] Resulting FontFamily object 314 * 315 * RETURNS 316 * SUCCESS: Ok 317 * FAILURE: An element of GpStatus 318 */ 319 GpStatus WINGDIPAPI GdipGetFamily(GpFont *font, GpFontFamily **family) 320 { 321 TRACE("%p %p\n", font, family); 322 323 if (!(font && family)) 324 return InvalidParameter; 325 326 return GdipCloneFontFamily(font->family, family); 327 } 328 329 static REAL get_font_size(const GpFont *font) 330 { 331 return font->emSize; 332 } 333 334 /****************************************************************************** 335 * GdipGetFontSize [GDIPLUS.@] 336 * 337 * Returns the size of the font in Units 338 * 339 * PARAMS 340 * *font [I] The font to retrieve size from 341 * *size [O] Pointer to hold retrieved value 342 * 343 * RETURNS 344 * SUCCESS: Ok 345 * FAILURE: InvalidParameter (font or size was NULL) 346 * 347 * NOTES 348 * Size returned is actually emSize -- not internal size used for drawing. 349 */ 350 GpStatus WINGDIPAPI GdipGetFontSize(GpFont *font, REAL *size) 351 { 352 TRACE("(%p, %p)\n", font, size); 353 354 if (!(font && size)) return InvalidParameter; 355 356 *size = get_font_size(font); 357 TRACE("%s,%d => %f\n", debugstr_w(font->family->FamilyName), font->otm.otmTextMetrics.tmHeight, *size); 358 359 return Ok; 360 } 361 362 static INT get_font_style(const GpFont *font) 363 { 364 INT style; 365 366 if (font->otm.otmTextMetrics.tmWeight > FW_REGULAR) 367 style = FontStyleBold; 368 else 369 style = FontStyleRegular; 370 if (font->otm.otmTextMetrics.tmItalic) 371 style |= FontStyleItalic; 372 if (font->otm.otmTextMetrics.tmUnderlined) 373 style |= FontStyleUnderline; 374 if (font->otm.otmTextMetrics.tmStruckOut) 375 style |= FontStyleStrikeout; 376 377 return style; 378 } 379 380 /******************************************************************************* 381 * GdipGetFontStyle [GDIPLUS.@] 382 * 383 * Gets the font's style, returned in bitwise OR of FontStyle enumeration 384 * 385 * PARAMS 386 * font [I] font to request from 387 * style [O] resulting pointer to a FontStyle enumeration 388 * 389 * RETURNS 390 * SUCCESS: Ok 391 * FAILURE: InvalidParameter 392 */ 393 GpStatus WINGDIPAPI GdipGetFontStyle(GpFont *font, INT *style) 394 { 395 TRACE("%p %p\n", font, style); 396 397 if (!(font && style)) 398 return InvalidParameter; 399 400 *style = get_font_style(font); 401 TRACE("%s,%d => %d\n", debugstr_w(font->family->FamilyName), font->otm.otmTextMetrics.tmHeight, *style); 402 403 return Ok; 404 } 405 406 /******************************************************************************* 407 * GdipGetFontUnit [GDIPLUS.@] 408 * 409 * PARAMS 410 * font [I] Font to retrieve from 411 * unit [O] Return value 412 * 413 * RETURNS 414 * FAILURE: font or unit was NULL 415 * OK: otherwise 416 */ 417 GpStatus WINGDIPAPI GdipGetFontUnit(GpFont *font, Unit *unit) 418 { 419 TRACE("(%p, %p)\n", font, unit); 420 421 if (!(font && unit)) return InvalidParameter; 422 423 *unit = font->unit; 424 TRACE("%s,%d => %d\n", debugstr_w(font->family->FamilyName), font->otm.otmTextMetrics.tmHeight, *unit); 425 426 return Ok; 427 } 428 429 /******************************************************************************* 430 * GdipGetLogFontA [GDIPLUS.@] 431 */ 432 GpStatus WINGDIPAPI GdipGetLogFontA(GpFont *font, GpGraphics *graphics, 433 LOGFONTA *lfa) 434 { 435 GpStatus status; 436 LOGFONTW lfw; 437 438 TRACE("(%p, %p, %p)\n", font, graphics, lfa); 439 440 status = GdipGetLogFontW(font, graphics, &lfw); 441 if(status != Ok) 442 return status; 443 444 memcpy(lfa, &lfw, FIELD_OFFSET(LOGFONTA,lfFaceName) ); 445 446 if(!WideCharToMultiByte(CP_ACP, 0, lfw.lfFaceName, -1, lfa->lfFaceName, LF_FACESIZE, NULL, NULL)) 447 return GenericError; 448 449 return Ok; 450 } 451 452 /******************************************************************************* 453 * GdipGetLogFontW [GDIPLUS.@] 454 */ 455 GpStatus WINGDIPAPI GdipGetLogFontW(GpFont *font, GpGraphics *graphics, LOGFONTW *lf) 456 { 457 REAL angle, rel_height, height; 458 GpMatrix matrix; 459 GpPointF pt[3]; 460 461 TRACE("(%p, %p, %p)\n", font, graphics, lf); 462 463 if (!font || !graphics || !lf) 464 return InvalidParameter; 465 466 matrix = graphics->worldtrans; 467 468 if (font->unit == UnitPixel || font->unit == UnitWorld) 469 { 470 height = units_to_pixels(font->emSize, graphics->unit, graphics->yres); 471 if (graphics->unit != UnitDisplay) 472 GdipScaleMatrix(&matrix, graphics->scale, graphics->scale, MatrixOrderAppend); 473 } 474 else 475 { 476 if (graphics->unit == UnitDisplay || graphics->unit == UnitPixel) 477 height = units_to_pixels(font->emSize, font->unit, graphics->xres); 478 else 479 height = units_to_pixels(font->emSize, font->unit, graphics->yres); 480 } 481 482 pt[0].X = 0.0; 483 pt[0].Y = 0.0; 484 pt[1].X = 1.0; 485 pt[1].Y = 0.0; 486 pt[2].X = 0.0; 487 pt[2].Y = 1.0; 488 GdipTransformMatrixPoints(&matrix, pt, 3); 489 angle = -gdiplus_atan2((pt[1].Y - pt[0].Y), (pt[1].X - pt[0].X)); 490 rel_height = sqrt((pt[2].Y - pt[0].Y) * (pt[2].Y - pt[0].Y)+ 491 (pt[2].X - pt[0].X) * (pt[2].X - pt[0].X)); 492 493 lf->lfHeight = -gdip_round(height * rel_height); 494 lf->lfWidth = 0; 495 lf->lfEscapement = lf->lfOrientation = gdip_round((angle / M_PI) * 1800.0); 496 if (lf->lfEscapement < 0) 497 { 498 lf->lfEscapement += 3600; 499 lf->lfOrientation += 3600; 500 } 501 lf->lfWeight = font->otm.otmTextMetrics.tmWeight; 502 lf->lfItalic = font->otm.otmTextMetrics.tmItalic ? 1 : 0; 503 lf->lfUnderline = font->otm.otmTextMetrics.tmUnderlined ? 1 : 0; 504 lf->lfStrikeOut = font->otm.otmTextMetrics.tmStruckOut ? 1 : 0; 505 lf->lfCharSet = font->otm.otmTextMetrics.tmCharSet; 506 lf->lfOutPrecision = OUT_DEFAULT_PRECIS; 507 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS; 508 lf->lfQuality = DEFAULT_QUALITY; 509 lf->lfPitchAndFamily = 0; 510 strcpyW(lf->lfFaceName, font->family->FamilyName); 511 512 TRACE("=> %s,%d\n", debugstr_w(lf->lfFaceName), lf->lfHeight); 513 514 return Ok; 515 } 516 517 /******************************************************************************* 518 * GdipCloneFont [GDIPLUS.@] 519 */ 520 GpStatus WINGDIPAPI GdipCloneFont(GpFont *font, GpFont **cloneFont) 521 { 522 GpStatus stat; 523 524 TRACE("(%p, %p)\n", font, cloneFont); 525 526 if(!font || !cloneFont) 527 return InvalidParameter; 528 529 *cloneFont = heap_alloc_zero(sizeof(GpFont)); 530 if(!*cloneFont) return OutOfMemory; 531 532 **cloneFont = *font; 533 stat = GdipCloneFontFamily(font->family, &(*cloneFont)->family); 534 if (stat != Ok) heap_free(*cloneFont); 535 536 return stat; 537 } 538 539 /******************************************************************************* 540 * GdipGetFontHeight [GDIPLUS.@] 541 * PARAMS 542 * font [I] Font to retrieve height from 543 * graphics [I] The current graphics context 544 * height [O] Resulting height 545 * RETURNS 546 * SUCCESS: Ok 547 * FAILURE: Another element of GpStatus 548 * 549 * NOTES 550 * Forwards to GdipGetFontHeightGivenDPI 551 */ 552 GpStatus WINGDIPAPI GdipGetFontHeight(GDIPCONST GpFont *font, 553 GDIPCONST GpGraphics *graphics, REAL *height) 554 { 555 REAL dpi; 556 GpStatus stat; 557 REAL font_height; 558 559 TRACE("%p %p %p\n", font, graphics, height); 560 561 if (!font || !height) return InvalidParameter; 562 563 stat = GdipGetFontHeightGivenDPI(font, font->family->dpi, &font_height); 564 if (stat != Ok) return stat; 565 566 if (!graphics) 567 { 568 *height = font_height; 569 TRACE("%s,%d => %f\n", 570 debugstr_w(font->family->FamilyName), font->otm.otmTextMetrics.tmHeight, *height); 571 return Ok; 572 } 573 574 stat = GdipGetDpiY((GpGraphics *)graphics, &dpi); 575 if (stat != Ok) return stat; 576 577 *height = pixels_to_units(font_height, graphics->unit, dpi); 578 579 TRACE("%s,%d(unit %d) => %f\n", 580 debugstr_w(font->family->FamilyName), font->otm.otmTextMetrics.tmHeight, graphics->unit, *height); 581 return Ok; 582 } 583 584 /******************************************************************************* 585 * GdipGetFontHeightGivenDPI [GDIPLUS.@] 586 * PARAMS 587 * font [I] Font to retrieve DPI from 588 * dpi [I] DPI to assume 589 * height [O] Return value 590 * 591 * RETURNS 592 * SUCCESS: Ok 593 * FAILURE: InvalidParameter if font or height is NULL 594 * 595 * NOTES 596 * According to MSDN, the result is (lineSpacing)*(fontSize / emHeight)*dpi 597 * (for anything other than unit Pixel) 598 */ 599 GpStatus WINGDIPAPI GdipGetFontHeightGivenDPI(GDIPCONST GpFont *font, REAL dpi, REAL *height) 600 { 601 GpStatus stat; 602 INT style; 603 UINT16 line_spacing, em_height; 604 REAL font_size; 605 606 if (!font || !height) return InvalidParameter; 607 608 TRACE("%p (%s), %f, %p\n", font, 609 debugstr_w(font->family->FamilyName), dpi, height); 610 611 font_size = units_to_pixels(get_font_size(font), font->unit, dpi); 612 style = get_font_style(font); 613 stat = GdipGetLineSpacing(font->family, style, &line_spacing); 614 if (stat != Ok) return stat; 615 stat = GdipGetEmHeight(font->family, style, &em_height); 616 if (stat != Ok) return stat; 617 618 *height = (REAL)line_spacing * font_size / (REAL)em_height; 619 620 TRACE("%s,%d => %f\n", 621 debugstr_w(font->family->FamilyName), font->otm.otmTextMetrics.tmHeight, *height); 622 623 return Ok; 624 } 625 626 /*********************************************************************** 627 * Borrowed from GDI32: 628 * 629 * Elf is really an ENUMLOGFONTEXW, and ntm is a NEWTEXTMETRICEXW. 630 * We have to use other types because of the FONTENUMPROCW definition. 631 */ 632 static INT CALLBACK is_font_installed_proc(const LOGFONTW *elf, 633 const TEXTMETRICW *ntm, DWORD type, LPARAM lParam) 634 { 635 const ENUMLOGFONTW *elfW = (const ENUMLOGFONTW *)elf; 636 LOGFONTW *lf = (LOGFONTW *)lParam; 637 638 if (type & RASTER_FONTTYPE) 639 return 1; 640 641 *lf = *elf; 642 /* replace substituted font name by a real one */ 643 lstrcpynW(lf->lfFaceName, elfW->elfFullName, LF_FACESIZE); 644 return 0; 645 } 646 647 struct font_metrics 648 { 649 WCHAR facename[LF_FACESIZE]; 650 UINT16 em_height, ascent, descent, line_spacing; /* in font units */ 651 int dpi; 652 }; 653 654 static BOOL get_font_metrics(HDC hdc, struct font_metrics *fm) 655 { 656 OUTLINETEXTMETRICW otm; 657 TT_OS2_V2 tt_os2; 658 TT_HHEA tt_hori; 659 LONG size; 660 UINT16 line_gap; 661 662 otm.otmSize = sizeof(otm); 663 if (!GetOutlineTextMetricsW(hdc, otm.otmSize, &otm)) return FALSE; 664 665 fm->em_height = otm.otmEMSquare; 666 fm->dpi = GetDeviceCaps(hdc, LOGPIXELSY); 667 668 memset(&tt_hori, 0, sizeof(tt_hori)); 669 if (GetFontData(hdc, MS_HHEA_TAG, 0, &tt_hori, sizeof(tt_hori)) != GDI_ERROR) 670 { 671 fm->ascent = GET_BE_WORD(tt_hori.Ascender); 672 fm->descent = -GET_BE_WORD(tt_hori.Descender); 673 TRACE("hhea: ascent %d, descent %d\n", fm->ascent, fm->descent); 674 line_gap = GET_BE_WORD(tt_hori.LineGap); 675 fm->line_spacing = fm->ascent + fm->descent + line_gap; 676 TRACE("line_gap %u, line_spacing %u\n", line_gap, fm->line_spacing); 677 if (fm->ascent + fm->descent != 0) return TRUE; 678 } 679 680 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0); 681 if (size == GDI_ERROR) return FALSE; 682 683 if (size > sizeof(tt_os2)) size = sizeof(tt_os2); 684 685 memset(&tt_os2, 0, sizeof(tt_os2)); 686 if (GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size) != size) return FALSE; 687 688 fm->ascent = GET_BE_WORD(tt_os2.usWinAscent); 689 fm->descent = GET_BE_WORD(tt_os2.usWinDescent); 690 TRACE("usWinAscent %u, usWinDescent %u\n", fm->ascent, fm->descent); 691 if (fm->ascent + fm->descent == 0) 692 { 693 fm->ascent = GET_BE_WORD(tt_os2.sTypoAscender); 694 fm->descent = GET_BE_WORD(tt_os2.sTypoDescender); 695 TRACE("sTypoAscender %u, sTypoDescender %u\n", fm->ascent, fm->descent); 696 } 697 line_gap = GET_BE_WORD(tt_os2.sTypoLineGap); 698 fm->line_spacing = fm->ascent + fm->descent + line_gap; 699 TRACE("line_gap %u, line_spacing %u\n", line_gap, fm->line_spacing); 700 return TRUE; 701 } 702 703 static GpStatus find_installed_font(const WCHAR *name, struct font_metrics *fm) 704 { 705 LOGFONTW lf; 706 HDC hdc = CreateCompatibleDC(0); 707 GpStatus ret = FontFamilyNotFound; 708 709 if(!EnumFontFamiliesW(hdc, name, is_font_installed_proc, (LPARAM)&lf)) 710 { 711 HFONT hfont, old_font; 712 713 strcpyW(fm->facename, lf.lfFaceName); 714 715 hfont = CreateFontIndirectW(&lf); 716 old_font = SelectObject(hdc, hfont); 717 ret = get_font_metrics(hdc, fm) ? Ok : NotTrueTypeFont; 718 SelectObject(hdc, old_font); 719 DeleteObject(hfont); 720 } 721 722 DeleteDC(hdc); 723 return ret; 724 } 725 726 /******************************************************************************* 727 * GdipCreateFontFamilyFromName [GDIPLUS.@] 728 * 729 * Creates a font family object based on a supplied name 730 * 731 * PARAMS 732 * name [I] Name of the font 733 * fontCollection [I] What font collection (if any) the font belongs to (may be NULL) 734 * FontFamily [O] Pointer to the resulting FontFamily object 735 * 736 * RETURNS 737 * SUCCESS: Ok 738 * FAILURE: FamilyNotFound if the requested FontFamily does not exist on the system 739 * FAILURE: Invalid parameter if FontFamily or name is NULL 740 * 741 * NOTES 742 * If fontCollection is NULL then the object is not part of any collection 743 * 744 */ 745 746 GpStatus WINGDIPAPI GdipCreateFontFamilyFromName(GDIPCONST WCHAR *name, 747 GpFontCollection *fontCollection, 748 GpFontFamily **FontFamily) 749 { 750 GpStatus stat; 751 GpFontFamily* ffamily; 752 struct font_metrics fm; 753 754 TRACE("%s, %p %p\n", debugstr_w(name), fontCollection, FontFamily); 755 756 if (!(name && FontFamily)) 757 return InvalidParameter; 758 if (fontCollection) 759 FIXME("No support for FontCollections yet!\n"); 760 761 stat = find_installed_font(name, &fm); 762 if (stat != Ok) return stat; 763 764 ffamily = heap_alloc_zero(sizeof (GpFontFamily)); 765 if (!ffamily) return OutOfMemory; 766 767 lstrcpyW(ffamily->FamilyName, fm.facename); 768 ffamily->em_height = fm.em_height; 769 ffamily->ascent = fm.ascent; 770 ffamily->descent = fm.descent; 771 ffamily->line_spacing = fm.line_spacing; 772 ffamily->dpi = fm.dpi; 773 774 *FontFamily = ffamily; 775 776 TRACE("<-- %p\n", ffamily); 777 778 return Ok; 779 } 780 781 static GpStatus clone_font_family(const GpFontFamily *family, GpFontFamily **clone) 782 { 783 *clone = heap_alloc_zero(sizeof(GpFontFamily)); 784 if (!*clone) return OutOfMemory; 785 786 **clone = *family; 787 788 return Ok; 789 } 790 791 /******************************************************************************* 792 * GdipCloneFontFamily [GDIPLUS.@] 793 * 794 * Creates a deep copy of a Font Family object 795 * 796 * PARAMS 797 * FontFamily [I] Font to clone 798 * clonedFontFamily [O] The resulting cloned font 799 * 800 * RETURNS 801 * SUCCESS: Ok 802 */ 803 GpStatus WINGDIPAPI GdipCloneFontFamily(GpFontFamily* FontFamily, GpFontFamily** clonedFontFamily) 804 { 805 GpStatus status; 806 807 if (!(FontFamily && clonedFontFamily)) return InvalidParameter; 808 809 TRACE("%p (%s), %p\n", FontFamily, 810 debugstr_w(FontFamily->FamilyName), clonedFontFamily); 811 812 status = clone_font_family(FontFamily, clonedFontFamily); 813 if (status != Ok) return status; 814 815 TRACE("<-- %p\n", *clonedFontFamily); 816 817 return Ok; 818 } 819 820 /******************************************************************************* 821 * GdipGetFamilyName [GDIPLUS.@] 822 * 823 * Returns the family name into name 824 * 825 * PARAMS 826 * *family [I] Family to retrieve from 827 * *name [O] WCHARS of the family name 828 * LANGID [I] charset 829 * 830 * RETURNS 831 * SUCCESS: Ok 832 * FAILURE: InvalidParameter if family is NULL 833 * 834 * NOTES 835 * If name is a NULL ptr, then both XP and Vista will crash (so we do as well) 836 */ 837 GpStatus WINGDIPAPI GdipGetFamilyName (GDIPCONST GpFontFamily *family, 838 WCHAR *name, LANGID language) 839 { 840 static int lang_fixme; 841 842 if (family == NULL) 843 return InvalidParameter; 844 845 TRACE("%p, %p, %d\n", family, name, language); 846 847 if (language != LANG_NEUTRAL && !lang_fixme++) 848 FIXME("No support for handling of multiple languages!\n"); 849 850 lstrcpynW (name, family->FamilyName, LF_FACESIZE); 851 852 return Ok; 853 } 854 855 856 /***************************************************************************** 857 * GdipDeleteFontFamily [GDIPLUS.@] 858 * 859 * Removes the specified FontFamily 860 * 861 * PARAMS 862 * *FontFamily [I] The family to delete 863 * 864 * RETURNS 865 * SUCCESS: Ok 866 * FAILURE: InvalidParameter if FontFamily is NULL. 867 * 868 */ 869 GpStatus WINGDIPAPI GdipDeleteFontFamily(GpFontFamily *FontFamily) 870 { 871 if (!FontFamily) 872 return InvalidParameter; 873 TRACE("Deleting %p (%s)\n", FontFamily, debugstr_w(FontFamily->FamilyName)); 874 875 heap_free (FontFamily); 876 877 return Ok; 878 } 879 880 GpStatus WINGDIPAPI GdipGetCellAscent(GDIPCONST GpFontFamily *family, 881 INT style, UINT16* CellAscent) 882 { 883 if (!(family && CellAscent)) return InvalidParameter; 884 885 *CellAscent = family->ascent; 886 TRACE("%s => %u\n", debugstr_w(family->FamilyName), *CellAscent); 887 888 return Ok; 889 } 890 891 GpStatus WINGDIPAPI GdipGetCellDescent(GDIPCONST GpFontFamily *family, 892 INT style, UINT16* CellDescent) 893 { 894 TRACE("(%p, %d, %p)\n", family, style, CellDescent); 895 896 if (!(family && CellDescent)) return InvalidParameter; 897 898 *CellDescent = family->descent; 899 TRACE("%s => %u\n", debugstr_w(family->FamilyName), *CellDescent); 900 901 return Ok; 902 } 903 904 /******************************************************************************* 905 * GdipGetEmHeight [GDIPLUS.@] 906 * 907 * Gets the height of the specified family in EmHeights 908 * 909 * PARAMS 910 * family [I] Family to retrieve from 911 * style [I] (optional) style 912 * EmHeight [O] return value 913 * 914 * RETURNS 915 * SUCCESS: Ok 916 * FAILURE: InvalidParameter 917 */ 918 GpStatus WINGDIPAPI GdipGetEmHeight(GDIPCONST GpFontFamily *family, INT style, UINT16* EmHeight) 919 { 920 if (!(family && EmHeight)) return InvalidParameter; 921 922 TRACE("%p (%s), %d, %p\n", family, debugstr_w(family->FamilyName), style, EmHeight); 923 924 *EmHeight = family->em_height; 925 TRACE("%s => %u\n", debugstr_w(family->FamilyName), *EmHeight); 926 927 return Ok; 928 } 929 930 931 /******************************************************************************* 932 * GdipGetLineSpacing [GDIPLUS.@] 933 * 934 * Returns the line spacing in design units 935 * 936 * PARAMS 937 * family [I] Family to retrieve from 938 * style [I] (Optional) font style 939 * LineSpacing [O] Return value 940 * 941 * RETURNS 942 * SUCCESS: Ok 943 * FAILURE: InvalidParameter (family or LineSpacing was NULL) 944 */ 945 GpStatus WINGDIPAPI GdipGetLineSpacing(GDIPCONST GpFontFamily *family, 946 INT style, UINT16* LineSpacing) 947 { 948 TRACE("%p, %d, %p\n", family, style, LineSpacing); 949 950 if (!(family && LineSpacing)) 951 return InvalidParameter; 952 953 if (style) FIXME("ignoring style\n"); 954 955 *LineSpacing = family->line_spacing; 956 TRACE("%s => %u\n", debugstr_w(family->FamilyName), *LineSpacing); 957 958 return Ok; 959 } 960 961 static INT CALLBACK font_has_style_proc(const LOGFONTW *elf, 962 const TEXTMETRICW *ntm, DWORD type, LPARAM lParam) 963 { 964 INT fontstyle = FontStyleRegular; 965 966 if (!ntm) return 1; 967 968 if (ntm->tmWeight >= FW_BOLD) fontstyle |= FontStyleBold; 969 if (ntm->tmItalic) fontstyle |= FontStyleItalic; 970 if (ntm->tmUnderlined) fontstyle |= FontStyleUnderline; 971 if (ntm->tmStruckOut) fontstyle |= FontStyleStrikeout; 972 973 return (INT)lParam != fontstyle; 974 } 975 976 GpStatus WINGDIPAPI GdipIsStyleAvailable(GDIPCONST GpFontFamily* family, 977 INT style, BOOL* IsStyleAvailable) 978 { 979 HDC hdc; 980 981 TRACE("%p %d %p\n", family, style, IsStyleAvailable); 982 983 if (!(family && IsStyleAvailable)) 984 return InvalidParameter; 985 986 *IsStyleAvailable = FALSE; 987 988 hdc = CreateCompatibleDC(0); 989 990 if(!EnumFontFamiliesW(hdc, family->FamilyName, font_has_style_proc, (LPARAM)style)) 991 *IsStyleAvailable = TRUE; 992 993 DeleteDC(hdc); 994 995 return Ok; 996 } 997 998 /***************************************************************************** 999 * GdipGetGenericFontFamilyMonospace [GDIPLUS.@] 1000 * 1001 * Obtains a serif family (Courier New on Windows) 1002 * 1003 * PARAMS 1004 * **nativeFamily [I] Where the font will be stored 1005 * 1006 * RETURNS 1007 * InvalidParameter if nativeFamily is NULL. 1008 * Ok otherwise. 1009 */ 1010 GpStatus WINGDIPAPI GdipGetGenericFontFamilyMonospace(GpFontFamily **nativeFamily) 1011 { 1012 static const WCHAR CourierNew[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'}; 1013 static const WCHAR LiberationMono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o','\0'}; 1014 GpStatus stat; 1015 1016 if (nativeFamily == NULL) return InvalidParameter; 1017 1018 stat = GdipCreateFontFamilyFromName(CourierNew, NULL, nativeFamily); 1019 1020 if (stat == FontFamilyNotFound) 1021 stat = GdipCreateFontFamilyFromName(LiberationMono, NULL, nativeFamily); 1022 1023 if (stat == FontFamilyNotFound) 1024 ERR("Missing 'Courier New' font\n"); 1025 1026 return stat; 1027 } 1028 1029 /***************************************************************************** 1030 * GdipGetGenericFontFamilySerif [GDIPLUS.@] 1031 * 1032 * Obtains a serif family (Times New Roman on Windows) 1033 * 1034 * PARAMS 1035 * **nativeFamily [I] Where the font will be stored 1036 * 1037 * RETURNS 1038 * InvalidParameter if nativeFamily is NULL. 1039 * Ok otherwise. 1040 */ 1041 GpStatus WINGDIPAPI GdipGetGenericFontFamilySerif(GpFontFamily **nativeFamily) 1042 { 1043 static const WCHAR TimesNewRoman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'}; 1044 static const WCHAR LiberationSerif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f','\0'}; 1045 GpStatus stat; 1046 1047 TRACE("(%p)\n", nativeFamily); 1048 1049 if (nativeFamily == NULL) return InvalidParameter; 1050 1051 stat = GdipCreateFontFamilyFromName(TimesNewRoman, NULL, nativeFamily); 1052 1053 if (stat == FontFamilyNotFound) 1054 stat = GdipCreateFontFamilyFromName(LiberationSerif, NULL, nativeFamily); 1055 1056 if (stat == FontFamilyNotFound) 1057 ERR("Missing 'Times New Roman' font\n"); 1058 1059 return stat; 1060 } 1061 1062 /***************************************************************************** 1063 * GdipGetGenericFontFamilySansSerif [GDIPLUS.@] 1064 * 1065 * Obtains a serif family (Microsoft Sans Serif on Windows) 1066 * 1067 * PARAMS 1068 * **nativeFamily [I] Where the font will be stored 1069 * 1070 * RETURNS 1071 * InvalidParameter if nativeFamily is NULL. 1072 * Ok otherwise. 1073 */ 1074 GpStatus WINGDIPAPI GdipGetGenericFontFamilySansSerif(GpFontFamily **nativeFamily) 1075 { 1076 GpStatus stat; 1077 static const WCHAR MicrosoftSansSerif[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f','\0'}; 1078 static const WCHAR Tahoma[] = {'T','a','h','o','m','a','\0'}; 1079 1080 TRACE("(%p)\n", nativeFamily); 1081 1082 if (nativeFamily == NULL) return InvalidParameter; 1083 1084 stat = GdipCreateFontFamilyFromName(MicrosoftSansSerif, NULL, nativeFamily); 1085 1086 if (stat == FontFamilyNotFound) 1087 /* FIXME: Microsoft Sans Serif is not installed on Wine. */ 1088 stat = GdipCreateFontFamilyFromName(Tahoma, NULL, nativeFamily); 1089 1090 return stat; 1091 } 1092 1093 /***************************************************************************** 1094 * GdipGetGenericFontFamilySansSerif [GDIPLUS.@] 1095 */ 1096 GpStatus WINGDIPAPI GdipNewPrivateFontCollection(GpFontCollection** fontCollection) 1097 { 1098 TRACE("%p\n", fontCollection); 1099 1100 if (!fontCollection) 1101 return InvalidParameter; 1102 1103 *fontCollection = heap_alloc_zero(sizeof(GpFontCollection)); 1104 if (!*fontCollection) return OutOfMemory; 1105 1106 (*fontCollection)->FontFamilies = NULL; 1107 (*fontCollection)->count = 0; 1108 (*fontCollection)->allocated = 0; 1109 1110 TRACE("<-- %p\n", *fontCollection); 1111 1112 return Ok; 1113 } 1114 1115 /***************************************************************************** 1116 * GdipDeletePrivateFontCollection [GDIPLUS.@] 1117 */ 1118 GpStatus WINGDIPAPI GdipDeletePrivateFontCollection(GpFontCollection **fontCollection) 1119 { 1120 INT i; 1121 1122 TRACE("%p\n", fontCollection); 1123 1124 if (!fontCollection) 1125 return InvalidParameter; 1126 1127 for (i = 0; i < (*fontCollection)->count; i++) heap_free((*fontCollection)->FontFamilies[i]); 1128 heap_free((*fontCollection)->FontFamilies); 1129 heap_free(*fontCollection); 1130 1131 return Ok; 1132 } 1133 1134 /***************************************************************************** 1135 * GdipPrivateAddFontFile [GDIPLUS.@] 1136 */ 1137 GpStatus WINGDIPAPI GdipPrivateAddFontFile(GpFontCollection *collection, GDIPCONST WCHAR *name) 1138 { 1139 HANDLE file, mapping; 1140 LARGE_INTEGER size; 1141 void *mem; 1142 GpStatus status; 1143 1144 TRACE("%p, %s\n", collection, debugstr_w(name)); 1145 1146 if (!collection || !name) return InvalidParameter; 1147 1148 file = CreateFileW(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); 1149 if (file == INVALID_HANDLE_VALUE) return InvalidParameter; 1150 1151 if (!GetFileSizeEx(file, &size) || size.u.HighPart) 1152 { 1153 CloseHandle(file); 1154 return InvalidParameter; 1155 } 1156 1157 mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL); 1158 CloseHandle(file); 1159 if (!mapping) return InvalidParameter; 1160 1161 mem = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0); 1162 CloseHandle(mapping); 1163 if (!mem) return InvalidParameter; 1164 1165 /* GdipPrivateAddMemoryFont creates a copy of the memory block */ 1166 status = GdipPrivateAddMemoryFont(collection, mem, size.u.LowPart); 1167 UnmapViewOfFile(mem); 1168 1169 return status; 1170 } 1171 1172 #define TT_PLATFORM_APPLE_UNICODE 0 1173 #define TT_PLATFORM_MACINTOSH 1 1174 #define TT_PLATFORM_MICROSOFT 3 1175 1176 #define TT_APPLE_ID_DEFAULT 0 1177 #define TT_APPLE_ID_ISO_10646 2 1178 #define TT_APPLE_ID_UNICODE_2_0 3 1179 1180 #define TT_MS_ID_SYMBOL_CS 0 1181 #define TT_MS_ID_UNICODE_CS 1 1182 1183 #define TT_MAC_ID_SIMPLIFIED_CHINESE 25 1184 1185 #define NAME_ID_FULL_FONT_NAME 4 1186 1187 typedef struct { 1188 USHORT major_version; 1189 USHORT minor_version; 1190 USHORT tables_no; 1191 USHORT search_range; 1192 USHORT entry_selector; 1193 USHORT range_shift; 1194 } tt_header; 1195 1196 typedef struct { 1197 char tag[4]; /* table name */ 1198 ULONG check_sum; /* Check sum */ 1199 ULONG offset; /* Offset from beginning of file */ 1200 ULONG length; /* length of the table in bytes */ 1201 } tt_table_directory; 1202 1203 typedef struct { 1204 USHORT format; /* format selector. Always 0 */ 1205 USHORT count; /* Name Records count */ 1206 USHORT string_offset; /* Offset for strings storage, * from start of the table */ 1207 } tt_name_table; 1208 1209 typedef struct { 1210 USHORT platform_id; 1211 USHORT encoding_id; 1212 USHORT language_id; 1213 USHORT name_id; 1214 USHORT length; 1215 USHORT offset; /* from start of storage area */ 1216 } tt_name_record; 1217 1218 /* Copied from gdi32/freetype.c */ 1219 1220 static const LANGID mac_langid_table[] = 1221 { 1222 MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ENGLISH */ 1223 MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FRENCH */ 1224 MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GERMAN */ 1225 MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ITALIAN */ 1226 MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DUTCH */ 1227 MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWEDISH */ 1228 MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SPANISH */ 1229 MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DANISH */ 1230 MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PORTUGUESE */ 1231 MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NORWEGIAN */ 1232 MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HEBREW */ 1233 MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_JAPANESE */ 1234 MAKELANGID(LANG_ARABIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARABIC */ 1235 MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FINNISH */ 1236 MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREEK */ 1237 MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ICELANDIC */ 1238 MAKELANGID(LANG_MALTESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALTESE */ 1239 MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKISH */ 1240 MAKELANGID(LANG_CROATIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CROATIAN */ 1241 MAKELANGID(LANG_CHINESE_TRADITIONAL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */ 1242 MAKELANGID(LANG_URDU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_URDU */ 1243 MAKELANGID(LANG_HINDI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HINDI */ 1244 MAKELANGID(LANG_THAI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_THAI */ 1245 MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KOREAN */ 1246 MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LITHUANIAN */ 1247 MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_POLISH */ 1248 MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HUNGARIAN */ 1249 MAKELANGID(LANG_ESTONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESTONIAN */ 1250 MAKELANGID(LANG_LATVIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LETTISH */ 1251 MAKELANGID(LANG_SAMI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SAAMISK */ 1252 MAKELANGID(LANG_FAEROESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FAEROESE */ 1253 MAKELANGID(LANG_FARSI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FARSI */ 1254 MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_RUSSIAN */ 1255 MAKELANGID(LANG_CHINESE_SIMPLIFIED,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */ 1256 MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), /* TT_MAC_LANGID_FLEMISH */ 1257 MAKELANGID(LANG_IRISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_IRISH */ 1258 MAKELANGID(LANG_ALBANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ALBANIAN */ 1259 MAKELANGID(LANG_ROMANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ROMANIAN */ 1260 MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CZECH */ 1261 MAKELANGID(LANG_SLOVAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVAK */ 1262 MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVENIAN */ 1263 0, /* TT_MAC_LANGID_YIDDISH */ 1264 MAKELANGID(LANG_SERBIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SERBIAN */ 1265 MAKELANGID(LANG_MACEDONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MACEDONIAN */ 1266 MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BULGARIAN */ 1267 MAKELANGID(LANG_UKRAINIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UKRAINIAN */ 1268 MAKELANGID(LANG_BELARUSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BYELORUSSIAN */ 1269 MAKELANGID(LANG_UZBEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UZBEK */ 1270 MAKELANGID(LANG_KAZAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KAZAKH */ 1271 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_CYRILLIC), /* TT_MAC_LANGID_AZERBAIJANI */ 1272 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */ 1273 MAKELANGID(LANG_ARMENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARMENIAN */ 1274 MAKELANGID(LANG_GEORGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GEORGIAN */ 1275 0, /* TT_MAC_LANGID_MOLDAVIAN */ 1276 MAKELANGID(LANG_KYRGYZ,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KIRGHIZ */ 1277 MAKELANGID(LANG_TAJIK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAJIKI */ 1278 MAKELANGID(LANG_TURKMEN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKMEN */ 1279 MAKELANGID(LANG_MONGOLIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MONGOLIAN */ 1280 MAKELANGID(LANG_MONGOLIAN,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */ 1281 MAKELANGID(LANG_PASHTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PASHTO */ 1282 0, /* TT_MAC_LANGID_KURDISH */ 1283 MAKELANGID(LANG_KASHMIRI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KASHMIRI */ 1284 MAKELANGID(LANG_SINDHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINDHI */ 1285 MAKELANGID(LANG_TIBETAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIBETAN */ 1286 MAKELANGID(LANG_NEPALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NEPALI */ 1287 MAKELANGID(LANG_SANSKRIT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SANSKRIT */ 1288 MAKELANGID(LANG_MARATHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MARATHI */ 1289 MAKELANGID(LANG_BENGALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BENGALI */ 1290 MAKELANGID(LANG_ASSAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ASSAMESE */ 1291 MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GUJARATI */ 1292 MAKELANGID(LANG_PUNJABI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PUNJABI */ 1293 MAKELANGID(LANG_ORIYA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ORIYA */ 1294 MAKELANGID(LANG_MALAYALAM,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAYALAM */ 1295 MAKELANGID(LANG_KANNADA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KANNADA */ 1296 MAKELANGID(LANG_TAMIL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAMIL */ 1297 MAKELANGID(LANG_TELUGU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TELUGU */ 1298 MAKELANGID(LANG_SINHALESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINHALESE */ 1299 0, /* TT_MAC_LANGID_BURMESE */ 1300 MAKELANGID(LANG_KHMER,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KHMER */ 1301 MAKELANGID(LANG_LAO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LAO */ 1302 MAKELANGID(LANG_VIETNAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_VIETNAMESE */ 1303 MAKELANGID(LANG_INDONESIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INDONESIAN */ 1304 0, /* TT_MAC_LANGID_TAGALOG */ 1305 MAKELANGID(LANG_MALAY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */ 1306 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */ 1307 MAKELANGID(LANG_AMHARIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AMHARIC */ 1308 MAKELANGID(LANG_TIGRIGNA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIGRINYA */ 1309 0, /* TT_MAC_LANGID_GALLA */ 1310 0, /* TT_MAC_LANGID_SOMALI */ 1311 MAKELANGID(LANG_SWAHILI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWAHILI */ 1312 0, /* TT_MAC_LANGID_RUANDA */ 1313 0, /* TT_MAC_LANGID_RUNDI */ 1314 0, /* TT_MAC_LANGID_CHEWA */ 1315 MAKELANGID(LANG_MALAGASY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAGASY */ 1316 MAKELANGID(LANG_ESPERANTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESPERANTO */ 1317 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */ 1318 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */ 1319 MAKELANGID(LANG_WELSH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_WELSH */ 1320 MAKELANGID(LANG_BASQUE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BASQUE */ 1321 MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CATALAN */ 1322 0, /* TT_MAC_LANGID_LATIN */ 1323 MAKELANGID(LANG_QUECHUA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_QUECHUA */ 1324 0, /* TT_MAC_LANGID_GUARANI */ 1325 0, /* TT_MAC_LANGID_AYMARA */ 1326 MAKELANGID(LANG_TATAR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TATAR */ 1327 MAKELANGID(LANG_UIGHUR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UIGHUR */ 1328 0, /* TT_MAC_LANGID_DZONGKHA */ 1329 0, /* TT_MAC_LANGID_JAVANESE */ 1330 0, /* TT_MAC_LANGID_SUNDANESE */ 1331 MAKELANGID(LANG_GALICIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GALICIAN */ 1332 MAKELANGID(LANG_AFRIKAANS,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AFRIKAANS */ 1333 MAKELANGID(LANG_BRETON,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BRETON */ 1334 MAKELANGID(LANG_INUKTITUT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INUKTITUT */ 1335 MAKELANGID(LANG_SCOTTISH_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SCOTTISH_GAELIC */ 1336 MAKELANGID(LANG_MANX_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MANX_GAELIC */ 1337 MAKELANGID(LANG_IRISH,SUBLANG_IRISH_IRELAND), /* TT_MAC_LANGID_IRISH_GAELIC */ 1338 0, /* TT_MAC_LANGID_TONGAN */ 1339 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */ 1340 MAKELANGID(LANG_GREENLANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREELANDIC */ 1341 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_LATIN), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */ 1342 }; 1343 1344 static inline WORD get_mac_code_page( const tt_name_record *name ) 1345 { 1346 WORD encoding_id = GET_BE_WORD(name->encoding_id); 1347 if (encoding_id == TT_MAC_ID_SIMPLIFIED_CHINESE) return 10008; /* special case */ 1348 return 10000 + encoding_id; 1349 } 1350 1351 static int match_name_table_language( const tt_name_record *name, LANGID lang ) 1352 { 1353 LANGID name_lang; 1354 1355 switch (GET_BE_WORD(name->platform_id)) 1356 { 1357 case TT_PLATFORM_MICROSOFT: 1358 switch (GET_BE_WORD(name->encoding_id)) 1359 { 1360 case TT_MS_ID_UNICODE_CS: 1361 case TT_MS_ID_SYMBOL_CS: 1362 name_lang = GET_BE_WORD(name->language_id); 1363 break; 1364 default: 1365 return 0; 1366 } 1367 break; 1368 case TT_PLATFORM_MACINTOSH: 1369 if (!IsValidCodePage( get_mac_code_page( name ))) return 0; 1370 name_lang = GET_BE_WORD(name->language_id); 1371 if (name_lang >= ARRAY_SIZE(mac_langid_table)) return 0; 1372 name_lang = mac_langid_table[name_lang]; 1373 break; 1374 case TT_PLATFORM_APPLE_UNICODE: 1375 switch (GET_BE_WORD(name->encoding_id)) 1376 { 1377 case TT_APPLE_ID_DEFAULT: 1378 case TT_APPLE_ID_ISO_10646: 1379 case TT_APPLE_ID_UNICODE_2_0: 1380 name_lang = GET_BE_WORD(name->language_id); 1381 if (name_lang >= ARRAY_SIZE(mac_langid_table)) return 0; 1382 name_lang = mac_langid_table[name_lang]; 1383 break; 1384 default: 1385 return 0; 1386 } 1387 break; 1388 default: 1389 return 0; 1390 } 1391 if (name_lang == lang) return 3; 1392 if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) return 2; 1393 if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) return 1; 1394 return 0; 1395 } 1396 1397 static WCHAR *copy_name_table_string( const tt_name_record *name, const BYTE *data ) 1398 { 1399 WORD name_len = GET_BE_WORD(name->length); 1400 WORD codepage; 1401 WCHAR *ret; 1402 int len; 1403 1404 switch (GET_BE_WORD(name->platform_id)) 1405 { 1406 case TT_PLATFORM_APPLE_UNICODE: 1407 case TT_PLATFORM_MICROSOFT: 1408 ret = heap_alloc((name_len / 2 + 1) * sizeof(WCHAR)); 1409 for (len = 0; len < name_len / 2; len++) 1410 ret[len] = (data[len * 2] << 8) | data[len * 2 + 1]; 1411 ret[len] = 0; 1412 return ret; 1413 case TT_PLATFORM_MACINTOSH: 1414 codepage = get_mac_code_page( name ); 1415 len = MultiByteToWideChar( codepage, 0, (char *)data, name_len, NULL, 0 ) + 1; 1416 if (!len) 1417 return NULL; 1418 ret = heap_alloc(len * sizeof(WCHAR)); 1419 len = MultiByteToWideChar( codepage, 0, (char *)data, name_len, ret, len - 1 ); 1420 ret[len] = 0; 1421 return ret; 1422 } 1423 return NULL; 1424 } 1425 1426 static WCHAR *load_ttf_name_id( const BYTE *mem, DWORD_PTR size, DWORD id ) 1427 { 1428 LANGID lang = GetSystemDefaultLangID(); 1429 const tt_header *header; 1430 const tt_name_table *name_table; 1431 const tt_name_record *name_record; 1432 DWORD pos, ofs, count; 1433 int i, res, best_lang = 0, best_index = -1; 1434 1435 if (sizeof(tt_header) > size) 1436 return NULL; 1437 header = (const tt_header*)mem; 1438 count = GET_BE_WORD(header->tables_no); 1439 1440 if (GET_BE_WORD(header->major_version) != 1 || GET_BE_WORD(header->minor_version) != 0) 1441 return NULL; 1442 1443 pos = sizeof(*header); 1444 for (i = 0; i < count; i++) 1445 { 1446 const tt_table_directory *table_directory = (const tt_table_directory*)&mem[pos]; 1447 pos += sizeof(*table_directory); 1448 if (memcmp(table_directory->tag, "name", 4) == 0) 1449 { 1450 ofs = GET_BE_DWORD(table_directory->offset); 1451 break; 1452 } 1453 } 1454 if (i >= count) 1455 return NULL; 1456 1457 if (ofs >= size) 1458 return NULL; 1459 pos = ofs + sizeof(*name_table); 1460 if (pos > size) 1461 return NULL; 1462 name_table = (const tt_name_table*)&mem[ofs]; 1463 count = GET_BE_WORD(name_table->count); 1464 if (GET_BE_WORD(name_table->string_offset) >= size - ofs) return NULL; 1465 ofs += GET_BE_WORD(name_table->string_offset); 1466 for (i=0; i<count; i++) 1467 { 1468 name_record = (const tt_name_record*)&mem[pos]; 1469 pos += sizeof(*name_record); 1470 if (pos > size) 1471 return NULL; 1472 1473 if (GET_BE_WORD(name_record->name_id) != id) continue; 1474 if (GET_BE_WORD(name_record->offset) >= size - ofs) return NULL; 1475 if (GET_BE_WORD(name_record->length) > size - ofs - GET_BE_WORD(name_record->offset)) return NULL; 1476 1477 res = match_name_table_language( name_record, lang ); 1478 if (res > best_lang) 1479 { 1480 best_lang = res; 1481 best_index = i; 1482 } 1483 } 1484 1485 if (best_lang) 1486 { 1487 WCHAR *ret; 1488 name_record = (const tt_name_record*)(name_table + 1) + best_index; 1489 ret = copy_name_table_string( name_record, mem+ofs+GET_BE_WORD(name_record->offset) ); 1490 TRACE( "name %u found platform %u lang %04x %s\n", GET_BE_WORD(name_record->name_id), 1491 GET_BE_WORD(name_record->platform_id), GET_BE_WORD(name_record->language_id), debugstr_w( ret )); 1492 return ret; 1493 } 1494 return NULL; 1495 } 1496 1497 struct add_font_param 1498 { 1499 GpFontCollection *collection; 1500 BOOL is_system; 1501 GpStatus stat; 1502 }; 1503 1504 static INT CALLBACK add_font_proc(const LOGFONTW *lfw, const TEXTMETRICW *ntm, DWORD type, LPARAM lParam); 1505 1506 /***************************************************************************** 1507 * GdipPrivateAddMemoryFont [GDIPLUS.@] 1508 */ 1509 GpStatus WINGDIPAPI GdipPrivateAddMemoryFont(GpFontCollection* fontCollection, 1510 GDIPCONST void* memory, INT length) 1511 { 1512 WCHAR *name; 1513 DWORD count = 0; 1514 HANDLE font; 1515 GpStatus ret = Ok; 1516 TRACE("%p, %p, %d\n", fontCollection, memory, length); 1517 1518 if (!fontCollection || !memory || !length) 1519 return InvalidParameter; 1520 1521 name = load_ttf_name_id(memory, length, NAME_ID_FULL_FONT_NAME); 1522 if (!name) 1523 return OutOfMemory; 1524 1525 font = AddFontMemResourceEx((void*)memory, length, NULL, &count); 1526 TRACE("%s: %p/%u\n", debugstr_w(name), font, count); 1527 if (!font || !count) 1528 ret = InvalidParameter; 1529 else 1530 { 1531 struct add_font_param param; 1532 HDC hdc; 1533 LOGFONTW lfw; 1534 1535 hdc = CreateCompatibleDC(0); 1536 1537 /* Truncate name if necessary, GDI32 can't deal with long names */ 1538 if(lstrlenW(name) > LF_FACESIZE - 1) 1539 name[LF_FACESIZE - 1] = 0; 1540 1541 lfw.lfCharSet = DEFAULT_CHARSET; 1542 lstrcpyW(lfw.lfFaceName, name); 1543 lfw.lfPitchAndFamily = 0; 1544 1545 param.collection = fontCollection; 1546 param.is_system = FALSE; 1547 if (!EnumFontFamiliesExW(hdc, &lfw, add_font_proc, (LPARAM)¶m, 0)) 1548 ret = param.stat; 1549 1550 DeleteDC(hdc); 1551 } 1552 heap_free(name); 1553 return ret; 1554 } 1555 1556 /***************************************************************************** 1557 * GdipGetFontCollectionFamilyCount [GDIPLUS.@] 1558 */ 1559 GpStatus WINGDIPAPI GdipGetFontCollectionFamilyCount( 1560 GpFontCollection* fontCollection, INT* numFound) 1561 { 1562 TRACE("%p, %p\n", fontCollection, numFound); 1563 1564 if (!(fontCollection && numFound)) 1565 return InvalidParameter; 1566 1567 *numFound = fontCollection->count; 1568 return Ok; 1569 } 1570 1571 /***************************************************************************** 1572 * GdipGetFontCollectionFamilyList [GDIPLUS.@] 1573 */ 1574 GpStatus WINGDIPAPI GdipGetFontCollectionFamilyList( 1575 GpFontCollection* fontCollection, INT numSought, 1576 GpFontFamily* gpfamilies[], INT* numFound) 1577 { 1578 INT i; 1579 GpStatus stat=Ok; 1580 1581 TRACE("%p, %d, %p, %p\n", fontCollection, numSought, gpfamilies, numFound); 1582 1583 if (!(fontCollection && gpfamilies && numFound)) 1584 return InvalidParameter; 1585 1586 memset(gpfamilies, 0, sizeof(*gpfamilies) * numSought); 1587 1588 for (i = 0; i < numSought && i < fontCollection->count && stat == Ok; i++) 1589 { 1590 stat = GdipCloneFontFamily(fontCollection->FontFamilies[i], &gpfamilies[i]); 1591 } 1592 1593 if (stat == Ok) 1594 *numFound = i; 1595 else 1596 { 1597 int numToFree=i; 1598 for (i=0; i<numToFree; i++) 1599 { 1600 GdipDeleteFontFamily(gpfamilies[i]); 1601 gpfamilies[i] = NULL; 1602 } 1603 } 1604 1605 return stat; 1606 } 1607 1608 void free_installed_fonts(void) 1609 { 1610 while (installedFontCollection.count) 1611 GdipDeleteFontFamily(installedFontCollection.FontFamilies[--installedFontCollection.count]); 1612 heap_free(installedFontCollection.FontFamilies); 1613 installedFontCollection.FontFamilies = NULL; 1614 installedFontCollection.allocated = 0; 1615 } 1616 1617 static INT CALLBACK add_font_proc(const LOGFONTW *lfw, const TEXTMETRICW *ntm, 1618 DWORD type, LPARAM lParam) 1619 { 1620 struct add_font_param *param = (struct add_font_param *)lParam; 1621 GpFontCollection *fonts = param->collection; 1622 GpFontFamily* family; 1623 GpStatus stat; 1624 int i; 1625 1626 param->stat = Ok; 1627 1628 if (type == RASTER_FONTTYPE) 1629 return 1; 1630 1631 /* skip rotated fonts */ 1632 if (lfw->lfFaceName[0] == '@') 1633 return 1; 1634 1635 if (fonts->count && strcmpiW(lfw->lfFaceName, fonts->FontFamilies[fonts->count-1]->FamilyName) == 0) 1636 return 1; 1637 1638 if (fonts->allocated == fonts->count) 1639 { 1640 INT new_alloc_count = fonts->allocated+50; 1641 GpFontFamily** new_family_list = heap_alloc(new_alloc_count*sizeof(void*)); 1642 1643 if (!new_family_list) 1644 { 1645 param->stat = OutOfMemory; 1646 return 0; 1647 } 1648 1649 memcpy(new_family_list, fonts->FontFamilies, fonts->count*sizeof(void*)); 1650 heap_free(fonts->FontFamilies); 1651 fonts->FontFamilies = new_family_list; 1652 fonts->allocated = new_alloc_count; 1653 } 1654 1655 if ((stat = GdipCreateFontFamilyFromName(lfw->lfFaceName, NULL, &family)) != Ok) 1656 { 1657 WARN("Failed to create font family for %s, status %d.\n", debugstr_w(lfw->lfFaceName), stat); 1658 if (param->is_system) 1659 return 1; 1660 param->stat = stat; 1661 return 0; 1662 } 1663 1664 /* skip duplicates */ 1665 for (i=0; i<fonts->count; i++) 1666 { 1667 if (strcmpiW(family->FamilyName, fonts->FontFamilies[i]->FamilyName) == 0) 1668 { 1669 GdipDeleteFontFamily(family); 1670 return 1; 1671 } 1672 } 1673 1674 fonts->FontFamilies[fonts->count++] = family; 1675 1676 return 1; 1677 } 1678 1679 GpStatus WINGDIPAPI GdipNewInstalledFontCollection( 1680 GpFontCollection** fontCollection) 1681 { 1682 TRACE("(%p)\n",fontCollection); 1683 1684 if (!fontCollection) 1685 return InvalidParameter; 1686 1687 if (installedFontCollection.count == 0) 1688 { 1689 struct add_font_param param; 1690 HDC hdc; 1691 LOGFONTW lfw; 1692 1693 hdc = CreateCompatibleDC(0); 1694 1695 lfw.lfCharSet = DEFAULT_CHARSET; 1696 lfw.lfFaceName[0] = 0; 1697 lfw.lfPitchAndFamily = 0; 1698 1699 param.collection = &installedFontCollection; 1700 param.is_system = TRUE; 1701 if (!EnumFontFamiliesExW(hdc, &lfw, add_font_proc, (LPARAM)¶m, 0)) 1702 { 1703 free_installed_fonts(); 1704 DeleteDC(hdc); 1705 return param.stat; 1706 } 1707 1708 DeleteDC(hdc); 1709 } 1710 1711 *fontCollection = &installedFontCollection; 1712 1713 return Ok; 1714 } 1715