Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "bindings/core/v8/ScriptCustomElementDefinition.h" | |
| 6 | |
| 7 #include "bindings/core/v8/ScriptState.h" | |
| 8 #include "bindings/core/v8/V8Binding.h" | |
| 9 #include "bindings/core/v8/V8CustomElementsRegistry.h" | |
| 10 #include "bindings/core/v8/V8HiddenValue.h" | |
| 11 #include "wtf/Allocator.h" | |
| 12 | |
| 13 namespace blink { | |
| 14 | |
| 15 // Retrieves the custom elements constructor -> name map, creating it | |
| 16 // if necessary. The same map is used to keep prototypes alive. | |
| 17 static v8::Local<v8::Map> ensureCustomElementsRegistryMap( | |
| 18 ScriptState* scriptState, | |
| 19 CustomElementsRegistry* registry) | |
| 20 { | |
| 21 CHECK(scriptState->world().isMainWorld()); | |
| 22 v8::Local<v8::String> name = V8HiddenValue::customElementsRegistryMap( | |
| 23 scriptState->isolate()); | |
| 24 v8::Local<v8::Object> wrapper = | |
| 25 toV8(registry, scriptState).As<v8::Object>(); | |
| 26 v8::Local<v8::Value> map = | |
| 27 V8HiddenValue::getHiddenValue(scriptState, wrapper, name); | |
| 28 if (map.IsEmpty()) { | |
| 29 map = v8::Map::New(scriptState->isolate()); | |
| 30 V8HiddenValue::setHiddenValue(scriptState, wrapper, name, map); | |
| 31 } | |
| 32 return map.As<v8::Map>(); | |
| 33 } | |
| 34 | |
| 35 ScriptCustomElementDefinition* ScriptCustomElementDefinition::forConstructor( | |
| 36 ScriptState* scriptState, | |
| 37 CustomElementsRegistry* registry, | |
| 38 const v8::Local<v8::Value>& constructor) | |
| 39 { | |
| 40 if (!scriptState->contextIsValid()) | |
|
haraken
2016/05/28 08:29:48
Nit: I'd remove this check.
We normally don't che
| |
| 41 return nullptr; | |
| 42 v8::Local<v8::Map> map = | |
| 43 ensureCustomElementsRegistryMap(scriptState, registry); | |
| 44 v8::Local<v8::Value> nameValue = v8CallOrCrash( | |
| 45 map->Get(scriptState->context(), constructor)); | |
| 46 if (!nameValue->IsString()) | |
| 47 return nullptr; | |
| 48 AtomicString name = toCoreAtomicString(nameValue.As<v8::String>()); | |
| 49 | |
| 50 // This downcast is safe because only | |
| 51 // ScriptCustomElementDefinitions have a name associated with a V8 | |
| 52 // constructor in the map; see | |
| 53 // ScriptCustomElementDefinition::create. This relies on three | |
| 54 // things: | |
| 55 // | |
| 56 // 1. Only ScriptCustomElementDefinition adds entries to the map. | |
| 57 // Audit the use of V8HiddenValue/hidden values in general and | |
| 58 // how the map is handled--it should never be leaked to script. | |
| 59 // | |
| 60 // 2. CustomElementsRegistry does not overwrite definitions with a | |
| 61 // given name--see the CHECK in CustomElementsRegistry::define | |
| 62 // --and adds ScriptCustomElementDefinitions to the map without | |
| 63 // fail. | |
| 64 // | |
| 65 // 3. The relationship between the CustomElementsRegistry and its | |
| 66 // map is never mixed up; this is guaranteed by the bindings | |
| 67 // system which provides a stable wrapper, and the map hangs | |
| 68 // off the wrapper. | |
| 69 // | |
| 70 // At a meta-level, this downcast is safe because there is | |
| 71 // currently only one implementation of CustomElementDefinition in | |
| 72 // product code and that is ScriptCustomElementDefinition. But | |
| 73 // that may change in the future. | |
| 74 CustomElementDefinition* definition = registry->definitionForName(name); | |
| 75 CHECK(definition); | |
| 76 return static_cast<ScriptCustomElementDefinition*>(definition); | |
| 77 } | |
| 78 | |
| 79 ScriptCustomElementDefinition* ScriptCustomElementDefinition::create( | |
| 80 ScriptState* scriptState, | |
| 81 CustomElementsRegistry* registry, | |
| 82 const CustomElementDescriptor& descriptor, | |
| 83 const v8::Local<v8::Object>& constructor, | |
| 84 const v8::Local<v8::Object>& prototype) | |
| 85 { | |
| 86 ScriptCustomElementDefinition* definition = | |
| 87 new ScriptCustomElementDefinition( | |
| 88 scriptState, | |
| 89 descriptor, | |
| 90 constructor, | |
| 91 prototype); | |
| 92 | |
| 93 // Add a constructor -> name mapping to the registry. | |
| 94 v8::Local<v8::Value> nameValue = | |
| 95 v8String(scriptState->isolate(), descriptor.name()); | |
| 96 v8::Local<v8::Map> map = | |
| 97 ensureCustomElementsRegistryMap(scriptState, registry); | |
| 98 v8CallOrCrash(map->Set(scriptState->context(), constructor, nameValue)); | |
| 99 // We add the prototype here to keep it alive; we make it a value | |
| 100 // not a key so authors cannot return another constructor as a | |
| 101 // prototype to overwrite a constructor in this map. We use the | |
| 102 // name because it is unique per-registry. | |
| 103 v8CallOrCrash(map->Set(scriptState->context(), nameValue, prototype)); | |
| 104 | |
| 105 return definition; | |
| 106 } | |
| 107 | |
| 108 ScriptCustomElementDefinition::ScriptCustomElementDefinition( | |
| 109 ScriptState* scriptState, | |
| 110 const CustomElementDescriptor& descriptor, | |
| 111 const v8::Local<v8::Object>& constructor, | |
| 112 const v8::Local<v8::Object>& prototype) | |
| 113 : CustomElementDefinition(descriptor) | |
| 114 , m_constructor(scriptState->isolate(), constructor) | |
| 115 , m_prototype(scriptState->isolate(), prototype) | |
| 116 { | |
| 117 // These objects are kept alive by references from the | |
| 118 // CustomElementsRegistry wrapper set up by | |
| 119 // ScriptCustomElementDefinition::create. | |
| 120 m_constructor.setPhantom(); | |
| 121 m_prototype.setPhantom(); | |
| 122 } | |
| 123 | |
| 124 v8::Local<v8::Object> ScriptCustomElementDefinition::constructor( | |
| 125 ScriptState* scriptState) const | |
| 126 { | |
| 127 DCHECK(!m_constructor.isEmpty()); | |
| 128 return m_constructor.newLocal(scriptState->isolate()); | |
| 129 } | |
| 130 | |
| 131 v8::Local<v8::Object> ScriptCustomElementDefinition::prototype( | |
| 132 ScriptState* scriptState) const | |
| 133 { | |
| 134 DCHECK(!m_prototype.isEmpty()); | |
| 135 return m_prototype.newLocal(scriptState->isolate()); | |
| 136 } | |
| 137 | |
| 138 } // namespace blink | |
| OLD | NEW |