Autosyncing with Wine HEAD
[reactos.git] / reactos / dll / win32 / gdiplus / font.c
index a05ef75..78de0a6 100644 (file)
 #include "winbase.h"
 #include "wingdi.h"
 #include "winnls.h"
+#include "winreg.h"
+#include "wine/debug.h"
+#include "wine/unicode.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL (gdiplus);
 
 #include "objbase.h"
 
 #include "gdiplus.h"
 #include "gdiplus_private.h"
 
+static const REAL mm_per_inch = 25.4;
+static const REAL inch_per_point = 1.0/72.0;
+
+static inline REAL get_dpi (void)
+{
+    REAL dpi;
+    GpGraphics *graphics;
+    HDC hdc = GetDC(0);
+    GdipCreateFromHDC (hdc, &graphics);
+    GdipGetDpiX(graphics, &dpi);
+    GdipDeleteGraphics(graphics);
+    ReleaseDC (0, hdc);
+
+    return dpi;
+}
+
+static inline REAL point_to_pixel (REAL point)
+{
+    return point * get_dpi() * inch_per_point;
+}
+
+static inline REAL inch_to_pixel (REAL inch)
+{
+    return inch * get_dpi();
+}
+
+static inline REAL document_to_pixel (REAL doc)
+{
+    return doc * (get_dpi() / 300.0); /* Per MSDN */
+}
+
+static inline REAL mm_to_pixel (REAL mm)
+{
+    return mm * (get_dpi() / mm_per_inch);
+}
+
+/*******************************************************************************
+ * GdipCreateFont [GDIPLUS.@]
+ *
+ * Create a new font based off of a FontFamily
+ *
+ * PARAMS
+ *  *fontFamily     [I] Family to base the font off of
+ *  emSize          [I] Size of the font
+ *  style           [I] Bitwise OR of FontStyle enumeration
+ *  unit            [I] Unit emSize is measured in
+ *  **font          [I] the resulting Font object
+ *
+ * RETURNS
+ *  SUCCESS: Ok
+ *  FAILURE: InvalidParameter if fontfamily or font is NULL.
+ *  FAILURE: FontFamilyNotFound if an invalid FontFamily is given
+ *
+ * NOTES
+ *  UnitDisplay is unsupported.
+ *  emSize is stored separately from lfHeight, to hold the fraction.
+ */
+GpStatus WINGDIPAPI GdipCreateFont(GDIPCONST GpFontFamily *fontFamily,
+                        REAL emSize, INT style, Unit unit, GpFont **font)
+{
+    WCHAR facename[LF_FACESIZE];
+    LOGFONTW* lfw;
+    const TEXTMETRICW* tmw;
+    GpStatus stat;
+
+    if (!fontFamily || !fontFamily->FamilyName || !font)
+        return InvalidParameter;
+
+    TRACE("%p (%s), %f, %d, %d, %p\n", fontFamily,
+            debugstr_w(fontFamily->FamilyName), emSize, style, unit, font);
+
+    stat = GdipGetFamilyName (fontFamily, facename, 0);
+    if (stat != Ok) return stat;
+    *font = GdipAlloc(sizeof(GpFont));
+
+    tmw = &fontFamily->tmw;
+    lfw = &((*font)->lfw);
+    ZeroMemory(&(*lfw), sizeof(*lfw));
+
+    lfw->lfWeight = tmw->tmWeight;
+    lfw->lfItalic = tmw->tmItalic;
+    lfw->lfUnderline = tmw->tmUnderlined;
+    lfw->lfStrikeOut = tmw->tmStruckOut;
+    lfw->lfCharSet = tmw->tmCharSet;
+    lfw->lfPitchAndFamily = tmw->tmPitchAndFamily;
+    lstrcpynW((lfw->lfFaceName), facename, sizeof(WCHAR) * LF_FACESIZE);
+
+    switch (unit)
+    {
+        case UnitWorld:
+            /* FIXME: Figure out when World != Pixel */
+            lfw->lfHeight = emSize; break;
+        case UnitDisplay:
+            FIXME("Unknown behavior for UnitDisplay! Please report!\n");
+            /* FIXME: Figure out how this works...
+             * MSDN says that if "DISPLAY" is a monitor, then pixel should be
+             * used. That's not what I got. Tests on Windows revealed no output,
+             * and the tests in tests/font crash windows */
+            lfw->lfHeight = 0; break;
+        case UnitPixel:
+            lfw->lfHeight = emSize; break;
+        case UnitPoint:
+            lfw->lfHeight = point_to_pixel(emSize); break;
+        case UnitInch:
+            lfw->lfHeight = inch_to_pixel(emSize); break;
+        case UnitDocument:
+            lfw->lfHeight = document_to_pixel(emSize); break;
+        case UnitMillimeter:
+            lfw->lfHeight = mm_to_pixel(emSize); break;
+    }
+
+    lfw->lfHeight *= -1;
+
+    lfw->lfWeight = style & FontStyleBold ? 700 : 400;
+    lfw->lfItalic = style & FontStyleItalic;
+    lfw->lfUnderline = style & FontStyleUnderline;
+    lfw->lfStrikeOut = style & FontStyleStrikeout;
+
+    (*font)->unit = unit;
+    (*font)->emSize = emSize;
+
+    return Ok;
+}
+
 GpStatus WINGDIPAPI GdipCreateFontFromLogfontW(HDC hdc,
     GDIPCONST LOGFONTW *logfont, GpFont **font)
 {
@@ -47,6 +176,9 @@ GpStatus WINGDIPAPI GdipCreateFontFromLogfontW(HDC hdc,
     (*font)->lfw.lfUnderline = logfont->lfUnderline;
     (*font)->lfw.lfStrikeOut = logfont->lfStrikeOut;
 
+    (*font)->emSize = logfont->lfHeight;
+    (*font)->unit = UnitPixel;
+
     hfont = CreateFontIndirectW(&(*font)->lfw);
     oldfont = SelectObject(hdc, hfont);
     GetTextMetricsW(hdc, &textmet);
@@ -68,7 +200,7 @@ GpStatus WINGDIPAPI GdipCreateFontFromLogfontA(HDC hdc,
     if(!lfa || !font)
         return InvalidParameter;
 
-    memcpy(&lfw, lfa, sizeof(LOGFONTA));
+    memcpy(&lfw, lfa, FIELD_OFFSET(LOGFONTA,lfFaceName) );
 
     if(!MultiByteToWideChar(CP_ACP, 0, lfa->lfFaceName, -1, lfw.lfFaceName, LF_FACESIZE))
         return GenericError;
@@ -106,6 +238,51 @@ GpStatus WINGDIPAPI GdipCreateFontFromDC(HDC hdc, GpFont **font)
     return GdipCreateFontFromLogfontW(hdc, &lfw, font);
 }
 
+/******************************************************************************
+ * GdipGetFontSize [GDIPLUS.@]
+ *
+ * Returns the size of the font in Units
+ *
+ * PARAMS
+ *  *font       [I] The font to retrieve size from
+ *  *size       [O] Pointer to hold retrieved value
+ *
+ * RETURNS
+ *  SUCCESS: Ok
+ *  FAILURE: InvalidParamter (font or size was NULL)
+ *
+ * NOTES
+ *  Size returned is actually emSize -- not internal size used for drawing.
+ */
+GpStatus WINGDIPAPI GdipGetFontSize(GpFont *font, REAL *size)
+{
+    if (!(font && size)) return InvalidParameter;
+
+    *size = font->emSize;
+
+    return Ok;
+}
+
+/*******************************************************************************
+ * GdipGetFontUnit  [GDIPLUS.@]
+ *
+ * PARAMS
+ *  font    [I] Font to retrieve from
+ *  unit    [O] Return value
+ *
+ * RETURNS
+ *  FAILURE: font or unit was NULL
+ *  OK: otherwise
+ */
+GpStatus WINGDIPAPI GdipGetFontUnit(GpFont *font, Unit *unit)
+{
+    if (!(font && unit)) return InvalidParameter;
+
+    *unit = font->unit;
+
+    return Ok;
+}
+
 /* FIXME: use graphics */
 GpStatus WINGDIPAPI GdipGetLogFontW(GpFont *font, GpGraphics *graphics,
     LOGFONTW *lfw)
@@ -130,3 +307,211 @@ GpStatus WINGDIPAPI GdipCloneFont(GpFont *font, GpFont **cloneFont)
 
     return Ok;
 }
+
+/* Borrowed from GDI32 */
+static INT CALLBACK is_font_installed_proc(const LOGFONTW *elf,
+                            const TEXTMETRICW *ntm, DWORD type, LPARAM lParam)
+{
+    return 0;
+}
+
+static BOOL is_font_installed(const WCHAR *name)
+{
+    HDC hdc = GetDC(0);
+    BOOL ret = FALSE;
+
+    if(!EnumFontFamiliesW(hdc, name, is_font_installed_proc, 0))
+        ret = TRUE;
+
+    ReleaseDC(0, hdc);
+    return ret;
+}
+
+/*******************************************************************************
+ * GdipCreateFontFamilyFromName [GDIPLUS.@]
+ *
+ * Creates a font family object based on a supplied name
+ *
+ * PARAMS
+ *  name               [I] Name of the font
+ *  fontCollection     [I] What font collection (if any) the font belongs to (may be NULL)
+ *  FontFamily         [O] Pointer to the resulting FontFamily object
+ *
+ * RETURNS
+ *  SUCCESS: Ok
+ *  FAILURE: FamilyNotFound if the requested FontFamily does not exist on the system
+ *  FAILURE: Invalid parameter if FontFamily or name is NULL
+ *
+ * NOTES
+ *   If fontCollection is NULL then the object is not part of any collection
+ *
+ */
+
+GpStatus WINGDIPAPI GdipCreateFontFamilyFromName(GDIPCONST WCHAR *name,
+                                        GpFontCollection *fontCollection,
+                                        GpFontFamily **FontFamily)
+{
+    GpFontFamily* ffamily;
+    HDC hdc;
+    HFONT hFont, hfont_old;
+    LOGFONTW lfw;
+
+    TRACE("%s, %p %p\n", debugstr_w(name), fontCollection, FontFamily);
+
+    if (!(name && FontFamily))
+        return InvalidParameter;
+    if (fontCollection)
+        FIXME("No support for FontCollections yet!\n");
+    if (!is_font_installed(name))
+        return FontFamilyNotFound;
+
+    ffamily = GdipAlloc(sizeof (GpFontFamily));
+    if (!ffamily) return OutOfMemory;
+
+    hdc = GetDC(0);
+    lstrcpynW(lfw.lfFaceName, name, sizeof(WCHAR) * LF_FACESIZE);
+    hFont = CreateFontIndirectW (&lfw);
+    hfont_old = SelectObject(hdc, hFont);
+
+    GetTextMetricsW(hdc, &ffamily->tmw);
+    DeleteObject(SelectObject(hdc, hfont_old));
+
+    ffamily->FamilyName = GdipAlloc(LF_FACESIZE * sizeof (WCHAR));
+    if (!ffamily->FamilyName)
+    {
+        GdipFree(ffamily);
+        ReleaseDC(0, hdc);
+        return OutOfMemory;
+    }
+
+    lstrcpynW(ffamily->FamilyName, name, sizeof(WCHAR) * LF_FACESIZE);
+
+    *FontFamily = ffamily;
+    ReleaseDC(0, hdc);
+
+    return Ok;
+}
+
+/*******************************************************************************
+ * GdipGetFamilyName [GDIPLUS.@]
+ *
+ * Returns the family name into name
+ *
+ * PARAMS
+ *  *family     [I] Family to retrieve from
+ *  *name       [O] WCHARS of the family name
+ *  LANGID      [I] charset
+ *
+ * RETURNS
+ *  SUCCESS: Ok
+ *  FAILURE: InvalidParameter if family is NULL
+ *
+ * NOTES
+ *   If name is a NULL ptr, then both XP and Vista will crash (so we do as well)
+ */
+GpStatus WINGDIPAPI GdipGetFamilyName (GDIPCONST GpFontFamily *family,
+                                       WCHAR *name, LANGID language)
+{
+    if (family == NULL)
+         return InvalidParameter;
+
+    TRACE("%p, %p, %d\n", family, name, language);
+
+    if (language != LANG_NEUTRAL)
+        FIXME("No support for handling of multiple languages!\n");
+
+    lstrcpynW (name, family->FamilyName, LF_FACESIZE);
+
+    return Ok;
+}
+
+
+/*****************************************************************************
+ * GdipDeleteFontFamily [GDIPLUS.@]
+ *
+ * Removes the specified FontFamily
+ *
+ * PARAMS
+ *  *FontFamily         [I] The family to delete
+ *
+ * RETURNS
+ *  SUCCESS: Ok
+ *  FAILURE: InvalidParameter if FontFamily is NULL.
+ *
+ */
+GpStatus WINGDIPAPI GdipDeleteFontFamily(GpFontFamily *FontFamily)
+{
+    if (!FontFamily)
+        return InvalidParameter;
+    TRACE("Deleting %p (%s)\n", FontFamily, debugstr_w(FontFamily->FamilyName));
+
+    GdipFree (FontFamily->FamilyName);
+    GdipFree (FontFamily);
+
+    return Ok;
+}
+
+/*****************************************************************************
+ * GdipGetGenericFontFamilyMonospace [GDIPLUS.@]
+ *
+ * Obtains a serif family (Courier New on Windows)
+ *
+ * PARAMS
+ *  **nativeFamily         [I] Where the font will be stored
+ *
+ * RETURNS
+ *  InvalidParameter if nativeFamily is NULL.
+ *  Ok otherwise.
+ */
+GpStatus WINGDIPAPI GdipGetGenericFontFamilyMonospace(GpFontFamily **nativeFamily)
+{
+    static const WCHAR CourierNew[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
+
+    if (nativeFamily == NULL) return InvalidParameter;
+
+    return GdipCreateFontFamilyFromName(CourierNew, NULL, nativeFamily);
+}
+
+/*****************************************************************************
+ * GdipGetGenericFontFamilySerif [GDIPLUS.@]
+ *
+ * Obtains a serif family (Times New Roman on Windows)
+ *
+ * PARAMS
+ *  **nativeFamily         [I] Where the font will be stored
+ *
+ * RETURNS
+ *  InvalidParameter if nativeFamily is NULL.
+ *  Ok otherwise.
+ */
+GpStatus WINGDIPAPI GdipGetGenericFontFamilySerif(GpFontFamily **nativeFamily)
+{
+    static const WCHAR TimesNewRoman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
+
+    if (nativeFamily == NULL) return InvalidParameter;
+
+    return GdipCreateFontFamilyFromName(TimesNewRoman, NULL, nativeFamily);
+}
+
+/*****************************************************************************
+ * GdipGetGenericFontFamilySansSerif [GDIPLUS.@]
+ *
+ * Obtains a serif family (Microsoft Sans Serif on Windows)
+ *
+ * PARAMS
+ *  **nativeFamily         [I] Where the font will be stored
+ *
+ * RETURNS
+ *  InvalidParameter if nativeFamily is NULL.
+ *  Ok otherwise.
+ */
+GpStatus WINGDIPAPI GdipGetGenericFontFamilySansSerif(GpFontFamily **nativeFamily)
+{
+    /* FIXME: On Windows this is called Microsoft Sans Serif, this shouldn't
+     * affect anything */
+    static const WCHAR MSSansSerif[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'};
+
+    if (nativeFamily == NULL) return InvalidParameter;
+
+    return GdipCreateFontFamilyFromName(MSSansSerif, NULL, nativeFamily);
+}