OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "bindings/core/v8/ScriptCustomElementDefinition.h" | |
6 | |
7 #include "bindings/core/v8/ScriptState.h" | |
8 #include "bindings/core/v8/V8CustomElementsRegistry.h" | |
9 #include "bindings/core/v8/V8HiddenValue.h" | |
10 #include "bindings/core/v8/V8PerContextData.h" | |
11 #include "core/frame/LocalDOMWindow.h" | |
12 #include "v8.h" | |
13 #include "wtf/Allocator.h" | |
14 #include "wtf/Noncopyable.h" | |
15 | |
16 namespace blink { | |
17 | |
18 // Custom elements stores state off the registry's wrapper. To avoid leaking | |
19 // contexts, that state should be manipulated in the registry's wrapper | |
20 // context. This helper retrieves the wrapper and enters its context. | |
21 class RegistryScriptStateScope { | |
22 STACK_ALLOCATED(); | |
23 WTF_MAKE_NONCOPYABLE(RegistryScriptStateScope); | |
24 public: | |
25 RegistryScriptStateScope( | |
26 ScriptState* current, | |
27 CustomElementsRegistry* registry) | |
28 : m_registry(toV8(registry, current).As<v8::Object>()) | |
29 , 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.
| |
30 , m_scope(m_scriptState) | |
31 { | |
32 CHECK(current->world().isMainWorld()); | |
33 } | |
34 | |
35 ScriptState* scriptState() const { return m_scriptState; } | |
36 ScriptState* operator->() const { return m_scriptState; } | |
37 const v8::Local<v8::Object>& wrapper() const { return m_registry; } | |
38 | |
39 private: | |
40 v8::Local<v8::Object> m_registry; | |
41 ScriptState* m_scriptState; | |
42 ScriptState::Scope m_scope; | |
43 }; | |
44 | |
45 // Retrieves the custom elements constructor -> ID map, creating it if | |
46 // necessary. The same map is used to keep prototypes alive. | |
47 static v8::Local<v8::Map> ensureCustomElementsRegistryMap( | |
48 RegistryScriptStateScope& scope) | |
49 { | |
50 v8::Local<v8::String> name = V8HiddenValue::customElementsRegistryMap( | |
51 scope->isolate()); | |
52 v8::Local<v8::Value> map = V8HiddenValue::getHiddenValue( | |
53 scope.scriptState(), | |
54 scope.wrapper(), | |
55 name); | |
56 if (map.IsEmpty()) { | |
57 map = v8::Map::New(scope->isolate()); | |
58 V8HiddenValue::setHiddenValue( | |
59 scope.scriptState(), | |
60 scope.wrapper(), | |
61 name, | |
62 map); | |
63 } | |
64 return map.As<v8::Map>(); | |
65 } | |
66 | |
67 ScriptCustomElementDefinition* ScriptCustomElementDefinition::forConstructor( | |
68 ScriptState* scriptState, | |
69 CustomElementsRegistry* registry, | |
70 const v8::Local<v8::Value>& constructor) | |
71 { | |
72 if (!scriptState->contextIsValid()) | |
73 return nullptr; | |
74 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
| |
75 v8::Local<v8::Map> map = ensureCustomElementsRegistryMap(scope); | |
76 v8::Local<v8::Value> entry = v8CallOrCrash( | |
77 map->Get(scope->context(), constructor)); | |
78 if (!entry->IsUint32()) | |
79 return nullptr; | |
80 uint32_t id = v8CallOrCrash(entry->Uint32Value(scope->context())); | |
81 if (V8PerContextData* perContextData = scope->perContextData()) | |
82 return perContextData->customElements()->getDefinition(id); | |
83 return nullptr; | |
84 } | |
85 | |
86 ScriptCustomElementDefinition* ScriptCustomElementDefinition::create( | |
87 ScriptState* scriptState, | |
88 CustomElementsRegistry* registry, | |
89 const CustomElementDescriptor& descriptor, | |
90 const v8::Local<v8::Object>& constructor, | |
91 const v8::Local<v8::Object>& prototype) | |
92 { | |
93 ScriptCustomElementDefinition* def = new ScriptCustomElementDefinition( | |
94 scriptState, | |
95 descriptor, | |
96 constructor, | |
97 prototype); | |
98 | |
99 RegistryScriptStateScope scope(scriptState, registry); | |
100 V8PerContextData* perContextData = scope->perContextData(); | |
101 if (!perContextData) | |
102 return nullptr; | |
103 uint32_t id = perContextData->customElements()->addDefinition(def); | |
104 | |
105 // Add a constructor -> ID mapping to the registry. | |
106 v8::Local<v8::Value> idValue = | |
107 v8::Integer::NewFromUnsigned(scope->isolate(), id); | |
108 v8::Local<v8::Map> map = ensureCustomElementsRegistryMap(scope); | |
109 v8CallOrCrash(map->Set(scope->context(), constructor, idValue)); | |
110 v8CallOrCrash(map->Set(scope->context(), idValue, prototype)); | |
111 | |
112 return def; | |
113 } | |
114 | |
115 ScriptCustomElementDefinition::ScriptCustomElementDefinition( | |
116 ScriptState* scriptState, | |
117 const CustomElementDescriptor& descriptor, | |
118 const v8::Local<v8::Object>& constructor, | |
119 const v8::Local<v8::Object>& prototype) | |
120 : CustomElementDefinition(descriptor) | |
121 , m_constructor(scriptState->isolate(), constructor) | |
122 , m_prototype(scriptState->isolate(), prototype) | |
123 { | |
124 // These objects are kept alive by references from the | |
125 // CustomElementsRegistry wrapper set up by | |
126 // ScriptCustomElementDefinition::create. | |
127 m_constructor.setPhantom(); | |
128 m_prototype.setPhantom(); | |
129 } | |
130 | |
131 v8::Local<v8::Object> ScriptCustomElementDefinition::constructor( | |
132 ScriptState* scriptState) const | |
133 { | |
134 DCHECK(!m_constructor.isEmpty()); | |
135 return m_constructor.newLocal(scriptState->isolate()); | |
136 } | |
137 | |
138 v8::Local<v8::Object> ScriptCustomElementDefinition::prototype( | |
139 ScriptState* scriptState) const | |
140 { | |
141 DCHECK(!m_prototype.isEmpty()); | |
142 return m_prototype.newLocal(scriptState->isolate()); | |
143 } | |
144 | |
145 } // namespace blink | |
OLD | NEW |