Auto merge of #21982 - emilio:gecko-sync, r=emilio

style: Sync changes from mozilla-central.

See each individual commit for details.

https://bugzilla.mozilla.org/show_bug.cgi?id=1500260

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/21982)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2018-10-18 23:58:28 -04:00 committed by GitHub
commit 91282778e4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
48 changed files with 799 additions and 902 deletions

View file

@ -553,12 +553,12 @@ pub fn convert_linear_gradient(
let angle = match direction {
LineDirection::Angle(angle) => angle.radians(),
LineDirection::Horizontal(x) => match x {
X::Left => Angle::Deg(270.).radians(),
X::Right => Angle::Deg(90.).radians(),
X::Left => Angle::from_degrees(270.).radians(),
X::Right => Angle::from_degrees(90.).radians(),
},
LineDirection::Vertical(y) => match y {
Y::Top => Angle::Deg(0.).radians(),
Y::Bottom => Angle::Deg(180.).radians(),
Y::Top => Angle::from_degrees(0.).radians(),
Y::Bottom => Angle::from_degrees(180.).radians(),
},
LineDirection::Corner(horizontal, vertical) => {
// This the angle for one of the diagonals of the box. Our angle

View file

@ -53,8 +53,11 @@ impl CSS {
pub fn Supports_(win: &Window, condition: DOMString) -> bool {
let mut input = ParserInput::new(&condition);
let mut input = Parser::new(&mut input);
let cond = parse_condition_or_declaration(&mut input);
if let Ok(cond) = cond {
let cond = match parse_condition_or_declaration(&mut input) {
Ok(c) => c,
Err(..) => return false,
};
let url = win.Document().url();
let context = ParserContext::new_for_cssom(
&url,
@ -64,10 +67,7 @@ impl CSS {
None,
None,
);
cond.eval(&context)
} else {
false
}
cond.eval(&context, &Default::default())
}
/// <https://drafts.css-houdini.org/css-paint-api-1/#paint-worklet>

View file

@ -81,7 +81,17 @@ impl CSSSupportsRule {
None,
None,
);
let enabled = cond.eval(&context);
let enabled = {
let namespaces =
self
.cssconditionrule
.parent_stylesheet()
.style_stylesheet()
.contents
.namespaces
.read();
cond.eval(&context, &namespaces)
};
let mut guard = self.cssconditionrule.shared_lock().write();
let rule = self.supportsrule.write_with(&mut guard);
rule.condition = cond;

View file

@ -259,8 +259,13 @@ where
Impl: SelectorImpl,
{
let location = input.current_source_location();
let selector = Selector::parse(parser, input)?;
// Ensure they're actually all compound selectors.
let selector = parse_selector(parser, input)?;
// Ensure they're actually all compound selectors without pseudo-elements.
if selector.has_pseudo_element() {
return Err(location.new_custom_error(SelectorParseErrorKind::PseudoElementInComplexSelector));
}
if selector.iter_raw_match_order().any(|s| s.is_combinator()) {
return Err(location.new_custom_error(SelectorParseErrorKind::NonCompoundSelector));
}
@ -1397,6 +1402,7 @@ where
impl<Impl: SelectorImpl> Selector<Impl> {
/// Parse a selector, without any pseudo-element.
#[inline]
pub fn parse<'i, 't, P>(
parser: &P,
input: &mut CssParser<'i, 't>,
@ -1404,12 +1410,7 @@ impl<Impl: SelectorImpl> Selector<Impl> {
where
P: Parser<'i, Impl = Impl>,
{
let selector = parse_selector(parser, input)?;
if selector.has_pseudo_element() {
let e = SelectorParseErrorKind::PseudoElementInComplexSelector;
return Err(input.new_custom_error(e));
}
Ok(selector)
parse_selector(parser, input)
}
}

View file

@ -17,7 +17,7 @@ mod bindings {
use bindgen::{Builder, CodegenConfig};
use regex::Regex;
use std::cmp;
use std::collections::{HashMap, HashSet};
use std::collections::HashSet;
use std::env;
use std::fs::{self, File};
use std::io::{Read, Write};
@ -43,7 +43,7 @@ mod bindings {
.expect("Failed to open config file")
.read_to_string(&mut contents)
.expect("Failed to read config file");
match toml::from_str::<toml::value::Table>(&contents) {
match toml::from_str::<Table>(&contents) {
Ok(result) => result,
Err(e) => panic!("Failed to parse config file: {}", e),
}
@ -58,22 +58,10 @@ mod bindings {
};
static ref BUILD_CONFIG: Table = {
// Load build-specific config overrides.
// FIXME: We should merge with CONFIG above instead of
// forcing callers to do it.
let path = PathBuf::from(env::var_os("MOZ_TOPOBJDIR").unwrap())
.join("layout/style/bindgen.toml");
read_config(&path)
};
static ref TARGET_INFO: HashMap<String, String> = {
const TARGET_PREFIX: &'static str = "CARGO_CFG_TARGET_";
let mut result = HashMap::new();
for (k, v) in env::vars() {
if k.starts_with(TARGET_PREFIX) {
result.insert(k[TARGET_PREFIX.len()..].to_lowercase(), v);
}
}
result
};
static ref INCLUDE_RE: Regex = Regex::new(r#"#include\s*"(.+?)""#).unwrap();
static ref DISTDIR_PATH: PathBuf = {
let path = PathBuf::from(env::var_os("MOZ_DIST").unwrap());
@ -145,35 +133,6 @@ mod bindings {
fn mutable_borrowed_type(self, ty: &str) -> Builder;
}
fn add_clang_args(mut builder: Builder, config: &Table, matched_os: &mut bool) -> Builder {
fn add_args(mut builder: Builder, values: &[toml::Value]) -> Builder {
for item in values.iter() {
builder = builder.clang_arg(item.as_str().expect("Expect string in list"));
}
builder
}
for (k, v) in config.iter() {
if k == "args" {
builder = add_args(builder, v.as_array().unwrap().as_slice());
continue;
}
let equal_idx = k.find('=').expect(&format!("Invalid key: {}", k));
let (target_type, target_value) = k.split_at(equal_idx);
if TARGET_INFO[target_type] != target_value[1..] {
continue;
}
if target_type == "os" {
*matched_os = true;
}
builder = match *v {
toml::Value::Table(ref table) => add_clang_args(builder, table, matched_os),
toml::Value::Array(ref array) => add_args(builder, array),
_ => panic!("Unknown type"),
};
}
builder
}
impl BuilderExt for Builder {
fn get_initial_builder() -> Builder {
use bindgen::RustTarget;
@ -207,16 +166,14 @@ mod bindings {
builder = builder.clang_arg("-DDEBUG=1").clang_arg("-DJS_DEBUG=1");
}
let mut matched_os = false;
let build_config = CONFIG["build"].as_table().expect("Malformed config file");
builder = add_clang_args(builder, build_config, &mut matched_os);
let build_config = BUILD_CONFIG["build"]
.as_table()
.expect("Malformed config file");
builder = add_clang_args(builder, build_config, &mut matched_os);
if !matched_os {
panic!("Unknown platform");
let extra_bindgen_flags = build_config["args"].as_array().unwrap().as_slice();
for item in extra_bindgen_flags.iter() {
builder = builder.clang_arg(item.as_str().expect("Expect string in list"));
}
builder
}
fn include<T: Into<String>>(self, file: T) -> Builder {
@ -300,35 +257,57 @@ mod bindings {
.expect("Unable to write output");
}
fn get_arc_types() -> Vec<String> {
fn get_types(filename: &str, macro_pat: &str) -> Vec<(String, String)> {
// Read the file
let mut list_file = File::open(DISTDIR_PATH.join("include/mozilla/ServoArcTypeList.h"))
.expect("Unable to open ServoArcTypeList.h");
let path = DISTDIR_PATH.join("include/mozilla/").join(filename);
let mut list_file = File::open(path).expect(&format!("Unable to open {}", filename));
let mut content = String::new();
list_file
.read_to_string(&mut content)
.expect("Fail to read ServoArcTypeList.h");
.expect(&format!("Failed to read {}", filename));
// Remove comments
let block_comment_re = Regex::new(r#"(?s)/\*.*?\*/"#).unwrap();
let line_comment_re = Regex::new(r#"//.*"#).unwrap();
let content = block_comment_re.replace_all(&content, "");
let content = line_comment_re.replace_all(&content, "");
// Extract the list
let re = Regex::new(r#"^SERVO_ARC_TYPE\(\w+,\s*(\w+)\)$"#).unwrap();
let re_string = format!(r#"^({})\(.+,\s*(\w+)\)$"#, macro_pat);
let re = Regex::new(&re_string).unwrap();
content
.lines()
.map(|line| line.trim())
.filter(|line| !line.is_empty())
.map(|line| {
re.captures(&line)
.expect(&format!(
"Unrecognized line in ServoArcTypeList.h: '{}'",
line
)).get(1)
.unwrap()
.as_str()
.to_string()
let captures = re
.captures(&line)
.expect(&format!("Unrecognized line in {}: '{}'", filename, line));
let macro_name = captures.get(1).unwrap().as_str().to_string();
let type_name = captures.get(2).unwrap().as_str().to_string();
(macro_name, type_name)
}).collect()
}
fn get_borrowed_types() -> Vec<(bool, String)> {
get_types("BorrowedTypeList.h", "GECKO_BORROWED_TYPE(?:_MUT)?")
.into_iter()
.map(|(macro_name, type_name)| (macro_name.ends_with("MUT"), type_name))
.collect()
}
fn get_arc_types() -> Vec<String> {
get_types("ServoArcTypeList.h", "SERVO_ARC_TYPE")
.into_iter()
.map(|(_, type_name)| type_name)
.collect()
}
fn get_boxed_types() -> Vec<String> {
get_types("ServoBoxedTypeList.h", "SERVO_BOXED_TYPE")
.into_iter()
.map(|(_, type_name)| type_name)
.collect()
}
struct BuilderWithConfig<'a> {
builder: Builder,
config: &'a Table,
@ -524,19 +503,6 @@ mod bindings {
"&'a mut ::gecko_bindings::structs::nsTArray<{}>;"),
cpp_type, rust_type))
})
.handle_table_items("servo-owned-types", |mut builder, item| {
let name = item["name"].as_str().unwrap();
builder = builder.blacklist_type(format!("{}Owned", name))
.raw_line(format!("pub type {0}Owned = ::gecko_bindings::sugar::ownership::Owned<{0}>;", name))
.blacklist_type(format!("{}OwnedOrNull", name))
.raw_line(format!(concat!("pub type {0}OwnedOrNull = ",
"::gecko_bindings::sugar::ownership::OwnedOrNull<{0}>;"), name))
.mutable_borrowed_type(name);
if item["opaque"].as_bool().unwrap() {
builder = builder.zero_size_type(name, &structs_types);
}
builder
})
.handle_str_items("servo-immutable-borrow-types", |b, ty| b.borrowed_type(ty))
// Right now the only immutable borrow types are ones which we import
// from the |structs| module. As such, we don't need to create an opaque
@ -544,6 +510,13 @@ mod bindings {
// which _do_ need to be opaque, we'll need a separate mode.
.handle_str_items("servo-borrow-types", |b, ty| b.mutable_borrowed_type(ty))
.get_builder();
for (is_mut, ty) in get_borrowed_types().iter() {
if *is_mut {
builder = builder.mutable_borrowed_type(ty);
} else {
builder = builder.borrowed_type(ty);
}
}
for ty in get_arc_types().iter() {
builder = builder
.blacklist_type(format!("{}Strong", ty))
@ -553,6 +526,22 @@ mod bindings {
)).borrowed_type(ty)
.zero_size_type(ty, &structs_types);
}
for ty in get_boxed_types().iter() {
builder = builder
.blacklist_type(format!("{}Owned", ty))
.raw_line(format!(
"pub type {0}Owned = ::gecko_bindings::sugar::ownership::Owned<{0}>;",
ty
)).blacklist_type(format!("{}OwnedOrNull", ty))
.raw_line(format!(
concat!(
"pub type {0}OwnedOrNull = ",
"::gecko_bindings::sugar::ownership::OwnedOrNull<{0}>;"
),
ty
)).mutable_borrowed_type(ty)
.zero_size_type(ty, &structs_types);
}
write_binding_file(builder, BINDINGS_FILE, &fixups);
}

View file

@ -8,6 +8,7 @@
#![allow(non_snake_case, missing_docs)]
use gecko::url::CssUrlData;
use gecko_bindings::bindings::RawServoCounterStyleRule;
use gecko_bindings::bindings::RawServoFontFeatureValuesRule;
use gecko_bindings::bindings::RawServoImportRule;
@ -22,6 +23,7 @@ use gecko_bindings::bindings::RawServoRuleNodeStrong;
use gecko_bindings::bindings::RawServoSupportsRule;
use gecko_bindings::bindings::ServoCssRules;
use gecko_bindings::structs::RawServoAnimationValue;
use gecko_bindings::structs::RawServoCssUrlData;
use gecko_bindings::structs::RawServoDeclarationBlock;
use gecko_bindings::structs::RawServoFontFaceRule;
use gecko_bindings::structs::RawServoMediaList;
@ -110,6 +112,9 @@ impl_arc_ffi!(Locked<FontFaceRule> => RawServoFontFaceRule
impl_arc_ffi!(Locked<CounterStyleRule> => RawServoCounterStyleRule
[Servo_CounterStyleRule_AddRef, Servo_CounterStyleRule_Release]);
impl_arc_ffi!(CssUrlData => RawServoCssUrlData
[Servo_CssUrlData_AddRef, Servo_CssUrlData_Release]);
// RuleNode is a Arc-like type but it does not use Arc.
impl StrongRuleNode {

View file

@ -11,7 +11,7 @@
use app_units::Au;
use gecko::values::GeckoStyleCoordConvertible;
use gecko_bindings::bindings;
use gecko_bindings::structs::{self, nsCSSUnit, nsStyleCoord_CalcValue};
use gecko_bindings::structs::{self, nsStyleCoord_CalcValue};
use gecko_bindings::structs::{nsresult, SheetType, nsStyleImage};
use gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue};
use std::f32::consts::PI;
@ -128,35 +128,7 @@ impl From<nsStyleCoord_CalcValue> for NonNegativeLengthOrPercentageOrAuto {
impl From<Angle> for CoordDataValue {
fn from(reference: Angle) -> Self {
match reference {
Angle::Deg(val) => CoordDataValue::Degree(val),
Angle::Grad(val) => CoordDataValue::Grad(val),
Angle::Rad(val) => CoordDataValue::Radian(val),
Angle::Turn(val) => CoordDataValue::Turn(val),
}
}
}
impl Angle {
/// Converts Angle struct into (value, unit) pair.
pub fn to_gecko_values(&self) -> (f32, nsCSSUnit) {
match *self {
Angle::Deg(val) => (val, nsCSSUnit::eCSSUnit_Degree),
Angle::Grad(val) => (val, nsCSSUnit::eCSSUnit_Grad),
Angle::Rad(val) => (val, nsCSSUnit::eCSSUnit_Radian),
Angle::Turn(val) => (val, nsCSSUnit::eCSSUnit_Turn),
}
}
/// Converts gecko (value, unit) pair into Angle struct
pub fn from_gecko_values(value: f32, unit: nsCSSUnit) -> Angle {
match unit {
nsCSSUnit::eCSSUnit_Degree => Angle::Deg(value),
nsCSSUnit::eCSSUnit_Grad => Angle::Grad(value),
nsCSSUnit::eCSSUnit_Radian => Angle::Rad(value),
nsCSSUnit::eCSSUnit_Turn => Angle::Turn(value),
_ => panic!("Unexpected unit for angle"),
}
CoordDataValue::Degree(reference.degrees())
}
}
@ -225,13 +197,13 @@ impl nsStyleImage {
match image {
GenericImage::Gradient(boxed_gradient) => self.set_gradient(*boxed_gradient),
GenericImage::Url(ref url) => unsafe {
bindings::Gecko_SetLayerImageImageValue(self, url.0.image_value.get());
bindings::Gecko_SetLayerImageImageValue(self, (url.0).0.url_value.get());
},
GenericImage::Rect(ref image_rect) => {
unsafe {
bindings::Gecko_SetLayerImageImageValue(
self,
image_rect.url.0.image_value.get(),
(image_rect.url.0).0.url_value.get(),
);
bindings::Gecko_InitializeImageCropRect(self);

View file

@ -8,7 +8,7 @@ use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
use context::QuirksMode;
use dom::TElement;
use gecko_bindings::bindings::{self, RawServoStyleSet};
use gecko_bindings::structs::{RawGeckoPresContextOwned, ServoStyleSetSizes, StyleSheet as DomStyleSheet};
use gecko_bindings::structs::{RawGeckoPresContextBorrowed, ServoStyleSetSizes, StyleSheet as DomStyleSheet};
use gecko_bindings::structs::{StyleSheetInfo, nsIDocument};
use gecko_bindings::sugar::ownership::{HasArcFFI, HasBoxFFI, HasFFI, HasSimpleFFI};
use invalidation::media_queries::{MediaListKey, ToMediaListKey};
@ -143,7 +143,7 @@ pub struct PerDocumentStyleData(AtomicRefCell<PerDocumentStyleDataImpl>);
impl PerDocumentStyleData {
/// Create a dummy `PerDocumentStyleData`.
pub fn new(pres_context: RawGeckoPresContextOwned) -> Self {
pub fn new(pres_context: RawGeckoPresContextBorrowed) -> Self {
let device = Device::new(pres_context);
// FIXME(emilio, tlin): How is this supposed to work with XBL? This is

View file

@ -12,7 +12,7 @@ use euclid::TypedScale;
use gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor};
use gecko_bindings::bindings;
use gecko_bindings::structs;
use gecko_bindings::structs::{nsPresContext, RawGeckoPresContextOwned};
use gecko_bindings::structs::{nsPresContext, RawGeckoPresContextBorrowed};
use media_queries::MediaType;
use properties::ComputedValues;
use servo_arc::Arc;
@ -30,7 +30,7 @@ pub struct Device {
/// NB: The pres context lifetime is tied to the styleset, who owns the
/// stylist, and thus the `Device`, so having a raw pres context pointer
/// here is fine.
pres_context: RawGeckoPresContextOwned,
pres_context: RawGeckoPresContextBorrowed,
default_values: Arc<ComputedValues>,
/// The font size of the root element
/// This is set when computing the style of the root
@ -77,7 +77,7 @@ unsafe impl Send for Device {}
impl Device {
/// Trivially constructs a new `Device`.
pub fn new(pres_context: RawGeckoPresContextOwned) -> Self {
pub fn new(pres_context: RawGeckoPresContextBorrowed) -> Self {
assert!(!pres_context.is_null());
Device {
pres_context,

View file

@ -57,15 +57,6 @@ impl PseudoElement {
PseudoElementCascadeType::Lazy
}
/// Whether cascading this pseudo-element makes it inherit all properties,
/// even reset ones.
///
/// This is used in Servo for anonymous boxes, though it's likely broken.
#[inline]
pub fn inherits_all(&self) -> bool {
false
}
/// Whether the pseudo-element should inherit from the default computed
/// values instead of from the parent element.
///

View file

@ -35,10 +35,11 @@ class Atom:
self.original_ident = ident
self.value = value
self.hash = hash
# The Gecko type: "nsStaticAtom", "nsICSSPseudoElement", or "nsIAnonBoxPseudo"
# The Gecko type: "nsStaticAtom", "nsCSSPseudoElementStaticAtom", or
# "nsAnonBoxPseudoStaticAtom".
self.ty = ty
# The type of atom: "Atom", "PseudoElement", "NonInheritingAnonBox",
# or "InheritingAnonBox"
# or "InheritingAnonBox".
self.atom_type = atom_type
if self.is_pseudo() or self.is_anon_box():
self.pseudo_ident = (ident.split("_", 1))[1]
@ -205,7 +206,7 @@ def write_atom_macro(atoms, file_name):
def write_pseudo_elements(atoms, target_filename):
pseudos = []
for atom in atoms:
if atom.type() == "nsICSSPseudoElement" or atom.type() == "nsICSSAnonBoxPseudo":
if atom.type() == "nsCSSPseudoElementStaticAtom" or atom.type() == "nsCSSAnonBoxPseudoStaticAtom":
pseudos.append(atom)
pseudo_definition_template = os.path.join(GECKO_DIR, "pseudo_element_definition.mako.rs")

View file

@ -6,18 +6,16 @@
use cssparser::Parser;
use gecko_bindings::bindings;
use gecko_bindings::structs::ServoBundledURI;
use gecko_bindings::structs::mozilla::css::URLValueData;
use gecko_bindings::structs::root::{RustString, nsStyleImageRequest};
use gecko_bindings::structs::root::mozilla::CORSMode;
use gecko_bindings::structs::root::mozilla::css::{ImageValue, URLValue};
use gecko_bindings::structs::root::mozilla::css::URLValue;
use gecko_bindings::structs::root::nsStyleImageRequest;
use gecko_bindings::sugar::ownership::{HasArcFFI, FFIArcHelpers};
use gecko_bindings::sugar::refptr::RefPtr;
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use nsstring::nsCString;
use parser::{Parse, ParserContext};
use servo_arc::{Arc, RawOffsetArc};
use servo_arc::Arc;
use std::fmt::{self, Write};
use std::mem;
use style_traits::{CssWriter, ParseError, ToCss};
use stylesheets::UrlExtraData;
use values::computed::{Context, ToComputedValue};
@ -25,12 +23,13 @@ use values::computed::{Context, ToComputedValue};
/// A CSS url() value for gecko.
#[css(function = "url")]
#[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToCss)]
pub struct CssUrl {
pub struct CssUrl(pub Arc<CssUrlData>);
/// Data shared between CssUrls.
#[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToCss)]
pub struct CssUrlData {
/// The URL in unresolved string form.
///
/// Refcounted since cloning this should be cheap and data: uris can be
/// really large.
serialization: Arc<String>,
serialization: String,
/// The URL extra data.
#[css(skip)]
@ -38,13 +37,12 @@ pub struct CssUrl {
}
impl CssUrl {
/// Try to parse a URL from a string value that is a valid CSS token for a
/// URL.
/// Parse a URL from a string value that is a valid CSS token for a URL.
pub fn parse_from_string(url: String, context: &ParserContext) -> Self {
CssUrl {
serialization: Arc::new(url),
CssUrl(Arc::new(CssUrlData {
serialization: url,
extra_data: context.url_data.clone(),
}
}))
}
/// Returns true if the URL is definitely invalid. We don't eagerly resolve
@ -54,15 +52,22 @@ impl CssUrl {
false
}
/// Convert from URLValueData to SpecifiedUrl.
unsafe fn from_url_value_data(url: &URLValueData) -> Self {
let arc_type = &url.mString as *const _ as *const RawOffsetArc<String>;
CssUrl {
serialization: Arc::from_raw_offset((*arc_type).clone()),
extra_data: UrlExtraData(url.mExtraData.to_safe()),
/// Returns true if this URL looks like a fragment.
/// See https://drafts.csswg.org/css-values/#local-urls
#[inline]
pub fn is_fragment(&self) -> bool {
self.0.is_fragment()
}
/// Return the unresolved url as string, or the empty string if it's
/// invalid.
#[inline]
pub fn as_str(&self) -> &str {
self.0.as_str()
}
}
impl CssUrlData {
/// Returns true if this URL looks like a fragment.
/// See https://drafts.csswg.org/css-values/#local-urls
pub fn is_fragment(&self) -> bool {
@ -74,24 +79,6 @@ impl CssUrl {
pub fn as_str(&self) -> &str {
&*self.serialization
}
/// Little helper for Gecko's ffi.
pub fn as_slice_components(&self) -> (*const u8, usize) {
(
self.serialization.as_str().as_ptr(),
self.serialization.as_str().len(),
)
}
/// Create a bundled URI suitable for sending to Gecko
/// to be constructed into a css::URLValue
pub fn for_ffi(&self) -> ServoBundledURI {
let arc_offset = Arc::into_raw_offset(self.serialization.clone());
ServoBundledURI {
mURLString: unsafe { mem::transmute::<_, RawOffsetArc<RustString>>(arc_offset) },
mExtraData: self.extra_data.0.get(),
}
}
}
impl Parse for CssUrl {
@ -117,7 +104,7 @@ impl MallocSizeOf for CssUrl {
}
}
/// A specified url() value for general usage.
/// A specified non-image `url()` value.
#[derive(Clone, Debug, SpecifiedValueInfo, ToCss)]
pub struct SpecifiedUrl {
/// The specified url value.
@ -129,72 +116,22 @@ pub struct SpecifiedUrl {
}
impl SpecifiedUrl {
fn from_css_url(url: CssUrl) -> Self {
let url_value = unsafe {
let ptr = bindings::Gecko_NewURLValue(url.for_ffi());
// We do not expect Gecko_NewURLValue returns null.
debug_assert!(!ptr.is_null());
RefPtr::from_addrefed(ptr)
};
Self { url, url_value }
}
}
impl PartialEq for SpecifiedUrl {
fn eq(&self, other: &Self) -> bool {
self.url.eq(&other.url)
}
}
impl Eq for SpecifiedUrl {}
impl Parse for SpecifiedUrl {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
CssUrl::parse(context, input).map(Self::from_css_url)
}
}
impl MallocSizeOf for SpecifiedUrl {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
let mut n = self.url.size_of(ops);
// Although this is a RefPtr, this is the primary reference because
// SpecifiedUrl is responsible for creating the url_value. So we
// measure unconditionally here.
n += unsafe { bindings::Gecko_URLValue_SizeOfIncludingThis(self.url_value.get()) };
n
}
}
/// A specified url() value for image.
///
/// This exists so that we can construct `ImageValue` and reuse it.
#[derive(Clone, Debug, SpecifiedValueInfo, ToCss)]
pub struct SpecifiedImageUrl {
/// The specified url value.
pub url: CssUrl,
/// Gecko's ImageValue so that we can reuse it while rematching a
/// property with this specified value.
#[css(skip)]
pub image_value: RefPtr<ImageValue>,
}
impl SpecifiedImageUrl {
/// Parse a URL from a string value. See SpecifiedUrl::parse_from_string.
/// Parse a URL from a string value.
pub fn parse_from_string(url: String, context: &ParserContext) -> Self {
Self::from_css_url(CssUrl::parse_from_string(url, context))
}
fn from_css_url_with_cors(url: CssUrl, cors: CORSMode) -> Self {
let image_value = unsafe {
let ptr = bindings::Gecko_ImageValue_Create(url.for_ffi(), cors);
// We do not expect Gecko_ImageValue_Create returns null.
let url_value = unsafe {
let ptr = bindings::Gecko_URLValue_Create(
url.0.clone().into_strong(),
cors,
);
// We do not expect Gecko_URLValue_Create returns null.
debug_assert!(!ptr.is_null());
RefPtr::from_addrefed(ptr)
};
Self { url, image_value }
Self { url, url_value }
}
fn from_css_url(url: CssUrl) -> Self {
@ -206,18 +143,9 @@ impl SpecifiedImageUrl {
use gecko_bindings::structs::root::mozilla::CORSMode_CORS_ANONYMOUS;
Self::from_css_url_with_cors(url, CORSMode_CORS_ANONYMOUS)
}
/// Provides an alternate method for parsing that associates the URL
/// with anonymous CORS headers.
pub fn parse_with_cors_anonymous<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
CssUrl::parse(context, input).map(Self::from_css_url_with_cors_anonymous)
}
}
impl Parse for SpecifiedImageUrl {
impl Parse for SpecifiedUrl {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
@ -226,21 +154,21 @@ impl Parse for SpecifiedImageUrl {
}
}
impl PartialEq for SpecifiedImageUrl {
impl PartialEq for SpecifiedUrl {
fn eq(&self, other: &Self) -> bool {
self.url.eq(&other.url)
}
}
impl Eq for SpecifiedImageUrl {}
impl Eq for SpecifiedUrl {}
impl MallocSizeOf for SpecifiedImageUrl {
impl MallocSizeOf for SpecifiedUrl {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
let mut n = self.url.size_of(ops);
// Although this is a RefPtr, this is the primary reference because
// SpecifiedUrl is responsible for creating the image_value. So we
// SpecifiedUrl is responsible for creating the url_value. So we
// measure unconditionally here.
n += unsafe { bindings::Gecko_ImageValue_SizeOfIncludingThis(self.image_value.get()) };
n += unsafe { bindings::Gecko_URLValue_SizeOfIncludingThis(self.url_value.get()) };
n
}
}
@ -259,6 +187,37 @@ impl ToComputedValue for SpecifiedUrl {
}
}
/// A specified image `url()` value.
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
pub struct SpecifiedImageUrl(pub SpecifiedUrl);
impl SpecifiedImageUrl {
/// Parse a URL from a string value that is a valid CSS token for a URL.
pub fn parse_from_string(url: String, context: &ParserContext) -> Self {
SpecifiedImageUrl(SpecifiedUrl::parse_from_string(url, context))
}
/// Provides an alternate method for parsing that associates the URL
/// with anonymous CORS headers.
pub fn parse_with_cors_anonymous<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
CssUrl::parse(context, input)
.map(SpecifiedUrl::from_css_url_with_cors_anonymous)
.map(SpecifiedImageUrl)
}
}
impl Parse for SpecifiedImageUrl {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
SpecifiedUrl::parse(context, input).map(SpecifiedImageUrl)
}
}
impl ToComputedValue for SpecifiedImageUrl {
type ComputedValue = ComputedImageUrl;
@ -274,9 +233,9 @@ impl ToComputedValue for SpecifiedImageUrl {
}
fn serialize_computed_url<W>(
url_value_data: &URLValueData,
url_value: &URLValue,
dest: &mut CssWriter<W>,
get_url: unsafe extern "C" fn(*const URLValueData, *mut nsCString),
get_url: unsafe extern "C" fn(*const URLValue, *mut nsCString),
) -> fmt::Result
where
W: Write,
@ -284,13 +243,13 @@ where
dest.write_str("url(")?;
unsafe {
let mut string = nsCString::new();
get_url(url_value_data, &mut string);
get_url(url_value, &mut string);
string.as_str_unchecked().to_css(dest)?;
}
dest.write_char(')')
}
/// The computed value of a CSS `url()`.
/// The computed value of a CSS non-image `url()`.
///
/// The only difference between specified and computed URLs is the
/// serialization.
@ -303,7 +262,7 @@ impl ToCss for ComputedUrl {
W: Write,
{
serialize_computed_url(
&self.0.url_value._base,
&self.0.url_value,
dest,
bindings::Gecko_GetComputedURLSpec,
)
@ -313,12 +272,18 @@ impl ToCss for ComputedUrl {
impl ComputedUrl {
/// Convert from RefPtr<URLValue> to ComputedUrl.
pub unsafe fn from_url_value(url_value: RefPtr<URLValue>) -> Self {
let url = CssUrl::from_url_value_data(&url_value._base);
let css_url = &*url_value.mCssUrl.mRawPtr;
let url = CssUrl(CssUrlData::as_arc(&css_url).clone_arc());
ComputedUrl(SpecifiedUrl { url, url_value })
}
/// Get a raw pointer to the URLValue held by this ComputedUrl, for FFI.
pub fn url_value_ptr(&self) -> *mut URLValue {
self.0.url_value.get()
}
}
/// The computed value of a CSS `url()` for image.
/// The computed value of a CSS image `url()`.
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)]
pub struct ComputedImageUrl(pub SpecifiedImageUrl);
@ -328,7 +293,7 @@ impl ToCss for ComputedImageUrl {
W: Write,
{
serialize_computed_url(
&self.0.image_value._base,
&(self.0).0.url_value,
dest,
bindings::Gecko_GetComputedImageURLSpec,
)
@ -338,8 +303,14 @@ impl ToCss for ComputedImageUrl {
impl ComputedImageUrl {
/// Convert from nsStyleImageReques to ComputedImageUrl.
pub unsafe fn from_image_request(image_request: &nsStyleImageRequest) -> Self {
let image_value = image_request.mImageValue.to_safe();
let url = CssUrl::from_url_value_data(&image_value._base);
ComputedImageUrl(SpecifiedImageUrl { url, image_value })
let url_value = image_request.mImageValue.to_safe();
let css_url = &*url_value.mCssUrl.mRawPtr;
let url = CssUrl(CssUrlData::as_arc(&css_url).clone_arc());
ComputedImageUrl(SpecifiedImageUrl(SpecifiedUrl { url, url_value }))
}
/// Get a raw pointer to the URLValue held by this ComputedImageUrl, for FFI.
pub fn url_value_ptr(&self) -> *mut URLValue {
(self.0).0.url_value.get()
}
}

View file

@ -19,7 +19,7 @@ use std::cmp::max;
use values::{Auto, Either, None_, Normal};
use values::computed::{Angle, ExtremumLength, Length, LengthOrPercentage, LengthOrPercentageOrAuto};
use values::computed::{LengthOrPercentageOrNone, Number, NumberOrPercentage};
use values::computed::{MaxLength, MozLength, Percentage};
use values::computed::{MaxLength as ComputedMaxLength, MozLength as ComputedMozLength, Percentage};
use values::computed::{NonNegativeLength, NonNegativeLengthOrPercentage, NonNegativeNumber};
use values::computed::FlexBasis as ComputedFlexBasis;
use values::computed::basic_shape::ShapeRadius as ComputedShapeRadius;
@ -29,6 +29,7 @@ use values::generics::box_::Perspective;
use values::generics::flex::FlexBasis;
use values::generics::gecko::ScrollSnapPoint;
use values::generics::grid::{TrackBreadth, TrackKeyword};
use values::generics::length::{MaxLength, MozLength};
/// A trait that defines an interface to convert from and to `nsStyleCoord`s.
pub trait GeckoStyleCoordConvertible: Sized {
@ -74,7 +75,7 @@ impl GeckoStyleCoordConvertible for ComputedFlexBasis {
}
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
if let Some(width) = MozLength::from_gecko_style_coord(coord) {
if let Some(width) = ComputedMozLength::from_gecko_style_coord(coord) {
return Some(FlexBasis::Width(width));
}
@ -325,10 +326,7 @@ impl GeckoStyleCoordConvertible for Angle {
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
match coord.as_value() {
CoordDataValue::Degree(val) => Some(Angle::Deg(val)),
CoordDataValue::Grad(val) => Some(Angle::Grad(val)),
CoordDataValue::Radian(val) => Some(Angle::Rad(val)),
CoordDataValue::Turn(val) => Some(Angle::Turn(val)),
CoordDataValue::Degree(val) => Some(Angle::from_degrees(val)),
_ => None,
}
}
@ -409,7 +407,7 @@ impl GeckoStyleCoordConvertible for ExtremumLength {
}
}
impl GeckoStyleCoordConvertible for MozLength {
impl GeckoStyleCoordConvertible for ComputedMozLength {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
match *self {
MozLength::LengthOrPercentageOrAuto(ref lopoa) => lopoa.to_gecko_style_coord(coord),
@ -426,7 +424,7 @@ impl GeckoStyleCoordConvertible for MozLength {
}
}
impl GeckoStyleCoordConvertible for MaxLength {
impl GeckoStyleCoordConvertible for ComputedMaxLength {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
match *self {
MaxLength::LengthOrPercentageOrNone(ref lopon) => lopon.to_gecko_style_coord(coord),

View file

@ -60,7 +60,7 @@ impl nsCSSValue {
pub unsafe fn array_unchecked(&self) -> &nsCSSValue_Array {
debug_assert!(
nsCSSUnit::eCSSUnit_Array as u32 <= self.mUnit as u32 &&
self.mUnit as u32 <= nsCSSUnit::eCSSUnit_Calc_Divided as u32
self.mUnit as u32 <= nsCSSUnit::eCSSUnit_Calc_Plus as u32
);
let array = *self.mValue.mArray.as_ref();
debug_assert!(!array.is_null());
@ -198,19 +198,19 @@ impl nsCSSValue {
/// Returns an `Angle` value from this `nsCSSValue`.
///
/// Panics if the unit is not `eCSSUnit_Degree` `eCSSUnit_Grad`, `eCSSUnit_Turn`
/// or `eCSSUnit_Radian`.
/// Panics if the unit is not `eCSSUnit_Degree`.
#[inline]
pub fn get_angle(&self) -> Angle {
Angle::from_gecko_values(self.float_unchecked(), self.mUnit)
debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_Degree);
Angle::from_degrees(self.float_unchecked())
}
/// Sets Angle value to this nsCSSValue.
pub fn set_angle(&mut self, angle: Angle) {
debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_Null);
let (value, unit) = angle.to_gecko_values();
self.mUnit = unit;
self.mUnit = nsCSSUnit::eCSSUnit_Degree;
unsafe {
*self.mValue.mFloat.as_mut() = value;
*self.mValue.mFloat.as_mut() = angle.degrees();
}
}

View file

@ -200,12 +200,6 @@ pub enum CoordDataValue {
Factor(f32),
/// eStyleUnit_Degree
Degree(f32),
/// eStyleUnit_Grad
Grad(f32),
/// eStyleUnit_Radian
Radian(f32),
/// eStyleUnit_Turn
Turn(f32),
/// eStyleUnit_FlexFraction
FlexFraction(f32),
/// eStyleUnit_Coord
@ -317,18 +311,6 @@ pub unsafe trait CoordDataMut: CoordData {
*unit = eStyleUnit_Degree;
*union.mFloat.as_mut() = f;
},
Grad(f) => {
*unit = eStyleUnit_Grad;
*union.mFloat.as_mut() = f;
},
Radian(f) => {
*unit = eStyleUnit_Radian;
*union.mFloat.as_mut() = f;
},
Turn(f) => {
*unit = eStyleUnit_Turn;
*union.mFloat.as_mut() = f;
},
FlexFraction(f) => {
*unit = eStyleUnit_FlexFraction;
*union.mFloat.as_mut() = f;
@ -393,9 +375,6 @@ pub unsafe trait CoordData {
eStyleUnit_Percent => Percent(self.get_float()),
eStyleUnit_Factor => Factor(self.get_float()),
eStyleUnit_Degree => Degree(self.get_float()),
eStyleUnit_Grad => Grad(self.get_float()),
eStyleUnit_Radian => Radian(self.get_float()),
eStyleUnit_Turn => Turn(self.get_float()),
eStyleUnit_FlexFraction => FlexFraction(self.get_float()),
eStyleUnit_Coord => Coord(self.get_integer()),
eStyleUnit_Integer => Integer(self.get_integer()),
@ -413,9 +392,6 @@ pub unsafe trait CoordData {
self.unit() == eStyleUnit_Percent ||
self.unit() == eStyleUnit_Factor ||
self.unit() == eStyleUnit_Degree ||
self.unit() == eStyleUnit_Grad ||
self.unit() == eStyleUnit_Radian ||
self.unit() == eStyleUnit_Turn ||
self.unit() == eStyleUnit_FlexFraction
);
*self.union().mFloat.as_ref()

View file

@ -82,9 +82,9 @@ impl<T> nsTArray<T> {
/// Resize and set the length of the array to `len`.
///
/// unsafe because the array may contain uninitialized members.
/// unsafe because this may leave the array with uninitialized elements.
///
/// This will not call constructors, if you need that, either manually add
/// This will not call constructors. If you need that, either manually add
/// bindings or run the typed `EnsureCapacity` call on the gecko side.
pub unsafe fn set_len(&mut self, len: u32) {
// this can leak
@ -96,6 +96,8 @@ impl<T> nsTArray<T> {
/// Resizes an array containing only POD elements
///
/// unsafe because this may leave the array with uninitialized elements.
///
/// This will not leak since it only works on POD types (and thus doesn't assert)
pub unsafe fn set_len_pod(&mut self, len: u32)
where
@ -105,4 +107,17 @@ impl<T> nsTArray<T> {
let header = self.header_mut();
header.mLength = len;
}
/// Collects the given iterator into this array.
///
/// Not unsafe because we won't leave uninitialized elements in the array.
pub fn assign_from_iter_pod<I>(&mut self, iter: I)
where
T: Copy,
I: ExactSizeIterator + Iterator<Item = T>,
{
debug_assert!(iter.len() <= 0xFFFFFFFF);
unsafe { self.set_len_pod(iter.len() as u32); }
self.iter_mut().zip(iter).for_each(|(r, v)| *r = v);
}
}

View file

@ -297,11 +297,6 @@ impl_threadsafe_refcount!(
bindings::Gecko_AddRefGridTemplateAreasValueArbitraryThread,
bindings::Gecko_ReleaseGridTemplateAreasValueArbitraryThread
);
impl_threadsafe_refcount!(
structs::ImageValue,
bindings::Gecko_AddRefImageValueArbitraryThread,
bindings::Gecko_ReleaseImageValueArbitraryThread
);
impl_threadsafe_refcount!(
structs::SharedFontList,
bindings::Gecko_AddRefSharedFontListArbitraryThread,

View file

@ -689,7 +689,10 @@ def set_gecko_property(ffi_name, expr):
}
SVGPaintKind::PaintServer(url) => {
unsafe {
bindings::Gecko_nsStyleSVGPaint_SetURLValue(paint, url.0.url_value.get());
bindings::Gecko_nsStyleSVGPaint_SetURLValue(
paint,
url.url_value_ptr(),
)
}
}
SVGPaintKind::Color(color) => {
@ -1370,35 +1373,22 @@ impl Clone for ${style_struct.gecko_struct_name} {
}
</%def>
<%def name="impl_font_settings(ident, tag_type, value_type, gecko_value_type)">
<%def name="impl_font_settings(ident, gecko_type, tag_type, value_type, gecko_value_type)">
<%
gecko_ffi_name = to_camel_case_lower(ident)
%>
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
let current_settings = &mut self.gecko.mFont.${gecko_ffi_name};
current_settings.clear_pod();
unsafe { current_settings.set_len_pod(v.0.len() as u32) };
for (current, other) in current_settings.iter_mut().zip(v.0.iter()) {
current.mTag = other.tag.0;
current.mValue = other.value as ${gecko_value_type};
}
let iter = v.0.iter().map(|other| structs::${gecko_type} {
mTag: other.tag.0,
mValue: other.value as ${gecko_value_type},
});
self.gecko.mFont.${gecko_ffi_name}.assign_from_iter_pod(iter);
}
pub fn copy_${ident}_from(&mut self, other: &Self) {
let current_settings = &mut self.gecko.mFont.${gecko_ffi_name};
let other_settings = &other.gecko.mFont.${gecko_ffi_name};
let settings_length = other_settings.len() as u32;
current_settings.clear_pod();
unsafe { current_settings.set_len_pod(settings_length) };
for (current, other) in current_settings.iter_mut().zip(other_settings.iter()) {
current.mTag = other.mTag;
current.mValue = other.mValue;
}
let iter = other.gecko.mFont.${gecko_ffi_name}.iter().map(|s| *s);
self.gecko.mFont.${gecko_ffi_name}.assign_from_iter_pod(iter);
}
pub fn reset_${ident}(&mut self, other: &Self) {
@ -2271,8 +2261,8 @@ fn static_assert() {
// Negative numbers are invalid at parse time, but <integer> is still an
// i32.
<% impl_font_settings("font_feature_settings", "FeatureTagValue", "i32", "u32") %>
<% impl_font_settings("font_variation_settings", "VariationValue", "f32", "f32") %>
<% impl_font_settings("font_feature_settings", "gfxFontFeature", "FeatureTagValue", "i32", "u32") %>
<% impl_font_settings("font_variation_settings", "gfxFontVariation", "VariationValue", "f32", "f32") %>
pub fn fixup_none_generic(&mut self, device: &Device) {
self.gecko.mFont.systemFont = false;
@ -3210,28 +3200,16 @@ fn static_assert() {
where I: IntoIterator<Item = longhands::scroll_snap_coordinate::computed_value::single_value::T>,
I::IntoIter: ExactSizeIterator
{
let v = v.into_iter();
unsafe { self.gecko.mScrollSnapCoordinate.set_len_pod(v.len() as u32); }
for (gecko, servo) in self.gecko.mScrollSnapCoordinate
.iter_mut()
.zip(v) {
gecko.mXPosition = servo.horizontal.into();
gecko.mYPosition = servo.vertical.into();
}
let iter = v.into_iter().map(|c| structs::mozilla::Position {
mXPosition: c.horizontal.into(),
mYPosition: c.vertical.into(),
});
self.gecko.mScrollSnapCoordinate.assign_from_iter_pod(iter);
}
pub fn copy_scroll_snap_coordinate_from(&mut self, other: &Self) {
unsafe {
self.gecko.mScrollSnapCoordinate
.set_len_pod(other.gecko.mScrollSnapCoordinate.len() as u32);
}
for (this, that) in self.gecko.mScrollSnapCoordinate
.iter_mut()
.zip(other.gecko.mScrollSnapCoordinate.iter()) {
*this = *that;
}
let iter = other.gecko.mScrollSnapCoordinate.iter().map(|c| *c);
self.gecko.mScrollSnapCoordinate.assign_from_iter_pod(iter);
}
pub fn reset_scroll_snap_coordinate(&mut self, other: &Self) {
@ -4153,7 +4131,10 @@ fn static_assert() {
}
UrlOrNone::Url(ref url) => {
unsafe {
Gecko_SetListStyleImageImageValue(&mut self.gecko, url.0.image_value.get());
Gecko_SetListStyleImageImageValue(
&mut self.gecko,
url.url_value_ptr(),
);
}
}
}
@ -4989,12 +4970,12 @@ fn set_style_svg_path(
Gecko_NewStyleSVGPath(shape_source);
&mut shape_source.__bindgen_anon_1.mSVGPath.as_mut().mPtr.as_mut().unwrap()
};
unsafe { gecko_path.mPath.set_len(servo_path.commands().len() as u32) };
debug_assert_eq!(gecko_path.mPath.len(), servo_path.commands().len());
for (servo, gecko) in servo_path.commands().iter().zip(gecko_path.mPath.iter_mut()) {
let iter = servo_path.commands().iter().map(|command| {
// unsafe: cbindgen ensures the representation is the same.
*gecko = unsafe { transmute(*servo) };
}
unsafe { transmute(*command) }
});
gecko_path.mPath.assign_from_iter_pod(iter);
// Setup fill-rule.
// unsafe: cbindgen ensures the representation is the same.
@ -5358,7 +5339,7 @@ clip-path
unsafe {
Gecko_SetCursorImageValue(
&mut self.gecko.mCursorImages[i],
v.images[i].url.0.image_value.get(),
v.images[i].url.url_value_ptr(),
);
}
@ -5659,7 +5640,7 @@ clip-path
unsafe {
bindings::Gecko_SetContentDataImageValue(
&mut self.gecko.mContents[i],
url.0.image_value.get(),
url.url_value_ptr(),
)
}
}

View file

@ -9,7 +9,7 @@
from itertools import groupby
%>
#[cfg(feature = "gecko")] use gecko_bindings::bindings::RawServoAnimationValueMap;
#[cfg(feature = "gecko")] use gecko_bindings::structs::RawServoAnimationValueMap;
#[cfg(feature = "gecko")] use gecko_bindings::structs::RawGeckoGfxMatrix4x4;
#[cfg(feature = "gecko")] use gecko_bindings::structs::nsCSSPropertyID;
#[cfg(feature = "gecko")] use gecko_bindings::sugar::ownership::{HasFFI, HasSimpleFFI};
@ -35,7 +35,7 @@ use values::animated::effects::Filter as AnimatedFilter;
use values::computed::{Angle, CalcLengthOrPercentage};
use values::computed::{ClipRect, Context};
use values::computed::{Length, LengthOrPercentage, LengthOrPercentageOrAuto};
use values::computed::{LengthOrPercentageOrNone, MaxLength};
use values::computed::LengthOrPercentageOrNone;
use values::computed::{NonNegativeNumber, Number, NumberOrPercentage, Percentage};
use values::computed::length::NonNegativeLengthOrPercentage;
use values::computed::ToComputedValue;
@ -893,11 +893,6 @@ impl ToAnimatedZero for LengthOrPercentageOrNone {
}
}
impl ToAnimatedZero for MaxLength {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
}
impl ToAnimatedZero for FontWeight {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {

View file

@ -111,7 +111,7 @@ ${helpers.predefined_type(
vector=False,
animation_value_type="discrete",
flags="APPLIES_TO_FIRST_LETTER",
boxed=True,
boxed=product == "servo",
)}
${helpers.predefined_type(

View file

@ -23,7 +23,7 @@ ${helpers.predefined_type(
${helpers.single_keyword(
"text-transform",
"none capitalize uppercase lowercase",
extra_gecko_values="full-width",
extra_gecko_values="full-width full-size-kana",
animation_value_type="discrete",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
spec="https://drafts.csswg.org/css-text/#propdef-text-transform",

View file

@ -1671,28 +1671,17 @@ impl PropertyId {
///
/// Returns Err(()) for unknown non-custom properties.
fn parse_unchecked(property_name: &str) -> Result<Self, ()> {
// FIXME(https://github.com/rust-lang/rust/issues/33156): remove this
// enum and use PropertyId when stable Rust allows destructors in
// statics.
//
// ShorthandAlias is not used in the Servo build.
// That's why we need to allow dead_code.
#[allow(dead_code)]
pub enum StaticId {
Longhand(LonghandId),
Shorthand(ShorthandId),
LonghandAlias(LonghandId, AliasId),
ShorthandAlias(ShorthandId, AliasId),
}
ascii_case_insensitive_phf_map! {
static_id -> StaticId = {
property_id -> PropertyId = {
% for (kind, properties) in [("Longhand", data.longhands), ("Shorthand", data.shorthands)]:
% for property in properties:
"${property.name}" => StaticId::${kind}(${kind}Id::${property.camel_case}),
"${property.name}" => PropertyId::${kind}(${kind}Id::${property.camel_case}),
% for alias in property.alias:
"${alias.name}" => {
StaticId::${kind}Alias(${kind}Id::${property.camel_case},
AliasId::${alias.camel_case})
PropertyId::${kind}Alias(
${kind}Id::${property.camel_case},
AliasId::${alias.camel_case},
)
},
% endfor
% endfor
@ -1700,24 +1689,12 @@ impl PropertyId {
}
}
Ok(match static_id(property_name) {
Some(&StaticId::Longhand(id)) => {
PropertyId::Longhand(id)
},
Some(&StaticId::Shorthand(id)) => {
PropertyId::Shorthand(id)
},
Some(&StaticId::LonghandAlias(id, alias)) => {
PropertyId::LonghandAlias(id, alias)
},
Some(&StaticId::ShorthandAlias(id, alias)) => {
PropertyId::ShorthandAlias(id, alias)
},
None => {
if let Some(id) = property_id(property_name) {
return Ok(id.clone())
}
let name = ::custom_properties::parse_name(property_name)?;
PropertyId::Custom(::custom_properties::Name::from(name))
},
})
Ok(PropertyId::Custom(::custom_properties::Name::from(name)))
}
/// Parses a property name, and returns an error if it's unknown or isn't
@ -3137,7 +3114,8 @@ pub enum StyleStructRef<'a, T: 'static> {
}
impl<'a, T: 'a> StyleStructRef<'a, T>
where T: Clone,
where
T: Clone,
{
/// Ensure a mutable reference of this value exists, either cloning the
/// borrowed value, or returning the owned one.
@ -3153,6 +3131,22 @@ impl<'a, T: 'a> StyleStructRef<'a, T>
}
}
/// Whether this is pointer-equal to the struct we're going to copy the
/// value from.
///
/// This is used to avoid allocations when people write stuff like `font:
/// inherit` or such `all: initial`.
#[inline]
pub fn ptr_eq(&self, struct_to_copy_from: &T) -> bool {
match *self {
StyleStructRef::Owned(..) => false,
StyleStructRef::Borrowed(arc) => {
&**arc as *const T == struct_to_copy_from as *const T
}
StyleStructRef::Vacated => panic!("Accessed vacated style struct")
}
}
/// Extract a unique Arc from this struct, vacating it.
///
/// The vacated state is a transient one, please put the Arc back
@ -3281,15 +3275,6 @@ impl<'a> StyleBuilder<'a> {
let reset_style = device.default_computed_values();
let inherited_style = parent_style.unwrap_or(reset_style);
let inherited_style_ignoring_first_line = parent_style_ignoring_first_line.unwrap_or(reset_style);
// FIXME(bz): inherits_all seems like a fundamentally broken idea. I'm
// 99% sure it should give incorrect behavior for table anonymous box
// backgrounds, for example. This code doesn't attempt to make it play
// nice with inherited_style_ignoring_first_line.
let reset_style = if pseudo.map_or(false, |p| p.inherits_all()) {
inherited_style
} else {
reset_style
};
let flags = inherited_style.flags.inherited();
@ -3388,6 +3373,10 @@ impl<'a> StyleBuilder<'a> {
self.flags.insert(ComputedValueFlags::INHERITS_DISPLAY);
% endif
if self.${property.style_struct.ident}.ptr_eq(inherited_struct) {
return;
}
self.${property.style_struct.ident}.mutate()
.copy_${property.ident}_from(
inherited_struct,
@ -3407,10 +3396,10 @@ impl<'a> StyleBuilder<'a> {
self.modified_reset = true;
% endif
// TODO(emilio): There's a maybe-worth it optimization here: We should
// avoid allocating a new reset struct if `reset_struct` and our struct
// is the same pointer. Would remove a bunch of stupid allocations if
// you did something like `* { all: initial }` or what not.
if self.${property.style_struct.ident}.ptr_eq(reset_struct) {
return;
}
self.${property.style_struct.ident}.mutate()
.reset_${property.ident}(
reset_struct,

View file

@ -221,11 +221,6 @@ impl PseudoElement {
}
}
/// To be removed.
pub fn inherits_all(&self) -> bool {
false
}
/// Covert non-canonical pseudo-element to canonical one, and keep a
/// canonical one as it is.
pub fn canonical(&self) -> PseudoElement {

View file

@ -23,6 +23,9 @@ use values::computed::{Context, ToComputedValue};
///
/// However, this approach is still not necessarily optimal: See
/// <https://bugzilla.mozilla.org/show_bug.cgi?id=1347435#c6>
///
/// TODO(emilio): This should be shrunk by making CssUrl a wrapper type of an
/// arc, and keep the serialization in that Arc. See gecko/url.rs for example.
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize, SpecifiedValueInfo)]
pub struct CssUrl {
/// The original URI. This might be optional since we may insert computed

View file

@ -179,12 +179,7 @@ impl Parse for VectorValues {
#[cfg(feature = "gecko")]
impl ToGeckoFontFeatureValues for VectorValues {
fn to_gecko_font_feature_values(&self, array: &mut nsTArray<u32>) {
unsafe {
array.set_len_pod(self.0.len() as u32);
}
for (dest, value) in array.iter_mut().zip(self.0.iter()) {
*dest = *value;
}
array.assign_from_iter_pod(self.0.iter().map(|v| *v));
}
}

View file

@ -277,7 +277,6 @@ impl CssRule {
// nested rules are in the body state
let mut rule_parser = TopLevelRuleParser {
stylesheet_origin: parent_stylesheet_contents.origin,
context,
shared_lock: &shared_lock,
loader,

View file

@ -19,7 +19,7 @@ use servo_arc::Arc;
use shared_lock::{Locked, SharedRwLock};
use str::starts_with_ignore_ascii_case;
use style_traits::{ParseError, StyleParseErrorKind};
use stylesheets::{CssRule, CssRuleType, CssRules, Origin, RulesMutateError, StylesheetLoader};
use stylesheets::{CssRule, CssRuleType, CssRules, RulesMutateError, StylesheetLoader};
use stylesheets::{DocumentRule, FontFeatureValuesRule, KeyframesRule, MediaRule};
use stylesheets::{NamespaceRule, PageRule, StyleRule, SupportsRule, ViewportRule};
use stylesheets::document_rule::DocumentCondition;
@ -41,8 +41,6 @@ pub struct InsertRuleContext<'a> {
/// The parser for the top-level rules in a stylesheet.
pub struct TopLevelRuleParser<'a> {
/// The origin of the stylesheet we're parsing.
pub stylesheet_origin: Origin,
/// A reference to the lock we need to use to create rules.
pub shared_lock: &'a SharedRwLock,
/// A reference to a stylesheet loader if applicable, for `@import` rules.
@ -69,7 +67,6 @@ pub struct TopLevelRuleParser<'a> {
impl<'b> TopLevelRuleParser<'b> {
fn nested<'a: 'b>(&'a self) -> NestedRuleParser<'a, 'b> {
NestedRuleParser {
stylesheet_origin: self.stylesheet_origin,
shared_lock: self.shared_lock,
context: &self.context,
namespaces: &self.namespaces,
@ -325,7 +322,6 @@ impl<'a, 'i> QualifiedRuleParser<'i> for TopLevelRuleParser<'a> {
#[derive(Clone)] // shallow, relatively cheap .clone
struct NestedRuleParser<'a, 'b: 'a> {
stylesheet_origin: Origin,
shared_lock: &'a SharedRwLock,
context: &'a ParserContext<'b>,
namespaces: &'a Namespaces,
@ -340,7 +336,6 @@ impl<'a, 'b> NestedRuleParser<'a, 'b> {
let context = ParserContext::new_with_rule_type(self.context, rule_type, self.namespaces);
let nested_parser = NestedRuleParser {
stylesheet_origin: self.stylesheet_origin,
shared_lock: self.shared_lock,
context: &context,
namespaces: self.namespaces,
@ -501,7 +496,7 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b> {
self.namespaces,
);
let enabled = condition.eval(&eval_context);
let enabled = condition.eval(&eval_context, self.namespaces);
Ok(CssRule::Supports(Arc::new(self.shared_lock.wrap(
SupportsRule {
condition,
@ -577,7 +572,7 @@ impl<'a, 'b, 'i> QualifiedRuleParser<'i> for NestedRuleParser<'a, 'b> {
input: &mut Parser<'i, 't>,
) -> Result<Self::Prelude, ParseError<'i>> {
let selector_parser = SelectorParser {
stylesheet_origin: self.stylesheet_origin,
stylesheet_origin: self.context.stylesheet_origin,
namespaces: self.namespaces,
url_data: Some(self.context.url_data),
};

View file

@ -374,7 +374,6 @@ impl Stylesheet {
);
let rule_parser = TopLevelRuleParser {
stylesheet_origin: origin,
shared_lock,
loader: stylesheet_loader,
context,

View file

@ -11,7 +11,8 @@ use cssparser::parse_important;
use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf};
use parser::ParserContext;
use properties::{PropertyDeclaration, PropertyId, SourcePropertyDeclaration};
use selectors::parser::SelectorParseErrorKind;
use selector_parser::{SelectorImpl, SelectorParser};
use selectors::parser::{Selector, SelectorParseErrorKind};
use servo_arc::Arc;
use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked};
use shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
@ -19,8 +20,8 @@ use std::ffi::{CStr, CString};
use std::fmt::{self, Write};
use std::str;
use str::CssStringWriter;
use style_traits::{CssWriter, ParseError, ToCss};
use stylesheets::{CssRuleType, CssRules};
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
use stylesheets::{CssRuleType, CssRules, Namespaces};
/// An [`@supports`][supports] rule.
///
@ -87,6 +88,8 @@ pub enum SupportsCondition {
Or(Vec<SupportsCondition>),
/// `property-ident: value` (value can be any tokens)
Declaration(Declaration),
/// A `selector()` function.
Selector(RawSelector),
/// `-moz-bool-pref("pref-name")`
/// Since we need to pass it through FFI to get the pref value,
/// we store it as CString directly.
@ -99,8 +102,8 @@ impl SupportsCondition {
/// Parse a condition
///
/// <https://drafts.csswg.org/css-conditional/#supports_condition>
pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<SupportsCondition, ParseError<'i>> {
if let Ok(_) = input.try(|i| i.expect_ident_matching("not")) {
pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
if input.try(|i| i.expect_ident_matching("not")).is_ok() {
let inner = SupportsCondition::parse_in_parens(input)?;
return Ok(SupportsCondition::Not(Box::new(inner)));
}
@ -109,10 +112,8 @@ impl SupportsCondition {
let location = input.current_source_location();
let (keyword, wrapper) = match input.next() {
Err(_) => {
// End of input
return Ok(in_parens);
},
Err(..) => return Ok(in_parens),
Ok(&Token::Ident(ref ident)) => {
match_ignore_ascii_case! { &ident,
"and" => ("and", SupportsCondition::And as fn(_) -> _),
@ -132,17 +133,48 @@ impl SupportsCondition {
.is_err()
{
// Did not find the expected keyword.
// If we found some other token,
// it will be rejected by `Parser::parse_entirely` somewhere up the stack.
// If we found some other token, it will be rejected by
// `Parser::parse_entirely` somewhere up the stack.
return Ok(wrapper(conditions));
}
}
}
/// Parses a functional supports condition.
fn parse_functional<'i, 't>(
function: &str,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
match_ignore_ascii_case!{ function,
// Although this is an internal syntax, it is not necessary
// to check parsing context as far as we accept any
// unexpected token as future syntax, and evaluate it to
// false when not in chrome / ua sheet.
// See https://drafts.csswg.org/css-conditional-3/#general_enclosed
"-moz-bool-pref" => {
let name = {
let name = input.expect_string()?;
CString::new(name.as_bytes())
}.map_err(|_| input.new_custom_error(StyleParseErrorKind::UnspecifiedError))?;
Ok(SupportsCondition::MozBoolPref(name))
}
"selector" => {
let pos = input.position();
consume_any_value(input)?;
Ok(SupportsCondition::Selector(RawSelector(
input.slice_from(pos).to_owned()
)))
}
_ => {
Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
}
}
}
/// <https://drafts.csswg.org/css-conditional-3/#supports_condition_in_parens>
fn parse_in_parens<'i, 't>(
input: &mut Parser<'i, 't>,
) -> Result<SupportsCondition, ParseError<'i>> {
) -> Result<Self, ParseError<'i>> {
// Whitespace is normally taken care of in `Parser::next`,
// but we want to not include it in `pos` for the SupportsCondition::FutureSyntax cases.
while input.try(Parser::expect_whitespace).is_ok() {}
@ -151,46 +183,45 @@ impl SupportsCondition {
// FIXME: remove clone() when lifetimes are non-lexical
match input.next()?.clone() {
Token::ParenthesisBlock => {
let nested = input
.try(|input| input.parse_nested_block(|i| parse_condition_or_declaration(i)));
let nested = input.try(|input| {
input.parse_nested_block(parse_condition_or_declaration)
});
if nested.is_ok() {
return nested;
}
},
Token::Function(ident) => {
// Although this is an internal syntax, it is not necessary to check
// parsing context as far as we accept any unexpected token as future
// syntax, and evaluate it to false when not in chrome / ua sheet.
// See https://drafts.csswg.org/css-conditional-3/#general_enclosed
if ident.eq_ignore_ascii_case("-moz-bool-pref") {
if let Ok(name) = input.try(|i| {
i.parse_nested_block(|i| {
i.expect_string()
.map(|s| s.to_string())
.map_err(CssParseError::<()>::from)
}).and_then(|s| CString::new(s).map_err(|_| location.new_custom_error(())))
}) {
return Ok(SupportsCondition::MozBoolPref(name));
}
let nested = input.try(|input| {
input.parse_nested_block(|input| {
SupportsCondition::parse_functional(&ident, input)
})
});
if nested.is_ok() {
return nested;
}
},
t => return Err(location.new_unexpected_token_error(t)),
}
input.parse_nested_block(|i| consume_any_value(i))?;
input.parse_nested_block(consume_any_value)?;
Ok(SupportsCondition::FutureSyntax(
input.slice_from(pos).to_owned(),
))
}
/// Evaluate a supports condition
pub fn eval(&self, cx: &ParserContext) -> bool {
pub fn eval(
&self,
cx: &ParserContext,
namespaces: &Namespaces,
) -> bool {
match *self {
SupportsCondition::Not(ref cond) => !cond.eval(cx),
SupportsCondition::Parenthesized(ref cond) => cond.eval(cx),
SupportsCondition::And(ref vec) => vec.iter().all(|c| c.eval(cx)),
SupportsCondition::Or(ref vec) => vec.iter().any(|c| c.eval(cx)),
SupportsCondition::Not(ref cond) => !cond.eval(cx, namespaces),
SupportsCondition::Parenthesized(ref cond) => cond.eval(cx, namespaces),
SupportsCondition::And(ref vec) => vec.iter().all(|c| c.eval(cx, namespaces)),
SupportsCondition::Or(ref vec) => vec.iter().any(|c| c.eval(cx, namespaces)),
SupportsCondition::Declaration(ref decl) => decl.eval(cx),
SupportsCondition::MozBoolPref(ref name) => eval_moz_bool_pref(name, cx),
SupportsCondition::Selector(ref selector) => selector.eval(cx, namespaces),
SupportsCondition::FutureSyntax(_) => false,
}
}
@ -265,6 +296,11 @@ impl ToCss for SupportsCondition {
decl.to_css(dest)?;
dest.write_str(")")
},
SupportsCondition::Selector(ref selector) => {
dest.write_str("selector(")?;
selector.to_css(dest)?;
dest.write_str(")")
}
SupportsCondition::MozBoolPref(ref name) => {
dest.write_str("-moz-bool-pref(")?;
let name =
@ -277,6 +313,69 @@ impl ToCss for SupportsCondition {
}
}
#[derive(Clone, Debug)]
/// A possibly-invalid CSS selector.
pub struct RawSelector(pub String);
impl ToCss for RawSelector {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
dest.write_str(&self.0)
}
}
impl RawSelector {
/// Tries to evaluate a `selector()` function.
pub fn eval(
&self,
context: &ParserContext,
namespaces: &Namespaces,
) -> bool {
#[cfg(feature = "gecko")]
{
if unsafe { !::gecko_bindings::structs::StaticPrefs_sVarCache_layout_css_supports_selector_enabled } {
return false;
}
}
let mut input = ParserInput::new(&self.0);
let mut input = Parser::new(&mut input);
input.parse_entirely(|input| -> Result<(), CssParseError<()>> {
let parser = SelectorParser {
namespaces,
stylesheet_origin: context.stylesheet_origin,
url_data: Some(context.url_data),
};
#[allow(unused_variables)]
let selector = Selector::<SelectorImpl>::parse(&parser, input)
.map_err(|_| input.new_custom_error(()))?;
#[cfg(feature = "gecko")]
{
use selector_parser::PseudoElement;
use selectors::parser::Component;
let has_any_unknown_webkit_pseudo =
selector.has_pseudo_element() &&
selector.iter_raw_match_order().any(|component| {
matches!(
*component,
Component::PseudoElement(PseudoElement::UnknownWebkit(..))
)
});
if has_any_unknown_webkit_pseudo {
return Err(input.new_custom_error(()));
}
}
Ok(())
}).is_ok()
}
}
#[derive(Clone, Debug)]
/// A possibly-invalid property declaration
pub struct Declaration(pub String);
@ -313,8 +412,7 @@ impl Declaration {
let mut input = ParserInput::new(&self.0);
let mut input = Parser::new(&mut input);
input
.parse_entirely(|input| -> Result<(), CssParseError<()>> {
input.parse_entirely(|input| -> Result<(), CssParseError<()>> {
let prop = input.expect_ident_cloned().unwrap();
input.expect_colon().unwrap();

View file

@ -614,14 +614,6 @@ impl Stylist {
/// Computes the style for a given "precomputed" pseudo-element, taking the
/// universal rules and applying them.
///
/// If `inherit_all` is true, then all properties are inherited from the
/// parent; otherwise, non-inherited properties are reset to their initial
/// values. The flow constructor uses this flag when constructing anonymous
/// flows.
///
/// TODO(emilio): The type parameter could go away with a void type
/// implementing TElement.
pub fn precomputed_values_for_pseudo<E>(
&self,
guards: &StylesheetGuards,
@ -2423,6 +2415,9 @@ impl CascadeData {
if let Some(ref mut slotted_rules) = self.slotted_rules {
slotted_rules.clear();
}
if let Some(ref mut host_rules) = self.host_rules {
host_rules.clear();
}
self.animations.clear();
self.extra_data.clear();
self.rules_source_order = 0;
@ -2448,6 +2443,9 @@ impl CascadeData {
if let Some(ref slotted_rules) = self.slotted_rules {
slotted_rules.add_size_of(ops, sizes);
}
if let Some(ref host_rules) = self.host_rules {
host_rules.add_size_of(ops, sizes);
}
sizes.mInvalidationMap += self.invalidation_map.size_of(ops);
sizes.mRevalidationSelectors += self.selectors_for_cache_revalidation.size_of(ops);
sizes.mOther += self.animations.size_of(ops);

View file

@ -292,8 +292,9 @@ impl ToAnimatedValue for ComputedMaxLength {
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
use values::computed::{Length, LengthOrPercentageOrNone, Percentage};
use values::generics::length::MaxLength as GenericMaxLength;
match animated {
ComputedMaxLength::LengthOrPercentageOrNone(lopn) => {
GenericMaxLength::LengthOrPercentageOrNone(lopn) => {
let result = match lopn {
LengthOrPercentageOrNone::Length(px) => {
LengthOrPercentageOrNone::Length(Length::new(px.px().max(0.)))
@ -303,7 +304,7 @@ impl ToAnimatedValue for ComputedMaxLength {
},
_ => lopn,
};
ComputedMaxLength::LengthOrPercentageOrNone(result)
GenericMaxLength::LengthOrPercentageOrNone(result)
},
_ => animated,
}
@ -321,8 +322,9 @@ impl ToAnimatedValue for ComputedMozLength {
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
use values::computed::{Length, LengthOrPercentageOrAuto, Percentage};
use values::generics::length::MozLength as GenericMozLength;
match animated {
ComputedMozLength::LengthOrPercentageOrAuto(lopa) => {
GenericMozLength::LengthOrPercentageOrAuto(lopa) => {
let result = match lopa {
LengthOrPercentageOrAuto::Length(px) => {
LengthOrPercentageOrAuto::Length(Length::new(px.px().max(0.)))
@ -332,7 +334,7 @@ impl ToAnimatedValue for ComputedMozLength {
},
_ => lopa,
};
ComputedMozLength::LengthOrPercentageOrAuto(result)
GenericMozLength::LengthOrPercentageOrAuto(result)
},
_ => animated,
}

View file

@ -7,36 +7,39 @@
use num_traits::Zero;
use std::{f32, f64};
use std::f64::consts::PI;
use std::fmt::{self, Write};
use std::ops::Add;
use style_traits::{CssWriter, ToCss};
use values::CSSFloat;
use values::animated::{Animate, Procedure};
use values::distance::{ComputeSquaredDistance, SquaredDistance};
/// A computed angle.
#[animate(fallback = "Self::animate_fallback")]
/// A computed angle in degrees.
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(
Animate, Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, ToAnimatedZero, ToCss,
)]
pub enum Angle {
/// An angle with degree unit.
#[css(dimension)]
Deg(CSSFloat),
/// An angle with gradian unit.
#[css(dimension)]
Grad(CSSFloat),
/// An angle with radian unit.
#[css(dimension)]
Rad(CSSFloat),
/// An angle with turn unit.
#[css(dimension)]
Turn(CSSFloat),
#[derive(Animate, Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, ToAnimatedZero)]
pub struct Angle(CSSFloat);
impl ToCss for Angle {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
self.degrees().to_css(dest)?;
dest.write_str("deg")
}
}
const RAD_PER_DEG: f64 = PI / 180.0;
impl Angle {
/// Creates a computed `Angle` value from a radian amount.
pub fn from_radians(radians: CSSFloat) -> Self {
Angle::Rad(radians)
Angle(radians / RAD_PER_DEG as f32)
}
/// Creates a computed `Angle` value from a degrees amount.
#[inline]
pub fn from_degrees(degrees: CSSFloat) -> Self {
Angle(degrees)
}
/// Returns the amount of radians this angle represents.
@ -48,43 +51,18 @@ impl Angle {
/// Returns the amount of radians this angle represents as a `f64`.
///
/// Gecko stores angles as singles, but does this computation using doubles.
/// See nsCSSValue::GetAngleValueInRadians.
///
/// This is significant enough to mess up rounding to the nearest
/// quarter-turn for 225 degrees, for example.
#[inline]
pub fn radians64(&self) -> f64 {
const RAD_PER_DEG: f64 = PI / 180.0;
const RAD_PER_GRAD: f64 = PI / 200.0;
const RAD_PER_TURN: f64 = PI * 2.0;
let radians = match *self {
Angle::Deg(val) => val as f64 * RAD_PER_DEG,
Angle::Grad(val) => val as f64 * RAD_PER_GRAD,
Angle::Turn(val) => val as f64 * RAD_PER_TURN,
Angle::Rad(val) => val as f64,
};
radians.min(f64::MAX).max(f64::MIN)
self.0 as f64 * RAD_PER_DEG
}
/// Return the value in degrees.
pub fn degrees(&self) -> f32 {
use std::f32::consts::PI;
self.radians() * 360. / (2. * PI)
}
/// <https://drafts.csswg.org/css-transitions/#animtype-number>
#[inline]
fn animate_fallback(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
Ok(Angle::from_radians(
self.radians().animate(&other.radians(), procedure)?,
))
}
}
impl AsRef<Angle> for Angle {
#[inline]
fn as_ref(&self) -> &Self {
self
pub fn degrees(&self) -> CSSFloat {
self.0
}
}
@ -93,27 +71,19 @@ impl Add for Angle {
#[inline]
fn add(self, rhs: Self) -> Self {
match (self, rhs) {
(Angle::Deg(x), Angle::Deg(y)) => Angle::Deg(x + y),
(Angle::Grad(x), Angle::Grad(y)) => Angle::Grad(x + y),
(Angle::Turn(x), Angle::Turn(y)) => Angle::Turn(x + y),
(Angle::Rad(x), Angle::Rad(y)) => Angle::Rad(x + y),
_ => Angle::from_radians(self.radians() + rhs.radians()),
}
Angle(self.0 + rhs.0)
}
}
impl Zero for Angle {
#[inline]
fn zero() -> Self {
Angle::from_radians(0.0)
Angle(0.0)
}
#[inline]
fn is_zero(&self) -> bool {
match *self {
Angle::Deg(val) | Angle::Grad(val) | Angle::Turn(val) | Angle::Rad(val) => val == 0.,
}
self.0 == 0.
}
}
@ -122,7 +92,6 @@ impl ComputeSquaredDistance for Angle {
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
// Use the formula for calculating the distance between angles defined in SVG:
// https://www.w3.org/TR/SVG/animate.html#complexDistances
self.radians64()
.compute_squared_distance(&other.radians64())
self.radians64().compute_squared_distance(&other.radians64())
}
}

View file

@ -866,7 +866,7 @@ impl ToAnimatedValue for FontStyleAngle {
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
FontStyleAngle(Angle::Deg(
FontStyleAngle(Angle::from_degrees(
animated
.degrees()
.min(specified::FONT_STYLE_OBLIQUE_MAX_ANGLE_DEGREES)
@ -899,7 +899,7 @@ impl FontStyle {
/// https://drafts.csswg.org/css-fonts-4/#valdef-font-style-oblique-angle
#[inline]
pub fn default_angle() -> FontStyleAngle {
FontStyleAngle(Angle::Deg(
FontStyleAngle(Angle::from_degrees(
specified::DEFAULT_FONT_STYLE_OBLIQUE_ANGLE_DEGREES,
))
}
@ -919,7 +919,7 @@ impl FontStyle {
if italic {
return generics::FontStyle::Italic;
}
generics::FontStyle::Oblique(FontStyleAngle(Angle::Deg(angle)))
generics::FontStyle::Oblique(FontStyleAngle(Angle::from_degrees(angle)))
}
}

View file

@ -5,9 +5,7 @@
//! `<length>` computed values, and related ones.
use app_units::Au;
use logical_geometry::WritingMode;
use ordered_float::NotNan;
use properties::LonghandId;
use std::fmt::{self, Write};
use std::ops::{Add, Neg};
use style_traits::{CssWriter, ToCss};
@ -17,6 +15,7 @@ use values::{specified, Auto, CSSFloat, Either, Normal};
use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
use values::distance::{ComputeSquaredDistance, SquaredDistance};
use values::generics::NonNegative;
use values::generics::length::{MaxLength as GenericMaxLength, MozLength as GenericMozLength};
use values::specified::length::{AbsoluteLength, FontBaseSize, FontRelativeLength};
use values::specified::length::ViewportPercentageLength;
@ -951,7 +950,8 @@ pub type NonNegativeLengthOrPercentageOrNormal = Either<NonNegativeLengthOrPerce
/// block-size, and inline-size.
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss)]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub enum ExtremumLength {
MozMaxContent,
MozMinContent,
@ -959,161 +959,24 @@ pub enum ExtremumLength {
MozAvailable,
}
impl ExtremumLength {
/// Returns whether this size keyword can be used for the given writing-mode
/// and property.
///
/// TODO: After these values are supported for both axes (and maybe
/// unprefixed, see bug 1322780) all this complexity can go away, and
/// everything can be derived (no need for uncacheable stuff).
fn valid_for(wm: WritingMode, longhand: LonghandId) -> bool {
// We only make sense on the inline axis.
match longhand {
// FIXME(emilio): The flex-basis thing is not quite clear...
LonghandId::FlexBasis |
LonghandId::MinWidth |
LonghandId::MaxWidth |
LonghandId::Width => !wm.is_vertical(),
LonghandId::MinHeight | LonghandId::MaxHeight | LonghandId::Height => wm.is_vertical(),
LonghandId::MinInlineSize | LonghandId::MaxInlineSize | LonghandId::InlineSize => true,
// The block-* properties are rejected at parse-time, so they're
// unexpected here.
_ => {
debug_assert!(
false,
"Unexpected property using ExtremumLength: {:?}",
longhand,
);
false
},
}
}
}
/// A value suitable for a `min-width`, `min-height`, `width` or `height`
/// property.
///
/// See values/specified/length.rs for more details.
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToAnimatedZero, ToCss)]
pub enum MozLength {
LengthOrPercentageOrAuto(LengthOrPercentageOrAuto),
#[animation(error)]
ExtremumLength(ExtremumLength),
}
/// A computed value for `min-width`, `min-height`, `width` or `height` property.
pub type MozLength = GenericMozLength<LengthOrPercentageOrAuto>;
impl MozLength {
/// Returns the `auto` value.
#[inline]
pub fn auto() -> Self {
MozLength::LengthOrPercentageOrAuto(LengthOrPercentageOrAuto::Auto)
GenericMozLength::LengthOrPercentageOrAuto(LengthOrPercentageOrAuto::Auto)
}
}
impl ToComputedValue for specified::MozLength {
type ComputedValue = MozLength;
#[inline]
fn to_computed_value(&self, context: &Context) -> MozLength {
debug_assert!(
context.for_non_inherited_property.is_some(),
"Someone added a MozLength to an inherited property? Evil!"
);
match *self {
specified::MozLength::LengthOrPercentageOrAuto(ref lopoa) => {
MozLength::LengthOrPercentageOrAuto(lopoa.to_computed_value(context))
},
specified::MozLength::ExtremumLength(ext) => {
context
.rule_cache_conditions
.borrow_mut()
.set_writing_mode_dependency(context.builder.writing_mode);
if !ExtremumLength::valid_for(
context.builder.writing_mode,
context.for_non_inherited_property.unwrap(),
) {
MozLength::auto()
} else {
MozLength::ExtremumLength(ext)
}
},
}
}
#[inline]
fn from_computed_value(computed: &MozLength) -> Self {
match *computed {
MozLength::LengthOrPercentageOrAuto(ref lopoa) => {
specified::MozLength::LengthOrPercentageOrAuto(
specified::LengthOrPercentageOrAuto::from_computed_value(lopoa),
)
},
MozLength::ExtremumLength(ext) => specified::MozLength::ExtremumLength(ext),
}
}
}
/// A value suitable for a `max-width` or `max-height` property.
/// See values/specified/length.rs for more details.
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToCss)]
pub enum MaxLength {
LengthOrPercentageOrNone(LengthOrPercentageOrNone),
#[animation(error)]
ExtremumLength(ExtremumLength),
}
/// A computed value for `max-width` or `min-height` property.
pub type MaxLength = GenericMaxLength<LengthOrPercentageOrNone>;
impl MaxLength {
/// Returns the `none` value.
#[inline]
pub fn none() -> Self {
MaxLength::LengthOrPercentageOrNone(LengthOrPercentageOrNone::None)
}
}
impl ToComputedValue for specified::MaxLength {
type ComputedValue = MaxLength;
#[inline]
fn to_computed_value(&self, context: &Context) -> MaxLength {
debug_assert!(
context.for_non_inherited_property.is_some(),
"Someone added a MaxLength to an inherited property? Evil!"
);
match *self {
specified::MaxLength::LengthOrPercentageOrNone(ref lopon) => {
MaxLength::LengthOrPercentageOrNone(lopon.to_computed_value(context))
},
specified::MaxLength::ExtremumLength(ext) => {
context
.rule_cache_conditions
.borrow_mut()
.set_writing_mode_dependency(context.builder.writing_mode);
if !ExtremumLength::valid_for(
context.builder.writing_mode,
context.for_non_inherited_property.unwrap(),
) {
MaxLength::none()
} else {
MaxLength::ExtremumLength(ext)
}
},
}
}
#[inline]
fn from_computed_value(computed: &MaxLength) -> Self {
match *computed {
MaxLength::LengthOrPercentageOrNone(ref lopon) => {
specified::MaxLength::LengthOrPercentageOrNone(
specified::LengthOrPercentageOrNone::from_computed_value(&lopon),
)
},
MaxLength::ExtremumLength(ref ext) => specified::MaxLength::ExtremumLength(ext.clone()),
}
GenericMaxLength::LengthOrPercentageOrNone(LengthOrPercentageOrNone::None)
}
}

View file

@ -0,0 +1,54 @@
/* 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/. */
//! Generic types for CSS values related to length.
use values::computed::ExtremumLength;
/// A generic value for the `width`, `height`, `min-width`, or `min-height` property.
///
/// Unlike `max-width` or `max-height` properties, a MozLength can be `auto`,
/// and cannot be `none`.
///
/// Note that it only accepts non-negative values.
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
#[derive(
Animate,
Clone,
ComputeSquaredDistance,
Copy,
Debug,
PartialEq,
SpecifiedValueInfo,
ToAnimatedZero,
ToComputedValue,
ToCss,
)]
pub enum MozLength<LengthOrPercentageOrAuto> {
LengthOrPercentageOrAuto(LengthOrPercentageOrAuto),
#[animation(error)]
ExtremumLength(ExtremumLength),
}
/// A generic value for the `max-width` or `max-height` property.
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
#[derive(
Animate,
Clone,
ComputeSquaredDistance,
Copy,
Debug,
PartialEq,
SpecifiedValueInfo,
ToAnimatedZero,
ToComputedValue,
ToCss
)]
pub enum MaxLength<LengthOrPercentageOrNone> {
LengthOrPercentageOrNone(LengthOrPercentageOrNone),
#[animation(error)]
ExtremumLength(ExtremumLength),
}

View file

@ -27,6 +27,7 @@ pub mod font;
pub mod gecko;
pub mod grid;
pub mod image;
pub mod length;
pub mod position;
pub mod rect;
pub mod size;

View file

@ -10,6 +10,7 @@ use num_traits::Zero;
use values::{computed, CSSFloat};
use values::computed::length::Length as ComputedLength;
use values::computed::length::LengthOrPercentage as ComputedLengthOrPercentage;
use values::specified::angle::Angle as SpecifiedAngle;
use values::specified::length::Length as SpecifiedLength;
use values::specified::length::LengthOrPercentage as SpecifiedLengthOrPercentage;
@ -394,10 +395,30 @@ pub trait ToMatrix {
fn to_3d_matrix(&self, reference_box: Option<&Rect<Au>>) -> Result<Transform3D<f64>, ()>;
}
/// A little helper to deal with both specified and computed angles.
pub trait ToRadians {
/// Return the radians value as a 64-bit floating point value.
fn radians64(&self) -> f64;
}
impl ToRadians for computed::angle::Angle {
#[inline]
fn radians64(&self) -> f64 {
computed::angle::Angle::radians64(self)
}
}
impl ToRadians for SpecifiedAngle {
#[inline]
fn radians64(&self) -> f64 {
computed::angle::Angle::from_degrees(self.degrees()).radians64()
}
}
impl<Angle, Number, Length, Integer, LoP> ToMatrix
for TransformOperation<Angle, Number, Length, Integer, LoP>
where
Angle: Copy + AsRef<computed::angle::Angle>,
Angle: ToRadians + Copy,
Number: Copy + Into<f32> + Into<f64>,
Length: ToAbsoluteLength,
LoP: ToAbsoluteLength,
@ -426,7 +447,7 @@ where
let reference_height = reference_box.map(|v| v.size.height);
let matrix = match *self {
Rotate3D(ax, ay, az, theta) => {
let theta = TWO_PI - theta.as_ref().radians64();
let theta = TWO_PI - theta.radians64();
let (ax, ay, az, theta) =
get_normalized_vector_and_angle(ax.into(), ay.into(), az.into(), theta);
Transform3D::create_rotation(
@ -437,15 +458,15 @@ where
)
},
RotateX(theta) => {
let theta = euclid::Angle::radians(TWO_PI - theta.as_ref().radians64());
let theta = euclid::Angle::radians(TWO_PI - theta.radians64());
Transform3D::create_rotation(1., 0., 0., theta)
},
RotateY(theta) => {
let theta = euclid::Angle::radians(TWO_PI - theta.as_ref().radians64());
let theta = euclid::Angle::radians(TWO_PI - theta.radians64());
Transform3D::create_rotation(0., 1., 0., theta)
},
RotateZ(theta) | Rotate(theta) => {
let theta = euclid::Angle::radians(TWO_PI - theta.as_ref().radians64());
let theta = euclid::Angle::radians(TWO_PI - theta.radians64());
Transform3D::create_rotation(0., 0., 1., theta)
},
Perspective(ref d) => {
@ -479,16 +500,16 @@ where
Transform3D::create_translation(0., 0., z.to_pixel_length(None)? as f64)
},
Skew(theta_x, theta_y) => Transform3D::create_skew(
euclid::Angle::radians(theta_x.as_ref().radians64()),
euclid::Angle::radians(theta_y.map_or(0., |a| a.as_ref().radians64())),
euclid::Angle::radians(theta_x.radians64()),
euclid::Angle::radians(theta_y.map_or(0., |a| a.radians64())),
),
SkewX(theta) => Transform3D::create_skew(
euclid::Angle::radians(theta.as_ref().radians64()),
euclid::Angle::radians(theta.radians64()),
euclid::Angle::radians(0.),
),
SkewY(theta) => Transform3D::create_skew(
euclid::Angle::radians(0.),
euclid::Angle::radians(theta.as_ref().radians64()),
euclid::Angle::radians(theta.radians64()),
),
Matrix3D(m) => m.into(),
Matrix(m) => m.into(),

View file

@ -6,6 +6,7 @@
use cssparser::{Parser, Token};
use parser::{Parse, ParserContext};
use std::f32::consts::PI;
use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, ToCss};
use values::CSSFloat;
@ -13,15 +14,47 @@ use values::computed::{Context, ToComputedValue};
use values::computed::angle::Angle as ComputedAngle;
use values::specified::calc::CalcNode;
/// A specified angle.
///
/// Computed angles are essentially same as specified ones except for `calc()`
/// value serialization. Therefore we are storing a computed angle inside
/// to hold the actual value and its unit.
/// A specified angle dimension.
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, ToCss)]
pub enum AngleDimension {
/// An angle with degree unit.
#[css(dimension)]
Deg(CSSFloat),
/// An angle with gradian unit.
#[css(dimension)]
Grad(CSSFloat),
/// An angle with radian unit.
#[css(dimension)]
Rad(CSSFloat),
/// An angle with turn unit.
#[css(dimension)]
Turn(CSSFloat),
}
impl AngleDimension {
/// Returns the amount of degrees this angle represents.
#[inline]
fn degrees(&self) -> CSSFloat {
const DEG_PER_RAD: f32 = 180.0 / PI;
const DEG_PER_TURN: f32 = 360.0;
const DEG_PER_GRAD: f32 = 180.0 / 200.0;
match *self {
AngleDimension::Deg(d) => d,
AngleDimension::Rad(rad) => rad * DEG_PER_RAD,
AngleDimension::Turn(turns) => turns * DEG_PER_TURN,
AngleDimension::Grad(gradians) => gradians * DEG_PER_GRAD,
}
}
}
/// A specified Angle value, which is just the angle dimension, plus whether it
/// was specified as `calc()` or not.
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq)]
pub struct Angle {
value: ComputedAngle,
value: AngleDimension,
was_calc: bool,
}
@ -41,22 +74,18 @@ impl ToCss for Angle {
}
}
// FIXME(emilio): Probably computed angles shouldn't preserve the unit and
// should serialize to degrees per:
//
// https://drafts.csswg.org/css-values/#compat
impl ToComputedValue for Angle {
type ComputedValue = ComputedAngle;
#[inline]
fn to_computed_value(&self, _context: &Context) -> Self::ComputedValue {
self.value
ComputedAngle::from_degrees(self.degrees())
}
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
Angle {
value: *computed,
value: AngleDimension::Deg(computed.degrees()),
was_calc: false,
}
}
@ -64,35 +93,18 @@ impl ToComputedValue for Angle {
impl Angle {
/// Creates an angle with the given value in degrees.
#[inline]
pub fn from_degrees(value: CSSFloat, was_calc: bool) -> Self {
Angle {
value: ComputedAngle::Deg(value),
value: AngleDimension::Deg(value),
was_calc,
}
}
/// Creates an angle with the given value in gradians.
pub fn from_gradians(value: CSSFloat, was_calc: bool) -> Self {
Angle {
value: ComputedAngle::Grad(value),
was_calc,
}
}
/// Creates an angle with the given value in turns.
pub fn from_turns(value: CSSFloat, was_calc: bool) -> Self {
Angle {
value: ComputedAngle::Turn(value),
was_calc,
}
}
/// Creates an angle with the given value in radians.
pub fn from_radians(value: CSSFloat, was_calc: bool) -> Self {
Angle {
value: ComputedAngle::Rad(value),
was_calc,
}
/// Returns the value of the angle in degrees, mostly for `calc()`.
#[inline]
pub fn degrees(&self) -> CSSFloat {
self.value.degrees()
}
/// Whether this specified angle came from a `calc()` expression.
@ -101,39 +113,21 @@ impl Angle {
self.was_calc
}
/// Returns the amount of radians this angle represents.
#[inline]
pub fn radians(self) -> f32 {
self.value.radians()
}
/// Returns the amount of degrees this angle represents.
#[inline]
pub fn degrees(self) -> f32 {
self.value.degrees()
}
/// Returns `0deg`.
#[inline]
pub fn zero() -> Self {
Self::from_degrees(0.0, false)
}
/// Returns an `Angle` parsed from a `calc()` expression.
pub fn from_calc(radians: CSSFloat) -> Self {
pub fn from_calc(degrees: CSSFloat) -> Self {
Angle {
value: ComputedAngle::Rad(radians),
value: AngleDimension::Deg(degrees),
was_calc: true,
}
}
}
impl AsRef<ComputedAngle> for Angle {
#[inline]
fn as_ref(&self) -> &ComputedAngle {
&self.value
}
}
/// Whether to allow parsing an unitless zero as a valid angle.
///
/// This should always be `No`, except for exceptions like:
@ -158,20 +152,26 @@ impl Parse for Angle {
impl Angle {
/// Parse an `<angle>` value given a value and an unit.
pub fn parse_dimension(value: CSSFloat, unit: &str, from_calc: bool) -> Result<Angle, ()> {
let angle = match_ignore_ascii_case! { unit,
"deg" => Angle::from_degrees(value, from_calc),
"grad" => Angle::from_gradians(value, from_calc),
"turn" => Angle::from_turns(value, from_calc),
"rad" => Angle::from_radians(value, from_calc),
pub fn parse_dimension(
value: CSSFloat,
unit: &str,
was_calc: bool,
) -> Result<Angle, ()> {
let value = match_ignore_ascii_case! { unit,
"deg" => AngleDimension::Deg(value),
"grad" => AngleDimension::Grad(value),
"turn" => AngleDimension::Turn(value),
"rad" => AngleDimension::Rad(value),
_ => return Err(())
};
Ok(angle)
Ok(Self { value, was_calc })
}
/// Parse an `<angle>` allowing unitless zero to represent a zero angle.
///
/// See the comment in `AllowUnitlessZeroAngle` for why.
#[inline]
pub fn parse_with_unitless<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,

View file

@ -966,20 +966,27 @@ pub enum Appearance {
/// A typical dialog button.
Button,
/// Various arrows that go in buttons
#[parse(condition = "in_ua_or_chrome_sheet")]
ButtonArrowDown,
#[parse(condition = "in_ua_or_chrome_sheet")]
ButtonArrowNext,
#[parse(condition = "in_ua_or_chrome_sheet")]
ButtonArrowPrevious,
#[parse(condition = "in_ua_or_chrome_sheet")]
ButtonArrowUp,
/// A rectangular button that contains complex content
/// like images (e.g. HTML <button> elements)
ButtonBevel,
/// The focus outline box inside of a button.
#[parse(condition = "in_ua_or_chrome_sheet")]
ButtonFocus,
/// The caret of a text area
Caret,
/// A dual toolbar button (e.g., a Back button with a dropdown)
#[parse(condition = "in_ua_or_chrome_sheet")]
Dualbutton,
/// A groupbox.
#[parse(condition = "in_ua_or_chrome_sheet")]
Groupbox,
/// A inner-spin button.
InnerSpinButton,
@ -988,12 +995,17 @@ pub enum Appearance {
/// A listbox item.
Listitem,
/// Menu Bar background
#[parse(condition = "in_ua_or_chrome_sheet")]
Menubar,
/// <menu> and <menuitem> appearances
#[parse(condition = "in_ua_or_chrome_sheet")]
Menuitem,
#[parse(condition = "in_ua_or_chrome_sheet")]
Checkmenuitem,
#[parse(condition = "in_ua_or_chrome_sheet")]
Radiomenuitem,
/// For text on non-iconic menuitems only
#[parse(condition = "in_ua_or_chrome_sheet")]
Menuitemtext,
/// A dropdown list.
Menulist,
@ -1004,13 +1016,19 @@ pub enum Appearance {
/// An editable textfield with a dropdown list (a combobox).
MenulistTextfield,
/// Menu Popup background.
#[parse(condition = "in_ua_or_chrome_sheet")]
Menupopup,
/// menu checkbox/radio appearances
#[parse(condition = "in_ua_or_chrome_sheet")]
Menucheckbox,
#[parse(condition = "in_ua_or_chrome_sheet")]
Menuradio,
#[parse(condition = "in_ua_or_chrome_sheet")]
Menuseparator,
#[parse(condition = "in_ua_or_chrome_sheet")]
Menuarrow,
/// An image in the menu gutter, like in bookmarks or history.
#[parse(condition = "in_ua_or_chrome_sheet")]
Menuimage,
/// A horizontal meter bar.
Meterbar,
@ -1035,19 +1053,25 @@ pub enum Appearance {
Radio,
/// A generic container that always repaints on state changes. This is a
/// hack to make XUL checkboxes and radio buttons work.
#[parse(condition = "in_ua_or_chrome_sheet")]
CheckboxContainer,
#[parse(condition = "in_ua_or_chrome_sheet")]
RadioContainer,
/// The label part of a checkbox or radio button, used for painting a focus
/// outline.
#[parse(condition = "in_ua_or_chrome_sheet")]
CheckboxLabel,
#[parse(condition = "in_ua_or_chrome_sheet")]
RadioLabel,
/// nsRangeFrame and its subparts
Range,
RangeThumb,
/// The resizer background area in a status bar for the resizer widget in
/// the corner of a window.
#[parse(condition = "in_ua_or_chrome_sheet")]
Resizerpanel,
/// The resizer itself.
#[parse(condition = "in_ua_or_chrome_sheet")]
Resizer,
/// A slider.
ScaleHorizontal,
@ -1061,18 +1085,26 @@ pub enum Appearance {
/// The ticks for a slider.
Scalethumbtick,
/// A scrollbar.
#[parse(condition = "in_ua_or_chrome_sheet")]
Scrollbar,
/// A small scrollbar.
#[parse(condition = "in_ua_or_chrome_sheet")]
ScrollbarSmall,
/// The scrollbar slider
#[parse(condition = "in_ua_or_chrome_sheet")]
ScrollbarHorizontal,
#[parse(condition = "in_ua_or_chrome_sheet")]
ScrollbarVertical,
/// A scrollbar button (up/down/left/right).
/// Keep these in order (some code casts these values to `int` in order to
/// compare them against each other).
#[parse(condition = "in_ua_or_chrome_sheet")]
ScrollbarbuttonUp,
#[parse(condition = "in_ua_or_chrome_sheet")]
ScrollbarbuttonDown,
#[parse(condition = "in_ua_or_chrome_sheet")]
ScrollbarbuttonLeft,
#[parse(condition = "in_ua_or_chrome_sheet")]
ScrollbarbuttonRight,
/// The scrollbar thumb.
ScrollbarthumbHorizontal,
@ -1081,107 +1113,166 @@ pub enum Appearance {
ScrollbartrackHorizontal,
ScrollbartrackVertical,
/// The scroll corner
#[parse(condition = "in_ua_or_chrome_sheet")]
Scrollcorner,
/// A searchfield.
Searchfield,
/// A separator. Can be horizontal or vertical.
#[parse(condition = "in_ua_or_chrome_sheet")]
Separator,
/// A spin control (up/down control for time/date pickers).
#[parse(condition = "in_ua_or_chrome_sheet")]
Spinner,
/// The up button of a spin control.
#[parse(condition = "in_ua_or_chrome_sheet")]
SpinnerUpbutton,
/// The down button of a spin control.
#[parse(condition = "in_ua_or_chrome_sheet")]
SpinnerDownbutton,
/// The textfield of a spin control
#[parse(condition = "in_ua_or_chrome_sheet")]
SpinnerTextfield,
/// A splitter. Can be horizontal or vertical.
#[parse(condition = "in_ua_or_chrome_sheet")]
Splitter,
/// A status bar in a main application window.
#[parse(condition = "in_ua_or_chrome_sheet")]
Statusbar,
/// A single pane of a status bar.
#[parse(condition = "in_ua_or_chrome_sheet")]
Statusbarpanel,
/// A single tab in a tab widget.
#[parse(condition = "in_ua_or_chrome_sheet")]
Tab,
/// A single pane (inside the tabpanels container).
#[parse(condition = "in_ua_or_chrome_sheet")]
Tabpanel,
/// The tab panels container.
#[parse(condition = "in_ua_or_chrome_sheet")]
Tabpanels,
/// The tabs scroll arrows (left/right).
#[parse(condition = "in_ua_or_chrome_sheet")]
TabScrollArrowBack,
#[parse(condition = "in_ua_or_chrome_sheet")]
TabScrollArrowForward,
/// A textfield or text area.
Textfield,
/// A multiline text field.
TextfieldMultiline,
/// A toolbar in an application window.
#[parse(condition = "in_ua_or_chrome_sheet")]
Toolbar,
/// A single toolbar button (with no associated dropdown).
#[parse(condition = "in_ua_or_chrome_sheet")]
Toolbarbutton,
/// The dropdown portion of a toolbar button
#[parse(condition = "in_ua_or_chrome_sheet")]
ToolbarbuttonDropdown,
/// The gripper for a toolbar.
#[parse(condition = "in_ua_or_chrome_sheet")]
Toolbargripper,
/// The toolbox that contains the toolbars.
#[parse(condition = "in_ua_or_chrome_sheet")]
Toolbox,
/// A tooltip.
#[parse(condition = "in_ua_or_chrome_sheet")]
Tooltip,
/// A listbox or tree widget header
#[parse(condition = "in_ua_or_chrome_sheet")]
Treeheader,
/// An individual header cell
#[parse(condition = "in_ua_or_chrome_sheet")]
Treeheadercell,
/// The sort arrow for a header.
#[parse(condition = "in_ua_or_chrome_sheet")]
Treeheadersortarrow,
/// A tree item.
#[parse(condition = "in_ua_or_chrome_sheet")]
Treeitem,
/// A tree widget branch line
#[parse(condition = "in_ua_or_chrome_sheet")]
Treeline,
/// A tree widget twisty.
#[parse(condition = "in_ua_or_chrome_sheet")]
Treetwisty,
/// Open tree widget twisty.
#[parse(condition = "in_ua_or_chrome_sheet")]
Treetwistyopen,
/// A tree widget.
#[parse(condition = "in_ua_or_chrome_sheet")]
Treeview,
/// Window and dialog backgrounds.
#[parse(condition = "in_ua_or_chrome_sheet")]
Window,
#[parse(condition = "in_ua_or_chrome_sheet")]
Dialog,
/// Vista Rebars.
#[parse(condition = "in_ua_or_chrome_sheet")]
MozWinCommunicationsToolbox,
#[parse(condition = "in_ua_or_chrome_sheet")]
MozWinMediaToolbox,
#[parse(condition = "in_ua_or_chrome_sheet")]
MozWinBrowsertabbarToolbox,
/// Vista glass.
#[parse(condition = "in_ua_or_chrome_sheet")]
MozWinGlass,
#[parse(condition = "in_ua_or_chrome_sheet")]
MozWinBorderlessGlass,
/// -moz-apperance style used in setting proper glass margins.
#[parse(condition = "in_ua_or_chrome_sheet")]
MozWinExcludeGlass,
/// Titlebar elements on the Mac.
#[parse(condition = "in_ua_or_chrome_sheet")]
MozMacFullscreenButton,
/// Mac help button.
#[parse(condition = "in_ua_or_chrome_sheet")]
MozMacHelpButton,
/// Windows themed window frame elements.
#[parse(condition = "in_ua_or_chrome_sheet")]
MozWindowButtonBox,
#[parse(condition = "in_ua_or_chrome_sheet")]
MozWindowButtonBoxMaximized,
#[parse(condition = "in_ua_or_chrome_sheet")]
MozWindowButtonClose,
#[parse(condition = "in_ua_or_chrome_sheet")]
MozWindowButtonMaximize,
#[parse(condition = "in_ua_or_chrome_sheet")]
MozWindowButtonMinimize,
#[parse(condition = "in_ua_or_chrome_sheet")]
MozWindowButtonRestore,
#[parse(condition = "in_ua_or_chrome_sheet")]
MozWindowFrameBottom,
#[parse(condition = "in_ua_or_chrome_sheet")]
MozWindowFrameLeft,
#[parse(condition = "in_ua_or_chrome_sheet")]
MozWindowFrameRight,
#[parse(condition = "in_ua_or_chrome_sheet")]
MozWindowTitlebar,
#[parse(condition = "in_ua_or_chrome_sheet")]
MozWindowTitlebarMaximized,
#[parse(condition = "in_ua_or_chrome_sheet")]
MozGtkInfoBar,
#[parse(condition = "in_ua_or_chrome_sheet")]
MozMacActiveSourceListSelection,
#[parse(condition = "in_ua_or_chrome_sheet")]
MozMacDisclosureButtonClosed,
#[parse(condition = "in_ua_or_chrome_sheet")]
MozMacDisclosureButtonOpen,
#[parse(condition = "in_ua_or_chrome_sheet")]
MozMacSourceList,
#[parse(condition = "in_ua_or_chrome_sheet")]
MozMacSourceListSelection,
#[parse(condition = "in_ua_or_chrome_sheet")]
MozMacVibrancyDark,
#[parse(condition = "in_ua_or_chrome_sheet")]
MozMacVibrancyLight,
#[parse(condition = "in_ua_or_chrome_sheet")]
MozMacVibrantTitlebarDark,
#[parse(condition = "in_ua_or_chrome_sheet")]
MozMacVibrantTitlebarLight,
/// A non-disappearing scrollbar.

View file

@ -469,22 +469,22 @@ impl CalcNode {
CalcNode::Sub(ref a, ref b) => {
let lhs = a.to_angle()?;
let rhs = b.to_angle()?;
Angle::from_calc(lhs.radians() - rhs.radians())
Angle::from_calc(lhs.degrees() - rhs.degrees())
},
CalcNode::Sum(ref a, ref b) => {
let lhs = a.to_angle()?;
let rhs = b.to_angle()?;
Angle::from_calc(lhs.radians() + rhs.radians())
Angle::from_calc(lhs.degrees() + rhs.degrees())
},
CalcNode::Mul(ref a, ref b) => match a.to_angle() {
Ok(lhs) => {
let rhs = b.to_number()?;
Angle::from_calc(lhs.radians() * rhs)
Angle::from_calc(lhs.degrees() * rhs)
},
Err(..) => {
let lhs = a.to_number()?;
let rhs = b.to_angle()?;
Angle::from_calc(lhs * rhs.radians())
Angle::from_calc(lhs * rhs.degrees())
},
},
CalcNode::Div(ref a, ref b) => {
@ -493,7 +493,7 @@ impl CalcNode {
if rhs == 0. {
return Err(());
}
Angle::from_calc(lhs.radians() / rhs)
Angle::from_calc(lhs.degrees() / rhs)
},
CalcNode::Number(..) |
CalcNode::Length(..) |

View file

@ -301,7 +301,7 @@ impl SpecifiedFontStyle {
}
fn compute_angle(angle: &Angle) -> ComputedAngle {
ComputedAngle::Deg(Self::compute_angle_degrees(angle))
ComputedAngle::from_degrees(Self::compute_angle_degrees(angle))
}
/// Parse a suitable angle for font-style: oblique.

View file

@ -15,7 +15,6 @@ use selectors::parser::SelectorParseErrorKind;
#[cfg(feature = "servo")]
use servo_url::ServoUrl;
use std::cmp::Ordering;
use std::f32::consts::PI;
use std::fmt::{self, Write};
use style_traits::{CssType, CssWriter, KeywordsCollectFn, ParseError};
use style_traits::{StyleParseErrorKind, SpecifiedValueInfo, ToCss};
@ -679,7 +678,7 @@ impl GradientKind {
impl generic::LineDirection for LineDirection {
fn points_downwards(&self, compat_mode: CompatMode) -> bool {
match *self {
LineDirection::Angle(ref angle) => angle.radians() == PI,
LineDirection::Angle(ref angle) => angle.degrees() == 180.0,
LineDirection::Vertical(Y::Bottom) if compat_mode == CompatMode::Modern => true,
LineDirection::Vertical(Y::Top) if compat_mode != CompatMode::Modern => true,
#[cfg(feature = "gecko")]

View file

@ -19,6 +19,7 @@ use super::{AllowQuirks, Number, Percentage, ToComputedValue};
use values::{Auto, CSSFloat, Either, Normal};
use values::computed::{self, CSSPixelLength, Context, ExtremumLength};
use values::generics::NonNegative;
use values::generics::length::{MaxLength as GenericMaxLength, MozLength as GenericMozLength};
use values::specified::calc::CalcNode;
pub use values::specified::calc::CalcLengthOrPercentage;
@ -1188,18 +1189,8 @@ impl LengthOrNumber {
}
}
/// A value suitable for a `min-width` or `min-height` property.
///
/// Unlike `max-width` or `max-height` properties, a MozLength can be `auto`,
/// and cannot be `none`.
///
/// Note that it only accepts non-negative values.
#[allow(missing_docs)]
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
pub enum MozLength {
LengthOrPercentageOrAuto(LengthOrPercentageOrAuto),
ExtremumLength(ExtremumLength),
}
/// A specified value for `min-width`, `min-height`, `width` or `height` property.
pub type MozLength = GenericMozLength<LengthOrPercentageOrAuto>;
impl Parse for MozLength {
fn parse<'i, 't>(
@ -1219,7 +1210,7 @@ impl MozLength {
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let length = LengthOrPercentageOrAuto::parse_non_negative(context, input)?;
Ok(MozLength::LengthOrPercentageOrAuto(length))
Ok(GenericMozLength::LengthOrPercentageOrAuto(length))
}
/// Parses, with quirks.
@ -1229,34 +1220,29 @@ impl MozLength {
allow_quirks: AllowQuirks,
) -> Result<Self, ParseError<'i>> {
if let Ok(l) = input.try(ExtremumLength::parse) {
return Ok(MozLength::ExtremumLength(l));
return Ok(GenericMozLength::ExtremumLength(l));
}
let length =
LengthOrPercentageOrAuto::parse_non_negative_quirky(context, input, allow_quirks)?;
Ok(MozLength::LengthOrPercentageOrAuto(length))
Ok(GenericMozLength::LengthOrPercentageOrAuto(length))
}
/// Returns `auto`.
#[inline]
pub fn auto() -> Self {
MozLength::LengthOrPercentageOrAuto(LengthOrPercentageOrAuto::auto())
GenericMozLength::LengthOrPercentageOrAuto(LengthOrPercentageOrAuto::auto())
}
/// Returns `0%`.
#[inline]
pub fn zero_percent() -> Self {
MozLength::LengthOrPercentageOrAuto(LengthOrPercentageOrAuto::zero_percent())
GenericMozLength::LengthOrPercentageOrAuto(LengthOrPercentageOrAuto::zero_percent())
}
}
/// A value suitable for a `max-width` or `max-height` property.
#[allow(missing_docs)]
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
pub enum MaxLength {
LengthOrPercentageOrNone(LengthOrPercentageOrNone),
ExtremumLength(ExtremumLength),
}
/// A specified value for `max-width` or `max-height` property.
pub type MaxLength = GenericMaxLength<LengthOrPercentageOrNone>;
impl Parse for MaxLength {
fn parse<'i, 't>(
@ -1276,7 +1262,7 @@ impl MaxLength {
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let length = LengthOrPercentageOrNone::parse_non_negative(context, input)?;
Ok(MaxLength::LengthOrPercentageOrNone(length))
Ok(GenericMaxLength::LengthOrPercentageOrNone(length))
}
/// Parses, with quirks.
@ -1286,11 +1272,11 @@ impl MaxLength {
allow_quirks: AllowQuirks,
) -> Result<Self, ParseError<'i>> {
if let Ok(l) = input.try(ExtremumLength::parse) {
return Ok(MaxLength::ExtremumLength(l));
return Ok(GenericMaxLength::ExtremumLength(l));
}
let length =
LengthOrPercentageOrNone::parse_non_negative_quirky(context, input, allow_quirks)?;
Ok(MaxLength::LengthOrPercentageOrNone(length))
Ok(GenericMaxLength::LengthOrPercentageOrNone(length))
}
}

View file

@ -611,60 +611,6 @@ mod shorthand_serialization {
}
}
mod transform {
pub use super::*;
use style::values::generics::transform::TransformOperation;
use style::values::specified::{Angle, Number};
use style::values::specified::transform::TransformOperation as SpecifiedOperation;
#[test]
fn should_serialize_none_correctly() {
use style::properties::longhands::transform;
assert_roundtrip_with_context!(transform::parse, "none");
}
#[inline(always)]
fn validate_serialization(op: &SpecifiedOperation, expected_string: &'static str) {
let css_string = op.to_css_string();
assert_eq!(css_string, expected_string);
}
#[test]
fn transform_scale() {
validate_serialization(&TransformOperation::Scale(Number::new(1.3), None), "scale(1.3)");
validate_serialization(
&TransformOperation::Scale(Number::new(2.0), Some(Number::new(2.0))),
"scale(2, 2)");
validate_serialization(&TransformOperation::ScaleX(Number::new(42.0)), "scaleX(42)");
validate_serialization(&TransformOperation::ScaleY(Number::new(0.3)), "scaleY(0.3)");
validate_serialization(&TransformOperation::ScaleZ(Number::new(1.0)), "scaleZ(1)");
validate_serialization(
&TransformOperation::Scale3D(Number::new(4.0), Number::new(5.0), Number::new(6.0)),
"scale3d(4, 5, 6)");
}
#[test]
fn transform_skew() {
validate_serialization(
&TransformOperation::Skew(Angle::from_degrees(42.3, false), None),
"skew(42.3deg)");
validate_serialization(
&TransformOperation::Skew(Angle::from_gradians(-50.0, false), Some(Angle::from_turns(0.73, false))),
"skew(-50grad, 0.73turn)");
validate_serialization(
&TransformOperation::SkewX(Angle::from_radians(0.31, false)), "skewX(0.31rad)");
}
#[test]
fn transform_rotate() {
validate_serialization(
&TransformOperation::Rotate(Angle::from_turns(35.0, false)),
"rotate(35turn)"
)
}
}
mod quotes {
pub use super::*;

View file

@ -1,2 +0,0 @@
[at-supports-040.html]
expected: FAIL

View file

@ -1,4 +0,0 @@
[CSS.html]
[CSS.supports, selector function]
expected: FAIL

View file

@ -26166,7 +26166,7 @@
"reftest"
],
"css/transform_skew_ref.html": [
"caf92ca6f50d1cfe27f9202ebf79d76dead03ba0",
"b6ef9bb8fe9c129b02f5f3213865673a42638190",
"support"
],
"css/transform_stacking_context_a.html": [

View file

@ -17,15 +17,15 @@ div>div {
}
.transformed1_ref {
transform: matrix(1, 0, 0.25534192122, 1, 0, 0);
transform: matrix(1, 0, 0.255342, 1, 0, 0);
}
.transformed2_ref {
transform: matrix(1, 0.54630248984, 0, 1, 0, 0);
transform: matrix(1, 0.546302, 0, 1, 0, 0);
}
.transformed3_ref {
transform: matrix(1, 0.54630248984, 0.25534192122, 1, 0, 0);
transform: matrix(1, 0.546302, 0.255342, 1, 0, 0);
}
</style>