mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
svg: Add mock SVGImageElement interface (#36975)
Add mock SVGImageElement interface to fix TIMEOUT WPT tests which are related to ImageBitmap (html/canvas/*). https://svgwg.org/svg2-draft/embedded.html#InterfaceSVGImageElement Rationality of this change to fire event "error" on any attempt to fetch image resource on href attribute change to not block WPT tests execution. Some WPT tests use the legacy namespace attribute "xlink:href", so support for it was added to source code. https://svgwg.org/svg2-draft/linking.html#XLinkHrefAttribute - setAttributeNS("http://www.w3.org/1999/xlink", 'xlink:href', src); Testing: Covered by existed WPT tests - fetch/metadata/generated/svg-image* - html/canvas/element/manual/* - html/dom/idlharness.https.html - html/semantics/embedded-content/the-canvas-element/* - html/webappapis/scripting/events/event-handler-all-global-events.html - mozilla/interfaces.https.html Fixes: https://github.com/servo/servo/issues/35881 Signed-off-by: Andrei Volykhin <andrei.volykhin@gmail.com>
This commit is contained in:
parent
e4f62d5c16
commit
6468734aea
24 changed files with 262 additions and 811 deletions
|
@ -8,7 +8,7 @@ use std::mem;
|
|||
|
||||
use devtools_traits::AttrInfo;
|
||||
use dom_struct::dom_struct;
|
||||
use html5ever::{LocalName, Namespace, Prefix, ns};
|
||||
use html5ever::{LocalName, Namespace, Prefix, local_name, ns};
|
||||
use style::attr::{AttrIdentifier, AttrValue};
|
||||
use style::values::GenericAtomIdent;
|
||||
use stylo_atoms::Atom;
|
||||
|
@ -179,7 +179,7 @@ impl Attr {
|
|||
assert_eq!(Some(owner), self.owner().as_deref());
|
||||
owner.will_mutate_attr(self);
|
||||
self.swap_value(&mut value);
|
||||
if *self.namespace() == ns!() {
|
||||
if is_relevant_attribute(self.namespace(), self.local_name()) {
|
||||
vtable_for(owner.upcast()).attribute_mutated(
|
||||
self,
|
||||
AttributeMutation::Set(Some(&value)),
|
||||
|
@ -283,3 +283,9 @@ impl<'dom> AttrHelpersForLayout<'dom> for LayoutDom<'dom, Attr> {
|
|||
&self.unsafe_get().identifier.namespace.0
|
||||
}
|
||||
}
|
||||
|
||||
/// A helper function to check if attribute is relevant.
|
||||
pub(crate) fn is_relevant_attribute(namespace: &Namespace, local_name: &LocalName) -> bool {
|
||||
// <https://svgwg.org/svg2-draft/linking.html#XLinkHrefAttribute>
|
||||
namespace == &ns!() || (namespace == &ns!(xlink) && local_name == &local_name!("href"))
|
||||
}
|
||||
|
|
|
@ -85,6 +85,7 @@ use crate::dom::htmlulistelement::HTMLUListElement;
|
|||
use crate::dom::htmlunknownelement::HTMLUnknownElement;
|
||||
use crate::dom::htmlvideoelement::HTMLVideoElement;
|
||||
use crate::dom::svgelement::SVGElement;
|
||||
use crate::dom::svgimageelement::SVGImageElement;
|
||||
use crate::dom::svgsvgelement::SVGSVGElement;
|
||||
use crate::realms::{InRealm, enter_realm};
|
||||
use crate::script_runtime::CanGc;
|
||||
|
@ -114,6 +115,7 @@ fn create_svg_element(
|
|||
}
|
||||
|
||||
match name.local {
|
||||
local_name!("image") => make!(SVGImageElement),
|
||||
local_name!("svg") => make!(SVGSVGElement),
|
||||
_ => make!(SVGElement),
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ use xml5ever::serialize::TraversalScope::{
|
|||
|
||||
use crate::conversions::Convert;
|
||||
use crate::dom::activation::Activatable;
|
||||
use crate::dom::attr::{Attr, AttrHelpersForLayout};
|
||||
use crate::dom::attr::{Attr, AttrHelpersForLayout, is_relevant_attribute};
|
||||
use crate::dom::bindings::cell::{DomRefCell, Ref, RefMut, ref_filter_map};
|
||||
use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
|
||||
|
@ -1705,7 +1705,7 @@ impl Element {
|
|||
assert!(attr.GetOwnerElement().as_deref() == Some(self));
|
||||
self.will_mutate_attr(attr);
|
||||
self.attrs.borrow_mut().push(Dom::from_ref(attr));
|
||||
if attr.namespace() == &ns!() {
|
||||
if is_relevant_attribute(attr.namespace(), attr.local_name()) {
|
||||
vtable_for(self.upcast()).attribute_mutated(attr, AttributeMutation::Set(None), can_gc);
|
||||
}
|
||||
}
|
||||
|
@ -1847,7 +1847,7 @@ impl Element {
|
|||
local_name: &LocalName,
|
||||
value: DOMString,
|
||||
) -> AttrValue {
|
||||
if *namespace == ns!() {
|
||||
if is_relevant_attribute(namespace, local_name) {
|
||||
vtable_for(self.upcast()).parse_plain_attribute(local_name, value)
|
||||
} else {
|
||||
AttrValue::String(value.into())
|
||||
|
@ -1902,7 +1902,7 @@ impl Element {
|
|||
|
||||
self.attrs.borrow_mut().remove(idx);
|
||||
attr.set_owner(None);
|
||||
if attr.namespace() == &ns!() {
|
||||
if is_relevant_attribute(attr.namespace(), attr.local_name()) {
|
||||
vtable_for(self.upcast()).attribute_mutated(
|
||||
&attr,
|
||||
AttributeMutation::Removed,
|
||||
|
@ -2722,7 +2722,7 @@ impl ElementMethods<crate::DomTypeHolder> for Element {
|
|||
attr.set_owner(Some(self));
|
||||
self.attrs.borrow_mut()[position] = Dom::from_ref(attr);
|
||||
old_attr.set_owner(None);
|
||||
if attr.namespace() == &ns!() {
|
||||
if is_relevant_attribute(attr.namespace(), attr.local_name()) {
|
||||
vtable.attribute_mutated(
|
||||
attr,
|
||||
AttributeMutation::Set(Some(&old_attr.value())),
|
||||
|
|
|
@ -547,6 +547,7 @@ pub(crate) mod submitevent;
|
|||
pub(crate) mod subtlecrypto;
|
||||
pub(crate) mod svgelement;
|
||||
pub(crate) mod svggraphicselement;
|
||||
pub(crate) mod svgimageelement;
|
||||
pub(crate) mod svgsvgelement;
|
||||
pub(crate) mod testbinding;
|
||||
pub(crate) mod testbindingiterable;
|
||||
|
|
|
@ -4206,6 +4206,9 @@ impl From<ElementTypeIdWrapper> for LayoutElementType {
|
|||
ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTextAreaElement) => {
|
||||
LayoutElementType::HTMLTextAreaElement
|
||||
},
|
||||
ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
|
||||
SVGGraphicsElementTypeId::SVGImageElement,
|
||||
)) => LayoutElementType::SVGImageElement,
|
||||
ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
|
||||
SVGGraphicsElementTypeId::SVGSVGElement,
|
||||
)) => LayoutElementType::SVGSVGElement,
|
||||
|
|
|
@ -82,6 +82,9 @@ impl SVGElementMethods<crate::DomTypeHolder> for SVGElement {
|
|||
})
|
||||
}
|
||||
|
||||
// <https://html.spec.whatwg.org/multipage/#globaleventhandlers>
|
||||
global_event_handlers!();
|
||||
|
||||
// FIXME: The nonce should be stored in an internal slot instead of an
|
||||
// attribute (https://html.spec.whatwg.org/multipage/#cryptographicnonce)
|
||||
// https://html.spec.whatwg.org/multipage/#dom-noncedelement-nonce
|
||||
|
|
96
components/script/dom/svgimageelement.rs
Normal file
96
components/script/dom/svgimageelement.rs
Normal file
|
@ -0,0 +1,96 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use html5ever::{LocalName, Prefix, local_name, ns};
|
||||
use js::rust::HandleObject;
|
||||
use style::attr::AttrValue;
|
||||
|
||||
use crate::dom::attr::Attr;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::document::Document;
|
||||
use crate::dom::element::AttributeMutation;
|
||||
use crate::dom::node::{Node, NodeTraits};
|
||||
use crate::dom::svggraphicselement::SVGGraphicsElement;
|
||||
use crate::dom::virtualmethods::VirtualMethods;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
/// <https://svgwg.org/svg2-draft/embedded.html#Placement>
|
||||
const DEFAULT_WIDTH: u32 = 300;
|
||||
const DEFAULT_HEIGHT: u32 = 150;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct SVGImageElement {
|
||||
svggraphicselement: SVGGraphicsElement,
|
||||
}
|
||||
|
||||
impl SVGImageElement {
|
||||
fn new_inherited(
|
||||
local_name: LocalName,
|
||||
prefix: Option<Prefix>,
|
||||
document: &Document,
|
||||
) -> SVGImageElement {
|
||||
SVGImageElement {
|
||||
svggraphicselement: SVGGraphicsElement::new_inherited(local_name, prefix, document),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(crown, allow(crown::unrooted_must_root))]
|
||||
pub(crate) fn new(
|
||||
local_name: LocalName,
|
||||
prefix: Option<Prefix>,
|
||||
document: &Document,
|
||||
proto: Option<HandleObject>,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<SVGImageElement> {
|
||||
Node::reflect_node_with_proto(
|
||||
Box::new(SVGImageElement::new_inherited(local_name, prefix, document)),
|
||||
document,
|
||||
proto,
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
/// <https://svgwg.org/svg2-draft/linking.html#processingURL>
|
||||
fn fetch_image_resource(&self) {
|
||||
// TODO: Process and fetch the image resource (as HTMLImageElement).
|
||||
// Reject any resource fetching request immediately.
|
||||
self.owner_global()
|
||||
.task_manager()
|
||||
.dom_manipulation_task_source()
|
||||
.queue_simple_event(self.upcast(), atom!("error"));
|
||||
}
|
||||
}
|
||||
|
||||
impl VirtualMethods for SVGImageElement {
|
||||
fn super_type(&self) -> Option<&dyn VirtualMethods> {
|
||||
Some(self.upcast::<SVGGraphicsElement>() as &dyn VirtualMethods)
|
||||
}
|
||||
|
||||
fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation, can_gc: CanGc) {
|
||||
self.super_type()
|
||||
.unwrap()
|
||||
.attribute_mutated(attr, mutation, can_gc);
|
||||
if attr.local_name() == &local_name!("href") &&
|
||||
matches!(attr.namespace(), &ns!() | &ns!(xlink))
|
||||
{
|
||||
if let AttributeMutation::Set(_) = mutation {
|
||||
self.fetch_image_resource();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue {
|
||||
match *name {
|
||||
local_name!("width") => AttrValue::from_u32(value.into(), DEFAULT_WIDTH),
|
||||
local_name!("height") => AttrValue::from_u32(value.into(), DEFAULT_HEIGHT),
|
||||
_ => self
|
||||
.super_type()
|
||||
.unwrap()
|
||||
.parse_plain_attribute(name, value),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -61,6 +61,7 @@ use crate::dom::htmlvideoelement::HTMLVideoElement;
|
|||
use crate::dom::node::{BindContext, ChildrenMutation, CloneChildrenFlag, Node, UnbindContext};
|
||||
use crate::dom::shadowroot::ShadowRoot;
|
||||
use crate::dom::svgelement::SVGElement;
|
||||
use crate::dom::svgimageelement::SVGImageElement;
|
||||
use crate::dom::svgsvgelement::SVGSVGElement;
|
||||
|
||||
/// Trait to allow DOM nodes to opt-in to overriding (or adding to) common
|
||||
|
@ -298,6 +299,9 @@ pub(crate) fn vtable_for(node: &Node) -> &dyn VirtualMethods {
|
|||
NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTitleElement)) => {
|
||||
node.downcast::<HTMLTitleElement>().unwrap() as &dyn VirtualMethods
|
||||
},
|
||||
NodeTypeId::Element(ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
|
||||
SVGGraphicsElementTypeId::SVGImageElement,
|
||||
))) => node.downcast::<SVGImageElement>().unwrap() as &dyn VirtualMethods,
|
||||
NodeTypeId::Element(ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
|
||||
SVGGraphicsElementTypeId::SVGSVGElement,
|
||||
))) => node.downcast::<SVGSVGElement>().unwrap() as &dyn VirtualMethods,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue