ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

font.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.