Skip to main content

script/dom/html/embedded_content/
htmlobjectelement.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::default::Default;
6
7use dom_struct::dom_struct;
8use html5ever::{LocalName, Prefix, local_name};
9use js::context::{JSContext, NoGC};
10use js::rust::HandleObject;
11use pixels::RasterImage;
12use script_bindings::cell::DomRefCell;
13use servo_arc::Arc;
14use style::attr::{AttrValue, LengthOrPercentageOrAuto};
15
16use crate::dom::bindings::codegen::Bindings::HTMLObjectElementBinding::HTMLObjectElementMethods;
17use crate::dom::bindings::inheritance::Castable;
18use crate::dom::bindings::root::{DomRoot, LayoutDom, MutNullableDom};
19use crate::dom::bindings::str::DOMString;
20use crate::dom::document::Document;
21use crate::dom::element::attributes::storage::AttrRef;
22use crate::dom::element::{AttributeMutation, Element};
23use crate::dom::html::htmlelement::HTMLElement;
24use crate::dom::html::htmlformelement::{FormControl, HTMLFormElement};
25use crate::dom::node::virtualmethods::VirtualMethods;
26use crate::dom::node::{Node, NodeTraits};
27use crate::dom::validation::Validatable;
28use crate::dom::validitystate::ValidityState;
29
30#[dom_struct]
31pub(crate) struct HTMLObjectElement {
32    htmlelement: HTMLElement,
33    #[no_trace]
34    #[conditional_malloc_size_of]
35    image: DomRefCell<Option<Arc<RasterImage>>>,
36    form_owner: MutNullableDom<HTMLFormElement>,
37    validity_state: MutNullableDom<ValidityState>,
38}
39
40impl HTMLObjectElement {
41    fn new_inherited(
42        local_name: LocalName,
43        prefix: Option<Prefix>,
44        document: &Document,
45    ) -> HTMLObjectElement {
46        HTMLObjectElement {
47            htmlelement: HTMLElement::new_inherited(local_name, prefix, document),
48            image: DomRefCell::new(None),
49            form_owner: Default::default(),
50            validity_state: Default::default(),
51        }
52    }
53
54    pub(crate) fn new(
55        cx: &mut js::context::JSContext,
56        local_name: LocalName,
57        prefix: Option<Prefix>,
58        document: &Document,
59        proto: Option<HandleObject>,
60    ) -> DomRoot<HTMLObjectElement> {
61        Node::reflect_node_with_proto(
62            cx,
63            Box::new(HTMLObjectElement::new_inherited(
64                local_name, prefix, document,
65            )),
66            document,
67            proto,
68        )
69    }
70}
71
72trait ProcessDataURL {
73    fn process_data_url(&self);
74}
75
76impl ProcessDataURL for &HTMLObjectElement {
77    // Makes the local `data` member match the status of the `data` attribute and starts
78    /// prefetching the image. This method must be called after `data` is changed.
79    fn process_data_url(&self) {
80        let element = self.upcast::<Element>();
81
82        // TODO: support other values
83        if let (None, Some(_uri)) = (
84            element.get_attribute_string_value(&local_name!("type")),
85            element.get_attribute_string_value(&local_name!("data")),
86        ) {
87            // TODO(gw): Prefetch the image here.
88        }
89    }
90}
91
92impl HTMLObjectElementMethods<crate::DomTypeHolder> for HTMLObjectElement {
93    // https://html.spec.whatwg.org/multipage/#dom-object-type
94    make_getter!(Type, "type");
95
96    // https://html.spec.whatwg.org/multipage/#dom-object-type
97    make_setter!(SetType, "type");
98
99    // https://html.spec.whatwg.org/multipage/#dom-object-usemap
100    make_getter!(UseMap, "usemap");
101
102    // https://html.spec.whatwg.org/multipage/#dom-object-usemap
103    make_setter!(SetUseMap, "usemap");
104
105    // <https://html.spec.whatwg.org/multipage/#dom-object-width>
106    make_getter!(Width, "width");
107    // <https://html.spec.whatwg.org/multipage/#dom-object-width>
108    make_dimension_setter!(SetWidth, "width");
109
110    // <https://html.spec.whatwg.org/multipage/#dom-object-height>
111    make_getter!(Height, "height");
112    // <https://html.spec.whatwg.org/multipage/#dom-object-height>
113    make_dimension_setter!(SetHeight, "height");
114
115    // https://html.spec.whatwg.org/multipage/#dom-object-hspace
116    make_dimension_uint_getter!(Hspace, "hspace");
117    // https://html.spec.whatwg.org/multipage/#dom-object-hspace
118    make_dimension_uint_setter!(SetHspace, "hspace");
119
120    // https://html.spec.whatwg.org/multipage/#dom-object-vspace
121    make_dimension_uint_getter!(Vspace, "vspace");
122    // https://html.spec.whatwg.org/multipage/#dom-object-vspace
123    make_dimension_uint_setter!(SetVspace, "vspace");
124
125    /// <https://html.spec.whatwg.org/multipage/#dom-fae-form>
126    fn GetForm(&self) -> Option<DomRoot<HTMLFormElement>> {
127        self.form_owner()
128    }
129
130    /// <https://html.spec.whatwg.org/multipage/#dom-cva-willvalidate>
131    fn WillValidate(&self, no_gc: &NoGC) -> bool {
132        self.is_instance_validatable(no_gc)
133    }
134
135    /// <https://html.spec.whatwg.org/multipage/#dom-cva-validity>
136    fn Validity(&self, cx: &mut JSContext) -> DomRoot<ValidityState> {
137        self.validity_state(cx)
138    }
139
140    /// <https://html.spec.whatwg.org/multipage/#dom-cva-checkvalidity>
141    fn CheckValidity(&self, cx: &mut JSContext) -> bool {
142        self.check_validity(cx)
143    }
144
145    /// <https://html.spec.whatwg.org/multipage/#dom-cva-reportvalidity>
146    fn ReportValidity(&self, cx: &mut JSContext) -> bool {
147        self.report_validity(cx)
148    }
149
150    /// <https://html.spec.whatwg.org/multipage/#dom-cva-validationmessage>
151    fn ValidationMessage(&self, cx: &mut JSContext) -> DOMString {
152        self.validation_message(cx)
153    }
154
155    /// <https://html.spec.whatwg.org/multipage/#dom-cva-setcustomvalidity>
156    fn SetCustomValidity(&self, cx: &mut JSContext, error: DOMString) {
157        self.validity_state(cx).set_custom_error_message(cx, error);
158    }
159}
160
161impl Validatable for HTMLObjectElement {
162    fn as_element(&self) -> &Element {
163        self.upcast()
164    }
165
166    fn validity_state(&self, cx: &mut JSContext) -> DomRoot<ValidityState> {
167        self.validity_state
168            .or_init(|| ValidityState::new(cx, &self.owner_window(), self.upcast()))
169    }
170
171    fn is_instance_validatable(&self, _no_gc: &NoGC) -> bool {
172        // https://html.spec.whatwg.org/multipage/#the-object-element%3Abarred-from-constraint-validation
173        false
174    }
175}
176
177impl VirtualMethods for HTMLObjectElement {
178    fn super_type(&self) -> Option<&dyn VirtualMethods> {
179        Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
180    }
181
182    fn attribute_mutated(
183        &self,
184        cx: &mut js::context::JSContext,
185        attr: AttrRef<'_>,
186        mutation: AttributeMutation,
187    ) {
188        self.super_type()
189            .unwrap()
190            .attribute_mutated(cx, attr, mutation);
191        match *attr.local_name() {
192            local_name!("data") => {
193                if let AttributeMutation::Set(_) = mutation {
194                    self.process_data_url();
195                }
196            },
197            local_name!("form") => {
198                self.form_attribute_mutated(cx, mutation);
199            },
200            _ => {},
201        }
202    }
203
204    fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue {
205        match *name {
206            local_name!("width") |
207            local_name!("height") |
208            local_name!("hspace") |
209            local_name!("vspace") => AttrValue::from_dimension(value.into()),
210            _ => self
211                .super_type()
212                .unwrap()
213                .parse_plain_attribute(name, value),
214        }
215    }
216
217    fn attribute_affects_presentational_hints(&self, attr: AttrRef<'_>) -> bool {
218        match attr.local_name() {
219            &local_name!("width") |
220            &local_name!("height") |
221            &local_name!("hspace") |
222            &local_name!("vspace") => true,
223            _ => self
224                .super_type()
225                .unwrap()
226                .attribute_affects_presentational_hints(attr),
227        }
228    }
229}
230
231impl FormControl for HTMLObjectElement {
232    fn form_owner(&self) -> Option<DomRoot<HTMLFormElement>> {
233        self.form_owner.get()
234    }
235
236    fn set_form_owner(&self, _cx: &mut JSContext, form: Option<&HTMLFormElement>) {
237        self.form_owner.set(form);
238    }
239
240    fn to_html_element(&self) -> &HTMLElement {
241        self.upcast::<HTMLElement>()
242    }
243}
244
245impl LayoutDom<'_, HTMLObjectElement> {
246    pub(crate) fn width(self) -> LengthOrPercentageOrAuto {
247        self.upcast::<Element>()
248            .dimension_attr_value(local_name!("width"))
249    }
250
251    pub(crate) fn height(self) -> LengthOrPercentageOrAuto {
252        self.upcast::<Element>()
253            .dimension_attr_value(local_name!("height"))
254    }
255
256    pub(crate) fn margin_right_left(self) -> LengthOrPercentageOrAuto {
257        self.upcast::<Element>()
258            .dimension_attr_value(local_name!("hspace"))
259    }
260
261    pub(crate) fn margin_top_bottom(self) -> LengthOrPercentageOrAuto {
262        self.upcast::<Element>()
263            .dimension_attr_value(local_name!("vspace"))
264    }
265}