blob: 8e590ffed403e0a0d16688c6ad4ffc217a2637da [file] [log] [blame]
/*
* Copyright (C) 2008, 2009, 2011 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "third_party/blink/renderer/bindings/core/v8/window_proxy.h"
#include <utility>
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_gc_for_context_dispose.h"
#include "third_party/blink/renderer/core/frame/dom_window.h"
#include "third_party/blink/renderer/core/frame/frame.h"
#include "third_party/blink/renderer/platform/bindings/v8_dom_wrapper.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
#include "v8/include/v8.h"
namespace blink {
WindowProxy::~WindowProxy() {
// clearForClose() or clearForNavigation() must be invoked before destruction
// starts.
DCHECK(lifecycle_ != Lifecycle::kContextIsInitialized);
}
void WindowProxy::Trace(Visitor* visitor) const {
visitor->Trace(frame_);
visitor->Trace(global_proxy_);
}
WindowProxy::WindowProxy(v8::Isolate* isolate,
Frame& frame,
scoped_refptr<DOMWrapperWorld> world)
: isolate_(isolate),
frame_(frame),
world_(std::move(world)),
lifecycle_(Lifecycle::kContextIsUninitialized) {}
void WindowProxy::ClearForClose() {
DisposeContext(lifecycle_ == Lifecycle::kV8MemoryIsForciblyPurged
? Lifecycle::kFrameIsDetachedAndV8MemoryIsPurged
: Lifecycle::kFrameIsDetached,
kFrameWillNotBeReused);
}
void WindowProxy::ClearForNavigation() {
DisposeContext(Lifecycle::kGlobalObjectIsDetached, kFrameWillBeReused);
}
void WindowProxy::ClearForSwap() {
DisposeContext(Lifecycle::kGlobalObjectIsDetached, kFrameWillNotBeReused);
}
void WindowProxy::ClearForV8MemoryPurge() {
DisposeContext(Lifecycle::kV8MemoryIsForciblyPurged, kFrameWillNotBeReused);
}
v8::Local<v8::Object> WindowProxy::GlobalProxyIfNotDetached() {
if (lifecycle_ == Lifecycle::kContextIsInitialized) {
DLOG_IF(FATAL, !is_global_object_attached_)
<< "Context is initialized but global object is detached!";
return global_proxy_.NewLocal(isolate_);
}
return v8::Local<v8::Object>();
}
v8::Local<v8::Object> WindowProxy::ReleaseGlobalProxy() {
DCHECK(lifecycle_ == Lifecycle::kContextIsUninitialized ||
lifecycle_ == Lifecycle::kGlobalObjectIsDetached);
// Make sure the global object was detached from the proxy by calling
// ClearForSwap().
DLOG_IF(FATAL, is_global_object_attached_)
<< "Context not detached by calling ClearForSwap()";
v8::Local<v8::Object> global_proxy = global_proxy_.NewLocal(isolate_);
global_proxy_.Clear();
return global_proxy;
}
void WindowProxy::SetGlobalProxy(v8::Local<v8::Object> global_proxy) {
DCHECK_EQ(lifecycle_, Lifecycle::kContextIsUninitialized);
CHECK(global_proxy_.IsEmpty());
global_proxy_.Set(isolate_, global_proxy);
// The global proxy was transferred from a previous WindowProxy, so the state
// should be detached, not uninitialized. This ensures that it will be
// properly reinitialized when needed, e.g. by `UpdateDocument()`.
lifecycle_ = Lifecycle::kGlobalObjectIsDetached;
}
// Create a new environment and setup the global object.
//
// The global object corresponds to a DOMWindow instance. However, to
// allow properties of the JS DOMWindow instance to be shadowed, we
// use a shadow object as the global object and use the JS DOMWindow
// instance as the prototype for that shadow object. The JS DOMWindow
// instance is undetectable from JavaScript code because the __proto__
// accessors skip that object.
//
// The shadow object and the DOMWindow instance are seen as one object
// from JavaScript. The JavaScript object that corresponds to a
// DOMWindow instance is the shadow object. When mapping a DOMWindow
// instance to a V8 object, we return the shadow object.
//
// To implement split-window, see
// 1) https://bugs.webkit.org/show_bug.cgi?id=17249
// 2) https://wiki.mozilla.org/Gecko:SplitWindow
// 3) https://bugzilla.mozilla.org/show_bug.cgi?id=296639
// we need to split the shadow object further into two objects:
// an outer window and an inner window. The inner window is the hidden
// prototype of the outer window. The inner window is the default
// global object of the context. A variable declared in the global
// scope is a property of the inner window.
//
// The outer window sticks to a LocalFrame, it is exposed to JavaScript
// via window.window, window.self, window.parent, etc. The outer window
// has a security token which is the domain. The outer window cannot
// have its own properties. window.foo = 'x' is delegated to the
// inner window.
//
// When a frame navigates to a new page, the inner window is cut off
// the outer window, and the outer window identify is preserved for
// the frame. However, a new inner window is created for the new page.
// If there are JS code holds a closure to the old inner window,
// it won't be able to reach the outer window via its global object.
void WindowProxy::InitializeIfNeeded() {
if (lifecycle_ == Lifecycle::kContextIsUninitialized ||
lifecycle_ == Lifecycle::kGlobalObjectIsDetached) {
Initialize();
}
}
} // namespace blink