Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenfont.c
Go to the documentation of this file.
00001 /* 00002 * Copyright (C) 2007 Google (Evan Stade) 00003 * Copyright (C) 2012 Dmitry Timoshkov 00004 * 00005 * This library is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU Lesser General Public 00007 * License as published by the Free Software Foundation; either 00008 * version 2.1 of the License, or (at your option) any later version. 00009 * 00010 * This library is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 * Lesser General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Lesser General Public 00016 * License along with this library; if not, write to the Free Software 00017 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00018 */ 00019 00020 #include <stdarg.h> 00021 00022 #include "windef.h" 00023 #include "winbase.h" 00024 #include "wingdi.h" 00025 #include "winnls.h" 00026 #include "winreg.h" 00027 #include "wine/debug.h" 00028 #include "wine/unicode.h" 00029 00030 WINE_DEFAULT_DEBUG_CHANNEL (gdiplus); 00031 00032 #include "objbase.h" 00033 00034 #include "gdiplus.h" 00035 #include "gdiplus_private.h" 00036 00037 /* PANOSE is 10 bytes in size, need to pack the structure properly */ 00038 #include "pshpack2.h" 00039 typedef struct 00040 { 00041 USHORT version; 00042 SHORT xAvgCharWidth; 00043 USHORT usWeightClass; 00044 USHORT usWidthClass; 00045 SHORT fsType; 00046 SHORT ySubscriptXSize; 00047 SHORT ySubscriptYSize; 00048 SHORT ySubscriptXOffset; 00049 SHORT ySubscriptYOffset; 00050 SHORT ySuperscriptXSize; 00051 SHORT ySuperscriptYSize; 00052 SHORT ySuperscriptXOffset; 00053 SHORT ySuperscriptYOffset; 00054 SHORT yStrikeoutSize; 00055 SHORT yStrikeoutPosition; 00056 SHORT sFamilyClass; 00057 PANOSE panose; 00058 ULONG ulUnicodeRange1; 00059 ULONG ulUnicodeRange2; 00060 ULONG ulUnicodeRange3; 00061 ULONG ulUnicodeRange4; 00062 CHAR achVendID[4]; 00063 USHORT fsSelection; 00064 USHORT usFirstCharIndex; 00065 USHORT usLastCharIndex; 00066 /* According to the Apple spec, original version didn't have the below fields, 00067 * version numbers were taken from the OpenType spec. 00068 */ 00069 /* version 0 (TrueType 1.5) */ 00070 USHORT sTypoAscender; 00071 USHORT sTypoDescender; 00072 USHORT sTypoLineGap; 00073 USHORT usWinAscent; 00074 USHORT usWinDescent; 00075 /* version 1 (TrueType 1.66) */ 00076 ULONG ulCodePageRange1; 00077 ULONG ulCodePageRange2; 00078 /* version 2 (OpenType 1.2) */ 00079 SHORT sxHeight; 00080 SHORT sCapHeight; 00081 USHORT usDefaultChar; 00082 USHORT usBreakChar; 00083 USHORT usMaxContext; 00084 } TT_OS2_V2; 00085 00086 typedef struct 00087 { 00088 ULONG Version; 00089 SHORT Ascender; 00090 SHORT Descender; 00091 SHORT LineGap; 00092 USHORT advanceWidthMax; 00093 SHORT minLeftSideBearing; 00094 SHORT minRightSideBearing; 00095 SHORT xMaxExtent; 00096 SHORT caretSlopeRise; 00097 SHORT caretSlopeRun; 00098 SHORT caretOffset; 00099 SHORT reserved[4]; 00100 SHORT metricDataFormat; 00101 USHORT numberOfHMetrics; 00102 } TT_HHEA; 00103 #include "poppack.h" 00104 00105 #ifdef WORDS_BIGENDIAN 00106 #define GET_BE_WORD(x) (x) 00107 #define GET_BE_DWORD(x) (x) 00108 #else 00109 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x)) 00110 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x))); 00111 #endif 00112 00113 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \ 00114 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \ 00115 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24)) 00116 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2') 00117 #define MS_HHEA_TAG MS_MAKE_TAG('h','h','e','a') 00118 00119 static const REAL mm_per_inch = 25.4; 00120 static const REAL inch_per_point = 1.0/72.0; 00121 00122 static GpFontCollection installedFontCollection = {0}; 00123 00124 static LONG em_size_to_pixel(REAL em_size, Unit unit, LONG dpi) 00125 { 00126 switch (unit) 00127 { 00128 default: 00129 FIXME("Unhandled unit type: %d\n", unit); 00130 return 0; 00131 00132 case UnitPixel: 00133 case UnitWorld: 00134 /* FIXME: Figure out when World != Pixel */ 00135 return em_size; 00136 case UnitDisplay: 00137 FIXME("Unknown behavior for UnitDisplay! Please report!\n"); 00138 /* FIXME: Figure out how this works... 00139 * MSDN says that if "DISPLAY" is a monitor, then pixel should be 00140 * used. That's not what I got. Tests on Windows revealed no output, 00141 * and the tests in tests/font crash windows */ 00142 return 0; 00143 case UnitPoint: 00144 return em_size * dpi * inch_per_point; 00145 case UnitInch: 00146 return em_size * dpi; 00147 case UnitDocument: 00148 return em_size * dpi / 300.0; /* Per MSDN */ 00149 case UnitMillimeter: 00150 return em_size * dpi / mm_per_inch; 00151 } 00152 } 00153 00154 /******************************************************************************* 00155 * GdipCreateFont [GDIPLUS.@] 00156 * 00157 * Create a new font based off of a FontFamily 00158 * 00159 * PARAMS 00160 * *fontFamily [I] Family to base the font off of 00161 * emSize [I] Size of the font 00162 * style [I] Bitwise OR of FontStyle enumeration 00163 * unit [I] Unit emSize is measured in 00164 * **font [I] the resulting Font object 00165 * 00166 * RETURNS 00167 * SUCCESS: Ok 00168 * FAILURE: InvalidParameter if fontfamily or font is NULL. 00169 * FAILURE: FontFamilyNotFound if an invalid FontFamily is given 00170 * 00171 * NOTES 00172 * UnitDisplay is unsupported. 00173 * emSize is stored separately from lfHeight, to hold the fraction. 00174 */ 00175 GpStatus WINGDIPAPI GdipCreateFont(GDIPCONST GpFontFamily *fontFamily, 00176 REAL emSize, INT style, Unit unit, GpFont **font) 00177 { 00178 HFONT hfont; 00179 OUTLINETEXTMETRICW otm; 00180 LOGFONTW lfw; 00181 HDC hdc; 00182 GpStatus stat; 00183 int ret; 00184 00185 if (!fontFamily || !font || emSize < 0.0) 00186 return InvalidParameter; 00187 00188 TRACE("%p (%s), %f, %d, %d, %p\n", fontFamily, 00189 debugstr_w(fontFamily->FamilyName), emSize, style, unit, font); 00190 00191 memset(&lfw, 0, sizeof(lfw)); 00192 00193 stat = GdipGetFamilyName(fontFamily, lfw.lfFaceName, LANG_NEUTRAL); 00194 if (stat != Ok) return stat; 00195 00196 lfw.lfHeight = -em_size_to_pixel(emSize, unit, fontFamily->dpi); 00197 lfw.lfWeight = style & FontStyleBold ? FW_BOLD : FW_REGULAR; 00198 lfw.lfItalic = style & FontStyleItalic; 00199 lfw.lfUnderline = style & FontStyleUnderline; 00200 lfw.lfStrikeOut = style & FontStyleStrikeout; 00201 00202 hfont = CreateFontIndirectW(&lfw); 00203 hdc = CreateCompatibleDC(0); 00204 SelectObject(hdc, hfont); 00205 otm.otmSize = sizeof(otm); 00206 ret = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm); 00207 DeleteDC(hdc); 00208 DeleteObject(hfont); 00209 00210 if (!ret) return NotTrueTypeFont; 00211 00212 *font = GdipAlloc(sizeof(GpFont)); 00213 if (!*font) return OutOfMemory; 00214 00215 (*font)->unit = unit; 00216 (*font)->emSize = emSize; 00217 (*font)->otm = otm; 00218 00219 stat = GdipCloneFontFamily((GpFontFamily *)fontFamily, &(*font)->family); 00220 if (stat != Ok) 00221 { 00222 GdipFree(*font); 00223 return stat; 00224 } 00225 00226 TRACE("<-- %p\n", *font); 00227 00228 return Ok; 00229 } 00230 00231 /******************************************************************************* 00232 * GdipCreateFontFromLogfontW [GDIPLUS.@] 00233 */ 00234 GpStatus WINGDIPAPI GdipCreateFontFromLogfontW(HDC hdc, 00235 GDIPCONST LOGFONTW *logfont, GpFont **font) 00236 { 00237 HFONT hfont, oldfont; 00238 OUTLINETEXTMETRICW otm; 00239 GpStatus stat; 00240 int ret; 00241 00242 TRACE("(%p, %p, %p)\n", hdc, logfont, font); 00243 00244 if (!hdc || !logfont || !font) 00245 return InvalidParameter; 00246 00247 hfont = CreateFontIndirectW(logfont); 00248 oldfont = SelectObject(hdc, hfont); 00249 otm.otmSize = sizeof(otm); 00250 ret = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm); 00251 SelectObject(hdc, oldfont); 00252 DeleteObject(hfont); 00253 00254 if (!ret) return NotTrueTypeFont; 00255 00256 *font = GdipAlloc(sizeof(GpFont)); 00257 if (!*font) return OutOfMemory; 00258 00259 (*font)->unit = UnitWorld; 00260 (*font)->emSize = otm.otmTextMetrics.tmAscent; 00261 (*font)->otm = otm; 00262 00263 stat = GdipCreateFontFamilyFromName(logfont->lfFaceName, NULL, &(*font)->family); 00264 if (stat != Ok) 00265 { 00266 GdipFree(*font); 00267 return NotTrueTypeFont; 00268 } 00269 00270 TRACE("<-- %p\n", *font); 00271 00272 return Ok; 00273 } 00274 00275 /******************************************************************************* 00276 * GdipCreateFontFromLogfontA [GDIPLUS.@] 00277 */ 00278 GpStatus WINGDIPAPI GdipCreateFontFromLogfontA(HDC hdc, 00279 GDIPCONST LOGFONTA *lfa, GpFont **font) 00280 { 00281 LOGFONTW lfw; 00282 00283 TRACE("(%p, %p, %p)\n", hdc, lfa, font); 00284 00285 if(!lfa || !font) 00286 return InvalidParameter; 00287 00288 memcpy(&lfw, lfa, FIELD_OFFSET(LOGFONTA,lfFaceName) ); 00289 00290 if(!MultiByteToWideChar(CP_ACP, 0, lfa->lfFaceName, -1, lfw.lfFaceName, LF_FACESIZE)) 00291 return GenericError; 00292 00293 return GdipCreateFontFromLogfontW(hdc, &lfw, font); 00294 } 00295 00296 /******************************************************************************* 00297 * GdipDeleteFont [GDIPLUS.@] 00298 */ 00299 GpStatus WINGDIPAPI GdipDeleteFont(GpFont* font) 00300 { 00301 TRACE("(%p)\n", font); 00302 00303 if(!font) 00304 return InvalidParameter; 00305 00306 GdipDeleteFontFamily(font->family); 00307 GdipFree(font); 00308 00309 return Ok; 00310 } 00311 00312 /******************************************************************************* 00313 * GdipCreateFontFromDC [GDIPLUS.@] 00314 */ 00315 GpStatus WINGDIPAPI GdipCreateFontFromDC(HDC hdc, GpFont **font) 00316 { 00317 HFONT hfont; 00318 LOGFONTW lfw; 00319 00320 TRACE("(%p, %p)\n", hdc, font); 00321 00322 if(!font) 00323 return InvalidParameter; 00324 00325 hfont = GetCurrentObject(hdc, OBJ_FONT); 00326 if(!hfont) 00327 return GenericError; 00328 00329 if(!GetObjectW(hfont, sizeof(LOGFONTW), &lfw)) 00330 return GenericError; 00331 00332 return GdipCreateFontFromLogfontW(hdc, &lfw, font); 00333 } 00334 00335 /******************************************************************************* 00336 * GdipGetFamily [GDIPLUS.@] 00337 * 00338 * Returns the FontFamily for the specified Font 00339 * 00340 * PARAMS 00341 * font [I] Font to request from 00342 * family [O] Resulting FontFamily object 00343 * 00344 * RETURNS 00345 * SUCCESS: Ok 00346 * FAILURE: An element of GpStatus 00347 */ 00348 GpStatus WINGDIPAPI GdipGetFamily(GpFont *font, GpFontFamily **family) 00349 { 00350 TRACE("%p %p\n", font, family); 00351 00352 if (!(font && family)) 00353 return InvalidParameter; 00354 00355 return GdipCloneFontFamily(font->family, family); 00356 } 00357 00358 /****************************************************************************** 00359 * GdipGetFontSize [GDIPLUS.@] 00360 * 00361 * Returns the size of the font in Units 00362 * 00363 * PARAMS 00364 * *font [I] The font to retrieve size from 00365 * *size [O] Pointer to hold retrieved value 00366 * 00367 * RETURNS 00368 * SUCCESS: Ok 00369 * FAILURE: InvalidParameter (font or size was NULL) 00370 * 00371 * NOTES 00372 * Size returned is actually emSize -- not internal size used for drawing. 00373 */ 00374 GpStatus WINGDIPAPI GdipGetFontSize(GpFont *font, REAL *size) 00375 { 00376 TRACE("(%p, %p)\n", font, size); 00377 00378 if (!(font && size)) return InvalidParameter; 00379 00380 *size = font->emSize; 00381 TRACE("%s,%d => %f\n", debugstr_w(font->family->FamilyName), font->otm.otmTextMetrics.tmHeight, *size); 00382 00383 return Ok; 00384 } 00385 00386 /******************************************************************************* 00387 * GdipGetFontStyle [GDIPLUS.@] 00388 * 00389 * Gets the font's style, returned in bitwise OR of FontStyle enumeration 00390 * 00391 * PARAMS 00392 * font [I] font to request from 00393 * style [O] resulting pointer to a FontStyle enumeration 00394 * 00395 * RETURNS 00396 * SUCCESS: Ok 00397 * FAILURE: InvalidParameter 00398 */ 00399 GpStatus WINGDIPAPI GdipGetFontStyle(GpFont *font, INT *style) 00400 { 00401 TRACE("%p %p\n", font, style); 00402 00403 if (!(font && style)) 00404 return InvalidParameter; 00405 00406 if (font->otm.otmTextMetrics.tmWeight > FW_REGULAR) 00407 *style = FontStyleBold; 00408 else 00409 *style = FontStyleRegular; 00410 if (font->otm.otmTextMetrics.tmItalic) 00411 *style |= FontStyleItalic; 00412 if (font->otm.otmTextMetrics.tmUnderlined) 00413 *style |= FontStyleUnderline; 00414 if (font->otm.otmTextMetrics.tmStruckOut) 00415 *style |= FontStyleStrikeout; 00416 00417 return Ok; 00418 } 00419 00420 /******************************************************************************* 00421 * GdipGetFontUnit [GDIPLUS.@] 00422 * 00423 * PARAMS 00424 * font [I] Font to retrieve from 00425 * unit [O] Return value 00426 * 00427 * RETURNS 00428 * FAILURE: font or unit was NULL 00429 * OK: otherwise 00430 */ 00431 GpStatus WINGDIPAPI GdipGetFontUnit(GpFont *font, Unit *unit) 00432 { 00433 TRACE("(%p, %p)\n", font, unit); 00434 00435 if (!(font && unit)) return InvalidParameter; 00436 00437 *unit = font->unit; 00438 TRACE("%s,%d => %d\n", debugstr_w(font->family->FamilyName), font->otm.otmTextMetrics.tmHeight, *unit); 00439 00440 return Ok; 00441 } 00442 00443 /******************************************************************************* 00444 * GdipGetLogFontA [GDIPLUS.@] 00445 */ 00446 GpStatus WINGDIPAPI GdipGetLogFontA(GpFont *font, GpGraphics *graphics, 00447 LOGFONTA *lfa) 00448 { 00449 GpStatus status; 00450 LOGFONTW lfw; 00451 00452 TRACE("(%p, %p, %p)\n", font, graphics, lfa); 00453 00454 status = GdipGetLogFontW(font, graphics, &lfw); 00455 if(status != Ok) 00456 return status; 00457 00458 memcpy(lfa, &lfw, FIELD_OFFSET(LOGFONTA,lfFaceName) ); 00459 00460 if(!WideCharToMultiByte(CP_ACP, 0, lfw.lfFaceName, -1, lfa->lfFaceName, LF_FACESIZE, NULL, NULL)) 00461 return GenericError; 00462 00463 return Ok; 00464 } 00465 00466 /******************************************************************************* 00467 * GdipGetLogFontW [GDIPLUS.@] 00468 */ 00469 GpStatus WINGDIPAPI GdipGetLogFontW(GpFont *font, GpGraphics *graphics, 00470 LOGFONTW *lfw) 00471 { 00472 TRACE("(%p, %p, %p)\n", font, graphics, lfw); 00473 00474 /* FIXME: use graphics */ 00475 if(!font || !graphics || !lfw) 00476 return InvalidParameter; 00477 00478 lfw->lfHeight = -font->otm.otmTextMetrics.tmAscent; 00479 lfw->lfWidth = 0; 00480 lfw->lfEscapement = 0; 00481 lfw->lfOrientation = 0; 00482 lfw->lfWeight = font->otm.otmTextMetrics.tmWeight; 00483 lfw->lfItalic = font->otm.otmTextMetrics.tmItalic ? 1 : 0; 00484 lfw->lfUnderline = font->otm.otmTextMetrics.tmUnderlined ? 1 : 0; 00485 lfw->lfStrikeOut = font->otm.otmTextMetrics.tmStruckOut ? 1 : 0; 00486 lfw->lfCharSet = font->otm.otmTextMetrics.tmCharSet; 00487 lfw->lfOutPrecision = OUT_DEFAULT_PRECIS; 00488 lfw->lfClipPrecision = CLIP_DEFAULT_PRECIS; 00489 lfw->lfQuality = DEFAULT_QUALITY; 00490 lfw->lfPitchAndFamily = 0; 00491 strcpyW(lfw->lfFaceName, font->family->FamilyName); 00492 00493 TRACE("=> %s,%d\n", debugstr_w(lfw->lfFaceName), lfw->lfHeight); 00494 00495 return Ok; 00496 } 00497 00498 /******************************************************************************* 00499 * GdipCloneFont [GDIPLUS.@] 00500 */ 00501 GpStatus WINGDIPAPI GdipCloneFont(GpFont *font, GpFont **cloneFont) 00502 { 00503 GpStatus stat; 00504 00505 TRACE("(%p, %p)\n", font, cloneFont); 00506 00507 if(!font || !cloneFont) 00508 return InvalidParameter; 00509 00510 *cloneFont = GdipAlloc(sizeof(GpFont)); 00511 if(!*cloneFont) return OutOfMemory; 00512 00513 **cloneFont = *font; 00514 stat = GdipCloneFontFamily(font->family, &(*cloneFont)->family); 00515 if (stat != Ok) GdipFree(*cloneFont); 00516 00517 return stat; 00518 } 00519 00520 /******************************************************************************* 00521 * GdipGetFontHeight [GDIPLUS.@] 00522 * PARAMS 00523 * font [I] Font to retrieve height from 00524 * graphics [I] The current graphics context 00525 * height [O] Resulting height 00526 * RETURNS 00527 * SUCCESS: Ok 00528 * FAILURE: Another element of GpStatus 00529 * 00530 * NOTES 00531 * Forwards to GdipGetFontHeightGivenDPI 00532 */ 00533 GpStatus WINGDIPAPI GdipGetFontHeight(GDIPCONST GpFont *font, 00534 GDIPCONST GpGraphics *graphics, REAL *height) 00535 { 00536 REAL dpi; 00537 GpStatus stat; 00538 00539 TRACE("%p %p %p\n", font, graphics, height); 00540 00541 if (graphics) 00542 { 00543 stat = GdipGetDpiY((GpGraphics*)graphics, &dpi); 00544 if (stat != Ok) return stat; 00545 } 00546 else 00547 dpi = font->family->dpi; 00548 00549 return GdipGetFontHeightGivenDPI(font, dpi, height); 00550 } 00551 00552 /******************************************************************************* 00553 * GdipGetFontHeightGivenDPI [GDIPLUS.@] 00554 * PARAMS 00555 * font [I] Font to retrieve DPI from 00556 * dpi [I] DPI to assume 00557 * height [O] Return value 00558 * 00559 * RETURNS 00560 * SUCCESS: Ok 00561 * FAILURE: InvalidParameter if font or height is NULL 00562 * 00563 * NOTES 00564 * According to MSDN, the result is (lineSpacing)*(fontSize / emHeight)*dpi 00565 * (for anything other than unit Pixel) 00566 */ 00567 GpStatus WINGDIPAPI GdipGetFontHeightGivenDPI(GDIPCONST GpFont *font, REAL dpi, REAL *height) 00568 { 00569 GpStatus stat; 00570 INT style; 00571 UINT16 line_spacing, em_height; 00572 REAL font_height, font_size; 00573 00574 if (!font || !height) return InvalidParameter; 00575 00576 TRACE("%p (%s), %f, %p\n", font, 00577 debugstr_w(font->family->FamilyName), dpi, height); 00578 00579 stat = GdipGetFontSize((GpFont *)font, &font_size); 00580 if (stat != Ok) return stat; 00581 stat = GdipGetFontStyle((GpFont *)font, &style); 00582 if (stat != Ok) return stat; 00583 stat = GdipGetLineSpacing(font->family, style, &line_spacing); 00584 if (stat != Ok) return stat; 00585 stat = GdipGetEmHeight(font->family, style, &em_height); 00586 if (stat != Ok) return stat; 00587 00588 font_height = (REAL)line_spacing * font_size / (REAL)em_height; 00589 00590 switch (font->unit) 00591 { 00592 case UnitPixel: 00593 case UnitWorld: 00594 *height = font_height; 00595 break; 00596 case UnitPoint: 00597 *height = font_height * dpi * inch_per_point; 00598 break; 00599 case UnitInch: 00600 *height = font_height * dpi; 00601 break; 00602 case UnitDocument: 00603 *height = font_height * (dpi / 300.0); 00604 break; 00605 case UnitMillimeter: 00606 *height = font_height * (dpi / mm_per_inch); 00607 break; 00608 default: 00609 FIXME("Unhandled unit type: %d\n", font->unit); 00610 return NotImplemented; 00611 } 00612 00613 TRACE("%s,%d(unit %d) => %f\n", 00614 debugstr_w(font->family->FamilyName), font->otm.otmTextMetrics.tmHeight, font->unit, *height); 00615 00616 return Ok; 00617 } 00618 00619 /*********************************************************************** 00620 * Borrowed from GDI32: 00621 * 00622 * Elf is really an ENUMLOGFONTEXW, and ntm is a NEWTEXTMETRICEXW. 00623 * We have to use other types because of the FONTENUMPROCW definition. 00624 */ 00625 static INT CALLBACK is_font_installed_proc(const LOGFONTW *elf, 00626 const TEXTMETRICW *ntm, DWORD type, LPARAM lParam) 00627 { 00628 if (type != TRUETYPE_FONTTYPE) 00629 return 1; 00630 00631 *(LOGFONTW *)lParam = *elf; 00632 00633 return 0; 00634 } 00635 00636 struct font_metrics 00637 { 00638 UINT16 em_height, ascent, descent, line_spacing; /* in font units */ 00639 int dpi; 00640 }; 00641 00642 static BOOL get_font_metrics(HDC hdc, struct font_metrics *fm) 00643 { 00644 OUTLINETEXTMETRICW otm; 00645 TT_OS2_V2 tt_os2; 00646 TT_HHEA tt_hori; 00647 LONG size; 00648 UINT16 line_gap; 00649 00650 otm.otmSize = sizeof(otm); 00651 if (!GetOutlineTextMetricsW(hdc, otm.otmSize, &otm)) return FALSE; 00652 00653 fm->em_height = otm.otmEMSquare; 00654 fm->dpi = GetDeviceCaps(hdc, LOGPIXELSY); 00655 00656 memset(&tt_hori, 0, sizeof(tt_hori)); 00657 if (GetFontData(hdc, MS_HHEA_TAG, 0, &tt_hori, sizeof(tt_hori)) != GDI_ERROR) 00658 { 00659 fm->ascent = GET_BE_WORD(tt_hori.Ascender); 00660 fm->descent = -GET_BE_WORD(tt_hori.Descender); 00661 TRACE("hhea: ascent %d, descent %d\n", fm->ascent, fm->descent); 00662 line_gap = GET_BE_WORD(tt_hori.LineGap); 00663 fm->line_spacing = fm->ascent + fm->descent + line_gap; 00664 TRACE("line_gap %u, line_spacing %u\n", line_gap, fm->line_spacing); 00665 if (fm->ascent + fm->descent != 0) return TRUE; 00666 } 00667 00668 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0); 00669 if (size == GDI_ERROR) return FALSE; 00670 00671 if (size > sizeof(tt_os2)) size = sizeof(tt_os2); 00672 00673 memset(&tt_os2, 0, sizeof(tt_os2)); 00674 if (GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size) != size) return FALSE; 00675 00676 fm->ascent = GET_BE_WORD(tt_os2.usWinAscent); 00677 fm->descent = GET_BE_WORD(tt_os2.usWinDescent); 00678 TRACE("usWinAscent %u, usWinDescent %u\n", fm->ascent, fm->descent); 00679 if (fm->ascent + fm->descent == 0) 00680 { 00681 fm->ascent = GET_BE_WORD(tt_os2.sTypoAscender); 00682 fm->descent = GET_BE_WORD(tt_os2.sTypoDescender); 00683 TRACE("sTypoAscender %u, sTypoDescender %u\n", fm->ascent, fm->descent); 00684 } 00685 line_gap = GET_BE_WORD(tt_os2.sTypoLineGap); 00686 fm->line_spacing = fm->ascent + fm->descent + line_gap; 00687 TRACE("line_gap %u, line_spacing %u\n", line_gap, fm->line_spacing); 00688 return TRUE; 00689 } 00690 00691 static GpStatus find_installed_font(const WCHAR *name, struct font_metrics *fm) 00692 { 00693 LOGFONTW lf; 00694 HDC hdc = CreateCompatibleDC(0); 00695 GpStatus ret = FontFamilyNotFound; 00696 00697 if(!EnumFontFamiliesW(hdc, name, is_font_installed_proc, (LPARAM)&lf)) 00698 { 00699 HFONT hfont, old_font; 00700 00701 hfont = CreateFontIndirectW(&lf); 00702 old_font = SelectObject(hdc, hfont); 00703 ret = get_font_metrics(hdc, fm) ? Ok : NotTrueTypeFont; 00704 SelectObject(hdc, old_font); 00705 DeleteObject(hfont); 00706 } 00707 00708 DeleteDC(hdc); 00709 return ret; 00710 } 00711 00712 /******************************************************************************* 00713 * GdipCreateFontFamilyFromName [GDIPLUS.@] 00714 * 00715 * Creates a font family object based on a supplied name 00716 * 00717 * PARAMS 00718 * name [I] Name of the font 00719 * fontCollection [I] What font collection (if any) the font belongs to (may be NULL) 00720 * FontFamily [O] Pointer to the resulting FontFamily object 00721 * 00722 * RETURNS 00723 * SUCCESS: Ok 00724 * FAILURE: FamilyNotFound if the requested FontFamily does not exist on the system 00725 * FAILURE: Invalid parameter if FontFamily or name is NULL 00726 * 00727 * NOTES 00728 * If fontCollection is NULL then the object is not part of any collection 00729 * 00730 */ 00731 00732 GpStatus WINGDIPAPI GdipCreateFontFamilyFromName(GDIPCONST WCHAR *name, 00733 GpFontCollection *fontCollection, 00734 GpFontFamily **FontFamily) 00735 { 00736 GpStatus stat; 00737 GpFontFamily* ffamily; 00738 struct font_metrics fm; 00739 00740 TRACE("%s, %p %p\n", debugstr_w(name), fontCollection, FontFamily); 00741 00742 if (!(name && FontFamily)) 00743 return InvalidParameter; 00744 if (fontCollection) 00745 FIXME("No support for FontCollections yet!\n"); 00746 00747 stat = find_installed_font(name, &fm); 00748 if (stat != Ok) return stat; 00749 00750 ffamily = GdipAlloc(sizeof (GpFontFamily)); 00751 if (!ffamily) return OutOfMemory; 00752 00753 lstrcpynW(ffamily->FamilyName, name, LF_FACESIZE); 00754 ffamily->em_height = fm.em_height; 00755 ffamily->ascent = fm.ascent; 00756 ffamily->descent = fm.descent; 00757 ffamily->line_spacing = fm.line_spacing; 00758 ffamily->dpi = fm.dpi; 00759 00760 *FontFamily = ffamily; 00761 00762 TRACE("<-- %p\n", ffamily); 00763 00764 return Ok; 00765 } 00766 00767 /******************************************************************************* 00768 * GdipCloneFontFamily [GDIPLUS.@] 00769 * 00770 * Creates a deep copy of a Font Family object 00771 * 00772 * PARAMS 00773 * FontFamily [I] Font to clone 00774 * clonedFontFamily [O] The resulting cloned font 00775 * 00776 * RETURNS 00777 * SUCCESS: Ok 00778 */ 00779 GpStatus WINGDIPAPI GdipCloneFontFamily(GpFontFamily* FontFamily, GpFontFamily** clonedFontFamily) 00780 { 00781 if (!(FontFamily && clonedFontFamily)) return InvalidParameter; 00782 00783 TRACE("%p (%s), %p\n", FontFamily, 00784 debugstr_w(FontFamily->FamilyName), clonedFontFamily); 00785 00786 *clonedFontFamily = GdipAlloc(sizeof(GpFontFamily)); 00787 if (!*clonedFontFamily) return OutOfMemory; 00788 00789 **clonedFontFamily = *FontFamily; 00790 lstrcpyW((*clonedFontFamily)->FamilyName, FontFamily->FamilyName); 00791 00792 TRACE("<-- %p\n", *clonedFontFamily); 00793 00794 return Ok; 00795 } 00796 00797 /******************************************************************************* 00798 * GdipGetFamilyName [GDIPLUS.@] 00799 * 00800 * Returns the family name into name 00801 * 00802 * PARAMS 00803 * *family [I] Family to retrieve from 00804 * *name [O] WCHARS of the family name 00805 * LANGID [I] charset 00806 * 00807 * RETURNS 00808 * SUCCESS: Ok 00809 * FAILURE: InvalidParameter if family is NULL 00810 * 00811 * NOTES 00812 * If name is a NULL ptr, then both XP and Vista will crash (so we do as well) 00813 */ 00814 GpStatus WINGDIPAPI GdipGetFamilyName (GDIPCONST GpFontFamily *family, 00815 WCHAR *name, LANGID language) 00816 { 00817 static int lang_fixme; 00818 00819 if (family == NULL) 00820 return InvalidParameter; 00821 00822 TRACE("%p, %p, %d\n", family, name, language); 00823 00824 if (language != LANG_NEUTRAL && !lang_fixme++) 00825 FIXME("No support for handling of multiple languages!\n"); 00826 00827 lstrcpynW (name, family->FamilyName, LF_FACESIZE); 00828 00829 return Ok; 00830 } 00831 00832 00833 /***************************************************************************** 00834 * GdipDeleteFontFamily [GDIPLUS.@] 00835 * 00836 * Removes the specified FontFamily 00837 * 00838 * PARAMS 00839 * *FontFamily [I] The family to delete 00840 * 00841 * RETURNS 00842 * SUCCESS: Ok 00843 * FAILURE: InvalidParameter if FontFamily is NULL. 00844 * 00845 */ 00846 GpStatus WINGDIPAPI GdipDeleteFontFamily(GpFontFamily *FontFamily) 00847 { 00848 if (!FontFamily) 00849 return InvalidParameter; 00850 TRACE("Deleting %p (%s)\n", FontFamily, debugstr_w(FontFamily->FamilyName)); 00851 00852 GdipFree (FontFamily); 00853 00854 return Ok; 00855 } 00856 00857 GpStatus WINGDIPAPI GdipGetCellAscent(GDIPCONST GpFontFamily *family, 00858 INT style, UINT16* CellAscent) 00859 { 00860 if (!(family && CellAscent)) return InvalidParameter; 00861 00862 *CellAscent = family->ascent; 00863 TRACE("%s => %u\n", debugstr_w(family->FamilyName), *CellAscent); 00864 00865 return Ok; 00866 } 00867 00868 GpStatus WINGDIPAPI GdipGetCellDescent(GDIPCONST GpFontFamily *family, 00869 INT style, UINT16* CellDescent) 00870 { 00871 TRACE("(%p, %d, %p)\n", family, style, CellDescent); 00872 00873 if (!(family && CellDescent)) return InvalidParameter; 00874 00875 *CellDescent = family->descent; 00876 TRACE("%s => %u\n", debugstr_w(family->FamilyName), *CellDescent); 00877 00878 return Ok; 00879 } 00880 00881 /******************************************************************************* 00882 * GdipGetEmHeight [GDIPLUS.@] 00883 * 00884 * Gets the height of the specified family in EmHeights 00885 * 00886 * PARAMS 00887 * family [I] Family to retrieve from 00888 * style [I] (optional) style 00889 * EmHeight [O] return value 00890 * 00891 * RETURNS 00892 * SUCCESS: Ok 00893 * FAILURE: InvalidParameter 00894 */ 00895 GpStatus WINGDIPAPI GdipGetEmHeight(GDIPCONST GpFontFamily *family, INT style, UINT16* EmHeight) 00896 { 00897 if (!(family && EmHeight)) return InvalidParameter; 00898 00899 TRACE("%p (%s), %d, %p\n", family, debugstr_w(family->FamilyName), style, EmHeight); 00900 00901 *EmHeight = family->em_height; 00902 TRACE("%s => %u\n", debugstr_w(family->FamilyName), *EmHeight); 00903 00904 return Ok; 00905 } 00906 00907 00908 /******************************************************************************* 00909 * GdipGetLineSpacing [GDIPLUS.@] 00910 * 00911 * Returns the line spacing in design units 00912 * 00913 * PARAMS 00914 * family [I] Family to retrieve from 00915 * style [I] (Optional) font style 00916 * LineSpacing [O] Return value 00917 * 00918 * RETURNS 00919 * SUCCESS: Ok 00920 * FAILURE: InvalidParameter (family or LineSpacing was NULL) 00921 */ 00922 GpStatus WINGDIPAPI GdipGetLineSpacing(GDIPCONST GpFontFamily *family, 00923 INT style, UINT16* LineSpacing) 00924 { 00925 TRACE("%p, %d, %p\n", family, style, LineSpacing); 00926 00927 if (!(family && LineSpacing)) 00928 return InvalidParameter; 00929 00930 if (style) FIXME("ignoring style\n"); 00931 00932 *LineSpacing = family->line_spacing; 00933 TRACE("%s => %u\n", debugstr_w(family->FamilyName), *LineSpacing); 00934 00935 return Ok; 00936 } 00937 00938 static INT CALLBACK font_has_style_proc(const LOGFONTW *elf, 00939 const TEXTMETRICW *ntm, DWORD type, LPARAM lParam) 00940 { 00941 INT fontstyle = FontStyleRegular; 00942 00943 if (!ntm) return 1; 00944 00945 if (ntm->tmWeight >= FW_BOLD) fontstyle |= FontStyleBold; 00946 if (ntm->tmItalic) fontstyle |= FontStyleItalic; 00947 if (ntm->tmUnderlined) fontstyle |= FontStyleUnderline; 00948 if (ntm->tmStruckOut) fontstyle |= FontStyleStrikeout; 00949 00950 return (INT)lParam != fontstyle; 00951 } 00952 00953 GpStatus WINGDIPAPI GdipIsStyleAvailable(GDIPCONST GpFontFamily* family, 00954 INT style, BOOL* IsStyleAvailable) 00955 { 00956 HDC hdc; 00957 00958 TRACE("%p %d %p\n", family, style, IsStyleAvailable); 00959 00960 if (!(family && IsStyleAvailable)) 00961 return InvalidParameter; 00962 00963 *IsStyleAvailable = FALSE; 00964 00965 hdc = GetDC(0); 00966 00967 if(!EnumFontFamiliesW(hdc, family->FamilyName, font_has_style_proc, (LPARAM)style)) 00968 *IsStyleAvailable = TRUE; 00969 00970 ReleaseDC(0, hdc); 00971 00972 return Ok; 00973 } 00974 00975 /***************************************************************************** 00976 * GdipGetGenericFontFamilyMonospace [GDIPLUS.@] 00977 * 00978 * Obtains a serif family (Courier New on Windows) 00979 * 00980 * PARAMS 00981 * **nativeFamily [I] Where the font will be stored 00982 * 00983 * RETURNS 00984 * InvalidParameter if nativeFamily is NULL. 00985 * Ok otherwise. 00986 */ 00987 GpStatus WINGDIPAPI GdipGetGenericFontFamilyMonospace(GpFontFamily **nativeFamily) 00988 { 00989 static const WCHAR CourierNew[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'}; 00990 static const WCHAR LiberationMono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o','\0'}; 00991 GpStatus stat; 00992 00993 if (nativeFamily == NULL) return InvalidParameter; 00994 00995 stat = GdipCreateFontFamilyFromName(CourierNew, NULL, nativeFamily); 00996 00997 if (stat == FontFamilyNotFound) 00998 stat = GdipCreateFontFamilyFromName(LiberationMono, NULL, nativeFamily); 00999 01000 if (stat == FontFamilyNotFound) 01001 ERR("Missing 'Courier New' font\n"); 01002 01003 return stat; 01004 } 01005 01006 /***************************************************************************** 01007 * GdipGetGenericFontFamilySerif [GDIPLUS.@] 01008 * 01009 * Obtains a serif family (Times New Roman on Windows) 01010 * 01011 * PARAMS 01012 * **nativeFamily [I] Where the font will be stored 01013 * 01014 * RETURNS 01015 * InvalidParameter if nativeFamily is NULL. 01016 * Ok otherwise. 01017 */ 01018 GpStatus WINGDIPAPI GdipGetGenericFontFamilySerif(GpFontFamily **nativeFamily) 01019 { 01020 static const WCHAR TimesNewRoman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'}; 01021 static const WCHAR LiberationSerif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f','\0'}; 01022 GpStatus stat; 01023 01024 TRACE("(%p)\n", nativeFamily); 01025 01026 if (nativeFamily == NULL) return InvalidParameter; 01027 01028 stat = GdipCreateFontFamilyFromName(TimesNewRoman, NULL, nativeFamily); 01029 01030 if (stat == FontFamilyNotFound) 01031 stat = GdipCreateFontFamilyFromName(LiberationSerif, NULL, nativeFamily); 01032 01033 if (stat == FontFamilyNotFound) 01034 ERR("Missing 'Times New Roman' font\n"); 01035 01036 return stat; 01037 } 01038 01039 /***************************************************************************** 01040 * GdipGetGenericFontFamilySansSerif [GDIPLUS.@] 01041 * 01042 * Obtains a serif family (Microsoft Sans Serif on Windows) 01043 * 01044 * PARAMS 01045 * **nativeFamily [I] Where the font will be stored 01046 * 01047 * RETURNS 01048 * InvalidParameter if nativeFamily is NULL. 01049 * Ok otherwise. 01050 */ 01051 GpStatus WINGDIPAPI GdipGetGenericFontFamilySansSerif(GpFontFamily **nativeFamily) 01052 { 01053 GpStatus stat; 01054 static const WCHAR MicrosoftSansSerif[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f','\0'}; 01055 static const WCHAR Tahoma[] = {'T','a','h','o','m','a','\0'}; 01056 01057 TRACE("(%p)\n", nativeFamily); 01058 01059 if (nativeFamily == NULL) return InvalidParameter; 01060 01061 stat = GdipCreateFontFamilyFromName(MicrosoftSansSerif, NULL, nativeFamily); 01062 01063 if (stat == FontFamilyNotFound) 01064 /* FIXME: Microsoft Sans Serif is not installed on Wine. */ 01065 stat = GdipCreateFontFamilyFromName(Tahoma, NULL, nativeFamily); 01066 01067 return stat; 01068 } 01069 01070 /***************************************************************************** 01071 * GdipGetGenericFontFamilySansSerif [GDIPLUS.@] 01072 */ 01073 GpStatus WINGDIPAPI GdipNewPrivateFontCollection(GpFontCollection** fontCollection) 01074 { 01075 TRACE("%p\n", fontCollection); 01076 01077 if (!fontCollection) 01078 return InvalidParameter; 01079 01080 *fontCollection = GdipAlloc(sizeof(GpFontCollection)); 01081 if (!*fontCollection) return OutOfMemory; 01082 01083 (*fontCollection)->FontFamilies = NULL; 01084 (*fontCollection)->count = 0; 01085 (*fontCollection)->allocated = 0; 01086 01087 TRACE("<-- %p\n", *fontCollection); 01088 01089 return Ok; 01090 } 01091 01092 /***************************************************************************** 01093 * GdipDeletePrivateFontCollection [GDIPLUS.@] 01094 */ 01095 GpStatus WINGDIPAPI GdipDeletePrivateFontCollection(GpFontCollection **fontCollection) 01096 { 01097 INT i; 01098 01099 TRACE("%p\n", fontCollection); 01100 01101 if (!fontCollection) 01102 return InvalidParameter; 01103 01104 for (i = 0; i < (*fontCollection)->count; i++) GdipFree((*fontCollection)->FontFamilies[i]); 01105 GdipFree(*fontCollection); 01106 01107 return Ok; 01108 } 01109 01110 /***************************************************************************** 01111 * GdipPrivateAddFontFile [GDIPLUS.@] 01112 */ 01113 GpStatus WINGDIPAPI GdipPrivateAddFontFile(GpFontCollection* fontCollection, 01114 GDIPCONST WCHAR* filename) 01115 { 01116 FIXME("stub: %p, %s\n", fontCollection, debugstr_w(filename)); 01117 01118 if (!(fontCollection && filename)) 01119 return InvalidParameter; 01120 01121 return NotImplemented; 01122 } 01123 01124 /* Copied from msi/font.c */ 01125 01126 typedef struct _tagTT_OFFSET_TABLE { 01127 USHORT uMajorVersion; 01128 USHORT uMinorVersion; 01129 USHORT uNumOfTables; 01130 USHORT uSearchRange; 01131 USHORT uEntrySelector; 01132 USHORT uRangeShift; 01133 } TT_OFFSET_TABLE; 01134 01135 typedef struct _tagTT_TABLE_DIRECTORY { 01136 char szTag[4]; /* table name */ 01137 ULONG uCheckSum; /* Check sum */ 01138 ULONG uOffset; /* Offset from beginning of file */ 01139 ULONG uLength; /* length of the table in bytes */ 01140 } TT_TABLE_DIRECTORY; 01141 01142 typedef struct _tagTT_NAME_TABLE_HEADER { 01143 USHORT uFSelector; /* format selector. Always 0 */ 01144 USHORT uNRCount; /* Name Records count */ 01145 USHORT uStorageOffset; /* Offset for strings storage, 01146 * from start of the table */ 01147 } TT_NAME_TABLE_HEADER; 01148 01149 #define NAME_ID_FULL_FONT_NAME 4 01150 #define NAME_ID_VERSION 5 01151 01152 typedef struct _tagTT_NAME_RECORD { 01153 USHORT uPlatformID; 01154 USHORT uEncodingID; 01155 USHORT uLanguageID; 01156 USHORT uNameID; 01157 USHORT uStringLength; 01158 USHORT uStringOffset; /* from start of storage area */ 01159 } TT_NAME_RECORD; 01160 01161 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x)) 01162 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x))) 01163 01164 /* 01165 * Code based off of code located here 01166 * http://www.codeproject.com/gdi/fontnamefromfile.asp 01167 */ 01168 static WCHAR *load_ttf_name_id( const char *mem, DWORD_PTR size, DWORD id, WCHAR *ret, DWORD len ) 01169 { 01170 const TT_TABLE_DIRECTORY *tblDir; 01171 TT_OFFSET_TABLE ttOffsetTable; 01172 TT_NAME_TABLE_HEADER ttNTHeader; 01173 TT_NAME_RECORD ttRecord; 01174 DWORD ofs, pos; 01175 int i; 01176 01177 if (sizeof(TT_OFFSET_TABLE) > size) 01178 return NULL; 01179 ttOffsetTable = *(TT_OFFSET_TABLE*)mem; 01180 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables); 01181 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion); 01182 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion); 01183 01184 if (ttOffsetTable.uMajorVersion != 1 || ttOffsetTable.uMinorVersion != 0) 01185 return NULL; 01186 01187 pos = sizeof(ttOffsetTable); 01188 for (i = 0; i < ttOffsetTable.uNumOfTables; i++) 01189 { 01190 tblDir = (const TT_TABLE_DIRECTORY*)&mem[pos]; 01191 pos += sizeof(*tblDir); 01192 if (memcmp(tblDir->szTag,"name",4)==0) 01193 { 01194 ofs = SWAPLONG(tblDir->uOffset); 01195 break; 01196 } 01197 } 01198 if (i >= ttOffsetTable.uNumOfTables) 01199 return NULL; 01200 01201 pos = ofs + sizeof(ttNTHeader); 01202 if (pos > size) 01203 return NULL; 01204 ttNTHeader = *(TT_NAME_TABLE_HEADER*)&mem[ofs]; 01205 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount); 01206 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset); 01207 for(i=0; i<ttNTHeader.uNRCount; i++) 01208 { 01209 ttRecord = *(TT_NAME_RECORD*)&mem[pos]; 01210 pos += sizeof(ttRecord); 01211 if (pos > size) 01212 return NULL; 01213 01214 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID); 01215 if (ttRecord.uNameID == id) 01216 { 01217 const char *buf; 01218 01219 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength); 01220 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset); 01221 if (ofs + ttRecord.uStringOffset + ttNTHeader.uStorageOffset + ttRecord.uStringLength > size) 01222 return NULL; 01223 buf = mem + ofs + ttRecord.uStringOffset + ttNTHeader.uStorageOffset; 01224 len = MultiByteToWideChar(CP_ACP, 0, buf, ttRecord.uStringLength, ret, len-1); 01225 ret[len] = 0; 01226 return ret; 01227 } 01228 } 01229 return NULL; 01230 } 01231 01232 static INT CALLBACK add_font_proc(const LOGFONTW *lfw, const TEXTMETRICW *ntm, DWORD type, LPARAM lParam); 01233 01234 /***************************************************************************** 01235 * GdipPrivateAddMemoryFont [GDIPLUS.@] 01236 */ 01237 GpStatus WINGDIPAPI GdipPrivateAddMemoryFont(GpFontCollection* fontCollection, 01238 GDIPCONST void* memory, INT length) 01239 { 01240 WCHAR buf[32], *name; 01241 DWORD count = 0; 01242 HANDLE font; 01243 TRACE("%p, %p, %d\n", fontCollection, memory, length); 01244 01245 if (!fontCollection || !memory || !length) 01246 return InvalidParameter; 01247 01248 name = load_ttf_name_id(memory, length, NAME_ID_FULL_FONT_NAME, buf, sizeof(buf)/sizeof(*buf)); 01249 if (!name) 01250 return OutOfMemory; 01251 01252 font = AddFontMemResourceEx((void*)memory, length, NULL, &count); 01253 TRACE("%s: %p/%u\n", debugstr_w(name), font, count); 01254 if (!font || !count) 01255 return InvalidParameter; 01256 01257 if (count) 01258 { 01259 HDC hdc; 01260 LOGFONTW lfw; 01261 01262 hdc = GetDC(0); 01263 01264 lfw.lfCharSet = DEFAULT_CHARSET; 01265 lstrcpyW(lfw.lfFaceName, name); 01266 lfw.lfPitchAndFamily = 0; 01267 01268 if (!EnumFontFamiliesExW(hdc, &lfw, add_font_proc, (LPARAM)fontCollection, 0)) 01269 { 01270 ReleaseDC(0, hdc); 01271 return OutOfMemory; 01272 } 01273 01274 ReleaseDC(0, hdc); 01275 } 01276 return Ok; 01277 } 01278 01279 /***************************************************************************** 01280 * GdipGetFontCollectionFamilyCount [GDIPLUS.@] 01281 */ 01282 GpStatus WINGDIPAPI GdipGetFontCollectionFamilyCount( 01283 GpFontCollection* fontCollection, INT* numFound) 01284 { 01285 TRACE("%p, %p\n", fontCollection, numFound); 01286 01287 if (!(fontCollection && numFound)) 01288 return InvalidParameter; 01289 01290 *numFound = fontCollection->count; 01291 return Ok; 01292 } 01293 01294 /***************************************************************************** 01295 * GdipGetFontCollectionFamilyList [GDIPLUS.@] 01296 */ 01297 GpStatus WINGDIPAPI GdipGetFontCollectionFamilyList( 01298 GpFontCollection* fontCollection, INT numSought, 01299 GpFontFamily* gpfamilies[], INT* numFound) 01300 { 01301 INT i; 01302 GpStatus stat=Ok; 01303 01304 TRACE("%p, %d, %p, %p\n", fontCollection, numSought, gpfamilies, numFound); 01305 01306 if (!(fontCollection && gpfamilies && numFound)) 01307 return InvalidParameter; 01308 01309 memset(gpfamilies, 0, sizeof(*gpfamilies) * numSought); 01310 01311 for (i = 0; i < numSought && i < fontCollection->count && stat == Ok; i++) 01312 { 01313 stat = GdipCloneFontFamily(fontCollection->FontFamilies[i], &gpfamilies[i]); 01314 } 01315 01316 if (stat == Ok) 01317 *numFound = i; 01318 else 01319 { 01320 int numToFree=i; 01321 for (i=0; i<numToFree; i++) 01322 { 01323 GdipDeleteFontFamily(gpfamilies[i]); 01324 gpfamilies[i] = NULL; 01325 } 01326 } 01327 01328 return stat; 01329 } 01330 01331 void free_installed_fonts(void) 01332 { 01333 while (installedFontCollection.count) 01334 GdipDeleteFontFamily(installedFontCollection.FontFamilies[--installedFontCollection.count]); 01335 HeapFree(GetProcessHeap(), 0, installedFontCollection.FontFamilies); 01336 installedFontCollection.FontFamilies = NULL; 01337 installedFontCollection.allocated = 0; 01338 } 01339 01340 static INT CALLBACK add_font_proc(const LOGFONTW *lfw, const TEXTMETRICW *ntm, 01341 DWORD type, LPARAM lParam) 01342 { 01343 GpFontCollection* fonts = (GpFontCollection*)lParam; 01344 int i; 01345 01346 if (type == RASTER_FONTTYPE) 01347 return 1; 01348 01349 /* skip duplicates */ 01350 for (i=0; i<fonts->count; i++) 01351 if (strcmpiW(lfw->lfFaceName, fonts->FontFamilies[i]->FamilyName) == 0) 01352 return 1; 01353 01354 if (fonts->allocated == fonts->count) 01355 { 01356 INT new_alloc_count = fonts->allocated+50; 01357 GpFontFamily** new_family_list = HeapAlloc(GetProcessHeap(), 0, new_alloc_count*sizeof(void*)); 01358 01359 if (!new_family_list) 01360 return 0; 01361 01362 memcpy(new_family_list, fonts->FontFamilies, fonts->count*sizeof(void*)); 01363 HeapFree(GetProcessHeap(), 0, fonts->FontFamilies); 01364 fonts->FontFamilies = new_family_list; 01365 fonts->allocated = new_alloc_count; 01366 } 01367 01368 if (GdipCreateFontFamilyFromName(lfw->lfFaceName, NULL, &fonts->FontFamilies[fonts->count]) == Ok) 01369 fonts->count++; 01370 else 01371 return 0; 01372 01373 return 1; 01374 } 01375 01376 GpStatus WINGDIPAPI GdipNewInstalledFontCollection( 01377 GpFontCollection** fontCollection) 01378 { 01379 TRACE("(%p)\n",fontCollection); 01380 01381 if (!fontCollection) 01382 return InvalidParameter; 01383 01384 if (installedFontCollection.count == 0) 01385 { 01386 HDC hdc; 01387 LOGFONTW lfw; 01388 01389 hdc = GetDC(0); 01390 01391 lfw.lfCharSet = DEFAULT_CHARSET; 01392 lfw.lfFaceName[0] = 0; 01393 lfw.lfPitchAndFamily = 0; 01394 01395 if (!EnumFontFamiliesExW(hdc, &lfw, add_font_proc, (LPARAM)&installedFontCollection, 0)) 01396 { 01397 free_installed_fonts(); 01398 ReleaseDC(0, hdc); 01399 return OutOfMemory; 01400 } 01401 01402 ReleaseDC(0, hdc); 01403 } 01404 01405 *fontCollection = &installedFontCollection; 01406 01407 return Ok; 01408 } Generated on Sun May 27 2012 04:20:51 for ReactOS by
1.7.6.1
|