diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs index b71e6b845cdb..a58c0f120112 100644 --- a/components/script/dom/htmlimageelement.rs +++ b/components/script/dom/htmlimageelement.rs @@ -3,6 +3,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use app_units::Au; +use core::ops::Deref; +use cssparser::Parser; use dom::attr::Attr; use dom::attr::AttrValue; use dom::bindings::cell::DOMRefCell; @@ -31,7 +33,11 @@ use script_runtime::{CommonScriptMsg, ScriptChan}; use script_thread::Runnable; use std::sync::Arc; use string_cache::Atom; +use style::media_queries::MediaQuery; +use style::values::CSSFloat; +use style::values::specified::{Length, ViewportPercentageLength}; use url::Url; +use util; use util::str::{DOMString, LengthOrPercentageOrAuto}; #[derive(JSTraceable, HeapSizeOf)] @@ -49,6 +55,11 @@ struct ImageRequest { image: Option>, metadata: Option, } +#[allow(dead_code)] +pub struct Size { + pub query: Option, + pub length: Length, +} #[dom_struct] pub struct HTMLImageElement { htmlelement: HTMLElement, @@ -398,3 +409,61 @@ fn image_dimension_setter(element: &Element, attr: Atom, value: u32) { let value = AttrValue::Dimension(DOMString::from(value.to_string()), dim); element.set_attribute(&attr, value); } + + +pub fn parse_a_sizes_attribute(input: DOMString, width: Option) -> Vec { + let mut sizes = Vec::::new(); + let unparsed_sizes = input.deref().split(',').collect::>(); + + for unparsed_size in &unparsed_sizes { + let temp = *unparsed_size; + let whitespace = temp.chars().rev().take_while(|c| util::str::char_is_whitespace(*c)).count(); + let trimmed: String = unparsed_size.chars().take(temp.chars().count() - whitespace).collect(); + // TODO: do we need to throw/assert + if trimmed.is_empty() { + warn!("parse error while parsing sizes attribute"); + continue; + } + let length = Parser::new(&trimmed).try(Length::parse_non_negative); + match length { + Ok(len) => sizes.push(Size { + length: len, + query: None + }), + Err(_) => { + println!("Starts with media expression and not length"); + let mut media_query_parser = Parser::new(&trimmed); + let media_query = media_query_parser.try(MediaQuery::parse); + match media_query { + Ok(query) => { + let length = media_query_parser.try(Length::parse_non_negative); + if length.is_ok() { + sizes.push (Size { + length: length.unwrap(), + query: Some(query) + }) + } + }, + Err(_) => { + println!("Could not convert to MediaQuery/Length"); + continue; + }, + } + }, + } + } + if sizes.len() == 0 { + let size = match width { + Some(w) => Size { + length: Length::from_px(w as f32), + query: None + }, + None => Size { + length: Length::ViewportPercentage(ViewportPercentageLength::Vw(100 as f32)), + query: None + }, + }; + sizes.push(size); + } + sizes +} diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index adba235f7f4c..81b4aa558855 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -1850,9 +1850,17 @@ dependencies = [ name = "script_tests" version = "0.0.1" dependencies = [ + "app_units 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", "plugins 0.0.1", + "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "script 0.0.1", + "selectors 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", + "string_cache 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "style 0.0.1", + "style_traits 0.0.1", "url 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", ] diff --git a/components/style/media_queries.rs b/components/style/media_queries.rs index b19b4d81c7ec..1f05f775de14 100644 --- a/components/style/media_queries.rs +++ b/components/style/media_queries.rs @@ -140,7 +140,7 @@ impl Expression { } impl MediaQuery { - fn parse(input: &mut Parser) -> Result { + pub fn parse(input: &mut Parser) -> Result { let mut expressions = vec![]; let qualifier = if input.try(|input| input.expect_ident_matching("only")).is_ok() { diff --git a/tests/unit/script/Cargo.toml b/tests/unit/script/Cargo.toml index 171ffb6920e8..004dfb8088a7 100644 --- a/tests/unit/script/Cargo.toml +++ b/tests/unit/script/Cargo.toml @@ -12,5 +12,13 @@ doctest = false msg = {path = "../../../components/msg"} plugins = {path = "../../../components/plugins"} script = {path = "../../../components/script"} +style = {path = "../../../components/style"} +style_traits = {path = "../../../components/style_traits"} util = {path = "../../../components/util"} +app_units = {version = "0.2.3", features = ["plugins"]} +cssparser = {version = "0.5.4", features = ["heap_size"]} +euclid = {version = "0.6.4", features = ["plugins"]} +selectors = {version = "0.5", features = ["heap_size"]} +string_cache = {version = "0.2", features = ["heap_size"]} url = {version = "1.0.0", features = ["heap_size"]} +rustc-serialize = "0.3" diff --git a/tests/unit/script/lib.rs b/tests/unit/script/lib.rs index 2dbbd16ea7ac..03b603c6f012 100644 --- a/tests/unit/script/lib.rs +++ b/tests/unit/script/lib.rs @@ -5,8 +5,88 @@ #![feature(plugin)] #![plugin(plugins)] +use app_units::Au; +use cssparser::{Parser, SourcePosition}; +use script::dom::htmlimageelement::{parse_a_sizes_attribute, Size}; +use style::media_queries::*; +use style::values::specified; +use util::str::DOMString; + +#[test] +fn some_parse_sizes_test() { + let result = parse_a_sizes_attribute(DOMString::from("(min-width: 900px) 1000px, + (max-width: 900px) and (min-width: 400px) 50em, + 100vw "), + None); + assert_eq!(result.len(), 3); +} + +#[test] +fn some_parse_sizes_1_test() { + let mut result = parse_a_sizes_attribute(DOMString::from("(min-width: 900px) 1000px, + (max-width: 900px) and (min-width: 400px) 50em, + 100vw "), + None); + result.pop(); + let mut component_secondlast = result.pop(); + if component_secondlast.is_some() { + let component_query = component_secondlast.unwrap().query; + if component_query.is_some() { + let component_query_expr = component_query.unwrap().expressions; + assert_eq!(component_query_expr.len() , 2); + } + } +} + +#[test] +fn some_parse_sizes_2_test() { + let mut result = parse_a_sizes_attribute(DOMString::from("(min-width: 900px) 1000px, + (max-width: 900px) and (min-width: 400px) 50em, + 100vw "), + None); + result.pop(); + result.pop(); + let mut component_first = result.pop(); + if component_first.is_some() { + let component_query = component_first.unwrap().query; + if component_query.is_some() { + let component_query_expr = component_query.unwrap().expressions; + match component_query_expr[0] { + Expression::Width(Range::Min(w)) => assert!(w == specified::Length::Absolute(Au::from_px(900))), + _ => panic!("wrong expression type"), + } + } + } +} + +#[test] +fn some_parse_sizes_3_test() { + let mut result = parse_a_sizes_attribute(DOMString::from("(min-width: 900px) 1000px, + (max-width: 900px) and (min-width: 400px) 50em , + 100vw "), + None); + result.pop(); + let mut component_secondlast = result.pop(); + if component_secondlast.is_some() { + let component_query = component_secondlast.unwrap().query; + if component_query.is_some() { + let component_query_expr = component_query.unwrap().expressions; + match component_query_expr[0] { + Expression::Width(Range::Max(w)) => assert!(w == specified::Length::Absolute(Au::from_px(900))), + _ => panic!("wrong expression type"), + } + match component_query_expr[1] { + Expression::Width(Range::Min(w)) => assert!(w == specified::Length::Absolute(Au::from_px(400))), + _ => panic!("wrong expression type"), + } + } + } +} +extern crate app_units; +extern crate cssparser; extern crate msg; extern crate script; +extern crate style; extern crate url; extern crate util;