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/V8CustomElementsRegistry.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/V8HiddenValue.h" | 13 #include "bindings/core/v8/V8HiddenValue.h" |
13 #include "bindings/core/v8/V8ScriptRunner.h" | 14 #include "bindings/core/v8/V8ScriptRunner.h" |
14 #include "bindings/core/v8/V8ThrowException.h" | 15 #include "bindings/core/v8/V8ThrowException.h" |
15 #include "core/dom/ExceptionCode.h" | 16 #include "core/dom/ExceptionCode.h" |
16 #include "core/dom/custom/CustomElement.h" | 17 #include "core/dom/custom/CustomElement.h" |
18 #include "core/events/ErrorEvent.h" | |
17 #include "core/html/HTMLElement.h" | 19 #include "core/html/HTMLElement.h" |
18 #include "v8.h" | 20 #include "v8.h" |
19 #include "wtf/Allocator.h" | 21 #include "wtf/Allocator.h" |
20 | 22 |
21 namespace blink { | 23 namespace blink { |
22 | 24 |
23 // Retrieves the custom elements constructor -> name map, creating it | 25 // Retrieves the custom elements constructor -> name map, creating it |
24 // if necessary. The same map is used to keep prototypes alive. | 26 // if necessary. The same map is used to keep prototypes alive. |
25 static v8::Local<v8::Map> ensureCustomElementsRegistryMap( | 27 static v8::Local<v8::Map> ensureCustomElementsRegistryMap( |
26 ScriptState* scriptState, | 28 ScriptState* scriptState, |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
98 } | 100 } |
99 | 101 |
100 ScriptCustomElementDefinition* ScriptCustomElementDefinition::create( | 102 ScriptCustomElementDefinition* ScriptCustomElementDefinition::create( |
101 ScriptState* scriptState, | 103 ScriptState* scriptState, |
102 CustomElementsRegistry* registry, | 104 CustomElementsRegistry* registry, |
103 const CustomElementDescriptor& descriptor, | 105 const CustomElementDescriptor& descriptor, |
104 const v8::Local<v8::Object>& constructor, | 106 const v8::Local<v8::Object>& constructor, |
105 const v8::Local<v8::Object>& prototype, | 107 const v8::Local<v8::Object>& prototype, |
106 const v8::Local<v8::Function>& connectedCallback, | 108 const v8::Local<v8::Function>& connectedCallback, |
107 const v8::Local<v8::Function>& disconnectedCallback, | 109 const v8::Local<v8::Function>& disconnectedCallback, |
110 const v8::Local<v8::Function>& adoptedCallback, | |
108 const v8::Local<v8::Function>& attributeChangedCallback, | 111 const v8::Local<v8::Function>& attributeChangedCallback, |
109 const HashSet<AtomicString>& observedAttributes) | 112 const HashSet<AtomicString>& observedAttributes) |
110 { | 113 { |
111 ScriptCustomElementDefinition* definition = | 114 ScriptCustomElementDefinition* definition = |
112 new ScriptCustomElementDefinition( | 115 new ScriptCustomElementDefinition( |
113 scriptState, | 116 scriptState, |
114 descriptor, | 117 descriptor, |
115 constructor, | 118 constructor, |
116 prototype, | 119 prototype, |
117 connectedCallback, | 120 connectedCallback, |
118 disconnectedCallback, | 121 disconnectedCallback, |
122 adoptedCallback, | |
119 attributeChangedCallback, | 123 attributeChangedCallback, |
120 observedAttributes); | 124 observedAttributes); |
121 | 125 |
122 // Add a constructor -> name mapping to the registry. | 126 // Add a constructor -> name mapping to the registry. |
123 v8::Local<v8::Value> nameValue = | 127 v8::Local<v8::Value> nameValue = |
124 v8String(scriptState->isolate(), descriptor.name()); | 128 v8String(scriptState->isolate(), descriptor.name()); |
125 v8::Local<v8::Map> map = | 129 v8::Local<v8::Map> map = |
126 ensureCustomElementsRegistryMap(scriptState, registry); | 130 ensureCustomElementsRegistryMap(scriptState, registry); |
127 v8CallOrCrash(map->Set(scriptState->context(), constructor, nameValue)); | 131 v8CallOrCrash(map->Set(scriptState->context(), constructor, nameValue)); |
128 definition->m_constructor.setPhantom(); | 132 definition->m_constructor.setPhantom(); |
129 | 133 |
130 // We add the prototype and callbacks here to keep them alive. We use the | 134 // We add the prototype and callbacks here to keep them alive. We use the |
131 // name as the key because it is unique per-registry. | 135 // name as the key because it is unique per-registry. |
132 v8::Local<v8::Array> array = v8::Array::New(scriptState->isolate(), 4); | 136 v8::Local<v8::Array> array = v8::Array::New(scriptState->isolate(), 5); |
133 keepAlive(array, 0, prototype, definition->m_prototype, scriptState); | 137 keepAlive(array, 0, prototype, definition->m_prototype, scriptState); |
134 keepAlive(array, 1, connectedCallback, definition->m_connectedCallback, scri ptState); | 138 keepAlive(array, 1, connectedCallback, definition->m_connectedCallback, scri ptState); |
135 keepAlive(array, 2, disconnectedCallback, definition->m_disconnectedCallback , scriptState); | 139 keepAlive(array, 2, disconnectedCallback, definition->m_disconnectedCallback , scriptState); |
136 keepAlive(array, 3, attributeChangedCallback, definition->m_attributeChanged Callback, scriptState); | 140 keepAlive(array, 3, attributeChangedCallback, definition->m_attributeChanged Callback, scriptState); |
141 keepAlive(array, 4, adoptedCallback, definition->m_adoptedCallback, scriptSt ate); | |
137 v8CallOrCrash(map->Set(scriptState->context(), nameValue, array)); | 142 v8CallOrCrash(map->Set(scriptState->context(), nameValue, array)); |
138 | 143 |
139 return definition; | 144 return definition; |
140 } | 145 } |
141 | 146 |
142 ScriptCustomElementDefinition::ScriptCustomElementDefinition( | 147 ScriptCustomElementDefinition::ScriptCustomElementDefinition( |
143 ScriptState* scriptState, | 148 ScriptState* scriptState, |
144 const CustomElementDescriptor& descriptor, | 149 const CustomElementDescriptor& descriptor, |
145 const v8::Local<v8::Object>& constructor, | 150 const v8::Local<v8::Object>& constructor, |
146 const v8::Local<v8::Object>& prototype, | 151 const v8::Local<v8::Object>& prototype, |
147 const v8::Local<v8::Function>& connectedCallback, | 152 const v8::Local<v8::Function>& connectedCallback, |
148 const v8::Local<v8::Function>& disconnectedCallback, | 153 const v8::Local<v8::Function>& disconnectedCallback, |
154 const v8::Local<v8::Function>& adoptedCallback, | |
149 const v8::Local<v8::Function>& attributeChangedCallback, | 155 const v8::Local<v8::Function>& attributeChangedCallback, |
150 const HashSet<AtomicString>& observedAttributes) | 156 const HashSet<AtomicString>& observedAttributes) |
151 : CustomElementDefinition(descriptor, observedAttributes) | 157 : CustomElementDefinition(descriptor, observedAttributes) |
152 , m_scriptState(scriptState) | 158 , m_scriptState(scriptState) |
153 , m_constructor(scriptState->isolate(), constructor) | 159 , m_constructor(scriptState->isolate(), constructor) |
154 { | 160 { |
155 } | 161 } |
156 | 162 |
157 HTMLElement* ScriptCustomElementDefinition::createElementSync( | 163 HTMLElement* ScriptCustomElementDefinition::createElementSync( |
158 Document& document, const QualifiedName& tagName, | 164 Document& document, const QualifiedName& tagName, |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
217 return false; | 223 return false; |
218 ScriptState::Scope scope(m_scriptState.get()); | 224 ScriptState::Scope scope(m_scriptState.get()); |
219 v8::Isolate* isolate = m_scriptState->isolate(); | 225 v8::Isolate* isolate = m_scriptState->isolate(); |
220 | 226 |
221 // Step 5 says to rethrow the exception; but there is no one to | 227 // Step 5 says to rethrow the exception; but there is no one to |
222 // catch it. The side effect is to report the error. | 228 // catch it. The side effect is to report the error. |
223 v8::TryCatch tryCatch(isolate); | 229 v8::TryCatch tryCatch(isolate); |
224 tryCatch.SetVerbose(true); | 230 tryCatch.SetVerbose(true); |
225 | 231 |
226 Element* result = runConstructor(); | 232 Element* result = runConstructor(); |
227 if (!result) | 233 |
234 // To report exception thrown from runConstructor() | |
235 if (tryCatch.HasCaught()) | |
228 return false; | 236 return false; |
229 | 237 |
238 // To report InvalidStateError Exception, when the constructor returns some differnt object | |
dominicc (has gone to gerrit)
2016/08/02 07:48:57
Spelling: different
| |
230 if (result != element) { | 239 if (result != element) { |
231 V8ThrowException::throwException( | 240 const String& message = "custom element constructors must call super() f irst and must " |
232 V8ThrowException::createDOMException( | 241 "not return a different object"; |
233 m_scriptState->isolate(), | 242 |
dominicc (has gone to gerrit)
2016/08/02 07:48:57
Maybe delete this blank line; since the message an
| |
234 InvalidStateError, | 243 std::unique_ptr<SourceLocation> location = SourceLocation::fromFunction( constructor().As<v8::Function>()); |
235 "custom element constructors must call super() first and must " | 244 v8::Local<v8::Value> exception = V8ThrowException::createDOMException( |
236 "not return a different object", | 245 m_scriptState->isolate(), |
237 constructor()), | 246 InvalidStateError, |
238 m_scriptState->isolate()); | 247 message, |
248 constructor()); | |
249 fireErrorEvent(m_scriptState.get(), message, exception, std::move(locati on)); | |
239 return false; | 250 return false; |
240 } | 251 } |
241 | 252 |
242 return true; | 253 return true; |
243 } | 254 } |
244 | 255 |
245 Element* ScriptCustomElementDefinition::runConstructor() | 256 Element* ScriptCustomElementDefinition::runConstructor() |
246 { | 257 { |
247 v8::Isolate* isolate = m_scriptState->isolate(); | 258 v8::Isolate* isolate = m_scriptState->isolate(); |
248 DCHECK(ScriptState::current(isolate) == m_scriptState); | 259 DCHECK(ScriptState::current(isolate) == m_scriptState); |
249 ExecutionContext* executionContext = m_scriptState->getExecutionContext(); | 260 ExecutionContext* executionContext = m_scriptState->getExecutionContext(); |
250 v8::Local<v8::Value> result; | 261 v8::Local<v8::Value> result; |
251 if (!v8Call(V8ScriptRunner::callAsConstructor( | 262 if (!v8Call(V8ScriptRunner::callAsConstructor( |
252 isolate, | 263 isolate, |
253 constructor(), | 264 constructor(), |
254 executionContext, | 265 executionContext, |
255 0, | 266 0, |
256 nullptr), | 267 nullptr), |
257 result)) { | 268 result)) { |
258 return nullptr; | 269 return nullptr; |
259 } | 270 } |
260 return V8Element::toImplWithTypeCheck(isolate, result); | 271 return V8Element::toImplWithTypeCheck(isolate, result); |
261 } | 272 } |
262 | 273 |
274 void ScriptCustomElementDefinition::fireErrorEvent(ScriptState* scriptState, con st String& message, v8::Local<v8::Value> exception, std::unique_ptr<SourceLocati on> location) | |
275 { | |
276 ErrorEvent* event = ErrorEvent::create(message, std::move(location), &script State->world()); | |
277 V8ErrorHandler::storeExceptionOnErrorEventWrapper(scriptState, event, except ion, scriptState->context()->Global()); | |
278 ExecutionContext* executionContext = scriptState->getExecutionContext(); | |
279 executionContext->reportException(event, NotSharableCrossOrigin); | |
280 } | |
281 | |
263 v8::Local<v8::Object> ScriptCustomElementDefinition::constructor() const | 282 v8::Local<v8::Object> ScriptCustomElementDefinition::constructor() const |
264 { | 283 { |
265 DCHECK(!m_constructor.isEmpty()); | 284 DCHECK(!m_constructor.isEmpty()); |
266 return m_constructor.newLocal(m_scriptState->isolate()); | 285 return m_constructor.newLocal(m_scriptState->isolate()); |
267 } | 286 } |
268 | 287 |
269 v8::Local<v8::Object> ScriptCustomElementDefinition::prototype() const | 288 v8::Local<v8::Object> ScriptCustomElementDefinition::prototype() const |
270 { | 289 { |
271 DCHECK(!m_prototype.isEmpty()); | 290 DCHECK(!m_prototype.isEmpty()); |
272 return m_prototype.newLocal(m_scriptState->isolate()); | 291 return m_prototype.newLocal(m_scriptState->isolate()); |
273 } | 292 } |
274 | 293 |
275 // CustomElementDefinition | 294 // CustomElementDefinition |
276 ScriptValue ScriptCustomElementDefinition::getConstructorForScript() | 295 ScriptValue ScriptCustomElementDefinition::getConstructorForScript() |
277 { | 296 { |
278 return ScriptValue(m_scriptState.get(), constructor()); | 297 return ScriptValue(m_scriptState.get(), constructor()); |
279 } | 298 } |
280 | 299 |
281 bool ScriptCustomElementDefinition::hasConnectedCallback() const | 300 bool ScriptCustomElementDefinition::hasConnectedCallback() const |
282 { | 301 { |
283 return !m_connectedCallback.isEmpty(); | 302 return !m_connectedCallback.isEmpty(); |
284 } | 303 } |
285 | 304 |
286 bool ScriptCustomElementDefinition::hasDisconnectedCallback() const | 305 bool ScriptCustomElementDefinition::hasDisconnectedCallback() const |
287 { | 306 { |
288 return !m_disconnectedCallback.isEmpty(); | 307 return !m_disconnectedCallback.isEmpty(); |
289 } | 308 } |
290 | 309 |
310 bool ScriptCustomElementDefinition::hasAdoptedCallback() const | |
311 { | |
312 return !m_adoptedCallback.isEmpty(); | |
313 } | |
314 | |
291 void ScriptCustomElementDefinition::runCallback( | 315 void ScriptCustomElementDefinition::runCallback( |
292 v8::Local<v8::Function> callback, | 316 v8::Local<v8::Function> callback, |
293 Element* element, int argc, v8::Local<v8::Value> argv[]) | 317 Element* element, int argc, v8::Local<v8::Value> argv[]) |
294 { | 318 { |
295 DCHECK(ScriptState::current(m_scriptState->isolate()) == m_scriptState); | 319 DCHECK(ScriptState::current(m_scriptState->isolate()) == m_scriptState); |
296 v8::Isolate* isolate = m_scriptState->isolate(); | 320 v8::Isolate* isolate = m_scriptState->isolate(); |
297 | 321 |
298 // Invoke custom element reactions | 322 // Invoke custom element reactions |
299 // https://html.spec.whatwg.org/multipage/scripting.html#invoke-custom-eleme nt-reactions | 323 // https://html.spec.whatwg.org/multipage/scripting.html#invoke-custom-eleme nt-reactions |
300 // If this throws any exception, then report the exception. | 324 // If this throws any exception, then report the exception. |
(...skipping 21 matching lines...) Expand all Loading... | |
322 | 346 |
323 void ScriptCustomElementDefinition::runDisconnectedCallback(Element* element) | 347 void ScriptCustomElementDefinition::runDisconnectedCallback(Element* element) |
324 { | 348 { |
325 if (!m_scriptState->contextIsValid()) | 349 if (!m_scriptState->contextIsValid()) |
326 return; | 350 return; |
327 ScriptState::Scope scope(m_scriptState.get()); | 351 ScriptState::Scope scope(m_scriptState.get()); |
328 v8::Isolate* isolate = m_scriptState->isolate(); | 352 v8::Isolate* isolate = m_scriptState->isolate(); |
329 runCallback(m_disconnectedCallback.newLocal(isolate), element); | 353 runCallback(m_disconnectedCallback.newLocal(isolate), element); |
330 } | 354 } |
331 | 355 |
356 void ScriptCustomElementDefinition::runAdoptedCallback(Element* element) | |
357 { | |
358 if (!m_scriptState->contextIsValid()) | |
359 return; | |
360 ScriptState::Scope scope(m_scriptState.get()); | |
361 v8::Isolate* isolate = m_scriptState->isolate(); | |
362 runCallback(m_adoptedCallback.newLocal(isolate), element); | |
363 } | |
364 | |
332 void ScriptCustomElementDefinition::runAttributeChangedCallback( | 365 void ScriptCustomElementDefinition::runAttributeChangedCallback( |
333 Element* element, const QualifiedName& name, | 366 Element* element, const QualifiedName& name, |
334 const AtomicString& oldValue, const AtomicString& newValue) | 367 const AtomicString& oldValue, const AtomicString& newValue) |
335 { | 368 { |
336 if (!m_scriptState->contextIsValid()) | 369 if (!m_scriptState->contextIsValid()) |
337 return; | 370 return; |
338 ScriptState::Scope scope(m_scriptState.get()); | 371 ScriptState::Scope scope(m_scriptState.get()); |
339 v8::Isolate* isolate = m_scriptState->isolate(); | 372 v8::Isolate* isolate = m_scriptState->isolate(); |
340 const int argc = 4; | 373 const int argc = 4; |
341 v8::Local<v8::Value> argv[argc] = { | 374 v8::Local<v8::Value> argv[argc] = { |
342 v8String(isolate, name.localName()), | 375 v8String(isolate, name.localName()), |
343 v8StringOrNull(isolate, oldValue), | 376 v8StringOrNull(isolate, oldValue), |
344 v8StringOrNull(isolate, newValue), | 377 v8StringOrNull(isolate, newValue), |
345 v8String(isolate, name.namespaceURI()), | 378 v8String(isolate, name.namespaceURI()), |
346 }; | 379 }; |
347 runCallback(m_attributeChangedCallback.newLocal(isolate), element, | 380 runCallback(m_attributeChangedCallback.newLocal(isolate), element, |
348 argc, argv); | 381 argc, argv); |
349 } | 382 } |
350 | 383 |
351 } // namespace blink | 384 } // namespace blink |
OLD | NEW |