mirror of
https://github.com/servo/servo.git
synced 2025-07-24 15:50:21 +01:00
parent
99ad3678fa
commit
138a0480fe
22 changed files with 500 additions and 20 deletions
|
@ -68,6 +68,7 @@ serde = "0.8"
|
|||
smallvec = "0.1"
|
||||
string_cache = {version = "0.2.26", features = ["heap_size", "unstable"]}
|
||||
style = {path = "../style"}
|
||||
style_traits = {path = "../style_traits"}
|
||||
time = "0.1.12"
|
||||
url = {version = "1.2", features = ["heap_size", "query_encoding"]}
|
||||
util = {path = "../util"}
|
||||
|
|
|
@ -14,6 +14,10 @@
|
|||
|
||||
DOMInterfaces = {
|
||||
|
||||
'MediaQueryList': {
|
||||
'weakReferenceable': True,
|
||||
},
|
||||
|
||||
'Promise': {
|
||||
'spiderMonkeyInterface': True,
|
||||
},
|
||||
|
|
|
@ -90,6 +90,7 @@ use std::time::{SystemTime, Instant};
|
|||
use string_cache::{Atom, Namespace, QualName};
|
||||
use style::attr::{AttrIdentifier, AttrValue, LengthOrPercentageOrAuto};
|
||||
use style::element_state::*;
|
||||
use style::media_queries::MediaQueryList;
|
||||
use style::properties::PropertyDeclarationBlock;
|
||||
use style::selector_impl::{ElementSnapshot, PseudoElement};
|
||||
use style::values::specified::Length;
|
||||
|
@ -366,7 +367,7 @@ no_jsmanaged_fields!(WebGLProgramId);
|
|||
no_jsmanaged_fields!(WebGLRenderbufferId);
|
||||
no_jsmanaged_fields!(WebGLShaderId);
|
||||
no_jsmanaged_fields!(WebGLTextureId);
|
||||
|
||||
no_jsmanaged_fields!(MediaQueryList);
|
||||
|
||||
impl JSTraceable for Box<ScriptChan + Send> {
|
||||
#[inline]
|
||||
|
|
156
components/script/dom/mediaquerylist.rs
Normal file
156
components/script/dom/mediaquerylist.rs
Normal file
|
@ -0,0 +1,156 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use cssparser::ToCss;
|
||||
use dom::bindings::cell::DOMRefCell;
|
||||
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
|
||||
use dom::bindings::codegen::Bindings::EventListenerBinding::EventListener;
|
||||
use dom::bindings::codegen::Bindings::EventTargetBinding::EventTargetMethods;
|
||||
use dom::bindings::codegen::Bindings::MediaQueryListBinding::{self, MediaQueryListMethods};
|
||||
use dom::bindings::inheritance::Castable;
|
||||
use dom::bindings::js::{JS, Root};
|
||||
use dom::bindings::reflector::reflect_dom_object;
|
||||
use dom::bindings::str::DOMString;
|
||||
use dom::bindings::trace::JSTraceable;
|
||||
use dom::bindings::weakref::{WeakRef, WeakRefVec};
|
||||
use dom::document::Document;
|
||||
use dom::eventtarget::EventTarget;
|
||||
use euclid::scale_factor::ScaleFactor;
|
||||
use js::jsapi::JSTracer;
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
use style;
|
||||
use style::media_queries::{Device, MediaType};
|
||||
use style_traits::{PagePx, ViewportPx};
|
||||
|
||||
pub enum MediaQueryListMatchState {
|
||||
Same(bool),
|
||||
Changed(bool),
|
||||
}
|
||||
|
||||
#[dom_struct]
|
||||
pub struct MediaQueryList {
|
||||
eventtarget: EventTarget,
|
||||
document: JS<Document>,
|
||||
media_query_list: style::media_queries::MediaQueryList,
|
||||
last_match_state: Cell<Option<bool>>
|
||||
}
|
||||
|
||||
impl MediaQueryList {
|
||||
fn new_inherited(document: &Document,
|
||||
media_query_list: style::media_queries::MediaQueryList) -> MediaQueryList {
|
||||
MediaQueryList {
|
||||
eventtarget: EventTarget::new_inherited(),
|
||||
document: JS::from_ref(document),
|
||||
media_query_list: media_query_list,
|
||||
last_match_state: Cell::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(document: &Document,
|
||||
media_query_list: style::media_queries::MediaQueryList) -> Root<MediaQueryList> {
|
||||
reflect_dom_object(box MediaQueryList::new_inherited(document, media_query_list),
|
||||
document.window(),
|
||||
MediaQueryListBinding::Wrap)
|
||||
}
|
||||
}
|
||||
|
||||
impl MediaQueryList {
|
||||
fn evaluate_changes(&self) -> MediaQueryListMatchState {
|
||||
let matches = self.evaluate();
|
||||
|
||||
let result = if let Some(old_matches) = self.last_match_state.get() {
|
||||
if old_matches == matches {
|
||||
MediaQueryListMatchState::Same(matches)
|
||||
} else {
|
||||
MediaQueryListMatchState::Changed(matches)
|
||||
}
|
||||
} else {
|
||||
MediaQueryListMatchState::Changed(matches)
|
||||
};
|
||||
|
||||
self.last_match_state.set(Some(matches));
|
||||
result
|
||||
}
|
||||
|
||||
pub fn evaluate(&self) -> bool {
|
||||
if let Some(window_size) = self.document.window().window_size() {
|
||||
let viewport_size = window_size.visible_viewport;
|
||||
// TODO: support real ViewportPx, including zoom level
|
||||
// This information seems not to be tracked currently, so we assume
|
||||
// ViewportPx == PagePx
|
||||
let page_to_viewport: ScaleFactor<f32, PagePx, ViewportPx> = ScaleFactor::new(1.0);
|
||||
let device = Device::new(MediaType::Screen, viewport_size * page_to_viewport);
|
||||
self.media_query_list.evaluate(&device)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MediaQueryListMethods for MediaQueryList {
|
||||
// https://drafts.csswg.org/cssom-view/#dom-mediaquerylist-media
|
||||
fn Media(&self) -> DOMString {
|
||||
let mut s = String::new();
|
||||
self.media_query_list.to_css(&mut s).unwrap();
|
||||
DOMString::from_string(s)
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-mediaquerylist-matches
|
||||
fn Matches(&self) -> bool {
|
||||
match self.last_match_state.get() {
|
||||
None => self.evaluate(),
|
||||
Some(state) => state,
|
||||
}
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-mediaquerylist-addlistener
|
||||
fn AddListener(&self, listener: Option<Rc<EventListener>>) {
|
||||
self.upcast::<EventTarget>().AddEventListener(DOMString::from_string("change".to_owned()),
|
||||
listener, false);
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-mediaquerylist-removelistener
|
||||
fn RemoveListener(&self, listener: Option<Rc<EventListener>>) {
|
||||
self.upcast::<EventTarget>().RemoveEventListener(DOMString::from_string("change".to_owned()),
|
||||
listener, false);
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-mediaquerylist-onchange
|
||||
event_handler!(change, GetOnchange, SetOnchange);
|
||||
}
|
||||
|
||||
#[derive(HeapSizeOf)]
|
||||
pub struct WeakMediaQueryListVec {
|
||||
cell: DOMRefCell<WeakRefVec<MediaQueryList>>,
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
impl WeakMediaQueryListVec {
|
||||
/// Create a new vector of weak references to MediaQueryList
|
||||
pub fn new() -> Self {
|
||||
WeakMediaQueryListVec { cell: DOMRefCell::new(WeakRefVec::new()) }
|
||||
}
|
||||
|
||||
pub fn push(&self, mql: &MediaQueryList) {
|
||||
self.cell.borrow_mut().push(WeakRef::new(mql));
|
||||
}
|
||||
|
||||
/// Evaluate media query lists and report changes
|
||||
/// https://drafts.csswg.org/cssom-view/#evaluate-media-queries-and-report-changes
|
||||
pub fn evaluate_and_report_changes(&self) {
|
||||
for mql in self.cell.borrow().iter() {
|
||||
if let MediaQueryListMatchState::Changed(_) = mql.root().unwrap().evaluate_changes() {
|
||||
mql.root().unwrap().upcast::<EventTarget>().fire_simple_event("change");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
impl JSTraceable for WeakMediaQueryListVec {
|
||||
fn trace(&self, _: *mut JSTracer) {
|
||||
self.cell.borrow_mut().retain_alive()
|
||||
}
|
||||
}
|
|
@ -357,6 +357,7 @@ pub mod imagedata;
|
|||
pub mod keyboardevent;
|
||||
pub mod location;
|
||||
pub mod mediaerror;
|
||||
pub mod mediaquerylist;
|
||||
pub mod messageevent;
|
||||
pub mod mimetype;
|
||||
pub mod mimetypearray;
|
||||
|
|
14
components/script/dom/webidls/MediaQueryList.webidl
Normal file
14
components/script/dom/webidls/MediaQueryList.webidl
Normal file
|
@ -0,0 +1,14 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#mediaquerylist
|
||||
|
||||
[Exposed=(Window)]
|
||||
interface MediaQueryList : EventTarget {
|
||||
readonly attribute DOMString media;
|
||||
readonly attribute boolean matches;
|
||||
void addListener(EventListener? listener);
|
||||
void removeListener(EventListener? listener);
|
||||
attribute EventHandler onchange;
|
||||
};
|
|
@ -120,7 +120,7 @@ dictionary ScrollToOptions : ScrollOptions {
|
|||
|
||||
// http://dev.w3.org/csswg/cssom-view/#extensions-to-the-window-interface
|
||||
partial interface Window {
|
||||
//MediaQueryList matchMedia(DOMString query);
|
||||
[Exposed=(Window), NewObject] MediaQueryList matchMedia(DOMString query);
|
||||
[SameObject] readonly attribute Screen screen;
|
||||
|
||||
// browsing context
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use app_units::Au;
|
||||
use cssparser::Parser;
|
||||
use devtools_traits::{ScriptToDevtoolsControlMsg, TimelineMarker, TimelineMarkerType};
|
||||
use dom::bindings::callback::ExceptionHandling;
|
||||
use dom::bindings::cell::DOMRefCell;
|
||||
|
@ -35,6 +36,7 @@ use dom::globalscope::GlobalScope;
|
|||
use dom::history::History;
|
||||
use dom::htmliframeelement::build_mozbrowser_custom_event;
|
||||
use dom::location::Location;
|
||||
use dom::mediaquerylist::{MediaQueryList, WeakMediaQueryListVec};
|
||||
use dom::messageevent::MessageEvent;
|
||||
use dom::navigator::Navigator;
|
||||
use dom::node::{Node, from_untrusted_node_address, window_from_node};
|
||||
|
@ -87,6 +89,7 @@ use std::sync::mpsc::TryRecvError::{Disconnected, Empty};
|
|||
use string_cache::Atom;
|
||||
use style::context::ReflowGoal;
|
||||
use style::error_reporting::ParseErrorReporter;
|
||||
use style::media_queries;
|
||||
use style::properties::longhands::overflow_x;
|
||||
use style::selector_impl::PseudoElement;
|
||||
use style::str::HTML_SPACE_CHARACTERS;
|
||||
|
@ -234,6 +237,9 @@ pub struct Window {
|
|||
|
||||
/// A list of scroll offsets for each scrollable element.
|
||||
scroll_offsets: DOMRefCell<HashMap<UntrustedNodeAddress, Point2D<f32>>>,
|
||||
|
||||
/// All the MediaQueryLists we need to update
|
||||
media_query_lists: WeakMediaQueryListVec,
|
||||
}
|
||||
|
||||
impl Window {
|
||||
|
@ -310,6 +316,10 @@ impl Window {
|
|||
pub fn set_scroll_offsets(&self, offsets: HashMap<UntrustedNodeAddress, Point2D<f32>>) {
|
||||
*self.scroll_offsets.borrow_mut() = offsets
|
||||
}
|
||||
|
||||
pub fn current_viewport(&self) -> Rect<Au> {
|
||||
self.current_viewport.clone().get()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
|
||||
|
@ -857,6 +867,16 @@ impl WindowMethods for Window {
|
|||
}
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-matchmedia
|
||||
fn MatchMedia(&self, query: DOMString) -> Root<MediaQueryList> {
|
||||
let mut parser = Parser::new(&query);
|
||||
let media_query_list = media_queries::parse_media_query_list(&mut parser);
|
||||
let document = self.Document();
|
||||
let mql = MediaQueryList::new(&document, media_query_list);
|
||||
self.media_query_lists.push(&*mql);
|
||||
mql
|
||||
}
|
||||
|
||||
#[allow(unrooted_must_root)]
|
||||
// https://fetch.spec.whatwg.org/#fetch-method
|
||||
fn Fetch(&self, input: RequestOrUSVString, init: &RequestInit) -> Rc<Promise> {
|
||||
|
@ -1486,6 +1506,10 @@ impl Window {
|
|||
let custom_event = build_mozbrowser_custom_event(&self, event);
|
||||
custom_event.upcast::<Event>().fire(self.upcast());
|
||||
}
|
||||
|
||||
pub fn evaluate_media_queries_and_report_changes(&self) {
|
||||
self.media_query_lists.evaluate_and_report_changes();
|
||||
}
|
||||
}
|
||||
|
||||
impl Window {
|
||||
|
@ -1572,6 +1596,7 @@ impl Window {
|
|||
ignore_further_async_events: Arc::new(AtomicBool::new(false)),
|
||||
error_reporter: error_reporter,
|
||||
scroll_offsets: DOMRefCell::new(HashMap::new()),
|
||||
media_query_lists: WeakMediaQueryListVec::new(),
|
||||
};
|
||||
|
||||
WindowBinding::Wrap(runtime.cx(), win)
|
||||
|
|
|
@ -82,6 +82,7 @@ extern crate smallvec;
|
|||
#[macro_use(atom, ns)] extern crate string_cache;
|
||||
#[macro_use]
|
||||
extern crate style;
|
||||
extern crate style_traits;
|
||||
extern crate time;
|
||||
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
|
||||
extern crate tinyfiledialogs;
|
||||
|
|
|
@ -2101,6 +2101,11 @@ impl ScriptThread {
|
|||
0i32);
|
||||
uievent.upcast::<Event>().fire(window.upcast());
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#event-loop-processing-model
|
||||
// Step 7.7 - evaluate media queries and report changes
|
||||
// Since we have resized, we need to re-evaluate MQLs
|
||||
window.evaluate_media_queries_and_report_changes();
|
||||
}
|
||||
|
||||
/// Initiate a non-blocking fetch for a specified resource. Stores the InProgressLoad
|
||||
|
|
1
components/servo/Cargo.lock
generated
1
components/servo/Cargo.lock
generated
|
@ -1987,6 +1987,7 @@ dependencies = [
|
|||
"smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"string_cache 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"style 0.0.1",
|
||||
"style_traits 0.0.1",
|
||||
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tinyfiledialogs 0.1.0 (git+https://github.com/jdm/tinyfiledialogs)",
|
||||
"url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
|
@ -135,6 +135,8 @@ pub mod values;
|
|||
pub mod viewport;
|
||||
pub mod workqueue;
|
||||
|
||||
use cssparser::ToCss;
|
||||
use std::fmt;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// The CSS properties supported by the style system.
|
||||
|
@ -174,3 +176,16 @@ pub fn arc_ptr_eq<T: 'static>(a: &Arc<T>, b: &Arc<T>) -> bool {
|
|||
let b: &T = &**b;
|
||||
(a as *const T) == (b as *const T)
|
||||
}
|
||||
|
||||
pub fn serialize_comma_separated_list<W, T>(dest: &mut W, list: &[T])
|
||||
-> fmt::Result where W: fmt::Write, T: ToCss {
|
||||
if list.len() > 0 {
|
||||
for item in &list[..list.len()-1] {
|
||||
try!(item.to_css(dest));
|
||||
try!(write!(dest, ", "));
|
||||
}
|
||||
list[list.len()-1].to_css(dest)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,9 +7,12 @@
|
|||
//! [mq]: https://drafts.csswg.org/mediaqueries/
|
||||
|
||||
use app_units::Au;
|
||||
use cssparser::{Delimiter, Parser, Token};
|
||||
use cssparser::{Delimiter, Parser, ToCss, Token};
|
||||
use euclid::size::{Size2D, TypedSize2D};
|
||||
use properties::longhands;
|
||||
use serialize_comma_separated_list;
|
||||
use std::fmt::{self, Write};
|
||||
use string_cache::Atom;
|
||||
use style_traits::ViewportPx;
|
||||
use values::specified;
|
||||
|
||||
|
@ -20,6 +23,14 @@ pub struct MediaQueryList {
|
|||
pub media_queries: Vec<MediaQuery>
|
||||
}
|
||||
|
||||
impl ToCss for MediaQueryList {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
|
||||
where W: fmt::Write
|
||||
{
|
||||
serialize_comma_separated_list(dest, &self.media_queries)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub enum Range<T> {
|
||||
|
@ -104,20 +115,58 @@ impl MediaQuery {
|
|||
}
|
||||
}
|
||||
|
||||
impl ToCss for MediaQuery {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
|
||||
where W: fmt::Write
|
||||
{
|
||||
if self.qualifier == Some(Qualifier::Not) {
|
||||
try!(write!(dest, "not "));
|
||||
}
|
||||
|
||||
let mut type_ = String::new();
|
||||
match self.media_type {
|
||||
MediaQueryType::All => try!(write!(type_, "all")),
|
||||
MediaQueryType::MediaType(MediaType::Screen) => try!(write!(type_, "screen")),
|
||||
MediaQueryType::MediaType(MediaType::Print) => try!(write!(type_, "print")),
|
||||
MediaQueryType::MediaType(MediaType::Unknown(ref desc)) => try!(write!(type_, "{}", desc)),
|
||||
};
|
||||
if self.expressions.is_empty() {
|
||||
return write!(dest, "{}", type_)
|
||||
} else if type_ != "all" || self.qualifier == Some(Qualifier::Not) {
|
||||
try!(write!(dest, "{} and ", type_));
|
||||
}
|
||||
for (i, &e) in self.expressions.iter().enumerate() {
|
||||
try!(write!(dest, "("));
|
||||
let (mm, l) = match e {
|
||||
Expression::Width(Range::Min(ref l)) => ("min", l),
|
||||
Expression::Width(Range::Max(ref l)) => ("max", l),
|
||||
};
|
||||
try!(write!(dest, "{}-width: ", mm));
|
||||
try!(l.to_css(dest));
|
||||
if i == self.expressions.len() - 1 {
|
||||
try!(write!(dest, ")"));
|
||||
} else {
|
||||
try!(write!(dest, ") and "));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// http://dev.w3.org/csswg/mediaqueries-3/#media0
|
||||
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub enum MediaQueryType {
|
||||
All, // Always true
|
||||
MediaType(MediaType),
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub enum MediaType {
|
||||
Screen,
|
||||
Print,
|
||||
Unknown,
|
||||
Unknown(Atom),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -181,7 +230,7 @@ impl MediaQuery {
|
|||
"screen" => MediaQueryType::MediaType(MediaType::Screen),
|
||||
"print" => MediaQueryType::MediaType(MediaType::Print),
|
||||
"all" => MediaQueryType::All,
|
||||
_ => MediaQueryType::MediaType(MediaType::Unknown)
|
||||
_ => MediaQueryType::MediaType(MediaType::Unknown(Atom::from(&*ident)))
|
||||
}
|
||||
} else {
|
||||
// Media type is only optional if qualifier is not specified.
|
||||
|
@ -233,8 +282,8 @@ impl MediaQueryList {
|
|||
self.media_queries.iter().any(|mq| {
|
||||
// Check if media matches. Unknown media never matches.
|
||||
let media_match = match mq.media_type {
|
||||
MediaQueryType::MediaType(MediaType::Unknown) => false,
|
||||
MediaQueryType::MediaType(media_type) => media_type == device.media_type,
|
||||
MediaQueryType::MediaType(MediaType::Unknown(_)) => false,
|
||||
MediaQueryType::MediaType(ref media_type) => *media_type == device.media_type,
|
||||
MediaQueryType::All => true,
|
||||
};
|
||||
|
||||
|
|
1
ports/cef/Cargo.lock
generated
1
ports/cef/Cargo.lock
generated
|
@ -1838,6 +1838,7 @@ dependencies = [
|
|||
"smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"string_cache 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"style 0.0.1",
|
||||
"style_traits 0.0.1",
|
||||
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tinyfiledialogs 0.1.0 (git+https://github.com/jdm/tinyfiledialogs)",
|
||||
"url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
|
@ -6,6 +6,7 @@ use app_units::Au;
|
|||
use cssparser::{Parser, SourcePosition};
|
||||
use euclid::size::TypedSize2D;
|
||||
use std::borrow::ToOwned;
|
||||
use string_cache::Atom;
|
||||
use style::error_reporting::ParseErrorReporter;
|
||||
use style::media_queries::*;
|
||||
use style::parser::ParserContextExtraData;
|
||||
|
@ -126,7 +127,7 @@ fn test_mq_unknown() {
|
|||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == None, css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown(Atom::from("fridge"))), css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
|
@ -134,7 +135,7 @@ fn test_mq_unknown() {
|
|||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Only), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown(Atom::from("glass"))), css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
|
@ -142,7 +143,7 @@ fn test_mq_unknown() {
|
|||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown(Atom::from("wood"))), css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
}
|
||||
|
@ -247,7 +248,7 @@ fn test_mq_expressions() {
|
|||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == None, css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown(Atom::from("fridge"))), css.to_owned());
|
||||
assert!(q.expressions.len() == 1, css.to_owned());
|
||||
match q.expressions[0] {
|
||||
Expression::Width(Range::Max(w)) => assert!(w == specified::Length::Absolute(Au::from_px(52))),
|
||||
|
|
|
@ -3,6 +3,3 @@
|
|||
[window_inherited_functions]
|
||||
expected: FAIL
|
||||
|
||||
[window_functions]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -24,9 +24,6 @@
|
|||
[Window method: getSelection]
|
||||
expected: FAIL
|
||||
|
||||
[Window method: matchMedia]
|
||||
expected: FAIL
|
||||
|
||||
[Window readonly attribute: applicationCache]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -6542,6 +6542,12 @@
|
|||
"url": "/_mozilla/css/float_relative_to_position.html"
|
||||
}
|
||||
],
|
||||
"css/matchMedia.html": [
|
||||
{
|
||||
"path": "css/matchMedia.html",
|
||||
"url": "/_mozilla/css/matchMedia.html"
|
||||
}
|
||||
],
|
||||
"css/media_calc_crash.html": [
|
||||
{
|
||||
"path": "css/media_calc_crash.html",
|
||||
|
|
15
tests/wpt/mozilla/meta/css/matchMedia.html.ini
Normal file
15
tests/wpt/mozilla/meta/css/matchMedia.html.ini
Normal file
|
@ -0,0 +1,15 @@
|
|||
[matchMedia.html]
|
||||
type: testharness
|
||||
expected: OK
|
||||
|
||||
[window.matchMedia exists]
|
||||
expected: FAIL
|
||||
|
||||
[MediaQueryList.matches for "(min-aspect-ratio: 1/1)"]
|
||||
expected: FAIL
|
||||
|
||||
[MediaQueryList.matches for "(width: 200px)"]
|
||||
expected: FAIL
|
||||
|
||||
[Resize iframe from 200x100 to 200x50, then to 100x50]
|
||||
expected: FAIL
|
1
tests/wpt/mozilla/tests/css/blank.html
Normal file
1
tests/wpt/mozilla/tests/css/blank.html
Normal file
|
@ -0,0 +1 @@
|
|||
<!--intentionally blank-->
|
188
tests/wpt/mozilla/tests/css/matchMedia.html
Normal file
188
tests/wpt/mozilla/tests/css/matchMedia.html
Normal file
|
@ -0,0 +1,188 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>CSS Test: CSSOM View matchMedia and MediaQueryList</title>
|
||||
<link rel="author" title="Rune Lillesveen" href="mailto:rune@opera.com">
|
||||
<link rel="help" href="http://www.w3.org/TR/cssom-view/#dom-window-matchmedia">
|
||||
<link rel="help" href="http://www.w3.org/TR/cssom-view/#the-mediaquerylist-interface">
|
||||
<link rel="help" href="http://www.w3.org/TR/cssom-1/#serializing-media-queries">
|
||||
<meta name="flags" content="dom">
|
||||
<script src="/resources/testharness.js" type="text/javascript"></script>
|
||||
<script src="/resources/testharnessreport.js" type="text/javascript"></script>
|
||||
<style type="text/css">
|
||||
iframe { border: none; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>Test not run - javascript required.</noscript>
|
||||
<div id="log"></div>
|
||||
<iframe width="200" height="100" src="blank.html"></iframe>
|
||||
<script type="text/javascript">
|
||||
function reflow(doc) {
|
||||
doc.body.offsetWidth;
|
||||
}
|
||||
|
||||
var iframe = document.querySelector("iframe");
|
||||
iframe.onload = function(){
|
||||
var iframe_window = iframe.contentWindow;
|
||||
|
||||
reflow(iframe_window.document);
|
||||
|
||||
test(function(){
|
||||
assert_inherits(window, "matchMedia");
|
||||
}, "window.matchMedia exists");
|
||||
|
||||
test(function(){
|
||||
assert_true(window.matchMedia instanceof Function, "FATAL ERROR: The window.matchMedia function is not present. The rest of the testsuite will fail to run.");
|
||||
}, "window.matchMedia is a Function");
|
||||
|
||||
var mql, mql1, mql2, mql3;
|
||||
|
||||
test(function(){
|
||||
mql = window.matchMedia("all");
|
||||
assert_true(mql instanceof MediaQueryList, "matchMedia(\"all\") returned MediaQueryList object.");
|
||||
}, "window.matchMedia(\"all\")");
|
||||
|
||||
test(function(){
|
||||
assert_idl_attribute(mql, "media", "Check that MediaQueryList.media exists.");
|
||||
}, "MediaQueryList.media exists");
|
||||
|
||||
test(function(){
|
||||
assert_readonly(mql, "media", "Check that MediaQueryList.media is readonly.");
|
||||
}, "MediaQueryList.media is readonly");
|
||||
|
||||
test(function(){
|
||||
assert_equals(mql.media, "all");
|
||||
}, "MediaQueryList.media for \"all\"");
|
||||
|
||||
test(function(){
|
||||
assert_idl_attribute(mql, "matches", "Check that MediaQueryList.matches exists.");
|
||||
}, "MediaQueryList.matches exists");
|
||||
|
||||
test(function(){
|
||||
assert_readonly(mql, "matches", "Check that MediaQueryList.matches is readonly.");
|
||||
}, "MediaQueryList.matches is readonly");
|
||||
|
||||
test(function(){
|
||||
assert_true(mql.matches);
|
||||
}, "MediaQueryList.matches for \"all\"");
|
||||
|
||||
test(function(){
|
||||
assert_inherits(mql, "addListener");
|
||||
}, "MediaQueryList.addListener exists");
|
||||
|
||||
test(function(){
|
||||
assert_true(mql.addListener instanceof Function);
|
||||
}, "MediaQueryList.addListener is a Function");
|
||||
|
||||
test(function(){
|
||||
assert_inherits(mql, "removeListener");
|
||||
}, "MediaQueryList.removeListener exists");
|
||||
|
||||
test(function(){
|
||||
assert_true(mql.removeListener instanceof Function);
|
||||
}, "MediaQueryList.removeListener is a Function");
|
||||
|
||||
test(function(){
|
||||
mql = window.matchMedia("::");
|
||||
assert_true(mql instanceof MediaQueryList, "window.matchMedia(\"::\") returned MediaQueryList object.");
|
||||
assert_equals(mql.media, "not all", "MediaQueryList.media serialized as \"not all\" from original string with syntax error.");
|
||||
}, "MediaQueryList.media syntax error");
|
||||
|
||||
test(function(){
|
||||
assert_false(mql.matches);
|
||||
}, "MediaQueryList.matches for \"not all\"");
|
||||
|
||||
test(function(){
|
||||
mql = iframe_window.matchMedia("(max-width: 199px), all and (min-width: 200px)");
|
||||
assert_equals(mql.media, "(max-width: 199px), (min-width: 200px)");
|
||||
assert_true(mql.matches);
|
||||
}, "MediaQueryList.matches for \"(max-width: 199px), all and (min-width: 200px)\"")
|
||||
|
||||
test(function(){
|
||||
mql = iframe_window.matchMedia("(min-aspect-ratio: 1/1)");
|
||||
assert_true(mql.matches);
|
||||
}, "MediaQueryList.matches for \"(min-aspect-ratio: 1/1)\"");
|
||||
|
||||
test(function(){
|
||||
mql = iframe_window.matchMedia("(width: 200px)");
|
||||
assert_true(mql.matches);
|
||||
}, "MediaQueryList.matches for \"(width: 200px)\"");
|
||||
|
||||
test(function(){
|
||||
mql1 = iframe_window.matchMedia("(max-height: 50px)");
|
||||
assert_false(mql1.matches);
|
||||
}, "MediaQueryList.matches for \"(max-height: 50px)\"");
|
||||
|
||||
test(function(){
|
||||
mql2 = iframe_window.matchMedia("(min-width: 150px)");
|
||||
assert_true(mql2.matches);
|
||||
}, "MediaQueryList.matches for \"(min-width: 150px)\"");
|
||||
|
||||
var resizeTest = async_test("Resize iframe from 200x100 to 200x50, then to 100x50");
|
||||
var listenerOrderTest = async_test("Listeners are called in the order which they have been added");
|
||||
var duplicateListenerTest = async_test("Listener added twice is only called once.");
|
||||
|
||||
window.onload = function(){
|
||||
|
||||
var rmListener = function(x){
|
||||
resizeTest.step(function(){
|
||||
assert_unreached("removeListener was not successful.");
|
||||
});
|
||||
};
|
||||
|
||||
var dupListener = function(x){
|
||||
duplicateListenerTest.step(function(){
|
||||
assert_false(mql1.dupListenerCalled, "Check that this listener has not been called before.");
|
||||
mql1.dupListenerCalled = true;
|
||||
});
|
||||
};
|
||||
|
||||
mql1.firstListenerCalled = false;
|
||||
mql1.dupListenerCalled = false;
|
||||
// Add listener twice and remove it below. Should not be called.
|
||||
mql1.addListener(rmListener);
|
||||
mql1.addListener(rmListener);
|
||||
// Add listener twice. Should only be called once.
|
||||
mql1.addListener(dupListener);
|
||||
mql1.addListener(dupListener);
|
||||
|
||||
mql1.addListener(function(x){
|
||||
resizeTest.step(function(){
|
||||
assert_equals(x, mql1, "Check that the MediaQueryList passed to the handler is the same that addListener was invoked on.");
|
||||
assert_true(x.matches, "(max-height: 50px) should now pass.");
|
||||
assert_true(mql2.matches, "(min-width: 150px) should still pass.");
|
||||
iframe.width = "100";
|
||||
});
|
||||
|
||||
listenerOrderTest.step(function(){
|
||||
assert_false(mql1.firstListenerCalled, "Check that this listener is only called once.");
|
||||
mql1.firstListenerCalled = true;
|
||||
});
|
||||
});
|
||||
|
||||
mql1.addListener(function(x){
|
||||
listenerOrderTest.step(function(){
|
||||
assert_true(mql1.firstListenerCalled, "Check that the listener added last is called last.");
|
||||
});
|
||||
listenerOrderTest.done();
|
||||
});
|
||||
|
||||
mql1.removeListener(rmListener);
|
||||
|
||||
mql2.addListener(function(x){
|
||||
duplicateListenerTest.done();
|
||||
resizeTest.step(function(){
|
||||
assert_equals(x, mql2, "Check that the MediaQueryList passed to the handler is the same that addListener was invoked on.");
|
||||
assert_true(mql1.matches, "(max-height: 50px) should still pass.");
|
||||
assert_false(x.matches, "(min-width: 150px) should now fail.");
|
||||
});
|
||||
resizeTest.done();
|
||||
});
|
||||
|
||||
iframe.height = "50";
|
||||
};
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -128,6 +128,7 @@ test_interfaces([
|
|||
"KeyboardEvent",
|
||||
"Location",
|
||||
"MediaError",
|
||||
"MediaQueryList",
|
||||
"MessageEvent",
|
||||
"MimeType",
|
||||
"MimeTypeArray",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue