Run rustfmt on selectors, servo_arc, and style.

This was generated with:

./mach cargo fmt --package selectors &&
./mach cargo fmt --package servo_arc &&
./mach cargo fmt --package style

Using rustfmt 0.4.1-nightly (a4462d1 2018-03-26)
This commit is contained in:
Bobby Holley 2018-04-10 17:35:15 -07:00
parent f7ae1a37e3
commit c99bcdd4b8
181 changed files with 9981 additions and 7933 deletions

View file

@ -19,9 +19,7 @@ impl<Impl: SelectorImpl> AttrSelectorWithNamespace<Impl> {
pub fn namespace(&self) -> NamespaceConstraint<&Impl::NamespaceUrl> {
match self.namespace {
NamespaceConstraint::Any => NamespaceConstraint::Any,
NamespaceConstraint::Specific((_, ref url)) => {
NamespaceConstraint::Specific(url)
}
NamespaceConstraint::Specific((_, ref url)) => NamespaceConstraint::Specific(url),
}
}
}
@ -41,7 +39,7 @@ pub enum ParsedAttrSelectorOperation<AttrValue> {
operator: AttrSelectorOperator,
case_sensitivity: ParsedCaseSensitivity,
expected_value: AttrValue,
}
},
}
#[derive(Clone, Eq, PartialEq)]
@ -51,16 +49,25 @@ pub enum AttrSelectorOperation<AttrValue> {
operator: AttrSelectorOperator,
case_sensitivity: CaseSensitivity,
expected_value: AttrValue,
}
},
}
impl<AttrValue> AttrSelectorOperation<AttrValue> {
pub fn eval_str(&self, element_attr_value: &str) -> bool where AttrValue: AsRef<str> {
pub fn eval_str(&self, element_attr_value: &str) -> bool
where
AttrValue: AsRef<str>,
{
match *self {
AttrSelectorOperation::Exists => true,
AttrSelectorOperation::WithValue { operator, case_sensitivity, ref expected_value } => {
operator.eval_str(element_attr_value, expected_value.as_ref(), case_sensitivity)
}
AttrSelectorOperation::WithValue {
operator,
case_sensitivity,
ref expected_value,
} => operator.eval_str(
element_attr_value,
expected_value.as_ref(),
case_sensitivity,
),
}
}
}
@ -76,7 +83,10 @@ pub enum AttrSelectorOperator {
}
impl ToCss for AttrSelectorOperator {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where
W: fmt::Write,
{
// https://drafts.csswg.org/cssom/#serializing-selectors
// See "attribute selector".
dest.write_str(match *self {
@ -91,34 +101,30 @@ impl ToCss for AttrSelectorOperator {
}
impl AttrSelectorOperator {
pub fn eval_str(self, element_attr_value: &str, attr_selector_value: &str,
case_sensitivity: CaseSensitivity) -> bool {
pub fn eval_str(
self,
element_attr_value: &str,
attr_selector_value: &str,
case_sensitivity: CaseSensitivity,
) -> bool {
let e = element_attr_value.as_bytes();
let s = attr_selector_value.as_bytes();
let case = case_sensitivity;
match self {
AttrSelectorOperator::Equal => {
case.eq(e, s)
}
AttrSelectorOperator::Prefix => {
e.len() >= s.len() && case.eq(&e[..s.len()], s)
}
AttrSelectorOperator::Equal => case.eq(e, s),
AttrSelectorOperator::Prefix => e.len() >= s.len() && case.eq(&e[..s.len()], s),
AttrSelectorOperator::Suffix => {
e.len() >= s.len() && case.eq(&e[(e.len() - s.len())..], s)
}
},
AttrSelectorOperator::Substring => {
case.contains(element_attr_value, attr_selector_value)
}
AttrSelectorOperator::Includes => {
element_attr_value.split(SELECTOR_WHITESPACE)
.any(|part| case.eq(part.as_bytes(), s))
}
},
AttrSelectorOperator::Includes => element_attr_value
.split(SELECTOR_WHITESPACE)
.any(|part| case.eq(part.as_bytes(), s)),
AttrSelectorOperator::DashMatch => {
case.eq(e, s) || (
e.get(s.len()) == Some(&b'-') &&
case.eq(&e[..s.len()], s)
)
}
case.eq(e, s) || (e.get(s.len()) == Some(&b'-') && case.eq(&e[..s.len()], s))
},
}
}
}
@ -137,12 +143,13 @@ impl ParsedCaseSensitivity {
pub fn to_unconditional(self, is_html_element_in_html_document: bool) -> CaseSensitivity {
match self {
ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument
if is_html_element_in_html_document => {
if is_html_element_in_html_document =>
{
CaseSensitivity::AsciiCaseInsensitive
}
},
ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => {
CaseSensitivity::CaseSensitive
}
},
ParsedCaseSensitivity::CaseSensitive => CaseSensitivity::CaseSensitive,
ParsedCaseSensitivity::AsciiCaseInsensitive => CaseSensitivity::AsciiCaseInsensitive,
}
@ -170,14 +177,12 @@ impl CaseSensitivity {
if let Some((&n_first_byte, n_rest)) = needle.as_bytes().split_first() {
haystack.bytes().enumerate().any(|(i, byte)| {
if !byte.eq_ignore_ascii_case(&n_first_byte) {
return false
return false;
}
let after_this_byte = &haystack.as_bytes()[i + 1..];
match after_this_byte.get(..n_rest.len()) {
None => false,
Some(haystack_slice) => {
haystack_slice.eq_ignore_ascii_case(n_rest)
}
Some(haystack_slice) => haystack_slice.eq_ignore_ascii_case(n_rest),
}
})
} else {
@ -185,7 +190,7 @@ impl CaseSensitivity {
// though these cases should be handled with *NeverMatches and never go here.
true
}
}
},
}
}
}

View file

@ -72,11 +72,17 @@ pub type NonCountingBloomFilter = CountingBloomFilter<BloomStorageBool>;
/// positive rate for N == 100 and to quite bad false positive
/// rates for larger N.
#[derive(Clone)]
pub struct CountingBloomFilter<S> where S: BloomStorage {
pub struct CountingBloomFilter<S>
where
S: BloomStorage,
{
storage: S,
}
impl<S> CountingBloomFilter<S> where S: BloomStorage {
impl<S> CountingBloomFilter<S>
where
S: BloomStorage,
{
/// Creates a new bloom filter.
#[inline]
pub fn new() -> Self {
@ -128,8 +134,7 @@ impl<S> CountingBloomFilter<S> where S: BloomStorage {
#[inline]
pub fn might_contain_hash(&self, hash: u32) -> bool {
!self.storage.first_slot_is_empty(hash) &&
!self.storage.second_slot_is_empty(hash)
!self.storage.first_slot_is_empty(hash) && !self.storage.second_slot_is_empty(hash)
}
/// Check whether the filter might contain an item. This can
@ -142,7 +147,10 @@ impl<S> CountingBloomFilter<S> where S: BloomStorage {
}
}
impl<S> Debug for CountingBloomFilter<S> where S: BloomStorage {
impl<S> Debug for CountingBloomFilter<S>
where
S: BloomStorage,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut slots_used = 0;
for i in 0..ARRAY_SIZE {
@ -154,7 +162,7 @@ impl<S> Debug for CountingBloomFilter<S> where S: BloomStorage {
}
}
pub trait BloomStorage : Clone + Default {
pub trait BloomStorage: Clone + Default {
fn slot_is_empty(&self, index: usize) -> bool;
fn adjust_slot(&mut self, index: usize, increment: bool);
fn is_zeroed(&self) -> bool;
@ -199,7 +207,8 @@ impl BloomStorage for BloomStorageU8 {
#[inline]
fn adjust_slot(&mut self, index: usize, increment: bool) {
let slot = &mut self.counters[index];
if *slot != 0xff { // full
if *slot != 0xff {
// full
if increment {
*slot += 1;
} else {
@ -249,8 +258,10 @@ impl BloomStorage for BloomStorageBool {
// Since we have only one bit for storage, decrementing it
// should never do anything. Assert against an accidental
// decrementing of a bit that was never set.
assert!(increment || (*byte & bit) != 0,
"should not decrement if slot is already false");
assert!(
increment || (*byte & bit) != 0,
"should not decrement if slot is already false"
);
if increment {
*byte |= bit;
@ -314,34 +325,33 @@ fn create_and_insert_some_stuff() {
transmute::<[u8; ARRAY_SIZE % 8], [u8; 0]>([]);
}
for i in 0_usize .. 1000 {
for i in 0_usize..1000 {
bf.insert(&i);
}
for i in 0_usize .. 1000 {
for i in 0_usize..1000 {
assert!(bf.might_contain(&i));
}
let false_positives =
(1001_usize .. 2000).filter(|i| bf.might_contain(i)).count();
let false_positives = (1001_usize..2000).filter(|i| bf.might_contain(i)).count();
assert!(false_positives < 150, "{} is not < 150", false_positives); // 15%.
for i in 0_usize .. 100 {
for i in 0_usize..100 {
bf.remove(&i);
}
for i in 100_usize .. 1000 {
for i in 100_usize..1000 {
assert!(bf.might_contain(&i));
}
let false_positives = (0_usize .. 100).filter(|i| bf.might_contain(i)).count();
let false_positives = (0_usize..100).filter(|i| bf.might_contain(i)).count();
assert!(false_positives < 20, "{} is not < 20", false_positives); // 20%.
bf.clear();
for i in 0_usize .. 2000 {
for i in 0_usize..2000 {
assert!(!bf.might_contain(&i));
}
}
@ -376,13 +386,13 @@ mod bench {
let mut gen1 = HashGenerator::default();
let mut gen2 = HashGenerator::default();
let mut bf = BloomFilter::new();
for _ in 0_usize .. 1000 {
for _ in 0_usize..1000 {
bf.insert_hash(gen1.next());
}
for _ in 0_usize .. 100 {
for _ in 0_usize..100 {
bf.remove_hash(gen2.next());
}
for _ in 100_usize .. 200 {
for _ in 100_usize..200 {
test::black_box(bf.might_contain_hash(gen2.next()));
}
});
@ -392,8 +402,10 @@ mod bench {
fn might_contain_10(b: &mut test::Bencher) {
let bf = BloomFilter::new();
let mut gen = HashGenerator::default();
b.iter(|| for _ in 0..10 {
test::black_box(bf.might_contain_hash(gen.next()));
b.iter(|| {
for _ in 0..10 {
test::black_box(bf.might_contain_hash(gen.next()));
}
});
}
@ -407,8 +419,10 @@ mod bench {
fn insert_10(b: &mut test::Bencher) {
let mut bf = BloomFilter::new();
let mut gen = HashGenerator::default();
b.iter(|| for _ in 0..10 {
test::black_box(bf.insert_hash(gen.next()));
b.iter(|| {
for _ in 0..10 {
test::black_box(bf.insert_hash(gen.next()));
}
});
}
@ -417,8 +431,10 @@ mod bench {
let mut bf = BloomFilter::new();
let mut gen = HashGenerator::default();
// Note: this will underflow, and that's ok.
b.iter(|| for _ in 0..10 {
bf.remove_hash(gen.next())
b.iter(|| {
for _ in 0..10 {
bf.remove_hash(gen.next())
}
});
}
}

View file

@ -116,12 +116,13 @@ impl<Impl: SelectorImpl> SelectorBuilder<Impl> {
self.build_with_specificity_and_flags(spec)
}
/// Builds with an explicit SpecificityAndFlags. This is separated from build() so
/// that unit tests can pass an explicit specificity.
#[inline(always)]
pub fn build_with_specificity_and_flags(&mut self, spec: SpecificityAndFlags)
-> ThinArc<SpecificityAndFlags, Component<Impl>> {
pub fn build_with_specificity_and_flags(
&mut self,
spec: SpecificityAndFlags,
) -> ThinArc<SpecificityAndFlags, Component<Impl>> {
// First, compute the total number of Components we'll need to allocate
// space for.
let full_len = self.simple_selectors.len() + self.combinators.len();
@ -159,9 +160,8 @@ struct SelectorBuilderIter<'a, Impl: SelectorImpl> {
impl<'a, Impl: SelectorImpl> ExactSizeIterator for SelectorBuilderIter<'a, Impl> {
fn len(&self) -> usize {
self.current_simple_selectors.len() +
self.rest_of_simple_selectors.len() +
self.combinators.len()
self.current_simple_selectors.len() + self.rest_of_simple_selectors.len() +
self.combinators.len()
}
}
@ -173,9 +173,7 @@ impl<'a, Impl: SelectorImpl> Iterator for SelectorBuilderIter<'a, Impl> {
// Move a simple selector out of this slice iterator.
// This is safe because weve called SmallVec::set_len(0) above,
// so SmallVec::drop wont drop this simple selector.
unsafe {
Some(ptr::read(simple_selector_ref))
}
unsafe { Some(ptr::read(simple_selector_ref)) }
} else {
self.combinators.next().map(|(combinator, len)| {
let (rest, current) = split_from_end(self.rest_of_simple_selectors, len);
@ -235,10 +233,8 @@ impl Add for Specificity {
fn add(self, rhs: Specificity) -> Specificity {
Specificity {
id_selectors: self.id_selectors + rhs.id_selectors,
class_like_selectors:
self.class_like_selectors + rhs.class_like_selectors,
element_selectors:
self.element_selectors + rhs.element_selectors,
class_like_selectors: self.class_like_selectors + rhs.class_like_selectors,
element_selectors: self.element_selectors + rhs.element_selectors,
}
}
}
@ -266,28 +262,28 @@ impl From<u32> for Specificity {
impl From<Specificity> for u32 {
fn from(specificity: Specificity) -> u32 {
cmp::min(specificity.id_selectors, MAX_10BIT) << 20
| cmp::min(specificity.class_like_selectors, MAX_10BIT) << 10
| cmp::min(specificity.element_selectors, MAX_10BIT)
cmp::min(specificity.id_selectors, MAX_10BIT) << 20 |
cmp::min(specificity.class_like_selectors, MAX_10BIT) << 10 |
cmp::min(specificity.element_selectors, MAX_10BIT)
}
}
fn specificity<Impl>(iter: slice::Iter<Component<Impl>>) -> u32
where Impl: SelectorImpl
where
Impl: SelectorImpl,
{
complex_selector_specificity(iter).into()
}
fn complex_selector_specificity<Impl>(mut iter: slice::Iter<Component<Impl>>)
-> Specificity
where Impl: SelectorImpl
fn complex_selector_specificity<Impl>(mut iter: slice::Iter<Component<Impl>>) -> Specificity
where
Impl: SelectorImpl,
{
fn simple_selector_specificity<Impl>(
simple_selector: &Component<Impl>,
specificity: &mut Specificity,
)
where
Impl: SelectorImpl
) where
Impl: SelectorImpl,
{
match *simple_selector {
Component::Combinator(..) => unreachable!(),
@ -298,44 +294,41 @@ fn complex_selector_specificity<Impl>(mut iter: slice::Iter<Component<Impl>>)
//
// Though other engines compute it dynamically, so maybe we should
// do that instead, eventually.
Component::Slotted(..) |
Component::PseudoElement(..) |
Component::LocalName(..) => {
Component::Slotted(..) | Component::PseudoElement(..) | Component::LocalName(..) => {
specificity.element_selectors += 1
}
Component::ID(..) => {
specificity.id_selectors += 1
}
},
Component::ID(..) => specificity.id_selectors += 1,
Component::Class(..) |
Component::AttributeInNoNamespace { .. } |
Component::AttributeInNoNamespaceExists { .. } |
Component::AttributeOther(..) |
Component::FirstChild | Component::LastChild |
Component::OnlyChild | Component::Root |
Component::Empty | Component::Scope |
Component::FirstChild |
Component::LastChild |
Component::OnlyChild |
Component::Root |
Component::Empty |
Component::Scope |
Component::Host(..) |
Component::NthChild(..) |
Component::NthLastChild(..) |
Component::NthOfType(..) |
Component::NthLastOfType(..) |
Component::FirstOfType | Component::LastOfType |
Component::FirstOfType |
Component::LastOfType |
Component::OnlyOfType |
Component::NonTSPseudoClass(..) => {
specificity.class_like_selectors += 1
}
Component::NonTSPseudoClass(..) => specificity.class_like_selectors += 1,
Component::ExplicitUniversalType |
Component::ExplicitAnyNamespace |
Component::ExplicitNoNamespace |
Component::DefaultNamespace(..) |
Component::Namespace(..) => {
// Does not affect specificity
}
},
Component::Negation(ref negated) => {
for ss in negated.iter() {
simple_selector_specificity(&ss, specificity);
}
}
},
}
}

View file

@ -54,7 +54,7 @@ impl VisitedHandlingMode {
matches!(
*self,
VisitedHandlingMode::RelevantLinkVisited |
VisitedHandlingMode::AllLinksVisitedAndUnvisited
VisitedHandlingMode::AllLinksVisitedAndUnvisited
)
}
@ -63,7 +63,7 @@ impl VisitedHandlingMode {
matches!(
*self,
VisitedHandlingMode::AllLinksUnvisited |
VisitedHandlingMode::AllLinksVisitedAndUnvisited
VisitedHandlingMode::AllLinksVisitedAndUnvisited
)
}
}
@ -85,8 +85,7 @@ impl QuirksMode {
#[inline]
pub fn classes_and_ids_case_sensitivity(self) -> CaseSensitivity {
match self {
QuirksMode::NoQuirks |
QuirksMode::LimitedQuirks => CaseSensitivity::CaseSensitive,
QuirksMode::NoQuirks | QuirksMode::LimitedQuirks => CaseSensitivity::CaseSensitive,
QuirksMode::Quirks => CaseSensitivity::AsciiCaseInsensitive,
}
}
@ -161,7 +160,7 @@ where
bloom_filter,
nth_index_cache,
VisitedHandlingMode::AllLinksUnvisited,
quirks_mode
quirks_mode,
)
}
@ -196,8 +195,7 @@ where
#[inline]
pub fn set_quirks_mode(&mut self, quirks_mode: QuirksMode) {
self.quirks_mode = quirks_mode;
self.classes_and_ids_case_sensitivity =
quirks_mode.classes_and_ids_case_sensitivity();
self.classes_and_ids_case_sensitivity = quirks_mode.classes_and_ids_case_sensitivity();
}
/// Whether we're matching a nested selector.
@ -249,10 +247,7 @@ where
where
F: FnOnce(&mut Self) -> R,
{
debug_assert!(
!self.in_negation,
"Someone messed up parsing?"
);
debug_assert!(!self.in_negation, "Someone messed up parsing?");
self.in_negation = true;
let result = self.nest(f);
self.in_negation = false;
@ -284,11 +279,7 @@ where
/// Runs F with a given shadow host which is the root of the tree whose
/// rules we're matching.
#[inline]
pub fn with_shadow_host<F, E, R>(
&mut self,
host: Option<E>,
f: F,
) -> R
pub fn with_shadow_host<F, E, R>(&mut self, host: Option<E>, f: F) -> R
where
E: Element,
F: FnOnce(&mut Self) -> R,

View file

@ -5,11 +5,15 @@
// Make |cargo bench| work.
#![cfg_attr(feature = "bench", feature(test))]
#[macro_use] extern crate bitflags;
#[macro_use] extern crate cssparser;
#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate cssparser;
extern crate fnv;
#[macro_use] extern crate log;
#[macro_use] extern crate matches;
#[macro_use]
extern crate log;
#[macro_use]
extern crate matches;
extern crate phf;
extern crate precomputed_hash;
extern crate servo_arc;
@ -27,5 +31,5 @@ mod tree;
pub mod visitor;
pub use nth_index_cache::NthIndexCache;
pub use parser::{SelectorImpl, Parser, SelectorList};
pub use parser::{Parser, SelectorImpl, SelectorList};
pub use tree::{Element, OpaqueElement};

View file

@ -2,11 +2,11 @@
* 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/. */
use attr::{ParsedAttrSelectorOperation, AttrSelectorOperation, NamespaceConstraint};
use bloom::{BLOOM_HASH_MASK, BloomFilter};
use attr::{AttrSelectorOperation, NamespaceConstraint, ParsedAttrSelectorOperation};
use bloom::{BloomFilter, BLOOM_HASH_MASK};
use nth_index_cache::NthIndexCacheInner;
use parser::{AncestorHashes, Combinator, Component, LocalName};
use parser::{Selector, SelectorImpl, SelectorIter, SelectorList, NonTSPseudoClass};
use parser::{NonTSPseudoClass, Selector, SelectorImpl, SelectorIter, SelectorList};
use std::borrow::Borrow;
use std::iter;
use tree::Element;
@ -52,8 +52,8 @@ impl ElementSelectorFlags {
/// Returns the subset of flags that apply to the parent.
pub fn for_parent(self) -> ElementSelectorFlags {
self & (ElementSelectorFlags::HAS_SLOW_SELECTOR |
ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS |
ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR)
ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS |
ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR)
}
}
@ -70,19 +70,12 @@ pub fn matches_selector_list<E>(
context: &mut MatchingContext<E::Impl>,
) -> bool
where
E: Element
E: Element,
{
// This is pretty much any(..) but manually inlined because the compiler
// refuses to do so from querySelector / querySelectorAll.
for selector in &selector_list.0 {
let matches = matches_selector(
selector,
0,
None,
element,
context,
&mut |_, _| {},
);
let matches = matches_selector(selector, 0, None, element, context, &mut |_, _| {});
if matches {
return true;
@ -219,7 +212,7 @@ pub enum CompoundSelectorMatchingResult {
FullyMatched,
/// The compound selector matched, and the next combinator offset is
/// `next_combinator_offset`.
Matched { next_combinator_offset: usize, },
Matched { next_combinator_offset: usize },
/// The selector didn't match.
NotMatched,
}
@ -238,7 +231,7 @@ pub fn matches_compound_selector_from<E>(
element: &E,
) -> CompoundSelectorMatchingResult
where
E: Element
E: Element,
{
if cfg!(debug_assertions) && from_offset != 0 {
selector.combinator_at_parse_order(from_offset - 1); // This asserts.
@ -267,12 +260,12 @@ where
let iter = selector.iter_from(selector.len() - from_offset);
debug_assert!(
iter.clone().next().is_some() || (
from_offset != selector.len() && matches!(
selector.combinator_at_parse_order(from_offset),
Combinator::SlotAssignment | Combinator::PseudoElement
)
),
iter.clone().next().is_some() ||
(from_offset != selector.len() &&
matches!(
selector.combinator_at_parse_order(from_offset),
Combinator::SlotAssignment | Combinator::PseudoElement
)),
"Got the math wrong: {:?} | {:?} | {} {}",
selector,
selector.iter_raw_match_order().as_slice(),
@ -281,12 +274,7 @@ where
);
for component in iter {
if !matches_simple_selector(
component,
element,
&mut local_context,
&mut |_, _| {}
) {
if !matches_simple_selector(component, element, &mut local_context, &mut |_, _| {}) {
return CompoundSelectorMatchingResult::NotMatched;
}
}
@ -294,7 +282,7 @@ where
if from_offset != selector.len() {
return CompoundSelectorMatchingResult::Matched {
next_combinator_offset: from_offset,
}
};
}
CompoundSelectorMatchingResult::FullyMatched
@ -314,8 +302,7 @@ where
{
// If this is the special pseudo-element mode, consume the ::pseudo-element
// before proceeding, since the caller has already handled that part.
if context.matching_mode() == MatchingMode::ForStatelessPseudoElement &&
!context.is_nested() {
if context.matching_mode() == MatchingMode::ForStatelessPseudoElement && !context.is_nested() {
// Consume the pseudo.
match *iter.next().unwrap() {
Component::PseudoElement(ref pseudo) => {
@ -324,19 +311,23 @@ where
return false;
}
}
}
},
_ => {
debug_assert!(false,
"Used MatchingMode::ForStatelessPseudoElement \
in a non-pseudo selector");
}
debug_assert!(
false,
"Used MatchingMode::ForStatelessPseudoElement \
in a non-pseudo selector"
);
},
}
// The only other parser-allowed Component in this sequence is a state
// class. We just don't match in that case.
if let Some(s) = iter.next() {
debug_assert!(matches!(*s, Component::NonTSPseudoClass(..)),
"Someone messed up pseudo-element parsing");
debug_assert!(
matches!(*s, Component::NonTSPseudoClass(..)),
"Someone messed up pseudo-element parsing"
);
return false;
}
@ -347,17 +338,12 @@ where
}
}
let result = matches_complex_selector_internal(
iter,
element,
context,
flags_setter,
Rightmost::Yes,
);
let result =
matches_complex_selector_internal(iter, element, context, flags_setter, Rightmost::Yes);
match result {
SelectorMatchingResult::Matched => true,
_ => false
_ => false,
}
}
@ -378,36 +364,33 @@ fn matches_hover_and_active_quirk<Impl: SelectorImpl>(
// This compound selector had a pseudo-element to the right that we
// intentionally skipped.
if rightmost == Rightmost::Yes &&
context.matching_mode() == MatchingMode::ForStatelessPseudoElement {
context.matching_mode() == MatchingMode::ForStatelessPseudoElement
{
return MatchesHoverAndActiveQuirk::No;
}
let all_match = selector_iter.clone().all(|simple| {
match *simple {
Component::LocalName(_) |
Component::AttributeInNoNamespaceExists { .. } |
Component::AttributeInNoNamespace { .. } |
Component::AttributeOther(_) |
Component::ID(_) |
Component::Class(_) |
Component::PseudoElement(_) |
Component::Negation(_) |
Component::FirstChild |
Component::LastChild |
Component::OnlyChild |
Component::Empty |
Component::NthChild(_, _) |
Component::NthLastChild(_, _) |
Component::NthOfType(_, _) |
Component::NthLastOfType(_, _) |
Component::FirstOfType |
Component::LastOfType |
Component::OnlyOfType => false,
Component::NonTSPseudoClass(ref pseudo_class) => {
pseudo_class.is_active_or_hover()
},
_ => true,
}
let all_match = selector_iter.clone().all(|simple| match *simple {
Component::LocalName(_) |
Component::AttributeInNoNamespaceExists { .. } |
Component::AttributeInNoNamespace { .. } |
Component::AttributeOther(_) |
Component::ID(_) |
Component::Class(_) |
Component::PseudoElement(_) |
Component::Negation(_) |
Component::FirstChild |
Component::LastChild |
Component::OnlyChild |
Component::Empty |
Component::NthChild(_, _) |
Component::NthLastChild(_, _) |
Component::NthOfType(_, _) |
Component::NthLastOfType(_, _) |
Component::FirstOfType |
Component::LastOfType |
Component::OnlyOfType => false,
Component::NonTSPseudoClass(ref pseudo_class) => pseudo_class.is_active_or_hover(),
_ => true,
});
if all_match {
@ -433,19 +416,15 @@ where
E: Element,
{
match combinator {
Combinator::NextSibling |
Combinator::LaterSibling => {
element.prev_sibling_element()
}
Combinator::Child |
Combinator::Descendant => {
Combinator::NextSibling | Combinator::LaterSibling => element.prev_sibling_element(),
Combinator::Child | Combinator::Descendant => {
if element.blocks_ancestor_combinators() {
return None;
}
match element.parent_element() {
Some(e) => return Some(e),
None => {}
None => {},
}
if !element.parent_node_is_shadow_root() {
@ -473,14 +452,16 @@ where
}
element.containing_shadow_host()
}
},
Combinator::SlotAssignment => {
debug_assert!(element.assigned_slot().map_or(true, |s| s.is_html_slot_element()));
debug_assert!(
element
.assigned_slot()
.map_or(true, |s| s.is_html_slot_element())
);
element.assigned_slot()
}
Combinator::PseudoElement => {
element.pseudo_element_originating_element()
}
},
Combinator::PseudoElement => element.pseudo_element_originating_element(),
}
}
@ -495,19 +476,25 @@ where
E: Element,
F: FnMut(&E, ElementSelectorFlags),
{
debug!("Matching complex selector {:?} for {:?}", selector_iter, element);
debug!(
"Matching complex selector {:?} for {:?}",
selector_iter, element
);
let matches_compound_selector = matches_compound_selector(
&mut selector_iter,
element,
context,
flags_setter,
rightmost
rightmost,
);
let combinator = selector_iter.next_sequence();
if combinator.map_or(false, |c| c.is_sibling()) {
flags_setter(element, ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS);
flags_setter(
element,
ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS,
);
}
if !matches_compound_selector {
@ -520,20 +507,16 @@ where
};
let candidate_not_found = match combinator {
Combinator::NextSibling |
Combinator::LaterSibling => {
Combinator::NextSibling | Combinator::LaterSibling => {
SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant
}
},
Combinator::Child |
Combinator::Descendant |
Combinator::SlotAssignment |
Combinator::PseudoElement => {
SelectorMatchingResult::NotMatchedGlobally
}
Combinator::PseudoElement => SelectorMatchingResult::NotMatchedGlobally,
};
let mut next_element =
next_element_for_combinator(element, combinator, &selector_iter);
let mut next_element = next_element_for_combinator(element, combinator, &selector_iter);
// Stop matching :visited as soon as we find a link, or a combinator for
// something that isn't an ancestor.
@ -549,16 +532,15 @@ where
Some(next_element) => next_element,
};
let result =
context.with_visited_handling_mode(visited_handling, |context| {
matches_complex_selector_internal(
selector_iter.clone(),
&element,
context,
flags_setter,
Rightmost::No,
)
});
let result = context.with_visited_handling_mode(visited_handling, |context| {
matches_complex_selector_internal(
selector_iter.clone(),
&element,
context,
flags_setter,
Rightmost::No,
)
});
match (result, combinator) {
// Return the status immediately.
@ -566,22 +548,24 @@ where
(SelectorMatchingResult::NotMatchedGlobally, _) |
(_, Combinator::NextSibling) => {
return result;
}
},
// Upgrade the failure status to
// NotMatchedAndRestartFromClosestDescendant.
(_, Combinator::PseudoElement) |
(_, Combinator::Child) => {
(_, Combinator::PseudoElement) | (_, Combinator::Child) => {
return SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant;
}
},
// If the failure status is
// NotMatchedAndRestartFromClosestDescendant and combinator is
// Combinator::LaterSibling, give up this Combinator::LaterSibling
// matching and restart from the closest descendant combinator.
(SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant, Combinator::LaterSibling) => {
(
SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant,
Combinator::LaterSibling,
) => {
return result;
}
},
// The Combinator::Descendant combinator and the status is
// NotMatchedAndRestartFromClosestLaterSibling or
@ -596,23 +580,19 @@ where
visited_handling = VisitedHandlingMode::AllLinksUnvisited;
}
next_element =
next_element_for_combinator(&element, combinator, &selector_iter);
next_element = next_element_for_combinator(&element, combinator, &selector_iter);
}
}
#[inline]
fn matches_local_name<E>(
element: &E,
local_name: &LocalName<E::Impl>
) -> bool
fn matches_local_name<E>(element: &E, local_name: &LocalName<E::Impl>) -> bool
where
E: Element,
{
let name = select_name(
element.is_html_element_in_html_document(),
&local_name.name,
&local_name.lower_name
&local_name.lower_name,
).borrow();
element.local_name() == name
}
@ -661,19 +641,13 @@ where
None => return true,
};
let mut local_context =
LocalMatchingContext {
shared: context,
matches_hover_and_active_quirk,
};
iter::once(selector).chain(selector_iter).all(|simple| {
matches_simple_selector(
simple,
element,
&mut local_context,
flags_setter,
)
})
let mut local_context = LocalMatchingContext {
shared: context,
matches_hover_and_active_quirk,
};
iter::once(selector)
.chain(selector_iter)
.all(|simple| matches_simple_selector(simple, element, &mut local_context, flags_setter))
}
/// Determines whether the given element matches the given single selector.
@ -693,49 +667,40 @@ where
Component::Combinator(_) => unreachable!(),
Component::Slotted(ref selector) => {
// <slots> are never flattened tree slottables.
!element.is_html_slot_element() &&
element.assigned_slot().is_some() &&
context.shared.nest(|context| {
matches_complex_selector(
selector.iter(),
element,
context,
flags_setter,
)
})
}
!element.is_html_slot_element() && element.assigned_slot().is_some() &&
context.shared.nest(|context| {
matches_complex_selector(selector.iter(), element, context, flags_setter)
})
},
Component::PseudoElement(ref pseudo) => {
element.match_pseudo_element(pseudo, context.shared)
}
Component::LocalName(ref local_name) => {
matches_local_name(element, local_name)
}
Component::ExplicitUniversalType |
Component::ExplicitAnyNamespace => {
true
}
Component::Namespace(_, ref url) |
Component::DefaultNamespace(ref url) => {
},
Component::LocalName(ref local_name) => matches_local_name(element, local_name),
Component::ExplicitUniversalType | Component::ExplicitAnyNamespace => true,
Component::Namespace(_, ref url) | Component::DefaultNamespace(ref url) => {
element.namespace() == url.borrow()
}
},
Component::ExplicitNoNamespace => {
let ns = ::parser::namespace_empty_string::<E::Impl>();
element.namespace() == ns.borrow()
}
},
Component::ID(ref id) => {
element.has_id(id, context.shared.classes_and_ids_case_sensitivity())
}
},
Component::Class(ref class) => {
element.has_class(class, context.shared.classes_and_ids_case_sensitivity())
}
Component::AttributeInNoNamespaceExists { ref local_name, ref local_name_lower } => {
},
Component::AttributeInNoNamespaceExists {
ref local_name,
ref local_name_lower,
} => {
let is_html = element.is_html_element_in_html_document();
element.attr_matches(
&NamespaceConstraint::Specific(&::parser::namespace_empty_string::<E::Impl>()),
select_name(is_html, local_name, local_name_lower),
&AttrSelectorOperation::Exists
&AttrSelectorOperation::Exists,
)
}
},
Component::AttributeInNoNamespace {
ref local_name,
ref local_name_lower,
@ -745,7 +710,7 @@ where
never_matches,
} => {
if never_matches {
return false
return false;
}
let is_html = element.is_html_element_in_html_document();
element.attr_matches(
@ -755,12 +720,12 @@ where
operator: operator,
case_sensitivity: case_sensitivity.to_unconditional(is_html),
expected_value: value,
}
},
)
}
},
Component::AttributeOther(ref attr_sel) => {
if attr_sel.never_matches {
return false
return false;
}
let is_html = element.is_html_element_in_html_document();
element.attr_matches(
@ -772,105 +737,80 @@ where
operator,
case_sensitivity,
ref expected_value,
} => {
AttrSelectorOperation::WithValue {
operator: operator,
case_sensitivity: case_sensitivity.to_unconditional(is_html),
expected_value: expected_value,
}
}
}
} => AttrSelectorOperation::WithValue {
operator: operator,
case_sensitivity: case_sensitivity.to_unconditional(is_html),
expected_value: expected_value,
},
},
)
}
},
Component::NonTSPseudoClass(ref pc) => {
if context.matches_hover_and_active_quirk == MatchesHoverAndActiveQuirk::Yes &&
!context.shared.is_nested() &&
pc.is_active_or_hover() &&
!element.is_link()
!context.shared.is_nested() && pc.is_active_or_hover() &&
!element.is_link()
{
return false;
}
element.match_non_ts_pseudo_class(
pc,
&mut context.shared,
flags_setter
)
}
Component::FirstChild => {
matches_first_child(element, flags_setter)
}
Component::LastChild => {
matches_last_child(element, flags_setter)
}
element.match_non_ts_pseudo_class(pc, &mut context.shared, flags_setter)
},
Component::FirstChild => matches_first_child(element, flags_setter),
Component::LastChild => matches_last_child(element, flags_setter),
Component::OnlyChild => {
matches_first_child(element, flags_setter) &&
matches_last_child(element, flags_setter)
}
Component::Root => {
element.is_root()
}
matches_first_child(element, flags_setter) && matches_last_child(element, flags_setter)
},
Component::Root => element.is_root(),
Component::Empty => {
flags_setter(element, ElementSelectorFlags::HAS_EMPTY_SELECTOR);
element.is_empty()
}
},
Component::Host(ref selector) => {
context.shared.shadow_host().map_or(false, |host| host == element.opaque()) &&
selector.as_ref().map_or(true, |selector| {
context.shared.nest(|context| {
matches_complex_selector(
selector.iter(),
element,
context,
flags_setter,
)
context
.shared
.shadow_host()
.map_or(false, |host| host == element.opaque()) &&
selector.as_ref().map_or(true, |selector| {
context.shared.nest(|context| {
matches_complex_selector(selector.iter(), element, context, flags_setter)
})
})
})
}
Component::Scope => {
match context.shared.scope_element {
Some(ref scope_element) => element.opaque() == *scope_element,
None => element.is_root(),
}
}
},
Component::Scope => match context.shared.scope_element {
Some(ref scope_element) => element.opaque() == *scope_element,
None => element.is_root(),
},
Component::NthChild(a, b) => {
matches_generic_nth_child(element, context, a, b, false, false, flags_setter)
}
},
Component::NthLastChild(a, b) => {
matches_generic_nth_child(element, context, a, b, false, true, flags_setter)
}
},
Component::NthOfType(a, b) => {
matches_generic_nth_child(element, context, a, b, true, false, flags_setter)
}
},
Component::NthLastOfType(a, b) => {
matches_generic_nth_child(element, context, a, b, true, true, flags_setter)
}
},
Component::FirstOfType => {
matches_generic_nth_child(element, context, 0, 1, true, false, flags_setter)
}
},
Component::LastOfType => {
matches_generic_nth_child(element, context, 0, 1, true, true, flags_setter)
}
},
Component::OnlyOfType => {
matches_generic_nth_child(element, context, 0, 1, true, false, flags_setter) &&
matches_generic_nth_child(element, context, 0, 1, true, true, flags_setter)
}
Component::Negation(ref negated) => {
context.shared.nest_for_negation(|context| {
let mut local_context = LocalMatchingContext {
matches_hover_and_active_quirk: MatchesHoverAndActiveQuirk::No,
shared: context,
};
!negated.iter().all(|ss| {
matches_simple_selector(
ss,
element,
&mut local_context,
flags_setter,
)
})
})
}
matches_generic_nth_child(element, context, 0, 1, true, true, flags_setter)
},
Component::Negation(ref negated) => context.shared.nest_for_negation(|context| {
let mut local_context = LocalMatchingContext {
matches_hover_and_active_quirk: MatchesHoverAndActiveQuirk::No,
shared: context,
};
!negated
.iter()
.all(|ss| matches_simple_selector(ss, element, &mut local_context, flags_setter))
}),
}
}
@ -901,26 +841,40 @@ where
return false;
}
flags_setter(element, if is_from_end {
ElementSelectorFlags::HAS_SLOW_SELECTOR
} else {
ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS
});
flags_setter(
element,
if is_from_end {
ElementSelectorFlags::HAS_SLOW_SELECTOR
} else {
ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS
},
);
// Grab a reference to the appropriate cache.
let mut cache = context.shared.nth_index_cache.as_mut().map(|c| {
c.get(is_of_type, is_from_end)
});
let mut cache = context
.shared
.nth_index_cache
.as_mut()
.map(|c| c.get(is_of_type, is_from_end));
// Lookup or compute the index.
let index = if let Some(i) = cache.as_mut().and_then(|c| c.lookup(element.opaque())) {
i
} else {
let i = nth_child_index(element, is_of_type, is_from_end, cache.as_mut().map(|s| &mut **s));
let i = nth_child_index(
element,
is_of_type,
is_from_end,
cache.as_mut().map(|s| &mut **s),
);
cache.as_mut().map(|c| c.insert(element.opaque(), i));
i
};
debug_assert_eq!(index, nth_child_index(element, is_of_type, is_from_end, None), "invalid cache");
debug_assert_eq!(
index,
nth_child_index(element, is_of_type, is_from_end, None),
"invalid cache"
);
// Is there a non-negative integer n such that An+B=index?
match index.checked_sub(b) {
@ -934,8 +888,7 @@ where
#[inline]
fn same_type<E: Element>(a: &E, b: &E) -> bool {
a.local_name() == b.local_name() &&
a.namespace() == b.namespace()
a.local_name() == b.local_name() && a.namespace() == b.namespace()
}
#[inline]
@ -972,7 +925,13 @@ where
let mut index: i32 = 1;
let mut curr = element.clone();
let next = |e: E| if is_from_end { e.next_sibling_element() } else { e.prev_sibling_element() };
let next = |e: E| {
if is_from_end {
e.next_sibling_element()
} else {
e.prev_sibling_element()
}
};
while let Some(e) = next(curr) {
curr = e;
if !is_of_type || same_type(element, &curr) {
@ -981,7 +940,7 @@ where
// function.
if !is_from_end {
if let Some(i) = cache.as_mut().and_then(|c| c.lookup(curr.opaque())) {
return i + index
return i + index;
}
}
index += 1;

View file

@ -20,11 +20,7 @@ pub struct NthIndexCache {
impl NthIndexCache {
/// Gets the appropriate cache for the given parameters.
pub fn get(
&mut self,
is_of_type: bool,
is_from_end: bool
) -> &mut NthIndexCacheInner {
pub fn get(&mut self, is_of_type: bool, is_from_end: bool) -> &mut NthIndexCacheInner {
match (is_of_type, is_from_end) {
(false, false) => &mut self.nth,
(false, true) => &mut self.nth_last,

File diff suppressed because it is too large Load diff

View file

@ -5,7 +5,7 @@
//! Traits that nodes must implement. Breaks the otherwise-cyclic dependency
//! between layout and style.
use attr::{AttrSelectorOperation, NamespaceConstraint, CaseSensitivity};
use attr::{AttrSelectorOperation, CaseSensitivity, NamespaceConstraint};
use matching::{ElementSelectorFlags, MatchingContext};
use parser::SelectorImpl;
use servo_arc::NonZeroPtrMut;

View file

@ -38,9 +38,7 @@ pub trait SelectorVisitor {
///
/// Gets the combinator to the right of the selector, or `None` if the
/// selector is the rightmost one.
fn visit_complex_selector(&mut self,
_combinator_to_right: Option<Combinator>)
-> bool {
fn visit_complex_selector(&mut self, _combinator_to_right: Option<Combinator>) -> bool {
true
}
}

View file

@ -24,7 +24,8 @@
#![allow(missing_docs)]
extern crate nodrop;
#[cfg(feature = "servo")] extern crate serde;
#[cfg(feature = "servo")]
extern crate serde;
extern crate stable_deref_trait;
use nodrop::NoDrop;
@ -186,7 +187,9 @@ impl<T> Arc<T> {
count: atomic::AtomicUsize::new(1),
data: data,
});
Arc { p: NonZeroPtrMut::new(Box::into_raw(x)) }
Arc {
p: NonZeroPtrMut::new(Box::into_raw(x)),
}
}
#[inline]
@ -217,7 +220,8 @@ impl<T> Arc<T> {
/// provided callback. The refcount is not modified.
#[inline(always)]
pub fn with_raw_offset_arc<F, U>(&self, f: F) -> U
where F: FnOnce(&RawOffsetArc<T>) -> U
where
F: FnOnce(&RawOffsetArc<T>) -> U,
{
// Synthesize transient Arc, which never touches the refcount of the ArcInner.
let transient = unsafe { NoDrop::new(Arc::into_raw_offset(ptr::read(self))) };
@ -256,7 +260,6 @@ impl<T: ?Sized> Arc<T> {
let _ = Box::from_raw(self.ptr());
}
#[inline]
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
this.ptr() == other.ptr()
@ -296,7 +299,9 @@ impl<T: ?Sized> Clone for Arc<T> {
process::abort();
}
Arc { p: NonZeroPtrMut::new(self.ptr()) }
Arc {
p: NonZeroPtrMut::new(self.ptr()),
}
}
}
@ -484,8 +489,7 @@ unsafe impl<T: ?Sized> StableDeref for Arc<T> {}
unsafe impl<T: ?Sized> CloneStableDeref for Arc<T> {}
#[cfg(feature = "servo")]
impl<'de, T: Deserialize<'de>> Deserialize<'de> for Arc<T>
{
impl<'de, T: Deserialize<'de>> Deserialize<'de> for Arc<T> {
fn deserialize<D>(deserializer: D) -> Result<Arc<T>, D::Error>
where
D: ::serde::de::Deserializer<'de>,
@ -495,8 +499,7 @@ impl<'de, T: Deserialize<'de>> Deserialize<'de> for Arc<T>
}
#[cfg(feature = "servo")]
impl<T: Serialize> Serialize for Arc<T>
{
impl<T: Serialize> Serialize for Arc<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ::serde::ser::Serializer,
@ -526,9 +529,10 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> {
/// iterator to generate the slice. The resulting Arc will be fat.
#[inline]
pub fn from_header_and_iter<I>(header: H, mut items: I) -> Self
where I: Iterator<Item=T> + ExactSizeIterator
where
I: Iterator<Item = T> + ExactSizeIterator,
{
use ::std::mem::size_of;
use std::mem::size_of;
assert_ne!(size_of::<T>(), 0, "Need to think about ZST");
// Compute the required size for the allocation.
@ -592,18 +596,32 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> {
ptr::write(&mut ((*ptr).data.header), header);
let mut current: *mut T = &mut (*ptr).data.slice[0];
for _ in 0..num_items {
ptr::write(current, items.next().expect("ExactSizeIterator over-reported length"));
ptr::write(
current,
items
.next()
.expect("ExactSizeIterator over-reported length"),
);
current = current.offset(1);
}
assert!(items.next().is_none(), "ExactSizeIterator under-reported length");
assert!(
items.next().is_none(),
"ExactSizeIterator under-reported length"
);
// We should have consumed the buffer exactly.
debug_assert_eq!(current as *mut u8, buffer.offset(size as isize));
}
// Return the fat Arc.
assert_eq!(size_of::<Self>(), size_of::<usize>() * 2, "The Arc will be fat");
Arc { p: NonZeroPtrMut::new(ptr) }
assert_eq!(
size_of::<Self>(),
size_of::<usize>() * 2,
"The Arc will be fat"
);
Arc {
p: NonZeroPtrMut::new(ptr),
}
}
#[inline]
@ -647,13 +665,11 @@ unsafe impl<H: Sync + Send, T: Sync + Send> Sync for ThinArc<H, T> {}
// Synthesize a fat pointer from a thin pointer.
//
// See the comment around the analogous operation in from_header_and_iter.
fn thin_to_thick<H, T>(thin: *mut ArcInner<HeaderSliceWithLength<H, [T; 1]>>)
-> *mut ArcInner<HeaderSliceWithLength<H, [T]>>
{
fn thin_to_thick<H, T>(
thin: *mut ArcInner<HeaderSliceWithLength<H, [T; 1]>>,
) -> *mut ArcInner<HeaderSliceWithLength<H, [T]>> {
let len = unsafe { (*thin).data.header.length };
let fake_slice: *mut [T] = unsafe {
slice::from_raw_parts_mut(thin as *mut T, len)
};
let fake_slice: *mut [T] = unsafe { slice::from_raw_parts_mut(thin as *mut T, len) };
fake_slice as *mut ArcInner<HeaderSliceWithLength<H, [T]>>
}
@ -663,11 +679,12 @@ impl<H: 'static, T: 'static> ThinArc<H, T> {
/// provided callback. The refcount is not modified.
#[inline]
pub fn with_arc<F, U>(&self, f: F) -> U
where F: FnOnce(&Arc<HeaderSliceWithLength<H, [T]>>) -> U
where
F: FnOnce(&Arc<HeaderSliceWithLength<H, [T]>>) -> U,
{
// Synthesize transient Arc, which never touches the refcount of the ArcInner.
let transient = NoDrop::new(Arc {
p: NonZeroPtrMut::new(thin_to_thick(self.ptr))
p: NonZeroPtrMut::new(thin_to_thick(self.ptr)),
});
// Expose the transient Arc to the callback, which may clone it if it wants.
@ -718,13 +735,16 @@ impl<H: 'static, T: 'static> Arc<HeaderSliceWithLength<H, [T]>> {
/// is not modified.
#[inline]
pub fn into_thin(a: Self) -> ThinArc<H, T> {
assert_eq!(a.header.length, a.slice.len(),
"Length needs to be correct for ThinArc to work");
assert_eq!(
a.header.length,
a.slice.len(),
"Length needs to be correct for ThinArc to work"
);
let fat_ptr: *mut ArcInner<HeaderSliceWithLength<H, [T]>> = a.ptr();
mem::forget(a);
let thin_ptr = fat_ptr as *mut [usize] as *mut usize;
ThinArc {
ptr: thin_ptr as *mut ArcInner<HeaderSliceWithLength<H, [T; 1]>>
ptr: thin_ptr as *mut ArcInner<HeaderSliceWithLength<H, [T; 1]>>,
}
}
@ -735,7 +755,7 @@ impl<H: 'static, T: 'static> Arc<HeaderSliceWithLength<H, [T]>> {
let ptr = thin_to_thick(a.ptr);
mem::forget(a);
Arc {
p: NonZeroPtrMut::new(ptr)
p: NonZeroPtrMut::new(ptr),
}
}
}
@ -743,11 +763,7 @@ impl<H: 'static, T: 'static> Arc<HeaderSliceWithLength<H, [T]>> {
impl<H: PartialEq + 'static, T: PartialEq + 'static> PartialEq for ThinArc<H, T> {
#[inline]
fn eq(&self, other: &ThinArc<H, T>) -> bool {
ThinArc::with_arc(self, |a| {
ThinArc::with_arc(other, |b| {
*a == *b
})
})
ThinArc::with_arc(self, |a| ThinArc::with_arc(other, |b| *a == *b))
}
}
@ -793,11 +809,12 @@ impl<T: 'static> Clone for RawOffsetArc<T> {
impl<T: 'static> Drop for RawOffsetArc<T> {
fn drop(&mut self) {
let _ = Arc::from_raw_offset(RawOffsetArc { ptr: self.ptr.clone() });
let _ = Arc::from_raw_offset(RawOffsetArc {
ptr: self.ptr.clone(),
});
}
}
impl<T: fmt::Debug + 'static> fmt::Debug for RawOffsetArc<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
@ -819,7 +836,8 @@ impl<T: 'static> RawOffsetArc<T> {
/// provided callback. The refcount is not modified.
#[inline]
pub fn with_arc<F, U>(&self, f: F) -> U
where F: FnOnce(&Arc<T>) -> U
where
F: FnOnce(&Arc<T>) -> U,
{
// Synthesize transient Arc, which never touches the refcount of the ArcInner.
let transient = unsafe { NoDrop::new(Arc::from_raw(self.ptr.ptr())) };
@ -839,7 +857,10 @@ impl<T: 'static> RawOffsetArc<T> {
/// If uniquely owned, provide a mutable reference
/// Else create a copy, and mutate that
#[inline]
pub fn make_mut(&mut self) -> &mut T where T: Clone {
pub fn make_mut(&mut self) -> &mut T
where
T: Clone,
{
unsafe {
// extract the RawOffsetArc as an owned variable
let this = ptr::read(self);
@ -931,7 +952,11 @@ impl<'a, T> ArcBorrow<'a, T> {
}
#[inline]
pub fn with_arc<F, U>(&self, f: F) -> U where F: FnOnce(&Arc<T>) -> U, T: 'static {
pub fn with_arc<F, U>(&self, f: F) -> U
where
F: FnOnce(&Arc<T>) -> U,
T: 'static,
{
// Synthesize transient Arc, which never touches the refcount.
let transient = unsafe { NoDrop::new(Arc::from_raw(self.0)) };
@ -970,7 +995,9 @@ mod tests {
impl Drop for Canary {
fn drop(&mut self) {
unsafe { (*self.0).fetch_add(1, SeqCst); }
unsafe {
(*self.0).fetch_add(1, SeqCst);
}
}
}

View file

@ -103,14 +103,13 @@ impl KeyframesAnimationState {
// Update the next iteration direction if applicable.
match self.direction {
AnimationDirection::Alternate |
AnimationDirection::AlternateReverse => {
AnimationDirection::Alternate | AnimationDirection::AlternateReverse => {
self.current_direction = match self.current_direction {
AnimationDirection::Normal => AnimationDirection::Reverse,
AnimationDirection::Reverse => AnimationDirection::Normal,
_ => unreachable!(),
};
}
},
_ => {},
}
@ -124,12 +123,13 @@ impl KeyframesAnimationState {
///
/// There are some bits of state we can't just replace, over all taking in
/// account times, so here's that logic.
pub fn update_from_other(&mut self,
other: &Self,
timer: &Timer) {
pub fn update_from_other(&mut self, other: &Self, timer: &Timer) {
use self::KeyframesRunningState::*;
debug!("KeyframesAnimationState::update_from_other({:?}, {:?})", self, other);
debug!(
"KeyframesAnimationState::update_from_other({:?}, {:?})",
self, other
);
// NB: We shall not touch the started_at field, since we don't want to
// restart the animation.
@ -149,12 +149,13 @@ impl KeyframesAnimationState {
//
// If we're pausing the animation, compute the progress value.
match (&mut self.running_state, old_running_state) {
(&mut Running, Paused(progress))
=> new_started_at = timer.seconds() - (self.duration * progress),
(&mut Paused(ref mut new), Paused(old))
=> *new = old,
(&mut Paused(ref mut progress), Running)
=> *progress = (timer.seconds() - old_started_at) / old_duration,
(&mut Running, Paused(progress)) => {
new_started_at = timer.seconds() - (self.duration * progress)
},
(&mut Paused(ref mut new), Paused(old)) => *new = old,
(&mut Paused(ref mut progress), Running) => {
*progress = (timer.seconds() - old_started_at) / old_duration
},
_ => {},
}
@ -162,9 +163,11 @@ impl KeyframesAnimationState {
// TODO: see how changing the limit affects rendering in other browsers.
// We might need to keep the iteration count even when it's infinite.
match (&mut self.iteration_state, old_iteration_state) {
(&mut KeyframesIterationState::Finite(ref mut iters, _), KeyframesIterationState::Finite(old_iters, _))
=> *iters = old_iters,
_ => {}
(
&mut KeyframesIterationState::Finite(ref mut iters, _),
KeyframesIterationState::Finite(old_iters, _),
) => *iters = old_iters,
_ => {},
}
self.current_direction = old_direction;
@ -242,7 +245,6 @@ impl Animation {
}
}
/// A single animation frame of a single property.
#[derive(Clone, Debug)]
pub struct AnimationFrame {
@ -284,8 +286,9 @@ impl PropertyAnimation {
match transition_property {
TransitionProperty::Unsupported(_) => result,
TransitionProperty::Shorthand(ref shorthand_id) => {
shorthand_id.longhands().filter_map(|longhand| {
TransitionProperty::Shorthand(ref shorthand_id) => shorthand_id
.longhands()
.filter_map(|longhand| {
PropertyAnimation::from_longhand(
longhand,
timing_function,
@ -293,8 +296,8 @@ impl PropertyAnimation {
old_style,
new_style,
)
}).collect()
}
})
.collect(),
TransitionProperty::Longhand(longhand_id) => {
let animation = PropertyAnimation::from_longhand(
longhand_id,
@ -308,7 +311,7 @@ impl PropertyAnimation {
result.push(animation);
}
result
}
},
}
}
@ -319,11 +322,7 @@ impl PropertyAnimation {
old_style: &ComputedValues,
new_style: &ComputedValues,
) -> Option<PropertyAnimation> {
let animated_property = AnimatedProperty::from_longhand(
longhand,
old_style,
new_style,
)?;
let animated_property = AnimatedProperty::from_longhand(longhand, old_style, new_style)?;
let property_animation = PropertyAnimation {
property: animated_property,
@ -398,14 +397,13 @@ pub fn start_transitions_if_applicable(
old_style: &ComputedValues,
new_style: &mut Arc<ComputedValues>,
timer: &Timer,
possibly_expired_animations: &[PropertyAnimation]
possibly_expired_animations: &[PropertyAnimation],
) -> bool {
let mut had_animations = false;
for i in 0..new_style.get_box().transition_property_count() {
// Create any property animations, if applicable.
let property_animations = PropertyAnimation::from_transition(i,
old_style,
Arc::make_mut(new_style));
let property_animations =
PropertyAnimation::from_transition(i, old_style, Arc::make_mut(new_style));
for property_animation in property_animations {
// Set the property to the initial value.
//
@ -418,22 +416,28 @@ pub fn start_transitions_if_applicable(
// running on the same node.
//
// [1]: https://drafts.csswg.org/css-transitions/#starting
if possibly_expired_animations.iter().any(|animation| {
animation.has_the_same_end_value_as(&property_animation)
}) {
continue
if possibly_expired_animations
.iter()
.any(|animation| animation.has_the_same_end_value_as(&property_animation))
{
continue;
}
// Kick off the animation.
let box_style = new_style.get_box();
let now = timer.seconds();
let start_time =
now + (box_style.transition_delay_mod(i).seconds() as f64);
let start_time = now + (box_style.transition_delay_mod(i).seconds() as f64);
new_animations_sender
.send(Animation::Transition(opaque_node, start_time, AnimationFrame {
duration: box_style.transition_duration_mod(i).seconds() as f64,
property_animation: property_animation,
}, /* is_expired = */ false)).unwrap();
.send(Animation::Transition(
opaque_node,
start_time,
AnimationFrame {
duration: box_style.transition_duration_mod(i).seconds() as f64,
property_animation: property_animation,
},
/* is_expired = */ false,
))
.unwrap();
had_animations = true;
}
@ -454,7 +458,9 @@ where
{
match step.value {
KeyframesStepValue::ComputedValues => style_from_cascade.clone(),
KeyframesStepValue::Declarations { block: ref declarations } => {
KeyframesStepValue::Declarations {
block: ref declarations,
} => {
let guard = declarations.read_with(context.guards.author);
let iter = || {
@ -462,33 +468,33 @@ where
// so we have to filter them out.
// See the spec issue https://github.com/w3c/csswg-drafts/issues/1824
// Also we filter our non-animatable properties.
guard.normal_declaration_iter()
.filter(|declaration| declaration.is_animatable())
.map(|decl| (decl, CascadeLevel::Animations))
guard
.normal_declaration_iter()
.filter(|declaration| declaration.is_animatable())
.map(|decl| (decl, CascadeLevel::Animations))
};
// This currently ignores visited styles, which seems acceptable,
// as existing browsers don't appear to animate visited styles.
let computed =
properties::apply_declarations::<E, _, _>(
context.stylist.device(),
/* pseudo = */ None,
previous_style.rules(),
&context.guards,
iter,
Some(previous_style),
Some(previous_style),
Some(previous_style),
/* visited_style = */ None,
font_metrics_provider,
CascadeFlags::empty(),
context.quirks_mode(),
/* rule_cache = */ None,
&mut Default::default(),
/* element = */ None,
);
let computed = properties::apply_declarations::<E, _, _>(
context.stylist.device(),
/* pseudo = */ None,
previous_style.rules(),
&context.guards,
iter,
Some(previous_style),
Some(previous_style),
Some(previous_style),
/* visited_style = */ None,
font_metrics_provider,
CascadeFlags::empty(),
context.quirks_mode(),
/* rule_cache = */ None,
&mut Default::default(),
/* element = */ None,
);
computed
}
},
}
}
@ -507,13 +513,13 @@ pub fn maybe_start_animations(
let name = if let Some(atom) = name.as_atom() {
atom
} else {
continue
continue;
};
debug!("maybe_start_animations: name={}", name);
let total_duration = box_style.animation_duration_mod(i).seconds();
if total_duration == 0. {
continue
continue;
}
if let Some(ref anim) = context.stylist.get_animation(name) {
@ -539,10 +545,12 @@ pub fn maybe_start_animations(
let animation_direction = box_style.animation_direction_mod(i);
let initial_direction = match animation_direction {
AnimationDirection::Normal |
AnimationDirection::Alternate => AnimationDirection::Normal,
AnimationDirection::Reverse |
AnimationDirection::AlternateReverse => AnimationDirection::Reverse,
AnimationDirection::Normal | AnimationDirection::Alternate => {
AnimationDirection::Normal
},
AnimationDirection::Reverse | AnimationDirection::AlternateReverse => {
AnimationDirection::Reverse
},
};
let running_state = match box_style.animation_play_state_mod(i) {
@ -550,19 +558,23 @@ pub fn maybe_start_animations(
AnimationPlayState::Running => KeyframesRunningState::Running,
};
new_animations_sender
.send(Animation::Keyframes(node, name.clone(), KeyframesAnimationState {
started_at: animation_start,
duration: duration as f64,
delay: delay as f64,
iteration_state: iteration_state,
running_state: running_state,
direction: animation_direction,
current_direction: initial_direction,
expired: false,
cascade_style: new_style.clone(),
})).unwrap();
.send(Animation::Keyframes(
node,
name.clone(),
KeyframesAnimationState {
started_at: animation_start,
duration: duration as f64,
delay: delay as f64,
iteration_state: iteration_state,
running_state: running_state,
direction: animation_direction,
current_direction: initial_direction,
expired: false,
cascade_style: new_style.clone(),
},
))
.unwrap();
had_animations = true;
}
}
@ -572,10 +584,12 @@ pub fn maybe_start_animations(
/// Updates a given computed style for a given animation frame. Returns a bool
/// representing if the style was indeed updated.
pub fn update_style_for_animation_frame(mut new_style: &mut Arc<ComputedValues>,
now: f64,
start_time: f64,
frame: &AnimationFrame) -> bool {
pub fn update_style_for_animation_frame(
mut new_style: &mut Arc<ComputedValues>,
now: f64,
start_time: f64,
frame: &AnimationFrame,
) -> bool {
let mut progress = (now - start_time) / frame.duration;
if progress > 1.0 {
progress = 1.0
@ -585,7 +599,9 @@ pub fn update_style_for_animation_frame(mut new_style: &mut Arc<ComputedValues>,
return false;
}
frame.property_animation.update(Arc::make_mut(&mut new_style), progress);
frame
.property_animation
.update(Arc::make_mut(&mut new_style), progress);
true
}
@ -595,8 +611,7 @@ pub fn update_style_for_animation<E>(
animation: &Animation,
style: &mut Arc<ComputedValues>,
font_metrics_provider: &FontMetricsProvider,
)
where
) where
E: TElement,
{
debug!("update_style_for_animation: entering");
@ -607,15 +622,17 @@ where
debug!("update_style_for_animation: transition found");
let now = context.timer.seconds();
let mut new_style = (*style).clone();
let updated_style = update_style_for_animation_frame(&mut new_style,
now, start_time,
frame);
let updated_style =
update_style_for_animation_frame(&mut new_style, now, start_time, frame);
if updated_style {
*style = new_style
}
}
},
Animation::Keyframes(_, ref name, ref state) => {
debug!("update_style_for_animation: animation found: \"{}\", {:?}", name, state);
debug!(
"update_style_for_animation: animation found: \"{}\", {:?}",
name, state
);
let duration = state.duration;
let started_at = state.started_at;
@ -628,7 +645,7 @@ where
None => {
warn!("update_style_for_animation: Animation {:?} not found", name);
return;
}
},
Some(animation) => animation,
};
@ -642,14 +659,20 @@ where
let index = match maybe_index {
Some(index) => index,
None => {
warn!("update_style_for_animation: Animation {:?} not found in style", name);
warn!(
"update_style_for_animation: Animation {:?} not found in style",
name
);
return;
}
},
};
let total_duration = style.get_box().animation_duration_mod(index).seconds() as f64;
if total_duration == 0. {
debug!("update_style_for_animation: zero duration for animation {:?}", name);
debug!(
"update_style_for_animation: zero duration for animation {:?}",
name
);
return;
}
@ -662,38 +685,50 @@ where
total_progress = 1.;
}
debug!("update_style_for_animation: anim \"{}\", steps: {:?}, state: {:?}, progress: {}",
name, animation.steps, state, total_progress);
debug!(
"update_style_for_animation: anim \"{}\", steps: {:?}, state: {:?}, progress: {}",
name, animation.steps, state, total_progress
);
// Get the target and the last keyframe position.
let last_keyframe_position;
let target_keyframe_position;
match state.current_direction {
AnimationDirection::Normal => {
target_keyframe_position =
animation.steps.iter().position(|step| {
total_progress as f32 <= step.start_percentage.0
});
target_keyframe_position = animation
.steps
.iter()
.position(|step| total_progress as f32 <= step.start_percentage.0);
last_keyframe_position = target_keyframe_position.and_then(|pos| {
if pos != 0 { Some(pos - 1) } else { None }
}).unwrap_or(0);
}
last_keyframe_position = target_keyframe_position
.and_then(|pos| if pos != 0 { Some(pos - 1) } else { None })
.unwrap_or(0);
},
AnimationDirection::Reverse => {
target_keyframe_position =
animation.steps.iter().rev().position(|step| {
total_progress as f32 <= 1. - step.start_percentage.0
}).map(|pos| animation.steps.len() - pos - 1);
target_keyframe_position = animation
.steps
.iter()
.rev()
.position(|step| total_progress as f32 <= 1. - step.start_percentage.0)
.map(|pos| animation.steps.len() - pos - 1);
last_keyframe_position = target_keyframe_position.and_then(|pos| {
if pos != animation.steps.len() - 1 { Some(pos + 1) } else { None }
}).unwrap_or(animation.steps.len() - 1);
}
last_keyframe_position = target_keyframe_position
.and_then(|pos| {
if pos != animation.steps.len() - 1 {
Some(pos + 1)
} else {
None
}
})
.unwrap_or(animation.steps.len() - 1);
},
_ => unreachable!(),
}
debug!("update_style_for_animation: keyframe from {:?} to {:?}",
last_keyframe_position, target_keyframe_position);
debug!(
"update_style_for_animation: keyframe from {:?} to {:?}",
last_keyframe_position, target_keyframe_position
);
let target_keyframe = match target_keyframe_position {
Some(target) => &animation.steps[target],
@ -701,20 +736,22 @@ where
warn!("update_style_for_animation: No current keyframe found for animation \"{}\" at progress {}",
name, total_progress);
return;
}
},
};
let last_keyframe = &animation.steps[last_keyframe_position];
let relative_timespan = (target_keyframe.start_percentage.0 - last_keyframe.start_percentage.0).abs();
let relative_timespan =
(target_keyframe.start_percentage.0 - last_keyframe.start_percentage.0).abs();
let relative_duration = relative_timespan as f64 * duration;
let last_keyframe_ended_at = match state.current_direction {
AnimationDirection::Normal => {
state.started_at + (total_duration * last_keyframe.start_percentage.0 as f64)
}
},
AnimationDirection::Reverse => {
state.started_at + (total_duration * (1. - last_keyframe.start_percentage.0 as f64))
}
state.started_at +
(total_duration * (1. - last_keyframe.start_percentage.0 as f64))
},
_ => unreachable!(),
};
let relative_progress = (now - last_keyframe_ended_at) / relative_duration;
@ -748,32 +785,42 @@ where
let mut new_style = (*style).clone();
for property in animation.properties_changed.iter() {
debug!("update_style_for_animation: scanning prop {:?} for animation \"{}\"",
property, name);
debug!(
"update_style_for_animation: scanning prop {:?} for animation \"{}\"",
property, name
);
let animation = PropertyAnimation::from_longhand(
property,
timing_function,
Time::from_seconds(relative_duration as f32),
&from_style,
&target_style
&target_style,
);
match animation {
Some(property_animation) => {
debug!("update_style_for_animation: got property animation for prop {:?}", property);
debug!(
"update_style_for_animation: got property animation for prop {:?}",
property
);
debug!("update_style_for_animation: {:?}", property_animation);
property_animation.update(Arc::make_mut(&mut new_style), relative_progress);
}
},
None => {
debug!("update_style_for_animation: property animation {:?} not animating",
property);
}
debug!(
"update_style_for_animation: property animation {:?} not animating",
property
);
},
}
}
debug!("update_style_for_animation: got style change in animation \"{}\"", name);
debug!(
"update_style_for_animation: got style change in animation \"{}\"",
name
);
*style = new_style;
}
},
}
}

View file

@ -9,7 +9,7 @@ use rule_tree::{CascadeLevel, StyleSource};
use servo_arc::Arc;
use shared_lock::Locked;
use smallvec::SmallVec;
use std::fmt::{Debug, self};
use std::fmt::{self, Debug};
use std::mem;
/// List of applicable declarations. This is a transient structure that shuttles
@ -89,9 +89,10 @@ impl ApplicableDeclarationBlock {
/// Constructs an applicable declaration block from a given property
/// declaration block and importance.
#[inline]
pub fn from_declarations(declarations: Arc<Locked<PropertyDeclarationBlock>>,
level: CascadeLevel)
-> Self {
pub fn from_declarations(
declarations: Arc<Locked<PropertyDeclarationBlock>>,
level: CascadeLevel,
) -> Self {
ApplicableDeclarationBlock {
source: StyleSource::Declarations(declarations),
order_and_level: SourceOrderAndCascadeLevel::new(0, level),
@ -101,16 +102,12 @@ impl ApplicableDeclarationBlock {
/// Constructs an applicable declaration block from the given components
#[inline]
pub fn new(source: StyleSource,
order: u32,
level: CascadeLevel,
specificity: u32) -> Self {
pub fn new(source: StyleSource, order: u32, level: CascadeLevel, specificity: u32) -> Self {
ApplicableDeclarationBlock {
source: source,
order_and_level: SourceOrderAndCascadeLevel::new(order, level),
specificity: specificity,
}
}
/// Returns the source order of the block.

View file

@ -6,7 +6,7 @@
//!
//! [attr]: https://dom.spec.whatwg.org/#interface-attr
use {Atom, Prefix, Namespace, LocalName};
use {Atom, LocalName, Namespace, Prefix};
use app_units::Au;
use cssparser::{self, Color, RGBA};
use euclid::num::Zero;
@ -17,7 +17,7 @@ use servo_arc::Arc;
use servo_url::ServoUrl;
use shared_lock::Locked;
use std::str::FromStr;
use str::{HTML_SPACE_CHARACTERS, read_exponent, read_fraction};
use str::{read_exponent, read_fraction, HTML_SPACE_CHARACTERS};
use str::{read_numbers, split_commas, split_html_space_chars};
use str::str_join;
use values::specified::Length;
@ -64,18 +64,19 @@ pub enum AttrValue {
/// Note that we don't necessarily need to do that (we could just clone the
/// declaration block), but that avoids keeping a refcounted
/// declarationblock for longer than needed.
Declaration(String,
#[ignore_malloc_size_of = "Arc"]
Arc<Locked<PropertyDeclarationBlock>>)
Declaration(
String,
#[ignore_malloc_size_of = "Arc"] Arc<Locked<PropertyDeclarationBlock>>,
),
}
/// Shared implementation to parse an integer according to
/// <https://html.spec.whatwg.org/multipage/#rules-for-parsing-integers> or
/// <https://html.spec.whatwg.org/multipage/#rules-for-parsing-non-negative-integers>
fn do_parse_integer<T: Iterator<Item=char>>(input: T) -> Result<i64, ()> {
let mut input = input.skip_while(|c| {
HTML_SPACE_CHARACTERS.iter().any(|s| s == c)
}).peekable();
fn do_parse_integer<T: Iterator<Item = char>>(input: T) -> Result<i64, ()> {
let mut input = input
.skip_while(|c| HTML_SPACE_CHARACTERS.iter().any(|s| s == c))
.peekable();
let sign = match input.peek() {
None => return Err(()),
@ -97,18 +98,14 @@ fn do_parse_integer<T: Iterator<Item=char>>(input: T) -> Result<i64, ()> {
/// Parse an integer according to
/// <https://html.spec.whatwg.org/multipage/#rules-for-parsing-integers>.
pub fn parse_integer<T: Iterator<Item=char>>(input: T) -> Result<i32, ()> {
do_parse_integer(input).and_then(|result| {
result.to_i32().ok_or(())
})
pub fn parse_integer<T: Iterator<Item = char>>(input: T) -> Result<i32, ()> {
do_parse_integer(input).and_then(|result| result.to_i32().ok_or(()))
}
/// Parse an integer according to
/// <https://html.spec.whatwg.org/multipage/#rules-for-parsing-non-negative-integers>
pub fn parse_unsigned_integer<T: Iterator<Item=char>>(input: T) -> Result<u32, ()> {
do_parse_integer(input).and_then(|result| {
result.to_u32().ok_or(())
})
pub fn parse_unsigned_integer<T: Iterator<Item = char>>(input: T) -> Result<u32, ()> {
do_parse_integer(input).and_then(|result| result.to_u32().ok_or(()))
}
/// Parse a floating-point number according to
@ -122,26 +119,35 @@ pub fn parse_double(string: &str) -> Result<f64, ()> {
Some(&'-') => {
input.next();
(-1f64, -1f64, 1)
}
},
Some(&'+') => {
input.next();
(1f64, 1f64, 1)
}
_ => (1f64, 1f64, 0)
},
_ => (1f64, 1f64, 0),
};
let (value, value_digits) = if let Some(&'.') = input.peek() {
(0f64, 0)
} else {
let (read_val, read_digits) = read_numbers(input);
(value * read_val.and_then(|result| result.to_f64()).unwrap_or(1f64), read_digits)
(
value * read_val.and_then(|result| result.to_f64()).unwrap_or(1f64),
read_digits,
)
};
let input = trimmed.chars().skip(value_digits + chars_skipped).peekable();
let input = trimmed
.chars()
.skip(value_digits + chars_skipped)
.peekable();
let (mut value, fraction_digits) = read_fraction(input, divisor, value);
let input = trimmed.chars().skip(value_digits + chars_skipped + fraction_digits).peekable();
let input = trimmed
.chars()
.skip(value_digits + chars_skipped + fraction_digits)
.peekable();
if let Some(exp) = read_exponent(input) {
value *= 10f64.powi(exp)
@ -152,22 +158,27 @@ pub fn parse_double(string: &str) -> Result<f64, ()> {
impl AttrValue {
pub fn from_serialized_tokenlist(tokens: String) -> AttrValue {
let atoms =
split_html_space_chars(&tokens)
.map(Atom::from)
.fold(vec![], |mut acc, atom| {
if !acc.contains(&atom) { acc.push(atom) }
let atoms = split_html_space_chars(&tokens).map(Atom::from).fold(
vec![],
|mut acc, atom| {
if !acc.contains(&atom) {
acc.push(atom)
}
acc
});
},
);
AttrValue::TokenList(tokens, atoms)
}
pub fn from_comma_separated_tokenlist(tokens: String) -> AttrValue {
let atoms = split_commas(&tokens).map(Atom::from)
.fold(vec![], |mut acc, atom| {
if !acc.contains(&atom) { acc.push(atom) }
acc
});
let atoms = split_commas(&tokens)
.map(Atom::from)
.fold(vec![], |mut acc, atom| {
if !acc.contains(&atom) {
acc.push(atom)
}
acc
});
AttrValue::TokenList(tokens, atoms)
}
@ -407,7 +418,7 @@ pub fn parse_nonzero_length(value: &str) -> LengthOrPercentageOrAuto {
pub fn parse_legacy_color(mut input: &str) -> Result<RGBA, ()> {
// Steps 1 and 2.
if input.is_empty() {
return Err(())
return Err(());
}
// Step 3.
@ -415,7 +426,7 @@ pub fn parse_legacy_color(mut input: &str) -> Result<RGBA, ()> {
// Step 4.
if input.eq_ignore_ascii_case("transparent") {
return Err(())
return Err(());
}
// Step 5.
@ -425,12 +436,13 @@ pub fn parse_legacy_color(mut input: &str) -> Result<RGBA, ()> {
// Step 6.
if input.len() == 4 {
if let (b'#', Ok(r), Ok(g), Ok(b)) =
(input.as_bytes()[0],
hex(input.as_bytes()[1] as char),
hex(input.as_bytes()[2] as char),
hex(input.as_bytes()[3] as char)) {
return Ok(RGBA::new(r * 17, g * 17, b * 17, 255))
if let (b'#', Ok(r), Ok(g), Ok(b)) = (
input.as_bytes()[0],
hex(input.as_bytes()[1] as char),
hex(input.as_bytes()[2] as char),
hex(input.as_bytes()[3] as char),
) {
return Ok(RGBA::new(r * 17, g * 17, b * 17, 255));
}
}
@ -449,7 +461,7 @@ pub fn parse_legacy_color(mut input: &str) -> Result<RGBA, ()> {
for (char_count, (index, _)) in input.char_indices().enumerate() {
if char_count == 128 {
input = &input[..index];
break
break;
}
}
@ -476,9 +488,11 @@ pub fn parse_legacy_color(mut input: &str) -> Result<RGBA, ()> {
// Step 12.
let mut length = input.len() / 3;
let (mut red, mut green, mut blue) = (&input[..length],
&input[length..length * 2],
&input[length * 2..]);
let (mut red, mut green, mut blue) = (
&input[..length],
&input[length..length * 2],
&input[length * 2..],
);
// Step 13.
if length > 8 {
@ -497,10 +511,12 @@ pub fn parse_legacy_color(mut input: &str) -> Result<RGBA, ()> {
}
// Steps 15-20.
return Ok(RGBA::new(hex_string(red).unwrap(),
hex_string(green).unwrap(),
hex_string(blue).unwrap(),
255));
return Ok(RGBA::new(
hex_string(red).unwrap(),
hex_string(green).unwrap(),
hex_string(blue).unwrap(),
255,
));
fn hex(ch: char) -> Result<u8, ()> {
match ch {
@ -519,7 +535,7 @@ pub fn parse_legacy_color(mut input: &str) -> Result<RGBA, ()> {
let upper = hex(string[0] as char)?;
let lower = hex(string[1] as char)?;
Ok((upper << 4) | lower)
}
},
}
}
}
@ -536,7 +552,7 @@ pub fn parse_length(mut value: &str) -> LengthOrPercentageOrAuto {
// Step 4
if value.is_empty() {
return LengthOrPercentageOrAuto::Auto
return LengthOrPercentageOrAuto::Auto;
}
// Step 5
@ -565,16 +581,16 @@ pub fn parse_length(mut value: &str) -> LengthOrPercentageOrAuto {
'%' => {
found_percent = true;
end_index = i;
break
}
break;
},
'.' if !found_full_stop => {
found_full_stop = true;
continue
}
continue;
},
_ => {
end_index = i;
break
}
break;
},
}
}
value = &value[..end_index];

View file

@ -16,7 +16,6 @@ use stylesheet_set::AuthorStylesheetSet;
use stylesheets::StylesheetInDocument;
use stylist::CascadeData;
/// A set of author stylesheets and their computed representation, such as the
/// ones used for ShadowRoot and XBL.
pub struct AuthorStyles<S>
@ -57,27 +56,20 @@ where
device: &Device,
quirks_mode: QuirksMode,
guard: &SharedRwLockReadGuard,
)
where
) where
E: TElement,
S: ToMediaListKey,
{
let flusher = self.stylesheets.flush::<E>(
/* host = */ None,
/* snapshot_map = */ None,
);
let flusher = self.stylesheets
.flush::<E>(/* host = */ None, /* snapshot_map = */ None);
if flusher.sheets.dirty() {
self.quirks_mode = quirks_mode;
}
// Ignore OOM.
let _ = self.data.rebuild(
device,
quirks_mode,
flusher.sheets,
guard,
);
let _ = self.data
.rebuild(device, quirks_mode, flusher.sheets, guard);
}
}

View file

@ -71,11 +71,11 @@ impl Bezier {
for _ in 0..NEWTON_METHOD_ITERATIONS {
let x2 = self.sample_curve_x(t);
if x2.approx_eq(x, epsilon) {
return t
return t;
}
let dx = self.sample_curve_derivative_x(t);
if dx.approx_eq(0.0, 1e-6) {
break
break;
}
t -= (x2 - x) / dx;
}
@ -84,16 +84,16 @@ impl Bezier {
let (mut lo, mut hi, mut t) = (0.0, 1.0, x);
if t < lo {
return lo
return lo;
}
if t > hi {
return hi
return hi;
}
while lo < hi {
let x2 = self.sample_curve_x(t);
if x2.approx_eq(x, epsilon) {
return t
return t;
}
if x > x2 {
lo = t
@ -124,4 +124,3 @@ impl ApproxEq for f64 {
(self - value).abs() < epsilon
}
}

View file

@ -7,7 +7,7 @@
#![deny(missing_docs)]
use atomic_refcell::{AtomicRefMut, AtomicRefCell};
use atomic_refcell::{AtomicRefCell, AtomicRefMut};
use dom::{SendElement, TElement};
use owning_ref::OwningHandle;
use selectors::bloom::BloomFilter;
@ -105,9 +105,7 @@ where
f(id.get_hash());
}
element.each_class(|class| {
f(class.get_hash())
});
element.each_class(|class| f(class.get_hash()));
}
impl<E: TElement> Drop for StyleBloom<E> {
@ -129,8 +127,12 @@ impl<E: TElement> StyleBloom<E> {
#[inline(never)]
pub fn new() -> Self {
let bloom_arc = BLOOM_KEY.with(|b| b.clone());
let filter = OwningHandle::new_with_fn(bloom_arc, |x| unsafe { x.as_ref() }.unwrap().borrow_mut());
debug_assert!(filter.is_zeroed(), "Forgot to zero the bloom filter last time");
let filter =
OwningHandle::new_with_fn(bloom_arc, |x| unsafe { x.as_ref() }.unwrap().borrow_mut());
debug_assert!(
filter.is_zeroed(),
"Forgot to zero the bloom filter last time"
);
StyleBloom {
filter: filter,
elements: Default::default(),
@ -169,7 +171,10 @@ impl<E: TElement> StyleBloom<E> {
/// Pop the last element in the bloom filter and return it.
#[inline]
fn pop(&mut self) -> Option<E> {
let PushedElement { element, num_hashes } = self.elements.pop()?;
let PushedElement {
element,
num_hashes,
} = self.elements.pop()?;
let popped_element = *element;
// Verify that the pushed hashes match the ones we'd get from the element.
@ -237,7 +242,10 @@ impl<E: TElement> StyleBloom<E> {
if cfg!(debug_assertions) {
let mut checked = 0;
while let Some(parent) = element.traversal_parent() {
assert_eq!(parent, *(self.elements[self.elements.len() - 1 - checked].element));
assert_eq!(
parent,
*(self.elements[self.elements.len() - 1 - checked].element)
);
element = parent;
checked += 1;
}
@ -261,10 +269,7 @@ impl<E: TElement> StyleBloom<E> {
///
/// Returns the new bloom filter depth, that the traversal code is
/// responsible to keep around if it wants to get an effective filter.
pub fn insert_parents_recovering(&mut self,
element: E,
element_depth: usize)
{
pub fn insert_parents_recovering(&mut self, element: E, element_depth: usize) {
// Easy case, we're in a different restyle, or we're empty.
if self.elements.is_empty() {
self.rebuild(element);
@ -277,7 +282,7 @@ impl<E: TElement> StyleBloom<E> {
// Yay, another easy case.
self.clear();
return;
}
},
};
if self.current_parent() == Some(traversal_parent) {
@ -291,10 +296,11 @@ impl<E: TElement> StyleBloom<E> {
}
// We should've early exited above.
debug_assert!(element_depth != 0,
"We should have already cleared the bloom filter");
debug_assert!(!self.elements.is_empty(),
"How! We should've just rebuilt!");
debug_assert!(
element_depth != 0,
"We should have already cleared the bloom filter"
);
debug_assert!(!self.elements.is_empty(), "How! We should've just rebuilt!");
// Now the fun begins: We have the depth of the dom and the depth of the
// last element inserted in the filter, let's try to find a common
@ -327,8 +333,7 @@ impl<E: TElement> StyleBloom<E> {
// TODO(emilio): Seems like we could insert parents here, then
// reverse the slice.
parents_to_insert.push(common_parent);
common_parent =
common_parent.traversal_parent().expect("We were lied to");
common_parent = common_parent.traversal_parent().expect("We were lied to");
common_parent_depth -= 1;
}
@ -359,7 +364,7 @@ impl<E: TElement> StyleBloom<E> {
} else {
panic!("should have found a common ancestor");
}
}
},
}
}

View file

@ -16,7 +16,7 @@ extern crate walkdir;
use std::env;
use std::path::Path;
use std::process::{Command, exit};
use std::process::{exit, Command};
use walkdir::WalkDir;
#[cfg(feature = "gecko")]
@ -29,11 +29,19 @@ mod build_gecko {
#[cfg(windows)]
fn find_python() -> String {
if Command::new("python2.7.exe").arg("--version").output().is_ok() {
if Command::new("python2.7.exe")
.arg("--version")
.output()
.is_ok()
{
return "python2.7.exe".to_owned();
}
if Command::new("python27.exe").arg("--version").output().is_ok() {
if Command::new("python27.exe")
.arg("--version")
.output()
.is_ok()
{
return "python27.exe".to_owned();
}
@ -41,13 +49,21 @@ fn find_python() -> String {
return "python.exe".to_owned();
}
panic!(concat!("Can't find python (tried python2.7.exe, python27.exe, and python.exe)! ",
"Try fixing PATH or setting the PYTHON env var"));
panic!(concat!(
"Can't find python (tried python2.7.exe, python27.exe, and python.exe)! ",
"Try fixing PATH or setting the PYTHON env var"
));
}
#[cfg(not(windows))]
fn find_python() -> String {
if Command::new("python2.7").arg("--version").output().unwrap().status.success() {
if Command::new("python2.7")
.arg("--version")
.output()
.unwrap()
.status
.success()
{
"python2.7"
} else {
"python"
@ -64,14 +80,19 @@ fn generate_properties() {
match entry.path().extension().and_then(|e| e.to_str()) {
Some("mako") | Some("rs") | Some("py") | Some("zip") => {
println!("cargo:rerun-if-changed={}", entry.path().display());
}
_ => {}
},
_ => {},
}
}
let script = Path::new(&env::var_os("CARGO_MANIFEST_DIR").unwrap())
.join("properties").join("build.py");
let product = if cfg!(feature = "gecko") { "gecko" } else { "servo" };
.join("properties")
.join("build.py");
let product = if cfg!(feature = "gecko") {
"gecko"
} else {
"servo"
};
let status = Command::new(&*PYTHON)
.arg(&script)
.arg(product)
@ -90,8 +111,10 @@ fn main() {
panic!("The style crate requires enabling one of its 'servo' or 'gecko' feature flags");
}
if gecko && servo {
panic!("The style crate does not support enabling both its 'servo' or 'gecko' \
feature flags at the same time.");
panic!(
"The style crate does not support enabling both its 'servo' or 'gecko' \
feature flags at the same time."
);
}
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:out_dir={}", env::var("OUT_DIR").unwrap());

View file

@ -7,13 +7,18 @@ mod common {
use std::path::{Path, PathBuf};
lazy_static! {
pub static ref OUTDIR_PATH: PathBuf = PathBuf::from(env::var_os("OUT_DIR").unwrap()).join("gecko");
pub static ref OUTDIR_PATH: PathBuf =
PathBuf::from(env::var_os("OUT_DIR").unwrap()).join("gecko");
}
/// Copy contents of one directory into another.
/// It currently only does a shallow copy.
pub fn copy_dir<P, Q, F>(from: P, to: Q, callback: F) -> io::Result<()>
where P: AsRef<Path>, Q: AsRef<Path>, F: Fn(&Path) {
where
P: AsRef<Path>,
Q: AsRef<Path>,
F: Fn(&Path),
{
let to = to.as_ref();
for entry in from.as_ref().read_dir()? {
let entry = entry?;
@ -31,12 +36,12 @@ mod bindings {
use bindgen::callbacks::{EnumVariantCustomBehavior, EnumVariantValue, ParseCallbacks};
use regex::{Regex, RegexSet};
use std::cmp;
use std::collections::{HashSet, HashMap};
use std::collections::{HashMap, HashSet};
use std::env;
use std::fs::{self, File};
use std::io::{Read, Write};
use std::path::{Path, PathBuf};
use std::process::{Command, exit};
use std::process::{exit, Command};
use std::slice;
use std::sync::Mutex;
use std::time::SystemTime;
@ -53,11 +58,13 @@ mod bindings {
update_last_modified(&path);
let mut contents = String::new();
File::open(path).expect("Failed to open config file")
.read_to_string(&mut contents).expect("Failed to read config file");
File::open(path)
.expect("Failed to open config file")
.read_to_string(&mut contents)
.expect("Failed to read config file");
match toml::from_str::<toml::value::Table>(&contents) {
Ok(result) => result,
Err(e) => panic!("Failed to parse config file: {}", e)
Err(e) => panic!("Failed to parse config file: {}", e),
}
}
@ -109,8 +116,7 @@ mod bindings {
}
fn update_last_modified(file: &Path) {
let modified = get_modified_time(file)
.expect("Couldn't get file modification time");
let modified = get_modified_time(file).expect("Couldn't get file modification time");
let mut last_modified = LAST_MODIFIED.lock().unwrap();
*last_modified = cmp::max(modified, *last_modified);
}
@ -194,19 +200,14 @@ mod bindings {
// Disable rust unions, because we replace some types inside of
// them.
let mut builder = Builder::default()
.rust_target(RustTarget::Stable_1_0);
let rustfmt_path = env::var_os("MOZ_AUTOMATION").and_then(|_| {
env::var_os("TOOLTOOL_DIR").or_else(|| env::var_os("MOZ_SRC"))
}).map(PathBuf::from);
let mut builder = Builder::default().rust_target(RustTarget::Stable_1_0);
let rustfmt_path = env::var_os("MOZ_AUTOMATION")
.and_then(|_| env::var_os("TOOLTOOL_DIR").or_else(|| env::var_os("MOZ_SRC")))
.map(PathBuf::from);
builder = match rustfmt_path {
Some(path) => {
builder.with_rustfmt(path.join("rustc").join("bin").join("rustfmt"))
},
None => {
builder.rustfmt_bindings(env::var_os("STYLO_RUSTFMT_BINDINGS").is_some())
}
Some(path) => builder.with_rustfmt(path.join("rustc").join("bin").join("rustfmt")),
None => builder.rustfmt_bindings(env::var_os("STYLO_RUSTFMT_BINDINGS").is_some()),
};
for dir in SEARCH_PATHS.iter() {
@ -222,7 +223,9 @@ mod bindings {
let mut matched_os = false;
let build_config = CONFIG["build"].as_table().expect("Malformed config file");
builder = add_clang_args(builder, build_config, &mut matched_os);
let build_config = BUILD_CONFIG["build"].as_table().expect("Malformed config file");
let build_config = BUILD_CONFIG["build"]
.as_table()
.expect("Malformed config file");
builder = add_clang_args(builder, build_config, &mut matched_os);
if !matched_os {
panic!("Unknown platform");
@ -253,20 +256,26 @@ mod bindings {
self.blacklist_type(format!("{}Borrowed", ty))
.raw_line(format!("pub type {0}Borrowed<'a> = &'a {0};", ty))
.blacklist_type(format!("{}BorrowedOrNull", ty))
.raw_line(format!("pub type {0}BorrowedOrNull<'a> = Option<&'a {0}>;", ty))
.raw_line(format!(
"pub type {0}BorrowedOrNull<'a> = Option<&'a {0}>;",
ty
))
}
fn mutable_borrowed_type(self, ty: &str) -> Builder {
self.borrowed_type(ty)
.blacklist_type(format!("{}BorrowedMut", ty))
.raw_line(format!("pub type {0}BorrowedMut<'a> = &'a mut {0};", ty))
.blacklist_type(format!("{}BorrowedMutOrNull", ty))
.raw_line(format!("pub type {0}BorrowedMutOrNull<'a> = Option<&'a mut {0}>;", ty))
.raw_line(format!(
"pub type {0}BorrowedMutOrNull<'a> = Option<&'a mut {0}>;",
ty
))
}
}
struct Fixup {
pat: String,
rep: String
rep: String,
}
fn write_binding_file(builder: Builder, file: &str, fixups: &[Fixup]) {
@ -283,15 +292,24 @@ mod bindings {
let mut result = match result {
Ok(bindings) => bindings.to_string(),
Err(_) => {
panic!("Failed to generate bindings, flags: {:?}", command_line_opts);
panic!(
"Failed to generate bindings, flags: {:?}",
command_line_opts
);
},
};
for fixup in fixups.iter() {
result = Regex::new(&fixup.pat).unwrap().replace_all(&result, &*fixup.rep)
.into_owned().into();
result = Regex::new(&fixup.pat)
.unwrap()
.replace_all(&result, &*fixup.rep)
.into_owned()
.into();
}
let bytes = result.into_bytes();
File::create(&out_file).unwrap().write_all(&bytes).expect("Unable to write output");
File::create(&out_file)
.unwrap()
.write_all(&bytes)
.expect("Unable to write output");
}
fn get_arc_types() -> Vec<String> {
@ -299,16 +317,29 @@ mod bindings {
let mut list_file = File::open(DISTDIR_PATH.join("include/mozilla/ServoArcTypeList.h"))
.expect("Unable to open ServoArcTypeList.h");
let mut content = String::new();
list_file.read_to_string(&mut content).expect("Fail to read ServoArcTypeList.h");
list_file
.read_to_string(&mut content)
.expect("Fail to read ServoArcTypeList.h");
// Remove comments
let block_comment_re = Regex::new(r#"(?s)/\*.*?\*/"#).unwrap();
let content = block_comment_re.replace_all(&content, "");
// Extract the list
let re = Regex::new(r#"^SERVO_ARC_TYPE\(\w+,\s*(\w+)\)$"#).unwrap();
content.lines().map(|line| line.trim()).filter(|line| !line.is_empty())
.map(|line| re.captures(&line)
.expect(&format!("Unrecognized line in ServoArcTypeList.h: '{}'", line))
.get(1).unwrap().as_str().to_string())
content
.lines()
.map(|line| line.trim())
.filter(|line| !line.is_empty())
.map(|line| {
re.captures(&line)
.expect(&format!(
"Unrecognized line in ServoArcTypeList.h: '{}'",
line
))
.get(1)
.unwrap()
.as_str()
.to_string()
})
.collect()
}
@ -320,13 +351,16 @@ mod bindings {
impl<'a> BuilderWithConfig<'a> {
fn new(builder: Builder, config: &'a Table) -> Self {
BuilderWithConfig {
builder, config,
builder,
config,
used_keys: HashSet::new(),
}
}
fn handle_list<F>(self, key: &'static str, func: F) -> BuilderWithConfig<'a>
where F: FnOnce(Builder, slice::Iter<'a, toml::Value>) -> Builder {
where
F: FnOnce(Builder, slice::Iter<'a, toml::Value>) -> Builder,
{
let mut builder = self.builder;
let config = self.config;
let mut used_keys = self.used_keys;
@ -334,19 +368,27 @@ mod bindings {
used_keys.insert(key);
builder = func(builder, list.as_array().unwrap().as_slice().iter());
}
BuilderWithConfig { builder, config, used_keys }
BuilderWithConfig {
builder,
config,
used_keys,
}
}
fn handle_items<F>(self, key: &'static str, mut func: F) -> BuilderWithConfig<'a>
where F: FnMut(Builder, &'a toml::Value) -> Builder {
where
F: FnMut(Builder, &'a toml::Value) -> Builder,
{
self.handle_list(key, |b, iter| iter.fold(b, |b, item| func(b, item)))
}
fn handle_str_items<F>(self, key: &'static str, mut func: F) -> BuilderWithConfig<'a>
where F: FnMut(Builder, &'a str) -> Builder {
where
F: FnMut(Builder, &'a str) -> Builder,
{
self.handle_items(key, |b, item| func(b, item.as_str().unwrap()))
}
fn handle_table_items<F>(self, key: &'static str, mut func: F) -> BuilderWithConfig<'a>
where
F: FnMut(Builder, &'a Table) -> Builder
F: FnMut(Builder, &'a Table) -> Builder,
{
self.handle_items(key, |b, item| func(b, item.as_table().unwrap()))
}
@ -377,16 +419,20 @@ mod bindings {
#[derive(Debug)]
struct Callbacks(HashMap<String, RegexSet>);
impl ParseCallbacks for Callbacks {
fn enum_variant_behavior(&self,
enum_name: Option<&str>,
variant_name: &str,
_variant_value: EnumVariantValue)
-> Option<EnumVariantCustomBehavior> {
enum_name.and_then(|enum_name| self.0.get(enum_name))
.and_then(|regex| if regex.is_match(variant_name) {
Some(EnumVariantCustomBehavior::Constify)
} else {
None
fn enum_variant_behavior(
&self,
enum_name: Option<&str>,
variant_name: &str,
_variant_value: EnumVariantValue,
) -> Option<EnumVariantCustomBehavior> {
enum_name
.and_then(|enum_name| self.0.get(enum_name))
.and_then(|regex| {
if regex.is_match(variant_name) {
Some(EnumVariantCustomBehavior::Constify)
} else {
None
}
})
}
}
@ -411,7 +457,11 @@ mod bindings {
for item in iter {
let item = item.as_table().unwrap();
let name = item["enum"].as_str().unwrap();
let variants = item["variants"].as_array().unwrap().as_slice().iter()
let variants = item["variants"]
.as_array()
.unwrap()
.as_slice()
.iter()
.map(|item| item.as_str().unwrap());
map.insert(name.into(), RegexSet::new(variants).unwrap());
}
@ -422,18 +472,22 @@ mod bindings {
let gecko = item["gecko"].as_str().unwrap();
let servo = item["servo"].as_str().unwrap();
let gecko_name = gecko.rsplit("::").next().unwrap();
let gecko = gecko.split("::")
.map(|s| format!("\\s*{}\\s*", s))
.collect::<Vec<_>>()
.join("::");
let gecko = gecko
.split("::")
.map(|s| format!("\\s*{}\\s*", s))
.collect::<Vec<_>>()
.join("::");
fixups.push(Fixup {
pat: format!("\\broot\\s*::\\s*{}\\b", gecko),
rep: format!("::gecko_bindings::structs::{}", gecko_name)
rep: format!("::gecko_bindings::structs::{}", gecko_name),
});
builder.blacklist_type(gecko)
.raw_line(format!("pub type {0}{2} = {1}{2};", gecko_name, servo,
if generic { "<T>" } else { "" }))
builder.blacklist_type(gecko).raw_line(format!(
"pub type {0}{2} = {1}{2};",
gecko_name,
servo,
if generic { "<T>" } else { "" }
))
})
.get_builder();
write_binding_file(builder, STRUCTS_FILE, &fixups);
@ -458,13 +512,15 @@ mod bindings {
}
let mut file = self.file.as_ref().unwrap().lock().unwrap();
let _ =
writeln!(file, "{} - {} - {} @ {}:{}",
record.level(),
record.target(),
record.args(),
record.file().unwrap_or("<unknown>"),
record.line().unwrap_or(0));
let _ = writeln!(
file,
"{} - {} - {} @ {}:{}",
record.level(),
record.target(),
record.args(),
record.file().unwrap_or("<unknown>"),
record.line().unwrap_or(0)
);
}
fn flush(&self) {
@ -476,13 +532,12 @@ mod bindings {
if let Some(path) = env::var_os("STYLO_BUILD_LOG") {
log::set_max_level(log::LevelFilter::Debug);
log::set_boxed_logger(
Box::new(BuildLogger {
file: fs::File::create(path).ok().map(Mutex::new),
filter: env::var("STYLO_BUILD_FILTER").ok()
.unwrap_or_else(|| "bindgen".to_owned()),
})
).expect("Failed to set logger.");
log::set_boxed_logger(Box::new(BuildLogger {
file: fs::File::create(path).ok().map(Mutex::new),
filter: env::var("STYLO_BUILD_FILTER")
.ok()
.unwrap_or_else(|| "bindgen".to_owned()),
})).expect("Failed to set logger.");
true
} else {
@ -550,7 +605,10 @@ mod bindings {
for ty in get_arc_types().iter() {
builder = builder
.blacklist_type(format!("{}Strong", ty))
.raw_line(format!("pub type {0}Strong = ::gecko_bindings::sugar::ownership::Strong<{0}>;", ty))
.raw_line(format!(
"pub type {0}Strong = ::gecko_bindings::sugar::ownership::Strong<{0}>;",
ty
))
.borrowed_type(ty)
.zero_size_type(ty, &structs_types);
}
@ -559,7 +617,8 @@ mod bindings {
fn generate_atoms() {
let script = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap())
.join("gecko").join("regen_atoms.py");
.join("gecko")
.join("regen_atoms.py");
println!("cargo:rerun-if-changed={}", script.display());
let status = Command::new(&*PYTHON)
.arg(&script)

View file

@ -4,37 +4,46 @@
//! The context within which style is calculated.
#[cfg(feature = "servo")] use animation::Animation;
#[cfg(feature = "servo")]
use animation::Animation;
use app_units::Au;
use bloom::StyleBloom;
use data::{EagerPseudoStyles, ElementData};
use dom::{TElement, SendElement};
#[cfg(feature = "servo")] use dom::OpaqueNode;
use dom::{SendElement, TElement};
#[cfg(feature = "servo")]
use dom::OpaqueNode;
use euclid::Size2D;
use euclid::TypedScale;
use fnv::FnvHashMap;
use font_metrics::FontMetricsProvider;
#[cfg(feature = "gecko")] use gecko_bindings::structs;
#[cfg(feature = "gecko")]
use gecko_bindings::structs;
use parallel::{STACK_SAFETY_MARGIN_KB, STYLE_THREAD_STACK_SIZE_KB};
#[cfg(feature = "servo")] use parking_lot::RwLock;
#[cfg(feature = "servo")]
use parking_lot::RwLock;
use properties::ComputedValues;
#[cfg(feature = "servo")] use properties::PropertyId;
#[cfg(feature = "servo")]
use properties::PropertyId;
use rule_cache::RuleCache;
use rule_tree::StrongRuleNode;
use selector_parser::{EAGER_PSEUDO_COUNT, SnapshotMap};
use selector_parser::{SnapshotMap, EAGER_PSEUDO_COUNT};
use selectors::NthIndexCache;
use selectors::matching::ElementSelectorFlags;
use servo_arc::Arc;
#[cfg(feature = "servo")] use servo_atoms::Atom;
#[cfg(feature = "servo")]
use servo_atoms::Atom;
use shared_lock::StylesheetGuards;
use sharing::StyleSharingCache;
use std::fmt;
use std::ops;
#[cfg(feature = "servo")] use std::sync::Mutex;
#[cfg(feature = "servo")] use std::sync::mpsc::Sender;
#[cfg(feature = "servo")]
use std::sync::Mutex;
#[cfg(feature = "servo")]
use std::sync::mpsc::Sender;
use style_traits::CSSPixel;
use style_traits::DevicePixel;
#[cfg(feature = "servo")] use style_traits::SpeculativePainter;
#[cfg(feature = "servo")]
use style_traits::SpeculativePainter;
use stylist::Stylist;
use thread_state::{self, ThreadState};
use time;
@ -89,7 +98,8 @@ const DEFAULT_STATISTICS_THRESHOLD: usize = 50;
fn get_env_usize(name: &str) -> Option<usize> {
use std::env;
env::var(name).ok().map(|s| {
s.parse::<usize>().expect("Couldn't parse environmental variable as usize")
s.parse::<usize>()
.expect("Couldn't parse environmental variable as usize")
})
}
@ -111,7 +121,7 @@ impl Default for StyleSystemOptions {
disable_style_sharing_cache: get_env_bool("DISABLE_STYLE_SHARING_CACHE"),
dump_style_statistics: get_env_bool("DUMP_STYLE_STATISTICS"),
style_statistics_threshold: get_env_usize("STYLE_STATISTICS_THRESHOLD")
.unwrap_or(DEFAULT_STATISTICS_THRESHOLD),
.unwrap_or(DEFAULT_STATISTICS_THRESHOLD),
}
}
}
@ -176,7 +186,6 @@ pub struct SharedStyleContext<'a> {
/// Data needed to create the thread-local style context from the shared one.
#[cfg(feature = "servo")]
pub local_context_creation_data: Mutex<ThreadLocalStyleContextCreationInfo>,
}
impl<'a> SharedStyleContext<'a> {
@ -236,7 +245,7 @@ pub struct EagerPseudoCascadeInputs(Option<[Option<CascadeInputs>; EAGER_PSEUDO_
impl Clone for EagerPseudoCascadeInputs {
fn clone(&self) -> Self {
if self.0.is_none() {
return EagerPseudoCascadeInputs(None)
return EagerPseudoCascadeInputs(None);
}
let self_inputs = self.0.as_ref().unwrap();
let mut inputs: [Option<CascadeInputs>; EAGER_PSEUDO_COUNT] = Default::default();
@ -352,21 +361,48 @@ pub struct TraversalStatistics {
/// See https://bugzilla.mozilla.org/show_bug.cgi?id=1331856#c2
impl fmt::Display for TraversalStatistics {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
debug_assert!(self.traversal_time_ms != 0.0, "should have set traversal time");
debug_assert!(
self.traversal_time_ms != 0.0,
"should have set traversal time"
);
writeln!(f, "[PERF] perf block start")?;
writeln!(f, "[PERF],traversal,{}", if self.is_parallel {
"parallel"
} else {
"sequential"
})?;
writeln!(f, "[PERF],elements_traversed,{}", self.aggregated.elements_traversed)?;
writeln!(f, "[PERF],elements_styled,{}", self.aggregated.elements_styled)?;
writeln!(f, "[PERF],elements_matched,{}", self.aggregated.elements_matched)?;
writeln!(
f,
"[PERF],traversal,{}",
if self.is_parallel {
"parallel"
} else {
"sequential"
}
)?;
writeln!(
f,
"[PERF],elements_traversed,{}",
self.aggregated.elements_traversed
)?;
writeln!(
f,
"[PERF],elements_styled,{}",
self.aggregated.elements_styled
)?;
writeln!(
f,
"[PERF],elements_matched,{}",
self.aggregated.elements_matched
)?;
writeln!(f, "[PERF],styles_shared,{}", self.aggregated.styles_shared)?;
writeln!(f, "[PERF],styles_reused,{}", self.aggregated.styles_reused)?;
writeln!(f, "[PERF],selectors,{}", self.selectors)?;
writeln!(f, "[PERF],revalidation_selectors,{}", self.revalidation_selectors)?;
writeln!(f, "[PERF],dependency_selectors,{}", self.dependency_selectors)?;
writeln!(
f,
"[PERF],revalidation_selectors,{}",
self.revalidation_selectors
)?;
writeln!(
f,
"[PERF],dependency_selectors,{}",
self.dependency_selectors
)?;
writeln!(f, "[PERF],declarations,{}", self.declarations)?;
writeln!(f, "[PERF],stylist_rebuilds,{}", self.stylist_rebuilds)?;
writeln!(f, "[PERF],traversal_time_ms,{}", self.traversal_time_ms)?;
@ -382,13 +418,16 @@ impl TraversalStatistics {
aggregated: PerThreadTraversalStatistics,
traversal: &D,
parallel: bool,
start: f64
start: f64,
) -> TraversalStatistics
where
E: TElement,
D: DomTraversal<E>,
{
let threshold = traversal.shared_context().options.style_statistics_threshold;
let threshold = traversal
.shared_context()
.options
.style_statistics_threshold;
let stylist = traversal.shared_context().stylist;
let is_large = aggregated.elements_traversed as usize >= threshold;
TraversalStatistics {
@ -400,7 +439,7 @@ impl TraversalStatistics {
stylist_rebuilds: stylist.num_rebuilds() as u32,
traversal_time_ms: (time::precise_time_s() - start) * 1000.0,
is_parallel: parallel,
is_large
is_large,
}
}
}
@ -438,7 +477,6 @@ bitflags! {
}
}
/// A task to be run in sequential mode on the parent (non-worker) thread. This
/// is used by the style system to queue up work which is not safe to do during
/// the parallel traversal.
@ -459,7 +497,7 @@ pub enum SequentialTask<E: TElement> {
/// CSSTransitions.
before_change_style: Option<Arc<ComputedValues>>,
/// The tasks which are performed in this SequentialTask.
tasks: UpdateAnimationsTasks
tasks: UpdateAnimationsTasks,
},
/// Performs one of a number of possible tasks as a result of animation-only
@ -472,7 +510,7 @@ pub enum SequentialTask<E: TElement> {
/// The target element.
el: SendElement<E>,
/// The tasks which are performed in this SequentialTask.
tasks: PostAnimationTasks
tasks: PostAnimationTasks,
},
}
@ -484,13 +522,17 @@ impl<E: TElement> SequentialTask<E> {
match self {
Unused(_) => unreachable!(),
#[cfg(feature = "gecko")]
UpdateAnimations { el, before_change_style, tasks } => {
UpdateAnimations {
el,
before_change_style,
tasks,
} => {
el.update_animations(before_change_style, tasks);
}
},
#[cfg(feature = "gecko")]
PostAnimation { el, tasks } => {
el.process_post_animation(tasks);
}
},
}
}
@ -565,7 +607,8 @@ impl<E: TElement> SelectorFlagsMap<E> {
let f = self.map.entry(el).or_insert(ElementSelectorFlags::empty());
*f |= flags;
self.cache.insert((unsafe { SendElement::new(element) }, *f))
self.cache
.insert((unsafe { SendElement::new(element) }, *f))
}
/// Applies the flags. Must be called on the main thread.
@ -573,7 +616,9 @@ impl<E: TElement> SelectorFlagsMap<E> {
debug_assert_eq!(thread_state::get(), ThreadState::LAYOUT);
self.cache.evict_all();
for (el, flags) in self.map.drain() {
unsafe { el.set_selector_flags(flags); }
unsafe {
el.set_selector_flags(flags);
}
}
}
}
@ -615,11 +660,10 @@ where
}
}
/// A helper type for stack limit checking. This assumes that stacks grow
/// down, which is true for all non-ancient CPU architectures.
pub struct StackLimitChecker {
lower_limit: usize
lower_limit: usize,
}
impl StackLimitChecker {
@ -628,7 +672,7 @@ impl StackLimitChecker {
#[inline(never)]
pub fn new(stack_size_limit: usize) -> Self {
StackLimitChecker {
lower_limit: StackLimitChecker::get_sp() - stack_size_limit
lower_limit: StackLimitChecker::get_sp() - stack_size_limit,
}
}
@ -680,7 +724,6 @@ impl StackLimitChecker {
}
}
/// A thread-local style context.
///
/// This context contains data that needs to be used during restyling, but is
@ -730,13 +773,19 @@ impl<E: TElement> ThreadLocalStyleContext<E> {
sharing_cache: StyleSharingCache::new(),
rule_cache: RuleCache::new(),
bloom_filter: StyleBloom::new(),
new_animations_sender: shared.local_context_creation_data.lock().unwrap().new_animations_sender.clone(),
new_animations_sender: shared
.local_context_creation_data
.lock()
.unwrap()
.new_animations_sender
.clone(),
tasks: SequentialTaskList(Vec::new()),
selector_flags: SelectorFlagsMap::new(),
statistics: PerThreadTraversalStatistics::default(),
font_metrics_provider: E::FontMetricsProvider::create_from(shared),
stack_limit_checker: StackLimitChecker::new(
(STYLE_THREAD_STACK_SIZE_KB - STACK_SAFETY_MARGIN_KB) * 1024),
(STYLE_THREAD_STACK_SIZE_KB - STACK_SAFETY_MARGIN_KB) * 1024,
),
nth_index_cache: NthIndexCache::default(),
}
}
@ -753,7 +802,8 @@ impl<E: TElement> ThreadLocalStyleContext<E> {
statistics: PerThreadTraversalStatistics::default(),
font_metrics_provider: E::FontMetricsProvider::create_from(shared),
stack_limit_checker: StackLimitChecker::new(
(STYLE_THREAD_STACK_SIZE_KB - STACK_SAFETY_MARGIN_KB) * 1024),
(STYLE_THREAD_STACK_SIZE_KB - STACK_SAFETY_MARGIN_KB) * 1024,
),
nth_index_cache: NthIndexCache::default(),
}
}

View file

@ -8,9 +8,9 @@
use Atom;
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser};
use cssparser::{Parser, Token, CowRcStr, SourceLocation};
use cssparser::{CowRcStr, Parser, SourceLocation, Token};
use error_reporting::{ContextualParseError, ParseErrorReporter};
use parser::{ParserContext, ParserErrorContext, Parse};
use parser::{Parse, ParserContext, ParserErrorContext};
use selectors::parser::SelectorParseErrorKind;
use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
use std::fmt::{self, Write};
@ -27,7 +27,7 @@ use values::specified::Integer;
///
/// This allows the reserved counter style names "decimal" and "disc".
pub fn parse_counter_style_name<'i, 't>(
input: &mut Parser<'i, 't>
input: &mut Parser<'i, 't>,
) -> Result<CustomIdent, ParseError<'i>> {
macro_rules! predefined {
($($name: expr,)+) => {
@ -61,16 +61,15 @@ fn is_valid_name_definition(ident: &CustomIdent) -> bool {
/// Parse the prelude of an @counter-style rule
pub fn parse_counter_style_name_definition<'i, 't>(
input: &mut Parser<'i, 't>
input: &mut Parser<'i, 't>,
) -> Result<CustomIdent, ParseError<'i>> {
parse_counter_style_name(input)
.and_then(|ident| {
if !is_valid_name_definition(&ident) {
Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
} else {
Ok(ident)
}
})
parse_counter_style_name(input).and_then(|ident| {
if !is_valid_name_definition(&ident) {
Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
} else {
Ok(ident)
}
})
}
/// Parse the body (inside `{}`) of an @counter-style rule
@ -81,7 +80,8 @@ pub fn parse_counter_style_body<'i, 't, R>(
input: &mut Parser<'i, 't>,
location: SourceLocation,
) -> Result<CounterStyleRuleData, ParseError<'i>>
where R: ParseErrorReporter
where
R: ParseErrorReporter,
{
let start = input.current_source_location();
let mut rule = CounterStyleRuleData::empty(name, location);
@ -94,7 +94,10 @@ pub fn parse_counter_style_body<'i, 't, R>(
while let Some(declaration) = iter.next() {
if let Err((error, slice)) = declaration {
let location = error.location;
let error = ContextualParseError::UnsupportedCounterStyleDescriptorDeclaration(slice, error);
let error = ContextualParseError::UnsupportedCounterStyleDescriptorDeclaration(
slice,
error,
);
context.log_css_error(error_context, location, error)
}
}
@ -104,27 +107,31 @@ pub fn parse_counter_style_body<'i, 't, R>(
ref system @ System::Fixed { .. } |
ref system @ System::Symbolic |
ref system @ System::Alphabetic |
ref system @ System::Numeric
if rule.symbols.is_none() => {
ref system @ System::Numeric if rule.symbols.is_none() =>
{
let system = system.to_css_string();
Some(ContextualParseError::InvalidCounterStyleWithoutSymbols(system))
Some(ContextualParseError::InvalidCounterStyleWithoutSymbols(
system,
))
}
ref system @ System::Alphabetic |
ref system @ System::Numeric
if rule.symbols().unwrap().0.len() < 2 => {
ref system @ System::Alphabetic | ref system @ System::Numeric
if rule.symbols().unwrap().0.len() < 2 =>
{
let system = system.to_css_string();
Some(ContextualParseError::InvalidCounterStyleNotEnoughSymbols(system))
Some(ContextualParseError::InvalidCounterStyleNotEnoughSymbols(
system,
))
}
System::Additive if rule.additive_symbols.is_none() => {
Some(ContextualParseError::InvalidCounterStyleWithoutAdditiveSymbols)
}
},
System::Extends(_) if rule.symbols.is_some() => {
Some(ContextualParseError::InvalidCounterStyleExtendsWithSymbols)
}
},
System::Extends(_) if rule.additive_symbols.is_some() => {
Some(ContextualParseError::InvalidCounterStyleExtendsWithAdditiveSymbols)
}
_ => None
},
_ => None,
};
if let Some(error) = error {
context.log_css_error(error_context, start, error);
@ -149,7 +156,7 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for CounterStyleRuleParser<'a, 'b> {
macro_rules! checker {
($self:ident._($value:ident)) => {};
($self:ident.$checker:ident($value:ident)) => {
($self:ident. $checker:ident($value:ident)) => {
if !$self.$checker(&$value) {
return false;
}
@ -349,14 +356,17 @@ pub enum System {
/// 'fixed <integer>?'
Fixed {
/// '<integer>?'
first_symbol_value: Option<Integer>
first_symbol_value: Option<Integer>,
},
/// 'extends <counter-style-name>'
Extends(CustomIdent),
}
impl Parse for System {
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
try_match_ident_ignore_ascii_case! { input,
"cyclic" => Ok(System::Cyclic),
"numeric" => Ok(System::Numeric),
@ -393,11 +403,11 @@ impl ToCss for System {
} else {
dest.write_str("fixed")
}
}
},
System::Extends(ref other) => {
dest.write_str("extends ")?;
other.to_css(dest)
}
},
}
}
}
@ -416,15 +426,14 @@ pub enum Symbol {
}
impl Parse for Symbol {
fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
fn parse<'i, 't>(
_context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let location = input.current_source_location();
match *input.next()? {
Token::QuotedString(ref s) => Ok(Symbol::String(s.as_ref().to_owned())),
Token::Ident(ref s) => {
Ok(Symbol::Ident(
CustomIdent::from_ident(location, s, &[])?,
))
}
Token::Ident(ref s) => Ok(Symbol::Ident(CustomIdent::from_ident(location, s, &[])?)),
ref t => Err(location.new_unexpected_token_error(t.clone())),
}
}
@ -446,7 +455,10 @@ impl Symbol {
pub struct Negative(pub Symbol, pub Option<Symbol>);
impl Parse for Negative {
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
Ok(Negative(
Symbol::parse(context, input)?,
input.try(|input| Symbol::parse(context, input)).ok(),
@ -470,26 +482,37 @@ pub enum CounterBound {
}
impl Parse for Ranges {
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
if input.try(|input| input.expect_ident_matching("auto")).is_ok() {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
if input
.try(|input| input.expect_ident_matching("auto"))
.is_ok()
{
Ok(Ranges(Vec::new()))
} else {
input.parse_comma_separated(|input| {
let opt_start = parse_bound(context, input)?;
let opt_end = parse_bound(context, input)?;
if let (CounterBound::Integer(start), CounterBound::Integer(end)) = (opt_start, opt_end) {
if start > end {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
input
.parse_comma_separated(|input| {
let opt_start = parse_bound(context, input)?;
let opt_end = parse_bound(context, input)?;
if let (CounterBound::Integer(start), CounterBound::Integer(end)) =
(opt_start, opt_end)
{
if start > end {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
}
}
Ok(opt_start..opt_end)
}).map(Ranges)
Ok(opt_start..opt_end)
})
.map(Ranges)
}
}
}
fn parse_bound<'i, 't>(
context: &ParserContext, input: &mut Parser<'i, 't>,
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<CounterBound, ParseError<'i>> {
if let Ok(integer) = input.try(|input| Integer::parse(context, input)) {
return Ok(CounterBound::Integer(integer));
@ -531,7 +554,10 @@ where
pub struct Pad(pub Integer, pub Symbol);
impl Parse for Pad {
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let pad_with = input.try(|input| Symbol::parse(context, input));
let min_length = Integer::parse_non_negative(context, input)?;
let pad_with = pad_with.or_else(|_| Symbol::parse(context, input))?;
@ -544,7 +570,10 @@ impl Parse for Pad {
pub struct Fallback(pub CustomIdent);
impl Parse for Fallback {
fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
fn parse<'i, 't>(
_context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
parse_counter_style_name(input).map(Fallback)
}
}
@ -555,16 +584,19 @@ impl Parse for Fallback {
pub struct Symbols(#[css(iterable)] pub Vec<Symbol>);
impl Parse for Symbols {
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let mut symbols = Vec::new();
loop {
if let Ok(s) = input.try(|input| Symbol::parse(context, input)) {
symbols.push(s)
} else {
if symbols.is_empty() {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
} else {
return Ok(Symbols(symbols))
return Ok(Symbols(symbols));
}
}
}
@ -576,11 +608,17 @@ impl Parse for Symbols {
pub struct AdditiveSymbols(pub Vec<AdditiveTuple>);
impl Parse for AdditiveSymbols {
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let tuples = Vec::<AdditiveTuple>::parse(context, input)?;
// FIXME maybe? https://github.com/w3c/csswg-drafts/issues/1220
if tuples.windows(2).any(|window| window[0].weight <= window[1].weight) {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
if tuples
.windows(2)
.any(|window| window[0].weight <= window[1].weight)
{
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
Ok(AdditiveSymbols(tuples))
}
@ -600,7 +638,10 @@ impl OneOrMoreSeparated for AdditiveTuple {
}
impl Parse for AdditiveTuple {
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let symbol = input.try(|input| Symbol::parse(context, input));
let weight = Integer::parse_non_negative(context, input)?;
let symbol = symbol.or_else(|_| Symbol::parse(context, input))?;
@ -629,7 +670,10 @@ pub enum SpeakAs {
}
impl Parse for SpeakAs {
fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
fn parse<'i, 't>(
_context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let mut is_spell_out = false;
let result = input.try(|input| {
let ident = input.expect_ident().map_err(|_| ())?;
@ -648,10 +692,8 @@ impl Parse for SpeakAs {
if is_spell_out {
// spell-out is not supported, but dont parse it as a <counter-style-name>.
// See bug 1024178.
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
result.or_else(|_| {
Ok(SpeakAs::Other(parse_counter_style_name(input)?))
})
result.or_else(|_| Ok(SpeakAs::Other(parse_counter_style_name(input)?)))
}
}

View file

@ -11,7 +11,7 @@ use cssparser::{Delimiter, Parser, ParserInput, SourcePosition, Token, TokenSeri
use hash::map::Entry;
use precomputed_hash::PrecomputedHash;
use properties::{CSSWideKeyword, DeclaredValue};
use selector_map::{PrecomputedHashSet, PrecomputedHashMap};
use selector_map::{PrecomputedHashMap, PrecomputedHashSet};
use selectors::parser::SelectorParseErrorKind;
use servo_arc::Arc;
use smallvec::SmallVec;
@ -19,7 +19,7 @@ use std::borrow::{Borrow, Cow};
use std::cmp;
use std::fmt::{self, Write};
use std::hash::Hash;
use style_traits::{CssWriter, ToCss, StyleParseErrorKind, ParseError};
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
/// A custom property name is just an `Atom`.
///
@ -110,15 +110,18 @@ where
/// it's necessary.
#[allow(unused_mut)]
pub fn insert(&mut self, key: K, value: V) {
let OrderedMap { ref mut index, ref mut values } = *self;
let OrderedMap {
ref mut index,
ref mut values,
} = *self;
match values.entry(key) {
Entry::Vacant(mut entry) => {
index.push(entry.key().clone());
entry.insert(value);
}
},
Entry::Occupied(mut entry) => {
entry.insert(value);
}
},
}
}
@ -170,7 +173,8 @@ where
}
fn remove_set<S>(&mut self, set: &::hash::HashSet<K, S>)
where S: ::std::hash::BuildHasher,
where
S: ::std::hash::BuildHasher,
{
if set.is_empty() {
return;
@ -187,7 +191,8 @@ where
/// added to the key-value map.
pub struct OrderedMapIterator<'a, K, V>
where
K: 'a + Eq + PrecomputedHash + Hash + Clone, V: 'a,
K: 'a + Eq + PrecomputedHash + Hash + Clone,
V: 'a,
{
/// The OrderedMap itself.
inner: &'a OrderedMap<K, V>,
@ -225,20 +230,22 @@ impl VariableValue {
&mut self,
css: &str,
css_first_token_type: TokenSerializationType,
css_last_token_type: TokenSerializationType
css_last_token_type: TokenSerializationType,
) {
// This happens e.g. between two subsequent var() functions:
// `var(--a)var(--b)`.
//
// In that case, css_*_token_type is nonsensical.
if css.is_empty() {
return
return;
}
self.first_token_type.set_if_nothing(css_first_token_type);
// If self.first_token_type was nothing,
// self.last_token_type is also nothing and this will be false:
if self.last_token_type.needs_separator_when_before(css_first_token_type) {
if self.last_token_type
.needs_separator_when_before(css_first_token_type)
{
self.css.push_str("/**/")
}
self.css.push_str(css);
@ -249,20 +256,22 @@ impl VariableValue {
&mut self,
position: (SourcePosition, TokenSerializationType),
input: &Parser,
last_token_type: TokenSerializationType
last_token_type: TokenSerializationType,
) {
self.push(input.slice_from(position.0), position.1, last_token_type)
}
fn push_variable(&mut self, variable: &ComputedValue) {
debug_assert!(variable.references.is_empty());
self.push(&variable.css, variable.first_token_type, variable.last_token_type)
self.push(
&variable.css,
variable.first_token_type,
variable.last_token_type,
)
}
/// Parse a custom property value.
pub fn parse<'i, 't>(
input: &mut Parser<'i, 't>,
) -> Result<Arc<Self>, ParseError<'i>> {
pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Arc<Self>, ParseError<'i>> {
let mut references = PrecomputedHashSet::default();
let (first_token_type, css, last_token_type) =
@ -272,30 +281,27 @@ impl VariableValue {
css: css.into_owned(),
first_token_type,
last_token_type,
references
references,
}))
}
}
/// Parse the value of a non-custom property that contains `var()` references.
pub fn parse_non_custom_with_var<'i, 't>
(input: &mut Parser<'i, 't>)
-> Result<(TokenSerializationType, Cow<'i, str>), ParseError<'i>> {
pub fn parse_non_custom_with_var<'i, 't>(
input: &mut Parser<'i, 't>,
) -> Result<(TokenSerializationType, Cow<'i, str>), ParseError<'i>> {
let (first_token_type, css, _) = parse_self_contained_declaration_value(input, None)?;
Ok((first_token_type, css))
}
fn parse_self_contained_declaration_value<'i, 't>(
input: &mut Parser<'i, 't>,
references: Option<&mut PrecomputedHashSet<Name>>
) -> Result<
(TokenSerializationType, Cow<'i, str>, TokenSerializationType),
ParseError<'i>
>
{
references: Option<&mut PrecomputedHashSet<Name>>,
) -> Result<(TokenSerializationType, Cow<'i, str>, TokenSerializationType), ParseError<'i>> {
let start_position = input.position();
let mut missing_closing_characters = String::new();
let (first, last) = parse_declaration_value(input, references, &mut missing_closing_characters)?;
let (first, last) =
parse_declaration_value(input, references, &mut missing_closing_characters)?;
let mut css: Cow<str> = input.slice_from(start_position).into();
if !missing_closing_characters.is_empty() {
// Unescaped backslash at EOF in a quoted string is ignored.
@ -311,7 +317,7 @@ fn parse_self_contained_declaration_value<'i, 't>(
fn parse_declaration_value<'i, 't>(
input: &mut Parser<'i, 't>,
references: Option<&mut PrecomputedHashSet<Name>>,
missing_closing_characters: &mut String
missing_closing_characters: &mut String,
) -> Result<(TokenSerializationType, TokenSerializationType), ParseError<'i>> {
input.parse_until_before(Delimiter::Bang | Delimiter::Semicolon, |input| {
// Need at least one token
@ -328,13 +334,18 @@ fn parse_declaration_value<'i, 't>(
fn parse_declaration_value_block<'i, 't>(
input: &mut Parser<'i, 't>,
mut references: Option<&mut PrecomputedHashSet<Name>>,
missing_closing_characters: &mut String
missing_closing_characters: &mut String,
) -> Result<(TokenSerializationType, TokenSerializationType), ParseError<'i>> {
let mut token_start = input.position();
let mut token = match input.next_including_whitespace_and_comments() {
// FIXME: remove clone() when borrows are non-lexical
Ok(token) => token.clone(),
Err(_) => return Ok((TokenSerializationType::nothing(), TokenSerializationType::nothing()))
Err(_) => {
return Ok((
TokenSerializationType::nothing(),
TokenSerializationType::nothing(),
))
},
};
let first_token_type = token.serialization_type();
loop {
@ -344,77 +355,77 @@ fn parse_declaration_value_block<'i, 't>(
parse_declaration_value_block(
input,
references.as_mut().map(|r| &mut **r),
missing_closing_characters
missing_closing_characters,
)
})?
}
};
}
macro_rules! check_closed {
($closing: expr) => {
($closing:expr) => {
if !input.slice_from(token_start).ends_with($closing) {
missing_closing_characters.push_str($closing)
}
}
};
}
let last_token_type = match token {
Token::Comment(_) => {
let token_slice = input.slice_from(token_start);
if !token_slice.ends_with("*/") {
missing_closing_characters.push_str(
if token_slice.ends_with('*') { "/" } else { "*/" })
missing_closing_characters.push_str(if token_slice.ends_with('*') {
"/"
} else {
"*/"
})
}
token.serialization_type()
}
},
Token::BadUrl(u) => {
let e = StyleParseErrorKind::BadUrlInDeclarationValueBlock(u);
return Err(input.new_custom_error(e))
}
return Err(input.new_custom_error(e));
},
Token::BadString(s) => {
let e = StyleParseErrorKind::BadStringInDeclarationValueBlock(s);
return Err(input.new_custom_error(e))
}
return Err(input.new_custom_error(e));
},
Token::CloseParenthesis => {
let e = StyleParseErrorKind::UnbalancedCloseParenthesisInDeclarationValueBlock;
return Err(input.new_custom_error(e))
}
return Err(input.new_custom_error(e));
},
Token::CloseSquareBracket => {
let e = StyleParseErrorKind::UnbalancedCloseSquareBracketInDeclarationValueBlock;
return Err(input.new_custom_error(e))
}
return Err(input.new_custom_error(e));
},
Token::CloseCurlyBracket => {
let e = StyleParseErrorKind::UnbalancedCloseCurlyBracketInDeclarationValueBlock;
return Err(input.new_custom_error(e))
}
return Err(input.new_custom_error(e));
},
Token::Function(ref name) => {
if name.eq_ignore_ascii_case("var") {
let args_start = input.state();
input.parse_nested_block(|input| {
parse_var_function(
input,
references.as_mut().map(|r| &mut **r),
)
parse_var_function(input, references.as_mut().map(|r| &mut **r))
})?;
input.reset(&args_start);
}
nested!();
check_closed!(")");
Token::CloseParenthesis.serialization_type()
}
},
Token::ParenthesisBlock => {
nested!();
check_closed!(")");
Token::CloseParenthesis.serialization_type()
}
},
Token::CurlyBracketBlock => {
nested!();
check_closed!("}");
Token::CloseCurlyBracket.serialization_type()
}
},
Token::SquareBracketBlock => {
nested!();
check_closed!("]");
Token::CloseSquareBracket.serialization_type()
}
},
Token::QuotedString(_) => {
let token_slice = input.slice_from(token_start);
let quote = &token_slice[..1];
@ -423,13 +434,15 @@ fn parse_declaration_value_block<'i, 't>(
missing_closing_characters.push_str(quote)
}
token.serialization_type()
}
},
Token::Ident(ref value) |
Token::AtKeyword(ref value) |
Token::Hash(ref value) |
Token::IDHash(ref value) |
Token::UnquotedUrl(ref value) |
Token::Dimension { unit: ref value, .. } => {
Token::Dimension {
unit: ref value, ..
} => {
if value.ends_with("<EFBFBD>") && input.slice_from(token_start).ends_with("\\") {
// Unescaped backslash at EOF in these contexts is interpreted as U+FFFD
// Check the value in case the final backslash was itself escaped.
@ -441,10 +454,8 @@ fn parse_declaration_value_block<'i, 't>(
check_closed!(")");
}
token.serialization_type()
}
_ => {
token.serialization_type()
}
},
_ => token.serialization_type(),
};
token_start = input.position();
@ -459,12 +470,12 @@ fn parse_declaration_value_block<'i, 't>(
// If the var function is valid, return Ok((custom_property_name, fallback))
fn parse_var_function<'i, 't>(
input: &mut Parser<'i, 't>,
references: Option<&mut PrecomputedHashSet<Name>>
references: Option<&mut PrecomputedHashSet<Name>>,
) -> Result<(), ParseError<'i>> {
let name = input.expect_ident_cloned()?;
let name: Result<_, ParseError> =
parse_name(&name)
.map_err(|()| input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(name.clone())));
let name: Result<_, ParseError> = parse_name(&name).map_err(|()| {
input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(name.clone()))
});
let name = name?;
if input.try(|input| input.expect_comma()).is_ok() {
// Exclude `!` and `;` at the top level
@ -535,18 +546,17 @@ impl<'a> CustomPropertiesBuilder<'a> {
DeclaredValue::CSSWideKeyword(keyword) => match keyword {
CSSWideKeyword::Initial => {
map.remove(name);
}
},
// handled in value_may_affect_style
CSSWideKeyword::Unset |
CSSWideKeyword::Inherit => unreachable!(),
}
CSSWideKeyword::Unset | CSSWideKeyword::Inherit => unreachable!(),
},
}
}
fn value_may_affect_style(
&self,
name: &Name,
value: &DeclaredValue<Arc<SpecifiedValue>>
value: &DeclaredValue<Arc<SpecifiedValue>>,
) -> bool {
match *value {
DeclaredValue::CSSWideKeyword(CSSWideKeyword::Unset) |
@ -555,28 +565,29 @@ impl<'a> CustomPropertiesBuilder<'a> {
// explicit 'inherit' or 'unset' means we can just use
// any existing value in the inherited CustomPropertiesMap.
return false;
}
_ => {}
},
_ => {},
}
let existing_value =
self.custom_properties.as_ref().and_then(|m| m.get(name))
.or_else(|| self.inherited.and_then(|m| m.get(name)));
let existing_value = self.custom_properties
.as_ref()
.and_then(|m| m.get(name))
.or_else(|| self.inherited.and_then(|m| m.get(name)));
match (existing_value, value) {
(None, &DeclaredValue::CSSWideKeyword(CSSWideKeyword::Initial)) => {
// The initial value of a custom property is the same as it
// not existing in the map.
return false;
}
},
(Some(existing_value), &DeclaredValue::Value(specified_value)) => {
// Don't bother overwriting an existing inherited value with
// the same specified value.
if existing_value == specified_value {
return false;
}
}
_ => {}
},
_ => {},
}
true
@ -682,11 +693,13 @@ fn substitute_all(custom_properties_map: &mut CustomPropertiesMap) {
// Whether this variable has been visited in this traversal.
let key;
match context.index_map.entry(name) {
Entry::Occupied(entry) => { return Some(*entry.get()); }
Entry::Occupied(entry) => {
return Some(*entry.get());
},
Entry::Vacant(entry) => {
key = entry.key().clone();
entry.insert(context.count);
}
},
}
// Hold a strong reference to the value so that we don't
// need to keep reference to context.map.
@ -713,7 +726,9 @@ fn substitute_all(custom_properties_map: &mut CustomPropertiesMap) {
Some(index) => index,
// There is nothing to do if the next variable has been
// fully resolved at this point.
None => { continue; }
None => {
continue;
},
};
let next_info = &context.var_info[next_index];
if next_index > index {
@ -745,13 +760,17 @@ fn substitute_all(custom_properties_map: &mut CustomPropertiesMap) {
let mut in_loop = self_ref;
let name;
loop {
let var_index = context.stack.pop()
let var_index = context
.stack
.pop()
.expect("The current variable should still be in stack");
let var_info = &mut context.var_info[var_index];
// We should never visit the variable again, so it's safe
// to take the name away, so that we don't do additional
// reference count.
let var_name = var_info.name.take()
let var_name = var_info
.name
.take()
.expect("Variable should not be poped from stack twice");
if var_index == index {
name = var_name;
@ -789,7 +808,7 @@ fn substitute_all(custom_properties_map: &mut CustomPropertiesMap) {
}
}
Err(())
}
},
);
if let Ok(last_token_type) = result {
computed_value.push_from(position, &input, last_token_type);
@ -835,22 +854,27 @@ fn substitute_block<'i, 't, F>(
input: &mut Parser<'i, 't>,
position: &mut (SourcePosition, TokenSerializationType),
partial_computed_value: &mut ComputedValue,
substitute_one: &mut F
substitute_one: &mut F,
) -> Result<TokenSerializationType, ParseError<'i>>
where
F: FnMut(&Name, &mut ComputedValue) -> Result<TokenSerializationType, ()>
F: FnMut(&Name, &mut ComputedValue) -> Result<TokenSerializationType, ()>,
{
let mut last_token_type = TokenSerializationType::nothing();
let mut set_position_at_next_iteration = false;
loop {
let before_this_token = input.position();
// FIXME: remove clone() when borrows are non-lexical
let next = input.next_including_whitespace_and_comments().map(|t| t.clone());
let next = input
.next_including_whitespace_and_comments()
.map(|t| t.clone());
if set_position_at_next_iteration {
*position = (before_this_token, match next {
Ok(ref token) => token.serialization_type(),
Err(_) => TokenSerializationType::nothing(),
});
*position = (
before_this_token,
match next {
Ok(ref token) => token.serialization_type(),
Err(_) => TokenSerializationType::nothing(),
},
);
set_position_at_next_iteration = false;
}
let token = match next {
@ -860,7 +884,10 @@ where
match token {
Token::Function(ref name) if name.eq_ignore_ascii_case("var") => {
partial_computed_value.push(
input.slice(position.0..before_this_token), position.1, last_token_type);
input.slice(position.0..before_this_token),
position.1,
last_token_type,
);
input.parse_nested_block(|input| {
// parse_var_function() ensures neither .unwrap() will fail.
let name = input.expect_ident_cloned().unwrap();
@ -882,13 +909,17 @@ where
input.reset(&after_comma);
let mut position = (after_comma.position(), first_token_type);
last_token_type = substitute_block(
input, &mut position, partial_computed_value, substitute_one)?;
input,
&mut position,
partial_computed_value,
substitute_one,
)?;
partial_computed_value.push_from(position, input, last_token_type);
}
Ok(())
})?;
set_position_at_next_iteration = true
}
},
Token::Function(_) |
Token::ParenthesisBlock |
@ -899,9 +930,9 @@ where
})?;
// Its the same type for CloseCurlyBracket and CloseSquareBracket.
last_token_type = Token::CloseParenthesis.serialization_type();
}
},
_ => last_token_type = token.serialization_type()
_ => last_token_type = token.serialization_type(),
}
}
// FIXME: deal with things being implicitly closed at the end of the input. E.g.
@ -925,14 +956,17 @@ pub fn substitute<'i>(
let mut input = Parser::new(&mut input);
let mut position = (input.position(), first_token_type);
let last_token_type = substitute_block(
&mut input, &mut position, &mut substituted, &mut |name, substituted| {
&mut input,
&mut position,
&mut substituted,
&mut |name, substituted| {
if let Some(value) = computed_values_map.and_then(|map| map.get(name)) {
substituted.push_variable(value);
Ok(value.last_token_type)
} else {
Err(())
}
}
},
)?;
substituted.push_from(position, &input, last_token_type);
Ok(substituted.css)

View file

@ -12,7 +12,7 @@ use invalidation::element::restyle_hints::RestyleHint;
use malloc_size_of::MallocSizeOfOps;
use properties::ComputedValues;
use rule_tree::StrongRuleNode;
use selector_parser::{EAGER_PSEUDO_COUNT, PseudoElement, RestyleDamage};
use selector_parser::{PseudoElement, RestyleDamage, EAGER_PSEUDO_COUNT};
use selectors::NthIndexCache;
use servo_arc::Arc;
use shared_lock::StylesheetGuards;
@ -95,7 +95,12 @@ impl fmt::Debug for EagerPseudoArray {
write!(f, "EagerPseudoArray {{ ")?;
for i in 0..EAGER_PSEUDO_COUNT {
if let Some(ref values) = self[i] {
write!(f, "{:?}: {:?}, ", PseudoElement::from_eager_index(i), &values.rules)?;
write!(
f,
"{:?}: {:?}, ",
PseudoElement::from_eager_index(i),
&values.rules
)?;
}
}
write!(f, "}}")
@ -132,7 +137,9 @@ impl EagerPseudoStyles {
/// Returns a reference to the style for a given eager pseudo, if it exists.
pub fn get(&self, pseudo: &PseudoElement) -> Option<&Arc<ComputedValues>> {
debug_assert!(pseudo.is_eager());
self.0.as_ref().and_then(|p| p[pseudo.eager_index()].as_ref())
self.0
.as_ref()
.and_then(|p| p[pseudo.eager_index()].as_ref())
}
/// Sets the style for the eager pseudo.
@ -188,8 +195,12 @@ impl ElementStyles {
// substitute the rule node instead.
impl fmt::Debug for ElementStyles {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ElementStyles {{ primary: {:?}, pseudos: {:?} }}",
self.primary.as_ref().map(|x| &x.rules), self.pseudos)
write!(
f,
"ElementStyles {{ primary: {:?}, pseudos: {:?} }}",
self.primary.as_ref().map(|x| &x.rules),
self.pseudos
)
}
}
@ -248,13 +259,15 @@ impl ElementData {
use invalidation::element::invalidator::TreeStyleInvalidator;
use invalidation::element::state_and_attributes::StateAndAttrInvalidationProcessor;
debug!("invalidate_style_if_needed: {:?}, flags: {:?}, has_snapshot: {}, \
handled_snapshot: {}, pseudo: {:?}",
element,
shared_context.traversal_flags,
element.has_snapshot(),
element.handled_snapshot(),
element.implemented_pseudo_element());
debug!(
"invalidate_style_if_needed: {:?}, flags: {:?}, has_snapshot: {}, \
handled_snapshot: {}, pseudo: {:?}",
element,
shared_context.traversal_flags,
element.has_snapshot(),
element.handled_snapshot(),
element.implemented_pseudo_element()
);
if !element.has_snapshot() || element.handled_snapshot() {
return InvalidationResult::empty();
@ -275,11 +288,7 @@ impl ElementData {
nth_index_cache,
);
let invalidator = TreeStyleInvalidator::new(
element,
stack_limit_checker,
&mut processor,
);
let invalidator = TreeStyleInvalidator::new(element, stack_limit_checker, &mut processor);
let result = invalidator.invalidate();
@ -305,8 +314,8 @@ impl ElementData {
/// Returns this element's primary style as a resolved style to use for sharing.
pub fn share_primary_style(&self) -> PrimaryStyle {
let reused_via_rule_node =
self.flags.contains(ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE);
let reused_via_rule_node = self.flags
.contains(ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE);
PrimaryStyle {
style: ResolvedStyle(self.styles.primary().clone()),
@ -317,19 +326,18 @@ impl ElementData {
/// Sets a new set of styles, returning the old ones.
pub fn set_styles(&mut self, new_styles: ResolvedElementStyles) -> ElementStyles {
if new_styles.primary.reused_via_rule_node {
self.flags.insert(ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE);
self.flags
.insert(ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE);
} else {
self.flags.remove(ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE);
self.flags
.remove(ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE);
}
mem::replace(&mut self.styles, new_styles.into())
}
/// Returns the kind of restyling that we're going to need to do on this
/// element, based of the stored restyle hint.
pub fn restyle_kind(
&self,
shared_context: &SharedStyleContext
) -> RestyleKind {
pub fn restyle_kind(&self, shared_context: &SharedStyleContext) -> RestyleKind {
if shared_context.traversal_flags.for_animation_only() {
return self.restyle_kind_for_animation(shared_context);
}
@ -343,25 +351,29 @@ impl ElementData {
}
if self.hint.has_replacements() {
debug_assert!(!self.hint.has_animation_hint(),
"Animation only restyle hint should have already processed");
debug_assert!(
!self.hint.has_animation_hint(),
"Animation only restyle hint should have already processed"
);
return RestyleKind::CascadeWithReplacements(self.hint & RestyleHint::replacements());
}
debug_assert!(self.hint.has_recascade_self(),
"We definitely need to do something: {:?}!", self.hint);
debug_assert!(
self.hint.has_recascade_self(),
"We definitely need to do something: {:?}!",
self.hint
);
return RestyleKind::CascadeOnly;
}
/// Returns the kind of restyling for animation-only restyle.
fn restyle_kind_for_animation(
&self,
shared_context: &SharedStyleContext,
) -> RestyleKind {
fn restyle_kind_for_animation(&self, shared_context: &SharedStyleContext) -> RestyleKind {
debug_assert!(shared_context.traversal_flags.for_animation_only());
debug_assert!(self.has_styles(),
"Unstyled element shouldn't be traversed during \
animation-only traversal");
debug_assert!(
self.has_styles(),
"Unstyled element shouldn't be traversed during \
animation-only traversal"
);
// return either CascadeWithReplacements or CascadeOnly in case of
// animation-only restyle. I.e. animation-only restyle never does
@ -384,11 +396,13 @@ impl ElementData {
pub fn important_rules_are_different(
&self,
rules: &StrongRuleNode,
guards: &StylesheetGuards
guards: &StylesheetGuards,
) -> bool {
debug_assert!(self.has_styles());
let (important_rules, _custom) =
self.styles.primary().rules().get_properties_overriding_animations(&guards);
let (important_rules, _custom) = self.styles
.primary()
.rules()
.get_properties_overriding_animations(&guards);
let (other_important_rules, _custom) = rules.get_properties_overriding_animations(&guards);
important_rules != other_important_rules
}
@ -419,7 +433,8 @@ impl ElementData {
/// to do a post-traversal.
pub fn set_restyled(&mut self) {
self.flags.insert(ElementDataFlags::WAS_RESTYLED);
self.flags.remove(ElementDataFlags::TRAVERSED_WITHOUT_STYLING);
self.flags
.remove(ElementDataFlags::TRAVERSED_WITHOUT_STYLING);
}
/// Returns true if this element was restyled.
@ -430,13 +445,15 @@ impl ElementData {
/// Mark that we traversed this element without computing any style for it.
pub fn set_traversed_without_styling(&mut self) {
self.flags.insert(ElementDataFlags::TRAVERSED_WITHOUT_STYLING);
self.flags
.insert(ElementDataFlags::TRAVERSED_WITHOUT_STYLING);
}
/// Returns whether the element was traversed without computing any style for
/// it.
pub fn traversed_without_styling(&self) -> bool {
self.flags.contains(ElementDataFlags::TRAVERSED_WITHOUT_STYLING)
self.flags
.contains(ElementDataFlags::TRAVERSED_WITHOUT_STYLING)
}
/// Returns whether this element has been part of a restyle.
@ -464,8 +481,10 @@ impl ElementData {
/// happens later in the styling pipeline. The former gives us the stronger guarantees
/// we need for style sharing, the latter does not.
pub fn safe_for_cousin_sharing(&self) -> bool {
!self.flags.intersects(ElementDataFlags::TRAVERSED_WITHOUT_STYLING |
ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE)
!self.flags.intersects(
ElementDataFlags::TRAVERSED_WITHOUT_STYLING |
ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE,
)
}
/// Measures memory usage.

View file

@ -7,11 +7,13 @@
#![allow(unsafe_code)]
#![deny(missing_docs)]
use {Atom, Namespace, LocalName, WeakAtom};
use {Atom, LocalName, Namespace, WeakAtom};
use applicable_declarations::ApplicableDeclarationBlock;
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
#[cfg(feature = "gecko")] use context::PostAnimationTasks;
#[cfg(feature = "gecko")] use context::UpdateAnimationsTasks;
#[cfg(feature = "gecko")]
use context::PostAnimationTasks;
#[cfg(feature = "gecko")]
use context::UpdateAnimationsTasks;
use data::ElementData;
use element_state::ElementState;
use font_metrics::FontMetricsProvider;
@ -77,7 +79,7 @@ where
let n = self.0.next()?;
// Filter out nodes that layout should ignore.
if n.is_text_node() || n.is_element() {
return Some(n)
return Some(n);
}
}
}
@ -87,7 +89,7 @@ where
pub struct DomChildren<N>(Option<N>);
impl<N> Iterator for DomChildren<N>
where
N: TNode
N: TNode,
{
type Item = N;
@ -106,7 +108,7 @@ pub struct DomDescendants<N> {
impl<N> Iterator for DomDescendants<N>
where
N: TNode
N: TNode,
{
type Item = N;
@ -119,7 +121,7 @@ where
}
/// The `TDocument` trait, to represent a document node.
pub trait TDocument : Sized + Copy + Clone {
pub trait TDocument: Sized + Copy + Clone {
/// The concrete `TNode` type.
type ConcreteNode: TNode<ConcreteDocument = Self>;
@ -147,7 +149,7 @@ pub trait TDocument : Sized + Copy + Clone {
/// The `TNode` trait. This is the main generic trait over which the style
/// system can be implemented.
pub trait TNode : Sized + Copy + Clone + Debug + NodeInfo + PartialEq {
pub trait TNode: Sized + Copy + Clone + Debug + NodeInfo + PartialEq {
/// The concrete `TElement` type.
type ConcreteElement: TElement<ConcreteNode = Self>;
@ -278,12 +280,13 @@ impl<N: TNode> Debug for ShowSubtreeDataAndPrimaryValues<N> {
fn fmt_with_data<N: TNode>(f: &mut fmt::Formatter, n: N) -> fmt::Result {
if let Some(el) = n.as_element() {
write!(
f, "{:?} dd={} aodd={} data={:?}",
f,
"{:?} dd={} aodd={} data={:?}",
el,
el.has_dirty_descendants(),
el.has_animation_only_dirty_descendants(),
el.borrow_data(),
)
)
} else {
write!(f, "{:?}", n)
}
@ -296,15 +299,19 @@ fn fmt_with_data_and_primary_values<N: TNode>(f: &mut fmt::Formatter, n: N) -> f
let aodd = el.has_animation_only_dirty_descendants();
let data = el.borrow_data();
let values = data.as_ref().and_then(|d| d.styles.get_primary());
write!(f, "{:?} dd={} aodd={} data={:?} values={:?}", el, dd, aodd, &data, values)
write!(
f,
"{:?} dd={} aodd={} data={:?} values={:?}",
el, dd, aodd, &data, values
)
} else {
write!(f, "{:?}", n)
}
}
fn fmt_subtree<F, N: TNode>(f: &mut fmt::Formatter, stringify: &F, n: N, indent: u32)
-> fmt::Result
where F: Fn(&mut fmt::Formatter, N) -> fmt::Result
fn fmt_subtree<F, N: TNode>(f: &mut fmt::Formatter, stringify: &F, n: N, indent: u32) -> fmt::Result
where
F: Fn(&mut fmt::Formatter, N) -> fmt::Result,
{
for _ in 0..indent {
write!(f, " ")?;
@ -321,7 +328,7 @@ fn fmt_subtree<F, N: TNode>(f: &mut fmt::Formatter, stringify: &F, n: N, indent:
}
/// The ShadowRoot trait.
pub trait TShadowRoot : Sized + Copy + Clone + PartialEq {
pub trait TShadowRoot: Sized + Copy + Clone + PartialEq {
/// The concrete node type.
type ConcreteNode: TNode<ConcreteShadowRoot = Self>;
@ -338,15 +345,8 @@ pub trait TShadowRoot : Sized + Copy + Clone + PartialEq {
}
/// The element trait, the main abstraction the style crate acts over.
pub trait TElement
: Eq
+ PartialEq
+ Debug
+ Hash
+ Sized
+ Copy
+ Clone
+ SelectorsElement<Impl = SelectorImpl>
pub trait TElement:
Eq + PartialEq + Debug + Hash + Sized + Copy + Clone + SelectorsElement<Impl = SelectorImpl>
{
/// The concrete node type.
type ConcreteNode: TNode<ConcreteElement = Self>;
@ -371,12 +371,16 @@ pub trait TElement
///
/// Otherwise we may set document-level state incorrectly, like the root
/// font-size used for rem units.
fn owner_doc_matches_for_testing(&self, _: &Device) -> bool { true }
fn owner_doc_matches_for_testing(&self, _: &Device) -> bool {
true
}
/// Whether this element should match user and author rules.
///
/// We use this for Native Anonymous Content in Gecko.
fn matches_user_and_author_rules(&self) -> bool { true }
fn matches_user_and_author_rules(&self) -> bool {
true
}
/// Returns the depth of this element in the DOM.
fn depth(&self) -> usize {
@ -424,7 +428,8 @@ pub trait TElement
fn each_anonymous_content_child<F>(&self, _f: F)
where
F: FnMut(Self),
{}
{
}
/// Return whether this element is an element in the HTML namespace.
fn is_html_element(&self) -> bool;
@ -445,8 +450,7 @@ pub trait TElement
/// Unset the style attribute's dirty bit.
/// Servo doesn't need to manage ditry bit for style attribute.
fn unset_dirty_style_attribute(&self) {
}
fn unset_dirty_style_attribute(&self) {}
/// Get this element's SMIL override declarations.
fn smil_override(&self) -> Option<ArcBorrow<Locked<PropertyDeclarationBlock>>> {
@ -458,7 +462,7 @@ pub trait TElement
/// FIXME(emilio): Is this really useful?
fn animation_rules(&self) -> AnimationRules {
if !self.may_have_animations() {
return AnimationRules(None, None)
return AnimationRules(None, None);
}
AnimationRules(self.animation_rule(), self.transition_rule())
@ -484,7 +488,9 @@ pub trait TElement
fn id(&self) -> Option<&WeakAtom>;
/// Internal iterator for the classes of this element.
fn each_class<F>(&self, callback: F) where F: FnMut(&Atom);
fn each_class<F>(&self, callback: F)
where
F: FnMut(&Atom);
/// Whether a given element may generate a pseudo-element.
///
@ -492,11 +498,7 @@ pub trait TElement
/// `::-first-line` or `::-first-letter`, when we know it won't affect us.
///
/// TODO(emilio, bz): actually implement the logic for it.
fn may_generate_pseudo(
&self,
pseudo: &PseudoElement,
_primary_style: &ComputedValues,
) -> bool {
fn may_generate_pseudo(&self, pseudo: &PseudoElement, _primary_style: &ComputedValues) -> bool {
// ::before/::after are always supported for now, though we could try to
// optimize out leaf elements.
@ -505,8 +507,10 @@ pub trait TElement
// block-inside things that might have any computed display value due to
// things like fieldsets, legends, etc. Need to figure out how this
// should work.
debug_assert!(pseudo.is_eager(),
"Someone called may_generate_pseudo with a non-eager pseudo.");
debug_assert!(
pseudo.is_eager(),
"Someone called may_generate_pseudo with a non-eager pseudo."
);
true
}
@ -542,8 +546,7 @@ pub trait TElement
// animation-name in normal restyle and creating a new CSS
// animation in a SequentialTask) is processed after the normal
// traversal in that we had elements that handled snapshot.
return data.has_styles() &&
!data.hint.has_animation_hint_or_recascade();
return data.has_styles() && !data.hint.has_animation_hint_or_recascade();
}
if self.has_snapshot() && !self.handled_snapshot() {
@ -595,37 +598,43 @@ pub trait TElement
/// processing.
///
/// Only safe to call with exclusive access to the element.
unsafe fn set_animation_only_dirty_descendants(&self) {
}
unsafe fn set_animation_only_dirty_descendants(&self) {}
/// Flag that this element has no descendant for animation-only restyle processing.
///
/// Only safe to call with exclusive access to the element.
unsafe fn unset_animation_only_dirty_descendants(&self) {
}
unsafe fn unset_animation_only_dirty_descendants(&self) {}
/// Clear all bits related describing the dirtiness of descendants.
///
/// In Gecko, this corresponds to the regular dirty descendants bit, the
/// animation-only dirty descendants bit, and the lazy frame construction
/// descendants bit.
unsafe fn clear_descendant_bits(&self) { self.unset_dirty_descendants(); }
unsafe fn clear_descendant_bits(&self) {
self.unset_dirty_descendants();
}
/// Clear all element flags related to dirtiness.
///
/// In Gecko, this corresponds to the regular dirty descendants bit, the
/// animation-only dirty descendants bit, the lazy frame construction bit,
/// and the lazy frame construction descendants bit.
unsafe fn clear_dirty_bits(&self) { self.unset_dirty_descendants(); }
unsafe fn clear_dirty_bits(&self) {
self.unset_dirty_descendants();
}
/// Returns true if this element is a visited link.
///
/// Servo doesn't support visited styles yet.
fn is_visited_link(&self) -> bool { false }
fn is_visited_link(&self) -> bool {
false
}
/// Returns true if this element is native anonymous (only Gecko has native
/// anonymous content).
fn is_native_anonymous(&self) -> bool { false }
fn is_native_anonymous(&self) -> bool {
false
}
/// Returns the pseudo-element implemented by this element, if any.
///
@ -637,7 +646,9 @@ pub trait TElement
/// given otherwise we don't know if we need to create an element or not.
///
/// Servo doesn't have to deal with this.
fn implemented_pseudo_element(&self) -> Option<PseudoElement> { None }
fn implemented_pseudo_element(&self) -> Option<PseudoElement> {
None
}
/// Atomically stores the number of children of this node that we will
/// need to process during bottom-up traversal.
@ -692,13 +703,17 @@ pub trait TElement
/// In Gecko, element has a flag that represents the element may have
/// any type of animations or not to bail out animation stuff early.
/// Whereas Servo doesn't have such flag.
fn may_have_animations(&self) -> bool { false }
fn may_have_animations(&self) -> bool {
false
}
/// Creates a task to update various animation state on a given (pseudo-)element.
#[cfg(feature = "gecko")]
fn update_animations(&self,
before_change_style: Option<Arc<ComputedValues>>,
tasks: UpdateAnimationsTasks);
fn update_animations(
&self,
before_change_style: Option<Arc<ComputedValues>>,
tasks: UpdateAnimationsTasks,
);
/// Creates a task to process post animation on a given element.
#[cfg(feature = "gecko")]
@ -722,7 +737,7 @@ pub trait TElement
Some(d) => d,
None => return false,
};
return data.hint.has_animation_hint()
return data.hint.has_animation_hint();
}
/// Returns the anonymous content for the current element's XBL binding,
@ -740,7 +755,9 @@ pub trait TElement
fn containing_shadow(&self) -> Option<<Self::ConcreteNode as TNode>::ConcreteShadowRoot>;
/// XBL hack for style sharing. :(
fn has_same_xbl_proto_binding_as(&self, _other: Self) -> bool { true }
fn has_same_xbl_proto_binding_as(&self, _other: Self) -> bool {
true
}
/// Return the element which we can use to look up rules in the selector
/// maps.
@ -826,7 +843,7 @@ pub trait TElement
fn might_need_transitions_update(
&self,
old_values: Option<&ComputedValues>,
new_values: &ComputedValues
new_values: &ComputedValues,
) -> bool;
/// Returns true if one of the transitions needs to be updated on this element. We check all
@ -837,7 +854,7 @@ pub trait TElement
fn needs_transitions_update(
&self,
before_change_style: &ComputedValues,
after_change_style: &ComputedValues
after_change_style: &ComputedValues,
) -> bool;
/// Returns the value of the `xml:lang=""` attribute (or, if appropriate,
@ -852,7 +869,7 @@ pub trait TElement
fn match_element_lang(
&self,
override_lang: Option<Option<AttrValue>>,
value: &PseudoClassStringArg
value: &PseudoClassStringArg,
) -> bool;
/// Returns whether this element is the main body element of the HTML
@ -865,8 +882,7 @@ pub trait TElement
&self,
visited_handling: VisitedHandlingMode,
hints: &mut V,
)
where
) where
V: Push<ApplicableDeclarationBlock>;
}

View file

@ -26,12 +26,7 @@ pub fn element_matches<E>(
where
E: Element,
{
let mut context = MatchingContext::new(
MatchingMode::Normal,
None,
None,
quirks_mode,
);
let mut context = MatchingContext::new(MatchingMode::Normal, None, None, quirks_mode);
context.scope_element = Some(element.opaque());
context.current_host = element.containing_shadow_host().map(|e| e.opaque());
matching::matches_selector_list(selector_list, element, &mut context)
@ -93,7 +88,9 @@ pub struct QueryAll;
impl<E: TElement> SelectorQuery<E> for QueryAll {
type Output = QuerySelectorAllResult<E>;
fn should_stop_after_first_match() -> bool { false }
fn should_stop_after_first_match() -> bool {
false
}
fn append_element(output: &mut Self::Output, element: E) {
output.push(element);
@ -110,7 +107,9 @@ pub struct QueryFirst;
impl<E: TElement> SelectorQuery<E> for QueryFirst {
type Output = Option<E>;
fn should_stop_after_first_match() -> bool { true }
fn should_stop_after_first_match() -> bool {
true
}
fn append_element(output: &mut Self::Output, element: E) {
if output.is_none() {
@ -140,7 +139,9 @@ where
Q: SelectorQuery<E>,
Q::Output: 'a,
{
fn light_tree_only(&self) -> bool { true }
fn light_tree_only(&self) -> bool {
true
}
fn collect_invalidations(
&mut self,
@ -164,12 +165,11 @@ where
// For now, assert it's a root element.
debug_assert!(element.parent_element().is_none());
let target_vector =
if self.matching_context.scope_element.is_some() {
&mut descendant_invalidations.dom_descendants
} else {
self_invalidations
};
let target_vector = if self.matching_context.scope_element.is_some() {
&mut descendant_invalidations.dom_descendants
} else {
self_invalidations
};
for selector in self.selector_list.0.iter() {
target_vector.push(Invalidation::new(selector, 0))
@ -184,7 +184,7 @@ where
fn should_process_descendants(&mut self, _: E) -> bool {
if Q::should_stop_after_first_match() {
return Q::is_empty(&self.results)
return Q::is_empty(&self.results);
}
true
@ -198,11 +198,7 @@ where
fn invalidated_descendants(&mut self, _e: E, _child: E) {}
}
fn collect_all_elements<E, Q, F>(
root: E::ConcreteNode,
results: &mut Q::Output,
mut filter: F,
)
fn collect_all_elements<E, Q, F>(root: E::ConcreteNode, results: &mut Q::Output, mut filter: F)
where
E: TElement,
Q: SelectorQuery<E>,
@ -279,8 +275,7 @@ fn collect_elements_with_id<E, Q, F>(
results: &mut Q::Output,
quirks_mode: QuirksMode,
mut filter: F,
)
where
) where
E: TElement,
Q: SelectorQuery<E>,
F: FnMut(E) -> bool,
@ -289,15 +284,14 @@ where
let elements = match fast_connected_elements_with_id(&doc, root, id, quirks_mode) {
Ok(elements) => elements,
Err(()) => {
let case_sensitivity =
quirks_mode.classes_and_ids_case_sensitivity();
let case_sensitivity = quirks_mode.classes_and_ids_case_sensitivity();
collect_all_elements::<E, Q, _>(root, results, |e| {
e.has_id(id, case_sensitivity) && filter(e)
});
return;
}
},
};
for element in elements {
@ -332,35 +326,28 @@ where
match *component {
Component::ExplicitUniversalType => {
collect_all_elements::<E, Q, _>(root, results, |_| true)
}
},
Component::ID(ref id) => {
collect_elements_with_id::<E, Q, _>(
root,
id,
results,
quirks_mode,
|_| true,
);
}
collect_elements_with_id::<E, Q, _>(root, id, results, quirks_mode, |_| true);
},
Component::Class(ref class) => {
let case_sensitivity = quirks_mode.classes_and_ids_case_sensitivity();
collect_all_elements::<E, Q, _>(root, results, |element| {
element.has_class(class, case_sensitivity)
})
}
Component::LocalName(LocalName { ref name, ref lower_name }) => {
collect_all_elements::<E, Q, _>(root, results, |element| {
if element.is_html_element_in_html_document() {
element.local_name() == lower_name.borrow()
} else {
element.local_name() == name.borrow()
}
})
}
},
Component::LocalName(LocalName {
ref name,
ref lower_name,
}) => collect_all_elements::<E, Q, _>(root, results, |element| {
if element.is_html_element_in_html_document() {
element.local_name() == lower_name.borrow()
} else {
element.local_name() == name.borrow()
}
}),
// TODO(emilio): More fast paths?
_ => {
return Err(())
}
_ => return Err(()),
}
Ok(())
@ -411,26 +398,15 @@ where
if combinator.is_none() {
// In the rightmost compound, just find descendants of
// root that match the selector list with that id.
collect_elements_with_id::<E, Q, _>(
root,
id,
results,
quirks_mode,
|e| {
matching::matches_selector_list(
selector_list,
&e,
matching_context,
)
}
);
collect_elements_with_id::<E, Q, _>(root, id, results, quirks_mode, |e| {
matching::matches_selector_list(selector_list, &e, matching_context)
});
return Ok(());
}
let doc = root.owner_doc();
let elements =
fast_connected_elements_with_id(&doc, root, id, quirks_mode)?;
let elements = fast_connected_elements_with_id(&doc, root, id, quirks_mode)?;
if elements.is_empty() {
return Ok(());
@ -473,7 +449,7 @@ where
}
return Ok(());
}
},
_ => {},
}
}
@ -505,8 +481,7 @@ fn query_selector_slow<E, Q>(
selector_list: &SelectorList<E::Impl>,
results: &mut Q::Output,
matching_context: &mut MatchingContext<E::Impl>,
)
where
) where
E: TElement,
Q: SelectorQuery<E>,
{
@ -530,8 +505,7 @@ pub fn query_selector<E, Q>(
selector_list: &SelectorList<E::Impl>,
results: &mut Q::Output,
may_use_invalidation: MayUseInvalidation,
)
where
) where
E: TElement,
Q: SelectorQuery<E>,
{
@ -554,12 +528,8 @@ where
None => root.as_shadow_root().map(|root| root.host().opaque()),
};
let fast_result = query_selector_fast::<E, Q>(
root,
selector_list,
results,
&mut matching_context,
);
let fast_result =
query_selector_fast::<E, Q>(root, selector_list, results, &mut matching_context);
if fast_result.is_ok() {
return;
@ -577,17 +547,11 @@ where
//
// A selector with a combinator needs to have a length of at least 3: A
// simple selector, a combinator, and another simple selector.
let invalidation_may_be_useful =
may_use_invalidation == MayUseInvalidation::Yes &&
let invalidation_may_be_useful = may_use_invalidation == MayUseInvalidation::Yes &&
selector_list.0.iter().any(|s| s.len() > 2);
if root_element.is_some() || !invalidation_may_be_useful {
query_selector_slow::<E, Q>(
root,
selector_list,
results,
&mut matching_context,
);
query_selector_slow::<E, Q>(root, selector_list, results, &mut matching_context);
} else {
let mut processor = QuerySelectorProcessor::<E, Q> {
results,
@ -597,11 +561,8 @@ where
for node in root.dom_children() {
if let Some(e) = node.as_element() {
TreeStyleInvalidator::new(
e,
/* stack_limit_checker = */ None,
&mut processor,
).invalidate();
TreeStyleInvalidator::new(e, /* stack_limit_checker = */ None, &mut processor)
.invalidate();
}
}
}

View file

@ -7,7 +7,7 @@
#![deny(missing_docs)]
use context::{StyleContext, PerThreadTraversalStatistics};
use context::{PerThreadTraversalStatistics, StyleContext};
use context::{ThreadLocalStyleContext, TraversalStatistics};
use dom::{SendNode, TElement, TNode};
use parallel;
@ -39,9 +39,8 @@ fn report_statistics(stats: &PerThreadTraversalStatistics) {
// This should only be called in the main thread, or it may be racy
// to update the statistics in a global variable.
debug_assert!(unsafe { ::gecko_bindings::bindings::Gecko_IsMainThread() });
let gecko_stats = unsafe {
&mut ::gecko_bindings::structs::ServoTraversalStatistics_sSingleton
};
let gecko_stats =
unsafe { &mut ::gecko_bindings::structs::ServoTraversalStatistics_sSingleton };
gecko_stats.mElementsTraversed += stats.elements_traversed;
gecko_stats.mElementsStyled += stats.elements_styled;
gecko_stats.mElementsMatched += stats.elements_matched;
@ -63,18 +62,22 @@ fn report_statistics(stats: &PerThreadTraversalStatistics) {
pub fn traverse_dom<E, D>(
traversal: &D,
token: PreTraverseToken<E>,
pool: Option<&rayon::ThreadPool>
)
where
pool: Option<&rayon::ThreadPool>,
) where
E: TElement,
D: DomTraversal<E>,
{
let root =
token.traversal_root().expect("Should've ensured we needed to traverse");
let root = token
.traversal_root()
.expect("Should've ensured we needed to traverse");
let report_stats = should_report_statistics();
let dump_stats = traversal.shared_context().options.dump_style_statistics;
let start_time = if dump_stats { Some(time::precise_time_s()) } else { None };
let start_time = if dump_stats {
Some(time::precise_time_s())
} else {
None
};
// Declare the main-thread context, as well as the worker-thread contexts,
// which we may or may not instantiate. It's important to declare the worker-
@ -96,21 +99,26 @@ where
// Process the nodes breadth-first, just like the parallel traversal does.
// This helps keep similar traversal characteristics for the style sharing
// cache.
let mut discovered =
VecDeque::<SendNode<E::ConcreteNode>>::with_capacity(WORK_UNIT_MAX * 2);
let mut discovered = VecDeque::<SendNode<E::ConcreteNode>>::with_capacity(WORK_UNIT_MAX * 2);
let mut depth = root.depth();
let mut nodes_remaining_at_current_depth = 1;
discovered.push_back(unsafe { SendNode::new(root.as_node()) });
while let Some(node) = discovered.pop_front() {
let mut children_to_process = 0isize;
let traversal_data = PerLevelTraversalData { current_dom_depth: depth };
let traversal_data = PerLevelTraversalData {
current_dom_depth: depth,
};
traversal.process_preorder(&traversal_data, &mut context, *node, |n| {
children_to_process += 1;
discovered.push_back(unsafe { SendNode::new(n) });
});
traversal.handle_postorder_traversal(&mut context, root.as_node().opaque(),
*node, children_to_process);
traversal.handle_postorder_traversal(
&mut context,
root.as_node().opaque(),
*node,
children_to_process,
);
nodes_remaining_at_current_depth -= 1;
if nodes_remaining_at_current_depth == 0 {
@ -131,11 +139,13 @@ where
DispatchMode::TailCall,
/* recursion_ok = */ true,
root_opaque,
PerLevelTraversalData { current_dom_depth: depth },
PerLevelTraversalData {
current_dom_depth: depth,
},
scope,
pool,
traversal,
maybe_tls.as_ref().unwrap()
maybe_tls.as_ref().unwrap(),
);
});
});
@ -147,16 +157,13 @@ where
// Collect statistics from thread-locals if requested.
if dump_stats || report_stats {
let mut aggregate =
mem::replace(&mut context.thread_local.statistics, Default::default());
let mut aggregate = mem::replace(&mut context.thread_local.statistics, Default::default());
let parallel = maybe_tls.is_some();
if let Some(ref mut tls) = maybe_tls {
let slots = unsafe { tls.unsafe_get() };
aggregate = slots.iter().fold(aggregate, |acc, t| {
match *t.borrow() {
None => acc,
Some(ref cx) => &cx.statistics + &acc,
}
aggregate = slots.iter().fold(aggregate, |acc, t| match *t.borrow() {
None => acc,
Some(ref cx) => &cx.statistics + &acc,
});
}
@ -165,12 +172,8 @@ where
}
// dump statistics to stdout if requested
if dump_stats {
let stats = TraversalStatistics::new(
aggregate,
traversal,
parallel,
start_time.unwrap()
);
let stats =
TraversalStatistics::new(aggregate, traversal, parallel, start_time.unwrap());
if stats.is_large {
println!("{}", stats);
}

View file

@ -14,7 +14,7 @@ use servo_arc::Arc;
use shared_lock::SharedRwLock;
use std::borrow::Cow;
use std::str;
use stylesheets::{Stylesheet, StylesheetLoader, Origin, UrlExtraData};
use stylesheets::{Origin, Stylesheet, StylesheetLoader, UrlExtraData};
struct EncodingRs;
@ -26,8 +26,7 @@ impl EncodingSupport for EncodingRs {
}
fn is_utf16_be_or_le(encoding: &Self::Encoding) -> bool {
*encoding == encoding_rs::UTF_16LE ||
*encoding == encoding_rs::UTF_16BE
*encoding == encoding_rs::UTF_16LE || *encoding == encoding_rs::UTF_16BE
}
fn from_label(ascii_label: &[u8]) -> Option<Self::Encoding> {
@ -35,11 +34,16 @@ impl EncodingSupport for EncodingRs {
}
}
fn decode_stylesheet_bytes<'a>(css: &'a [u8], protocol_encoding_label: Option<&str>,
environment_encoding: Option<&'static encoding_rs::Encoding>)
-> Cow<'a, str> {
fn decode_stylesheet_bytes<'a>(
css: &'a [u8],
protocol_encoding_label: Option<&str>,
environment_encoding: Option<&'static encoding_rs::Encoding>,
) -> Cow<'a, str> {
let fallback_encoding = stylesheet_encoding::<EncodingRs>(
css, protocol_encoding_label.map(str::as_bytes), environment_encoding);
css,
protocol_encoding_label.map(str::as_bytes),
environment_encoding,
);
let (result, _used_encoding, _) = fallback_encoding.decode(&css);
// FIXME record used encoding for environment encoding of @import
result
@ -51,48 +55,56 @@ impl Stylesheet {
///
/// Takes care of decoding the network bytes and forwards the resulting
/// string to `Stylesheet::from_str`.
pub fn from_bytes<R>(bytes: &[u8],
url_data: UrlExtraData,
protocol_encoding_label: Option<&str>,
environment_encoding: Option<&'static encoding_rs::Encoding>,
origin: Origin,
media: MediaList,
shared_lock: SharedRwLock,
stylesheet_loader: Option<&StylesheetLoader>,
error_reporter: &R,
quirks_mode: QuirksMode)
-> Stylesheet
where R: ParseErrorReporter
pub fn from_bytes<R>(
bytes: &[u8],
url_data: UrlExtraData,
protocol_encoding_label: Option<&str>,
environment_encoding: Option<&'static encoding_rs::Encoding>,
origin: Origin,
media: MediaList,
shared_lock: SharedRwLock,
stylesheet_loader: Option<&StylesheetLoader>,
error_reporter: &R,
quirks_mode: QuirksMode,
) -> Stylesheet
where
R: ParseErrorReporter,
{
let string = decode_stylesheet_bytes(bytes, protocol_encoding_label, environment_encoding);
Stylesheet::from_str(&string,
url_data,
origin,
Arc::new(shared_lock.wrap(media)),
shared_lock,
stylesheet_loader,
error_reporter,
quirks_mode,
0)
Stylesheet::from_str(
&string,
url_data,
origin,
Arc::new(shared_lock.wrap(media)),
shared_lock,
stylesheet_loader,
error_reporter,
quirks_mode,
0,
)
}
/// Updates an empty stylesheet with a set of bytes that reached over the
/// network.
pub fn update_from_bytes<R>(existing: &Stylesheet,
bytes: &[u8],
protocol_encoding_label: Option<&str>,
environment_encoding: Option<&'static encoding_rs::Encoding>,
url_data: UrlExtraData,
stylesheet_loader: Option<&StylesheetLoader>,
error_reporter: &R)
where R: ParseErrorReporter
pub fn update_from_bytes<R>(
existing: &Stylesheet,
bytes: &[u8],
protocol_encoding_label: Option<&str>,
environment_encoding: Option<&'static encoding_rs::Encoding>,
url_data: UrlExtraData,
stylesheet_loader: Option<&StylesheetLoader>,
error_reporter: &R,
) where
R: ParseErrorReporter,
{
let string = decode_stylesheet_bytes(bytes, protocol_encoding_label, environment_encoding);
Self::update_from_str(existing,
&string,
url_data,
stylesheet_loader,
error_reporter,
0)
Self::update_from_str(
existing,
&string,
url_data,
stylesheet_loader,
error_reporter,
0,
)
}
}

View file

@ -6,7 +6,7 @@
#![deny(missing_docs)]
use cssparser::{Token, SourceLocation, ParseErrorKind, BasicParseErrorKind};
use cssparser::{BasicParseErrorKind, ParseErrorKind, SourceLocation, Token};
use log;
use std::fmt;
use style_traits::ParseError;
@ -62,11 +62,19 @@ impl<'a> fmt::Display for ContextualParseError<'a> {
Token::QuotedString(ref s) => write!(f, "quoted string \"{}\"", s),
Token::UnquotedUrl(ref u) => write!(f, "url {}", u),
Token::Delim(ref d) => write!(f, "delimiter {}", d),
Token::Number { int_value: Some(i), .. } => write!(f, "number {}", i),
Token::Number {
int_value: Some(i), ..
} => write!(f, "number {}", i),
Token::Number { value, .. } => write!(f, "number {}", value),
Token::Percentage { int_value: Some(i), .. } => write!(f, "percentage {}", i),
Token::Percentage { unit_value, .. } => write!(f, "percentage {}", unit_value * 100.),
Token::Dimension { value, ref unit, .. } => write!(f, "dimension {}{}", value, unit),
Token::Percentage {
int_value: Some(i), ..
} => write!(f, "percentage {}", i),
Token::Percentage { unit_value, .. } => {
write!(f, "percentage {}", unit_value * 100.)
},
Token::Dimension {
value, ref unit, ..
} => write!(f, "dimension {}{}", value, unit),
Token::WhiteSpace(_) => write!(f, "whitespace"),
Token::Comment(_) => write!(f, "comment"),
Token::Colon => write!(f, "colon (:)"),
@ -96,22 +104,20 @@ impl<'a> fmt::Display for ContextualParseError<'a> {
ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken(ref t)) => {
write!(f, "found unexpected ")?;
token_to_str(t, f)
}
},
ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput) => {
write!(f, "unexpected end of input")
}
},
ParseErrorKind::Basic(BasicParseErrorKind::AtRuleInvalid(ref i)) => {
write!(f, "@ rule invalid: {}", i)
}
},
ParseErrorKind::Basic(BasicParseErrorKind::AtRuleBodyInvalid) => {
write!(f, "@ rule invalid")
}
},
ParseErrorKind::Basic(BasicParseErrorKind::QualifiedRuleInvalid) => {
write!(f, "qualified rule invalid")
}
ParseErrorKind::Custom(ref err) => {
write!(f, "{:?}", err)
}
},
ParseErrorKind::Custom(ref err) => write!(f, "{:?}", err),
}
}
@ -119,65 +125,86 @@ impl<'a> fmt::Display for ContextualParseError<'a> {
ContextualParseError::UnsupportedPropertyDeclaration(decl, ref err) => {
write!(f, "Unsupported property declaration: '{}', ", decl)?;
parse_error_to_str(err, f)
}
},
ContextualParseError::UnsupportedFontFaceDescriptor(decl, ref err) => {
write!(f, "Unsupported @font-face descriptor declaration: '{}', ", decl)?;
write!(
f,
"Unsupported @font-face descriptor declaration: '{}', ",
decl
)?;
parse_error_to_str(err, f)
}
},
ContextualParseError::UnsupportedFontFeatureValuesDescriptor(decl, ref err) => {
write!(f, "Unsupported @font-feature-values descriptor declaration: '{}', ", decl)?;
write!(
f,
"Unsupported @font-feature-values descriptor declaration: '{}', ",
decl
)?;
parse_error_to_str(err, f)
}
},
ContextualParseError::InvalidKeyframeRule(rule, ref err) => {
write!(f, "Invalid keyframe rule: '{}', ", rule)?;
parse_error_to_str(err, f)
}
},
ContextualParseError::InvalidFontFeatureValuesRule(rule, ref err) => {
write!(f, "Invalid font feature value rule: '{}', ", rule)?;
parse_error_to_str(err, f)
}
},
ContextualParseError::UnsupportedKeyframePropertyDeclaration(decl, ref err) => {
write!(f, "Unsupported keyframe property declaration: '{}', ", decl)?;
parse_error_to_str(err, f)
}
},
ContextualParseError::InvalidRule(rule, ref err) => {
write!(f, "Invalid rule: '{}', ", rule)?;
parse_error_to_str(err, f)
}
},
ContextualParseError::UnsupportedRule(rule, ref err) => {
write!(f, "Unsupported rule: '{}', ", rule)?;
parse_error_to_str(err, f)
}
},
ContextualParseError::UnsupportedViewportDescriptorDeclaration(decl, ref err) => {
write!(f, "Unsupported @viewport descriptor declaration: '{}', ", decl)?;
write!(
f,
"Unsupported @viewport descriptor declaration: '{}', ",
decl
)?;
parse_error_to_str(err, f)
}
},
ContextualParseError::UnsupportedCounterStyleDescriptorDeclaration(decl, ref err) => {
write!(f, "Unsupported @counter-style descriptor declaration: '{}', ", decl)?;
write!(
f,
"Unsupported @counter-style descriptor declaration: '{}', ",
decl
)?;
parse_error_to_str(err, f)
}
ContextualParseError::InvalidCounterStyleWithoutSymbols(ref system) => {
write!(f, "Invalid @counter-style rule: 'system: {}' without 'symbols'", system)
}
ContextualParseError::InvalidCounterStyleNotEnoughSymbols(ref system) => {
write!(f, "Invalid @counter-style rule: 'system: {}' less than two 'symbols'", system)
}
ContextualParseError::InvalidCounterStyleWithoutAdditiveSymbols => {
write!(f, "Invalid @counter-style rule: 'system: additive' without 'additive-symbols'")
}
ContextualParseError::InvalidCounterStyleExtendsWithSymbols => {
write!(f, "Invalid @counter-style rule: 'system: extends …' with 'symbols'")
}
ContextualParseError::InvalidCounterStyleExtendsWithAdditiveSymbols => {
write!(f, "Invalid @counter-style rule: 'system: extends …' with 'additive-symbols'")
}
},
ContextualParseError::InvalidCounterStyleWithoutSymbols(ref system) => write!(
f,
"Invalid @counter-style rule: 'system: {}' without 'symbols'",
system
),
ContextualParseError::InvalidCounterStyleNotEnoughSymbols(ref system) => write!(
f,
"Invalid @counter-style rule: 'system: {}' less than two 'symbols'",
system
),
ContextualParseError::InvalidCounterStyleWithoutAdditiveSymbols => write!(
f,
"Invalid @counter-style rule: 'system: additive' without 'additive-symbols'"
),
ContextualParseError::InvalidCounterStyleExtendsWithSymbols => write!(
f,
"Invalid @counter-style rule: 'system: extends …' with 'symbols'"
),
ContextualParseError::InvalidCounterStyleExtendsWithAdditiveSymbols => write!(
f,
"Invalid @counter-style rule: 'system: extends …' with 'additive-symbols'"
),
ContextualParseError::InvalidMediaRule(media_rule, ref err) => {
write!(f, "Invalid media rule: {}, ", media_rule)?;
parse_error_to_str(err, f)
}
ContextualParseError::UnsupportedValue(_value, ref err) => {
parse_error_to_str(err, f)
}
},
ContextualParseError::UnsupportedValue(_value, ref err) => parse_error_to_str(err, f),
}
}
}
@ -188,10 +215,12 @@ pub trait ParseErrorReporter {
///
/// Returns the current input being parsed, the source location it was
/// reported from, and a message.
fn report_error(&self,
url: &UrlExtraData,
location: SourceLocation,
error: ContextualParseError);
fn report_error(
&self,
url: &UrlExtraData,
location: SourceLocation,
error: ContextualParseError,
);
}
/// An error reporter that uses [the `log` crate](https://github.com/rust-lang-nursery/log)
@ -203,12 +232,20 @@ pub trait ParseErrorReporter {
pub struct RustLogReporter;
impl ParseErrorReporter for RustLogReporter {
fn report_error(&self,
url: &UrlExtraData,
location: SourceLocation,
error: ContextualParseError) {
fn report_error(
&self,
url: &UrlExtraData,
location: SourceLocation,
error: ContextualParseError,
) {
if log_enabled!(log::Level::Info) {
info!("Url:\t{}\n{}:{} {}", url.as_str(), location.line, location.column, error)
info!(
"Url:\t{}\n{}:{} {}",
url.as_str(),
location.line,
location.column,
error
)
}
}
}
@ -217,10 +254,12 @@ impl ParseErrorReporter for RustLogReporter {
pub struct NullReporter;
impl ParseErrorReporter for NullReporter {
fn report_error(&self,
_url: &UrlExtraData,
_location: SourceLocation,
_error: ContextualParseError) {
fn report_error(
&self,
_url: &UrlExtraData,
_location: SourceLocation,
_error: ContextualParseError,
) {
// do nothing
}
}

View file

@ -11,11 +11,11 @@
#[cfg(feature = "gecko")]
use computed_values::{font_stretch, font_style, font_weight};
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser};
use cssparser::{SourceLocation, CowRcStr};
use cssparser::{CowRcStr, SourceLocation};
#[cfg(feature = "gecko")]
use cssparser::UnicodeRange;
use error_reporting::{ContextualParseError, ParseErrorReporter};
use parser::{ParserContext, ParserErrorContext, Parse};
use parser::{Parse, ParserContext, ParserErrorContext};
#[cfg(feature = "gecko")]
use properties::longhands::font_language_override;
use selectors::parser::SelectorParseErrorKind;
@ -59,7 +59,10 @@ pub struct UrlSource {
}
impl ToCss for UrlSource {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: fmt::Write,
{
self.url.to_css(dest)?;
if !self.format_hints.is_empty() {
dest.write_str(" format(")?;
@ -80,8 +83,7 @@ impl ToCss for UrlSource {
/// on whether and when it is downloaded and ready to use.
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq)]
#[derive(ToComputedValue, ToCss)]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)]
pub enum FontDisplay {
Auto,
Block,
@ -105,8 +107,10 @@ pub enum FontWeight {
#[cfg(feature = "gecko")]
impl Parse for FontWeight {
fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<FontWeight, ParseError<'i>> {
fn parse<'i, 't>(
_: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<FontWeight, ParseError<'i>> {
let result = input.try(|input| {
let ident = input.expect_ident().map_err(|_| ())?;
match_ignore_ascii_case! { &ident,
@ -126,12 +130,14 @@ impl Parse for FontWeight {
/// Parse the block inside a `@font-face` rule.
///
/// Note that the prelude parsing code lives in the `stylesheets` module.
pub fn parse_font_face_block<R>(context: &ParserContext,
error_context: &ParserErrorContext<R>,
input: &mut Parser,
location: SourceLocation)
-> FontFaceRuleData
where R: ParseErrorReporter
pub fn parse_font_face_block<R>(
context: &ParserContext,
error_context: &ParserErrorContext<R>,
input: &mut Parser,
location: SourceLocation,
) -> FontFaceRuleData
where
R: ParseErrorReporter,
{
let mut rule = FontFaceRuleData::empty(location);
{
@ -167,19 +173,27 @@ impl<'a> FontFace<'a> {
/// sources which don't list any format hint, or the ones which list at
/// least "truetype" or "opentype".
pub fn effective_sources(&self) -> EffectiveSources {
EffectiveSources(self.sources().iter().rev().filter(|source| {
if let Source::Url(ref url_source) = **source {
let hints = &url_source.format_hints;
// We support only opentype fonts and truetype is an alias for
// that format. Sources without format hints need to be
// downloaded in case we support them.
hints.is_empty() || hints.iter().any(|hint| {
hint == "truetype" || hint == "opentype" || hint == "woff"
EffectiveSources(
self.sources()
.iter()
.rev()
.filter(|source| {
if let Source::Url(ref url_source) = **source {
let hints = &url_source.format_hints;
// We support only opentype fonts and truetype is an alias for
// that format. Sources without format hints need to be
// downloaded in case we support them.
hints.is_empty() ||
hints.iter().any(|hint| {
hint == "truetype" || hint == "opentype" || hint == "woff"
})
} else {
true
}
})
} else {
true
}
}).cloned().collect())
.cloned()
.collect(),
)
}
}
@ -209,22 +223,28 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for FontFaceRuleParser<'a, 'b> {
}
impl Parse for Source {
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Source, ParseError<'i>> {
if input.try(|input| input.expect_function_matching("local")).is_ok() {
return input.parse_nested_block(|input| {
FamilyName::parse(context, input)
}).map(Source::Local)
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Source, ParseError<'i>> {
if input
.try(|input| input.expect_function_matching("local"))
.is_ok()
{
return input
.parse_nested_block(|input| FamilyName::parse(context, input))
.map(Source::Local);
}
let url = SpecifiedUrl::parse(context, input)?;
// Parsing optional format()
let format_hints = if input.try(|input| input.expect_function_matching("format")).is_ok() {
let format_hints = if input
.try(|input| input.expect_function_matching("format"))
.is_ok()
{
input.parse_nested_block(|input| {
input.parse_comma_separated(|input| {
Ok(input.expect_string()?.as_ref().to_owned())
})
input.parse_comma_separated(|input| Ok(input.expect_string()?.as_ref().to_owned()))
})?
} else {
vec![]
@ -250,7 +270,9 @@ macro_rules! is_descriptor_enabled {
mozilla::StaticPrefs_sVarCache_layout_css_font_variations_enabled
}
};
($name: tt) => { true }
($name:tt) => {
true
};
}
macro_rules! font_face_descriptors_common {

View file

@ -40,8 +40,14 @@ pub trait FontMetricsProvider {
/// TODO: We could make this take the full list, I guess, and save a few
/// virtual calls in the case we are repeatedly unable to find font metrics?
/// That is not too common in practice though.
fn query(&self, _font: &Font, _font_size: Au, _wm: WritingMode,
_in_media_query: bool, _device: &Device) -> FontMetricsQueryResult {
fn query(
&self,
_font: &Font,
_font_size: Au,
_wm: WritingMode,
_in_media_query: bool,
_device: &Device,
) -> FontMetricsQueryResult {
FontMetricsQueryResult::NotAvailable
}
@ -49,7 +55,9 @@ pub trait FontMetricsProvider {
fn get_size(&self, font_name: &Atom, font_family: u8) -> Au;
/// Construct from a shared style context
fn create_from(context: &SharedStyleContext) -> Self where Self: Sized;
fn create_from(context: &SharedStyleContext) -> Self
where
Self: Sized;
}
// TODO: Servo's font metrics provider will probably not live in this crate, so this will

View file

@ -35,13 +35,13 @@ use rule_tree::StrongRuleNode;
use servo_arc::{Arc, ArcBorrow};
use shared_lock::Locked;
use std::{mem, ptr};
use stylesheets::{CssRules, CounterStyleRule, FontFaceRule, FontFeatureValuesRule};
use stylesheets::{CounterStyleRule, CssRules, FontFaceRule, FontFeatureValuesRule};
use stylesheets::{DocumentRule, ImportRule, KeyframesRule, MediaRule, NamespaceRule, PageRule};
use stylesheets::{StylesheetContents, StyleRule, SupportsRule};
use stylesheets::{StyleRule, StylesheetContents, SupportsRule};
use stylesheets::keyframes_rule::Keyframe;
macro_rules! impl_arc_ffi {
($servo_type:ty => $gecko_type:ty [$addref:ident, $release:ident]) => {
($servo_type:ty => $gecko_type:ty[$addref:ident, $release:ident]) => {
unsafe impl HasFFI for $servo_type {
type FFIType = $gecko_type;
}
@ -56,7 +56,7 @@ macro_rules! impl_arc_ffi {
pub unsafe extern "C" fn $release(obj: &$gecko_type) {
<$servo_type>::release(obj);
}
}
};
}
impl_arc_ffi!(Locked<CssRules> => ServoCssRules
@ -153,7 +153,6 @@ pub unsafe extern "C" fn Servo_ComputedStyle_Release(obj: &ComputedValues) {
});
}
impl From<Arc<ComputedValues>> for Strong<ComputedValues> {
fn from(arc: Arc<ComputedValues>) -> Self {
unsafe { mem::transmute(Arc::into_raw_offset(arc)) }

View file

@ -12,8 +12,8 @@ use app_units::Au;
use gecko::values::{convert_rgba_to_nscolor, GeckoStyleCoordConvertible};
use gecko_bindings::bindings;
use gecko_bindings::structs::{self, nsCSSUnit, nsStyleCoord_CalcValue};
use gecko_bindings::structs::{nsStyleImage, nsresult, SheetType};
use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordData, CoordDataMut};
use gecko_bindings::structs::{nsresult, SheetType, nsStyleImage};
use gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue};
use std::f32::consts::PI;
use stylesheets::{Origin, RulesMutateError};
use values::computed::{Angle, CalcLengthOrPercentage, Gradient, Image};
@ -22,7 +22,7 @@ use values::computed::{Percentage, TextAlign};
use values::computed::url::ComputedImageUrl;
use values::generics::box_::VerticalAlign;
use values::generics::grid::{TrackListValue, TrackSize};
use values::generics::image::{CompatMode, Image as GenericImage, GradientItem};
use values::generics::image::{CompatMode, GradientItem, Image as GenericImage};
use values::generics::rect::Rect;
impl From<CalcLengthOrPercentage> for nsStyleCoord_CalcValue {
@ -50,19 +50,15 @@ impl From<nsStyleCoord_CalcValue> for CalcLengthOrPercentage {
impl From<LengthOrPercentage> for nsStyleCoord_CalcValue {
fn from(other: LengthOrPercentage) -> nsStyleCoord_CalcValue {
match other {
LengthOrPercentage::Length(px) => {
nsStyleCoord_CalcValue {
mLength: px.to_i32_au(),
mPercent: 0.0,
mHasPercent: false,
}
LengthOrPercentage::Length(px) => nsStyleCoord_CalcValue {
mLength: px.to_i32_au(),
mPercent: 0.0,
mHasPercent: false,
},
LengthOrPercentage::Percentage(pc) => {
nsStyleCoord_CalcValue {
mLength: 0,
mPercent: pc.0,
mHasPercent: true,
}
LengthOrPercentage::Percentage(pc) => nsStyleCoord_CalcValue {
mLength: 0,
mPercent: pc.0,
mHasPercent: true,
},
LengthOrPercentage::Calc(calc) => calc.into(),
}
@ -73,20 +69,16 @@ impl LengthOrPercentageOrAuto {
/// Convert this value in an appropriate `nsStyleCoord::CalcValue`.
pub fn to_calc_value(&self) -> Option<nsStyleCoord_CalcValue> {
match *self {
LengthOrPercentageOrAuto::Length(px) => {
Some(nsStyleCoord_CalcValue {
mLength: px.to_i32_au(),
mPercent: 0.0,
mHasPercent: false,
})
},
LengthOrPercentageOrAuto::Percentage(pc) => {
Some(nsStyleCoord_CalcValue {
mLength: 0,
mPercent: pc.0,
mHasPercent: true,
})
},
LengthOrPercentageOrAuto::Length(px) => Some(nsStyleCoord_CalcValue {
mLength: px.to_i32_au(),
mPercent: 0.0,
mHasPercent: false,
}),
LengthOrPercentageOrAuto::Percentage(pc) => Some(nsStyleCoord_CalcValue {
mLength: 0,
mPercent: pc.0,
mHasPercent: true,
}),
LengthOrPercentageOrAuto::Calc(calc) => Some(calc.into()),
LengthOrPercentageOrAuto::Auto => None,
}
@ -151,13 +143,9 @@ impl nsStyleImage {
/// Set a given Servo `Image` value into this `nsStyleImage`.
pub fn set(&mut self, image: Image) {
match image {
GenericImage::Gradient(boxed_gradient) => {
self.set_gradient(*boxed_gradient)
},
GenericImage::Url(ref url) => {
unsafe {
bindings::Gecko_SetLayerImageImageValue(self, url.image_value.get());
}
GenericImage::Gradient(boxed_gradient) => self.set_gradient(*boxed_gradient),
GenericImage::Url(ref url) => unsafe {
bindings::Gecko_SetLayerImageImageValue(self, url.image_value.get());
},
GenericImage::Rect(ref image_rect) => {
unsafe {
@ -166,17 +154,23 @@ impl nsStyleImage {
// Set CropRect
let ref mut rect = *self.mCropRect.mPtr;
image_rect.top.to_gecko_style_coord(&mut rect.data_at_mut(0));
image_rect.right.to_gecko_style_coord(&mut rect.data_at_mut(1));
image_rect.bottom.to_gecko_style_coord(&mut rect.data_at_mut(2));
image_rect.left.to_gecko_style_coord(&mut rect.data_at_mut(3));
image_rect
.top
.to_gecko_style_coord(&mut rect.data_at_mut(0));
image_rect
.right
.to_gecko_style_coord(&mut rect.data_at_mut(1));
image_rect
.bottom
.to_gecko_style_coord(&mut rect.data_at_mut(2));
image_rect
.left
.to_gecko_style_coord(&mut rect.data_at_mut(3));
}
}
GenericImage::Element(ref element) => {
unsafe {
bindings::Gecko_SetImageElement(self, element.as_ptr());
}
}
},
GenericImage::Element(ref element) => unsafe {
bindings::Gecko_SetImageElement(self, element.as_ptr());
},
}
}
@ -199,12 +193,14 @@ impl nsStyleImage {
let gecko_gradient = match gradient.kind {
GradientKind::Linear(direction) => {
let gecko_gradient = unsafe {
bindings::Gecko_CreateGradient(structs::NS_STYLE_GRADIENT_SHAPE_LINEAR as u8,
structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as u8,
gradient.repeating,
gradient.compat_mode != CompatMode::Modern,
gradient.compat_mode == CompatMode::Moz,
stop_count as u32)
bindings::Gecko_CreateGradient(
structs::NS_STYLE_GRADIENT_SHAPE_LINEAR as u8,
structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as u8,
gradient.repeating,
gradient.compat_mode != CompatMode::Modern,
gradient.compat_mode == CompatMode::Moz,
stop_count as u32,
)
};
match direction {
@ -223,10 +219,12 @@ impl nsStyleImage {
};
unsafe {
(*gecko_gradient).mBgPosX
.set_value(CoordDataValue::Percent(x));
(*gecko_gradient).mBgPosY
.set_value(CoordDataValue::Percent(0.5));
(*gecko_gradient)
.mBgPosX
.set_value(CoordDataValue::Percent(x));
(*gecko_gradient)
.mBgPosY
.set_value(CoordDataValue::Percent(0.5));
}
},
LineDirection::Vertical(y) => {
@ -238,10 +236,12 @@ impl nsStyleImage {
Y::Bottom => 1.0,
};
unsafe {
(*gecko_gradient).mBgPosX
.set_value(CoordDataValue::Percent(0.5));
(*gecko_gradient).mBgPosY
.set_value(CoordDataValue::Percent(y));
(*gecko_gradient)
.mBgPosX
.set_value(CoordDataValue::Percent(0.5));
(*gecko_gradient)
.mBgPosY
.set_value(CoordDataValue::Percent(y));
}
},
LineDirection::Corner(horiz, vert) => {
@ -255,66 +255,65 @@ impl nsStyleImage {
};
unsafe {
(*gecko_gradient).mBgPosX
.set_value(CoordDataValue::Percent(percent_x));
(*gecko_gradient).mBgPosY
.set_value(CoordDataValue::Percent(percent_y));
(*gecko_gradient)
.mBgPosX
.set_value(CoordDataValue::Percent(percent_x));
(*gecko_gradient)
.mBgPosY
.set_value(CoordDataValue::Percent(percent_y));
}
},
#[cfg(feature = "gecko")]
LineDirection::MozPosition(position, angle) => {
unsafe {
if let Some(position) = position {
(*gecko_gradient).mBgPosX.set(position.horizontal);
(*gecko_gradient).mBgPosY.set(position.vertical);
}
if let Some(angle) = angle {
(*gecko_gradient).mAngle.set(angle);
}
LineDirection::MozPosition(position, angle) => unsafe {
if let Some(position) = position {
(*gecko_gradient).mBgPosX.set(position.horizontal);
(*gecko_gradient).mBgPosY.set(position.vertical);
}
if let Some(angle) = angle {
(*gecko_gradient).mAngle.set(angle);
}
},
}
gecko_gradient
},
GradientKind::Radial(shape, position, angle) => {
let keyword_to_gecko_size = |keyword| {
match keyword {
ShapeExtent::ClosestSide => CLOSEST_SIDE,
ShapeExtent::FarthestSide => FARTHEST_SIDE,
ShapeExtent::ClosestCorner => CLOSEST_CORNER,
ShapeExtent::FarthestCorner => FARTHEST_CORNER,
ShapeExtent::Contain => CLOSEST_SIDE,
ShapeExtent::Cover => FARTHEST_CORNER,
}
let keyword_to_gecko_size = |keyword| match keyword {
ShapeExtent::ClosestSide => CLOSEST_SIDE,
ShapeExtent::FarthestSide => FARTHEST_SIDE,
ShapeExtent::ClosestCorner => CLOSEST_CORNER,
ShapeExtent::FarthestCorner => FARTHEST_CORNER,
ShapeExtent::Contain => CLOSEST_SIDE,
ShapeExtent::Cover => FARTHEST_CORNER,
};
let (gecko_shape, gecko_size) = match shape {
EndingShape::Circle(ref circle) => {
let size = match *circle {
Circle::Extent(extent) => {
keyword_to_gecko_size(extent)
},
Circle::Extent(extent) => keyword_to_gecko_size(extent),
_ => structs::NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE,
};
(structs::NS_STYLE_GRADIENT_SHAPE_CIRCULAR as u8, size as u8)
},
EndingShape::Ellipse(ref ellipse) => {
let size = match *ellipse {
Ellipse::Extent(extent) => {
keyword_to_gecko_size(extent)
},
Ellipse::Extent(extent) => keyword_to_gecko_size(extent),
_ => structs::NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE,
};
(structs::NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL as u8, size as u8)
}
(
structs::NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL as u8,
size as u8,
)
},
};
let gecko_gradient = unsafe {
bindings::Gecko_CreateGradient(gecko_shape,
gecko_size,
gradient.repeating,
gradient.compat_mode == CompatMode::Moz,
gradient.compat_mode == CompatMode::Moz,
stop_count as u32)
bindings::Gecko_CreateGradient(
gecko_shape,
gecko_size,
gradient.repeating,
gradient.compat_mode == CompatMode::Moz,
gradient.compat_mode == CompatMode::Moz,
stop_count as u32,
)
};
// Clear mBgPos field and set mAngle if angle is set. Otherwise clear it.
@ -326,18 +325,18 @@ impl nsStyleImage {
// Setting radius values depending shape
match shape {
EndingShape::Circle(Circle::Radius(length)) => {
unsafe {
let au = length.to_i32_au();
(*gecko_gradient).mRadiusX.set_value(CoordDataValue::Coord(au));
(*gecko_gradient).mRadiusY.set_value(CoordDataValue::Coord(au));
}
EndingShape::Circle(Circle::Radius(length)) => unsafe {
let au = length.to_i32_au();
(*gecko_gradient)
.mRadiusX
.set_value(CoordDataValue::Coord(au));
(*gecko_gradient)
.mRadiusY
.set_value(CoordDataValue::Coord(au));
},
EndingShape::Ellipse(Ellipse::Radii(x, y)) => {
unsafe {
(*gecko_gradient).mRadiusX.set(x);
(*gecko_gradient).mRadiusY.set(y);
}
EndingShape::Ellipse(Ellipse::Radii(x, y)) => unsafe {
(*gecko_gradient).mRadiusX.set(x);
(*gecko_gradient).mRadiusY.set(y);
},
_ => {},
}
@ -354,9 +353,7 @@ impl nsStyleImage {
// NB: stops are guaranteed to be none in the gecko side by
// default.
let gecko_stop = unsafe {
&mut (*gecko_gradient).mStops[index]
};
let gecko_stop = unsafe { &mut (*gecko_gradient).mStops[index] };
let mut coord = nsStyleCoord::null();
match *item {
@ -368,7 +365,7 @@ impl nsStyleImage {
GradientItem::InterpolationHint(hint) => {
gecko_stop.mIsInterpolationHint = true;
coord.set(Some(hint));
}
},
}
gecko_stop.mLocation.move_from(coord);
@ -382,28 +379,38 @@ impl nsStyleImage {
/// Converts into Image.
pub unsafe fn into_image(self: &nsStyleImage) -> Option<Image> {
use gecko_bindings::structs::nsStyleImageType;
use values::computed::{NumberOrPercentage, MozImageRect};
use values::computed::{MozImageRect, NumberOrPercentage};
match self.mType {
nsStyleImageType::eStyleImageType_Null => {
None
},
nsStyleImageType::eStyleImageType_Null => None,
nsStyleImageType::eStyleImageType_Image => {
let url = self.get_image_url();
if self.mCropRect.mPtr.is_null() {
Some(GenericImage::Url(url))
} else {
let ref rect = *self.mCropRect.mPtr;
match (NumberOrPercentage::from_gecko_style_coord(&rect.data_at(0)),
NumberOrPercentage::from_gecko_style_coord(&rect.data_at(1)),
NumberOrPercentage::from_gecko_style_coord(&rect.data_at(2)),
NumberOrPercentage::from_gecko_style_coord(&rect.data_at(3))) {
(Some(top), Some(right), Some(bottom), Some(left)) =>
Some(GenericImage::Rect(Box::new(MozImageRect { url, top, right, bottom, left } ))),
match (
NumberOrPercentage::from_gecko_style_coord(&rect.data_at(0)),
NumberOrPercentage::from_gecko_style_coord(&rect.data_at(1)),
NumberOrPercentage::from_gecko_style_coord(&rect.data_at(2)),
NumberOrPercentage::from_gecko_style_coord(&rect.data_at(3)),
) {
(Some(top), Some(right), Some(bottom), Some(left)) => {
Some(GenericImage::Rect(Box::new(MozImageRect {
url,
top,
right,
bottom,
left,
})))
},
_ => {
debug_assert!(false, "mCropRect could not convert to NumberOrPercentage");
debug_assert!(
false,
"mCropRect could not convert to NumberOrPercentage"
);
None
}
},
}
}
},
@ -415,7 +422,7 @@ impl nsStyleImage {
let atom = bindings::Gecko_GetImageElement(self);
Some(GenericImage::Element(Atom::from_raw(atom)))
},
_ => panic!("Unexpected image type")
_ => panic!("Unexpected image type"),
}
}
@ -434,11 +441,13 @@ impl nsStyleImage {
use values::computed::{Length, LengthOrPercentage};
use values::computed::image::LineDirection;
use values::computed::position::Position;
use values::generics::image::{ColorStop, CompatMode, Circle, Ellipse};
use values::generics::image::{Circle, ColorStop, CompatMode, Ellipse};
use values::generics::image::{EndingShape, GradientKind, ShapeExtent};
use values::specified::position::{X, Y};
let gecko_gradient = bindings::Gecko_GetGradientImageValue(self).as_ref().unwrap();
let gecko_gradient = bindings::Gecko_GetGradientImageValue(self)
.as_ref()
.unwrap();
let angle = Angle::from_gecko_style_coord(&gecko_gradient.mAngle);
let horizontal_style = LengthOrPercentage::from_gecko_style_coord(&gecko_gradient.mBgPosX);
let vertical_style = LengthOrPercentage::from_gecko_style_coord(&gecko_gradient.mBgPosY);
@ -458,7 +467,7 @@ impl nsStyleImage {
None
}
},
_ => None
_ => None,
};
let vertical_as_corner = match vertical {
LengthOrPercentage::Percentage(percentage) => {
@ -470,23 +479,34 @@ impl nsStyleImage {
None
}
},
_ => None
_ => None,
};
match (horizontal_as_corner, vertical_as_corner) {
(Some(hc), Some(vc)) => LineDirection::Corner(hc, vc),
_ => LineDirection::MozPosition(
Some(Position { horizontal, vertical }), None)
Some(Position {
horizontal,
vertical,
}),
None,
),
}
},
(Some(_), Some(horizontal), Some(vertical)) =>
LineDirection::MozPosition(
Some(Position { horizontal, vertical }), angle),
(Some(_), Some(horizontal), Some(vertical)) => LineDirection::MozPosition(
Some(Position {
horizontal,
vertical,
}),
angle,
),
_ => {
debug_assert!(horizontal_style.is_none() && vertical_style.is_none(),
"Unexpected linear gradient direction");
debug_assert!(
horizontal_style.is_none() && vertical_style.is_none(),
"Unexpected linear gradient direction"
);
LineDirection::MozPosition(None, None)
}
},
};
GradientKind::Linear(line_direction)
},
@ -508,31 +528,41 @@ impl nsStyleImage {
structs::NS_STYLE_GRADIENT_SHAPE_CIRCULAR => {
let circle = match gecko_gradient.mSize as u32 {
structs::NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE => {
let radius = Length::from_gecko_style_coord(&gecko_gradient.mRadiusX)
.expect("mRadiusX could not convert to Length");
debug_assert_eq!(radius,
Length::from_gecko_style_coord(&gecko_gradient.mRadiusY).unwrap());
let radius = Length::from_gecko_style_coord(
&gecko_gradient.mRadiusX,
).expect("mRadiusX could not convert to Length");
debug_assert_eq!(
radius,
Length::from_gecko_style_coord(&gecko_gradient.mRadiusY)
.unwrap()
);
Circle::Radius(radius)
},
size => Circle::Extent(gecko_size_to_keyword(size))
size => Circle::Extent(gecko_size_to_keyword(size)),
};
EndingShape::Circle(circle)
},
structs::NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL => {
let length_percentage_keyword = match gecko_gradient.mSize as u32 {
structs::NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE => {
match (LengthOrPercentage::from_gecko_style_coord(&gecko_gradient.mRadiusX),
LengthOrPercentage::from_gecko_style_coord(&gecko_gradient.mRadiusY)) {
(Some(x), Some(y)) => Ellipse::Radii(x, y),
_ => {
debug_assert!(false,
structs::NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE => match (
LengthOrPercentage::from_gecko_style_coord(
&gecko_gradient.mRadiusX,
),
LengthOrPercentage::from_gecko_style_coord(
&gecko_gradient.mRadiusY,
),
) {
(Some(x), Some(y)) => Ellipse::Radii(x, y),
_ => {
debug_assert!(false,
"mRadiusX, mRadiusY could not convert to LengthOrPercentage");
Ellipse::Radii(LengthOrPercentage::zero(),
LengthOrPercentage::zero())
}
}
Ellipse::Radii(
LengthOrPercentage::zero(),
LengthOrPercentage::zero(),
)
},
},
size => Ellipse::Extent(gecko_size_to_keyword(size))
size => Ellipse::Extent(gecko_size_to_keyword(size)),
};
EndingShape::Ellipse(length_percentage_keyword)
},
@ -540,45 +570,58 @@ impl nsStyleImage {
};
let position = match (horizontal_style, vertical_style) {
(Some(horizontal), Some(vertical)) => Position { horizontal, vertical },
(Some(horizontal), Some(vertical)) => Position {
horizontal,
vertical,
},
_ => {
debug_assert!(false,
"mRadiusX, mRadiusY could not convert to LengthOrPercentage");
debug_assert!(
false,
"mRadiusX, mRadiusY could not convert to LengthOrPercentage"
);
Position {
horizontal: LengthOrPercentage::zero(),
vertical: LengthOrPercentage::zero()
vertical: LengthOrPercentage::zero(),
}
}
},
};
GradientKind::Radial(shape, position, angle)
}
},
};
let items = gecko_gradient.mStops.iter().map(|ref stop| {
if stop.mIsInterpolationHint {
GradientItem::InterpolationHint(
LengthOrPercentage::from_gecko_style_coord(&stop.mLocation)
.expect("mLocation could not convert to LengthOrPercentage")
)
} else {
GradientItem::ColorStop(ColorStop {
color: convert_nscolor_to_rgba(stop.mColor),
position: LengthOrPercentage::from_gecko_style_coord(&stop.mLocation)
})
}
}).collect();
let items = gecko_gradient
.mStops
.iter()
.map(|ref stop| {
if stop.mIsInterpolationHint {
GradientItem::InterpolationHint(
LengthOrPercentage::from_gecko_style_coord(&stop.mLocation)
.expect("mLocation could not convert to LengthOrPercentage"),
)
} else {
GradientItem::ColorStop(ColorStop {
color: convert_nscolor_to_rgba(stop.mColor),
position: LengthOrPercentage::from_gecko_style_coord(&stop.mLocation),
})
}
})
.collect();
let compat_mode =
if gecko_gradient.mMozLegacySyntax {
CompatMode::Moz
} else if gecko_gradient.mLegacySyntax {
CompatMode::WebKit
} else {
CompatMode::Modern
};
let compat_mode = if gecko_gradient.mMozLegacySyntax {
CompatMode::Moz
} else if gecko_gradient.mLegacySyntax {
CompatMode::WebKit
} else {
CompatMode::Modern
};
Box::new(Gradient { items, repeating: gecko_gradient.mRepeating, kind, compat_mode })
Box::new(Gradient {
items,
repeating: gecko_gradient.mRepeating,
kind,
compat_mode,
})
}
}
@ -607,10 +650,10 @@ pub mod basic_shape {
/// Convert StyleShapeSource to ShapeSource except URL and Image
/// types.
fn into_shape_source<ReferenceBox, ImageOrUrl>(
&self
&self,
) -> Option<ShapeSource<BasicShape, ReferenceBox, ImageOrUrl>>
where
ReferenceBox: From<StyleGeometryBox>
ReferenceBox: From<StyleGeometryBox>,
{
match self.mType {
StyleShapeSourceType::None => Some(ShapeSource::None),
@ -630,41 +673,39 @@ pub mod basic_shape {
}
}
impl<'a> From<&'a StyleShapeSource> for ClippingShape
{
impl<'a> From<&'a StyleShapeSource> for ClippingShape {
fn from(other: &'a StyleShapeSource) -> Self {
match other.mType {
StyleShapeSourceType::URL => {
unsafe {
let shape_image = &*other.mShapeImage.mPtr;
let other_url = &(**shape_image.__bindgen_anon_1.mURLValue.as_ref());
let url = ComputedUrl::from_url_value_data(&other_url._base).unwrap();
ShapeSource::ImageOrUrl(url)
}
StyleShapeSourceType::URL => unsafe {
let shape_image = &*other.mShapeImage.mPtr;
let other_url = &(**shape_image.__bindgen_anon_1.mURLValue.as_ref());
let url = ComputedUrl::from_url_value_data(&other_url._base).unwrap();
ShapeSource::ImageOrUrl(url)
},
StyleShapeSourceType::Image => {
unreachable!("ClippingShape doesn't support Image!");
}
_ => other.into_shape_source().expect("Couldn't convert to StyleSource!")
},
_ => other
.into_shape_source()
.expect("Couldn't convert to StyleSource!"),
}
}
}
impl<'a> From<&'a StyleShapeSource> for FloatAreaShape
{
impl<'a> From<&'a StyleShapeSource> for FloatAreaShape {
fn from(other: &'a StyleShapeSource) -> Self {
match other.mType {
StyleShapeSourceType::URL => {
unreachable!("FloatAreaShape doesn't support URL!");
},
StyleShapeSourceType::Image => {
unsafe {
let shape_image = &*other.mShapeImage.mPtr;
let image = shape_image.into_image().expect("Cannot convert to Image");
ShapeSource::ImageOrUrl(image)
}
}
_ => other.into_shape_source().expect("Couldn't convert to StyleSource!")
StyleShapeSourceType::Image => unsafe {
let shape_image = &*other.mShapeImage.mPtr;
let image = shape_image.into_image().expect("Cannot convert to Image");
ShapeSource::ImageOrUrl(image)
},
_ => other
.into_shape_source()
.expect("Couldn't convert to StyleSource!"),
}
}
}
@ -688,20 +729,16 @@ pub mod basic_shape {
rect: rect,
round: Some(round),
})
}
StyleBasicShapeType::Circle => {
GenericBasicShape::Circle(Circle {
radius: (&other.mCoordinates[0]).into(),
position: (&other.mPosition).into()
})
}
StyleBasicShapeType::Ellipse => {
GenericBasicShape::Ellipse(Ellipse {
semiaxis_x: (&other.mCoordinates[0]).into(),
semiaxis_y: (&other.mCoordinates[1]).into(),
position: (&other.mPosition).into()
})
}
},
StyleBasicShapeType::Circle => GenericBasicShape::Circle(Circle {
radius: (&other.mCoordinates[0]).into(),
position: (&other.mPosition).into(),
}),
StyleBasicShapeType::Ellipse => GenericBasicShape::Ellipse(Ellipse {
semiaxis_x: (&other.mCoordinates[0]).into(),
semiaxis_y: (&other.mCoordinates[1]).into(),
position: (&other.mPosition).into(),
}),
StyleBasicShapeType::Polygon => {
let fill_rule = if other.mFillRule == StyleFillRule::Evenodd {
FillRule::Evenodd
@ -722,7 +759,7 @@ pub mod basic_shape {
fill: fill_rule,
coordinates: coords,
})
}
},
}
}
}
@ -734,7 +771,8 @@ pub mod basic_shape {
LengthOrPercentage::from_gecko_style_coord(&other.data_at(index))
.expect("<border-radius> should be a length, percentage, or calc value"),
LengthOrPercentage::from_gecko_style_coord(&other.data_at(index + 1))
.expect("<border-radius> should be a length, percentage, or calc value"))
.expect("<border-radius> should be a length, percentage, or calc value"),
)
};
GenericBorderRadius {
@ -752,8 +790,14 @@ pub mod basic_shape {
/// Set this `BorderRadius` into a given `nsStyleCoord`.
pub fn set_corners(&self, other: &mut nsStyleCorners) {
let mut set_corner = |field: &BorderCornerRadius, index| {
field.0.width().to_gecko_style_coord(&mut other.data_at_mut(index));
field.0.height().to_gecko_style_coord(&mut other.data_at_mut(index + 1));
field
.0
.width()
.to_gecko_style_coord(&mut other.data_at_mut(index));
field
.0
.height()
.to_gecko_style_coord(&mut other.data_at_mut(index + 1));
};
set_corner(&self.top_left, 0);
set_corner(&self.top_right, 2);
@ -779,7 +823,7 @@ pub mod basic_shape {
fn from(other: position::Position) -> Self {
structs::Position {
mXPosition: other.horizontal.into(),
mYPosition: other.vertical.into()
mYPosition: other.vertical.into(),
}
}
}
@ -887,11 +931,15 @@ impl TrackSize<LengthOrPercentage> {
use values::generics::grid::{TrackBreadth, TrackSize};
if gecko_min.unit() == nsStyleUnit::eStyleUnit_None {
debug_assert!(gecko_max.unit() == nsStyleUnit::eStyleUnit_Coord ||
gecko_max.unit() == nsStyleUnit::eStyleUnit_Percent ||
gecko_max.unit() == nsStyleUnit::eStyleUnit_Calc);
return TrackSize::FitContent(LengthOrPercentage::from_gecko_style_coord(gecko_max)
.expect("gecko_max could not convert to LengthOrPercentage"));
debug_assert!(
gecko_max.unit() == nsStyleUnit::eStyleUnit_Coord ||
gecko_max.unit() == nsStyleUnit::eStyleUnit_Percent ||
gecko_max.unit() == nsStyleUnit::eStyleUnit_Calc
);
return TrackSize::FitContent(
LengthOrPercentage::from_gecko_style_coord(gecko_max)
.expect("gecko_max could not convert to LengthOrPercentage"),
);
}
let min = TrackBreadth::from_gecko_style_coord(gecko_min)
@ -947,7 +995,10 @@ impl TrackListValue<LengthOrPercentage, Integer> {
}
}
impl<T> Rect<T> where T: GeckoStyleCoordConvertible {
impl<T> Rect<T>
where
T: GeckoStyleCoordConvertible,
{
/// Convert this generic Rect to given Gecko fields.
pub fn to_gecko_rect(&self, sides: &mut ::gecko_bindings::structs::nsStyleSides) {
self.0.to_gecko_style_coord(&mut sides.data_at_mut(0));
@ -957,18 +1008,17 @@ impl<T> Rect<T> where T: GeckoStyleCoordConvertible {
}
/// Convert from given Gecko data to generic Rect.
pub fn from_gecko_rect(sides: &::gecko_bindings::structs::nsStyleSides)
-> Option<::values::generics::rect::Rect<T>> {
pub fn from_gecko_rect(
sides: &::gecko_bindings::structs::nsStyleSides,
) -> Option<::values::generics::rect::Rect<T>> {
use values::generics::rect::Rect;
Some(
Rect::new(
T::from_gecko_style_coord(&sides.data_at(0)).expect("coord[0] cound not convert"),
T::from_gecko_style_coord(&sides.data_at(1)).expect("coord[1] cound not convert"),
T::from_gecko_style_coord(&sides.data_at(2)).expect("coord[2] cound not convert"),
T::from_gecko_style_coord(&sides.data_at(3)).expect("coord[3] cound not convert")
)
)
Some(Rect::new(
T::from_gecko_style_coord(&sides.data_at(0)).expect("coord[0] cound not convert"),
T::from_gecko_style_coord(&sides.data_at(1)).expect("coord[1] cound not convert"),
T::from_gecko_style_coord(&sides.data_at(2)).expect("coord[2] cound not convert"),
T::from_gecko_style_coord(&sides.data_at(3)).expect("coord[3] cound not convert"),
))
}
}
@ -997,7 +1047,7 @@ impl TextAlign {
///
/// Intended for use with presentation attributes, not style structs
pub fn from_gecko_keyword(kw: u32) -> Self {
match kw {
match kw {
structs::NS_STYLE_TEXT_ALIGN_LEFT => TextAlign::Left,
structs::NS_STYLE_TEXT_ALIGN_RIGHT => TextAlign::Right,
structs::NS_STYLE_TEXT_ALIGN_CENTER => TextAlign::Center,

View file

@ -8,7 +8,7 @@ use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
use dom::TElement;
use gecko_bindings::bindings::{self, RawServoStyleSet};
use gecko_bindings::structs::{self, RawGeckoPresContextOwned, ServoStyleSetSizes, ServoStyleSheet};
use gecko_bindings::structs::{StyleSheetInfo, ServoStyleSheetInner, nsIDocument};
use gecko_bindings::structs::{ServoStyleSheetInner, StyleSheetInfo, nsIDocument};
use gecko_bindings::sugar::ownership::{HasArcFFI, HasBoxFFI, HasFFI, HasSimpleFFI};
use invalidation::media_queries::{MediaListKey, ToMediaListKey};
use malloc_size_of::MallocSizeOfOps;
@ -16,7 +16,7 @@ use media_queries::{Device, MediaList};
use properties::ComputedValues;
use selector_parser::SnapshotMap;
use servo_arc::Arc;
use shared_lock::{Locked, StylesheetGuards, SharedRwLockReadGuard};
use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
use stylesheets::{StylesheetContents, StylesheetInDocument};
use stylist::Stylist;
@ -27,9 +27,7 @@ pub struct GeckoStyleSheet(*const ServoStyleSheet);
impl ToMediaListKey for ::gecko::data::GeckoStyleSheet {
fn to_media_list_key(&self) -> MediaListKey {
use std::mem;
unsafe {
MediaListKey::from_raw(mem::transmute(self.0))
}
unsafe { MediaListKey::from_raw(mem::transmute(self.0)) }
}
}
@ -90,8 +88,7 @@ impl StylesheetInDocument for GeckoStyleSheet {
use std::mem;
unsafe {
let servo_media_list =
self.raw()._base.mMedia.mRawPtr as *const ServoMediaList;
let servo_media_list = self.raw()._base.mMedia.mRawPtr as *const ServoMediaList;
if servo_media_list.is_null() {
return None;
}
@ -128,9 +125,8 @@ impl PerDocumentStyleData {
// right now not always honored, see bug 1405543...
//
// Should we just force XBL Stylists to be NoQuirks?
let quirks_mode = unsafe {
(*device.pres_context().mDocument.raw::<nsIDocument>()).mCompatMode
};
let quirks_mode =
unsafe { (*device.pres_context().mDocument.raw::<nsIDocument>()).mCompatMode };
PerDocumentStyleData(AtomicRefCell::new(PerDocumentStyleDataImpl {
stylist: Stylist::new(device, quirks_mode.into()),
@ -159,24 +155,27 @@ impl PerDocumentStyleDataImpl {
where
E: TElement,
{
self.stylist.flush(
&StylesheetGuards::same(guard),
document_element,
snapshots,
)
self.stylist
.flush(&StylesheetGuards::same(guard), document_element, snapshots)
}
/// Returns whether private browsing is enabled.
fn is_private_browsing_enabled(&self) -> bool {
let doc =
self.stylist.device().pres_context().mDocument.raw::<nsIDocument>();
let doc = self.stylist
.device()
.pres_context()
.mDocument
.raw::<nsIDocument>();
unsafe { bindings::Gecko_IsPrivateBrowsingEnabled(doc) }
}
/// Returns whether the document is being used as an image.
fn is_being_used_as_an_image(&self) -> bool {
let doc =
self.stylist.device().pres_context().mDocument.raw::<nsIDocument>();
let doc = self.stylist
.device()
.pres_context()
.mDocument
.raw::<nsIDocument>();
unsafe { (*doc).mIsBeingUsedAsImage() }
}

View file

@ -7,13 +7,13 @@
use app_units::AU_PER_PX;
use app_units::Au;
use context::QuirksMode;
use cssparser::{Parser, RGBA, Token, BasicParseErrorKind};
use cssparser::{BasicParseErrorKind, Parser, Token, RGBA};
use euclid::Size2D;
use euclid::TypedScale;
use gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor};
use gecko_bindings::bindings;
use gecko_bindings::structs;
use gecko_bindings::structs::{nsCSSKeyword, nsCSSProps_KTableEntry, nsCSSValue, nsCSSUnit};
use gecko_bindings::structs::{nsCSSKeyword, nsCSSProps_KTableEntry, nsCSSUnit, nsCSSValue};
use gecko_bindings::structs::{nsMediaFeature, nsMediaFeature_RangeType};
use gecko_bindings::structs::{nsMediaFeature_ValueType, nsPresContext};
use gecko_bindings::structs::RawGeckoPresContextOwned;
@ -26,10 +26,10 @@ use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize, Ordering};
use str::starts_with_ignore_ascii_case;
use string_cache::Atom;
use style_traits::{CSSPixel, CssWriter, DevicePixel};
use style_traits::{ToCss, ParseError, StyleParseErrorKind};
use style_traits::{ParseError, StyleParseErrorKind, ToCss};
use style_traits::viewport::ViewportConstraints;
use stylesheets::Origin;
use values::{CSSFloat, CustomIdent, KeyframesName, serialize_atom_identifier};
use values::{serialize_atom_identifier, CSSFloat, CustomIdent, KeyframesName};
use values::computed::{self, ToComputedValue};
use values::computed::font::FontSize;
use values::specified::{Integer, Length, Number};
@ -84,10 +84,7 @@ impl Device {
/// Tells the device that a new viewport rule has been found, and stores the
/// relevant viewport constraints.
pub fn account_for_viewport_rule(
&mut self,
_constraints: &ViewportConstraints,
) {
pub fn account_for_viewport_rule(&mut self, _constraints: &ViewportConstraints) {
unreachable!("Gecko doesn't support @viewport");
}
@ -121,14 +118,16 @@ impl Device {
/// Set the font size of the root element (for rem)
pub fn set_root_font_size(&self, size: Au) {
self.root_font_size.store(size.0 as isize, Ordering::Relaxed)
self.root_font_size
.store(size.0 as isize, Ordering::Relaxed)
}
/// Sets the body text color for the "inherit color from body" quirk.
///
/// <https://quirks.spec.whatwg.org/#the-tables-inherit-color-from-body-quirk>
pub fn set_body_text_color(&self, color: RGBA) {
self.body_text_color.store(convert_rgba_to_nscolor(&color) as usize, Ordering::Relaxed)
self.body_text_color
.store(convert_rgba_to_nscolor(&color) as usize, Ordering::Relaxed)
}
/// Returns the body text color.
@ -201,7 +200,9 @@ impl Device {
/// Returns the device pixel ratio.
pub fn device_pixel_ratio(&self) -> TypedScale<f32, CSSPixel, DevicePixel> {
let override_dppx = self.pres_context().mOverrideDPPX;
if override_dppx > 0.0 { return TypedScale::new(override_dppx); }
if override_dppx > 0.0 {
return TypedScale::new(override_dppx);
}
let au_per_dpx = self.pres_context().mCurAppUnitsPerDevPixel as f32;
let au_per_px = AU_PER_PX as f32;
TypedScale::new(au_per_px / au_per_dpx)
@ -249,11 +250,13 @@ pub struct Expression {
impl ToCss for Expression {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where W: fmt::Write,
where
W: fmt::Write,
{
dest.write_str("(")?;
if (self.feature.mReqFlags & structs::nsMediaFeature_RequirementFlags_eHasWebkitPrefix) != 0 {
if (self.feature.mReqFlags & structs::nsMediaFeature_RequirementFlags_eHasWebkitPrefix) != 0
{
dest.write_str("-webkit-")?;
}
match self.range {
@ -263,7 +266,9 @@ impl ToCss for Expression {
}
// NB: CssStringWriter not needed, feature names are under control.
write!(dest, "{}", unsafe { Atom::from_static(*self.feature.mName) })?;
write!(dest, "{}", unsafe {
Atom::from_static(*self.feature.mName)
})?;
if let Some(ref val) = self.value {
dest.write_str(": ")?;
@ -276,8 +281,8 @@ impl ToCss for Expression {
impl PartialEq for Expression {
fn eq(&self, other: &Expression) -> bool {
self.feature.mName == other.feature.mName &&
self.value == other.value && self.range == other.range
self.feature.mName == other.feature.mName && self.value == other.value &&
self.range == other.range
}
}
@ -307,14 +312,14 @@ impl Resolution {
fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
let location = input.current_source_location();
let (value, unit) = match *input.next()? {
Token::Dimension { value, ref unit, .. } => {
(value, unit)
},
Token::Dimension {
value, ref unit, ..
} => (value, unit),
ref t => return Err(location.new_unexpected_token_error(t.clone())),
};
if value <= 0. {
return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
(match_ignore_ascii_case! { &unit,
@ -322,7 +327,9 @@ impl Resolution {
"dppx" => Ok(Resolution::Dppx(value)),
"dpcm" => Ok(Resolution::Dpcm(value)),
_ => Err(())
}).map_err(|()| location.new_custom_error(StyleParseErrorKind::UnexpectedDimension(unit.clone())))
}).map_err(|()| {
location.new_custom_error(StyleParseErrorKind::UnexpectedDimension(unit.clone()))
})
}
}
@ -369,36 +376,38 @@ impl MediaExpressionValue {
debug_assert_eq!(css_value.mUnit, nsCSSUnit::eCSSUnit_Pixel);
let pixels = css_value.float_unchecked();
Some(MediaExpressionValue::Length(Length::from_px(pixels)))
}
},
nsMediaFeature_ValueType::eInteger => {
let i = css_value.integer_unchecked();
debug_assert!(i >= 0);
Some(MediaExpressionValue::Integer(i as u32))
}
},
nsMediaFeature_ValueType::eFloat => {
debug_assert_eq!(css_value.mUnit, nsCSSUnit::eCSSUnit_Number);
Some(MediaExpressionValue::Float(css_value.float_unchecked()))
}
},
nsMediaFeature_ValueType::eBoolInteger => {
debug_assert_eq!(css_value.mUnit, nsCSSUnit::eCSSUnit_Integer);
let i = css_value.integer_unchecked();
debug_assert!(i == 0 || i == 1);
Some(MediaExpressionValue::BoolInteger(i == 1))
}
},
nsMediaFeature_ValueType::eResolution => {
debug_assert_eq!(css_value.mUnit, nsCSSUnit::eCSSUnit_Pixel);
Some(MediaExpressionValue::Resolution(Resolution::Dppx(css_value.float_unchecked())))
}
Some(MediaExpressionValue::Resolution(Resolution::Dppx(
css_value.float_unchecked(),
)))
},
nsMediaFeature_ValueType::eEnumerated => {
let value = css_value.integer_unchecked() as i16;
Some(MediaExpressionValue::Enumerated(value))
}
},
nsMediaFeature_ValueType::eIdent => {
debug_assert_eq!(css_value.mUnit, nsCSSUnit::eCSSUnit_AtomIdent);
Some(MediaExpressionValue::Ident(unsafe {
Atom::from_raw(*css_value.mValue.mAtom.as_ref())
}))
}
},
nsMediaFeature_ValueType::eIntRatio => {
let array = unsafe { css_value.array_unchecked() };
debug_assert_eq!(array.len(), 2);
@ -407,31 +416,28 @@ impl MediaExpressionValue {
debug_assert!(first >= 0 && second >= 0);
Some(MediaExpressionValue::IntRatio(first as u32, second as u32))
}
},
}
}
}
impl MediaExpressionValue {
fn to_css<W>(&self, dest: &mut CssWriter<W>, for_expr: &Expression) -> fmt::Result
where W: fmt::Write,
where
W: fmt::Write,
{
match *self {
MediaExpressionValue::Length(ref l) => l.to_css(dest),
MediaExpressionValue::Integer(v) => v.to_css(dest),
MediaExpressionValue::Float(v) => v.to_css(dest),
MediaExpressionValue::BoolInteger(v) => {
dest.write_str(if v { "1" } else { "0" })
},
MediaExpressionValue::BoolInteger(v) => dest.write_str(if v { "1" } else { "0" }),
MediaExpressionValue::IntRatio(a, b) => {
a.to_css(dest)?;
dest.write_char('/')?;
b.to_css(dest)
},
MediaExpressionValue::Resolution(ref r) => r.to_css(dest),
MediaExpressionValue::Ident(ref ident) => {
serialize_atom_identifier(ident, dest)
}
MediaExpressionValue::Ident(ref ident) => serialize_atom_identifier(ident, dest),
MediaExpressionValue::Enumerated(value) => unsafe {
use std::{slice, str};
use std::os::raw::c_char;
@ -440,20 +446,18 @@ impl MediaExpressionValue {
// well-formed utf-8.
let mut length = 0;
let (keyword, _value) =
find_in_table(*for_expr.feature.mData.mKeywordTable.as_ref(),
|_kw, val| val == value)
.expect("Value not found in the keyword table?");
let (keyword, _value) = find_in_table(
*for_expr.feature.mData.mKeywordTable.as_ref(),
|_kw, val| val == value,
).expect("Value not found in the keyword table?");
let buffer: *const c_char =
bindings::Gecko_CSSKeywordString(keyword, &mut length);
let buffer =
slice::from_raw_parts(buffer as *const u8, length as usize);
let buffer: *const c_char = bindings::Gecko_CSSKeywordString(keyword, &mut length);
let buffer = slice::from_raw_parts(buffer as *const u8, length as usize);
let string = str::from_utf8_unchecked(buffer);
dest.write_str(string)
}
},
}
}
}
@ -479,7 +483,7 @@ unsafe fn find_in_table<F>(
mut f: F,
) -> Option<(nsCSSKeyword, i16)>
where
F: FnMut(nsCSSKeyword, i16) -> bool
F: FnMut(nsCSSKeyword, i16) -> bool,
{
loop {
let value = (*current_entry).mValue;
@ -511,52 +515,50 @@ fn parse_feature_value<'i, 't>(
nsMediaFeature_ValueType::eInteger => {
let integer = Integer::parse_non_negative(context, input)?;
MediaExpressionValue::Integer(integer.value() as u32)
}
},
nsMediaFeature_ValueType::eBoolInteger => {
let integer = Integer::parse_non_negative(context, input)?;
let value = integer.value();
if value > 1 {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
MediaExpressionValue::BoolInteger(value == 1)
}
},
nsMediaFeature_ValueType::eFloat => {
let number = Number::parse(context, input)?;
MediaExpressionValue::Float(number.get())
}
},
nsMediaFeature_ValueType::eIntRatio => {
let a = Integer::parse_positive(context, input)?;
input.expect_delim('/')?;
let b = Integer::parse_positive(context, input)?;
MediaExpressionValue::IntRatio(a.value() as u32, b.value() as u32)
}
},
nsMediaFeature_ValueType::eResolution => {
MediaExpressionValue::Resolution(Resolution::parse(input)?)
}
},
nsMediaFeature_ValueType::eEnumerated => {
let location = input.current_source_location();
let keyword = input.expect_ident()?;
let keyword = unsafe {
bindings::Gecko_LookupCSSKeyword(
keyword.as_bytes().as_ptr(),
keyword.len() as u32,
)
bindings::Gecko_LookupCSSKeyword(keyword.as_bytes().as_ptr(), keyword.len() as u32)
};
let first_table_entry: *const nsCSSProps_KTableEntry = unsafe {
*feature.mData.mKeywordTable.as_ref()
};
let first_table_entry: *const nsCSSProps_KTableEntry =
unsafe { *feature.mData.mKeywordTable.as_ref() };
let value = match unsafe { find_in_table(first_table_entry, |kw, _| kw == keyword) } {
Some((_kw, value)) => value,
None => return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
None => {
return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
},
};
MediaExpressionValue::Enumerated(value)
}
},
nsMediaFeature_ValueType::eIdent => {
MediaExpressionValue::Ident(Atom::from(input.expect_ident()?.as_ref()))
}
},
};
Ok(value)
@ -569,7 +571,11 @@ impl Expression {
value: Option<MediaExpressionValue>,
range: Range,
) -> Self {
Self { feature, value, range }
Self {
feature,
value,
range,
}
}
/// Parse a media expression of the form:
@ -581,12 +587,14 @@ impl Expression {
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
input.expect_parenthesis_block().map_err(|err|
input.expect_parenthesis_block().map_err(|err| {
err.location.new_custom_error(match err.kind {
BasicParseErrorKind::UnexpectedToken(t) => StyleParseErrorKind::ExpectedIdentifier(t),
BasicParseErrorKind::UnexpectedToken(t) => {
StyleParseErrorKind::ExpectedIdentifier(t)
},
_ => StyleParseErrorKind::UnspecifiedError,
})
)?;
})?;
input.parse_nested_block(|input| {
// FIXME: remove extra indented block when lifetimes are non-lexical
@ -594,17 +602,19 @@ impl Expression {
let range;
{
let location = input.current_source_location();
let ident = input.expect_ident().map_err(|err|
let ident = input.expect_ident().map_err(|err| {
err.location.new_custom_error(match err.kind {
BasicParseErrorKind::UnexpectedToken(t) => StyleParseErrorKind::ExpectedIdentifier(t),
BasicParseErrorKind::UnexpectedToken(t) => {
StyleParseErrorKind::ExpectedIdentifier(t)
},
_ => StyleParseErrorKind::UnspecifiedError,
})
)?;
})?;
let mut flags = 0;
if context.chrome_rules_enabled() ||
context.stylesheet_origin == Origin::UserAgent {
if context.chrome_rules_enabled() || context.stylesheet_origin == Origin::UserAgent
{
flags |= structs::nsMediaFeature_RequirementFlags_eUserAgentAndChromeOnly;
}
@ -612,10 +622,13 @@ impl Expression {
let mut feature_name = &**ident;
if unsafe { structs::StaticPrefs_sVarCache_layout_css_prefixes_webkit } &&
starts_with_ignore_ascii_case(feature_name, "-webkit-") {
starts_with_ignore_ascii_case(feature_name, "-webkit-")
{
feature_name = &feature_name[8..];
flags |= structs::nsMediaFeature_RequirementFlags_eHasWebkitPrefix;
if unsafe { structs::StaticPrefs_sVarCache_layout_css_prefixes_device_pixel_ratio_webkit } {
if unsafe {
structs::StaticPrefs_sVarCache_layout_css_prefixes_device_pixel_ratio_webkit
} {
flags |= structs::nsMediaFeature_RequirementFlags_eWebkitDevicePixelRatioPrefEnabled;
}
}
@ -641,25 +654,26 @@ impl Expression {
Ok((f, r)) => {
feature = f;
range = r;
}
},
Err(()) => {
return Err(location.new_custom_error(
StyleParseErrorKind::MediaQueryExpectedFeatureName(ident.clone())
StyleParseErrorKind::MediaQueryExpectedFeatureName(ident.clone()),
))
}
},
}
if (feature.mReqFlags & !flags) != 0 {
return Err(location.new_custom_error(
StyleParseErrorKind::MediaQueryExpectedFeatureName(ident.clone())
))
StyleParseErrorKind::MediaQueryExpectedFeatureName(ident.clone()),
));
}
if range != Range::Equal &&
feature.mRangeType != nsMediaFeature_RangeType::eMinMaxAllowed {
feature.mRangeType != nsMediaFeature_RangeType::eMinMaxAllowed
{
return Err(location.new_custom_error(
StyleParseErrorKind::MediaQueryExpectedFeatureName(ident.clone())
))
StyleParseErrorKind::MediaQueryExpectedFeatureName(ident.clone()),
));
}
}
@ -670,16 +684,16 @@ impl Expression {
// reject them here too.
if input.try(|i| i.expect_colon()).is_err() {
if range != Range::Equal {
return Err(input.new_custom_error(StyleParseErrorKind::RangedExpressionWithNoValue))
return Err(input.new_custom_error(StyleParseErrorKind::RangedExpressionWithNoValue));
}
return Ok(Expression::new(feature, None, range));
}
let value = parse_feature_value(feature,
feature.mValueType,
context, input).map_err(|err|
err.location.new_custom_error(StyleParseErrorKind::MediaQueryExpectedFeatureValue)
)?;
let value =
parse_feature_value(feature, feature.mValueType, context, input).map_err(|err| {
err.location
.new_custom_error(StyleParseErrorKind::MediaQueryExpectedFeatureValue)
})?;
Ok(Expression::new(feature, Some(value), range))
})
@ -690,7 +704,10 @@ impl Expression {
let mut css_value = nsCSSValue::null();
unsafe {
(self.feature.mGetter.unwrap())(
device.pres_context().mDocument.raw::<structs::nsIDocument>(),
device
.pres_context()
.mDocument
.raw::<structs::nsIDocument>(),
self.feature,
&mut css_value,
)
@ -713,9 +730,11 @@ impl Expression {
use self::MediaExpressionValue::*;
use std::cmp::Ordering;
debug_assert!(self.range == Range::Equal ||
self.feature.mRangeType == nsMediaFeature_RangeType::eMinMaxAllowed,
"Whoops, wrong range");
debug_assert!(
self.range == Range::Equal ||
self.feature.mRangeType == nsMediaFeature_RangeType::eMinMaxAllowed,
"Whoops, wrong range"
);
// http://dev.w3.org/csswg/mediaqueries3/#units
// em units are relative to the initial font-size.
@ -727,54 +746,57 @@ impl Expression {
return match *actual_value {
BoolInteger(v) => v,
Integer(v) => v != 0,
Length(ref l) => {
computed::Context::for_media_query_evaluation(
device,
quirks_mode,
|context| l.to_computed_value(&context).px() != 0.,
)
},
Length(ref l) => computed::Context::for_media_query_evaluation(
device,
quirks_mode,
|context| l.to_computed_value(&context).px() != 0.,
),
_ => true,
}
}
};
},
};
// FIXME(emilio): Handle the possible floating point errors?
let cmp = match (required_value, actual_value) {
(&Length(ref one), &Length(ref other)) => {
computed::Context::for_media_query_evaluation(device, quirks_mode, |context| {
one.to_computed_value(&context).to_i32_au()
one.to_computed_value(&context)
.to_i32_au()
.cmp(&other.to_computed_value(&context).to_i32_au())
})
}
},
(&Integer(one), &Integer(ref other)) => one.cmp(other),
(&BoolInteger(one), &BoolInteger(ref other)) => one.cmp(other),
(&Float(one), &Float(ref other)) => one.partial_cmp(other).unwrap(),
(&IntRatio(one_num, one_den), &IntRatio(other_num, other_den)) => {
// Extend to avoid overflow.
(one_num as u64 * other_den as u64).cmp(
&(other_num as u64 * one_den as u64))
}
(one_num as u64 * other_den as u64).cmp(&(other_num as u64 * one_den as u64))
},
(&Resolution(ref one), &Resolution(ref other)) => {
let actual_dpi = unsafe {
if (*device.pres_context).mOverrideDPPX > 0.0 {
self::Resolution::Dppx((*device.pres_context).mOverrideDPPX)
.to_dpi()
self::Resolution::Dppx((*device.pres_context).mOverrideDPPX).to_dpi()
} else {
other.to_dpi()
}
};
one.to_dpi().partial_cmp(&actual_dpi).unwrap()
}
},
(&Ident(ref one), &Ident(ref other)) => {
debug_assert_ne!(self.feature.mRangeType, nsMediaFeature_RangeType::eMinMaxAllowed);
debug_assert_ne!(
self.feature.mRangeType,
nsMediaFeature_RangeType::eMinMaxAllowed
);
return one == other;
}
},
(&Enumerated(one), &Enumerated(other)) => {
debug_assert_ne!(self.feature.mRangeType, nsMediaFeature_RangeType::eMinMaxAllowed);
debug_assert_ne!(
self.feature.mRangeType,
nsMediaFeature_RangeType::eMinMaxAllowed
);
return one == other;
}
},
_ => unreachable!(),
};

View file

@ -17,7 +17,10 @@ use std::fmt;
use string_cache::Atom;
use values::serialize_atom_identifier;
include!(concat!(env!("OUT_DIR"), "/gecko/pseudo_element_definition.rs"));
include!(concat!(
env!("OUT_DIR"),
"/gecko/pseudo_element_definition.rs"
));
impl ::selectors::parser::PseudoElement for PseudoElement {
type Impl = SelectorImpl;
@ -42,11 +45,11 @@ impl PseudoElement {
pub fn cascade_type(&self) -> PseudoElementCascadeType {
if self.is_eager() {
debug_assert!(!self.is_anon_box());
return PseudoElementCascadeType::Eager
return PseudoElementCascadeType::Eager;
}
if self.is_precomputed() {
return PseudoElementCascadeType::Precomputed
return PseudoElementCascadeType::Precomputed;
}
PseudoElementCascadeType::Lazy
@ -73,7 +76,9 @@ impl PseudoElement {
/// Gets the canonical index of this eagerly-cascaded pseudo-element.
#[inline]
pub fn eager_index(&self) -> usize {
EAGER_PSEUDOS.iter().position(|p| p == self)
EAGER_PSEUDOS
.iter()
.position(|p| p == self)
.expect("Not an eager pseudo")
}

View file

@ -57,8 +57,7 @@ impl GeckoRestyleDamage {
&mut reset_only,
)
};
if reset_only &&
old_style.custom_properties() != new_style.custom_properties() {
if reset_only && old_style.custom_properties() != new_style.custom_properties() {
// The Gecko_CalcStyleDifference call only checks the non-custom
// property structs, so we check the custom properties here. Since
// they generate no damage themselves, we can skip this check if we

View file

@ -8,14 +8,14 @@ use byteorder::{BigEndian, WriteBytesExt};
use computed_values::{font_stretch, font_style, font_weight};
use counter_style::{self, CounterBound};
use cssparser::UnicodeRange;
use font_face::{Source, FontDisplay, FontWeight};
use font_face::{FontDisplay, FontWeight, Source};
use gecko_bindings::structs::{self, nsCSSValue};
use gecko_bindings::sugar::ns_css_value::ToNsCssValue;
use properties::longhands::font_language_override;
use std::str;
use values::computed::font::FamilyName;
use values::generics::font::FontTag;
use values::specified::font::{SpecifiedFontVariationSettings, SpecifiedFontFeatureSettings};
use values::specified::font::{SpecifiedFontFeatureSettings, SpecifiedFontVariationSettings};
impl<'a> ToNsCssValue for &'a FamilyName {
fn convert(self, nscssvalue: &mut nsCSSValue) {
@ -32,10 +32,8 @@ impl ToNsCssValue for font_weight::T {
impl<'a> ToNsCssValue for &'a FontWeight {
fn convert(self, nscssvalue: &mut nsCSSValue) {
match *self {
FontWeight::Normal =>
nscssvalue.set_enum(structs::NS_FONT_WEIGHT_NORMAL as i32),
FontWeight::Bold =>
nscssvalue.set_enum(structs::NS_FONT_WEIGHT_BOLD as i32),
FontWeight::Normal => nscssvalue.set_enum(structs::NS_FONT_WEIGHT_NORMAL as i32),
FontWeight::Bold => nscssvalue.set_enum(structs::NS_FONT_WEIGHT_BOLD as i32),
FontWeight::Weight(weight) => nscssvalue.set_integer(weight.0 as i32),
}
}
@ -83,7 +81,9 @@ impl<'a> ToNsCssValue for &'a font_language_override::SpecifiedValue {
fn convert(self, nscssvalue: &mut nsCSSValue) {
match *self {
font_language_override::SpecifiedValue::Normal => nscssvalue.set_normal(),
font_language_override::SpecifiedValue::Override(ref lang) => nscssvalue.set_string(&*lang),
font_language_override::SpecifiedValue::Override(ref lang) => {
nscssvalue.set_string(&*lang)
},
// This path is unreachable because the descriptor is only specified by the user.
font_language_override::SpecifiedValue::System(_) => unreachable!(),
}
@ -139,11 +139,17 @@ impl<'a> ToNsCssValue for &'a Vec<Source> {
Source::Local(_) => 1,
}
});
let mut target_srcs =
nscssvalue.set_array(src_len as i32).as_mut_slice().iter_mut();
macro_rules! next { () => {
target_srcs.next().expect("Length of target_srcs should be enough")
} }
let mut target_srcs = nscssvalue
.set_array(src_len as i32)
.as_mut_slice()
.iter_mut();
macro_rules! next {
() => {
target_srcs
.next()
.expect("Length of target_srcs should be enough")
};
}
for src in self.iter() {
match *src {
Source::Url(ref url) => {
@ -151,10 +157,10 @@ impl<'a> ToNsCssValue for &'a Vec<Source> {
for hint in url.format_hints.iter() {
next!().set_font_format(&hint);
}
}
},
Source::Local(ref family) => {
next!().set_local_font(&family.name);
}
},
}
}
debug_assert!(target_srcs.next().is_none(), "Should have filled all slots");
@ -165,7 +171,8 @@ impl<'a> ToNsCssValue for &'a Vec<UnicodeRange> {
fn convert(self, nscssvalue: &mut nsCSSValue) {
let target_ranges = nscssvalue
.set_array((self.len() * 2) as i32)
.as_mut_slice().chunks_mut(2);
.as_mut_slice()
.chunks_mut(2);
for (range, target) in self.iter().zip(target_ranges) {
target[0].set_integer(range.start as i32);
target[1].set_integer(range.end as i32);
@ -194,20 +201,22 @@ impl<'a> ToNsCssValue for &'a counter_style::System {
Alphabetic => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_ALPHABETIC as i32),
Symbolic => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_SYMBOLIC as i32),
Additive => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_ADDITIVE as i32),
Fixed { ref first_symbol_value } => {
Fixed {
ref first_symbol_value,
} => {
let mut a = nsCSSValue::null();
let mut b = nsCSSValue::null();
a.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_FIXED as i32);
b.set_integer(first_symbol_value.map_or(1, |v| v.value()));
nscssvalue.set_pair(&a, &b);
}
},
Extends(ref other) => {
let mut a = nsCSSValue::null();
let mut b = nsCSSValue::null();
a.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_EXTENDS as i32);
b.set_atom_ident(other.0.clone());
nscssvalue.set_pair(&a, &b);
}
},
}
}
}

View file

@ -5,7 +5,7 @@
//! Gecko-specific bits for selector-parsing.
use cssparser::{BasicParseError, BasicParseErrorKind, Parser};
use cssparser::{ToCss, Token, CowRcStr, SourceLocation};
use cssparser::{CowRcStr, SourceLocation, ToCss, Token};
use element_state::{DocumentState, ElementState};
use gecko_bindings::structs;
use gecko_bindings::structs::RawServoSelectorList;
@ -13,7 +13,7 @@ use gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI};
use invalidation::element::document_state::InvalidationMatchingData;
use selector_parser::{Direction, SelectorParser};
use selectors::SelectorList;
use selectors::parser::{self as selector_parser, Selector, Visit, SelectorParseErrorKind};
use selectors::parser::{self as selector_parser, Selector, SelectorParseErrorKind, Visit};
use selectors::visitor::SelectorVisitor;
use std::fmt;
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
@ -65,7 +65,10 @@ macro_rules! pseudo_class_name {
apply_non_ts_list!(pseudo_class_name);
impl ToCss for NonTSPseudoClass {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where
W: fmt::Write,
{
use cssparser::CssStringWriter;
use std::fmt::Write;
macro_rules! pseudo_class_serialize {
@ -133,7 +136,6 @@ impl Visit for NonTSPseudoClass {
}
}
impl NonTSPseudoClass {
/// Parses the name and returns a non-ts-pseudo-class if succeeds.
/// None otherwise. It doesn't check whether the pseudo-class is enabled
@ -154,8 +156,12 @@ impl NonTSPseudoClass {
/// Returns true if this pseudo-class has any of the given flags set.
fn has_any_flag(&self, flags: NonTSPseudoClassFlag) -> bool {
macro_rules! check_flag {
(_) => (false);
($flags:ident) => (NonTSPseudoClassFlag::$flags.intersects(flags));
(_) => {
false
};
($flags:ident) => {
NonTSPseudoClassFlag::$flags.intersects(flags)
};
}
macro_rules! pseudo_class_check_is_enabled_in {
(bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*],
@ -178,11 +184,14 @@ impl NonTSPseudoClass {
match *self {
// For pseudo-classes with pref, the availability in content
// depends on the pref.
NonTSPseudoClass::Fullscreen =>
unsafe { mozilla::StaticPrefs_sVarCache_full_screen_api_unprefix_enabled },
NonTSPseudoClass::Fullscreen => unsafe {
mozilla::StaticPrefs_sVarCache_full_screen_api_unprefix_enabled
},
// Otherwise, a pseudo-class is enabled in content when it
// doesn't have any enabled flag.
_ => !self.has_any_flag(NonTSPseudoClassFlag::PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME),
_ => !self.has_any_flag(
NonTSPseudoClassFlag::PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME,
),
}
}
@ -190,16 +199,21 @@ impl NonTSPseudoClass {
///
/// We intentionally skip the link-related ones.
pub fn is_safe_user_action_state(&self) -> bool {
matches!(*self, NonTSPseudoClass::Hover |
NonTSPseudoClass::Active |
NonTSPseudoClass::Focus)
matches!(
*self,
NonTSPseudoClass::Hover | NonTSPseudoClass::Active | NonTSPseudoClass::Focus
)
}
/// Get the state flag associated with a pseudo-class, if any.
pub fn state_flag(&self) -> ElementState {
macro_rules! flag {
(_) => (ElementState::empty());
($state:ident) => (ElementState::$state);
(_) => {
ElementState::empty()
};
($state:ident) => {
ElementState::$state
};
}
macro_rules! pseudo_class_state {
(bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*],
@ -229,7 +243,7 @@ impl NonTSPseudoClass {
/// revalidation.
pub fn needs_cache_revalidation(&self) -> bool {
self.state_flag().is_empty() &&
!matches!(*self,
!matches!(*self,
// :-moz-any is handled by the revalidation visitor walking
// the things inside it; it does not need to cause
// revalidation on its own.
@ -261,10 +275,11 @@ impl NonTSPseudoClass {
/// Returns true if the evaluation of the pseudo-class depends on the
/// element's attributes.
pub fn is_attr_based(&self) -> bool {
matches!(*self,
NonTSPseudoClass::MozTableBorderNonzero |
NonTSPseudoClass::MozBrowserFrame |
NonTSPseudoClass::Lang(..))
matches!(
*self,
NonTSPseudoClass::MozTableBorderNonzero | NonTSPseudoClass::MozBrowserFrame |
NonTSPseudoClass::Lang(..)
)
}
}
@ -297,22 +312,19 @@ impl ::selectors::SelectorImpl for SelectorImpl {
}
impl<'a> SelectorParser<'a> {
fn is_pseudo_class_enabled(
&self,
pseudo_class: &NonTSPseudoClass,
) -> bool {
fn is_pseudo_class_enabled(&self, pseudo_class: &NonTSPseudoClass) -> bool {
if pseudo_class.is_enabled_in_content() {
return true;
}
if self.in_user_agent_stylesheet() &&
pseudo_class.has_any_flag(NonTSPseudoClassFlag::PSEUDO_CLASS_ENABLED_IN_UA_SHEETS)
pseudo_class.has_any_flag(NonTSPseudoClassFlag::PSEUDO_CLASS_ENABLED_IN_UA_SHEETS)
{
return true;
}
if self.chrome_rules_enabled() &&
pseudo_class.has_any_flag(NonTSPseudoClassFlag::PSEUDO_CLASS_ENABLED_IN_CHROME)
pseudo_class.has_any_flag(NonTSPseudoClassFlag::PSEUDO_CLASS_ENABLED_IN_CHROME)
{
return true;
}
@ -320,10 +332,7 @@ impl<'a> SelectorParser<'a> {
return false;
}
fn is_pseudo_element_enabled(
&self,
pseudo_element: &PseudoElement,
) -> bool {
fn is_pseudo_element_enabled(&self, pseudo_element: &PseudoElement) -> bool {
if pseudo_element.enabled_in_content() {
return true;
}
@ -359,8 +368,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
fn pseudo_element_allows_single_colon(name: &str) -> bool {
// FIXME: -moz-tree check should probably be ascii-case-insensitive.
::selectors::parser::is_css2_pseudo_element(name) ||
name.starts_with("-moz-tree-")
::selectors::parser::is_css2_pseudo_element(name) || name.starts_with("-moz-tree-")
}
fn parse_non_ts_pseudo_class(
@ -373,7 +381,11 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
return Ok(pseudo_class);
}
}
Err(location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name)))
Err(
location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
name,
)),
)
}
fn parse_non_ts_functional_pseudo_class<'t>(
@ -420,7 +432,11 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
if self.is_pseudo_class_enabled(&pseudo_class) {
Ok(pseudo_class)
} else {
Err(parser.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name)))
Err(
parser.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
name,
)),
)
}
}
@ -435,9 +451,11 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
}
}
Err(location.new_custom_error(
SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name)
))
Err(
location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
name,
)),
)
}
fn parse_functional_pseudo_element<'t>(
@ -456,7 +474,10 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
Ok(&Token::Ident(ref ident)) => args.push(Atom::from(ident.as_ref())),
Ok(&Token::Comma) => {},
Ok(t) => return Err(location.new_unexpected_token_error(t.clone())),
Err(BasicParseError { kind: BasicParseErrorKind::EndOfInput, .. }) => break,
Err(BasicParseError {
kind: BasicParseErrorKind::EndOfInput,
..
}) => break,
_ => unreachable!("Parser::next() shouldn't return any other error"),
}
}
@ -465,9 +486,11 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
return Ok(pseudo);
}
}
Err(parser.new_custom_error(
SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name)
))
Err(
parser.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
name,
)),
)
}
fn default_namespace(&self) -> Option<Namespace> {
@ -484,7 +507,8 @@ impl SelectorImpl {
/// `fun` on it.
#[inline]
pub fn each_eagerly_cascaded_pseudo_element<F>(mut fun: F)
where F: FnMut(PseudoElement),
where
F: FnMut(PseudoElement),
{
for pseudo in &EAGER_PSEUDOS {
fun(pseudo.clone())

View file

@ -9,7 +9,7 @@ use WeakAtom;
use dom::TElement;
use element_state::ElementState;
use gecko::snapshot_helpers;
use gecko::wrapper::{NamespaceConstraintHelpers, GeckoElement};
use gecko::wrapper::{GeckoElement, NamespaceConstraintHelpers};
use gecko_bindings::bindings;
use gecko_bindings::structs::ServoElementSnapshot;
use gecko_bindings::structs::ServoElementSnapshotFlags as Flags;
@ -91,13 +91,13 @@ impl GeckoElementSnapshot {
unsafe {
match *operation {
AttrSelectorOperation::Exists => {
bindings:: Gecko_SnapshotHasAttr(
self,
ns.atom_or_null(),
local_name.as_ptr(),
)
}
AttrSelectorOperation::WithValue { operator, case_sensitivity, expected_value } => {
bindings::Gecko_SnapshotHasAttr(self, ns.atom_or_null(), local_name.as_ptr())
},
AttrSelectorOperation::WithValue {
operator,
case_sensitivity,
expected_value,
} => {
let ignore_case = match case_sensitivity {
CaseSensitivity::CaseSensitive => false,
CaseSensitivity::AsciiCaseInsensitive => true,
@ -109,7 +109,7 @@ impl GeckoElementSnapshot {
ns.atom_or_null(),
local_name.as_ptr(),
expected_value.as_ptr(),
ignore_case
ignore_case,
),
AttrSelectorOperator::Includes => bindings::Gecko_SnapshotAttrIncludes(
self,
@ -139,15 +139,17 @@ impl GeckoElementSnapshot {
expected_value.as_ptr(),
ignore_case,
),
AttrSelectorOperator::Substring => bindings::Gecko_SnapshotAttrHasSubstring(
self,
ns.atom_or_null(),
local_name.as_ptr(),
expected_value.as_ptr(),
ignore_case,
),
AttrSelectorOperator::Substring => {
bindings::Gecko_SnapshotAttrHasSubstring(
self,
ns.atom_or_null(),
local_name.as_ptr(),
expected_value.as_ptr(),
ignore_case,
)
},
}
}
},
}
}
}
@ -170,12 +172,10 @@ impl ElementSnapshot for GeckoElementSnapshot {
#[inline]
fn id_attr(&self) -> Option<&WeakAtom> {
if !self.has_any(Flags::Id) {
return None
return None;
}
let ptr = unsafe {
bindings::Gecko_SnapshotAtomAttrValue(self, atom!("id").as_ptr())
};
let ptr = unsafe { bindings::Gecko_SnapshotAtomAttrValue(self, atom!("id").as_ptr()) };
// FIXME(emilio): This should assert, since this flag is exact.
if ptr.is_null() {
@ -202,7 +202,7 @@ impl ElementSnapshot for GeckoElementSnapshot {
#[inline]
fn each_class<F>(&self, callback: F)
where
F: FnMut(&Atom)
F: FnMut(&Atom),
{
if !self.has_any(Flags::MaybeClass) {
return;

View file

@ -11,13 +11,14 @@ use string_cache::Atom;
/// A function that, given an element of type `T`, allows you to get a single
/// class or a class list.
pub type ClassOrClassList<T> = unsafe extern fn (T, *mut *mut nsAtom, *mut *mut *mut nsAtom) -> u32;
pub type ClassOrClassList<T> =
unsafe extern "C" fn(T, *mut *mut nsAtom, *mut *mut *mut nsAtom) -> u32;
/// A function to return whether an element of type `T` has a given class.
///
/// The `bool` argument represents whether it should compare case-insensitively
/// or not.
pub type HasClass<T> = unsafe extern fn (T, *mut nsAtom, bool) -> bool;
pub type HasClass<T> = unsafe extern "C" fn(T, *mut nsAtom, bool) -> bool;
/// Given an item `T`, a class name, and a getter function, return whether that
/// element has the class that `name` represents.
@ -36,30 +37,25 @@ pub fn has_class<T>(
unsafe { getter(item, name.as_ptr(), ignore_case) }
}
/// Given an item, a callback, and a getter, execute `callback` for each class
/// this `item` has.
pub fn each_class<F, T>(
item: T,
mut callback: F,
getter: ClassOrClassList<T>,
)
pub fn each_class<F, T>(item: T, mut callback: F, getter: ClassOrClassList<T>)
where
F: FnMut(&Atom)
F: FnMut(&Atom),
{
unsafe {
let mut class: *mut nsAtom = ptr::null_mut();
let mut list: *mut *mut nsAtom = ptr::null_mut();
let length = getter(item, &mut class, &mut list);
match length {
0 => {}
0 => {},
1 => Atom::with(class, callback),
n => {
let classes = slice::from_raw_parts(list, n as usize);
for c in classes {
Atom::with(*c, &mut callback)
}
}
},
}
}
}

View file

@ -5,9 +5,9 @@
//! Gecko-specific bits for the styling DOM traversal.
use context::{SharedStyleContext, StyleContext};
use dom::{TNode, TElement};
use dom::{TElement, TNode};
use gecko::wrapper::{GeckoElement, GeckoNode};
use traversal::{DomTraversal, PerLevelTraversalData, recalc_style_at};
use traversal::{recalc_style_at, DomTraversal, PerLevelTraversalData};
/// This is the simple struct that Gecko uses to encapsulate a DOM traversal for
/// styling.
@ -18,19 +18,19 @@ pub struct RecalcStyleOnly<'a> {
impl<'a> RecalcStyleOnly<'a> {
/// Create a `RecalcStyleOnly` traversal from a `SharedStyleContext`.
pub fn new(shared: SharedStyleContext<'a>) -> Self {
RecalcStyleOnly {
shared: shared,
}
RecalcStyleOnly { shared: shared }
}
}
impl<'recalc, 'le> DomTraversal<GeckoElement<'le>> for RecalcStyleOnly<'recalc> {
fn process_preorder<F>(&self,
traversal_data: &PerLevelTraversalData,
context: &mut StyleContext<GeckoElement<'le>>,
node: GeckoNode<'le>,
note_child: F)
where F: FnMut(GeckoNode<'le>),
fn process_preorder<F>(
&self,
traversal_data: &PerLevelTraversalData,
context: &mut StyleContext<GeckoElement<'le>>,
node: GeckoNode<'le>,
note_child: F,
) where
F: FnMut(GeckoNode<'le>),
{
if let Some(el) = node.as_element() {
let mut data = unsafe { el.ensure_data() };
@ -43,7 +43,9 @@ impl<'recalc, 'le> DomTraversal<GeckoElement<'le>> for RecalcStyleOnly<'recalc>
}
/// We don't use the post-order traversal for anything.
fn needs_postorder_traversal() -> bool { false }
fn needs_postorder_traversal() -> bool {
false
}
fn shared_context(&self) -> &SharedStyleContext {
&self.shared

View file

@ -8,7 +8,7 @@ use cssparser::Parser;
use gecko_bindings::bindings;
use gecko_bindings::structs::{ServoBundledURI, URLExtraData};
use gecko_bindings::structs::mozilla::css::URLValueData;
use gecko_bindings::structs::root::{nsStyleImageRequest, RustString};
use gecko_bindings::structs::root::{RustString, nsStyleImageRequest};
use gecko_bindings::structs::root::mozilla::css::{ImageValue, URLValue};
use gecko_bindings::sugar::refptr::RefPtr;
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
@ -37,9 +37,10 @@ impl CssUrl {
/// URL.
///
/// Returns `Err` in the case that extra_data is incomplete.
pub fn parse_from_string<'a>(url: String,
context: &ParserContext)
-> Result<Self, ParseError<'a>> {
pub fn parse_from_string<'a>(
url: String,
context: &ParserContext,
) -> Result<Self, ParseError<'a>> {
Ok(CssUrl {
serialization: Arc::new(url),
extra_data: context.url_data.clone(),
@ -57,9 +58,8 @@ impl CssUrl {
unsafe fn from_url_value_data(url: &URLValueData) -> Result<Self, ()> {
Ok(CssUrl {
serialization: if url.mUsingRustString {
let arc_type = url.mStrings.mRustString.as_ref()
as *const _ as
*const RawOffsetArc<String>;
let arc_type =
url.mStrings.mRustString.as_ref() as *const _ as *const RawOffsetArc<String>;
Arc::from_raw_offset((*arc_type).clone())
} else {
Arc::new(url.mStrings.mString.as_ref().to_string())
@ -84,7 +84,10 @@ impl CssUrl {
/// Little helper for Gecko's ffi.
pub fn as_slice_components(&self) -> (*const u8, usize) {
(self.serialization.as_str().as_ptr(), self.serialization.as_str().len())
(
self.serialization.as_str().as_ptr(),
self.serialization.as_str().len(),
)
}
/// Create a bundled URI suitable for sending to Gecko
@ -92,16 +95,17 @@ impl CssUrl {
pub fn for_ffi(&self) -> ServoBundledURI {
let arc_offset = Arc::into_raw_offset(self.serialization.clone());
ServoBundledURI {
mURLString: unsafe {
mem::transmute::<_, RawOffsetArc<RustString>>(arc_offset)
},
mURLString: unsafe { mem::transmute::<_, RawOffsetArc<RustString>>(arc_offset) },
mExtraData: self.extra_data.get(),
}
}
}
impl Parse for CssUrl {
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let url = input.expect_url()?;
Self::parse_from_string(url.as_ref().to_owned(), context)
}
@ -157,7 +161,10 @@ impl PartialEq for SpecifiedUrl {
impl Eq for SpecifiedUrl {}
impl Parse for SpecifiedUrl {
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
CssUrl::parse(context, input).map(Self::from_css_url)
}
}
@ -200,7 +207,7 @@ impl SpecifiedImageUrl {
/// Parse a URL from a string value. See SpecifiedUrl::parse_from_string.
pub fn parse_from_string<'a>(
url: String,
context: &ParserContext
context: &ParserContext,
) -> Result<Self, ParseError<'a>> {
CssUrl::parse_from_string(url, context).map(Self::from_css_url)
}
@ -223,7 +230,10 @@ impl SpecifiedImageUrl {
}
impl Parse for SpecifiedImageUrl {
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
CssUrl::parse(context, input).map(Self::from_css_url)
}
}

View file

@ -31,7 +31,7 @@ use values::generics::gecko::ScrollSnapPoint;
use values::generics::grid::{TrackBreadth, TrackKeyword};
/// A trait that defines an interface to convert from and to `nsStyleCoord`s.
pub trait GeckoStyleCoordConvertible : Sized {
pub trait GeckoStyleCoordConvertible: Sized {
/// Convert this to a `nsStyleCoord`.
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T);
/// Given a `nsStyleCoord`, try to get a value of this type..
@ -46,7 +46,9 @@ impl nsStyleCoord {
}
}
impl<A: GeckoStyleCoordConvertible, B: GeckoStyleCoordConvertible> GeckoStyleCoordConvertible for Either<A, B> {
impl<A: GeckoStyleCoordConvertible, B: GeckoStyleCoordConvertible> GeckoStyleCoordConvertible
for Either<A, B>
{
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
match *self {
Either::First(ref v) => v.to_gecko_style_coord(coord),
@ -56,30 +58,28 @@ impl<A: GeckoStyleCoordConvertible, B: GeckoStyleCoordConvertible> GeckoStyleCoo
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
A::from_gecko_style_coord(coord)
.map(Either::First)
.or_else(|| B::from_gecko_style_coord(coord).map(Either::Second))
.map(Either::First)
.or_else(|| B::from_gecko_style_coord(coord).map(Either::Second))
}
}
impl GeckoStyleCoordConvertible for ComputedFlexBasis {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
match *self {
FlexBasis::Content => {
coord.set_value(
CoordDataValue::Enumerated(structs::NS_STYLE_FLEX_BASIS_CONTENT)
)
},
FlexBasis::Content => coord.set_value(CoordDataValue::Enumerated(
structs::NS_STYLE_FLEX_BASIS_CONTENT,
)),
FlexBasis::Width(ref w) => w.to_gecko_style_coord(coord),
}
}
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
if let Some(width) = MozLength::from_gecko_style_coord(coord) {
return Some(FlexBasis::Width(width))
return Some(FlexBasis::Width(width));
}
if let CoordDataValue::Enumerated(structs::NS_STYLE_FLEX_BASIS_CONTENT) = coord.as_value() {
return Some(FlexBasis::Content)
return Some(FlexBasis::Content);
}
None
@ -123,9 +123,7 @@ impl GeckoStyleCoordConvertible for NumberOrPercentage {
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
match coord.as_value() {
CoordDataValue::Factor(f) => Some(NumberOrPercentage::Number(f)),
CoordDataValue::Percent(p) => {
Some(NumberOrPercentage::Percentage(Percentage(p)))
},
CoordDataValue::Percent(p) => Some(NumberOrPercentage::Percentage(Percentage(p))),
_ => None,
}
}
@ -207,7 +205,9 @@ impl GeckoStyleCoordConvertible for LengthOrPercentageOrAuto {
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
match coord.as_value() {
CoordDataValue::Coord(coord) => Some(LengthOrPercentageOrAuto::Length(Au(coord).into())),
CoordDataValue::Coord(coord) => {
Some(LengthOrPercentageOrAuto::Length(Au(coord).into()))
},
CoordDataValue::Percent(p) => Some(LengthOrPercentageOrAuto::Percentage(Percentage(p))),
CoordDataValue::Auto => Some(LengthOrPercentageOrAuto::Auto),
CoordDataValue::Calc(calc) => Some(LengthOrPercentageOrAuto::Calc(calc.into())),
@ -229,7 +229,9 @@ impl GeckoStyleCoordConvertible for LengthOrPercentageOrNone {
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
match coord.as_value() {
CoordDataValue::Coord(coord) => Some(LengthOrPercentageOrNone::Length(Au(coord).into())),
CoordDataValue::Coord(coord) => {
Some(LengthOrPercentageOrNone::Length(Au(coord).into()))
},
CoordDataValue::Percent(p) => Some(LengthOrPercentageOrNone::Percentage(Percentage(p))),
CoordDataValue::None => Some(LengthOrPercentageOrNone::None),
CoordDataValue::Calc(calc) => Some(LengthOrPercentageOrNone::Calc(calc.into())),
@ -244,16 +246,19 @@ impl<L: GeckoStyleCoordConvertible> GeckoStyleCoordConvertible for TrackBreadth<
TrackBreadth::Breadth(ref lop) => lop.to_gecko_style_coord(coord),
TrackBreadth::Fr(fr) => coord.set_value(CoordDataValue::FlexFraction(fr)),
TrackBreadth::Keyword(TrackKeyword::Auto) => coord.set_value(CoordDataValue::Auto),
TrackBreadth::Keyword(TrackKeyword::MinContent) =>
coord.set_value(CoordDataValue::Enumerated(StyleGridTrackBreadth::MinContent as u32)),
TrackBreadth::Keyword(TrackKeyword::MaxContent) =>
coord.set_value(CoordDataValue::Enumerated(StyleGridTrackBreadth::MaxContent as u32)),
TrackBreadth::Keyword(TrackKeyword::MinContent) => coord.set_value(
CoordDataValue::Enumerated(StyleGridTrackBreadth::MinContent as u32),
),
TrackBreadth::Keyword(TrackKeyword::MaxContent) => coord.set_value(
CoordDataValue::Enumerated(StyleGridTrackBreadth::MaxContent as u32),
),
}
}
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
L::from_gecko_style_coord(coord).map(TrackBreadth::Breadth).or_else(|| {
match coord.as_value() {
L::from_gecko_style_coord(coord)
.map(TrackBreadth::Breadth)
.or_else(|| match coord.as_value() {
CoordDataValue::Enumerated(v) => {
if v == StyleGridTrackBreadth::MinContent as u32 {
Some(TrackBreadth::Keyword(TrackKeyword::MinContent))
@ -266,18 +271,19 @@ impl<L: GeckoStyleCoordConvertible> GeckoStyleCoordConvertible for TrackBreadth<
CoordDataValue::FlexFraction(fr) => Some(TrackBreadth::Fr(fr)),
CoordDataValue::Auto => Some(TrackBreadth::Keyword(TrackKeyword::Auto)),
_ => L::from_gecko_style_coord(coord).map(TrackBreadth::Breadth),
}
})
})
}
}
impl GeckoStyleCoordConvertible for ComputedShapeRadius {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
match *self {
ShapeRadius::ClosestSide =>
coord.set_value(CoordDataValue::Enumerated(StyleShapeRadius::ClosestSide as u32)),
ShapeRadius::FarthestSide =>
coord.set_value(CoordDataValue::Enumerated(StyleShapeRadius::FarthestSide as u32)),
ShapeRadius::ClosestSide => coord.set_value(CoordDataValue::Enumerated(
StyleShapeRadius::ClosestSide as u32,
)),
ShapeRadius::FarthestSide => coord.set_value(CoordDataValue::Enumerated(
StyleShapeRadius::FarthestSide as u32,
)),
ShapeRadius::Length(lop) => lop.to_gecko_style_coord(coord),
}
}
@ -292,7 +298,7 @@ impl GeckoStyleCoordConvertible for ComputedShapeRadius {
} else {
None
}
}
},
_ => LengthOrPercentage::from_gecko_style_coord(coord).map(ShapeRadius::Length),
}
}
@ -374,27 +380,30 @@ impl GeckoStyleCoordConvertible for ExtremumLength {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
use gecko_bindings::structs::{NS_STYLE_WIDTH_AVAILABLE, NS_STYLE_WIDTH_FIT_CONTENT};
use gecko_bindings::structs::{NS_STYLE_WIDTH_MAX_CONTENT, NS_STYLE_WIDTH_MIN_CONTENT};
coord.set_value(CoordDataValue::Enumerated(
match *self {
ExtremumLength::MozMaxContent => NS_STYLE_WIDTH_MAX_CONTENT,
ExtremumLength::MozMinContent => NS_STYLE_WIDTH_MIN_CONTENT,
ExtremumLength::MozFitContent => NS_STYLE_WIDTH_FIT_CONTENT,
ExtremumLength::MozAvailable => NS_STYLE_WIDTH_AVAILABLE,
}
))
coord.set_value(CoordDataValue::Enumerated(match *self {
ExtremumLength::MozMaxContent => NS_STYLE_WIDTH_MAX_CONTENT,
ExtremumLength::MozMinContent => NS_STYLE_WIDTH_MIN_CONTENT,
ExtremumLength::MozFitContent => NS_STYLE_WIDTH_FIT_CONTENT,
ExtremumLength::MozAvailable => NS_STYLE_WIDTH_AVAILABLE,
}))
}
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
use gecko_bindings::structs::{NS_STYLE_WIDTH_AVAILABLE, NS_STYLE_WIDTH_FIT_CONTENT};
use gecko_bindings::structs::{NS_STYLE_WIDTH_MAX_CONTENT, NS_STYLE_WIDTH_MIN_CONTENT};
match coord.as_value() {
CoordDataValue::Enumerated(NS_STYLE_WIDTH_MAX_CONTENT) =>
Some(ExtremumLength::MozMaxContent),
CoordDataValue::Enumerated(NS_STYLE_WIDTH_MIN_CONTENT) =>
Some(ExtremumLength::MozMinContent),
CoordDataValue::Enumerated(NS_STYLE_WIDTH_FIT_CONTENT) =>
Some(ExtremumLength::MozFitContent),
CoordDataValue::Enumerated(NS_STYLE_WIDTH_AVAILABLE) => Some(ExtremumLength::MozAvailable),
CoordDataValue::Enumerated(NS_STYLE_WIDTH_MAX_CONTENT) => {
Some(ExtremumLength::MozMaxContent)
},
CoordDataValue::Enumerated(NS_STYLE_WIDTH_MIN_CONTENT) => {
Some(ExtremumLength::MozMinContent)
},
CoordDataValue::Enumerated(NS_STYLE_WIDTH_FIT_CONTENT) => {
Some(ExtremumLength::MozFitContent)
},
CoordDataValue::Enumerated(NS_STYLE_WIDTH_AVAILABLE) => {
Some(ExtremumLength::MozAvailable)
},
_ => None,
}
}
@ -409,8 +418,11 @@ impl GeckoStyleCoordConvertible for MozLength {
}
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
LengthOrPercentageOrAuto::from_gecko_style_coord(coord).map(MozLength::LengthOrPercentageOrAuto)
.or_else(|| ExtremumLength::from_gecko_style_coord(coord).map(MozLength::ExtremumLength))
LengthOrPercentageOrAuto::from_gecko_style_coord(coord)
.map(MozLength::LengthOrPercentageOrAuto)
.or_else(|| {
ExtremumLength::from_gecko_style_coord(coord).map(MozLength::ExtremumLength)
})
}
}
@ -423,8 +435,11 @@ impl GeckoStyleCoordConvertible for MaxLength {
}
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
LengthOrPercentageOrNone::from_gecko_style_coord(coord).map(MaxLength::LengthOrPercentageOrNone)
.or_else(|| ExtremumLength::from_gecko_style_coord(coord).map(MaxLength::ExtremumLength))
LengthOrPercentageOrNone::from_gecko_style_coord(coord)
.map(MaxLength::LengthOrPercentageOrNone)
.or_else(|| {
ExtremumLength::from_gecko_style_coord(coord).map(MaxLength::ExtremumLength)
})
}
}
@ -440,13 +455,13 @@ impl GeckoStyleCoordConvertible for ScrollSnapPoint<LengthOrPercentage> {
use gecko_bindings::structs::root::nsStyleUnit;
use values::generics::gecko::ScrollSnapPoint;
Some(
match coord.unit() {
nsStyleUnit::eStyleUnit_None => ScrollSnapPoint::None,
_ => ScrollSnapPoint::Repeat(LengthOrPercentage::from_gecko_style_coord(coord)
.expect("coord could not convert to LengthOrPercentage")),
}
)
Some(match coord.unit() {
nsStyleUnit::eStyleUnit_None => ScrollSnapPoint::None,
_ => ScrollSnapPoint::Repeat(
LengthOrPercentage::from_gecko_style_coord(coord)
.expect("coord could not convert to LengthOrPercentage"),
),
})
}
}
@ -473,18 +488,18 @@ where
/// Convert a given RGBA value to `nscolor`.
pub fn convert_rgba_to_nscolor(rgba: &RGBA) -> u32 {
((rgba.alpha as u32) << 24) |
((rgba.blue as u32) << 16) |
((rgba.green as u32) << 8) |
(rgba.red as u32)
((rgba.alpha as u32) << 24) | ((rgba.blue as u32) << 16) | ((rgba.green as u32) << 8) |
(rgba.red as u32)
}
/// Convert a given `nscolor` to a Servo RGBA value.
pub fn convert_nscolor_to_rgba(color: u32) -> RGBA {
RGBA::new((color & 0xff) as u8,
(color >> 8 & 0xff) as u8,
(color >> 16 & 0xff) as u8,
(color >> 24 & 0xff) as u8)
RGBA::new(
(color & 0xff) as u8,
(color >> 8 & 0xff) as u8,
(color >> 16 & 0xff) as u8,
(color >> 24 & 0xff) as u8,
)
}
/// Round `width` down to the nearest device pixel, but any non-zero value that
@ -495,7 +510,10 @@ pub fn round_border_to_device_pixels(width: Au, au_per_device_px: Au) -> Au {
if width == Au(0) {
Au(0)
} else {
max(au_per_device_px, Au(width.0 / au_per_device_px.0 * au_per_device_px.0))
max(
au_per_device_px,
Au(width.0 / au_per_device_px.0 * au_per_device_px.0),
)
}
}
@ -513,16 +531,27 @@ impl CounterStyleOrNone {
set_name(gecko_value, name.0.into_addrefed(), pres_context);
},
CounterStyleOrNone::Symbols(symbols_type, symbols) => {
let symbols: Vec<_> = symbols.0.iter().map(|symbol| match *symbol {
Symbol::String(ref s) => nsCStr::from(s),
Symbol::Ident(_) => unreachable!("Should not have identifier in symbols()"),
}).collect();
let symbols: Vec<_> = symbols.iter()
let symbols: Vec<_> = symbols
.0
.iter()
.map(|symbol| match *symbol {
Symbol::String(ref s) => nsCStr::from(s),
Symbol::Ident(_) => unreachable!("Should not have identifier in symbols()"),
})
.collect();
let symbols: Vec<_> = symbols
.iter()
.map(|symbol| symbol as &nsACString as *const _)
.collect();
unsafe { set_symbols(gecko_value, symbols_type.to_gecko_keyword(),
symbols.as_ptr(), symbols.len() as u32) };
}
unsafe {
set_symbols(
gecko_value,
symbols_type.to_gecko_keyword(),
symbols.as_ptr(),
symbols.len() as u32,
)
};
},
}
}
@ -541,18 +570,18 @@ impl CounterStyleOrNone {
Either::First(CounterStyleOrNone::Name(CustomIdent(name)))
}
} else {
let anonymous = unsafe {
bindings::Gecko_CounterStyle_GetAnonymous(gecko_value).as_ref()
}.unwrap();
let anonymous =
unsafe { bindings::Gecko_CounterStyle_GetAnonymous(gecko_value).as_ref() }.unwrap();
let symbols = &anonymous.mSymbols;
if anonymous.mSingleString {
debug_assert_eq!(symbols.len(), 1);
Either::Second(symbols[0].to_string())
} else {
let symbol_type = SymbolsType::from_gecko_keyword(anonymous.mSystem as u32);
let symbols = symbols.iter().map(|gecko_symbol| {
Symbol::String(gecko_symbol.to_string())
}).collect();
let symbols = symbols
.iter()
.map(|gecko_symbol| Symbol::String(gecko_symbol.to_string()))
.collect();
Either::First(CounterStyleOrNone::Symbols(symbol_type, Symbols(symbols)))
}
}

File diff suppressed because it is too large Load diff

View file

@ -13,7 +13,8 @@ pub mod bindings {
// foreign structs to have `PhantomData`. We should remove this once the lint
// ignores this case.
#[allow(dead_code, improper_ctypes, non_camel_case_types, non_snake_case, non_upper_case_globals, missing_docs)]
#[allow(dead_code, improper_ctypes, non_camel_case_types, non_snake_case, non_upper_case_globals,
missing_docs)]
pub mod structs {
include!(concat!(env!("OUT_DIR"), "/gecko/structs.rs"));
}

View file

@ -53,8 +53,10 @@ impl Deref for RefPtr<nsCSSShadowArray> {
&[]
} else {
unsafe {
slice::from_raw_parts((*self.mRawPtr).mArray.as_ptr(),
(*self.mRawPtr).mLength as usize)
slice::from_raw_parts(
(*self.mRawPtr).mArray.as_ptr(),
(*self.mRawPtr).mLength as usize,
)
}
}
}
@ -66,8 +68,10 @@ impl DerefMut for RefPtr<nsCSSShadowArray> {
&mut []
} else {
unsafe {
slice::from_raw_parts_mut((*self.mRawPtr).mArray.as_mut_ptr(),
(*self.mRawPtr).mLength as usize)
slice::from_raw_parts_mut(
(*self.mRawPtr).mArray.as_mut_ptr(),
(*self.mRawPtr).mLength as usize,
)
}
}
}

View file

@ -5,7 +5,7 @@
//! Rust helpers for Gecko's `nsCSSShadowItem`.
use app_units::Au;
use gecko::values::{convert_rgba_to_nscolor, convert_nscolor_to_rgba};
use gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor};
use gecko_bindings::structs::nsCSSShadowItem;
use values::computed::RGBAColor;
use values::computed::effects::{BoxShadow, SimpleShadow};

View file

@ -6,8 +6,8 @@
use gecko_bindings::bindings;
use gecko_bindings::structs;
use gecko_bindings::structs::{nsCSSValue, nsCSSUnit};
use gecko_bindings::structs::{nsCSSValue_Array, nsCSSValueList};
use gecko_bindings::structs::{nsCSSUnit, nsCSSValue};
use gecko_bindings::structs::{nsCSSValueList, nsCSSValue_Array};
use gecko_string_cache::Atom;
use std::marker::PhantomData;
use std::mem;
@ -32,15 +32,17 @@ impl nsCSSValue {
/// Returns this nsCSSValue value as an integer, unchecked in release
/// builds.
pub fn integer_unchecked(&self) -> i32 {
debug_assert!(self.mUnit == nsCSSUnit::eCSSUnit_Integer ||
self.mUnit == nsCSSUnit::eCSSUnit_Enumerated);
debug_assert!(
self.mUnit == nsCSSUnit::eCSSUnit_Integer ||
self.mUnit == nsCSSUnit::eCSSUnit_Enumerated
);
unsafe { *self.mValue.mInt.as_ref() }
}
/// Checks if it is an integer and returns it if so
pub fn integer(&self) -> Option<i32> {
if self.mUnit == nsCSSUnit::eCSSUnit_Integer ||
self.mUnit == nsCSSUnit::eCSSUnit_Enumerated {
if self.mUnit == nsCSSUnit::eCSSUnit_Integer || self.mUnit == nsCSSUnit::eCSSUnit_Enumerated
{
Some(unsafe { *self.mValue.mInt.as_ref() })
} else {
None
@ -57,8 +59,10 @@ impl nsCSSValue {
/// Returns this nsCSSValue as a nsCSSValue::Array, unchecked in release
/// builds.
pub unsafe fn array_unchecked(&self) -> &nsCSSValue_Array {
debug_assert!(nsCSSUnit::eCSSUnit_Array as u32 <= self.mUnit as u32 &&
self.mUnit as u32 <= nsCSSUnit::eCSSUnit_Calc_Divided as u32);
debug_assert!(
nsCSSUnit::eCSSUnit_Array as u32 <= self.mUnit as u32 &&
self.mUnit as u32 <= nsCSSUnit::eCSSUnit_Calc_Divided as u32
);
let array = *self.mValue.mArray.as_ref();
debug_assert!(!array.is_null());
&*array
@ -67,15 +71,9 @@ impl nsCSSValue {
/// Sets LengthOrPercentage value to this nsCSSValue.
pub unsafe fn set_lop(&mut self, lop: LengthOrPercentage) {
match lop {
LengthOrPercentage::Length(px) => {
self.set_px(px.px())
}
LengthOrPercentage::Percentage(pc) => {
self.set_percentage(pc.0)
}
LengthOrPercentage::Calc(calc) => {
bindings::Gecko_CSSValue_SetCalc(self, calc.into())
}
LengthOrPercentage::Length(px) => self.set_px(px.px()),
LengthOrPercentage::Percentage(pc) => self.set_percentage(pc.0),
LengthOrPercentage::Calc(calc) => bindings::Gecko_CSSValue_SetCalc(self, calc.into()),
}
}
@ -95,9 +93,9 @@ impl nsCSSValue {
nsCSSUnit::eCSSUnit_Pixel => {
LengthOrPercentage::Length(Length::new(bindings::Gecko_CSSValue_GetNumber(self)))
},
nsCSSUnit::eCSSUnit_Percent => {
LengthOrPercentage::Percentage(Percentage(bindings::Gecko_CSSValue_GetPercentage(self)))
},
nsCSSUnit::eCSSUnit_Percent => LengthOrPercentage::Percentage(Percentage(
bindings::Gecko_CSSValue_GetPercentage(self),
)),
nsCSSUnit::eCSSUnit_Calc => {
LengthOrPercentage::Calc(bindings::Gecko_CSSValue_GetCalc(self).into())
},
@ -108,16 +106,17 @@ impl nsCSSValue {
/// Returns Length value.
pub unsafe fn get_length(&self) -> Length {
match self.mUnit {
nsCSSUnit::eCSSUnit_Pixel => {
Length::new(bindings::Gecko_CSSValue_GetNumber(self))
},
nsCSSUnit::eCSSUnit_Pixel => Length::new(bindings::Gecko_CSSValue_GetNumber(self)),
_ => panic!("Unexpected unit"),
}
}
fn set_valueless_unit(&mut self, unit: nsCSSUnit) {
debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_Null);
debug_assert!(unit as u32 <= nsCSSUnit::eCSSUnit_DummyInherit as u32, "Not a valueless unit");
debug_assert!(
unit as u32 <= nsCSSUnit::eCSSUnit_DummyInherit as u32,
"Not a valueless unit"
);
self.mUnit = unit;
}
@ -241,9 +240,14 @@ impl nsCSSValue {
/// Set to a list value
///
/// This is only supported on the main thread.
pub fn set_list<I>(&mut self, values: I) where I: ExactSizeIterator<Item=nsCSSValue> {
pub fn set_list<I>(&mut self, values: I)
where
I: ExactSizeIterator<Item = nsCSSValue>,
{
debug_assert!(values.len() > 0, "Empty list is not supported");
unsafe { bindings::Gecko_CSSValue_SetList(self, values.len() as u32); }
unsafe {
bindings::Gecko_CSSValue_SetList(self, values.len() as u32);
}
debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_List);
let list: &mut structs::nsCSSValueList = &mut unsafe {
self.mValue.mList.as_ref() // &*nsCSSValueList_heap
@ -258,9 +262,13 @@ impl nsCSSValue {
///
/// This is only supported on the main thread.
pub fn set_pair_list<I>(&mut self, mut values: I)
where I: ExactSizeIterator<Item=(nsCSSValue, nsCSSValue)> {
where
I: ExactSizeIterator<Item = (nsCSSValue, nsCSSValue)>,
{
debug_assert!(values.len() > 0, "Empty list is not supported");
unsafe { bindings::Gecko_CSSValue_SetPairList(self, values.len() as u32); }
unsafe {
bindings::Gecko_CSSValue_SetPairList(self, values.len() as u32);
}
debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_PairList);
let mut item_ptr = &mut unsafe {
self.mValue.mPairList.as_ref() // &*nsCSSValuePairList_heap
@ -276,13 +284,21 @@ impl nsCSSValue {
}
/// Set a shared list
pub fn set_shared_list<I>(&mut self, values: I) where I: ExactSizeIterator<Item=nsCSSValue> {
pub fn set_shared_list<I>(&mut self, values: I)
where
I: ExactSizeIterator<Item = nsCSSValue>,
{
debug_assert!(values.len() > 0, "Empty list is not supported");
unsafe { bindings::Gecko_CSSValue_InitSharedList(self, values.len() as u32) };
debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_SharedList);
let list = unsafe {
self.mValue.mSharedList.as_ref()
.as_mut().expect("List pointer should be non-null").mHead.as_mut()
self.mValue
.mSharedList
.as_ref()
.as_mut()
.expect("List pointer should be non-null")
.mHead
.as_mut()
};
debug_assert!(list.is_some(), "New created shared list shouldn't be null");
for (item, new_value) in list.unwrap().into_iter().zip(values) {
@ -311,7 +327,7 @@ impl<'a> Iterator for nsCSSValueListIterator<'a> {
self.current = unsafe { item.mNext.as_ref() };
Some(&item.mValue)
},
None => None
None => None,
}
}
}
@ -321,7 +337,9 @@ impl<'a> IntoIterator for &'a nsCSSValueList {
type IntoIter = nsCSSValueListIterator<'a>;
fn into_iter(self) -> Self::IntoIter {
nsCSSValueListIterator { current: Some(self) }
nsCSSValueListIterator {
current: Some(self),
}
}
}
@ -340,7 +358,7 @@ impl<'a> Iterator for nsCSSValueListMutIterator<'a> {
self.current = item.mNext;
Some(&mut item.mValue)
},
None => None
None => None,
}
}
}
@ -350,8 +368,10 @@ impl<'a> IntoIterator for &'a mut nsCSSValueList {
type IntoIter = nsCSSValueListMutIterator<'a>;
fn into_iter(self) -> Self::IntoIter {
nsCSSValueListMutIterator { current: self as *mut nsCSSValueList,
phantom: PhantomData }
nsCSSValueListMutIterator {
current: self as *mut nsCSSValueList,
phantom: PhantomData,
}
}
}

View file

@ -8,7 +8,7 @@ use gecko_bindings::bindings::Gecko_EnsureStyleAnimationArrayLength;
use gecko_bindings::bindings::Gecko_EnsureStyleTransitionArrayLength;
use gecko_bindings::structs::{StyleAnimation, StyleTransition};
use gecko_bindings::structs::nsStyleAutoArray;
use std::iter::{once, Chain, Once, IntoIterator};
use std::iter::{once, Chain, IntoIterator, Once};
use std::ops::{Index, IndexMut};
use std::slice::{Iter, IterMut};
@ -55,7 +55,10 @@ impl nsStyleAutoArray<StyleAnimation> {
/// Ensures that the array has length at least the given length.
pub fn ensure_len(&mut self, len: usize) {
unsafe {
Gecko_EnsureStyleAnimationArrayLength(self as *mut nsStyleAutoArray<StyleAnimation> as *mut _, len);
Gecko_EnsureStyleAnimationArrayLength(
self as *mut nsStyleAutoArray<StyleAnimation> as *mut _,
len,
);
}
}
}
@ -64,7 +67,10 @@ impl nsStyleAutoArray<StyleTransition> {
/// Ensures that the array has length at least the given length.
pub fn ensure_len(&mut self, len: usize) {
unsafe {
Gecko_EnsureStyleTransitionArrayLength(self as *mut nsStyleAutoArray<StyleTransition> as *mut _, len);
Gecko_EnsureStyleTransitionArrayLength(
self as *mut nsStyleAutoArray<StyleTransition> as *mut _,
len,
);
}
}
}

View file

@ -6,7 +6,7 @@
use gecko_bindings::bindings;
use gecko_bindings::structs::{nsStyleCoord, nsStyleCoord_Calc, nsStyleCoord_CalcValue};
use gecko_bindings::structs::{nsStyleCorners, nsStyleUnit, nsStyleUnion, nsStyleSides, nscoord};
use gecko_bindings::structs::{nscoord, nsStyleCorners, nsStyleSides, nsStyleUnion, nsStyleUnit};
use std::mem;
impl nsStyleCoord {
@ -23,15 +23,11 @@ impl nsStyleCoord {
unsafe impl CoordData for nsStyleCoord {
#[inline]
fn unit(&self) -> nsStyleUnit {
unsafe {
*self.get_mUnit()
}
unsafe { *self.get_mUnit() }
}
#[inline]
fn union(&self) -> nsStyleUnion {
unsafe {
*self.get_mValue()
}
unsafe { *self.get_mValue() }
}
}
@ -56,8 +52,7 @@ impl nsStyleCoord_CalcValue {
impl PartialEq for nsStyleCoord_CalcValue {
fn eq(&self, other: &Self) -> bool {
self.mLength == other.mLength &&
self.mPercent == other.mPercent &&
self.mLength == other.mLength && self.mPercent == other.mPercent &&
self.mHasPercent == other.mHasPercent
}
}
@ -101,29 +96,21 @@ pub struct SidesDataMut<'a> {
unsafe impl<'a> CoordData for SidesData<'a> {
#[inline]
fn unit(&self) -> nsStyleUnit {
unsafe {
self.sides.get_mUnits()[self.index]
}
unsafe { self.sides.get_mUnits()[self.index] }
}
#[inline]
fn union(&self) -> nsStyleUnion {
unsafe {
self.sides.get_mValues()[self.index]
}
unsafe { self.sides.get_mValues()[self.index] }
}
}
unsafe impl<'a> CoordData for SidesDataMut<'a> {
#[inline]
fn unit(&self) -> nsStyleUnit {
unsafe {
self.sides.get_mUnits()[self.index]
}
unsafe { self.sides.get_mUnits()[self.index] }
}
#[inline]
fn union(&self) -> nsStyleUnion {
unsafe {
self.sides.get_mValues()[self.index]
}
unsafe { self.sides.get_mValues()[self.index] }
}
}
unsafe impl<'a> CoordDataMut for SidesDataMut<'a> {
@ -170,26 +157,18 @@ pub struct CornersDataMut<'a> {
unsafe impl<'a> CoordData for CornersData<'a> {
fn unit(&self) -> nsStyleUnit {
unsafe {
self.corners.get_mUnits()[self.index]
}
unsafe { self.corners.get_mUnits()[self.index] }
}
fn union(&self) -> nsStyleUnion {
unsafe {
self.corners.get_mValues()[self.index]
}
unsafe { self.corners.get_mValues()[self.index] }
}
}
unsafe impl<'a> CoordData for CornersDataMut<'a> {
fn unit(&self) -> nsStyleUnit {
unsafe {
self.corners.get_mUnits()[self.index]
}
unsafe { self.corners.get_mUnits()[self.index] }
}
fn union(&self) -> nsStyleUnion {
unsafe {
self.corners.get_mValues()[self.index]
}
unsafe { self.corners.get_mValues()[self.index] }
}
}
unsafe impl<'a> CoordDataMut for CornersDataMut<'a> {
@ -238,9 +217,8 @@ pub enum CoordDataValue {
Calc(nsStyleCoord_CalcValue),
}
/// A trait to abstract on top of a mutable `nsStyleCoord`-like object.
pub unsafe trait CoordDataMut : CoordData {
pub unsafe trait CoordDataMut: CoordData {
/// Get mutably the unit and the union.
///
/// This is unsafe since it's possible to modify the unit without changing
@ -313,63 +291,63 @@ pub unsafe trait CoordDataMut : CoordData {
Null => {
*unit = eStyleUnit_Null;
*union.mInt.as_mut() = 0;
}
},
Normal => {
*unit = eStyleUnit_Normal;
*union.mInt.as_mut() = 0;
}
},
Auto => {
*unit = eStyleUnit_Auto;
*union.mInt.as_mut() = 0;
}
},
None => {
*unit = eStyleUnit_None;
*union.mInt.as_mut() = 0;
}
},
Percent(f) => {
*unit = eStyleUnit_Percent;
*union.mFloat.as_mut() = f;
}
},
Factor(f) => {
*unit = eStyleUnit_Factor;
*union.mFloat.as_mut() = f;
}
},
Degree(f) => {
*unit = eStyleUnit_Degree;
*union.mFloat.as_mut() = f;
}
},
Grad(f) => {
*unit = eStyleUnit_Grad;
*union.mFloat.as_mut() = f;
}
},
Radian(f) => {
*unit = eStyleUnit_Radian;
*union.mFloat.as_mut() = f;
}
},
Turn(f) => {
*unit = eStyleUnit_Turn;
*union.mFloat.as_mut() = f;
}
},
FlexFraction(f) => {
*unit = eStyleUnit_FlexFraction;
*union.mFloat.as_mut() = f;
}
},
Coord(coord) => {
*unit = eStyleUnit_Coord;
*union.mInt.as_mut() = coord;
}
},
Integer(i) => {
*unit = eStyleUnit_Integer;
*union.mInt.as_mut() = i;
}
},
Enumerated(i) => {
*unit = eStyleUnit_Enumerated;
*union.mInt.as_mut() = i as i32;
}
},
Calc(calc) => {
// Gecko_SetStyleCoordCalcValue changes the unit internally
bindings::Gecko_SetStyleCoordCalcValue(unit, union, calc);
}
},
}
}
}
@ -400,7 +378,6 @@ pub unsafe trait CoordData {
/// Get the `nsStyleUnion` for this object.
fn union(&self) -> nsStyleUnion;
#[inline(always)]
/// Get the appropriate value for this object.
fn as_value(&self) -> CoordDataValue {
@ -431,10 +408,12 @@ pub unsafe trait CoordData {
/// Pretend inner value is a float; obtain it.
unsafe fn get_float(&self) -> f32 {
use gecko_bindings::structs::nsStyleUnit::*;
debug_assert!(self.unit() == eStyleUnit_Percent || self.unit() == eStyleUnit_Factor
|| self.unit() == eStyleUnit_Degree || self.unit() == eStyleUnit_Grad
|| self.unit() == eStyleUnit_Radian || self.unit() == eStyleUnit_Turn
|| self.unit() == eStyleUnit_FlexFraction);
debug_assert!(
self.unit() == eStyleUnit_Percent || self.unit() == eStyleUnit_Factor ||
self.unit() == eStyleUnit_Degree || self.unit() == eStyleUnit_Grad ||
self.unit() == eStyleUnit_Radian || self.unit() == eStyleUnit_Turn ||
self.unit() == eStyleUnit_FlexFraction
);
*self.union().mFloat.as_ref()
}
@ -442,8 +421,10 @@ pub unsafe trait CoordData {
/// Pretend inner value is an int; obtain it.
unsafe fn get_integer(&self) -> i32 {
use gecko_bindings::structs::nsStyleUnit::*;
debug_assert!(self.unit() == eStyleUnit_Coord || self.unit() == eStyleUnit_Integer
|| self.unit() == eStyleUnit_Enumerated);
debug_assert!(
self.unit() == eStyleUnit_Coord || self.unit() == eStyleUnit_Integer ||
self.unit() == eStyleUnit_Enumerated
);
*self.union().mInt.as_ref()
}
@ -455,7 +436,6 @@ pub unsafe trait CoordData {
(*self.as_calc())._base
}
#[inline]
/// Pretend the inner value is a calc expression, and obtain it.
unsafe fn as_calc(&self) -> &nsStyleCoord_Calc {

View file

@ -14,19 +14,13 @@ impl<T> Deref for nsTArray<T> {
type Target = [T];
fn deref<'a>(&'a self) -> &'a [T] {
unsafe {
slice::from_raw_parts(self.slice_begin(),
self.header().mLength as usize)
}
unsafe { slice::from_raw_parts(self.slice_begin(), self.header().mLength as usize) }
}
}
impl<T> DerefMut for nsTArray<T> {
fn deref_mut<'a>(&'a mut self) -> &'a mut [T] {
unsafe {
slice::from_raw_parts_mut(self.slice_begin(),
self.header().mLength as usize)
}
unsafe { slice::from_raw_parts_mut(self.slice_begin(), self.header().mLength as usize) }
}
}
@ -56,8 +50,11 @@ impl<T> nsTArray<T> {
pub fn ensure_capacity(&mut self, cap: usize) {
if cap >= self.len() {
unsafe {
bindings::Gecko_EnsureTArrayCapacity(self as *mut nsTArray<T> as *mut _,
cap, mem::size_of::<T>())
bindings::Gecko_EnsureTArrayCapacity(
self as *mut nsTArray<T> as *mut _,
cap,
mem::size_of::<T>(),
)
}
}
}
@ -66,17 +63,19 @@ impl<T> nsTArray<T> {
#[inline]
pub unsafe fn clear(&mut self) {
if self.len() != 0 {
bindings::Gecko_ClearPODTArray(self as *mut nsTArray<T> as *mut _,
mem::size_of::<T>(),
mem::align_of::<T>());
bindings::Gecko_ClearPODTArray(
self as *mut nsTArray<T> as *mut _,
mem::size_of::<T>(),
mem::align_of::<T>(),
);
}
}
/// Clears a POD array. This is safe since copy types are memcopyable.
#[inline]
pub fn clear_pod(&mut self)
where T: Copy
where
T: Copy,
{
unsafe { self.clear() }
}
@ -98,7 +97,10 @@ impl<T> nsTArray<T> {
/// Resizes an array containing only POD elements
///
/// This will not leak since it only works on POD types (and thus doesn't assert)
pub unsafe fn set_len_pod(&mut self, len: u32) where T: Copy {
pub unsafe fn set_len_pod(&mut self, len: u32)
where
T: Copy,
{
self.ensure_capacity(len as usize);
let header = self.header_mut();
header.mLength = len;

View file

@ -12,31 +12,41 @@ use values::specified::transform::TimingFunction;
impl nsTimingFunction {
fn set_as_step(&mut self, function_type: nsTimingFunction_Type, steps: u32) {
debug_assert!(function_type == nsTimingFunction_Type::StepStart ||
function_type == nsTimingFunction_Type::StepEnd,
"function_type should be step-start or step-end");
debug_assert!(
function_type == nsTimingFunction_Type::StepStart ||
function_type == nsTimingFunction_Type::StepEnd,
"function_type should be step-start or step-end"
);
self.mType = function_type;
unsafe {
self.__bindgen_anon_1.__bindgen_anon_1.as_mut().mStepsOrFrames = steps;
self.__bindgen_anon_1
.__bindgen_anon_1
.as_mut()
.mStepsOrFrames = steps;
}
}
fn set_as_frames(&mut self, frames: u32) {
self.mType = nsTimingFunction_Type::Frames;
unsafe {
self.__bindgen_anon_1.__bindgen_anon_1.as_mut().mStepsOrFrames = frames;
self.__bindgen_anon_1
.__bindgen_anon_1
.as_mut()
.mStepsOrFrames = frames;
}
}
fn set_as_bezier(
&mut self,
function_type: nsTimingFunction_Type,
x1: f32, y1: f32, x2: f32, y2: f32,
x1: f32,
y1: f32,
x2: f32,
y2: f32,
) {
self.mType = function_type;
unsafe {
let ref mut gecko_cubic_bezier =
self.__bindgen_anon_1.mFunc.as_mut();
let ref mut gecko_cubic_bezier = self.__bindgen_anon_1.mFunc.as_mut();
gecko_cubic_bezier.mX1 = x1;
gecko_cubic_bezier.mY1 = y1;
gecko_cubic_bezier.mX2 = x2;
@ -71,7 +81,10 @@ impl From<TimingFunction> for nsTimingFunction {
GenericTimingFunction::CubicBezier { x1, y1, x2, y2 } => {
tf.set_as_bezier(
nsTimingFunction_Type::CubicBezier,
x1.get(), y1.get(), x2.get(), y2.get(),
x1.get(),
y1.get(),
x2.get(),
y2.get(),
);
},
GenericTimingFunction::Keyword(keyword) => {
@ -86,43 +99,48 @@ impl From<TimingFunction> for nsTimingFunction {
impl From<nsTimingFunction> for ComputedTimingFunction {
fn from(function: nsTimingFunction) -> ComputedTimingFunction {
match function.mType {
nsTimingFunction_Type::StepStart => {
GenericTimingFunction::Steps(
unsafe { function.__bindgen_anon_1.__bindgen_anon_1.as_ref().mStepsOrFrames },
StepPosition::Start)
},
nsTimingFunction_Type::StepEnd => {
GenericTimingFunction::Steps(
unsafe { function.__bindgen_anon_1.__bindgen_anon_1.as_ref().mStepsOrFrames },
StepPosition::End)
},
nsTimingFunction_Type::Frames => {
GenericTimingFunction::Frames(
unsafe { function.__bindgen_anon_1.__bindgen_anon_1.as_ref().mStepsOrFrames })
}
nsTimingFunction_Type::Ease => {
GenericTimingFunction::Keyword(TimingKeyword::Ease)
},
nsTimingFunction_Type::Linear => {
GenericTimingFunction::Keyword(TimingKeyword::Linear)
},
nsTimingFunction_Type::EaseIn => {
GenericTimingFunction::Keyword(TimingKeyword::EaseIn)
},
nsTimingFunction_Type::StepStart => GenericTimingFunction::Steps(
unsafe {
function
.__bindgen_anon_1
.__bindgen_anon_1
.as_ref()
.mStepsOrFrames
},
StepPosition::Start,
),
nsTimingFunction_Type::StepEnd => GenericTimingFunction::Steps(
unsafe {
function
.__bindgen_anon_1
.__bindgen_anon_1
.as_ref()
.mStepsOrFrames
},
StepPosition::End,
),
nsTimingFunction_Type::Frames => GenericTimingFunction::Frames(unsafe {
function
.__bindgen_anon_1
.__bindgen_anon_1
.as_ref()
.mStepsOrFrames
}),
nsTimingFunction_Type::Ease => GenericTimingFunction::Keyword(TimingKeyword::Ease),
nsTimingFunction_Type::Linear => GenericTimingFunction::Keyword(TimingKeyword::Linear),
nsTimingFunction_Type::EaseIn => GenericTimingFunction::Keyword(TimingKeyword::EaseIn),
nsTimingFunction_Type::EaseOut => {
GenericTimingFunction::Keyword(TimingKeyword::EaseOut)
},
nsTimingFunction_Type::EaseInOut => {
GenericTimingFunction::Keyword(TimingKeyword::EaseInOut)
},
nsTimingFunction_Type::CubicBezier => {
unsafe {
GenericTimingFunction::CubicBezier {
x1: function.__bindgen_anon_1.mFunc.as_ref().mX1,
y1: function.__bindgen_anon_1.mFunc.as_ref().mY1,
x2: function.__bindgen_anon_1.mFunc.as_ref().mX2,
y2: function.__bindgen_anon_1.mFunc.as_ref().mY2,
}
nsTimingFunction_Type::CubicBezier => unsafe {
GenericTimingFunction::CubicBezier {
x1: function.__bindgen_anon_1.mFunc.as_ref().mX1,
y1: function.__bindgen_anon_1.mFunc.as_ref().mY1,
x2: function.__bindgen_anon_1.mFunc.as_ref().mX2,
y2: function.__bindgen_anon_1.mFunc.as_ref().mY2,
}
},
}

View file

@ -11,7 +11,7 @@ use std::ops::{Deref, DerefMut};
use std::ptr;
/// Indicates that a given Servo type has a corresponding Gecko FFI type.
pub unsafe trait HasFFI : Sized + 'static {
pub unsafe trait HasFFI: Sized + 'static {
/// The corresponding Gecko type that this rust type represents.
///
/// See the examples in `components/style/gecko/conversions.rs`.
@ -20,7 +20,7 @@ pub unsafe trait HasFFI : Sized + 'static {
/// Indicates that a given Servo type has the same layout as the corresponding
/// `HasFFI::FFIType` type.
pub unsafe trait HasSimpleFFI : HasFFI {
pub unsafe trait HasSimpleFFI: HasFFI {
#[inline]
/// Given a Servo-side reference, converts it to an FFI-safe reference which
/// can be passed to Gecko.
@ -57,7 +57,7 @@ pub unsafe trait HasSimpleFFI : HasFFI {
/// Indicates that the given Servo type is passed over FFI
/// as a Box
pub unsafe trait HasBoxFFI : HasSimpleFFI {
pub unsafe trait HasBoxFFI: HasSimpleFFI {
#[inline]
/// Converts a borrowed Arc to a borrowed FFI reference.
///
@ -73,7 +73,7 @@ pub unsafe trait HasBoxFFI : HasSimpleFFI {
/// and Borrowed.
///
/// In this case, the FFIType is the rough equivalent of ArcInner<Self>.
pub unsafe trait HasArcFFI : HasFFI {
pub unsafe trait HasArcFFI: HasFFI {
// these methods can't be on Borrowed because it leads to an unspecified
// impl parameter
/// Artificially increments the refcount of a (possibly null) borrowed Arc
@ -109,9 +109,7 @@ pub unsafe trait HasArcFFI : HasFFI {
///
/// &GeckoType -> &Arc<ServoType>
fn as_arc<'a>(ptr: &'a &Self::FFIType) -> &'a RawOffsetArc<Self> {
unsafe {
transmute::<&&Self::FFIType, &RawOffsetArc<Self>>(ptr)
}
unsafe { transmute::<&&Self::FFIType, &RawOffsetArc<Self>>(ptr) }
}
#[inline]
@ -119,9 +117,7 @@ pub unsafe trait HasArcFFI : HasFFI {
///
/// &Arc<ServoType> -> &GeckoType
fn arc_as_borrowed<'a>(arc: &'a RawOffsetArc<Self>) -> &'a &Self::FFIType {
unsafe {
transmute::<&RawOffsetArc<Self>, &&Self::FFIType>(arc)
}
unsafe { transmute::<&RawOffsetArc<Self>, &&Self::FFIType>(arc) }
}
#[inline]
@ -165,7 +161,8 @@ impl<GeckoType> Strong<GeckoType> {
///
/// Strong<GeckoType> -> Arc<ServoType>
pub fn into_arc<ServoType>(self) -> RawOffsetArc<ServoType>
where ServoType: HasArcFFI<FFIType = GeckoType>,
where
ServoType: HasArcFFI<FFIType = GeckoType>,
{
self.into_arc_opt().unwrap()
}
@ -177,7 +174,8 @@ impl<GeckoType> Strong<GeckoType> {
///
/// Strong<GeckoType> -> Arc<ServoType>
pub fn into_arc_opt<ServoType>(self) -> Option<RawOffsetArc<ServoType>>
where ServoType: HasArcFFI<FFIType = GeckoType>,
where
ServoType: HasArcFFI<FFIType = GeckoType>,
{
if self.is_null() {
None
@ -194,7 +192,8 @@ impl<GeckoType> Strong<GeckoType> {
///
/// Strong<GeckoType> -> Arc<ServoType>
pub fn as_arc_opt<ServoType>(&self) -> Option<&RawOffsetArc<ServoType>>
where ServoType: HasArcFFI<FFIType = GeckoType>,
where
ServoType: HasArcFFI<FFIType = GeckoType>,
{
if self.is_null() {
None
@ -271,7 +270,8 @@ pub struct Owned<GeckoType> {
impl<GeckoType> Owned<GeckoType> {
/// Gets this `Owned` type as a `Box<ServoType>`.
pub fn into_box<ServoType>(self) -> Box<ServoType>
where ServoType: HasBoxFFI<FFIType = GeckoType>,
where
ServoType: HasBoxFFI<FFIType = GeckoType>,
{
unsafe { transmute(self) }
}
@ -313,7 +313,8 @@ impl<GeckoType> OwnedOrNull<GeckoType> {
/// Returns an owned pointer if this is non-null, and `None` otherwise.
pub fn into_box_opt<ServoType>(self) -> Option<Box<ServoType>>
where ServoType: HasBoxFFI<FFIType = GeckoType>,
where
ServoType: HasBoxFFI<FFIType = GeckoType>,
{
if self.is_null() {
None

View file

@ -105,7 +105,9 @@ impl<T: RefCounted> RefPtr<T> {
/// Addref the inner data, obviously leaky on its own.
pub fn addref(&self) {
unsafe { (*self.ptr).addref(); }
unsafe {
(*self.ptr).addref();
}
}
/// Release the inner data.
@ -208,7 +210,9 @@ impl<T: RefCounted> structs::RefPtr<T> {
/// `self` must be valid, possibly null.
pub fn set_move(&mut self, other: RefPtr<T>) {
if !self.mRawPtr.is_null() {
unsafe { (*self.mRawPtr).release(); }
unsafe {
(*self.mRawPtr).release();
}
}
*self = other.forget();
}
@ -217,7 +221,10 @@ impl<T: RefCounted> structs::RefPtr<T> {
impl<T> structs::RefPtr<T> {
/// Sets the contents to an Arc<T>
/// will leak existing contents
pub fn set_arc_leaky<U>(&mut self, other: Arc<U>) where U: HasArcFFI<FFIType = T> {
pub fn set_arc_leaky<U>(&mut self, other: Arc<U>)
where
U: HasArcFFI<FFIType = T>,
{
*self = unsafe { mem::transmute(Arc::into_raw_offset(other)) };
}
}
@ -248,7 +255,7 @@ unsafe impl<T: ThreadSafeRefCounted> Send for RefPtr<T> {}
unsafe impl<T: ThreadSafeRefCounted> Sync for RefPtr<T> {}
macro_rules! impl_refcount {
($t:ty, $addref:ident, $release:ident) => (
($t:ty, $addref:ident, $release:ident) => {
unsafe impl RefCounted for $t {
fn addref(&self) {
unsafe { ::gecko_bindings::bindings::$addref(self as *const _ as *mut _) }
@ -257,38 +264,51 @@ macro_rules! impl_refcount {
::gecko_bindings::bindings::$release(self as *const _ as *mut _)
}
}
);
};
}
// Companion of NS_DECL_THREADSAFE_FFI_REFCOUNTING.
//
// Gets you a free RefCounted impl implemented via FFI.
macro_rules! impl_threadsafe_refcount {
($t:ty, $addref:ident, $release:ident) => (
($t:ty, $addref:ident, $release:ident) => {
impl_refcount!($t, $addref, $release);
unsafe impl ThreadSafeRefCounted for $t {}
);
};
}
impl_threadsafe_refcount!(::gecko_bindings::structs::RawGeckoURLExtraData,
Gecko_AddRefURLExtraDataArbitraryThread,
Gecko_ReleaseURLExtraDataArbitraryThread);
impl_threadsafe_refcount!(::gecko_bindings::structs::nsStyleQuoteValues,
Gecko_AddRefQuoteValuesArbitraryThread,
Gecko_ReleaseQuoteValuesArbitraryThread);
impl_threadsafe_refcount!(::gecko_bindings::structs::nsCSSValueSharedList,
Gecko_AddRefCSSValueSharedListArbitraryThread,
Gecko_ReleaseCSSValueSharedListArbitraryThread);
impl_threadsafe_refcount!(::gecko_bindings::structs::mozilla::css::URLValue,
Gecko_AddRefCSSURLValueArbitraryThread,
Gecko_ReleaseCSSURLValueArbitraryThread);
impl_threadsafe_refcount!(::gecko_bindings::structs::mozilla::css::GridTemplateAreasValue,
Gecko_AddRefGridTemplateAreasValueArbitraryThread,
Gecko_ReleaseGridTemplateAreasValueArbitraryThread);
impl_threadsafe_refcount!(::gecko_bindings::structs::ImageValue,
Gecko_AddRefImageValueArbitraryThread,
Gecko_ReleaseImageValueArbitraryThread);
impl_threadsafe_refcount!(::gecko_bindings::structs::SharedFontList,
Gecko_AddRefSharedFontListArbitraryThread,
Gecko_ReleaseSharedFontListArbitraryThread);
impl_threadsafe_refcount!(
::gecko_bindings::structs::RawGeckoURLExtraData,
Gecko_AddRefURLExtraDataArbitraryThread,
Gecko_ReleaseURLExtraDataArbitraryThread
);
impl_threadsafe_refcount!(
::gecko_bindings::structs::nsStyleQuoteValues,
Gecko_AddRefQuoteValuesArbitraryThread,
Gecko_ReleaseQuoteValuesArbitraryThread
);
impl_threadsafe_refcount!(
::gecko_bindings::structs::nsCSSValueSharedList,
Gecko_AddRefCSSValueSharedListArbitraryThread,
Gecko_ReleaseCSSValueSharedListArbitraryThread
);
impl_threadsafe_refcount!(
::gecko_bindings::structs::mozilla::css::URLValue,
Gecko_AddRefCSSURLValueArbitraryThread,
Gecko_ReleaseCSSURLValueArbitraryThread
);
impl_threadsafe_refcount!(
::gecko_bindings::structs::mozilla::css::GridTemplateAreasValue,
Gecko_AddRefGridTemplateAreasValueArbitraryThread,
Gecko_ReleaseGridTemplateAreasValueArbitraryThread
);
impl_threadsafe_refcount!(
::gecko_bindings::structs::ImageValue,
Gecko_AddRefImageValueArbitraryThread,
Gecko_ReleaseImageValueArbitraryThread
);
impl_threadsafe_refcount!(
::gecko_bindings::structs::SharedFontList,
Gecko_AddRefSharedFontListArbitraryThread,
Gecko_ReleaseSharedFontListArbitraryThread
);

View file

@ -14,7 +14,7 @@ use gecko_bindings::structs::{nsAtom, nsAtom_AtomKind, nsDynamicAtom, nsStaticAt
use nsstring::{nsAString, nsStr};
use precomputed_hash::PrecomputedHash;
use std::{mem, slice, str};
use std::borrow::{Cow, Borrow};
use std::borrow::{Borrow, Cow};
use std::char::{self, DecodeUtf16};
use std::fmt::{self, Write};
use std::hash::{Hash, Hasher};
@ -33,7 +33,9 @@ pub mod namespace;
pub use self::namespace::{Namespace, WeakNamespace};
macro_rules! local_name {
($s: tt) => { atom!($s) }
($s:tt) => {
atom!($s)
};
}
/// A strong reference to a Gecko atom.
@ -55,9 +57,7 @@ impl Deref for Atom {
#[inline]
fn deref(&self) -> &WeakAtom {
unsafe {
&*self.0
}
unsafe { &*self.0 }
}
}
@ -99,9 +99,7 @@ impl WeakAtom {
/// Clone this atom, bumping the refcount if the atom is not static.
#[inline]
pub fn clone(&self) -> Atom {
unsafe {
Atom::from_raw(self.as_ptr())
}
unsafe { Atom::from_raw(self.as_ptr()) }
}
/// Get the atom hash.
@ -114,16 +112,16 @@ impl WeakAtom {
#[inline]
pub fn as_slice(&self) -> &[u16] {
let string = if self.is_static() {
let atom_ptr = self.as_ptr() as *const nsStaticAtom;
let string_offset = unsafe { (*atom_ptr).mStringOffset };
let string_offset = -(string_offset as isize);
let u8_ptr = atom_ptr as *const u8;
// It is safe to use offset() here because both addresses are within
// the same struct, e.g. mozilla::detail::gGkAtoms.
unsafe { u8_ptr.offset(string_offset) as *const u16 }
let atom_ptr = self.as_ptr() as *const nsStaticAtom;
let string_offset = unsafe { (*atom_ptr).mStringOffset };
let string_offset = -(string_offset as isize);
let u8_ptr = atom_ptr as *const u8;
// It is safe to use offset() here because both addresses are within
// the same struct, e.g. mozilla::detail::gGkAtoms.
unsafe { u8_ptr.offset(string_offset) as *const u16 }
} else {
let atom_ptr = self.as_ptr() as *const nsDynamicAtom;
unsafe { (*(atom_ptr)).mString }
let atom_ptr = self.as_ptr() as *const nsDynamicAtom;
unsafe { (*(atom_ptr)).mString }
};
unsafe { slice::from_raw_parts(string, self.len() as usize) }
}
@ -139,7 +137,7 @@ impl WeakAtom {
/// pretty slow.
pub fn with_str<F, Output>(&self, cb: F) -> Output
where
F: FnOnce(&str) -> Output
F: FnOnce(&str) -> Output,
{
let mut buffer: [u8; 64] = unsafe { mem::uninitialized() };
@ -175,17 +173,13 @@ impl WeakAtom {
/// Returns whether this atom is static.
#[inline]
pub fn is_static(&self) -> bool {
unsafe {
(*self.as_ptr()).mKind() == nsAtom_AtomKind::Static as u32
}
unsafe { (*self.as_ptr()).mKind() == nsAtom_AtomKind::Static as u32 }
}
/// Returns the length of the atom string.
#[inline]
pub fn len(&self) -> u32 {
unsafe {
(*self.as_ptr()).mLength()
}
unsafe { (*self.as_ptr()).mLength() }
}
/// Returns whether this atom is the empty string.
@ -204,7 +198,10 @@ impl WeakAtom {
/// Convert this atom to ASCII lower-case
pub fn to_ascii_lowercase(&self) -> Atom {
let slice = self.as_slice();
match slice.iter().position(|&char16| (b'A' as u16) <= char16 && char16 <= (b'Z' as u16)) {
match slice
.iter()
.position(|&char16| (b'A' as u16) <= char16 && char16 <= (b'Z' as u16))
{
None => self.clone(),
Some(i) => {
let mut buffer: [u16; 64] = unsafe { mem::uninitialized() };
@ -222,7 +219,7 @@ impl WeakAtom {
}
}
Atom::from(&*mutable_slice)
}
},
}
}
@ -245,8 +242,9 @@ impl WeakAtom {
/// Return whether this atom is an ASCII-case-insensitive match for the given string
pub fn eq_str_ignore_ascii_case(&self, other: &str) -> bool {
self.chars().map(|r| r.map(|c: char| c.to_ascii_lowercase()))
.eq(other.chars().map(|c: char| Ok(c.to_ascii_lowercase())))
self.chars()
.map(|r| r.map(|c: char| c.to_ascii_lowercase()))
.eq(other.chars().map(|c: char| Ok(c.to_ascii_lowercase())))
}
}
@ -267,7 +265,10 @@ impl fmt::Display for WeakAtom {
impl Atom {
/// Execute a callback with the atom represented by `ptr`.
pub unsafe fn with<F, R>(ptr: *mut nsAtom, callback: F) -> R where F: FnOnce(&Atom) -> R {
pub unsafe fn with<F, R>(ptr: *mut nsAtom, callback: F) -> R
where
F: FnOnce(&Atom) -> R,
{
let atom = Atom(WeakAtom::new(ptr));
let ret = callback(&atom);
mem::forget(atom);
@ -283,8 +284,10 @@ impl Atom {
#[inline]
pub unsafe fn from_static(ptr: *mut nsStaticAtom) -> Self {
let atom = Atom(ptr as *mut WeakAtom);
debug_assert!(atom.is_static(),
"Called from_static for a non-static atom!");
debug_assert!(
atom.is_static(),
"Called from_static for a non-static atom!"
);
atom
}
@ -316,13 +319,19 @@ impl Atom {
}
impl Hash for Atom {
fn hash<H>(&self, state: &mut H) where H: Hasher {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
state.write_u32(self.get_hash());
}
}
impl Hash for WeakAtom {
fn hash<H>(&self, state: &mut H) where H: Hasher {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
state.write_u32(self.get_hash());
}
}
@ -330,9 +339,7 @@ impl Hash for WeakAtom {
impl Clone for Atom {
#[inline(always)]
fn clone(&self) -> Atom {
unsafe {
Atom::from_raw(self.as_ptr())
}
unsafe { Atom::from_raw(self.as_ptr()) }
}
}
@ -362,9 +369,7 @@ impl fmt::Debug for Atom {
impl fmt::Display for Atom {
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
unsafe {
(&*self.0).fmt(w)
}
unsafe { (&*self.0).fmt(w) }
}
}
@ -373,9 +378,10 @@ impl<'a> From<&'a str> for Atom {
fn from(string: &str) -> Atom {
debug_assert!(string.len() <= u32::max_value() as usize);
unsafe {
Atom(WeakAtom::new(
Gecko_Atomize(string.as_ptr() as *const _, string.len() as u32)
))
Atom(WeakAtom::new(Gecko_Atomize(
string.as_ptr() as *const _,
string.len() as u32,
)))
}
}
}
@ -390,11 +396,7 @@ impl<'a> From<&'a [u16]> for Atom {
impl<'a> From<&'a nsAString> for Atom {
#[inline]
fn from(string: &nsAString) -> Atom {
unsafe {
Atom(WeakAtom::new(
Gecko_Atomize16(string)
))
}
unsafe { Atom(WeakAtom::new(Gecko_Atomize16(string))) }
}
}

View file

@ -13,8 +13,12 @@ use string_cache::{Atom, WeakAtom};
#[macro_export]
macro_rules! ns {
() => { $crate::string_cache::Namespace(atom!("")) };
($s: tt) => { $crate::string_cache::Namespace(atom!($s)) };
() => {
$crate::string_cache::Namespace(atom!(""))
};
($s:tt) => {
$crate::string_cache::Namespace(atom!($s))
};
}
/// A Gecko namespace is just a wrapped atom.
@ -41,16 +45,13 @@ impl Deref for WeakNamespace {
}
}
impl Deref for Namespace {
type Target = WeakNamespace;
#[inline]
fn deref(&self) -> &WeakNamespace {
let weak: *const WeakAtom = &*self.0;
unsafe {
&*(weak as *const WeakNamespace)
}
unsafe { &*(weak as *const WeakNamespace) }
}
}

View file

@ -17,7 +17,6 @@ pub use hashglobe::hash_set::HashSet;
#[cfg(feature = "servo")]
pub use hashglobe::fake::{HashMap, HashSet};
/// Appropriate reexports of hash_map types
pub mod map {
#[cfg(feature = "gecko")]

View file

@ -42,11 +42,7 @@ pub struct DocumentStateInvalidationProcessor<'a, E: TElement, I> {
impl<'a, E: TElement, I> DocumentStateInvalidationProcessor<'a, E, I> {
/// Creates a new DocumentStateInvalidationProcessor.
#[inline]
pub fn new(
rules: I,
document_states_changed: DocumentState,
quirks_mode: QuirksMode,
) -> Self {
pub fn new(rules: I, document_states_changed: DocumentState, quirks_mode: QuirksMode) -> Self {
let mut matching_context = MatchingContext::new_for_visited(
MatchingMode::Normal,
None,
@ -59,7 +55,11 @@ impl<'a, E: TElement, I> DocumentStateInvalidationProcessor<'a, E, I> {
document_state: document_states_changed,
};
Self { rules, document_states_changed, matching_context }
Self {
rules,
document_states_changed,
matching_context,
}
}
}

View file

@ -36,7 +36,7 @@ use std::fmt;
/// still need to take the ElementWrapper approach for attribute-dependent
/// style. So we do it the same both ways for now to reduce complexity, but it's
/// worth measuring the performance impact (if any) of the mStateMask approach.
pub trait ElementSnapshot : Sized {
pub trait ElementSnapshot: Sized {
/// The state of the snapshot, if any.
fn state(&self) -> Option<ElementState>;
@ -158,7 +158,7 @@ where
_setter: &mut F,
) -> bool
where
F: FnMut(&Self, ElementSelectorFlags),
F: FnMut(&Self, ElementSelectorFlags),
{
// Some pseudo-classes need special handling to evaluate them against
// the snapshot.
@ -167,11 +167,11 @@ where
NonTSPseudoClass::MozAny(ref selectors) => {
use selectors::matching::matches_complex_selector;
return context.nest(|context| {
selectors.iter().any(|s| {
matches_complex_selector(s.iter(), self, context, _setter)
})
selectors
.iter()
.any(|s| matches_complex_selector(s.iter(), self, context, _setter))
});
}
},
// :dir is implemented in terms of state flags, but which state flag
// it maps to depends on the argument to :dir. That means we can't
@ -194,7 +194,7 @@ where
None => self.element.state(),
};
return state.contains(selector_flag);
}
},
// For :link and :visited, we don't actually want to test the
// element state directly.
@ -203,10 +203,10 @@ where
// match.
NonTSPseudoClass::Link => {
return self.is_link() && context.visited_handling().matches_unvisited()
}
},
NonTSPseudoClass::Visited => {
return self.is_link() && context.visited_handling().matches_visited()
}
},
#[cfg(feature = "gecko")]
NonTSPseudoClass::MozTableBorderNonzero => {
@ -215,7 +215,7 @@ where
return snapshot.mIsTableBorderNonzero();
}
}
}
},
#[cfg(feature = "gecko")]
NonTSPseudoClass::MozBrowserFrame => {
@ -224,34 +224,27 @@ where
return snapshot.mIsMozBrowserFrame();
}
}
}
},
// :lang() needs to match using the closest ancestor xml:lang="" or
// lang="" attribtue from snapshots.
NonTSPseudoClass::Lang(ref lang_arg) => {
return self.element.match_element_lang(Some(self.get_lang()), lang_arg);
}
return self.element
.match_element_lang(Some(self.get_lang()), lang_arg);
},
_ => {}
_ => {},
}
let flag = pseudo_class.state_flag();
if flag.is_empty() {
return self.element.match_non_ts_pseudo_class(
pseudo_class,
context,
&mut |_, _| {},
)
return self.element
.match_non_ts_pseudo_class(pseudo_class, context, &mut |_, _| {});
}
match self.snapshot().and_then(|s| s.state()) {
Some(snapshot_state) => snapshot_state.intersects(flag),
None => {
self.element.match_non_ts_pseudo_class(
pseudo_class,
context,
&mut |_, _| {},
)
}
None => self.element
.match_non_ts_pseudo_class(pseudo_class, context, &mut |_, _| {}),
}
}
@ -334,26 +327,24 @@ where
match self.snapshot() {
Some(snapshot) if snapshot.has_attrs() => {
snapshot.attr_matches(ns, local_name, operation)
}
_ => self.element.attr_matches(ns, local_name, operation)
},
_ => self.element.attr_matches(ns, local_name, operation),
}
}
fn has_id(&self, id: &Atom, case_sensitivity: CaseSensitivity) -> bool {
match self.snapshot() {
Some(snapshot) if snapshot.has_attrs() => {
snapshot.id_attr().map_or(false, |atom| case_sensitivity.eq_atom(&atom, id))
}
_ => self.element.has_id(id, case_sensitivity)
Some(snapshot) if snapshot.has_attrs() => snapshot
.id_attr()
.map_or(false, |atom| case_sensitivity.eq_atom(&atom, id)),
_ => self.element.has_id(id, case_sensitivity),
}
}
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
match self.snapshot() {
Some(snapshot) if snapshot.has_attrs() => {
snapshot.has_class(name, case_sensitivity)
}
_ => self.element.has_class(name, case_sensitivity)
Some(snapshot) if snapshot.has_attrs() => snapshot.has_class(name, case_sensitivity),
_ => self.element.has_class(name, case_sensitivity),
}
}
@ -366,12 +357,14 @@ where
}
fn pseudo_element_originating_element(&self) -> Option<Self> {
self.element.pseudo_element_originating_element()
self.element
.pseudo_element_originating_element()
.map(|e| ElementWrapper::new(e, self.snapshot_map))
}
fn assigned_slot(&self) -> Option<Self> {
self.element.assigned_slot()
self.element
.assigned_slot()
.map(|e| ElementWrapper::new(e, self.snapshot_map))
}

View file

@ -92,17 +92,22 @@ impl Dependency {
return None;
}
Some(self.selector.combinator_at_match_order(self.selector_offset - 1))
Some(
self.selector
.combinator_at_match_order(self.selector_offset - 1),
)
}
/// The kind of invalidation that this would generate.
pub fn invalidation_kind(&self) -> DependencyInvalidationKind {
match self.combinator() {
None => DependencyInvalidationKind::Element,
Some(Combinator::Child) |
Some(Combinator::Descendant) => DependencyInvalidationKind::Descendants,
Some(Combinator::LaterSibling) |
Some(Combinator::NextSibling) => DependencyInvalidationKind::Siblings,
Some(Combinator::Child) | Some(Combinator::Descendant) => {
DependencyInvalidationKind::Descendants
},
Some(Combinator::LaterSibling) | Some(Combinator::NextSibling) => {
DependencyInvalidationKind::Siblings
},
// TODO(emilio): We could look at the selector itself to see if it's
// an eager pseudo, and return only Descendants here if not.
Some(Combinator::PseudoElement) => DependencyInvalidationKind::ElementAndDescendants,
@ -196,15 +201,14 @@ impl InvalidationMap {
/// Returns the number of dependencies stored in the invalidation map.
pub fn len(&self) -> usize {
self.state_affecting_selectors.len() +
self.document_state_selectors.len() +
self.other_attribute_affecting_selectors.len() +
self.id_to_selector.iter().fold(0, |accum, (_, ref v)| {
accum + v.len()
}) +
self.class_to_selector.iter().fold(0, |accum, (_, ref v)| {
accum + v.len()
})
self.state_affecting_selectors.len() + self.document_state_selectors.len() +
self.other_attribute_affecting_selectors.len() +
self.id_to_selector
.iter()
.fold(0, |accum, (_, ref v)| accum + v.len()) +
self.class_to_selector
.iter()
.fold(0, |accum, (_, ref v)| accum + v.len())
}
/// Clears this map, leaving it empty.
@ -283,22 +287,26 @@ impl InvalidationMap {
}
if !compound_visitor.state.is_empty() {
self.state_affecting_selectors
.insert(StateDependency {
self.state_affecting_selectors.insert(
StateDependency {
dep: Dependency {
selector: selector.clone(),
selector_offset: sequence_start,
},
state: compound_visitor.state,
}, quirks_mode)?;
},
quirks_mode,
)?;
}
if compound_visitor.other_attributes {
self.other_attribute_affecting_selectors
.insert(Dependency {
self.other_attribute_affecting_selectors.insert(
Dependency {
selector: selector.clone(),
selector_offset: sequence_start,
}, quirks_mode)?;
},
quirks_mode,
)?;
}
combinator = iter.next_sequence();
@ -310,10 +318,11 @@ impl InvalidationMap {
}
if !document_state.is_empty() {
self.document_state_selectors.try_push(DocumentStateDependency {
state: document_state,
selector: selector.clone(),
})?;
self.document_state_selectors
.try_push(DocumentStateDependency {
state: document_state,
selector: selector.clone(),
})?;
}
Ok(())
@ -365,22 +374,20 @@ impl<'a> SelectorVisitor for CompoundSelectorDependencyCollector<'a> {
match *s {
Component::ID(ref id) => {
self.ids.push(id.clone());
}
},
Component::Class(ref class) => {
self.classes.push(class.clone());
}
},
Component::NonTSPseudoClass(ref pc) => {
self.other_attributes |= pc.is_attr_based();
self.state |= match *pc {
#[cfg(feature = "gecko")]
NonTSPseudoClass::Dir(ref dir) => {
dir_selector_to_state(dir)
}
NonTSPseudoClass::Dir(ref dir) => dir_selector_to_state(dir),
_ => pc.state_flag(),
};
*self.document_state |= pc.document_state_flag();
}
_ => {}
},
_ => {},
}
true

View file

@ -22,12 +22,16 @@ where
/// Whether an invalidation that contains only an eager pseudo-element
/// selector like ::before or ::after triggers invalidation of the element
/// that would originate it.
fn invalidates_on_eager_pseudo_element(&self) -> bool { false }
fn invalidates_on_eager_pseudo_element(&self) -> bool {
false
}
/// Whether the invalidation processor only cares about light-tree
/// descendants of a given element, that is, doesn't invalidate
/// pseudo-elements, NAC, or XBL anon content.
fn light_tree_only(&self) -> bool { false }
fn light_tree_only(&self) -> bool {
false
}
/// The matching context that should be used to process invalidations.
fn matching_context(&mut self) -> &mut MatchingContext<'a, E::Impl>;
@ -72,8 +76,7 @@ pub struct DescendantInvalidationLists<'a> {
impl<'a> DescendantInvalidationLists<'a> {
fn is_empty(&self) -> bool {
self.dom_descendants.is_empty() &&
self.slotted_descendants.is_empty()
self.dom_descendants.is_empty() && self.slotted_descendants.is_empty()
}
}
@ -88,7 +91,7 @@ where
element: E,
stack_limit_checker: Option<&'a StackLimitChecker>,
processor: &'a mut P,
_marker: ::std::marker::PhantomData<&'b ()>
_marker: ::std::marker::PhantomData<&'b ()>,
}
/// A vector of invalidations, optimized for small invalidation sets.
@ -154,12 +157,8 @@ impl<'a> Invalidation<'a> {
//
// We should be able to do better here!
match self.selector.combinator_at_parse_order(self.offset - 1) {
Combinator::Descendant |
Combinator::LaterSibling |
Combinator::PseudoElement => true,
Combinator::SlotAssignment |
Combinator::NextSibling |
Combinator::Child => false,
Combinator::Descendant | Combinator::LaterSibling | Combinator::PseudoElement => true,
Combinator::SlotAssignment | Combinator::NextSibling | Combinator::Child => false,
}
}
@ -169,12 +168,13 @@ impl<'a> Invalidation<'a> {
}
match self.selector.combinator_at_parse_order(self.offset - 1) {
Combinator::Child |
Combinator::Descendant |
Combinator::PseudoElement => InvalidationKind::Descendant(DescendantInvalidationKind::Dom),
Combinator::SlotAssignment => InvalidationKind::Descendant(DescendantInvalidationKind::Slotted),
Combinator::NextSibling |
Combinator::LaterSibling => InvalidationKind::Sibling,
Combinator::Child | Combinator::Descendant | Combinator::PseudoElement => {
InvalidationKind::Descendant(DescendantInvalidationKind::Dom)
},
Combinator::SlotAssignment => {
InvalidationKind::Descendant(DescendantInvalidationKind::Slotted)
},
Combinator::NextSibling | Combinator::LaterSibling => InvalidationKind::Sibling,
}
}
}
@ -275,9 +275,17 @@ where
);
debug!("Collected invalidations (self: {}): ", invalidated_self);
debug!(" > self: {}, {:?}", self_invalidations.len(), self_invalidations);
debug!(
" > self: {}, {:?}",
self_invalidations.len(),
self_invalidations
);
debug!(" > descendants: {:?}", descendant_invalidations);
debug!(" > siblings: {}, {:?}", sibling_invalidations.len(), sibling_invalidations);
debug!(
" > siblings: {}, {:?}",
sibling_invalidations.len(),
sibling_invalidations
);
let invalidated_self_from_collection = invalidated_self;
@ -307,10 +315,7 @@ where
///
/// Returns whether any sibling's style or any sibling descendant's style
/// was invalidated.
fn invalidate_siblings(
&mut self,
sibling_invalidations: &mut InvalidationVector<'b>,
) -> bool {
fn invalidate_siblings(&mut self, sibling_invalidations: &mut InvalidationVector<'b>) -> bool {
if sibling_invalidations.is_empty() {
return false;
}
@ -319,19 +324,14 @@ where
let mut any_invalidated = false;
while let Some(sibling) = current {
let mut sibling_invalidator = TreeStyleInvalidator::new(
sibling,
self.stack_limit_checker,
self.processor,
);
let mut sibling_invalidator =
TreeStyleInvalidator::new(sibling, self.stack_limit_checker, self.processor);
let mut invalidations_for_descendants =
DescendantInvalidationLists::default();
let invalidated_sibling =
sibling_invalidator.process_sibling_invalidations(
&mut invalidations_for_descendants,
sibling_invalidations,
);
let mut invalidations_for_descendants = DescendantInvalidationLists::default();
let invalidated_sibling = sibling_invalidator.process_sibling_invalidations(
&mut invalidations_for_descendants,
sibling_invalidations,
);
if invalidated_sibling {
sibling_invalidator.processor.invalidated_self(sibling);
@ -340,9 +340,7 @@ where
any_invalidated |= invalidated_sibling;
any_invalidated |=
sibling_invalidator.invalidate_descendants(
&invalidations_for_descendants,
);
sibling_invalidator.invalidate_descendants(&invalidations_for_descendants);
if sibling_invalidations.is_empty() {
break;
@ -387,38 +385,30 @@ where
sibling_invalidations: &mut InvalidationVector<'b>,
descendant_invalidation_kind: DescendantInvalidationKind,
) -> bool {
let mut invalidations_for_descendants =
DescendantInvalidationLists::default();
let mut invalidations_for_descendants = DescendantInvalidationLists::default();
let mut invalidated_child = false;
let invalidated_descendants = {
let mut child_invalidator = TreeStyleInvalidator::new(
child,
self.stack_limit_checker,
self.processor,
let mut child_invalidator =
TreeStyleInvalidator::new(child, self.stack_limit_checker, self.processor);
invalidated_child |= child_invalidator.process_sibling_invalidations(
&mut invalidations_for_descendants,
sibling_invalidations,
);
invalidated_child |=
child_invalidator.process_sibling_invalidations(
&mut invalidations_for_descendants,
sibling_invalidations,
);
invalidated_child |=
child_invalidator.process_descendant_invalidations(
invalidations,
&mut invalidations_for_descendants,
sibling_invalidations,
descendant_invalidation_kind,
);
invalidated_child |= child_invalidator.process_descendant_invalidations(
invalidations,
&mut invalidations_for_descendants,
sibling_invalidations,
descendant_invalidation_kind,
);
if invalidated_child {
child_invalidator.processor.invalidated_self(child);
}
child_invalidator.invalidate_descendants(
&invalidations_for_descendants,
)
child_invalidator.invalidate_descendants(&invalidations_for_descendants)
};
// The child may not be a flattened tree child of the current element,
@ -433,16 +423,12 @@ where
invalidated_child || invalidated_descendants
}
fn invalidate_nac(
&mut self,
invalidations: &[Invalidation<'b>],
) -> bool {
fn invalidate_nac(&mut self, invalidations: &[Invalidation<'b>]) -> bool {
let mut any_nac_root = false;
let element = self.element;
element.each_anonymous_content_child(|nac| {
any_nac_root |=
self.invalidate_pseudo_element_or_nac(nac, invalidations);
any_nac_root |= self.invalidate_pseudo_element_or_nac(nac, invalidations);
});
any_nac_root
@ -480,10 +466,7 @@ where
any_descendant
}
fn invalidate_slotted_elements(
&mut self,
invalidations: &[Invalidation<'b>],
) -> bool {
fn invalidate_slotted_elements(&mut self, invalidations: &[Invalidation<'b>]) -> bool {
if invalidations.is_empty() {
return false;
}
@ -519,10 +502,7 @@ where
any
}
fn invalidate_non_slotted_descendants(
&mut self,
invalidations: &[Invalidation<'b>],
) -> bool {
fn invalidate_non_slotted_descendants(&mut self, invalidations: &[Invalidation<'b>]) -> bool {
if invalidations.is_empty() {
return false;
}
@ -543,30 +523,25 @@ where
// where we rely on iterating every element that ends up in the composed
// doc, but we could fix that invalidating per subtree.
if let Some(root) = self.element.shadow_root() {
any_descendant |=
self.invalidate_dom_descendants_of(root.as_node(), invalidations);
any_descendant |= self.invalidate_dom_descendants_of(root.as_node(), invalidations);
}
// This is needed for XBL (technically) unconditionally, because XBL
// bindings do not block combinators in any way. However this is kinda
// broken anyway, since we should be looking at XBL rules too.
if let Some(anon_content) = self.element.xbl_binding_anonymous_content() {
any_descendant |=
self.invalidate_dom_descendants_of(anon_content, invalidations);
any_descendant |= self.invalidate_dom_descendants_of(anon_content, invalidations);
}
if let Some(before) = self.element.before_pseudo_element() {
any_descendant |=
self.invalidate_pseudo_element_or_nac(before, invalidations);
any_descendant |= self.invalidate_pseudo_element_or_nac(before, invalidations);
}
let node = self.element.as_node();
any_descendant |=
self.invalidate_dom_descendants_of(node, invalidations);
any_descendant |= self.invalidate_dom_descendants_of(node, invalidations);
if let Some(after) = self.element.after_pseudo_element() {
any_descendant |=
self.invalidate_pseudo_element_or_nac(after, invalidations);
any_descendant |= self.invalidate_pseudo_element_or_nac(after, invalidations);
}
any_descendant |= self.invalidate_nac(invalidations);
@ -576,20 +551,18 @@ where
/// Given the descendant invalidation lists, go through the current
/// element's descendants, and invalidate style on them.
fn invalidate_descendants(
&mut self,
invalidations: &DescendantInvalidationLists<'b>,
) -> bool {
fn invalidate_descendants(&mut self, invalidations: &DescendantInvalidationLists<'b>) -> bool {
if invalidations.is_empty() {
return false;
}
debug!("StyleTreeInvalidator::invalidate_descendants({:?})",
self.element);
debug!(
"StyleTreeInvalidator::invalidate_descendants({:?})",
self.element
);
debug!(" > {:?}", invalidations);
let should_process =
self.processor.should_process_descendants(self.element);
let should_process = self.processor.should_process_descendants(self.element);
if !should_process {
return false;
@ -604,10 +577,8 @@ where
let mut any_descendant = false;
any_descendant |=
self.invalidate_non_slotted_descendants(&invalidations.dom_descendants);
any_descendant |=
self.invalidate_slotted_elements(&invalidations.slotted_descendants);
any_descendant |= self.invalidate_non_slotted_descendants(&invalidations.dom_descendants);
any_descendant |= self.invalidate_slotted_elements(&invalidations.slotted_descendants);
any_descendant
}
@ -704,14 +675,16 @@ where
sibling_invalidations: &mut InvalidationVector<'b>,
invalidation_kind: InvalidationKind,
) -> SingleInvalidationResult {
debug!("TreeStyleInvalidator::process_invalidation({:?}, {:?}, {:?})",
self.element, invalidation, invalidation_kind);
debug!(
"TreeStyleInvalidator::process_invalidation({:?}, {:?}, {:?})",
self.element, invalidation, invalidation_kind
);
let matching_result = matches_compound_selector_from(
&invalidation.selector,
invalidation.offset,
self.processor.matching_context(),
&self.element
&self.element,
);
let mut invalidated_self = false;
@ -721,34 +694,33 @@ where
debug!(" > Invalidation matched completely");
matched = true;
invalidated_self = true;
}
CompoundSelectorMatchingResult::Matched { next_combinator_offset } => {
let next_combinator =
invalidation.selector.combinator_at_parse_order(next_combinator_offset);
},
CompoundSelectorMatchingResult::Matched {
next_combinator_offset,
} => {
let next_combinator = invalidation
.selector
.combinator_at_parse_order(next_combinator_offset);
matched = true;
if matches!(next_combinator, Combinator::PseudoElement) {
// This will usually be the very next component, except for
// the fact that we store compound selectors the other way
// around, so there could also be state pseudo-classes.
let pseudo_selector =
invalidation.selector
.iter_raw_parse_order_from(next_combinator_offset + 1)
.skip_while(|c| matches!(**c, Component::NonTSPseudoClass(..)))
.next()
.unwrap();
let pseudo_selector = invalidation
.selector
.iter_raw_parse_order_from(next_combinator_offset + 1)
.skip_while(|c| matches!(**c, Component::NonTSPseudoClass(..)))
.next()
.unwrap();
let pseudo = match *pseudo_selector {
Component::PseudoElement(ref pseudo) => pseudo,
_ => {
unreachable!(
"Someone seriously messed up selector parsing: \
{:?} at offset {:?}: {:?}",
invalidation.selector,
next_combinator_offset,
pseudo_selector,
)
}
_ => unreachable!(
"Someone seriously messed up selector parsing: \
{:?} at offset {:?}: {:?}",
invalidation.selector, next_combinator_offset, pseudo_selector,
),
};
// FIXME(emilio): This is not ideal, and could not be
@ -765,21 +737,21 @@ where
//
// Note that we'll also restyle the pseudo-element because
// it would match this invalidation.
if self.processor.invalidates_on_eager_pseudo_element() &&
pseudo.is_eager() {
if self.processor.invalidates_on_eager_pseudo_element() && pseudo.is_eager() {
invalidated_self = true;
}
}
let next_invalidation = Invalidation {
selector: invalidation.selector,
offset: next_combinator_offset + 1,
matched_by_any_previous: false,
};
debug!(" > Invalidation matched, next: {:?}, ({:?})",
next_invalidation, next_combinator);
debug!(
" > Invalidation matched, next: {:?}, ({:?})",
next_invalidation, next_combinator
);
let next_invalidation_kind = next_invalidation.kind();
@ -842,32 +814,39 @@ where
//
// [div div div, div div, div]
//
let can_skip_pushing =
next_invalidation_kind == invalidation_kind &&
let can_skip_pushing = next_invalidation_kind == invalidation_kind &&
invalidation.matched_by_any_previous &&
next_invalidation.effective_for_next();
if can_skip_pushing {
debug!(" > Can avoid push, since the invalidation had \
already been matched before");
debug!(
" > Can avoid push, since the invalidation had \
already been matched before"
);
} else {
match next_invalidation_kind {
InvalidationKind::Descendant(DescendantInvalidationKind::Dom) => {
descendant_invalidations.dom_descendants.push(next_invalidation);
}
descendant_invalidations
.dom_descendants
.push(next_invalidation);
},
InvalidationKind::Descendant(DescendantInvalidationKind::Slotted) => {
descendant_invalidations.slotted_descendants.push(next_invalidation);
}
descendant_invalidations
.slotted_descendants
.push(next_invalidation);
},
InvalidationKind::Sibling => {
sibling_invalidations.push(next_invalidation);
}
},
}
}
}
CompoundSelectorMatchingResult::NotMatched => {}
},
CompoundSelectorMatchingResult::NotMatched => {},
}
SingleInvalidationResult { invalidated_self, matched, }
SingleInvalidationResult {
invalidated_self,
matched,
}
}
}

View file

@ -67,9 +67,8 @@ impl RestyleHint {
/// Returns whether we need to restyle this element.
pub fn has_non_animation_invalidations(&self) -> bool {
self.intersects(
RestyleHint::RESTYLE_SELF |
RestyleHint::RECASCADE_SELF |
(Self::replacements() & !Self::for_animations())
RestyleHint::RESTYLE_SELF | RestyleHint::RECASCADE_SELF |
(Self::replacements() & !Self::for_animations()),
)
}
@ -84,23 +83,24 @@ impl RestyleHint {
return Self::empty();
}
debug_assert!(!self.has_animation_hint(),
"There should not be any animation restyle hints \
during normal traversal");
debug_assert!(
!self.has_animation_hint(),
"There should not be any animation restyle hints \
during normal traversal"
);
// Else we should clear ourselves, and return the propagated hint.
mem::replace(self, Self::empty())
.propagate_for_non_animation_restyle()
mem::replace(self, Self::empty()).propagate_for_non_animation_restyle()
}
/// Returns a new `CascadeHint` appropriate for children of the current
/// element.
fn propagate_for_non_animation_restyle(&self) -> Self {
if self.contains(RestyleHint::RESTYLE_DESCENDANTS) {
return Self::restyle_subtree()
return Self::restyle_subtree();
}
if self.contains(RestyleHint::RECASCADE_DESCENDANTS) {
return Self::recascade_subtree()
return Self::recascade_subtree();
}
Self::empty()
}
@ -119,7 +119,8 @@ impl RestyleHint {
/// The replacements for the animation cascade levels.
#[inline]
pub fn for_animations() -> Self {
RestyleHint::RESTYLE_SMIL | RestyleHint::RESTYLE_CSS_ANIMATIONS | RestyleHint::RESTYLE_CSS_TRANSITIONS
RestyleHint::RESTYLE_SMIL | RestyleHint::RESTYLE_CSS_ANIMATIONS |
RestyleHint::RESTYLE_CSS_TRANSITIONS
}
/// Returns whether the hint specifies that the currently element must be
@ -199,8 +200,10 @@ impl From<nsRestyleHint> for RestyleHint {
let mut hint = RestyleHint::empty();
debug_assert!(raw.0 & eRestyle_LaterSiblings.0 == 0,
"Handle later siblings manually if necessary plz.");
debug_assert!(
raw.0 & eRestyle_LaterSiblings.0 == 0,
"Handle later siblings manually if necessary plz."
);
if (raw.0 & (eRestyle_Self.0 | eRestyle_Subtree.0)) != 0 {
raw.0 &= !eRestyle_Self.0;

View file

@ -92,12 +92,10 @@ impl<'a, 'b: 'a, E: TElement> StateAndAttrInvalidationProcessor<'a, 'b, E> {
}
}
/// Whether we should process the descendants of a given element for style
/// invalidation.
pub fn should_process_descendants(data: &ElementData) -> bool {
!data.styles.is_display_none() &&
!data.hint.contains(RestyleHint::RESTYLE_DESCENDANTS)
!data.styles.is_display_none() && !data.hint.contains(RestyleHint::RESTYLE_DESCENDANTS)
}
/// Propagates the bits after invalidating a descendant child.
@ -136,14 +134,17 @@ where
}
}
impl<'a, 'b: 'a, E: 'a> InvalidationProcessor<'a, E> for StateAndAttrInvalidationProcessor<'a, 'b, E>
impl<'a, 'b: 'a, E: 'a> InvalidationProcessor<'a, E>
for StateAndAttrInvalidationProcessor<'a, 'b, E>
where
E: TElement,
{
/// We need to invalidate style on an eager pseudo-element, in order to
/// process changes that could otherwise end up in ::before or ::after
/// content being generated.
fn invalidates_on_eager_pseudo_element(&self) -> bool { true }
fn invalidates_on_eager_pseudo_element(&self) -> bool {
true
}
fn matching_context(&mut self) -> &mut MatchingContext<'a, E::Impl> {
&mut self.matching_context
@ -158,8 +159,7 @@ where
) -> bool {
debug_assert!(element.has_snapshot(), "Why bothering?");
let wrapper =
ElementWrapper::new(element, &*self.shared_context.snapshot_map);
let wrapper = ElementWrapper::new(element, &*self.shared_context.snapshot_map);
let state_changes = wrapper.state_changes();
let snapshot = wrapper.snapshot().expect("has_snapshot lied");
@ -223,12 +223,11 @@ where
classes_removed
);
let lookup_element =
if element.implemented_pseudo_element().is_some() {
element.pseudo_element_originating_element().unwrap()
} else {
element
};
let lookup_element = if element.implemented_pseudo_element().is_some() {
element.pseudo_element_originating_element().unwrap()
} else {
element
};
let invalidated_self = {
let mut collector = Collector {
@ -255,7 +254,8 @@ where
for (cascade_data, origin) in self.shared_context.stylist.iter_origins() {
if document_origins.contains(origin.into()) {
collector.collect_dependencies_in_invalidation_map(cascade_data.invalidation_map());
collector
.collect_dependencies_in_invalidation_map(cascade_data.invalidation_map());
}
}
@ -294,7 +294,7 @@ where
fn should_process_descendants(&mut self, element: E) -> bool {
if element == self.element {
return should_process_descendants(&self.data)
return should_process_descendants(&self.data);
}
match element.borrow_data() {
@ -329,10 +329,7 @@ where
E: TElement,
'selectors: 'a,
{
fn collect_dependencies_in_invalidation_map(
&mut self,
map: &'selectors InvalidationMap,
) {
fn collect_dependencies_in_invalidation_map(&mut self, map: &'selectors InvalidationMap) {
let quirks_mode = self.matching_context.quirks_mode();
let removed_id = self.removed_id;
if let Some(ref id) = removed_id {
@ -360,30 +357,21 @@ where
}
}
let should_examine_attribute_selector_map =
self.snapshot.other_attr_changed() ||
let should_examine_attribute_selector_map = self.snapshot.other_attr_changed() ||
(self.snapshot.class_changed() && map.has_class_attribute_selectors) ||
(self.snapshot.id_changed() && map.has_id_attribute_selectors);
if should_examine_attribute_selector_map {
self.collect_dependencies_in_map(
&map.other_attribute_affecting_selectors
)
self.collect_dependencies_in_map(&map.other_attribute_affecting_selectors)
}
let state_changes = self.state_changes;
if !state_changes.is_empty() {
self.collect_state_dependencies(
&map.state_affecting_selectors,
state_changes,
)
self.collect_state_dependencies(&map.state_affecting_selectors, state_changes)
}
}
fn collect_dependencies_in_map(
&mut self,
map: &'selectors SelectorMap<Dependency>,
) {
fn collect_dependencies_in_map(&mut self, map: &'selectors SelectorMap<Dependency>) {
map.lookup_with_additional(
self.lookup_element,
self.matching_context.quirks_mode(),
@ -410,12 +398,14 @@ where
if !dependency.state.intersects(state_changes) {
return true;
}
let visited_dependent =
if dependency.state.intersects(ElementState::IN_VISITED_OR_UNVISITED_STATE) {
VisitedDependent::Yes
} else {
VisitedDependent::No
};
let visited_dependent = if dependency
.state
.intersects(ElementState::IN_VISITED_OR_UNVISITED_STATE)
{
VisitedDependent::Yes
} else {
VisitedDependent::No
};
self.scan_dependency(&dependency.dep, visited_dependent);
true
},
@ -431,27 +421,28 @@ where
) -> bool {
let element = &self.element;
let wrapper = &self.wrapper;
self.matching_context.with_visited_handling_mode(visited_handling_mode, |mut context| {
let matches_now = matches_selector(
&dependency.selector,
dependency.selector_offset,
None,
element,
&mut context,
&mut |_, _| {},
);
self.matching_context
.with_visited_handling_mode(visited_handling_mode, |mut context| {
let matches_now = matches_selector(
&dependency.selector,
dependency.selector_offset,
None,
element,
&mut context,
&mut |_, _| {},
);
let matched_then = matches_selector(
&dependency.selector,
dependency.selector_offset,
None,
wrapper,
&mut context,
&mut |_, _| {},
);
let matched_then = matches_selector(
&dependency.selector,
dependency.selector_offset,
None,
wrapper,
&mut context,
&mut |_, _| {},
);
matched_then != matches_now
})
matched_then != matches_now
})
}
fn scan_dependency(
@ -459,20 +450,17 @@ where
dependency: &'selectors Dependency,
is_visited_dependent: VisitedDependent,
) {
debug!("TreeStyleInvalidator::scan_dependency({:?}, {:?}, {:?})",
self.element,
dependency,
is_visited_dependent,
debug!(
"TreeStyleInvalidator::scan_dependency({:?}, {:?}, {:?})",
self.element, dependency, is_visited_dependent,
);
if !self.dependency_may_be_relevant(dependency) {
return;
}
let should_account_for_dependency = self.check_dependency(
VisitedHandlingMode::AllLinksVisitedAndUnvisited,
dependency,
);
let should_account_for_dependency =
self.check_dependency(VisitedHandlingMode::AllLinksVisitedAndUnvisited, dependency);
if should_account_for_dependency {
return self.note_dependency(dependency);
@ -494,13 +482,9 @@ where
//
// NOTE: This thing is actually untested because testing it is flaky,
// see the tests that were added and then backed out in bug 1328509.
if is_visited_dependent == VisitedDependent::Yes &&
self.element.is_link()
{
let should_account_for_dependency = self.check_dependency(
VisitedHandlingMode::RelevantLinkVisited,
dependency,
);
if is_visited_dependent == VisitedDependent::Yes && self.element.is_link() {
let should_account_for_dependency =
self.check_dependency(VisitedHandlingMode::RelevantLinkVisited, dependency);
if should_account_for_dependency {
return self.note_dependency(dependency);
@ -518,10 +502,7 @@ where
}
debug_assert_ne!(dependency.selector_offset, 0);
debug_assert_ne!(
dependency.selector_offset,
dependency.selector.len()
);
debug_assert_ne!(dependency.selector_offset, dependency.selector.len());
let invalidation = Invalidation::new(
&dependency.selector,
@ -532,17 +513,23 @@ where
DependencyInvalidationKind::Element => unreachable!(),
DependencyInvalidationKind::ElementAndDescendants => {
self.invalidates_self = true;
self.descendant_invalidations.dom_descendants.push(invalidation);
}
self.descendant_invalidations
.dom_descendants
.push(invalidation);
},
DependencyInvalidationKind::Descendants => {
self.descendant_invalidations.dom_descendants.push(invalidation);
}
self.descendant_invalidations
.dom_descendants
.push(invalidation);
},
DependencyInvalidationKind::Siblings => {
self.sibling_invalidations.push(invalidation);
}
},
DependencyInvalidationKind::SlottedElements => {
self.descendant_invalidations.slotted_descendants.push(invalidation);
}
self.descendant_invalidations
.slotted_descendants
.push(invalidation);
},
}
}

View file

@ -35,7 +35,7 @@ impl MediaListKey {
/// A trait to get a given `MediaListKey` for a given item that can hold a
/// `MediaList`.
pub trait ToMediaListKey : Sized {
pub trait ToMediaListKey: Sized {
/// Get a `MediaListKey` for this item. This key needs to uniquely identify
/// the item.
#[allow(unsafe_code)]
@ -73,14 +73,16 @@ impl EffectiveMediaQueryResults {
/// Returns whether a given item was known to be effective when the results
/// were cached.
pub fn was_effective<T>(&self, item: &T) -> bool
where T: ToMediaListKey,
where
T: ToMediaListKey,
{
self.set.contains(&item.to_media_list_key())
}
/// Notices that an effective item has been seen, and caches it as matching.
pub fn saw_effective<T>(&mut self, item: &T)
where T: ToMediaListKey,
where
T: ToMediaListKey,
{
// NOTE(emilio): We can't assert that we don't cache the same item twice
// because of stylesheet reusing... shrug.
@ -97,19 +99,12 @@ impl NestedRuleIterationCondition for PotentiallyEffectiveMediaRules {
_: &SharedRwLockReadGuard,
_: &Device,
_: QuirksMode,
_: &ImportRule)
-> bool
{
_: &ImportRule,
) -> bool {
true
}
fn process_media(
_: &SharedRwLockReadGuard,
_: &Device,
_: QuirksMode,
_: &MediaRule)
-> bool
{
fn process_media(_: &SharedRwLockReadGuard, _: &Device, _: QuirksMode, _: &MediaRule) -> bool {
true
}
@ -118,9 +113,8 @@ impl NestedRuleIterationCondition for PotentiallyEffectiveMediaRules {
guard: &SharedRwLockReadGuard,
device: &Device,
quirks_mode: QuirksMode,
rule: &DocumentRule)
-> bool
{
rule: &DocumentRule,
) -> bool {
use stylesheets::EffectiveRules;
EffectiveRules::process_document(guard, device, quirks_mode, rule)
}
@ -130,9 +124,8 @@ impl NestedRuleIterationCondition for PotentiallyEffectiveMediaRules {
guard: &SharedRwLockReadGuard,
device: &Device,
quirks_mode: QuirksMode,
rule: &SupportsRule)
-> bool
{
rule: &SupportsRule,
) -> bool {
use stylesheets::EffectiveRules;
EffectiveRules::process_supports(guard, device, quirks_mode, rule)
}

View file

@ -32,7 +32,10 @@ enum Invalidation {
/// An element with a given class name.
Class(Atom),
/// An element with a given local name.
LocalName { name: SelectorLocalName, lower_name: SelectorLocalName },
LocalName {
name: SelectorLocalName,
lower_name: SelectorLocalName,
},
}
impl Invalidation {
@ -64,7 +67,7 @@ impl Invalidation {
return true;
}
}
}
},
Invalidation::ID(ref id) => {
if let Some(ref element_id) = element.id() {
if case_sensitivity.eq_atom(element_id, id) {
@ -79,14 +82,17 @@ impl Invalidation {
}
}
}
}
Invalidation::LocalName { ref name, ref lower_name } => {
},
Invalidation::LocalName {
ref name,
ref lower_name,
} => {
// This could look at the quirks mode of the document, instead
// of testing against both names, but it's probably not worth
// it.
let local_name = element.local_name();
return *local_name == **name || *local_name == **lower_name
}
return *local_name == **name || *local_name == **lower_name;
},
}
false
@ -132,9 +138,8 @@ impl StylesheetInvalidationSet {
&mut self,
device: &Device,
stylesheet: &S,
guard: &SharedRwLockReadGuard
)
where
guard: &SharedRwLockReadGuard,
) where
S: StylesheetInDocument,
{
debug!("StylesheetInvalidationSet::collect_invalidations_for");
@ -143,8 +148,7 @@ impl StylesheetInvalidationSet {
return;
}
if !stylesheet.enabled() ||
!stylesheet.is_effective_for_device(device, guard) {
if !stylesheet.enabled() || !stylesheet.is_effective_for_device(device, guard) {
debug!(" > Stylesheet was not effective");
return; // Nothing to do here.
}
@ -158,8 +162,14 @@ impl StylesheetInvalidationSet {
}
}
debug!(" > resulting subtree invalidations: {:?}", self.invalid_scopes);
debug!(" > resulting self invalidations: {:?}", self.invalid_elements);
debug!(
" > resulting subtree invalidations: {:?}",
self.invalid_scopes
);
debug!(
" > resulting self invalidations: {:?}",
self.invalid_elements
);
debug!(" > fully_invalid: {}", self.fully_invalid);
}
@ -167,15 +177,15 @@ impl StylesheetInvalidationSet {
/// `document_element` is provided.
///
/// Returns true if any invalidations ocurred.
pub fn flush<E>(
&mut self,
document_element: Option<E>,
snapshots: Option<&SnapshotMap>,
) -> bool
pub fn flush<E>(&mut self, document_element: Option<E>, snapshots: Option<&SnapshotMap>) -> bool
where
E: TElement,
{
debug!("Stylist::flush({:?}, snapshots: {})", document_element, snapshots.is_some());
debug!(
"Stylist::flush({:?}, snapshots: {})",
document_element,
snapshots.is_some()
);
let have_invalidations = match document_element {
Some(e) => self.process_invalidations(e, snapshots),
None => false,
@ -196,10 +206,8 @@ impl StylesheetInvalidationSet {
E: TElement,
{
debug!(
"Stylist::process_invalidations({:?}, {:?}, {:?})",
element,
self.invalid_scopes,
self.invalid_elements,
"Stylist::process_invalidations({:?}, {:?}, {:?})",
element, self.invalid_scopes, self.invalid_elements,
);
{
@ -209,8 +217,7 @@ impl StylesheetInvalidationSet {
};
if self.fully_invalid {
debug!("process_invalidations: fully_invalid({:?})",
element);
debug!("process_invalidations: fully_invalid({:?})", element);
data.hint.insert(RestyleHint::restyle_subtree());
return true;
}
@ -221,8 +228,11 @@ impl StylesheetInvalidationSet {
return false;
}
let case_sensitivity =
element.as_node().owner_doc().quirks_mode().classes_and_ids_case_sensitivity();
let case_sensitivity = element
.as_node()
.owner_doc()
.quirks_mode()
.classes_and_ids_case_sensitivity();
self.process_invalidations_in_subtree(element, snapshots, case_sensitivity)
}
@ -252,8 +262,10 @@ impl StylesheetInvalidationSet {
}
if data.hint.contains_subtree() {
debug!("process_invalidations_in_subtree: {:?} was already invalid",
element);
debug!(
"process_invalidations_in_subtree: {:?} was already invalid",
element
);
return false;
}
@ -261,8 +273,10 @@ impl StylesheetInvalidationSet {
let snapshot = element_wrapper.as_ref().and_then(|e| e.snapshot());
for invalidation in &self.invalid_scopes {
if invalidation.matches(element, snapshot, case_sensitivity) {
debug!("process_invalidations_in_subtree: {:?} matched subtree {:?}",
element, invalidation);
debug!(
"process_invalidations_in_subtree: {:?} matched subtree {:?}",
element, invalidation
);
data.hint.insert(RestyleHint::restyle_subtree());
return true;
}
@ -273,8 +287,10 @@ impl StylesheetInvalidationSet {
if !data.hint.contains(RestyleHint::RESTYLE_SELF) {
for invalidation in &self.invalid_elements {
if invalidation.matches(element, snapshot, case_sensitivity) {
debug!("process_invalidations_in_subtree: {:?} matched self {:?}",
element, invalidation);
debug!(
"process_invalidations_in_subtree: {:?} matched self {:?}",
element, invalidation
);
data.hint.insert(RestyleHint::RESTYLE_SELF);
self_invalid = true;
break;
@ -295,40 +311,45 @@ impl StylesheetInvalidationSet {
}
if any_children_invalid {
debug!("Children of {:?} changed, setting dirty descendants",
element);
debug!(
"Children of {:?} changed, setting dirty descendants",
element
);
unsafe { element.set_dirty_descendants() }
}
return self_invalid || any_children_invalid
return self_invalid || any_children_invalid;
}
fn scan_component(
component: &Component<SelectorImpl>,
invalidation: &mut Option<Invalidation>)
{
invalidation: &mut Option<Invalidation>,
) {
match *component {
Component::LocalName(LocalName { ref name, ref lower_name }) => {
Component::LocalName(LocalName {
ref name,
ref lower_name,
}) => {
if invalidation.as_ref().map_or(true, |s| !s.is_id_or_class()) {
*invalidation = Some(Invalidation::LocalName {
name: name.clone(),
lower_name: lower_name.clone(),
});
}
}
},
Component::Class(ref class) => {
if invalidation.as_ref().map_or(true, |s| !s.is_id()) {
*invalidation = Some(Invalidation::Class(class.clone()));
}
}
},
Component::ID(ref id) => {
if invalidation.is_none() {
*invalidation = Some(Invalidation::ID(id.clone()));
}
}
},
_ => {
// Ignore everything else, at least for now.
}
},
}
}
@ -347,7 +368,10 @@ impl StylesheetInvalidationSet {
/// of the selector, to reduce the amount of traversal we need to do
/// when flushing invalidations.
fn collect_invalidations(&mut self, selector: &Selector<SelectorImpl>) {
debug!("StylesheetInvalidationSet::collect_invalidations({:?})", selector);
debug!(
"StylesheetInvalidationSet::collect_invalidations({:?})",
selector
);
let mut element_invalidation: Option<Invalidation> = None;
let mut subtree_invalidation: Option<Invalidation> = None;
@ -369,7 +393,7 @@ impl StylesheetInvalidationSet {
None => break,
Some(combinator) => {
scan_for_subtree_invalidation = combinator.is_ancestor();
}
},
}
scan_for_element_invalidation = false;
}
@ -408,44 +432,41 @@ impl StylesheetInvalidationSet {
return;
}
}
}
Document(..) |
Namespace(..) |
Import(..) |
Media(..) |
Supports(..) => {
},
Document(..) | Namespace(..) | Import(..) | Media(..) | Supports(..) => {
// Do nothing, relevant nested rules are visited as part of the
// iteration.
}
},
FontFace(..) => {
// Do nothing, @font-face doesn't affect computed style
// information. We'll restyle when the font face loads, if
// needed.
}
},
Keyframes(ref lock) => {
let keyframes_rule = lock.read_with(guard);
if device.animation_name_may_be_referenced(&keyframes_rule.name) {
debug!(" > Found @keyframes rule potentially referenced \
from the page, marking the whole tree invalid.");
debug!(
" > Found @keyframes rule potentially referenced \
from the page, marking the whole tree invalid."
);
self.fully_invalid = true;
} else {
// Do nothing, this animation can't affect the style of
// existing elements.
}
}
CounterStyle(..) |
Page(..) |
Viewport(..) |
FontFeatureValues(..) => {
debug!(" > Found unsupported rule, marking the whole subtree \
invalid.");
},
CounterStyle(..) | Page(..) | Viewport(..) | FontFeatureValues(..) => {
debug!(
" > Found unsupported rule, marking the whole subtree \
invalid."
);
// TODO(emilio): Can we do better here?
//
// At least in `@page`, we could check the relevant media, I
// guess.
self.fully_invalid = true;
}
},
}
}
}

View file

@ -30,30 +30,43 @@ extern crate arrayvec;
extern crate atomic_refcell;
#[macro_use]
extern crate bitflags;
#[allow(unused_extern_crates)] extern crate byteorder;
#[cfg(feature = "gecko")] #[macro_use] #[no_link] extern crate cfg_if;
#[macro_use] extern crate cssparser;
#[macro_use] extern crate debug_unreachable;
#[allow(unused_extern_crates)]
extern crate byteorder;
#[cfg(feature = "gecko")]
#[macro_use]
#[no_link]
extern crate cfg_if;
#[macro_use]
extern crate cssparser;
#[macro_use]
extern crate debug_unreachable;
extern crate euclid;
extern crate fallible;
extern crate fnv;
#[cfg(feature = "gecko")] #[macro_use] pub mod gecko_string_cache;
#[cfg(feature = "gecko")]
#[macro_use]
pub mod gecko_string_cache;
extern crate hashglobe;
#[cfg(feature = "servo")] #[macro_use] extern crate html5ever;
#[cfg(feature = "servo")]
#[macro_use]
extern crate html5ever;
extern crate itertools;
extern crate itoa;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
#[macro_use] extern crate malloc_size_of;
#[macro_use] extern crate malloc_size_of_derive;
#[macro_use]
extern crate malloc_size_of;
#[macro_use]
extern crate malloc_size_of_derive;
#[allow(unused_extern_crates)]
#[macro_use]
extern crate matches;
#[cfg(feature = "gecko")]
pub extern crate nsstring;
#[cfg(feature = "gecko")] extern crate num_cpus;
#[cfg(feature = "gecko")]
extern crate num_cpus;
extern crate num_integer;
extern crate num_traits;
extern crate ordered_float;
@ -62,14 +75,21 @@ extern crate parking_lot;
extern crate precomputed_hash;
extern crate rayon;
extern crate selectors;
#[cfg(feature = "servo")] #[macro_use] extern crate serde;
#[cfg(feature = "servo")]
#[macro_use]
extern crate serde;
pub extern crate servo_arc;
#[cfg(feature = "servo")] #[macro_use] extern crate servo_atoms;
#[cfg(feature = "servo")] extern crate servo_config;
#[cfg(feature = "servo")] extern crate servo_url;
#[cfg(feature = "servo")]
#[macro_use]
extern crate servo_atoms;
#[cfg(feature = "servo")]
extern crate servo_config;
#[cfg(feature = "servo")]
extern crate servo_url;
extern crate smallbitvec;
extern crate smallvec;
#[cfg(feature = "servo")] extern crate string_cache;
#[cfg(feature = "servo")]
extern crate string_cache;
#[macro_use]
extern crate style_derive;
extern crate style_traits;
@ -83,10 +103,12 @@ extern crate void;
#[macro_use]
mod macros;
#[cfg(feature = "servo")] pub mod animation;
#[cfg(feature = "servo")]
pub mod animation;
pub mod applicable_declarations;
#[allow(missing_docs)] // TODO.
#[cfg(feature = "servo")] pub mod attr;
#[cfg(feature = "servo")]
pub mod attr;
pub mod author_styles;
pub mod bezier;
pub mod bloom;
@ -98,12 +120,17 @@ pub mod dom;
pub mod dom_apis;
pub mod driver;
pub mod element_state;
#[cfg(feature = "servo")] mod encoding_support;
#[cfg(feature = "servo")]
mod encoding_support;
pub mod error_reporting;
pub mod font_face;
pub mod font_metrics;
#[cfg(feature = "gecko")] #[allow(unsafe_code)] pub mod gecko;
#[cfg(feature = "gecko")] #[allow(unsafe_code)] pub mod gecko_bindings;
#[cfg(feature = "gecko")]
#[allow(unsafe_code)]
pub mod gecko;
#[cfg(feature = "gecko")]
#[allow(unsafe_code)]
pub mod gecko_bindings;
pub mod hash;
pub mod invalidation;
#[allow(missing_docs)] // TODO.
@ -133,16 +160,25 @@ pub mod traversal_flags;
#[allow(non_camel_case_types)]
pub mod values;
#[cfg(feature = "gecko")] pub use gecko_string_cache as string_cache;
#[cfg(feature = "gecko")] pub use gecko_string_cache::Atom;
#[cfg(feature = "gecko")] pub use gecko_string_cache::Namespace;
#[cfg(feature = "gecko")] pub use gecko_string_cache::Atom as Prefix;
#[cfg(feature = "gecko")] pub use gecko_string_cache::Atom as LocalName;
#[cfg(feature = "gecko")]
pub use gecko_string_cache as string_cache;
#[cfg(feature = "gecko")]
pub use gecko_string_cache::Atom;
#[cfg(feature = "gecko")]
pub use gecko_string_cache::Namespace;
#[cfg(feature = "gecko")]
pub use gecko_string_cache::Atom as Prefix;
#[cfg(feature = "gecko")]
pub use gecko_string_cache::Atom as LocalName;
#[cfg(feature = "servo")] pub use servo_atoms::Atom;
#[cfg(feature = "servo")] pub use html5ever::Prefix;
#[cfg(feature = "servo")] pub use html5ever::LocalName;
#[cfg(feature = "servo")] pub use html5ever::Namespace;
#[cfg(feature = "servo")]
pub use servo_atoms::Atom;
#[cfg(feature = "servo")]
pub use html5ever::Prefix;
#[cfg(feature = "servo")]
pub use html5ever::LocalName;
#[cfg(feature = "servo")]
pub use html5ever::Namespace;
/// The CSS properties supported by the style system.
/// Generated from the properties.mako.rs template by build.rs
@ -154,7 +190,9 @@ pub mod properties {
}
// uses a macro from properties
#[cfg(feature = "servo")] #[allow(unsafe_code)] pub mod servo;
#[cfg(feature = "servo")]
#[allow(unsafe_code)]
pub mod servo;
#[cfg(feature = "gecko")]
#[allow(unsafe_code, missing_docs)]
@ -178,8 +216,10 @@ macro_rules! reexport_computed_values {
}
longhand_properties_idents!(reexport_computed_values);
#[cfg(feature = "gecko")] use gecko_string_cache::WeakAtom;
#[cfg(feature = "servo")] use servo_atoms::Atom as WeakAtom;
#[cfg(feature = "gecko")]
use gecko_string_cache::WeakAtom;
#[cfg(feature = "servo")]
use servo_atoms::Atom as WeakAtom;
/// Extension methods for selectors::attr::CaseSensitivity
pub trait CaseSensitivityExt {

View file

@ -4,7 +4,7 @@
//! Geometry in flow-relative space.
use euclid::{Point2D, Rect, Size2D, SideOffsets2D};
use euclid::{Point2D, Rect, SideOffsets2D, Size2D};
use euclid::num::Zero;
use properties::style_structs;
use std::cmp::{max, min};
@ -15,12 +15,12 @@ use unicode_bidi as bidi;
pub enum BlockFlowDirection {
TopToBottom,
RightToLeft,
LeftToRight
LeftToRight,
}
pub enum InlineBaseDirection {
LeftToRight,
RightToLeft
RightToLeft,
}
// TODO: improve the readability of the WritingMode serialization, refer to the Debug:fmt()
@ -228,7 +228,6 @@ impl fmt::Display for WritingMode {
}
}
/// Wherever logical geometry is used, the writing mode is known based on context:
/// every method takes a `mode` parameter.
/// However, this context is easy to get wrong.
@ -244,7 +243,7 @@ struct DebugWritingMode;
#[derive(Clone, Copy, Eq, PartialEq)]
#[cfg_attr(feature = "servo", derive(Serialize))]
struct DebugWritingMode {
mode: WritingMode
mode: WritingMode,
}
#[cfg(not(debug_assertions))]
@ -291,28 +290,30 @@ impl Debug for DebugWritingMode {
}
}
// Used to specify the logical direction.
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(Serialize))]
pub enum Direction {
Inline,
Block
Block,
}
/// A 2D size in flow-relative dimensions
#[derive(Clone, Copy, Eq, PartialEq)]
#[cfg_attr(feature = "servo", derive(Serialize))]
pub struct LogicalSize<T> {
pub inline: T, // inline-size, a.k.a. logical width, a.k.a. measure
pub inline: T, // inline-size, a.k.a. logical width, a.k.a. measure
pub block: T, // block-size, a.k.a. logical height, a.k.a. extent
debug_writing_mode: DebugWritingMode,
}
impl<T: Debug> Debug for LogicalSize<T> {
fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
write!(formatter, "LogicalSize({:?}, i{:?}×b{:?})",
self.debug_writing_mode, self.inline, self.block)
write!(
formatter,
"LogicalSize({:?}, i{:?}×b{:?})",
self.debug_writing_mode, self.inline, self.block
)
}
}
@ -408,12 +409,13 @@ impl<T: Copy> LogicalSize<T> {
}
}
impl<T: Add<T, Output=T>> Add for LogicalSize<T> {
impl<T: Add<T, Output = T>> Add for LogicalSize<T> {
type Output = LogicalSize<T>;
#[inline]
fn add(self, other: LogicalSize<T>) -> LogicalSize<T> {
self.debug_writing_mode.check_debug(other.debug_writing_mode);
self.debug_writing_mode
.check_debug(other.debug_writing_mode);
LogicalSize {
debug_writing_mode: self.debug_writing_mode,
inline: self.inline + other.inline,
@ -422,12 +424,13 @@ impl<T: Add<T, Output=T>> Add for LogicalSize<T> {
}
}
impl<T: Sub<T, Output=T>> Sub for LogicalSize<T> {
impl<T: Sub<T, Output = T>> Sub for LogicalSize<T> {
type Output = LogicalSize<T>;
#[inline]
fn sub(self, other: LogicalSize<T>) -> LogicalSize<T> {
self.debug_writing_mode.check_debug(other.debug_writing_mode);
self.debug_writing_mode
.check_debug(other.debug_writing_mode);
LogicalSize {
debug_writing_mode: self.debug_writing_mode,
inline: self.inline - other.inline,
@ -436,7 +439,6 @@ impl<T: Sub<T, Output=T>> Sub for LogicalSize<T> {
}
}
/// A 2D point in flow-relative dimensions
#[derive(Clone, Copy, Eq, PartialEq)]
#[cfg_attr(feature = "servo", derive(Serialize))]
@ -450,8 +452,11 @@ pub struct LogicalPoint<T> {
impl<T: Debug> Debug for LogicalPoint<T> {
fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
write!(formatter, "LogicalPoint({:?} (i{:?}, b{:?}))",
self.debug_writing_mode, self.i, self.b)
write!(
formatter,
"LogicalPoint({:?} (i{:?}, b{:?}))",
self.debug_writing_mode, self.i, self.b
)
}
}
@ -478,19 +483,34 @@ impl<T: Copy> LogicalPoint<T> {
}
}
impl<T: Copy + Sub<T, Output=T>> LogicalPoint<T> {
impl<T: Copy + Sub<T, Output = T>> LogicalPoint<T> {
#[inline]
pub fn from_physical(mode: WritingMode, point: Point2D<T>, container_size: Size2D<T>)
-> LogicalPoint<T> {
pub fn from_physical(
mode: WritingMode,
point: Point2D<T>,
container_size: Size2D<T>,
) -> LogicalPoint<T> {
if mode.is_vertical() {
LogicalPoint {
i: if mode.is_inline_tb() { point.y } else { container_size.height - point.y },
b: if mode.is_vertical_lr() { point.x } else { container_size.width - point.x },
i: if mode.is_inline_tb() {
point.y
} else {
container_size.height - point.y
},
b: if mode.is_vertical_lr() {
point.x
} else {
container_size.width - point.x
},
debug_writing_mode: DebugWritingMode::new(mode),
}
} else {
LogicalPoint {
i: if mode.is_bidi_ltr() { point.x } else { container_size.width - point.x },
i: if mode.is_bidi_ltr() {
point.x
} else {
container_size.width - point.x
},
b: point.y,
debug_writing_mode: DebugWritingMode::new(mode),
}
@ -501,9 +521,17 @@ impl<T: Copy + Sub<T, Output=T>> LogicalPoint<T> {
pub fn x(&self, mode: WritingMode, container_size: Size2D<T>) -> T {
self.debug_writing_mode.check(mode);
if mode.is_vertical() {
if mode.is_vertical_lr() { self.b } else { container_size.width - self.b }
if mode.is_vertical_lr() {
self.b
} else {
container_size.width - self.b
}
} else {
if mode.is_bidi_ltr() { self.i } else { container_size.width - self.i }
if mode.is_bidi_ltr() {
self.i
} else {
container_size.width - self.i
}
}
}
@ -511,9 +539,17 @@ impl<T: Copy + Sub<T, Output=T>> LogicalPoint<T> {
pub fn set_x(&mut self, mode: WritingMode, x: T, container_size: Size2D<T>) {
self.debug_writing_mode.check(mode);
if mode.is_vertical() {
self.b = if mode.is_vertical_lr() { x } else { container_size.width - x }
self.b = if mode.is_vertical_lr() {
x
} else {
container_size.width - x
}
} else {
self.i = if mode.is_bidi_ltr() { x } else { container_size.width - x }
self.i = if mode.is_bidi_ltr() {
x
} else {
container_size.width - x
}
}
}
@ -521,7 +557,11 @@ impl<T: Copy + Sub<T, Output=T>> LogicalPoint<T> {
pub fn y(&self, mode: WritingMode, container_size: Size2D<T>) -> T {
self.debug_writing_mode.check(mode);
if mode.is_vertical() {
if mode.is_inline_tb() { self.i } else { container_size.height - self.i }
if mode.is_inline_tb() {
self.i
} else {
container_size.height - self.i
}
} else {
self.b
}
@ -531,7 +571,11 @@ impl<T: Copy + Sub<T, Output=T>> LogicalPoint<T> {
pub fn set_y(&mut self, mode: WritingMode, y: T, container_size: Size2D<T>) {
self.debug_writing_mode.check(mode);
if mode.is_vertical() {
self.i = if mode.is_inline_tb() { y } else { container_size.height - y }
self.i = if mode.is_inline_tb() {
y
} else {
container_size.height - y
}
} else {
self.b = y
}
@ -542,34 +586,56 @@ impl<T: Copy + Sub<T, Output=T>> LogicalPoint<T> {
self.debug_writing_mode.check(mode);
if mode.is_vertical() {
Point2D::new(
if mode.is_vertical_lr() { self.b } else { container_size.width - self.b },
if mode.is_inline_tb() { self.i } else { container_size.height - self.i })
if mode.is_vertical_lr() {
self.b
} else {
container_size.width - self.b
},
if mode.is_inline_tb() {
self.i
} else {
container_size.height - self.i
},
)
} else {
Point2D::new(
if mode.is_bidi_ltr() { self.i } else { container_size.width - self.i },
self.b)
if mode.is_bidi_ltr() {
self.i
} else {
container_size.width - self.i
},
self.b,
)
}
}
#[inline]
pub fn convert(&self, mode_from: WritingMode, mode_to: WritingMode, container_size: Size2D<T>)
-> LogicalPoint<T> {
pub fn convert(
&self,
mode_from: WritingMode,
mode_to: WritingMode,
container_size: Size2D<T>,
) -> LogicalPoint<T> {
if mode_from == mode_to {
self.debug_writing_mode.check(mode_from);
*self
} else {
LogicalPoint::from_physical(
mode_to, self.to_physical(mode_from, container_size), container_size)
mode_to,
self.to_physical(mode_from, container_size),
container_size,
)
}
}
}
impl<T: Copy + Add<T, Output=T>> LogicalPoint<T> {
impl<T: Copy + Add<T, Output = T>> LogicalPoint<T> {
/// This doesnt really makes sense,
/// but happens when dealing with multiple origins.
#[inline]
pub fn add_point(&self, other: &LogicalPoint<T>) -> LogicalPoint<T> {
self.debug_writing_mode.check_debug(other.debug_writing_mode);
self.debug_writing_mode
.check_debug(other.debug_writing_mode);
LogicalPoint {
debug_writing_mode: self.debug_writing_mode,
i: self.i + other.i,
@ -578,12 +644,13 @@ impl<T: Copy + Add<T, Output=T>> LogicalPoint<T> {
}
}
impl<T: Copy + Add<T, Output=T>> Add<LogicalSize<T>> for LogicalPoint<T> {
impl<T: Copy + Add<T, Output = T>> Add<LogicalSize<T>> for LogicalPoint<T> {
type Output = LogicalPoint<T>;
#[inline]
fn add(self, other: LogicalSize<T>) -> LogicalPoint<T> {
self.debug_writing_mode.check_debug(other.debug_writing_mode);
self.debug_writing_mode
.check_debug(other.debug_writing_mode);
LogicalPoint {
debug_writing_mode: self.debug_writing_mode,
i: self.i + other.inline,
@ -592,12 +659,13 @@ impl<T: Copy + Add<T, Output=T>> Add<LogicalSize<T>> for LogicalPoint<T> {
}
}
impl<T: Copy + Sub<T, Output=T>> Sub<LogicalSize<T>> for LogicalPoint<T> {
impl<T: Copy + Sub<T, Output = T>> Sub<LogicalSize<T>> for LogicalPoint<T> {
type Output = LogicalPoint<T>;
#[inline]
fn sub(self, other: LogicalSize<T>) -> LogicalPoint<T> {
self.debug_writing_mode.check_debug(other.debug_writing_mode);
self.debug_writing_mode
.check_debug(other.debug_writing_mode);
LogicalPoint {
debug_writing_mode: self.debug_writing_mode,
i: self.i - other.inline,
@ -606,7 +674,6 @@ impl<T: Copy + Sub<T, Output=T>> Sub<LogicalSize<T>> for LogicalPoint<T> {
}
}
/// A "margin" in flow-relative dimensions
/// Represents the four sides of the margins, borders, or padding of a CSS box,
/// or a combination of those.
@ -629,12 +696,15 @@ impl<T: Debug> Debug for LogicalMargin<T> {
"".to_owned()
};
write!(formatter, "LogicalMargin({}i:{:?}..{:?} b:{:?}..{:?})",
write!(
formatter,
"LogicalMargin({}i:{:?}..{:?} b:{:?}..{:?})",
writing_mode_string,
self.inline_start,
self.inline_end,
self.block_start,
self.block_end)
self.block_end
)
}
}
@ -653,8 +723,13 @@ impl<T: Zero> LogicalMargin<T> {
impl<T: Copy> LogicalMargin<T> {
#[inline]
pub fn new(mode: WritingMode, block_start: T, inline_end: T, block_end: T, inline_start: T)
-> LogicalMargin<T> {
pub fn new(
mode: WritingMode,
block_start: T,
inline_end: T,
block_end: T,
inline_start: T,
) -> LogicalMargin<T> {
LogicalMargin {
block_start: block_start,
inline_end: inline_end,
@ -708,7 +783,11 @@ impl<T: Copy> LogicalMargin<T> {
pub fn top(&self, mode: WritingMode) -> T {
self.debug_writing_mode.check(mode);
if mode.is_vertical() {
if mode.is_inline_tb() { self.inline_start } else { self.inline_end }
if mode.is_inline_tb() {
self.inline_start
} else {
self.inline_end
}
} else {
self.block_start
}
@ -718,7 +797,11 @@ impl<T: Copy> LogicalMargin<T> {
pub fn set_top(&mut self, mode: WritingMode, top: T) {
self.debug_writing_mode.check(mode);
if mode.is_vertical() {
if mode.is_inline_tb() { self.inline_start = top } else { self.inline_end = top }
if mode.is_inline_tb() {
self.inline_start = top
} else {
self.inline_end = top
}
} else {
self.block_start = top
}
@ -728,9 +811,17 @@ impl<T: Copy> LogicalMargin<T> {
pub fn right(&self, mode: WritingMode) -> T {
self.debug_writing_mode.check(mode);
if mode.is_vertical() {
if mode.is_vertical_lr() { self.block_end } else { self.block_start }
if mode.is_vertical_lr() {
self.block_end
} else {
self.block_start
}
} else {
if mode.is_bidi_ltr() { self.inline_end } else { self.inline_start }
if mode.is_bidi_ltr() {
self.inline_end
} else {
self.inline_start
}
}
}
@ -738,9 +829,17 @@ impl<T: Copy> LogicalMargin<T> {
pub fn set_right(&mut self, mode: WritingMode, right: T) {
self.debug_writing_mode.check(mode);
if mode.is_vertical() {
if mode.is_vertical_lr() { self.block_end = right } else { self.block_start = right }
if mode.is_vertical_lr() {
self.block_end = right
} else {
self.block_start = right
}
} else {
if mode.is_bidi_ltr() { self.inline_end = right } else { self.inline_start = right }
if mode.is_bidi_ltr() {
self.inline_end = right
} else {
self.inline_start = right
}
}
}
@ -748,7 +847,11 @@ impl<T: Copy> LogicalMargin<T> {
pub fn bottom(&self, mode: WritingMode) -> T {
self.debug_writing_mode.check(mode);
if mode.is_vertical() {
if mode.is_inline_tb() { self.inline_end } else { self.inline_start }
if mode.is_inline_tb() {
self.inline_end
} else {
self.inline_start
}
} else {
self.block_end
}
@ -758,7 +861,11 @@ impl<T: Copy> LogicalMargin<T> {
pub fn set_bottom(&mut self, mode: WritingMode, bottom: T) {
self.debug_writing_mode.check(mode);
if mode.is_vertical() {
if mode.is_inline_tb() { self.inline_end = bottom } else { self.inline_start = bottom }
if mode.is_inline_tb() {
self.inline_end = bottom
} else {
self.inline_start = bottom
}
} else {
self.block_end = bottom
}
@ -768,9 +875,17 @@ impl<T: Copy> LogicalMargin<T> {
pub fn left(&self, mode: WritingMode) -> T {
self.debug_writing_mode.check(mode);
if mode.is_vertical() {
if mode.is_vertical_lr() { self.block_start } else { self.block_end }
if mode.is_vertical_lr() {
self.block_start
} else {
self.block_end
}
} else {
if mode.is_bidi_ltr() { self.inline_start } else { self.inline_end }
if mode.is_bidi_ltr() {
self.inline_start
} else {
self.inline_end
}
}
}
@ -778,9 +893,17 @@ impl<T: Copy> LogicalMargin<T> {
pub fn set_left(&mut self, mode: WritingMode, left: T) {
self.debug_writing_mode.check(mode);
if mode.is_vertical() {
if mode.is_vertical_lr() { self.block_start = left } else { self.block_end = left }
if mode.is_vertical_lr() {
self.block_start = left
} else {
self.block_end = left
}
} else {
if mode.is_bidi_ltr() { self.inline_start = left } else { self.inline_end = left }
if mode.is_bidi_ltr() {
self.inline_start = left
} else {
self.inline_end = left
}
}
}
@ -835,11 +958,11 @@ impl<T: PartialEq + Zero> LogicalMargin<T> {
#[inline]
pub fn is_zero(&self) -> bool {
self.block_start == Zero::zero() && self.inline_end == Zero::zero() &&
self.block_end == Zero::zero() && self.inline_start == Zero::zero()
self.block_end == Zero::zero() && self.inline_start == Zero::zero()
}
}
impl<T: Copy + Add<T, Output=T>> LogicalMargin<T> {
impl<T: Copy + Add<T, Output = T>> LogicalMargin<T> {
#[inline]
pub fn inline_start_end(&self) -> T {
self.inline_start + self.inline_end
@ -853,10 +976,8 @@ impl<T: Copy + Add<T, Output=T>> LogicalMargin<T> {
#[inline]
pub fn start_end(&self, direction: Direction) -> T {
match direction {
Direction::Inline =>
self.inline_start + self.inline_end,
Direction::Block =>
self.block_start + self.block_end
Direction::Inline => self.inline_start + self.inline_end,
Direction::Block => self.block_start + self.block_end,
}
}
@ -881,12 +1002,13 @@ impl<T: Copy + Add<T, Output=T>> LogicalMargin<T> {
}
}
impl<T: Add<T, Output=T>> Add for LogicalMargin<T> {
impl<T: Add<T, Output = T>> Add for LogicalMargin<T> {
type Output = LogicalMargin<T>;
#[inline]
fn add(self, other: LogicalMargin<T>) -> LogicalMargin<T> {
self.debug_writing_mode.check_debug(other.debug_writing_mode);
self.debug_writing_mode
.check_debug(other.debug_writing_mode);
LogicalMargin {
debug_writing_mode: self.debug_writing_mode,
block_start: self.block_start + other.block_start,
@ -897,12 +1019,13 @@ impl<T: Add<T, Output=T>> Add for LogicalMargin<T> {
}
}
impl<T: Sub<T, Output=T>> Sub for LogicalMargin<T> {
impl<T: Sub<T, Output = T>> Sub for LogicalMargin<T> {
type Output = LogicalMargin<T>;
#[inline]
fn sub(self, other: LogicalMargin<T>) -> LogicalMargin<T> {
self.debug_writing_mode.check_debug(other.debug_writing_mode);
self.debug_writing_mode
.check_debug(other.debug_writing_mode);
LogicalMargin {
debug_writing_mode: self.debug_writing_mode,
block_start: self.block_start - other.block_start,
@ -913,7 +1036,6 @@ impl<T: Sub<T, Output=T>> Sub for LogicalMargin<T> {
}
}
/// A rectangle in flow-relative dimensions
#[derive(Clone, Copy, Eq, PartialEq)]
#[cfg_attr(feature = "servo", derive(Serialize))]
@ -931,12 +1053,11 @@ impl<T: Debug> Debug for LogicalRect<T> {
"".to_owned()
};
write!(formatter, "LogicalRect({}i{:?}×b{:?}, @ (i{:?},b{:?}))",
writing_mode_string,
self.size.inline,
self.size.block,
self.start.i,
self.start.b)
write!(
formatter,
"LogicalRect({}i{:?}×b{:?}, @ (i{:?},b{:?}))",
writing_mode_string, self.size.inline, self.size.block, self.start.i, self.start.b
)
}
}
@ -953,8 +1074,13 @@ impl<T: Zero> LogicalRect<T> {
impl<T: Copy> LogicalRect<T> {
#[inline]
pub fn new(mode: WritingMode, inline_start: T, block_start: T, inline: T, block: T)
-> LogicalRect<T> {
pub fn new(
mode: WritingMode,
inline_start: T,
block_start: T,
inline: T,
block: T,
) -> LogicalRect<T> {
LogicalRect {
start: LogicalPoint::new(mode, inline_start, block_start),
size: LogicalSize::new(mode, inline, block),
@ -963,8 +1089,11 @@ impl<T: Copy> LogicalRect<T> {
}
#[inline]
pub fn from_point_size(mode: WritingMode, start: LogicalPoint<T>, size: LogicalSize<T>)
-> LogicalRect<T> {
pub fn from_point_size(
mode: WritingMode,
start: LogicalPoint<T>,
size: LogicalSize<T>,
) -> LogicalRect<T> {
start.debug_writing_mode.check(mode);
size.debug_writing_mode.check(mode);
LogicalRect {
@ -975,10 +1104,13 @@ impl<T: Copy> LogicalRect<T> {
}
}
impl<T: Copy + Add<T, Output=T> + Sub<T, Output=T>> LogicalRect<T> {
impl<T: Copy + Add<T, Output = T> + Sub<T, Output = T>> LogicalRect<T> {
#[inline]
pub fn from_physical(mode: WritingMode, rect: Rect<T>, container_size: Size2D<T>)
-> LogicalRect<T> {
pub fn from_physical(
mode: WritingMode,
rect: Rect<T>,
container_size: Size2D<T>,
) -> LogicalRect<T> {
let inline_start;
let block_start;
let inline;
@ -1060,14 +1192,21 @@ impl<T: Copy + Add<T, Output=T> + Sub<T, Output=T>> LogicalRect<T> {
}
#[inline]
pub fn convert(&self, mode_from: WritingMode, mode_to: WritingMode, container_size: Size2D<T>)
-> LogicalRect<T> {
pub fn convert(
&self,
mode_from: WritingMode,
mode_to: WritingMode,
container_size: Size2D<T>,
) -> LogicalRect<T> {
if mode_from == mode_to {
self.debug_writing_mode.check(mode_from);
*self
} else {
LogicalRect::from_physical(
mode_to, self.to_physical(mode_from, container_size), container_size)
mode_to,
self.to_physical(mode_from, container_size),
container_size,
)
}
}
@ -1091,10 +1230,11 @@ impl<T: Copy + Add<T, Output=T> + Sub<T, Output=T>> LogicalRect<T> {
}
}
impl<T: Copy + Ord + Add<T, Output=T> + Sub<T, Output=T>> LogicalRect<T> {
impl<T: Copy + Ord + Add<T, Output = T> + Sub<T, Output = T>> LogicalRect<T> {
#[inline]
pub fn union(&self, other: &LogicalRect<T>) -> LogicalRect<T> {
self.debug_writing_mode.check_debug(other.debug_writing_mode);
self.debug_writing_mode
.check_debug(other.debug_writing_mode);
let inline_start = min(self.start.i, other.start.i);
let block_start = min(self.start.b, other.start.b);
@ -1114,12 +1254,13 @@ impl<T: Copy + Ord + Add<T, Output=T> + Sub<T, Output=T>> LogicalRect<T> {
}
}
impl<T: Copy + Add<T, Output=T> + Sub<T, Output=T>> Add<LogicalMargin<T>> for LogicalRect<T> {
impl<T: Copy + Add<T, Output = T> + Sub<T, Output = T>> Add<LogicalMargin<T>> for LogicalRect<T> {
type Output = LogicalRect<T>;
#[inline]
fn add(self, other: LogicalMargin<T>) -> LogicalRect<T> {
self.debug_writing_mode.check_debug(other.debug_writing_mode);
self.debug_writing_mode
.check_debug(other.debug_writing_mode);
LogicalRect {
start: LogicalPoint {
// Growing a rectangle on the start side means pushing its
@ -1138,13 +1279,13 @@ impl<T: Copy + Add<T, Output=T> + Sub<T, Output=T>> Add<LogicalMargin<T>> for Lo
}
}
impl<T: Copy + Add<T, Output=T> + Sub<T, Output=T>> Sub<LogicalMargin<T>> for LogicalRect<T> {
impl<T: Copy + Add<T, Output = T> + Sub<T, Output = T>> Sub<LogicalMargin<T>> for LogicalRect<T> {
type Output = LogicalRect<T>;
#[inline]
fn sub(self, other: LogicalMargin<T>) -> LogicalRect<T> {
self.debug_writing_mode.check_debug(other.debug_writing_mode);
self.debug_writing_mode
.check_debug(other.debug_writing_mode);
LogicalRect {
start: LogicalPoint {
// Shrinking a rectangle on the start side means pushing its

View file

@ -7,16 +7,16 @@
macro_rules! exclusive_value {
(($value:ident, $set:expr) => $ident:path) => {
if $value.intersects($set) {
return Err(())
return Err(());
} else {
$ident
}
}
};
}
#[cfg(feature = "gecko")]
macro_rules! impl_gecko_keyword_conversions {
($name: ident, $utype: ty) => {
($name:ident, $utype:ty) => {
impl From<$utype> for $name {
fn from(bits: $utype) -> $name {
$name::from_gecko_keyword(bits)
@ -44,7 +44,7 @@ macro_rules! trivial_to_computed_value {
other.clone()
}
}
}
};
}
/// A macro to parse an identifier, or return an `UnexpectedIndent` error
@ -66,10 +66,10 @@ macro_rules! try_match_ident_ignore_ascii_case {
}
macro_rules! define_keyword_type {
($name: ident, $css: expr) => {
($name:ident, $css:expr) => {
#[allow(missing_docs)]
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, MallocSizeOf)]
#[derive(PartialEq, ToAnimatedValue, ToAnimatedZero, ToComputedValue, ToCss)]
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, MallocSizeOf, PartialEq,
ToAnimatedValue, ToAnimatedZero, ToComputedValue, ToCss)]
pub struct $name;
impl fmt::Debug for $name {
@ -81,9 +81,12 @@ macro_rules! define_keyword_type {
impl $crate::parser::Parse for $name {
fn parse<'i, 't>(
_context: &$crate::parser::ParserContext,
input: &mut ::cssparser::Parser<'i, 't>
input: &mut ::cssparser::Parser<'i, 't>,
) -> Result<$name, ::style_traits::ParseError<'i>> {
input.expect_ident_matching($css).map(|_| $name).map_err(|e| e.into())
input
.expect_ident_matching($css)
.map(|_| $name)
.map_err(|e| e.into())
}
}
};
@ -91,7 +94,7 @@ macro_rules! define_keyword_type {
#[cfg(feature = "gecko")]
macro_rules! impl_bitflags_conversions {
($name: ident) => {
($name:ident) => {
impl From<u8> for $name {
fn from(bits: u8) -> $name {
$name::from_bits(bits).expect("bits contain valid flag")

View file

@ -96,17 +96,18 @@ trait PrivateMatchMethods: TElement {
use properties::PropertyDeclarationBlock;
use shared_lock::Locked;
debug_assert!(replacements.intersects(RestyleHint::replacements()) &&
(replacements & !RestyleHint::replacements()).is_empty());
debug_assert!(
replacements.intersects(RestyleHint::replacements()) &&
(replacements & !RestyleHint::replacements()).is_empty()
);
let stylist = &context.shared.stylist;
let guards = &context.shared.guards;
let primary_rules =
match cascade_visited {
CascadeVisitedMode::Unvisited => cascade_inputs.primary.rules.as_mut(),
CascadeVisitedMode::Visited => cascade_inputs.primary.visited_rules.as_mut(),
};
let primary_rules = match cascade_visited {
CascadeVisitedMode::Unvisited => cascade_inputs.primary.rules.as_mut(),
CascadeVisitedMode::Visited => cascade_inputs.primary.visited_rules.as_mut(),
};
let primary_rules = match primary_rules {
Some(r) => r,
@ -115,16 +116,16 @@ trait PrivateMatchMethods: TElement {
let replace_rule_node = |level: CascadeLevel,
pdb: Option<ArcBorrow<Locked<PropertyDeclarationBlock>>>,
path: &mut StrongRuleNode| -> bool {
path: &mut StrongRuleNode|
-> bool {
let mut important_rules_changed = false;
let new_node =
stylist.rule_tree().update_rule_at_level(
level,
pdb,
path,
guards,
&mut important_rules_changed,
);
let new_node = stylist.rule_tree().update_rule_at_level(
level,
pdb,
path,
guards,
&mut important_rules_changed,
);
if let Some(n) = new_node {
*path = n;
}
@ -192,15 +193,18 @@ trait PrivateMatchMethods: TElement {
fn after_change_style(
&self,
context: &mut StyleContext<Self>,
primary_style: &Arc<ComputedValues>
primary_style: &Arc<ComputedValues>,
) -> Option<Arc<ComputedValues>> {
use context::CascadeInputs;
use style_resolver::{PseudoElementResolution, StyleResolverForElement};
use stylist::RuleInclusion;
let rule_node = primary_style.rules();
let without_transition_rules =
context.shared.stylist.rule_tree().remove_transition_rule_if_applicable(rule_node);
let without_transition_rules = context
.shared
.stylist
.rule_tree()
.remove_transition_rule_if_applicable(rule_node);
if without_transition_rules == *rule_node {
// We don't have transition rule in this case, so return None to let
// the caller use the original ComputedValues.
@ -209,16 +213,18 @@ trait PrivateMatchMethods: TElement {
// FIXME(bug 868975): We probably need to transition visited style as
// well.
let inputs =
CascadeInputs {
rules: Some(without_transition_rules),
visited_rules: primary_style.visited_rules().cloned()
};
let inputs = CascadeInputs {
rules: Some(without_transition_rules),
visited_rules: primary_style.visited_rules().cloned(),
};
// Actually `PseudoElementResolution` doesn't really matter.
let style =
StyleResolverForElement::new(*self, context, RuleInclusion::All, PseudoElementResolution::IfApplicable)
.cascade_style_and_visited_with_default_parents(inputs);
let style = StyleResolverForElement::new(
*self,
context,
RuleInclusion::All,
PseudoElementResolution::IfApplicable,
).cascade_style_and_visited_with_default_parents(inputs);
Some(style.0)
}
@ -240,8 +246,10 @@ trait PrivateMatchMethods: TElement {
let old_box_style = old.get_box();
let keyframes_could_have_changed =
context.shared.traversal_flags.contains(TraversalFlags::ForCSSRuleChanges);
let keyframes_could_have_changed = context
.shared
.traversal_flags
.contains(TraversalFlags::ForCSSRuleChanges);
// If the traversal is triggered due to changes in CSS rules changes, we
// need to try to update all CSS animations on the element if the
@ -250,9 +258,7 @@ trait PrivateMatchMethods: TElement {
//
// TODO: We should check which @keyframes were added/changed/deleted and
// update only animations corresponding to those @keyframes.
if keyframes_could_have_changed &&
(has_new_animation_style || self.has_css_animations())
{
if keyframes_could_have_changed && (has_new_animation_style || self.has_css_animations()) {
return true;
}
@ -285,7 +291,7 @@ trait PrivateMatchMethods: TElement {
context: &mut StyleContext<Self>,
old_values: Option<&ComputedValues>,
new_values: &ComputedValues,
restyle_hints: RestyleHint
restyle_hints: RestyleHint,
) {
use context::PostAnimationTasks;
@ -337,8 +343,10 @@ trait PrivateMatchMethods: TElement {
tasks.insert(UpdateAnimationsTasks::CSS_ANIMATIONS);
}
let before_change_style = if self.might_need_transitions_update(old_values.as_ref().map(|s| &**s),
new_values) {
let before_change_style = if self.might_need_transitions_update(
old_values.as_ref().map(|s| &**s),
new_values,
) {
let after_change_style = if self.has_css_transitions() {
self.after_change_style(context, new_values)
} else {
@ -351,13 +359,9 @@ trait PrivateMatchMethods: TElement {
let needs_transitions_update = {
// We borrow new_values here, so need to add a scope to make
// sure we release it before assigning a new value to it.
let after_change_style_ref =
after_change_style.as_ref().unwrap_or(&new_values);
let after_change_style_ref = after_change_style.as_ref().unwrap_or(&new_values);
self.needs_transitions_update(
old_values.as_ref().unwrap(),
after_change_style_ref,
)
self.needs_transitions_update(old_values.as_ref().unwrap(), after_change_style_ref)
};
if needs_transitions_update {
@ -387,9 +391,8 @@ trait PrivateMatchMethods: TElement {
}
if !tasks.is_empty() {
let task = ::context::SequentialTask::update_animations(*self,
before_change_style,
tasks);
let task =
::context::SequentialTask::update_animations(*self, before_change_style, tasks);
context.thread_local.tasks.push(task);
}
}
@ -442,7 +445,6 @@ trait PrivateMatchMethods: TElement {
}
}
/// Computes and applies non-redundant damage.
fn accumulate_damage_for(
&self,
@ -453,10 +455,11 @@ trait PrivateMatchMethods: TElement {
pseudo: Option<&PseudoElement>,
) -> ChildCascadeRequirement {
debug!("accumulate_damage_for: {:?}", self);
debug_assert!(!shared_context.traversal_flags.contains(TraversalFlags::Forgetful));
debug_assert!(!shared_context
.traversal_flags
.contains(TraversalFlags::Forgetful));
let difference =
self.compute_style_difference(old_values, new_values, pseudo);
let difference = self.compute_style_difference(old_values, new_values, pseudo);
*damage |= difference.damage;
@ -465,21 +468,22 @@ trait PrivateMatchMethods: TElement {
// We need to cascade the children in order to ensure the correct
// propagation of inherited computed value flags.
if old_values.flags.maybe_inherited() != new_values.flags.maybe_inherited() {
debug!(" > flags changed: {:?} != {:?}", old_values.flags, new_values.flags);
debug!(
" > flags changed: {:?} != {:?}",
old_values.flags, new_values.flags
);
return ChildCascadeRequirement::MustCascadeChildren;
}
match difference.change {
StyleChange::Unchanged => {
return ChildCascadeRequirement::CanSkipCascade
},
StyleChange::Unchanged => return ChildCascadeRequirement::CanSkipCascade,
StyleChange::Changed { reset_only } => {
// If inherited properties changed, the best we can do is
// cascade the children.
if !reset_only {
return ChildCascadeRequirement::MustCascadeChildren
return ChildCascadeRequirement::MustCascadeChildren;
}
}
},
}
let old_display = old_values.get_box().clone_display();
@ -492,14 +496,14 @@ trait PrivateMatchMethods: TElement {
// that gets handled on the frame constructor when processing
// the reframe, so no need to handle that here.
if old_display == Display::None && old_display != new_display {
return ChildCascadeRequirement::MustCascadeChildren
return ChildCascadeRequirement::MustCascadeChildren;
}
// Blockification of children may depend on our display value,
// so we need to actually do the recascade. We could potentially
// do better, but it doesn't seem worth it.
if old_display.is_item_container() != new_display.is_item_container() {
return ChildCascadeRequirement::MustCascadeChildren
return ChildCascadeRequirement::MustCascadeChildren;
}
// Line break suppression may also be affected if the display
@ -507,7 +511,7 @@ trait PrivateMatchMethods: TElement {
#[cfg(feature = "gecko")]
{
if old_display.is_ruby_type() != new_display.is_ruby_type() {
return ChildCascadeRequirement::MustCascadeChildren
return ChildCascadeRequirement::MustCascadeChildren;
}
}
@ -520,23 +524,20 @@ trait PrivateMatchMethods: TElement {
{
use values::specified::align::AlignFlags;
let old_justify_items =
old_values.get_position().clone_justify_items();
let new_justify_items =
new_values.get_position().clone_justify_items();
let old_justify_items = old_values.get_position().clone_justify_items();
let new_justify_items = new_values.get_position().clone_justify_items();
let was_legacy_justify_items =
old_justify_items.computed.0.contains(AlignFlags::LEGACY);
let is_legacy_justify_items =
new_justify_items.computed.0.contains(AlignFlags::LEGACY);
let is_legacy_justify_items = new_justify_items.computed.0.contains(AlignFlags::LEGACY);
if is_legacy_justify_items != was_legacy_justify_items {
return ChildCascadeRequirement::MustCascadeChildren;
}
if was_legacy_justify_items &&
old_justify_items.computed != new_justify_items.computed {
if was_legacy_justify_items && old_justify_items.computed != new_justify_items.computed
{
return ChildCascadeRequirement::MustCascadeChildren;
}
}
@ -577,8 +578,11 @@ trait PrivateMatchMethods: TElement {
animation::complete_expired_transitions(this_opaque, style, context);
// Merge any running animations into the current style, and cancel them.
let had_running_animations =
context.running_animations.read().get(&this_opaque).is_some();
let had_running_animations = context
.running_animations
.read()
.get(&this_opaque)
.is_some();
if !had_running_animations {
return;
}
@ -616,7 +620,7 @@ trait PrivateMatchMethods: TElement {
impl<E: TElement> PrivateMatchMethods for E {}
/// The public API that elements expose for selector matching.
pub trait MatchMethods : TElement {
pub trait MatchMethods: TElement {
/// Returns the closest parent element that doesn't have a display: contents
/// style (and thus generates a box).
///
@ -635,8 +639,12 @@ pub trait MatchMethods : TElement {
None => return current,
};
let is_display_contents =
current.borrow_data().unwrap().styles.primary().is_display_contents();
let is_display_contents = current
.borrow_data()
.unwrap()
.styles
.primary()
.is_display_contents();
if !is_display_contents {
return current;
@ -673,7 +681,11 @@ pub trait MatchMethods : TElement {
let device = context.shared.stylist.device();
let new_font_size = new_primary_style.get_font().clone_font_size();
if old_styles.primary.as_ref().map_or(true, |s| s.get_font().clone_font_size() != new_font_size) {
if old_styles
.primary
.as_ref()
.map_or(true, |s| s.get_font().clone_font_size() != new_font_size)
{
debug_assert!(self.owner_doc_matches_for_testing(device));
device.set_root_font_size(new_font_size.size());
// If the root font-size changed since last time, and something
@ -701,7 +713,11 @@ pub trait MatchMethods : TElement {
}
// Don't accumulate damage if we're in a forgetful traversal.
if context.shared.traversal_flags.contains(TraversalFlags::Forgetful) {
if context
.shared
.traversal_flags
.contains(TraversalFlags::Forgetful)
{
return ChildCascadeRequirement::MustCascadeChildren;
}
@ -719,7 +735,7 @@ pub trait MatchMethods : TElement {
&old_primary_style,
new_primary_style,
None,
)
),
);
if data.styles.pseudos.is_empty() && old_styles.pseudos.is_empty() {
@ -727,9 +743,11 @@ pub trait MatchMethods : TElement {
return cascade_requirement;
}
let pseudo_styles =
old_styles.pseudos.as_array().iter().zip(
data.styles.pseudos.as_array().iter());
let pseudo_styles = old_styles
.pseudos
.as_array()
.iter()
.zip(data.styles.pseudos.as_array().iter());
for (i, (old, new)) in pseudo_styles.enumerate() {
match (old, new) {
@ -741,7 +759,7 @@ pub trait MatchMethods : TElement {
new,
Some(&PseudoElement::from_eager_index(i)),
);
}
},
(&None, &None) => {},
_ => {
// It's possible that we're switching from not having
@ -757,14 +775,13 @@ pub trait MatchMethods : TElement {
data.damage |= RestyleDamage::reconstruct();
return cascade_requirement;
}
}
},
}
}
cascade_requirement
}
/// Applies selector flags to an element, deferring mutations of the parent
/// until after the traversal.
///
@ -783,7 +800,9 @@ pub trait MatchMethods : TElement {
// If this is the element we're styling, we have exclusive
// access to the element, and thus it's fine inserting them,
// even from the worker.
unsafe { element.set_selector_flags(self_flags); }
unsafe {
element.set_selector_flags(self_flags);
}
} else {
// Otherwise, this element is an ancestor of the current element
// we're styling, and thus multiple children could write to it
@ -829,7 +848,7 @@ pub trait MatchMethods : TElement {
replacements,
context,
CascadeVisitedMode::Visited,
cascade_inputs
cascade_inputs,
);
result
}
@ -841,7 +860,7 @@ pub trait MatchMethods : TElement {
&self,
old_values: &ComputedValues,
new_values: &ComputedValues,
pseudo: Option<&PseudoElement>
pseudo: Option<&PseudoElement>,
) -> StyleDifference {
debug_assert!(pseudo.map_or(true, |p| p.is_eager()));
RestyleDamage::compute_style_difference(old_values, new_values)

View file

@ -9,13 +9,13 @@
use Atom;
use context::QuirksMode;
use cssparser::{Delimiter, Parser};
use cssparser::{Token, ParserInput};
use cssparser::{ParserInput, Token};
use error_reporting::{ContextualParseError, ParseErrorReporter};
use parser::{ParserContext, ParserErrorContext};
use selectors::parser::SelectorParseErrorKind;
use std::fmt::{self, Write};
use str::string_as_ascii_lowercase;
use style_traits::{CssWriter, ToCss, ParseError, StyleParseErrorKind};
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
use values::CustomIdent;
#[cfg(feature = "servo")]
@ -36,7 +36,9 @@ pub struct MediaList {
impl MediaList {
/// Create an empty MediaList.
pub fn empty() -> Self {
MediaList { media_queries: vec![] }
MediaList {
media_queries: vec![],
}
}
}
@ -182,44 +184,54 @@ impl MediaQuery {
/// Parse a media query given css input.
///
/// Returns an error if any of the expressions is unknown.
pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<MediaQuery, ParseError<'i>> {
pub fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<MediaQuery, ParseError<'i>> {
let mut expressions = vec![];
let qualifier = if input.try(|input| input.expect_ident_matching("only")).is_ok() {
let qualifier = if input
.try(|input| input.expect_ident_matching("only"))
.is_ok()
{
Some(Qualifier::Only)
} else if input.try(|input| input.expect_ident_matching("not")).is_ok() {
} else if input
.try(|input| input.expect_ident_matching("not"))
.is_ok()
{
Some(Qualifier::Not)
} else {
None
};
let media_type = match input.try(|i| i.expect_ident_cloned()) {
Ok(ident) => {
MediaQueryType::parse(&*ident)
.map_err(|()| {
input.new_custom_error(
SelectorParseErrorKind::UnexpectedIdent(ident.clone())
)
})?
}
Ok(ident) => MediaQueryType::parse(&*ident).map_err(|()| {
input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone()))
})?,
Err(_) => {
// Media type is only optional if qualifier is not specified.
if qualifier.is_some() {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
// Without a media type, require at least one expression.
expressions.push(Expression::parse(context, input)?);
MediaQueryType::All
}
},
};
// Parse any subsequent expressions
loop {
if input.try(|input| input.expect_ident_matching("and")).is_err() {
return Ok(MediaQuery { qualifier, media_type, expressions })
if input
.try(|input| input.expect_ident_matching("and"))
.is_err()
{
return Ok(MediaQuery {
qualifier,
media_type,
expressions,
});
}
expressions.push(Expression::parse(context, input)?)
}
@ -241,7 +253,7 @@ where
R: ParseErrorReporter,
{
if input.is_exhausted() {
return MediaList::empty()
return MediaList::empty();
}
let mut media_queries = vec![];
@ -254,8 +266,8 @@ where
Err(err) => {
media_queries.push(MediaQuery::never_matching());
let location = err.location;
let error = ContextualParseError::InvalidMediaRule(
input.slice_from(start_position), err);
let error =
ContextualParseError::InvalidMediaRule(input.slice_from(start_position), err);
let error_context = ParserErrorContext { error_reporter };
context.log_css_error(&error_context, location, error);
},
@ -282,9 +294,9 @@ impl MediaList {
let media_match = mq.media_type.matches(device.media_type());
// Check if all conditions match (AND condition)
let query_match =
media_match &&
mq.expressions.iter()
let query_match = media_match &&
mq.expressions
.iter()
.all(|expression| expression.matches(&device, quirks_mode));
// Apply the logical NOT qualifier to the result
@ -309,7 +321,9 @@ impl MediaList {
let mut parser = Parser::new(&mut input);
let new_query = match MediaQuery::parse(&context, &mut parser) {
Ok(query) => query,
Err(_) => { return false; }
Err(_) => {
return false;
},
};
// This algorithm doesn't actually matches the current spec,
// but it matches the behavior of Gecko and Edge.
@ -328,7 +342,9 @@ impl MediaList {
let mut parser = Parser::new(&mut input);
let old_query = match MediaQuery::parse(context, &mut parser) {
Ok(query) => query,
Err(_) => { return false; }
Err(_) => {
return false;
},
};
let old_len = self.media_queries.len();
self.media_queries.retain(|query| query != &old_query);

View file

@ -78,8 +78,7 @@ type WorkUnit<N> = ArrayVec<[SendNode<N>; WORK_UNIT_MAX]>;
fn create_thread_local_context<'scope, E, D>(
traversal: &'scope D,
slot: &mut Option<ThreadLocalStyleContext<E>>,
)
where
) where
E: TElement + 'scope,
D: DomTraversal<E>,
{
@ -109,8 +108,7 @@ fn top_down_dom<'a, 'scope, E, D>(
pool: &'scope rayon::ThreadPool,
traversal: &'scope D,
tls: &'scope ScopedTLS<'scope, ThreadLocalStyleContext<E>>,
)
where
) where
E: TElement + 'scope,
D: DomTraversal<E>,
{
@ -128,8 +126,9 @@ where
{
// Scope the borrow of the TLS so that the borrow is dropped before
// a potential recursive call when we pass TailCall.
let mut tlc = tls.ensure(
|slot: &mut Option<ThreadLocalStyleContext<E>>| create_thread_local_context(traversal, slot));
let mut tlc = tls.ensure(|slot: &mut Option<ThreadLocalStyleContext<E>>| {
create_thread_local_context(traversal, slot)
});
// Check that we're not in danger of running out of stack.
recursion_ok = !tlc.stack_limit_checker.limit_exceeded();
@ -180,15 +179,17 @@ where
if discovered_child_nodes.len() >= WORK_UNIT_MAX {
let mut traversal_data_copy = traversal_data.clone();
traversal_data_copy.current_dom_depth += 1;
traverse_nodes(discovered_child_nodes.drain(),
DispatchMode::NotTailCall,
recursion_ok,
root,
traversal_data_copy,
scope,
pool,
traversal,
tls);
traverse_nodes(
discovered_child_nodes.drain(),
DispatchMode::NotTailCall,
recursion_ok,
root,
traversal_data_copy,
scope,
pool,
traversal,
tls,
);
}
let node = **n;
@ -199,8 +200,7 @@ where
discovered_child_nodes.push(send_n);
});
traversal.handle_postorder_traversal(&mut context, root, node,
children_to_process);
traversal.handle_postorder_traversal(&mut context, root, node, children_to_process);
}
}
@ -209,15 +209,17 @@ where
// worth of them) directly on this thread by passing TailCall.
if !discovered_child_nodes.is_empty() {
traversal_data.current_dom_depth += 1;
traverse_nodes(discovered_child_nodes.drain(),
DispatchMode::TailCall,
recursion_ok,
root,
traversal_data,
scope,
pool,
traversal,
tls);
traverse_nodes(
discovered_child_nodes.drain(),
DispatchMode::TailCall,
recursion_ok,
root,
traversal_data,
scope,
pool,
traversal,
tls,
);
}
}
@ -232,7 +234,9 @@ pub enum DispatchMode {
}
impl DispatchMode {
fn is_tail_call(&self) -> bool { matches!(*self, DispatchMode::TailCall) }
fn is_tail_call(&self) -> bool {
matches!(*self, DispatchMode::TailCall)
}
}
/// Enqueues |nodes| for processing, possibly on this thread if the tail call
@ -247,12 +251,11 @@ pub fn traverse_nodes<'a, 'scope, E, D, I>(
scope: &'a rayon::Scope<'scope>,
pool: &'scope rayon::ThreadPool,
traversal: &'scope D,
tls: &'scope ScopedTLS<'scope, ThreadLocalStyleContext<E>>
)
where
tls: &'scope ScopedTLS<'scope, ThreadLocalStyleContext<E>>,
) where
E: TElement + 'scope,
D: DomTraversal<E>,
I: ExactSizeIterator<Item = SendNode<E::ConcreteNode>>
I: ExactSizeIterator<Item = SendNode<E::ConcreteNode>>,
{
debug_assert_ne!(nodes.len(), 0);
@ -263,22 +266,19 @@ where
// overflow due to excessive tail recursion. The stack overflow avoidance
// isn't observable to content -- we're still completely correct, just not
// using tail recursion any more. See Gecko bugs 1368302 and 1376883.
let may_dispatch_tail = mode.is_tail_call() &&
recursion_ok &&
!pool.current_thread_has_pending_tasks().unwrap();
let may_dispatch_tail =
mode.is_tail_call() && recursion_ok && !pool.current_thread_has_pending_tasks().unwrap();
// In the common case, our children fit within a single work unit, in which
// case we can pass the SmallVec directly and avoid extra allocation.
if nodes.len() <= WORK_UNIT_MAX {
let work: WorkUnit<E::ConcreteNode> = nodes.collect();
if may_dispatch_tail {
top_down_dom(&work, root,
traversal_data, scope, pool, traversal, tls);
top_down_dom(&work, root, traversal_data, scope, pool, traversal, tls);
} else {
scope.spawn(move |scope| {
let work = work;
top_down_dom(&work, root,
traversal_data, scope, pool, traversal, tls);
top_down_dom(&work, root, traversal_data, scope, pool, traversal, tls);
});
}
} else {
@ -287,8 +287,7 @@ where
let traversal_data_copy = traversal_data.clone();
scope.spawn(move |scope| {
let n = nodes;
top_down_dom(&*n, root,
traversal_data_copy, scope, pool, traversal, tls)
top_down_dom(&*n, root, traversal_data_copy, scope, pool, traversal, tls)
});
}
}

View file

@ -6,9 +6,9 @@
use context::QuirksMode;
use cssparser::{Parser, SourceLocation, UnicodeRange};
use error_reporting::{ParseErrorReporter, ContextualParseError};
use error_reporting::{ContextualParseError, ParseErrorReporter};
use style_traits::{OneOrMoreSeparated, ParseError, ParsingMode, Separator};
use stylesheets::{CssRuleType, Origin, UrlExtraData, Namespaces};
use stylesheets::{CssRuleType, Namespaces, Origin, UrlExtraData};
/// Asserts that all ParsingMode flags have a matching ParsingMode value in gecko.
#[cfg(feature = "gecko")]
@ -116,12 +116,14 @@ impl<'a> ParserContext<'a> {
/// Whether we're in a @page rule.
#[inline]
pub fn in_page_rule(&self) -> bool {
self.rule_type.map_or(false, |rule_type| rule_type == CssRuleType::Page)
self.rule_type
.map_or(false, |rule_type| rule_type == CssRuleType::Page)
}
/// Get the rule type, which assumes that one is available.
pub fn rule_type(&self) -> CssRuleType {
self.rule_type.expect("Rule type expected, but none was found.")
self.rule_type
.expect("Rule type expected, but none was found.")
}
/// Record a CSS parse error with this contexts error reporting.
@ -130,15 +132,16 @@ impl<'a> ParserContext<'a> {
context: &ParserErrorContext<R>,
location: SourceLocation,
error: ContextualParseError,
)
where
) where
R: ParseErrorReporter,
{
let location = SourceLocation {
line: location.line,
column: location.column,
};
context.error_reporter.report_error(self.url_data, location, error)
context
.error_reporter
.report_error(self.url_data, location, error)
}
/// Returns whether chrome-only rules should be parsed.
@ -151,7 +154,7 @@ impl<'a> ParserContext<'a> {
// trait. This will make it easy to write more generic values in the future.
/// A trait to abstract parsing of a specified value given a `ParserContext` and
/// CSS input.
pub trait Parse : Sized {
pub trait Parse: Sized {
/// Parse a value of this type.
///
/// Returns an error on failure.
@ -166,15 +169,19 @@ where
T: Parse + OneOrMoreSeparated,
<T as OneOrMoreSeparated>::S: Separator,
{
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
<T as OneOrMoreSeparated>::S::parse(input, |i| T::parse(context, i))
}
}
impl Parse for UnicodeRange {
fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
fn parse<'i, 't>(
_context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
UnicodeRange::parse(input).map_err(|e| e.into())
}
}

View file

@ -94,7 +94,7 @@ impl RuleCache {
/// and animations.
fn get_rule_node_for_cache<'r>(
guards: &StylesheetGuards,
mut rule_node: Option<&'r StrongRuleNode>
mut rule_node: Option<&'r StrongRuleNode>,
) -> Option<&'r StrongRuleNode> {
while let Some(node) = rule_node {
match *node.style_source() {
@ -104,8 +104,8 @@ impl RuleCache {
if decls.contains_any_reset() {
break;
}
}
StyleSource::None => {}
},
StyleSource::None => {},
StyleSource::Style(_) => break,
}
rule_node = node.parent();
@ -129,9 +129,11 @@ impl RuleCache {
// A pseudo-element with property restrictions can result in different
// computed values if it's also used for a non-pseudo.
if builder_with_early_props.pseudo
.and_then(|p| p.property_restriction())
.is_some() {
if builder_with_early_props
.pseudo
.and_then(|p| p.property_restriction())
.is_some()
{
return None;
}
@ -142,7 +144,7 @@ impl RuleCache {
for &(ref conditions, ref values) in cached_values.iter() {
if conditions.matches(builder_with_early_props) {
debug!("Using cached reset style with conditions {:?}", conditions);
return Some(&**values)
return Some(&**values);
}
}
None
@ -179,7 +181,10 @@ impl RuleCache {
None => return false,
};
debug!("Inserting cached reset style with conditions {:?}", conditions);
debug!(
"Inserting cached reset style with conditions {:?}",
conditions
);
self.map
.entry(rules)
.or_insert_with(SmallVec::new)
@ -187,5 +192,4 @@ impl RuleCache {
true
}
}

View file

@ -13,7 +13,7 @@ use gecko::selector_parser::PseudoElement;
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use properties::{Importance, LonghandIdSet, PropertyDeclarationBlock};
use servo_arc::{Arc, ArcBorrow, NonZeroPtrMut};
use shared_lock::{Locked, StylesheetGuards, SharedRwLockReadGuard};
use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
use smallvec::SmallVec;
use std::io::{self, Write};
use std::mem;
@ -52,15 +52,23 @@ pub struct RuleTree {
impl Drop for RuleTree {
fn drop(&mut self) {
// GC the rule tree.
unsafe { self.gc(); }
unsafe {
self.gc();
}
// After the GC, the free list should be empty.
debug_assert_eq!(self.root.get().next_free.load(Ordering::Relaxed), FREE_LIST_SENTINEL);
debug_assert_eq!(
self.root.get().next_free.load(Ordering::Relaxed),
FREE_LIST_SENTINEL
);
// Remove the sentinel. This indicates that GCs will no longer occur.
// Any further drops of StrongRuleNodes must occur on the main thread,
// and will trigger synchronous dropping of the Rule nodes.
self.root.get().next_free.store(ptr::null_mut(), Ordering::Relaxed);
self.root
.get()
.next_free
.store(ptr::null_mut(), Ordering::Relaxed);
}
}
@ -104,7 +112,9 @@ impl StyleSource {
match (self, other) {
(&Style(ref one), &Style(ref other)) => Arc::ptr_eq(one, other),
(&Declarations(ref one), &Declarations(ref other)) => Arc::ptr_eq(one, other),
(&None, _) | (_, &None) => panic!("Should not check for equality between null StyleSource objects"),
(&None, _) | (_, &None) => {
panic!("Should not check for equality between null StyleSource objects")
},
_ => false,
}
}
@ -185,10 +195,10 @@ impl RuleTree {
pub fn insert_ordered_rules_with_important<'a, I>(
&self,
iter: I,
guards: &StylesheetGuards
guards: &StylesheetGuards,
) -> StrongRuleNode
where
I: Iterator<Item=(StyleSource, CascadeLevel)>,
I: Iterator<Item = (StyleSource, CascadeLevel)>,
{
use self::CascadeLevel::*;
let mut current = self.root.clone();
@ -283,7 +293,7 @@ impl RuleTree {
pub fn compute_rule_node(
&self,
applicable_declarations: &mut ApplicableDeclarationList,
guards: &StylesheetGuards
guards: &StylesheetGuards,
) -> StrongRuleNode {
let rules = applicable_declarations.drain().map(|d| d.order_and_level());
let rule_node = self.insert_ordered_rules_with_important(rules, guards);
@ -293,15 +303,15 @@ impl RuleTree {
/// Insert the given rules, that must be in proper order by specifity, and
/// return the corresponding rule node representing the last inserted one.
pub fn insert_ordered_rules<'a, I>(&self, iter: I) -> StrongRuleNode
where I: Iterator<Item=(StyleSource, CascadeLevel)>,
where
I: Iterator<Item = (StyleSource, CascadeLevel)>,
{
self.insert_ordered_rules_from(self.root.clone(), iter)
}
fn insert_ordered_rules_from<'a, I>(&self,
from: StrongRuleNode,
iter: I) -> StrongRuleNode
where I: Iterator<Item=(StyleSource, CascadeLevel)>,
fn insert_ordered_rules_from<'a, I>(&self, from: StrongRuleNode, iter: I) -> StrongRuleNode
where
I: Iterator<Item = (StyleSource, CascadeLevel)>,
{
let mut current = from;
let mut last_level = current.get().level;
@ -327,13 +337,14 @@ impl RuleTree {
///
/// Returns the resulting node that represents the new path, or None if
/// the old path is still valid.
pub fn update_rule_at_level(&self,
level: CascadeLevel,
pdb: Option<ArcBorrow<Locked<PropertyDeclarationBlock>>>,
path: &StrongRuleNode,
guards: &StylesheetGuards,
important_rules_changed: &mut bool)
-> Option<StrongRuleNode> {
pub fn update_rule_at_level(
&self,
level: CascadeLevel,
pdb: Option<ArcBorrow<Locked<PropertyDeclarationBlock>>>,
path: &StrongRuleNode,
guards: &StylesheetGuards,
important_rules_changed: &mut bool,
) -> Option<StrongRuleNode> {
debug_assert!(level.is_unique_per_element());
// TODO(emilio): Being smarter with lifetimes we could avoid a bit of
// the refcount churn.
@ -384,8 +395,10 @@ impl RuleTree {
}
current = current.parent().unwrap().clone();
}
debug_assert!(current.get().level != level,
"Multiple rules should've been replaced?");
debug_assert!(
current.get().level != level,
"Multiple rules should've been replaced?"
);
// Insert the rule if it's relevant at this level in the cascade.
//
@ -395,23 +408,26 @@ impl RuleTree {
if let Some(pdb) = pdb {
if level.is_important() {
if pdb.read_with(level.guard(guards)).any_important() {
current = current.ensure_child(self.root.downgrade(),
StyleSource::Declarations(pdb.clone_arc()),
level);
current = current.ensure_child(
self.root.downgrade(),
StyleSource::Declarations(pdb.clone_arc()),
level,
);
}
} else {
if pdb.read_with(level.guard(guards)).any_normal() {
current = current.ensure_child(self.root.downgrade(),
StyleSource::Declarations(pdb.clone_arc()),
level);
current = current.ensure_child(
self.root.downgrade(),
StyleSource::Declarations(pdb.clone_arc()),
level,
);
}
}
}
// Now the rule is in the relevant place, push the children as
// necessary.
let rule =
self.insert_ordered_rules_from(current, children.drain().rev());
let rule = self.insert_ordered_rules_from(current, children.drain().rev());
Some(rule)
}
@ -432,8 +448,8 @@ impl RuleTree {
return path.clone();
}
let iter = path.self_and_ancestors().take_while(
|node| node.cascade_level() >= CascadeLevel::SMILOverride);
let iter = path.self_and_ancestors()
.take_while(|node| node.cascade_level() >= CascadeLevel::SMILOverride);
let mut last = path;
let mut children = SmallVec::<[_; 10]>::new();
for node in iter {
@ -443,7 +459,8 @@ impl RuleTree {
last = node;
}
let rule = self.insert_ordered_rules_from(last.parent().unwrap().clone(), children.drain().rev());
let rule =
self.insert_ordered_rules_from(last.parent().unwrap().clone(), children.drain().rev());
rule
}
@ -459,11 +476,13 @@ impl RuleTree {
guards: &StylesheetGuards,
) -> StrongRuleNode {
let mut dummy = false;
self.update_rule_at_level(CascadeLevel::Transitions,
Some(pdb.borrow_arc()),
path,
guards,
&mut dummy).expect("Should return a valid rule node")
self.update_rule_at_level(
CascadeLevel::Transitions,
Some(pdb.borrow_arc()),
path,
guards,
&mut dummy,
).expect("Should return a valid rule node")
}
}
@ -575,9 +594,9 @@ impl CascadeLevel {
#[inline]
pub fn is_animation(&self) -> bool {
match *self {
CascadeLevel::SMILOverride |
CascadeLevel::Animations |
CascadeLevel::Transitions => true,
CascadeLevel::SMILOverride | CascadeLevel::Animations | CascadeLevel::Transitions => {
true
},
_ => false,
}
}
@ -642,32 +661,32 @@ unsafe impl Send for RuleTree {}
#[cfg(feature = "gecko")]
#[cfg(debug_assertions)]
mod gecko_leak_checking {
use std::mem::size_of;
use std::os::raw::{c_char, c_void};
use super::RuleNode;
use std::mem::size_of;
use std::os::raw::{c_char, c_void};
use super::RuleNode;
extern "C" {
pub fn NS_LogCtor(aPtr: *const c_void, aTypeName: *const c_char, aSize: u32);
pub fn NS_LogDtor(aPtr: *const c_void, aTypeName: *const c_char, aSize: u32);
}
static NAME: &'static [u8] = b"RuleNode\0";
/// Logs the creation of a heap-allocated object to Gecko's leak-checking machinery.
pub fn log_ctor(ptr: *const RuleNode) {
let s = NAME as *const [u8] as *const u8 as *const c_char;
unsafe {
NS_LogCtor(ptr as *const c_void, s, size_of::<RuleNode>() as u32);
extern "C" {
pub fn NS_LogCtor(aPtr: *const c_void, aTypeName: *const c_char, aSize: u32);
pub fn NS_LogDtor(aPtr: *const c_void, aTypeName: *const c_char, aSize: u32);
}
}
/// Logs the destruction of a heap-allocated object to Gecko's leak-checking machinery.
pub fn log_dtor(ptr: *const RuleNode) {
let s = NAME as *const [u8] as *const u8 as *const c_char;
unsafe {
NS_LogDtor(ptr as *const c_void, s, size_of::<RuleNode>() as u32);
static NAME: &'static [u8] = b"RuleNode\0";
/// Logs the creation of a heap-allocated object to Gecko's leak-checking machinery.
pub fn log_ctor(ptr: *const RuleNode) {
let s = NAME as *const [u8] as *const u8 as *const c_char;
unsafe {
NS_LogCtor(ptr as *const c_void, s, size_of::<RuleNode>() as u32);
}
}
/// Logs the destruction of a heap-allocated object to Gecko's leak-checking machinery.
pub fn log_dtor(ptr: *const RuleNode) {
let s = NAME as *const [u8] as *const u8 as *const c_char;
unsafe {
NS_LogDtor(ptr as *const c_void, s, size_of::<RuleNode>() as u32);
}
}
}
}
@ -686,10 +705,12 @@ fn log_drop(_ptr: *const RuleNode) {
}
impl RuleNode {
fn new(root: WeakRuleNode,
parent: StrongRuleNode,
source: StyleSource,
level: CascadeLevel) -> Self {
fn new(
root: WeakRuleNode,
parent: StrongRuleNode,
source: StyleSource,
level: CascadeLevel,
) -> Self {
debug_assert!(root.upgrade().parent().is_none());
RuleNode {
root: Some(root),
@ -751,21 +772,25 @@ impl RuleNode {
/// This is expected to be called before freeing the node from the free
/// list.
unsafe fn remove_from_child_list(&self) {
debug!("Remove from child list: {:?}, parent: {:?}",
self as *const RuleNode, self.parent.as_ref().map(|p| p.ptr()));
debug!(
"Remove from child list: {:?}, parent: {:?}",
self as *const RuleNode,
self.parent.as_ref().map(|p| p.ptr())
);
// NB: The other siblings we use in this function can also be dead, so
// we can't use `get` here, since it asserts.
let prev_sibling =
self.prev_sibling().swap(ptr::null_mut(), Ordering::Relaxed);
let prev_sibling = self.prev_sibling().swap(ptr::null_mut(), Ordering::Relaxed);
let next_sibling =
self.next_sibling.swap(ptr::null_mut(), Ordering::Relaxed);
let next_sibling = self.next_sibling.swap(ptr::null_mut(), Ordering::Relaxed);
// Store the `next` pointer as appropriate, either in the previous
// sibling, or in the parent otherwise.
if prev_sibling.is_null() {
let parent = self.parent.as_ref().unwrap();
parent.get().first_child.store(next_sibling, Ordering::Relaxed);
parent
.get()
.first_child
.store(next_sibling, Ordering::Relaxed);
} else {
let previous = &*prev_sibling;
previous.next_sibling.store(next_sibling, Ordering::Relaxed);
@ -786,9 +811,13 @@ impl RuleNode {
let _ = write!(writer, " ");
}
let _ = writeln!(writer, " - {:?} (ref: {:?}, parent: {:?})",
self as *const _, self.refcount.load(Ordering::Relaxed),
self.parent.as_ref().map(|p| p.ptr()));
let _ = writeln!(
writer,
" - {:?} (ref: {:?}, parent: {:?})",
self as *const _,
self.refcount.load(Ordering::Relaxed),
self.parent.as_ref().map(|p| p.ptr())
);
for _ in 0..indent {
let _ = write!(writer, " ");
@ -805,7 +834,10 @@ impl RuleNode {
let _ = write!(writer, "\n");
for child in self.iter_children() {
child.upgrade().get().dump(guards, writer, indent + INDENT_INCREMENT);
child
.upgrade()
.get()
.dump(guards, writer, indent + INDENT_INCREMENT);
}
}
@ -817,7 +849,7 @@ impl RuleNode {
None
} else {
Some(WeakRuleNode::from_ptr(first_child))
}
},
}
}
}
@ -864,7 +896,7 @@ impl StrongRuleNode {
fn from_ptr(ptr: *mut RuleNode) -> Self {
StrongRuleNode {
p: NonZeroPtrMut::new(ptr)
p: NonZeroPtrMut::new(ptr),
}
}
@ -881,7 +913,7 @@ impl StrongRuleNode {
&self,
root: WeakRuleNode,
source: StyleSource,
level: CascadeLevel
level: CascadeLevel,
) -> StrongRuleNode {
let mut last = None;
@ -894,17 +926,13 @@ impl StrongRuleNode {
// WeakRuleNode, and implementing this on WeakRuleNode itself...
for child in self.get().iter_children() {
let child_node = unsafe { &*child.ptr() };
if child_node.level == level &&
child_node.source.ptr_equals(&source) {
if child_node.level == level && child_node.source.ptr_equals(&source) {
return child.upgrade();
}
last = Some(child);
}
let mut node = Box::new(RuleNode::new(root,
self.clone(),
source.clone(),
level));
let mut node = Box::new(RuleNode::new(root, self.clone(), source.clone(), level));
let new_ptr: *mut RuleNode = &mut *node;
loop {
@ -920,9 +948,7 @@ impl StrongRuleNode {
// We use `AqcRel` semantics to ensure the initializing writes
// in `node` are visible after the swap succeeds.
let existing =
next_sibling_ptr.compare_and_swap(ptr::null_mut(),
new_ptr,
Ordering::AcqRel);
next_sibling_ptr.compare_and_swap(ptr::null_mut(), new_ptr, Ordering::AcqRel);
if existing.is_null() {
// Now we know we're in the correct position in the child
@ -985,7 +1011,7 @@ impl StrongRuleNode {
/// Get an iterator for this rule node and its ancestors.
pub fn self_and_ancestors(&self) -> SelfAndAncestors {
SelfAndAncestors {
current: Some(self)
current: Some(self),
}
}
@ -1008,29 +1034,41 @@ impl StrongRuleNode {
// case, so just don't crash in the case we're doing the final GC in
// script.
debug_assert!(!thread_state::get().is_worker() &&
(thread_state::get().is_layout() ||
thread_state::get().is_script()));
debug_assert!(
!thread_state::get().is_worker() &&
(thread_state::get().is_layout() || thread_state::get().is_script())
);
let current = me.next_free.load(Ordering::Relaxed);
if current == FREE_LIST_SENTINEL {
return None;
}
debug_assert!(!current.is_null(),
"Multiple threads are operating on the free list at the \
same time?");
debug_assert!(current != self.ptr(),
"How did the root end up in the free list?");
debug_assert!(
!current.is_null(),
"Multiple threads are operating on the free list at the \
same time?"
);
debug_assert!(
current != self.ptr(),
"How did the root end up in the free list?"
);
let next = (*current).next_free.swap(ptr::null_mut(), Ordering::Relaxed);
let next = (*current)
.next_free
.swap(ptr::null_mut(), Ordering::Relaxed);
debug_assert!(!next.is_null(),
"How did a null pointer end up in the free list?");
debug_assert!(
!next.is_null(),
"How did a null pointer end up in the free list?"
);
me.next_free.store(next, Ordering::Relaxed);
debug!("Popping from free list: cur: {:?}, next: {:?}", current, next);
debug!(
"Popping from free list: cur: {:?}, next: {:?}",
current, next
);
Some(WeakRuleNode::from_ptr(current))
}
@ -1105,7 +1143,7 @@ impl StrongRuleNode {
author_colors_allowed: bool,
) -> bool
where
E: ::dom::TElement
E: ::dom::TElement,
{
use gecko_bindings::structs::NS_AUTHOR_SPECIFIED_BACKGROUND;
use gecko_bindings::structs::NS_AUTHOR_SPECIFIED_BORDER;
@ -1116,10 +1154,8 @@ impl StrongRuleNode {
use values::specified::Color;
// Reset properties:
const BACKGROUND_PROPS: &'static [LonghandId] = &[
LonghandId::BackgroundColor,
LonghandId::BackgroundImage,
];
const BACKGROUND_PROPS: &'static [LonghandId] =
&[LonghandId::BackgroundColor, LonghandId::BackgroundImage];
const BORDER_PROPS: &'static [LonghandId] = &[
LonghandId::BorderTopColor,
@ -1138,7 +1174,6 @@ impl StrongRuleNode {
LonghandId::BorderTopRightRadius,
LonghandId::BorderBottomRightRadius,
LonghandId::BorderBottomLeftRadius,
LonghandId::BorderInlineStartColor,
LonghandId::BorderInlineStartStyle,
LonghandId::BorderInlineStartWidth,
@ -1158,7 +1193,6 @@ impl StrongRuleNode {
LonghandId::PaddingRight,
LonghandId::PaddingBottom,
LonghandId::PaddingLeft,
LonghandId::PaddingInlineStart,
LonghandId::PaddingInlineEnd,
LonghandId::PaddingBlockStart,
@ -1187,7 +1221,7 @@ impl StrongRuleNode {
// If author colors are not allowed, only claim to have author-specified
// rules if we're looking at a non-color property or if we're looking at
// the background color and it's set to transparent.
const IGNORED_WHEN_COLORS_DISABLED: &'static [LonghandId] = &[
const IGNORED_WHEN_COLORS_DISABLED: &'static [LonghandId] = &[
LonghandId::BackgroundImage,
LonghandId::BorderTopColor,
LonghandId::BorderRightColor,
@ -1222,30 +1256,31 @@ impl StrongRuleNode {
for node in element_rule_node.self_and_ancestors() {
let source = node.style_source();
let declarations = if source.is_some() {
source.read(node.cascade_level().guard(guards)).declaration_importance_iter()
source
.read(node.cascade_level().guard(guards))
.declaration_importance_iter()
} else {
continue
continue;
};
// Iterate over declarations of the longhands we care about.
let node_importance = node.importance();
let longhands = declarations.rev()
.filter_map(|(declaration, importance)| {
if importance != node_importance { return None }
match declaration.id() {
PropertyDeclarationId::Longhand(id) => {
Some((id, declaration))
}
_ => None
}
});
let longhands = declarations.rev().filter_map(|(declaration, importance)| {
if importance != node_importance {
return None;
}
match declaration.id() {
PropertyDeclarationId::Longhand(id) => Some((id, declaration)),
_ => None,
}
});
match node.cascade_level() {
// Non-author rules:
CascadeLevel::UANormal |
CascadeLevel::UAImportant |
CascadeLevel::UserNormal |
CascadeLevel::UserImportant => {
CascadeLevel::UserImportant => {
for (id, declaration) in longhands {
if properties.contains(id) {
// This property was set by a non-author rule.
@ -1256,13 +1291,15 @@ impl StrongRuleNode {
// However, if it is inherited, then it might be
// inherited from an author rule from an
// ancestor element's rule nodes.
if declaration.get_css_wide_keyword() == Some(CSSWideKeyword::Inherit) {
if declaration.get_css_wide_keyword() ==
Some(CSSWideKeyword::Inherit)
{
have_explicit_ua_inherit = true;
inherited_properties.insert(id);
}
}
}
}
},
// Author rules:
CascadeLevel::PresHints |
CascadeLevel::AuthorNormal |
@ -1275,18 +1312,22 @@ impl StrongRuleNode {
for (id, declaration) in longhands {
if properties.contains(id) {
if !author_colors_allowed {
if let PropertyDeclaration::BackgroundColor(ref color) = *declaration {
return *color == Color::transparent()
if let PropertyDeclaration::BackgroundColor(ref color) =
*declaration
{
return *color == Color::transparent();
}
}
return true
return true;
}
}
}
},
}
}
if !have_explicit_ua_inherit { break }
if !have_explicit_ua_inherit {
break;
}
// Continue to the parent element and search for the inherited properties.
if let Some(pseudo) = pseudo.take() {
@ -1296,7 +1337,7 @@ impl StrongRuleNode {
} else {
element = match element.inheritance_parent() {
Some(parent) => parent,
None => break
None => break,
};
let parent_data = element.mutate_data().unwrap();
@ -1322,9 +1363,10 @@ impl StrongRuleNode {
///
/// If there are any custom properties, we set the boolean value of the
/// returned tuple to true.
pub fn get_properties_overriding_animations(&self,
guards: &StylesheetGuards)
-> (LonghandIdSet, bool) {
pub fn get_properties_overriding_animations(
&self,
guards: &StylesheetGuards,
) -> (LonghandIdSet, bool) {
use properties::PropertyDeclarationId;
// We want to iterate over cascade levels that override the animations
@ -1335,15 +1377,16 @@ impl StrongRuleNode {
// transitions and animations are present for a given element and
// property, transitions are suppressed so that they don't actually
// override animations.
let iter =
self.self_and_ancestors()
.skip_while(|node| node.cascade_level() == CascadeLevel::Transitions)
.take_while(|node| node.cascade_level() > CascadeLevel::Animations);
let iter = self.self_and_ancestors()
.skip_while(|node| node.cascade_level() == CascadeLevel::Transitions)
.take_while(|node| node.cascade_level() > CascadeLevel::Animations);
let mut result = (LonghandIdSet::new(), false);
for node in iter {
let style = node.style_source();
for (decl, important) in style.read(node.cascade_level().guard(guards))
.declaration_importance_iter() {
for (decl, important) in style
.read(node.cascade_level().guard(guards))
.declaration_importance_iter()
{
// Although we are only iterating over cascade levels that
// override animations, in a given property declaration block we
// can have a mixture of !important and non-!important
@ -1352,7 +1395,7 @@ impl StrongRuleNode {
if important.important() {
match decl.id() {
PropertyDeclarationId::Longhand(id) => result.0.insert(id),
PropertyDeclarationId::Custom(_) => result.1 = true
PropertyDeclarationId::Custom(_) => result.1 = true,
}
}
}
@ -1363,8 +1406,10 @@ impl StrongRuleNode {
/// Returns PropertyDeclarationBlock for this node.
/// This function must be called only for animation level node.
fn get_animation_style(&self) -> &Arc<Locked<PropertyDeclarationBlock>> {
debug_assert!(self.cascade_level().is_animation(),
"The cascade level should be an animation level");
debug_assert!(
self.cascade_level().is_animation(),
"The cascade level should be an animation level"
);
match *self.style_source() {
StyleSource::Declarations(ref block) => block,
StyleSource::Style(_) => unreachable!("animating style should not be a style rule"),
@ -1405,7 +1450,11 @@ impl<'a> Iterator for SelfAndAncestors<'a> {
impl Clone for StrongRuleNode {
fn clone(&self) -> Self {
debug!("{:?}: {:?}+", self.ptr(), self.get().refcount.load(Ordering::Relaxed));
debug!(
"{:?}: {:?}+",
self.ptr(),
self.get().refcount.load(Ordering::Relaxed)
);
debug_assert!(self.get().refcount.load(Ordering::Relaxed) > 0);
self.get().refcount.fetch_add(1, Ordering::Relaxed);
StrongRuleNode::from_ptr(self.ptr())
@ -1416,22 +1465,27 @@ impl Drop for StrongRuleNode {
fn drop(&mut self) {
let node = unsafe { &*self.ptr() };
debug!("{:?}: {:?}-", self.ptr(), node.refcount.load(Ordering::Relaxed));
debug!("Dropping node: {:?}, root: {:?}, parent: {:?}",
self.ptr(),
node.root.as_ref().map(|r| r.ptr()),
node.parent.as_ref().map(|p| p.ptr()));
debug!(
"{:?}: {:?}-",
self.ptr(),
node.refcount.load(Ordering::Relaxed)
);
debug!(
"Dropping node: {:?}, root: {:?}, parent: {:?}",
self.ptr(),
node.root.as_ref().map(|r| r.ptr()),
node.parent.as_ref().map(|p| p.ptr())
);
let should_drop = {
debug_assert!(node.refcount.load(Ordering::Relaxed) > 0);
node.refcount.fetch_sub(1, Ordering::Relaxed) == 1
};
if !should_drop {
return
return;
}
debug_assert_eq!(node.first_child.load(Ordering::Acquire),
ptr::null_mut());
debug_assert_eq!(node.first_child.load(Ordering::Acquire), ptr::null_mut());
if node.parent.is_none() {
debug!("Dropping root node!");
// The free list should be null by this point
@ -1456,9 +1510,10 @@ impl Drop for StrongRuleNode {
//
// [1] https://bugzilla.mozilla.org/show_bug.cgi?id=439184
if old_head.is_null() {
debug_assert!(!thread_state::get().is_worker() &&
(thread_state::get().is_layout() ||
thread_state::get().is_script()));
debug_assert!(
!thread_state::get().is_worker() &&
(thread_state::get().is_layout() || thread_state::get().is_script())
);
// Add the node as the sole entry in the free list.
debug_assert!(node.next_free.load(Ordering::Relaxed).is_null());
node.next_free.store(FREE_LIST_SENTINEL, Ordering::Relaxed);
@ -1472,12 +1527,13 @@ impl Drop for StrongRuleNode {
// enforced by having the gc() method live on StrongRuleNode rather than
// RuleNode.
let strong_root: StrongRuleNode = node.root.as_ref().unwrap().upgrade();
unsafe { strong_root.gc(); }
unsafe {
strong_root.gc();
}
// Leave the free list null, like we found it, such that additional
// drops for straggling rule nodes will take this same codepath.
debug_assert_eq!(root.next_free.load(Ordering::Relaxed),
FREE_LIST_SENTINEL);
debug_assert_eq!(root.next_free.load(Ordering::Relaxed), FREE_LIST_SENTINEL);
root.next_free.store(ptr::null_mut(), Ordering::Relaxed);
// Return. If strong_root is the last strong reference to the root,
@ -1500,10 +1556,12 @@ impl Drop for StrongRuleNode {
// reads/writes we do below are properly visible from multiple threads
// racing.
loop {
match free_list.compare_exchange_weak(old_head,
FREE_LIST_LOCKED,
Ordering::Acquire,
Ordering::Relaxed) {
match free_list.compare_exchange_weak(
old_head,
FREE_LIST_LOCKED,
Ordering::Acquire,
Ordering::Relaxed,
) {
Ok(..) => {
if old_head != FREE_LIST_LOCKED {
break;
@ -1533,7 +1591,8 @@ impl Drop for StrongRuleNode {
// Increment the free count. This doesn't need to be an RMU atomic
// operation, because the free list is "locked".
let old_free_count = root.free_count().load(Ordering::Relaxed);
root.free_count().store(old_free_count + 1, Ordering::Relaxed);
root.free_count()
.store(old_free_count + 1, Ordering::Relaxed);
// This can be release because of the locking of the free list, that
// ensures that all the other nodes racing with this one are using
@ -1559,7 +1618,7 @@ impl WeakRuleNode {
fn from_ptr(ptr: *mut RuleNode) -> Self {
WeakRuleNode {
p: NonZeroPtrMut::new(ptr)
p: NonZeroPtrMut::new(ptr),
}
}

View file

@ -16,8 +16,8 @@ use hashglobe::FailedAllocationError;
use precomputed_hash::PrecomputedHash;
use rule_tree::CascadeLevel;
use selector_parser::SelectorImpl;
use selectors::matching::{matches_selector, MatchingContext, ElementSelectorFlags};
use selectors::parser::{Component, Combinator, SelectorIter};
use selectors::matching::{matches_selector, ElementSelectorFlags, MatchingContext};
use selectors::parser::{Combinator, Component, SelectorIter};
use smallvec::SmallVec;
use std::hash::{BuildHasherDefault, Hash, Hasher};
use stylist::Rule;
@ -43,8 +43,10 @@ pub type PrecomputedHashSet<K> = HashSet<K, BuildHasherDefault<PrecomputedHasher
impl Hasher for PrecomputedHasher {
#[inline]
fn write(&mut self, _: &[u8]) {
unreachable!("Called into PrecomputedHasher with something that isn't \
a u32")
unreachable!(
"Called into PrecomputedHasher with something that isn't \
a u32"
)
}
#[inline]
@ -60,7 +62,7 @@ impl Hasher for PrecomputedHasher {
}
/// A trait to abstract over a given selector map entry.
pub trait SelectorMapEntry : Sized + Clone {
pub trait SelectorMapEntry: Sized + Clone {
/// Gets the selector we should use to index in the selector map.
fn selector(&self) -> SelectorIter<SelectorImpl>;
}
@ -161,13 +163,12 @@ impl SelectorMap<Rule> {
context: &mut MatchingContext<E::Impl>,
flags_setter: &mut F,
cascade_level: CascadeLevel,
)
where
) where
E: TElement,
F: FnMut(&E, ElementSelectorFlags),
{
if self.is_empty() {
return
return;
}
let quirks_mode = context.quirks_mode();
@ -222,7 +223,8 @@ impl SelectorMap<Rule> {
);
// Sort only the rules we just added.
matching_rules_list[init_len..].sort_unstable_by_key(|block| (block.specificity, block.source_order()));
matching_rules_list[init_len..]
.sort_unstable_by_key(|block| (block.specificity, block.source_order()));
}
/// Adds rules in `rules` that match `element` to the `matching_rules` list.
@ -233,20 +235,20 @@ impl SelectorMap<Rule> {
context: &mut MatchingContext<E::Impl>,
flags_setter: &mut F,
cascade_level: CascadeLevel,
)
where
) where
E: TElement,
F: FnMut(&E, ElementSelectorFlags),
{
for rule in rules {
if matches_selector(&rule.selector,
0,
Some(&rule.hashes),
&element,
context,
flags_setter) {
matching_rules.push(
rule.to_applicable_declaration_block(cascade_level));
if matches_selector(
&rule.selector,
0,
Some(&rule.hashes),
&element,
context,
flags_setter,
) {
matching_rules.push(rule.to_applicable_declaration_block(cascade_level));
}
}
}
@ -262,14 +264,12 @@ impl<T: SelectorMapEntry> SelectorMap<T> {
self.count += 1;
let vector = match find_bucket(entry.selector()) {
Bucket::ID(id) => {
self.id_hash.try_entry(id.clone(), quirks_mode)?
.or_insert_with(SmallVec::new)
}
Bucket::Class(class) => {
self.class_hash.try_entry(class.clone(), quirks_mode)?
.or_insert_with(SmallVec::new)
}
Bucket::ID(id) => self.id_hash
.try_entry(id.clone(), quirks_mode)?
.or_insert_with(SmallVec::new),
Bucket::Class(class) => self.class_hash
.try_entry(class.clone(), quirks_mode)?
.or_insert_with(SmallVec::new),
Bucket::LocalName { name, lower_name } => {
// If the local name in the selector isn't lowercase, insert it
// into the rule hash twice. This means that, during lookup, we
@ -288,12 +288,11 @@ impl<T: SelectorMapEntry> SelectorMap<T> {
.or_insert_with(SmallVec::new)
.try_push(entry.clone())?;
}
self.local_name_hash.try_entry(name.clone())?
self.local_name_hash
.try_entry(name.clone())?
.or_insert_with(SmallVec::new)
}
Bucket::Universal => {
&mut self.other
}
},
Bucket::Universal => &mut self.other,
};
vector.try_push(entry)
@ -312,7 +311,7 @@ impl<T: SelectorMapEntry> SelectorMap<T> {
pub fn lookup<'a, E, F>(&'a self, element: E, quirks_mode: QuirksMode, mut f: F) -> bool
where
E: TElement,
F: FnMut(&'a T) -> bool
F: FnMut(&'a T) -> bool,
{
// Id.
if let Some(id) = element.id() {
@ -380,7 +379,7 @@ impl<T: SelectorMapEntry> SelectorMap<T> {
) -> bool
where
E: TElement,
F: FnMut(&'a T) -> bool
F: FnMut(&'a T) -> bool,
{
// Do the normal lookup.
if !self.lookup(element, quirks_mode, |entry| f(entry)) {
@ -416,22 +415,21 @@ impl<T: SelectorMapEntry> SelectorMap<T> {
enum Bucket<'a> {
ID(&'a Atom),
Class(&'a Atom),
LocalName { name: &'a LocalName, lower_name: &'a LocalName, },
LocalName {
name: &'a LocalName,
lower_name: &'a LocalName,
},
Universal,
}
fn specific_bucket_for<'a>(
component: &'a Component<SelectorImpl>
) -> Bucket<'a> {
fn specific_bucket_for<'a>(component: &'a Component<SelectorImpl>) -> Bucket<'a> {
match *component {
Component::ID(ref id) => Bucket::ID(id),
Component::Class(ref class) => Bucket::Class(class),
Component::LocalName(ref selector) => {
Bucket::LocalName {
name: &selector.name,
lower_name: &selector.lower_name,
}
}
Component::LocalName(ref selector) => Bucket::LocalName {
name: &selector.name,
lower_name: &selector.lower_name,
},
// ::slotted(..) isn't a normal pseudo-element, so we can insert it on
// the rule hash normally without much problem. For example, in a
// selector like:
@ -458,7 +456,7 @@ fn specific_bucket_for<'a>(
// Meanwhile taking the code path below is slower, but still correct.
// Component::Slotted(ref selector) => find_bucket(selector.iter()),
Component::Host(Some(ref selector)) => find_bucket(selector.iter()),
_ => Bucket::Universal
_ => Bucket::Universal,
}
}
@ -480,12 +478,12 @@ fn find_bucket<'a>(mut iter: SelectorIter<'a, SelectorImpl>) -> Bucket<'a> {
Bucket::ID(..) => return new_bucket,
Bucket::Class(..) => {
current_bucket = new_bucket;
}
},
Bucket::LocalName { .. } => {
if matches!(current_bucket, Bucket::Universal) {
current_bucket = new_bucket;
}
}
},
Bucket::Universal => {},
}
}
@ -497,12 +495,14 @@ fn find_bucket<'a>(mut iter: SelectorIter<'a, SelectorImpl>) -> Bucket<'a> {
}
}
return current_bucket
return current_bucket;
}
/// Wrapper for PrecomputedHashMap that does ASCII-case-insensitive lookup in quirks mode.
#[derive(Debug, MallocSizeOf)]
pub struct MaybeCaseInsensitiveHashMap<K: PrecomputedHash + Hash + Eq, V: 'static>(PrecomputedHashMap<K, V>);
pub struct MaybeCaseInsensitiveHashMap<K: PrecomputedHash + Hash + Eq, V: 'static>(
PrecomputedHashMap<K, V>,
);
// FIXME(Manishearth) the 'static bound can be removed when
// our HashMap fork (hashglobe) is able to use NonZero,

View file

@ -10,7 +10,7 @@ use cssparser::{Parser as CssParser, ParserInput};
use selectors::parser::SelectorList;
use std::fmt::{self, Debug, Write};
use style_traits::{CssWriter, ParseError, ToCss};
use stylesheets::{Origin, Namespaces, UrlExtraData};
use stylesheets::{Namespaces, Origin, UrlExtraData};
/// A convenient alias for the type that represents an attribute value used for
/// selector parser implementation.
@ -51,8 +51,9 @@ impl<'a> SelectorParser<'a> {
/// account namespaces.
///
/// This is used for some DOM APIs like `querySelector`.
pub fn parse_author_origin_no_namespace(input: &str)
-> Result<SelectorList<SelectorImpl>, ParseError> {
pub fn parse_author_origin_no_namespace(
input: &str,
) -> Result<SelectorList<SelectorImpl>, ParseError> {
let namespaces = Namespaces::default();
let parser = SelectorParser {
stylesheet_origin: Origin::Author,
@ -71,8 +72,7 @@ impl<'a> SelectorParser<'a> {
/// Whether we're parsing selectors in a stylesheet that has chrome
/// privilege.
pub fn chrome_rules_enabled(&self) -> bool {
self.url_data.map_or(false, |d| d.is_chrome()) ||
self.stylesheet_origin == Origin::User
self.url_data.map_or(false, |d| d.is_chrome()) || self.stylesheet_origin == Origin::User
}
}
@ -154,11 +154,7 @@ impl<T> PerPseudoElementMap<T> {
}
/// Get an entry for `pseudo`, or create it with calling `f`.
pub fn get_or_insert_with<F>(
&mut self,
pseudo: &PseudoElement,
f: F,
) -> &mut T
pub fn get_or_insert_with<F>(&mut self, pseudo: &PseudoElement, f: F) -> &mut T
where
F: FnOnce() -> T,
{
@ -201,7 +197,10 @@ impl Direction {
}
impl ToCss for Direction {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: Write {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
let dir_str = match *self {
Direction::Rtl => "rtl",
Direction::Ltr => "ltr",

View file

@ -7,14 +7,14 @@
use app_units::Au;
use context::QuirksMode;
use cssparser::{Parser, RGBA};
use euclid::{TypedScale, Size2D, TypedSize2D};
use euclid::{Size2D, TypedScale, TypedSize2D};
use media_queries::MediaType;
use parser::ParserContext;
use properties::ComputedValues;
use selectors::parser::SelectorParseErrorKind;
use std::fmt::{self, Write};
use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering};
use style_traits::{CSSPixel, CssWriter, DevicePixel, ToCss, ParseError};
use style_traits::{CSSPixel, CssWriter, DevicePixel, ParseError, ToCss};
use style_traits::viewport::ViewportConstraints;
use values::{specified, KeyframesName};
use values::computed::{self, ToComputedValue};
@ -57,7 +57,7 @@ impl Device {
pub fn new(
media_type: MediaType,
viewport_size: TypedSize2D<f32, CSSPixel>,
device_pixel_ratio: TypedScale<f32, CSSPixel, DevicePixel>
device_pixel_ratio: TypedScale<f32, CSSPixel, DevicePixel>,
) -> Device {
Device {
media_type,
@ -86,7 +86,8 @@ impl Device {
/// Set the font size of the root element (for rem)
pub fn set_root_font_size(&self, size: Au) {
self.root_font_size.store(size.0 as isize, Ordering::Relaxed)
self.root_font_size
.store(size.0 as isize, Ordering::Relaxed)
}
/// Sets the body text color for the "inherit color from body" quirk.
@ -111,8 +112,10 @@ impl Device {
/// among other things, to resolve viewport units.
#[inline]
pub fn au_viewport_size(&self) -> Size2D<Au> {
Size2D::new(Au::from_f32_px(self.viewport_size.width),
Au::from_f32_px(self.viewport_size.height))
Size2D::new(
Au::from_f32_px(self.viewport_size.width),
Au::from_f32_px(self.viewport_size.height),
)
}
/// Like the above, but records that we've used viewport units.
@ -184,8 +187,10 @@ impl Expression {
/// ```
///
/// Only supports width and width ranges for now.
pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
pub fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
input.expect_parenthesis_block()?;
input.parse_nested_block(|input| {
let name = input.expect_ident_cloned()?;
@ -214,11 +219,11 @@ impl Expression {
match self.0 {
ExpressionKind::Width(ref range) => {
match range.to_computed_range(device, quirks_mode) {
Range::Min(ref width) => { value >= *width },
Range::Max(ref width) => { value <= *width },
Range::Eq(ref width) => { value == *width },
Range::Min(ref width) => value >= *width,
Range::Max(ref width) => value <= *width,
Range::Eq(ref width) => value == *width,
}
}
},
}
}
}
@ -256,12 +261,10 @@ pub enum Range<T> {
impl Range<specified::Length> {
fn to_computed_range(&self, device: &Device, quirks_mode: QuirksMode) -> Range<Au> {
computed::Context::for_media_query_evaluation(device, quirks_mode, |context| {
match *self {
Range::Min(ref width) => Range::Min(Au::from(width.to_computed_value(&context))),
Range::Max(ref width) => Range::Max(Au::from(width.to_computed_value(&context))),
Range::Eq(ref width) => Range::Eq(Au::from(width.to_computed_value(&context)))
}
computed::Context::for_media_query_evaluation(device, quirks_mode, |context| match *self {
Range::Min(ref width) => Range::Min(Au::from(width.to_computed_value(&context))),
Range::Max(ref width) => Range::Max(Au::from(width.to_computed_value(&context))),
Range::Eq(ref width) => Range::Eq(Au::from(width.to_computed_value(&context))),
})
}
}

View file

@ -61,10 +61,7 @@ malloc_size_of_is_0!(ServoRestyleDamage);
impl ServoRestyleDamage {
/// Compute the `StyleDifference` (including the appropriate restyle damage)
/// for a given style change between `old` and `new`.
pub fn compute_style_difference(
old: &ComputedValues,
new: &ComputedValues,
) -> StyleDifference {
pub fn compute_style_difference(old: &ComputedValues, new: &ComputedValues) -> StyleDifference {
let damage = compute_damage(old, new);
let change = if damage.is_empty() {
StyleChange::Unchanged
@ -84,9 +81,9 @@ impl ServoRestyleDamage {
/// RECONSTRUCT_FLOW imply everything else?
pub fn rebuild_and_reflow() -> ServoRestyleDamage {
ServoRestyleDamage::REPAINT | ServoRestyleDamage::REPOSITION |
ServoRestyleDamage::STORE_OVERFLOW | ServoRestyleDamage::BUBBLE_ISIZES |
ServoRestyleDamage::REFLOW_OUT_OF_FLOW | ServoRestyleDamage::REFLOW |
ServoRestyleDamage::RECONSTRUCT_FLOW
ServoRestyleDamage::STORE_OVERFLOW | ServoRestyleDamage::BUBBLE_ISIZES |
ServoRestyleDamage::REFLOW_OUT_OF_FLOW | ServoRestyleDamage::REFLOW |
ServoRestyleDamage::RECONSTRUCT_FLOW
}
/// Returns a bitmask indicating that the frame needs to be reconstructed.
@ -99,28 +96,35 @@ impl ServoRestyleDamage {
pub fn damage_for_parent(self, child_is_absolutely_positioned: bool) -> ServoRestyleDamage {
if child_is_absolutely_positioned {
self & (ServoRestyleDamage::REPAINT | ServoRestyleDamage::REPOSITION |
ServoRestyleDamage::STORE_OVERFLOW | ServoRestyleDamage::REFLOW_OUT_OF_FLOW |
ServoRestyleDamage::RESOLVE_GENERATED_CONTENT)
ServoRestyleDamage::STORE_OVERFLOW |
ServoRestyleDamage::REFLOW_OUT_OF_FLOW |
ServoRestyleDamage::RESOLVE_GENERATED_CONTENT)
} else {
self & (ServoRestyleDamage::REPAINT | ServoRestyleDamage::REPOSITION |
ServoRestyleDamage::STORE_OVERFLOW | ServoRestyleDamage::REFLOW |
ServoRestyleDamage::REFLOW_OUT_OF_FLOW | ServoRestyleDamage::RESOLVE_GENERATED_CONTENT)
ServoRestyleDamage::STORE_OVERFLOW |
ServoRestyleDamage::REFLOW |
ServoRestyleDamage::REFLOW_OUT_OF_FLOW |
ServoRestyleDamage::RESOLVE_GENERATED_CONTENT)
}
}
/// Supposing the *parent* of a flow with the given `position` property has
/// this damage, returns the damage that we should add to this flow.
pub fn damage_for_child(self,
parent_is_absolutely_positioned: bool,
child_is_absolutely_positioned: bool)
-> ServoRestyleDamage {
match (parent_is_absolutely_positioned, child_is_absolutely_positioned) {
pub fn damage_for_child(
self,
parent_is_absolutely_positioned: bool,
child_is_absolutely_positioned: bool,
) -> ServoRestyleDamage {
match (
parent_is_absolutely_positioned,
child_is_absolutely_positioned,
) {
(false, true) => {
// Absolute children are out-of-flow and therefore insulated from changes.
//
// FIXME(pcwalton): Au contraire, if the containing block dimensions change!
self & (ServoRestyleDamage::REPAINT | ServoRestyleDamage::REPOSITION)
}
},
(true, false) => {
// Changing the position of an absolutely-positioned block requires us to reflow
// its kids.
@ -129,11 +133,12 @@ impl ServoRestyleDamage {
} else {
self
}
}
},
_ => {
// TODO(pcwalton): Take floatedness into account.
self & (ServoRestyleDamage::REPAINT | ServoRestyleDamage::REPOSITION | ServoRestyleDamage::REFLOW)
}
self & (ServoRestyleDamage::REPAINT | ServoRestyleDamage::REPOSITION |
ServoRestyleDamage::REFLOW)
},
}
}
}
@ -148,20 +153,25 @@ impl fmt::Display for ServoRestyleDamage {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let mut first_elem = true;
let to_iter =
[ (ServoRestyleDamage::REPAINT, "Repaint")
, (ServoRestyleDamage::REPOSITION, "Reposition")
, (ServoRestyleDamage::STORE_OVERFLOW, "StoreOverflow")
, (ServoRestyleDamage::BUBBLE_ISIZES, "BubbleISizes")
, (ServoRestyleDamage::REFLOW_OUT_OF_FLOW, "ReflowOutOfFlow")
, (ServoRestyleDamage::REFLOW, "Reflow")
, (ServoRestyleDamage::RESOLVE_GENERATED_CONTENT, "ResolveGeneratedContent")
, (ServoRestyleDamage::RECONSTRUCT_FLOW, "ReconstructFlow")
];
let to_iter = [
(ServoRestyleDamage::REPAINT, "Repaint"),
(ServoRestyleDamage::REPOSITION, "Reposition"),
(ServoRestyleDamage::STORE_OVERFLOW, "StoreOverflow"),
(ServoRestyleDamage::BUBBLE_ISIZES, "BubbleISizes"),
(ServoRestyleDamage::REFLOW_OUT_OF_FLOW, "ReflowOutOfFlow"),
(ServoRestyleDamage::REFLOW, "Reflow"),
(
ServoRestyleDamage::RESOLVE_GENERATED_CONTENT,
"ResolveGeneratedContent",
),
(ServoRestyleDamage::RECONSTRUCT_FLOW, "ReconstructFlow"),
];
for &(damage, damage_str) in &to_iter {
if self.contains(damage) {
if !first_elem { write!(f, " | ")?; }
if !first_elem {
write!(f, " | ")?;
}
write!(f, "{}", damage_str)?;
first_elem = false;
}
@ -181,27 +191,59 @@ fn compute_damage(old: &ComputedValues, new: &ComputedValues) -> ServoRestyleDam
// This should check every CSS property, as enumerated in the fields of
// http://doc.servo.org/style/properties/struct.ComputedValues.html
restyle_damage_rebuild_and_reflow!(old, new, damage,
[ServoRestyleDamage::REPAINT, ServoRestyleDamage::REPOSITION,
ServoRestyleDamage::STORE_OVERFLOW, ServoRestyleDamage::BUBBLE_ISIZES,
ServoRestyleDamage::REFLOW_OUT_OF_FLOW, ServoRestyleDamage::REFLOW,
ServoRestyleDamage::RECONSTRUCT_FLOW]) ||
restyle_damage_rebuild_and_reflow!(
old,
new,
damage,
[
ServoRestyleDamage::REPAINT,
ServoRestyleDamage::REPOSITION,
ServoRestyleDamage::STORE_OVERFLOW,
ServoRestyleDamage::BUBBLE_ISIZES,
ServoRestyleDamage::REFLOW_OUT_OF_FLOW,
ServoRestyleDamage::REFLOW,
ServoRestyleDamage::RECONSTRUCT_FLOW
]
) ||
(new.get_box().display == Display::Inline &&
restyle_damage_rebuild_and_reflow_inline!(old, new, damage,
[ServoRestyleDamage::REPAINT, ServoRestyleDamage::REPOSITION,
ServoRestyleDamage::STORE_OVERFLOW, ServoRestyleDamage::BUBBLE_ISIZES,
ServoRestyleDamage::REFLOW_OUT_OF_FLOW, ServoRestyleDamage::REFLOW,
ServoRestyleDamage::RECONSTRUCT_FLOW])) ||
restyle_damage_reflow!(old, new, damage,
[ServoRestyleDamage::REPAINT, ServoRestyleDamage::REPOSITION,
ServoRestyleDamage::STORE_OVERFLOW, ServoRestyleDamage::BUBBLE_ISIZES,
ServoRestyleDamage::REFLOW_OUT_OF_FLOW, ServoRestyleDamage::REFLOW]) ||
restyle_damage_reflow_out_of_flow!(old, new, damage,
[ServoRestyleDamage::REPAINT, ServoRestyleDamage::REPOSITION,
ServoRestyleDamage::STORE_OVERFLOW, ServoRestyleDamage::REFLOW_OUT_OF_FLOW]) ||
restyle_damage_repaint!(old, new, damage,
[ServoRestyleDamage::REPAINT]);
restyle_damage_rebuild_and_reflow_inline!(
old,
new,
damage,
[
ServoRestyleDamage::REPAINT,
ServoRestyleDamage::REPOSITION,
ServoRestyleDamage::STORE_OVERFLOW,
ServoRestyleDamage::BUBBLE_ISIZES,
ServoRestyleDamage::REFLOW_OUT_OF_FLOW,
ServoRestyleDamage::REFLOW,
ServoRestyleDamage::RECONSTRUCT_FLOW
]
)) ||
restyle_damage_reflow!(
old,
new,
damage,
[
ServoRestyleDamage::REPAINT,
ServoRestyleDamage::REPOSITION,
ServoRestyleDamage::STORE_OVERFLOW,
ServoRestyleDamage::BUBBLE_ISIZES,
ServoRestyleDamage::REFLOW_OUT_OF_FLOW,
ServoRestyleDamage::REFLOW
]
) ||
restyle_damage_reflow_out_of_flow!(
old,
new,
damage,
[
ServoRestyleDamage::REPAINT,
ServoRestyleDamage::REPOSITION,
ServoRestyleDamage::STORE_OVERFLOW,
ServoRestyleDamage::REFLOW_OUT_OF_FLOW
]
) || restyle_damage_repaint!(old, new, damage, [ServoRestyleDamage::REPAINT]);
// Paint worklets may depend on custom properties,
// so if they have changed we should repaint.

View file

@ -6,9 +6,9 @@
//! Servo's selector parser.
use {Atom, Prefix, Namespace, LocalName, CaseSensitivityExt};
use {Atom, CaseSensitivityExt, LocalName, Namespace, Prefix};
use attr::{AttrIdentifier, AttrValue};
use cssparser::{Parser as CssParser, ToCss, serialize_identifier, CowRcStr, SourceLocation};
use cssparser::{serialize_identifier, CowRcStr, Parser as CssParser, SourceLocation, ToCss};
use dom::{OpaqueNode, TElement, TNode};
use element_state::{DocumentState, ElementState};
use fnv::FnvHashMap;
@ -17,8 +17,8 @@ use invalidation::element::element_wrapper::ElementSnapshot;
use properties::{CascadeFlags, ComputedValues, PropertyFlags};
use properties::longhands::display::computed_value::T as Display;
use selector_parser::{AttrValue as SelectorAttrValue, PseudoElementCascadeType, SelectorParser};
use selectors::attr::{AttrSelectorOperation, NamespaceConstraint, CaseSensitivity};
use selectors::parser::{Visit, SelectorParseErrorKind};
use selectors::attr::{AttrSelectorOperation, CaseSensitivity, NamespaceConstraint};
use selectors::parser::{SelectorParseErrorKind, Visit};
use selectors::visitor::SelectorVisitor;
use std::fmt;
use std::mem;
@ -73,7 +73,10 @@ impl ::selectors::parser::PseudoElement for PseudoElement {
}
impl ToCss for PseudoElement {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where
W: fmt::Write,
{
use self::PseudoElement::*;
dest.write_str(match *self {
After => "::after",
@ -194,9 +197,9 @@ impl PseudoElement {
#[inline]
pub fn cascade_type(&self) -> PseudoElementCascadeType {
match *self {
PseudoElement::After |
PseudoElement::Before |
PseudoElement::Selection => PseudoElementCascadeType::Eager,
PseudoElement::After | PseudoElement::Before | PseudoElement::Selection => {
PseudoElementCascadeType::Eager
},
PseudoElement::DetailsSummary => PseudoElementCascadeType::Lazy,
PseudoElement::DetailsContent |
PseudoElement::ServoText |
@ -256,7 +259,9 @@ impl PseudoElement {
}
/// Stub, only Gecko needs this
pub fn pseudo_info(&self) { () }
pub fn pseudo_info(&self) {
()
}
/// Property flag that properties must have to apply to this pseudo-element.
#[inline]
@ -318,20 +323,23 @@ impl ::selectors::parser::NonTSPseudoClass for NonTSPseudoClass {
}
impl ToCss for NonTSPseudoClass {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where
W: fmt::Write,
{
use self::NonTSPseudoClass::*;
match *self {
Lang(ref lang) => {
dest.write_str(":lang(")?;
serialize_identifier(lang, dest)?;
return dest.write_str(")")
}
return dest.write_str(")");
},
ServoCaseSensitiveTypeAttr(ref value) => {
dest.write_str(":-servo-case-sensitive-type-attr(")?;
serialize_identifier(value, dest)?;
return dest.write_str(")")
}
_ => {}
return dest.write_str(")");
},
_ => {},
}
dest.write_str(match *self {
@ -351,8 +359,7 @@ impl ToCss for NonTSPseudoClass {
ServoNonZeroBorder => ":-servo-nonzero-border",
Target => ":target",
Visited => ":visited",
Lang(_) |
ServoCaseSensitiveTypeAttr(_) => unreachable!(),
Lang(_) | ServoCaseSensitiveTypeAttr(_) => unreachable!(),
})
}
}
@ -360,9 +367,9 @@ impl ToCss for NonTSPseudoClass {
impl Visit for NonTSPseudoClass {
type Impl = SelectorImpl;
fn visit<V>(&self, _: &mut V) -> bool
where V: SelectorVisitor<Impl = Self::Impl>
where
V: SelectorVisitor<Impl = Self::Impl>,
{
true
}
@ -599,7 +606,8 @@ impl SelectorImpl {
/// `fun` on it.
#[inline]
pub fn each_eagerly_cascaded_pseudo_element<F>(mut fun: F)
where F: FnMut(PseudoElement),
where
F: FnMut(PseudoElement),
{
for i in 0..EAGER_PSEUDO_COUNT {
fun(PseudoElement::from_eager_index(i));
@ -684,16 +692,23 @@ impl ServoElementSnapshot {
}
fn get_attr(&self, namespace: &Namespace, name: &LocalName) -> Option<&AttrValue> {
self.attrs.as_ref().unwrap().iter()
.find(|&&(ref ident, _)| ident.local_name == *name &&
ident.namespace == *namespace)
self.attrs
.as_ref()
.unwrap()
.iter()
.find(|&&(ref ident, _)| ident.local_name == *name && ident.namespace == *namespace)
.map(|&(_, ref v)| v)
}
fn any_attr_ignore_ns<F>(&self, name: &LocalName, mut f: F) -> bool
where F: FnMut(&AttrValue) -> bool {
self.attrs.as_ref().unwrap().iter()
.any(|&(ref ident, ref v)| ident.local_name == *name && f(v))
where
F: FnMut(&AttrValue) -> bool,
{
self.attrs
.as_ref()
.unwrap()
.iter()
.any(|&(ref ident, ref v)| ident.local_name == *name && f(v))
}
}
@ -707,16 +722,22 @@ impl ElementSnapshot for ServoElementSnapshot {
}
fn id_attr(&self) -> Option<&Atom> {
self.get_attr(&ns!(), &local_name!("id")).map(|v| v.as_atom())
self.get_attr(&ns!(), &local_name!("id"))
.map(|v| v.as_atom())
}
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
self.get_attr(&ns!(), &local_name!("class"))
.map_or(false, |v| v.as_tokens().iter().any(|atom| case_sensitivity.eq_atom(atom, name)))
.map_or(false, |v| {
v.as_tokens()
.iter()
.any(|atom| case_sensitivity.eq_atom(atom, name))
})
}
fn each_class<F>(&self, mut callback: F)
where F: FnMut(&Atom),
where
F: FnMut(&Atom),
{
if let Some(v) = self.get_attr(&ns!(), &local_name!("class")) {
for class in v.as_tokens() {
@ -734,19 +755,18 @@ impl ElementSnapshot for ServoElementSnapshot {
impl ServoElementSnapshot {
/// selectors::Element::attr_matches
pub fn attr_matches(&self,
ns: &NamespaceConstraint<&Namespace>,
local_name: &LocalName,
operation: &AttrSelectorOperation<&String>)
-> bool {
pub fn attr_matches(
&self,
ns: &NamespaceConstraint<&Namespace>,
local_name: &LocalName,
operation: &AttrSelectorOperation<&String>,
) -> bool {
match *ns {
NamespaceConstraint::Specific(ref ns) => {
self.get_attr(ns, local_name)
.map_or(false, |value| value.eval_selector(operation))
}
NamespaceConstraint::Specific(ref ns) => self.get_attr(ns, local_name)
.map_or(false, |value| value.eval_selector(operation)),
NamespaceConstraint::Any => {
self.any_attr_ignore_ns(local_name, |value| value.eval_selector(operation))
}
},
}
}
}
@ -762,7 +782,9 @@ pub fn extended_filtering(tag: &str, range: &str) -> bool {
// step 2
// Note: [Level-4 spec](https://drafts.csswg.org/selectors/#lang-pseudo) check for wild card
if let (Some(range_subtag), Some(tag_subtag)) = (range_subtags.next(), tag_subtags.next()) {
if !(range_subtag.eq_ignore_ascii_case(tag_subtag) || range_subtag.eq_ignore_ascii_case("*")) {
if !(range_subtag.eq_ignore_ascii_case(tag_subtag) ||
range_subtag.eq_ignore_ascii_case("*"))
{
return false;
}
}
@ -795,7 +817,7 @@ pub fn extended_filtering(tag: &str, range: &str) -> bool {
// step 3b
None => {
return false;
}
},
}
}
// step 4

View file

@ -42,9 +42,10 @@ impl CssUrl {
/// Try to parse a URL from a string value that is a valid CSS token for a
/// URL. Never fails - the API is only fallible to be compatible with the
/// gecko version.
pub fn parse_from_string<'a>(url: String,
context: &ParserContext)
-> Result<Self, ParseError<'a>> {
pub fn parse_from_string<'a>(
url: String,
context: &ParserContext,
) -> Result<Self, ParseError<'a>> {
let serialization = Arc::new(url);
let resolved = context.url_data.join(&serialization).ok();
Ok(CssUrl {
@ -104,7 +105,10 @@ impl CssUrl {
}
impl Parse for CssUrl {
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let url = input.expect_url()?;
Self::parse_from_string(url.as_ref().to_owned(), context)
}
@ -133,7 +137,7 @@ impl ToCss for CssUrl {
// user *and* it's an invalid url that has been transformed
// back to specified value via the "uncompute" functionality.
None => "about:invalid",
}
},
};
dest.write_str("url(")?;
@ -158,7 +162,7 @@ impl ToComputedValue for SpecifiedUrl {
None => {
unreachable!("Found specified url with neither resolved or original URI!");
},
}
},
}
}
@ -171,7 +175,7 @@ impl ToComputedValue for SpecifiedUrl {
ComputedUrl::Invalid(ref url) => SpecifiedUrl {
original: Some(url.clone()),
resolved: None,
}
},
}
}
}

View file

@ -5,7 +5,7 @@
//! Different objects protected by the same lock
#[cfg(feature = "gecko")]
use atomic_refcell::{AtomicRefCell, AtomicRef, AtomicRefMut};
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
#[cfg(feature = "servo")]
use parking_lot::RwLock;
use servo_arc::Arc;
@ -51,7 +51,7 @@ impl SharedRwLock {
#[cfg(feature = "servo")]
pub fn new() -> Self {
SharedRwLock {
arc: Arc::new(RwLock::new(()))
arc: Arc::new(RwLock::new(())),
}
}
@ -59,7 +59,7 @@ impl SharedRwLock {
#[cfg(feature = "gecko")]
pub fn new() -> Self {
SharedRwLock {
cell: Arc::new(AtomicRefCell::new(SomethingZeroSizedButTyped))
cell: Arc::new(AtomicRefCell::new(SomethingZeroSizedButTyped)),
}
}
@ -109,9 +109,7 @@ impl<'a> Drop for SharedRwLockReadGuard<'a> {
fn drop(&mut self) {
// Unsafe: self.lock is private to this module, only ever set after `raw_read()`,
// and never copied or cloned (see `compile_time_assert` below).
unsafe {
self.0.arc.raw_unlock_read()
}
unsafe { self.0.arc.raw_unlock_read() }
}
}
@ -126,9 +124,7 @@ impl<'a> Drop for SharedRwLockWriteGuard<'a> {
fn drop(&mut self) {
// Unsafe: self.lock is private to this module, only ever set after `raw_write()`,
// and never copied or cloned (see `compile_time_assert` below).
unsafe {
self.0.arc.raw_unlock_write()
}
unsafe { self.0.arc.raw_unlock_write() }
}
}
@ -163,8 +159,10 @@ impl<T> Locked<T> {
/// Access the data for reading.
pub fn read_with<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a T {
assert!(self.same_lock_as(&guard.0),
"Locked::read_with called with a guard from an unrelated SharedRwLock");
assert!(
self.same_lock_as(&guard.0),
"Locked::read_with called with a guard from an unrelated SharedRwLock"
);
let ptr = self.data.get();
// Unsafe:
@ -173,9 +171,7 @@ impl<T> Locked<T> {
// and weve checked that its the correct lock.
// * The returned reference borrows *both* the data and the guard,
// so that it can outlive neither.
unsafe {
&*ptr
}
unsafe { &*ptr }
}
/// Access the data for reading without verifying the lock. Use with caution.
@ -187,8 +183,10 @@ impl<T> Locked<T> {
/// Access the data for writing.
pub fn write_with<'a>(&'a self, guard: &'a mut SharedRwLockWriteGuard) -> &'a mut T {
assert!(self.same_lock_as(&guard.0),
"Locked::write_with called with a guard from an unrelated SharedRwLock");
assert!(
self.same_lock_as(&guard.0),
"Locked::write_with called with a guard from an unrelated SharedRwLock"
);
let ptr = self.data.get();
// Unsafe:
@ -199,9 +197,7 @@ impl<T> Locked<T> {
// so that it can outlive neither.
// * We require a mutable borrow of the guard,
// so that one write guard can only be used once at a time.
unsafe {
&mut *ptr
}
unsafe { &mut *ptr }
}
}
@ -211,13 +207,13 @@ mod compile_time_assert {
trait Marker1 {}
impl<T: Clone> Marker1 for T {}
impl<'a> Marker1 for SharedRwLockReadGuard<'a> {} // Assert SharedRwLockReadGuard: !Clone
impl<'a> Marker1 for SharedRwLockWriteGuard<'a> {} // Assert SharedRwLockWriteGuard: !Clone
impl<'a> Marker1 for SharedRwLockReadGuard<'a> {} // Assert SharedRwLockReadGuard: !Clone
impl<'a> Marker1 for SharedRwLockWriteGuard<'a> {} // Assert SharedRwLockWriteGuard: !Clone
trait Marker2 {}
impl<T: Copy> Marker2 for T {}
impl<'a> Marker2 for SharedRwLockReadGuard<'a> {} // Assert SharedRwLockReadGuard: !Copy
impl<'a> Marker2 for SharedRwLockWriteGuard<'a> {} // Assert SharedRwLockWriteGuard: !Copy
impl<'a> Marker2 for SharedRwLockReadGuard<'a> {} // Assert SharedRwLockReadGuard: !Copy
impl<'a> Marker2 for SharedRwLockWriteGuard<'a> {} // Assert SharedRwLockWriteGuard: !Copy
}
/// Like ToCss, but with a lock guard given by the caller, and with the writer specified
@ -248,10 +244,9 @@ pub struct DeepCloneParams {
#[cfg(feature = "servo")]
pub struct DeepCloneParams;
/// A trait to do a deep clone of a given CSS type. Gets a lock and a read
/// guard, in order to be able to read and clone nested structures.
pub trait DeepCloneWithLock : Sized {
pub trait DeepCloneWithLock: Sized {
/// Deep clones this object.
fn deep_clone_with_lock(
&self,

View file

@ -16,7 +16,7 @@ use sharing::{StyleSharingCandidate, StyleSharingTarget};
/// sharing.
pub fn parents_allow_sharing<E>(
target: &mut StyleSharingTarget<E>,
candidate: &mut StyleSharingCandidate<E>
candidate: &mut StyleSharingCandidate<E>,
) -> bool
where
E: TElement,
@ -58,7 +58,7 @@ where
/// Whether two elements have the same same style attribute (by pointer identity).
pub fn have_same_style_attribute<E>(
target: &mut StyleSharingTarget<E>,
candidate: &mut StyleSharingCandidate<E>
candidate: &mut StyleSharingCandidate<E>,
) -> bool
where
E: TElement,
@ -66,14 +66,14 @@ where
match (target.style_attribute(), candidate.style_attribute()) {
(None, None) => true,
(Some(_), None) | (None, Some(_)) => false,
(Some(a), Some(b)) => &*a as *const _ == &*b as *const _
(Some(a), Some(b)) => &*a as *const _ == &*b as *const _,
}
}
/// Whether two elements have the same same presentational attributes.
pub fn have_same_presentational_hints<E>(
target: &mut StyleSharingTarget<E>,
candidate: &mut StyleSharingCandidate<E>
candidate: &mut StyleSharingCandidate<E>,
) -> bool
where
E: TElement,
@ -114,18 +114,10 @@ where
{
let stylist = &shared_context.stylist;
let for_element = target.revalidation_match_results(
stylist,
bloom,
nth_index_cache,
selector_flags_map,
);
let for_element =
target.revalidation_match_results(stylist, bloom, nth_index_cache, selector_flags_map);
let for_candidate = candidate.revalidation_match_results(
stylist,
bloom,
nth_index_cache,
);
let for_candidate = candidate.revalidation_match_results(stylist, bloom, nth_index_cache);
// This assert "ensures", to some extent, that the two candidates have
// matched the same rulehash buckets, and as such, that the bits we're
@ -156,7 +148,7 @@ where
let may_have_rules_for_element = match element_id {
Some(id) => stylist.may_have_rules_for_id(id, element),
None => false
None => false,
};
if may_have_rules_for_element {
@ -165,6 +157,6 @@ where
match candidate_id {
Some(id) => stylist.may_have_rules_for_id(id, candidate),
None => false
None => false,
}
}

View file

@ -69,7 +69,7 @@ use applicable_declarations::ApplicableDeclarationBlock;
use atomic_refcell::{AtomicRefCell, AtomicRefMut};
use bloom::StyleBloom;
use context::{SelectorFlagsMap, SharedStyleContext, StyleContext};
use dom::{TElement, SendElement};
use dom::{SendElement, TElement};
use matching::MatchMethods;
use owning_ref::OwningHandle;
use properties::ComputedValues;
@ -84,7 +84,7 @@ use std::mem;
use std::ops::Deref;
use style_resolver::{PrimaryStyle, ResolvedElementStyles};
use stylist::Stylist;
use uluru::{LRUCache, Entry};
use uluru::{Entry, LRUCache};
mod checks;
@ -119,7 +119,9 @@ impl OpaqueComputedValues {
OpaqueComputedValues(p)
}
fn eq(&self, cv: &ComputedValues) -> bool { Self::from(cv) == *self }
fn eq(&self, cv: &ComputedValues) -> bool {
Self::from(cv) == *self
}
}
/// Some data we want to avoid recomputing all the time while trying to share
@ -159,7 +161,7 @@ impl ValidationData {
let mut pres_hints = SmallVec::new();
element.synthesize_presentational_hints_for_legacy_attributes(
VisitedHandlingMode::AllLinksUnvisited,
&mut pres_hints
&mut pres_hints,
);
pres_hints
})
@ -189,11 +191,14 @@ impl ValidationData {
where
E: TElement,
{
self.parent_style_identity.get_or_insert_with(|| {
let parent = el.inheritance_parent().unwrap();
let values = OpaqueComputedValues::from(parent.borrow_data().unwrap().styles.primary());
values
}).clone()
self.parent_style_identity
.get_or_insert_with(|| {
let parent = el.inheritance_parent().unwrap();
let values =
OpaqueComputedValues::from(parent.borrow_data().unwrap().styles.primary());
values
})
.clone()
}
/// Computes the revalidation results if needed, and returns it.
@ -220,8 +225,7 @@ impl ValidationData {
// just do revalidation selector matching without a bloom
// filter, to avoid thrashing the filter.
let bloom_to_use = if bloom_known_valid {
debug_assert_eq!(bloom.current_parent(),
element.traversal_parent());
debug_assert_eq!(bloom.current_parent(), element.traversal_parent());
Some(bloom.filter())
} else {
if bloom.current_parent() == element.traversal_parent() {
@ -269,7 +273,6 @@ impl<E: TElement> Deref for StyleSharingCandidate<E> {
}
}
impl<E: TElement> StyleSharingCandidate<E> {
/// Get the classlist of this candidate.
fn class_list(&mut self) -> &[Atom] {
@ -300,7 +303,8 @@ impl<E: TElement> StyleSharingCandidate<E> {
bloom,
nth_index_cache,
/* bloom_known_valid = */ false,
&mut |_, _| {})
&mut |_, _| {},
)
}
}
@ -352,7 +356,7 @@ impl<E: TElement> StyleSharingTarget<E> {
stylist: &Stylist,
bloom: &StyleBloom<E>,
nth_index_cache: &mut NthIndexCache,
selector_flags_map: &mut SelectorFlagsMap<E>
selector_flags_map: &mut SelectorFlagsMap<E>,
) -> &SmallBitVec {
// It's important to set the selector flags. Otherwise, if we succeed in
// sharing the style, we may not set the slow selector flags for the
@ -380,7 +384,8 @@ impl<E: TElement> StyleSharingTarget<E> {
bloom,
nth_index_cache,
/* bloom_known_valid = */ true,
&mut set_selector_flags)
&mut set_selector_flags,
)
}
/// Attempts to share a style with another node.
@ -395,19 +400,25 @@ impl<E: TElement> StyleSharingTarget<E> {
let nth_index_cache = &mut context.thread_local.nth_index_cache;
if cache.dom_depth != bloom_filter.matching_depth() {
debug!("Can't share style, because DOM depth changed from {:?} to {:?}, element: {:?}",
cache.dom_depth, bloom_filter.matching_depth(), self.element);
debug!(
"Can't share style, because DOM depth changed from {:?} to {:?}, element: {:?}",
cache.dom_depth,
bloom_filter.matching_depth(),
self.element
);
return None;
}
debug_assert_eq!(bloom_filter.current_parent(),
self.element.traversal_parent());
debug_assert_eq!(
bloom_filter.current_parent(),
self.element.traversal_parent()
);
cache.share_style_if_possible(
shared_context,
selector_flags_map,
bloom_filter,
nth_index_cache,
self
self,
)
}
@ -440,16 +451,15 @@ impl<Candidate> SharingCacheBase<Candidate> {
}
impl<E: TElement> SharingCache<E> {
fn insert(
&mut self,
element: E,
validation_data_holder: Option<&mut StyleSharingTarget<E>>,
) {
fn insert(&mut self, element: E, validation_data_holder: Option<&mut StyleSharingTarget<E>>) {
let validation_data = match validation_data_holder {
Some(v) => v.take_validation_data(),
None => ValidationData::default(),
};
self.entries.insert(StyleSharingCandidate { element, validation_data });
self.entries.insert(StyleSharingCandidate {
element,
validation_data,
});
}
}
@ -514,10 +524,17 @@ impl<E: TElement> StyleSharingCache<E> {
// See https://github.com/servo/servo/pull/18420#issuecomment-328769322
#[inline(never)]
pub fn new() -> Self {
assert_eq!(mem::size_of::<SharingCache<E>>(), mem::size_of::<TypelessSharingCache>());
assert_eq!(mem::align_of::<SharingCache<E>>(), mem::align_of::<TypelessSharingCache>());
assert_eq!(
mem::size_of::<SharingCache<E>>(),
mem::size_of::<TypelessSharingCache>()
);
assert_eq!(
mem::align_of::<SharingCache<E>>(),
mem::align_of::<TypelessSharingCache>()
);
let cache_arc = SHARING_CACHE_KEY.with(|c| c.clone());
let cache = OwningHandle::new_with_fn(cache_arc, |x| unsafe { x.as_ref() }.unwrap().borrow_mut());
let cache =
OwningHandle::new_with_fn(cache_arc, |x| unsafe { x.as_ref() }.unwrap().borrow_mut());
debug_assert!(cache.is_empty());
StyleSharingCache {
@ -545,7 +562,7 @@ impl<E: TElement> StyleSharingCache<E> {
None => {
debug!("Failing to insert to the cache: no parent element");
return;
}
},
};
if element.is_native_anonymous() {
@ -593,11 +610,16 @@ impl<E: TElement> StyleSharingCache<E> {
return;
}
debug!("Inserting into cache: {:?} with parent {:?}", element, parent);
debug!(
"Inserting into cache: {:?} with parent {:?}",
element, parent
);
if self.dom_depth != dom_depth {
debug!("Clearing cache because depth changed from {:?} to {:?}, element: {:?}",
self.dom_depth, dom_depth, element);
debug!(
"Clearing cache because depth changed from {:?} to {:?}, element: {:?}",
self.dom_depth, dom_depth, element
);
self.clear();
self.dom_depth = dom_depth;
}
@ -619,14 +641,18 @@ impl<E: TElement> StyleSharingCache<E> {
target: &mut StyleSharingTarget<E>,
) -> Option<ResolvedElementStyles> {
if shared_context.options.disable_style_sharing_cache {
debug!("{:?} Cannot share style: style sharing cache disabled",
target.element);
debug!(
"{:?} Cannot share style: style sharing cache disabled",
target.element
);
return None;
}
if target.inheritance_parent().is_none() {
debug!("{:?} Cannot share style: element has no parent",
target.element);
debug!(
"{:?} Cannot share style: element has no parent",
target.element
);
return None;
}
@ -642,7 +668,7 @@ impl<E: TElement> StyleSharingCache<E> {
&shared_context,
bloom_filter,
nth_index_cache,
selector_flags_map
selector_flags_map,
)
})
}
@ -653,7 +679,7 @@ impl<E: TElement> StyleSharingCache<E> {
shared: &SharedStyleContext,
bloom: &StyleBloom<E>,
nth_index_cache: &mut NthIndexCache,
selector_flags_map: &mut SelectorFlagsMap<E>
selector_flags_map: &mut SelectorFlagsMap<E>,
) -> Option<ResolvedElementStyles> {
debug_assert!(!target.is_native_anonymous());
@ -708,7 +734,10 @@ impl<E: TElement> StyleSharingCache<E> {
// Other than this, we don't need anything else like the containing XBL
// binding parent or what not, since two elements with different XBL
// bindings will necessarily end up with different style.
if !target.element.has_same_xbl_proto_binding_as(candidate.element) {
if !target
.element
.has_same_xbl_proto_binding_as(candidate.element)
{
trace!("Miss: Different proto bindings");
return None;
}
@ -732,18 +761,15 @@ impl<E: TElement> StyleSharingCache<E> {
}
if target.matches_user_and_author_rules() !=
candidate.element.matches_user_and_author_rules() {
candidate.element.matches_user_and_author_rules()
{
trace!("Miss: User and Author Rules");
return None;
}
// It's possible that there are no styles for either id.
let may_match_different_id_rules =
checks::may_match_different_id_rules(
shared,
target.element,
candidate.element,
);
checks::may_match_different_id_rules(shared, target.element, candidate.element);
if may_match_different_id_rules {
trace!("Miss: ID Attr");
@ -765,8 +791,14 @@ impl<E: TElement> StyleSharingCache<E> {
return None;
}
if !checks::revalidate(target, candidate, shared, bloom,
nth_index_cache, selector_flags_map) {
if !checks::revalidate(
target,
candidate,
shared,
bloom,
nth_index_cache,
selector_flags_map,
) {
trace!("Miss: Revalidation");
return None;
}
@ -776,7 +808,10 @@ impl<E: TElement> StyleSharingCache<E> {
shared.traversal_flags,
));
debug!("Sharing allowed between {:?} and {:?}", target.element, candidate.element);
debug!(
"Sharing allowed between {:?} and {:?}",
target.element, candidate.element
);
Some(candidate.element.borrow_data().unwrap().share_styles())
}

View file

@ -22,13 +22,8 @@ pub type StaticStringVec = &'static [&'static str];
/// A "space character" according to:
///
/// <https://html.spec.whatwg.org/multipage/#space-character>
pub static HTML_SPACE_CHARACTERS: StaticCharVec = &[
'\u{0020}',
'\u{0009}',
'\u{000a}',
'\u{000c}',
'\u{000d}',
];
pub static HTML_SPACE_CHARACTERS: StaticCharVec =
&['\u{0020}', '\u{0009}', '\u{000a}', '\u{000c}', '\u{000d}'];
/// Whether a character is a HTML whitespace character.
#[inline]
@ -43,13 +38,17 @@ pub fn is_whitespace(s: &str) -> bool {
}
#[inline]
fn not_empty(&split: &&str) -> bool { !split.is_empty() }
fn not_empty(&split: &&str) -> bool {
!split.is_empty()
}
/// Split a string on HTML whitespace.
#[inline]
pub fn split_html_space_chars<'a>(s: &'a str) ->
Filter<Split<'a, StaticCharVec>, fn(&&str) -> bool> {
s.split(HTML_SPACE_CHARACTERS).filter(not_empty as fn(&&str) -> bool)
pub fn split_html_space_chars<'a>(
s: &'a str,
) -> Filter<Split<'a, StaticCharVec>, fn(&&str) -> bool> {
s.split(HTML_SPACE_CHARACTERS)
.filter(not_empty as fn(&&str) -> bool)
}
/// Split a string on commas.
@ -78,44 +77,45 @@ fn is_exponent_char(c: char) -> bool {
}
/// Read a set of ascii digits and read them into a number.
pub fn read_numbers<I: Iterator<Item=char>>(mut iter: Peekable<I>) -> (Option<i64>, usize) {
pub fn read_numbers<I: Iterator<Item = char>>(mut iter: Peekable<I>) -> (Option<i64>, usize) {
match iter.peek() {
Some(c) if is_ascii_digit(c) => (),
_ => return (None, 0),
}
iter.take_while(is_ascii_digit).map(|d| {
d as i64 - '0' as i64
}).fold((Some(0i64), 0), |accumulator, d| {
let digits = accumulator.0.and_then(|accumulator| {
accumulator.checked_mul(10)
}).and_then(|accumulator| {
accumulator.checked_add(d)
});
(digits, accumulator.1 + 1)
})
iter.take_while(is_ascii_digit)
.map(|d| d as i64 - '0' as i64)
.fold((Some(0i64), 0), |accumulator, d| {
let digits = accumulator
.0
.and_then(|accumulator| accumulator.checked_mul(10))
.and_then(|accumulator| accumulator.checked_add(d));
(digits, accumulator.1 + 1)
})
}
/// Read a decimal fraction.
pub fn read_fraction<I: Iterator<Item=char>>(mut iter: Peekable<I>,
mut divisor: f64,
value: f64) -> (f64, usize) {
pub fn read_fraction<I: Iterator<Item = char>>(
mut iter: Peekable<I>,
mut divisor: f64,
value: f64,
) -> (f64, usize) {
match iter.peek() {
Some(c) if is_decimal_point(*c) => (),
_ => return (value, 0),
}
iter.next();
iter.take_while(is_ascii_digit).map(|d|
d as i64 - '0' as i64
).fold((value, 1), |accumulator, d| {
divisor *= 10f64;
(accumulator.0 + d as f64 / divisor, accumulator.1 + 1)
})
iter.take_while(is_ascii_digit)
.map(|d| d as i64 - '0' as i64)
.fold((value, 1), |accumulator, d| {
divisor *= 10f64;
(accumulator.0 + d as f64 / divisor, accumulator.1 + 1)
})
}
/// Reads an exponent from an iterator over chars, for example `e100`.
pub fn read_exponent<I: Iterator<Item=char>>(mut iter: Peekable<I>) -> Option<i32> {
pub fn read_exponent<I: Iterator<Item = char>>(mut iter: Peekable<I>) -> Option<i32> {
match iter.peek() {
Some(c) if is_exponent_char(*c) => (),
_ => return None,
@ -127,31 +127,36 @@ pub fn read_exponent<I: Iterator<Item=char>>(mut iter: Peekable<I>) -> Option<i3
Some(&'-') => {
iter.next();
read_numbers(iter).0.map(|exp| -exp.to_i32().unwrap_or(0))
}
},
Some(&'+') => {
iter.next();
read_numbers(iter).0.map(|exp| exp.to_i32().unwrap_or(0))
}
Some(_) => read_numbers(iter).0.map(|exp| exp.to_i32().unwrap_or(0))
},
Some(_) => read_numbers(iter).0.map(|exp| exp.to_i32().unwrap_or(0)),
}
}
/// Join a set of strings with a given delimiter `join`.
pub fn str_join<I, T>(strs: I, join: &str) -> String
where I: IntoIterator<Item=T>,
T: AsRef<str>,
where
I: IntoIterator<Item = T>,
T: AsRef<str>,
{
strs.into_iter().enumerate().fold(String::new(), |mut acc, (i, s)| {
if i > 0 { acc.push_str(join); }
acc.push_str(s.as_ref());
acc
})
strs.into_iter()
.enumerate()
.fold(String::new(), |mut acc, (i, s)| {
if i > 0 {
acc.push_str(join);
}
acc.push_str(s.as_ref());
acc
})
}
/// Returns true if a given string has a given prefix with case-insensitive match.
pub fn starts_with_ignore_ascii_case(string: &str, prefix: &str) -> bool {
string.len() >= prefix.len() &&
string.as_bytes()[0..prefix.len()].eq_ignore_ascii_case(prefix.as_bytes())
string.as_bytes()[0..prefix.len()].eq_ignore_ascii_case(prefix.as_bytes())
}
/// Returns an ascii lowercase version of a string, only allocating if needed.

View file

@ -65,14 +65,9 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
element.map_or(false, |e| e.skip_item_display_fixup())
}
/// Apply the blockification rules based on the table in CSS 2.2 section 9.7.
/// <https://drafts.csswg.org/css2/visuren.html#dis-pos-flo>
fn blockify_if_necessary<E>(
&mut self,
layout_parent_style: &ComputedValues,
element: Option<E>,
)
fn blockify_if_necessary<E>(&mut self, layout_parent_style: &ComputedValues, element: Option<E>)
where
E: TElement,
{
@ -82,13 +77,18 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
if !blockify {
blockify = $if_what;
}
}
};
}
let is_root = self.style.pseudo.is_none() && element.map_or(false, |e| e.is_root());
blockify_if!(is_root);
if !self.skip_item_display_fixup(element) {
blockify_if!(layout_parent_style.get_box().clone_display().is_item_container());
blockify_if!(
layout_parent_style
.get_box()
.clone_display()
.is_item_container()
);
}
let is_item_or_root = blockify;
@ -103,10 +103,9 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
let display = self.style.get_box().clone_display();
let blockified_display = display.equivalent_block_display(is_root);
if display != blockified_display {
self.style.mutate_box().set_adjusted_display(
blockified_display,
is_item_or_root,
);
self.style
.mutate_box()
.set_adjusted_display(blockified_display, is_item_or_root);
}
}
@ -114,22 +113,35 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
pub fn set_bits(&mut self) {
let display = self.style.get_box().clone_display();
if !display.is_contents() && !self.style.get_text().clone_text_decoration_line().is_empty() {
self.style.flags.insert(ComputedValueFlags::HAS_TEXT_DECORATION_LINES);
if !display.is_contents() &&
!self.style
.get_text()
.clone_text_decoration_line()
.is_empty()
{
self.style
.flags
.insert(ComputedValueFlags::HAS_TEXT_DECORATION_LINES);
}
if display == Display::None {
self.style.flags.insert(ComputedValueFlags::IS_IN_DISPLAY_NONE_SUBTREE);
self.style
.flags
.insert(ComputedValueFlags::IS_IN_DISPLAY_NONE_SUBTREE);
}
if self.style.is_pseudo_element() {
self.style.flags.insert(ComputedValueFlags::IS_IN_PSEUDO_ELEMENT_SUBTREE);
self.style
.flags
.insert(ComputedValueFlags::IS_IN_PSEUDO_ELEMENT_SUBTREE);
}
#[cfg(feature = "servo")]
{
if self.style.get_parent_column().is_multicol() {
self.style.flags.insert(ComputedValueFlags::CAN_BE_FRAGMENTED);
self.style
.flags
.insert(ComputedValueFlags::CAN_BE_FRAGMENTED);
}
}
}
@ -162,15 +174,18 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
use computed_values::text_combine_upright::T as TextCombineUpright;
use computed_values::writing_mode::T as WritingMode;
let writing_mode =
self.style.get_inheritedbox().clone_writing_mode();
let text_combine_upright =
self.style.get_inheritedtext().clone_text_combine_upright();
let writing_mode = self.style.get_inheritedbox().clone_writing_mode();
let text_combine_upright = self.style.get_inheritedtext().clone_text_combine_upright();
if writing_mode != WritingMode::HorizontalTb &&
text_combine_upright == TextCombineUpright::All {
self.style.flags.insert(ComputedValueFlags::IS_TEXT_COMBINED);
self.style.mutate_inheritedbox().set_writing_mode(WritingMode::HorizontalTb);
text_combine_upright == TextCombineUpright::All
{
self.style
.flags
.insert(ComputedValueFlags::IS_TEXT_COMBINED);
self.style
.mutate_inheritedbox()
.set_writing_mode(WritingMode::HorizontalTb);
}
}
@ -184,9 +199,13 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
fn adjust_for_text_in_ruby(&mut self) {
let parent_display = self.style.get_parent_box().clone_display();
if parent_display.is_ruby_type() ||
self.style.get_parent_flags().contains(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK)
self.style
.get_parent_flags()
.contains(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK)
{
self.style.flags.insert(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK);
self.style
.flags
.insert(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK);
}
}
@ -203,24 +222,19 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
///
/// <https://lists.w3.org/Archives/Public/www-style/2017Mar/0045.html>
/// <https://github.com/servo/servo/issues/15754>
fn adjust_for_writing_mode(
&mut self,
layout_parent_style: &ComputedValues,
) {
let our_writing_mode =
self.style.get_inheritedbox().clone_writing_mode();
let parent_writing_mode =
layout_parent_style.get_inheritedbox().clone_writing_mode();
fn adjust_for_writing_mode(&mut self, layout_parent_style: &ComputedValues) {
let our_writing_mode = self.style.get_inheritedbox().clone_writing_mode();
let parent_writing_mode = layout_parent_style.get_inheritedbox().clone_writing_mode();
if our_writing_mode != parent_writing_mode &&
self.style.get_box().clone_display() == Display::Inline {
self.style.get_box().clone_display() == Display::Inline
{
// TODO(emilio): Figure out if we can just set the adjusted display
// on Gecko too and unify this code path.
if cfg!(feature = "servo") {
self.style.mutate_box().set_adjusted_display(
Display::InlineBlock,
false,
);
self.style
.mutate_box()
.set_adjusted_display(Display::InlineBlock, false);
} else {
self.style.mutate_box().set_display(Display::InlineBlock);
}
@ -241,13 +255,17 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
}
if self.style.get_box().clone_display() == Display::Inline {
self.style.mutate_box().set_adjusted_display(Display::InlineBlock,
false);
self.style
.mutate_box()
.set_adjusted_display(Display::InlineBlock, false);
}
// When 'contain: paint', update overflow from 'visible' to 'clip'.
if self.style.get_box().clone_contain().contains(SpecifiedValue::PAINT) {
if self.style
.get_box()
.clone_contain()
.contains(SpecifiedValue::PAINT)
{
if self.style.get_box().clone_overflow_x() == Overflow::Visible {
let box_style = self.style.mutate_box();
box_style.set_overflow_x(Overflow::MozHiddenUnscrollable);
@ -282,15 +300,15 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
use computed_values::align_self::T as AlignSelf;
if self.style.get_position().clone_align_self() == AlignSelf::Auto &&
!self.style.out_of_flow_positioned() {
let self_align =
match layout_parent_style.get_position().clone_align_items() {
AlignItems::Stretch => AlignSelf::Stretch,
AlignItems::Baseline => AlignSelf::Baseline,
AlignItems::FlexStart => AlignSelf::FlexStart,
AlignItems::FlexEnd => AlignSelf::FlexEnd,
AlignItems::Center => AlignSelf::Center,
};
!self.style.out_of_flow_positioned()
{
let self_align = match layout_parent_style.get_position().clone_align_items() {
AlignItems::Stretch => AlignSelf::Stretch,
AlignItems::Baseline => AlignSelf::Baseline,
AlignItems::FlexStart => AlignSelf::FlexStart,
AlignItems::FlexEnd => AlignSelf::FlexEnd,
AlignItems::Center => AlignSelf::Center,
};
self.style.mutate_position().set_align_self(self_align);
}
}
@ -305,8 +323,11 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
/// The initial value of outline-width may be changed at computed value time.
fn adjust_for_outline(&mut self) {
if self.style.get_outline().clone_outline_style().none_or_hidden() &&
self.style.get_outline().outline_has_nonzero_width() {
if self.style
.get_outline()
.clone_outline_style()
.none_or_hidden() && self.style.get_outline().outline_has_nonzero_width()
{
self.style.mutate_outline().set_outline_width(Au(0).into());
}
}
@ -349,8 +370,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
}
}
if overflow_x != original_overflow_x ||
overflow_y != original_overflow_y {
if overflow_x != original_overflow_x || overflow_y != original_overflow_y {
let box_style = self.style.mutate_box();
box_style.set_overflow_x(overflow_x);
box_style.set_overflow_y(overflow_y);
@ -365,8 +385,8 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
//
// FIXME(emilio): ::before and ::after should support display: contents,
// see bug 1418138.
if self.style.pseudo.is_none() ||
self.style.get_box().clone_display() != Display::Contents {
if self.style.pseudo.is_none() || self.style.get_box().clone_display() != Display::Contents
{
return;
}
@ -380,10 +400,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
/// in matching.rs because anonymous box restyling works separately to the
/// normal cascading process.
#[cfg(feature = "gecko")]
fn adjust_for_fieldset_content(
&mut self,
layout_parent_style: &ComputedValues,
) {
fn adjust_for_fieldset_content(&mut self, layout_parent_style: &ComputedValues) {
match self.style.pseudo {
Some(ref p) if p.is_fieldset_content() => {},
_ => return,
@ -395,10 +412,8 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
// when <fieldset> has "display: contents".
let parent_display = layout_parent_style.get_box().clone_display();
let new_display = match parent_display {
Display::Flex |
Display::InlineFlex => Some(Display::Flex),
Display::Grid |
Display::InlineGrid => Some(Display::Grid),
Display::Flex | Display::InlineFlex => Some(Display::Flex),
Display::Grid | Display::InlineGrid => Some(Display::Grid),
_ => None,
};
if let Some(new_display) = new_display {
@ -420,13 +435,13 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
}
match self.style.get_inheritedtext().clone_text_align() {
TextAlign::MozLeft |
TextAlign::MozCenter |
TextAlign::MozRight => {},
TextAlign::MozLeft | TextAlign::MozCenter | TextAlign::MozRight => {},
_ => return,
}
self.style.mutate_inheritedtext().set_text_align(TextAlign::Start)
self.style
.mutate_inheritedtext()
.set_text_align(TextAlign::Start)
}
/// Computes the used text decoration for Servo.
@ -445,16 +460,16 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
}
#[cfg(feature = "gecko")]
fn should_suppress_linebreak(
&self,
layout_parent_style: &ComputedValues,
) -> bool {
fn should_suppress_linebreak(&self, layout_parent_style: &ComputedValues) -> bool {
// Line break suppression should only be propagated to in-flow children.
if self.style.floated() || self.style.out_of_flow_positioned() {
return false;
}
let parent_display = layout_parent_style.get_box().clone_display();
if layout_parent_style.flags.contains(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK) {
if layout_parent_style
.flags
.contains(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK)
{
// Line break suppression is propagated to any children of
// line participants.
if parent_display.is_line_participant() {
@ -463,15 +478,13 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
}
match self.style.get_box().clone_display() {
// Ruby base and text are always non-breakable.
Display::RubyBase |
Display::RubyText => true,
Display::RubyBase | Display::RubyText => true,
// Ruby base container and text container are breakable.
// Note that, when certain HTML tags, e.g. form controls, have ruby
// level container display type, they could also escape from the
// line break suppression flag while they shouldn't. However, it is
// generally fine since they themselves are non-breakable.
Display::RubyBaseContainer |
Display::RubyTextContainer => false,
Display::RubyBaseContainer | Display::RubyTextContainer => false,
// Anything else is non-breakable if and only if its layout parent
// has a ruby display type, because any of the ruby boxes can be
// anonymous.
@ -485,11 +498,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
/// * suppress border and padding for ruby level containers,
/// * correct unicode-bidi.
#[cfg(feature = "gecko")]
fn adjust_for_ruby<E>(
&mut self,
layout_parent_style: &ComputedValues,
element: Option<E>,
)
fn adjust_for_ruby<E>(&mut self, layout_parent_style: &ComputedValues, element: Option<E>)
where
E: TElement,
{
@ -498,12 +507,16 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
let self_display = self.style.get_box().clone_display();
// Check whether line break should be suppressed for this element.
if self.should_suppress_linebreak(layout_parent_style) {
self.style.flags.insert(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK);
self.style
.flags
.insert(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK);
// Inlinify the display type if allowed.
if !self.skip_item_display_fixup(element) {
let inline_display = self_display.inlinify();
if self_display != inline_display {
self.style.mutate_box().set_adjusted_display(inline_display, false);
self.style
.mutate_box()
.set_adjusted_display(inline_display, false);
}
}
}
@ -520,8 +533,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
// per spec https://drafts.csswg.org/css-ruby-1/#bidi
if self_display.is_ruby_type() {
let new_value = match self.style.get_text().clone_unicode_bidi() {
UnicodeBidi::Normal |
UnicodeBidi::Embed => Some(UnicodeBidi::Isolate),
UnicodeBidi::Normal | UnicodeBidi::Embed => Some(UnicodeBidi::Isolate),
UnicodeBidi::BidiOverride => Some(UnicodeBidi::IsolateOverride),
_ => None,
};
@ -548,19 +560,21 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
return;
}
let is_link_element =
self.style.pseudo.is_none() &&
element.map_or(false, |e| e.is_link());
let is_link_element = self.style.pseudo.is_none() && element.map_or(false, |e| e.is_link());
if !is_link_element {
return;
}
if element.unwrap().is_visited_link() {
self.style.flags.insert(ComputedValueFlags::IS_RELEVANT_LINK_VISITED);
self.style
.flags
.insert(ComputedValueFlags::IS_RELEVANT_LINK_VISITED);
} else {
// Need to remove to handle unvisited link inside visited.
self.style.flags.remove(ComputedValueFlags::IS_RELEVANT_LINK_VISITED);
self.style
.flags
.remove(ComputedValueFlags::IS_RELEVANT_LINK_VISITED);
}
}
@ -578,10 +592,13 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
return;
}
let parent_justify_items =
self.style.get_parent_position().clone_justify_items();
let parent_justify_items = self.style.get_parent_position().clone_justify_items();
if !parent_justify_items.computed.0.contains(align::AlignFlags::LEGACY) {
if !parent_justify_items
.computed
.0
.contains(align::AlignFlags::LEGACY)
{
return;
}
@ -605,19 +622,18 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
layout_parent_style: &ComputedValues,
element: Option<E>,
flags: CascadeFlags,
)
where
) where
E: TElement,
{
if cfg!(debug_assertions) {
if element.and_then(|e| e.implemented_pseudo_element()).is_some() {
if element
.and_then(|e| e.implemented_pseudo_element())
.is_some()
{
// It'd be nice to assert `self.style.pseudo == Some(&pseudo)`,
// but we do resolve ::-moz-list pseudos on ::before / ::after
// content, sigh.
debug_assert!(
self.style.pseudo.is_some(),
"Someone really messed up"
);
debug_assert!(self.style.pseudo.is_some(), "Someone really messed up");
}
}
// FIXME(emilio): The apply_declarations callsite in Servo's

View file

@ -6,7 +6,7 @@
use applicable_declarations::ApplicableDeclarationList;
use context::{CascadeInputs, ElementCascadeInputs, StyleContext};
use data::{ElementStyles, EagerPseudoStyles};
use data::{EagerPseudoStyles, ElementStyles};
use dom::TElement;
use log::Level::Trace;
use matching::MatchMethods;
@ -99,7 +99,10 @@ where
layout_parent_style = Some(layout_parent_data.styles.primary());
}
f(parent_style.map(|x| &**x), layout_parent_style.map(|s| &**s))
f(
parent_style.map(|x| &**x),
layout_parent_style.map(|s| &**s),
)
}
fn eager_pseudo_is_definitely_not_generated(
@ -113,12 +116,14 @@ fn eager_pseudo_is_definitely_not_generated(
}
if !style.flags.intersects(ComputedValueFlags::INHERITS_DISPLAY) &&
style.get_box().clone_display() == Display::None {
style.get_box().clone_display() == Display::None
{
return true;
}
if !style.flags.intersects(ComputedValueFlags::INHERITS_CONTENT) &&
style.ineffective_content_property() {
style.ineffective_content_property()
{
return true;
}
@ -153,21 +158,19 @@ where
parent_style: Option<&ComputedValues>,
layout_parent_style: Option<&ComputedValues>,
) -> PrimaryStyle {
let primary_results =
self.match_primary(VisitedHandlingMode::AllLinksUnvisited);
let primary_results = self.match_primary(VisitedHandlingMode::AllLinksUnvisited);
let inside_link =
parent_style.map_or(false, |s| s.visited_style().is_some());
let inside_link = parent_style.map_or(false, |s| s.visited_style().is_some());
let visited_rules =
if self.context.shared.visited_styles_enabled &&
(inside_link || self.element.is_link()) {
let visited_matching_results =
self.match_primary(VisitedHandlingMode::RelevantLinkVisited);
Some(visited_matching_results.rule_node)
} else {
None
};
let visited_rules = if self.context.shared.visited_styles_enabled &&
(inside_link || self.element.is_link())
{
let visited_matching_results =
self.match_primary(VisitedHandlingMode::RelevantLinkVisited);
Some(visited_matching_results.rule_node)
} else {
None
};
self.cascade_primary_style(
CascadeInputs {
@ -188,9 +191,7 @@ where
// Before doing the cascade, check the sharing cache and see if we can
// reuse the style via rule node identity.
let may_reuse =
!self.element.is_native_anonymous() &&
parent_style.is_some() &&
inputs.rules.is_some();
!self.element.is_native_anonymous() && parent_style.is_some() && inputs.rules.is_some();
if may_reuse {
let cached = self.context.thread_local.sharing_cache.lookup_by_rules(
@ -226,28 +227,27 @@ where
parent_style: Option<&ComputedValues>,
layout_parent_style: Option<&ComputedValues>,
) -> ResolvedElementStyles {
let primary_style =
self.resolve_primary_style(parent_style, layout_parent_style);
let primary_style = self.resolve_primary_style(parent_style, layout_parent_style);
let mut pseudo_styles = EagerPseudoStyles::default();
if self.element.implemented_pseudo_element().is_none() {
let layout_parent_style_for_pseudo =
if primary_style.style().is_display_contents() {
layout_parent_style
} else {
Some(primary_style.style())
};
let layout_parent_style_for_pseudo = if primary_style.style().is_display_contents() {
layout_parent_style
} else {
Some(primary_style.style())
};
SelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| {
let pseudo_style = self.resolve_pseudo_style(
&pseudo,
&primary_style,
layout_parent_style_for_pseudo
layout_parent_style_for_pseudo,
);
if let Some(style) = pseudo_style {
if !matches!(self.pseudo_resolution, PseudoElementResolution::Force) &&
eager_pseudo_is_definitely_not_generated(&pseudo, &style.0) {
eager_pseudo_is_definitely_not_generated(&pseudo, &style.0)
{
return;
}
pseudo_styles.set(&pseudo, style.0);
@ -279,7 +279,7 @@ where
inputs,
parent_style,
layout_parent_style,
/* pseudo = */ None
/* pseudo = */ None,
)
})
}
@ -318,7 +318,7 @@ where
&self.context.shared.guards,
&values,
pseudo,
&conditions
&conditions,
);
ResolvedStyle(values)
@ -330,35 +330,32 @@ where
inputs: ElementCascadeInputs,
) -> ResolvedElementStyles {
with_default_parent_styles(self.element, move |parent_style, layout_parent_style| {
let primary_style = self.cascade_primary_style(
inputs.primary,
parent_style,
layout_parent_style,
);
let primary_style =
self.cascade_primary_style(inputs.primary, parent_style, layout_parent_style);
let mut pseudo_styles = EagerPseudoStyles::default();
if let Some(mut pseudo_array) = inputs.pseudos.into_array() {
let layout_parent_style_for_pseudo =
if primary_style.style().is_display_contents() {
layout_parent_style
} else {
Some(primary_style.style())
};
let layout_parent_style_for_pseudo = if primary_style.style().is_display_contents()
{
layout_parent_style
} else {
Some(primary_style.style())
};
for (i, inputs) in pseudo_array.iter_mut().enumerate() {
if let Some(inputs) = inputs.take() {
let pseudo = PseudoElement::from_eager_index(i);
let style =
self.cascade_style_and_visited(
inputs,
Some(primary_style.style()),
layout_parent_style_for_pseudo,
Some(&pseudo),
);
let style = self.cascade_style_and_visited(
inputs,
Some(primary_style.style()),
layout_parent_style_for_pseudo,
Some(&pseudo),
);
if !matches!(self.pseudo_resolution, PseudoElementResolution::Force) &&
eager_pseudo_is_definitely_not_generated(&pseudo, &style.0) {
eager_pseudo_is_definitely_not_generated(&pseudo, &style.0)
{
continue;
}
@ -383,7 +380,7 @@ where
let rules = self.match_pseudo(
originating_element_style.style(),
pseudo,
VisitedHandlingMode::AllLinksUnvisited
VisitedHandlingMode::AllLinksUnvisited,
)?;
let mut visited_rules = None;
@ -398,7 +395,7 @@ where
Some(self.cascade_style_and_visited(
CascadeInputs {
rules: Some(rules),
visited_rules
visited_rules,
},
Some(originating_element_style.style()),
layout_parent_style,
@ -406,25 +403,23 @@ where
))
}
fn match_primary(
&mut self,
visited_handling: VisitedHandlingMode,
) -> MatchingResults {
debug!("Match primary for {:?}, visited: {:?}",
self.element, visited_handling);
fn match_primary(&mut self, visited_handling: VisitedHandlingMode) -> MatchingResults {
debug!(
"Match primary for {:?}, visited: {:?}",
self.element, visited_handling
);
let mut applicable_declarations = ApplicableDeclarationList::new();
let map = &mut self.context.thread_local.selector_flags;
let bloom_filter = self.context.thread_local.bloom_filter.filter();
let nth_index_cache = &mut self.context.thread_local.nth_index_cache;
let mut matching_context =
MatchingContext::new_for_visited(
MatchingMode::Normal,
Some(bloom_filter),
Some(nth_index_cache),
visited_handling,
self.context.shared.quirks_mode(),
);
let mut matching_context = MatchingContext::new_for_visited(
MatchingMode::Normal,
Some(bloom_filter),
Some(nth_index_cache),
visited_handling,
self.context.shared.quirks_mode(),
);
let stylist = &self.context.shared.stylist;
let implemented_pseudo = self.element.implemented_pseudo_element();
@ -451,10 +446,9 @@ where
// FIXME(emilio): This is a hack for animations, and should go away.
self.element.unset_dirty_style_attribute();
let rule_node = stylist.rule_tree().compute_rule_node(
&mut applicable_declarations,
&self.context.shared.guards
);
let rule_node = stylist
.rule_tree()
.compute_rule_node(&mut applicable_declarations, &self.context.shared.guards);
if log_enabled!(Trace) {
trace!("Matched rules for {:?}:", self.element);
@ -466,7 +460,7 @@ where
}
}
MatchingResults { rule_node, }
MatchingResults { rule_node }
}
fn match_pseudo(
@ -475,31 +469,36 @@ where
pseudo_element: &PseudoElement,
visited_handling: VisitedHandlingMode,
) -> Option<StrongRuleNode> {
debug!("Match pseudo {:?} for {:?}, visited: {:?}",
self.element, pseudo_element, visited_handling);
debug!(
"Match pseudo {:?} for {:?}, visited: {:?}",
self.element, pseudo_element, visited_handling
);
debug_assert!(pseudo_element.is_eager());
debug_assert!(self.element.implemented_pseudo_element().is_none(),
"Element pseudos can't have any other pseudo.");
debug_assert!(
self.element.implemented_pseudo_element().is_none(),
"Element pseudos can't have any other pseudo."
);
let mut applicable_declarations = ApplicableDeclarationList::new();
let stylist = &self.context.shared.stylist;
if !self.element.may_generate_pseudo(pseudo_element, originating_element_style) {
if !self.element
.may_generate_pseudo(pseudo_element, originating_element_style)
{
return None;
}
let bloom_filter = self.context.thread_local.bloom_filter.filter();
let nth_index_cache = &mut self.context.thread_local.nth_index_cache;
let mut matching_context =
MatchingContext::new_for_visited(
MatchingMode::ForStatelessPseudoElement,
Some(bloom_filter),
Some(nth_index_cache),
visited_handling,
self.context.shared.quirks_mode(),
);
let mut matching_context = MatchingContext::new_for_visited(
MatchingMode::ForStatelessPseudoElement,
Some(bloom_filter),
Some(nth_index_cache),
visited_handling,
self.context.shared.quirks_mode(),
);
let map = &mut self.context.thread_local.selector_flags;
let resolving_element = self.element;
@ -518,17 +517,16 @@ where
self.rule_inclusion,
&mut applicable_declarations,
&mut matching_context,
&mut set_selector_flags
&mut set_selector_flags,
);
if applicable_declarations.is_empty() {
return None;
}
let rule_node = stylist.rule_tree().compute_rule_node(
&mut applicable_declarations,
&self.context.shared.guards
);
let rule_node = stylist
.rule_tree()
.compute_rule_node(&mut applicable_declarations, &self.context.shared.guards);
Some(rule_node)
}

View file

@ -30,7 +30,10 @@ where
S: StylesheetInDocument + PartialEq + 'static,
{
fn new(sheet: S) -> Self {
Self { sheet, committed: false }
Self {
sheet,
committed: false,
}
}
}
@ -48,7 +51,6 @@ where
}
}
impl<'a, S> Iterator for StylesheetCollectionIterator<'a, S>
where
S: StylesheetInDocument + PartialEq + 'static,
@ -86,14 +88,16 @@ where
if self.current.is_none() {
let next_origin = self.origins.next()?;
self.current =
Some((next_origin, self.collections.borrow_for_origin(&next_origin).iter()));
self.current = Some((
next_origin,
self.collections.borrow_for_origin(&next_origin).iter(),
));
}
{
let (origin, ref mut iter) = *self.current.as_mut().unwrap();
if let Some(s) = iter.next() {
return Some((s, origin))
return Some((s, origin));
}
}
@ -176,7 +180,7 @@ where
/// appropriate stylesheets that need work.
pub struct SheetCollectionFlusher<'a, S>
where
S: StylesheetInDocument + PartialEq + 'static
S: StylesheetInDocument + PartialEq + 'static,
{
iter: slice::IterMut<'a, StylesheetSetEntry<S>>,
validity: DataValidity,
@ -216,7 +220,7 @@ where
if !committed {
// If the sheet was uncommitted, we need to do a full rebuild
// anyway.
return Some((&potential_sheet.sheet, SheetRebuildKind::Full))
return Some((&potential_sheet.sheet, SheetRebuildKind::Full));
}
let rebuild_kind = match self.validity {
@ -283,9 +287,7 @@ where
}
fn remove(&mut self, sheet: &S) {
let index = self.entries.iter().position(|entry| {
entry.sheet == *sheet
});
let index = self.entries.iter().position(|entry| entry.sheet == *sheet);
if cfg!(feature = "gecko") && index.is_none() {
// FIXME(emilio): Make Gecko's PresShell::AddUserSheet not suck.
return;
@ -322,9 +324,10 @@ where
fn insert_before(&mut self, sheet: S, before_sheet: &S) {
debug_assert!(!self.contains(&sheet));
let index = self.entries.iter().position(|entry| {
entry.sheet == *before_sheet
}).expect("`before_sheet` stylesheet not found");
let index = self.entries
.iter()
.position(|entry| entry.sheet == *before_sheet)
.expect("`before_sheet` stylesheet not found");
// Inserting stylesheets somewhere but at the end changes the validity
// of the cascade data, but not the invalidation data.
@ -483,7 +486,9 @@ where
/// Returns the number of stylesheets in the set.
pub fn len(&self) -> usize {
self.collections.iter_origins().fold(0, |s, (item, _)| s + item.len())
self.collections
.iter_origins()
.fold(0, |s, (item, _)| s + item.len())
}
/// Returns the `index`th stylesheet in the set for the given origin.
@ -493,7 +498,9 @@ where
/// Returns whether the given set has changed from the last flush.
pub fn has_changed(&self) -> bool {
self.collections.iter_origins().any(|(collection, _)| collection.dirty)
self.collections
.iter_origins()
.any(|(collection, _)| collection.dirty)
}
/// Flush the current set, unmarking it as dirty, and returns a
@ -508,8 +515,7 @@ where
{
debug!("DocumentStylesheetSet::flush");
let had_invalidations =
self.invalidations.flush(document_element, snapshots);
let had_invalidations = self.invalidations.flush(document_element, snapshots);
DocumentStylesheetFlusher {
collections: &mut self.collections,
@ -620,7 +626,8 @@ where
/// Mark the sheet set dirty, as appropriate.
pub fn force_dirty(&mut self) {
self.invalidations.invalidate_fully();
self.collection.set_data_validity_at_least(DataValidity::FullyInvalid);
self.collection
.set_data_validity_at_least(DataValidity::FullyInvalid);
}
/// Flush the stylesheets for this author set.

View file

@ -103,15 +103,17 @@ macro_rules! parse_quoted_or_unquoted_string {
($input:ident, $url_matching_function:expr) => {
$input.parse_nested_block(|input| {
let start = input.position();
input.parse_entirely(|input| {
let string = input.expect_string()?;
Ok($url_matching_function(string.as_ref().to_owned()))
}).or_else(|_: ParseError| {
while let Ok(_) = input.next() {}
Ok($url_matching_function(input.slice_from(start).to_string()))
})
input
.parse_entirely(|input| {
let string = input.expect_string()?;
Ok($url_matching_function(string.as_ref().to_owned()))
})
.or_else(|_: ParseError| {
while let Ok(_) = input.next() {}
Ok($url_matching_function(input.slice_from(start).to_string()))
})
})
}
};
}
impl UrlMatchingFunction {
@ -120,17 +122,28 @@ impl UrlMatchingFunction {
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
if input.try(|input| input.expect_function_matching("url-prefix")).is_ok() {
return parse_quoted_or_unquoted_string!(input, UrlMatchingFunction::UrlPrefix)
if input
.try(|input| input.expect_function_matching("url-prefix"))
.is_ok()
{
return parse_quoted_or_unquoted_string!(input, UrlMatchingFunction::UrlPrefix);
}
if input.try(|input| input.expect_function_matching("domain")).is_ok() {
return parse_quoted_or_unquoted_string!(input, UrlMatchingFunction::Domain)
if input
.try(|input| input.expect_function_matching("domain"))
.is_ok()
{
return parse_quoted_or_unquoted_string!(input, UrlMatchingFunction::Domain);
}
if input.try(|input| input.expect_function_matching("regexp")).is_ok() {
if input
.try(|input| input.expect_function_matching("regexp"))
.is_ok()
{
return input.parse_nested_block(|input| {
Ok(UrlMatchingFunction::Regexp(input.expect_string()?.as_ref().to_owned()))
Ok(UrlMatchingFunction::Regexp(
input.expect_string()?.as_ref().to_owned(),
))
});
}
@ -158,9 +171,7 @@ impl UrlMatchingFunction {
UrlMatchingFunction::Domain(ref pat) |
UrlMatchingFunction::Regexp(ref pat) => pat,
});
unsafe {
Gecko_DocumentRule_UseForPresentation(device.pres_context(), &*pattern, func)
}
unsafe { Gecko_DocumentRule_UseForPresentation(device.pres_context(), &*pattern, func) }
}
#[cfg(not(feature = "gecko"))]
@ -187,24 +198,25 @@ impl DocumentCondition {
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let conditions = input.parse_comma_separated(|input| {
UrlMatchingFunction::parse(context, input)
})?;
let conditions =
input.parse_comma_separated(|input| UrlMatchingFunction::parse(context, input))?;
let condition = DocumentCondition(conditions);
if !condition.allowed_in(context) {
return Err(input.new_custom_error(
StyleParseErrorKind::UnsupportedAtRule("-moz-document".into())
))
return Err(
input.new_custom_error(StyleParseErrorKind::UnsupportedAtRule(
"-moz-document".into(),
)),
);
}
Ok(condition)
}
/// Evaluate a document condition.
pub fn evaluate(&self, device: &Device) -> bool {
self.0.iter().any(|url_matching_function| {
url_matching_function.evaluate(device)
})
self.0
.iter()
.any(|url_matching_function| url_matching_function.evaluate(device))
}
#[cfg(feature = "servo")]
@ -225,7 +237,9 @@ impl DocumentCondition {
return true;
}
if !unsafe { structs::StaticPrefs_sVarCache_layout_css_moz_document_url_prefix_hack_enabled } {
if !unsafe {
structs::StaticPrefs_sVarCache_layout_css_moz_document_url_prefix_hack_enabled
} {
return false;
}
@ -239,7 +253,7 @@ impl DocumentCondition {
// NOTE(emilio): This technically allows url-prefix("") too, but...
match self.0[0] {
UrlMatchingFunction::UrlPrefix(ref prefix) => prefix.is_empty(),
_ => false
_ => false,
}
}
}

View file

@ -15,7 +15,7 @@ use error_reporting::{ContextualParseError, ParseErrorReporter};
use gecko_bindings::bindings::Gecko_AppendFeatureValueHashEntry;
#[cfg(feature = "gecko")]
use gecko_bindings::structs::{self, gfxFontFeatureValueSet, nsTArray};
use parser::{ParserContext, ParserErrorContext, Parse};
use parser::{Parse, ParserContext, ParserErrorContext};
use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
use std::fmt::{self, Write};
use str::CssStringWriter;
@ -62,11 +62,18 @@ pub trait ToGeckoFontFeatureValues {
pub struct SingleValue(pub u32);
impl Parse for SingleValue {
fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SingleValue, ParseError<'i>> {
fn parse<'i, 't>(
_context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<SingleValue, ParseError<'i>> {
let location = input.current_source_location();
match *input.next()? {
Token::Number { int_value: Some(v), .. } if v >= 0 => Ok(SingleValue(v as u32)),
Token::Number {
int_value: Some(v), ..
} if v >= 0 =>
{
Ok(SingleValue(v as u32))
},
ref t => Err(location.new_unexpected_token_error(t.clone())),
}
}
@ -75,7 +82,9 @@ impl Parse for SingleValue {
#[cfg(feature = "gecko")]
impl ToGeckoFontFeatureValues for SingleValue {
fn to_gecko_font_feature_values(&self, array: &mut nsTArray<u32>) {
unsafe { array.set_len_pod(1); }
unsafe {
array.set_len_pod(1);
}
array[0] = self.0 as u32;
}
}
@ -85,22 +94,32 @@ impl ToGeckoFontFeatureValues for SingleValue {
pub struct PairValues(pub u32, pub Option<u32>);
impl Parse for PairValues {
fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<PairValues, ParseError<'i>> {
fn parse<'i, 't>(
_context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<PairValues, ParseError<'i>> {
let location = input.current_source_location();
let first = match *input.next()? {
Token::Number { int_value: Some(a), .. } if a >= 0 => a as u32,
Token::Number {
int_value: Some(a), ..
} if a >= 0 =>
{
a as u32
},
ref t => return Err(location.new_unexpected_token_error(t.clone())),
};
let location = input.current_source_location();
match input.next() {
Ok(&Token::Number { int_value: Some(b), .. }) if b >= 0 => {
Ok(&Token::Number {
int_value: Some(b), ..
}) if b >= 0 =>
{
Ok(PairValues(first, Some(b as u32)))
}
},
// It can't be anything other than number.
Ok(t) => Err(location.new_unexpected_token_error(t.clone())),
// It can be just one value.
Err(_) => Ok(PairValues(first, None))
Err(_) => Ok(PairValues(first, None)),
}
}
}
@ -110,7 +129,9 @@ impl ToGeckoFontFeatureValues for PairValues {
fn to_gecko_font_feature_values(&self, array: &mut nsTArray<u32>) {
let len = if self.1.is_some() { 2 } else { 1 };
unsafe { array.set_len_pod(len); }
unsafe {
array.set_len_pod(len);
}
array[0] = self.0 as u32;
if let Some(second) = self.1 {
array[1] = second as u32;
@ -123,15 +144,20 @@ impl ToGeckoFontFeatureValues for PairValues {
pub struct VectorValues(#[css(iterable)] pub Vec<u32>);
impl Parse for VectorValues {
fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<VectorValues, ParseError<'i>> {
fn parse<'i, 't>(
_context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<VectorValues, ParseError<'i>> {
let mut vec = vec![];
loop {
let location = input.current_source_location();
match input.next() {
Ok(&Token::Number { int_value: Some(a), .. }) if a >= 0 => {
Ok(&Token::Number {
int_value: Some(a), ..
}) if a >= 0 =>
{
vec.push(a as u32);
},
}
// It can't be anything other than number.
Ok(t) => return Err(location.new_unexpected_token_error(t.clone())),
Err(_) => break,
@ -149,7 +175,9 @@ impl Parse for VectorValues {
#[cfg(feature = "gecko")]
impl ToGeckoFontFeatureValues for VectorValues {
fn to_gecko_font_feature_values(&self, array: &mut nsTArray<u32>) {
unsafe { array.set_len_pod(self.0.len() as u32); }
unsafe {
array.set_len_pod(self.0.len() as u32);
}
for (dest, value) in array.iter_mut().zip(self.0.iter()) {
*dest = *value;
}
@ -157,9 +185,13 @@ impl ToGeckoFontFeatureValues for VectorValues {
}
/// Parses a list of `FamilyName`s.
pub fn parse_family_name_list<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Vec<FamilyName>, ParseError<'i>> {
input.parse_comma_separated(|i| FamilyName::parse(context, i)).map_err(|e| e.into())
pub fn parse_family_name_list<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Vec<FamilyName>, ParseError<'i>> {
input
.parse_comma_separated(|i| FamilyName::parse(context, i))
.map_err(|e| e.into())
}
/// @font-feature-values inside block parser. Parses a list of `FFVDeclaration`.
@ -178,13 +210,17 @@ impl<'a, 'b, 'i, T> AtRuleParser<'i> for FFVDeclarationsParser<'a, 'b, T> {
}
impl<'a, 'b, 'i, T> DeclarationParser<'i> for FFVDeclarationsParser<'a, 'b, T>
where T: Parse
where
T: Parse,
{
type Declaration = ();
type Error = StyleParseErrorKind<'i>;
fn parse_value<'t>(&mut self, name: CowRcStr<'i>, input: &mut Parser<'i, 't>)
-> Result<(), ParseError<'i>> {
fn parse_value<'t>(
&mut self,
name: CowRcStr<'i>,
input: &mut Parser<'i, 't>,
) -> Result<(), ParseError<'i>> {
let value = input.parse_entirely(|i| T::parse(self.context, i))?;
let new = FFVDeclaration {
name: Atom::from(&*name),

View file

@ -8,7 +8,7 @@
use cssparser::SourceLocation;
use media_queries::MediaList;
use shared_lock::{DeepCloneWithLock, DeepCloneParams};
use shared_lock::{DeepCloneParams, DeepCloneWithLock};
use shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
use std::fmt::{self, Write};
use str::CssStringWriter;
@ -32,10 +32,7 @@ impl DeepCloneWithLock for ImportSheet {
use gecko::data::GeckoStyleSheet;
use gecko_bindings::bindings;
let clone = unsafe {
bindings::Gecko_StyleSheet_Clone(
self.0.raw() as *const _,
params.reference_sheet
)
bindings::Gecko_StyleSheet_Clone(self.0.raw() as *const _, params.reference_sheet)
};
ImportSheet(unsafe { GeckoStyleSheet::from_addrefed(clone) })
}
@ -117,7 +114,7 @@ impl ToCssWithGuard for ImportRule {
Some(media) if !media.is_empty() => {
dest.write_str(" ")?;
media.to_css(&mut CssWriter::new(dest))?;
}
},
_ => {},
};

View file

@ -4,9 +4,9 @@
//! Keyframes: https://drafts.csswg.org/css-animations/#keyframes
use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, RuleListParser, ParserInput, CowRcStr};
use cssparser::{DeclarationListParser, DeclarationParser, parse_one_rule, SourceLocation, Token};
use error_reporting::{NullReporter, ContextualParseError, ParseErrorReporter};
use cssparser::{AtRuleParser, CowRcStr, Parser, ParserInput, QualifiedRuleParser, RuleListParser};
use cssparser::{parse_one_rule, DeclarationListParser, DeclarationParser, SourceLocation, Token};
use error_reporting::{ContextualParseError, NullReporter, ParseErrorReporter};
use parser::{ParserContext, ParserErrorContext};
use properties::{DeclarationSource, Importance, PropertyDeclaration};
use properties::{LonghandId, PropertyDeclarationBlock, PropertyId};
@ -21,7 +21,7 @@ use str::CssStringWriter;
use style_traits::{CssWriter, ParseError, ParsingMode, StyleParseErrorKind, ToCss};
use stylesheets::{CssRuleType, StylesheetContents};
use stylesheets::rule_parser::VendorPrefix;
use values::{KeyframesName, serialize_percentage};
use values::{serialize_percentage, KeyframesName};
/// A [`@keyframes`][keyframes] rule.
///
@ -82,11 +82,14 @@ impl DeepCloneWithLock for KeyframesRule {
) -> Self {
KeyframesRule {
name: self.name.clone(),
keyframes: self.keyframes.iter()
keyframes: self.keyframes
.iter()
.map(|x| {
Arc::new(lock.wrap(
x.read_with(guard).deep_clone_with_lock(lock, guard, params)
))
Arc::new(lock.wrap(x.read_with(guard).deep_clone_with_lock(
lock,
guard,
params,
)))
})
.collect(),
vendor_prefix: self.vendor_prefix.clone(),
@ -108,7 +111,7 @@ impl ::std::cmp::Ord for KeyframePercentage {
}
}
impl ::std::cmp::Eq for KeyframePercentage { }
impl ::std::cmp::Eq for KeyframePercentage {}
impl ToCss for KeyframePercentage {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
@ -136,12 +139,14 @@ impl KeyframePercentage {
Token::Ident(ref identifier) if identifier.as_ref().eq_ignore_ascii_case("to") => {
Ok(KeyframePercentage::new(1.))
},
Token::Percentage { unit_value: percentage, .. } if percentage >= 0. && percentage <= 1. => {
Token::Percentage {
unit_value: percentage,
..
} if percentage >= 0. && percentage <= 1. =>
{
Ok(KeyframePercentage::new(percentage))
},
_ => {
Err(input.new_unexpected_token_error(token))
},
_ => Err(input.new_unexpected_token_error(token)),
}
}
}
@ -166,8 +171,9 @@ impl KeyframeSelector {
/// Parse a keyframe selector from CSS input.
pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
input.parse_comma_separated(KeyframePercentage::parse)
.map(KeyframeSelector)
input
.parse_comma_separated(KeyframePercentage::parse)
.map(KeyframeSelector)
}
}
@ -212,9 +218,11 @@ impl Keyframe {
&url_data,
Some(CssRuleType::Keyframe),
ParsingMode::DEFAULT,
parent_stylesheet_contents.quirks_mode
parent_stylesheet_contents.quirks_mode,
);
let error_context = ParserErrorContext { error_reporter: &error_reporter };
let error_context = ParserErrorContext {
error_reporter: &error_reporter,
};
context.namespaces = Some(&*namespaces);
let mut input = ParserInput::new(css);
let mut input = Parser::new(&mut input);
@ -259,7 +267,7 @@ pub enum KeyframesStepValue {
#[cfg_attr(feature = "gecko",
ignore_malloc_size_of = "XXX: Primary ref, measure if DMD says it's worthwhile")]
#[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")]
block: Arc<Locked<PropertyDeclarationBlock>>
block: Arc<Locked<PropertyDeclarationBlock>>,
},
/// A synthetic step computed from the current computed values at the time
/// of the animation.
@ -283,18 +291,20 @@ pub struct KeyframesStep {
impl KeyframesStep {
#[inline]
fn new(percentage: KeyframePercentage,
value: KeyframesStepValue,
guard: &SharedRwLockReadGuard) -> Self {
fn new(
percentage: KeyframePercentage,
value: KeyframesStepValue,
guard: &SharedRwLockReadGuard,
) -> Self {
let declared_timing_function = match value {
KeyframesStepValue::Declarations { ref block } => {
block.read_with(guard).declarations().iter().any(|prop_decl| {
match *prop_decl {
PropertyDeclaration::AnimationTimingFunction(..) => true,
_ => false,
}
})
}
KeyframesStepValue::Declarations { ref block } => block
.read_with(guard)
.declarations()
.iter()
.any(|prop_decl| match *prop_decl {
PropertyDeclaration::AnimationTimingFunction(..) => true,
_ => false,
}),
_ => false,
};
@ -306,16 +316,21 @@ impl KeyframesStep {
}
/// Return specified TransitionTimingFunction if this KeyframesSteps has 'animation-timing-function'.
pub fn get_animation_timing_function(&self, guard: &SharedRwLockReadGuard)
-> Option<SpecifiedTimingFunction> {
pub fn get_animation_timing_function(
&self,
guard: &SharedRwLockReadGuard,
) -> Option<SpecifiedTimingFunction> {
if !self.declared_timing_function {
return None;
}
match self.value {
KeyframesStepValue::Declarations { ref block } => {
let guard = block.read_with(guard);
let (declaration, _) =
guard.get(PropertyDeclarationId::Longhand(LonghandId::AnimationTimingFunction)).unwrap();
let (declaration, _) = guard
.get(PropertyDeclarationId::Longhand(
LonghandId::AnimationTimingFunction,
))
.unwrap();
match *declaration {
PropertyDeclaration::AnimationTimingFunction(ref value) => {
// Use the first value.
@ -350,7 +365,7 @@ pub struct KeyframesAnimation {
/// Get all the animated properties in a keyframes animation.
fn get_animated_properties(
keyframes: &[Arc<Locked<Keyframe>>],
guard: &SharedRwLockReadGuard
guard: &SharedRwLockReadGuard,
) -> LonghandIdSet {
let mut ret = LonghandIdSet::new();
// NB: declarations are already deduplicated, so we don't have to check for
@ -417,9 +432,13 @@ impl KeyframesAnimation {
for keyframe in keyframes {
let keyframe = keyframe.read_with(&guard);
for percentage in keyframe.selector.0.iter() {
result.steps.push(KeyframesStep::new(*percentage, KeyframesStepValue::Declarations {
block: keyframe.block.clone(),
}, guard));
result.steps.push(KeyframesStep::new(
*percentage,
KeyframesStepValue::Declarations {
block: keyframe.block.clone(),
},
guard,
));
}
}
@ -428,15 +447,22 @@ impl KeyframesAnimation {
// Prepend autogenerated keyframes if appropriate.
if result.steps[0].start_percentage.0 != 0. {
result.steps.insert(0, KeyframesStep::new(KeyframePercentage::new(0.),
KeyframesStepValue::ComputedValues,
guard));
result.steps.insert(
0,
KeyframesStep::new(
KeyframePercentage::new(0.),
KeyframesStepValue::ComputedValues,
guard,
),
);
}
if result.steps.last().unwrap().start_percentage.0 != 1. {
result.steps.push(KeyframesStep::new(KeyframePercentage::new(1.),
KeyframesStepValue::ComputedValues,
guard));
result.steps.push(KeyframesStep::new(
KeyframePercentage::new(1.),
KeyframesStepValue::ComputedValues,
guard,
));
}
result
@ -463,20 +489,27 @@ pub fn parse_keyframe_list<R>(
context: &ParserContext,
error_context: &ParserErrorContext<R>,
input: &mut Parser,
shared_lock: &SharedRwLock
shared_lock: &SharedRwLock,
) -> Vec<Arc<Locked<Keyframe>>>
where R: ParseErrorReporter
where
R: ParseErrorReporter,
{
debug_assert!(context.namespaces.is_some(),
"Parsing a keyframe list from a context without namespaces?");
debug_assert!(
context.namespaces.is_some(),
"Parsing a keyframe list from a context without namespaces?"
);
let mut declarations = SourcePropertyDeclaration::new();
RuleListParser::new_for_nested_rule(input, KeyframeListParser {
context: context,
error_context: error_context,
shared_lock: shared_lock,
declarations: &mut declarations,
}).filter_map(Result::ok).collect()
RuleListParser::new_for_nested_rule(
input,
KeyframeListParser {
context: context,
error_context: error_context,
shared_lock: shared_lock,
declarations: &mut declarations,
},
).filter_map(Result::ok)
.collect()
}
impl<'a, 'i, R> AtRuleParser<'i> for KeyframeListParser<'a, R> {
@ -497,33 +530,40 @@ impl<'a, 'i, R: ParseErrorReporter> QualifiedRuleParser<'i> for KeyframeListPars
type QualifiedRule = Arc<Locked<Keyframe>>;
type Error = StyleParseErrorKind<'i>;
fn parse_prelude<'t>(&mut self, input: &mut Parser<'i, 't>) -> Result<Self::Prelude, ParseError<'i>> {
fn parse_prelude<'t>(
&mut self,
input: &mut Parser<'i, 't>,
) -> Result<Self::Prelude, ParseError<'i>> {
let start_position = input.position();
let start_location = input.current_source_location();
match KeyframeSelector::parse(input) {
Ok(sel) => {
Ok(KeyframeSelectorParserPrelude {
selector: sel,
source_location: start_location,
})
},
Ok(sel) => Ok(KeyframeSelectorParserPrelude {
selector: sel,
source_location: start_location,
}),
Err(e) => {
let location = e.location;
let error = ContextualParseError::InvalidKeyframeRule(input.slice_from(start_position), e.clone());
self.context.log_css_error(self.error_context, location, error);
let error = ContextualParseError::InvalidKeyframeRule(
input.slice_from(start_position),
e.clone(),
);
self.context
.log_css_error(self.error_context, location, error);
Err(e)
}
},
}
}
fn parse_block<'t>(&mut self, prelude: Self::Prelude, input: &mut Parser<'i, 't>)
-> Result<Self::QualifiedRule, ParseError<'i>> {
let context =
ParserContext::new_with_rule_type(
self.context,
CssRuleType::Keyframe,
self.context.namespaces.unwrap(),
);
fn parse_block<'t>(
&mut self,
prelude: Self::Prelude,
input: &mut Parser<'i, 't>,
) -> Result<Self::QualifiedRule, ParseError<'i>> {
let context = ParserContext::new_with_rule_type(
self.context,
CssRuleType::Keyframe,
self.context.namespaces.unwrap(),
);
let parser = KeyframeDeclarationParser {
context: &context,
@ -539,13 +579,14 @@ impl<'a, 'i, R: ParseErrorReporter> QualifiedRuleParser<'i> for KeyframeListPars
Importance::Normal,
DeclarationSource::Parsing,
);
}
},
Err((error, slice)) => {
iter.parser.declarations.clear();
let location = error.location;
let error = ContextualParseError::UnsupportedKeyframePropertyDeclaration(slice, error);
let error =
ContextualParseError::UnsupportedKeyframePropertyDeclaration(slice, error);
context.log_css_error(self.error_context, location, error);
}
},
}
// `parse_important` is not called here, `!important` is not allowed in keyframe blocks.
}

View file

@ -46,7 +46,9 @@ impl ToCssWithGuard for MediaRule {
// https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSMediaRule
fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
dest.write_str("@media ")?;
self.media_queries.read_with(guard).to_css(&mut CssWriter::new(dest))?;
self.media_queries
.read_with(guard)
.to_css(&mut CssWriter::new(dest))?;
self.rules.read_with(guard).to_css_block(guard, dest)
}
}

View file

@ -50,7 +50,7 @@ pub use self::rule_parser::{State, TopLevelRuleParser};
pub use self::rule_list::{CssRules, CssRulesHelpers};
pub use self::rules_iterator::{AllRules, EffectiveRules};
pub use self::rules_iterator::{NestedRuleIterationCondition, RulesIterator};
pub use self::stylesheet::{Namespaces, Stylesheet, DocumentStyleSheet};
pub use self::stylesheet::{DocumentStyleSheet, Namespaces, Stylesheet};
pub use self::stylesheet::{StylesheetContents, StylesheetInDocument, UserAgentStylesheets};
pub use self::style_rule::StyleRule;
pub use self::supports_rule::SupportsRule;
@ -94,7 +94,6 @@ impl Eq for UrlExtraData {}
pub enum CssRule {
// No Charset here, CSSCharsetRule has been removed from CSSOM
// https://drafts.csswg.org/cssom/#changes-from-5-december-2013
Namespace(Arc<Locked<NamespaceRule>>),
Import(Arc<Locked<ImportRule>>),
Style(Arc<Locked<StyleRule>>),
@ -116,18 +115,19 @@ impl CssRule {
match *self {
// Not all fields are currently fully measured. Extra measurement
// may be added later.
CssRule::Namespace(_) => 0,
// We don't need to measure ImportRule::stylesheet because we measure
// it on the C++ side in the child list of the ServoStyleSheet.
CssRule::Import(_) => 0,
CssRule::Style(ref lock) =>
lock.unconditional_shallow_size_of(ops) + lock.read_with(guard).size_of(guard, ops),
CssRule::Style(ref lock) => {
lock.unconditional_shallow_size_of(ops) + lock.read_with(guard).size_of(guard, ops)
},
CssRule::Media(ref lock) =>
lock.unconditional_shallow_size_of(ops) + lock.read_with(guard).size_of(guard, ops),
CssRule::Media(ref lock) => {
lock.unconditional_shallow_size_of(ops) + lock.read_with(guard).size_of(guard, ops)
},
CssRule::FontFace(_) => 0,
CssRule::FontFeatureValues(_) => 0,
@ -135,14 +135,17 @@ impl CssRule {
CssRule::Viewport(_) => 0,
CssRule::Keyframes(_) => 0,
CssRule::Supports(ref lock) =>
lock.unconditional_shallow_size_of(ops) + lock.read_with(guard).size_of(guard, ops),
CssRule::Supports(ref lock) => {
lock.unconditional_shallow_size_of(ops) + lock.read_with(guard).size_of(guard, ops)
},
CssRule::Page(ref lock) =>
lock.unconditional_shallow_size_of(ops) + lock.read_with(guard).size_of(guard, ops),
CssRule::Page(ref lock) => {
lock.unconditional_shallow_size_of(ops) + lock.read_with(guard).size_of(guard, ops)
},
CssRule::Document(ref lock) =>
lock.unconditional_shallow_size_of(ops) + lock.read_with(guard).size_of(guard, ops),
CssRule::Document(ref lock) => {
lock.unconditional_shallow_size_of(ops) + lock.read_with(guard).size_of(guard, ops)
},
}
}
}
@ -151,28 +154,28 @@ impl CssRule {
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CssRuleType {
// https://drafts.csswg.org/cssom/#the-cssrule-interface
Style = 1,
Charset = 2,
Import = 3,
Media = 4,
FontFace = 5,
Page = 6,
Style = 1,
Charset = 2,
Import = 3,
Media = 4,
FontFace = 5,
Page = 6,
// https://drafts.csswg.org/css-animations-1/#interface-cssrule-idl
Keyframes = 7,
Keyframe = 8,
Keyframes = 7,
Keyframe = 8,
// https://drafts.csswg.org/cssom/#the-cssrule-interface
Margin = 9,
Namespace = 10,
Margin = 9,
Namespace = 10,
// https://drafts.csswg.org/css-counter-styles-3/#extentions-to-cssrule-interface
CounterStyle = 11,
CounterStyle = 11,
// https://drafts.csswg.org/css-conditional-3/#extentions-to-cssrule-interface
Supports = 12,
Supports = 12,
// https://www.w3.org/TR/2012/WD-css3-conditional-20120911/#extentions-to-cssrule-interface
Document = 13,
Document = 13,
// https://drafts.csswg.org/css-fonts-3/#om-fontfeaturevalues
FontFeatureValues = 14,
FontFeatureValues = 14,
// https://drafts.csswg.org/css-device-adapt/#css-rule-interface
Viewport = 15,
Viewport = 15,
}
#[allow(missing_docs)]
@ -213,7 +216,7 @@ impl CssRule {
CssRule::Viewport(_) => CssRuleType::Viewport,
CssRule::Supports(_) => CssRuleType::Supports,
CssRule::Page(_) => CssRuleType::Page,
CssRule::Document(_) => CssRuleType::Document,
CssRule::Document(_) => CssRuleType::Document,
}
}
@ -236,7 +239,7 @@ impl CssRule {
parent_stylesheet_contents: &StylesheetContents,
shared_lock: &SharedRwLock,
state: Option<State>,
loader: Option<&StylesheetLoader>
loader: Option<&StylesheetLoader>,
) -> Result<(Self, State), SingleRuleParseError> {
let url_data = parent_stylesheet_contents.url_data.read();
let error_reporter = NullReporter;
@ -258,7 +261,9 @@ impl CssRule {
let mut rule_parser = TopLevelRuleParser {
stylesheet_origin: parent_stylesheet_contents.origin,
context: context,
error_context: ParserErrorContext { error_reporter: &error_reporter },
error_context: ParserErrorContext {
error_reporter: &error_reporter,
},
shared_lock: &shared_lock,
loader: loader,
state: state,
@ -298,13 +303,19 @@ impl DeepCloneWithLock for CssRule {
},
CssRule::Style(ref arc) => {
let rule = arc.read_with(guard);
CssRule::Style(Arc::new(
lock.wrap(rule.deep_clone_with_lock(lock, guard, params))))
CssRule::Style(Arc::new(lock.wrap(rule.deep_clone_with_lock(
lock,
guard,
params,
))))
},
CssRule::Media(ref arc) => {
let rule = arc.read_with(guard);
CssRule::Media(Arc::new(
lock.wrap(rule.deep_clone_with_lock(lock, guard, params))))
CssRule::Media(Arc::new(lock.wrap(rule.deep_clone_with_lock(
lock,
guard,
params,
))))
},
CssRule::FontFace(ref arc) => {
let rule = arc.read_with(guard);
@ -324,23 +335,35 @@ impl DeepCloneWithLock for CssRule {
},
CssRule::Keyframes(ref arc) => {
let rule = arc.read_with(guard);
CssRule::Keyframes(Arc::new(
lock.wrap(rule.deep_clone_with_lock(lock, guard, params))))
CssRule::Keyframes(Arc::new(lock.wrap(rule.deep_clone_with_lock(
lock,
guard,
params,
))))
},
CssRule::Supports(ref arc) => {
let rule = arc.read_with(guard);
CssRule::Supports(Arc::new(
lock.wrap(rule.deep_clone_with_lock(lock, guard, params))))
CssRule::Supports(Arc::new(lock.wrap(rule.deep_clone_with_lock(
lock,
guard,
params,
))))
},
CssRule::Page(ref arc) => {
let rule = arc.read_with(guard);
CssRule::Page(Arc::new(
lock.wrap(rule.deep_clone_with_lock(lock, guard, params))))
CssRule::Page(Arc::new(lock.wrap(rule.deep_clone_with_lock(
lock,
guard,
params,
))))
},
CssRule::Document(ref arc) => {
let rule = arc.read_with(guard);
CssRule::Document(Arc::new(
lock.wrap(rule.deep_clone_with_lock(lock, guard, params))))
CssRule::Document(Arc::new(lock.wrap(rule.deep_clone_with_lock(
lock,
guard,
params,
))))
},
}
}

View file

@ -57,10 +57,7 @@ impl OriginSet {
/// See the `OriginSet` documentation for information about the order
/// origins are iterated.
pub fn iter(&self) -> OriginSetIterator {
OriginSetIterator {
set: *self,
cur: 0,
}
OriginSetIterator { set: *self, cur: 0 }
}
}
@ -94,7 +91,7 @@ impl Iterator for OriginSetIterator {
self.cur += 1;
if self.set.contains(origin.into()) {
return Some(origin)
return Some(origin);
}
}
}
@ -177,7 +174,10 @@ pub struct PerOriginIter<'a, T: 'a> {
rev: bool,
}
impl<'a, T> Iterator for PerOriginIter<'a, T> where T: 'a {
impl<'a, T> Iterator for PerOriginIter<'a, T>
where
T: 'a,
{
type Item = (&'a T, Origin);
fn next(&mut self) -> Option<Self::Item> {
@ -201,7 +201,10 @@ pub struct PerOriginIterMut<'a, T: 'a> {
_marker: PhantomData<&'a mut PerOrigin<T>>,
}
impl<'a, T> Iterator for PerOriginIterMut<'a, T> where T: 'a {
impl<'a, T> Iterator for PerOriginIterMut<'a, T>
where
T: 'a,
{
type Item = (&'a mut T, Origin);
fn next(&mut self) -> Option<Self::Item> {
@ -209,6 +212,9 @@ impl<'a, T> Iterator for PerOriginIterMut<'a, T> where T: 'a {
self.cur += 1;
Some((unsafe { (*self.data).borrow_mut_for_origin(&origin) }, origin))
Some((
unsafe { (*self.data).borrow_mut_for_origin(&origin) },
origin,
))
}
}

View file

@ -34,9 +34,12 @@ impl DeepCloneWithLock for CssRules {
guard: &SharedRwLockReadGuard,
params: &DeepCloneParams,
) -> Self {
CssRules(self.0.iter().map(|x| {
x.deep_clone_with_lock(lock, guard, params)
}).collect())
CssRules(
self.0
.iter()
.map(|x| x.deep_clone_with_lock(lock, guard, params))
.collect(),
)
}
}
@ -59,12 +62,9 @@ impl CssRules {
/// Returns whether all the rules in this list are namespace or import
/// rules.
fn only_ns_or_import(&self) -> bool {
self.0.iter().all(|r| {
match *r {
CssRule::Namespace(..) |
CssRule::Import(..) => true,
_ => false
}
self.0.iter().all(|r| match *r {
CssRule::Namespace(..) | CssRule::Import(..) => true,
_ => false,
})
}
@ -96,7 +96,11 @@ impl CssRules {
///
/// This should be speced into CSSOM spec at some point. See
/// <https://github.com/w3c/csswg-drafts/issues/1985>
pub fn to_css_block(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
pub fn to_css_block(
&self,
guard: &SharedRwLockReadGuard,
dest: &mut CssStringWriter,
) -> fmt::Result {
dest.write_str(" {")?;
for rule in self.0.iter() {
dest.write_str("\n ")?;
@ -116,25 +120,27 @@ pub trait CssRulesHelpers {
///
/// TODO(emilio): We could also pass the write guard down into the loader
/// instead, but that seems overkill.
fn insert_rule(&self,
lock: &SharedRwLock,
rule: &str,
parent_stylesheet_contents: &StylesheetContents,
index: usize,
nested: bool,
loader: Option<&StylesheetLoader>)
-> Result<CssRule, RulesMutateError>;
fn insert_rule(
&self,
lock: &SharedRwLock,
rule: &str,
parent_stylesheet_contents: &StylesheetContents,
index: usize,
nested: bool,
loader: Option<&StylesheetLoader>,
) -> Result<CssRule, RulesMutateError>;
}
impl CssRulesHelpers for RawOffsetArc<Locked<CssRules>> {
fn insert_rule(&self,
lock: &SharedRwLock,
rule: &str,
parent_stylesheet_contents: &StylesheetContents,
index: usize,
nested: bool,
loader: Option<&StylesheetLoader>)
-> Result<CssRule, RulesMutateError> {
fn insert_rule(
&self,
lock: &SharedRwLock,
rule: &str,
parent_stylesheet_contents: &StylesheetContents,
index: usize,
nested: bool,
loader: Option<&StylesheetLoader>,
) -> Result<CssRule, RulesMutateError> {
let state = {
let read_guard = lock.read();
let rules = self.read_with(&read_guard);
@ -157,13 +163,7 @@ impl CssRulesHelpers for RawOffsetArc<Locked<CssRules>> {
// Step 3, 4
// XXXManishearth should we also store the namespace map?
let (new_rule, new_state) =
CssRule::parse(
&rule,
parent_stylesheet_contents,
lock,
state,
loader
)?;
CssRule::parse(&rule, parent_stylesheet_contents, lock, state, loader)?;
{
let mut write_guard = lock.write();

View file

@ -7,7 +7,7 @@
use {Namespace, Prefix};
use counter_style::{parse_counter_style_body, parse_counter_style_name_definition};
use cssparser::{AtRuleParser, AtRuleType, Parser, QualifiedRuleParser, RuleListParser};
use cssparser::{CowRcStr, SourceLocation, BasicParseError, BasicParseErrorKind};
use cssparser::{BasicParseError, BasicParseErrorKind, CowRcStr, SourceLocation};
use error_reporting::{ContextualParseError, ParseErrorReporter};
use font_face::parse_font_face_block;
use media_queries::{parse_media_query_list, MediaList};
@ -18,8 +18,8 @@ use selectors::SelectorList;
use servo_arc::Arc;
use shared_lock::{Locked, SharedRwLock};
use str::starts_with_ignore_ascii_case;
use style_traits::{StyleParseErrorKind, ParseError};
use stylesheets::{CssRule, CssRules, CssRuleType, Origin, StylesheetLoader};
use style_traits::{ParseError, StyleParseErrorKind};
use stylesheets::{CssRule, CssRuleType, CssRules, Origin, StylesheetLoader};
use stylesheets::{DocumentRule, FontFeatureValuesRule, KeyframesRule, MediaRule};
use stylesheets::{NamespaceRule, PageRule, StyleRule, SupportsRule, ViewportRule};
use stylesheets::document_rule::DocumentCondition;
@ -146,7 +146,7 @@ impl<'a, 'i, R: ParseErrorReporter> AtRuleParser<'i> for TopLevelRuleParser<'a,
fn parse_prelude<'t>(
&mut self,
name: CowRcStr<'i>,
input: &mut Parser<'i, 't>
input: &mut Parser<'i, 't>,
) -> Result<AtRuleType<AtRuleNonBlockPrelude, AtRuleBlockPrelude>, ParseError<'i>> {
let location = input.current_source_location();
match_ignore_ascii_case! { &*name,
@ -203,18 +203,20 @@ impl<'a, 'i, R: ParseErrorReporter> AtRuleParser<'i> for TopLevelRuleParser<'a,
fn parse_block<'t>(
&mut self,
prelude: AtRuleBlockPrelude,
input: &mut Parser<'i, 't>
input: &mut Parser<'i, 't>,
) -> Result<CssRule, ParseError<'i>> {
AtRuleParser::parse_block(&mut self.nested(), prelude, input)
.map(|rule| { self.state = State::Body; rule })
AtRuleParser::parse_block(&mut self.nested(), prelude, input).map(|rule| {
self.state = State::Body;
rule
})
}
#[inline]
fn rule_without_block(&mut self, prelude: AtRuleNonBlockPrelude) -> CssRule {
match prelude {
AtRuleNonBlockPrelude::Import(url, media, location) => {
let loader =
self.loader.expect("Expected a stylesheet loader for @import");
let loader = self.loader
.expect("Expected a stylesheet loader for @import");
let import_rule = loader.request_stylesheet(
url,
@ -226,12 +228,10 @@ impl<'a, 'i, R: ParseErrorReporter> AtRuleParser<'i> for TopLevelRuleParser<'a,
self.state = State::Imports;
CssRule::Import(import_rule)
}
},
AtRuleNonBlockPrelude::Namespace(prefix, url, location) => {
let opt_prefix = if let Some(prefix) = prefix {
self.namespaces
.prefixes
.insert(prefix.clone(), url.clone());
self.namespaces.prefixes.insert(prefix.clone(), url.clone());
Some(prefix)
} else {
self.namespaces.default = Some(url.clone());
@ -239,14 +239,12 @@ impl<'a, 'i, R: ParseErrorReporter> AtRuleParser<'i> for TopLevelRuleParser<'a,
};
self.state = State::Namespaces;
CssRule::Namespace(Arc::new(
self.shared_lock.wrap(NamespaceRule {
prefix: opt_prefix,
url: url,
source_location: location,
})
))
}
CssRule::Namespace(Arc::new(self.shared_lock.wrap(NamespaceRule {
prefix: opt_prefix,
url: url,
source_location: location,
})))
},
}
}
}
@ -273,14 +271,16 @@ impl<'a, 'i, R: ParseErrorReporter> QualifiedRuleParser<'i> for TopLevelRulePars
fn parse_block<'t>(
&mut self,
prelude: QualifiedRuleParserPrelude,
input: &mut Parser<'i, 't>
input: &mut Parser<'i, 't>,
) -> Result<CssRule, ParseError<'i>> {
QualifiedRuleParser::parse_block(&mut self.nested(), prelude, input)
.map(|result| { self.state = State::Body; result })
QualifiedRuleParser::parse_block(&mut self.nested(), prelude, input).map(|result| {
self.state = State::Body;
result
})
}
}
#[derive(Clone)] // shallow, relatively cheap .clone
#[derive(Clone)] // shallow, relatively cheap .clone
struct NestedRuleParser<'a, 'b: 'a, R: 'b> {
stylesheet_origin: Origin,
shared_lock: &'a SharedRwLock,
@ -293,13 +293,9 @@ impl<'a, 'b, R: ParseErrorReporter> NestedRuleParser<'a, 'b, R> {
fn parse_nested_rules(
&mut self,
input: &mut Parser,
rule_type: CssRuleType
rule_type: CssRuleType,
) -> Arc<Locked<CssRules>> {
let context = ParserContext::new_with_rule_type(
self.context,
rule_type,
self.namespaces,
);
let context = ParserContext::new_with_rule_type(self.context, rule_type, self.namespaces);
let nested_parser = NestedRuleParser {
stylesheet_origin: self.stylesheet_origin,
@ -317,8 +313,9 @@ impl<'a, 'b, R: ParseErrorReporter> NestedRuleParser<'a, 'b, R> {
Err((error, slice)) => {
let location = error.location;
let error = ContextualParseError::InvalidRule(slice, error);
self.context.log_css_error(self.error_context, location, error);
}
self.context
.log_css_error(self.error_context, location, error);
},
}
}
CssRules::new(rules, self.shared_lock)
@ -334,7 +331,7 @@ impl<'a, 'b, 'i, R: ParseErrorReporter> AtRuleParser<'i> for NestedRuleParser<'a
fn parse_prelude<'t>(
&mut self,
name: CowRcStr<'i>,
input: &mut Parser<'i, 't>
input: &mut Parser<'i, 't>,
) -> Result<AtRuleType<AtRuleNonBlockPrelude, AtRuleBlockPrelude>, ParseError<'i>> {
let location = input.current_source_location();
@ -416,7 +413,7 @@ impl<'a, 'b, 'i, R: ParseErrorReporter> AtRuleParser<'i> for NestedRuleParser<'a
fn parse_block<'t>(
&mut self,
prelude: AtRuleBlockPrelude,
input: &mut Parser<'i, 't>
input: &mut Parser<'i, 't>,
) -> Result<CssRule, ParseError<'i>> {
match prelude {
AtRuleBlockPrelude::FontFace(location) => {
@ -427,8 +424,9 @@ impl<'a, 'b, 'i, R: ParseErrorReporter> AtRuleParser<'i> for NestedRuleParser<'a
);
Ok(CssRule::FontFace(Arc::new(self.shared_lock.wrap(
parse_font_face_block(&context, self.error_context, input, location).into()))))
}
parse_font_face_block(&context, self.error_context, input, location).into(),
))))
},
AtRuleBlockPrelude::FontFeatureValues(family_names, location) => {
let context = ParserContext::new_with_rule_type(
self.context,
@ -437,8 +435,15 @@ impl<'a, 'b, 'i, R: ParseErrorReporter> AtRuleParser<'i> for NestedRuleParser<'a
);
Ok(CssRule::FontFeatureValues(Arc::new(self.shared_lock.wrap(
FontFeatureValuesRule::parse(&context, self.error_context, input, family_names, location)))))
}
FontFeatureValuesRule::parse(
&context,
self.error_context,
input,
family_names,
location,
),
))))
},
AtRuleBlockPrelude::CounterStyle(name, location) => {
let context = ParserContext::new_with_rule_type(
self.context,
@ -446,23 +451,25 @@ impl<'a, 'b, 'i, R: ParseErrorReporter> AtRuleParser<'i> for NestedRuleParser<'a
self.namespaces,
);
Ok(CssRule::CounterStyle(Arc::new(self.shared_lock.wrap(
parse_counter_style_body(
name,
&context,
self.error_context,
input,
location
)?.into()
))))
}
Ok(CssRule::CounterStyle(Arc::new(
self.shared_lock.wrap(
parse_counter_style_body(
name,
&context,
self.error_context,
input,
location,
)?.into(),
),
)))
},
AtRuleBlockPrelude::Media(media_queries, location) => {
Ok(CssRule::Media(Arc::new(self.shared_lock.wrap(MediaRule {
media_queries: media_queries,
rules: self.parse_nested_rules(input, CssRuleType::Media),
source_location: location,
}))))
}
},
AtRuleBlockPrelude::Supports(cond, location) => {
let eval_context = ParserContext::new_with_rule_type(
self.context,
@ -471,13 +478,15 @@ impl<'a, 'b, 'i, R: ParseErrorReporter> AtRuleParser<'i> for NestedRuleParser<'a
);
let enabled = cond.eval(&eval_context);
Ok(CssRule::Supports(Arc::new(self.shared_lock.wrap(SupportsRule {
condition: cond,
rules: self.parse_nested_rules(input, CssRuleType::Supports),
enabled: enabled,
source_location: location,
}))))
}
Ok(CssRule::Supports(Arc::new(self.shared_lock.wrap(
SupportsRule {
condition: cond,
rules: self.parse_nested_rules(input, CssRuleType::Supports),
enabled: enabled,
source_location: location,
},
))))
},
AtRuleBlockPrelude::Viewport => {
let context = ParserContext::new_with_rule_type(
self.context,
@ -486,8 +495,9 @@ impl<'a, 'b, 'i, R: ParseErrorReporter> AtRuleParser<'i> for NestedRuleParser<'a
);
Ok(CssRule::Viewport(Arc::new(self.shared_lock.wrap(
ViewportRule::parse(&context, self.error_context, input)?))))
}
ViewportRule::parse(&context, self.error_context, input)?,
))))
},
AtRuleBlockPrelude::Keyframes(name, prefix, location) => {
let context = ParserContext::new_with_rule_type(
self.context,
@ -495,13 +505,20 @@ impl<'a, 'b, 'i, R: ParseErrorReporter> AtRuleParser<'i> for NestedRuleParser<'a
self.namespaces,
);
Ok(CssRule::Keyframes(Arc::new(self.shared_lock.wrap(KeyframesRule {
name: name,
keyframes: parse_keyframe_list(&context, self.error_context, input, self.shared_lock),
vendor_prefix: prefix,
source_location: location,
}))))
}
Ok(CssRule::Keyframes(Arc::new(self.shared_lock.wrap(
KeyframesRule {
name: name,
keyframes: parse_keyframe_list(
&context,
self.error_context,
input,
self.shared_lock,
),
vendor_prefix: prefix,
source_location: location,
},
))))
},
AtRuleBlockPrelude::Page(location) => {
let context = ParserContext::new_with_rule_type(
self.context,
@ -509,23 +526,26 @@ impl<'a, 'b, 'i, R: ParseErrorReporter> AtRuleParser<'i> for NestedRuleParser<'a
self.namespaces,
);
let declarations = parse_property_declaration_list(&context, self.error_context, input);
let declarations =
parse_property_declaration_list(&context, self.error_context, input);
Ok(CssRule::Page(Arc::new(self.shared_lock.wrap(PageRule {
block: Arc::new(self.shared_lock.wrap(declarations)),
source_location: location,
}))))
}
},
AtRuleBlockPrelude::Document(cond, location) => {
if cfg!(feature = "gecko") {
Ok(CssRule::Document(Arc::new(self.shared_lock.wrap(DocumentRule {
condition: cond,
rules: self.parse_nested_rules(input, CssRuleType::Document),
source_location: location,
}))))
Ok(CssRule::Document(Arc::new(self.shared_lock.wrap(
DocumentRule {
condition: cond,
rules: self.parse_nested_rules(input, CssRuleType::Document),
source_location: location,
},
))))
} else {
unreachable!()
}
}
},
}
}
}
@ -537,7 +557,7 @@ impl<'a, 'b, 'i, R: ParseErrorReporter> QualifiedRuleParser<'i> for NestedRulePa
fn parse_prelude<'t>(
&mut self,
input: &mut Parser<'i, 't>
input: &mut Parser<'i, 't>,
) -> Result<QualifiedRuleParserPrelude, ParseError<'i>> {
let selector_parser = SelectorParser {
stylesheet_origin: self.stylesheet_origin,
@ -557,13 +577,10 @@ impl<'a, 'b, 'i, R: ParseErrorReporter> QualifiedRuleParser<'i> for NestedRulePa
fn parse_block<'t>(
&mut self,
prelude: QualifiedRuleParserPrelude,
input: &mut Parser<'i, 't>
input: &mut Parser<'i, 't>,
) -> Result<CssRule, ParseError<'i>> {
let context = ParserContext::new_with_rule_type(
self.context,
CssRuleType::Style,
self.namespaces,
);
let context =
ParserContext::new_with_rule_type(self.context, CssRuleType::Style, self.namespaces);
let declarations = parse_property_declaration_list(&context, self.error_context, input);
Ok(CssRule::Style(Arc::new(self.shared_lock.wrap(StyleRule {

View file

@ -14,8 +14,9 @@ use stylesheets::StylesheetInDocument;
/// An iterator over a list of rules.
pub struct RulesIterator<'a, 'b, C>
where 'b: 'a,
C: NestedRuleIterationCondition + 'static,
where
'b: 'a,
C: NestedRuleIterationCondition + 'static,
{
device: &'a Device,
quirks_mode: QuirksMode,
@ -25,17 +26,17 @@ pub struct RulesIterator<'a, 'b, C>
}
impl<'a, 'b, C> RulesIterator<'a, 'b, C>
where 'b: 'a,
C: NestedRuleIterationCondition + 'static,
where
'b: 'a,
C: NestedRuleIterationCondition + 'static,
{
/// Creates a new `RulesIterator` to iterate over `rules`.
pub fn new(
device: &'a Device,
quirks_mode: QuirksMode,
guard: &'a SharedRwLockReadGuard<'b>,
rules: &'a CssRules)
-> Self
{
rules: &'a CssRules,
) -> Self {
let mut stack = SmallVec::new();
stack.push(rules.0.iter());
Self {
@ -54,8 +55,9 @@ impl<'a, 'b, C> RulesIterator<'a, 'b, C>
}
impl<'a, 'b, C> Iterator for RulesIterator<'a, 'b, C>
where 'b: 'a,
C: NestedRuleIterationCondition + 'static,
where
'b: 'a,
C: NestedRuleIterationCondition + 'static,
{
type Item = &'a CssRule;
@ -75,8 +77,8 @@ impl<'a, 'b, C> Iterator for RulesIterator<'a, 'b, C>
Some(r) => r,
None => {
nested_iter_finished = true;
continue
}
continue;
},
};
match *rule {
@ -87,51 +89,53 @@ impl<'a, 'b, C> Iterator for RulesIterator<'a, 'b, C>
CssRule::Viewport(_) |
CssRule::Keyframes(_) |
CssRule::Page(_) |
CssRule::FontFeatureValues(_) => {
return Some(rule)
},
CssRule::FontFeatureValues(_) => return Some(rule),
CssRule::Import(ref import_rule) => {
let import_rule = import_rule.read_with(self.guard);
if !C::process_import(self.guard,
self.device,
self.quirks_mode,
import_rule) {
if !C::process_import(
self.guard,
self.device,
self.quirks_mode,
import_rule,
) {
continue;
}
import_rule
.stylesheet.contents(self.guard).rules
.read_with(self.guard).0.iter()
}
.stylesheet
.contents(self.guard)
.rules
.read_with(self.guard)
.0
.iter()
},
CssRule::Document(ref doc_rule) => {
let doc_rule = doc_rule.read_with(self.guard);
if !C::process_document(self.guard,
self.device,
self.quirks_mode,
doc_rule) {
if !C::process_document(self.guard, self.device, self.quirks_mode, doc_rule)
{
continue;
}
doc_rule.rules.read_with(self.guard).0.iter()
}
},
CssRule::Media(ref lock) => {
let media_rule = lock.read_with(self.guard);
if !C::process_media(self.guard,
self.device,
self.quirks_mode,
media_rule) {
if !C::process_media(self.guard, self.device, self.quirks_mode, media_rule)
{
continue;
}
media_rule.rules.read_with(self.guard).0.iter()
}
},
CssRule::Supports(ref lock) => {
let supports_rule = lock.read_with(self.guard);
if !C::process_supports(self.guard,
self.device,
self.quirks_mode,
supports_rule) {
if !C::process_supports(
self.guard,
self.device,
self.quirks_mode,
supports_rule,
) {
continue;
}
supports_rule.rules.read_with(self.guard).0.iter()
}
},
}
};
@ -150,16 +154,16 @@ pub trait NestedRuleIterationCondition {
guard: &SharedRwLockReadGuard,
device: &Device,
quirks_mode: QuirksMode,
rule: &ImportRule)
-> bool;
rule: &ImportRule,
) -> bool;
/// Whether we should process the nested rules in a given `@media` rule.
fn process_media(
guard: &SharedRwLockReadGuard,
device: &Device,
quirks_mode: QuirksMode,
rule: &MediaRule)
-> bool;
rule: &MediaRule,
) -> bool;
/// Whether we should process the nested rules in a given `@-moz-document`
/// rule.
@ -167,16 +171,16 @@ pub trait NestedRuleIterationCondition {
guard: &SharedRwLockReadGuard,
device: &Device,
quirks_mode: QuirksMode,
rule: &DocumentRule)
-> bool;
rule: &DocumentRule,
) -> bool;
/// Whether we should process the nested rules in a given `@supports` rule.
fn process_supports(
guard: &SharedRwLockReadGuard,
device: &Device,
quirks_mode: QuirksMode,
rule: &SupportsRule)
-> bool;
rule: &SupportsRule,
) -> bool;
}
/// A struct that represents the condition that a rule applies to the document.
@ -187,9 +191,8 @@ impl NestedRuleIterationCondition for EffectiveRules {
guard: &SharedRwLockReadGuard,
device: &Device,
_quirks_mode: QuirksMode,
rule: &ImportRule)
-> bool
{
rule: &ImportRule,
) -> bool {
rule.stylesheet.is_effective_for_device(device, guard)
}
@ -197,19 +200,19 @@ impl NestedRuleIterationCondition for EffectiveRules {
guard: &SharedRwLockReadGuard,
device: &Device,
quirks_mode: QuirksMode,
rule: &MediaRule)
-> bool
{
rule.media_queries.read_with(guard).evaluate(device, quirks_mode)
rule: &MediaRule,
) -> bool {
rule.media_queries
.read_with(guard)
.evaluate(device, quirks_mode)
}
fn process_document(
_: &SharedRwLockReadGuard,
device: &Device,
_: QuirksMode,
rule: &DocumentRule)
-> bool
{
rule: &DocumentRule,
) -> bool {
rule.condition.evaluate(device)
}
@ -217,9 +220,8 @@ impl NestedRuleIterationCondition for EffectiveRules {
_: &SharedRwLockReadGuard,
_: &Device,
_: QuirksMode,
rule: &SupportsRule)
-> bool
{
rule: &SupportsRule,
) -> bool {
rule.enabled
}
}
@ -232,19 +234,12 @@ impl NestedRuleIterationCondition for AllRules {
_: &SharedRwLockReadGuard,
_: &Device,
_: QuirksMode,
_: &ImportRule)
-> bool
{
_: &ImportRule,
) -> bool {
true
}
fn process_media(
_: &SharedRwLockReadGuard,
_: &Device,
_: QuirksMode,
_: &MediaRule)
-> bool
{
fn process_media(_: &SharedRwLockReadGuard, _: &Device, _: QuirksMode, _: &MediaRule) -> bool {
true
}
@ -252,9 +247,8 @@ impl NestedRuleIterationCondition for AllRules {
_: &SharedRwLockReadGuard,
_: &Device,
_: QuirksMode,
_: &DocumentRule)
-> bool
{
_: &DocumentRule,
) -> bool {
true
}
@ -262,9 +256,8 @@ impl NestedRuleIterationCondition for AllRules {
_: &SharedRwLockReadGuard,
_: &Device,
_: QuirksMode,
_: &SupportsRule)
-> bool
{
_: &SupportsRule,
) -> bool {
true
}
}

View file

@ -62,7 +62,7 @@ impl StyleRule {
}
n += self.block.unconditional_shallow_size_of(ops) +
self.block.read_with(guard).size_of(ops);
self.block.read_with(guard).size_of(ops);
n
}
@ -88,4 +88,3 @@ impl ToCssWithGuard for StyleRule {
dest.write_str("}")
}
}

View file

@ -2,16 +2,16 @@
* 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/. */
use {Prefix, Namespace};
use {Namespace, Prefix};
use context::QuirksMode;
use cssparser::{Parser, RuleListParser, ParserInput};
use error_reporting::{ParseErrorReporter, ContextualParseError};
use cssparser::{Parser, ParserInput, RuleListParser};
use error_reporting::{ContextualParseError, ParseErrorReporter};
use fallible::FallibleVec;
use fnv::FnvHashMap;
use invalidation::media_queries::{MediaListKey, ToMediaListKey};
#[cfg(feature = "gecko")]
use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf};
use media_queries::{MediaList, Device};
use media_queries::{Device, MediaList};
use parking_lot::RwLock;
use parser::{ParserContext, ParserErrorContext};
use servo_arc::Arc;
@ -77,7 +77,7 @@ impl StylesheetContents {
stylesheet_loader: Option<&StylesheetLoader>,
error_reporter: &R,
quirks_mode: QuirksMode,
line_number_offset: u32
line_number_offset: u32,
) -> Self {
let namespaces = RwLock::new(Namespaces::default());
let (rules, source_map_url, source_url) = Stylesheet::parse_rules(
@ -108,7 +108,7 @@ impl StylesheetContents {
pub fn iter_rules<'a, 'b, C>(
&'a self,
device: &'a Device,
guard: &'a SharedRwLockReadGuard<'b>
guard: &'a SharedRwLockReadGuard<'b>,
) -> RulesIterator<'a, 'b, C>
where
C: NestedRuleIterationCondition,
@ -117,7 +117,7 @@ impl StylesheetContents {
device,
self.quirks_mode,
guard,
&self.rules.read_with(guard)
&self.rules.read_with(guard),
)
}
@ -138,9 +138,9 @@ impl DeepCloneWithLock for StylesheetContents {
params: &DeepCloneParams,
) -> Self {
// Make a deep clone of the rules, using the new lock.
let rules =
self.rules.read_with(guard)
.deep_clone_with_lock(lock, guard, params);
let rules = self.rules
.read_with(guard)
.deep_clone_with_lock(lock, guard, params);
Self {
rules: Arc::new(lock.wrap(rules)),
@ -206,11 +206,7 @@ pub trait StylesheetInDocument {
fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList>;
/// Returns whether the style-sheet applies for the current device.
fn is_effective_for_device(
&self,
device: &Device,
guard: &SharedRwLockReadGuard
) -> bool {
fn is_effective_for_device(&self, device: &Device, guard: &SharedRwLockReadGuard) -> bool {
match self.media(guard) {
Some(medialist) => medialist.evaluate(device, self.quirks_mode(guard)),
None => true,
@ -225,7 +221,7 @@ pub trait StylesheetInDocument {
fn iter_rules<'a, 'b, C>(
&'a self,
device: &'a Device,
guard: &'a SharedRwLockReadGuard<'b>
guard: &'a SharedRwLockReadGuard<'b>,
) -> RulesIterator<'a, 'b, C>
where
C: NestedRuleIterationCondition,
@ -239,7 +235,7 @@ pub trait StylesheetInDocument {
fn effective_rules<'a, 'b>(
&'a self,
device: &'a Device,
guard: &'a SharedRwLockReadGuard<'b>
guard: &'a SharedRwLockReadGuard<'b>,
) -> EffectiveRulesIterator<'a, 'b> {
self.iter_rules::<EffectiveRules>(device, guard)
}
@ -277,8 +273,7 @@ impl StylesheetInDocument for Stylesheet {
#[derive(Clone)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
pub struct DocumentStyleSheet(
#[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")]
pub Arc<Stylesheet>
#[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")] pub Arc<Stylesheet>,
);
impl PartialEq for DocumentStyleSheet {
@ -316,28 +311,26 @@ impl Stylesheet {
stylesheet_loader: Option<&StylesheetLoader>,
error_reporter: &R,
line_number_offset: u32,
)
where
) where
R: ParseErrorReporter,
{
let namespaces = RwLock::new(Namespaces::default());
let (rules, source_map_url, source_url) =
Stylesheet::parse_rules(
css,
&url_data,
existing.contents.origin,
&mut *namespaces.write(),
&existing.shared_lock,
stylesheet_loader,
error_reporter,
existing.contents.quirks_mode,
line_number_offset
);
let (rules, source_map_url, source_url) = Stylesheet::parse_rules(
css,
&url_data,
existing.contents.origin,
&mut *namespaces.write(),
&existing.shared_lock,
stylesheet_loader,
error_reporter,
existing.contents.quirks_mode,
line_number_offset,
);
*existing.contents.url_data.write() = url_data;
mem::swap(
&mut *existing.contents.namespaces.write(),
&mut *namespaces.write()
&mut *namespaces.write(),
);
// Acquire the lock *after* parsing, to minimize the exclusive section.
@ -356,19 +349,13 @@ impl Stylesheet {
stylesheet_loader: Option<&StylesheetLoader>,
error_reporter: &R,
quirks_mode: QuirksMode,
line_number_offset: u32
line_number_offset: u32,
) -> (Vec<CssRule>, Option<String>, Option<String>) {
let mut rules = Vec::new();
let mut input = ParserInput::new_with_line_number_offset(css, line_number_offset);
let mut input = Parser::new(&mut input);
let context = ParserContext::new(
origin,
url_data,
None,
ParsingMode::DEFAULT,
quirks_mode
);
let context = ParserContext::new(origin, url_data, None, ParsingMode::DEFAULT, quirks_mode);
let error_context = ParserErrorContext { error_reporter };
@ -384,8 +371,7 @@ impl Stylesheet {
};
{
let mut iter =
RuleListParser::new_for_stylesheet(&mut input, rule_parser);
let mut iter = RuleListParser::new_for_stylesheet(&mut input, rule_parser);
while let Some(result) = iter.next() {
match result {
@ -400,9 +386,12 @@ impl Stylesheet {
Err((error, slice)) => {
let location = error.location;
let error = ContextualParseError::InvalidRule(slice, error);
iter.parser.context.log_css_error(&iter.parser.error_context,
location, error);
}
iter.parser.context.log_css_error(
&iter.parser.error_context,
location,
error,
);
},
}
}
}
@ -426,9 +415,8 @@ impl Stylesheet {
stylesheet_loader: Option<&StylesheetLoader>,
error_reporter: &R,
quirks_mode: QuirksMode,
line_number_offset: u32)
-> Stylesheet
{
line_number_offset: u32,
) -> Stylesheet {
let contents = StylesheetContents::from_str(
css,
url_data,
@ -437,7 +425,7 @@ impl Stylesheet {
stylesheet_loader,
error_reporter,
quirks_mode,
line_number_offset
line_number_offset,
);
Stylesheet {
@ -476,11 +464,8 @@ impl Clone for Stylesheet {
// Make a deep clone of the media, using the new lock.
let media = self.media.read_with(&guard).clone();
let media = Arc::new(lock.wrap(media));
let contents = self.contents.deep_clone_with_lock(
&lock,
&guard,
&DeepCloneParams
);
let contents = self.contents
.deep_clone_with_lock(&lock, &guard, &DeepCloneParams);
Stylesheet {
contents,
@ -490,4 +475,3 @@ impl Clone for Stylesheet {
}
}
}

View file

@ -10,7 +10,7 @@ use cssparser::parse_important;
#[cfg(feature = "gecko")]
use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf};
use parser::ParserContext;
use properties::{PropertyId, PropertyDeclaration, SourcePropertyDeclaration};
use properties::{PropertyDeclaration, PropertyId, SourcePropertyDeclaration};
use selectors::parser::SelectorParseErrorKind;
use servo_arc::Arc;
use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked};
@ -111,33 +111,38 @@ impl SupportsCondition {
let (keyword, wrapper) = match input.next() {
Err(_) => {
// End of input
return Ok(in_parens)
}
return Ok(in_parens);
},
Ok(&Token::Ident(ref ident)) => {
match_ignore_ascii_case! { &ident,
"and" => ("and", SupportsCondition::And as fn(_) -> _),
"or" => ("or", SupportsCondition::Or as fn(_) -> _),
_ => return Err(location.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone())))
}
}
Ok(t) => return Err(location.new_unexpected_token_error(t.clone()))
},
Ok(t) => return Err(location.new_unexpected_token_error(t.clone())),
};
let mut conditions = Vec::with_capacity(2);
conditions.push(in_parens);
loop {
conditions.push(SupportsCondition::parse_in_parens(input)?);
if input.try(|input| input.expect_ident_matching(keyword)).is_err() {
if input
.try(|input| input.expect_ident_matching(keyword))
.is_err()
{
// Did not find the expected keyword.
// If we found some other token,
// it will be rejected by `Parser::parse_entirely` somewhere up the stack.
return Ok(wrapper(conditions))
return Ok(wrapper(conditions));
}
}
}
/// <https://drafts.csswg.org/css-conditional-3/#supports_condition_in_parens>
fn parse_in_parens<'i, 't>(input: &mut Parser<'i, 't>) -> Result<SupportsCondition, ParseError<'i>> {
fn parse_in_parens<'i, 't>(
input: &mut Parser<'i, 't>,
) -> Result<SupportsCondition, ParseError<'i>> {
// Whitespace is normally taken care of in `Parser::next`,
// but we want to not include it in `pos` for the SupportsCondition::FutureSyntax cases.
while input.try(Parser::expect_whitespace).is_ok() {}
@ -146,13 +151,12 @@ impl SupportsCondition {
// FIXME: remove clone() when lifetimes are non-lexical
match input.next()?.clone() {
Token::ParenthesisBlock => {
let nested = input.try(|input| {
input.parse_nested_block(|i| parse_condition_or_declaration(i))
});
let nested = input
.try(|input| input.parse_nested_block(|i| parse_condition_or_declaration(i)));
if nested.is_ok() {
return nested;
}
}
},
Token::Function(ident) => {
// Although this is an internal syntax, it is not necessary to check
// parsing context as far as we accept any unexpected token as future
@ -165,18 +169,19 @@ impl SupportsCondition {
.map(|s| s.to_string())
.map_err(CssParseError::<()>::from)
}).and_then(|s| {
CString::new(s)
.map_err(|_| location.new_custom_error(()))
})
CString::new(s).map_err(|_| location.new_custom_error(()))
})
}) {
return Ok(SupportsCondition::MozBoolPref(name));
}
}
}
},
t => return Err(location.new_unexpected_token_error(t)),
}
input.parse_nested_block(|i| consume_any_value(i))?;
Ok(SupportsCondition::FutureSyntax(input.slice_from(pos).to_owned()))
Ok(SupportsCondition::FutureSyntax(
input.slice_from(pos).to_owned(),
))
}
/// Evaluate a supports condition
@ -188,7 +193,7 @@ impl SupportsCondition {
SupportsCondition::Or(ref vec) => vec.iter().any(|c| c.eval(cx)),
SupportsCondition::Declaration(ref decl) => decl.eval(cx),
SupportsCondition::MozBoolPref(ref name) => eval_moz_bool_pref(name, cx),
SupportsCondition::FutureSyntax(_) => false
SupportsCondition::FutureSyntax(_) => false,
}
}
}
@ -210,8 +215,9 @@ fn eval_moz_bool_pref(_: &CStr, _: &ParserContext) -> bool {
/// supports_condition | declaration
/// <https://drafts.csswg.org/css-conditional/#dom-css-supports-conditiontext-conditiontext>
pub fn parse_condition_or_declaration<'i, 't>(input: &mut Parser<'i, 't>)
-> Result<SupportsCondition, ParseError<'i>> {
pub fn parse_condition_or_declaration<'i, 't>(
input: &mut Parser<'i, 't>,
) -> Result<SupportsCondition, ParseError<'i>> {
if let Ok(condition) = input.try(SupportsCondition::parse) {
Ok(SupportsCondition::Parenthesized(Box::new(condition)))
} else {
@ -228,12 +234,12 @@ impl ToCss for SupportsCondition {
SupportsCondition::Not(ref cond) => {
dest.write_str("not ")?;
cond.to_css(dest)
}
},
SupportsCondition::Parenthesized(ref cond) => {
dest.write_str("(")?;
cond.to_css(dest)?;
dest.write_str(")")
}
},
SupportsCondition::And(ref vec) => {
let mut first = true;
for cond in vec {
@ -244,7 +250,7 @@ impl ToCss for SupportsCondition {
cond.to_css(dest)?;
}
Ok(())
}
},
SupportsCondition::Or(ref vec) => {
let mut first = true;
for cond in vec {
@ -255,19 +261,19 @@ impl ToCss for SupportsCondition {
cond.to_css(dest)?;
}
Ok(())
}
},
SupportsCondition::Declaration(ref decl) => {
dest.write_str("(")?;
decl.to_css(dest)?;
dest.write_str(")")
}
},
SupportsCondition::MozBoolPref(ref name) => {
dest.write_str("-moz-bool-pref(")?;
let name = str::from_utf8(name.as_bytes())
.expect("Should be parsed from valid UTF-8");
let name =
str::from_utf8(name.as_bytes()).expect("Should be parsed from valid UTF-8");
name.to_css(dest)?;
dest.write_str(")")
}
},
SupportsCondition::FutureSyntax(ref s) => dest.write_str(&s),
}
}
@ -309,20 +315,21 @@ impl Declaration {
let mut input = ParserInput::new(&self.0);
let mut input = Parser::new(&mut input);
input.parse_entirely(|input| -> Result<(), CssParseError<()>> {
let prop = input.expect_ident_cloned().unwrap();
input.expect_colon().unwrap();
input
.parse_entirely(|input| -> Result<(), CssParseError<()>> {
let prop = input.expect_ident_cloned().unwrap();
input.expect_colon().unwrap();
let id = PropertyId::parse(&prop)
.map_err(|_| input.new_custom_error(()))?;
let id = PropertyId::parse(&prop).map_err(|_| input.new_custom_error(()))?;
let mut declarations = SourcePropertyDeclaration::new();
input.parse_until_before(Delimiter::Bang, |input| {
PropertyDeclaration::parse_into(&mut declarations, id, prop, &context, input)
.map_err(|_| input.new_custom_error(()))
})?;
let _ = input.try(parse_important);
Ok(())
}).is_ok()
let mut declarations = SourcePropertyDeclaration::new();
input.parse_until_before(Delimiter::Bang, |input| {
PropertyDeclaration::parse_into(&mut declarations, id, prop, &context, input)
.map_err(|_| input.new_custom_error(()))
})?;
let _ = input.try(parse_important);
Ok(())
})
.is_ok()
}
}

Some files were not shown because too many files have changed in this diff Show more