1/*
2 * Copyright (C) 2013 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,1 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 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20#include "config.h"
21#include "WebKitScriptWorld.h"
22
23#include "WebKitScriptWorldPrivate.h"
24#include <wtf/HashMap.h>
25#include <wtf/NeverDestroyed.h>
26#include <wtf/glib/WTFGType.h>
27
28using namespace WebKit;
29using namespace WebCore;
30
31enum {
32 WINDOW_OBJECT_CLEARED,
33
34 LAST_SIGNAL
35};
36
37typedef HashMap<InjectedBundleScriptWorld*, WebKitScriptWorld*> ScriptWorldMap;
38
39static ScriptWorldMap& scriptWorlds()
40{
41 static NeverDestroyed<ScriptWorldMap> map;
42 return map;
43}
44
45struct _WebKitScriptWorldPrivate {
46 ~_WebKitScriptWorldPrivate()
47 {
48 ASSERT(scriptWorlds().contains(scriptWorld.get()));
49 scriptWorlds().remove(scriptWorld.get());
50 }
51
52 RefPtr<InjectedBundleScriptWorld> scriptWorld;
53 CString name;
54};
55
56static guint signals[LAST_SIGNAL] = { 0, };
57
58WEBKIT_DEFINE_TYPE(WebKitScriptWorld, webkit_script_world, G_TYPE_OBJECT)
59
60static void webkit_script_world_class_init(WebKitScriptWorldClass* klass)
61{
62 /**
63 * WebKitScriptWorld::window-object-cleared:
64 * @world: the #WebKitScriptWorld on which the signal is emitted
65 * @page: a #WebKitWebPage
66 * @frame: the #WebKitFrame to which @world belongs
67 *
68 * Emitted when the JavaScript window object in a #WebKitScriptWorld has been
69 * cleared. This is the preferred place to set custom properties on the window
70 * object using the JavaScriptCore API. You can get the window object of @frame
71 * from the JavaScript execution context of @world that is returned by
72 * webkit_frame_get_js_context_for_script_world().
73 *
74 * Since: 2.2
75 */
76 signals[WINDOW_OBJECT_CLEARED] = g_signal_new(
77 "window-object-cleared",
78 G_TYPE_FROM_CLASS(klass),
79 G_SIGNAL_RUN_LAST,
80 0, nullptr, nullptr,
81 g_cclosure_marshal_generic,
82 G_TYPE_NONE, 2,
83 WEBKIT_TYPE_WEB_PAGE,
84 WEBKIT_TYPE_FRAME);
85}
86
87WebKitScriptWorld* webkitScriptWorldGet(InjectedBundleScriptWorld* scriptWorld)
88{
89 return scriptWorlds().get(scriptWorld);
90}
91
92InjectedBundleScriptWorld* webkitScriptWorldGetInjectedBundleScriptWorld(WebKitScriptWorld* world)
93{
94 return world->priv->scriptWorld.get();
95}
96
97void webkitScriptWorldWindowObjectCleared(WebKitScriptWorld* world, WebKitWebPage* page, WebKitFrame* frame)
98{
99 g_signal_emit(world, signals[WINDOW_OBJECT_CLEARED], 0, page, frame);
100}
101
102static WebKitScriptWorld* webkitScriptWorldCreate(Ref<InjectedBundleScriptWorld>&& scriptWorld)
103{
104 WebKitScriptWorld* world = WEBKIT_SCRIPT_WORLD(g_object_new(WEBKIT_TYPE_SCRIPT_WORLD, nullptr));
105 world->priv->scriptWorld = WTFMove(scriptWorld);
106 world->priv->name = world->priv->scriptWorld->name().utf8();
107
108 ASSERT(!scriptWorlds().contains(world->priv->scriptWorld.get()));
109 scriptWorlds().add(world->priv->scriptWorld.get(), world);
110
111 return world;
112}
113
114static gpointer createDefaultScriptWorld(gpointer)
115{
116 return webkitScriptWorldCreate(InjectedBundleScriptWorld::normalWorld());
117}
118
119/**
120 * webkit_script_world_get_default:
121 *
122 * Get the default #WebKitScriptWorld. This is the normal script world
123 * where all scripts are executed by default.
124 * You can get the JavaScript execution context of a #WebKitScriptWorld
125 * for a given #WebKitFrame with webkit_frame_get_javascript_context_for_script_world().
126 *
127 * Returns: (transfer none): the default #WebKitScriptWorld
128 *
129 * Since: 2.2
130 */
131WebKitScriptWorld* webkit_script_world_get_default(void)
132{
133 static GOnce onceInit = G_ONCE_INIT;
134 return WEBKIT_SCRIPT_WORLD(g_once(&onceInit, createDefaultScriptWorld, 0));
135}
136
137/**
138 * webkit_script_world_new:
139 *
140 * Creates a new isolated #WebKitScriptWorld. Scripts executed in
141 * isolated worlds have access to the DOM but not to other variable
142 * or functions created by the page.
143 * The #WebKitScriptWorld is created with a generated unique name. Use
144 * webkit_script_world_new_with_name() if you want to create it with a
145 * custom name.
146 * You can get the JavaScript execution context of a #WebKitScriptWorld
147 * for a given #WebKitFrame with webkit_frame_get_javascript_context_for_script_world().
148 *
149 * Returns: (transfer full): a new isolated #WebKitScriptWorld
150 *
151 * Since: 2.2
152 */
153WebKitScriptWorld* webkit_script_world_new(void)
154{
155 return webkitScriptWorldCreate(InjectedBundleScriptWorld::create());
156}
157
158/**
159 * webkit_script_world_new_with_name:
160 * @name: a name for the script world
161 *
162 * Creates a new isolated #WebKitScriptWorld with a name. Scripts executed in
163 * isolated worlds have access to the DOM but not to other variable
164 * or functions created by the page.
165 * You can get the JavaScript execution context of a #WebKitScriptWorld
166 * for a given #WebKitFrame with webkit_frame_get_javascript_context_for_script_world().
167 *
168 * Returns: (transfer full): a new isolated #WebKitScriptWorld
169 *
170 * Since: 2.22
171 */
172WebKitScriptWorld* webkit_script_world_new_with_name(const char* name)
173{
174 g_return_val_if_fail(name, nullptr);
175
176 return webkitScriptWorldCreate(InjectedBundleScriptWorld::create(String::fromUTF8(name)));
177}
178
179/**
180 * webkit_script_world_get_name:
181 * @world: a #WebKitScriptWorld
182 *
183 * Get the name of a #WebKitScriptWorld.
184 *
185 * Returns: the name of @world
186 *
187 * Since: 2.22
188 */
189const char* webkit_script_world_get_name(WebKitScriptWorld* world)
190{
191 g_return_val_if_fail(WEBKIT_IS_SCRIPT_WORLD(world), nullptr);
192
193 return world->priv->name.data();
194}
195