Chromium Code Reviews| Index: third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.cpp |
| diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..5e94cd255f4dccb177ff9251148379cb98a3679d |
| --- /dev/null |
| +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.cpp |
| @@ -0,0 +1,145 @@ |
| +// 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/ScriptCustomElementDefinition.h" |
| + |
| +#include "bindings/core/v8/ScriptState.h" |
| +#include "bindings/core/v8/V8CustomElementsRegistry.h" |
| +#include "bindings/core/v8/V8HiddenValue.h" |
| +#include "bindings/core/v8/V8PerContextData.h" |
| +#include "core/frame/LocalDOMWindow.h" |
| +#include "v8.h" |
| +#include "wtf/Allocator.h" |
| +#include "wtf/Noncopyable.h" |
| + |
| +namespace blink { |
| + |
| +// Custom elements stores state off the registry's wrapper. To avoid leaking |
| +// contexts, that state should be manipulated in the registry's wrapper |
| +// context. This helper retrieves the wrapper and enters its context. |
| +class RegistryScriptStateScope { |
| + STACK_ALLOCATED(); |
| + WTF_MAKE_NONCOPYABLE(RegistryScriptStateScope); |
| +public: |
| + RegistryScriptStateScope( |
| + ScriptState* current, |
| + CustomElementsRegistry* registry) |
| + : m_registry(toV8(registry, current).As<v8::Object>()) |
| + , m_scriptState(ScriptState::from(m_registry->CreationContext())) |
|
Yuki
2016/05/26 07:48:40
What script state are you expecting here? It's th
dominicc (has gone to gerrit)
2016/05/27 04:54:17
OK, added some examples.
|
| + , m_scope(m_scriptState) |
| + { |
| + CHECK(current->world().isMainWorld()); |
| + } |
| + |
| + ScriptState* scriptState() const { return m_scriptState; } |
| + ScriptState* operator->() const { return m_scriptState; } |
| + const v8::Local<v8::Object>& wrapper() const { return m_registry; } |
| + |
| +private: |
| + v8::Local<v8::Object> m_registry; |
| + ScriptState* m_scriptState; |
| + ScriptState::Scope m_scope; |
| +}; |
| + |
| +// Retrieves the custom elements constructor -> ID map, creating it if |
| +// necessary. The same map is used to keep prototypes alive. |
| +static v8::Local<v8::Map> ensureCustomElementsRegistryMap( |
| + RegistryScriptStateScope& scope) |
| +{ |
| + v8::Local<v8::String> name = V8HiddenValue::customElementsRegistryMap( |
| + scope->isolate()); |
| + v8::Local<v8::Value> map = V8HiddenValue::getHiddenValue( |
| + scope.scriptState(), |
| + scope.wrapper(), |
| + name); |
| + if (map.IsEmpty()) { |
| + map = v8::Map::New(scope->isolate()); |
| + V8HiddenValue::setHiddenValue( |
| + scope.scriptState(), |
| + scope.wrapper(), |
| + name, |
| + map); |
| + } |
| + return map.As<v8::Map>(); |
| +} |
| + |
| +ScriptCustomElementDefinition* ScriptCustomElementDefinition::forConstructor( |
| + ScriptState* scriptState, |
| + CustomElementsRegistry* registry, |
| + const v8::Local<v8::Value>& constructor) |
| +{ |
| + if (!scriptState->contextIsValid()) |
| + return nullptr; |
| + RegistryScriptStateScope scope(scriptState, registry); |
|
haraken
2016/05/26 08:33:46
Why do you need to enter ScriptState's scope here?
dominicc (has gone to gerrit)
2016/05/27 04:54:17
When the HTMLElement constructor uses forConstruct
|
| + v8::Local<v8::Map> map = ensureCustomElementsRegistryMap(scope); |
| + v8::Local<v8::Value> entry = v8CallOrCrash( |
| + map->Get(scope->context(), constructor)); |
| + if (!entry->IsUint32()) |
| + return nullptr; |
| + uint32_t id = v8CallOrCrash(entry->Uint32Value(scope->context())); |
| + if (V8PerContextData* perContextData = scope->perContextData()) |
| + return perContextData->customElements()->getDefinition(id); |
| + return nullptr; |
| +} |
| + |
| +ScriptCustomElementDefinition* ScriptCustomElementDefinition::create( |
| + ScriptState* scriptState, |
| + CustomElementsRegistry* registry, |
| + const CustomElementDescriptor& descriptor, |
| + const v8::Local<v8::Object>& constructor, |
| + const v8::Local<v8::Object>& prototype) |
| +{ |
| + ScriptCustomElementDefinition* def = new ScriptCustomElementDefinition( |
| + scriptState, |
| + descriptor, |
| + constructor, |
| + prototype); |
| + |
| + RegistryScriptStateScope scope(scriptState, registry); |
| + V8PerContextData* perContextData = scope->perContextData(); |
| + if (!perContextData) |
| + return nullptr; |
| + uint32_t id = perContextData->customElements()->addDefinition(def); |
| + |
| + // Add a constructor -> ID mapping to the registry. |
| + v8::Local<v8::Value> idValue = |
| + v8::Integer::NewFromUnsigned(scope->isolate(), id); |
| + v8::Local<v8::Map> map = ensureCustomElementsRegistryMap(scope); |
| + v8CallOrCrash(map->Set(scope->context(), constructor, idValue)); |
| + v8CallOrCrash(map->Set(scope->context(), idValue, prototype)); |
| + |
| + return def; |
| +} |
| + |
| +ScriptCustomElementDefinition::ScriptCustomElementDefinition( |
| + ScriptState* scriptState, |
| + const CustomElementDescriptor& descriptor, |
| + const v8::Local<v8::Object>& constructor, |
| + const v8::Local<v8::Object>& prototype) |
| + : CustomElementDefinition(descriptor) |
| + , m_constructor(scriptState->isolate(), constructor) |
| + , m_prototype(scriptState->isolate(), prototype) |
| +{ |
| + // These objects are kept alive by references from the |
| + // CustomElementsRegistry wrapper set up by |
| + // ScriptCustomElementDefinition::create. |
| + m_constructor.setPhantom(); |
| + m_prototype.setPhantom(); |
| +} |
| + |
| +v8::Local<v8::Object> ScriptCustomElementDefinition::constructor( |
| + ScriptState* scriptState) const |
| +{ |
| + DCHECK(!m_constructor.isEmpty()); |
| + return m_constructor.newLocal(scriptState->isolate()); |
| +} |
| + |
| +v8::Local<v8::Object> ScriptCustomElementDefinition::prototype( |
| + ScriptState* scriptState) const |
| +{ |
| + DCHECK(!m_prototype.isEmpty()); |
| + return m_prototype.newLocal(scriptState->isolate()); |
| +} |
| + |
| +} // namespace blink |