| 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 "core/dom/custom/CustomElementsRegistry.h" |    5 #include "core/dom/custom/CustomElementsRegistry.h" | 
|    6  |    6  | 
 |    7 // TODO(dominicc): Stop including Document.h when | 
 |    8 // v0CustomElementIsDefined has been removed. | 
 |    9 #include "bindings/core/v8/DOMWrapperWorld.h" | 
|    7 #include "bindings/core/v8/ExceptionState.h" |   10 #include "bindings/core/v8/ExceptionState.h" | 
|    8 #include "bindings/core/v8/ScriptState.h" |   11 #include "bindings/core/v8/ScriptState.h" | 
 |   12 #include "bindings/core/v8/ScriptValue.h" | 
 |   13 #include "bindings/core/v8/V8Binding.h" | 
 |   14 #include "bindings/core/v8/V8BindingMacros.h" | 
 |   15 #include "bindings/core/v8/V8HiddenValue.h" | 
 |   16 #include "core/dom/Document.h" | 
|    9 #include "core/dom/ElementRegistrationOptions.h" |   17 #include "core/dom/ElementRegistrationOptions.h" | 
 |   18 #include "core/dom/ExceptionCode.h" | 
 |   19 #include "core/dom/custom/CustomElement.h" | 
 |   20 #include "core/dom/custom/CustomElementDefinition.h" | 
 |   21 #include "core/dom/custom/V0CustomElementRegistrationContext.h" | 
 |   22 #include "core/dom/custom/V0CustomElementRegistry.h" | 
