JSHTMLElementCustom.cpp [plain text]
#include "config.h"
#include "JSHTMLElement.h"
#include "CustomElementRegistry.h"
#include "DOMWindow.h"
#include "Document.h"
#include "HTMLFormElement.h"
#include "JSCustomElementInterface.h"
#include "JSDOMConstructorBase.h"
#include "JSNodeCustom.h"
#include "ScriptExecutionContext.h"
#include <JavaScriptCore/InternalFunction.h>
#include <JavaScriptCore/JSWithScope.h>
namespace WebCore {
using namespace JSC;
EncodedJSValue constructJSHTMLElement(JSGlobalObject* lexicalGlobalObject, CallFrame& callFrame)
{
VM& vm = lexicalGlobalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto* jsConstructor = jsCast<JSDOMConstructorBase*>(callFrame.jsCallee());
ASSERT(jsConstructor);
auto* context = jsConstructor->scriptExecutionContext();
if (!context)
return throwConstructorScriptExecutionContextUnavailableError(*lexicalGlobalObject, scope, "HTMLElement");
ASSERT(context->isDocument());
auto* newTarget = callFrame.newTarget().getObject();
auto* newTargetGlobalObject = jsCast<JSDOMGlobalObject*>(getFunctionRealm(vm, newTarget));
JSValue htmlElementConstructorValue = JSHTMLElement::getConstructor(vm, newTargetGlobalObject);
if (newTarget == htmlElementConstructorValue)
return throwVMTypeError(lexicalGlobalObject, scope, "new.target is not a valid custom element constructor"_s);
auto& document = downcast<Document>(*context);
auto* window = document.domWindow();
if (!window)
return throwVMTypeError(lexicalGlobalObject, scope, "new.target is not a valid custom element constructor"_s);
auto* registry = window->customElementRegistry();
if (!registry)
return throwVMTypeError(lexicalGlobalObject, scope, "new.target is not a valid custom element constructor"_s);
auto* elementInterface = registry->findInterface(newTarget);
if (!elementInterface)
return throwVMTypeError(lexicalGlobalObject, scope, "new.target does not define a custom element"_s);
if (!elementInterface->isUpgradingElement()) {
Structure* baseStructure = getDOMStructure<JSHTMLElement>(vm, *newTargetGlobalObject);
auto* newElementStructure = InternalFunction::createSubclassStructure(lexicalGlobalObject, newTarget, baseStructure);
RETURN_IF_EXCEPTION(scope, { });
Ref<HTMLElement> element = HTMLElement::create(elementInterface->name(), document);
element->setIsDefinedCustomElement(*elementInterface);
auto* jsElement = JSHTMLElement::create(newElementStructure, newTargetGlobalObject, element.get());
cacheWrapper(newTargetGlobalObject->world(), element.ptr(), jsElement);
return JSValue::encode(jsElement);
}
Element* elementToUpgrade = elementInterface->lastElementInConstructionStack();
if (!elementToUpgrade) {
throwTypeError(lexicalGlobalObject, scope, "Cannot instantiate a custom element inside its own constructor during upgrades"_s);
return JSValue::encode(jsUndefined());
}
JSValue elementWrapperValue = toJS(lexicalGlobalObject, jsConstructor->globalObject(), *elementToUpgrade);
ASSERT(elementWrapperValue.isObject());
JSValue newPrototype = newTarget->get(lexicalGlobalObject, vm.propertyNames->prototype);
RETURN_IF_EXCEPTION(scope, encodedJSValue());
JSObject* elementWrapperObject = asObject(elementWrapperValue);
JSObject::setPrototype(elementWrapperObject, lexicalGlobalObject, newPrototype, true );
RETURN_IF_EXCEPTION(scope, encodedJSValue());
elementInterface->didUpgradeLastElementInConstructionStack();
return JSValue::encode(elementWrapperValue);
}
JSScope* JSHTMLElement::pushEventHandlerScope(JSGlobalObject* lexicalGlobalObject, JSScope* scope) const
{
HTMLElement& element = wrapped();
VM& vm = lexicalGlobalObject->vm();
scope = JSWithScope::create(vm, lexicalGlobalObject, scope, asObject(toJS(lexicalGlobalObject, globalObject(), element.document())));
if (HTMLFormElement* form = element.form())
scope = JSWithScope::create(vm, lexicalGlobalObject, scope, asObject(toJS(lexicalGlobalObject, globalObject(), *form)));
return JSWithScope::create(vm, lexicalGlobalObject, scope, asObject(toJS(lexicalGlobalObject, globalObject(), element)));
}
}