script/dom/media/
mediaquerylist.rs1use std::cell::Cell;
6use std::rc::Rc;
7
8use dom_struct::dom_struct;
9use js::context::JSContext;
10use script_bindings::callback::RootedCallback;
11use script_bindings::reflector::reflect_weak_referenceable_dom_object;
12use style::media_queries::MediaList;
13use style::stylesheets::CustomMediaEvaluator;
14use style_traits::ToCss;
15
16use crate::dom::bindings::codegen::Bindings::EventListenerBinding::EventListener;
17use crate::dom::bindings::codegen::Bindings::EventTargetBinding::{
18 AddEventListenerOptions, EventListenerOptions,
19};
20use crate::dom::bindings::codegen::Bindings::MediaQueryListBinding::MediaQueryListMethods;
21use crate::dom::bindings::inheritance::Castable;
22use crate::dom::bindings::root::{Dom, DomRoot};
23use crate::dom::bindings::str::DOMString;
24use crate::dom::document::Document;
25use crate::dom::eventtarget::EventTarget;
26
27pub(crate) enum MediaQueryListMatchState {
28 Same,
29 Changed,
30}
31
32#[dom_struct]
33pub(crate) struct MediaQueryList {
34 eventtarget: EventTarget,
35 document: Dom<Document>,
36 #[no_trace]
37 media_query_list: MediaList,
38 last_match_state: Cell<Option<bool>>,
39}
40
41impl MediaQueryList {
42 fn new_inherited(document: &Document, media_query_list: MediaList) -> MediaQueryList {
43 MediaQueryList {
44 eventtarget: EventTarget::new_inherited(),
45 document: Dom::from_ref(document),
46 media_query_list,
47 last_match_state: Cell::new(None),
48 }
49 }
50
51 pub(crate) fn new(
52 cx: &mut JSContext,
53 document: &Document,
54 media_query_list: MediaList,
55 ) -> DomRoot<MediaQueryList> {
56 reflect_weak_referenceable_dom_object(
57 cx,
58 Rc::new(MediaQueryList::new_inherited(document, media_query_list)),
59 document.window(),
60 )
61 }
62}
63
64impl MediaQueryList {
65 pub(crate) fn evaluate_changes(&self) -> MediaQueryListMatchState {
66 let matches = self.evaluate();
67
68 let result = if let Some(old_matches) = self.last_match_state.get() {
69 if old_matches == matches {
70 MediaQueryListMatchState::Same
71 } else {
72 MediaQueryListMatchState::Changed
73 }
74 } else {
75 MediaQueryListMatchState::Changed
76 };
77
78 self.last_match_state.set(Some(matches));
79 result
80 }
81
82 pub(crate) fn evaluate(&self) -> bool {
83 let quirks_mode = self.document.quirks_mode();
84 self.media_query_list.evaluate(
85 self.document.window().layout().device(),
86 quirks_mode,
87 &mut CustomMediaEvaluator::none(),
88 )
89 }
90}
91
92impl MediaQueryListMethods<crate::DomTypeHolder> for MediaQueryList {
93 fn Media(&self) -> DOMString {
95 self.media_query_list.to_css_string().into()
96 }
97
98 fn Matches(&self) -> bool {
100 match self.last_match_state.get() {
101 None => self.evaluate(),
102 Some(state) => state,
103 }
104 }
105
106 fn AddListener(&self, listener: Option<RootedCallback<EventListener>>) {
108 self.upcast::<EventTarget>().add_event_listener(
109 DOMString::from_static("change"),
110 listener,
111 AddEventListenerOptions {
112 parent: EventListenerOptions { capture: false },
113 once: false,
114 passive: None,
115 signal: None,
116 },
117 );
118 }
119
120 fn RemoveListener(&self, listener: Option<RootedCallback<EventListener>>) {
122 self.upcast::<EventTarget>().remove_event_listener(
123 DOMString::from_static("change"),
124 listener.as_deref(),
125 &EventListenerOptions { capture: false },
126 );
127 }
128
129 event_handler!(change, GetOnchange, SetOnchange);
131}