|   10  |   23  | 
|   11 namespace blink { |   24 namespace blink { | 
|   12  |   25  | 
|   13 CustomElementsRegistry::CustomElementsRegistry() |   26 CustomElementsRegistry* CustomElementsRegistry::create( | 
|   14 { |   27     ScriptState* scriptState, | 
|   15 } |   28     V0CustomElementRegistrationContext* v0) | 
|   16  |   29 { | 
 |   30     DCHECK(scriptState->world().isMainWorld()); | 
 |   31     CustomElementsRegistry* registry = new CustomElementsRegistry(v0); | 
 |   32     if (v0) | 
 |   33         v0->setV1(registry); | 
 |   34  | 
 |   35     v8::Isolate* isolate = scriptState->isolate(); | 
 |   36     v8::Local<v8::Object> wrapper = | 
 |   37         toV8(registry, scriptState).As<v8::Object>(); | 
 |   38     v8::Local<v8::String> name = | 
 |   39         V8HiddenValue::customElementsRegistryMap(isolate); | 
 |   40     v8::Local<v8::Map> map = v8::Map::New(isolate); | 
 |   41     bool didSetPrototype = | 
 |   42         V8HiddenValue::setHiddenValue(scriptState, wrapper, name, map); | 
 |   43     DCHECK(didSetPrototype); | 
 |   44  | 
 |   45     return registry; | 
 |   46 } | 
 |   47  | 
 |   48 CustomElementsRegistry::CustomElementsRegistry( | 
 |   49     const V0CustomElementRegistrationContext* v0) | 
 |   50     : m_v0(v0) | 
 |   51 { | 
 |   52 } | 
 |   53  | 
 |   54 // http://w3c.github.io/webcomponents/spec/custom/#dfn-element-definition | 
|   17 void CustomElementsRegistry::define(ScriptState* scriptState, |   55 void CustomElementsRegistry::define(ScriptState* scriptState, | 
|   18     const AtomicString& name, const ScriptValue& constructor, |   56     const AtomicString& name, const ScriptValue& constructorScriptValue, | 
|   19     const ElementRegistrationOptions& options, ExceptionState& exceptionState) |   57     const ElementRegistrationOptions& options, ExceptionState& exceptionState) | 
|   20 { |   58 { | 
|   21     // TODO(kojii): Element definition process not implemented yet. |   59     DCHECK(scriptState->world().isMainWorld()); | 
|   22     // http://w3c.github.io/webcomponents/spec/custom/#dfn-element-definition |   60     v8::Isolate* isolate = scriptState->isolate(); | 
 |   61     v8::Local<v8::Context> context = scriptState->context(); | 
 |   62  | 
 |   63     // TODO(dominicc): Make this check for constructors and not just | 
 |   64     // functions when | 
 |   65     // https://bugs.chromium.org/p/v8/issues/detail?id=4993 is fixed. | 
 |   66     v8::Local<v8::Value> constructorValue = constructorScriptValue.v8Value(); | 
 |   67     if (!constructorValue->IsFunction()) { | 
 |   68         exceptionState.throwTypeError( | 
 |   69             "constructor argument is not a constructor"); | 
 |   70         return; | 
 |   71     } | 
 |   72     v8::Local<v8::Object> constructor = constructorValue.As<v8::Object>(); | 
 |   73  | 
 |   74     // Raise an exception if the name is not valid. | 
 |   75     if (!CustomElement::isValidName(name)) { | 
 |   76         exceptionState.throwDOMException( | 
 |   77             SyntaxError, | 
 |   78             "\"" + name + "\" is not a valid custom element name"); | 
 |   79         return; | 
 |   80     } | 
 |   81  | 
 |   82     // Raise an exception if the name is already in use. | 
 |   83     if (nameIsDefined(name) || v0NameIsDefined(name)) { | 
 |   84         exceptionState.throwDOMException( | 
 |   85             NotSupportedError, | 
 |   86             "this name has already been used with this registry"); | 
 |   87         return; | 
 |   88     } | 
 |   89  | 
 |   90     // Raise an exception if the constructor is already registered. | 
 |   91     if (definitionForConstructor(scriptState, constructor)) { | 
 |   92         exceptionState.throwDOMException( | 
 |   93             NotSupportedError, | 
 |   94             "this constructor has already been used with this registry"); | 
 |   95         return; | 
 |   96     } | 
 |   97  | 
 |   98     // TODO(dominicc): Implement steps: | 
 |   99     // 5: localName | 
 |  100     // 6-7: extends processing | 
 |  101     // 8-9: observed attributes caching | 
 |  102  | 
 |  103     // TODO(dominicc): Add a test where the prototype getter destroys | 
 |  104     // the context. | 
 |  105  | 
 |  106     v8::TryCatch tryCatch(isolate); | 
 |  107     v8::Local<v8::String> prototypeString = | 
 |  108         v8AtomicString(isolate, "prototype"); | 
 |  109     v8::Local<v8::Value> prototypeValue; | 
 |  110     if (!v8Call( | 
 |  111         constructor->Get(context, prototypeString), prototypeValue)) { | 
 |  112         DCHECK(tryCatch.HasCaught()); | 
 |  113         tryCatch.ReThrow(); | 
 |  114         return; | 
 |  115     } | 
 |  116     if (!prototypeValue->IsObject()) { | 
 |  117         DCHECK(!tryCatch.HasCaught()); | 
 |  118         exceptionState.throwTypeError("constructor prototype is not an object"); | 
 |  119         return; | 
 |  120     } | 
 |  121     v8::Local<v8::Object> prototype = prototypeValue.As<v8::Object>(); | 
 |  122  | 
 |  123     // TODO(dominicc): Implement steps: | 
 |  124     // 12-13: connected callback | 
 |  125     // 14-15: disconnected callback | 
 |  126     // 16-17: attribute changed callback | 
 |  127  | 
 |  128     Id id = m_definitions.size(); | 
 |  129     v8::Local<v8::Value> idValue = v8::Integer::NewFromUnsigned(isolate, id); | 
 |  130     m_definitions.append(new CustomElementDefinition(this, id, name)); | 
 |  131     // This map is stored in a hidden reference from the | 
 |  132     // CustomElementsRegistry wrapper. | 
 |  133     v8::Local<v8::Map> map = idMap(scriptState); | 
 |  134     // The map keeps the constructor and prototypes alive. | 
 |  135     v8CallOrCrash(map->Set(context, constructor, idValue)); | 
 |  136     v8CallOrCrash(map->Set(context, idValue, prototype)); | 
 |  137     m_names.add(name); | 
 |  138  | 
 |  139     // TODO(dominicc): Implement steps: | 
 |  140     // 20: when-defined promise processing | 
 |  141     DCHECK(!tryCatch.HasCaught() || tryCatch.HasTerminated()); | 
 |  142 } | 
 |  143  | 
 |  144 CustomElementDefinition* CustomElementsRegistry::definitionForConstructor( | 
 |  145     ScriptState* scriptState, | 
 |  146     v8::Local<v8::Value> constructor) | 
 |  147 { | 
 |  148     Id id; | 
 |  149     if (!idForConstructor(scriptState, constructor, id)) | 
 |  150         return nullptr; | 
 |  151     return m_definitions[id]; | 
 |  152 } | 
 |  153  | 
 |  154 v8::Local<v8::Object> CustomElementsRegistry::prototype( | 
 |  155     ScriptState* scriptState, | 
 |  156     const CustomElementDefinition& def) | 
 |  157 { | 
 |  158     v8::Local<v8::Value> idValue = | 
 |  159         v8::Integer::NewFromUnsigned(scriptState->isolate(), def.id()); | 
 |  160     return v8CallOrCrash( | 
 |  161         idMap(scriptState)->Get(scriptState->context(), idValue)) | 
 |  162         .As<v8::Object>(); | 
 |  163 } | 
 |  164  | 
 |  165 bool CustomElementsRegistry::nameIsDefined(const AtomicString& name) const | 
 |  166 { | 
 |  167     return m_names.contains(name); | 
 |  168 } | 
 |  169  | 
 |  170 v8::Local<v8::Map> CustomElementsRegistry::idMap(ScriptState* scriptState) | 
 |  171 { | 
 |  172     DCHECK(scriptState->world().isMainWorld()); | 
 |  173     v8::Local<v8::Object> wrapper = | 
 |  174         toV8(this, scriptState).As<v8::Object>(); | 
 |  175     v8::Local<v8::String> name = V8HiddenValue::customElementsRegistryMap( | 
 |  176         scriptState->isolate()); | 
 |  177     return V8HiddenValue::getHiddenValue(scriptState, wrapper, name) | 
 |  178         .As<v8::Map>(); | 
 |  179 } | 
 |  180  | 
 |  181 bool CustomElementsRegistry::idForConstructor( | 
 |  182     ScriptState* scriptState, | 
 |  183     v8::Local<v8::Value> constructor, | 
 |  184     Id& id) | 
 |  185 { | 
 |  186     v8::Local<v8::Value> entry = v8CallOrCrash( | 
 |  187         idMap(scriptState)->Get(scriptState->context(), constructor)); | 
 |  188     if (!entry->IsUint32()) | 
 |  189         return false; | 
 |  190     id = v8CallOrCrash(entry->Uint32Value(scriptState->context())); | 
 |  191     return true; | 
 |  192 } | 
 |  193  | 
 |  194 bool CustomElementsRegistry::v0NameIsDefined(const AtomicString& name) | 
 |  195 { | 
 |  196     return m_v0.get() && m_v0->nameIsDefined(name); | 
|   23 } |  197 } | 
|   24  |  198  | 
|   25 DEFINE_TRACE(CustomElementsRegistry) |  199 DEFINE_TRACE(CustomElementsRegistry) | 
|   26 { |  200 { | 
 |  201     visitor->trace(m_definitions); | 
 |  202     visitor->trace(m_v0); | 
|   27 } |  203 } | 
|   28  |  204  | 
|   29 } // namespace blink |  205 } // namespace blink | 
| OLD | NEW |