Move util::str::parse_length into 'style' component.

The function is only used in the 'style' component, so we'll move it
there alongside other relevant parse functions.
This commit is contained in:
Corey Farwell 2016-03-24 10:37:14 -04:00
parent a8264ecc1f
commit 5efbf0fa8f
4 changed files with 91 additions and 92 deletions

View file

@ -8,10 +8,11 @@ use euclid::num::Zero;
use num::ToPrimitive; use num::ToPrimitive;
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::ops::Deref; use std::ops::Deref;
use std::str::FromStr;
use string_cache::{Atom, Namespace}; use string_cache::{Atom, Namespace};
use url::Url; use url::Url;
use util::str::{DOMString, LengthOrPercentageOrAuto, HTML_SPACE_CHARACTERS, WHITESPACE}; use util::str::{DOMString, LengthOrPercentageOrAuto, HTML_SPACE_CHARACTERS, WHITESPACE};
use util::str::{parse_length, read_numbers, split_html_space_chars, str_join}; use util::str::{read_numbers, split_html_space_chars, str_join};
use values::specified::{Length}; use values::specified::{Length};
// Duplicated from script::dom::values. // Duplicated from script::dom::values.
@ -398,6 +399,75 @@ pub fn parse_legacy_color(mut input: &str) -> Result<RGBA, ()> {
} }
} }
/// TODO: this function can be rewritten to return Result<LengthOrPercentage, _>
/// Parses a dimension value per HTML5 § 2.4.4.4. If unparseable, `Auto` is
/// returned.
/// https://html.spec.whatwg.org/multipage/#rules-for-parsing-dimension-values
pub fn parse_length(mut value: &str) -> LengthOrPercentageOrAuto {
// Steps 1 & 2 are not relevant
// Step 3
value = value.trim_left_matches(WHITESPACE);
// Step 4
if value.is_empty() {
return LengthOrPercentageOrAuto::Auto
}
// Step 5
if value.starts_with("+") {
value = &value[1..]
}
// Steps 6 & 7
match value.chars().nth(0) {
Some('0'...'9') => {},
_ => return LengthOrPercentageOrAuto::Auto,
}
// Steps 8 to 13
// We trim the string length to the minimum of:
// 1. the end of the string
// 2. the first occurence of a '%' (U+0025 PERCENT SIGN)
// 3. the second occurrence of a '.' (U+002E FULL STOP)
// 4. the occurrence of a character that is neither a digit nor '%' nor '.'
// Note: Step 10 is directly subsumed by FromStr::from_str
let mut end_index = value.len();
let (mut found_full_stop, mut found_percent) = (false, false);
for (i, ch) in value.chars().enumerate() {
match ch {
'0'...'9' => continue,
'%' => {
found_percent = true;
end_index = i;
break
}
'.' if !found_full_stop => {
found_full_stop = true;
continue
}
_ => {
end_index = i;
break
}
}
}
value = &value[..end_index];
if found_percent {
let result: Result<f32, _> = FromStr::from_str(value);
match result {
Ok(number) => return LengthOrPercentageOrAuto::Percentage((number as f32) / 100.0),
Err(_) => return LengthOrPercentageOrAuto::Auto,
}
}
match FromStr::from_str(value) {
Ok(number) => LengthOrPercentageOrAuto::Length(Au::from_f64_px(number)),
Err(_) => LengthOrPercentageOrAuto::Auto,
}
}
#[derive(Clone, HeapSizeOf, Debug)] #[derive(Clone, HeapSizeOf, Debug)]
pub struct AttrIdentifier { pub struct AttrIdentifier {
pub local_name: Atom, pub local_name: Atom,

View file

@ -10,7 +10,7 @@ use std::ffi::CStr;
use std::fmt; use std::fmt;
use std::iter::{Filter, Peekable}; use std::iter::{Filter, Peekable};
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::str::{Bytes, CharIndices, FromStr, Split, from_utf8}; use std::str::{Bytes, CharIndices, Split, from_utf8};
use string_cache::Atom; use string_cache::Atom;
#[derive(Clone, Debug, Deserialize, Eq, Hash, HeapSizeOf, Ord, PartialEq, PartialOrd, Serialize)] #[derive(Clone, Debug, Deserialize, Eq, Hash, HeapSizeOf, Ord, PartialEq, PartialOrd, Serialize)]
@ -187,75 +187,6 @@ pub enum LengthOrPercentageOrAuto {
Length(Au), Length(Au),
} }
/// TODO: this function can be rewritten to return Result<LengthOrPercentage, _>
/// Parses a dimension value per HTML5 § 2.4.4.4. If unparseable, `Auto` is
/// returned.
/// https://html.spec.whatwg.org/multipage/#rules-for-parsing-dimension-values
pub fn parse_length(mut value: &str) -> LengthOrPercentageOrAuto {
// Steps 1 & 2 are not relevant
// Step 3
value = value.trim_left_matches(WHITESPACE);
// Step 4
if value.is_empty() {
return LengthOrPercentageOrAuto::Auto
}
// Step 5
if value.starts_with("+") {
value = &value[1..]
}
// Steps 6 & 7
match value.chars().nth(0) {
Some('0'...'9') => {},
_ => return LengthOrPercentageOrAuto::Auto,
}
// Steps 8 to 13
// We trim the string length to the minimum of:
// 1. the end of the string
// 2. the first occurence of a '%' (U+0025 PERCENT SIGN)
// 3. the second occurrence of a '.' (U+002E FULL STOP)
// 4. the occurrence of a character that is neither a digit nor '%' nor '.'
// Note: Step 10 is directly subsumed by FromStr::from_str
let mut end_index = value.len();
let (mut found_full_stop, mut found_percent) = (false, false);
for (i, ch) in value.chars().enumerate() {
match ch {
'0'...'9' => continue,
'%' => {
found_percent = true;
end_index = i;
break
}
'.' if !found_full_stop => {
found_full_stop = true;
continue
}
_ => {
end_index = i;
break
}
}
}
value = &value[..end_index];
if found_percent {
let result: Result<f32, _> = FromStr::from_str(value);
match result {
Ok(number) => return LengthOrPercentageOrAuto::Percentage((number as f32) / 100.0),
Err(_) => return LengthOrPercentageOrAuto::Auto,
}
}
match FromStr::from_str(value) {
Ok(number) => LengthOrPercentageOrAuto::Length(Au::from_f64_px(number)),
Err(_) => LengthOrPercentageOrAuto::Auto,
}
}
#[derive(Clone, Eq, PartialEq, Hash, Debug, Deserialize, Serialize)] #[derive(Clone, Eq, PartialEq, Hash, Debug, Deserialize, Serialize)]
pub struct LowercaseString { pub struct LowercaseString {
inner: String, inner: String,

View file

@ -2,8 +2,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use style::attr::AttrValue; use app_units::Au;
use util::str::DOMString; use style::attr::{AttrValue, parse_length};
use util::str::{DOMString, LengthOrPercentageOrAuto};
#[test] #[test]
fn test_from_limited_i32_should_be_default_when_less_than_0() { fn test_from_limited_i32_should_be_default_when_less_than_0() {
@ -31,3 +32,18 @@ fn test_from_limited_i32_should_keep_parsed_value_when_not_an_int() {
_ => panic!("expected an successful parsing") _ => panic!("expected an successful parsing")
} }
} }
#[test]
pub fn test_parse_length() {
fn check(input: &str, expected: LengthOrPercentageOrAuto) {
let parsed = parse_length(input);
assert_eq!(parsed, expected);
}
check("0", LengthOrPercentageOrAuto::Length(Au::from_px(0)));
check("0.000%", LengthOrPercentageOrAuto::Percentage(0.0));
check("+5.82%", LengthOrPercentageOrAuto::Percentage(0.0582));
check("5.82", LengthOrPercentageOrAuto::Length(Au::from_f64_px(5.82)));
check("invalid", LengthOrPercentageOrAuto::Auto);
check("12 followed by invalid", LengthOrPercentageOrAuto::Length(Au::from_px(12)));
}

View file

@ -2,25 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use app_units::Au; use util::str::{search_index, split_html_space_chars, str_join};
use util::str::LengthOrPercentageOrAuto;
use util::str::{parse_length, search_index, split_html_space_chars, str_join};
#[test]
pub fn test_parse_length() {
fn check(input: &str, expected: LengthOrPercentageOrAuto) {
let parsed = parse_length(input);
assert_eq!(parsed, expected);
}
check("0", LengthOrPercentageOrAuto::Length(Au::from_px(0)));
check("0.000%", LengthOrPercentageOrAuto::Percentage(0.0));
check("+5.82%", LengthOrPercentageOrAuto::Percentage(0.0582));
check("5.82", LengthOrPercentageOrAuto::Length(Au::from_f64_px(5.82)));
check("invalid", LengthOrPercentageOrAuto::Auto);
check("12 followed by invalid", LengthOrPercentageOrAuto::Length(Au::from_px(12)));
}
#[test] #[test]
pub fn split_html_space_chars_whitespace() { pub fn split_html_space_chars_whitespace() {