mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
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:
commit
91282778e4
48 changed files with 799 additions and 902 deletions
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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, ()> {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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),
|
||||
};
|
||||
|
|
|
@ -374,7 +374,6 @@ impl Stylesheet {
|
|||
);
|
||||
|
||||
let rule_parser = TopLevelRuleParser {
|
||||
stylesheet_origin: origin,
|
||||
shared_lock,
|
||||
loader: stylesheet_loader,
|
||||
context,
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
54
components/style/values/generics/length.rs
Normal file
54
components/style/values/generics/length.rs
Normal 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),
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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(..) |
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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")]
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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::*;
|
||||
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
[at-supports-040.html]
|
||||
expected: FAIL
|
|
@ -1,4 +0,0 @@
|
|||
[CSS.html]
|
||||
[CSS.supports, selector function]
|
||||
expected: FAIL
|
||||
|
|
@ -26166,7 +26166,7 @@
|
|||
"reftest"
|
||||
],
|
||||
"css/transform_skew_ref.html": [
|
||||
"caf92ca6f50d1cfe27f9202ebf79d76dead03ba0",
|
||||
"b6ef9bb8fe9c129b02f5f3213865673a42638190",
|
||||
"support"
|
||||
],
|
||||
"css/transform_stacking_context_a.html": [
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue