summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/bindings/gobject/DOMObjectCache.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/bindings/gobject/DOMObjectCache.cpp')
-rw-r--r--Source/WebCore/bindings/gobject/DOMObjectCache.cpp154
1 files changed, 154 insertions, 0 deletions
diff --git a/Source/WebCore/bindings/gobject/DOMObjectCache.cpp b/Source/WebCore/bindings/gobject/DOMObjectCache.cpp
new file mode 100644
index 0000000..2e7f106
--- /dev/null
+++ b/Source/WebCore/bindings/gobject/DOMObjectCache.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * 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 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 Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#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;
+
+ // Unreffing the objects removes them from the cache in their
+ // finalize method, so just save them to do that while we are not
+ // iterating the cache itself.
+ 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;
+ // We can't really know what the user has done with the DOM
+ // objects, so in case any of the external references to them
+ // were unreffed (but not all, otherwise the object would be
+ // dead and out of the cache) we'll add a weak ref before we
+ // start to get rid of the cache's own references; if the
+ // object dies in the middle of the process, we'll just stop.
+ gboolean objectDead = FALSE;
+ g_object_weak_ref(data->object, weakRefNotify, &objectDead);
+ // We need to check objectDead first, otherwise the cache data
+ // might be garbage already.
+ while (!objectDead && data->timesReturned > 0) {
+ // If this is the last unref we are going to do,
+ // disconnect the weak ref. We cannot do it afterwards
+ // because the object might be dead at that point.
+ 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;
+
+ // We want to add one ref each time a wrapper is returned, so that
+ // the user can manually unref them if he chooses to.
+ 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)
+{
+ // call the ::put version that takes void* to do the basic cache
+ // insertion work
+ put(static_cast<void*>(objectHandle), wrapper);
+
+ DOMObjectCacheData* data = domObjects().get(objectHandle);
+ ASSERT(data);
+
+ data->frame = getFrameFromHandle(objectHandle);
+
+ return wrapper;
+}
+
+}