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