diff --git a/moli-dom/src/native/element/interface_names.rs b/moli-dom/src/native/element/interface_names.rs index e33c7841eb..d96369920b 100644 --- a/moli-dom/src/native/element/interface_names.rs +++ b/moli-dom/src/native/element/interface_names.rs @@ -95,6 +95,12 @@ pub fn svg_element_interface_name(local_name: &str) -> &'static str { "defs" => "SVGDefsElement", "desc" => "SVGDescElement", "ellipse" => "SVGEllipseElement", + "feComponentTransfer" => "SVGFEComponentTransferElement", + "feFlood" => "SVGFEFloodElement", + "feImage" => "SVGFEImageElement", + "feMerge" => "SVGFEMergeElement", + "feMergeNode" => "SVGFEMergeNodeElement", + "feTile" => "SVGFETileElement", "foreignObject" => "SVGForeignObjectElement", "g" => "SVGGElement", "image" => "SVGImageElement", diff --git a/moli-renderer-v8/src/context_bootstrap/bridge_descriptor/descriptors.rs b/moli-renderer-v8/src/context_bootstrap/bridge_descriptor/descriptors.rs index ce526a3ad0..e40e227287 100644 --- a/moli-renderer-v8/src/context_bootstrap/bridge_descriptor/descriptors.rs +++ b/moli-renderer-v8/src/context_bootstrap/bridge_descriptor/descriptors.rs @@ -129,6 +129,30 @@ const NODE_BRIDGE_DESCRIPTORS: &[BridgeDescriptor] = &[ SpecializedTemplateInstaller::None, SVG_GEOMETRY_RUNTIME_INSTALL_GROUPS, ), + descriptor( + web_api_interfaces::SVGFEComponentTransferElement::DESCRIPTOR, + ELEMENT_GROUPS, + ), + descriptor( + web_api_interfaces::SVGFEFloodElement::DESCRIPTOR, + ELEMENT_GROUPS, + ), + descriptor( + web_api_interfaces::SVGFEImageElement::DESCRIPTOR, + ELEMENT_GROUPS, + ), + descriptor( + web_api_interfaces::SVGFEMergeElement::DESCRIPTOR, + ELEMENT_GROUPS, + ), + descriptor( + web_api_interfaces::SVGFEMergeNodeElement::DESCRIPTOR, + ELEMENT_GROUPS, + ), + descriptor( + web_api_interfaces::SVGFETileElement::DESCRIPTOR, + ELEMENT_GROUPS, + ), descriptor( web_api_interfaces::SVGForeignObjectElement::DESCRIPTOR, ELEMENT_GROUPS, diff --git a/moli-renderer-v8/src/script_vm/tests/mod.rs b/moli-renderer-v8/src/script_vm/tests/mod.rs index 622eb3f7e2..4a524d0069 100644 --- a/moli-renderer-v8/src/script_vm/tests/mod.rs +++ b/moli-renderer-v8/src/script_vm/tests/mod.rs @@ -2161,6 +2161,7 @@ mod queue_microtask; mod rendering_update; mod script_terminal_completion; mod streams; +mod svg_filter_interfaces; mod url_components; mod webgl_interfaces; mod webidl_collections; diff --git a/moli-renderer-v8/src/script_vm/tests/svg_filter_interfaces.rs b/moli-renderer-v8/src/script_vm/tests/svg_filter_interfaces.rs new file mode 100644 index 0000000000..9b8eaefba9 --- /dev/null +++ b/moli-renderer-v8/src/script_vm/tests/svg_filter_interfaces.rs @@ -0,0 +1,48 @@ +use super::*; + +#[test] +fn svg_filter_interfaces_preserve_native_inheritance_and_realm_contracts() { + let mut vm = new_storage_page_task_executor_test_vm("https://svg-filter-interfaces.test/"); + vm.eval("document.body.innerHTML = ''") + .unwrap(); + assert_eq!(vm.eval(r#"(() => { + const assert = (ok, message) => { if (!ok) throw Error(message); }; + const ns = 'http://www.w3.org/2000/svg'; + const child = document.getElementById('child').contentWindow; + const detached = document.implementation.createHTMLDocument(''); + const xml = new DOMParser().parseFromString('', 'image/svg+xml'); + for (const [name, parentName] of [["SVGFEComponentTransferElement","SVGElement"],["SVGFEFloodElement","SVGElement"],["SVGFEImageElement","SVGElement"],["SVGFEMergeElement","SVGElement"],["SVGFEMergeNodeElement","SVGElement"],["SVGFETileElement","SVGElement"]]) { + for (const w of [window, child]) { + const C = w[name], parent = w[parentName]; + assert(typeof C === 'function' && C.name === name, name + ' exposed'); + assert(Object.getPrototypeOf(C.prototype) === parent.prototype, name + ' prototype inheritance'); + assert(Object.getPrototypeOf(C) === parent, name + ' interface inheritance'); + let error; + try { new C(); } catch (caught) { error = caught; } + assert(error instanceof w.TypeError, name + ' illegal constructor realm'); + } + } + const nodeType = Object.getOwnPropertyDescriptor(Node.prototype, 'nodeType').get; + for (const [tag, name] of [["feComponentTransfer","SVGFEComponentTransferElement"],["feFlood","SVGFEFloodElement"],["feImage","SVGFEImageElement"],["feMerge","SVGFEMergeElement"],["feMergeNode","SVGFEMergeNodeElement"],["feTile","SVGFETileElement"]]) { + for (const [doc, w] of [[document, window], [child.document, child], [detached, window], [xml, window]]) { + const element = doc.createElementNS(ns, tag), C = w[name]; + assert(element instanceof C && element instanceof w.SVGElement && element instanceof w.Node, tag + ' native factory brand'); + assert(Object.getPrototypeOf(element) === C.prototype && element.constructor === C, tag + ' factory prototype'); + assert(Object.prototype.toString.call(element) === '[object ' + name + ']', tag + ' native tag'); + assert(element.cloneNode(false) instanceof C, tag + ' cloned brand'); + assert(doc.importNode(element, false) instanceof C, tag + ' imported brand'); + element.setAttribute('data-test', 'value'); + assert(element.getAttribute('data-test') === 'value' && nodeType.call(element) === 1, tag + ' inherited DOM behavior'); + for (const receiver of [Object.create(element), new Proxy(element, {})]) { + let error; + try { nodeType.call(receiver); } catch (caught) { error = caught; } + assert(error instanceof TypeError, tag + ' rejects forged native identity'); + } + assert(!(doc.createElement(tag) instanceof C), tag + ' namespace-sensitive factory'); + } + const parsed = new DOMParser().parseFromString('<' + tag + '/>', 'image/svg+xml'); + assert(parsed.documentElement.firstElementChild instanceof window[name], tag + ' parsed XML brand'); + } + return true; +})()"#).unwrap(), "true"); +} diff --git a/moli-renderer-v8/src/web_api_interfaces.rs b/moli-renderer-v8/src/web_api_interfaces.rs index 5acca2d265..75679d83f4 100644 --- a/moli-renderer-v8/src/web_api_interfaces.rs +++ b/moli-renderer-v8/src/web_api_interfaces.rs @@ -392,6 +392,12 @@ interfaces! { SVGDescElement: SVGElement; SVGElement: Element; SVGEllipseElement: SVGGeometryElement; + SVGFEComponentTransferElement: SVGElement; + SVGFEFloodElement: SVGElement; + SVGFEImageElement: SVGElement; + SVGFEMergeElement: SVGElement; + SVGFEMergeNodeElement: SVGElement; + SVGFETileElement: SVGElement; SVGForeignObjectElement: SVGGraphicsElement; SVGGElement: SVGGraphicsElement; SVGGeometryElement: SVGGraphicsElement;