DOMObjectCache.cpp [plain text]
#include "config.h"
#include "DOMObjectCache.h"
#include "Document.h"
#include "Node.h"
#include "glib-object.h"
#include <wtf/HashMap.h>
namespace WebKit {
typedef struct {
GObject* object;
WebCore::Frame* frame;
guint timesReturned;
} DOMObjectCacheData;
typedef HashMap<void*, DOMObjectCacheData*> DOMObjectMap;
static DOMObjectMap& domObjects()
{
static DOMObjectMap staticDOMObjects;
return staticDOMObjects;
}
static WebCore::Frame* getFrameFromHandle(void* objectHandle)
{
WebCore::Node* node = static_cast<WebCore::Node*>(objectHandle);
if (!node->inDocument())
return 0;
WebCore::Document* document = node->document();
if (!document)
return 0;
return document->frame();
}
void DOMObjectCache::forget(void* objectHandle)
{
DOMObjectCacheData* cacheData = domObjects().get(objectHandle);
ASSERT(cacheData);
g_slice_free(DOMObjectCacheData, cacheData);
domObjects().take(objectHandle);
}
static void weakRefNotify(gpointer data, GObject* zombie)
{
gboolean* objectDead = static_cast<gboolean*>(data);
*objectDead = TRUE;
}
void DOMObjectCache::clearByFrame(WebCore::Frame* frame)
{
Vector<DOMObjectCacheData*> toUnref;
DOMObjectMap::iterator end = domObjects().end();
for (DOMObjectMap::iterator iter = domObjects().begin(); iter != end; ++iter) {
DOMObjectCacheData* data = iter->second;
ASSERT(data);
if ((!frame || data->frame == frame) && data->timesReturned)
toUnref.append(data);
}
Vector<DOMObjectCacheData*>::iterator last = toUnref.end();
for (Vector<DOMObjectCacheData*>::iterator it = toUnref.begin(); it != last; ++it) {
DOMObjectCacheData* data = *it;
gboolean objectDead = FALSE;
g_object_weak_ref(data->object, weakRefNotify, &objectDead);
while (!objectDead && data->timesReturned > 0) {
if (data->timesReturned == 1)
g_object_weak_unref(data->object, weakRefNotify, &objectDead);
data->timesReturned--;
g_object_unref(data->object);
}
}
}
DOMObjectCache::~DOMObjectCache()
{
clearByFrame();
}
void* DOMObjectCache::get(void* objectHandle)
{
DOMObjectCacheData* data = domObjects().get(objectHandle);
if (!data)
return 0;
ASSERT(data->object);
data->timesReturned++;
return g_object_ref(data->object);
}
void* DOMObjectCache::put(void* objectHandle, void* wrapper)
{
if (domObjects().get(objectHandle))
return wrapper;
DOMObjectCacheData* data = g_slice_new(DOMObjectCacheData);
data->object = static_cast<GObject*>(wrapper);
data->frame = 0;
data->timesReturned = 1;
domObjects().set(objectHandle, data);
return wrapper;
}
void* DOMObjectCache::put(WebCore::Node* objectHandle, void* wrapper)
{
put(static_cast<void*>(objectHandle), wrapper);
DOMObjectCacheData* data = domObjects().get(objectHandle);
ASSERT(data);
data->frame = getFrameFromHandle(objectHandle);
return wrapper;
}
}