mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
add CanGc as argument to methods in ElementInternals, GlobalScope, HTMLAnchorElement, HTMLAreaElement, HTMLCanvasElement Testing: These changes do not require tests because they are a refactor. Addresses part of https://github.com/servo/servo/issues/34573. Signed-off-by: Yerkebulan Tulibergenov <yerkebulan@gmail.com>
345 lines
12 KiB
Rust
345 lines
12 KiB
Rust
/* 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 std::cell::Cell;
|
|
use std::default::Default;
|
|
|
|
use dom_struct::dom_struct;
|
|
use html5ever::{LocalName, Prefix, local_name};
|
|
use js::rust::HandleObject;
|
|
use num_traits::ToPrimitive;
|
|
use servo_url::ServoUrl;
|
|
use style::attr::AttrValue;
|
|
use stylo_atoms::Atom;
|
|
|
|
use crate::dom::activation::Activatable;
|
|
use crate::dom::attr::Attr;
|
|
use crate::dom::bindings::cell::DomRefCell;
|
|
use crate::dom::bindings::codegen::Bindings::HTMLAnchorElementBinding::HTMLAnchorElementMethods;
|
|
use crate::dom::bindings::codegen::Bindings::MouseEventBinding::MouseEventMethods;
|
|
use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
|
|
use crate::dom::bindings::inheritance::Castable;
|
|
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
|
|
use crate::dom::bindings::str::{DOMString, USVString};
|
|
use crate::dom::document::Document;
|
|
use crate::dom::domtokenlist::DOMTokenList;
|
|
use crate::dom::element::{AttributeMutation, Element, reflect_referrer_policy_attribute};
|
|
use crate::dom::event::Event;
|
|
use crate::dom::eventtarget::EventTarget;
|
|
use crate::dom::htmlelement::HTMLElement;
|
|
use crate::dom::htmlhyperlinkelementutils::{HyperlinkElement, HyperlinkElementTraits};
|
|
use crate::dom::htmlimageelement::HTMLImageElement;
|
|
use crate::dom::mouseevent::MouseEvent;
|
|
use crate::dom::node::{BindContext, Node};
|
|
use crate::dom::virtualmethods::VirtualMethods;
|
|
use crate::links::{LinkRelations, follow_hyperlink};
|
|
use crate::script_runtime::CanGc;
|
|
|
|
#[dom_struct]
|
|
pub(crate) struct HTMLAnchorElement {
|
|
htmlelement: HTMLElement,
|
|
rel_list: MutNullableDom<DOMTokenList>,
|
|
#[no_trace]
|
|
relations: Cell<LinkRelations>,
|
|
#[no_trace]
|
|
url: DomRefCell<Option<ServoUrl>>,
|
|
}
|
|
|
|
impl HTMLAnchorElement {
|
|
fn new_inherited(
|
|
local_name: LocalName,
|
|
prefix: Option<Prefix>,
|
|
document: &Document,
|
|
) -> HTMLAnchorElement {
|
|
HTMLAnchorElement {
|
|
htmlelement: HTMLElement::new_inherited(local_name, prefix, document),
|
|
rel_list: Default::default(),
|
|
relations: Cell::new(LinkRelations::empty()),
|
|
url: DomRefCell::new(None),
|
|
}
|
|
}
|
|
|
|
#[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<HTMLAnchorElement> {
|
|
Node::reflect_node_with_proto(
|
|
Box::new(HTMLAnchorElement::new_inherited(
|
|
local_name, prefix, document,
|
|
)),
|
|
document,
|
|
proto,
|
|
can_gc,
|
|
)
|
|
}
|
|
}
|
|
|
|
impl HyperlinkElement for HTMLAnchorElement {
|
|
fn get_url(&self) -> &DomRefCell<Option<ServoUrl>> {
|
|
&self.url
|
|
}
|
|
}
|
|
|
|
impl VirtualMethods for HTMLAnchorElement {
|
|
fn super_type(&self) -> Option<&dyn VirtualMethods> {
|
|
Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
|
|
}
|
|
|
|
fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue {
|
|
match name {
|
|
&local_name!("rel") => AttrValue::from_serialized_tokenlist(value.into()),
|
|
_ => self
|
|
.super_type()
|
|
.unwrap()
|
|
.parse_plain_attribute(name, value),
|
|
}
|
|
}
|
|
|
|
fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation, can_gc: CanGc) {
|
|
self.super_type()
|
|
.unwrap()
|
|
.attribute_mutated(attr, mutation, can_gc);
|
|
|
|
match *attr.local_name() {
|
|
local_name!("rel") | local_name!("rev") => {
|
|
self.relations
|
|
.set(LinkRelations::for_element(self.upcast()));
|
|
},
|
|
_ => {},
|
|
}
|
|
}
|
|
|
|
fn bind_to_tree(&self, context: &BindContext, can_gc: CanGc) {
|
|
if let Some(s) = self.super_type() {
|
|
s.bind_to_tree(context, can_gc);
|
|
}
|
|
|
|
self.relations
|
|
.set(LinkRelations::for_element(self.upcast()));
|
|
}
|
|
}
|
|
|
|
impl HTMLAnchorElementMethods<crate::DomTypeHolder> for HTMLAnchorElement {
|
|
// https://html.spec.whatwg.org/multipage/#dom-a-text
|
|
fn Text(&self) -> DOMString {
|
|
self.upcast::<Node>().GetTextContent().unwrap()
|
|
}
|
|
|
|
// https://html.spec.whatwg.org/multipage/#dom-a-text
|
|
fn SetText(&self, value: DOMString, can_gc: CanGc) {
|
|
self.upcast::<Node>().SetTextContent(Some(value), can_gc)
|
|
}
|
|
|
|
// https://html.spec.whatwg.org/multipage/#dom-a-rel
|
|
make_getter!(Rel, "rel");
|
|
|
|
// https://html.spec.whatwg.org/multipage/#dom-a-rel
|
|
fn SetRel(&self, rel: DOMString, can_gc: CanGc) {
|
|
self.upcast::<Element>()
|
|
.set_tokenlist_attribute(&local_name!("rel"), rel, can_gc);
|
|
}
|
|
|
|
// https://html.spec.whatwg.org/multipage/#dom-a-rellist
|
|
fn RelList(&self, can_gc: CanGc) -> DomRoot<DOMTokenList> {
|
|
self.rel_list.or_init(|| {
|
|
DOMTokenList::new(
|
|
self.upcast(),
|
|
&local_name!("rel"),
|
|
Some(vec![
|
|
Atom::from("noopener"),
|
|
Atom::from("noreferrer"),
|
|
Atom::from("opener"),
|
|
]),
|
|
can_gc,
|
|
)
|
|
})
|
|
}
|
|
|
|
// https://html.spec.whatwg.org/multipage/#dom-a-coords
|
|
make_getter!(Coords, "coords");
|
|
|
|
// https://html.spec.whatwg.org/multipage/#dom-a-coords
|
|
make_setter!(SetCoords, "coords");
|
|
|
|
// https://html.spec.whatwg.org/multipage/#dom-a-name
|
|
make_getter!(Name, "name");
|
|
|
|
// https://html.spec.whatwg.org/multipage/#dom-a-name
|
|
make_atomic_setter!(SetName, "name");
|
|
|
|
// https://html.spec.whatwg.org/multipage/#dom-a-rev
|
|
make_getter!(Rev, "rev");
|
|
|
|
// https://html.spec.whatwg.org/multipage/#dom-a-rev
|
|
make_setter!(SetRev, "rev");
|
|
|
|
// https://html.spec.whatwg.org/multipage/#dom-a-shape
|
|
make_getter!(Shape, "shape");
|
|
|
|
// https://html.spec.whatwg.org/multipage/#dom-a-shape
|
|
make_setter!(SetShape, "shape");
|
|
|
|
// https://html.spec.whatwg.org/multipage/#attr-hyperlink-target
|
|
make_getter!(Target, "target");
|
|
|
|
// https://html.spec.whatwg.org/multipage/#attr-hyperlink-target
|
|
make_setter!(SetTarget, "target");
|
|
|
|
/// <https://html.spec.whatwg.org/multipage/#dom-hyperlink-href>
|
|
fn Href(&self) -> USVString {
|
|
self.get_href()
|
|
}
|
|
|
|
/// <https://html.spec.whatwg.org/multipage/#dom-hyperlink-href>
|
|
fn SetHref(&self, value: USVString, can_gc: CanGc) {
|
|
self.set_href(value, can_gc);
|
|
}
|
|
|
|
/// <https://html.spec.whatwg.org/multipage/#dom-hyperlink-origin>
|
|
fn Origin(&self) -> USVString {
|
|
self.get_origin()
|
|
}
|
|
|
|
/// <https://html.spec.whatwg.org/multipage/#dom-hyperlink-protocol>
|
|
fn Protocol(&self) -> USVString {
|
|
self.get_protocol()
|
|
}
|
|
|
|
/// <https://html.spec.whatwg.org/multipage/#dom-hyperlink-protocol>
|
|
fn SetProtocol(&self, value: USVString, can_gc: CanGc) {
|
|
self.set_protocol(value, can_gc);
|
|
}
|
|
|
|
/// <https://html.spec.whatwg.org/multipage/#dom-hyperlink-password>
|
|
fn Password(&self) -> USVString {
|
|
self.get_password()
|
|
}
|
|
|
|
/// <https://html.spec.whatwg.org/multipage/#dom-hyperlink-password>
|
|
fn SetPassword(&self, value: USVString, can_gc: CanGc) {
|
|
self.set_password(value, can_gc);
|
|
}
|
|
|
|
/// <https://html.spec.whatwg.org/multipage/#dom-hyperlink-hash>
|
|
fn Hash(&self) -> USVString {
|
|
self.get_hash()
|
|
}
|
|
|
|
/// <https://html.spec.whatwg.org/multipage/#dom-hyperlink-hash>
|
|
fn SetHash(&self, value: USVString, can_gc: CanGc) {
|
|
self.set_hash(value, can_gc);
|
|
}
|
|
|
|
/// <https://html.spec.whatwg.org/multipage/#dom-hyperlink-host>
|
|
fn Host(&self) -> USVString {
|
|
self.get_host()
|
|
}
|
|
|
|
/// <https://html.spec.whatwg.org/multipage/#dom-hyperlink-host>
|
|
fn SetHost(&self, value: USVString, can_gc: CanGc) {
|
|
self.set_host(value, can_gc);
|
|
}
|
|
|
|
/// <https://html.spec.whatwg.org/multipage/#dom-hyperlink-hostname>
|
|
fn Hostname(&self) -> USVString {
|
|
self.get_hostname()
|
|
}
|
|
|
|
/// <https://html.spec.whatwg.org/multipage/#dom-hyperlink-hostname>
|
|
fn SetHostname(&self, value: USVString, can_gc: CanGc) {
|
|
self.set_hostname(value, can_gc);
|
|
}
|
|
|
|
/// <https://html.spec.whatwg.org/multipage/#dom-hyperlink-port>
|
|
fn Port(&self) -> USVString {
|
|
self.get_port()
|
|
}
|
|
|
|
/// <https://html.spec.whatwg.org/multipage/#dom-hyperlink-port>
|
|
fn SetPort(&self, value: USVString, can_gc: CanGc) {
|
|
self.set_port(value, can_gc);
|
|
}
|
|
|
|
/// <https://html.spec.whatwg.org/multipage/#dom-hyperlink-pathname>
|
|
fn Pathname(&self) -> USVString {
|
|
self.get_pathname()
|
|
}
|
|
|
|
/// <https://html.spec.whatwg.org/multipage/#dom-hyperlink-pathname>
|
|
fn SetPathname(&self, value: USVString, can_gc: CanGc) {
|
|
self.set_pathname(value, can_gc);
|
|
}
|
|
|
|
/// <https://html.spec.whatwg.org/multipage/#dom-hyperlink-search>
|
|
fn Search(&self) -> USVString {
|
|
self.get_search()
|
|
}
|
|
|
|
/// <https://html.spec.whatwg.org/multipage/#dom-hyperlink-search>
|
|
fn SetSearch(&self, value: USVString, can_gc: CanGc) {
|
|
self.set_search(value, can_gc);
|
|
}
|
|
|
|
/// <https://html.spec.whatwg.org/multipage/#dom-hyperlink-username>
|
|
fn Username(&self) -> USVString {
|
|
self.get_username()
|
|
}
|
|
|
|
/// <https://html.spec.whatwg.org/multipage/#dom-hyperlink-username>
|
|
fn SetUsername(&self, value: USVString, can_gc: CanGc) {
|
|
self.set_username(value, can_gc);
|
|
}
|
|
|
|
// https://html.spec.whatwg.org/multipage/#dom-a-referrerpolicy
|
|
fn ReferrerPolicy(&self) -> DOMString {
|
|
reflect_referrer_policy_attribute(self.upcast::<Element>())
|
|
}
|
|
|
|
// https://html.spec.whatwg.org/multipage/#dom-script-referrerpolicy
|
|
make_setter!(SetReferrerPolicy, "referrerpolicy");
|
|
}
|
|
|
|
impl Activatable for HTMLAnchorElement {
|
|
fn as_element(&self) -> &Element {
|
|
self.upcast::<Element>()
|
|
}
|
|
|
|
fn is_instance_activatable(&self) -> bool {
|
|
// https://html.spec.whatwg.org/multipage/#hyperlink
|
|
// "a [...] element[s] with an href attribute [...] must [..] create a
|
|
// hyperlink"
|
|
// https://html.spec.whatwg.org/multipage/#the-a-element
|
|
// "The activation behaviour of a elements *that create hyperlinks*"
|
|
self.as_element().has_attribute(&local_name!("href"))
|
|
}
|
|
|
|
//https://html.spec.whatwg.org/multipage/#the-a-element:activation-behaviour
|
|
fn activation_behavior(&self, event: &Event, target: &EventTarget, can_gc: CanGc) {
|
|
let element = self.as_element();
|
|
let mouse_event = event.downcast::<MouseEvent>().unwrap();
|
|
let mut ismap_suffix = None;
|
|
|
|
// Step 1: If the target of the click event is an img element with an ismap attribute
|
|
// specified, then server-side image map processing must be performed.
|
|
if let Some(element) = target.downcast::<Element>() {
|
|
if target.is::<HTMLImageElement>() && element.has_attribute(&local_name!("ismap")) {
|
|
let target_node = element.upcast::<Node>();
|
|
let rect = target_node.bounding_content_box_or_zero(can_gc);
|
|
ismap_suffix = Some(format!(
|
|
"?{},{}",
|
|
mouse_event.ClientX().to_f32().unwrap() - rect.origin.x.to_f32_px(),
|
|
mouse_event.ClientY().to_f32().unwrap() - rect.origin.y.to_f32_px()
|
|
))
|
|
}
|
|
}
|
|
|
|
// Step 2.
|
|
//TODO: Download the link is `download` attribute is set.
|
|
follow_hyperlink(element, self.relations.get(), ismap_suffix);
|
|
}
|
|
}
|