mirror of
https://github.com/lexmount/moli.git
synced 2026-10-08 00:01:00 +00:00
fix(webidl): honor LegacyFactoryFunction NewTarget
This commit is contained in:
@@ -84,6 +84,7 @@ pub(in crate::context_bootstrap) fn image_constructor_callback<'s>(
|
||||
let value = v8::Integer::new_from_unsigned(scope, height);
|
||||
let _ = image.set(scope, v8str(scope, "height").into(), value.into());
|
||||
}
|
||||
apply_legacy_factory_new_target_prototype(scope, &args, image, "HTMLImageElement");
|
||||
rv.set(image.into());
|
||||
}
|
||||
|
||||
@@ -153,6 +154,7 @@ pub(in crate::context_bootstrap) fn audio_constructor_callback<'s>(
|
||||
);
|
||||
}
|
||||
}
|
||||
apply_legacy_factory_new_target_prototype(scope, &args, audio, "HTMLAudioElement");
|
||||
rv.set(audio.into());
|
||||
}
|
||||
|
||||
@@ -243,9 +245,28 @@ pub(in crate::context_bootstrap) fn option_constructor_callback<'s>(
|
||||
false,
|
||||
);
|
||||
}
|
||||
apply_legacy_factory_new_target_prototype(scope, &args, option, "HTMLOptionElement");
|
||||
rv.set(option.into());
|
||||
}
|
||||
|
||||
fn apply_legacy_factory_new_target_prototype<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
args: &v8::FunctionCallbackArguments<'s>,
|
||||
result: v8::Local<'s, v8::Object>,
|
||||
default_constructor_name: &str,
|
||||
) {
|
||||
let receiver = args.this();
|
||||
crate::util::apply_webidl_constructor_prototype_fallback(
|
||||
scope,
|
||||
receiver,
|
||||
args.new_target(),
|
||||
default_constructor_name,
|
||||
);
|
||||
if let Some(prototype) = receiver.get_prototype(scope) {
|
||||
let _ = result.set_prototype(scope, prototype);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn html_element_constructor_callback<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
args: v8::FunctionCallbackArguments<'s>,
|
||||
|
||||
@@ -2438,6 +2438,72 @@ fn html_legacy_factory_constructors_use_element_interface_prototypes() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn html_legacy_factory_constructors_honor_new_target_prototypes() {
|
||||
let mut vm = new_storage_test_vm("https://legacy-factory-new-target.test/");
|
||||
|
||||
let result = vm
|
||||
.eval(
|
||||
r#"
|
||||
(() => {
|
||||
function check(ctor, iface, localName, args) {
|
||||
const Derived = class extends ctor {};
|
||||
const instance = Reflect.construct(ctor, args, Derived);
|
||||
return [
|
||||
Object.getPrototypeOf(instance) === Derived.prototype,
|
||||
instance instanceof Derived,
|
||||
instance instanceof iface,
|
||||
instance.localName === localName
|
||||
].join(':');
|
||||
}
|
||||
|
||||
function fallback(ctor, iface) {
|
||||
function BadNewTarget() {}
|
||||
BadNewTarget.prototype = 1;
|
||||
const instance = Reflect.construct(ctor, [], BadNewTarget);
|
||||
return [
|
||||
Object.getPrototypeOf(instance) === iface.prototype,
|
||||
instance instanceof iface
|
||||
].join(':');
|
||||
}
|
||||
|
||||
let prototypeGets = 0;
|
||||
const proxyPrototype = Object.create(HTMLImageElement.prototype);
|
||||
const ProxyNewTarget = new Proxy(function() {}, {
|
||||
get(target, property, receiver) {
|
||||
if (property === 'prototype') {
|
||||
prototypeGets++;
|
||||
return proxyPrototype;
|
||||
}
|
||||
return Reflect.get(target, property, receiver);
|
||||
}
|
||||
});
|
||||
const proxyImage = Reflect.construct(Image, [], ProxyNewTarget);
|
||||
|
||||
return [
|
||||
check(Audio, HTMLAudioElement, 'audio', ['clip.mp3']),
|
||||
check(Image, HTMLImageElement, 'img', [4, 5]),
|
||||
check(Option, HTMLOptionElement, 'option', ['label', 'value']),
|
||||
fallback(Audio, HTMLAudioElement),
|
||||
fallback(Image, HTMLImageElement),
|
||||
fallback(Option, HTMLOptionElement),
|
||||
prototypeGets,
|
||||
Object.getPrototypeOf(proxyImage) === proxyPrototype
|
||||
].join('|');
|
||||
})()
|
||||
"#,
|
||||
)
|
||||
.expect("legacy factory NewTarget prototype probe should evaluate");
|
||||
|
||||
assert_eq!(
|
||||
result,
|
||||
concat!(
|
||||
"true:true:true:true|true:true:true:true|true:true:true:true|",
|
||||
"true:true|true:true|true:true|1|true"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn html_image_load_runs_on_its_dom_task_not_window_load_dispatch() {
|
||||
let loader = ResourceRequestClient::new(&moli_fetch::FetchConfig::default()).expect("loader");
|
||||
|
||||
Reference in New Issue
Block a user