Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Side by Side Diff: webkit/port/bindings/js/ScriptControllerChromium.cpp

Issue 8947: Fix the JSC build.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 12 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2008, Google Inc. 1 // Copyright (c) 2008, Google Inc.
2 // All rights reserved. 2 // All rights reserved.
3 // 3 //
4 // Redistribution and use in source and binary forms, with or without 4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are 5 // modification, are permitted provided that the following conditions are
6 // met: 6 // met:
7 // 7 //
8 // * Redistributions of source code must retain the above copyright 8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer. 9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above 10 // * Redistributions in binary form must reproduce the above
(...skipping 12 matching lines...) Expand all
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 29
30 #include "config.h" 30 #include "config.h"
31 #include "ScriptController.h" 31 #include "ScriptController.h"
32 32
33 #include "CString.h" 33 #include "bindings/npruntime.h"
34 #include "Document.h" 34 #include "c_instance.h"
35 #include "DOMWindow.h"
36 #include "Event.h"
37 #include "EventListener.h"
38 #include "EventNames.h"
39 #include "Frame.h"
40 #include "Node.h"
41 #include "NotImplemented.h"
42 #include "npruntime_priv.h"
43 #include "np_v8object.h"
44 #include "PausedTimeouts.h"
45 #include "Widget.h"
46 35
47 #include "v8_proxy.h"
48 #include "v8_binding.h"
49 #include "v8_npobject.h"
50
51 //TODO(eseidel): We should remove this glue dependency
52 #undef LOG // glue defines its own LOG macro 36 #undef LOG // glue defines its own LOG macro
53 #include "webkit/glue/webplugin_impl.h" 37 #include "webkit/glue/webplugin_impl.h"
54 38
55 NPRuntimeFunctions npruntime_functions = {
56 NPN_GetStringIdentifier,
57 NPN_GetStringIdentifiers,
58 NPN_GetIntIdentifier,
59 NPN_IdentifierIsString,
60 NPN_UTF8FromIdentifier,
61 NPN_IntFromIdentifier,
62 NPN_CreateObject,
63 NPN_RetainObject,
64 NPN_ReleaseObject,
65 NPN_Invoke,
66 NPN_InvokeDefault,
67 NPN_Evaluate,
68 NPN_GetProperty,
69 NPN_SetProperty,
70 NPN_RemoveProperty,
71 NPN_HasProperty,
72 NPN_HasMethod,
73 NPN_ReleaseVariantValue,
74 NPN_SetException
75 };
76
77
78 namespace WebCore { 39 namespace WebCore {
79 40
80 bool ScriptController::m_recordPlaybackMode = false;
81
82 void ScriptController::setFlags(const char* str, int length)
83 {
84 v8::V8::SetFlagsFromString(str, length);
85 }
86
87 void ScriptController::setDomain(Frame* frame, const String&)
88 {
89 V8Proxy::DomainChanged(frame);
90 }
91
92 Frame* ScriptController::retrieveActiveFrame()
93 {
94 return V8Proxy::retrieveActiveFrame();
95 }
96
97 bool ScriptController::isSafeScript(Frame* target)
98 {
99 return V8Proxy::CanAccessFrame(target, true);
100 }
101
102 void ScriptController::gcProtectJSWrapper(void* dom_object)
103 {
104 V8Proxy::GCProtect(static_cast<Peerable*>(dom_object));
105 }
106
107 void ScriptController::gcUnprotectJSWrapper(void* dom_object)
108 {
109 V8Proxy::GCUnprotect(static_cast<Peerable*>(dom_object));
110 }
111
112 void ScriptController::pauseTimeouts(OwnPtr<PausedTimeouts>& result)
113 {
114 DOMWindow* window = m_frame->domWindow();
115 if (!window) {
116 result.clear();
117 return;
118 }
119 window->pauseTimeouts(result);
120 }
121
122 void ScriptController::resumeTimeouts(OwnPtr<PausedTimeouts>& timeouts)
123 {
124 DOMWindow* window = m_frame->domWindow();
125 if (!window) {
126 timeouts.clear();
127 return;
128 }
129 window->resumeTimeouts(timeouts);
130 }
131
132 ScriptController::ScriptController(Frame* frame)
133 : m_frame(frame)
134 , m_sourceURL(0)
135 , m_processingTimerCallback(false)
136 , m_paused(false)
137 , m_proxy(new V8Proxy(frame))
138 #if ENABLE(NETSCAPE_PLUGIN_API)
139 , m_windowScriptNPObject(0)
140 #endif
141 {
142 }
143
144 ScriptController::~ScriptController()
145 {
146 }
147
148 void ScriptController::clearScriptObjects()
149 {
150 // TODO(eseidel): JSC handles binding root objects here, why don't we?
151
152 #if ENABLE(NETSCAPE_PLUGIN_API)
153 if (m_windowScriptNPObject) {
154 // Call _NPN_DeallocateObject() instead of _NPN_ReleaseObject() so that we don't leak if a plugin fails to release the window
155 // script object properly.
156 // This shouldn't cause any problems for plugins since they should have already been stopped and destroyed at this point.
157 _NPN_DeallocateObject(m_windowScriptNPObject);
158 m_windowScriptNPObject = 0;
159 }
160 #endif
161 }
162
163 void ScriptController::clearPluginObjects()
164 {
165 PluginObjectMap::iterator it = m_pluginObjects.begin();
166 for (; it != m_pluginObjects.end(); ++it) {
167 _NPN_UnregisterObject(it->second);
168 NPN_ReleaseObject(it->second);
169 }
170 m_pluginObjects.clear();
171 }
172
173 // Disconnect the proxy from its owner frame;
174 void ScriptController::disconnectFrame()
175 {
176 m_proxy->disconnectFrame();
177 }
178
179 bool ScriptController::processingUserGesture() const
180 {
181 Frame* active_frame = V8Proxy::retrieveActiveFrame();
182 // No script is running, must be run by users.
183 if (!active_frame)
184 return true;
185
186 V8Proxy* active_proxy = active_frame->script()->proxy();
187
188 v8::HandleScope handle_scope;
189 v8::Handle<v8::Context> context = V8Proxy::GetContext(active_frame);
190 // TODO(fqian): find all cases context can be empty:
191 // 1) JS is disabled;
192 // 2) page is NULL;
193 if (context.IsEmpty())
194 return true;
195
196 v8::Context::Scope scope(context);
197
198 v8::Handle<v8::Object> global = context->Global();
199 v8::Handle<v8::Value> jsevent = global->Get(v8::String::NewSymbol("event"));
200 Event* event = V8Proxy::ToNativeEvent(jsevent);
201
202 // Based on code from kjs_bindings.cpp.
203 // Note: This is more liberal than Firefox's implementation.
204 if (event) {
205 const AtomicString& type = event->type();
206 bool event_ok =
207 // mouse events
208 type == EventNames::clickEvent ||
209 type == EventNames::mousedownEvent ||
210 type == EventNames::mouseupEvent ||
211 type == EventNames::dblclickEvent ||
212 // keyboard events
213 type == EventNames::keydownEvent ||
214 type == EventNames::keypressEvent ||
215 type == EventNames::keyupEvent ||
216 // other accepted events
217 type == EventNames::selectEvent ||
218 type == EventNames::changeEvent ||
219 type == EventNames::focusEvent ||
220 type == EventNames::blurEvent ||
221 type == EventNames::submitEvent;
222
223 if (event_ok)
224 return true;
225 } else if (active_proxy->inlineCode() && !active_proxy->timerCallback())
226 // This is the <a href="javascript:window.open('...')> case -> we let it
227 // through
228 return true;
229
230 // This is the <script>window.open(...)</script> case or a timer callback ->
231 // block it
232 return false;
233 }
234
235
236 // Evaluate a script file in the environment of this proxy.
237 String ScriptController::evaluate(const String& filename, int baseLine,
238 const String& code, Node* node, bool* succ)
239 {
240 if (succ)
241 *succ = false;
242 String result;
243
244 v8::HandleScope hs;
245 v8::Handle<v8::Context> context = V8Proxy::GetContext(m_proxy->frame());
246 if (context.IsEmpty())
247 return result;
248
249 v8::Context::Scope scope(context);
250
251 // HTMLTokenizer used to use base zero line numbers for scripts, now it
252 // uses base 1. This confuses v8, which uses line offsets from the
253 // first line.
254 v8::Local<v8::Value> obj = m_proxy->Evaluate(filename, baseLine - 1, code,
255 node);
256
257 if (obj.IsEmpty() || obj->IsUndefined())
258 return result;
259
260 // If the return value is not a string, return 0 (what KJS does).
261 if (!obj->IsString()) {
262 v8::TryCatch exception_block;
263 obj = obj->ToString();
264 if (exception_block.HasCaught())
265 obj = v8::String::New("");
266 }
267
268 result = ToWebCoreString(obj);
269 if (succ)
270 *succ = true;
271
272 return result;
273 }
274
275 v8::Persistent<v8::Value> ScriptController::evaluate(const String& filename,
276 int baseLine,
277 const String& code,
278 Node* node)
279 {
280 v8::HandleScope hs;
281 v8::Handle<v8::Context> context = V8Proxy::GetContext(m_proxy->frame());
282 if (context.IsEmpty())
283 return v8::Persistent<v8::Value>();
284
285 v8::Context::Scope scope(context);
286
287 v8::Local<v8::Value> obj = m_proxy->Evaluate(filename, baseLine, code, node) ;
288
289 if (obj.IsEmpty())
290 return v8::Persistent<v8::Value>();
291
292 // TODO(fqian): keep track the global handle created.
293 return v8::Persistent<v8::Value>::New(obj);
294 }
295
296 void ScriptController::disposeJSResult(v8::Persistent<v8::Value> result)
297 {
298 result.Dispose();
299 result.Clear();
300 }
301
302 PassRefPtr<EventListener> ScriptController::createHTMLEventHandler(
303 const String& functionName, const String& code, Node* node)
304 {
305 return m_proxy->createHTMLEventHandler(functionName, code, node);
306 }
307
308 #if ENABLE(SVG)
309 PassRefPtr<EventListener> ScriptController::createSVGEventHandler(
310 const String& functionName, const String& code, Node* node)
311 {
312 return m_proxy->createSVGEventHandler(functionName, code, node);
313 }
314 #endif
315
316 void ScriptController::setEventHandlerLineno(int lineno)
317 {
318 m_proxy->setEventHandlerLineno(lineno);
319 }
320
321 void ScriptController::finishedWithEvent(Event* evt)
322 {
323 m_proxy->finishedWithEvent(evt);
324 }
325
326 void ScriptController::clearDocumentWrapper()
327 {
328 m_proxy->clearDocumentWrapper();
329 }
330
331 // Create a V8 object with an interceptor of NPObjectPropertyGetter
332 void ScriptController::BindToWindowObject(Frame* frame, const String& key, NPObj ect* object)
333 {
334 v8::HandleScope handle_scope;
335
336 v8::Handle<v8::Context> context = V8Proxy::GetContext(frame);
337 if (context.IsEmpty())
338 return;
339
340 v8::Context::Scope scope(context);
341
342 v8::Handle<v8::Object> value = CreateV8ObjectForNPObject(object, NULL);
343
344 // Attach to the global object
345 v8::Handle<v8::Object> global = context->Global();
346 global->Set(v8String(key), value);
347 }
348
349 void ScriptController::collectGarbage()
350 {
351 v8::HandleScope hs;
352 v8::Handle<v8::Context> context = V8Proxy::GetContext(m_proxy->frame());
353 if (context.IsEmpty())
354 return;
355
356 v8::Context::Scope scope(context);
357
358 m_proxy->Evaluate("", 0, "if (window.gc) void(gc());", NULL);
359 }
360
361 NPRuntimeFunctions* ScriptController::functions()
362 {
363 return &npruntime_functions;
364 }
365
366
367 bool ScriptController::haveInterpreter() const
368 {
369 return m_proxy->ContextInitialized();
370 }
371
372 bool ScriptController::isEnabled() const
373 {
374 return m_proxy->isEnabled();
375 }
376
377 JSInstanceHandle ScriptController::createScriptInstanceForWidget(Widget* widget) 41 JSInstanceHandle ScriptController::createScriptInstanceForWidget(Widget* widget)
378 { 42 {
379 ASSERT(widget != 0); 43 ASSERT(widget != 0);
380 44
381 if (widget->isFrameView()) 45 if (widget->isFrameView())
382 return JSInstanceHolder::EmptyInstance(); 46 return JSInstanceHolder::EmptyInstance();
383 47
384 // Note: We have to trust that the widget passed to us here 48 // Note: We have to trust that the widget passed to us here
385 // is a WebPluginImpl. There isn't a way to dynamically verify 49 // is a WebPluginImpl. There isn't a way to dynamically verify
386 // it, since the derived class (Widget) has no identifier. 50 // it, since the derived class (Widget) has no identifier.
387 WebPluginContainer* container = static_cast<WebPluginContainer*>(widget); 51 WebPluginContainer* container = static_cast<WebPluginContainer*>(widget);
388 if (!container) 52 if (!container)
389 return JSInstanceHolder::EmptyInstance(); 53 return JSInstanceHolder::EmptyInstance();
390 54
391 NPObject* npObject = container->GetPluginScriptableObject(); 55 NPObject* npObject = container->GetPluginScriptableObject();
392 if (!npObject) 56 if (!npObject)
393 return JSInstanceHolder::EmptyInstance(); 57 return JSInstanceHolder::EmptyInstance();
394 58
395 #if USE(JSC)
396 // Register 'widget' with the frame so that we can teardown 59 // Register 'widget' with the frame so that we can teardown
397 // subobjects when the container goes away. 60 // subobjects when the container goes away.
398 RefPtr<KJS::Bindings::RootObject> root = script()->createRootObject(widget); 61 RefPtr<JSC::Bindings::RootObject> root = createRootObject(widget);
399 KJS::Bindings::Instance* instance = 62 RefPtr<JSC::Bindings::Instance> instance =
400 KJS::Bindings::Instance::createBindingForLanguageInstance( 63 JSC::Bindings::CInstance::create(npObject, root.release());
401 KJS::Bindings::Instance::CLanguage, npObject,
402 root.release());
403 // GetPluginScriptableObject returns a retained NPObject. 64 // GetPluginScriptableObject returns a retained NPObject.
404 // The caller is expected to release it. 65 // The caller is expected to release it.
405 NPN_ReleaseObject(npObject); 66 NPN_ReleaseObject(npObject);
406 return instance; 67 return instance.release();
407 #elif USE(V8)
408 // Frame Memory Management for NPObjects
409 // -------------------------------------
410 // NPObjects are treated differently than other objects wrapped by JS.
411 // NPObjects are not Peerable, and cannot be made peerable, since NPObjects
412 // can be created either by the browser (e.g. the main window object) or by
413 // the plugin (the main plugin object for a HTMLEmbedElement). Further,
414 // unlike most DOM Objects, the frame is especially careful to ensure
415 // NPObjects terminate at frame teardown because if a plugin leaks a
416 // reference, it could leak its objects (or the browser's objects).
417 //
418 // The Frame maintains a list of plugin objects (m_pluginObjects)
419 // which it can use to quickly find the wrapped embed object.
420 //
421 // Inside the NPRuntime, we've added a few methods for registering
422 // wrapped NPObjects. The purpose of the registration is because
423 // javascript garbage collection is non-deterministic, yet we need to
424 // be able to tear down the plugin objects immediately. When an object
425 // is registered, javascript can use it. When the object is destroyed,
426 // or when the object's "owning" object is destroyed, the object will
427 // be un-registered, and the javascript engine must not use it.
428 //
429 // Inside the javascript engine, the engine can keep a reference to the
430 // NPObject as part of its wrapper. However, before accessing the object
431 // it must consult the NPN_Registry.
432
433 v8::Local<v8::Object> wrapper = CreateV8ObjectForNPObject(npObject, NULL);
434
435 // Track the plugin object. We've been given a reference to the object.
436 m_pluginObjects.set(widget, npObject);
437
438 JSInstance instance = wrapper;
439 return instance;
440 #endif
441 }
442
443 void ScriptController::cleanupScriptObjectsForPlugin(void* nativeHandle)
444 {
445 PluginObjectMap::iterator it = m_pluginObjects.find(nativeHandle);
446 if (it == m_pluginObjects.end())
447 return;
448 _NPN_UnregisterObject(it->second);
449 NPN_ReleaseObject(it->second);
450 m_pluginObjects.remove(it);
451 }
452
453 static NPObject* createNoScriptObject()
454 {
455 notImplemented();
456 return 0;
457 }
458
459 static NPObject* createScriptObject(Frame* frame)
460 {
461 v8::HandleScope handleScope;
462 v8::Handle<v8::Context> context = V8Proxy::GetContext(frame);
463 if (context.IsEmpty())
464 return createNoScriptObject();
465
466 v8::Context::Scope scope(context);
467 DOMWindow* window = frame->domWindow();
468 v8::Handle<v8::Value> global = V8Proxy::ToV8Object(V8ClassIndex::DOMWINDOW, window);
469 ASSERT(global->IsObject());
470 return NPN_CreateScriptObject(0, v8::Handle<v8::Object>::Cast(global), windo w);
471 }
472
473 NPObject* ScriptController::windowScriptNPObject()
474 {
475 if (m_windowScriptNPObject)
476 return m_windowScriptNPObject;
477
478 if (isEnabled()) {
479 // JavaScript is enabled, so there is a JavaScript window object.
480 // Return an NPObject bound to the window object.
481 m_windowScriptNPObject = createScriptObject(m_frame);
482 _NPN_RegisterObject(m_windowScriptNPObject, NULL);
483 } else {
484 // JavaScript is not enabled, so we cannot bind the NPObject to the
485 // JavaScript window object. Instead, we create an NPObject of a
486 // different class, one which is not bound to a JavaScript object.
487 m_windowScriptNPObject = createNoScriptObject();
488 }
489 return m_windowScriptNPObject;
490 }
491
492 NPObject* ScriptController::createScriptObjectForPluginElement(HTMLPlugInElement * plugin)
493 {
494 // Can't create NPObjects when JavaScript is disabled
495 if (!isEnabled())
496 return createNoScriptObject();
497
498 v8::HandleScope handleScope;
499 v8::Handle<v8::Context> context = V8Proxy::GetContext(m_frame);
500 if (context.IsEmpty())
501 return createNoScriptObject();
502 v8::Context::Scope scope(context);
503
504 DOMWindow* window = m_frame->domWindow();
505 v8::Handle<v8::Value> v8plugin = V8Proxy::ToV8Object(V8ClassIndex::HTMLEMBED ELEMENT, plugin);
506 if (!v8plugin->IsObject())
507 return createNoScriptObject();
508
509 return NPN_CreateScriptObject(0, v8::Handle<v8::Object>::Cast(v8plugin), win dow);
510 }
511
512
513 void ScriptController::clearWindowShell()
514 {
515 m_proxy->clearForNavigation();
516 }
517
518 void ScriptController::attachDebugger(void*)
519 {
520 notImplemented();
521 }
522
523 void ScriptController::updateDocument()
524 {
525 // TODO(eseidel): Should update document property on current window object
526 // and all previous window objects which may still be alive.
527 notImplemented();
528 }
529
530
531 JSInstanceHolder::JSInstanceHolder()
532 {
533 }
534
535 JSInstanceHolder::JSInstanceHolder(JSInstanceHandle instance)
536 {
537 *this = instance;
538 }
539
540 JSInstanceHolder::~JSInstanceHolder()
541 {
542 Clear();
543 }
544
545 bool JSInstanceHolder::IsEmpty()
546 {
547 return m_instance.IsEmpty();
548 }
549
550 JSInstance JSInstanceHolder::Get()
551 {
552 return v8::Local<v8::Object>::New(m_instance);
553 }
554
555 void JSInstanceHolder::Clear()
556 {
557 if (m_instance.IsEmpty())
558 return;
559 v8::HandleScope scope;
560 v8::Persistent<v8::Object> handle(m_instance);
561 #ifndef NDEBUG
562 V8Proxy::UnregisterGlobalHandle(this, handle);
563 #endif
564 handle.Dispose();
565 m_instance.Clear();
566 }
567
568 JSInstance JSInstanceHolder::EmptyInstance()
569 {
570 return v8::Local<v8::Object>();
571 }
572
573 JSInstanceHolder& JSInstanceHolder::operator=(JSInstanceHandle instance)
574 {
575 Clear();
576 if (instance.IsEmpty())
577 return *this;
578
579 v8::Persistent<v8::Object> handle =
580 v8::Persistent<v8::Object>::New(instance);
581 m_instance = handle;
582 #ifndef NDEBUG
583 V8Proxy::RegisterGlobalHandle(JSINSTANCE, this, handle);
584 #endif
585 return *this;
586 } 68 }
587 69
588 } // namespace WebCpre 70 } // namespace WebCpre
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698