Merge from Chromium at DEPS revision r212014

This commit was generated by merge_to_master.py.

Change-Id: Ib07d03553a1e81485ac4ffc92b91e977c4875409
diff --git a/Source/bindings/v8/V8CustomElementLifecycleCallbacks.cpp b/Source/bindings/v8/V8CustomElementLifecycleCallbacks.cpp
new file mode 100644
index 0000000..baf8d90
--- /dev/null
+++ b/Source/bindings/v8/V8CustomElementLifecycleCallbacks.cpp
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2013 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 "config.h"
+#include "bindings/v8/V8CustomElementLifecycleCallbacks.h"
+
+#include "V8Element.h"
+#include "bindings/v8/DOMDataStore.h"
+#include "bindings/v8/ScriptController.h"
+#include "bindings/v8/V8Binding.h"
+#include "bindings/v8/V8HiddenPropertyName.h"
+#include "core/dom/ScriptExecutionContext.h"
+#include "wtf/PassRefPtr.h"
+
+namespace WebCore {
+
+#define CALLBACK_LIST(V)                  \
+    V(created, Created)                   \
+    V(enteredDocument, EnteredDocument)   \
+    V(leftDocument, LeftDocument)         \
+    V(attributeChanged, AttributeChanged)
+
+PassRefPtr<V8CustomElementLifecycleCallbacks> V8CustomElementLifecycleCallbacks::create(ScriptExecutionContext* scriptExecutionContext, v8::Handle<v8::Object> prototype, v8::Handle<v8::Function> created, v8::Handle<v8::Function> enteredDocument, v8::Handle<v8::Function> leftDocument, v8::Handle<v8::Function> attributeChanged)
+{
+    // A given object can only be used as a Custom Element prototype
+    // once; see customElementIsInterfacePrototypeObject
+#define SET_HIDDEN_PROPERTY(Value, Name) \
+    ASSERT(prototype->GetHiddenValue(V8HiddenPropertyName::customElement##Name()).IsEmpty()); \
+    if (!Value.IsEmpty()) \
+        prototype->SetHiddenValue(V8HiddenPropertyName::customElement##Name(), Value);
+
+    CALLBACK_LIST(SET_HIDDEN_PROPERTY)
+#undef SET_HIDDEN_PROPERTY
+
+    return adoptRef(new V8CustomElementLifecycleCallbacks(scriptExecutionContext, prototype, created, enteredDocument, leftDocument, attributeChanged));
+}
+
+static CustomElementLifecycleCallbacks::CallbackType flagSet(v8::Handle<v8::Function> enteredDocument, v8::Handle<v8::Function> leftDocument, v8::Handle<v8::Function> attributeChanged)
+{
+    // V8 Custom Elements always run created to swizzle prototypes.
+    int flags = CustomElementLifecycleCallbacks::Created;
+
+    if (!enteredDocument.IsEmpty())
+        flags |= CustomElementLifecycleCallbacks::EnteredDocument;
+
+    if (!leftDocument.IsEmpty())
+        flags |= CustomElementLifecycleCallbacks::LeftDocument;
+
+    if (!attributeChanged.IsEmpty())
+        flags |= CustomElementLifecycleCallbacks::AttributeChanged;
+
+    return CustomElementLifecycleCallbacks::CallbackType(flags);
+}
+
+template <typename T>
+static void weakCallback(v8::Isolate*, v8::Persistent<T>*, ScopedPersistent<T>* handle)
+{
+    handle->clear();
+}
+
+V8CustomElementLifecycleCallbacks::V8CustomElementLifecycleCallbacks(ScriptExecutionContext* scriptExecutionContext, v8::Handle<v8::Object> prototype, v8::Handle<v8::Function> created, v8::Handle<v8::Function> enteredDocument, v8::Handle<v8::Function> leftDocument, v8::Handle<v8::Function> attributeChanged)
+    : CustomElementLifecycleCallbacks(flagSet(enteredDocument, leftDocument, attributeChanged))
+    , ActiveDOMCallback(scriptExecutionContext)
+    , m_world(DOMWrapperWorld::current())
+    , m_prototype(prototype)
+    , m_created(created)
+    , m_enteredDocument(enteredDocument)
+    , m_leftDocument(leftDocument)
+    , m_attributeChanged(attributeChanged)
+{
+    m_prototype.makeWeak(&m_prototype, weakCallback<v8::Object>);
+
+#define MAKE_WEAK(Var, _) \
+    if (!m_##Var.isEmpty()) \
+        m_##Var.makeWeak(&m_##Var, weakCallback<v8::Function>);
+
+    CALLBACK_LIST(MAKE_WEAK)
+#undef MAKE_WEAK
+}
+
+void V8CustomElementLifecycleCallbacks::created(Element* element)
+{
+    if (!canInvokeCallback())
+        return;
+
+    element->setIsUpgradedCustomElement();
+
+    v8::HandleScope handleScope;
+    v8::Handle<v8::Context> context = toV8Context(scriptExecutionContext(), m_world.get());
+    if (context.IsEmpty())
+        return;
+
+    v8::Context::Scope scope(context);
+    v8::Isolate* isolate = context->GetIsolate();
+
+    v8::Handle<v8::Object> receiver = DOMDataStore::current(isolate)->get<V8Element>(element);
+    if (!receiver.IsEmpty()) {
+        // Swizzle the prototype of the existing wrapper. We don't need to
+        // worry about non-existent wrappers; they will get the right
+        // prototype when wrapped.
+        v8::Handle<v8::Object> prototype = m_prototype.newLocal(isolate);
+        if (prototype.IsEmpty())
+            return;
+        receiver->SetPrototype(prototype);
+    }
+
+    v8::Handle<v8::Function> callback = m_created.newLocal(isolate);
+    if (callback.IsEmpty())
+        return;
+
+    if (receiver.IsEmpty())
+        receiver = toV8(element, context->Global(), isolate).As<v8::Object>();
+
+    ASSERT(!receiver.IsEmpty());
+
+    v8::TryCatch exceptionCatcher;
+    exceptionCatcher.SetVerbose(true);
+    ScriptController::callFunctionWithInstrumentation(scriptExecutionContext(), callback, receiver, 0, 0);
+}
+
+void V8CustomElementLifecycleCallbacks::enteredDocument(Element* element)
+{
+    call(m_enteredDocument, element);
+}
+
+void V8CustomElementLifecycleCallbacks::leftDocument(Element* element)
+{
+    call(m_leftDocument, element);
+}
+
+void V8CustomElementLifecycleCallbacks::attributeChanged(Element* element, const AtomicString& name, const AtomicString& oldValue, const AtomicString& newValue)
+{
+    if (!canInvokeCallback())
+        return;
+
+    v8::HandleScope handleScope;
+    v8::Handle<v8::Context> context = toV8Context(scriptExecutionContext(), m_world.get());
+    if (context.IsEmpty())
+        return;
+
+    v8::Context::Scope scope(context);
+    v8::Isolate* isolate = context->GetIsolate();
+
+    v8::Handle<v8::Object> receiver = toV8(element, context->Global(), isolate).As<v8::Object>();
+    ASSERT(!receiver.IsEmpty());
+
+    v8::Handle<v8::Function> callback = m_attributeChanged.newLocal(isolate);
+    if (callback.IsEmpty())
+        return;
+
+    v8::Handle<v8::Value> argv[] = {
+        v8String(name, isolate),
+        oldValue.isNull() ? v8::Handle<v8::Value>(v8::Null()) : v8::Handle<v8::Value>(v8String(oldValue, isolate)),
+        newValue.isNull() ? v8::Handle<v8::Value>(v8::Null()) : v8::Handle<v8::Value>(v8String(newValue, isolate))
+    };
+
+    v8::TryCatch exceptionCatcher;
+    exceptionCatcher.SetVerbose(true);
+    ScriptController::callFunctionWithInstrumentation(scriptExecutionContext(), callback, receiver, WTF_ARRAY_LENGTH(argv), argv);
+}
+
+void V8CustomElementLifecycleCallbacks::call(const ScopedPersistent<v8::Function>& weakCallback, Element* element)
+{
+    if (!canInvokeCallback())
+        return;
+
+    v8::HandleScope handleScope;
+    v8::Handle<v8::Context> context = toV8Context(scriptExecutionContext(), m_world.get());
+    if (context.IsEmpty())
+        return;
+
+    v8::Context::Scope scope(context);
+    v8::Isolate* isolate = context->GetIsolate();
+
+    v8::Handle<v8::Function> callback = weakCallback.newLocal(isolate);
+    if (callback.IsEmpty())
+        return;
+
+    v8::Handle<v8::Object> receiver = toV8(element, context->Global(), isolate).As<v8::Object>();
+    ASSERT(!receiver.IsEmpty());
+
+    v8::TryCatch exceptionCatcher;
+    exceptionCatcher.SetVerbose(true);
+    ScriptController::callFunctionWithInstrumentation(scriptExecutionContext(), callback, receiver, 0, 0);
+}
+
+} // namespace WebCore