Skip to main content

script/dom/
macros.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
5#[macro_export]
6macro_rules! make_getter(
7    ( $attr:ident, $htmlname:tt ) => (
8        fn $attr(&self) -> DOMString {
9            use $crate::dom::bindings::inheritance::Castable;
10            use $crate::dom::element::Element;
11            let element = self.upcast::<Element>();
12            element.get_string_attribute(&html5ever::local_name!($htmlname))
13        }
14    );
15);
16
17#[macro_export]
18macro_rules! make_bool_getter(
19    ( $attr:ident, $htmlname:tt ) => (
20        fn $attr(&self) -> bool {
21            use $crate::dom::bindings::inheritance::Castable;
22            use $crate::dom::element::Element;
23            let element = self.upcast::<Element>();
24            element.has_attribute(&html5ever::local_name!($htmlname))
25        }
26    );
27);
28
29#[macro_export]
30macro_rules! make_limited_int_setter(
31    ($attr:ident, $htmlname:tt, $default:expr) => (
32        fn $attr(&self, cx: &mut js::context::JSContext, value: i32) -> $crate::dom::bindings::error::ErrorResult {
33            use $crate::dom::bindings::inheritance::Castable;
34            use $crate::dom::element::Element;
35
36            let value = if value < 0 {
37                return Err($crate::dom::bindings::error::Error::IndexSize(None));
38            } else {
39                value
40            };
41
42            let element = self.upcast::<Element>();
43            element.set_int_attribute(cx, &html5ever::local_name!($htmlname), value);
44            Ok(())
45        }
46    );
47);
48
49#[macro_export]
50macro_rules! make_int_setter(
51    ($attr:ident, $htmlname:tt) => (
52        fn $attr(&self, cx: &mut js::context::JSContext, value: i32) {
53            use $crate::dom::bindings::inheritance::Castable;
54            use $crate::dom::element::Element;
55
56            let element = self.upcast::<Element>();
57            element.set_int_attribute(cx, &html5ever::local_name!($htmlname), value)
58        }
59    );
60);
61
62#[macro_export]
63macro_rules! make_int_getter(
64    ($attr:ident, $htmlname:tt, $default:expr) => (
65        fn $attr(&self) -> i32 {
66            use $crate::dom::bindings::inheritance::Castable;
67            use $crate::dom::element::element::Element;
68            let element = self.upcast::<Element>();
69            element.get_int_attribute(&html5ever::local_name!($htmlname), $default)
70        }
71    );
72
73    ($attr:ident, $htmlname:tt) => {
74        make_int_getter!($attr, $htmlname, 0);
75    };
76);
77
78#[macro_export]
79macro_rules! make_uint_getter(
80    ($attr:ident, $htmlname:tt, $default:expr) => (
81        fn $attr(&self) -> u32 {
82            use $crate::dom::bindings::inheritance::Castable;
83            use $crate::dom::element::Element;
84            let element = self.upcast::<Element>();
85            element.get_uint_attribute(&html5ever::local_name!($htmlname), $default)
86        }
87    );
88    ($attr:ident, $htmlname:tt) => {
89        make_uint_getter!($attr, $htmlname, 0);
90    };
91);
92
93#[macro_export]
94macro_rules! make_url_getter(
95    ( $attr:ident, $htmlname:tt ) => (
96        fn $attr(&self) -> USVString {
97            use $crate::dom::bindings::inheritance::Castable;
98            use $crate::dom::element::Element;
99            let element = self.upcast::<Element>();
100            element.get_url_attribute(&html5ever::local_name!($htmlname))
101        }
102    );
103);
104
105macro_rules! make_url_setter_inner(
106    ( $self:ident, $value:ident, $htmlname:tt, $can_gc:expr ) => (
107        use $crate::dom::bindings::inheritance::Castable;
108        use $crate::dom::element::Element;
109        use $crate::script_runtime::CanGc;
110        let element = $self.upcast::<Element>();
111        element.set_url_attribute(&html5ever::local_name!($htmlname), $value, $can_gc)
112    );
113);
114
115#[macro_export]
116macro_rules! make_url_setter(
117    ( $attr:ident, $htmlname:tt ) => (
118        fn $attr(&self, cx: &mut js::context::JSContext, value: USVString) {
119            make_url_setter_inner!(self, value, $htmlname, CanGc::from_cx(cx));
120        }
121    );
122    ( $cx:ident, $attr:ident, $htmlname:tt ) => (
123        fn $attr(&self, $cx: &mut js::context::JSContext, value: USVString) {
124            make_url_setter_inner!(self, value, $htmlname, CanGc::from_cx($cx));
125        }
126    );
127);
128
129#[macro_export]
130macro_rules! make_form_action_getter(
131    ( $attr:ident, $htmlname:tt ) => (
132        fn $attr(&self) -> DOMString {
133            use $crate::dom::bindings::inheritance::Castable;
134            use $crate::dom::element::Element;
135            let element = self.upcast::<Element>();
136            let doc = $crate::dom::node::NodeTraits::owner_document(self);
137            let attr = element.get_attribute(&html5ever::local_name!($htmlname));
138            let value = attr.as_ref().map(|attr| attr.value());
139            let value = match value {
140                Some(ref value) if !value.is_empty() => &***value,
141                _ => return doc.url().into_string().into(),
142            };
143            match doc.encoding_parse_a_url(value) {
144                Ok(parsed) => parsed.into_string().into(),
145                Err(_) => value.to_owned().into(),
146            }
147        }
148    );
149);
150
151#[macro_export]
152macro_rules! make_labels_getter(
153    ( $attr:ident, $memo:ident ) => (
154        fn $attr(&self) -> DomRoot<NodeList> {
155            use $crate::dom::html::htmlelement::HTMLElement;
156            use $crate::dom::nodelist::NodeList;
157            self.$memo.or_init(|| NodeList::new_labels_list(
158                self.upcast::<Node>().owner_doc().window(),
159                self.upcast::<HTMLElement>(),
160                CanGc::deprecated_note()
161                )
162            )
163        }
164    );
165);
166
167/// Implements the `To determine the state of an attribute` steps from
168/// <https://html.spec.whatwg.org/multipage/#keywords-and-enumerated-attributes>
169macro_rules! make_enumerated_getter(
170    ($attr:ident,
171        $htmlname:tt,
172        $($choices:literal)|+,
173        missing => $missing:literal,
174        invalid => $invalid:literal,
175        empty => $empty:literal
176    ) => (
177        fn $attr(&self) -> DOMString {
178            use $crate::dom::bindings::inheritance::Castable;
179            use $crate::dom::element::Element;
180            use $crate::dom::bindings::codegen::Bindings::AttrBinding::Attr_Binding::AttrMethods;
181
182            let attr_or_none = self.upcast::<Element>()
183                .get_attribute(&html5ever::local_name!($htmlname));
184            match attr_or_none  {
185                // Step 1. If the attribute is not specified:
186                None => {
187                    // Step 1.1. If the attribute has a missing value default state defined, then return that
188                    // missing value default state.
189                    // Step 1.2 Otherwise, return no state.
190                    return DOMString::from($missing);
191                },
192                Some(attr) => {
193                    // Step 2. If the attribute's value is an ASCII case-insensitive match for one of the keywords
194                    // defined for the attribute, then return the state represented by that keyword.
195                    let value: DOMString = attr.Value().to_ascii_lowercase().into();
196                    $(
197                        if value.str() == $choices {
198                            return value;
199                        }
200                    )+
201
202                    // Step 3. If the attribute has an empty value default state defined and the attribute's value
203                    // is the empty string, then return that empty value default state.
204                    if value.is_empty() {
205                        return DOMString::from($empty)
206                    }
207
208                    // Step 4. If the attribute has an invalid value default state defined, then return that invalid
209                    // value default state.
210                    // Step 5. Return no state.
211                    return DOMString::from($invalid);
212                }
213            }
214        }
215    );
216    ($attr:ident,
217        $htmlname:tt,
218        $($choices:literal)|+,
219    ) => (
220        make_enumerated_getter!(
221            $attr,
222            $htmlname,
223            $($choices)|+,
224            missing => "",
225            invalid => "",
226            empty => ""
227        );
228    );
229    ($attr:ident,
230        $htmlname:tt,
231        $($choices:literal)|+,
232        invalid => $invalid:literal
233    ) => (
234        make_enumerated_getter!(
235            $attr,
236            $htmlname,
237            $($choices)|+,
238            missing => "",
239            invalid => $invalid,
240            empty => $invalid
241        );
242    );
243    ($attr:ident,
244        $htmlname:tt,
245        $($choices:literal)|+,
246        missing => $missing:literal,
247    ) => (
248        make_enumerated_getter!(
249            $attr,
250            $htmlname,
251            $($choices)|+,
252            missing => $missing,
253            invalid => "",
254            empty => ""
255        );
256    );
257    ($attr:ident,
258        $htmlname:tt,
259        $($choices:literal)|+,
260        missing => $missing:literal,
261        invalid => $invalid:literal
262    ) => (
263        make_enumerated_getter!(
264            $attr,
265            $htmlname,
266            $($choices)|+,
267            missing => $missing,
268            invalid => $invalid,
269            empty => $invalid
270        );
271    );
272);
273
274macro_rules! make_setter_inner(
275    ( $self:ident, $value:ident, $htmlname:tt, $can_gc:expr ) => (
276        use $crate::dom::bindings::inheritance::Castable;
277        use $crate::dom::element::Element;
278        use $crate::script_runtime::CanGc;
279        let element = $self.upcast::<Element>();
280        element.set_string_attribute(&html5ever::local_name!($htmlname), $value, $can_gc)
281    );
282);
283
284// concat_idents! doesn't work for function name positions, so
285// we have to specify both the content name and the HTML name here
286#[macro_export]
287macro_rules! make_setter(
288    ( $attr:ident, $htmlname:tt ) => (
289        fn $attr(&self, cx: &mut js::context::JSContext, value: DOMString) {
290            make_setter_inner!(self, value, $htmlname, CanGc::from_cx(cx));
291        }
292    );
293    ( $cx:ident, $attr:ident, $htmlname:tt ) => (
294        fn $attr(&self, $cx: &mut js::context::JSContext, value: DOMString) {
295            make_setter_inner!(self, value, $htmlname, CanGc::from_cx($cx));
296        }
297    );
298);
299
300macro_rules! make_bool_setter_inner(
301    ( $self:ident, $value:ident, $htmlname:tt, $cx:expr ) => (
302        use $crate::dom::bindings::inheritance::Castable;
303        use $crate::dom::element::Element;
304        let element = $self.upcast::<Element>();
305        element.set_bool_attribute($cx, &html5ever::local_name!($htmlname), $value)
306    );
307);
308
309#[macro_export]
310macro_rules! make_bool_setter(
311    ( $attr:ident, $htmlname:tt ) => (
312        fn $attr(&self, cx: &mut js::context::JSContext, value: bool) {
313            make_bool_setter_inner!(self, value, $htmlname, cx);
314        }
315    );
316    ( $cx:ident, $attr:ident, $htmlname:tt ) => (
317        fn $attr(&self, $cx: &mut js::context::JSContext, value: bool) {
318            make_bool_setter_inner!(self, value, $htmlname, $cx);
319        }
320    );
321);
322
323#[macro_export]
324macro_rules! make_uint_setter(
325    ($attr:ident, $htmlname:tt, $default:expr) => (
326        fn $attr(&self, cx: &mut js::context::JSContext, value: u32) {
327            use $crate::dom::bindings::inheritance::Castable;
328            use $crate::dom::element::Element;
329            use $crate::dom::values::UNSIGNED_LONG_MAX;
330            use $crate::script_runtime::CanGc;
331            let value = if value > UNSIGNED_LONG_MAX {
332                $default
333            } else {
334                value
335            };
336            let element = self.upcast::<Element>();
337            element.set_uint_attribute(&html5ever::local_name!($htmlname), value, CanGc::from_cx(cx))
338        }
339    );
340    ($attr:ident, $htmlname:tt) => {
341        make_uint_setter!($attr, $htmlname, 0);
342    };
343);
344
345#[macro_export]
346macro_rules! make_clamped_uint_setter(
347    ($attr:ident, $htmlname:tt, $min:expr, $max:expr, $default:expr) => (
348        fn $attr(&self, cx: &mut js::context::JSContext, value: u32) {
349            use $crate::dom::bindings::inheritance::Castable;
350            use $crate::dom::element::Element;
351            use $crate::dom::values::UNSIGNED_LONG_MAX;
352            use $crate::script_runtime::CanGc;
353            let value = if value > UNSIGNED_LONG_MAX {
354                $default
355            } else {
356                value.clamp($min, $max)
357            };
358
359            let element = self.upcast::<Element>();
360            element.set_uint_attribute(&html5ever::local_name!($htmlname), value, CanGc::from_cx(cx))
361        }
362    );
363);
364
365#[macro_export]
366macro_rules! make_limited_uint_setter(
367    ($attr:ident, $htmlname:tt, $default:expr) => (
368        fn $attr(&self, cx: &mut js::context::JSContext, value: u32) -> $crate::dom::bindings::error::ErrorResult {
369            use $crate::dom::bindings::inheritance::Castable;
370            use $crate::dom::element::Element;
371            use $crate::dom::values::UNSIGNED_LONG_MAX;
372            use $crate::script_runtime::CanGc;
373            let value = if value == 0 {
374                return Err($crate::dom::bindings::error::Error::IndexSize(None));
375            } else if value > UNSIGNED_LONG_MAX {
376                $default
377            } else {
378                value
379            };
380            let element = self.upcast::<Element>();
381            element.set_uint_attribute(&html5ever::local_name!($htmlname), value, CanGc::from_cx(cx));
382            Ok(())
383        }
384    );
385);
386
387macro_rules! make_atomic_setter_inner(
388    ( $self:ident, $value:ident, $htmlname:tt, $cx:expr ) => (
389        use $crate::dom::bindings::inheritance::Castable;
390        use $crate::dom::element::Element;
391        let element = $self.upcast::<Element>();
392        element.set_atomic_attribute($cx, &html5ever::local_name!($htmlname), $value)
393    );
394);
395
396#[macro_export]
397macro_rules! make_atomic_setter(
398    ( $attr:ident, $htmlname:tt ) => (
399        fn $attr(&self, cx: &mut js::context::JSContext, value: DOMString) {
400            make_atomic_setter_inner!(self, value, $htmlname, cx);
401        }
402    );
403    ( $cx:ident, $attr:ident, $htmlname:tt ) => (
404        fn $attr(&self, $cx: &mut js::context::JSContext, value: DOMString) {
405            make_atomic_setter_inner!(self, value, $htmlname, $cx);
406        }
407    );
408);
409
410#[macro_export]
411macro_rules! make_legacy_color_setter(
412    ( $attr:ident, $htmlname:tt ) => (
413        fn $attr(&self, cx: &mut js::context::JSContext, value: DOMString) {
414            use $crate::dom::bindings::inheritance::Castable;
415            use $crate::dom::element::Element;
416            use style::attr::AttrValue;
417            use $crate::script_runtime::CanGc;
418            let element = self.upcast::<Element>();
419            let value = AttrValue::from_legacy_color(value.into());
420            element.set_attribute(&html5ever::local_name!($htmlname), value, CanGc::from_cx(cx))
421        }
422    );
423);
424
425#[macro_export]
426macro_rules! make_dimension_setter(
427    ( $attr:ident, $htmlname:tt ) => (
428        fn $attr(&self, cx: &mut js::context::JSContext, value: DOMString) {
429            use $crate::dom::bindings::inheritance::Castable;
430            use $crate::dom::element::Element;
431            use $crate::script_runtime::CanGc;
432            let element = self.upcast::<Element>();
433            let value = AttrValue::from_dimension(value.into());
434            element.set_attribute(&html5ever::local_name!($htmlname), value, CanGc::from_cx(cx))
435        }
436    );
437);
438
439#[macro_export]
440macro_rules! make_nonzero_dimension_setter(
441    ( $attr:ident, $htmlname:tt ) => (
442        fn $attr(&self, cx: &mut js::context::JSContext, value: DOMString) {
443            use $crate::dom::bindings::inheritance::Castable;
444            use $crate::dom::element::Element;
445            use $crate::script_runtime::CanGc;
446            let element = self.upcast::<Element>();
447            let value = AttrValue::from_nonzero_dimension(value.into());
448            element.set_attribute(&html5ever::local_name!($htmlname), value, CanGc::from_cx(cx))
449        }
450    );
451);
452
453#[macro_export]
454macro_rules! make_dimension_uint_getter(
455    ($attr:ident, $htmlname:tt, $default:expr) => (
456        fn $attr(&self) -> u32 {
457            use style::attr::parse_unsigned_integer;
458            use $crate::dom::bindings::inheritance::Castable;
459            use $crate::dom::element::Element;
460            use $crate::dom::values::UNSIGNED_LONG_MAX;
461            let element = self.upcast::<Element>();
462            element
463                .get_attribute(&html5ever::local_name!($htmlname))
464                .map_or($default, |attribute| parse_unsigned_integer(attribute.value().chars())
465                    .map_or($default, |value| {
466                        if value > UNSIGNED_LONG_MAX {
467                            $default
468                        } else {
469                            value
470                        }
471                    })
472                )
473        }
474    );
475    ($attr:ident, $htmlname:tt) => {
476        make_dimension_uint_getter!($attr, $htmlname, 0);
477    };
478);
479
480#[macro_export]
481macro_rules! make_dimension_uint_setter(
482    ($attr:ident, $htmlname:tt, $default:expr) => (
483        fn $attr(&self, cx: &mut js::context::JSContext, value: u32) {
484            use $crate::dom::bindings::inheritance::Castable;
485            use $crate::dom::element::Element;
486            use $crate::dom::values::UNSIGNED_LONG_MAX;
487            use $crate::script_runtime::CanGc;
488            let element = self.upcast::<Element>();
489            let value = if value > UNSIGNED_LONG_MAX {
490                $default
491            } else {
492                value
493            };
494            let value = AttrValue::from_dimension(value.to_string());
495            element.set_attribute(&html5ever::local_name!($htmlname), value, CanGc::from_cx(cx))
496        }
497    );
498    ($attr:ident, $htmlname:tt) => {
499        make_dimension_uint_setter!($attr, $htmlname, 0);
500    };
501);
502
503/// For use on non-jsmanaged types
504/// Use #[derive(JSTraceable)] on JS managed types
505macro_rules! unsafe_no_jsmanaged_fields(
506    ($($ty:ty),+) => (
507        $(
508            #[expect(unsafe_code)]
509            unsafe impl $crate::dom::bindings::trace::JSTraceable for $ty {
510                #[inline]
511                unsafe fn trace(&self, _: *mut ::js::jsapi::JSTracer) {
512                    // Do nothing
513                }
514            }
515        )+
516    );
517);
518
519/// These are used to generate a event handler which has no special case.
520macro_rules! define_event_handler(
521    ($handler: ty, $event_type: ident, $getter: ident, $setter: ident, $setter_fn: ident) => (
522        fn $getter(&self, cx: &mut js::context::JSContext) -> Option<::std::rc::Rc<$handler>> {
523            use crate::dom::bindings::inheritance::Castable;
524            use crate::dom::eventtarget::EventTarget;
525            let eventtarget = self.upcast::<EventTarget>();
526            eventtarget.get_event_handler_common(cx, stringify!($event_type))
527        }
528
529        fn $setter(&self, cx: &mut js::context::JSContext, listener: Option<::std::rc::Rc<$handler>>) {
530            use crate::dom::bindings::inheritance::Castable;
531            use crate::dom::eventtarget::EventTarget;
532            let eventtarget = self.upcast::<EventTarget>();
533            eventtarget.$setter_fn(cx, stringify!($event_type), listener)
534        }
535    )
536);
537
538macro_rules! define_window_owned_event_handler(
539    ($handler: ty, $event_type: ident, $getter: ident, $setter: ident) => (
540        fn $getter(&self, cx: &mut js::context::JSContext) -> Option<::std::rc::Rc<$handler>> {
541            let document = self.owner_document();
542            if document.has_browsing_context() {
543                document.window().$getter(cx)
544            } else {
545                None
546            }
547        }
548
549        fn $setter(&self, cx: &mut js::context::JSContext, listener: Option<::std::rc::Rc<$handler>>) {
550            let document = self.owner_document();
551            if document.has_browsing_context() {
552                document.window().$setter(cx, listener)
553            }
554        }
555    )
556);
557
558macro_rules! event_handler(
559    ($event_type: ident, $getter: ident, $setter: ident) => (
560        define_event_handler!(
561            crate::dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull,
562            $event_type,
563            $getter,
564            $setter,
565            set_event_handler_common
566        );
567    )
568);
569
570/// Similar to `event_handler!`, but also registers/unregisters a [`ConstellationInterest`]
571/// with the global scope when the handler is set or cleared.
572/// Use this macro for event handlers whose corresponding events are sent by the constellation
573/// only to interested pipelines.
574macro_rules! registered_event_handler(
575    ($interest:expr, $event_type: ident, $getter: ident, $setter: ident) => (
576        fn $getter(&self, cx: &mut js::context::JSContext) -> Option<::std::rc::Rc<
577            crate::dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull,
578        >> {
579            use crate::dom::bindings::inheritance::Castable;
580            use crate::dom::eventtarget::EventTarget;
581            let eventtarget = self.upcast::<EventTarget>();
582            eventtarget.get_event_handler_common(cx, stringify!($event_type))
583        }
584
585        fn $setter(&self, cx: &mut js::context::JSContext, listener: Option<::std::rc::Rc<
586            crate::dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull,
587        >>) {
588            use crate::dom::bindings::inheritance::Castable;
589            use crate::dom::bindings::reflector::DomGlobal;
590            use crate::dom::eventtarget::EventTarget;
591            let had_handler = self.$getter(cx).is_some();
592            let has_handler = listener.is_some();
593            let eventtarget = self.upcast::<EventTarget>();
594            eventtarget.set_event_handler_common(cx, stringify!($event_type), listener);
595            if !had_handler && has_handler {
596                self.global().register_interest($interest);
597            } else if had_handler && !has_handler {
598                self.global().unregister_interest($interest);
599            }
600        }
601    )
602);
603
604macro_rules! error_event_handler(
605    ($event_type: ident, $getter: ident, $setter: ident) => (
606        define_event_handler!(
607            crate::dom::bindings::codegen::Bindings::EventHandlerBinding::OnErrorEventHandlerNonNull,
608            $event_type,
609            $getter,
610            $setter,
611            set_error_event_handler
612        );
613    )
614);
615
616macro_rules! beforeunload_event_handler(
617    ($event_type: ident, $getter: ident, $setter: ident) => (
618        define_event_handler!(
619            crate::dom::bindings::codegen::Bindings::EventHandlerBinding::OnBeforeUnloadEventHandlerNonNull,
620            $event_type,
621            $getter,
622            $setter,
623            set_beforeunload_event_handler
624        );
625    )
626);
627
628macro_rules! window_owned_event_handler(
629    ($event_type: ident, $getter: ident, $setter: ident) => (
630        define_window_owned_event_handler!(
631            crate::dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull,
632            $event_type,
633            $getter,
634            $setter
635        );
636    )
637);
638
639macro_rules! window_owned_beforeunload_event_handler(
640    ($event_type: ident, $getter: ident, $setter: ident) => (
641        define_window_owned_event_handler!(
642            crate::dom::bindings::codegen::Bindings::EventHandlerBinding::OnBeforeUnloadEventHandlerNonNull,
643            $event_type,
644            $getter,
645            $setter
646        );
647    )
648);
649
650// https://html.spec.whatwg.org/multipage/#globaleventhandlers
651// see webidls/EventHandler.webidl
652// As more methods get added, just update them here.
653macro_rules! global_event_handlers(
654    () => (
655        // These are special when on body/frameset elements
656        event_handler!(blur, GetOnblur, SetOnblur);
657        error_event_handler!(error, GetOnerror, SetOnerror);
658        event_handler!(focus, GetOnfocus, SetOnfocus);
659        event_handler!(load, GetOnload, SetOnload);
660        event_handler!(resize, GetOnresize, SetOnresize);
661        event_handler!(scroll, GetOnscroll, SetOnscroll);
662        global_event_handlers!(NoOnload);
663
664    );
665    (NoOnload) => (
666        event_handler!(abort, GetOnabort, SetOnabort);
667        event_handler!(auxclick, GetOnauxclick, SetOnauxclick);
668        event_handler!(animationstart, GetOnanimationstart, SetOnanimationstart);
669        event_handler!(animationiteration, GetOnanimationiteration, SetOnanimationiteration);
670        event_handler!(animationend, GetOnanimationend, SetOnanimationend);
671        event_handler!(animationcancel, GetOnanimationcancel, SetOnanimationcancel);
672        event_handler!(beforeinput, GetOnbeforeinput, SetOnbeforeinput);
673        event_handler!(beforematch, GetOnbeforematch, SetOnbeforematch);
674        event_handler!(beforetoggle, GetOnbeforetoggle, SetOnbeforetoggle);
675        event_handler!(cancel, GetOncancel, SetOncancel);
676        event_handler!(canplay, GetOncanplay, SetOncanplay);
677        event_handler!(canplaythrough, GetOncanplaythrough, SetOncanplaythrough);
678        event_handler!(change, GetOnchange, SetOnchange);
679        event_handler!(click, GetOnclick, SetOnclick);
680        event_handler!(close, GetOnclose, SetOnclose);
681        event_handler!(command, GetOncommand, SetOncommand);
682        event_handler!(contextlost, GetOncontextlost, SetOncontextlost);
683        event_handler!(contextmenu, GetOncontextmenu, SetOncontextmenu);
684        event_handler!(contextrestored, GetOncontextrestored, SetOncontextrestored);
685        event_handler!(copy, GetOncopy, SetOncopy);
686        event_handler!(cuechange, GetOncuechange, SetOncuechange);
687        event_handler!(cut, GetOncut, SetOncut);
688        event_handler!(dblclick, GetOndblclick, SetOndblclick);
689        event_handler!(drag, GetOndrag, SetOndrag);
690        event_handler!(dragend, GetOndragend, SetOndragend);
691        event_handler!(dragenter, GetOndragenter, SetOndragenter);
692        event_handler!(dragleave, GetOndragleave, SetOndragleave);
693        event_handler!(dragover, GetOndragover, SetOndragover);
694        event_handler!(dragstart, GetOndragstart, SetOndragstart);
695        event_handler!(drop, GetOndrop, SetOndrop);
696        event_handler!(durationchange, GetOndurationchange, SetOndurationchange);
697        event_handler!(emptied, GetOnemptied, SetOnemptied);
698        event_handler!(ended, GetOnended, SetOnended);
699        event_handler!(formdata, GetOnformdata, SetOnformdata);
700        event_handler!(input, GetOninput, SetOninput);
701        event_handler!(invalid, GetOninvalid, SetOninvalid);
702        event_handler!(keydown, GetOnkeydown, SetOnkeydown);
703        event_handler!(keypress, GetOnkeypress, SetOnkeypress);
704        event_handler!(keyup, GetOnkeyup, SetOnkeyup);
705        event_handler!(loadeddata, GetOnloadeddata, SetOnloadeddata);
706        event_handler!(loadedmetadata, GetOnloadedmetadata, SetOnloadedmetadata);
707        event_handler!(loadstart, GetOnloadstart, SetOnloadstart);
708        event_handler!(mousedown, GetOnmousedown, SetOnmousedown);
709        event_handler!(mouseenter, GetOnmouseenter, SetOnmouseenter);
710        event_handler!(mouseleave, GetOnmouseleave, SetOnmouseleave);
711        event_handler!(mousemove, GetOnmousemove, SetOnmousemove);
712        event_handler!(mouseout, GetOnmouseout, SetOnmouseout);
713        event_handler!(mouseover, GetOnmouseover, SetOnmouseover);
714        event_handler!(mouseup, GetOnmouseup, SetOnmouseup);
715        event_handler!(paste, GetOnpaste, SetOnpaste);
716        event_handler!(pause, GetOnpause, SetOnpause);
717        event_handler!(play, GetOnplay, SetOnplay);
718        event_handler!(playing, GetOnplaying, SetOnplaying);
719        event_handler!(pointercancel, GetOnpointercancel, SetOnpointercancel);
720        event_handler!(pointerdown, GetOnpointerdown, SetOnpointerdown);
721        event_handler!(pointerenter, GetOnpointerenter, SetOnpointerenter);
722        event_handler!(pointerleave, GetOnpointerleave, SetOnpointerleave);
723        event_handler!(pointermove, GetOnpointermove, SetOnpointermove);
724        event_handler!(pointerout, GetOnpointerout, SetOnpointerout);
725        event_handler!(pointerover, GetOnpointerover, SetOnpointerover);
726        event_handler!(pointerup, GetOnpointerup, SetOnpointerup);
727        event_handler!(progress, GetOnprogress, SetOnprogress);
728        event_handler!(ratechange, GetOnratechange, SetOnratechange);
729        event_handler!(reset, GetOnreset, SetOnreset);
730        event_handler!(scrollend, GetOnscrollend, SetOnscrollend);
731        event_handler!(securitypolicyviolation, GetOnsecuritypolicyviolation, SetOnsecuritypolicyviolation);
732        event_handler!(seeked, GetOnseeked, SetOnseeked);
733        event_handler!(seeking, GetOnseeking, SetOnseeking);
734        event_handler!(select, GetOnselect, SetOnselect);
735        event_handler!(selectionchange, GetOnselectionchange, SetOnselectionchange);
736        event_handler!(selectstart, GetOnselectstart, SetOnselectstart);
737        event_handler!(slotchange, GetOnslotchange, SetOnslotchange);
738        event_handler!(stalled, GetOnstalled, SetOnstalled);
739        event_handler!(submit, GetOnsubmit, SetOnsubmit);
740        event_handler!(suspend, GetOnsuspend, SetOnsuspend);
741        event_handler!(timeupdate, GetOntimeupdate, SetOntimeupdate);
742        event_handler!(toggle, GetOntoggle, SetOntoggle);
743        event_handler!(transitioncancel, GetOntransitioncancel, SetOntransitioncancel);
744        event_handler!(transitionend, GetOntransitionend, SetOntransitionend);
745        event_handler!(transitionrun, GetOntransitionrun, SetOntransitionrun);
746        event_handler!(volumechange, GetOnvolumechange, SetOnvolumechange);
747        event_handler!(waiting, GetOnwaiting, SetOnwaiting);
748        event_handler!(webkitanimationend, GetOnwebkitanimationend, SetOnwebkitanimationend);
749        event_handler!(webkitanimationiteration, GetOnwebkitanimationiteration, SetOnwebkitanimationiteration);
750        event_handler!(webkitanimationstart, GetOnwebkitanimationstart, SetOnwebkitanimationstart);
751        event_handler!(webkittransitionend, GetOnwebkittransitionend, SetOnwebkittransitionend);
752        event_handler!(wheel, GetOnwheel, SetOnwheel);
753    )
754);
755
756// https://html.spec.whatwg.org/multipage/#windoweventhandlers
757// see webidls/EventHandler.webidl
758// As more methods get added, just update them here.
759macro_rules! window_event_handlers(
760    () => (
761        event_handler!(afterprint, GetOnafterprint, SetOnafterprint);
762        event_handler!(beforeprint, GetOnbeforeprint, SetOnbeforeprint);
763        beforeunload_event_handler!(beforeunload, GetOnbeforeunload,
764                                    SetOnbeforeunload);
765        event_handler!(hashchange, GetOnhashchange, SetOnhashchange);
766        event_handler!(languagechange, GetOnlanguagechange,
767                       SetOnlanguagechange);
768        event_handler!(message, GetOnmessage, SetOnmessage);
769        event_handler!(messageerror, GetOnmessageerror, SetOnmessageerror);
770        event_handler!(offline, GetOnoffline, SetOnoffline);
771        event_handler!(online, GetOnonline, SetOnonline);
772        event_handler!(pagehide, GetOnpagehide, SetOnpagehide);
773        event_handler!(pagereveal, GetOnpagereveal, SetOnpagereveal);
774        event_handler!(pageshow, GetOnpageshow, SetOnpageshow);
775        event_handler!(pageswap, GetOnpageswap, SetOnpageswap);
776        event_handler!(popstate, GetOnpopstate, SetOnpopstate);
777        event_handler!(rejectionhandled, GetOnrejectionhandled,
778                       SetOnrejectionhandled);
779        registered_event_handler!(
780            servo_constellation_traits::ConstellationInterest::StorageEvent,
781            storage, GetOnstorage, SetOnstorage
782        );
783        event_handler!(unhandledrejection, GetOnunhandledrejection,
784                       SetOnunhandledrejection);
785        event_handler!(unload, GetOnunload, SetOnunload);
786        #[cfg(feature = "gamepad")]
787        event_handler!(gamepadconnected, GetOngamepadconnected, SetOngamepadconnected);
788        #[cfg(feature = "gamepad")]
789        event_handler!(gamepaddisconnected, GetOngamepaddisconnected, SetOngamepaddisconnected);
790    );
791    (ForwardToWindow) => (
792        window_owned_event_handler!(afterprint, GetOnafterprint,
793                                    SetOnafterprint);
794        window_owned_event_handler!(beforeprint, GetOnbeforeprint,
795                                    SetOnbeforeprint);
796        window_owned_beforeunload_event_handler!(beforeunload,
797                                                 GetOnbeforeunload,
798                                                 SetOnbeforeunload);
799        window_owned_event_handler!(hashchange, GetOnhashchange,
800                                    SetOnhashchange);
801        window_owned_event_handler!(languagechange, GetOnlanguagechange,
802                                    SetOnlanguagechange);
803        window_owned_event_handler!(message, GetOnmessage, SetOnmessage);
804        window_owned_event_handler!(messageerror, GetOnmessageerror, SetOnmessageerror);
805        window_owned_event_handler!(offline, GetOnoffline, SetOnoffline);
806        window_owned_event_handler!(online, GetOnonline, SetOnonline);
807        window_owned_event_handler!(pagehide, GetOnpagehide, SetOnpagehide);
808        window_owned_event_handler!(pagereveal, GetOnpagereveal, SetOnpagereveal);
809        window_owned_event_handler!(pageshow, GetOnpageshow, SetOnpageshow);
810        window_owned_event_handler!(pageswap, GetOnpageswap, SetOnpageswap);
811        window_owned_event_handler!(popstate, GetOnpopstate, SetOnpopstate);
812        window_owned_event_handler!(rejectionhandled, GetOnrejectionhandled,
813                                    SetOnrejectionhandled);
814        window_owned_event_handler!(storage, GetOnstorage, SetOnstorage);
815        window_owned_event_handler!(unhandledrejection, GetOnunhandledrejection,
816                                    SetOnunhandledrejection);
817        window_owned_event_handler!(unload, GetOnunload, SetOnunload);
818        #[cfg(feature = "gamepad")]
819        window_owned_event_handler!(gamepadconnected, GetOngamepadconnected, SetOngamepadconnected);
820        #[cfg(feature = "gamepad")]
821        window_owned_event_handler!(gamepaddisconnected, GetOngamepaddisconnected, SetOngamepaddisconnected);
822    );
823);
824
825/// DOM struct implementation for simple interfaces inheriting from PerformanceEntry.
826macro_rules! impl_performance_entry_struct(
827    ($binding:ident, $struct:ident, $type:path,
828        { $( $(#[$attr:meta])* $field_name:ident : $field_type:ty, ),* } // Arguments
829    ) => (
830        use servo_base::cross_process_instant::CrossProcessInstant;
831        use time::Duration;
832
833        use crate::dom::bindings::reflector::reflect_dom_object;
834        use crate::dom::bindings::root::DomRoot;
835        use crate::dom::bindings::str::DOMString;
836        use crate::dom::globalscope::GlobalScope;
837        use crate::dom::performance::performanceentry::{EntryType, PerformanceEntry};
838        use crate::script_runtime::CanGc;
839        use dom_struct::dom_struct;
840
841        #[dom_struct]
842        pub(crate) struct $struct {
843            entry: PerformanceEntry,
844            $( $(#[$attr])* $field_name: $field_type, )*
845        }
846
847        impl $struct {
848            #[cfg_attr(crown, expect(crown::unrooted_must_root))]
849            fn new_inherited(
850                name: DOMString,
851                start_time: CrossProcessInstant,
852                duration: Duration,
853                $( $field_name: $field_type, )* ) -> $struct {
854                $struct {
855                    entry: PerformanceEntry::new_inherited(name,
856                                                           $type,
857                                                           Some(start_time),
858                                                           duration),
859                    $( $field_name: $field_name, )*
860                }
861            }
862
863            #[cfg_attr(crown, expect(crown::unrooted_must_root))]
864            pub(crate) fn new(global: &GlobalScope,
865                       name: DOMString,
866                       start_time: CrossProcessInstant,
867                       duration: Duration,
868                       $( $field_name: $field_type ),*
869                    ) -> DomRoot<$struct> {
870                let entry = $struct::new_inherited(
871                    name,
872                    start_time,
873                    duration,
874                    $( $field_name, )*
875                );
876                reflect_dom_object(Box::new(entry), global, CanGc::deprecated_note())
877            }
878        }
879    );
880);
881
882macro_rules! handle_potential_webgl_error {
883    ($context:expr, $call:expr, $return_on_error:expr) => {
884        match $call {
885            Ok(ret) => ret,
886            Err(error) => {
887                $context.webgl_error(error);
888                $return_on_error
889            },
890        }
891    };
892    ($context:expr, $call:expr) => {
893        handle_potential_webgl_error!($context, $call, ())
894    };
895}