From 7e42fd8b4e1acc5c7df9e6a03af07f1a00ec37cb Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Tue, 2 Feb 2010 10:20:50 +0000 Subject: [PATCH] oleaut32: If the font name property is changed, don't insist on the current charset when selecting a new font. --- dlls/oleaut32/olefont.c | 102 ++++++++++++++++++++++++++++++++-- dlls/oleaut32/tests/olefont.c | 58 +++++++++++++++++++ 2 files changed, 155 insertions(+), 5 deletions(-) diff --git a/dlls/oleaut32/olefont.c b/dlls/oleaut32/olefont.c index c0d9b66a7f6..df7de87bfc2 100644 --- a/dlls/oleaut32/olefont.c +++ b/dlls/oleaut32/olefont.c @@ -53,6 +53,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); #define FONTPERSIST_UNDERLINE 0x04 #define FONTPERSIST_STRIKETHROUGH 0x08 +static HDC olefont_hdc; /*********************************************************************** * List of the HFONTs it has given out, with each one having a separate @@ -91,6 +92,28 @@ static CRITICAL_SECTION_DEBUG OLEFontImpl_csHFONTLIST_debug = }; static CRITICAL_SECTION OLEFontImpl_csHFONTLIST = { &OLEFontImpl_csHFONTLIST_debug, -1, 0, 0, 0, 0 }; +static HDC get_dc(void) +{ + HDC hdc; + EnterCriticalSection(&OLEFontImpl_csHFONTLIST); + if(!olefont_hdc) + olefont_hdc = CreateCompatibleDC(NULL); + hdc = olefont_hdc; + LeaveCriticalSection(&OLEFontImpl_csHFONTLIST); + return hdc; +} + +static void delete_dc(void) +{ + EnterCriticalSection(&OLEFontImpl_csHFONTLIST); + if(olefont_hdc) + { + DeleteDC(olefont_hdc); + olefont_hdc = NULL; + } + LeaveCriticalSection(&OLEFontImpl_csHFONTLIST); +} + static void HFONTItem_Delete(PHFONTItem item) { DeleteObject(item->gdiFont); @@ -204,6 +227,17 @@ static HRESULT dec_ext_ref(HFONT hfont) return hr; } +static WCHAR *strdupW(const WCHAR* str) +{ + WCHAR *ret; + DWORD size = (strlenW(str) + 1) * sizeof(WCHAR); + + ret = HeapAlloc(GetProcessHeap(), 0, size); + if(ret) + memcpy(ret, str, size); + return ret; +} + /*********************************************************************** * Declaration of the implementation class for the IFont interface */ @@ -531,6 +565,7 @@ static ULONG WINAPI OLEFontImpl_Release( LIST_FOR_EACH_ENTRY_SAFE(item, cursor2, &OLEFontImpl_hFontList, HFONTItem, entry) HFONTItem_Delete(item); LeaveCriticalSection(&OLEFontImpl_csHFONTLIST); + delete_dc(); } else { @@ -542,31 +577,77 @@ static ULONG WINAPI OLEFontImpl_Release( return ret; } +typedef struct +{ + short orig_cs; + short avail_cs; +} enum_data; + +static int CALLBACK font_enum_proc(const LOGFONTW *elf, const TEXTMETRICW *ntm, DWORD type, LPARAM lp) +{ + enum_data *data = (enum_data*)lp; + + if(elf->lfCharSet == data->orig_cs) + { + data->avail_cs = data->orig_cs; + return 0; + } + if(data->avail_cs == -1) data->avail_cs = elf->lfCharSet; + return 1; +} + static void realize_font(OLEFontImpl *This) { if (This->dirty) { LOGFONTW logFont; INT fontHeight; + WCHAR text_face[LF_FACESIZE]; + HDC hdc = get_dc(); + HFONT old_font; + TEXTMETRICW tm; + + text_face[0] = 0; if(This->gdiFont) { + old_font = SelectObject(hdc, This->gdiFont); + GetTextFaceW(hdc, sizeof(text_face) / sizeof(text_face[0]), text_face); + SelectObject(hdc, old_font); dec_int_ref(This->gdiFont); This->gdiFont = 0; } + memset(&logFont, 0, sizeof(LOGFONTW)); + + lstrcpynW(logFont.lfFaceName, This->description.lpstrName, LF_FACESIZE); + logFont.lfCharSet = This->description.sCharset; + + /* If the font name has been changed then enumerate all charsets + and pick one that'll result in the font specified being selected */ + if(text_face[0] && lstrcmpiW(text_face, This->description.lpstrName)) + { + enum_data data; + data.orig_cs = This->description.sCharset; + data.avail_cs = -1; + logFont.lfCharSet = DEFAULT_CHARSET; + EnumFontFamiliesExW(get_dc(), &logFont, font_enum_proc, (LPARAM)&data, 0); + if(data.avail_cs != -1) logFont.lfCharSet = data.avail_cs; + } + + /* * The height of the font returned by the get_Size property is the * height of the font in points multiplied by 10000... Using some * simple conversions and the ratio given by the application, it can * be converted to a height in pixels. + * + * Standard ratio is 72 / 2540, or 18 / 635 in lowest terms. + * Ratio is applied here relative to the standard. */ - /* Standard ratio is 72 / 2540, or 18 / 635 in lowest terms. */ - /* Ratio is applied here relative to the standard. */ fontHeight = MulDiv( This->description.cySize.s.Lo, This->cyLogical*635, This->cyHimetric*18 ); - memset(&logFont, 0, sizeof(LOGFONTW)); logFont.lfHeight = ((fontHeight%10000L)>5000L) ? (-fontHeight/10000L) - 1 : (-fontHeight/10000L); @@ -574,17 +655,28 @@ static void realize_font(OLEFontImpl *This) logFont.lfUnderline = This->description.fUnderline; logFont.lfStrikeOut = This->description.fStrikethrough; logFont.lfWeight = This->description.sWeight; - logFont.lfCharSet = This->description.sCharset; logFont.lfOutPrecision = OUT_CHARACTER_PRECIS; logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS; logFont.lfQuality = DEFAULT_QUALITY; logFont.lfPitchAndFamily = DEFAULT_PITCH; - lstrcpynW(logFont.lfFaceName, This->description.lpstrName, LF_FACESIZE); This->gdiFont = CreateFontIndirectW(&logFont); This->dirty = FALSE; add_hfontitem(This->gdiFont); + + /* Fixup the name and charset properties so that they match the + selected font */ + old_font = SelectObject(get_dc(), This->gdiFont); + GetTextFaceW(hdc, sizeof(text_face) / sizeof(text_face[0]), text_face); + if(lstrcmpiW(text_face, This->description.lpstrName)) + { + HeapFree(GetProcessHeap(), 0, This->description.lpstrName); + This->description.lpstrName = strdupW(text_face); + } + GetTextMetricsW(hdc, &tm); + This->description.sCharset = tm.tmCharSet; + SelectObject(hdc, old_font); } } diff --git a/dlls/oleaut32/tests/olefont.c b/dlls/oleaut32/tests/olefont.c index 79dbade5be7..2f3eff8fcad 100644 --- a/dlls/oleaut32/tests/olefont.c +++ b/dlls/oleaut32/tests/olefont.c @@ -45,6 +45,7 @@ DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); static WCHAR MSSansSerif_font[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f',0}; static WCHAR system_font[] = { 'S','y','s','t','e','m',0 }; static WCHAR arial_font[] = { 'A','r','i','a','l',0 }; +static WCHAR marlett_font[] = { 'M','a','r','l','e','t','t',0 }; static HMODULE hOleaut32; @@ -1018,6 +1019,62 @@ todo_wine ok(obj_type == 0, "got obj type %d\n", obj_type); } +static void test_realization(void) +{ + IFont *font; + FONTDESC fontdesc; + HRESULT hr; + BSTR name; + SHORT cs; + + /* Try to create a symbol only font (marlett) with charset + set to ANSI. This will result in another, ANSI, font + being selected */ + fontdesc.cbSizeofstruct = sizeof(fontdesc); + fontdesc.lpstrName = marlett_font; + fontdesc.cySize.int64 = 12 * 10000; /* 12 pt */ + fontdesc.sWeight = FW_NORMAL; + fontdesc.sCharset = ANSI_CHARSET; + fontdesc.fItalic = FALSE; + fontdesc.fUnderline = FALSE; + fontdesc.fStrikethrough = FALSE; + + hr = pOleCreateFontIndirect(&fontdesc, &IID_IFont, (void **)&font); + ok_ole_success(hr, "OleCreateFontIndirect"); + + hr = IFont_get_Charset(font, &cs); + ok_ole_success(hr, "get_Charset"); + ok(cs == ANSI_CHARSET, "got charset %d\n", cs); + + IFont_Release(font); + + /* Now create an ANSI font and change the name to marlett */ + + fontdesc.lpstrName = arial_font; + + hr = pOleCreateFontIndirect(&fontdesc, &IID_IFont, (void **)&font); + ok_ole_success(hr, "OleCreateFontIndirect"); + + hr = IFont_get_Charset(font, &cs); + ok_ole_success(hr, "get_Charset"); + ok(cs == ANSI_CHARSET, "got charset %d\n", cs); + + name = SysAllocString(marlett_font); + hr = IFont_put_Name(font, name); + ok_ole_success(hr, "put_Name"); + SysFreeString(name); + + hr = IFont_get_Name(font, &name); + ok_ole_success(hr, "get_Name"); + ok(!lstrcmpiW(name, marlett_font), "got name %s\n", wine_dbgstr_w(name)); + SysFreeString(name); + + hr = IFont_get_Charset(font, &cs); + ok_ole_success(hr, "get_Charset"); + ok(cs == SYMBOL_CHARSET, "got charset %d\n", cs); + + IFont_Release(font); +} START_TEST(olefont) { @@ -1053,4 +1110,5 @@ START_TEST(olefont) test_AddRefHfont(); test_returns(); test_hfont_lifetime(); + test_realization(); }