blob: 3a4d686dc4ef14b2ab0168d66e18eb396a6650ae [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "bindings/core/v8/ScriptCustomElementDefinitionBuilder.h"
#include "bindings/core/v8/DOMWrapperWorld.h"
#include "bindings/core/v8/ExceptionState.h"
#include "bindings/core/v8/ScriptCustomElementDefinition.h"
#include "bindings/core/v8/ScriptState.h"
#include "bindings/core/v8/ScriptValue.h"
#include "bindings/core/v8/V8Binding.h"
#include "bindings/core/v8/V8BindingMacros.h"
#include "core/dom/ExceptionCode.h"
namespace blink {
ScriptCustomElementDefinitionBuilder* ScriptCustomElementDefinitionBuilder
::s_stack = nullptr;
ScriptCustomElementDefinitionBuilder::ScriptCustomElementDefinitionBuilder(
ScriptState* scriptState,
CustomElementsRegistry* registry,
const ScriptValue& constructor,
ExceptionState& exceptionState)
: m_prev(s_stack)
, m_scriptState(scriptState)
, m_registry(registry)
, m_constructorValue(constructor.v8Value())
, m_exceptionState(exceptionState)
{
s_stack = this;
}
ScriptCustomElementDefinitionBuilder::~ScriptCustomElementDefinitionBuilder()
{
s_stack = m_prev;
}
bool ScriptCustomElementDefinitionBuilder::checkConstructorIntrinsics()
{
DCHECK(m_scriptState->world().isMainWorld());
// The signature of CustomElementsRegistry.define says this is a
// Function
// https://html.spec.whatwg.org/multipage/scripting.html#customelementsregistry
CHECK(m_constructorValue->IsFunction());
m_constructor = m_constructorValue.As<v8::Object>();
if (!m_constructor->IsConstructor()) {
m_exceptionState.throwTypeError(
"constructor argument is not a constructor");
return false;
}
return true;
}
bool ScriptCustomElementDefinitionBuilder::checkConstructorNotRegistered()
{
if (ScriptCustomElementDefinition::forConstructor(
m_scriptState.get(),
m_registry,
m_constructor)) {
// Constructor is already registered.
m_exceptionState.throwDOMException(
NotSupportedError,
"this constructor has already been used with this registry");
return false;
}
for (auto builder = m_prev; builder; builder = builder->m_prev) {
CHECK(!builder->m_constructor.IsEmpty());
if (m_registry != builder->m_registry
|| m_constructor != builder->m_constructor) {
continue;
}
m_exceptionState.throwDOMException(
NotSupportedError,
"this constructor is already being defined in this registry");
return false;
}
return true;
}
bool ScriptCustomElementDefinitionBuilder::checkPrototype()
{
v8::Isolate* isolate = m_scriptState->isolate();
v8::Local<v8::Context> context = m_scriptState->context();
v8::Local<v8::String> prototypeString =
v8AtomicString(isolate, "prototype");
v8::Local<v8::Value> prototypeValue;
if (!v8Call(
m_constructor->Get(context, prototypeString), prototypeValue)) {
return false;
}
if (!prototypeValue->IsObject()) {
m_exceptionState.throwTypeError(
"constructor prototype is not an object");
return false;
}
m_prototype = prototypeValue.As<v8::Object>();
// If retrieving the prototype destroyed the context, indicate that
// defining the element should not proceed.
return true;
}
CustomElementDefinition* ScriptCustomElementDefinitionBuilder::build(
const CustomElementDescriptor& descriptor)
{
return ScriptCustomElementDefinition::create(
m_scriptState.get(),
m_registry,
descriptor,
m_constructor,
m_prototype);
}
} // namespace blink