OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "bindings/core/v8/ScriptCustomElementDefinition.h" | 5 #include "bindings/core/v8/ScriptCustomElementDefinition.h" |
6 | 6 |
7 #include "bindings/core/v8/ScriptState.h" | 7 #include "bindings/core/v8/ScriptState.h" |
8 #include "bindings/core/v8/V8Binding.h" | 8 #include "bindings/core/v8/V8Binding.h" |
9 #include "bindings/core/v8/V8BindingMacros.h" | 9 #include "bindings/core/v8/V8BindingMacros.h" |
10 #include "bindings/core/v8/V8CustomElementsRegistry.h" | 10 #include "bindings/core/v8/V8CustomElementRegistry.h" |
11 #include "bindings/core/v8/V8Element.h" | 11 #include "bindings/core/v8/V8Element.h" |
12 #include "bindings/core/v8/V8ErrorHandler.h" | 12 #include "bindings/core/v8/V8ErrorHandler.h" |
13 #include "bindings/core/v8/V8HiddenValue.h" | 13 #include "bindings/core/v8/V8HiddenValue.h" |
14 #include "bindings/core/v8/V8ScriptRunner.h" | 14 #include "bindings/core/v8/V8ScriptRunner.h" |
15 #include "bindings/core/v8/V8ThrowException.h" | 15 #include "bindings/core/v8/V8ThrowException.h" |
16 #include "core/dom/ExceptionCode.h" | 16 #include "core/dom/ExceptionCode.h" |
17 #include "core/dom/custom/CustomElement.h" | 17 #include "core/dom/custom/CustomElement.h" |
18 #include "core/events/ErrorEvent.h" | 18 #include "core/events/ErrorEvent.h" |
19 #include "core/html/HTMLElement.h" | 19 #include "core/html/HTMLElement.h" |
20 #include "v8.h" | 20 #include "v8.h" |
21 #include "wtf/Allocator.h" | 21 #include "wtf/Allocator.h" |
22 | 22 |
23 namespace blink { | 23 namespace blink { |
24 | 24 |
25 // Retrieves the custom elements constructor -> name map, creating it | 25 // Retrieves the custom elements constructor -> name map, creating it |
26 // if necessary. The same map is used to keep prototypes alive. | 26 // if necessary. The same map is used to keep prototypes alive. |
27 static v8::Local<v8::Map> ensureCustomElementsRegistryMap( | 27 static v8::Local<v8::Map> ensureCustomElementRegistryMap( |
28 ScriptState* scriptState, | 28 ScriptState* scriptState, |
29 CustomElementsRegistry* registry) | 29 CustomElementRegistry* registry) |
30 { | 30 { |
31 CHECK(scriptState->world().isMainWorld()); | 31 CHECK(scriptState->world().isMainWorld()); |
32 v8::Local<v8::String> name = V8HiddenValue::customElementsRegistryMap( | 32 v8::Local<v8::String> name = V8HiddenValue::customElementsRegistryMap( |
33 scriptState->isolate()); | 33 scriptState->isolate()); |
34 v8::Local<v8::Object> wrapper = | 34 v8::Local<v8::Object> wrapper = |
35 toV8(registry, scriptState).As<v8::Object>(); | 35 toV8(registry, scriptState).As<v8::Object>(); |
36 v8::Local<v8::Value> map = | 36 v8::Local<v8::Value> map = |
37 V8HiddenValue::getHiddenValue(scriptState, wrapper, name); | 37 V8HiddenValue::getHiddenValue(scriptState, wrapper, name); |
38 if (map.IsEmpty()) { | 38 if (map.IsEmpty()) { |
39 map = v8::Map::New(scriptState->isolate()); | 39 map = v8::Map::New(scriptState->isolate()); |
40 V8HiddenValue::setHiddenValue(scriptState, wrapper, name, map); | 40 V8HiddenValue::setHiddenValue(scriptState, wrapper, name, map); |
41 } | 41 } |
42 return map.As<v8::Map>(); | 42 return map.As<v8::Map>(); |
43 } | 43 } |
44 | 44 |
45 ScriptCustomElementDefinition* ScriptCustomElementDefinition::forConstructor( | 45 ScriptCustomElementDefinition* ScriptCustomElementDefinition::forConstructor( |
46 ScriptState* scriptState, | 46 ScriptState* scriptState, |
47 CustomElementsRegistry* registry, | 47 CustomElementRegistry* registry, |
48 const v8::Local<v8::Value>& constructor) | 48 const v8::Local<v8::Value>& constructor) |
49 { | 49 { |
50 v8::Local<v8::Map> map = | 50 v8::Local<v8::Map> map = |
51 ensureCustomElementsRegistryMap(scriptState, registry); | 51 ensureCustomElementRegistryMap(scriptState, registry); |
52 v8::Local<v8::Value> nameValue = map->Get(scriptState->context(), constructo
r).ToLocalChecked(); | 52 v8::Local<v8::Value> nameValue = map->Get(scriptState->context(), constructo
r).ToLocalChecked(); |
53 if (!nameValue->IsString()) | 53 if (!nameValue->IsString()) |
54 return nullptr; | 54 return nullptr; |
55 AtomicString name = toCoreAtomicString(nameValue.As<v8::String>()); | 55 AtomicString name = toCoreAtomicString(nameValue.As<v8::String>()); |
56 | 56 |
57 // This downcast is safe because only | 57 // This downcast is safe because only |
58 // ScriptCustomElementDefinitions have a name associated with a V8 | 58 // ScriptCustomElementDefinitions have a name associated with a V8 |
59 // constructor in the map; see | 59 // constructor in the map; see |
60 // ScriptCustomElementDefinition::create. This relies on three | 60 // ScriptCustomElementDefinition::create. This relies on three |
61 // things: | 61 // things: |
62 // | 62 // |
63 // 1. Only ScriptCustomElementDefinition adds entries to the map. | 63 // 1. Only ScriptCustomElementDefinition adds entries to the map. |
64 // Audit the use of V8HiddenValue/hidden values in general and | 64 // Audit the use of V8HiddenValue/hidden values in general and |
65 // how the map is handled--it should never be leaked to script. | 65 // how the map is handled--it should never be leaked to script. |
66 // | 66 // |
67 // 2. CustomElementsRegistry does not overwrite definitions with a | 67 // 2. CustomElementRegistry does not overwrite definitions with a |
68 // given name--see the CHECK in CustomElementsRegistry::define | 68 // given name--see the CHECK in CustomElementRegistry::define |
69 // --and adds ScriptCustomElementDefinitions to the map without | 69 // --and adds ScriptCustomElementDefinitions to the map without |
70 // fail. | 70 // fail. |
71 // | 71 // |
72 // 3. The relationship between the CustomElementsRegistry and its | 72 // 3. The relationship between the CustomElementRegistry and its |
73 // map is never mixed up; this is guaranteed by the bindings | 73 // map is never mixed up; this is guaranteed by the bindings |
74 // system which provides a stable wrapper, and the map hangs | 74 // system which provides a stable wrapper, and the map hangs |
75 // off the wrapper. | 75 // off the wrapper. |
76 // | 76 // |
77 // At a meta-level, this downcast is safe because there is | 77 // At a meta-level, this downcast is safe because there is |
78 // currently only one implementation of CustomElementDefinition in | 78 // currently only one implementation of CustomElementDefinition in |
79 // product code and that is ScriptCustomElementDefinition. But | 79 // product code and that is ScriptCustomElementDefinition. But |
80 // that may change in the future. | 80 // that may change in the future. |
81 CustomElementDefinition* definition = registry->definitionForName(name); | 81 CustomElementDefinition* definition = registry->definitionForName(name); |
82 CHECK(definition); | 82 CHECK(definition); |
(...skipping 10 matching lines...) Expand all Loading... |
93 return; | 93 return; |
94 | 94 |
95 array->Set(scriptState->context(), index, value).ToChecked(); | 95 array->Set(scriptState->context(), index, value).ToChecked(); |
96 | 96 |
97 persistent.set(scriptState->isolate(), value); | 97 persistent.set(scriptState->isolate(), value); |
98 persistent.setPhantom(); | 98 persistent.setPhantom(); |
99 } | 99 } |
100 | 100 |
101 ScriptCustomElementDefinition* ScriptCustomElementDefinition::create( | 101 ScriptCustomElementDefinition* ScriptCustomElementDefinition::create( |
102 ScriptState* scriptState, | 102 ScriptState* scriptState, |
103 CustomElementsRegistry* registry, | 103 CustomElementRegistry* registry, |
104 const CustomElementDescriptor& descriptor, | 104 const CustomElementDescriptor& descriptor, |
105 const v8::Local<v8::Object>& constructor, | 105 const v8::Local<v8::Object>& constructor, |
106 const v8::Local<v8::Object>& prototype, | 106 const v8::Local<v8::Object>& prototype, |
107 const v8::Local<v8::Function>& connectedCallback, | 107 const v8::Local<v8::Function>& connectedCallback, |
108 const v8::Local<v8::Function>& disconnectedCallback, | 108 const v8::Local<v8::Function>& disconnectedCallback, |
109 const v8::Local<v8::Function>& adoptedCallback, | 109 const v8::Local<v8::Function>& adoptedCallback, |
110 const v8::Local<v8::Function>& attributeChangedCallback, | 110 const v8::Local<v8::Function>& attributeChangedCallback, |
111 const HashSet<AtomicString>& observedAttributes) | 111 const HashSet<AtomicString>& observedAttributes) |
112 { | 112 { |
113 ScriptCustomElementDefinition* definition = | 113 ScriptCustomElementDefinition* definition = |
114 new ScriptCustomElementDefinition( | 114 new ScriptCustomElementDefinition( |
115 scriptState, | 115 scriptState, |
116 descriptor, | 116 descriptor, |
117 constructor, | 117 constructor, |
118 prototype, | 118 prototype, |
119 connectedCallback, | 119 connectedCallback, |
120 disconnectedCallback, | 120 disconnectedCallback, |
121 adoptedCallback, | 121 adoptedCallback, |
122 attributeChangedCallback, | 122 attributeChangedCallback, |
123 observedAttributes); | 123 observedAttributes); |
124 | 124 |
125 // Add a constructor -> name mapping to the registry. | 125 // Add a constructor -> name mapping to the registry. |
126 v8::Local<v8::Value> nameValue = | 126 v8::Local<v8::Value> nameValue = |
127 v8String(scriptState->isolate(), descriptor.name()); | 127 v8String(scriptState->isolate(), descriptor.name()); |
128 v8::Local<v8::Map> map = | 128 v8::Local<v8::Map> map = |
129 ensureCustomElementsRegistryMap(scriptState, registry); | 129 ensureCustomElementRegistryMap(scriptState, registry); |
130 map->Set(scriptState->context(), constructor, nameValue).ToLocalChecked(); | 130 map->Set(scriptState->context(), constructor, nameValue).ToLocalChecked(); |
131 definition->m_constructor.setPhantom(); | 131 definition->m_constructor.setPhantom(); |
132 | 132 |
133 // We add the prototype and callbacks here to keep them alive. We use the | 133 // We add the prototype and callbacks here to keep them alive. We use the |
134 // name as the key because it is unique per-registry. | 134 // name as the key because it is unique per-registry. |
135 v8::Local<v8::Array> array = v8::Array::New(scriptState->isolate(), 5); | 135 v8::Local<v8::Array> array = v8::Array::New(scriptState->isolate(), 5); |
136 keepAlive(array, 0, prototype, definition->m_prototype, scriptState); | 136 keepAlive(array, 0, prototype, definition->m_prototype, scriptState); |
137 keepAlive(array, 1, connectedCallback, definition->m_connectedCallback, scri
ptState); | 137 keepAlive(array, 1, connectedCallback, definition->m_connectedCallback, scri
ptState); |
138 keepAlive(array, 2, disconnectedCallback, definition->m_disconnectedCallback
, scriptState); | 138 keepAlive(array, 2, disconnectedCallback, definition->m_disconnectedCallback
, scriptState); |
139 keepAlive(array, 3, adoptedCallback, definition->m_adoptedCallback, scriptSt
ate); | 139 keepAlive(array, 3, adoptedCallback, definition->m_adoptedCallback, scriptSt
ate); |
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
371 v8String(isolate, name.localName()), | 371 v8String(isolate, name.localName()), |
372 v8StringOrNull(isolate, oldValue), | 372 v8StringOrNull(isolate, oldValue), |
373 v8StringOrNull(isolate, newValue), | 373 v8StringOrNull(isolate, newValue), |
374 v8String(isolate, name.namespaceURI()), | 374 v8String(isolate, name.namespaceURI()), |
375 }; | 375 }; |
376 runCallback(m_attributeChangedCallback.newLocal(isolate), element, | 376 runCallback(m_attributeChangedCallback.newLocal(isolate), element, |
377 argc, argv); | 377 argc, argv); |
378 } | 378 } |
379 | 379 |
380 } // namespace blink | 380 } // namespace blink |
OLD | NEW |