2008-03-25 17:34:57 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2007 Google (Evan Stade)
|
2012-05-19 10:03:40 +00:00
|
|
|
* Copyright (C) 2012 Dmitry Timoshkov
|
2008-03-25 17:34:57 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
2018-03-09 12:09:03 +00:00
|
|
|
#include <stdarg.h>
|
|
|
|
|
|
|
|
#include "windef.h"
|
|
|
|
#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"
|
2008-03-25 17:34:57 +00:00
|
|
|
#include "gdiplus_private.h"
|
|
|
|
|
2012-05-19 10:03:40 +00:00
|
|
|
/* PANOSE is 10 bytes in size, need to pack the structure properly */
|
2018-03-09 12:09:03 +00:00
|
|
|
#include "pshpack2.h"
|
2012-05-19 10:03:40 +00:00
|
|
|
typedef struct
|
2008-07-02 08:19:00 +00:00
|
|
|
{
|
2012-05-19 10:03:40 +00:00
|
|
|
USHORT version;
|
|
|
|
SHORT xAvgCharWidth;
|
|
|
|
USHORT usWeightClass;
|
|
|
|
USHORT usWidthClass;
|
|
|
|
SHORT fsType;
|
|
|
|
SHORT ySubscriptXSize;
|
|
|
|
SHORT ySubscriptYSize;
|
|
|
|
SHORT ySubscriptXOffset;
|
|
|
|
SHORT ySubscriptYOffset;
|
|
|
|
SHORT ySuperscriptXSize;
|
|
|
|
SHORT ySuperscriptYSize;
|
|
|
|
SHORT ySuperscriptXOffset;
|
|
|
|
SHORT ySuperscriptYOffset;
|
|
|
|
SHORT yStrikeoutSize;
|
|
|
|
SHORT yStrikeoutPosition;
|
|
|
|
SHORT sFamilyClass;
|
|
|
|
PANOSE panose;
|
|
|
|
ULONG ulUnicodeRange1;
|
|
|
|
ULONG ulUnicodeRange2;
|
|
|
|
ULONG ulUnicodeRange3;
|
|
|
|
ULONG ulUnicodeRange4;
|
|
|
|
CHAR achVendID[4];
|
|
|
|
USHORT fsSelection;
|
|
|
|
USHORT usFirstCharIndex;
|
|
|
|
USHORT usLastCharIndex;
|
|
|
|
/* According to the Apple spec, original version didn't have the below fields,
|
|
|
|
* version numbers were taken from the OpenType spec.
|
|
|
|
*/
|
|
|
|
/* version 0 (TrueType 1.5) */
|
|
|
|
USHORT sTypoAscender;
|
|
|
|
USHORT sTypoDescender;
|
|
|
|
USHORT sTypoLineGap;
|
|
|
|
USHORT usWinAscent;
|
|
|
|
USHORT usWinDescent;
|
|
|
|
/* version 1 (TrueType 1.66) */
|
|
|
|
ULONG ulCodePageRange1;
|
|
|
|
ULONG ulCodePageRange2;
|
|
|
|
/* version 2 (OpenType 1.2) */
|
|
|
|
SHORT sxHeight;
|
|
|
|
SHORT sCapHeight;
|
|
|
|
USHORT usDefaultChar;
|
|
|
|
USHORT usBreakChar;
|
|
|
|
USHORT usMaxContext;
|
|
|
|
} TT_OS2_V2;
|
|
|
|
|
|
|
|
typedef struct
|
2008-07-02 08:19:00 +00:00
|
|
|
{
|
2012-05-19 10:03:40 +00:00
|
|
|
ULONG Version;
|
|
|
|
SHORT Ascender;
|
|
|
|
SHORT Descender;
|
|
|
|
SHORT LineGap;
|
|
|
|
USHORT advanceWidthMax;
|
|
|
|
SHORT minLeftSideBearing;
|
|
|
|
SHORT minRightSideBearing;
|
|
|
|
SHORT xMaxExtent;
|
|
|
|
SHORT caretSlopeRise;
|
|
|
|
SHORT caretSlopeRun;
|
|
|
|
SHORT caretOffset;
|
|
|
|
SHORT reserved[4];
|
|
|
|
SHORT metricDataFormat;
|
|
|
|
USHORT numberOfHMetrics;
|
|
|
|
} TT_HHEA;
|
2018-03-09 12:09:03 +00:00
|
|
|
#include "poppack.h"
|
2012-05-19 10:03:40 +00:00
|
|
|
|
|
|
|
#ifdef WORDS_BIGENDIAN
|
|
|
|
#define GET_BE_WORD(x) (x)
|
|
|
|
#define GET_BE_DWORD(x) (x)
|
|
|
|
#else
|
|
|
|
#define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
|
|
|
|
#define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
|
|
|
|
((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
|
|
|
|
((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
|
|
|
|
#define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
|
|
|
|
#define MS_HHEA_TAG MS_MAKE_TAG('h','h','e','a')
|
2008-07-02 08:19:00 +00:00
|
|
|
|
2012-12-11 21:40:15 +00:00
|
|
|
static GpStatus clone_font_family(const GpFontFamily *, GpFontFamily **);
|
2008-07-02 08:19:00 +00:00
|
|
|
|
2012-05-19 10:03:40 +00:00
|
|
|
static GpFontCollection installedFontCollection = {0};
|
2008-07-02 08:19:00 +00:00
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
* 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)
|
|
|
|
{
|
2012-05-19 10:03:40 +00:00
|
|
|
HFONT hfont;
|
|
|
|
OUTLINETEXTMETRICW otm;
|
|
|
|
LOGFONTW lfw;
|
|
|
|
HDC hdc;
|
2008-07-02 08:19:00 +00:00
|
|
|
GpStatus stat;
|
2012-05-19 10:03:40 +00:00
|
|
|
int ret;
|
2008-07-02 08:19:00 +00:00
|
|
|
|
2012-05-19 10:03:40 +00:00
|
|
|
if (!fontFamily || !font || emSize < 0.0)
|
2008-07-02 08:19:00 +00:00
|
|
|
return InvalidParameter;
|
|
|
|
|
|
|
|
TRACE("%p (%s), %f, %d, %d, %p\n", fontFamily,
|
|
|
|
debugstr_w(fontFamily->FamilyName), emSize, style, unit, font);
|
|
|
|
|
2012-05-19 10:03:40 +00:00
|
|
|
memset(&lfw, 0, sizeof(lfw));
|
2008-07-02 08:19:00 +00:00
|
|
|
|
2012-05-19 10:03:40 +00:00
|
|
|
stat = GdipGetFamilyName(fontFamily, lfw.lfFaceName, LANG_NEUTRAL);
|
|
|
|
if (stat != Ok) return stat;
|
2008-07-02 08:19:00 +00:00
|
|
|
|
2012-12-11 21:40:15 +00:00
|
|
|
lfw.lfHeight = -units_to_pixels(emSize, unit, fontFamily->dpi);
|
2012-05-19 10:03:40 +00:00
|
|
|
lfw.lfWeight = style & FontStyleBold ? FW_BOLD : FW_REGULAR;
|
|
|
|
lfw.lfItalic = style & FontStyleItalic;
|
|
|
|
lfw.lfUnderline = style & FontStyleUnderline;
|
|
|
|
lfw.lfStrikeOut = style & FontStyleStrikeout;
|
|
|
|
|
|
|
|
hfont = CreateFontIndirectW(&lfw);
|
|
|
|
hdc = CreateCompatibleDC(0);
|
|
|
|
SelectObject(hdc, hfont);
|
|
|
|
otm.otmSize = sizeof(otm);
|
|
|
|
ret = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm);
|
|
|
|
DeleteDC(hdc);
|
|
|
|
DeleteObject(hfont);
|
2008-07-02 08:19:00 +00:00
|
|
|
|
2012-05-19 10:03:40 +00:00
|
|
|
if (!ret) return NotTrueTypeFont;
|
2008-07-02 08:19:00 +00:00
|
|
|
|
2015-11-22 10:10:02 +00:00
|
|
|
*font = heap_alloc_zero(sizeof(GpFont));
|
2012-05-19 10:03:40 +00:00
|
|
|
if (!*font) return OutOfMemory;
|
2008-07-02 08:19:00 +00:00
|
|
|
|
|
|
|
(*font)->unit = unit;
|
|
|
|
(*font)->emSize = emSize;
|
2012-05-19 10:03:40 +00:00
|
|
|
(*font)->otm = otm;
|
|
|
|
|
2012-12-11 21:40:15 +00:00
|
|
|
stat = clone_font_family(fontFamily, &(*font)->family);
|
2012-05-19 10:03:40 +00:00
|
|
|
if (stat != Ok)
|
|
|
|
{
|
2015-11-22 10:10:02 +00:00
|
|
|
heap_free(*font);
|
2012-05-19 10:03:40 +00:00
|
|
|
return stat;
|
|
|
|
}
|
2008-07-02 08:19:00 +00:00
|
|
|
|
2010-03-04 13:34:05 +00:00
|
|
|
TRACE("<-- %p\n", *font);
|
|
|
|
|
2008-07-02 08:19:00 +00:00
|
|
|
return Ok;
|
|
|
|
}
|
|
|
|
|
2008-08-05 12:23:58 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
* GdipCreateFontFromLogfontW [GDIPLUS.@]
|
|
|
|
*/
|
2008-03-25 17:34:57 +00:00
|
|
|
GpStatus WINGDIPAPI GdipCreateFontFromLogfontW(HDC hdc,
|
|
|
|
GDIPCONST LOGFONTW *logfont, GpFont **font)
|
|
|
|
{
|
|
|
|
HFONT hfont, oldfont;
|
2012-05-19 10:03:40 +00:00
|
|
|
OUTLINETEXTMETRICW otm;
|
2012-12-11 21:40:15 +00:00
|
|
|
WCHAR facename[LF_FACESIZE];
|
2012-05-19 10:03:40 +00:00
|
|
|
GpStatus stat;
|
|
|
|
int ret;
|
2008-03-25 17:34:57 +00:00
|
|
|
|
2008-09-07 10:32:49 +00:00
|
|
|
TRACE("(%p, %p, %p)\n", hdc, logfont, font);
|
|
|
|
|
2012-05-19 10:03:40 +00:00
|
|
|
if (!hdc || !logfont || !font)
|
2008-03-25 17:34:57 +00:00
|
|
|
return InvalidParameter;
|
|
|
|
|
2012-05-19 10:03:40 +00:00
|
|
|
hfont = CreateFontIndirectW(logfont);
|
2008-03-25 17:34:57 +00:00
|
|
|
oldfont = SelectObject(hdc, hfont);
|
2012-05-19 10:03:40 +00:00
|
|
|
otm.otmSize = sizeof(otm);
|
|
|
|
ret = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm);
|
2012-12-11 21:40:15 +00:00
|
|
|
GetTextFaceW(hdc, LF_FACESIZE, facename);
|
2012-05-19 10:03:40 +00:00
|
|
|
SelectObject(hdc, oldfont);
|
|
|
|
DeleteObject(hfont);
|
2008-03-25 17:34:57 +00:00
|
|
|
|
2012-05-19 10:03:40 +00:00
|
|
|
if (!ret) return NotTrueTypeFont;
|
2008-03-25 17:34:57 +00:00
|
|
|
|
2015-11-22 10:10:02 +00:00
|
|
|
*font = heap_alloc_zero(sizeof(GpFont));
|
2012-05-19 10:03:40 +00:00
|
|
|
if (!*font) return OutOfMemory;
|
2008-12-06 09:26:01 +00:00
|
|
|
|
2012-05-19 10:03:40 +00:00
|
|
|
(*font)->unit = UnitWorld;
|
|
|
|
(*font)->emSize = otm.otmTextMetrics.tmAscent;
|
|
|
|
(*font)->otm = otm;
|
|
|
|
|
2012-12-11 21:40:15 +00:00
|
|
|
stat = GdipCreateFontFamilyFromName(facename, NULL, &(*font)->family);
|
2012-05-19 10:03:40 +00:00
|
|
|
if (stat != Ok)
|
|
|
|
{
|
2015-11-22 10:10:02 +00:00
|
|
|
heap_free(*font);
|
2012-05-19 10:03:40 +00:00
|
|
|
return NotTrueTypeFont;
|
|
|
|
}
|
2008-03-25 17:34:57 +00:00
|
|
|
|
2010-03-04 13:34:05 +00:00
|
|
|
TRACE("<-- %p\n", *font);
|
|
|
|
|
2008-03-25 17:34:57 +00:00
|
|
|
return Ok;
|
|
|
|
}
|
|
|
|
|
2008-08-05 12:23:58 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
* GdipCreateFontFromLogfontA [GDIPLUS.@]
|
|
|
|
*/
|
2008-03-25 17:34:57 +00:00
|
|
|
GpStatus WINGDIPAPI GdipCreateFontFromLogfontA(HDC hdc,
|
|
|
|
GDIPCONST LOGFONTA *lfa, GpFont **font)
|
|
|
|
{
|
|
|
|
LOGFONTW lfw;
|
|
|
|
|
2008-09-07 10:32:49 +00:00
|
|
|
TRACE("(%p, %p, %p)\n", hdc, lfa, font);
|
|
|
|
|
2008-03-25 17:34:57 +00:00
|
|
|
if(!lfa || !font)
|
|
|
|
return InvalidParameter;
|
|
|
|
|
2008-06-01 13:14:02 +00:00
|
|
|
memcpy(&lfw, lfa, FIELD_OFFSET(LOGFONTA,lfFaceName) );
|
2008-03-25 17:34:57 +00:00
|
|
|
|
|
|
|
if(!MultiByteToWideChar(CP_ACP, 0, lfa->lfFaceName, -1, lfw.lfFaceName, LF_FACESIZE))
|
|
|
|
return GenericError;
|
|
|
|
|
2009-05-05 15:35:05 +00:00
|
|
|
return GdipCreateFontFromLogfontW(hdc, &lfw, font);
|
2008-03-25 17:34:57 +00:00
|
|
|
}
|
|
|
|
|
2008-08-05 12:23:58 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
* GdipDeleteFont [GDIPLUS.@]
|
|
|
|
*/
|
2008-03-25 17:34:57 +00:00
|
|
|
GpStatus WINGDIPAPI GdipDeleteFont(GpFont* font)
|
|
|
|
{
|
2008-09-07 10:32:49 +00:00
|
|
|
TRACE("(%p)\n", font);
|
|
|
|
|
2008-03-25 17:34:57 +00:00
|
|
|
if(!font)
|
|
|
|
return InvalidParameter;
|
|
|
|
|
2012-05-19 10:03:40 +00:00
|
|
|
GdipDeleteFontFamily(font->family);
|
2015-11-22 10:10:02 +00:00
|
|
|
heap_free(font);
|
2008-03-25 17:34:57 +00:00
|
|
|
|
|
|
|
return Ok;
|
|
|
|
}
|
|
|
|
|
2008-08-05 12:23:58 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
* GdipCreateFontFromDC [GDIPLUS.@]
|
|
|
|
*/
|
2008-05-04 19:41:25 +00:00
|
|
|
GpStatus WINGDIPAPI GdipCreateFontFromDC(HDC hdc, GpFont **font)
|
|
|
|
{
|
|
|
|
HFONT hfont;
|
|
|
|
LOGFONTW lfw;
|
|
|
|
|
2008-09-07 10:32:49 +00:00
|
|
|
TRACE("(%p, %p)\n", hdc, font);
|
|
|
|
|
2008-05-04 19:41:25 +00:00
|
|
|
if(!font)
|
|
|
|
return InvalidParameter;
|
|
|
|
|
2008-12-06 09:26:01 +00:00
|
|
|
hfont = GetCurrentObject(hdc, OBJ_FONT);
|
2008-05-04 19:41:25 +00:00
|
|
|
if(!hfont)
|
|
|
|
return GenericError;
|
|
|
|
|
|
|
|
if(!GetObjectW(hfont, sizeof(LOGFONTW), &lfw))
|
|
|
|
return GenericError;
|
|
|
|
|
|
|
|
return GdipCreateFontFromLogfontW(hdc, &lfw, font);
|
|
|
|
}
|
|
|
|
|
2008-09-07 10:32:49 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
* GdipGetFamily [GDIPLUS.@]
|
|
|
|
*
|
|
|
|
* Returns the FontFamily for the specified Font
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* font [I] Font to request from
|
|
|
|
* family [O] Resulting FontFamily object
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* SUCCESS: Ok
|
|
|
|
* FAILURE: An element of GpStatus
|
|
|
|
*/
|
|
|
|
GpStatus WINGDIPAPI GdipGetFamily(GpFont *font, GpFontFamily **family)
|
|
|
|
{
|
|
|
|
TRACE("%p %p\n", font, family);
|
|
|
|
|
|
|
|
if (!(font && family))
|
|
|
|
return InvalidParameter;
|
|
|
|
|
2012-05-19 10:03:40 +00:00
|
|
|
return GdipCloneFontFamily(font->family, family);
|
2008-09-07 10:32:49 +00:00
|
|
|
}
|
|
|
|
|
2012-12-11 21:40:15 +00:00
|
|
|
static REAL get_font_size(const GpFont *font)
|
|
|
|
{
|
|
|
|
return font->emSize;
|
|
|
|
}
|
|
|
|
|
2008-07-02 08:19:00 +00:00
|
|
|
/******************************************************************************
|
|
|
|
* 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
|
2009-05-05 15:35:05 +00:00
|
|
|
* FAILURE: InvalidParameter (font or size was NULL)
|
2008-07-02 08:19:00 +00:00
|
|
|
*
|
|
|
|
* NOTES
|
|
|
|
* Size returned is actually emSize -- not internal size used for drawing.
|
|
|
|
*/
|
|
|
|
GpStatus WINGDIPAPI GdipGetFontSize(GpFont *font, REAL *size)
|
|
|
|
{
|
2008-09-07 10:32:49 +00:00
|
|
|
TRACE("(%p, %p)\n", font, size);
|
|
|
|
|
2008-07-02 08:19:00 +00:00
|
|
|
if (!(font && size)) return InvalidParameter;
|
|
|
|
|
2012-12-11 21:40:15 +00:00
|
|
|
*size = get_font_size(font);
|
2012-05-19 10:03:40 +00:00
|
|
|
TRACE("%s,%d => %f\n", debugstr_w(font->family->FamilyName), font->otm.otmTextMetrics.tmHeight, *size);
|
2008-07-02 08:19:00 +00:00
|
|
|
|
|
|
|
return Ok;
|
|
|
|
}
|
|
|
|
|
2012-12-11 21:40:15 +00:00
|
|
|
static INT get_font_style(const GpFont *font)
|
|
|
|
{
|
|
|
|
INT style;
|
|
|
|
|
|
|
|
if (font->otm.otmTextMetrics.tmWeight > FW_REGULAR)
|
|
|
|
style = FontStyleBold;
|
|
|
|
else
|
|
|
|
style = FontStyleRegular;
|
|
|
|
if (font->otm.otmTextMetrics.tmItalic)
|
|
|
|
style |= FontStyleItalic;
|
|
|
|
if (font->otm.otmTextMetrics.tmUnderlined)
|
|
|
|
style |= FontStyleUnderline;
|
|
|
|
if (font->otm.otmTextMetrics.tmStruckOut)
|
|
|
|
style |= FontStyleStrikeout;
|
|
|
|
|
|
|
|
return style;
|
|
|
|
}
|
|
|
|
|
2008-09-07 10:32:49 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
* GdipGetFontStyle [GDIPLUS.@]
|
|
|
|
*
|
|
|
|
* Gets the font's style, returned in bitwise OR of FontStyle enumeration
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* font [I] font to request from
|
|
|
|
* style [O] resulting pointer to a FontStyle enumeration
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* SUCCESS: Ok
|
|
|
|
* FAILURE: InvalidParameter
|
|
|
|
*/
|
|
|
|
GpStatus WINGDIPAPI GdipGetFontStyle(GpFont *font, INT *style)
|
|
|
|
{
|
|
|
|
TRACE("%p %p\n", font, style);
|
|
|
|
|
|
|
|
if (!(font && style))
|
|
|
|
return InvalidParameter;
|
|
|
|
|
2012-12-11 21:40:15 +00:00
|
|
|
*style = get_font_style(font);
|
|
|
|
TRACE("%s,%d => %d\n", debugstr_w(font->family->FamilyName), font->otm.otmTextMetrics.tmHeight, *style);
|
2008-09-07 10:32:49 +00:00
|
|
|
|
|
|
|
return Ok;
|
|
|
|
}
|
|
|
|
|
2008-07-02 08:19:00 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
* 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)
|
|
|
|
{
|
2008-09-07 10:32:49 +00:00
|
|
|
TRACE("(%p, %p)\n", font, unit);
|
|
|
|
|
2008-07-02 08:19:00 +00:00
|
|
|
if (!(font && unit)) return InvalidParameter;
|
|
|
|
|
|
|
|
*unit = font->unit;
|
2012-05-19 10:03:40 +00:00
|
|
|
TRACE("%s,%d => %d\n", debugstr_w(font->family->FamilyName), font->otm.otmTextMetrics.tmHeight, *unit);
|
2008-07-02 08:19:00 +00:00
|
|
|
|
|
|
|
return Ok;
|
|
|
|
}
|
|
|
|
|
2009-02-14 08:14:34 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
* GdipGetLogFontA [GDIPLUS.@]
|
|
|
|
*/
|
|
|
|
GpStatus WINGDIPAPI GdipGetLogFontA(GpFont *font, GpGraphics *graphics,
|
|
|
|
LOGFONTA *lfa)
|
|
|
|
{
|
|
|
|
GpStatus status;
|
|
|
|
LOGFONTW lfw;
|
|
|
|
|
|
|
|
TRACE("(%p, %p, %p)\n", font, graphics, lfa);
|
|
|
|
|
|
|
|
status = GdipGetLogFontW(font, graphics, &lfw);
|
|
|
|
if(status != Ok)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
memcpy(lfa, &lfw, FIELD_OFFSET(LOGFONTA,lfFaceName) );
|
|
|
|
|
2009-05-05 15:35:05 +00:00
|
|
|
if(!WideCharToMultiByte(CP_ACP, 0, lfw.lfFaceName, -1, lfa->lfFaceName, LF_FACESIZE, NULL, NULL))
|
2009-02-14 08:14:34 +00:00
|
|
|
return GenericError;
|
|
|
|
|
|
|
|
return Ok;
|
|
|
|
}
|
|
|
|
|
2008-08-05 12:23:58 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
* GdipGetLogFontW [GDIPLUS.@]
|
|
|
|
*/
|
2012-12-11 21:40:15 +00:00
|
|
|
GpStatus WINGDIPAPI GdipGetLogFontW(GpFont *font, GpGraphics *graphics, LOGFONTW *lf)
|
2008-03-25 17:34:57 +00:00
|
|
|
{
|
2012-12-11 21:40:15 +00:00
|
|
|
REAL angle, rel_height, height;
|
|
|
|
GpMatrix matrix;
|
|
|
|
GpPointF pt[3];
|
2008-09-07 10:32:49 +00:00
|
|
|
|
2012-12-11 21:40:15 +00:00
|
|
|
TRACE("(%p, %p, %p)\n", font, graphics, lf);
|
|
|
|
|
|
|
|
if (!font || !graphics || !lf)
|
2008-03-25 17:34:57 +00:00
|
|
|
return InvalidParameter;
|
|
|
|
|
2012-12-11 21:40:15 +00:00
|
|
|
matrix = graphics->worldtrans;
|
|
|
|
|
2015-07-19 13:31:15 +00:00
|
|
|
if (font->unit == UnitPixel || font->unit == UnitWorld)
|
2012-12-11 21:40:15 +00:00
|
|
|
{
|
|
|
|
height = units_to_pixels(font->emSize, graphics->unit, graphics->yres);
|
|
|
|
if (graphics->unit != UnitDisplay)
|
|
|
|
GdipScaleMatrix(&matrix, graphics->scale, graphics->scale, MatrixOrderAppend);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (graphics->unit == UnitDisplay || graphics->unit == UnitPixel)
|
|
|
|
height = units_to_pixels(font->emSize, font->unit, graphics->xres);
|
|
|
|
else
|
|
|
|
height = units_to_pixels(font->emSize, font->unit, graphics->yres);
|
|
|
|
}
|
|
|
|
|
|
|
|
pt[0].X = 0.0;
|
|
|
|
pt[0].Y = 0.0;
|
|
|
|
pt[1].X = 1.0;
|
|
|
|
pt[1].Y = 0.0;
|
|
|
|
pt[2].X = 0.0;
|
|
|
|
pt[2].Y = 1.0;
|
|
|
|
GdipTransformMatrixPoints(&matrix, pt, 3);
|
|
|
|
angle = -gdiplus_atan2((pt[1].Y - pt[0].Y), (pt[1].X - pt[0].X));
|
|
|
|
rel_height = sqrt((pt[2].Y - pt[0].Y) * (pt[2].Y - pt[0].Y)+
|
|
|
|
(pt[2].X - pt[0].X) * (pt[2].X - pt[0].X));
|
|
|
|
|
|
|
|
lf->lfHeight = -gdip_round(height * rel_height);
|
|
|
|
lf->lfWidth = 0;
|
|
|
|
lf->lfEscapement = lf->lfOrientation = gdip_round((angle / M_PI) * 1800.0);
|
|
|
|
if (lf->lfEscapement < 0)
|
|
|
|
{
|
|
|
|
lf->lfEscapement += 3600;
|
|
|
|
lf->lfOrientation += 3600;
|
|
|
|
}
|
|
|
|
lf->lfWeight = font->otm.otmTextMetrics.tmWeight;
|
|
|
|
lf->lfItalic = font->otm.otmTextMetrics.tmItalic ? 1 : 0;
|
|
|
|
lf->lfUnderline = font->otm.otmTextMetrics.tmUnderlined ? 1 : 0;
|
|
|
|
lf->lfStrikeOut = font->otm.otmTextMetrics.tmStruckOut ? 1 : 0;
|
|
|
|
lf->lfCharSet = font->otm.otmTextMetrics.tmCharSet;
|
|
|
|
lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
|
|
|
|
lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
|
|
|
lf->lfQuality = DEFAULT_QUALITY;
|
|
|
|
lf->lfPitchAndFamily = 0;
|
|
|
|
strcpyW(lf->lfFaceName, font->family->FamilyName);
|
|
|
|
|
|
|
|
TRACE("=> %s,%d\n", debugstr_w(lf->lfFaceName), lf->lfHeight);
|
2008-03-25 17:34:57 +00:00
|
|
|
|
|
|
|
return Ok;
|
|
|
|
}
|
2008-05-04 19:41:25 +00:00
|
|
|
|
2008-08-05 12:23:58 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
* GdipCloneFont [GDIPLUS.@]
|
|
|
|
*/
|
2008-05-04 19:41:25 +00:00
|
|
|
GpStatus WINGDIPAPI GdipCloneFont(GpFont *font, GpFont **cloneFont)
|
|
|
|
{
|
2012-05-19 10:03:40 +00:00
|
|
|
GpStatus stat;
|
|
|
|
|
2008-09-07 10:32:49 +00:00
|
|
|
TRACE("(%p, %p)\n", font, cloneFont);
|
|
|
|
|
2008-05-04 19:41:25 +00:00
|
|
|
if(!font || !cloneFont)
|
|
|
|
return InvalidParameter;
|
|
|
|
|
2015-11-22 10:10:02 +00:00
|
|
|
*cloneFont = heap_alloc_zero(sizeof(GpFont));
|
2008-05-04 19:41:25 +00:00
|
|
|
if(!*cloneFont) return OutOfMemory;
|
|
|
|
|
|
|
|
**cloneFont = *font;
|
2012-05-19 10:03:40 +00:00
|
|
|
stat = GdipCloneFontFamily(font->family, &(*cloneFont)->family);
|
2015-11-22 10:10:02 +00:00
|
|
|
if (stat != Ok) heap_free(*cloneFont);
|
2008-05-04 19:41:25 +00:00
|
|
|
|
2012-05-19 10:03:40 +00:00
|
|
|
return stat;
|
2008-05-04 19:41:25 +00:00
|
|
|
}
|
2008-07-02 08:19:00 +00:00
|
|
|
|
2008-09-07 10:32:49 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
* GdipGetFontHeight [GDIPLUS.@]
|
|
|
|
* PARAMS
|
|
|
|
* font [I] Font to retrieve height from
|
|
|
|
* graphics [I] The current graphics context
|
|
|
|
* height [O] Resulting height
|
|
|
|
* RETURNS
|
|
|
|
* SUCCESS: Ok
|
|
|
|
* FAILURE: Another element of GpStatus
|
|
|
|
*
|
|
|
|
* NOTES
|
|
|
|
* Forwards to GdipGetFontHeightGivenDPI
|
|
|
|
*/
|
|
|
|
GpStatus WINGDIPAPI GdipGetFontHeight(GDIPCONST GpFont *font,
|
|
|
|
GDIPCONST GpGraphics *graphics, REAL *height)
|
|
|
|
{
|
|
|
|
REAL dpi;
|
2010-11-20 11:24:17 +00:00
|
|
|
GpStatus stat;
|
2012-12-11 21:40:15 +00:00
|
|
|
REAL font_height;
|
2008-09-07 10:32:49 +00:00
|
|
|
|
|
|
|
TRACE("%p %p %p\n", font, graphics, height);
|
|
|
|
|
2017-06-03 19:01:50 +00:00
|
|
|
if (!font || !height) return InvalidParameter;
|
|
|
|
|
2012-12-11 21:40:15 +00:00
|
|
|
stat = GdipGetFontHeightGivenDPI(font, font->family->dpi, &font_height);
|
|
|
|
if (stat != Ok) return stat;
|
|
|
|
|
|
|
|
if (!graphics)
|
2012-05-19 10:03:40 +00:00
|
|
|
{
|
2012-12-11 21:40:15 +00:00
|
|
|
*height = font_height;
|
|
|
|
TRACE("%s,%d => %f\n",
|
|
|
|
debugstr_w(font->family->FamilyName), font->otm.otmTextMetrics.tmHeight, *height);
|
|
|
|
return Ok;
|
2012-05-19 10:03:40 +00:00
|
|
|
}
|
2008-09-07 10:32:49 +00:00
|
|
|
|
2012-12-11 21:40:15 +00:00
|
|
|
stat = GdipGetDpiY((GpGraphics *)graphics, &dpi);
|
|
|
|
if (stat != Ok) return stat;
|
|
|
|
|
|
|
|
*height = pixels_to_units(font_height, graphics->unit, dpi);
|
|
|
|
|
|
|
|
TRACE("%s,%d(unit %d) => %f\n",
|
|
|
|
debugstr_w(font->family->FamilyName), font->otm.otmTextMetrics.tmHeight, graphics->unit, *height);
|
|
|
|
return Ok;
|
2008-09-07 10:32:49 +00:00
|
|
|
}
|
|
|
|
|
2008-08-05 12:23:58 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
* GdipGetFontHeightGivenDPI [GDIPLUS.@]
|
|
|
|
* PARAMS
|
|
|
|
* font [I] Font to retrieve DPI from
|
|
|
|
* dpi [I] DPI to assume
|
|
|
|
* height [O] Return value
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* SUCCESS: Ok
|
|
|
|
* FAILURE: InvalidParameter if font or height is NULL
|
|
|
|
*
|
|
|
|
* NOTES
|
|
|
|
* According to MSDN, the result is (lineSpacing)*(fontSize / emHeight)*dpi
|
|
|
|
* (for anything other than unit Pixel)
|
|
|
|
*/
|
|
|
|
GpStatus WINGDIPAPI GdipGetFontHeightGivenDPI(GDIPCONST GpFont *font, REAL dpi, REAL *height)
|
|
|
|
{
|
2012-05-19 10:03:40 +00:00
|
|
|
GpStatus stat;
|
|
|
|
INT style;
|
|
|
|
UINT16 line_spacing, em_height;
|
2012-12-11 21:40:15 +00:00
|
|
|
REAL font_size;
|
2012-05-19 10:03:40 +00:00
|
|
|
|
|
|
|
if (!font || !height) return InvalidParameter;
|
2008-12-06 09:26:01 +00:00
|
|
|
|
2008-09-07 10:32:49 +00:00
|
|
|
TRACE("%p (%s), %f, %p\n", font,
|
2012-05-19 10:03:40 +00:00
|
|
|
debugstr_w(font->family->FamilyName), dpi, height);
|
2008-09-07 10:32:49 +00:00
|
|
|
|
2012-12-11 21:40:15 +00:00
|
|
|
font_size = units_to_pixels(get_font_size(font), font->unit, dpi);
|
|
|
|
style = get_font_style(font);
|
2012-05-19 10:03:40 +00:00
|
|
|
stat = GdipGetLineSpacing(font->family, style, &line_spacing);
|
|
|
|
if (stat != Ok) return stat;
|
|
|
|
stat = GdipGetEmHeight(font->family, style, &em_height);
|
|
|
|
if (stat != Ok) return stat;
|
2008-08-05 12:23:58 +00:00
|
|
|
|
2012-12-11 21:40:15 +00:00
|
|
|
*height = (REAL)line_spacing * font_size / (REAL)em_height;
|
2008-12-06 09:26:01 +00:00
|
|
|
|
2012-12-11 21:40:15 +00:00
|
|
|
TRACE("%s,%d => %f\n",
|
|
|
|
debugstr_w(font->family->FamilyName), font->otm.otmTextMetrics.tmHeight, *height);
|
2012-05-19 10:03:40 +00:00
|
|
|
|
2008-09-07 10:32:49 +00:00
|
|
|
return Ok;
|
2008-08-05 12:23:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* Borrowed from GDI32:
|
|
|
|
*
|
|
|
|
* Elf is really an ENUMLOGFONTEXW, and ntm is a NEWTEXTMETRICEXW.
|
|
|
|
* We have to use other types because of the FONTENUMPROCW definition.
|
|
|
|
*/
|
2008-07-02 08:19:00 +00:00
|
|
|
static INT CALLBACK is_font_installed_proc(const LOGFONTW *elf,
|
|
|
|
const TEXTMETRICW *ntm, DWORD type, LPARAM lParam)
|
|
|
|
{
|
2015-11-22 10:10:02 +00:00
|
|
|
const ENUMLOGFONTW *elfW = (const ENUMLOGFONTW *)elf;
|
|
|
|
LOGFONTW *lf = (LOGFONTW *)lParam;
|
|
|
|
|
2012-12-11 21:40:15 +00:00
|
|
|
if (type & RASTER_FONTTYPE)
|
2008-08-05 12:23:58 +00:00
|
|
|
return 1;
|
|
|
|
|
2015-11-22 10:10:02 +00:00
|
|
|
*lf = *elf;
|
|
|
|
/* replace substituted font name by a real one */
|
|
|
|
lstrcpynW(lf->lfFaceName, elfW->elfFullName, LF_FACESIZE);
|
2008-07-02 08:19:00 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-05-19 10:03:40 +00:00
|
|
|
struct font_metrics
|
|
|
|
{
|
2012-12-11 21:40:15 +00:00
|
|
|
WCHAR facename[LF_FACESIZE];
|
2012-05-19 10:03:40 +00:00
|
|
|
UINT16 em_height, ascent, descent, line_spacing; /* in font units */
|
|
|
|
int dpi;
|
|
|
|
};
|
|
|
|
|
|
|
|
static BOOL get_font_metrics(HDC hdc, struct font_metrics *fm)
|
2008-07-02 08:19:00 +00:00
|
|
|
{
|
2012-05-19 10:03:40 +00:00
|
|
|
OUTLINETEXTMETRICW otm;
|
|
|
|
TT_OS2_V2 tt_os2;
|
|
|
|
TT_HHEA tt_hori;
|
|
|
|
LONG size;
|
|
|
|
UINT16 line_gap;
|
|
|
|
|
|
|
|
otm.otmSize = sizeof(otm);
|
|
|
|
if (!GetOutlineTextMetricsW(hdc, otm.otmSize, &otm)) return FALSE;
|
|
|
|
|
|
|
|
fm->em_height = otm.otmEMSquare;
|
|
|
|
fm->dpi = GetDeviceCaps(hdc, LOGPIXELSY);
|
2008-07-02 08:19:00 +00:00
|
|
|
|
2012-05-19 10:03:40 +00:00
|
|
|
memset(&tt_hori, 0, sizeof(tt_hori));
|
|
|
|
if (GetFontData(hdc, MS_HHEA_TAG, 0, &tt_hori, sizeof(tt_hori)) != GDI_ERROR)
|
|
|
|
{
|
|
|
|
fm->ascent = GET_BE_WORD(tt_hori.Ascender);
|
|
|
|
fm->descent = -GET_BE_WORD(tt_hori.Descender);
|
|
|
|
TRACE("hhea: ascent %d, descent %d\n", fm->ascent, fm->descent);
|
|
|
|
line_gap = GET_BE_WORD(tt_hori.LineGap);
|
|
|
|
fm->line_spacing = fm->ascent + fm->descent + line_gap;
|
|
|
|
TRACE("line_gap %u, line_spacing %u\n", line_gap, fm->line_spacing);
|
|
|
|
if (fm->ascent + fm->descent != 0) return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
|
|
|
|
if (size == GDI_ERROR) return FALSE;
|
2008-07-02 08:19:00 +00:00
|
|
|
|
2012-05-19 10:03:40 +00:00
|
|
|
if (size > sizeof(tt_os2)) size = sizeof(tt_os2);
|
|
|
|
|
|
|
|
memset(&tt_os2, 0, sizeof(tt_os2));
|
|
|
|
if (GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size) != size) return FALSE;
|
|
|
|
|
|
|
|
fm->ascent = GET_BE_WORD(tt_os2.usWinAscent);
|
|
|
|
fm->descent = GET_BE_WORD(tt_os2.usWinDescent);
|
|
|
|
TRACE("usWinAscent %u, usWinDescent %u\n", fm->ascent, fm->descent);
|
|
|
|
if (fm->ascent + fm->descent == 0)
|
|
|
|
{
|
|
|
|
fm->ascent = GET_BE_WORD(tt_os2.sTypoAscender);
|
|
|
|
fm->descent = GET_BE_WORD(tt_os2.sTypoDescender);
|
|
|
|
TRACE("sTypoAscender %u, sTypoDescender %u\n", fm->ascent, fm->descent);
|
|
|
|
}
|
|
|
|
line_gap = GET_BE_WORD(tt_os2.sTypoLineGap);
|
|
|
|
fm->line_spacing = fm->ascent + fm->descent + line_gap;
|
|
|
|
TRACE("line_gap %u, line_spacing %u\n", line_gap, fm->line_spacing);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GpStatus find_installed_font(const WCHAR *name, struct font_metrics *fm)
|
|
|
|
{
|
|
|
|
LOGFONTW lf;
|
|
|
|
HDC hdc = CreateCompatibleDC(0);
|
|
|
|
GpStatus ret = FontFamilyNotFound;
|
|
|
|
|
|
|
|
if(!EnumFontFamiliesW(hdc, name, is_font_installed_proc, (LPARAM)&lf))
|
|
|
|
{
|
|
|
|
HFONT hfont, old_font;
|
|
|
|
|
2015-11-22 10:10:02 +00:00
|
|
|
strcpyW(fm->facename, lf.lfFaceName);
|
|
|
|
|
2012-05-19 10:03:40 +00:00
|
|
|
hfont = CreateFontIndirectW(&lf);
|
|
|
|
old_font = SelectObject(hdc, hfont);
|
|
|
|
ret = get_font_metrics(hdc, fm) ? Ok : NotTrueTypeFont;
|
|
|
|
SelectObject(hdc, old_font);
|
|
|
|
DeleteObject(hfont);
|
|
|
|
}
|
|
|
|
|
|
|
|
DeleteDC(hdc);
|
2008-07-02 08:19:00 +00:00
|
|
|
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)
|
|
|
|
{
|
2012-05-19 10:03:40 +00:00
|
|
|
GpStatus stat;
|
2008-07-02 08:19:00 +00:00
|
|
|
GpFontFamily* ffamily;
|
2012-05-19 10:03:40 +00:00
|
|
|
struct font_metrics fm;
|
2008-07-02 08:19:00 +00:00
|
|
|
|
|
|
|
TRACE("%s, %p %p\n", debugstr_w(name), fontCollection, FontFamily);
|
|
|
|
|
|
|
|
if (!(name && FontFamily))
|
|
|
|
return InvalidParameter;
|
|
|
|
if (fontCollection)
|
|
|
|
FIXME("No support for FontCollections yet!\n");
|
2008-08-05 12:23:58 +00:00
|
|
|
|
2012-05-19 10:03:40 +00:00
|
|
|
stat = find_installed_font(name, &fm);
|
|
|
|
if (stat != Ok) return stat;
|
2008-07-02 08:19:00 +00:00
|
|
|
|
2015-11-22 10:10:02 +00:00
|
|
|
ffamily = heap_alloc_zero(sizeof (GpFontFamily));
|
2008-07-02 08:19:00 +00:00
|
|
|
if (!ffamily) return OutOfMemory;
|
|
|
|
|
2012-12-11 21:40:15 +00:00
|
|
|
lstrcpyW(ffamily->FamilyName, fm.facename);
|
2012-05-19 10:03:40 +00:00
|
|
|
ffamily->em_height = fm.em_height;
|
|
|
|
ffamily->ascent = fm.ascent;
|
|
|
|
ffamily->descent = fm.descent;
|
|
|
|
ffamily->line_spacing = fm.line_spacing;
|
|
|
|
ffamily->dpi = fm.dpi;
|
2008-07-02 08:19:00 +00:00
|
|
|
|
2008-08-05 12:23:58 +00:00
|
|
|
*FontFamily = ffamily;
|
2008-07-02 08:19:00 +00:00
|
|
|
|
2010-03-04 13:34:05 +00:00
|
|
|
TRACE("<-- %p\n", ffamily);
|
|
|
|
|
2008-08-05 12:23:58 +00:00
|
|
|
return Ok;
|
|
|
|
}
|
|
|
|
|
2012-12-11 21:40:15 +00:00
|
|
|
static GpStatus clone_font_family(const GpFontFamily *family, GpFontFamily **clone)
|
|
|
|
{
|
2015-11-22 10:10:02 +00:00
|
|
|
*clone = heap_alloc_zero(sizeof(GpFontFamily));
|
2012-12-11 21:40:15 +00:00
|
|
|
if (!*clone) return OutOfMemory;
|
|
|
|
|
|
|
|
**clone = *family;
|
|
|
|
|
|
|
|
return Ok;
|
|
|
|
}
|
|
|
|
|
2008-08-05 12:23:58 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
* GdipCloneFontFamily [GDIPLUS.@]
|
|
|
|
*
|
|
|
|
* Creates a deep copy of a Font Family object
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* FontFamily [I] Font to clone
|
|
|
|
* clonedFontFamily [O] The resulting cloned font
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* SUCCESS: Ok
|
|
|
|
*/
|
|
|
|
GpStatus WINGDIPAPI GdipCloneFontFamily(GpFontFamily* FontFamily, GpFontFamily** clonedFontFamily)
|
|
|
|
{
|
2012-12-11 21:40:15 +00:00
|
|
|
GpStatus status;
|
|
|
|
|
2008-08-05 12:23:58 +00:00
|
|
|
if (!(FontFamily && clonedFontFamily)) return InvalidParameter;
|
2008-07-02 08:19:00 +00:00
|
|
|
|
2012-05-19 10:03:40 +00:00
|
|
|
TRACE("%p (%s), %p\n", FontFamily,
|
2008-08-05 12:23:58 +00:00
|
|
|
debugstr_w(FontFamily->FamilyName), clonedFontFamily);
|
2008-07-02 08:19:00 +00:00
|
|
|
|
2012-12-11 21:40:15 +00:00
|
|
|
status = clone_font_family(FontFamily, clonedFontFamily);
|
|
|
|
if (status != Ok) return status;
|
2008-07-02 08:19:00 +00:00
|
|
|
|
2010-03-04 13:34:05 +00:00
|
|
|
TRACE("<-- %p\n", *clonedFontFamily);
|
|
|
|
|
2008-07-02 08:19:00 +00:00
|
|
|
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)
|
|
|
|
{
|
2010-04-20 08:30:10 +00:00
|
|
|
static int lang_fixme;
|
|
|
|
|
2008-07-02 08:19:00 +00:00
|
|
|
if (family == NULL)
|
|
|
|
return InvalidParameter;
|
|
|
|
|
|
|
|
TRACE("%p, %p, %d\n", family, name, language);
|
|
|
|
|
2010-04-20 08:30:10 +00:00
|
|
|
if (language != LANG_NEUTRAL && !lang_fixme++)
|
2008-07-02 08:19:00 +00:00
|
|
|
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));
|
|
|
|
|
2015-11-22 10:10:02 +00:00
|
|
|
heap_free (FontFamily);
|
2008-07-02 08:19:00 +00:00
|
|
|
|
|
|
|
return Ok;
|
|
|
|
}
|
|
|
|
|
2008-08-05 12:23:58 +00:00
|
|
|
GpStatus WINGDIPAPI GdipGetCellAscent(GDIPCONST GpFontFamily *family,
|
|
|
|
INT style, UINT16* CellAscent)
|
|
|
|
{
|
|
|
|
if (!(family && CellAscent)) return InvalidParameter;
|
|
|
|
|
2012-05-19 10:03:40 +00:00
|
|
|
*CellAscent = family->ascent;
|
|
|
|
TRACE("%s => %u\n", debugstr_w(family->FamilyName), *CellAscent);
|
2008-08-05 12:23:58 +00:00
|
|
|
|
|
|
|
return Ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
GpStatus WINGDIPAPI GdipGetCellDescent(GDIPCONST GpFontFamily *family,
|
|
|
|
INT style, UINT16* CellDescent)
|
|
|
|
{
|
2008-09-07 10:32:49 +00:00
|
|
|
TRACE("(%p, %d, %p)\n", family, style, CellDescent);
|
|
|
|
|
2008-08-05 12:23:58 +00:00
|
|
|
if (!(family && CellDescent)) return InvalidParameter;
|
|
|
|
|
2012-05-19 10:03:40 +00:00
|
|
|
*CellDescent = family->descent;
|
|
|
|
TRACE("%s => %u\n", debugstr_w(family->FamilyName), *CellDescent);
|
2008-08-05 12:23:58 +00:00
|
|
|
|
|
|
|
return Ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
* GdipGetEmHeight [GDIPLUS.@]
|
|
|
|
*
|
|
|
|
* Gets the height of the specified family in EmHeights
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* family [I] Family to retrieve from
|
|
|
|
* style [I] (optional) style
|
|
|
|
* EmHeight [O] return value
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* SUCCESS: Ok
|
|
|
|
* FAILURE: InvalidParameter
|
|
|
|
*/
|
|
|
|
GpStatus WINGDIPAPI GdipGetEmHeight(GDIPCONST GpFontFamily *family, INT style, UINT16* EmHeight)
|
|
|
|
{
|
|
|
|
if (!(family && EmHeight)) return InvalidParameter;
|
|
|
|
|
2008-12-06 09:26:01 +00:00
|
|
|
TRACE("%p (%s), %d, %p\n", family, debugstr_w(family->FamilyName), style, EmHeight);
|
2008-08-05 12:23:58 +00:00
|
|
|
|
2012-05-19 10:03:40 +00:00
|
|
|
*EmHeight = family->em_height;
|
|
|
|
TRACE("%s => %u\n", debugstr_w(family->FamilyName), *EmHeight);
|
2008-08-05 12:23:58 +00:00
|
|
|
|
|
|
|
return Ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
* GdipGetLineSpacing [GDIPLUS.@]
|
|
|
|
*
|
|
|
|
* Returns the line spacing in design units
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* family [I] Family to retrieve from
|
|
|
|
* style [I] (Optional) font style
|
|
|
|
* LineSpacing [O] Return value
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* SUCCESS: Ok
|
|
|
|
* FAILURE: InvalidParameter (family or LineSpacing was NULL)
|
|
|
|
*/
|
|
|
|
GpStatus WINGDIPAPI GdipGetLineSpacing(GDIPCONST GpFontFamily *family,
|
|
|
|
INT style, UINT16* LineSpacing)
|
|
|
|
{
|
2008-12-06 09:26:01 +00:00
|
|
|
TRACE("%p, %d, %p\n", family, style, LineSpacing);
|
2008-08-05 12:23:58 +00:00
|
|
|
|
2008-12-06 09:26:01 +00:00
|
|
|
if (!(family && LineSpacing))
|
|
|
|
return InvalidParameter;
|
2008-08-05 12:23:58 +00:00
|
|
|
|
2008-12-06 09:26:01 +00:00
|
|
|
if (style) FIXME("ignoring style\n");
|
|
|
|
|
2012-05-19 10:03:40 +00:00
|
|
|
*LineSpacing = family->line_spacing;
|
|
|
|
TRACE("%s => %u\n", debugstr_w(family->FamilyName), *LineSpacing);
|
2008-12-06 09:26:01 +00:00
|
|
|
|
|
|
|
return Ok;
|
2008-08-05 12:23:58 +00:00
|
|
|
}
|
|
|
|
|
Sync avifil, credui, crypt32, cryptdlg, cryptui, dnsapi, gdiplus, hhctrl, hnetcfg, iccvid, imaadp32, imm32, jscript, localspl, localui, mapi32, mciavi32, mcicda, mciqtz32, mciseq, mciwave, mshtml, msrle32, msvfw32, msvidc32, msxml3, oleacc, oleaut32 to Wine 1.2rc5 (Samuel Serapion, small changes by me)
Remove Esperanto and Walon languages from comctl32, comdlg32, mpr, msi, shlwapi, wininet
svn path=/trunk/; revision=47920
2010-07-01 11:09:47 +00:00
|
|
|
static INT CALLBACK font_has_style_proc(const LOGFONTW *elf,
|
|
|
|
const TEXTMETRICW *ntm, DWORD type, LPARAM lParam)
|
|
|
|
{
|
2012-05-19 10:03:40 +00:00
|
|
|
INT fontstyle = FontStyleRegular;
|
Sync avifil, credui, crypt32, cryptdlg, cryptui, dnsapi, gdiplus, hhctrl, hnetcfg, iccvid, imaadp32, imm32, jscript, localspl, localui, mapi32, mciavi32, mcicda, mciqtz32, mciseq, mciwave, mshtml, msrle32, msvfw32, msvidc32, msxml3, oleacc, oleaut32 to Wine 1.2rc5 (Samuel Serapion, small changes by me)
Remove Esperanto and Walon languages from comctl32, comdlg32, mpr, msi, shlwapi, wininet
svn path=/trunk/; revision=47920
2010-07-01 11:09:47 +00:00
|
|
|
|
|
|
|
if (!ntm) return 1;
|
|
|
|
|
|
|
|
if (ntm->tmWeight >= FW_BOLD) fontstyle |= FontStyleBold;
|
|
|
|
if (ntm->tmItalic) fontstyle |= FontStyleItalic;
|
|
|
|
if (ntm->tmUnderlined) fontstyle |= FontStyleUnderline;
|
|
|
|
if (ntm->tmStruckOut) fontstyle |= FontStyleStrikeout;
|
|
|
|
|
|
|
|
return (INT)lParam != fontstyle;
|
|
|
|
}
|
|
|
|
|
2008-08-05 12:23:58 +00:00
|
|
|
GpStatus WINGDIPAPI GdipIsStyleAvailable(GDIPCONST GpFontFamily* family,
|
|
|
|
INT style, BOOL* IsStyleAvailable)
|
|
|
|
{
|
Sync avifil, credui, crypt32, cryptdlg, cryptui, dnsapi, gdiplus, hhctrl, hnetcfg, iccvid, imaadp32, imm32, jscript, localspl, localui, mapi32, mciavi32, mcicda, mciqtz32, mciseq, mciwave, mshtml, msrle32, msvfw32, msvidc32, msxml3, oleacc, oleaut32 to Wine 1.2rc5 (Samuel Serapion, small changes by me)
Remove Esperanto and Walon languages from comctl32, comdlg32, mpr, msi, shlwapi, wininet
svn path=/trunk/; revision=47920
2010-07-01 11:09:47 +00:00
|
|
|
HDC hdc;
|
|
|
|
|
|
|
|
TRACE("%p %d %p\n", family, style, IsStyleAvailable);
|
2008-08-05 12:23:58 +00:00
|
|
|
|
|
|
|
if (!(family && IsStyleAvailable))
|
|
|
|
return InvalidParameter;
|
|
|
|
|
Sync avifil, credui, crypt32, cryptdlg, cryptui, dnsapi, gdiplus, hhctrl, hnetcfg, iccvid, imaadp32, imm32, jscript, localspl, localui, mapi32, mciavi32, mcicda, mciqtz32, mciseq, mciwave, mshtml, msrle32, msvfw32, msvidc32, msxml3, oleacc, oleaut32 to Wine 1.2rc5 (Samuel Serapion, small changes by me)
Remove Esperanto and Walon languages from comctl32, comdlg32, mpr, msi, shlwapi, wininet
svn path=/trunk/; revision=47920
2010-07-01 11:09:47 +00:00
|
|
|
*IsStyleAvailable = FALSE;
|
|
|
|
|
2013-05-23 17:23:00 +00:00
|
|
|
hdc = CreateCompatibleDC(0);
|
Sync avifil, credui, crypt32, cryptdlg, cryptui, dnsapi, gdiplus, hhctrl, hnetcfg, iccvid, imaadp32, imm32, jscript, localspl, localui, mapi32, mciavi32, mcicda, mciqtz32, mciseq, mciwave, mshtml, msrle32, msvfw32, msvidc32, msxml3, oleacc, oleaut32 to Wine 1.2rc5 (Samuel Serapion, small changes by me)
Remove Esperanto and Walon languages from comctl32, comdlg32, mpr, msi, shlwapi, wininet
svn path=/trunk/; revision=47920
2010-07-01 11:09:47 +00:00
|
|
|
|
|
|
|
if(!EnumFontFamiliesW(hdc, family->FamilyName, font_has_style_proc, (LPARAM)style))
|
|
|
|
*IsStyleAvailable = TRUE;
|
|
|
|
|
2013-05-23 17:23:00 +00:00
|
|
|
DeleteDC(hdc);
|
Sync avifil, credui, crypt32, cryptdlg, cryptui, dnsapi, gdiplus, hhctrl, hnetcfg, iccvid, imaadp32, imm32, jscript, localspl, localui, mapi32, mciavi32, mcicda, mciqtz32, mciseq, mciwave, mshtml, msrle32, msvfw32, msvidc32, msxml3, oleacc, oleaut32 to Wine 1.2rc5 (Samuel Serapion, small changes by me)
Remove Esperanto and Walon languages from comctl32, comdlg32, mpr, msi, shlwapi, wininet
svn path=/trunk/; revision=47920
2010-07-01 11:09:47 +00:00
|
|
|
|
|
|
|
return Ok;
|
2008-08-05 12:23:58 +00:00
|
|
|
}
|
|
|
|
|
2008-07-02 08:19:00 +00:00
|
|
|
/*****************************************************************************
|
|
|
|
* 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'};
|
2012-03-05 20:17:42 +00:00
|
|
|
static const WCHAR LiberationMono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o','\0'};
|
|
|
|
GpStatus stat;
|
2008-07-02 08:19:00 +00:00
|
|
|
|
|
|
|
if (nativeFamily == NULL) return InvalidParameter;
|
|
|
|
|
2012-03-05 20:17:42 +00:00
|
|
|
stat = GdipCreateFontFamilyFromName(CourierNew, NULL, nativeFamily);
|
|
|
|
|
|
|
|
if (stat == FontFamilyNotFound)
|
|
|
|
stat = GdipCreateFontFamilyFromName(LiberationMono, NULL, nativeFamily);
|
|
|
|
|
|
|
|
if (stat == FontFamilyNotFound)
|
|
|
|
ERR("Missing 'Courier New' font\n");
|
|
|
|
|
|
|
|
return stat;
|
2008-07-02 08:19:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* 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'};
|
2012-03-05 20:17:42 +00:00
|
|
|
static const WCHAR LiberationSerif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f','\0'};
|
|
|
|
GpStatus stat;
|
2008-07-02 08:19:00 +00:00
|
|
|
|
2008-09-07 10:32:49 +00:00
|
|
|
TRACE("(%p)\n", nativeFamily);
|
|
|
|
|
2008-07-02 08:19:00 +00:00
|
|
|
if (nativeFamily == NULL) return InvalidParameter;
|
|
|
|
|
2012-03-05 20:17:42 +00:00
|
|
|
stat = GdipCreateFontFamilyFromName(TimesNewRoman, NULL, nativeFamily);
|
|
|
|
|
|
|
|
if (stat == FontFamilyNotFound)
|
|
|
|
stat = GdipCreateFontFamilyFromName(LiberationSerif, NULL, nativeFamily);
|
|
|
|
|
|
|
|
if (stat == FontFamilyNotFound)
|
|
|
|
ERR("Missing 'Times New Roman' font\n");
|
|
|
|
|
|
|
|
return stat;
|
2008-07-02 08:19:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* 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)
|
|
|
|
{
|
2010-04-20 08:30:10 +00:00
|
|
|
GpStatus stat;
|
|
|
|
static const WCHAR MicrosoftSansSerif[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f','\0'};
|
|
|
|
static const WCHAR Tahoma[] = {'T','a','h','o','m','a','\0'};
|
2008-07-02 08:19:00 +00:00
|
|
|
|
2008-09-07 10:32:49 +00:00
|
|
|
TRACE("(%p)\n", nativeFamily);
|
|
|
|
|
2008-07-02 08:19:00 +00:00
|
|
|
if (nativeFamily == NULL) return InvalidParameter;
|
|
|
|
|
2010-04-20 08:30:10 +00:00
|
|
|
stat = GdipCreateFontFamilyFromName(MicrosoftSansSerif, NULL, nativeFamily);
|
|
|
|
|
|
|
|
if (stat == FontFamilyNotFound)
|
|
|
|
/* FIXME: Microsoft Sans Serif is not installed on Wine. */
|
|
|
|
stat = GdipCreateFontFamilyFromName(Tahoma, NULL, nativeFamily);
|
|
|
|
|
|
|
|
return stat;
|
2008-07-02 08:19:00 +00:00
|
|
|
}
|
2008-08-05 12:23:58 +00:00
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* GdipGetGenericFontFamilySansSerif [GDIPLUS.@]
|
|
|
|
*/
|
|
|
|
GpStatus WINGDIPAPI GdipNewPrivateFontCollection(GpFontCollection** fontCollection)
|
|
|
|
{
|
2008-12-06 09:26:01 +00:00
|
|
|
TRACE("%p\n", fontCollection);
|
2008-08-05 12:23:58 +00:00
|
|
|
|
|
|
|
if (!fontCollection)
|
|
|
|
return InvalidParameter;
|
|
|
|
|
2015-11-22 10:10:02 +00:00
|
|
|
*fontCollection = heap_alloc_zero(sizeof(GpFontCollection));
|
2008-12-06 09:26:01 +00:00
|
|
|
if (!*fontCollection) return OutOfMemory;
|
|
|
|
|
|
|
|
(*fontCollection)->FontFamilies = NULL;
|
|
|
|
(*fontCollection)->count = 0;
|
2009-05-23 10:32:19 +00:00
|
|
|
(*fontCollection)->allocated = 0;
|
2010-03-04 13:34:05 +00:00
|
|
|
|
|
|
|
TRACE("<-- %p\n", *fontCollection);
|
|
|
|
|
2008-12-06 09:26:01 +00:00
|
|
|
return Ok;
|
2008-08-05 12:23:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* GdipDeletePrivateFontCollection [GDIPLUS.@]
|
|
|
|
*/
|
|
|
|
GpStatus WINGDIPAPI GdipDeletePrivateFontCollection(GpFontCollection **fontCollection)
|
|
|
|
{
|
2008-12-06 09:26:01 +00:00
|
|
|
INT i;
|
|
|
|
|
|
|
|
TRACE("%p\n", fontCollection);
|
2008-08-05 12:23:58 +00:00
|
|
|
|
|
|
|
if (!fontCollection)
|
|
|
|
return InvalidParameter;
|
|
|
|
|
2015-11-22 10:10:02 +00:00
|
|
|
for (i = 0; i < (*fontCollection)->count; i++) heap_free((*fontCollection)->FontFamilies[i]);
|
2019-01-25 12:21:54 +00:00
|
|
|
heap_free((*fontCollection)->FontFamilies);
|
2015-11-22 10:10:02 +00:00
|
|
|
heap_free(*fontCollection);
|
2008-12-06 09:26:01 +00:00
|
|
|
|
|
|
|
return Ok;
|
2008-08-05 12:23:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* GdipPrivateAddFontFile [GDIPLUS.@]
|
|
|
|
*/
|
2014-04-22 15:42:03 +00:00
|
|
|
GpStatus WINGDIPAPI GdipPrivateAddFontFile(GpFontCollection *collection, GDIPCONST WCHAR *name)
|
2008-08-05 12:23:58 +00:00
|
|
|
{
|
2014-04-22 15:42:03 +00:00
|
|
|
HANDLE file, mapping;
|
|
|
|
LARGE_INTEGER size;
|
|
|
|
void *mem;
|
|
|
|
GpStatus status;
|
|
|
|
|
|
|
|
TRACE("%p, %s\n", collection, debugstr_w(name));
|
|
|
|
|
|
|
|
if (!collection || !name) return InvalidParameter;
|
2008-08-05 12:23:58 +00:00
|
|
|
|
2014-04-22 15:42:03 +00:00
|
|
|
file = CreateFileW(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
|
|
|
|
if (file == INVALID_HANDLE_VALUE) return InvalidParameter;
|
|
|
|
|
|
|
|
if (!GetFileSizeEx(file, &size) || size.u.HighPart)
|
|
|
|
{
|
|
|
|
CloseHandle(file);
|
2008-08-05 12:23:58 +00:00
|
|
|
return InvalidParameter;
|
2014-04-22 15:42:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
|
|
|
|
CloseHandle(file);
|
|
|
|
if (!mapping) return InvalidParameter;
|
|
|
|
|
|
|
|
mem = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
|
|
|
|
CloseHandle(mapping);
|
|
|
|
if (!mem) return InvalidParameter;
|
|
|
|
|
|
|
|
/* GdipPrivateAddMemoryFont creates a copy of the memory block */
|
|
|
|
status = GdipPrivateAddMemoryFont(collection, mem, size.u.LowPart);
|
|
|
|
UnmapViewOfFile(mem);
|
2008-08-05 12:23:58 +00:00
|
|
|
|
2014-04-22 15:42:03 +00:00
|
|
|
return status;
|
2008-08-05 12:23:58 +00:00
|
|
|
}
|
|
|
|
|
2013-09-19 15:10:19 +00:00
|
|
|
#define TT_PLATFORM_APPLE_UNICODE 0
|
|
|
|
#define TT_PLATFORM_MACINTOSH 1
|
|
|
|
#define TT_PLATFORM_MICROSOFT 3
|
|
|
|
|
|
|
|
#define TT_APPLE_ID_DEFAULT 0
|
|
|
|
#define TT_APPLE_ID_ISO_10646 2
|
|
|
|
#define TT_APPLE_ID_UNICODE_2_0 3
|
|
|
|
|
|
|
|
#define TT_MS_ID_SYMBOL_CS 0
|
|
|
|
#define TT_MS_ID_UNICODE_CS 1
|
|
|
|
|
|
|
|
#define TT_MAC_ID_SIMPLIFIED_CHINESE 25
|
2012-03-05 20:17:42 +00:00
|
|
|
|
|
|
|
#define NAME_ID_FULL_FONT_NAME 4
|
|
|
|
|
2013-09-19 15:10:19 +00:00
|
|
|
typedef struct {
|
|
|
|
USHORT major_version;
|
|
|
|
USHORT minor_version;
|
|
|
|
USHORT tables_no;
|
|
|
|
USHORT search_range;
|
|
|
|
USHORT entry_selector;
|
|
|
|
USHORT range_shift;
|
|
|
|
} tt_header;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
char tag[4]; /* table name */
|
|
|
|
ULONG check_sum; /* Check sum */
|
|
|
|
ULONG offset; /* Offset from beginning of file */
|
|
|
|
ULONG length; /* length of the table in bytes */
|
|
|
|
} tt_table_directory;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
USHORT format; /* format selector. Always 0 */
|
|
|
|
USHORT count; /* Name Records count */
|
|
|
|
USHORT string_offset; /* Offset for strings storage, * from start of the table */
|
|
|
|
} tt_name_table;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
USHORT platform_id;
|
|
|
|
USHORT encoding_id;
|
|
|
|
USHORT language_id;
|
|
|
|
USHORT name_id;
|
|
|
|
USHORT length;
|
|
|
|
USHORT offset; /* from start of storage area */
|
|
|
|
} tt_name_record;
|
|
|
|
|
|
|
|
/* Copied from gdi32/freetype.c */
|
|
|
|
|
|
|
|
static const LANGID mac_langid_table[] =
|
|
|
|
{
|
|
|
|
MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ENGLISH */
|
|
|
|
MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FRENCH */
|
|
|
|
MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GERMAN */
|
|
|
|
MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ITALIAN */
|
|
|
|
MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DUTCH */
|
|
|
|
MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWEDISH */
|
|
|
|
MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SPANISH */
|
|
|
|
MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DANISH */
|
|
|
|
MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PORTUGUESE */
|
|
|
|
MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NORWEGIAN */
|
|
|
|
MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HEBREW */
|
|
|
|
MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_JAPANESE */
|
|
|
|
MAKELANGID(LANG_ARABIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARABIC */
|
|
|
|
MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FINNISH */
|
|
|
|
MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREEK */
|
|
|
|
MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ICELANDIC */
|
|
|
|
MAKELANGID(LANG_MALTESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALTESE */
|
|
|
|
MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKISH */
|
|
|
|
MAKELANGID(LANG_CROATIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CROATIAN */
|
|
|
|
MAKELANGID(LANG_CHINESE_TRADITIONAL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
|
|
|
|
MAKELANGID(LANG_URDU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_URDU */
|
|
|
|
MAKELANGID(LANG_HINDI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HINDI */
|
|
|
|
MAKELANGID(LANG_THAI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_THAI */
|
|
|
|
MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KOREAN */
|
|
|
|
MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LITHUANIAN */
|
|
|
|
MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_POLISH */
|
|
|
|
MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HUNGARIAN */
|
|
|
|
MAKELANGID(LANG_ESTONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESTONIAN */
|
|
|
|
MAKELANGID(LANG_LATVIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LETTISH */
|
|
|
|
MAKELANGID(LANG_SAMI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SAAMISK */
|
|
|
|
MAKELANGID(LANG_FAEROESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FAEROESE */
|
|
|
|
MAKELANGID(LANG_FARSI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FARSI */
|
|
|
|
MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_RUSSIAN */
|
|
|
|
MAKELANGID(LANG_CHINESE_SIMPLIFIED,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
|
|
|
|
MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), /* TT_MAC_LANGID_FLEMISH */
|
|
|
|
MAKELANGID(LANG_IRISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_IRISH */
|
|
|
|
MAKELANGID(LANG_ALBANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ALBANIAN */
|
|
|
|
MAKELANGID(LANG_ROMANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ROMANIAN */
|
|
|
|
MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CZECH */
|
|
|
|
MAKELANGID(LANG_SLOVAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVAK */
|
|
|
|
MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVENIAN */
|
|
|
|
0, /* TT_MAC_LANGID_YIDDISH */
|
|
|
|
MAKELANGID(LANG_SERBIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SERBIAN */
|
|
|
|
MAKELANGID(LANG_MACEDONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MACEDONIAN */
|
|
|
|
MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BULGARIAN */
|
|
|
|
MAKELANGID(LANG_UKRAINIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UKRAINIAN */
|
|
|
|
MAKELANGID(LANG_BELARUSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BYELORUSSIAN */
|
|
|
|
MAKELANGID(LANG_UZBEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UZBEK */
|
|
|
|
MAKELANGID(LANG_KAZAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KAZAKH */
|
|
|
|
MAKELANGID(LANG_AZERI,SUBLANG_AZERI_CYRILLIC), /* TT_MAC_LANGID_AZERBAIJANI */
|
|
|
|
0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
|
|
|
|
MAKELANGID(LANG_ARMENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARMENIAN */
|
|
|
|
MAKELANGID(LANG_GEORGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GEORGIAN */
|
|
|
|
0, /* TT_MAC_LANGID_MOLDAVIAN */
|
|
|
|
MAKELANGID(LANG_KYRGYZ,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KIRGHIZ */
|
|
|
|
MAKELANGID(LANG_TAJIK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAJIKI */
|
|
|
|
MAKELANGID(LANG_TURKMEN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKMEN */
|
|
|
|
MAKELANGID(LANG_MONGOLIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MONGOLIAN */
|
|
|
|
MAKELANGID(LANG_MONGOLIAN,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
|
|
|
|
MAKELANGID(LANG_PASHTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PASHTO */
|
|
|
|
0, /* TT_MAC_LANGID_KURDISH */
|
|
|
|
MAKELANGID(LANG_KASHMIRI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KASHMIRI */
|
|
|
|
MAKELANGID(LANG_SINDHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINDHI */
|
|
|
|
MAKELANGID(LANG_TIBETAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIBETAN */
|
|
|
|
MAKELANGID(LANG_NEPALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NEPALI */
|
|
|
|
MAKELANGID(LANG_SANSKRIT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SANSKRIT */
|
|
|
|
MAKELANGID(LANG_MARATHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MARATHI */
|
|
|
|
MAKELANGID(LANG_BENGALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BENGALI */
|
|
|
|
MAKELANGID(LANG_ASSAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ASSAMESE */
|
|
|
|
MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GUJARATI */
|
|
|
|
MAKELANGID(LANG_PUNJABI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PUNJABI */
|
|
|
|
MAKELANGID(LANG_ORIYA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ORIYA */
|
|
|
|
MAKELANGID(LANG_MALAYALAM,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAYALAM */
|
|
|
|
MAKELANGID(LANG_KANNADA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KANNADA */
|
|
|
|
MAKELANGID(LANG_TAMIL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAMIL */
|
|
|
|
MAKELANGID(LANG_TELUGU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TELUGU */
|
|
|
|
MAKELANGID(LANG_SINHALESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINHALESE */
|
|
|
|
0, /* TT_MAC_LANGID_BURMESE */
|
|
|
|
MAKELANGID(LANG_KHMER,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KHMER */
|
|
|
|
MAKELANGID(LANG_LAO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LAO */
|
|
|
|
MAKELANGID(LANG_VIETNAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_VIETNAMESE */
|
|
|
|
MAKELANGID(LANG_INDONESIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INDONESIAN */
|
|
|
|
0, /* TT_MAC_LANGID_TAGALOG */
|
|
|
|
MAKELANGID(LANG_MALAY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
|
|
|
|
0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
|
|
|
|
MAKELANGID(LANG_AMHARIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AMHARIC */
|
|
|
|
MAKELANGID(LANG_TIGRIGNA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIGRINYA */
|
|
|
|
0, /* TT_MAC_LANGID_GALLA */
|
|
|
|
0, /* TT_MAC_LANGID_SOMALI */
|
|
|
|
MAKELANGID(LANG_SWAHILI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWAHILI */
|
|
|
|
0, /* TT_MAC_LANGID_RUANDA */
|
|
|
|
0, /* TT_MAC_LANGID_RUNDI */
|
|
|
|
0, /* TT_MAC_LANGID_CHEWA */
|
|
|
|
MAKELANGID(LANG_MALAGASY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAGASY */
|
|
|
|
MAKELANGID(LANG_ESPERANTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESPERANTO */
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
|
|
|
|
MAKELANGID(LANG_WELSH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_WELSH */
|
|
|
|
MAKELANGID(LANG_BASQUE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BASQUE */
|
|
|
|
MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CATALAN */
|
|
|
|
0, /* TT_MAC_LANGID_LATIN */
|
|
|
|
MAKELANGID(LANG_QUECHUA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_QUECHUA */
|
|
|
|
0, /* TT_MAC_LANGID_GUARANI */
|
|
|
|
0, /* TT_MAC_LANGID_AYMARA */
|
|
|
|
MAKELANGID(LANG_TATAR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TATAR */
|
|
|
|
MAKELANGID(LANG_UIGHUR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UIGHUR */
|
|
|
|
0, /* TT_MAC_LANGID_DZONGKHA */
|
|
|
|
0, /* TT_MAC_LANGID_JAVANESE */
|
|
|
|
0, /* TT_MAC_LANGID_SUNDANESE */
|
|
|
|
MAKELANGID(LANG_GALICIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GALICIAN */
|
|
|
|
MAKELANGID(LANG_AFRIKAANS,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AFRIKAANS */
|
|
|
|
MAKELANGID(LANG_BRETON,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BRETON */
|
|
|
|
MAKELANGID(LANG_INUKTITUT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INUKTITUT */
|
|
|
|
MAKELANGID(LANG_SCOTTISH_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
|
|
|
|
MAKELANGID(LANG_MANX_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MANX_GAELIC */
|
|
|
|
MAKELANGID(LANG_IRISH,SUBLANG_IRISH_IRELAND), /* TT_MAC_LANGID_IRISH_GAELIC */
|
|
|
|
0, /* TT_MAC_LANGID_TONGAN */
|
|
|
|
0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
|
|
|
|
MAKELANGID(LANG_GREENLANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREELANDIC */
|
|
|
|
MAKELANGID(LANG_AZERI,SUBLANG_AZERI_LATIN), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
|
|
|
|
};
|
2012-03-05 20:17:42 +00:00
|
|
|
|
2013-09-19 15:10:19 +00:00
|
|
|
static inline WORD get_mac_code_page( const tt_name_record *name )
|
|
|
|
{
|
|
|
|
WORD encoding_id = GET_BE_WORD(name->encoding_id);
|
|
|
|
if (encoding_id == TT_MAC_ID_SIMPLIFIED_CHINESE) return 10008; /* special case */
|
|
|
|
return 10000 + encoding_id;
|
|
|
|
}
|
2012-03-05 20:17:42 +00:00
|
|
|
|
2013-09-19 15:10:19 +00:00
|
|
|
static int match_name_table_language( const tt_name_record *name, LANGID lang )
|
|
|
|
{
|
|
|
|
LANGID name_lang;
|
|
|
|
|
|
|
|
switch (GET_BE_WORD(name->platform_id))
|
|
|
|
{
|
|
|
|
case TT_PLATFORM_MICROSOFT:
|
|
|
|
switch (GET_BE_WORD(name->encoding_id))
|
|
|
|
{
|
|
|
|
case TT_MS_ID_UNICODE_CS:
|
|
|
|
case TT_MS_ID_SYMBOL_CS:
|
|
|
|
name_lang = GET_BE_WORD(name->language_id);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TT_PLATFORM_MACINTOSH:
|
|
|
|
if (!IsValidCodePage( get_mac_code_page( name ))) return 0;
|
|
|
|
name_lang = GET_BE_WORD(name->language_id);
|
2018-05-27 03:10:39 +00:00
|
|
|
if (name_lang >= ARRAY_SIZE(mac_langid_table)) return 0;
|
2013-09-19 15:10:19 +00:00
|
|
|
name_lang = mac_langid_table[name_lang];
|
|
|
|
break;
|
|
|
|
case TT_PLATFORM_APPLE_UNICODE:
|
|
|
|
switch (GET_BE_WORD(name->encoding_id))
|
|
|
|
{
|
|
|
|
case TT_APPLE_ID_DEFAULT:
|
|
|
|
case TT_APPLE_ID_ISO_10646:
|
|
|
|
case TT_APPLE_ID_UNICODE_2_0:
|
|
|
|
name_lang = GET_BE_WORD(name->language_id);
|
2018-05-27 03:10:39 +00:00
|
|
|
if (name_lang >= ARRAY_SIZE(mac_langid_table)) return 0;
|
2013-09-19 15:10:19 +00:00
|
|
|
name_lang = mac_langid_table[name_lang];
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (name_lang == lang) return 3;
|
|
|
|
if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) return 2;
|
|
|
|
if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-01-18 23:17:41 +00:00
|
|
|
static WCHAR *copy_name_table_string( const tt_name_record *name, const BYTE *data )
|
2013-09-19 15:10:19 +00:00
|
|
|
{
|
|
|
|
WORD name_len = GET_BE_WORD(name->length);
|
|
|
|
WORD codepage;
|
2018-01-18 23:17:41 +00:00
|
|
|
WCHAR *ret;
|
|
|
|
int len;
|
2013-09-19 15:10:19 +00:00
|
|
|
|
|
|
|
switch (GET_BE_WORD(name->platform_id))
|
|
|
|
{
|
|
|
|
case TT_PLATFORM_APPLE_UNICODE:
|
|
|
|
case TT_PLATFORM_MICROSOFT:
|
2018-01-18 23:17:41 +00:00
|
|
|
ret = heap_alloc((name_len / 2 + 1) * sizeof(WCHAR));
|
2013-09-19 15:10:19 +00:00
|
|
|
for (len = 0; len < name_len / 2; len++)
|
|
|
|
ret[len] = (data[len * 2] << 8) | data[len * 2 + 1];
|
|
|
|
ret[len] = 0;
|
|
|
|
return ret;
|
|
|
|
case TT_PLATFORM_MACINTOSH:
|
|
|
|
codepage = get_mac_code_page( name );
|
2018-01-18 23:17:41 +00:00
|
|
|
len = MultiByteToWideChar( codepage, 0, (char *)data, name_len, NULL, 0 ) + 1;
|
2013-09-19 15:10:19 +00:00
|
|
|
if (!len)
|
|
|
|
return NULL;
|
2018-01-18 23:17:41 +00:00
|
|
|
ret = heap_alloc(len * sizeof(WCHAR));
|
|
|
|
len = MultiByteToWideChar( codepage, 0, (char *)data, name_len, ret, len - 1 );
|
2013-09-19 15:10:19 +00:00
|
|
|
ret[len] = 0;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-01-18 23:17:41 +00:00
|
|
|
static WCHAR *load_ttf_name_id( const BYTE *mem, DWORD_PTR size, DWORD id )
|
2012-03-05 20:17:42 +00:00
|
|
|
{
|
2013-09-19 15:10:19 +00:00
|
|
|
LANGID lang = GetSystemDefaultLangID();
|
|
|
|
const tt_header *header;
|
|
|
|
const tt_name_table *name_table;
|
|
|
|
const tt_name_record *name_record;
|
|
|
|
DWORD pos, ofs, count;
|
|
|
|
int i, res, best_lang = 0, best_index = -1;
|
|
|
|
|
|
|
|
if (sizeof(tt_header) > size)
|
2012-03-05 20:17:42 +00:00
|
|
|
return NULL;
|
2013-09-19 15:10:19 +00:00
|
|
|
header = (const tt_header*)mem;
|
|
|
|
count = GET_BE_WORD(header->tables_no);
|
2012-03-05 20:17:42 +00:00
|
|
|
|
2013-09-19 15:10:19 +00:00
|
|
|
if (GET_BE_WORD(header->major_version) != 1 || GET_BE_WORD(header->minor_version) != 0)
|
2012-03-05 20:17:42 +00:00
|
|
|
return NULL;
|
|
|
|
|
2013-09-19 15:10:19 +00:00
|
|
|
pos = sizeof(*header);
|
|
|
|
for (i = 0; i < count; i++)
|
2012-03-05 20:17:42 +00:00
|
|
|
{
|
2013-09-19 15:10:19 +00:00
|
|
|
const tt_table_directory *table_directory = (const tt_table_directory*)&mem[pos];
|
|
|
|
pos += sizeof(*table_directory);
|
|
|
|
if (memcmp(table_directory->tag, "name", 4) == 0)
|
2012-03-05 20:17:42 +00:00
|
|
|
{
|
2013-09-19 15:10:19 +00:00
|
|
|
ofs = GET_BE_DWORD(table_directory->offset);
|
2012-03-05 20:17:42 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-09-19 15:10:19 +00:00
|
|
|
if (i >= count)
|
2012-03-05 20:17:42 +00:00
|
|
|
return NULL;
|
|
|
|
|
2013-09-19 15:10:19 +00:00
|
|
|
if (ofs >= size)
|
|
|
|
return NULL;
|
|
|
|
pos = ofs + sizeof(*name_table);
|
2012-03-05 20:17:42 +00:00
|
|
|
if (pos > size)
|
|
|
|
return NULL;
|
2013-09-19 15:10:19 +00:00
|
|
|
name_table = (const tt_name_table*)&mem[ofs];
|
|
|
|
count = GET_BE_WORD(name_table->count);
|
|
|
|
if (GET_BE_WORD(name_table->string_offset) >= size - ofs) return NULL;
|
|
|
|
ofs += GET_BE_WORD(name_table->string_offset);
|
|
|
|
for (i=0; i<count; i++)
|
2012-03-05 20:17:42 +00:00
|
|
|
{
|
2013-09-19 15:10:19 +00:00
|
|
|
name_record = (const tt_name_record*)&mem[pos];
|
|
|
|
pos += sizeof(*name_record);
|
2012-03-05 20:17:42 +00:00
|
|
|
if (pos > size)
|
|
|
|
return NULL;
|
|
|
|
|
2013-09-19 15:10:19 +00:00
|
|
|
if (GET_BE_WORD(name_record->name_id) != id) continue;
|
|
|
|
if (GET_BE_WORD(name_record->offset) >= size - ofs) return NULL;
|
|
|
|
if (GET_BE_WORD(name_record->length) > size - ofs - GET_BE_WORD(name_record->offset)) return NULL;
|
|
|
|
|
|
|
|
res = match_name_table_language( name_record, lang );
|
|
|
|
if (res > best_lang)
|
2012-03-05 20:17:42 +00:00
|
|
|
{
|
2013-09-19 15:10:19 +00:00
|
|
|
best_lang = res;
|
|
|
|
best_index = i;
|
2012-03-05 20:17:42 +00:00
|
|
|
}
|
|
|
|
}
|
2013-09-19 15:10:19 +00:00
|
|
|
|
|
|
|
if (best_lang)
|
|
|
|
{
|
2018-01-18 23:17:41 +00:00
|
|
|
WCHAR *ret;
|
2013-09-19 15:10:19 +00:00
|
|
|
name_record = (const tt_name_record*)(name_table + 1) + best_index;
|
2018-01-18 23:17:41 +00:00
|
|
|
ret = copy_name_table_string( name_record, mem+ofs+GET_BE_WORD(name_record->offset) );
|
2013-09-19 15:10:19 +00:00
|
|
|
TRACE( "name %u found platform %u lang %04x %s\n", GET_BE_WORD(name_record->name_id),
|
|
|
|
GET_BE_WORD(name_record->platform_id), GET_BE_WORD(name_record->language_id), debugstr_w( ret ));
|
|
|
|
return ret;
|
|
|
|
}
|
2012-03-05 20:17:42 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-01-25 12:21:54 +00:00
|
|
|
struct add_font_param
|
|
|
|
{
|
|
|
|
GpFontCollection *collection;
|
|
|
|
BOOL is_system;
|
|
|
|
GpStatus stat;
|
|
|
|
};
|
|
|
|
|
2012-03-05 20:17:42 +00:00
|
|
|
static INT CALLBACK add_font_proc(const LOGFONTW *lfw, const TEXTMETRICW *ntm, DWORD type, LPARAM lParam);
|
|
|
|
|
2008-12-06 09:26:01 +00:00
|
|
|
/*****************************************************************************
|
|
|
|
* GdipPrivateAddMemoryFont [GDIPLUS.@]
|
|
|
|
*/
|
|
|
|
GpStatus WINGDIPAPI GdipPrivateAddMemoryFont(GpFontCollection* fontCollection,
|
|
|
|
GDIPCONST void* memory, INT length)
|
|
|
|
{
|
2018-01-18 23:17:41 +00:00
|
|
|
WCHAR *name;
|
2012-03-05 20:17:42 +00:00
|
|
|
DWORD count = 0;
|
|
|
|
HANDLE font;
|
2018-01-18 23:17:41 +00:00
|
|
|
GpStatus ret = Ok;
|
2012-03-05 20:17:42 +00:00
|
|
|
TRACE("%p, %p, %d\n", fontCollection, memory, length);
|
2008-12-06 09:26:01 +00:00
|
|
|
|
2012-03-05 20:17:42 +00:00
|
|
|
if (!fontCollection || !memory || !length)
|
2008-12-06 09:26:01 +00:00
|
|
|
return InvalidParameter;
|
|
|
|
|
2018-01-18 23:17:41 +00:00
|
|
|
name = load_ttf_name_id(memory, length, NAME_ID_FULL_FONT_NAME);
|
2012-03-05 20:17:42 +00:00
|
|
|
if (!name)
|
|
|
|
return OutOfMemory;
|
|
|
|
|
|
|
|
font = AddFontMemResourceEx((void*)memory, length, NULL, &count);
|
|
|
|
TRACE("%s: %p/%u\n", debugstr_w(name), font, count);
|
|
|
|
if (!font || !count)
|
2018-01-18 23:17:41 +00:00
|
|
|
ret = InvalidParameter;
|
|
|
|
else
|
2012-03-05 20:17:42 +00:00
|
|
|
{
|
2019-01-25 12:21:54 +00:00
|
|
|
struct add_font_param param;
|
2012-03-05 20:17:42 +00:00
|
|
|
HDC hdc;
|
|
|
|
LOGFONTW lfw;
|
|
|
|
|
2013-05-23 17:23:00 +00:00
|
|
|
hdc = CreateCompatibleDC(0);
|
2012-03-05 20:17:42 +00:00
|
|
|
|
2018-01-18 23:17:41 +00:00
|
|
|
/* Truncate name if necessary, GDI32 can't deal with long names */
|
|
|
|
if(lstrlenW(name) > LF_FACESIZE - 1)
|
|
|
|
name[LF_FACESIZE - 1] = 0;
|
|
|
|
|
2012-03-05 20:17:42 +00:00
|
|
|
lfw.lfCharSet = DEFAULT_CHARSET;
|
|
|
|
lstrcpyW(lfw.lfFaceName, name);
|
|
|
|
lfw.lfPitchAndFamily = 0;
|
|
|
|
|
2019-01-25 12:21:54 +00:00
|
|
|
param.collection = fontCollection;
|
|
|
|
param.is_system = FALSE;
|
|
|
|
if (!EnumFontFamiliesExW(hdc, &lfw, add_font_proc, (LPARAM)¶m, 0))
|
|
|
|
ret = param.stat;
|
2012-03-05 20:17:42 +00:00
|
|
|
|
2013-05-23 17:23:00 +00:00
|
|
|
DeleteDC(hdc);
|
2012-03-05 20:17:42 +00:00
|
|
|
}
|
2018-01-18 23:17:41 +00:00
|
|
|
heap_free(name);
|
|
|
|
return ret;
|
2008-12-06 09:26:01 +00:00
|
|
|
}
|
|
|
|
|
2008-08-05 12:23:58 +00:00
|
|
|
/*****************************************************************************
|
|
|
|
* GdipGetFontCollectionFamilyCount [GDIPLUS.@]
|
|
|
|
*/
|
|
|
|
GpStatus WINGDIPAPI GdipGetFontCollectionFamilyCount(
|
|
|
|
GpFontCollection* fontCollection, INT* numFound)
|
|
|
|
{
|
2008-12-06 09:26:01 +00:00
|
|
|
TRACE("%p, %p\n", fontCollection, numFound);
|
2008-08-05 12:23:58 +00:00
|
|
|
|
|
|
|
if (!(fontCollection && numFound))
|
|
|
|
return InvalidParameter;
|
|
|
|
|
2008-12-06 09:26:01 +00:00
|
|
|
*numFound = fontCollection->count;
|
|
|
|
return Ok;
|
2008-08-05 12:23:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* GdipGetFontCollectionFamilyList [GDIPLUS.@]
|
|
|
|
*/
|
|
|
|
GpStatus WINGDIPAPI GdipGetFontCollectionFamilyList(
|
|
|
|
GpFontCollection* fontCollection, INT numSought,
|
|
|
|
GpFontFamily* gpfamilies[], INT* numFound)
|
|
|
|
{
|
2008-12-06 09:26:01 +00:00
|
|
|
INT i;
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
GpStatus stat=Ok;
|
2008-12-06 09:26:01 +00:00
|
|
|
|
|
|
|
TRACE("%p, %d, %p, %p\n", fontCollection, numSought, gpfamilies, numFound);
|
2008-08-05 12:23:58 +00:00
|
|
|
|
|
|
|
if (!(fontCollection && gpfamilies && numFound))
|
|
|
|
return InvalidParameter;
|
|
|
|
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
memset(gpfamilies, 0, sizeof(*gpfamilies) * numSought);
|
|
|
|
|
|
|
|
for (i = 0; i < numSought && i < fontCollection->count && stat == Ok; i++)
|
2008-12-06 09:26:01 +00:00
|
|
|
{
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
stat = GdipCloneFontFamily(fontCollection->FontFamilies[i], &gpfamilies[i]);
|
2008-12-06 09:26:01 +00:00
|
|
|
}
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
|
|
|
|
if (stat == Ok)
|
|
|
|
*numFound = i;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int numToFree=i;
|
|
|
|
for (i=0; i<numToFree; i++)
|
|
|
|
{
|
|
|
|
GdipDeleteFontFamily(gpfamilies[i]);
|
|
|
|
gpfamilies[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return stat;
|
2008-12-06 09:26:01 +00:00
|
|
|
}
|
|
|
|
|
2009-05-23 10:32:19 +00:00
|
|
|
void free_installed_fonts(void)
|
|
|
|
{
|
|
|
|
while (installedFontCollection.count)
|
|
|
|
GdipDeleteFontFamily(installedFontCollection.FontFamilies[--installedFontCollection.count]);
|
2015-11-22 10:10:02 +00:00
|
|
|
heap_free(installedFontCollection.FontFamilies);
|
2009-05-23 10:32:19 +00:00
|
|
|
installedFontCollection.FontFamilies = NULL;
|
|
|
|
installedFontCollection.allocated = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static INT CALLBACK add_font_proc(const LOGFONTW *lfw, const TEXTMETRICW *ntm,
|
|
|
|
DWORD type, LPARAM lParam)
|
|
|
|
{
|
2019-01-25 12:21:54 +00:00
|
|
|
struct add_font_param *param = (struct add_font_param *)lParam;
|
|
|
|
GpFontCollection *fonts = param->collection;
|
2017-03-05 21:15:16 +00:00
|
|
|
GpFontFamily* family;
|
2019-01-25 12:21:54 +00:00
|
|
|
GpStatus stat;
|
2009-05-23 10:32:19 +00:00
|
|
|
int i;
|
|
|
|
|
2019-01-25 12:21:54 +00:00
|
|
|
param->stat = Ok;
|
|
|
|
|
2010-04-20 08:30:10 +00:00
|
|
|
if (type == RASTER_FONTTYPE)
|
|
|
|
return 1;
|
|
|
|
|
2017-03-05 21:15:16 +00:00
|
|
|
/* skip rotated fonts */
|
|
|
|
if (lfw->lfFaceName[0] == '@')
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (fonts->count && strcmpiW(lfw->lfFaceName, fonts->FontFamilies[fonts->count-1]->FamilyName) == 0)
|
|
|
|
return 1;
|
2009-05-23 10:32:19 +00:00
|
|
|
|
|
|
|
if (fonts->allocated == fonts->count)
|
|
|
|
{
|
|
|
|
INT new_alloc_count = fonts->allocated+50;
|
2015-11-22 10:10:02 +00:00
|
|
|
GpFontFamily** new_family_list = heap_alloc(new_alloc_count*sizeof(void*));
|
2009-05-23 10:32:19 +00:00
|
|
|
|
|
|
|
if (!new_family_list)
|
2019-01-25 12:21:54 +00:00
|
|
|
{
|
|
|
|
param->stat = OutOfMemory;
|
2009-05-23 10:32:19 +00:00
|
|
|
return 0;
|
2019-01-25 12:21:54 +00:00
|
|
|
}
|
2009-05-23 10:32:19 +00:00
|
|
|
|
|
|
|
memcpy(new_family_list, fonts->FontFamilies, fonts->count*sizeof(void*));
|
2015-11-22 10:10:02 +00:00
|
|
|
heap_free(fonts->FontFamilies);
|
2009-05-23 10:32:19 +00:00
|
|
|
fonts->FontFamilies = new_family_list;
|
|
|
|
fonts->allocated = new_alloc_count;
|
|
|
|
}
|
|
|
|
|
2019-01-25 12:21:54 +00:00
|
|
|
if ((stat = GdipCreateFontFamilyFromName(lfw->lfFaceName, NULL, &family)) != Ok)
|
|
|
|
{
|
|
|
|
WARN("Failed to create font family for %s, status %d.\n", debugstr_w(lfw->lfFaceName), stat);
|
|
|
|
if (param->is_system)
|
|
|
|
return 1;
|
|
|
|
param->stat = stat;
|
2009-05-23 10:32:19 +00:00
|
|
|
return 0;
|
2019-01-25 12:21:54 +00:00
|
|
|
}
|
2009-05-23 10:32:19 +00:00
|
|
|
|
2017-03-05 21:15:16 +00:00
|
|
|
/* skip duplicates */
|
|
|
|
for (i=0; i<fonts->count; i++)
|
|
|
|
{
|
|
|
|
if (strcmpiW(family->FamilyName, fonts->FontFamilies[i]->FamilyName) == 0)
|
|
|
|
{
|
|
|
|
GdipDeleteFontFamily(family);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fonts->FontFamilies[fonts->count++] = family;
|
|
|
|
|
2009-05-23 10:32:19 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-12-06 09:26:01 +00:00
|
|
|
GpStatus WINGDIPAPI GdipNewInstalledFontCollection(
|
|
|
|
GpFontCollection** fontCollection)
|
|
|
|
{
|
2009-05-23 10:32:19 +00:00
|
|
|
TRACE("(%p)\n",fontCollection);
|
2008-12-06 09:26:01 +00:00
|
|
|
|
|
|
|
if (!fontCollection)
|
|
|
|
return InvalidParameter;
|
|
|
|
|
2009-05-23 10:32:19 +00:00
|
|
|
if (installedFontCollection.count == 0)
|
|
|
|
{
|
2019-01-25 12:21:54 +00:00
|
|
|
struct add_font_param param;
|
2009-05-23 10:32:19 +00:00
|
|
|
HDC hdc;
|
|
|
|
LOGFONTW lfw;
|
|
|
|
|
2013-05-23 17:23:00 +00:00
|
|
|
hdc = CreateCompatibleDC(0);
|
2009-05-23 10:32:19 +00:00
|
|
|
|
|
|
|
lfw.lfCharSet = DEFAULT_CHARSET;
|
|
|
|
lfw.lfFaceName[0] = 0;
|
|
|
|
lfw.lfPitchAndFamily = 0;
|
|
|
|
|
2019-01-25 12:21:54 +00:00
|
|
|
param.collection = &installedFontCollection;
|
|
|
|
param.is_system = TRUE;
|
|
|
|
if (!EnumFontFamiliesExW(hdc, &lfw, add_font_proc, (LPARAM)¶m, 0))
|
2009-05-23 10:32:19 +00:00
|
|
|
{
|
|
|
|
free_installed_fonts();
|
2014-09-27 12:59:00 +00:00
|
|
|
DeleteDC(hdc);
|
2019-01-25 12:21:54 +00:00
|
|
|
return param.stat;
|
2009-05-23 10:32:19 +00:00
|
|
|
}
|
|
|
|
|
2013-05-23 17:23:00 +00:00
|
|
|
DeleteDC(hdc);
|
2009-05-23 10:32:19 +00:00
|
|
|
}
|
|
|
|
|
2009-05-09 09:26:16 +00:00
|
|
|
*fontCollection = &installedFontCollection;
|
|
|
|
|
|
|
|
return Ok;
|
2008-08-05 12:23:58 +00:00
|
|
|
}
|