2 * Copyright (C) 2010 Igalia S.L.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 #include "DOMObjectCache.h"
24 #include <wtf/HashMap.h>
30 WebCore::Frame* frame;
34 typedef HashMap<void*, DOMObjectCacheData*> DOMObjectMap;
36 static DOMObjectMap& domObjects()
38 static DOMObjectMap staticDOMObjects;
39 return staticDOMObjects;
42 static WebCore::Frame* getFrameFromHandle(void* objectHandle)
44 WebCore::Node* node = static_cast<WebCore::Node*>(objectHandle);
45 if (!node->inDocument())
47 WebCore::Document* document = node->document();
50 return document->frame();
53 void DOMObjectCache::forget(void* objectHandle)
55 DOMObjectCacheData* cacheData = domObjects().get(objectHandle);
57 g_slice_free(DOMObjectCacheData, cacheData);
58 domObjects().take(objectHandle);
61 static void weakRefNotify(gpointer data, GObject* zombie)
63 gboolean* objectDead = static_cast<gboolean*>(data);
67 void DOMObjectCache::clearByFrame(WebCore::Frame* frame)
69 Vector<DOMObjectCacheData*> toUnref;
71 // Unreffing the objects removes them from the cache in their
72 // finalize method, so just save them to do that while we are not
73 // iterating the cache itself.
74 DOMObjectMap::iterator end = domObjects().end();
75 for (DOMObjectMap::iterator iter = domObjects().begin(); iter != end; ++iter) {
76 DOMObjectCacheData* data = iter->second;
78 if ((!frame || data->frame == frame) && data->timesReturned)
82 Vector<DOMObjectCacheData*>::iterator last = toUnref.end();
83 for (Vector<DOMObjectCacheData*>::iterator it = toUnref.begin(); it != last; ++it) {
84 DOMObjectCacheData* data = *it;
85 // We can't really know what the user has done with the DOM
86 // objects, so in case any of the external references to them
87 // were unreffed (but not all, otherwise the object would be
88 // dead and out of the cache) we'll add a weak ref before we
89 // start to get rid of the cache's own references; if the
90 // object dies in the middle of the process, we'll just stop.
91 gboolean objectDead = FALSE;
92 g_object_weak_ref(data->object, weakRefNotify, &objectDead);
93 // We need to check objectDead first, otherwise the cache data
94 // might be garbage already.
95 while (!objectDead && data->timesReturned > 0) {
96 // If this is the last unref we are going to do,
97 // disconnect the weak ref. We cannot do it afterwards
98 // because the object might be dead at that point.
99 if (data->timesReturned == 1)
100 g_object_weak_unref(data->object, weakRefNotify, &objectDead);
101 data->timesReturned--;
102 g_object_unref(data->object);
107 DOMObjectCache::~DOMObjectCache()
112 void* DOMObjectCache::get(void* objectHandle)
114 DOMObjectCacheData* data = domObjects().get(objectHandle);
118 // We want to add one ref each time a wrapper is returned, so that
119 // the user can manually unref them if he chooses to.
120 ASSERT(data->object);
121 data->timesReturned++;
122 return g_object_ref(data->object);
125 void* DOMObjectCache::put(void* objectHandle, void* wrapper)
127 if (domObjects().get(objectHandle))
130 DOMObjectCacheData* data = g_slice_new(DOMObjectCacheData);
131 data->object = static_cast<GObject*>(wrapper);
133 data->timesReturned = 1;
135 domObjects().set(objectHandle, data);
139 void* DOMObjectCache::put(WebCore::Node* objectHandle, void* wrapper)
141 // call the ::put version that takes void* to do the basic cache
143 put(static_cast<void*>(objectHandle), wrapper);
145 DOMObjectCacheData* data = domObjects().get(objectHandle);
148 data->frame = getFrameFromHandle(objectHandle);