OSDN Git Service

Merge WebKit at r73109: Initial merge by git.
[android-x86/external-webkit.git] / WebCore / bindings / gobject / DOMObjectCache.cpp
1 /*
2  *  Copyright (C) 2010 Igalia S.L.
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #include "config.h"
20 #include "DOMObjectCache.h"
21
22 #include "Document.h"
23 #include "Node.h"
24 #include <wtf/HashMap.h>
25
26 namespace WebKit {
27
28 typedef struct {
29     GObject* object;
30     WebCore::Frame* frame;
31     guint timesReturned;
32 } DOMObjectCacheData;
33
34 typedef HashMap<void*, DOMObjectCacheData*> DOMObjectMap;
35
36 static DOMObjectMap& domObjects()
37 {
38     static DOMObjectMap staticDOMObjects;
39     return staticDOMObjects;
40 }
41
42 static WebCore::Frame* getFrameFromHandle(void* objectHandle)
43 {
44     WebCore::Node* node = static_cast<WebCore::Node*>(objectHandle);
45     if (!node->inDocument())
46         return 0;
47     WebCore::Document* document = node->document();
48     if (!document)
49         return 0;
50     return document->frame();
51 }
52
53 void DOMObjectCache::forget(void* objectHandle)
54 {
55     DOMObjectCacheData* cacheData = domObjects().get(objectHandle);
56     ASSERT(cacheData);
57     g_slice_free(DOMObjectCacheData, cacheData);
58     domObjects().take(objectHandle);
59 }
60
61 static void weakRefNotify(gpointer data, GObject* zombie)
62 {
63     gboolean* objectDead = static_cast<gboolean*>(data);
64     *objectDead = TRUE;
65 }
66
67 void DOMObjectCache::clearByFrame(WebCore::Frame* frame)
68 {
69     Vector<DOMObjectCacheData*> toUnref;
70
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;
77         ASSERT(data);
78         if ((!frame || data->frame == frame) && data->timesReturned)
79             toUnref.append(data);
80     }
81
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);
103         }
104     }
105 }
106
107 DOMObjectCache::~DOMObjectCache()
108 {
109     clearByFrame();
110 }
111
112 void* DOMObjectCache::get(void* objectHandle)
113 {
114     DOMObjectCacheData* data = domObjects().get(objectHandle);
115     if (!data)
116         return 0;
117
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);
123 }
124
125 void* DOMObjectCache::put(void* objectHandle, void* wrapper)
126 {
127     if (domObjects().get(objectHandle))
128         return wrapper;
129
130     DOMObjectCacheData* data = g_slice_new(DOMObjectCacheData);
131     data->object = static_cast<GObject*>(wrapper);
132     data->frame = 0;
133     data->timesReturned = 1;
134
135     domObjects().set(objectHandle, data);
136     return wrapper;
137 }
138
139 void* DOMObjectCache::put(WebCore::Node* objectHandle, void* wrapper)
140 {
141     // call the ::put version that takes void* to do the basic cache
142     // insertion work
143     put(static_cast<void*>(objectHandle), wrapper);
144
145     DOMObjectCacheData* data = domObjects().get(objectHandle);
146     ASSERT(data);
147
148     data->frame = getFrameFromHandle(objectHandle);
149
150     return wrapper;
151 }
152
153 }