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