Chromium Code Reviews| 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/V8CustomElementRegistry.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/V8PrivateProperty.h" | 13 #include "bindings/core/v8/V8PrivateProperty.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/ExecutionContext.h" | 17 #include "core/dom/ExecutionContext.h" |
| 18 #include "core/dom/custom/CustomElement.h" | 18 #include "core/dom/custom/CustomElement.h" |
| 19 #include "core/events/ErrorEvent.h" | 19 #include "core/events/ErrorEvent.h" |
| 20 #include "core/html/HTMLElement.h" | 20 #include "core/html/HTMLElement.h" |
| 21 #include "core/html/imports/HTMLImportsController.h" | 21 #include "core/html/imports/HTMLImportsController.h" |
| 22 #include "platform/wtf/Allocator.h" | 22 #include "platform/wtf/Allocator.h" |
| 23 #include "v8.h" | 23 #include "v8.h" |
| 24 | 24 |
| 25 namespace blink { | 25 namespace blink { |
| 26 | 26 |
| 27 // Retrieves the custom elements constructor -> name map, creating it | |
| 28 // if necessary. | |
| 29 static v8::Local<v8::Map> EnsureCustomElementRegistryMap( | |
| 30 ScriptState* script_state, | |
| 31 CustomElementRegistry* registry) { | |
| 32 CHECK(script_state->World().IsMainWorld()); | |
| 33 v8::Isolate* isolate = script_state->GetIsolate(); | |
| 34 | |
| 35 V8PrivateProperty::Symbol symbol = | |
| 36 V8PrivateProperty::GetCustomElementRegistryMap(isolate); | |
| 37 v8::Local<v8::Object> wrapper = ToV8(registry, script_state).As<v8::Object>(); | |
| 38 v8::Local<v8::Value> map = symbol.GetOrUndefined(wrapper); | |
| 39 if (map->IsUndefined()) { | |
| 40 map = v8::Map::New(isolate); | |
| 41 symbol.Set(wrapper, map); | |
| 42 } | |
| 43 return map.As<v8::Map>(); | |
| 44 } | |
| 45 | |
| 46 ScriptCustomElementDefinition* ScriptCustomElementDefinition::ForConstructor( | 27 ScriptCustomElementDefinition* ScriptCustomElementDefinition::ForConstructor( |
| 47 ScriptState* script_state, | 28 ScriptState* script_state, |
| 48 CustomElementRegistry* registry, | 29 CustomElementRegistry* registry, |
| 49 const v8::Local<v8::Value>& constructor) { | 30 const v8::Local<v8::Value>& constructor) { |
| 50 v8::Local<v8::Map> map = | 31 if (!constructor->IsObject()) |
| 51 EnsureCustomElementRegistryMap(script_state, registry); | |
| 52 v8::Local<v8::Value> name_value = | |
| 53 map->Get(script_state->GetContext(), constructor).ToLocalChecked(); | |
| 54 if (!name_value->IsString()) | |
| 55 return nullptr; | 32 return nullptr; |
| 56 AtomicString name = ToCoreAtomicString(name_value.As<v8::String>()); | 33 auto private_id = |
| 34 script_state->PerContextData()->GetPrivateCustomElementDefinitionId(); | |
| 35 v8::Local<v8::Value> id_value; | |
| 36 if (!V8Call(constructor.As<v8::Object>()->GetPrivate( | |
| 37 script_state->GetContext(), private_id), | |
| 38 id_value)) | |
| 39 return nullptr; | |
| 40 if (!id_value->IsUint32()) | |
| 41 return nullptr; | |
| 42 uint32_t id = id_value.As<v8::Uint32>()->Value(); | |
| 57 | 43 |
| 58 // This downcast is safe because only | 44 // This downcast is safe because only |
| 59 // ScriptCustomElementDefinitions have a name associated with a V8 | 45 // ScriptCustomElementDefinitions have a name associated with a V8 |
| 60 // constructor in the map; see | 46 // constructor in the map; see |
| 61 // ScriptCustomElementDefinition::create. This relies on three | 47 // ScriptCustomElementDefinition::create. This relies on three |
| 62 // things: | 48 // things: |
| 63 // | 49 // |
| 64 // 1. Only ScriptCustomElementDefinition adds entries to the map. | 50 // 1. Only ScriptCustomElementDefinition adds entries to the map. |
| 65 // Audit the use of private properties in general and how the | 51 // Audit the use of private properties in general and how the |
| 66 // map is handled--it should never be leaked to script. | 52 // map is handled--it should never be leaked to script. |
| 67 // | 53 // |
| 68 // 2. CustomElementRegistry does not overwrite definitions with a | 54 // 2. CustomElementRegistry does not overwrite definitions with a |
| 69 // given name--see the CHECK in CustomElementRegistry::define | 55 // given name--see the CHECK in CustomElementRegistry::define |
| 70 // --and adds ScriptCustomElementDefinitions to the map without | 56 // --and adds ScriptCustomElementDefinitions to the map without |
| 71 // fail. | 57 // fail. |
| 72 // | 58 // |
| 73 // 3. The relationship between the CustomElementRegistry and its | 59 // 3. The relationship between the CustomElementRegistry and its |
| 74 // map is never mixed up; this is guaranteed by the bindings | 60 // map is never mixed up; this is guaranteed by the bindings |
| 75 // system which provides a stable wrapper, and the map hangs | 61 // system which provides a stable wrapper, and the map hangs |
| 76 // off the wrapper. | 62 // off the wrapper. |
| 77 // | 63 // |
| 78 // At a meta-level, this downcast is safe because there is | 64 // At a meta-level, this downcast is safe because there is |
| 79 // currently only one implementation of CustomElementDefinition in | 65 // currently only one implementation of CustomElementDefinition in |
| 80 // product code and that is ScriptCustomElementDefinition. But | 66 // product code and that is ScriptCustomElementDefinition. But |
| 81 // that may change in the future. | 67 // that may change in the future. |
| 82 CustomElementDefinition* definition = registry->DefinitionForName(name); | 68 CustomElementDefinition* definition = registry->DefinitionForId(id); |
| 83 CHECK(definition); | 69 CHECK(definition); |
| 84 return static_cast<ScriptCustomElementDefinition*>(definition); | 70 ScriptCustomElementDefinition* scriptDefinition = |
| 71 static_cast<ScriptCustomElementDefinition*>(definition); | |
| 72 // v8::Object::GetPrivate notes that private properties may be | |
| 73 // inherited in future, so check that the definition's constructor | |
| 74 // is exactly the passed object. | |
| 75 return scriptDefinition->constructor_.Get() == constructor ? scriptDefinition | |
| 76 : nullptr; | |
| 85 } | 77 } |
| 86 | 78 |
| 87 using SymbolGetter = V8PrivateProperty::Symbol (*)(v8::Isolate*); | 79 using SymbolGetter = V8PrivateProperty::Symbol (*)(v8::Isolate*); |
| 88 | 80 |
| 89 template <typename T> | 81 template <typename T> |
| 90 static void KeepAlive(v8::Local<v8::Object>& object, | 82 static void KeepAlive(v8::Local<v8::Object>& object, |
| 91 SymbolGetter symbol_getter, | 83 SymbolGetter symbol_getter, |
| 92 const v8::Local<T>& value, | 84 const v8::Local<T>& value, |
| 93 ScopedPersistent<T>& persistent, | 85 ScopedPersistent<T>& persistent, |
| 94 ScriptState* script_state) { | 86 ScriptState* script_state) { |
| 95 if (value.IsEmpty()) | 87 if (value.IsEmpty()) |
| 96 return; | 88 return; |
| 97 | 89 |
| 98 v8::Isolate* isolate = script_state->GetIsolate(); | 90 v8::Isolate* isolate = script_state->GetIsolate(); |
| 99 symbol_getter(isolate).Set(object, value); | 91 symbol_getter(isolate).Set(object, value); |
| 100 persistent.Set(isolate, value); | 92 persistent.Set(isolate, value); |
| 101 persistent.SetPhantom(); | 93 persistent.SetPhantom(); |
| 102 } | 94 } |
| 103 | 95 |
| 104 ScriptCustomElementDefinition* ScriptCustomElementDefinition::Create( | 96 ScriptCustomElementDefinition* ScriptCustomElementDefinition::Create( |
| 105 ScriptState* script_state, | 97 ScriptState* script_state, |
| 106 CustomElementRegistry* registry, | 98 CustomElementRegistry* registry, |
| 107 const CustomElementDescriptor& descriptor, | 99 const CustomElementDescriptor& descriptor, |
| 100 CustomElementDefinition::Id id, | |
| 108 const v8::Local<v8::Object>& constructor, | 101 const v8::Local<v8::Object>& constructor, |
| 109 const v8::Local<v8::Function>& connected_callback, | 102 const v8::Local<v8::Function>& connected_callback, |
| 110 const v8::Local<v8::Function>& disconnected_callback, | 103 const v8::Local<v8::Function>& disconnected_callback, |
| 111 const v8::Local<v8::Function>& adopted_callback, | 104 const v8::Local<v8::Function>& adopted_callback, |
| 112 const v8::Local<v8::Function>& attribute_changed_callback, | 105 const v8::Local<v8::Function>& attribute_changed_callback, |
| 113 const HashSet<AtomicString>& observed_attributes) { | 106 const HashSet<AtomicString>& observed_attributes) { |
| 114 ScriptCustomElementDefinition* definition = new ScriptCustomElementDefinition( | 107 auto private_id = |
| 108 script_state->PerContextData()->GetPrivateCustomElementDefinitionId(); | |
| 109 CHECK(constructor | |
| 110 ->SetPrivate( | |
| 111 script_state->GetContext(), private_id, | |
| 112 v8::Integer::NewFromUnsigned(script_state->GetIsolate(), id)) | |
| 113 .ToChecked()); | |
| 114 return new ScriptCustomElementDefinition( | |
| 115 script_state, descriptor, constructor, connected_callback, | 115 script_state, descriptor, constructor, connected_callback, |
| 116 disconnected_callback, adopted_callback, attribute_changed_callback, | 116 disconnected_callback, adopted_callback, attribute_changed_callback, |
| 117 observed_attributes); | 117 observed_attributes); |
| 118 | |
| 119 // Add a constructor -> name mapping to the registry. | |
| 120 v8::Local<v8::Value> name_value = | |
| 121 V8String(script_state->GetIsolate(), descriptor.GetName()); | |
| 122 v8::Local<v8::Map> map = | |
| 123 EnsureCustomElementRegistryMap(script_state, registry); | |
| 124 map->Set(script_state->GetContext(), constructor, name_value) | |
| 125 .ToLocalChecked(); | |
| 126 definition->constructor_.SetPhantom(); | |
| 127 | |
| 128 // We add the callbacks here to keep them alive. We use the name as | |
| 129 // the key because it is unique per-registry. | |
| 130 v8::Local<v8::Object> object = v8::Object::New(script_state->GetIsolate()); | |
| 131 KeepAlive(object, V8PrivateProperty::GetCustomElementConnectedCallback, | |
| 132 connected_callback, definition->connected_callback_, script_state); | |
| 133 KeepAlive(object, V8PrivateProperty::GetCustomElementDisconnectedCallback, | |
| 134 disconnected_callback, definition->disconnected_callback_, | |
| 135 script_state); | |
| 136 KeepAlive(object, V8PrivateProperty::GetCustomElementAdoptedCallback, | |
| 137 adopted_callback, definition->adopted_callback_, script_state); | |
| 138 KeepAlive(object, V8PrivateProperty::GetCustomElementAttributeChangedCallback, | |
| 139 attribute_changed_callback, definition->attribute_changed_callback_, | |
| 140 script_state); | |
| 141 map->Set(script_state->GetContext(), name_value, object).ToLocalChecked(); | |
| 142 | |
| 143 return definition; | |
| 144 } | 118 } |
| 145 | 119 |
| 146 ScriptCustomElementDefinition::ScriptCustomElementDefinition( | 120 ScriptCustomElementDefinition::ScriptCustomElementDefinition( |
| 147 ScriptState* script_state, | 121 ScriptState* script_state, |
| 148 const CustomElementDescriptor& descriptor, | 122 const CustomElementDescriptor& descriptor, |
| 149 const v8::Local<v8::Object>& constructor, | 123 const v8::Local<v8::Object>& constructor, |
| 150 const v8::Local<v8::Function>& connected_callback, | 124 const v8::Local<v8::Function>& connected_callback, |
| 151 const v8::Local<v8::Function>& disconnected_callback, | 125 const v8::Local<v8::Function>& disconnected_callback, |
| 152 const v8::Local<v8::Function>& adopted_callback, | 126 const v8::Local<v8::Function>& adopted_callback, |
| 153 const v8::Local<v8::Function>& attribute_changed_callback, | 127 const v8::Local<v8::Function>& attribute_changed_callback, |
| 154 const HashSet<AtomicString>& observed_attributes) | 128 const HashSet<AtomicString>& observed_attributes) |
| 155 : CustomElementDefinition(descriptor, observed_attributes), | 129 : CustomElementDefinition(descriptor, observed_attributes), |
| 156 script_state_(script_state), | 130 script_state_(script_state), |
| 157 constructor_(script_state->GetIsolate(), constructor) {} | 131 constructor_(script_state->GetIsolate(), this, constructor), |
| 132 connected_callback_(this), | |
| 133 disconnected_callback_(this), | |
| 134 adopted_callback_(this), | |
| 135 attribute_changed_callback_(this) { | |
| 136 v8::Isolate* isolate = script_state->GetIsolate(); | |
| 137 if (!connected_callback.IsEmpty()) | |
| 138 connected_callback_.Set(isolate, connected_callback); | |
| 139 if (!disconnected_callback.IsEmpty()) | |
| 140 disconnected_callback_.Set(isolate, disconnected_callback); | |
| 141 if (!adopted_callback.IsEmpty()) | |
| 142 adopted_callback_.Set(isolate, adopted_callback); | |
| 143 if (!attribute_changed_callback.IsEmpty()) | |
| 144 attribute_changed_callback_.Set(isolate, attribute_changed_callback); | |
| 145 } | |
| 158 | 146 |
| 159 static void DispatchErrorEvent(v8::Isolate* isolate, | 147 static void DispatchErrorEvent(v8::Isolate* isolate, |
| 160 v8::Local<v8::Value> exception, | 148 v8::Local<v8::Value> exception, |
| 161 v8::Local<v8::Object> constructor) { | 149 v8::Local<v8::Object> constructor) { |
| 162 v8::TryCatch try_catch(isolate); | 150 v8::TryCatch try_catch(isolate); |
| 163 try_catch.SetVerbose(true); | 151 try_catch.SetVerbose(true); |
| 164 V8ScriptRunner::ThrowException( | 152 V8ScriptRunner::ThrowException( |
| 165 isolate, exception, constructor.As<v8::Function>()->GetScriptOrigin()); | 153 isolate, exception, constructor.As<v8::Function>()->GetScriptOrigin()); |
| 166 } | 154 } |
| 167 | 155 |
| 156 DEFINE_TRACE_WRAPPERS(ScriptCustomElementDefinition) { | |
| 157 visitor->TraceWrappers(constructor_); | |
| 158 visitor->TraceWrappers(connected_callback_); | |
|
Michael Lippautz
2017/04/19 08:49:12
Continued from the declaration:
visitor->TraceW
| |
| 159 visitor->TraceWrappers(disconnected_callback_); | |
| 160 visitor->TraceWrappers(adopted_callback_); | |
| 161 visitor->TraceWrappers(attribute_changed_callback_); | |
| 162 } | |
| 163 | |
| 168 HTMLElement* ScriptCustomElementDefinition::HandleCreateElementSyncException( | 164 HTMLElement* ScriptCustomElementDefinition::HandleCreateElementSyncException( |
| 169 Document& document, | 165 Document& document, |
| 170 const QualifiedName& tag_name, | 166 const QualifiedName& tag_name, |
| 171 v8::Isolate* isolate, | 167 v8::Isolate* isolate, |
| 172 ExceptionState& exception_state) { | 168 ExceptionState& exception_state) { |
| 173 DCHECK(exception_state.HadException()); | 169 DCHECK(exception_state.HadException()); |
| 174 // 6.1."If any of these subsubsteps threw an exception".1 | 170 // 6.1."If any of these subsubsteps threw an exception".1 |
| 175 // Report the exception. | 171 // Report the exception. |
| 176 DispatchErrorEvent(isolate, exception_state.GetException(), Constructor()); | 172 DispatchErrorEvent(isolate, exception_state.GetException(), Constructor()); |
| 177 exception_state.ClearException(); | 173 exception_state.ClearException(); |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 277 if (!V8Call(V8ScriptRunner::CallAsConstructor(isolate, Constructor(), | 273 if (!V8Call(V8ScriptRunner::CallAsConstructor(isolate, Constructor(), |
| 278 execution_context, 0, nullptr), | 274 execution_context, 0, nullptr), |
| 279 result)) { | 275 result)) { |
| 280 return nullptr; | 276 return nullptr; |
| 281 } | 277 } |
| 282 return V8Element::toImplWithTypeCheck(isolate, result); | 278 return V8Element::toImplWithTypeCheck(isolate, result); |
| 283 } | 279 } |
| 284 | 280 |
| 285 v8::Local<v8::Object> ScriptCustomElementDefinition::Constructor() const { | 281 v8::Local<v8::Object> ScriptCustomElementDefinition::Constructor() const { |
| 286 DCHECK(!constructor_.IsEmpty()); | 282 DCHECK(!constructor_.IsEmpty()); |
| 287 return constructor_.NewLocal(script_state_->GetIsolate()); | 283 return constructor_.NewLocal(script_state_->GetIsolate()).As<v8::Object>(); |
|
Michael Lippautz
2017/04/19 08:49:12
This cast is not needed then.
(And all below.)
| |
| 288 } | 284 } |
| 289 | 285 |
| 290 // CustomElementDefinition | 286 // CustomElementDefinition |
| 291 ScriptValue ScriptCustomElementDefinition::GetConstructorForScript() { | 287 ScriptValue ScriptCustomElementDefinition::GetConstructorForScript() { |
| 292 return ScriptValue(script_state_.Get(), Constructor()); | 288 return ScriptValue(script_state_.Get(), Constructor()); |
| 293 } | 289 } |
| 294 | 290 |
| 295 bool ScriptCustomElementDefinition::HasConnectedCallback() const { | 291 bool ScriptCustomElementDefinition::HasConnectedCallback() const { |
| 296 return !connected_callback_.IsEmpty(); | 292 return !connected_callback_.IsEmpty(); |
| 297 } | 293 } |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 324 ToV8(element, script_state_->GetContext()->Global(), isolate); | 320 ToV8(element, script_state_->GetContext()->Global(), isolate); |
| 325 V8ScriptRunner::CallFunction(callback, execution_context, element_handle, | 321 V8ScriptRunner::CallFunction(callback, execution_context, element_handle, |
| 326 argc, argv, isolate); | 322 argc, argv, isolate); |
| 327 } | 323 } |
| 328 | 324 |
| 329 void ScriptCustomElementDefinition::RunConnectedCallback(Element* element) { | 325 void ScriptCustomElementDefinition::RunConnectedCallback(Element* element) { |
| 330 if (!script_state_->ContextIsValid()) | 326 if (!script_state_->ContextIsValid()) |
| 331 return; | 327 return; |
| 332 ScriptState::Scope scope(script_state_.Get()); | 328 ScriptState::Scope scope(script_state_.Get()); |
| 333 v8::Isolate* isolate = script_state_->GetIsolate(); | 329 v8::Isolate* isolate = script_state_->GetIsolate(); |
| 334 RunCallback(connected_callback_.NewLocal(isolate), element); | 330 RunCallback(connected_callback_.NewLocal(isolate).As<v8::Function>(), |
| 331 element); | |
| 335 } | 332 } |
| 336 | 333 |
| 337 void ScriptCustomElementDefinition::RunDisconnectedCallback(Element* element) { | 334 void ScriptCustomElementDefinition::RunDisconnectedCallback(Element* element) { |
| 338 if (!script_state_->ContextIsValid()) | 335 if (!script_state_->ContextIsValid()) |
| 339 return; | 336 return; |
| 340 ScriptState::Scope scope(script_state_.Get()); | 337 ScriptState::Scope scope(script_state_.Get()); |
| 341 v8::Isolate* isolate = script_state_->GetIsolate(); | 338 v8::Isolate* isolate = script_state_->GetIsolate(); |
| 342 RunCallback(disconnected_callback_.NewLocal(isolate), element); | 339 RunCallback(disconnected_callback_.NewLocal(isolate).As<v8::Function>(), |
| 340 element); | |
| 343 } | 341 } |
| 344 | 342 |
| 345 void ScriptCustomElementDefinition::RunAdoptedCallback(Element* element, | 343 void ScriptCustomElementDefinition::RunAdoptedCallback(Element* element, |
| 346 Document* old_owner, | 344 Document* old_owner, |
| 347 Document* new_owner) { | 345 Document* new_owner) { |
| 348 if (!script_state_->ContextIsValid()) | 346 if (!script_state_->ContextIsValid()) |
| 349 return; | 347 return; |
| 350 ScriptState::Scope scope(script_state_.Get()); | 348 ScriptState::Scope scope(script_state_.Get()); |
| 351 v8::Isolate* isolate = script_state_->GetIsolate(); | 349 v8::Isolate* isolate = script_state_->GetIsolate(); |
| 352 v8::Local<v8::Value> argv[] = { | 350 v8::Local<v8::Value> argv[] = { |
| 353 ToV8(old_owner, script_state_->GetContext()->Global(), isolate), | 351 ToV8(old_owner, script_state_->GetContext()->Global(), isolate), |
| 354 ToV8(new_owner, script_state_->GetContext()->Global(), isolate)}; | 352 ToV8(new_owner, script_state_->GetContext()->Global(), isolate)}; |
| 355 RunCallback(adopted_callback_.NewLocal(isolate), element, | 353 RunCallback(adopted_callback_.NewLocal(isolate).As<v8::Function>(), element, |
| 356 WTF_ARRAY_LENGTH(argv), argv); | 354 WTF_ARRAY_LENGTH(argv), argv); |
| 357 } | 355 } |
| 358 | 356 |
| 359 void ScriptCustomElementDefinition::RunAttributeChangedCallback( | 357 void ScriptCustomElementDefinition::RunAttributeChangedCallback( |
| 360 Element* element, | 358 Element* element, |
| 361 const QualifiedName& name, | 359 const QualifiedName& name, |
| 362 const AtomicString& old_value, | 360 const AtomicString& old_value, |
| 363 const AtomicString& new_value) { | 361 const AtomicString& new_value) { |
| 364 if (!script_state_->ContextIsValid()) | 362 if (!script_state_->ContextIsValid()) |
| 365 return; | 363 return; |
| 366 ScriptState::Scope scope(script_state_.Get()); | 364 ScriptState::Scope scope(script_state_.Get()); |
| 367 v8::Isolate* isolate = script_state_->GetIsolate(); | 365 v8::Isolate* isolate = script_state_->GetIsolate(); |
| 368 v8::Local<v8::Value> argv[] = { | 366 v8::Local<v8::Value> argv[] = { |
| 369 V8String(isolate, name.LocalName()), V8StringOrNull(isolate, old_value), | 367 V8String(isolate, name.LocalName()), V8StringOrNull(isolate, old_value), |
| 370 V8StringOrNull(isolate, new_value), | 368 V8StringOrNull(isolate, new_value), |
| 371 V8StringOrNull(isolate, name.NamespaceURI()), | 369 V8StringOrNull(isolate, name.NamespaceURI()), |
| 372 }; | 370 }; |
| 373 RunCallback(attribute_changed_callback_.NewLocal(isolate), element, | 371 RunCallback(attribute_changed_callback_.NewLocal(isolate).As<v8::Function>(), |
| 374 WTF_ARRAY_LENGTH(argv), argv); | 372 element, WTF_ARRAY_LENGTH(argv), argv); |
| 375 } | 373 } |
| 376 | 374 |
| 377 } // namespace blink | 375 } // namespace blink |
| OLD | NEW |