Chromium Code Reviews| Index: Source/bindings/v8/CustomElementHelpers.cpp |
| diff --git a/Source/bindings/v8/CustomElementHelpers.cpp b/Source/bindings/v8/CustomElementHelpers.cpp |
| index a55d0628ca941466e4f233a246728eda2021bbd8..d1e9adf53ce67f199edcac19cc860e63b9da4f54 100644 |
| --- a/Source/bindings/v8/CustomElementHelpers.cpp |
| +++ b/Source/bindings/v8/CustomElementHelpers.cpp |
| @@ -34,13 +34,14 @@ |
| #include "HTMLNames.h" |
| #include "SVGNames.h" |
| -#include "V8CustomElementConstructor.h" |
| +#include "V8Document.h" |
| #include "V8HTMLElementWrapperFactory.h" |
| #include "V8SVGElementWrapperFactory.h" |
| #include "bindings/v8/DOMDataStore.h" |
| #include "bindings/v8/DOMWrapperWorld.h" |
| #include "bindings/v8/ScriptController.h" |
| #include "core/dom/CustomElementRegistry.h" |
| +#include "core/dom/Element.h" |
| #include "core/dom/Node.h" |
| #include "core/html/HTMLElement.h" |
| #include "core/html/HTMLUnknownElement.h" |
| @@ -53,8 +54,6 @@ v8::Handle<v8::Object> CustomElementHelpers::createWrapper(PassRefPtr<Element> i |
| ASSERT(impl); |
| // The constructor and registered lifecycle callbacks should be visible only from main world. |
| - // FIXME: This shouldn't be needed once each custom element has its own FunctionTemplate |
| - // https://bugs.webkit.org/show_bug.cgi?id=108138 |
| // FIXME: creationContext.IsEmpty() should never happen. Remove |
| // this when callers (like InspectorController::inspect) are fixed |
| @@ -121,27 +120,81 @@ v8::Handle<v8::Object> CustomElementHelpers::createUpgradeCandidateWrapper(PassR |
| } |
| } |
| -bool CustomElementHelpers::initializeConstructorWrapper(CustomElementConstructor* constructor, const ScriptValue& prototype, ScriptState* state) |
| +void constructCustomElement(const v8::FunctionCallbackInfo<v8::Value>& args) |
|
Hajime Morrita
2013/06/10 04:32:22
Nit: can be static.
|
| { |
| - ASSERT(isFeatureAllowed(state)); |
| - ASSERT(!prototype.v8Value().IsEmpty() && prototype.v8Value()->IsObject()); |
| - v8::Handle<v8::Value> wrapperValue = toV8(constructor, state->context()->Global(), state->context()->GetIsolate()); |
| - if (wrapperValue.IsEmpty() || !wrapperValue->IsObject()) |
| - return false; |
| - v8::Handle<v8::Function> wrapper = v8::Handle<v8::Function>::Cast(wrapperValue); |
| - // - Object::ForceSet() nor Object::SetAccessor Doesn't work against the "prototype" property of function objects. |
| - // - Set()-ing here is safe because |
| - // - Hooking Object.prototype's defineProperty() with "prototype" or "constructor" also doesn't affect on these properties of function objects and |
| - // - Using Set() is okay becaues each function has "prototype" property from start and Objects.prototype cannot intercept the property access. |
| - v8::Handle<v8::String> prototypeKey = v8String("prototype", state->context()->GetIsolate()); |
| - ASSERT(wrapper->HasOwnProperty(prototypeKey)); |
| - wrapper->Set(prototypeKey, prototype.v8Value(), v8::ReadOnly); |
| - |
| - v8::Handle<v8::String> constructorKey = v8String("constructor", state->context()->GetIsolate()); |
| - v8::Handle<v8::Object> prototypeObject = v8::Handle<v8::Object>::Cast(prototype.v8Value()); |
| - ASSERT(!prototypeObject->HasOwnProperty(constructorKey)); |
| - prototypeObject->ForceSet(constructorKey, wrapper, v8::ReadOnly); |
| - return true; |
| + v8::Isolate* isolate = args.GetIsolate(); |
| + |
| + if (!args.IsConstructCall()) { |
| + throwTypeError("DOM object constructor cannot be called as a function.", isolate); |
| + return; |
| + } |
| + |
| + if (args.Length() > 0) { |
| + throwTypeError(0, isolate); |
| + return; |
| + } |
| + |
| + Document* document = V8Document::toNative(v8::Handle<v8::Object>::Cast(args.Callee()->GetHiddenValue(v8String("document", isolate)))); |
| + V8TRYCATCH_FOR_V8STRINGRESOURCE_VOID(V8StringResource<>, namespaceURI, args.Callee()->GetHiddenValue(v8String("namespaceURI", isolate))); |
| + V8TRYCATCH_FOR_V8STRINGRESOURCE_VOID(V8StringResource<>, name, args.Callee()->GetHiddenValue(v8String("name", isolate))); |
| + v8::Handle<v8::Value> maybeType = args.Callee()->GetHiddenValue(v8String("type", isolate)); |
| + V8TRYCATCH_FOR_V8STRINGRESOURCE_VOID(V8StringResource<>, type, maybeType); |
| + |
| + ExceptionCode ec = 0; |
| + CustomElementRegistry::CallbackDeliveryScope deliveryScope; |
| + RefPtr<Element> element = document->createElementNS(namespaceURI, name, maybeType->IsNull() ? nullAtom : type, ec); |
| + if (ec) { |
| + setDOMException(ec, isolate); |
| + return; |
| + } |
| + v8SetReturnValue(args, toV8Fast(element.release(), args, document)); |
| +} |
| + |
| +ScriptValue CustomElementHelpers::createConstructor(ScriptState* state, const ScriptValue& prototypeValue, Document* document, const AtomicString& namespaceURI, const AtomicString& name, const AtomicString& type) |
| +{ |
| + v8::Isolate* isolate = state->context()->GetIsolate(); |
| + |
| + v8::TryCatch tryCatch; |
| + v8::Local<v8::FunctionTemplate> constructorTemplate = v8::FunctionTemplate::New(); |
| + constructorTemplate->SetCallHandler(constructCustomElement); |
| + v8::Handle<v8::Function> constructor = constructorTemplate->GetFunction(); |
| + if (tryCatch.HasCaught()) { |
| + state->setException(tryCatch.Exception()); |
| + return ScriptValue(); |
| + } |
| + |
| + v8::Handle<v8::String> v8Name = v8String(name, isolate); |
| + v8::Handle<v8::Value> v8Type; |
| + |
| + if (type.isNull()) { |
| + v8Type = v8::Null(isolate); |
| + constructor->SetName(v8Name); |
| + } else { |
| + v8::Handle<v8::String> v8TypeString = v8String(type, isolate); |
| + v8Type = v8TypeString; |
| + constructor->SetName(v8TypeString); |
| + } |
| + |
| + constructor->SetHiddenValue(v8String("document", isolate), toV8(document, state->context()->Global(), isolate)); |
| + constructor->SetHiddenValue(v8String("namespaceURI", isolate), v8String(namespaceURI, isolate)); |
| + constructor->SetHiddenValue(v8String("name", isolate), v8Name); |
| + constructor->SetHiddenValue(v8String("type", isolate), v8Type); |
| + |
| + // Neither Object::ForceSet nor Object::SetAccessor can set the |
| + // "prototype" property of function objects, so we use Set() |
| + // instead. This is safe because each function has "prototype" |
| + // property from birth so the Function, etc. prototypes will not |
| + // intercept the property access. |
| + v8::Handle<v8::Object> prototype = v8::Handle<v8::Object>::Cast(prototypeValue.v8Value()); |
| + v8::Handle<v8::String> prototypeKey = v8String("prototype", isolate); |
| + ASSERT(constructor->HasOwnProperty(prototypeKey)); |
| + constructor->Set(prototypeKey, prototype, v8::ReadOnly); |
| + |
| + prototype->ForceSet(v8String("constructor", isolate), constructor, v8::ReadOnly); |
| + |
| + ASSERT(!tryCatch.HasCaught()); |
| + |
| + return ScriptValue(constructor); |
| } |
| static bool hasValidPrototypeChainFor(v8::Handle<v8::Object> prototypeObject, WrapperTypeInfo* typeInfo, v8::Handle<v8::Context> context) |