/* * Font and collections * * Copyright 2012 Nikolay Sivov for CodeWeavers * * 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 */ #define COBJMACROS #include "dwrite.h" #include "dwrite_private.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(dwrite); /* PANOSE is 10 bytes in size, need to pack the structure properly */ #include "pshpack2.h" typedef struct { 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; #include "poppack.h" #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') struct dwrite_fontfamily { IDWriteFontFamily IDWriteFontFamily_iface; LONG ref; WCHAR *familyname; }; struct dwrite_font { IDWriteFont IDWriteFont_iface; LONG ref; IDWriteFontFamily *family; IDWriteFontFace *face; DWRITE_FONT_STYLE style; DWRITE_FONT_STRETCH stretch; DWRITE_FONT_WEIGHT weight; }; struct dwrite_fontface { IDWriteFontFace IDWriteFontFace_iface; LONG ref; }; static inline struct dwrite_fontface *impl_from_IDWriteFontFace(IDWriteFontFace *iface) { return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace_iface); } static inline struct dwrite_font *impl_from_IDWriteFont(IDWriteFont *iface) { return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont_iface); } static inline struct dwrite_fontfamily *impl_from_IDWriteFontFamily(IDWriteFontFamily *iface) { return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontFamily_iface); } static HRESULT WINAPI dwritefontface_QueryInterface(IDWriteFontFace *iface, REFIID riid, void **obj) { struct dwrite_fontface *This = impl_from_IDWriteFontFace(iface); TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFace)) { *obj = iface; IDWriteFontFace_AddRef(iface); return S_OK; } *obj = NULL; return E_NOINTERFACE; } static ULONG WINAPI dwritefontface_AddRef(IDWriteFontFace *iface) { struct dwrite_fontface *This = impl_from_IDWriteFontFace(iface); ULONG ref = InterlockedIncrement(&This->ref); TRACE("(%p)->(%d)\n", This, ref); return ref; } static ULONG WINAPI dwritefontface_Release(IDWriteFontFace *iface) { struct dwrite_fontface *This = impl_from_IDWriteFontFace(iface); ULONG ref = InterlockedDecrement(&This->ref); TRACE("(%p)->(%d)\n", This, ref); if (!ref) heap_free(This); return S_OK; } static DWRITE_FONT_FACE_TYPE WINAPI dwritefontface_GetType(IDWriteFontFace *iface) { struct dwrite_fontface *This = impl_from_IDWriteFontFace(iface); FIXME("(%p): stub\n", This); return DWRITE_FONT_FACE_TYPE_UNKNOWN; } static HRESULT WINAPI dwritefontface_GetFiles(IDWriteFontFace *iface, UINT32 *number_of_files, IDWriteFontFile **fontfiles) { struct dwrite_fontface *This = impl_from_IDWriteFontFace(iface); FIXME("(%p)->(%p %p): stub\n", This, number_of_files, fontfiles); return E_NOTIMPL; } static UINT32 WINAPI dwritefontface_GetIndex(IDWriteFontFace *iface) { struct dwrite_fontface *This = impl_from_IDWriteFontFace(iface); FIXME("(%p): stub\n", This); return 0; } static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_GetSimulations(IDWriteFontFace *iface) { struct dwrite_fontface *This = impl_from_IDWriteFontFace(iface); FIXME("(%p): stub\n", This); return DWRITE_FONT_SIMULATIONS_NONE; } static BOOL WINAPI dwritefontface_IsSymbolFont(IDWriteFontFace *iface) { struct dwrite_fontface *This = impl_from_IDWriteFontFace(iface); FIXME("(%p): stub\n", This); return FALSE; } static void WINAPI dwritefontface_GetMetrics(IDWriteFontFace *iface, DWRITE_FONT_METRICS *metrics) { struct dwrite_fontface *This = impl_from_IDWriteFontFace(iface); FIXME("(%p)->(%p): stub\n", This, metrics); } static UINT16 WINAPI dwritefontface_GetGlyphCount(IDWriteFontFace *iface) { struct dwrite_fontface *This = impl_from_IDWriteFontFace(iface); FIXME("(%p): stub\n", This); return 0; } static HRESULT WINAPI dwritefontface_GetDesignGlyphMetrics(IDWriteFontFace *iface, UINT16 const *glyph_indices, UINT32 glyph_count, DWRITE_GLYPH_METRICS *metrics, BOOL is_sideways) { struct dwrite_fontface *This = impl_from_IDWriteFontFace(iface); FIXME("(%p)->(%p %u %p %d): stub\n", This, glyph_indices, glyph_count, metrics, is_sideways); return E_NOTIMPL; } static HRESULT WINAPI dwritefontface_GetGlyphIndices(IDWriteFontFace *iface, UINT32 const *codepoints, UINT32 count, UINT16 *glyph_indices) { struct dwrite_fontface *This = impl_from_IDWriteFontFace(iface); FIXME("(%p)->(%p %u %p): stub\n", This, codepoints, count, glyph_indices); return E_NOTIMPL; } static HRESULT WINAPI dwritefontface_TryGetFontTable(IDWriteFontFace *iface, UINT32 table_tag, const void **table_data, UINT32 *table_size, void **context, BOOL *exists) { struct dwrite_fontface *This = impl_from_IDWriteFontFace(iface); FIXME("(%p)->(%u %p %p %p %p): stub\n", This, table_tag, table_data, table_size, context, exists); return E_NOTIMPL; } static void WINAPI dwritefontface_ReleaseFontTable(IDWriteFontFace *iface, void *table_context) { struct dwrite_fontface *This = impl_from_IDWriteFontFace(iface); FIXME("(%p)->(%p): stub\n", This, table_context); } static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace *iface, FLOAT emSize, UINT16 const *glyph_indices, FLOAT const* glyph_advances, DWRITE_GLYPH_OFFSET const *glyph_offsets, UINT32 glyph_count, BOOL is_sideways, BOOL is_rtl, IDWriteGeometrySink *geometrysink) { struct dwrite_fontface *This = impl_from_IDWriteFontFace(iface); FIXME("(%p)->(%f %p %p %p %u %d %d %p): stub\n", This, emSize, glyph_indices, glyph_advances, glyph_offsets, glyph_count, is_sideways, is_rtl, geometrysink); return E_NOTIMPL; } static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace *iface, FLOAT emSize, FLOAT pixels_per_dip, DWRITE_MEASURING_MODE mode, IDWriteRenderingParams* params, DWRITE_RENDERING_MODE* rendering_mode) { struct dwrite_fontface *This = impl_from_IDWriteFontFace(iface); FIXME("(%p)->(%f %f %d %p %p): stub\n", This, emSize, pixels_per_dip, mode, params, rendering_mode); return E_NOTIMPL; } static HRESULT WINAPI dwritefontface_GetGdiCompatibleMetrics(IDWriteFontFace *iface, FLOAT emSize, FLOAT pixels_per_dip, DWRITE_MATRIX const *transform, DWRITE_FONT_METRICS *metrics) { struct dwrite_fontface *This = impl_from_IDWriteFontFace(iface); FIXME("(%p)->(%f %f %p %p): stub\n", This, emSize, pixels_per_dip, transform, metrics); return E_NOTIMPL; } static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFace *iface, FLOAT emSize, FLOAT pixels_per_dip, DWRITE_MATRIX const *transform, BOOL use_gdi_natural, UINT16 const *glyph_indices, UINT32 glyph_count, DWRITE_GLYPH_METRICS *metrics, BOOL is_sideways) { struct dwrite_fontface *This = impl_from_IDWriteFontFace(iface); FIXME("(%p)->(%f %f %p %d %p %u %p %d): stub\n", This, emSize, pixels_per_dip, transform, use_gdi_natural, glyph_indices, glyph_count, metrics, is_sideways); return E_NOTIMPL; } static const IDWriteFontFaceVtbl dwritefontfacevtbl = { dwritefontface_QueryInterface, dwritefontface_AddRef, dwritefontface_Release, dwritefontface_GetType, dwritefontface_GetFiles, dwritefontface_GetIndex, dwritefontface_GetSimulations, dwritefontface_IsSymbolFont, dwritefontface_GetMetrics, dwritefontface_GetGlyphCount, dwritefontface_GetDesignGlyphMetrics, dwritefontface_GetGlyphIndices, dwritefontface_TryGetFontTable, dwritefontface_ReleaseFontTable, dwritefontface_GetGlyphRunOutline, dwritefontface_GetRecommendedRenderingMode, dwritefontface_GetGdiCompatibleMetrics, dwritefontface_GetGdiCompatibleGlyphMetrics }; static HRESULT create_fontface(IDWriteFontFace **face) { struct dwrite_fontface *This; *face = NULL; This = heap_alloc(sizeof(struct dwrite_fontface)); if (!This) return E_OUTOFMEMORY; This->IDWriteFontFace_iface.lpVtbl = &dwritefontfacevtbl; This->ref = 1; *face = &This->IDWriteFontFace_iface; return S_OK; } static HRESULT WINAPI dwritefont_QueryInterface(IDWriteFont *iface, REFIID riid, void **obj) { struct dwrite_font *This = impl_from_IDWriteFont(iface); TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFont)) { *obj = iface; IDWriteFont_AddRef(iface); return S_OK; } *obj = NULL; return E_NOINTERFACE; } static ULONG WINAPI dwritefont_AddRef(IDWriteFont *iface) { struct dwrite_font *This = impl_from_IDWriteFont(iface); ULONG ref = InterlockedIncrement(&This->ref); TRACE("(%p)->(%d)\n", This, ref); return ref; } static ULONG WINAPI dwritefont_Release(IDWriteFont *iface) { struct dwrite_font *This = impl_from_IDWriteFont(iface); ULONG ref = InterlockedDecrement(&This->ref); TRACE("(%p)->(%d)\n", This, ref); if (!ref) { IDWriteFontFamily_Release(This->family); heap_free(This); } return S_OK; } static HRESULT WINAPI dwritefont_GetFontFamily(IDWriteFont *iface, IDWriteFontFamily **family) { struct dwrite_font *This = impl_from_IDWriteFont(iface); TRACE("(%p)->(%p)\n", This, family); *family = This->family; IDWriteFontFamily_AddRef(*family); return S_OK; } static DWRITE_FONT_WEIGHT WINAPI dwritefont_GetWeight(IDWriteFont *iface) { struct dwrite_font *This = impl_from_IDWriteFont(iface); TRACE("(%p)\n", This); return This->weight; } static DWRITE_FONT_STRETCH WINAPI dwritefont_GetStretch(IDWriteFont *iface) { struct dwrite_font *This = impl_from_IDWriteFont(iface); TRACE("(%p)\n", This); return This->stretch; } static DWRITE_FONT_STYLE WINAPI dwritefont_GetStyle(IDWriteFont *iface) { struct dwrite_font *This = impl_from_IDWriteFont(iface); TRACE("(%p)\n", This); return This->style; } static BOOL WINAPI dwritefont_IsSymbolFont(IDWriteFont *iface) { struct dwrite_font *This = impl_from_IDWriteFont(iface); FIXME("(%p): stub\n", This); return FALSE; } static HRESULT WINAPI dwritefont_GetFaceNames(IDWriteFont *iface, IDWriteLocalizedStrings **names) { struct dwrite_font *This = impl_from_IDWriteFont(iface); FIXME("(%p)->(%p): stub\n", This, names); return E_NOTIMPL; } static HRESULT WINAPI dwritefont_GetInformationalStrings(IDWriteFont *iface, DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists) { struct dwrite_font *This = impl_from_IDWriteFont(iface); FIXME("(%p)->(%d %p %p): stub\n", This, stringid, strings, exists); return E_NOTIMPL; } static DWRITE_FONT_SIMULATIONS WINAPI dwritefont_GetSimulations(IDWriteFont *iface) { struct dwrite_font *This = impl_from_IDWriteFont(iface); FIXME("(%p): stub\n", This); return DWRITE_FONT_SIMULATIONS_NONE; } static void WINAPI dwritefont_GetMetrics(IDWriteFont *iface, DWRITE_FONT_METRICS *metrics) { struct dwrite_font *This = impl_from_IDWriteFont(iface); FIXME("(%p)->(%p): stub\n", This, metrics); } static HRESULT WINAPI dwritefont_HasCharacter(IDWriteFont *iface, UINT32 value, BOOL *exists) { struct dwrite_font *This = impl_from_IDWriteFont(iface); FIXME("(%p)->(0x%08x %p): stub\n", This, value, exists); return E_NOTIMPL; } static HRESULT WINAPI dwritefont_CreateFontFace(IDWriteFont *iface, IDWriteFontFace **face) { struct dwrite_font *This = impl_from_IDWriteFont(iface); TRACE("(%p)->(%p)\n", This, face); if (!This->face) { HRESULT hr = create_fontface(&This->face); if (FAILED(hr)) return hr; *face = This->face; return hr; } *face = This->face; IDWriteFontFace_AddRef(*face); return S_OK; } static const IDWriteFontVtbl dwritefontvtbl = { dwritefont_QueryInterface, dwritefont_AddRef, dwritefont_Release, dwritefont_GetFontFamily, dwritefont_GetWeight, dwritefont_GetStretch, dwritefont_GetStyle, dwritefont_IsSymbolFont, dwritefont_GetFaceNames, dwritefont_GetInformationalStrings, dwritefont_GetSimulations, dwritefont_GetMetrics, dwritefont_HasCharacter, dwritefont_CreateFontFace }; static HRESULT WINAPI dwritefontfamily_QueryInterface(IDWriteFontFamily *iface, REFIID riid, void **obj) { struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface); TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontList) || IsEqualIID(riid, &IID_IDWriteFontFamily)) { *obj = iface; IDWriteFontFamily_AddRef(iface); return S_OK; } *obj = NULL; return E_NOINTERFACE; } static ULONG WINAPI dwritefontfamily_AddRef(IDWriteFontFamily *iface) { struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface); ULONG ref = InterlockedIncrement(&This->ref); TRACE("(%p)->(%d)\n", This, ref); return ref; } static ULONG WINAPI dwritefontfamily_Release(IDWriteFontFamily *iface) { struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface); ULONG ref = InterlockedDecrement(&This->ref); TRACE("(%p)->(%d)\n", This, ref); if (!ref) { heap_free(This->familyname); heap_free(This); } return S_OK; } static HRESULT WINAPI dwritefontfamily_GetFontCollection(IDWriteFontFamily *iface, IDWriteFontCollection **collection) { struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface); FIXME("(%p)->(%p): stub\n", This, collection); return E_NOTIMPL; } static UINT32 WINAPI dwritefontfamily_GetFontCount(IDWriteFontFamily *iface) { struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface); FIXME("(%p): stub\n", This); return 0; } static HRESULT WINAPI dwritefontfamily_GetFont(IDWriteFontFamily *iface, UINT32 index, IDWriteFont **font) { struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface); FIXME("(%p)->(%u %p): stub\n", This, index, font); return E_NOTIMPL; } static HRESULT WINAPI dwritefontfamily_GetFamilyNames(IDWriteFontFamily *iface, IDWriteLocalizedStrings **names) { struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface); static const WCHAR enusW[] = {'e','n','-','u','s',0}; HRESULT hr; TRACE("(%p)->(%p)\n", This, names); hr = create_localizedstrings(names); if (FAILED(hr)) return hr; return add_localizedstring(*names, enusW, This->familyname); } static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily *iface, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont **font) { struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface); FIXME("(%p)->(%d %d %d %p): stub\n", This, weight, stretch, style, font); return E_NOTIMPL; } static HRESULT WINAPI dwritefontfamily_GetMatchingFonts(IDWriteFontFamily *iface, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontList **fonts) { struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface); FIXME("(%p)->(%d %d %d %p): stub\n", This, weight, stretch, style, fonts); return E_NOTIMPL; } static const IDWriteFontFamilyVtbl fontfamilyvtbl = { dwritefontfamily_QueryInterface, dwritefontfamily_AddRef, dwritefontfamily_Release, dwritefontfamily_GetFontCollection, dwritefontfamily_GetFontCount, dwritefontfamily_GetFont, dwritefontfamily_GetFamilyNames, dwritefontfamily_GetFirstMatchingFont, dwritefontfamily_GetMatchingFonts }; static HRESULT create_fontfamily(const WCHAR *familyname, IDWriteFontFamily **family) { struct dwrite_fontfamily *This; *family = NULL; This = heap_alloc(sizeof(struct dwrite_fontfamily)); if (!This) return E_OUTOFMEMORY; This->IDWriteFontFamily_iface.lpVtbl = &fontfamilyvtbl; This->ref = 1; This->familyname = heap_strdupW(familyname); *family = &This->IDWriteFontFamily_iface; return S_OK; } static void get_font_properties(struct dwrite_font *font, HDC hdc) { TT_OS2_V2 tt_os2; LONG size; /* default stretch and weight to normal */ font->stretch = DWRITE_FONT_STRETCH_NORMAL; font->weight = DWRITE_FONT_WEIGHT_NORMAL; size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0); if (size != GDI_ERROR) { 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; /* DWRITE_FONT_STRETCH enumeration values directly match font data values */ if (GET_BE_WORD(tt_os2.usWidthClass) <= DWRITE_FONT_STRETCH_ULTRA_EXPANDED) font->stretch = GET_BE_WORD(tt_os2.usWidthClass); font->weight = GET_BE_WORD(tt_os2.usWeightClass); TRACE("stretch=%d, weight=%d\n", font->stretch, font->weight); } } HRESULT create_font_from_logfont(const LOGFONTW *logfont, IDWriteFont **font) { const WCHAR* facename, *familyname; struct dwrite_font *This; IDWriteFontFamily *family; OUTLINETEXTMETRICW *otm; HRESULT hr; HFONT hfont; HDC hdc; int ret; *font = NULL; This = heap_alloc(sizeof(struct dwrite_font)); if (!This) return E_OUTOFMEMORY; hfont = CreateFontIndirectW(logfont); if (!hfont) { heap_free(This); return DWRITE_E_NOFONT; } hdc = CreateCompatibleDC(0); SelectObject(hdc, hfont); ret = GetOutlineTextMetricsW(hdc, 0, NULL); otm = heap_alloc(ret); otm->otmSize = ret; ret = GetOutlineTextMetricsW(hdc, otm->otmSize, otm); get_font_properties(This, hdc); DeleteDC(hdc); DeleteObject(hfont); facename = (WCHAR*)((char*)otm + (ptrdiff_t)otm->otmpFaceName); familyname = (WCHAR*)((char*)otm + (ptrdiff_t)otm->otmpFamilyName); TRACE("facename=%s, familyname=%s\n", debugstr_w(facename), debugstr_w(familyname)); hr = create_fontfamily(familyname, &family); heap_free(otm); if (hr != S_OK) { heap_free(This); return hr; } This->IDWriteFont_iface.lpVtbl = &dwritefontvtbl; This->ref = 1; This->face = NULL; This->family = family; This->style = logfont->lfItalic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL; *font = &This->IDWriteFont_iface; return S_OK; }