Source/WebCore: https://bugs.webkit.org/show_bug.cgi?id=73054
[WebKit-https.git] / Source / WebCore / bindings / v8 / custom / V8DOMWindowCustom.cpp
1 /*
2  * Copyright (C) 2009, 2011 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
29  */
30
31 #include "config.h"
32 #include "V8DOMWindow.h"
33
34 #include "ArrayBuffer.h"
35 #include "Chrome.h"
36 #include "ContentSecurityPolicy.h"
37 #include "DOMTimer.h"
38 #include "DOMWindow.h"
39 #include "ExceptionCode.h"
40 #include "Frame.h"
41 #include "FrameLoadRequest.h"
42 #include "FrameView.h"
43 #include "HTMLCollection.h"
44 #include "HTMLDocument.h"
45 #include "MediaPlayer.h"
46 #include "MessagePort.h"
47 #include "Page.h"
48 #include "PlatformScreen.h"
49 #include "ScheduledAction.h"
50 #include "ScriptSourceCode.h"
51 #include "SerializedScriptValue.h"
52 #include "Settings.h"
53 #include "SharedWorkerRepository.h"
54 #include "Storage.h"
55 #include "V8Binding.h"
56 #include "V8BindingMacros.h"
57 #include "V8BindingState.h"
58 #include "V8EventListener.h"
59 #include "V8GCForContextDispose.h"
60 #include "V8HiddenPropertyName.h"
61 #include "V8HTMLCollection.h"
62 #include "V8Node.h"
63 #include "V8Proxy.h"
64 #include "V8Utilities.h"
65 #include "WindowFeatures.h"
66
67 namespace WebCore {
68
69 v8::Handle<v8::Value> WindowSetTimeoutImpl(const v8::Arguments& args, bool singleShot)
70 {
71     int argumentCount = args.Length();
72
73     if (argumentCount < 1)
74         return v8::Undefined();
75
76     DOMWindow* imp = V8DOMWindow::toNative(args.Holder());
77     ScriptExecutionContext* scriptContext = static_cast<ScriptExecutionContext*>(imp->document());
78
79     if (!scriptContext) {
80         V8Proxy::setDOMException(INVALID_ACCESS_ERR);
81         return v8::Undefined();
82     }
83
84     v8::Handle<v8::Value> function = args[0];
85     WTF::String functionString;
86     if (!function->IsFunction()) {
87         if (function->IsString())
88             functionString = toWebCoreString(function);
89         else {
90             v8::Handle<v8::Value> v8String = function->ToString();
91
92             // Bail out if string conversion failed.
93             if (v8String.IsEmpty())
94                 return v8::Undefined();
95
96             functionString = toWebCoreString(v8String);
97         }
98
99         // Don't allow setting timeouts to run empty functions!
100         // (Bug 1009597)
101         if (functionString.length() == 0)
102             return v8::Undefined();
103     }
104
105     int32_t timeout = 0;
106     if (argumentCount >= 2)
107         timeout = args[1]->Int32Value();
108
109     if (!V8BindingSecurity::canAccessFrame(V8BindingState::Only(), imp->frame(), true))
110         return v8::Undefined();
111
112     int id;
113     if (function->IsFunction()) {
114         int paramCount = argumentCount >= 2 ? argumentCount - 2 : 0;
115         v8::Local<v8::Value>* params = 0;
116         if (paramCount > 0) {
117             params = new v8::Local<v8::Value>[paramCount];
118             for (int i = 0; i < paramCount; i++)
119                 // parameters must be globalized
120                 params[i] = args[i+2];
121         }
122
123         // params is passed to action, and released in action's destructor
124         OwnPtr<ScheduledAction> action = adoptPtr(new ScheduledAction(V8Proxy::context(imp->frame()), v8::Handle<v8::Function>::Cast(function), paramCount, params));
125
126         // FIXME: We should use OwnArrayPtr for params.
127         delete[] params;
128
129         id = DOMTimer::install(scriptContext, action.release(), timeout, singleShot);
130     } else {
131         if (imp->document() && !imp->document()->contentSecurityPolicy()->allowEval())
132             return v8::Integer::New(0);
133         id = DOMTimer::install(scriptContext, adoptPtr(new ScheduledAction(V8Proxy::context(imp->frame()), functionString)), timeout, singleShot);
134     }
135
136     // Try to do the idle notification before the timeout expires to get better
137     // use of any idle time. Aim for the middle of the interval for simplicity.
138     if (timeout > 0) {
139         double maximumFireInterval = static_cast<double>(timeout) / 1000 / 2;
140         V8GCForContextDispose::instance().notifyIdleSooner(maximumFireInterval);
141     }
142
143     return v8::Integer::New(id);
144 }
145
146 v8::Handle<v8::Value> V8DOMWindow::eventAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
147 {
148     v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8DOMWindow::GetTemplate(), info.This());
149     if (holder.IsEmpty())
150         return v8::Undefined();
151
152     Frame* frame = V8DOMWindow::toNative(holder)->frame();
153     if (!V8BindingSecurity::canAccessFrame(V8BindingState::Only(), frame, true))
154         return v8::Undefined();
155
156     v8::Local<v8::Context> context = V8Proxy::context(frame);
157     if (context.IsEmpty())
158         return v8::Undefined();
159
160     v8::Handle<v8::String> eventSymbol = V8HiddenPropertyName::event();
161     v8::Handle<v8::Value> jsEvent = context->Global()->GetHiddenValue(eventSymbol);
162     if (jsEvent.IsEmpty())
163         return v8::Undefined();
164     return jsEvent;
165 }
166
167 void V8DOMWindow::eventAccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
168 {
169     v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8DOMWindow::GetTemplate(), info.This());
170     if (holder.IsEmpty())
171         return;
172
173     Frame* frame = V8DOMWindow::toNative(holder)->frame();
174     if (!V8BindingSecurity::canAccessFrame(V8BindingState::Only(), frame, true))
175         return;
176
177     v8::Local<v8::Context> context = V8Proxy::context(frame);
178     if (context.IsEmpty())
179         return;
180
181     v8::Handle<v8::String> eventSymbol = V8HiddenPropertyName::event();
182     context->Global()->SetHiddenValue(eventSymbol, value);
183 }
184
185 void V8DOMWindow::locationAccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
186 {
187     DOMWindow* imp = V8DOMWindow::toNative(info.Holder());
188     State<V8Binding>* state = V8BindingState::Only();
189
190     DOMWindow* activeWindow = state->activeWindow();
191     if (!activeWindow)
192       return;
193
194     DOMWindow* firstWindow = state->firstWindow();
195     if (!firstWindow)
196       return;
197
198     imp->setLocation(toWebCoreString(value), activeWindow, firstWindow);
199 }
200
201 void V8DOMWindow::openerAccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
202 {
203     DOMWindow* imp = V8DOMWindow::toNative(info.Holder());
204
205     if (!V8BindingSecurity::canAccessFrame(V8BindingState::Only(), imp->frame(), true))
206         return;
207
208     // Opener can be shadowed if it is in the same domain.
209     // Have a special handling of null value to behave
210     // like Firefox. See bug http://b/1224887 & http://b/791706.
211     if (value->IsNull()) {
212         // imp->frame() cannot be null,
213         // otherwise, SameOrigin check would have failed.
214         ASSERT(imp->frame());
215         imp->frame()->loader()->setOpener(0);
216     }
217
218     // Delete the accessor from this object.
219     info.Holder()->Delete(name);
220
221     // Put property on the front (this) object.
222     info.This()->Set(name, value);
223 }
224
225 v8::Handle<v8::Value> V8DOMWindow::addEventListenerCallback(const v8::Arguments& args)
226 {
227     INC_STATS("DOM.DOMWindow.addEventListener()");
228
229     String eventType = toWebCoreString(args[0]);
230     bool useCapture = args[2]->BooleanValue();
231
232     DOMWindow* imp = V8DOMWindow::toNative(args.Holder());
233
234     if (!V8BindingSecurity::canAccessFrame(V8BindingState::Only(), imp->frame(), true))
235         return v8::Undefined();
236
237     Document* doc = imp->document();
238
239     if (!doc)
240         return v8::Undefined();
241
242     // FIXME: Check if there is not enough arguments
243     V8Proxy* proxy = V8Proxy::retrieve(imp->frame());
244     if (!proxy)
245         return v8::Undefined();
246
247     RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(args[1], false, ListenerFindOrCreate);
248
249     if (listener) {
250         imp->addEventListener(eventType, listener, useCapture);
251         createHiddenDependency(args.Holder(), args[1], eventListenerCacheIndex);
252     }
253
254     return v8::Undefined();
255 }
256
257
258 v8::Handle<v8::Value> V8DOMWindow::removeEventListenerCallback(const v8::Arguments& args)
259 {
260     INC_STATS("DOM.DOMWindow.removeEventListener()");
261
262     String eventType = toWebCoreString(args[0]);
263     bool useCapture = args[2]->BooleanValue();
264
265     DOMWindow* imp = V8DOMWindow::toNative(args.Holder());
266
267     if (!V8BindingSecurity::canAccessFrame(V8BindingState::Only(), imp->frame(), true))
268         return v8::Undefined();
269
270     Document* doc = imp->document();
271
272     if (!doc)
273         return v8::Undefined();
274
275     V8Proxy* proxy = V8Proxy::retrieve(imp->frame());
276     if (!proxy)
277         return v8::Undefined();
278
279     RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(args[1], false, ListenerFindOnly);
280
281     if (listener) {
282         imp->removeEventListener(eventType, listener.get(), useCapture);
283         removeHiddenDependency(args.Holder(), args[1], eventListenerCacheIndex);
284     }
285
286     return v8::Undefined();
287 }
288
289 static v8::Handle<v8::Value> handlePostMessageCallback(const v8::Arguments& args, bool doTransfer)
290 {
291     DOMWindow* window = V8DOMWindow::toNative(args.Holder());
292
293     DOMWindow* source = V8Proxy::retrieveFrameForCallingContext()->domWindow();
294     ASSERT(source->frame());
295
296     // This function has variable arguments and can either be:
297     //   postMessage(message, port, targetOrigin);
298     // or
299     //   postMessage(message, targetOrigin);
300     MessagePortArray portArray;
301     ArrayBufferArray arrayBufferArray;
302     String targetOrigin;
303     {
304         v8::TryCatch tryCatch;
305         if (args.Length() > 2) {
306             if (!extractTransferables(args[1], portArray, arrayBufferArray))
307                 return v8::Undefined();
308             targetOrigin = toWebCoreStringWithNullOrUndefinedCheck(args[2]);
309         } else
310             targetOrigin = toWebCoreStringWithNullOrUndefinedCheck(args[1]);
311
312         if (tryCatch.HasCaught())
313             return v8::Undefined();
314     }
315
316
317     bool didThrow = false;
318     RefPtr<SerializedScriptValue> message =
319         SerializedScriptValue::create(args[0],
320                                       doTransfer ? &portArray : 0,
321                                       doTransfer ? &arrayBufferArray : 0,
322                                       didThrow);
323     if (didThrow)
324         return v8::Undefined();
325
326     ExceptionCode ec = 0;
327     window->postMessage(message.release(), &portArray, targetOrigin, source, ec);
328     return throwError(ec);
329 }
330
331 v8::Handle<v8::Value> V8DOMWindow::postMessageCallback(const v8::Arguments& args)
332 {
333     INC_STATS("DOM.DOMWindow.postMessage()");
334     return handlePostMessageCallback(args, false);
335 }
336
337 v8::Handle<v8::Value> V8DOMWindow::webkitPostMessageCallback(const v8::Arguments& args)
338 {
339     INC_STATS("DOM.DOMWindow.webkitPostMessage()");
340     return handlePostMessageCallback(args, true);
341 }
342
343 // FIXME(fqian): returning string is cheating, and we should
344 // fix this by calling toString function on the receiver.
345 // However, V8 implements toString in JavaScript, which requires
346 // switching context of receiver. I consider it is dangerous.
347 v8::Handle<v8::Value> V8DOMWindow::toStringCallback(const v8::Arguments& args)
348 {
349     INC_STATS("DOM.DOMWindow.toString()");
350     v8::Handle<v8::Object> domWrapper = V8DOMWrapper::lookupDOMWrapper(V8DOMWindow::GetTemplate(), args.This());
351     if (domWrapper.IsEmpty())
352         return args.This()->ObjectProtoToString();
353     return domWrapper->ObjectProtoToString();
354 }
355
356 v8::Handle<v8::Value> V8DOMWindow::releaseEventsCallback(const v8::Arguments& args)
357 {
358     INC_STATS("DOM.DOMWindow.nop()");
359     return v8::Undefined();
360 }
361
362 v8::Handle<v8::Value> V8DOMWindow::captureEventsCallback(const v8::Arguments& args)
363 {
364     INC_STATS("DOM.DOMWindow.nop()");
365     return v8::Undefined();
366 }
367
368 class DialogHandler {
369 public:
370     explicit DialogHandler(v8::Handle<v8::Value> dialogArguments)
371         : m_dialogArguments(dialogArguments)
372     {
373     }
374
375     void dialogCreated(DOMWindow*);
376     v8::Handle<v8::Value> returnValue() const;
377
378 private:
379     v8::Handle<v8::Value> m_dialogArguments;
380     v8::Handle<v8::Context> m_dialogContext;
381 };
382
383 inline void DialogHandler::dialogCreated(DOMWindow* dialogFrame)
384 {
385     m_dialogContext = V8Proxy::context(dialogFrame->frame());
386     if (m_dialogContext.IsEmpty())
387         return;
388     if (m_dialogArguments.IsEmpty())
389         return;
390     v8::Context::Scope scope(m_dialogContext);
391     m_dialogContext->Global()->Set(v8::String::New("dialogArguments"), m_dialogArguments);
392 }
393
394 inline v8::Handle<v8::Value> DialogHandler::returnValue() const
395 {
396     if (m_dialogContext.IsEmpty())
397         return v8::Undefined();
398     v8::Context::Scope scope(m_dialogContext);
399     v8::Handle<v8::Value> returnValue = m_dialogContext->Global()->Get(v8::String::New("returnValue"));
400     if (returnValue.IsEmpty())
401         return v8::Undefined();
402     return returnValue;
403 }
404
405 static void setUpDialog(DOMWindow* dialog, void* handler)
406 {
407     static_cast<DialogHandler*>(handler)->dialogCreated(dialog);
408 }
409
410 v8::Handle<v8::Value> V8DOMWindow::showModalDialogCallback(const v8::Arguments& args)
411 {
412     INC_STATS("DOM.DOMWindow.showModalDialog()");
413     DOMWindow* impl = V8DOMWindow::toNative(args.Holder());
414
415     V8BindingState* state = V8BindingState::Only();
416
417     DOMWindow* activeWindow = state->activeWindow();
418     DOMWindow* firstWindow = state->firstWindow();
419
420     // FIXME: Handle exceptions properly.
421     String urlString = toWebCoreStringWithNullOrUndefinedCheck(args[0]);
422     String dialogFeaturesString = toWebCoreStringWithNullOrUndefinedCheck(args[2]);
423
424     DialogHandler handler(args[1]);
425
426     impl->showModalDialog(urlString, dialogFeaturesString, activeWindow, firstWindow, setUpDialog, &handler);
427
428     return handler.returnValue();
429 }
430
431 v8::Handle<v8::Value> V8DOMWindow::openCallback(const v8::Arguments& args)
432 {
433     INC_STATS("DOM.DOMWindow.open()");
434     DOMWindow* impl = V8DOMWindow::toNative(args.Holder());
435
436     V8BindingState* state = V8BindingState::Only();
437
438     DOMWindow* activeWindow = state->activeWindow();
439     DOMWindow* firstWindow = state->firstWindow();
440
441     // FIXME: Handle exceptions properly.
442     String urlString = toWebCoreStringWithNullOrUndefinedCheck(args[0]);
443     AtomicString frameName = (args[1]->IsUndefined() || args[1]->IsNull()) ? "_blank" : AtomicString(toWebCoreString(args[1]));
444     String windowFeaturesString = toWebCoreStringWithNullOrUndefinedCheck(args[2]);
445
446     RefPtr<DOMWindow> openedWindow = impl->open(urlString, frameName, windowFeaturesString, activeWindow, firstWindow);
447     if (!openedWindow)
448         return v8::Undefined();
449     return toV8(openedWindow.release());
450 }
451
452 v8::Handle<v8::Value> V8DOMWindow::indexedPropertyGetter(uint32_t index, const v8::AccessorInfo& info)
453 {
454     INC_STATS("DOM.DOMWindow.IndexedPropertyGetter");
455
456     DOMWindow* window = V8DOMWindow::toNative(info.Holder());
457     if (!window)
458         return notHandledByInterceptor();
459
460     Frame* frame = window->frame();
461     if (!frame)
462         return notHandledByInterceptor();
463
464     Frame* child = frame->tree()->child(index);
465     if (child)
466         return toV8(child->domWindow());
467
468     return notHandledByInterceptor();
469 }
470
471
472 v8::Handle<v8::Value> V8DOMWindow::namedPropertyGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
473 {
474     INC_STATS("DOM.DOMWindow.NamedPropertyGetter");
475
476     DOMWindow* window = V8DOMWindow::toNative(info.Holder());
477     if (!window)
478         return notHandledByInterceptor();
479
480     Frame* frame = window->frame();
481     // window is detached from a frame.
482     if (!frame)
483         return notHandledByInterceptor();
484
485     // Search sub-frames.
486     AtomicString propName = v8StringToAtomicWebCoreString(name);
487     Frame* child = frame->tree()->child(propName);
488     if (child)
489         return toV8(child->domWindow());
490
491     // Search IDL functions defined in the prototype
492     if (!info.Holder()->GetRealNamedProperty(name).IsEmpty())
493         return notHandledByInterceptor();
494
495     // Search named items in the document.
496     Document* doc = frame->document();
497
498     if (doc && doc->isHTMLDocument()) {
499         if (static_cast<HTMLDocument*>(doc)->hasNamedItem(propName.impl()) || doc->hasElementWithId(propName.impl())) {
500             RefPtr<HTMLCollection> items = doc->windowNamedItems(propName);
501             if (items->length() >= 1) {
502                 if (items->length() == 1)
503                     return toV8(items->firstItem());
504                 return toV8(items.release());
505             }
506         }
507     }
508
509     return notHandledByInterceptor();
510 }
511
512
513 v8::Handle<v8::Value> V8DOMWindow::setTimeoutCallback(const v8::Arguments& args)
514 {
515     INC_STATS("DOM.DOMWindow.setTimeout()");
516     return WindowSetTimeoutImpl(args, true);
517 }
518
519
520 v8::Handle<v8::Value> V8DOMWindow::setIntervalCallback(const v8::Arguments& args)
521 {
522     INC_STATS("DOM.DOMWindow.setInterval()");
523     return WindowSetTimeoutImpl(args, false);
524 }
525
526 bool V8DOMWindow::namedSecurityCheck(v8::Local<v8::Object> host, v8::Local<v8::Value> key, v8::AccessType type, v8::Local<v8::Value>)
527 {
528     v8::Handle<v8::Object> window = V8DOMWrapper::lookupDOMWrapper(V8DOMWindow::GetTemplate(), host);
529     if (window.IsEmpty())
530         return false;  // the frame is gone.
531
532     DOMWindow* targetWindow = V8DOMWindow::toNative(window);
533
534     ASSERT(targetWindow);
535
536     Frame* target = targetWindow->frame();
537     if (!target)
538         return false;
539
540     if (key->IsString()) {
541         DEFINE_STATIC_LOCAL(AtomicString, nameOfProtoProperty, ("__proto__"));
542
543         String name = toWebCoreString(key);
544         // Notice that we can't call HasRealNamedProperty for ACCESS_HAS
545         // because that would generate infinite recursion.
546         if (type == v8::ACCESS_HAS && target->tree()->child(name))
547             return true;
548         // We need to explicitly compare against nameOfProtoProperty because
549         // V8's JSObject::LocalLookup finds __proto__ before
550         // interceptors and even when __proto__ isn't a "real named property".
551         if (type == v8::ACCESS_GET && target->tree()->child(name) && !host->HasRealNamedProperty(key->ToString()) && name != nameOfProtoProperty)
552             return true;
553     }
554
555     return V8BindingSecurity::canAccessFrame(V8BindingState::Only(), target, false);
556 }
557
558 bool V8DOMWindow::indexedSecurityCheck(v8::Local<v8::Object> host, uint32_t index, v8::AccessType type, v8::Local<v8::Value>)
559 {
560     v8::Handle<v8::Object> window = V8DOMWrapper::lookupDOMWrapper(V8DOMWindow::GetTemplate(), host);
561     if (window.IsEmpty())
562         return false;
563
564     DOMWindow* targetWindow = V8DOMWindow::toNative(window);
565
566     ASSERT(targetWindow);
567
568     Frame* target = targetWindow->frame();
569     if (!target)
570         return false;
571
572     // Notice that we can't call HasRealNamedProperty for ACCESS_HAS
573     // because that would generate infinite recursion.
574     if (type == v8::ACCESS_HAS && target->tree()->child(index))
575         return true;
576     if (type == v8::ACCESS_GET && target->tree()->child(index) && !host->HasRealIndexedProperty(index))
577         return true;
578
579     return V8BindingSecurity::canAccessFrame(V8BindingState::Only(), target, false);
580 }
581
582 v8::Handle<v8::Value> toV8(DOMWindow* window)
583 {
584     if (!window)
585         return v8::Null();
586     // Initializes environment of a frame, and return the global object
587     // of the frame.
588     Frame* frame = window->frame();
589     if (!frame)
590         return v8::Handle<v8::Object>();
591
592     // Special case: Because of evaluateInIsolatedWorld() one DOMWindow can have
593     // multiple contexts and multiple global objects associated with it. When
594     // code running in one of those contexts accesses the window object, we
595     // want to return the global object associated with that context, not
596     // necessarily the first global object associated with that DOMWindow.
597     v8::Handle<v8::Context> currentContext = v8::Context::GetCurrent();
598     v8::Handle<v8::Object> currentGlobal = currentContext->Global();
599     v8::Handle<v8::Object> windowWrapper = V8DOMWrapper::lookupDOMWrapper(V8DOMWindow::GetTemplate(), currentGlobal);
600     if (!windowWrapper.IsEmpty()) {
601         if (V8DOMWindow::toNative(windowWrapper) == window)
602             return currentGlobal;
603     }
604
605     // Otherwise, return the global object associated with this frame.
606     v8::Handle<v8::Context> context = V8Proxy::context(frame);
607     if (context.IsEmpty())
608         return v8::Handle<v8::Object>();
609
610     v8::Handle<v8::Object> global = context->Global();
611     ASSERT(!global.IsEmpty());
612     return global;
613 }
614
615 } // namespace WebCore