Commit 7aaaf738 authored by Huw Davies's avatar Huw Davies Committed by Alexandre Julliard

oleaut32: Fix font handle lifetimes.

parent 439d5852
...@@ -62,10 +62,13 @@ typedef struct _HFONTItem ...@@ -62,10 +62,13 @@ typedef struct _HFONTItem
{ {
struct list entry; struct list entry;
/* Reference count for that instance of the class. */ /* Reference count of any IFont objects that own this hfont */
LONG ref; LONG int_refs;
/* Total reference count of any refs held by the application obtained by AddRefHfont plus any internal refs */
LONG total_refs;
/* Contain the font associated with this object. */ /* The font associated with this object. */
HFONT gdiFont; HFONT gdiFont;
} HFONTItem, *PHFONTItem; } HFONTItem, *PHFONTItem;
...@@ -95,6 +98,96 @@ static void HFONTItem_Delete(PHFONTItem item) ...@@ -95,6 +98,96 @@ static void HFONTItem_Delete(PHFONTItem item)
HeapFree(GetProcessHeap(), 0, item); HeapFree(GetProcessHeap(), 0, item);
} }
/* Find hfont item entry in the list. Should be called while holding the crit sect */
static HFONTItem *find_hfontitem(HFONT hfont)
{
HFONTItem *item;
LIST_FOR_EACH_ENTRY(item, &OLEFontImpl_hFontList, HFONTItem, entry)
{
if (item->gdiFont == hfont)
return item;
}
return NULL;
}
static HRESULT inc_int_ref(HFONT hfont)
{
HFONTItem *item;
HRESULT hr = S_FALSE;
EnterCriticalSection(&OLEFontImpl_csHFONTLIST);
item = find_hfontitem(hfont);
if(item)
{
item->int_refs++;
item->total_refs++;
hr = S_OK;
}
LeaveCriticalSection(&OLEFontImpl_csHFONTLIST);
return hr;
}
/* decrements the internal ref of a hfont item. If both refs are zero it'll
remove the item from the list and delete the hfont */
static HRESULT dec_int_ref(HFONT hfont)
{
HFONTItem *item;
HRESULT hr = S_FALSE;
EnterCriticalSection(&OLEFontImpl_csHFONTLIST);
item = find_hfontitem(hfont);
if(item)
{
item->int_refs--;
item->total_refs--;
if(item->int_refs == 0 && item->total_refs == 0)
HFONTItem_Delete(item);
hr = S_OK;
}
LeaveCriticalSection(&OLEFontImpl_csHFONTLIST);
return hr;
}
static HRESULT inc_ext_ref(HFONT hfont)
{
HFONTItem *item;
HRESULT hr = S_FALSE;
EnterCriticalSection(&OLEFontImpl_csHFONTLIST);
item = find_hfontitem(hfont);
if(item)
{
item->total_refs++;
hr = S_OK;
}
LeaveCriticalSection(&OLEFontImpl_csHFONTLIST);
return hr;
}
static HRESULT dec_ext_ref(HFONT hfont)
{
HFONTItem *item;
HRESULT hr = S_FALSE;
EnterCriticalSection(&OLEFontImpl_csHFONTLIST);
item = find_hfontitem(hfont);
if(item)
{
if(--item->total_refs >= 0) hr = S_OK;
}
LeaveCriticalSection(&OLEFontImpl_csHFONTLIST);
return hr;
}
/*********************************************************************** /***********************************************************************
* Declaration of the implementation class for the IFont interface * Declaration of the implementation class for the IFont interface
*/ */
...@@ -277,6 +370,7 @@ static void OLEFont_SendNotify(OLEFontImpl* this, DISPID dispID) ...@@ -277,6 +370,7 @@ static void OLEFont_SendNotify(OLEFontImpl* this, DISPID dispID)
CONNECTDATA CD; CONNECTDATA CD;
HRESULT hres; HRESULT hres;
dec_int_ref(this->gdiFont);
this->gdiFont = 0; this->gdiFont = 0;
hres = IConnectionPoint_EnumConnections(this->pPropertyNotifyCP, &pEnum); hres = IConnectionPoint_EnumConnections(this->pPropertyNotifyCP, &pEnum);
if (SUCCEEDED(hres)) if (SUCCEEDED(hres))
...@@ -402,7 +496,6 @@ static ULONG WINAPI OLEFontImpl_Release( ...@@ -402,7 +496,6 @@ static ULONG WINAPI OLEFontImpl_Release(
{ {
OLEFontImpl *this = (OLEFontImpl *)iface; OLEFontImpl *this = (OLEFontImpl *)iface;
ULONG ret; ULONG ret;
PHFONTItem ptr, next;
TRACE("(%p)->(ref=%d)\n", this, this->ref); TRACE("(%p)->(ref=%d)\n", this, this->ref);
/* Decrease the reference count for current interface */ /* Decrease the reference count for current interface */
...@@ -412,14 +505,21 @@ static ULONG WINAPI OLEFontImpl_Release( ...@@ -412,14 +505,21 @@ static ULONG WINAPI OLEFontImpl_Release(
if (ret == 0) if (ret == 0)
{ {
ULONG fontlist_refs = InterlockedDecrement(&ifont_cnt); ULONG fontlist_refs = InterlockedDecrement(&ifont_cnt);
/* Check if all HFONT list refs are zero */
/* Final IFont object so destroy font cache */
if (fontlist_refs == 0) if (fontlist_refs == 0)
{ {
HFONTItem *item, *cursor2;
EnterCriticalSection(&OLEFontImpl_csHFONTLIST); EnterCriticalSection(&OLEFontImpl_csHFONTLIST);
LIST_FOR_EACH_ENTRY_SAFE(ptr, next, &OLEFontImpl_hFontList, HFONTItem, entry) LIST_FOR_EACH_ENTRY_SAFE(item, cursor2, &OLEFontImpl_hFontList, HFONTItem, entry)
HFONTItem_Delete(ptr); HFONTItem_Delete(item);
LeaveCriticalSection(&OLEFontImpl_csHFONTLIST); LeaveCriticalSection(&OLEFontImpl_csHFONTLIST);
} }
else
{
dec_int_ref(this->gdiFont);
}
OLEFontImpl_Destroy(this); OLEFontImpl_Destroy(this);
} }
...@@ -829,7 +929,8 @@ static HRESULT WINAPI OLEFontImpl_get_hFont( ...@@ -829,7 +929,8 @@ static HRESULT WINAPI OLEFontImpl_get_hFont(
/* Add font to the cache */ /* Add font to the cache */
newEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(HFONTItem)); newEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(HFONTItem));
newEntry->ref = 1; newEntry->int_refs = 1;
newEntry->total_refs = 1;
newEntry->gdiFont = this->gdiFont; newEntry->gdiFont = this->gdiFont;
EnterCriticalSection(&OLEFontImpl_csHFONTLIST); EnterCriticalSection(&OLEFontImpl_csHFONTLIST);
list_add_tail(&OLEFontImpl_hFontList,&newEntry->entry); list_add_tail(&OLEFontImpl_hFontList,&newEntry->entry);
...@@ -851,12 +952,8 @@ static HRESULT WINAPI OLEFontImpl_Clone( ...@@ -851,12 +952,8 @@ static HRESULT WINAPI OLEFontImpl_Clone(
IFont** ppfont) IFont** ppfont)
{ {
OLEFontImpl* newObject = 0; OLEFontImpl* newObject = 0;
LOGFONTW logFont;
INT fontHeight;
CY cySize;
PHFONTItem newEntry;
OLEFontImpl *this = (OLEFontImpl *)iface; OLEFontImpl *this = (OLEFontImpl *)iface;
TRACE("(%p)->(%p)\n", this, ppfont); TRACE("(%p)->(%p)\n", this, ppfont);
if (ppfont == NULL) if (ppfont == NULL)
...@@ -882,36 +979,12 @@ static HRESULT WINAPI OLEFontImpl_Clone( ...@@ -882,36 +979,12 @@ static HRESULT WINAPI OLEFontImpl_Clone(
(1+strlenW(this->description.lpstrName))*2 (1+strlenW(this->description.lpstrName))*2
); );
strcpyW(newObject->description.lpstrName, this->description.lpstrName); strcpyW(newObject->description.lpstrName, this->description.lpstrName);
/* We need to clone the HFONT too. This is just cut & paste from above */
IFont_get_Size(iface, &cySize);
fontHeight = MulDiv(cySize.s.Lo, this->cyLogical*635,this->cyHimetric*18);
memset(&logFont, 0, sizeof(LOGFONTW));
logFont.lfHeight = ((fontHeight%10000L)>5000L) ? (-fontHeight/10000L)-1 : /* Increment internal ref in hfont item list */
(-fontHeight/10000L); if(newObject->gdiFont) inc_int_ref(newObject->gdiFont);
logFont.lfItalic = this->description.fItalic;
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;
strcpyW(logFont.lfFaceName,this->description.lpstrName);
newObject->gdiFont = CreateFontIndirectW(&logFont);
/* Add font to the cache */
InterlockedIncrement(&ifont_cnt); 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 */ /* create new connection points */
newObject->pPropertyNotifyCP = NULL; newObject->pPropertyNotifyCP = NULL;
...@@ -1024,29 +1097,13 @@ static HRESULT WINAPI OLEFontImpl_AddRefHfont( ...@@ -1024,29 +1097,13 @@ static HRESULT WINAPI OLEFontImpl_AddRefHfont(
IFont* iface, IFont* iface,
HFONT hfont) HFONT hfont)
{ {
OLEFontImpl *this = (OLEFontImpl *)iface; OLEFontImpl *this = (OLEFontImpl *)iface;
PHFONTItem ptr, next;
HRESULT hres = S_FALSE; /* assume not present */
TRACE("(%p)->(%p)\n", this, hfont); TRACE("(%p)->(%p)\n", this, hfont);
if (!hfont) if (!hfont) return E_INVALIDARG;
return E_INVALIDARG;
/* Check of the hFont is already in the list */ return inc_ext_ref(hfont);
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 hres;
} }
/************************************************************************ /************************************************************************
...@@ -1058,34 +1115,13 @@ static HRESULT WINAPI OLEFontImpl_ReleaseHfont( ...@@ -1058,34 +1115,13 @@ static HRESULT WINAPI OLEFontImpl_ReleaseHfont(
IFont* iface, IFont* iface,
HFONT hfont) HFONT hfont)
{ {
OLEFontImpl *this = (OLEFontImpl *)iface; OLEFontImpl *this = (OLEFontImpl *)iface;
PHFONTItem ptr, next;
HRESULT hres = S_FALSE; /* assume not present */
TRACE("(%p)->(%p)\n", this, hfont); TRACE("(%p)->(%p)\n", this, hfont);
if (!hfont) if (!hfont) return E_INVALIDARG;
return E_INVALIDARG;
/* Check of the hFont is already in the list */ return dec_ext_ref(hfont);
EnterCriticalSection(&OLEFontImpl_csHFONTLIST);
LIST_FOR_EACH_ENTRY_SAFE(ptr, next, &OLEFontImpl_hFontList, HFONTItem, entry)
{
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 hres;
} }
/************************************************************************ /************************************************************************
...@@ -1678,7 +1714,7 @@ static HRESULT WINAPI OLEFontImpl_Load( ...@@ -1678,7 +1714,7 @@ static HRESULT WINAPI OLEFontImpl_Load(
this->description.lpstrName[len] = 0; this->description.lpstrName[len] = 0;
/* Ensure use of this font causes a new one to be created @@@@ */ /* Ensure use of this font causes a new one to be created @@@@ */
DeleteObject(this->gdiFont); dec_int_ref(this->gdiFont);
this->gdiFont = 0; this->gdiFont = 0;
return S_OK; return S_OK;
...@@ -2283,9 +2319,6 @@ static void OLEFontImpl_Destroy(OLEFontImpl* fontDesc) ...@@ -2283,9 +2319,6 @@ static void OLEFontImpl_Destroy(OLEFontImpl* fontDesc)
HeapFree(GetProcessHeap(), 0, fontDesc->description.lpstrName); HeapFree(GetProcessHeap(), 0, fontDesc->description.lpstrName);
if (fontDesc->gdiFont!=0)
DeleteObject(fontDesc->gdiFont);
if (fontDesc->pPropertyNotifyCP) if (fontDesc->pPropertyNotifyCP)
IConnectionPoint_Release(fontDesc->pPropertyNotifyCP); IConnectionPoint_Release(fontDesc->pPropertyNotifyCP);
if (fontDesc->pFontEventsCP) if (fontDesc->pFontEventsCP)
......
...@@ -838,7 +838,7 @@ static void test_returns(void) ...@@ -838,7 +838,7 @@ static void test_returns(void)
static void test_hfont_lifetime(void) static void test_hfont_lifetime(void)
{ {
IFont *font; IFont *font, *font2;
FONTDESC fontdesc; FONTDESC fontdesc;
HRESULT hr; HRESULT hr;
HFONT hfont, first_hfont = NULL; HFONT hfont, first_hfont = NULL;
...@@ -877,13 +877,13 @@ static void test_hfont_lifetime(void) ...@@ -877,13 +877,13 @@ static void test_hfont_lifetime(void)
/* put_Size doesn't cause the new font to be realized */ /* put_Size doesn't cause the new font to be realized */
obj_type = GetObjectType(last_hfont); obj_type = GetObjectType(last_hfont);
todo_wine
ok(obj_type == OBJ_FONT, "got obj type %d\n", obj_type); ok(obj_type == OBJ_FONT, "got obj type %d\n", obj_type);
hr = IFont_get_hFont(font, &hfont); hr = IFont_get_hFont(font, &hfont);
ok_ole_success(hr, "get_hFont"); ok_ole_success(hr, "get_hFont");
obj_type = GetObjectType(last_hfont); obj_type = GetObjectType(last_hfont);
todo_wine
ok(obj_type == 0, "%d: got obj type %d\n", i, obj_type); ok(obj_type == 0, "%d: got obj type %d\n", i, obj_type);
} }
...@@ -939,6 +939,7 @@ todo_wine ...@@ -939,6 +939,7 @@ todo_wine
/* put_Size doesn't cause the new font to be realized */ /* put_Size doesn't cause the new font to be realized */
obj_type = GetObjectType(last_hfont); obj_type = GetObjectType(last_hfont);
todo_wine
ok(obj_type == OBJ_FONT, "got obj type %d\n", obj_type); ok(obj_type == OBJ_FONT, "got obj type %d\n", obj_type);
hr = IFont_get_hFont(font, &hfont); hr = IFont_get_hFont(font, &hfont);
...@@ -951,7 +952,6 @@ todo_wine ...@@ -951,7 +952,6 @@ todo_wine
ok_ole_success(hr, "ReleaseHfont"); ok_ole_success(hr, "ReleaseHfont");
obj_type = GetObjectType(last_hfont); obj_type = GetObjectType(last_hfont);
todo_wine
ok(obj_type == 0, "%d: got obj type %d\n", i, obj_type); ok(obj_type == 0, "%d: got obj type %d\n", i, obj_type);
} }
...@@ -982,6 +982,42 @@ todo_wine ...@@ -982,6 +982,42 @@ todo_wine
obj_type = GetObjectType(first_hfont); obj_type = GetObjectType(first_hfont);
ok(obj_type == 0, "got obj type %d\n", obj_type); ok(obj_type == 0, "got obj type %d\n", obj_type);
/* If we take two internal references on a hfont then we can release
it twice. So it looks like there's a total reference count
that includes internal and external references */
hr = pOleCreateFontIndirect(&fontdesc, &IID_IFont, (void **)&font);
ok_ole_success(hr, "OleCreateFontIndirect");
hr = pOleCreateFontIndirect(&fontdesc, &IID_IFont, (void **)&font2);
ok_ole_success(hr, "OleCreateFontIndirect");
hr = IFont_get_hFont(font, &hfont);
ok_ole_success(hr, "get_hFont");
hr = IFont_get_hFont(font2, &first_hfont);
ok_ole_success(hr, "get_hFont");
todo_wine
ok(hfont == first_hfont, "fonts differ\n");
hr = IFont_ReleaseHfont(font, hfont);
ok(hr == S_OK, "got %08x\n", hr);
hr = IFont_ReleaseHfont(font, hfont);
todo_wine
ok(hr == S_OK, "got %08x\n", hr);
hr = IFont_ReleaseHfont(font, hfont);
ok(hr == S_FALSE, "got %08x\n", hr);
obj_type = GetObjectType(hfont);
ok(obj_type == OBJ_FONT, "got obj type %d\n", obj_type);
IFont_Release(font);
obj_type = GetObjectType(hfont);
ok(obj_type == OBJ_FONT, "got obj type %d\n", obj_type);
IFont_Release(font2);
obj_type = GetObjectType(hfont);
ok(obj_type == 0, "got obj type %d\n", obj_type);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment