/*
 * 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/remote_window_proxy.h"

#include <algorithm>
#include <utility>

#include "third_party/blink/renderer/bindings/core/v8/v8_window.h"
#include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
#include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
#include "third_party/blink/renderer/platform/bindings/v8_dom_wrapper.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
#include "v8/include/v8.h"

namespace blink {

RemoteWindowProxy::RemoteWindowProxy(v8::Isolate* isolate,
                                     RemoteFrame& frame,
                                     scoped_refptr<DOMWrapperWorld> world)
    : WindowProxy(isolate, frame, std::move(world)) {}

void RemoteWindowProxy::DisposeContext(Lifecycle next_status,
                                       FrameReuseStatus) {
  DCHECK(next_status == Lifecycle::kV8MemoryIsForciblyPurged ||
         next_status == Lifecycle::kGlobalObjectIsDetached ||
         next_status == Lifecycle::kFrameIsDetached ||
         next_status == Lifecycle::kFrameIsDetachedAndV8MemoryIsPurged);

  // If the current lifecycle is kV8MemoryIsForciblyPurged, next status should
  // be either kFrameIsDetachedAndV8MemoryIsPurged, or kGlobalObjectIsDetached.
  // If the former, |global_proxy_| should become weak, and if the latter, the
  // necessary operations are already done so can return here.
  if (lifecycle_ == Lifecycle::kV8MemoryIsForciblyPurged) {
    DCHECK(next_status == Lifecycle::kGlobalObjectIsDetached ||
           next_status == Lifecycle::kFrameIsDetachedAndV8MemoryIsPurged);
    lifecycle_ = next_status;
    return;
  }

  if (lifecycle_ != Lifecycle::kContextIsInitialized)
    return;

  if ((next_status == Lifecycle::kV8MemoryIsForciblyPurged ||
       next_status == Lifecycle::kGlobalObjectIsDetached) &&
      !global_proxy_.IsEmpty()) {
    v8::HandleScope handle_scope(GetIsolate());
    global_proxy_.Get().SetWrapperClassId(0);
    V8DOMWrapper::ClearNativeInfo(GetIsolate(),
                                  global_proxy_.NewLocal(GetIsolate()));
#if DCHECK_IS_ON()
    DidDetachGlobalObject();
#endif
  }

  DCHECK_EQ(lifecycle_, Lifecycle::kContextIsInitialized);
  lifecycle_ = next_status;
}

void RemoteWindowProxy::Initialize() {
  TRACE_EVENT1("v8", "RemoteWindowProxy::initialize", "isMainWindow",
               GetFrame()->IsMainFrame());
  ScriptForbiddenScope::AllowUserAgentScript allow_script;

  v8::HandleScope handle_scope(GetIsolate());
  CreateContext();
  SetupWindowPrototypeChain();
}

void RemoteWindowProxy::CreateContext() {
  // Create a new v8::Context with the window object as the global object
  // (aka the inner global). Reuse the outer global proxy if it already exists.
  v8::Local<v8::ObjectTemplate> global_template =
      V8Window::GetWrapperTypeInfo()
          ->GetV8ClassTemplate(GetIsolate(), *world_)
          .As<v8::FunctionTemplate>()
          ->InstanceTemplate();
  CHECK(!global_template.IsEmpty());

  v8::Local<v8::Object> global_proxy =
      v8::Context::NewRemoteContext(GetIsolate(), global_template,
                                    global_proxy_.NewLocal(GetIsolate()))
          .ToLocalChecked();
  if (global_proxy_.IsEmpty())
    global_proxy_.Set(GetIsolate(), global_proxy);
  else
    DCHECK(global_proxy_.Get() == global_proxy);
  CHECK(!global_proxy_.IsEmpty());

#if DCHECK_IS_ON()
  DidAttachGlobalObject();
#endif

  DCHECK(lifecycle_ == Lifecycle::kContextIsUninitialized ||
         lifecycle_ == Lifecycle::kGlobalObjectIsDetached);
  lifecycle_ = Lifecycle::kContextIsInitialized;
}

void RemoteWindowProxy::SetupWindowPrototypeChain() {
  // Associate the window wrapper object and its prototype chain with the
  // corresponding native DOMWindow object.
  DOMWindow* window = GetFrame()->DomWindow();
  const WrapperTypeInfo* wrapper_type_info = window->GetWrapperTypeInfo();

  // The global proxy object.  Note this is not the global object.
  v8::Local<v8::Object> global_proxy = global_proxy_.NewLocal(GetIsolate());
  V8DOMWrapper::SetNativeInfo(GetIsolate(), global_proxy, wrapper_type_info,
                              window);
  // Mark the handle to be traced by Oilpan, since the global proxy has a
  // reference to the DOMWindow.
  global_proxy_.Get().SetWrapperClassId(wrapper_type_info->wrapper_class_id);

  // The global object, aka window wrapper object.
  v8::Local<v8::Object> window_wrapper =
      global_proxy->GetPrototype().As<v8::Object>();
  V8DOMWrapper::SetNativeInfo(GetIsolate(), window_wrapper, wrapper_type_info,
                              window);
}

}  // namespace blink
