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