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