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