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/ScriptCustomElementDefinitionBuilder.h" | 5 #include "bindings/core/v8/ScriptCustomElementDefinitionBuilder.h" |
| 6 | 6 |
| 7 #include "bindings/core/v8/DOMWrapperWorld.h" | 7 #include <utility> |
| 8 #include "bindings/core/v8/ExceptionState.h" | 8 #include "bindings/core/v8/ExceptionState.h" |
| 9 #include "bindings/core/v8/IDLTypes.h" | 9 #include "bindings/core/v8/IDLTypes.h" |
| 10 #include "bindings/core/v8/NativeValueTraitsImpl.h" | 10 #include "bindings/core/v8/NativeValueTraitsImpl.h" |
| 11 #include "bindings/core/v8/ScriptCustomElementDefinition.h" | 11 #include "bindings/core/v8/ScriptCustomElementDefinition.h" |
| 12 #include "bindings/core/v8/ScriptState.h" | 12 #include "bindings/core/v8/ScriptState.h" |
| 13 #include "bindings/core/v8/ScriptValue.h" | 13 #include "bindings/core/v8/ScriptValue.h" |
| 14 #include "bindings/core/v8/V8BindingForCore.h" | 14 #include "bindings/core/v8/V8BindingForCore.h" |
| 15 #include "bindings/core/v8/V8BindingMacros.h" | 15 #include "bindings/core/v8/V8BindingMacros.h" |
| 16 #include "core/dom/ExceptionCode.h" | 16 #include "core/dom/ExceptionCode.h" |
| 17 | 17 |
| 18 namespace blink { | 18 namespace blink { |
| 19 | 19 |
| 20 ScriptCustomElementDefinitionBuilder* | |
| 21 ScriptCustomElementDefinitionBuilder::stack_ = nullptr; | |
| 22 | |
| 23 ScriptCustomElementDefinitionBuilder::ScriptCustomElementDefinitionBuilder( | 20 ScriptCustomElementDefinitionBuilder::ScriptCustomElementDefinitionBuilder( |
| 24 ScriptState* script_state, | 21 ScriptState* script_state, |
| 25 CustomElementRegistry* registry, | 22 CustomElementRegistry* registry, |
| 26 const ScriptValue& constructor, | 23 const ScriptValue& constructor, |
| 27 ExceptionState& exception_state) | 24 ExceptionState& exception_state) |
| 28 : prev_(stack_), | 25 : script_state_(script_state), |
| 29 script_state_(script_state), | |
| 30 registry_(registry), | 26 registry_(registry), |
| 31 constructor_value_(constructor.V8Value()), | 27 constructor_value_(constructor.V8Value()), |
| 32 exception_state_(exception_state) { | 28 exception_state_(exception_state) {} |
| 33 stack_ = this; | |
| 34 } | |
| 35 | |
| 36 ScriptCustomElementDefinitionBuilder::~ScriptCustomElementDefinitionBuilder() { | |
| 37 stack_ = prev_; | |
| 38 } | |
| 39 | 29 |
| 40 bool ScriptCustomElementDefinitionBuilder::CheckConstructorIntrinsics() { | 30 bool ScriptCustomElementDefinitionBuilder::CheckConstructorIntrinsics() { |
| 41 DCHECK(script_state_->World().IsMainWorld()); | 31 DCHECK(script_state_->World().IsMainWorld()); |
| 42 | 32 |
| 43 // The signature of CustomElementRegistry.define says this is a | 33 // The signature of CustomElementRegistry.define says this is a |
| 44 // Function | 34 // Function |
| 45 // https://html.spec.whatwg.org/multipage/scripting.html#customelementsregistr y | 35 // https://html.spec.whatwg.org/multipage/scripting.html#customelementsregistr y |
| 46 CHECK(constructor_value_->IsFunction()); | 36 CHECK(constructor_value_->IsFunction()); |
| 47 constructor_ = constructor_value_.As<v8::Object>(); | 37 constructor_ = constructor_value_.As<v8::Object>(); |
| 48 if (!constructor_->IsConstructor()) { | 38 if (!constructor_->IsConstructor()) { |
| 49 exception_state_.ThrowTypeError( | 39 exception_state_.ThrowTypeError( |
| 50 "constructor argument is not a constructor"); | 40 "constructor argument is not a constructor"); |
| 51 return false; | 41 return false; |
| 52 } | 42 } |
| 53 return true; | 43 return true; |
| 54 } | 44 } |
| 55 | 45 |
| 56 bool ScriptCustomElementDefinitionBuilder::CheckConstructorNotRegistered() { | 46 bool ScriptCustomElementDefinitionBuilder::CheckConstructorNotRegistered() { |
| 57 if (ScriptCustomElementDefinition::ForConstructor(script_state_.Get(), | 47 if (!ScriptCustomElementDefinition::ForConstructor(script_state_.Get(), |
| 58 registry_, constructor_)) { | 48 registry_, constructor_)) { |
| 59 // Constructor is already registered. | 49 return true; |
| 60 exception_state_.ThrowDOMException( | |
| 61 kNotSupportedError, | |
| 62 "this constructor has already been used with this registry"); | |
| 63 return false; | |
| 64 } | 50 } |
| 65 for (auto builder = prev_; builder; builder = builder->prev_) { | 51 // Constructor is already registered. |
| 66 CHECK(!builder->constructor_.IsEmpty()); | 52 exception_state_.ThrowDOMException( |
| 67 if (registry_ != builder->registry_ || | 53 kNotSupportedError, |
| 68 constructor_ != builder->constructor_) { | 54 "this constructor has already been used with this registry"); |
| 69 continue; | 55 return false; |
| 70 } | |
| 71 exception_state_.ThrowDOMException( | |
| 72 kNotSupportedError, | |
| 73 "this constructor is already being defined in this registry"); | |
| 74 return false; | |
| 75 } | |
| 76 return true; | |
| 77 } | 56 } |
| 78 | 57 |
| 79 bool ScriptCustomElementDefinitionBuilder::ValueForName( | 58 bool ScriptCustomElementDefinitionBuilder::ValueForName( |
| 59 v8::Isolate* isolate, | |
| 60 v8::Local<v8::Context>& context, | |
| 61 const v8::TryCatch& try_catch, | |
| 80 const v8::Local<v8::Object>& object, | 62 const v8::Local<v8::Object>& object, |
| 81 const StringView& name, | 63 const StringView& name, |
| 82 v8::Local<v8::Value>& value) const { | 64 v8::Local<v8::Value>& value) const { |
| 83 v8::Isolate* isolate = script_state_->GetIsolate(); | |
| 84 v8::Local<v8::Context> context = script_state_->GetContext(); | |
| 85 v8::Local<v8::String> name_string = V8AtomicString(isolate, name); | 65 v8::Local<v8::String> name_string = V8AtomicString(isolate, name); |
| 86 v8::TryCatch try_catch(isolate); | |
| 87 if (!object->Get(context, name_string).ToLocal(&value)) { | 66 if (!object->Get(context, name_string).ToLocal(&value)) { |
| 88 exception_state_.RethrowV8Exception(try_catch.Exception()); | 67 exception_state_.RethrowV8Exception(try_catch.Exception()); |
| 89 return false; | 68 return false; |
| 90 } | 69 } |
| 91 return true; | 70 return script_state_->ContextIsValid(); |
|
haraken
2017/04/28 08:49:30
What is this change for?
| |
| 92 } | 71 } |
| 93 | 72 |
| 94 bool ScriptCustomElementDefinitionBuilder::CheckPrototype() { | 73 bool ScriptCustomElementDefinitionBuilder::CheckPrototype() { |
| 74 v8::Isolate* isolate = script_state_->GetIsolate(); | |
| 75 v8::Local<v8::Context> context = script_state_->GetContext(); | |
| 76 v8::TryCatch try_catch(isolate); | |
|
haraken
2017/04/28 08:49:30
Are you intentionally moving the TryCatch scope to
| |
| 95 v8::Local<v8::Value> prototype_value; | 77 v8::Local<v8::Value> prototype_value; |
| 96 if (!ValueForName(constructor_, "prototype", prototype_value)) | 78 if (!ValueForName(isolate, context, try_catch, constructor_, "prototype", |
| 79 prototype_value)) | |
| 97 return false; | 80 return false; |
| 98 if (!prototype_value->IsObject()) { | 81 if (!prototype_value->IsObject()) { |
| 99 exception_state_.ThrowTypeError("constructor prototype is not an object"); | 82 exception_state_.ThrowTypeError("constructor prototype is not an object"); |
| 100 return false; | 83 return false; |
| 101 } | 84 } |
| 102 prototype_ = prototype_value.As<v8::Object>(); | 85 prototype_ = prototype_value.As<v8::Object>(); |
| 103 // If retrieving the prototype destroyed the context, indicate that | 86 // If retrieving the prototype destroyed the context, indicate that |
| 104 // defining the element should not proceed. | 87 // defining the element should not proceed. |
| 105 return true; | 88 return script_state_->ContextIsValid(); |
| 106 } | 89 } |
| 107 | 90 |
| 108 bool ScriptCustomElementDefinitionBuilder::CallableForName( | 91 bool ScriptCustomElementDefinitionBuilder::CallableForName( |
| 92 v8::Isolate* isolate, | |
| 93 v8::Local<v8::Context>& context, | |
| 94 const v8::TryCatch& try_catch, | |
| 109 const StringView& name, | 95 const StringView& name, |
| 110 v8::Local<v8::Function>& callback) const { | 96 v8::Local<v8::Function>& callback) const { |
| 111 v8::Local<v8::Value> value; | 97 v8::Local<v8::Value> value; |
| 112 if (!ValueForName(prototype_, name, value)) | 98 if (!ValueForName(isolate, context, try_catch, prototype_, name, value)) |
| 113 return false; | 99 return false; |
| 114 // "undefined" means "omitted", so return true. | 100 // "undefined" means "omitted" which is valid. |
| 115 if (value->IsUndefined()) | 101 if (value->IsUndefined()) |
| 116 return true; | 102 return true; |
| 117 if (!value->IsFunction()) { | 103 if (!value->IsFunction()) { |
| 118 exception_state_.ThrowTypeError(String::Format( | 104 exception_state_.ThrowTypeError(String::Format( |
| 119 "\"%s\" is not a callable object", name.ToString().Ascii().data())); | 105 "\"%s\" is not a callable object", name.ToString().Ascii().data())); |
| 120 return false; | 106 return false; |
| 121 } | 107 } |
| 122 callback = value.As<v8::Function>(); | 108 callback = value.As<v8::Function>(); |
| 123 return true; | 109 return true; |
| 124 } | 110 } |
| 125 | 111 |
| 126 bool ScriptCustomElementDefinitionBuilder::RetrieveObservedAttributes() { | 112 bool ScriptCustomElementDefinitionBuilder::RetrieveObservedAttributes( |
| 113 v8::Isolate* isolate, | |
| 114 v8::Local<v8::Context>& context, | |
| 115 const v8::TryCatch& try_catch) { | |
| 127 v8::Local<v8::Value> observed_attributes_value; | 116 v8::Local<v8::Value> observed_attributes_value; |
| 128 if (!ValueForName(constructor_, "observedAttributes", | 117 if (!ValueForName(isolate, context, try_catch, constructor_, |
| 129 observed_attributes_value)) | 118 "observedAttributes", observed_attributes_value)) |
| 130 return false; | 119 return false; |
| 131 if (observed_attributes_value->IsUndefined()) | 120 if (observed_attributes_value->IsUndefined()) |
| 132 return true; | 121 return true; |
| 133 Vector<String> list = NativeValueTraits<IDLSequence<IDLString>>::NativeValue( | 122 Vector<String> list = NativeValueTraits<IDLSequence<IDLString>>::NativeValue( |
| 134 script_state_->GetIsolate(), observed_attributes_value, exception_state_); | 123 isolate, observed_attributes_value, exception_state_); |
| 135 if (exception_state_.HadException()) | 124 if (exception_state_.HadException() || !script_state_->ContextIsValid()) |
| 136 return false; | 125 return false; |
| 137 if (list.IsEmpty()) | 126 if (list.IsEmpty()) |
| 138 return true; | 127 return true; |
| 139 observed_attributes_.ReserveCapacityForSize(list.size()); | 128 observed_attributes_.ReserveCapacityForSize(list.size()); |
| 140 for (const auto& attribute : list) | 129 for (const auto& attribute : list) |
| 141 observed_attributes_.insert(AtomicString(attribute)); | 130 observed_attributes_.insert(AtomicString(attribute)); |
| 142 return true; | 131 return true; |
| 143 } | 132 } |
| 144 | 133 |
| 145 bool ScriptCustomElementDefinitionBuilder::RememberOriginalProperties() { | 134 bool ScriptCustomElementDefinitionBuilder::RememberOriginalProperties() { |
| 146 // Spec requires to use values of these properties at the point | 135 // Spec requires to use values of these properties at the point |
| 147 // CustomElementDefinition is built, even if JS changes them afterwards. | 136 // CustomElementDefinition is built, even if JS changes them afterwards. |
| 148 return CallableForName("connectedCallback", connected_callback_) && | 137 v8::Isolate* isolate = script_state_->GetIsolate(); |
| 149 CallableForName("disconnectedCallback", disconnected_callback_) && | 138 v8::Local<v8::Context> context = script_state_->GetContext(); |
| 150 CallableForName("adoptedCallback", adopted_callback_) && | 139 v8::TryCatch try_catch(isolate); |
| 151 CallableForName("attributeChangedCallback", | 140 return CallableForName(isolate, context, try_catch, "connectedCallback", |
| 141 connected_callback_) && | |
| 142 CallableForName(isolate, context, try_catch, "disconnectedCallback", | |
| 143 disconnected_callback_) && | |
| 144 CallableForName(isolate, context, try_catch, "adoptedCallback", | |
| 145 adopted_callback_) && | |
| 146 CallableForName(isolate, context, try_catch, | |
| 147 "attributeChangedCallback", | |
| 152 attribute_changed_callback_) && | 148 attribute_changed_callback_) && |
| 153 (attribute_changed_callback_.IsEmpty() || | 149 (attribute_changed_callback_.IsEmpty() || |
| 154 RetrieveObservedAttributes()); | 150 RetrieveObservedAttributes(isolate, context, try_catch)); |
| 155 } | 151 } |
| 156 | 152 |
| 157 CustomElementDefinition* ScriptCustomElementDefinitionBuilder::Build( | 153 CustomElementDefinition* ScriptCustomElementDefinitionBuilder::Build( |
| 158 const CustomElementDescriptor& descriptor) { | 154 const CustomElementDescriptor& descriptor, |
| 155 CustomElementDefinition::Id id) { | |
| 159 return ScriptCustomElementDefinition::Create( | 156 return ScriptCustomElementDefinition::Create( |
| 160 script_state_.Get(), registry_, descriptor, constructor_, | 157 script_state_.Get(), registry_, descriptor, id, constructor_, |
| 161 connected_callback_, disconnected_callback_, adopted_callback_, | 158 connected_callback_, disconnected_callback_, adopted_callback_, |
| 162 attribute_changed_callback_, observed_attributes_); | 159 attribute_changed_callback_, std::move(observed_attributes_)); |
| 163 } | 160 } |
| 164 | 161 |
| 165 } // namespace blink | 162 } // namespace blink |
| OLD | NEW |