This source file includes following definitions.
- create
- flagSet
- weakCallback
- m_attributeChanged
- creationContextData
- setBinding
- created
- attached
- detached
- attributeChanged
- call
#include "config.h"
#include "bindings/v8/V8CustomElementLifecycleCallbacks.h"
#include "V8Element.h"
#include "bindings/v8/CustomElementBinding.h"
#include "bindings/v8/DOMDataStore.h"
#include "bindings/v8/ScriptController.h"
#include "bindings/v8/V8Binding.h"
#include "bindings/v8/V8HiddenValue.h"
#include "bindings/v8/V8PerContextData.h"
#include "core/dom/ExecutionContext.h"
#include "core/inspector/InspectorInstrumentation.h"
#include "wtf/PassOwnPtr.h"
namespace WebCore {
#define CALLBACK_LIST(V) \
V(created, Created) \
V(attached, Attached) \
V(detached, Detached) \
V(attributeChanged, AttributeChanged)
PassRefPtr<V8CustomElementLifecycleCallbacks> V8CustomElementLifecycleCallbacks::create(ExecutionContext* executionContext, v8::Handle<v8::Object> prototype, v8::Handle<v8::Function> created, v8::Handle<v8::Function> attached, v8::Handle<v8::Function> detached, v8::Handle<v8::Function> attributeChanged)
{
v8::Isolate* isolate = toIsolate(executionContext);
#define SET_HIDDEN_VALUE(Value, Name) \
ASSERT(V8HiddenValue::getHiddenValue(isolate, prototype, V8HiddenValue::customElement##Name(isolate)).IsEmpty()); \
if (!Value.IsEmpty()) \
V8HiddenValue::setHiddenValue(isolate, prototype, V8HiddenValue::customElement##Name(isolate), Value);
CALLBACK_LIST(SET_HIDDEN_VALUE)
#undef SET_HIDDEN_VALUE
return adoptRef(new V8CustomElementLifecycleCallbacks(executionContext, prototype, created, attached, detached, attributeChanged));
}
static CustomElementLifecycleCallbacks::CallbackType flagSet(v8::Handle<v8::Function> attached, v8::Handle<v8::Function> detached, v8::Handle<v8::Function> attributeChanged)
{
int flags = CustomElementLifecycleCallbacks::Created;
if (!attached.IsEmpty())
flags |= CustomElementLifecycleCallbacks::Attached;
if (!detached.IsEmpty())
flags |= CustomElementLifecycleCallbacks::Detached;
if (!attributeChanged.IsEmpty())
flags |= CustomElementLifecycleCallbacks::AttributeChanged;
return CustomElementLifecycleCallbacks::CallbackType(flags);
}
template <typename T>
static void weakCallback(const v8::WeakCallbackData<T, ScopedPersistent<T> >& data)
{
data.GetParameter()->clear();
}
V8CustomElementLifecycleCallbacks::V8CustomElementLifecycleCallbacks(ExecutionContext* executionContext, v8::Handle<v8::Object> prototype, v8::Handle<v8::Function> created, v8::Handle<v8::Function> attached, v8::Handle<v8::Function> detached, v8::Handle<v8::Function> attributeChanged)
: CustomElementLifecycleCallbacks(flagSet(attached, detached, attributeChanged))
, ContextLifecycleObserver(executionContext)
, m_owner(0)
, m_scriptState(NewScriptState::current(toIsolate(executionContext)))
, m_prototype(m_scriptState->isolate(), prototype)
, m_created(m_scriptState->isolate(), created)
, m_attached(m_scriptState->isolate(), attached)
, m_detached(m_scriptState->isolate(), detached)
, m_attributeChanged(m_scriptState->isolate(), attributeChanged)
{
m_prototype.setWeak(&m_prototype, weakCallback<v8::Object>);
#define MAKE_WEAK(Var, _) \
if (!m_##Var.isEmpty()) \
m_##Var.setWeak(&m_##Var, weakCallback<v8::Function>);
CALLBACK_LIST(MAKE_WEAK)
#undef MAKE_WEAK
}
V8PerContextData* V8CustomElementLifecycleCallbacks::creationContextData()
{
if (!executionContext())
return 0;
v8::Handle<v8::Context> context = m_scriptState->context();
if (context.IsEmpty())
return 0;
return V8PerContextData::from(context);
}
V8CustomElementLifecycleCallbacks::~V8CustomElementLifecycleCallbacks()
{
if (!m_owner)
return;
v8::HandleScope handleScope(m_scriptState->isolate());
if (V8PerContextData* perContextData = creationContextData())
perContextData->clearCustomElementBinding(m_owner);
}
bool V8CustomElementLifecycleCallbacks::setBinding(CustomElementDefinition* owner, PassOwnPtr<CustomElementBinding> binding)
{
ASSERT(!m_owner);
V8PerContextData* perContextData = creationContextData();
if (!perContextData)
return false;
m_owner = owner;
perContextData->addCustomElementBinding(owner, binding);
return true;
}
void V8CustomElementLifecycleCallbacks::created(Element* element)
{
if (!executionContext() || executionContext()->activeDOMObjectsAreStopped())
return;
element->setCustomElementState(Element::Upgraded);
v8::Isolate* isolate = m_scriptState->isolate();
v8::HandleScope handleScope(isolate);
v8::Handle<v8::Context> context = m_scriptState->context();
if (context.IsEmpty())
return;
v8::Context::Scope scope(context);
v8::Handle<v8::Object> receiver = DOMDataStore::current(isolate).get<V8Element>(element, isolate);
if (!receiver.IsEmpty()) {
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());
InspectorInstrumentation::willExecuteCustomElementCallback(element);
v8::TryCatch exceptionCatcher;
exceptionCatcher.SetVerbose(true);
ScriptController::callFunction(executionContext(), callback, receiver, 0, 0, isolate);
}
void V8CustomElementLifecycleCallbacks::attached(Element* element)
{
call(m_attached, element);
}
void V8CustomElementLifecycleCallbacks::detached(Element* element)
{
call(m_detached, element);
}
void V8CustomElementLifecycleCallbacks::attributeChanged(Element* element, const AtomicString& name, const AtomicString& oldValue, const AtomicString& newValue)
{
if (!executionContext() || executionContext()->activeDOMObjectsAreStopped())
return;
v8::Isolate* isolate = m_scriptState->isolate();
v8::HandleScope handleScope(isolate);
v8::Handle<v8::Context> context = m_scriptState->context();
if (context.IsEmpty())
return;
v8::Context::Scope scope(context);
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(isolate, name),
oldValue.isNull() ? v8::Handle<v8::Value>(v8::Null(isolate)) : v8::Handle<v8::Value>(v8String(isolate, oldValue)),
newValue.isNull() ? v8::Handle<v8::Value>(v8::Null(isolate)) : v8::Handle<v8::Value>(v8String(isolate, newValue))
};
InspectorInstrumentation::willExecuteCustomElementCallback(element);
v8::TryCatch exceptionCatcher;
exceptionCatcher.SetVerbose(true);
ScriptController::callFunction(executionContext(), callback, receiver, WTF_ARRAY_LENGTH(argv), argv, isolate);
}
void V8CustomElementLifecycleCallbacks::call(const ScopedPersistent<v8::Function>& weakCallback, Element* element)
{
if (!executionContext() || executionContext()->activeDOMObjectsAreStopped())
return;
v8::Isolate* isolate = m_scriptState->isolate();
v8::HandleScope handleScope(isolate);
v8::Handle<v8::Context> context = m_scriptState->context();
if (context.IsEmpty())
return;
v8::Context::Scope scope(context);
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());
InspectorInstrumentation::willExecuteCustomElementCallback(element);
v8::TryCatch exceptionCatcher;
exceptionCatcher.SetVerbose(true);
ScriptController::callFunction(executionContext(), callback, receiver, 0, 0, isolate);
}
}