script/dom/html/
htmlmetaelement.rs1use std::str::FromStr;
6
7use compositing_traits::viewport_description::ViewportDescription;
8use dom_struct::dom_struct;
9use html5ever::{LocalName, Prefix, local_name, ns};
10use js::rust::HandleObject;
11use style::str::HTML_SPACE_CHARACTERS;
12
13use crate::dom::attr::Attr;
14use crate::dom::bindings::codegen::Bindings::HTMLMetaElementBinding::HTMLMetaElementMethods;
15use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
16use crate::dom::bindings::inheritance::Castable;
17use crate::dom::bindings::root::DomRoot;
18use crate::dom::bindings::str::DOMString;
19use crate::dom::document::{Document, determine_policy_for_token};
20use crate::dom::element::{AttributeMutation, Element};
21use crate::dom::html::htmlelement::HTMLElement;
22use crate::dom::html::htmlheadelement::HTMLHeadElement;
23use crate::dom::node::{BindContext, Node, NodeTraits, UnbindContext};
24use crate::dom::virtualmethods::VirtualMethods;
25use crate::script_runtime::CanGc;
26
27#[dom_struct]
28pub(crate) struct HTMLMetaElement {
29 htmlelement: HTMLElement,
30}
31
32impl HTMLMetaElement {
33 fn new_inherited(
34 local_name: LocalName,
35 prefix: Option<Prefix>,
36 document: &Document,
37 ) -> HTMLMetaElement {
38 HTMLMetaElement {
39 htmlelement: HTMLElement::new_inherited(local_name, prefix, document),
40 }
41 }
42
43 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
44 pub(crate) fn new(
45 local_name: LocalName,
46 prefix: Option<Prefix>,
47 document: &Document,
48 proto: Option<HandleObject>,
49 can_gc: CanGc,
50 ) -> DomRoot<HTMLMetaElement> {
51 Node::reflect_node_with_proto(
52 Box::new(HTMLMetaElement::new_inherited(local_name, prefix, document)),
53 document,
54 proto,
55 can_gc,
56 )
57 }
58
59 fn process_attributes(&self) {
60 let element = self.upcast::<Element>();
61 if let Some(ref name) = element.get_name() {
62 let name = name.to_ascii_lowercase();
63 let name = name.trim_matches(HTML_SPACE_CHARACTERS);
64 if name == "referrer" {
65 self.apply_referrer();
66 }
67 if name == "viewport" {
68 self.parse_and_send_viewport_if_necessary();
69 }
70 } else if !self.HttpEquiv().is_empty() {
72 match self.HttpEquiv().to_ascii_lowercase().as_str() {
74 "refresh" => self.declarative_refresh(),
75 "content-security-policy" => self.apply_csp_list(),
76 _ => {},
77 }
78 }
79 }
80
81 fn process_referrer_attribute(&self) {
82 let element = self.upcast::<Element>();
83 if let Some(ref name) = element.get_name() {
84 let name = name.to_ascii_lowercase();
85 let name = name.trim_matches(HTML_SPACE_CHARACTERS);
86
87 if name == "referrer" {
88 self.apply_referrer();
89 }
90 }
91 }
92
93 fn apply_referrer(&self) {
95 let doc = self.owner_document();
96 let meta_node = self.upcast::<Node>();
101 if !meta_node.is_in_a_document_tree() {
102 return;
103 }
104
105 if self.upcast::<Element>().get_name() != Some(atom!("referrer")) {
108 return;
109 }
110
111 let content = self
113 .upcast::<Element>()
114 .get_attribute(&ns!(), &local_name!("content"));
115 if let Some(attr) = content {
116 let attr = attr.value();
117 let attr_val = attr.trim();
118 if !attr_val.is_empty() {
119 doc.set_referrer_policy(determine_policy_for_token(attr_val));
120 }
121 }
122 }
123
124 fn parse_and_send_viewport_if_necessary(&self) {
126 if !self.owner_window().is_top_level() {
128 return;
129 }
130 let element = self.upcast::<Element>();
131 let Some(content) = element.get_attribute(&ns!(), &local_name!("content")) else {
132 return;
133 };
134
135 if let Ok(viewport) = ViewportDescription::from_str(&content.value()) {
136 self.owner_window()
137 .compositor_api()
138 .viewport(self.owner_window().webview_id(), viewport);
139 }
140 }
141
142 fn apply_csp_list(&self) {
144 if let Some(parent) = self.upcast::<Node>().GetParentElement() {
145 if let Some(head) = parent.downcast::<HTMLHeadElement>() {
146 head.set_content_security_policy();
147 }
148 }
149 }
150
151 fn declarative_refresh(&self) {
153 if !self.upcast::<Node>().is_in_a_document_tree() {
154 return;
155 }
156
157 let content = self.Content();
159 if !content.is_empty() {
161 self.owner_document()
163 .shared_declarative_refresh_steps(content.as_bytes());
164 }
165 }
166}
167
168impl HTMLMetaElementMethods<crate::DomTypeHolder> for HTMLMetaElement {
169 make_getter!(Name, "name");
171
172 make_atomic_setter!(SetName, "name");
174
175 make_getter!(Content, "content");
177
178 make_setter!(SetContent, "content");
180
181 make_getter!(HttpEquiv, "http-equiv");
183 make_atomic_setter!(SetHttpEquiv, "http-equiv");
185
186 make_getter!(Scheme, "scheme");
188 make_setter!(SetScheme, "scheme");
190}
191
192impl VirtualMethods for HTMLMetaElement {
193 fn super_type(&self) -> Option<&dyn VirtualMethods> {
194 Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
195 }
196
197 fn bind_to_tree(&self, context: &BindContext, can_gc: CanGc) {
198 if let Some(s) = self.super_type() {
199 s.bind_to_tree(context, can_gc);
200 }
201
202 if context.tree_connected {
203 self.process_attributes();
204 }
205 }
206
207 fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation, can_gc: CanGc) {
208 if let Some(s) = self.super_type() {
209 s.attribute_mutated(attr, mutation, can_gc);
210 }
211
212 self.process_referrer_attribute();
213 }
214
215 fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
216 if let Some(s) = self.super_type() {
217 s.unbind_from_tree(context, can_gc);
218 }
219
220 if context.tree_connected {
221 self.process_referrer_attribute();
222 }
223 }
224}