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 #include "bindings/core/v8/DOMWrapperWorld.h" |
7 #include "bindings/core/v8/ExceptionState.h" | 8 #include "bindings/core/v8/ExceptionState.h" |
8 #include "bindings/core/v8/ScriptState.h" | 9 #include "bindings/core/v8/ScriptState.h" |
| 10 #include "bindings/core/v8/ScriptValue.h" |
| 11 #include "bindings/core/v8/V8Binding.h" |
9 #include "core/dom/ElementRegistrationOptions.h" | 12 #include "core/dom/ElementRegistrationOptions.h" |
| 13 #include "core/dom/ExceptionCode.h" |
| 14 #include "core/dom/custom/CustomElement.h" |
| 15 #include "core/dom/custom/CustomElementDefinition.h" |
10 | 16 |
11 namespace blink { | 17 namespace blink { |
12 | 18 |
13 CustomElementsRegistry::CustomElementsRegistry() | 19 CustomElementsRegistry::CustomElementsRegistry(v8::Isolate* isolate) |
| 20 : m_constructorIdMap(isolate, v8::NativeWeakMap::New(isolate)) |
14 { | 21 { |
| 22 ASSERT(DOMWrapperWorld::current(isolate).isMainWorld()); |
15 } | 23 } |
16 | 24 |
| 25 // http://w3c.github.io/webcomponents/spec/custom/#dfn-element-definition |
17 void CustomElementsRegistry::define(ScriptState* scriptState, | 26 void CustomElementsRegistry::define(ScriptState* scriptState, |
18 const AtomicString& name, const ScriptValue& constructor, | 27 const AtomicString& name, const ScriptValue& constructor, |
19 const ElementRegistrationOptions& options, ExceptionState& exceptionState) | 28 const ElementRegistrationOptions& options, ExceptionState& exceptionState) |
20 { | 29 { |
21 // TODO(kojii): Element definition process not implemented yet. | 30 // TODO(dominicc): Check that all of the early returns are |
22 // http://w3c.github.io/webcomponents/spec/custom/#dfn-element-definition | 31 // throwing an exception or terminating. |
| 32 |
| 33 v8::Isolate* isolate = scriptState->isolate(); |
| 34 v8::Local<v8::Context> context = scriptState->context(); |
| 35 |
| 36 // TODO(dominicc): Make this check for constructors and not just |
| 37 // functions when |
| 38 // https://bugs.chromium.org/p/v8/issues/detail?id=4993 is fixed. |
| 39 v8::Local<v8::Value> constructorValue = constructor.v8Value(); |
| 40 if (!constructorValue->IsFunction()) { |
| 41 exceptionState.throwTypeError( |
| 42 "constructor argument is not a constructor"); |
| 43 return; |
| 44 } |
| 45 v8::Local<v8::Object> constructorObject = |
| 46 constructorValue.As<v8::Object>(); |
| 47 |
| 48 // Raise an exception if the name is not valid. |
| 49 if (!CustomElement::isValidName(name)) { |
| 50 exceptionState.throwSyntaxError( |
| 51 "\"" + name + "\" is not a valid custom element name"); |
| 52 return; |
| 53 } |
| 54 |
| 55 // Raise an exception if the name is already in use. |
| 56 if (m_names.contains(name)) { |
| 57 exceptionState.throwDOMException( |
| 58 NotSupportedError, |
| 59 "this name has already been used with this registry"); |
| 60 return; |
| 61 } |
| 62 |
| 63 // Raise an exception if the constructor is already registered. |
| 64 if (definitionForConstructor(context, constructorObject)) { |
| 65 exceptionState.throwDOMException( |
| 66 NotSupportedError, |
| 67 "this constructor has already been used with this registry"); |
| 68 return; |
| 69 } |
| 70 |
| 71 // TODO(dominicc): Implement steps: |
| 72 // 5: localName |
| 73 // 6-7: extends processing |
| 74 // 8-9: observed attributes caching |
| 75 |
| 76 v8::MaybeLocal<v8::Value> maybePrototype = constructorObject->Get( |
| 77 context, |
| 78 v8AtomicString(isolate, "prototype")); |
| 79 v8::Local<v8::Value> prototypeValue; |
| 80 // TODO(dominicc): Check whether returning undefined results in an |
| 81 // empty handle; we must be throwing an exception on exit. |
| 82 if (!maybePrototype.ToLocal(&prototypeValue)) |
| 83 return; |
| 84 if (!prototypeValue->IsObject()) { |
| 85 exceptionState.throwTypeError("constructor prototype is not an object"); |
| 86 return; |
| 87 } |
| 88 // TODO(dominicc): Consider making this a v8::Isolate+v8::Object |
| 89 ScriptValue prototype(scriptState, prototypeValue); |
| 90 |
| 91 // TODO(dominicc): Implement steps: |
| 92 // 12-13: connected callback |
| 93 // 14-15: disconnected callback |
| 94 // 16-17: attribute changed callback |
| 95 |
| 96 size_t id = m_definitions.size(); |
| 97 m_definitions.append(new CustomElementDefinition(name, prototype)); |
| 98 m_constructorIdMap.Get(isolate)->Set( |
| 99 constructorObject, |
| 100 v8::Integer::NewFromUnsigned(isolate, id)); |
| 101 m_names.add(name); |
| 102 |
| 103 // TODO(dominicc): Implement steps: |
| 104 // 20: when-defined promise processing |
| 105 } |
| 106 |
| 107 CustomElementDefinition* CustomElementsRegistry::definitionForConstructor( |
| 108 v8::Handle<v8::Context> context, |
| 109 v8::Handle<v8::Value> constructor) |
| 110 { |
| 111 v8::Local<v8::Value> entry = |
| 112 m_constructorIdMap.Get(context->GetIsolate())->Get(constructor); |
| 113 if (!entry->IsUint32()) |
| 114 return nullptr; |
| 115 return m_definitions[entry->Uint32Value(context).FromJust()]; |
23 } | 116 } |
24 | 117 |
25 DEFINE_TRACE(CustomElementsRegistry) | 118 DEFINE_TRACE(CustomElementsRegistry) |
26 { | 119 { |
| 120 visitor->trace(m_definitions); |
27 } | 121 } |
28 | 122 |
29 } // namespace blink | 123 } // namespace blink |
OLD | NEW |