diff --git a/Cargo.lock b/Cargo.lock index 67e5cd38f21..194148cc721 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2695,6 +2695,7 @@ dependencies = [ "msg 0.0.1", "script 0.0.1", "servo_url 0.0.1", + "style 0.0.1", ] [[package]] diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs index 7c2255d6696..1fea05fc0d9 100644 --- a/components/script/dom/htmlimageelement.rs +++ b/components/script/dom/htmlimageelement.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use app_units::{Au, AU_PER_PX}; +use cssparser::{Parser, ParserInput}; use document_loader::{LoadType, LoadBlocker}; use dom::activation::Activatable; use dom::attr::Attr; @@ -52,10 +53,17 @@ use script_thread::ScriptThread; use servo_url::ServoUrl; use servo_url::origin::ImmutableOrigin; use std::cell::{Cell, RefMut}; +use std::char; use std::default::Default; use std::i32; use std::sync::{Arc, Mutex}; use style::attr::{AttrValue, LengthOrPercentageOrAuto}; +use style::context::QuirksMode; +use style::media_queries::MediaQuery; +use style::parser::ParserContext; +use style::values::specified::{Length, ViewportPercentageLength}; +use style::values::specified::length::NoCalcLength; +use style_traits::ParsingMode; use task_source::TaskSource; #[derive(Clone, Copy, HeapSizeOf, JSTraceable)] @@ -66,6 +74,13 @@ enum State { CompletelyAvailable, Broken, } + +#[derive(Debug, PartialEq)] +pub struct Size { + pub query: Option, + pub length: Length, +} + #[derive(Clone, Copy, HeapSizeOf, JSTraceable)] enum ImageRequestPhase { Pending, @@ -728,6 +743,60 @@ impl LayoutHTMLImageElementHelpers for LayoutDom { } } +//https://html.spec.whatwg.org/multipage/#parse-a-sizes-attribute +pub fn parse_a_sizes_attribute(input: DOMString, width: Option) -> Vec { + let mut sizes = Vec::::new(); + for unparsed_size in input.split(',') { + let whitespace = unparsed_size.chars().rev().take_while(|c| char::is_whitespace(*c)).count(); + let trimmed: String = unparsed_size.chars().take(unparsed_size.chars().count() - whitespace).collect(); + + if trimmed.is_empty() { + continue; + } + let mut input = ParserInput::new(&trimmed); + let url = ServoUrl::parse("about:blank").unwrap(); + let context = ParserContext::new_for_cssom(&url, + None, + ParsingMode::empty(), + QuirksMode::NoQuirks); + let mut parser = Parser::new(&mut input); + let length = parser.try(|i| Length::parse_non_negative(&context, i)); + match length { + Ok(len) => sizes.push(Size { + length: len, + query: None + }), + Err(_) => { + let mut media_query_parser = parser; + let media_query = media_query_parser.try(|i| MediaQuery::parse(&context, i)); + if let Ok(query) = media_query { + let length = Length::parse_non_negative(&context, &mut media_query_parser); + if let Ok(length) = length { + sizes.push(Size { + length: length, + query: Some(query) + }) + } + } + }, + } + } + if sizes.is_empty() { + let size = match width { + Some(w) => Size { + length: Length::from_px(w as f32), + query: None + }, + None => Size { + length: Length::NoCalc(NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vw(100.))), + query: None + }, + }; + sizes.push(size); + } + sizes +} + impl HTMLImageElementMethods for HTMLImageElement { // https://html.spec.whatwg.org/multipage/#dom-img-alt make_getter!(Alt, "alt"); diff --git a/components/script/test.rs b/components/script/test.rs index 0ff6811b14d..88baa21f42f 100644 --- a/components/script/test.rs +++ b/components/script/test.rs @@ -15,6 +15,10 @@ pub mod area { pub use dom::htmlareaelement::{Area, Shape}; } +pub mod sizes { + pub use dom::htmlimageelement::{parse_a_sizes_attribute, Size}; +} + pub mod size_of { use dom::characterdata::CharacterData; use dom::element::Element; diff --git a/components/style/servo/media_queries.rs b/components/style/servo/media_queries.rs index 36e64ee47da..8d99b8ba81e 100644 --- a/components/style/servo/media_queries.rs +++ b/components/style/servo/media_queries.rs @@ -164,7 +164,7 @@ pub enum ExpressionKind { /// http://dev.w3.org/csswg/mediaqueries-3/#media1 #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] -pub struct Expression(ExpressionKind); +pub struct Expression(pub ExpressionKind); impl Expression { /// The kind of expression we're, just for unit testing. diff --git a/tests/unit/script/Cargo.toml b/tests/unit/script/Cargo.toml index d88f4d9a75f..7785cced6a9 100644 --- a/tests/unit/script/Cargo.toml +++ b/tests/unit/script/Cargo.toml @@ -14,3 +14,4 @@ euclid = "0.15" msg = {path = "../../../components/msg"} script = {path = "../../../components/script"} servo_url = {path = "../../../components/url"} +style = {path = "../../../components/style"} diff --git a/tests/unit/script/htmlimageelement.rs b/tests/unit/script/htmlimageelement.rs new file mode 100644 index 00000000000..5c9106b6c0f --- /dev/null +++ b/tests/unit/script/htmlimageelement.rs @@ -0,0 +1,101 @@ +/* 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 script::test::DOMString; +use script::test::sizes::{parse_a_sizes_attribute, Size}; +use style::media_queries::{MediaQuery, MediaQueryType}; +use style::media_queries::Expression; +use style::servo::media_queries::{ExpressionKind, Range}; +use style::values::specified::{Length, NoCalcLength, AbsoluteLength, ViewportPercentageLength}; + +pub fn test_length_for_no_default_provided(len: f32) -> Length { + let length = Length::NoCalc(NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vw(len))); + return length; +} + +#[test] +fn no_default_provided() { + let mut a = vec![]; + let length = test_length_for_no_default_provided(100f32); + let size = Size { query: None, length: length }; + a.push(size); + assert_eq!(parse_a_sizes_attribute(DOMString::new(), None), a); +} + +pub fn test_length_for_default_provided(len: f32) -> Length { + let length = Length::NoCalc(NoCalcLength::Absolute(AbsoluteLength::Px(len))); + return length; +} + +#[test] +fn default_provided() { + let mut a = vec![]; + let length = test_length_for_default_provided(2f32); + let size = Size { query: None, length: length }; + a.push(size); + assert_eq!(parse_a_sizes_attribute(DOMString::new(), Some(2)), a); +} + +pub fn test_media_query(len: f32) -> MediaQuery { + let length = Length::NoCalc(NoCalcLength::Absolute(AbsoluteLength::Px(len))); + let expr = Expression(ExpressionKind::Width(Range::Max(length))); + let media_query = MediaQuery { + qualifier: None, + media_type: MediaQueryType::All, + expressions: vec![expr] + }; + media_query +} + +pub fn test_length(len: f32) -> Length { + let length = Length::NoCalc(NoCalcLength::Absolute(AbsoluteLength::Px(len))); + return length; +} + +#[test] +fn one_value() { + let mut a = vec![]; + let media_query = test_media_query(200f32); + let length = test_length(545f32); + let size = Size { query: Some(media_query), length: length }; + a.push(size); + assert_eq!(parse_a_sizes_attribute(DOMString::from("(max-width: 200px) 545px"), None), a); +} + +#[test] +fn more_then_one_value() { + let media_query = test_media_query(900f32); + let length = test_length(1000f32); + let size = Size { query: Some(media_query), length: length }; + let media_query1 = test_media_query(900f32); + let length1 = test_length(50f32); + let size1 = Size { query: Some(media_query1), length: length1 }; + let a = &[size, size1]; + assert_eq!(parse_a_sizes_attribute(DOMString::from("(max-width: 900px) 1000px, (max-width: 900px) 50px"), + None), a); +} + +#[test] +fn no_extra_whitespace() { + let mut a = vec![]; + let media_query = test_media_query(200f32); + let length = test_length(545f32); + let size = Size { query: Some(media_query), length: length }; + a.push(size); + assert_eq!(parse_a_sizes_attribute(DOMString::from("(max-width: 200px) 545px"), None), a); +} + +#[test] +fn extra_whitespace() { + let media_query = test_media_query(900f32); + let length = test_length(1000f32); + let size = Size { query: Some(media_query), length: length }; + let media_query1 = test_media_query(900f32); + let length1 = test_length(50f32); + let size1 = Size { query: Some(media_query1), length: length1 }; + let a = &[size, size1]; + assert_eq!(parse_a_sizes_attribute( + DOMString::from("(max-width: 900px) 1000px, (max-width: 900px) 50px"), + None), a); +} diff --git a/tests/unit/script/lib.rs b/tests/unit/script/lib.rs index 83131e51dd2..21b89a304c5 100644 --- a/tests/unit/script/lib.rs +++ b/tests/unit/script/lib.rs @@ -6,10 +6,12 @@ extern crate euclid; extern crate msg; extern crate script; extern crate servo_url; +extern crate style; #[cfg(test)] mod origin; #[cfg(all(test, target_pointer_width = "64"))] mod size_of; #[cfg(test)] mod textinput; #[cfg(test)] mod headers; #[cfg(test)] mod htmlareaelement; +#[cfg(test)] mod htmlimageelement;