mirror of
https://github.com/servo/servo.git
synced 2025-07-24 15:50:21 +01:00
Auto merge of #14535 - servo:property-id, r=mbrubeck
Introduce a PropertyId enum and use it instead of strings of property names <!-- Please describe your changes on the following line: --> * `LonghandId` and `ShorthandId` are C-like enums * `Atom` is used for the name of custom properties. * `PropertyDeclarationId` is the identifier for `PropertyDeclaration`, after parsing and shorthand expansion. (Longhand or custom property.) * `PropertyId` represents any CSS property, e.g. in CSSOM. (Longhand, shorthand, or custom.) CC @upsuper --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- 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/14535) <!-- Reviewable:end -->
This commit is contained in:
commit
6dd4b4822f
27 changed files with 601 additions and 459 deletions
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -2610,6 +2610,8 @@ dependencies = [
|
||||||
"ordered-float 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ordered-float 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"owning_ref 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"owning_ref 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parking_lot 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parking_lot 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"phf 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"phf_codegen 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"plugins 0.0.1",
|
"plugins 0.0.1",
|
||||||
"quickersort 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quickersort 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -2636,6 +2638,7 @@ dependencies = [
|
||||||
"cssparser 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cssparser 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"html5ever-atoms 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"html5ever-atoms 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"owning_ref 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"owning_ref 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parking_lot 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parking_lot 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
|
@ -32,21 +32,6 @@ number
|
||||||
|
|
||||||
dir
|
dir
|
||||||
|
|
||||||
bottom
|
|
||||||
top
|
|
||||||
left
|
|
||||||
right
|
|
||||||
width
|
|
||||||
height
|
|
||||||
margin-bottom
|
|
||||||
margin-top
|
|
||||||
margin-left
|
|
||||||
margin-right
|
|
||||||
padding-bottom
|
|
||||||
padding-top
|
|
||||||
padding-left
|
|
||||||
padding-right
|
|
||||||
|
|
||||||
DOMContentLoaded
|
DOMContentLoaded
|
||||||
select
|
select
|
||||||
input
|
input
|
||||||
|
|
|
@ -24,7 +24,6 @@ use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutElemen
|
||||||
use script_traits::LayoutMsg as ConstellationMsg;
|
use script_traits::LayoutMsg as ConstellationMsg;
|
||||||
use script_traits::UntrustedNodeAddress;
|
use script_traits::UntrustedNodeAddress;
|
||||||
use sequential;
|
use sequential;
|
||||||
use servo_atoms::Atom;
|
|
||||||
use std::cmp::{min, max};
|
use std::cmp::{min, max};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
@ -32,8 +31,8 @@ use style::computed_values;
|
||||||
use style::context::StyleContext;
|
use style::context::StyleContext;
|
||||||
use style::dom::TElement;
|
use style::dom::TElement;
|
||||||
use style::logical_geometry::{WritingMode, BlockFlowDirection, InlineBaseDirection};
|
use style::logical_geometry::{WritingMode, BlockFlowDirection, InlineBaseDirection};
|
||||||
|
use style::properties::{style_structs, PropertyId, PropertyDeclarationId, LonghandId};
|
||||||
use style::properties::longhands::{display, position};
|
use style::properties::longhands::{display, position};
|
||||||
use style::properties::style_structs;
|
|
||||||
use style::selector_parser::PseudoElement;
|
use style::selector_parser::PseudoElement;
|
||||||
use style::stylist::Stylist;
|
use style::stylist::Stylist;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
|
@ -75,7 +74,7 @@ pub struct LayoutThreadData {
|
||||||
pub scroll_area_response: Rect<i32>,
|
pub scroll_area_response: Rect<i32>,
|
||||||
|
|
||||||
/// A queued response for the resolved style property of an element.
|
/// A queued response for the resolved style property of an element.
|
||||||
pub resolved_style_response: Option<String>,
|
pub resolved_style_response: String,
|
||||||
|
|
||||||
/// A queued response for the offset parent/rect of a node.
|
/// A queued response for the offset parent/rect of a node.
|
||||||
pub offset_parent_response: OffsetParentResponse,
|
pub offset_parent_response: OffsetParentResponse,
|
||||||
|
@ -628,8 +627,8 @@ pub fn process_node_scroll_area_request< N: LayoutNode>(requested_node: N, layou
|
||||||
pub fn process_resolved_style_request<'a, N, C>(requested_node: N,
|
pub fn process_resolved_style_request<'a, N, C>(requested_node: N,
|
||||||
style_context: &'a C,
|
style_context: &'a C,
|
||||||
pseudo: &Option<PseudoElement>,
|
pseudo: &Option<PseudoElement>,
|
||||||
property: &Atom,
|
property: &PropertyId,
|
||||||
layout_root: &mut Flow) -> Option<String>
|
layout_root: &mut Flow) -> String
|
||||||
where N: LayoutNode,
|
where N: LayoutNode,
|
||||||
C: StyleContext<'a>
|
C: StyleContext<'a>
|
||||||
{
|
{
|
||||||
|
@ -667,13 +666,25 @@ pub fn process_resolved_style_request<'a, N, C>(requested_node: N,
|
||||||
// The pseudo doesn't exist, return nothing. Chrome seems to query
|
// The pseudo doesn't exist, return nothing. Chrome seems to query
|
||||||
// the element itself in this case, Firefox uses the resolved value.
|
// the element itself in this case, Firefox uses the resolved value.
|
||||||
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=29006
|
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=29006
|
||||||
return None;
|
return String::new();
|
||||||
}
|
}
|
||||||
Some(layout_el) => layout_el
|
Some(layout_el) => layout_el
|
||||||
};
|
};
|
||||||
|
|
||||||
let style = &*layout_el.resolved_style();
|
let style = &*layout_el.resolved_style();
|
||||||
|
|
||||||
|
let longhand_id = match *property {
|
||||||
|
PropertyId::Longhand(id) => id,
|
||||||
|
|
||||||
|
// Firefox returns blank strings for the computed value of shorthands,
|
||||||
|
// so this should be web-compatible.
|
||||||
|
PropertyId::Shorthand(_) => return String::new(),
|
||||||
|
|
||||||
|
PropertyId::Custom(ref name) => {
|
||||||
|
return style.computed_value_to_string(PropertyDeclarationId::Custom(name))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Clear any temporarily-resolved data to maintain our invariants. See the comment
|
// Clear any temporarily-resolved data to maintain our invariants. See the comment
|
||||||
// at the top of this function.
|
// at the top of this function.
|
||||||
display_none_root.map(|r| clear_descendant_data(r, &|e| e.as_node().clear_data()));
|
display_none_root.map(|r| clear_descendant_data(r, &|e| e.as_node().clear_data()));
|
||||||
|
@ -697,7 +708,7 @@ pub fn process_resolved_style_request<'a, N, C>(requested_node: N,
|
||||||
layout_el: <N::ConcreteThreadSafeLayoutNode as ThreadSafeLayoutNode>::ConcreteThreadSafeLayoutElement,
|
layout_el: <N::ConcreteThreadSafeLayoutNode as ThreadSafeLayoutNode>::ConcreteThreadSafeLayoutElement,
|
||||||
layout_root: &mut Flow,
|
layout_root: &mut Flow,
|
||||||
requested_node: N,
|
requested_node: N,
|
||||||
property: &Atom) -> Option<String> {
|
longhand_id: LonghandId) -> String {
|
||||||
let maybe_data = layout_el.borrow_layout_data();
|
let maybe_data = layout_el.borrow_layout_data();
|
||||||
let position = maybe_data.map_or(Point2D::zero(), |data| {
|
let position = maybe_data.map_or(Point2D::zero(), |data| {
|
||||||
match (*data).flow_construction_result {
|
match (*data).flow_construction_result {
|
||||||
|
@ -708,13 +719,13 @@ pub fn process_resolved_style_request<'a, N, C>(requested_node: N,
|
||||||
_ => Point2D::zero()
|
_ => Point2D::zero()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let property = match *property {
|
let property = match longhand_id {
|
||||||
atom!("bottom") => PositionProperty::Bottom,
|
LonghandId::Bottom => PositionProperty::Bottom,
|
||||||
atom!("top") => PositionProperty::Top,
|
LonghandId::Top => PositionProperty::Top,
|
||||||
atom!("left") => PositionProperty::Left,
|
LonghandId::Left => PositionProperty::Left,
|
||||||
atom!("right") => PositionProperty::Right,
|
LonghandId::Right => PositionProperty::Right,
|
||||||
atom!("width") => PositionProperty::Width,
|
LonghandId::Width => PositionProperty::Width,
|
||||||
atom!("height") => PositionProperty::Height,
|
LonghandId::Height => PositionProperty::Height,
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
};
|
};
|
||||||
let mut iterator =
|
let mut iterator =
|
||||||
|
@ -723,27 +734,25 @@ pub fn process_resolved_style_request<'a, N, C>(requested_node: N,
|
||||||
position);
|
position);
|
||||||
sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root,
|
sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root,
|
||||||
&mut iterator);
|
&mut iterator);
|
||||||
iterator.result.map(|r| r.to_css_string())
|
iterator.result.map(|r| r.to_css_string()).unwrap_or(String::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: we will return neither the computed nor used value for margin and padding.
|
// TODO: we will return neither the computed nor used value for margin and padding.
|
||||||
// Firefox returns blank strings for the computed value of shorthands,
|
match longhand_id {
|
||||||
// so this should be web-compatible.
|
LonghandId::MarginBottom | LonghandId::MarginTop |
|
||||||
match *property {
|
LonghandId::MarginLeft | LonghandId::MarginRight |
|
||||||
atom!("margin-bottom") | atom!("margin-top") |
|
LonghandId::PaddingBottom | LonghandId::PaddingTop |
|
||||||
atom!("margin-left") | atom!("margin-right") |
|
LonghandId::PaddingLeft | LonghandId::PaddingRight
|
||||||
atom!("padding-bottom") | atom!("padding-top") |
|
|
||||||
atom!("padding-left") | atom!("padding-right")
|
|
||||||
if applies && style.get_box().display != display::computed_value::T::none => {
|
if applies && style.get_box().display != display::computed_value::T::none => {
|
||||||
let (margin_padding, side) = match *property {
|
let (margin_padding, side) = match longhand_id {
|
||||||
atom!("margin-bottom") => (MarginPadding::Margin, Side::Bottom),
|
LonghandId::MarginBottom => (MarginPadding::Margin, Side::Bottom),
|
||||||
atom!("margin-top") => (MarginPadding::Margin, Side::Top),
|
LonghandId::MarginTop => (MarginPadding::Margin, Side::Top),
|
||||||
atom!("margin-left") => (MarginPadding::Margin, Side::Left),
|
LonghandId::MarginLeft => (MarginPadding::Margin, Side::Left),
|
||||||
atom!("margin-right") => (MarginPadding::Margin, Side::Right),
|
LonghandId::MarginRight => (MarginPadding::Margin, Side::Right),
|
||||||
atom!("padding-bottom") => (MarginPadding::Padding, Side::Bottom),
|
LonghandId::PaddingBottom => (MarginPadding::Padding, Side::Bottom),
|
||||||
atom!("padding-top") => (MarginPadding::Padding, Side::Top),
|
LonghandId::PaddingTop => (MarginPadding::Padding, Side::Top),
|
||||||
atom!("padding-left") => (MarginPadding::Padding, Side::Left),
|
LonghandId::PaddingLeft => (MarginPadding::Padding, Side::Left),
|
||||||
atom!("padding-right") => (MarginPadding::Padding, Side::Right),
|
LonghandId::PaddingRight => (MarginPadding::Padding, Side::Right),
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
};
|
};
|
||||||
let mut iterator =
|
let mut iterator =
|
||||||
|
@ -753,23 +762,22 @@ pub fn process_resolved_style_request<'a, N, C>(requested_node: N,
|
||||||
style.writing_mode);
|
style.writing_mode);
|
||||||
sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root,
|
sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root,
|
||||||
&mut iterator);
|
&mut iterator);
|
||||||
iterator.result.map(|r| r.to_css_string())
|
iterator.result.map(|r| r.to_css_string()).unwrap_or(String::new())
|
||||||
},
|
},
|
||||||
|
|
||||||
atom!("bottom") | atom!("top") | atom!("right") |
|
LonghandId::Bottom | LonghandId::Top | LonghandId::Right | LonghandId::Left
|
||||||
atom!("left")
|
|
||||||
if applies && positioned && style.get_box().display !=
|
if applies && positioned && style.get_box().display !=
|
||||||
display::computed_value::T::none => {
|
display::computed_value::T::none => {
|
||||||
used_value_for_position_property(layout_el, layout_root, requested_node, property)
|
used_value_for_position_property(layout_el, layout_root, requested_node, longhand_id)
|
||||||
}
|
}
|
||||||
atom!("width") | atom!("height")
|
LonghandId::Width | LonghandId::Height
|
||||||
if applies && style.get_box().display !=
|
if applies && style.get_box().display !=
|
||||||
display::computed_value::T::none => {
|
display::computed_value::T::none => {
|
||||||
used_value_for_position_property(layout_el, layout_root, requested_node, property)
|
used_value_for_position_property(layout_el, layout_root, requested_node, longhand_id)
|
||||||
}
|
}
|
||||||
// FIXME: implement used value computation for line-height
|
// FIXME: implement used value computation for line-height
|
||||||
ref property => {
|
_ => {
|
||||||
style.computed_value_to_string(&*property).ok()
|
style.computed_value_to_string(PropertyDeclarationId::Longhand(longhand_id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -466,7 +466,7 @@ impl LayoutThread {
|
||||||
scroll_root_id_response: None,
|
scroll_root_id_response: None,
|
||||||
scroll_area_response: Rect::zero(),
|
scroll_area_response: Rect::zero(),
|
||||||
overflow_response: NodeOverflowResponse(None),
|
overflow_response: NodeOverflowResponse(None),
|
||||||
resolved_style_response: None,
|
resolved_style_response: String::new(),
|
||||||
offset_parent_response: OffsetParentResponse::empty(),
|
offset_parent_response: OffsetParentResponse::empty(),
|
||||||
margin_style_response: MarginStyleResponse::empty(),
|
margin_style_response: MarginStyleResponse::empty(),
|
||||||
stacking_context_scroll_offsets: HashMap::new(),
|
stacking_context_scroll_offsets: HashMap::new(),
|
||||||
|
@ -1018,7 +1018,7 @@ impl LayoutThread {
|
||||||
rw_data.scroll_root_id_response = None;
|
rw_data.scroll_root_id_response = None;
|
||||||
},
|
},
|
||||||
ReflowQueryType::ResolvedStyleQuery(_, _, _) => {
|
ReflowQueryType::ResolvedStyleQuery(_, _, _) => {
|
||||||
rw_data.resolved_style_response = None;
|
rw_data.resolved_style_response = String::new();
|
||||||
},
|
},
|
||||||
ReflowQueryType::OffsetParentQuery(_) => {
|
ReflowQueryType::OffsetParentQuery(_) => {
|
||||||
rw_data.offset_parent_response = OffsetParentResponse::empty();
|
rw_data.offset_parent_response = OffsetParentResponse::empty();
|
||||||
|
|
|
@ -286,6 +286,12 @@ impl Into<Vec<u8>> for DOMString {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> Into<Cow<'a, str>> for DOMString {
|
||||||
|
fn into(self) -> Cow<'a, str> {
|
||||||
|
self.0.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Extend<char> for DOMString {
|
impl Extend<char> for DOMString {
|
||||||
fn extend<I>(&mut self, iterable: I) where I: IntoIterator<Item=char> {
|
fn extend<I>(&mut self, iterable: I) where I: IntoIterator<Item=char> {
|
||||||
self.0.extend(iterable)
|
self.0.extend(iterable)
|
||||||
|
|
|
@ -12,12 +12,11 @@ use dom::element::Element;
|
||||||
use dom::node::{Node, NodeDamage, window_from_node};
|
use dom::node::{Node, NodeDamage, window_from_node};
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use servo_atoms::Atom;
|
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use style::parser::ParserContextExtraData;
|
use style::parser::ParserContextExtraData;
|
||||||
use style::properties::{Shorthand, Importance, PropertyDeclarationBlock};
|
use style::properties::{Importance, PropertyDeclarationBlock, PropertyId, LonghandId, ShorthandId};
|
||||||
use style::properties::{is_supported_property, parse_one_declaration, parse_style_attribute};
|
use style::properties::{parse_one_declaration, parse_style_attribute};
|
||||||
use style::selector_parser::PseudoElement;
|
use style::selector_parser::PseudoElement;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
|
|
||||||
|
@ -37,13 +36,13 @@ pub enum CSSModificationAccess {
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! css_properties(
|
macro_rules! css_properties(
|
||||||
( $([$getter:ident, $setter:ident, $cssprop:expr]),* ) => (
|
( $([$getter:ident, $setter:ident, $id:expr],)* ) => (
|
||||||
$(
|
$(
|
||||||
fn $getter(&self) -> DOMString {
|
fn $getter(&self) -> DOMString {
|
||||||
self.GetPropertyValue(DOMString::from($cssprop))
|
self.get_property_value($id)
|
||||||
}
|
}
|
||||||
fn $setter(&self, value: DOMString) -> ErrorResult {
|
fn $setter(&self, value: DOMString) -> ErrorResult {
|
||||||
self.SetPropertyValue(DOMString::from($cssprop), value)
|
self.set_property($id, value, DOMString::new())
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
);
|
);
|
||||||
|
@ -74,41 +73,21 @@ impl CSSStyleDeclaration {
|
||||||
CSSStyleDeclarationBinding::Wrap)
|
CSSStyleDeclarationBinding::Wrap)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_computed_style(&self, property: &Atom) -> Option<DOMString> {
|
fn get_computed_style(&self, property: PropertyId) -> DOMString {
|
||||||
let node = self.owner.upcast::<Node>();
|
let node = self.owner.upcast::<Node>();
|
||||||
if !node.is_in_doc() {
|
if !node.is_in_doc() {
|
||||||
// TODO: Node should be matched against the style rules of this window.
|
// TODO: Node should be matched against the style rules of this window.
|
||||||
// Firefox is currently the only browser to implement this.
|
// Firefox is currently the only browser to implement this.
|
||||||
return None;
|
return DOMString::new();
|
||||||
}
|
}
|
||||||
let addr = node.to_trusted_node_address();
|
let addr = node.to_trusted_node_address();
|
||||||
window_from_node(&*self.owner).resolved_style_query(addr, self.pseudo.clone(), property)
|
window_from_node(&*self.owner).resolved_style_query(addr, self.pseudo.clone(), property)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
|
fn get_property_value(&self, id: PropertyId) -> DOMString {
|
||||||
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-length
|
|
||||||
fn Length(&self) -> u32 {
|
|
||||||
let elem = self.owner.upcast::<Element>();
|
|
||||||
let len = match *elem.style_attribute().borrow() {
|
|
||||||
Some(ref lock) => lock.read().declarations.len(),
|
|
||||||
None => 0,
|
|
||||||
};
|
|
||||||
len as u32
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-item
|
|
||||||
fn Item(&self, index: u32) -> DOMString {
|
|
||||||
self.IndexedGetter(index).unwrap_or_default()
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertyvalue
|
|
||||||
fn GetPropertyValue(&self, mut property: DOMString) -> DOMString {
|
|
||||||
if self.readonly {
|
if self.readonly {
|
||||||
// Readonly style declarations are used for getComputedStyle.
|
// Readonly style declarations are used for getComputedStyle.
|
||||||
property.make_ascii_lowercase();
|
return self.get_computed_style(id);
|
||||||
let property = Atom::from(property);
|
|
||||||
return self.get_computed_style(&property).unwrap_or(DOMString::new());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let style_attribute = self.owner.style_attribute().borrow();
|
let style_attribute = self.owner.style_attribute().borrow();
|
||||||
|
@ -120,44 +99,16 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut string = String::new();
|
let mut string = String::new();
|
||||||
style_attribute.property_value_to_css(&property, &mut string).unwrap();
|
style_attribute.property_value_to_css(&id, &mut string).unwrap();
|
||||||
DOMString::from(string)
|
DOMString::from(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertypriority
|
fn set_property(&self, id: PropertyId, value: DOMString, priority: DOMString) -> ErrorResult {
|
||||||
fn GetPropertyPriority(&self, property: DOMString) -> DOMString {
|
|
||||||
let style_attribute = self.owner.style_attribute().borrow();
|
|
||||||
let style_attribute = if let Some(ref lock) = *style_attribute {
|
|
||||||
lock.read()
|
|
||||||
} else {
|
|
||||||
// No style attribute is like an empty style attribute: no matching declaration.
|
|
||||||
return DOMString::new()
|
|
||||||
};
|
|
||||||
|
|
||||||
if style_attribute.property_priority(&property).important() {
|
|
||||||
DOMString::from("important")
|
|
||||||
} else {
|
|
||||||
// Step 4
|
|
||||||
DOMString::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-setproperty
|
|
||||||
fn SetProperty(&self,
|
|
||||||
property: DOMString,
|
|
||||||
value: DOMString,
|
|
||||||
priority: DOMString)
|
|
||||||
-> ErrorResult {
|
|
||||||
// Step 1
|
// Step 1
|
||||||
if self.readonly {
|
if self.readonly {
|
||||||
return Err(Error::NoModificationAllowed);
|
return Err(Error::NoModificationAllowed);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 3
|
|
||||||
if !is_supported_property(&property) {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut style_attribute = self.owner.style_attribute().borrow_mut();
|
let mut style_attribute = self.owner.style_attribute().borrow_mut();
|
||||||
|
|
||||||
if value.is_empty() {
|
if value.is_empty() {
|
||||||
|
@ -171,7 +122,7 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
|
||||||
return Ok(())
|
return Ok(())
|
||||||
};
|
};
|
||||||
|
|
||||||
style_attribute.remove_property(&property);
|
style_attribute.remove_property(&id);
|
||||||
empty = style_attribute.declarations.is_empty()
|
empty = style_attribute.declarations.is_empty()
|
||||||
}
|
}
|
||||||
if empty {
|
if empty {
|
||||||
|
@ -188,7 +139,7 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
|
||||||
// Step 6
|
// Step 6
|
||||||
let window = window_from_node(&*self.owner);
|
let window = window_from_node(&*self.owner);
|
||||||
let declarations =
|
let declarations =
|
||||||
parse_one_declaration(&property, &value, &window.get_url(), window.css_error_reporter(),
|
parse_one_declaration(id, &value, &window.get_url(), window.css_error_reporter(),
|
||||||
ParserContextExtraData::default());
|
ParserContextExtraData::default());
|
||||||
|
|
||||||
// Step 7
|
// Step 7
|
||||||
|
@ -228,6 +179,75 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
|
||||||
node.dirty(NodeDamage::NodeStyleDamaged);
|
node.dirty(NodeDamage::NodeStyleDamaged);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
|
||||||
|
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-length
|
||||||
|
fn Length(&self) -> u32 {
|
||||||
|
let elem = self.owner.upcast::<Element>();
|
||||||
|
let len = match *elem.style_attribute().borrow() {
|
||||||
|
Some(ref lock) => lock.read().declarations.len(),
|
||||||
|
None => 0,
|
||||||
|
};
|
||||||
|
len as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-item
|
||||||
|
fn Item(&self, index: u32) -> DOMString {
|
||||||
|
self.IndexedGetter(index).unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertyvalue
|
||||||
|
fn GetPropertyValue(&self, property: DOMString) -> DOMString {
|
||||||
|
let id = if let Ok(id) = PropertyId::parse(property.into()) {
|
||||||
|
id
|
||||||
|
} else {
|
||||||
|
// Unkwown property
|
||||||
|
return DOMString::new()
|
||||||
|
};
|
||||||
|
self.get_property_value(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertypriority
|
||||||
|
fn GetPropertyPriority(&self, property: DOMString) -> DOMString {
|
||||||
|
let id = if let Ok(id) = PropertyId::parse(property.into()) {
|
||||||
|
id
|
||||||
|
} else {
|
||||||
|
// Unkwown property
|
||||||
|
return DOMString::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
let style_attribute = self.owner.style_attribute().borrow();
|
||||||
|
let style_attribute = if let Some(ref lock) = *style_attribute {
|
||||||
|
lock.read()
|
||||||
|
} else {
|
||||||
|
// No style attribute is like an empty style attribute: no matching declaration.
|
||||||
|
return DOMString::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
if style_attribute.property_priority(&id).important() {
|
||||||
|
DOMString::from("important")
|
||||||
|
} else {
|
||||||
|
// Step 4
|
||||||
|
DOMString::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-setproperty
|
||||||
|
fn SetProperty(&self,
|
||||||
|
property: DOMString,
|
||||||
|
value: DOMString,
|
||||||
|
priority: DOMString)
|
||||||
|
-> ErrorResult {
|
||||||
|
// Step 3
|
||||||
|
let id = if let Ok(id) = PropertyId::parse(property.into()) {
|
||||||
|
id
|
||||||
|
} else {
|
||||||
|
// Unkwown property
|
||||||
|
return Ok(())
|
||||||
|
};
|
||||||
|
self.set_property(id, value, priority)
|
||||||
|
}
|
||||||
|
|
||||||
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-setpropertypriority
|
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-setpropertypriority
|
||||||
fn SetPropertyPriority(&self, property: DOMString, priority: DOMString) -> ErrorResult {
|
fn SetPropertyPriority(&self, property: DOMString, priority: DOMString) -> ErrorResult {
|
||||||
|
@ -237,9 +257,12 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 2 & 3
|
// Step 2 & 3
|
||||||
if !is_supported_property(&property) {
|
let id = if let Ok(id) = PropertyId::parse(property.into()) {
|
||||||
return Ok(());
|
id
|
||||||
}
|
} else {
|
||||||
|
// Unkwown property
|
||||||
|
return Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
// Step 4
|
// Step 4
|
||||||
let importance = match &*priority {
|
let importance = match &*priority {
|
||||||
|
@ -253,10 +276,7 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
|
||||||
let mut style_attribute = lock.write();
|
let mut style_attribute = lock.write();
|
||||||
|
|
||||||
// Step 5 & 6
|
// Step 5 & 6
|
||||||
match Shorthand::from_name(&property) {
|
style_attribute.set_importance(&id, importance);
|
||||||
Some(shorthand) => style_attribute.set_importance(shorthand.longhands(), importance),
|
|
||||||
None => style_attribute.set_importance(&[&*property], importance),
|
|
||||||
}
|
|
||||||
|
|
||||||
self.owner.set_style_attr(style_attribute.to_css_string());
|
self.owner.set_style_attr(style_attribute.to_css_string());
|
||||||
let node = self.owner.upcast::<Node>();
|
let node = self.owner.upcast::<Node>();
|
||||||
|
@ -277,6 +297,13 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
|
||||||
return Err(Error::NoModificationAllowed);
|
return Err(Error::NoModificationAllowed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let id = if let Ok(id) = PropertyId::parse(property.into()) {
|
||||||
|
id
|
||||||
|
} else {
|
||||||
|
// Unkwown property, cannot be there to remove.
|
||||||
|
return Ok(DOMString::new())
|
||||||
|
};
|
||||||
|
|
||||||
let mut style_attribute = self.owner.style_attribute().borrow_mut();
|
let mut style_attribute = self.owner.style_attribute().borrow_mut();
|
||||||
let mut string = String::new();
|
let mut string = String::new();
|
||||||
let empty;
|
let empty;
|
||||||
|
@ -289,10 +316,10 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Step 3
|
// Step 3
|
||||||
style_attribute.property_value_to_css(&property, &mut string).unwrap();
|
style_attribute.property_value_to_css(&id, &mut string).unwrap();
|
||||||
|
|
||||||
// Step 4 & 5
|
// Step 4 & 5
|
||||||
style_attribute.remove_property(&property);
|
style_attribute.remove_property(&id);
|
||||||
self.owner.set_style_attr(style_attribute.to_css_string());
|
self.owner.set_style_attr(style_attribute.to_css_string());
|
||||||
empty = style_attribute.declarations.is_empty()
|
empty = style_attribute.declarations.is_empty()
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,6 +92,7 @@ use std::sync::mpsc::TryRecvError::{Disconnected, Empty};
|
||||||
use style::context::ReflowGoal;
|
use style::context::ReflowGoal;
|
||||||
use style::error_reporting::ParseErrorReporter;
|
use style::error_reporting::ParseErrorReporter;
|
||||||
use style::media_queries;
|
use style::media_queries;
|
||||||
|
use style::properties::PropertyId;
|
||||||
use style::properties::longhands::overflow_x;
|
use style::properties::longhands::overflow_x;
|
||||||
use style::selector_parser::PseudoElement;
|
use style::selector_parser::PseudoElement;
|
||||||
use style::str::HTML_SPACE_CHARACTERS;
|
use style::str::HTML_SPACE_CHARACTERS;
|
||||||
|
@ -1295,16 +1296,16 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolved_style_query(&self,
|
pub fn resolved_style_query(&self,
|
||||||
element: TrustedNodeAddress,
|
element: TrustedNodeAddress,
|
||||||
pseudo: Option<PseudoElement>,
|
pseudo: Option<PseudoElement>,
|
||||||
property: &Atom) -> Option<DOMString> {
|
property: PropertyId) -> DOMString {
|
||||||
if !self.reflow(ReflowGoal::ForScriptQuery,
|
if !self.reflow(ReflowGoal::ForScriptQuery,
|
||||||
ReflowQueryType::ResolvedStyleQuery(element, pseudo, property.clone()),
|
ReflowQueryType::ResolvedStyleQuery(element, pseudo, property),
|
||||||
ReflowReason::Query) {
|
ReflowReason::Query) {
|
||||||
return None;
|
return DOMString::new();
|
||||||
}
|
}
|
||||||
let ResolvedStyleResponse(resolved) = self.layout_rpc.resolved_style();
|
let ResolvedStyleResponse(resolved) = self.layout_rpc.resolved_style();
|
||||||
resolved.map(DOMString::from)
|
DOMString::from(resolved)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn offset_parent_query(&self, node: TrustedNodeAddress) -> (Option<Root<Element>>, Rect<Au>) {
|
pub fn offset_parent_query(&self, node: TrustedNodeAddress) -> (Option<Root<Element>>, Rect<Au>) {
|
||||||
|
|
|
@ -14,11 +14,11 @@ use profile_traits::mem::ReportsChan;
|
||||||
use rpc::LayoutRPC;
|
use rpc::LayoutRPC;
|
||||||
use script_traits::{ConstellationControlMsg, LayoutControlMsg};
|
use script_traits::{ConstellationControlMsg, LayoutControlMsg};
|
||||||
use script_traits::{LayoutMsg as ConstellationMsg, StackingContextScrollState, WindowSizeData};
|
use script_traits::{LayoutMsg as ConstellationMsg, StackingContextScrollState, WindowSizeData};
|
||||||
use servo_atoms::Atom;
|
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::mpsc::{Receiver, Sender};
|
use std::sync::mpsc::{Receiver, Sender};
|
||||||
use style::context::ReflowGoal;
|
use style::context::ReflowGoal;
|
||||||
|
use style::properties::PropertyId;
|
||||||
use style::selector_parser::PseudoElement;
|
use style::selector_parser::PseudoElement;
|
||||||
use style::stylesheets::Stylesheet;
|
use style::stylesheets::Stylesheet;
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ pub enum ReflowQueryType {
|
||||||
NodeScrollRootIdQuery(TrustedNodeAddress),
|
NodeScrollRootIdQuery(TrustedNodeAddress),
|
||||||
NodeGeometryQuery(TrustedNodeAddress),
|
NodeGeometryQuery(TrustedNodeAddress),
|
||||||
NodeScrollGeometryQuery(TrustedNodeAddress),
|
NodeScrollGeometryQuery(TrustedNodeAddress),
|
||||||
ResolvedStyleQuery(TrustedNodeAddress, Option<PseudoElement>, Atom),
|
ResolvedStyleQuery(TrustedNodeAddress, Option<PseudoElement>, PropertyId),
|
||||||
OffsetParentQuery(TrustedNodeAddress),
|
OffsetParentQuery(TrustedNodeAddress),
|
||||||
MarginStyleQuery(TrustedNodeAddress),
|
MarginStyleQuery(TrustedNodeAddress),
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ pub struct HitTestResponse {
|
||||||
pub node_address: Option<UntrustedNodeAddress>,
|
pub node_address: Option<UntrustedNodeAddress>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ResolvedStyleResponse(pub Option<String>);
|
pub struct ResolvedStyleResponse(pub String);
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct OffsetParentResponse {
|
pub struct OffsetParentResponse {
|
||||||
|
|
|
@ -40,6 +40,7 @@ num-traits = "0.1.32"
|
||||||
ordered-float = "0.2.2"
|
ordered-float = "0.2.2"
|
||||||
owning_ref = "0.2.2"
|
owning_ref = "0.2.2"
|
||||||
parking_lot = "0.3.3"
|
parking_lot = "0.3.3"
|
||||||
|
phf = "0.7.20"
|
||||||
quickersort = "2.0.0"
|
quickersort = "2.0.0"
|
||||||
rand = "0.3"
|
rand = "0.3"
|
||||||
rayon = "0.5"
|
rayon = "0.5"
|
||||||
|
@ -64,4 +65,5 @@ version = "1.0"
|
||||||
kernel32-sys = "0.2"
|
kernel32-sys = "0.2"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
phf_codegen = "0.7.20"
|
||||||
walkdir = "0.1"
|
walkdir = "0.1"
|
||||||
|
|
|
@ -3,8 +3,11 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
extern crate walkdir;
|
extern crate walkdir;
|
||||||
|
extern crate phf_codegen;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufWriter, BufReader, BufRead, Write};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::{Command, exit};
|
use std::process::{Command, exit};
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
@ -61,4 +64,21 @@ fn main() {
|
||||||
if !status.success() {
|
if !status.success() {
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let path = Path::new(&env::var("OUT_DIR").unwrap()).join("static_ids.rs");
|
||||||
|
let static_ids = Path::new(&env::var("OUT_DIR").unwrap()).join("static_ids.txt");
|
||||||
|
let mut file = BufWriter::new(File::create(&path).unwrap());
|
||||||
|
let static_ids = BufReader::new(File::open(&static_ids).unwrap());
|
||||||
|
|
||||||
|
write!(&mut file, "static STATIC_IDS: ::phf::Map<&'static str, StaticId> = ").unwrap();
|
||||||
|
let mut map = phf_codegen::Map::new();
|
||||||
|
for result in static_ids.lines() {
|
||||||
|
let line = result.unwrap();
|
||||||
|
let mut split = line.split('\t');
|
||||||
|
let key = split.next().unwrap().to_owned();
|
||||||
|
let value = split.next().unwrap();
|
||||||
|
map.entry(key, value);
|
||||||
|
}
|
||||||
|
map.build(&mut file).unwrap();
|
||||||
|
write!(&mut file, ";\n").unwrap();
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,9 @@ use gecko_bindings::bindings::Gecko_Atomize;
|
||||||
use gecko_bindings::bindings::Gecko_ReleaseAtom;
|
use gecko_bindings::bindings::Gecko_ReleaseAtom;
|
||||||
use gecko_bindings::structs::nsIAtom;
|
use gecko_bindings::structs::nsIAtom;
|
||||||
use heapsize::HeapSizeOf;
|
use heapsize::HeapSizeOf;
|
||||||
use std::ascii::AsciiExt;
|
|
||||||
use std::borrow::{Cow, Borrow};
|
use std::borrow::{Cow, Borrow};
|
||||||
use std::char::{self, DecodeUtf16};
|
use std::char::{self, DecodeUtf16};
|
||||||
use std::fmt;
|
use std::fmt::{self, Write};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::iter::Cloned;
|
use std::iter::Cloned;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
@ -111,14 +110,6 @@ impl WeakAtom {
|
||||||
cb(&owned)
|
cb(&owned)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn eq_str_ignore_ascii_case(&self, s: &str) -> bool {
|
|
||||||
self.chars().map(|r| match r {
|
|
||||||
Ok(c) => c.to_ascii_lowercase() as u32,
|
|
||||||
Err(e) => e.unpaired_surrogate() as u32,
|
|
||||||
}).eq(s.chars().map(|c| c.to_ascii_lowercase() as u32))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_string(&self) -> String {
|
pub fn to_string(&self) -> String {
|
||||||
String::from_utf16(self.as_slice()).unwrap()
|
String::from_utf16(self.as_slice()).unwrap()
|
||||||
|
@ -154,7 +145,7 @@ impl fmt::Debug for WeakAtom {
|
||||||
impl fmt::Display for WeakAtom {
|
impl fmt::Display for WeakAtom {
|
||||||
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
|
||||||
for c in self.chars() {
|
for c in self.chars() {
|
||||||
try!(write!(w, "{}", c.unwrap_or(char::REPLACEMENT_CHARACTER)))
|
try!(w.write_char(c.unwrap_or(char::REPLACEMENT_CHARACTER)))
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, RuleListParser};
|
||||||
use cssparser::{DeclarationListParser, DeclarationParser, parse_one_rule};
|
use cssparser::{DeclarationListParser, DeclarationParser, parse_one_rule};
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use parser::{ParserContext, ParserContextExtraData, log_css_error};
|
use parser::{ParserContext, ParserContextExtraData, log_css_error};
|
||||||
use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock};
|
use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock, PropertyId};
|
||||||
use properties::PropertyDeclarationParseResult;
|
use properties::PropertyDeclarationParseResult;
|
||||||
use properties::animated_properties::TransitionProperty;
|
use properties::animated_properties::TransitionProperty;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -343,8 +343,9 @@ impl<'a, 'b> DeclarationParser for KeyframeDeclarationParser<'a, 'b> {
|
||||||
type Declaration = Vec<PropertyDeclaration>;
|
type Declaration = Vec<PropertyDeclaration>;
|
||||||
|
|
||||||
fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<Vec<PropertyDeclaration>, ()> {
|
fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<Vec<PropertyDeclaration>, ()> {
|
||||||
|
let id = try!(PropertyId::parse(name.into()));
|
||||||
let mut results = Vec::new();
|
let mut results = Vec::new();
|
||||||
match PropertyDeclaration::parse(name, self.context, input, &mut results, true) {
|
match PropertyDeclaration::parse(id, self.context, input, &mut results, true) {
|
||||||
PropertyDeclarationParseResult::ValidOrIgnoredDeclaration => {}
|
PropertyDeclarationParseResult::ValidOrIgnoredDeclaration => {}
|
||||||
_ => return Err(())
|
_ => return Err(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
//#![deny(unsafe_code)]
|
//#![deny(unsafe_code)]
|
||||||
#![allow(unused_unsafe)]
|
#![allow(unused_unsafe)]
|
||||||
|
|
||||||
#![recursion_limit = "500"] // For match_ignore_ascii_case in PropertyDeclaration::parse
|
#![recursion_limit = "500"] // For define_css_keyword_enum! in -moz-appearance
|
||||||
|
|
||||||
extern crate app_units;
|
extern crate app_units;
|
||||||
#[allow(unused_extern_crates)]
|
#[allow(unused_extern_crates)]
|
||||||
|
@ -71,6 +71,7 @@ extern crate num_traits;
|
||||||
extern crate ordered_float;
|
extern crate ordered_float;
|
||||||
extern crate owning_ref;
|
extern crate owning_ref;
|
||||||
extern crate parking_lot;
|
extern crate parking_lot;
|
||||||
|
extern crate phf;
|
||||||
extern crate quickersort;
|
extern crate quickersort;
|
||||||
extern crate rayon;
|
extern crate rayon;
|
||||||
extern crate rustc_serialize;
|
extern crate rustc_serialize;
|
||||||
|
|
|
@ -33,6 +33,7 @@ def main():
|
||||||
rust = render(template, product=product, data=properties, __file__=template)
|
rust = render(template, product=product, data=properties, __file__=template)
|
||||||
if output == "style-crate":
|
if output == "style-crate":
|
||||||
write(os.environ["OUT_DIR"], "properties.rs", rust)
|
write(os.environ["OUT_DIR"], "properties.rs", rust)
|
||||||
|
write(os.environ["OUT_DIR"], "static_ids.txt", static_ids(properties))
|
||||||
if product == "gecko":
|
if product == "gecko":
|
||||||
template = os.path.join(BASE, "gecko.mako.rs")
|
template = os.path.join(BASE, "gecko.mako.rs")
|
||||||
rust = render(template, data=properties)
|
rust = render(template, data=properties)
|
||||||
|
@ -69,6 +70,15 @@ def write(directory, filename, content):
|
||||||
open(os.path.join(directory, filename), "wb").write(content)
|
open(os.path.join(directory, filename), "wb").write(content)
|
||||||
|
|
||||||
|
|
||||||
|
def static_ids(properties):
|
||||||
|
return '\n'.join(
|
||||||
|
"%s\tStaticId::%s(%sId::%s)" % (p.name, kind, kind, p.camel_case)
|
||||||
|
for kind, props in [("Longhand", properties.longhands),
|
||||||
|
("Shorthand", properties.shorthands)]
|
||||||
|
for p in props
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def write_html(properties):
|
def write_html(properties):
|
||||||
properties = dict(
|
properties = dict(
|
||||||
(p.name, {
|
(p.name, {
|
||||||
|
|
|
@ -7,7 +7,6 @@ use cssparser::{Parser, AtRuleParser, DeclarationParser, Delimiter};
|
||||||
use error_reporting::ParseErrorReporter;
|
use error_reporting::ParseErrorReporter;
|
||||||
use parser::{ParserContext, ParserContextExtraData, log_css_error};
|
use parser::{ParserContext, ParserContextExtraData, log_css_error};
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
use std::ascii::AsciiExt;
|
|
||||||
use std::boxed::Box as StdBox;
|
use std::boxed::Box as StdBox;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
|
@ -65,90 +64,94 @@ impl PropertyDeclarationBlock {
|
||||||
self.declarations.len() > self.important_count as usize
|
self.declarations.len() > self.important_count as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, property_name: &str) -> Option< &(PropertyDeclaration, Importance)> {
|
pub fn get(&self, property: PropertyDeclarationId) -> Option< &(PropertyDeclaration, Importance)> {
|
||||||
self.declarations.iter().find(|&&(ref decl, _)| decl.matches(property_name))
|
self.declarations.iter().find(|&&(ref decl, _)| decl.id() == property)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find the value of the given property in this block and serialize it
|
/// Find the value of the given property in this block and serialize it
|
||||||
///
|
///
|
||||||
/// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertyvalue
|
/// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertyvalue
|
||||||
pub fn property_value_to_css<W>(&self, property_name: &str, dest: &mut W) -> fmt::Result
|
pub fn property_value_to_css<W>(&self, property: &PropertyId, dest: &mut W) -> fmt::Result
|
||||||
where W: fmt::Write {
|
where W: fmt::Write {
|
||||||
// Step 1
|
// Step 1: done when parsing a string to PropertyId
|
||||||
let property = property_name.to_ascii_lowercase();
|
|
||||||
|
|
||||||
// Step 2
|
// Step 2
|
||||||
if let Some(shorthand) = Shorthand::from_name(&property) {
|
match property.as_shorthand() {
|
||||||
// Step 2.1
|
Ok(shorthand) => {
|
||||||
let mut list = Vec::new();
|
// Step 2.1
|
||||||
let mut important_count = 0;
|
let mut list = Vec::new();
|
||||||
|
let mut important_count = 0;
|
||||||
|
|
||||||
// Step 2.2
|
// Step 2.2
|
||||||
for longhand in shorthand.longhands() {
|
for &longhand in shorthand.longhands() {
|
||||||
// Step 2.2.1
|
// Step 2.2.1
|
||||||
let declaration = self.get(longhand);
|
let declaration = self.get(PropertyDeclarationId::Longhand(longhand));
|
||||||
|
|
||||||
// Step 2.2.2 & 2.2.3
|
// Step 2.2.2 & 2.2.3
|
||||||
match declaration {
|
match declaration {
|
||||||
Some(&(ref declaration, importance)) => {
|
Some(&(ref declaration, importance)) => {
|
||||||
list.push(declaration);
|
list.push(declaration);
|
||||||
if importance.important() {
|
if importance.important() {
|
||||||
important_count += 1;
|
important_count += 1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3.3.2.4
|
||||||
|
// If there is one or more longhand with important, and one or more
|
||||||
|
// without important, we don't serialize it as a shorthand.
|
||||||
|
if important_count > 0 && important_count != list.len() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2.3
|
||||||
|
// We don't print !important when serializing individual properties,
|
||||||
|
// so we treat this as a normal-importance property
|
||||||
|
let importance = Importance::Normal;
|
||||||
|
let appendable_value = shorthand.get_shorthand_appendable_value(list).unwrap();
|
||||||
|
append_declaration_value(dest, appendable_value, importance)
|
||||||
|
}
|
||||||
|
Err(longhand_or_custom) => {
|
||||||
|
if let Some(&(ref value, _importance)) = self.get(longhand_or_custom) {
|
||||||
|
// Step 3
|
||||||
|
value.to_css(dest)
|
||||||
|
} else {
|
||||||
|
// Step 4
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 3.3.2.4
|
|
||||||
// If there is one or more longhand with important, and one or more
|
|
||||||
// without important, we don't serialize it as a shorthand.
|
|
||||||
if important_count > 0 && important_count != list.len() {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 2.3
|
|
||||||
// We don't print !important when serializing individual properties,
|
|
||||||
// so we treat this as a normal-importance property
|
|
||||||
let importance = Importance::Normal;
|
|
||||||
let appendable_value = shorthand.get_shorthand_appendable_value(list).unwrap();
|
|
||||||
return append_declaration_value(dest, appendable_value, importance)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(&(ref value, _importance)) = self.get(property_name) {
|
|
||||||
// Step 3
|
|
||||||
value.to_css(dest)
|
|
||||||
} else {
|
|
||||||
// Step 4
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertypriority
|
/// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertypriority
|
||||||
pub fn property_priority(&self, property_name: &str) -> Importance {
|
pub fn property_priority(&self, property: &PropertyId) -> Importance {
|
||||||
// Step 1
|
// Step 1: done when parsing a string to PropertyId
|
||||||
let property = property_name.to_ascii_lowercase();
|
|
||||||
|
|
||||||
// Step 2
|
// Step 2
|
||||||
if let Some(shorthand) = Shorthand::from_name(&property) {
|
match property.as_shorthand() {
|
||||||
// Step 2.1 & 2.2 & 2.3
|
Ok(shorthand) => {
|
||||||
if shorthand.longhands().iter().all(|l| {
|
// Step 2.1 & 2.2 & 2.3
|
||||||
self.get(l).map_or(false, |&(_, importance)| importance.important())
|
if shorthand.longhands().iter().all(|&l| {
|
||||||
}) {
|
self.get(PropertyDeclarationId::Longhand(l))
|
||||||
Importance::Important
|
.map_or(false, |&(_, importance)| importance.important())
|
||||||
} else {
|
}) {
|
||||||
Importance::Normal
|
Importance::Important
|
||||||
|
} else {
|
||||||
|
Importance::Normal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(longhand_or_custom) => {
|
||||||
|
// Step 3
|
||||||
|
self.get(longhand_or_custom).map_or(Importance::Normal, |&(_, importance)| importance)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Step 3
|
|
||||||
self.get(&property).map_or(Importance::Normal, |&(_, importance)| importance)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_parsed_declaration(&mut self, declaration: PropertyDeclaration,
|
pub fn set_parsed_declaration(&mut self, declaration: PropertyDeclaration, importance: Importance) {
|
||||||
importance: Importance) {
|
|
||||||
for slot in &mut *self.declarations {
|
for slot in &mut *self.declarations {
|
||||||
if slot.0.name() == declaration.name() {
|
if slot.0.id() == declaration.id() {
|
||||||
match (slot.1, importance) {
|
match (slot.1, importance) {
|
||||||
(Importance::Normal, Importance::Important) => {
|
(Importance::Normal, Importance::Important) => {
|
||||||
self.important_count += 1;
|
self.important_count += 1;
|
||||||
|
@ -169,9 +172,9 @@ impl PropertyDeclarationBlock {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_importance(&mut self, property_names: &[&str], new_importance: Importance) {
|
pub fn set_importance(&mut self, property: &PropertyId, new_importance: Importance) {
|
||||||
for &mut (ref declaration, ref mut importance) in &mut self.declarations {
|
for &mut (ref declaration, ref mut importance) in &mut self.declarations {
|
||||||
if property_names.iter().any(|p| declaration.matches(p)) {
|
if declaration.id().is_or_is_longhand_of(property) {
|
||||||
match (*importance, new_importance) {
|
match (*importance, new_importance) {
|
||||||
(Importance::Normal, Importance::Important) => {
|
(Importance::Normal, Importance::Important) => {
|
||||||
self.important_count += 1;
|
self.important_count += 1;
|
||||||
|
@ -187,44 +190,34 @@ impl PropertyDeclarationBlock {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-removeproperty
|
/// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-removeproperty
|
||||||
pub fn remove_property(&mut self, property_name: &str) {
|
pub fn remove_property(&mut self, property: &PropertyId) {
|
||||||
// Step 2
|
|
||||||
let property = property_name.to_ascii_lowercase();
|
|
||||||
|
|
||||||
match Shorthand::from_name(&property) {
|
|
||||||
// Step 4
|
|
||||||
Some(shorthand) => self.remove_longhands(shorthand.longhands()),
|
|
||||||
// Step 5
|
|
||||||
None => self.remove_longhands(&[&*property]),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove_longhands(&mut self, names: &[&str]) {
|
|
||||||
let important_count = &mut self.important_count;
|
let important_count = &mut self.important_count;
|
||||||
self.declarations.retain(|&(ref declaration, importance)| {
|
self.declarations.retain(|&(ref declaration, importance)| {
|
||||||
let retain = !names.iter().any(|n| declaration.matches(n));
|
let remove = declaration.id().is_or_is_longhand_of(property);
|
||||||
if !retain && importance.important() {
|
if remove && importance.important() {
|
||||||
*important_count -= 1
|
*important_count -= 1
|
||||||
}
|
}
|
||||||
retain
|
!remove
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Take a declaration block known to contain a single property and serialize it.
|
/// Take a declaration block known to contain a single property and serialize it.
|
||||||
pub fn single_value_to_css<W>(&self, property_name: &str, dest: &mut W) -> fmt::Result
|
pub fn single_value_to_css<W>(&self, property: &PropertyId, dest: &mut W) -> fmt::Result
|
||||||
where W: fmt::Write {
|
where W: fmt::Write {
|
||||||
match self.declarations.len() {
|
match property.as_shorthand() {
|
||||||
0 => Err(fmt::Error),
|
Err(_longhand_or_custom) => {
|
||||||
1 if self.declarations[0].0.name().eq_str_ignore_ascii_case(property_name) => {
|
if self.declarations.len() == 1 {
|
||||||
self.declarations[0].0.to_css(dest)
|
self.declarations[0].0.to_css(dest)
|
||||||
|
} else {
|
||||||
|
Err(fmt::Error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
Ok(shorthand) => {
|
||||||
// we use this function because a closure won't be `Clone`
|
// we use this function because a closure won't be `Clone`
|
||||||
fn get_declaration(dec: &(PropertyDeclaration, Importance))
|
fn get_declaration(dec: &(PropertyDeclaration, Importance))
|
||||||
-> &PropertyDeclaration {
|
-> &PropertyDeclaration {
|
||||||
&dec.0
|
&dec.0
|
||||||
}
|
}
|
||||||
let shorthand = try!(Shorthand::from_name(property_name).ok_or(fmt::Error));
|
|
||||||
if !self.declarations.iter().all(|decl| decl.0.shorthands().contains(&shorthand)) {
|
if !self.declarations.iter().all(|decl| decl.0.shorthands().contains(&shorthand)) {
|
||||||
return Err(fmt::Error)
|
return Err(fmt::Error)
|
||||||
}
|
}
|
||||||
|
@ -254,7 +247,7 @@ impl ToCss for PropertyDeclarationBlock {
|
||||||
// Step 3
|
// Step 3
|
||||||
for &(ref declaration, importance) in &*self.declarations {
|
for &(ref declaration, importance) in &*self.declarations {
|
||||||
// Step 3.1
|
// Step 3.1
|
||||||
let property = declaration.name();
|
let property = declaration.id();
|
||||||
|
|
||||||
// Step 3.2
|
// Step 3.2
|
||||||
if already_serialized.contains(&property) {
|
if already_serialized.contains(&property) {
|
||||||
|
@ -266,11 +259,11 @@ impl ToCss for PropertyDeclarationBlock {
|
||||||
if !shorthands.is_empty() {
|
if !shorthands.is_empty() {
|
||||||
// Step 3.3.1
|
// Step 3.3.1
|
||||||
let mut longhands = self.declarations.iter()
|
let mut longhands = self.declarations.iter()
|
||||||
.filter(|d| !already_serialized.contains(&d.0.name()))
|
.filter(|d| !already_serialized.contains(&d.0.id()))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
// Step 3.3.2
|
// Step 3.3.2
|
||||||
for shorthand in shorthands {
|
for &shorthand in shorthands {
|
||||||
let properties = shorthand.longhands();
|
let properties = shorthand.longhands();
|
||||||
|
|
||||||
// Substep 2 & 3
|
// Substep 2 & 3
|
||||||
|
@ -278,8 +271,7 @@ impl ToCss for PropertyDeclarationBlock {
|
||||||
let mut important_count = 0;
|
let mut important_count = 0;
|
||||||
|
|
||||||
for &&(ref longhand, longhand_importance) in longhands.iter() {
|
for &&(ref longhand, longhand_importance) in longhands.iter() {
|
||||||
let longhand_name = longhand.name();
|
if longhand.id().is_longhand_of(shorthand) {
|
||||||
if properties.iter().any(|p| &longhand_name == *p) {
|
|
||||||
current_longhands.push(longhand);
|
current_longhands.push(longhand);
|
||||||
if longhand_importance.important() {
|
if longhand_importance.important() {
|
||||||
important_count += 1;
|
important_count += 1;
|
||||||
|
@ -325,7 +317,7 @@ impl ToCss for PropertyDeclarationBlock {
|
||||||
|
|
||||||
for current_longhand in current_longhands {
|
for current_longhand in current_longhands {
|
||||||
// Substep 9
|
// Substep 9
|
||||||
already_serialized.push(current_longhand.name());
|
already_serialized.push(current_longhand.id());
|
||||||
let index_to_remove = longhands.iter().position(|l| l.0 == *current_longhand);
|
let index_to_remove = longhands.iter().position(|l| l.0 == *current_longhand);
|
||||||
if let Some(index) = index_to_remove {
|
if let Some(index) = index_to_remove {
|
||||||
// Substep 10
|
// Substep 10
|
||||||
|
@ -348,9 +340,9 @@ impl ToCss for PropertyDeclarationBlock {
|
||||||
// "error: unable to infer enough type information about `_`;
|
// "error: unable to infer enough type information about `_`;
|
||||||
// type annotations or generic parameter binding required [E0282]"
|
// type annotations or generic parameter binding required [E0282]"
|
||||||
// Use the same type as earlier call to reuse generated code.
|
// Use the same type as earlier call to reuse generated code.
|
||||||
try!(append_serialization::<W, Cloned<slice::Iter< &PropertyDeclaration>>>(
|
try!(append_serialization::<W, Cloned<slice::Iter< &PropertyDeclaration>>, _>(
|
||||||
dest,
|
dest,
|
||||||
&property.to_string(),
|
&property,
|
||||||
AppendableValue::Declaration(declaration),
|
AppendableValue::Declaration(declaration),
|
||||||
importance,
|
importance,
|
||||||
&mut is_first_serialization));
|
&mut is_first_serialization));
|
||||||
|
@ -367,7 +359,7 @@ impl ToCss for PropertyDeclarationBlock {
|
||||||
pub enum AppendableValue<'a, I>
|
pub enum AppendableValue<'a, I>
|
||||||
where I: Iterator<Item=&'a PropertyDeclaration> {
|
where I: Iterator<Item=&'a PropertyDeclaration> {
|
||||||
Declaration(&'a PropertyDeclaration),
|
Declaration(&'a PropertyDeclaration),
|
||||||
DeclarationsForShorthand(Shorthand, I),
|
DeclarationsForShorthand(ShorthandId, I),
|
||||||
Css(&'a str)
|
Css(&'a str)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,13 +399,15 @@ pub fn append_declaration_value<'a, W, I>
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn append_serialization<'a, W, I>(dest: &mut W,
|
pub fn append_serialization<'a, W, I, N>(dest: &mut W,
|
||||||
property_name: &str,
|
property_name: &N,
|
||||||
appendable_value: AppendableValue<'a, I>,
|
appendable_value: AppendableValue<'a, I>,
|
||||||
importance: Importance,
|
importance: Importance,
|
||||||
is_first_serialization: &mut bool)
|
is_first_serialization: &mut bool)
|
||||||
-> fmt::Result
|
-> fmt::Result
|
||||||
where W: fmt::Write, I: Iterator<Item=&'a PropertyDeclaration> {
|
where W: fmt::Write,
|
||||||
|
I: Iterator<Item=&'a PropertyDeclaration>,
|
||||||
|
N: ToCss {
|
||||||
try!(handle_first_serialization(dest, is_first_serialization));
|
try!(handle_first_serialization(dest, is_first_serialization));
|
||||||
|
|
||||||
// Overflow does not behave like a normal shorthand. When overflow-x and overflow-y are not of equal
|
// Overflow does not behave like a normal shorthand. When overflow-x and overflow-y are not of equal
|
||||||
|
@ -422,7 +416,8 @@ pub fn append_serialization<'a, W, I>(dest: &mut W,
|
||||||
return append_declaration_value(dest, appendable_value, importance);
|
return append_declaration_value(dest, appendable_value, importance);
|
||||||
}
|
}
|
||||||
|
|
||||||
try!(write!(dest, "{}:", property_name));
|
try!(property_name.to_css(dest));
|
||||||
|
try!(dest.write_char(':'));
|
||||||
|
|
||||||
// for normal parsed values, add a space between key: and value
|
// for normal parsed values, add a space between key: and value
|
||||||
match &appendable_value {
|
match &appendable_value {
|
||||||
|
@ -451,7 +446,7 @@ pub fn parse_style_attribute(input: &str,
|
||||||
parse_property_declaration_list(&context, &mut Parser::new(input))
|
parse_property_declaration_list(&context, &mut Parser::new(input))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_one_declaration(name: &str,
|
pub fn parse_one_declaration(id: PropertyId,
|
||||||
input: &str,
|
input: &str,
|
||||||
base_url: &ServoUrl,
|
base_url: &ServoUrl,
|
||||||
error_reporter: StdBox<ParseErrorReporter + Send>,
|
error_reporter: StdBox<ParseErrorReporter + Send>,
|
||||||
|
@ -459,7 +454,7 @@ pub fn parse_one_declaration(name: &str,
|
||||||
-> Result<Vec<PropertyDeclaration>, ()> {
|
-> Result<Vec<PropertyDeclaration>, ()> {
|
||||||
let context = ParserContext::new_with_extra_data(Origin::Author, base_url, error_reporter, extra_data);
|
let context = ParserContext::new_with_extra_data(Origin::Author, base_url, error_reporter, extra_data);
|
||||||
let mut results = vec![];
|
let mut results = vec![];
|
||||||
match PropertyDeclaration::parse(name, &context, &mut Parser::new(input), &mut results, false) {
|
match PropertyDeclaration::parse(id, &context, &mut Parser::new(input), &mut results, false) {
|
||||||
PropertyDeclarationParseResult::ValidOrIgnoredDeclaration => Ok(results),
|
PropertyDeclarationParseResult::ValidOrIgnoredDeclaration => Ok(results),
|
||||||
_ => Err(())
|
_ => Err(())
|
||||||
}
|
}
|
||||||
|
@ -482,9 +477,10 @@ impl<'a, 'b> DeclarationParser for PropertyDeclarationParser<'a, 'b> {
|
||||||
|
|
||||||
fn parse_value(&mut self, name: &str, input: &mut Parser)
|
fn parse_value(&mut self, name: &str, input: &mut Parser)
|
||||||
-> Result<(Vec<PropertyDeclaration>, Importance), ()> {
|
-> Result<(Vec<PropertyDeclaration>, Importance), ()> {
|
||||||
|
let id = try!(PropertyId::parse(name.into()));
|
||||||
let mut results = vec![];
|
let mut results = vec![];
|
||||||
try!(input.parse_until_before(Delimiter::Bang, |input| {
|
try!(input.parse_until_before(Delimiter::Bang, |input| {
|
||||||
match PropertyDeclaration::parse(name, self.context, input, &mut results, false) {
|
match PropertyDeclaration::parse(id, self.context, input, &mut results, false) {
|
||||||
PropertyDeclarationParseResult::ValidOrIgnoredDeclaration => Ok(()),
|
PropertyDeclarationParseResult::ValidOrIgnoredDeclaration => Ok(()),
|
||||||
_ => Err(())
|
_ => Err(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@
|
||||||
pub mod single_value {
|
pub mod single_value {
|
||||||
use cssparser::Parser;
|
use cssparser::Parser;
|
||||||
use parser::{Parse, ParserContext, ParserContextExtraData};
|
use parser::{Parse, ParserContext, ParserContextExtraData};
|
||||||
use properties::{CSSWideKeyword, DeclaredValue, Shorthand};
|
use properties::{CSSWideKeyword, DeclaredValue, ShorthandId};
|
||||||
use values::computed::{Context, ToComputedValue};
|
use values::computed::{Context, ToComputedValue};
|
||||||
use values::{computed, specified};
|
use values::{computed, specified};
|
||||||
${caller.body()}
|
${caller.body()}
|
||||||
|
@ -182,7 +182,7 @@
|
||||||
% if not property.derived_from:
|
% if not property.derived_from:
|
||||||
use cssparser::Parser;
|
use cssparser::Parser;
|
||||||
use parser::{Parse, ParserContext, ParserContextExtraData};
|
use parser::{Parse, ParserContext, ParserContextExtraData};
|
||||||
use properties::{CSSWideKeyword, DeclaredValue, Shorthand};
|
use properties::{CSSWideKeyword, DeclaredValue, ShorthandId};
|
||||||
% endif
|
% endif
|
||||||
use values::{Auto, Either, None_, Normal};
|
use values::{Auto, Either, None_, Normal};
|
||||||
use cascade_info::CascadeInfo;
|
use cascade_info::CascadeInfo;
|
||||||
|
@ -380,7 +380,7 @@
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use cssparser::Parser;
|
use cssparser::Parser;
|
||||||
use parser::ParserContext;
|
use parser::ParserContext;
|
||||||
use properties::{longhands, PropertyDeclaration, DeclaredValue, Shorthand};
|
use properties::{longhands, PropertyDeclaration, DeclaredValue, ShorthandId};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
|
|
||||||
|
@ -500,7 +500,7 @@
|
||||||
css: css.clone().into_owned(),
|
css: css.clone().into_owned(),
|
||||||
first_token_type: first_token_type,
|
first_token_type: first_token_type,
|
||||||
base_url: context.base_url.clone(),
|
base_url: context.base_url.clone(),
|
||||||
from_shorthand: Some(Shorthand::${shorthand.camel_case}),
|
from_shorthand: Some(ShorthandId::${shorthand.camel_case}),
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
% endfor
|
% endfor
|
||||||
|
|
|
@ -10,13 +10,12 @@
|
||||||
|
|
||||||
<%namespace name="helpers" file="/helpers.mako.rs" />
|
<%namespace name="helpers" file="/helpers.mako.rs" />
|
||||||
|
|
||||||
use std::ascii::AsciiExt;
|
use std::borrow::Cow;
|
||||||
use std::boxed::Box as StdBox;
|
use std::boxed::Box as StdBox;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use Atom;
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
#[cfg(feature = "servo")] use cssparser::{Color as CSSParserColor, RGBA};
|
#[cfg(feature = "servo")] use cssparser::{Color as CSSParserColor, RGBA};
|
||||||
use cssparser::{Parser, TokenSerializationType};
|
use cssparser::{Parser, TokenSerializationType};
|
||||||
|
@ -25,6 +24,7 @@ use error_reporting::ParseErrorReporter;
|
||||||
use euclid::size::Size2D;
|
use euclid::size::Size2D;
|
||||||
use computed_values;
|
use computed_values;
|
||||||
use font_metrics::FontMetricsProvider;
|
use font_metrics::FontMetricsProvider;
|
||||||
|
#[cfg(feature = "gecko")] use gecko_bindings::structs::nsCSSPropertyID;
|
||||||
#[cfg(feature = "servo")] use logical_geometry::{LogicalMargin, PhysicalSide};
|
#[cfg(feature = "servo")] use logical_geometry::{LogicalMargin, PhysicalSide};
|
||||||
use logical_geometry::WritingMode;
|
use logical_geometry::WritingMode;
|
||||||
use parser::{Parse, ParserContext, ParserContextExtraData};
|
use parser::{Parse, ParserContext, ParserContextExtraData};
|
||||||
|
@ -40,6 +40,12 @@ use rule_tree::StrongRuleNode;
|
||||||
use self::property_bit_field::PropertyBitField;
|
use self::property_bit_field::PropertyBitField;
|
||||||
pub use self::declaration_block::*;
|
pub use self::declaration_block::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! property_name {
|
||||||
|
($s: tt) => { atom!($s) }
|
||||||
|
}
|
||||||
|
|
||||||
<%!
|
<%!
|
||||||
from data import Method, Keyword, to_rust_ident
|
from data import Method, Keyword, to_rust_ident
|
||||||
import os.path
|
import os.path
|
||||||
|
@ -242,7 +248,7 @@ mod property_bit_field {
|
||||||
css: &String,
|
css: &String,
|
||||||
first_token_type: TokenSerializationType,
|
first_token_type: TokenSerializationType,
|
||||||
base_url: &ServoUrl,
|
base_url: &ServoUrl,
|
||||||
from_shorthand: Option<Shorthand>,
|
from_shorthand: Option<ShorthandId>,
|
||||||
custom_properties: &Option<Arc<::custom_properties::ComputedValuesMap>>,
|
custom_properties: &Option<Arc<::custom_properties::ComputedValuesMap>>,
|
||||||
f: F,
|
f: F,
|
||||||
error_reporter: &mut StdBox<ParseErrorReporter + Send>,
|
error_reporter: &mut StdBox<ParseErrorReporter + Send>,
|
||||||
|
@ -265,7 +271,7 @@ mod property_bit_field {
|
||||||
}
|
}
|
||||||
% for shorthand in data.shorthands:
|
% for shorthand in data.shorthands:
|
||||||
% if property in shorthand.sub_properties:
|
% if property in shorthand.sub_properties:
|
||||||
Some(Shorthand::${shorthand.camel_case}) => {
|
Some(ShorthandId::${shorthand.camel_case}) => {
|
||||||
shorthands::${shorthand.ident}::parse_value(&context, input)
|
shorthands::${shorthand.ident}::parse_value(&context, input)
|
||||||
.map(|result| match result.${property.ident} {
|
.map(|result| match result.${property.ident} {
|
||||||
Some(value) => DeclaredValue::Value(value),
|
Some(value) => DeclaredValue::Value(value),
|
||||||
|
@ -378,41 +384,56 @@ impl Parse for CSSWideKeyword {
|
||||||
|
|
||||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
pub enum Shorthand {
|
pub enum LonghandId {
|
||||||
|
% for i, property in enumerate(data.longhands):
|
||||||
|
${property.camel_case} = ${i},
|
||||||
|
% endfor
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LonghandId {
|
||||||
|
pub fn name(&self) -> &'static str {
|
||||||
|
match *self {
|
||||||
|
% for property in data.longhands:
|
||||||
|
LonghandId::${property.camel_case} => "${property.name}",
|
||||||
|
% endfor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
pub enum ShorthandId {
|
||||||
% for property in data.shorthands:
|
% for property in data.shorthands:
|
||||||
${property.camel_case},
|
${property.camel_case},
|
||||||
% endfor
|
% endfor
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Shorthand {
|
impl ToCss for ShorthandId {
|
||||||
pub fn from_name(name: &str) -> Option<Shorthand> {
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
match_ignore_ascii_case! { name,
|
dest.write_str(self.name())
|
||||||
% for property in data.shorthands:
|
|
||||||
"${property.name}" => Some(Shorthand::${property.camel_case}),
|
|
||||||
% endfor
|
|
||||||
_ => None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShorthandId {
|
||||||
pub fn name(&self) -> &'static str {
|
pub fn name(&self) -> &'static str {
|
||||||
match *self {
|
match *self {
|
||||||
% for property in data.shorthands:
|
% for property in data.shorthands:
|
||||||
Shorthand::${property.camel_case} => "${property.name}",
|
ShorthandId::${property.camel_case} => "${property.name}",
|
||||||
% endfor
|
% endfor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn longhands(&self) -> &'static [&'static str] {
|
pub fn longhands(&self) -> &'static [LonghandId] {
|
||||||
% for property in data.shorthands:
|
% for property in data.shorthands:
|
||||||
static ${property.ident.upper()}: &'static [&'static str] = &[
|
static ${property.ident.upper()}: &'static [LonghandId] = &[
|
||||||
% for sub in property.sub_properties:
|
% for sub in property.sub_properties:
|
||||||
"${sub.name}",
|
LonghandId::${sub.camel_case},
|
||||||
% endfor
|
% endfor
|
||||||
];
|
];
|
||||||
% endfor
|
% endfor
|
||||||
match *self {
|
match *self {
|
||||||
% for property in data.shorthands:
|
% for property in data.shorthands:
|
||||||
Shorthand::${property.camel_case} => ${property.ident.upper()},
|
ShorthandId::${property.camel_case} => ${property.ident.upper()},
|
||||||
% endfor
|
% endfor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -421,7 +442,7 @@ impl Shorthand {
|
||||||
where W: fmt::Write, I: Iterator<Item=&'a PropertyDeclaration> {
|
where W: fmt::Write, I: Iterator<Item=&'a PropertyDeclaration> {
|
||||||
match *self {
|
match *self {
|
||||||
% for property in data.shorthands:
|
% for property in data.shorthands:
|
||||||
Shorthand::${property.camel_case} => {
|
ShorthandId::${property.camel_case} => {
|
||||||
match shorthands::${property.ident}::LonghandsToSerialize::from_iter(declarations) {
|
match shorthands::${property.ident}::LonghandsToSerialize::from_iter(declarations) {
|
||||||
Ok(longhands) => longhands.to_css(dest),
|
Ok(longhands) => longhands.to_css(dest),
|
||||||
Err(_) => Err(fmt::Error)
|
Err(_) => Err(fmt::Error)
|
||||||
|
@ -443,11 +464,9 @@ impl Shorthand {
|
||||||
match self.get_shorthand_appendable_value(declarations) {
|
match self.get_shorthand_appendable_value(declarations) {
|
||||||
None => Ok(false),
|
None => Ok(false),
|
||||||
Some(appendable_value) => {
|
Some(appendable_value) => {
|
||||||
let property_name = self.name();
|
|
||||||
|
|
||||||
append_serialization(
|
append_serialization(
|
||||||
dest,
|
dest,
|
||||||
property_name,
|
&self,
|
||||||
appendable_value,
|
appendable_value,
|
||||||
importance,
|
importance,
|
||||||
is_first_serialization
|
is_first_serialization
|
||||||
|
@ -496,7 +515,7 @@ pub enum DeclaredValue<T> {
|
||||||
css: String,
|
css: String,
|
||||||
first_token_type: TokenSerializationType,
|
first_token_type: TokenSerializationType,
|
||||||
base_url: ServoUrl,
|
base_url: ServoUrl,
|
||||||
from_shorthand: Option<Shorthand>,
|
from_shorthand: Option<ShorthandId>,
|
||||||
},
|
},
|
||||||
Initial,
|
Initial,
|
||||||
Inherit,
|
Inherit,
|
||||||
|
@ -533,6 +552,133 @@ impl<T: ToCss> ToCss for DeclaredValue<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Clone)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
pub enum PropertyDeclarationId<'a> {
|
||||||
|
Longhand(LonghandId),
|
||||||
|
Custom(&'a ::custom_properties::Name),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ToCss for PropertyDeclarationId<'a> {
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
match *self {
|
||||||
|
PropertyDeclarationId::Longhand(id) => dest.write_str(id.name()),
|
||||||
|
PropertyDeclarationId::Custom(name) => write!(dest, "--{}", name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PropertyDeclarationId<'a> {
|
||||||
|
pub fn is_or_is_longhand_of(&self, other: &PropertyId) -> bool {
|
||||||
|
match *self {
|
||||||
|
PropertyDeclarationId::Longhand(id) => {
|
||||||
|
match *other {
|
||||||
|
PropertyId::Longhand(other_id) => id == other_id,
|
||||||
|
PropertyId::Shorthand(shorthand) => shorthand.longhands().contains(&id),
|
||||||
|
PropertyId::Custom(_) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PropertyDeclarationId::Custom(name) => {
|
||||||
|
matches!(*other, PropertyId::Custom(ref other_name) if name == other_name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_longhand_of(&self, shorthand: ShorthandId) -> bool {
|
||||||
|
match *self {
|
||||||
|
PropertyDeclarationId::Longhand(ref id) => shorthand.longhands().contains(id),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq, Clone)]
|
||||||
|
pub enum PropertyId {
|
||||||
|
Longhand(LonghandId),
|
||||||
|
Shorthand(ShorthandId),
|
||||||
|
Custom(::custom_properties::Name),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for PropertyId {
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
self.to_css(formatter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToCss for PropertyId {
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
match *self {
|
||||||
|
PropertyId::Longhand(id) => dest.write_str(id.name()),
|
||||||
|
PropertyId::Shorthand(id) => dest.write_str(id.name()),
|
||||||
|
PropertyId::Custom(ref name) => write!(dest, "--{}", name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME(https://github.com/rust-lang/rust/issues/33156): remove this enum and use PropertyId
|
||||||
|
// when stable Rust allows destructors in statics.
|
||||||
|
enum StaticId {
|
||||||
|
Longhand(LonghandId),
|
||||||
|
Shorthand(ShorthandId),
|
||||||
|
}
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/static_ids.rs"));
|
||||||
|
|
||||||
|
impl PropertyId {
|
||||||
|
/// Returns Err(()) for unknown non-custom properties
|
||||||
|
pub fn parse(s: Cow<str>) -> Result<Self, ()> {
|
||||||
|
if let Ok(name) = ::custom_properties::parse_name(&s) {
|
||||||
|
return Ok(PropertyId::Custom(::custom_properties::Name::from(name)))
|
||||||
|
}
|
||||||
|
|
||||||
|
let lower_case = ::str::cow_into_ascii_lowercase(s);
|
||||||
|
match STATIC_IDS.get(&*lower_case) {
|
||||||
|
Some(&StaticId::Longhand(id)) => Ok(PropertyId::Longhand(id)),
|
||||||
|
Some(&StaticId::Shorthand(id)) => Ok(PropertyId::Shorthand(id)),
|
||||||
|
None => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
pub fn from_nscsspropertyid(id: nsCSSPropertyID) -> Result<Self, ()> {
|
||||||
|
use gecko_bindings::structs::*;
|
||||||
|
<%
|
||||||
|
def to_nscsspropertyid(ident):
|
||||||
|
if ident == "word_wrap":
|
||||||
|
return "nsCSSPropertyID_eCSSPropertyAlias_WordWrap"
|
||||||
|
|
||||||
|
if ident == "float":
|
||||||
|
ident = "float_"
|
||||||
|
elif "outline_radius" in ident:
|
||||||
|
ident = ident.replace("right", "Right").replace("left", "Left")
|
||||||
|
elif ident.startswith("_moz_"):
|
||||||
|
ident = ident[len("_moz_"):]
|
||||||
|
return "nsCSSPropertyID::eCSSProperty_" + ident
|
||||||
|
%>
|
||||||
|
match id {
|
||||||
|
% for property in data.longhands:
|
||||||
|
${to_nscsspropertyid(property.ident)} => {
|
||||||
|
Ok(PropertyId::Longhand(LonghandId::${property.camel_case}))
|
||||||
|
}
|
||||||
|
% endfor
|
||||||
|
% for property in data.shorthands:
|
||||||
|
${to_nscsspropertyid(property.ident)} => {
|
||||||
|
Ok(PropertyId::Shorthand(ShorthandId::${property.camel_case}))
|
||||||
|
}
|
||||||
|
% endfor
|
||||||
|
_ => Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_shorthand(&self) -> Result<ShorthandId, PropertyDeclarationId> {
|
||||||
|
match *self {
|
||||||
|
PropertyId::Shorthand(id) => Ok(id),
|
||||||
|
PropertyId::Longhand(id) => Err(PropertyDeclarationId::Longhand(id)),
|
||||||
|
PropertyId::Custom(ref name) => Err(PropertyDeclarationId::Custom(name)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone)]
|
#[derive(PartialEq, Clone)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
pub enum PropertyDeclaration {
|
pub enum PropertyDeclaration {
|
||||||
|
@ -566,51 +712,10 @@ pub enum PropertyDeclarationParseResult {
|
||||||
ValidOrIgnoredDeclaration,
|
ValidOrIgnoredDeclaration,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Clone)]
|
|
||||||
pub enum PropertyDeclarationName {
|
|
||||||
Longhand(&'static str),
|
|
||||||
Custom(::custom_properties::Name),
|
|
||||||
Internal
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PropertyDeclarationName {
|
|
||||||
pub fn eq_str_ignore_ascii_case(&self, other: &str) -> bool {
|
|
||||||
match *self {
|
|
||||||
PropertyDeclarationName::Longhand(s) => s.eq_ignore_ascii_case(other),
|
|
||||||
PropertyDeclarationName::Custom(ref n) => n.eq_str_ignore_ascii_case(other),
|
|
||||||
PropertyDeclarationName::Internal => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq<str> for PropertyDeclarationName {
|
|
||||||
fn eq(&self, other: &str) -> bool {
|
|
||||||
match *self {
|
|
||||||
PropertyDeclarationName::Longhand(n) => n == other,
|
|
||||||
PropertyDeclarationName::Custom(ref n) => {
|
|
||||||
n.with_str(|s| ::custom_properties::parse_name(other) == Ok(s))
|
|
||||||
}
|
|
||||||
PropertyDeclarationName::Internal => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for PropertyDeclarationName {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match *self {
|
|
||||||
PropertyDeclarationName::Longhand(n) => f.write_str(n),
|
|
||||||
PropertyDeclarationName::Custom(ref n) => {
|
|
||||||
try!(f.write_str("--"));
|
|
||||||
n.with_str(|s| f.write_str(s))
|
|
||||||
}
|
|
||||||
PropertyDeclarationName::Internal => Ok(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for PropertyDeclaration {
|
impl fmt::Debug for PropertyDeclaration {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
try!(write!(f, "{}: ", self.name()));
|
try!(self.id().to_css(f));
|
||||||
|
try!(f.write_str(": "));
|
||||||
match *self {
|
match *self {
|
||||||
% for property in data.longhands:
|
% for property in data.longhands:
|
||||||
% if not property.derived_from:
|
% if not property.derived_from:
|
||||||
|
@ -643,45 +748,20 @@ impl ToCss for PropertyDeclaration {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PropertyDeclaration {
|
impl PropertyDeclaration {
|
||||||
pub fn name(&self) -> PropertyDeclarationName {
|
pub fn id(&self) -> PropertyDeclarationId {
|
||||||
match *self {
|
match *self {
|
||||||
% for property in data.longhands:
|
% for property in data.longhands:
|
||||||
PropertyDeclaration::${property.camel_case}(..) =>
|
PropertyDeclaration::${property.camel_case}(..) => {
|
||||||
% if not property.derived_from:
|
PropertyDeclarationId::Longhand(LonghandId::${property.camel_case})
|
||||||
PropertyDeclarationName::Longhand("${property.name}"),
|
}
|
||||||
% else:
|
|
||||||
PropertyDeclarationName::Internal,
|
|
||||||
% endif
|
|
||||||
% endfor
|
% endfor
|
||||||
PropertyDeclaration::Custom(ref name, _) => {
|
PropertyDeclaration::Custom(ref name, _) => {
|
||||||
PropertyDeclarationName::Custom(name.clone())
|
PropertyDeclarationId::Custom(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
pub fn with_variables_from_shorthand(&self, shorthand: ShorthandId) -> Option< &str> {
|
||||||
pub fn discriminant_value(&self) -> usize {
|
|
||||||
match *self {
|
|
||||||
% for i, property in enumerate(data.longhands):
|
|
||||||
PropertyDeclaration::${property.camel_case}(..) => ${i},
|
|
||||||
% endfor
|
|
||||||
PropertyDeclaration::Custom(..) => ${len(data.longhands)}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn value(&self) -> String {
|
|
||||||
let mut value = String::new();
|
|
||||||
if let Err(_) = self.to_css(&mut value) {
|
|
||||||
panic!("unsupported property declaration: {}", self.name());
|
|
||||||
}
|
|
||||||
|
|
||||||
value
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If this is a pending-substitution value from the given shorthand, return that value
|
|
||||||
// Extra space here because < seems to be removed by Mako when immediately followed by &.
|
|
||||||
// ↓
|
|
||||||
pub fn with_variables_from_shorthand(&self, shorthand: Shorthand) -> Option< &str> {
|
|
||||||
match *self {
|
match *self {
|
||||||
% for property in data.longhands:
|
% for property in data.longhands:
|
||||||
PropertyDeclaration::${property.camel_case}(ref value) => match *value {
|
PropertyDeclaration::${property.camel_case}(ref value) => match *value {
|
||||||
|
@ -727,49 +807,34 @@ impl PropertyDeclaration {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn matches(&self, name: &str) -> bool {
|
|
||||||
match *self {
|
|
||||||
% for property in data.longhands:
|
|
||||||
PropertyDeclaration::${property.camel_case}(..) =>
|
|
||||||
% if not property.derived_from:
|
|
||||||
name.eq_ignore_ascii_case("${property.name}"),
|
|
||||||
% else:
|
|
||||||
false,
|
|
||||||
% endif
|
|
||||||
% endfor
|
|
||||||
PropertyDeclaration::Custom(ref declaration_name, _) => {
|
|
||||||
declaration_name.with_str(|s| ::custom_properties::parse_name(name) == Ok(s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The `in_keyframe_block` parameter controls this:
|
/// The `in_keyframe_block` parameter controls this:
|
||||||
///
|
///
|
||||||
/// https://drafts.csswg.org/css-animations/#keyframes
|
/// https://drafts.csswg.org/css-animations/#keyframes
|
||||||
/// > The <declaration-list> inside of <keyframe-block> accepts any CSS property
|
/// > The <declaration-list> inside of <keyframe-block> accepts any CSS property
|
||||||
/// > except those defined in this specification,
|
/// > except those defined in this specification,
|
||||||
/// > but does accept the `animation-play-state` property and interprets it specially.
|
/// > but does accept the `animation-play-state` property and interprets it specially.
|
||||||
pub fn parse(name: &str, context: &ParserContext, input: &mut Parser,
|
pub fn parse(id: PropertyId, context: &ParserContext, input: &mut Parser,
|
||||||
result_list: &mut Vec<PropertyDeclaration>,
|
result_list: &mut Vec<PropertyDeclaration>,
|
||||||
in_keyframe_block: bool)
|
in_keyframe_block: bool)
|
||||||
-> PropertyDeclarationParseResult {
|
-> PropertyDeclarationParseResult {
|
||||||
if let Ok(name) = ::custom_properties::parse_name(name) {
|
match id {
|
||||||
let value = match input.try(|i| CSSWideKeyword::parse(context, i)) {
|
PropertyId::Custom(name) => {
|
||||||
Ok(CSSWideKeyword::UnsetKeyword) | // Custom properties are alawys inherited
|
let value = match input.try(|i| CSSWideKeyword::parse(context, i)) {
|
||||||
Ok(CSSWideKeyword::InheritKeyword) => DeclaredValue::Inherit,
|
Ok(CSSWideKeyword::UnsetKeyword) | // Custom properties are alawys inherited
|
||||||
Ok(CSSWideKeyword::InitialKeyword) => DeclaredValue::Initial,
|
Ok(CSSWideKeyword::InheritKeyword) => DeclaredValue::Inherit,
|
||||||
Err(()) => match ::custom_properties::SpecifiedValue::parse(context, input) {
|
Ok(CSSWideKeyword::InitialKeyword) => DeclaredValue::Initial,
|
||||||
Ok(value) => DeclaredValue::Value(value),
|
Err(()) => match ::custom_properties::SpecifiedValue::parse(context, input) {
|
||||||
Err(()) => return PropertyDeclarationParseResult::InvalidValue,
|
Ok(value) => DeclaredValue::Value(value),
|
||||||
}
|
Err(()) => return PropertyDeclarationParseResult::InvalidValue,
|
||||||
};
|
}
|
||||||
result_list.push(PropertyDeclaration::Custom(Atom::from(name), value));
|
};
|
||||||
return PropertyDeclarationParseResult::ValidOrIgnoredDeclaration;
|
result_list.push(PropertyDeclaration::Custom(name, value));
|
||||||
}
|
return PropertyDeclarationParseResult::ValidOrIgnoredDeclaration;
|
||||||
match_ignore_ascii_case! { name,
|
}
|
||||||
|
PropertyId::Longhand(id) => match id {
|
||||||
% for property in data.longhands:
|
% for property in data.longhands:
|
||||||
% if not property.derived_from:
|
LonghandId::${property.camel_case} => {
|
||||||
"${property.name}" => {
|
% if not property.derived_from:
|
||||||
% if not property.allowed_in_keyframe_block:
|
% if not property.allowed_in_keyframe_block:
|
||||||
if in_keyframe_block {
|
if in_keyframe_block {
|
||||||
return PropertyDeclarationParseResult::AnimationPropertyInKeyframeBlock
|
return PropertyDeclarationParseResult::AnimationPropertyInKeyframeBlock
|
||||||
|
@ -793,13 +858,15 @@ impl PropertyDeclaration {
|
||||||
},
|
},
|
||||||
Err(()) => PropertyDeclarationParseResult::InvalidValue,
|
Err(()) => PropertyDeclarationParseResult::InvalidValue,
|
||||||
}
|
}
|
||||||
},
|
% else:
|
||||||
% else:
|
PropertyDeclarationParseResult::UnknownProperty
|
||||||
"${property.name}" => PropertyDeclarationParseResult::UnknownProperty,
|
% endif
|
||||||
% endif
|
}
|
||||||
% endfor
|
% endfor
|
||||||
|
},
|
||||||
|
PropertyId::Shorthand(id) => match id {
|
||||||
% for shorthand in data.shorthands:
|
% for shorthand in data.shorthands:
|
||||||
"${shorthand.name}" => {
|
ShorthandId::${shorthand.camel_case} => {
|
||||||
% if not shorthand.allowed_in_keyframe_block:
|
% if not shorthand.allowed_in_keyframe_block:
|
||||||
if in_keyframe_block {
|
if in_keyframe_block {
|
||||||
return PropertyDeclarationParseResult::AnimationPropertyInKeyframeBlock
|
return PropertyDeclarationParseResult::AnimationPropertyInKeyframeBlock
|
||||||
|
@ -846,19 +913,13 @@ impl PropertyDeclaration {
|
||||||
Err(()) => PropertyDeclarationParseResult::InvalidValue,
|
Err(()) => PropertyDeclarationParseResult::InvalidValue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
% endfor
|
|
||||||
|
|
||||||
_ => {
|
|
||||||
if cfg!(all(debug_assertions, feature = "gecko")) && !name.starts_with('-') {
|
|
||||||
println!("stylo: Unimplemented property setter: {}", name);
|
|
||||||
}
|
}
|
||||||
PropertyDeclarationParseResult::UnknownProperty
|
% endfor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shorthands(&self) -> &'static [Shorthand] {
|
pub fn shorthands(&self) -> &'static [ShorthandId] {
|
||||||
// first generate longhand to shorthands lookup map
|
// first generate longhand to shorthands lookup map
|
||||||
<%
|
<%
|
||||||
longhand_to_shorthand_map = {}
|
longhand_to_shorthand_map = {}
|
||||||
|
@ -875,9 +936,9 @@ impl PropertyDeclaration {
|
||||||
|
|
||||||
// based on lookup results for each longhand, create result arrays
|
// based on lookup results for each longhand, create result arrays
|
||||||
% for property in data.longhands:
|
% for property in data.longhands:
|
||||||
static ${property.ident.upper()}: &'static [Shorthand] = &[
|
static ${property.ident.upper()}: &'static [ShorthandId] = &[
|
||||||
% for shorthand in longhand_to_shorthand_map.get(property.ident, []):
|
% for shorthand in longhand_to_shorthand_map.get(property.ident, []):
|
||||||
Shorthand::${shorthand},
|
ShorthandId::${shorthand},
|
||||||
% endfor
|
% endfor
|
||||||
];
|
];
|
||||||
% endfor
|
% endfor
|
||||||
|
@ -1321,18 +1382,21 @@ impl ComputedValues {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn computed_value_to_string(&self, name: &str) -> Result<String, ()> {
|
pub fn computed_value_to_string(&self, property: PropertyDeclarationId) -> String {
|
||||||
match name {
|
match property {
|
||||||
% for style_struct in data.active_style_structs():
|
% for style_struct in data.active_style_structs():
|
||||||
% for longhand in style_struct.longhands:
|
% for longhand in style_struct.longhands:
|
||||||
"${longhand.name}" => Ok(self.${style_struct.ident}.${longhand.ident}.to_css_string()),
|
PropertyDeclarationId::Longhand(LonghandId::${longhand.camel_case}) => {
|
||||||
|
self.${style_struct.ident}.${longhand.ident}.to_css_string()
|
||||||
|
}
|
||||||
% endfor
|
% endfor
|
||||||
% endfor
|
% endfor
|
||||||
_ => {
|
PropertyDeclarationId::Custom(name) => {
|
||||||
let name = try!(::custom_properties::parse_name(name));
|
self.custom_properties
|
||||||
let map = try!(self.custom_properties.as_ref().ok_or(()));
|
.as_ref()
|
||||||
let value = try!(map.get(&Atom::from(name)).ok_or(()));
|
.and_then(|map| map.get(name))
|
||||||
Ok(value.to_css_string())
|
.map(|value| value.to_css_string())
|
||||||
|
.unwrap_or(String::new())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1576,9 +1640,11 @@ pub fn apply_declarations<'a, F, I>(viewport_size: Size2D<Au>,
|
||||||
ComputedValues::do_cascade_property(|cascade_property| {
|
ComputedValues::do_cascade_property(|cascade_property| {
|
||||||
% for category_to_cascade_now in ["early", "other"]:
|
% for category_to_cascade_now in ["early", "other"]:
|
||||||
for declaration in iter_declarations() {
|
for declaration in iter_declarations() {
|
||||||
if let PropertyDeclaration::Custom(..) = *declaration {
|
let longhand_id = match declaration.id() {
|
||||||
continue
|
PropertyDeclarationId::Longhand(id) => id,
|
||||||
}
|
PropertyDeclarationId::Custom(..) => continue,
|
||||||
|
};
|
||||||
|
|
||||||
// The computed value of some properties depends on the
|
// The computed value of some properties depends on the
|
||||||
// (sometimes computed) value of *other* properties.
|
// (sometimes computed) value of *other* properties.
|
||||||
//
|
//
|
||||||
|
@ -1610,7 +1676,7 @@ pub fn apply_declarations<'a, F, I>(viewport_size: Size2D<Au>,
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
let discriminant = declaration.discriminant_value();
|
let discriminant = longhand_id as usize;
|
||||||
(cascade_property[discriminant])(declaration,
|
(cascade_property[discriminant])(declaration,
|
||||||
inherited_style,
|
inherited_style,
|
||||||
&mut context,
|
&mut context,
|
||||||
|
@ -1948,31 +2014,21 @@ pub fn modify_style_for_inline_absolute_hypothetical_fragment(style: &mut Arc<Co
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: https://github.com/w3c/csswg-drafts/issues/580
|
|
||||||
pub fn is_supported_property(property: &str) -> bool {
|
|
||||||
match_ignore_ascii_case! { property,
|
|
||||||
% for property in data.shorthands + data.longhands:
|
|
||||||
"${property.name}" => true,
|
|
||||||
% endfor
|
|
||||||
_ => property.starts_with("--")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! css_properties_accessors {
|
macro_rules! css_properties_accessors {
|
||||||
($macro_name: ident) => {
|
($macro_name: ident) => {
|
||||||
$macro_name! {
|
$macro_name! {
|
||||||
% for property in data.shorthands + data.longhands:
|
% for kind, props in [("Longhand", data.longhands), ("Shorthand", data.shorthands)]:
|
||||||
% if not property.derived_from and not property.internal:
|
% for property in props:
|
||||||
% if '-' in property.name:
|
% if not property.derived_from and not property.internal:
|
||||||
[${property.ident.capitalize()}, Set${property.ident.capitalize()}, "${property.name}"],
|
% if '-' in property.name:
|
||||||
|
[${property.ident.capitalize()}, Set${property.ident.capitalize()},
|
||||||
|
PropertyId::${kind}(${kind}Id::${property.camel_case})],
|
||||||
|
% endif
|
||||||
|
[${property.camel_case}, Set${property.camel_case},
|
||||||
|
PropertyId::${kind}(${kind}Id::${property.camel_case})],
|
||||||
% endif
|
% endif
|
||||||
% if property != data.longhands[-1]:
|
% endfor
|
||||||
[${property.camel_case}, Set${property.camel_case}, "${property.name}"],
|
|
||||||
% else:
|
|
||||||
[${property.camel_case}, Set${property.camel_case}, "${property.name}"]
|
|
||||||
% endif
|
|
||||||
% endif
|
|
||||||
% endfor
|
% endfor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use properties::{AppendableValue, DeclaredValue, PropertyDeclaration, Shorthand};
|
use properties::{AppendableValue, DeclaredValue, PropertyDeclaration, ShorthandId};
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
use values::specified::{BorderStyle, CSSColor};
|
use values::specified::{BorderStyle, CSSColor};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -88,7 +88,7 @@ fn serialize_directional_border<W, I>(dest: &mut W,
|
||||||
pub fn is_overflow_shorthand<'a, I>(appendable_value: &AppendableValue<'a, I>) -> bool
|
pub fn is_overflow_shorthand<'a, I>(appendable_value: &AppendableValue<'a, I>) -> bool
|
||||||
where I: Iterator<Item=&'a PropertyDeclaration> {
|
where I: Iterator<Item=&'a PropertyDeclaration> {
|
||||||
if let AppendableValue::DeclarationsForShorthand(shorthand, _) = *appendable_value {
|
if let AppendableValue::DeclarationsForShorthand(shorthand, _) = *appendable_value {
|
||||||
if let Shorthand::Overflow = shorthand {
|
if let ShorthandId::Overflow = shorthand {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use num_traits::ToPrimitive;
|
use num_traits::ToPrimitive;
|
||||||
|
use std::ascii::AsciiExt;
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::convert::AsRef;
|
use std::convert::AsRef;
|
||||||
use std::iter::{Filter, Peekable};
|
use std::iter::{Filter, Peekable};
|
||||||
use std::str::Split;
|
use std::str::Split;
|
||||||
|
@ -125,3 +127,13 @@ pub fn str_join<I, T>(strs: I, join: &str) -> String
|
||||||
acc
|
acc
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Like AsciiExt::to_ascii_lowercase, but avoids allocating when the input is already lower-case.
|
||||||
|
pub fn cow_into_ascii_lowercase<'a, S: Into<Cow<'a, str>>>(s: S) -> Cow<'a, str> {
|
||||||
|
let mut cow = s.into();
|
||||||
|
match cow.bytes().position(|byte| byte >= b'A' && byte <= b'Z') {
|
||||||
|
Some(first_uppercase) => cow.to_mut()[first_uppercase..].make_ascii_lowercase(),
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
cow
|
||||||
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ use style::gecko_bindings::sugar::refptr::{GeckoArcPrincipal, GeckoArcURI};
|
||||||
use style::parallel;
|
use style::parallel;
|
||||||
use style::parser::{ParserContext, ParserContextExtraData};
|
use style::parser::{ParserContext, ParserContextExtraData};
|
||||||
use style::properties::{CascadeFlags, ComputedValues, Importance, PropertyDeclaration};
|
use style::properties::{CascadeFlags, ComputedValues, Importance, PropertyDeclaration};
|
||||||
use style::properties::{PropertyDeclarationParseResult, PropertyDeclarationBlock};
|
use style::properties::{PropertyDeclarationParseResult, PropertyDeclarationBlock, PropertyId};
|
||||||
use style::properties::{apply_declarations, parse_one_declaration};
|
use style::properties::{apply_declarations, parse_one_declaration};
|
||||||
use style::restyle_hints::RestyleHint;
|
use style::restyle_hints::RestyleHint;
|
||||||
use style::selector_parser::PseudoElementCascadeType;
|
use style::selector_parser::PseudoElementCascadeType;
|
||||||
|
@ -534,6 +534,11 @@ pub extern "C" fn Servo_ParseProperty(property: *const nsACString, value: *const
|
||||||
principal: *mut ThreadSafePrincipalHolder)
|
principal: *mut ThreadSafePrincipalHolder)
|
||||||
-> RawServoDeclarationBlockStrong {
|
-> RawServoDeclarationBlockStrong {
|
||||||
let name = unsafe { property.as_ref().unwrap().as_str_unchecked() };
|
let name = unsafe { property.as_ref().unwrap().as_str_unchecked() };
|
||||||
|
let id = if let Ok(id) = PropertyId::parse(name.into()) {
|
||||||
|
id
|
||||||
|
} else {
|
||||||
|
return RawServoDeclarationBlockStrong::null()
|
||||||
|
};
|
||||||
let value = unsafe { value.as_ref().unwrap().as_str_unchecked() };
|
let value = unsafe { value.as_ref().unwrap().as_str_unchecked() };
|
||||||
let base_str = unsafe { base_url.as_ref().unwrap().as_str_unchecked() };
|
let base_str = unsafe { base_url.as_ref().unwrap().as_str_unchecked() };
|
||||||
let base_url = ServoUrl::parse(base_str).unwrap();
|
let base_url = ServoUrl::parse(base_str).unwrap();
|
||||||
|
@ -548,7 +553,7 @@ pub extern "C" fn Servo_ParseProperty(property: *const nsACString, value: *const
|
||||||
extra_data);
|
extra_data);
|
||||||
|
|
||||||
let mut results = vec![];
|
let mut results = vec![];
|
||||||
match PropertyDeclaration::parse(name, &context, &mut Parser::new(value),
|
match PropertyDeclaration::parse(id, &context, &mut Parser::new(value),
|
||||||
&mut results, false) {
|
&mut results, false) {
|
||||||
PropertyDeclarationParseResult::ValidOrIgnoredDeclaration => {},
|
PropertyDeclarationParseResult::ValidOrIgnoredDeclaration => {},
|
||||||
_ => return RawServoDeclarationBlockStrong::null(),
|
_ => return RawServoDeclarationBlockStrong::null(),
|
||||||
|
@ -611,7 +616,7 @@ pub extern "C" fn Servo_DeclarationBlock_SerializeOneValue(
|
||||||
buffer: *mut nsAString)
|
buffer: *mut nsAString)
|
||||||
{
|
{
|
||||||
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
|
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
|
||||||
let property = get_property_name_from_atom(property, is_custom);
|
let property = get_property_id_from_atom(property, is_custom);
|
||||||
let mut string = String::new();
|
let mut string = String::new();
|
||||||
let rv = declarations.read().single_value_to_css(&property, &mut string);
|
let rv = declarations.read().single_value_to_css(&property, &mut string);
|
||||||
debug_assert!(rv.is_ok());
|
debug_assert!(rv.is_ok());
|
||||||
|
@ -631,23 +636,21 @@ pub extern "C" fn Servo_DeclarationBlock_GetNthProperty(declarations: RawServoDe
|
||||||
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
|
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
|
||||||
if let Some(&(ref decl, _)) = declarations.read().declarations.get(index as usize) {
|
if let Some(&(ref decl, _)) = declarations.read().declarations.get(index as usize) {
|
||||||
let result = unsafe { result.as_mut().unwrap() };
|
let result = unsafe { result.as_mut().unwrap() };
|
||||||
write!(result, "{}", decl.name()).unwrap();
|
decl.id().to_css(result).unwrap();
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME Methods of PropertyDeclarationBlock should take atoms directly.
|
fn get_property_id_from_atom(atom: *mut nsIAtom, is_custom: bool) -> PropertyId {
|
||||||
// This function is just a temporary workaround before that finishes.
|
|
||||||
fn get_property_name_from_atom(atom: *mut nsIAtom, is_custom: bool) -> String {
|
|
||||||
let atom = Atom::from(atom);
|
let atom = Atom::from(atom);
|
||||||
if !is_custom {
|
if !is_custom {
|
||||||
atom.to_string()
|
// FIXME: can we do this mapping without going through a UTF-8 string?
|
||||||
|
// Maybe even from nsCSSPropertyID directly?
|
||||||
|
PropertyId::parse(atom.to_string().into()).expect("got unknown property name from Gecko")
|
||||||
} else {
|
} else {
|
||||||
let mut result = String::with_capacity(atom.len() as usize + 2);
|
PropertyId::Custom(atom)
|
||||||
write!(result, "--{}", atom).unwrap();
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -656,7 +659,7 @@ pub extern "C" fn Servo_DeclarationBlock_GetPropertyValue(declarations: RawServo
|
||||||
property: *mut nsIAtom, is_custom: bool,
|
property: *mut nsIAtom, is_custom: bool,
|
||||||
value: *mut nsAString) {
|
value: *mut nsAString) {
|
||||||
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
|
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
|
||||||
let property = get_property_name_from_atom(property, is_custom);
|
let property = get_property_id_from_atom(property, is_custom);
|
||||||
declarations.read().property_value_to_css(&property, unsafe { value.as_mut().unwrap() }).unwrap();
|
declarations.read().property_value_to_css(&property, unsafe { value.as_mut().unwrap() }).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -664,7 +667,7 @@ pub extern "C" fn Servo_DeclarationBlock_GetPropertyValue(declarations: RawServo
|
||||||
pub extern "C" fn Servo_DeclarationBlock_GetPropertyIsImportant(declarations: RawServoDeclarationBlockBorrowed,
|
pub extern "C" fn Servo_DeclarationBlock_GetPropertyIsImportant(declarations: RawServoDeclarationBlockBorrowed,
|
||||||
property: *mut nsIAtom, is_custom: bool) -> bool {
|
property: *mut nsIAtom, is_custom: bool) -> bool {
|
||||||
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
|
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
|
||||||
let property = get_property_name_from_atom(property, is_custom);
|
let property = get_property_id_from_atom(property, is_custom);
|
||||||
declarations.read().property_priority(&property).important()
|
declarations.read().property_priority(&property).important()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -672,12 +675,12 @@ pub extern "C" fn Servo_DeclarationBlock_GetPropertyIsImportant(declarations: Ra
|
||||||
pub extern "C" fn Servo_DeclarationBlock_SetProperty(declarations: RawServoDeclarationBlockBorrowed,
|
pub extern "C" fn Servo_DeclarationBlock_SetProperty(declarations: RawServoDeclarationBlockBorrowed,
|
||||||
property: *mut nsIAtom, is_custom: bool,
|
property: *mut nsIAtom, is_custom: bool,
|
||||||
value: *mut nsACString, is_important: bool) -> bool {
|
value: *mut nsACString, is_important: bool) -> bool {
|
||||||
let property = get_property_name_from_atom(property, is_custom);
|
let property = get_property_id_from_atom(property, is_custom);
|
||||||
let value = unsafe { value.as_ref().unwrap().as_str_unchecked() };
|
let value = unsafe { value.as_ref().unwrap().as_str_unchecked() };
|
||||||
// FIXME Needs real URL and ParserContextExtraData.
|
// FIXME Needs real URL and ParserContextExtraData.
|
||||||
let base_url = &*DUMMY_BASE_URL;
|
let base_url = &*DUMMY_BASE_URL;
|
||||||
let extra_data = ParserContextExtraData::default();
|
let extra_data = ParserContextExtraData::default();
|
||||||
if let Ok(decls) = parse_one_declaration(&property, value, &base_url,
|
if let Ok(decls) = parse_one_declaration(property, value, &base_url,
|
||||||
Box::new(StdoutErrorReporter), extra_data) {
|
Box::new(StdoutErrorReporter), extra_data) {
|
||||||
let mut declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations).write();
|
let mut declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations).write();
|
||||||
let importance = if is_important { Importance::Important } else { Importance::Normal };
|
let importance = if is_important { Importance::Important } else { Importance::Normal };
|
||||||
|
@ -694,19 +697,24 @@ pub extern "C" fn Servo_DeclarationBlock_SetProperty(declarations: RawServoDecla
|
||||||
pub extern "C" fn Servo_DeclarationBlock_RemoveProperty(declarations: RawServoDeclarationBlockBorrowed,
|
pub extern "C" fn Servo_DeclarationBlock_RemoveProperty(declarations: RawServoDeclarationBlockBorrowed,
|
||||||
property: *mut nsIAtom, is_custom: bool) {
|
property: *mut nsIAtom, is_custom: bool) {
|
||||||
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
|
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
|
||||||
let property = get_property_name_from_atom(property, is_custom);
|
let property = get_property_id_from_atom(property, is_custom);
|
||||||
declarations.write().remove_property(&property);
|
declarations.write().remove_property(&property);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn Servo_CSSSupports(property: *const nsACString, value: *const nsACString) -> bool {
|
pub extern "C" fn Servo_CSSSupports(property: *const nsACString, value: *const nsACString) -> bool {
|
||||||
let property = unsafe { property.as_ref().unwrap().as_str_unchecked() };
|
let property = unsafe { property.as_ref().unwrap().as_str_unchecked() };
|
||||||
|
let id = if let Ok(id) = PropertyId::parse(property.into()) {
|
||||||
|
id
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
};
|
||||||
let value = unsafe { value.as_ref().unwrap().as_str_unchecked() };
|
let value = unsafe { value.as_ref().unwrap().as_str_unchecked() };
|
||||||
|
|
||||||
let base_url = &*DUMMY_BASE_URL;
|
let base_url = &*DUMMY_BASE_URL;
|
||||||
let extra_data = ParserContextExtraData::default();
|
let extra_data = ParserContextExtraData::default();
|
||||||
|
|
||||||
match parse_one_declaration(&property, &value, &base_url, Box::new(StdoutErrorReporter), extra_data) {
|
match parse_one_declaration(id, &value, &base_url, Box::new(StdoutErrorReporter), extra_data) {
|
||||||
Ok(decls) => !decls.is_empty(),
|
Ok(decls) => !decls.is_empty(),
|
||||||
Err(()) => false,
|
Err(()) => false,
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ testing = ["style/testing"]
|
||||||
app_units = "0.3"
|
app_units = "0.3"
|
||||||
cssparser = {version = "0.7", features = ["heap_size"]}
|
cssparser = {version = "0.7", features = ["heap_size"]}
|
||||||
euclid = "0.10.1"
|
euclid = "0.10.1"
|
||||||
|
matches = "0.1"
|
||||||
owning_ref = "0.2.2"
|
owning_ref = "0.2.2"
|
||||||
parking_lot = "0.3"
|
parking_lot = "0.3"
|
||||||
rustc-serialize = "0.3"
|
rustc-serialize = "0.3"
|
||||||
|
|
|
@ -10,6 +10,7 @@ extern crate app_units;
|
||||||
extern crate cssparser;
|
extern crate cssparser;
|
||||||
extern crate euclid;
|
extern crate euclid;
|
||||||
#[macro_use] extern crate html5ever_atoms;
|
#[macro_use] extern crate html5ever_atoms;
|
||||||
|
#[macro_use] #[allow(unused_extern_crates)] extern crate matches;
|
||||||
extern crate owning_ref;
|
extern crate owning_ref;
|
||||||
extern crate parking_lot;
|
extern crate parking_lot;
|
||||||
extern crate rustc_serialize;
|
extern crate rustc_serialize;
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
pub use std::sync::Arc;
|
pub use std::sync::Arc;
|
||||||
pub use style::computed_values::display::T::inline_block;
|
pub use style::computed_values::display::T::inline_block;
|
||||||
pub use style::properties::{DeclaredValue, PropertyDeclaration, PropertyDeclarationBlock, Importance};
|
pub use style::properties::{DeclaredValue, PropertyDeclaration, PropertyDeclarationBlock, Importance, PropertyId};
|
||||||
pub use style::values::specified::{BorderStyle, BorderWidth, CSSColor, Length};
|
pub use style::values::specified::{BorderStyle, BorderWidth, CSSColor, Length};
|
||||||
pub use style::values::specified::{LengthOrPercentage, LengthOrPercentageOrAuto, LengthOrPercentageOrAutoOrContent};
|
pub use style::values::specified::{LengthOrPercentage, LengthOrPercentageOrAuto, LengthOrPercentageOrAutoOrContent};
|
||||||
pub use style::properties::longhands::outline_color::computed_value::T as ComputedColor;
|
pub use style::properties::longhands::outline_color::computed_value::T as ComputedColor;
|
||||||
|
@ -1027,7 +1027,8 @@ mod shorthand_serialization {
|
||||||
|
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
|
|
||||||
let x = block.single_value_to_css("scroll-snap-type", &mut s);
|
let id = PropertyId::parse("scroll-snap-type".into()).unwrap();
|
||||||
|
let x = block.single_value_to_css(&id, &mut s);
|
||||||
|
|
||||||
assert_eq!(x.is_ok(), true);
|
assert_eq!(x.is_ok(), true);
|
||||||
assert_eq!(s, "");
|
assert_eq!(s, "");
|
||||||
|
@ -1049,7 +1050,8 @@ mod shorthand_serialization {
|
||||||
|
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
|
|
||||||
let x = block.single_value_to_css("scroll-snap-type", &mut s);
|
let id = PropertyId::parse("scroll-snap-type".into()).unwrap();
|
||||||
|
let x = block.single_value_to_css(&id, &mut s);
|
||||||
|
|
||||||
assert_eq!(x.is_ok(), true);
|
assert_eq!(x.is_ok(), true);
|
||||||
assert_eq!(s, "mandatory");
|
assert_eq!(s, "mandatory");
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use style::str::{split_html_space_chars, str_join};
|
use std::borrow::Cow;
|
||||||
|
use style::str::{split_html_space_chars, str_join, cow_into_ascii_lowercase};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn split_html_space_chars_whitespace() {
|
pub fn split_html_space_chars_whitespace() {
|
||||||
|
@ -33,3 +34,13 @@ pub fn test_str_join_many() {
|
||||||
let expected = "-alpha--beta-gamma-";
|
let expected = "-alpha--beta-gamma-";
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_cow_into_ascii_lowercase() {
|
||||||
|
assert!(matches!(cow_into_ascii_lowercase("abc.d"), Cow::Borrowed("abc.d")));
|
||||||
|
let string = String::from("abc.d");
|
||||||
|
assert!(matches!(cow_into_ascii_lowercase(string), Cow::Owned(ref s) if s == "abc.d"));
|
||||||
|
assert!(matches!(cow_into_ascii_lowercase("Abc.d"), Cow::Owned(ref s) if s == "abc.d"));
|
||||||
|
assert!(matches!(cow_into_ascii_lowercase("aBC.D"), Cow::Owned(ref s) if s == "abc.d"));
|
||||||
|
assert!(matches!(cow_into_ascii_lowercase("abc.D"), Cow::Owned(ref s) if s == "abc.d"));
|
||||||
|
}
|
||||||
|
|
|
@ -16,8 +16,8 @@ use std::sync::atomic::AtomicBool;
|
||||||
use style::error_reporting::ParseErrorReporter;
|
use style::error_reporting::ParseErrorReporter;
|
||||||
use style::keyframes::{Keyframe, KeyframeSelector, KeyframePercentage};
|
use style::keyframes::{Keyframe, KeyframeSelector, KeyframePercentage};
|
||||||
use style::parser::ParserContextExtraData;
|
use style::parser::ParserContextExtraData;
|
||||||
use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, DeclaredValue, longhands};
|
|
||||||
use style::properties::Importance;
|
use style::properties::Importance;
|
||||||
|
use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, DeclaredValue, longhands};
|
||||||
use style::properties::longhands::animation_play_state;
|
use style::properties::longhands::animation_play_state;
|
||||||
use style::stylesheets::{Origin, Namespaces};
|
use style::stylesheets::{Origin, Namespaces};
|
||||||
use style::stylesheets::{Stylesheet, NamespaceRule, CssRule, CssRules, StyleRule, KeyframesRule};
|
use style::stylesheets::{Stylesheet, NamespaceRule, CssRule, CssRules, StyleRule, KeyframesRule};
|
||||||
|
|
|
@ -101,7 +101,7 @@ fn test_insert() {
|
||||||
let rules_list = get_mock_rules(&[".intro.foo", "#top"]);
|
let rules_list = get_mock_rules(&[".intro.foo", "#top"]);
|
||||||
let mut selector_map = SelectorMap::new();
|
let mut selector_map = SelectorMap::new();
|
||||||
selector_map.insert(rules_list[1][0].clone());
|
selector_map.insert(rules_list[1][0].clone());
|
||||||
assert_eq!(1, selector_map.id_hash.get(&atom!("top")).unwrap()[0].source_order);
|
assert_eq!(1, selector_map.id_hash.get(&Atom::from("top")).unwrap()[0].source_order);
|
||||||
selector_map.insert(rules_list[0][0].clone());
|
selector_map.insert(rules_list[0][0].clone());
|
||||||
assert_eq!(0, selector_map.class_hash.get(&Atom::from("intro")).unwrap()[0].source_order);
|
assert_eq!(0, selector_map.class_hash.get(&Atom::from("intro")).unwrap()[0].source_order);
|
||||||
assert!(selector_map.class_hash.get(&Atom::from("foo")).is_none());
|
assert!(selector_map.class_hash.get(&Atom::from("foo")).is_none());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue