oleaut32: Fix IFont::AddRefHFont and IFont::ReleaseRefHFont.
The tests show that there is a global cache that keeps references to HFONTs that is released when all IFont objects are released. (Based on a patch by Benjamin Arai.)
This commit is contained in:
parent
0b43e9b552
commit
4c40b3974c
|
@ -34,6 +34,7 @@
|
|||
#include "winbase.h"
|
||||
#include "wingdi.h"
|
||||
#include "winuser.h"
|
||||
#include "wine/list.h"
|
||||
#include "wine/unicode.h"
|
||||
#include "objbase.h"
|
||||
#include "oleauto.h" /* for SysAllocString(....) */
|
||||
|
@ -52,6 +53,48 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole);
|
|||
#define FONTPERSIST_UNDERLINE 0x04
|
||||
#define FONTPERSIST_STRIKETHROUGH 0x08
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* List of the HFONTs it has given out, with each one having a separate
|
||||
* ref count.
|
||||
*/
|
||||
typedef struct _HFONTItem
|
||||
{
|
||||
struct list entry;
|
||||
|
||||
/* Reference count for that instance of the class. */
|
||||
LONG ref;
|
||||
|
||||
/* Contain the font associated with this object. */
|
||||
HFONT gdiFont;
|
||||
|
||||
} HFONTItem, *PHFONTItem;
|
||||
|
||||
static struct list OLEFontImpl_hFontList = LIST_INIT(OLEFontImpl_hFontList);
|
||||
|
||||
/* Counts how many fonts contain at least one lock */
|
||||
static LONG ifont_cnt = 0;
|
||||
|
||||
/***********************************************************************
|
||||
* Critical section for OLEFontImpl_hFontList
|
||||
*/
|
||||
static CRITICAL_SECTION OLEFontImpl_csHFONTLIST;
|
||||
static CRITICAL_SECTION_DEBUG OLEFontImpl_csHFONTLIST_debug =
|
||||
{
|
||||
0, 0, &OLEFontImpl_csHFONTLIST,
|
||||
{ &OLEFontImpl_csHFONTLIST_debug.ProcessLocksList,
|
||||
&OLEFontImpl_csHFONTLIST_debug.ProcessLocksList },
|
||||
0, 0, { (DWORD_PTR)(__FILE__ ": OLEFontImpl_csHFONTLIST") }
|
||||
};
|
||||
static CRITICAL_SECTION OLEFontImpl_csHFONTLIST = { &OLEFontImpl_csHFONTLIST_debug, -1, 0, 0, 0, 0 };
|
||||
|
||||
static void HFONTItem_Delete(PHFONTItem item)
|
||||
{
|
||||
DeleteObject(item->gdiFont);
|
||||
list_remove(&item->entry);
|
||||
HeapFree(GetProcessHeap(), 0, item);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Declaration of the implementation class for the IFont interface
|
||||
*/
|
||||
|
@ -86,11 +129,6 @@ struct OLEFontImpl
|
|||
*/
|
||||
HFONT gdiFont;
|
||||
|
||||
/*
|
||||
* Font lock count.
|
||||
*/
|
||||
DWORD fontLock;
|
||||
|
||||
/*
|
||||
* Size ratio
|
||||
*/
|
||||
|
@ -406,6 +444,7 @@ static void OLEFont_SendNotify(OLEFontImpl* this, DISPID dispID)
|
|||
CONNECTDATA CD;
|
||||
HRESULT hres;
|
||||
|
||||
this->gdiFont = 0;
|
||||
hres = IConnectionPoint_EnumConnections(this->pPropertyNotifyCP, &pEnum);
|
||||
if (SUCCEEDED(hres))
|
||||
{
|
||||
|
@ -509,7 +548,6 @@ static OLEFontImpl* OLEFontImpl_Construct(LPFONTDESC fontDesc)
|
|||
* Initializing all the other members.
|
||||
*/
|
||||
newObject->gdiFont = 0;
|
||||
newObject->fontLock = 0;
|
||||
newObject->cyLogical = 72L;
|
||||
newObject->cyHimetric = 2540L;
|
||||
newObject->pPropertyNotifyCP = NULL;
|
||||
|
@ -524,6 +562,8 @@ static OLEFontImpl* OLEFontImpl_Construct(LPFONTDESC fontDesc)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
InterlockedIncrement(&ifont_cnt);
|
||||
|
||||
TRACE("returning %p\n", newObject);
|
||||
return newObject;
|
||||
}
|
||||
|
@ -631,17 +671,26 @@ ULONG WINAPI OLEFontImpl_Release(
|
|||
{
|
||||
OLEFontImpl *this = (OLEFontImpl *)iface;
|
||||
ULONG ret;
|
||||
PHFONTItem ptr, next;
|
||||
TRACE("(%p)->(ref=%d)\n", this, this->ref);
|
||||
|
||||
/*
|
||||
* Decrease the reference count on this object.
|
||||
*/
|
||||
/* Decrease the reference count for current interface */
|
||||
ret = InterlockedDecrement(&this->ref);
|
||||
|
||||
/*
|
||||
* If the reference count goes down to 0, perform suicide.
|
||||
*/
|
||||
if (ret==0) OLEFontImpl_Destroy(this);
|
||||
/* If the reference count goes down to 0, destroy. */
|
||||
if (ret == 0)
|
||||
{
|
||||
ULONG fontlist_refs = InterlockedDecrement(&ifont_cnt);
|
||||
/* Check if all HFONT list refs are zero */
|
||||
if (fontlist_refs == 0)
|
||||
{
|
||||
EnterCriticalSection(&OLEFontImpl_csHFONTLIST);
|
||||
LIST_FOR_EACH_ENTRY_SAFE(ptr, next, &OLEFontImpl_hFontList, HFONTItem, entry)
|
||||
HFONTItem_Delete(ptr);
|
||||
LeaveCriticalSection(&OLEFontImpl_csHFONTLIST);
|
||||
}
|
||||
OLEFontImpl_Destroy(this);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1013,6 +1062,7 @@ static HRESULT WINAPI OLEFontImpl_get_hFont(
|
|||
LOGFONTW logFont;
|
||||
INT fontHeight;
|
||||
CY cySize;
|
||||
PHFONTItem newEntry;
|
||||
|
||||
/*
|
||||
* The height of the font returned by the get_Size property is the
|
||||
|
@ -1042,6 +1092,14 @@ static HRESULT WINAPI OLEFontImpl_get_hFont(
|
|||
strcpyW(logFont.lfFaceName,this->description.lpstrName);
|
||||
|
||||
this->gdiFont = CreateFontIndirectW(&logFont);
|
||||
|
||||
/* Add font to the cache */
|
||||
newEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(HFONTItem));
|
||||
newEntry->ref = 1;
|
||||
newEntry->gdiFont = this->gdiFont;
|
||||
EnterCriticalSection(&OLEFontImpl_csHFONTLIST);
|
||||
list_add_tail(&OLEFontImpl_hFontList,&newEntry->entry);
|
||||
LeaveCriticalSection(&OLEFontImpl_csHFONTLIST);
|
||||
}
|
||||
|
||||
*phfont = this->gdiFont;
|
||||
|
@ -1062,6 +1120,8 @@ static HRESULT WINAPI OLEFontImpl_Clone(
|
|||
LOGFONTW logFont;
|
||||
INT fontHeight;
|
||||
CY cySize;
|
||||
PHFONTItem newEntry;
|
||||
|
||||
OLEFontImpl *this = (OLEFontImpl *)iface;
|
||||
TRACE("(%p)->(%p)\n", this, ppfont);
|
||||
|
||||
|
@ -1110,6 +1170,15 @@ static HRESULT WINAPI OLEFontImpl_Clone(
|
|||
|
||||
newObject->gdiFont = CreateFontIndirectW(&logFont);
|
||||
|
||||
/* Add font to the cache */
|
||||
InterlockedIncrement(&ifont_cnt);
|
||||
newEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(HFONTItem));
|
||||
newEntry->ref = 1;
|
||||
newEntry->gdiFont = newObject->gdiFont;
|
||||
EnterCriticalSection(&OLEFontImpl_csHFONTLIST);
|
||||
list_add_tail(&OLEFontImpl_hFontList,&newEntry->entry);
|
||||
LeaveCriticalSection(&OLEFontImpl_csHFONTLIST);
|
||||
|
||||
/* create new connection points */
|
||||
newObject->pPropertyNotifyCP = NULL;
|
||||
newObject->pFontEventsCP = NULL;
|
||||
|
@ -1222,15 +1291,28 @@ static HRESULT WINAPI OLEFontImpl_AddRefHfont(
|
|||
HFONT hfont)
|
||||
{
|
||||
OLEFontImpl *this = (OLEFontImpl *)iface;
|
||||
TRACE("(%p)->(%p) (lock=%d)\n", this, hfont, this->fontLock);
|
||||
PHFONTItem ptr, next;
|
||||
HRESULT hres = S_FALSE; /* assume not present */
|
||||
|
||||
if ( (hfont == 0) ||
|
||||
(hfont != this->gdiFont) )
|
||||
TRACE("(%p)->(%p)\n", this, hfont);
|
||||
|
||||
if (!hfont)
|
||||
return E_INVALIDARG;
|
||||
|
||||
this->fontLock++;
|
||||
/* Check of the hFont is already in the list */
|
||||
EnterCriticalSection(&OLEFontImpl_csHFONTLIST);
|
||||
LIST_FOR_EACH_ENTRY_SAFE(ptr, next, &OLEFontImpl_hFontList, HFONTItem, entry)
|
||||
{
|
||||
if (ptr->gdiFont == hfont)
|
||||
{
|
||||
ptr->ref++;
|
||||
hres = S_OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&OLEFontImpl_csHFONTLIST);
|
||||
|
||||
return S_OK;
|
||||
return hres;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
|
@ -1243,24 +1325,33 @@ static HRESULT WINAPI OLEFontImpl_ReleaseHfont(
|
|||
HFONT hfont)
|
||||
{
|
||||
OLEFontImpl *this = (OLEFontImpl *)iface;
|
||||
TRACE("(%p)->(%p) (lock=%d)\n", this, hfont, this->fontLock);
|
||||
PHFONTItem ptr, next;
|
||||
HRESULT hres = S_FALSE; /* assume not present */
|
||||
|
||||
if ( (hfont == 0) ||
|
||||
(hfont != this->gdiFont) )
|
||||
TRACE("(%p)->(%p)\n", this, hfont);
|
||||
|
||||
if (!hfont)
|
||||
return E_INVALIDARG;
|
||||
|
||||
this->fontLock--;
|
||||
|
||||
/*
|
||||
* If we just released our last font reference, destroy it.
|
||||
*/
|
||||
if (this->fontLock==0)
|
||||
/* Check of the hFont is already in the list */
|
||||
EnterCriticalSection(&OLEFontImpl_csHFONTLIST);
|
||||
LIST_FOR_EACH_ENTRY_SAFE(ptr, next, &OLEFontImpl_hFontList, HFONTItem, entry)
|
||||
{
|
||||
DeleteObject(this->gdiFont);
|
||||
this->gdiFont = 0;
|
||||
if ((ptr->gdiFont == hfont) && ptr->ref)
|
||||
{
|
||||
/* Remove from cache and delete object if not referenced */
|
||||
if (!--ptr->ref)
|
||||
{
|
||||
if (ptr->gdiFont == this->gdiFont)
|
||||
this->gdiFont = NULL;
|
||||
}
|
||||
hres = S_OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&OLEFontImpl_csHFONTLIST);
|
||||
|
||||
return S_OK;
|
||||
return hres;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
|
|
|
@ -638,9 +638,9 @@ static void test_ReleaseHfont(void)
|
|||
|
||||
/* Try to add a bad HFONT */
|
||||
hres = IFont_ReleaseHfont(ifnt1,(HFONT)32);
|
||||
todo_wine {ok(hres == S_FALSE,
|
||||
ok(hres == S_FALSE,
|
||||
"IFont_ReleaseHfont: (Bad HFONT) Expected S_FALSE but got 0x%08x\n",
|
||||
hres);}
|
||||
hres);
|
||||
|
||||
/* Release all refs */
|
||||
hres = IFont_ReleaseHfont(ifnt1,hfnt1);
|
||||
|
@ -655,15 +655,15 @@ static void test_ReleaseHfont(void)
|
|||
|
||||
/* Check that both lists are empty */
|
||||
hres = IFont_ReleaseHfont(ifnt1,hfnt1);
|
||||
todo_wine {ok(hres == S_FALSE,
|
||||
ok(hres == S_FALSE,
|
||||
"IFont_AddRefHfont: (Release ref) Expected S_FALSE but got 0x%08x\n",
|
||||
hres);}
|
||||
hres);
|
||||
|
||||
/* The list should be empty */
|
||||
hres = IFont_ReleaseHfont(ifnt2,hfnt2);
|
||||
todo_wine {ok(hres == S_FALSE,
|
||||
ok(hres == S_FALSE,
|
||||
"IFont_AddRefHfont: (Release ref) Expected S_FALSE but got 0x%08x\n",
|
||||
hres);}
|
||||
hres);
|
||||
|
||||
IFont_Release(ifnt1);
|
||||
IFont_Release(ifnt2);
|
||||
|
@ -672,9 +672,6 @@ static void test_ReleaseHfont(void)
|
|||
static void test_AddRefHfont(void)
|
||||
{
|
||||
FONTDESC fd;
|
||||
LPVOID pvObj1 = NULL;
|
||||
LPVOID pvObj2 = NULL;
|
||||
LPVOID pvObj3 = NULL;
|
||||
IFont* ifnt1 = NULL;
|
||||
IFont* ifnt2 = NULL;
|
||||
IFont* ifnt3 = NULL;
|
||||
|
@ -695,12 +692,10 @@ static void test_AddRefHfont(void)
|
|||
fd.fStrikethrough = 0;
|
||||
|
||||
/* Create HFONTs and IFONTs */
|
||||
pOleCreateFontIndirect(&fd, &IID_IFont, &pvObj1);
|
||||
ifnt1 = pvObj1;
|
||||
pOleCreateFontIndirect(&fd, &IID_IFont, (void **)&ifnt1);
|
||||
IFont_get_hFont(ifnt1,&hfnt1);
|
||||
fd.lpstrName = arial_font;
|
||||
pOleCreateFontIndirect(&fd, &IID_IFont, &pvObj2);
|
||||
ifnt2 = pvObj2;
|
||||
pOleCreateFontIndirect(&fd, &IID_IFont, (void **)&ifnt2);
|
||||
IFont_get_hFont(ifnt2,&hfnt2);
|
||||
|
||||
/* Try invalid HFONT */
|
||||
|
@ -711,9 +706,9 @@ static void test_AddRefHfont(void)
|
|||
|
||||
/* Try to add a bad HFONT */
|
||||
hres = IFont_AddRefHfont(ifnt1,(HFONT)32);
|
||||
todo_wine{ ok(hres == S_FALSE,
|
||||
ok(hres == S_FALSE,
|
||||
"IFont_AddRefHfont: (Bad HFONT) Expected S_FALSE but got 0x%08x\n",
|
||||
hres);}
|
||||
hres);
|
||||
|
||||
/* Add simple IFONT HFONT pair */
|
||||
hres = IFont_AddRefHfont(ifnt1,hfnt1);
|
||||
|
@ -723,9 +718,9 @@ static void test_AddRefHfont(void)
|
|||
|
||||
/* IFONT and HFONT do not have to be the same (always looks at HFONT) */
|
||||
hres = IFont_AddRefHfont(ifnt2,hfnt1);
|
||||
todo_wine {ok(hres == S_OK,
|
||||
ok(hres == S_OK,
|
||||
"IFont_AddRefHfont: (Add ref) Expected S_OK but got 0x%08x\n",
|
||||
hres);}
|
||||
hres);
|
||||
|
||||
/* Release all hfnt1 refs */
|
||||
hres = IFont_ReleaseHfont(ifnt1,hfnt1);
|
||||
|
@ -734,20 +729,20 @@ static void test_AddRefHfont(void)
|
|||
hres);
|
||||
|
||||
hres = IFont_ReleaseHfont(ifnt1,hfnt1);
|
||||
todo_wine {ok(hres == S_OK,
|
||||
ok(hres == S_OK,
|
||||
"IFont_AddRefHfont: (Release ref) Expected S_OK but got 0x%08x\n",
|
||||
hres);}
|
||||
hres);
|
||||
|
||||
hres = IFont_ReleaseHfont(ifnt1,hfnt1);
|
||||
todo_wine {ok(hres == S_OK,
|
||||
ok(hres == S_OK,
|
||||
"IFont_AddRefHfont: (Release ref) Expected S_OK but got 0x%08x\n",
|
||||
hres);}
|
||||
hres);
|
||||
|
||||
/* Check if hfnt1 is empty */
|
||||
hres = IFont_ReleaseHfont(ifnt1,hfnt1);
|
||||
todo_wine {ok(hres == S_FALSE,
|
||||
ok(hres == S_FALSE,
|
||||
"IFont_AddRefHfont: (Release ref) Expected S_FALSE but got 0x%08x\n",
|
||||
hres);}
|
||||
hres);
|
||||
|
||||
/* Release all hfnt2 refs */
|
||||
hres = IFont_ReleaseHfont(ifnt2,hfnt2);
|
||||
|
@ -757,9 +752,9 @@ static void test_AddRefHfont(void)
|
|||
|
||||
/* Check if hfnt2 is empty */
|
||||
hres = IFont_ReleaseHfont(ifnt2,hfnt2);
|
||||
todo_wine {ok(hres == S_FALSE,
|
||||
ok(hres == S_FALSE,
|
||||
"IFont_AddRefHfont: (Release ref) Expected S_FALSE but got 0x%08x\n",
|
||||
hres);}
|
||||
hres);
|
||||
|
||||
/* Show that releasing an IFONT does not always release it from the HFONT cache. */
|
||||
|
||||
|
@ -767,15 +762,15 @@ static void test_AddRefHfont(void)
|
|||
|
||||
/* Add a reference for destroyed hfnt1 */
|
||||
hres = IFont_AddRefHfont(ifnt2,hfnt1);
|
||||
todo_wine {ok(hres == S_OK,
|
||||
ok(hres == S_OK,
|
||||
"IFont_AddRefHfont: (Add ref) Expected S_OK but got 0x%08x\n",
|
||||
hres);}
|
||||
hres);
|
||||
|
||||
/* Decrement reference for destroyed hfnt1 */
|
||||
hres = IFont_ReleaseHfont(ifnt2,hfnt1);
|
||||
todo_wine {ok(hres == S_OK,
|
||||
ok(hres == S_OK,
|
||||
"IFont_AddRefHfont: (Release ref) Expected S_OK but got 0x%08x\n",
|
||||
hres);}
|
||||
hres);
|
||||
|
||||
/* Shows that releasing all IFONT's does clear the HFONT cache. */
|
||||
|
||||
|
@ -783,23 +778,22 @@ static void test_AddRefHfont(void)
|
|||
|
||||
/* Need to make a new IFONT for testing */
|
||||
fd.fUnderline = 1;
|
||||
pOleCreateFontIndirect(&fd, &IID_IFont, &pvObj3);
|
||||
ifnt3 = pvObj3;
|
||||
pOleCreateFontIndirect(&fd, &IID_IFont, (void **)&ifnt3);
|
||||
IFont_get_hFont(ifnt3,&hfnt3);
|
||||
|
||||
/* Add a reference for destroyed hfnt1 */
|
||||
hres = IFont_AddRefHfont(ifnt3,hfnt1);
|
||||
todo_wine {ok(hres == S_FALSE,
|
||||
ok(hres == S_FALSE,
|
||||
"IFont_AddRefHfont: (Add ref) Expected S_OK but got 0x%08x\n",
|
||||
hres);}
|
||||
hres);
|
||||
|
||||
/* Decrement reference for destroyed hfnt1 */
|
||||
hres = IFont_ReleaseHfont(ifnt3,hfnt1);
|
||||
todo_wine {ok(hres == S_FALSE,
|
||||
ok(hres == S_FALSE,
|
||||
"IFont_AddRefHfont: (Release ref) Expected S_OK but got 0x%08x\n",
|
||||
hres);}
|
||||
hres);
|
||||
|
||||
hres = IFont_Release(ifnt3);
|
||||
IFont_Release(ifnt3);
|
||||
}
|
||||
|
||||
START_TEST(olefont)
|
||||
|
|
Loading…
Reference in New Issue