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 |