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

style: Sync changes from mozilla-central.

See each individual commit for details.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/24204)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2019-09-13 09:25:22 -04:00 committed by GitHub
commit 75bc72b29f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
49 changed files with 1124 additions and 1192 deletions

View file

@ -61,11 +61,11 @@ use style::properties::{style_structs, ComputedValues};
use style::servo::restyle_damage::ServoRestyleDamage; use style::servo::restyle_damage::ServoRestyleDamage;
use style::values::computed::effects::SimpleShadow; use style::values::computed::effects::SimpleShadow;
use style::values::computed::image::{Image, ImageLayer}; use style::values::computed::image::{Image, ImageLayer};
use style::values::computed::{Gradient, LengthOrAuto}; use style::values::computed::{ClipRectOrAuto, Gradient, LengthOrAuto};
use style::values::generics::background::BackgroundSize; use style::values::generics::background::BackgroundSize;
use style::values::generics::image::{GradientKind, PaintWorklet}; use style::values::generics::image::{GradientKind, PaintWorklet};
use style::values::specified::ui::CursorKind; use style::values::specified::ui::CursorKind;
use style::values::{Either, RGBA}; use style::values::RGBA;
use style_traits::ToCss; use style_traits::ToCss;
use webrender_api::units::{LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D}; use webrender_api::units::{LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D};
use webrender_api::{self, BorderDetails, BorderRadius, BorderSide, BoxShadowClipMode, ColorF}; use webrender_api::{self, BorderDetails, BorderRadius, BorderSide, BoxShadowClipMode, ColorF};
@ -2632,8 +2632,8 @@ impl BlockFlow {
) { ) {
// Account for `clip` per CSS 2.1 § 11.1.2. // Account for `clip` per CSS 2.1 § 11.1.2.
let style_clip_rect = match self.fragment.style().get_effects().clip { let style_clip_rect = match self.fragment.style().get_effects().clip {
Either::First(style_clip_rect) => style_clip_rect, ClipRectOrAuto::Rect(ref r) => r,
_ => return, ClipRectOrAuto::Auto => return,
}; };
// CSS `clip` should only apply to position:absolute or positione:fixed elements. // CSS `clip` should only apply to position:absolute or positione:fixed elements.

View file

@ -1497,11 +1497,10 @@ impl LayoutThread {
// Create a layout context for use throughout the following passes. // Create a layout context for use throughout the following passes.
let mut layout_context = self.build_layout_context(guards.clone(), true, &map); let mut layout_context = self.build_layout_context(guards.clone(), true, &map);
let pool;
let (thread_pool, num_threads) = if self.parallel_flag { let (thread_pool, num_threads) = if self.parallel_flag {
( pool = STYLE_THREAD_POOL.pool();
STYLE_THREAD_POOL.style_thread_pool.as_ref(), (pool.as_ref(), STYLE_THREAD_POOL.num_threads)
STYLE_THREAD_POOL.num_threads,
)
} else { } else {
(None, 1) (None, 1)
}; };
@ -1859,8 +1858,10 @@ impl LayoutThread {
|| { || {
let profiler_metadata = self.profiler_metadata(); let profiler_metadata = self.profiler_metadata();
let pool;
let thread_pool = if self.parallel_flag { let thread_pool = if self.parallel_flag {
STYLE_THREAD_POOL.style_thread_pool.as_ref() pool = STYLE_THREAD_POOL.pool();
pool.as_ref()
} else { } else {
None None
}; };

View file

@ -64,7 +64,7 @@ pub type BloomFilter = CountingBloomFilter<BloomStorageU8>;
/// Similarly, using a KeySize of 10 would lead to a 4% false /// Similarly, using a KeySize of 10 would lead to a 4% false
/// positive rate for N == 100 and to quite bad false positive /// positive rate for N == 100 and to quite bad false positive
/// rates for larger N. /// rates for larger N.
#[derive(Clone)] #[derive(Clone, Default)]
pub struct CountingBloomFilter<S> pub struct CountingBloomFilter<S>
where where
S: BloomStorage, S: BloomStorage,
@ -79,9 +79,7 @@ where
/// Creates a new bloom filter. /// Creates a new bloom filter.
#[inline] #[inline]
pub fn new() -> Self { pub fn new() -> Self {
CountingBloomFilter { Default::default()
storage: Default::default(),
}
} }
#[inline] #[inline]

View file

@ -13,13 +13,20 @@ use owning_ref::OwningHandle;
use selectors::bloom::BloomFilter; use selectors::bloom::BloomFilter;
use servo_arc::Arc; use servo_arc::Arc;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::mem::ManuallyDrop;
thread_local! { thread_local! {
/// Bloom filters are large allocations, so we store them in thread-local storage /// Bloom filters are large allocations, so we store them in thread-local storage
/// such that they can be reused across style traversals. StyleBloom is responsible /// such that they can be reused across style traversals. StyleBloom is responsible
/// for ensuring that the bloom filter is zeroed when it is dropped. /// for ensuring that the bloom filter is zeroed when it is dropped.
static BLOOM_KEY: Arc<AtomicRefCell<BloomFilter>> = ///
Arc::new_leaked(AtomicRefCell::new(BloomFilter::new())); /// We intentionally leak this from TLS because we don't have the guarantee
/// of TLS destructors to run in worker threads.
///
/// We could change this once https://github.com/rayon-rs/rayon/issues/688
/// is fixed, hopefully.
static BLOOM_KEY: ManuallyDrop<Arc<AtomicRefCell<BloomFilter>>> =
ManuallyDrop::new(Arc::new_leaked(Default::default()));
} }
/// A struct that allows us to fast-reject deep descendant selectors avoiding /// A struct that allows us to fast-reject deep descendant selectors avoiding
@ -128,7 +135,7 @@ impl<E: TElement> StyleBloom<E> {
// See https://github.com/servo/servo/pull/18420#issuecomment-328769322 // See https://github.com/servo/servo/pull/18420#issuecomment-328769322
#[inline(never)] #[inline(never)]
pub fn new() -> Self { pub fn new() -> Self {
let bloom_arc = BLOOM_KEY.with(|b| b.clone()); let bloom_arc = BLOOM_KEY.with(|b| Arc::clone(&*b));
let filter = let filter =
OwningHandle::new_with_fn(bloom_arc, |x| unsafe { x.as_ref() }.unwrap().borrow_mut()); OwningHandle::new_with_fn(bloom_arc, |x| unsafe { x.as_ref() }.unwrap().borrow_mut());
debug_assert!( debug_assert!(
@ -136,7 +143,7 @@ impl<E: TElement> StyleBloom<E> {
"Forgot to zero the bloom filter last time" "Forgot to zero the bloom filter last time"
); );
StyleBloom { StyleBloom {
filter: filter, filter,
elements: Default::default(), elements: Default::default(),
pushed_hashes: Default::default(), pushed_hashes: Default::default(),
} }

View file

@ -104,7 +104,7 @@ where
}; };
let size = get_size(device); let size = get_size(device);
let value = AspectRatio(size.width.0 as u32, size.height.0 as u32); let value = AspectRatio(size.width.0 as f32, size.height.0 as f32);
RangeOrOperator::evaluate_with_query_value(range_or_operator, query_value, value) RangeOrOperator::evaluate_with_query_value(range_or_operator, query_value, value)
} }
@ -559,7 +559,7 @@ lazy_static! {
feature!( feature!(
atom!("aspect-ratio"), atom!("aspect-ratio"),
AllowsRanges::Yes, AllowsRanges::Yes,
Evaluator::IntRatio(eval_aspect_ratio), Evaluator::NumberRatio(eval_aspect_ratio),
ParsingRequirements::empty(), ParsingRequirements::empty(),
), ),
feature!( feature!(
@ -583,7 +583,7 @@ lazy_static! {
feature!( feature!(
atom!("device-aspect-ratio"), atom!("device-aspect-ratio"),
AllowsRanges::Yes, AllowsRanges::Yes,
Evaluator::IntRatio(eval_device_aspect_ratio), Evaluator::NumberRatio(eval_device_aspect_ratio),
ParsingRequirements::empty(), ParsingRequirements::empty(),
), ),
feature!( feature!(

View file

@ -8,7 +8,7 @@
use crate::counter_style::{Symbol, Symbols}; use crate::counter_style::{Symbol, Symbols};
use crate::gecko_bindings::structs::CounterStylePtr; use crate::gecko_bindings::structs::CounterStylePtr;
use crate::values::generics::CounterStyleOrNone; use crate::values::generics::CounterStyle;
use crate::values::Either; use crate::values::Either;
use crate::Atom; use crate::Atom;
use app_units::Au; use app_units::Au;
@ -49,19 +49,17 @@ pub fn round_border_to_device_pixels(width: Au, au_per_device_px: Au) -> Au {
} }
} }
impl CounterStyleOrNone { impl CounterStyle {
/// Convert this counter style to a Gecko CounterStylePtr. /// Convert this counter style to a Gecko CounterStylePtr.
pub fn to_gecko_value(self, gecko_value: &mut CounterStylePtr) { pub fn to_gecko_value(self, gecko_value: &mut CounterStylePtr) {
use crate::gecko_bindings::bindings::Gecko_SetCounterStyleToName as set_name; use crate::gecko_bindings::bindings::Gecko_SetCounterStyleToName as set_name;
use crate::gecko_bindings::bindings::Gecko_SetCounterStyleToSymbols as set_symbols; use crate::gecko_bindings::bindings::Gecko_SetCounterStyleToSymbols as set_symbols;
match self { match self {
CounterStyleOrNone::None => unsafe { CounterStyle::Name(name) => unsafe {
set_name(gecko_value, atom!("none").into_addrefed()); debug_assert_ne!(name.0, atom!("none"));
},
CounterStyleOrNone::Name(name) => unsafe {
set_name(gecko_value, name.0.into_addrefed()); set_name(gecko_value, name.0.into_addrefed());
}, },
CounterStyleOrNone::Symbols(symbols_type, symbols) => { CounterStyle::Symbols(symbols_type, symbols) => {
let symbols: Vec<_> = symbols let symbols: Vec<_> = symbols
.0 .0
.iter() .iter()
@ -86,7 +84,7 @@ impl CounterStyleOrNone {
} }
} }
/// Convert Gecko CounterStylePtr to CounterStyleOrNone or String. /// Convert Gecko CounterStylePtr to CounterStyle or String.
pub fn from_gecko_value(gecko_value: &CounterStylePtr) -> Either<Self, String> { pub fn from_gecko_value(gecko_value: &CounterStylePtr) -> Either<Self, String> {
use crate::gecko_bindings::bindings; use crate::gecko_bindings::bindings;
use crate::values::generics::SymbolsType; use crate::values::generics::SymbolsType;
@ -95,11 +93,8 @@ impl CounterStyleOrNone {
let name = unsafe { bindings::Gecko_CounterStyle_GetName(gecko_value) }; let name = unsafe { bindings::Gecko_CounterStyle_GetName(gecko_value) };
if !name.is_null() { if !name.is_null() {
let name = unsafe { Atom::from_raw(name) }; let name = unsafe { Atom::from_raw(name) };
if name == atom!("none") { debug_assert_ne!(name, atom!("none"));
Either::First(CounterStyleOrNone::None) Either::First(CounterStyle::Name(CustomIdent(name)))
} else {
Either::First(CounterStyleOrNone::Name(CustomIdent(name)))
}
} else { } else {
let anonymous = let anonymous =
unsafe { bindings::Gecko_CounterStyle_GetAnonymous(gecko_value).as_ref() }.unwrap(); unsafe { bindings::Gecko_CounterStyle_GetAnonymous(gecko_value).as_ref() }.unwrap();
@ -113,7 +108,7 @@ impl CounterStyleOrNone {
.iter() .iter()
.map(|gecko_symbol| Symbol::String(gecko_symbol.to_string().into())) .map(|gecko_symbol| Symbol::String(gecko_symbol.to_string().into()))
.collect(); .collect();
Either::First(CounterStyleOrNone::Symbols(symbol_type, Symbols(symbols))) Either::First(CounterStyle::Symbols(symbol_type, Symbols(symbols)))
} }
} }
} }

View file

@ -706,44 +706,6 @@ impl<'le> GeckoElement<'le> {
!self.xbl_binding_with_content().is_none() !self.xbl_binding_with_content().is_none()
} }
/// This duplicates the logic in Gecko's virtual nsINode::GetBindingParent
/// function, which only has two implementations: one for XUL elements, and
/// one for other elements.
///
/// We just hard code in our knowledge of those two implementations here.
fn xbl_binding_parent(&self) -> Option<Self> {
if self.is_xul_element() {
// FIXME(heycam): Having trouble with bindgen on nsXULElement,
// where the binding parent is stored in a member variable
// rather than in slots. So just get it through FFI for now.
unsafe {
bindings::Gecko_GetBindingParent(self.0)
.as_ref()
.map(GeckoElement)
}
} else {
let binding_parent =
unsafe { self.non_xul_xbl_binding_parent().as_ref() }.map(GeckoElement);
debug_assert!(
binding_parent ==
unsafe {
bindings::Gecko_GetBindingParent(self.0)
.as_ref()
.map(GeckoElement)
}
);
binding_parent
}
}
#[inline]
fn non_xul_xbl_binding_parent(&self) -> *mut RawGeckoElement {
debug_assert!(!self.is_xul_element());
self.extended_slots()
.map_or(ptr::null_mut(), |slots| slots._base.mBindingParent.mRawPtr)
}
#[inline] #[inline]
fn namespace_id(&self) -> i32 { fn namespace_id(&self) -> i32 {
self.as_node().node_info().mInner.mNamespaceID self.as_node().node_info().mInner.mNamespaceID
@ -865,19 +827,9 @@ impl<'le> GeckoElement<'le> {
return self.flags() & (NODE_IS_NATIVE_ANONYMOUS_ROOT as u32) != 0; return self.flags() & (NODE_IS_NATIVE_ANONYMOUS_ROOT as u32) != 0;
} }
/// This logic is duplicated in Gecko's nsIContent::IsInAnonymousSubtree.
#[inline] #[inline]
fn is_in_anonymous_subtree(&self) -> bool { fn is_in_anonymous_subtree(&self) -> bool {
if self.is_in_native_anonymous_subtree() { unsafe { bindings::Gecko_IsInAnonymousSubtree(self.0) }
return true;
}
let binding_parent = match self.xbl_binding_parent() {
Some(p) => p,
None => return false,
};
binding_parent.shadow_root().is_none()
} }
/// Returns true if this node is the shadow root of an use-element shadow tree. /// Returns true if this node is the shadow root of an use-element shadow tree.

View file

@ -10,8 +10,10 @@ use crate::gecko_bindings::bindings;
use crate::parallel::STYLE_THREAD_STACK_SIZE_KB; use crate::parallel::STYLE_THREAD_STACK_SIZE_KB;
use crate::shared_lock::SharedRwLock; use crate::shared_lock::SharedRwLock;
use crate::thread_state; use crate::thread_state;
use parking_lot::{RwLock, RwLockReadGuard};
use rayon; use rayon;
use std::env; use std::env;
use std::sync::atomic::{AtomicUsize, Ordering};
/// Global style data /// Global style data
pub struct GlobalStyleData { pub struct GlobalStyleData {
@ -22,20 +24,28 @@ pub struct GlobalStyleData {
pub options: StyleSystemOptions, pub options: StyleSystemOptions,
} }
/// Global thread pool /// Global thread pool.
pub struct StyleThreadPool { pub struct StyleThreadPool {
/// How many threads parallel styling can use. /// How many threads parallel styling can use.
pub num_threads: usize, pub num_threads: usize,
/// The parallel styling thread pool. /// The parallel styling thread pool.
pub style_thread_pool: Option<rayon::ThreadPool>, ///
/// For leak-checking purposes, we want to terminate the thread-pool, which
/// waits for all the async jobs to complete. Thus the RwLock.
style_thread_pool: RwLock<Option<rayon::ThreadPool>>,
} }
fn thread_name(index: usize) -> String { fn thread_name(index: usize) -> String {
format!("StyleThread#{}", index) format!("StyleThread#{}", index)
} }
// A counter so that we can wait for shutdown of all threads. See
// StyleThreadPool::shutdown.
static ALIVE_WORKER_THREADS: AtomicUsize = AtomicUsize::new(0);
fn thread_startup(_index: usize) { fn thread_startup(_index: usize) {
ALIVE_WORKER_THREADS.fetch_add(1, Ordering::Relaxed);
thread_state::initialize_layout_worker_thread(); thread_state::initialize_layout_worker_thread();
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
unsafe { unsafe {
@ -55,6 +65,43 @@ fn thread_shutdown(_: usize) {
bindings::Gecko_UnregisterProfilerThread(); bindings::Gecko_UnregisterProfilerThread();
bindings::Gecko_SetJemallocThreadLocalArena(false); bindings::Gecko_SetJemallocThreadLocalArena(false);
} }
ALIVE_WORKER_THREADS.fetch_sub(1, Ordering::Relaxed);
}
impl StyleThreadPool {
/// Shuts down the thread pool, waiting for all work to complete.
pub fn shutdown() {
if ALIVE_WORKER_THREADS.load(Ordering::Relaxed) == 0 {
return;
}
{
// Drop the pool.
let _ = STYLE_THREAD_POOL.style_thread_pool.write().take();
}
// Spin until all our threads are done. This will usually be pretty
// fast, as on shutdown there should be basically no threads left
// running.
//
// This still _technically_ doesn't give us the guarantee of TLS
// destructors running on the worker threads. For that we'd need help
// from rayon to properly join the threads.
//
// See https://github.com/rayon-rs/rayon/issues/688
//
// So we instead intentionally leak TLS stuff (see BLOOM_KEY and co) for
// now until that's fixed.
while ALIVE_WORKER_THREADS.load(Ordering::Relaxed) != 0 {
std::thread::yield_now();
}
}
/// Returns a reference to the thread pool.
///
/// We only really want to give read-only access to the pool, except
/// for shutdown().
pub fn pool(&self) -> RwLockReadGuard<Option<rayon::ThreadPool>> {
self.style_thread_pool.read()
}
} }
lazy_static! { lazy_static! {
@ -113,10 +160,11 @@ lazy_static! {
}; };
StyleThreadPool { StyleThreadPool {
num_threads: num_threads, num_threads,
style_thread_pool: pool, style_thread_pool: RwLock::new(pool),
} }
}; };
/// Global style data /// Global style data
pub static ref GLOBAL_STYLE_DATA: GlobalStyleData = GlobalStyleData { pub static ref GLOBAL_STYLE_DATA: GlobalStyleData = GlobalStyleData {
shared_lock: SharedRwLock::new_leaked(), shared_lock: SharedRwLock::new_leaked(),

View file

@ -16,7 +16,7 @@ use crate::invalidation::element::invalidator::{Invalidation, InvalidationProces
use crate::invalidation::element::restyle_hints::RestyleHint; use crate::invalidation::element::restyle_hints::RestyleHint;
use crate::selector_map::SelectorMap; use crate::selector_map::SelectorMap;
use crate::selector_parser::Snapshot; use crate::selector_parser::Snapshot;
use crate::stylesheets::origin::{Origin, OriginSet}; use crate::stylesheets::origin::OriginSet;
use crate::{Atom, WeakAtom}; use crate::{Atom, WeakAtom};
use selectors::attr::CaseSensitivity; use selectors::attr::CaseSensitivity;
use selectors::matching::matches_selector; use selectors::matching::matches_selector;
@ -246,7 +246,7 @@ where
}; };
let document_origins = if !matches_document_author_rules { let document_origins = if !matches_document_author_rules {
Origin::UserAgent.into() OriginSet::ORIGIN_USER_AGENT | OriginSet::ORIGIN_USER
} else { } else {
OriginSet::all() OriginSet::all()
}; };

View file

@ -26,16 +26,48 @@ pub enum InlineBaseDirection {
// TODO: improve the readability of the WritingMode serialization, refer to the Debug:fmt() // TODO: improve the readability of the WritingMode serialization, refer to the Debug:fmt()
bitflags!( bitflags!(
#[cfg_attr(feature = "servo", derive(MallocSizeOf, Serialize))] #[cfg_attr(feature = "servo", derive(MallocSizeOf, Serialize))]
#[repr(C)]
pub struct WritingMode: u8 { pub struct WritingMode: u8 {
const RTL = 1 << 0; /// A vertical writing mode; writing-mode is vertical-rl,
const VERTICAL = 1 << 1; /// vertical-lr, sideways-lr, or sideways-rl.
const VERTICAL = 1 << 0;
/// The inline flow direction is reversed against the physical
/// direction (i.e. right-to-left or bottom-to-top); writing-mode is
/// sideways-lr or direction is rtl (but not both).
///
/// (This bit can be derived from the others, but we store it for
/// convenience.)
const INLINE_REVERSED = 1 << 1;
/// A vertical writing mode whose block progression direction is left-
/// to-right; writing-mode is vertical-lr or sideways-lr.
///
/// Never set without VERTICAL.
const VERTICAL_LR = 1 << 2; const VERTICAL_LR = 1 << 2;
/// For vertical writing modes only. When set, line-over/line-under /// The line-over/line-under sides are inverted with respect to the
/// sides are inverted from block-start/block-end. This flag is /// block-start/block-end edge; writing-mode is vertical-lr.
/// set when sideways-lr is used. ///
/// Never set without VERTICAL and VERTICAL_LR.
const LINE_INVERTED = 1 << 3; const LINE_INVERTED = 1 << 3;
const SIDEWAYS = 1 << 4; /// direction is rtl.
const UPRIGHT = 1 << 5; const RTL = 1 << 4;
/// Horizontal text within a vertical writing mode is displayed sideways
/// and runs top-to-bottom or bottom-to-top; set in these cases:
///
/// * writing-mode: vertical-rl; text-orientation: sideways;
/// * writing-mode: vertical-lr; text-orientation: sideways;
/// * writing-mode: sideways-rl;
/// * writing-mode: sideways-lr;
///
/// Never set without VERTICAL.
const SIDEWAYS = 1 << 5;
/// Horizontal text within a vertical writing mode is displayed with each
/// glyph upright; set in these cases:
///
/// * writing-mode: vertical-rl; text-orientation: upright;
/// * writing-mode: vertical-lr: text-orientation: upright;
///
/// Never set without VERTICAL.
const UPRIGHT = 1 << 6;
} }
); );
@ -47,33 +79,52 @@ impl WritingMode {
let mut flags = WritingMode::empty(); let mut flags = WritingMode::empty();
match inheritedbox_style.clone_direction() { let direction = inheritedbox_style.clone_direction();
let writing_mode = inheritedbox_style.clone_writing_mode();
match direction {
Direction::Ltr => {}, Direction::Ltr => {},
Direction::Rtl => { Direction::Rtl => {
flags.insert(WritingMode::RTL); flags.insert(WritingMode::RTL);
}, },
} }
match inheritedbox_style.clone_writing_mode() { match writing_mode {
SpecifiedWritingMode::HorizontalTb => {}, SpecifiedWritingMode::HorizontalTb => {
if direction == Direction::Rtl {
flags.insert(WritingMode::INLINE_REVERSED);
}
},
SpecifiedWritingMode::VerticalRl => { SpecifiedWritingMode::VerticalRl => {
flags.insert(WritingMode::VERTICAL); flags.insert(WritingMode::VERTICAL);
if direction == Direction::Rtl {
flags.insert(WritingMode::INLINE_REVERSED);
}
}, },
SpecifiedWritingMode::VerticalLr => { SpecifiedWritingMode::VerticalLr => {
flags.insert(WritingMode::VERTICAL); flags.insert(WritingMode::VERTICAL);
flags.insert(WritingMode::VERTICAL_LR); flags.insert(WritingMode::VERTICAL_LR);
flags.insert(WritingMode::LINE_INVERTED);
if direction == Direction::Rtl {
flags.insert(WritingMode::INLINE_REVERSED);
}
}, },
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
SpecifiedWritingMode::SidewaysRl => { SpecifiedWritingMode::SidewaysRl => {
flags.insert(WritingMode::VERTICAL); flags.insert(WritingMode::VERTICAL);
flags.insert(WritingMode::SIDEWAYS); flags.insert(WritingMode::SIDEWAYS);
if direction == Direction::Rtl {
flags.insert(WritingMode::INLINE_REVERSED);
}
}, },
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
SpecifiedWritingMode::SidewaysLr => { SpecifiedWritingMode::SidewaysLr => {
flags.insert(WritingMode::VERTICAL); flags.insert(WritingMode::VERTICAL);
flags.insert(WritingMode::VERTICAL_LR); flags.insert(WritingMode::VERTICAL_LR);
flags.insert(WritingMode::LINE_INVERTED);
flags.insert(WritingMode::SIDEWAYS); flags.insert(WritingMode::SIDEWAYS);
if direction == Direction::Ltr {
flags.insert(WritingMode::INLINE_REVERSED);
}
}, },
} }
@ -81,19 +132,21 @@ impl WritingMode {
{ {
use crate::properties::longhands::text_orientation::computed_value::T as TextOrientation; use crate::properties::longhands::text_orientation::computed_value::T as TextOrientation;
// If FLAG_SIDEWAYS is already set, this means writing-mode is // text-orientation only has an effect for vertical-rl and
// either sideways-rl or sideways-lr, and for both of these values, // vertical-lr values of writing-mode.
// text-orientation has no effect. match writing_mode {
if !flags.intersects(WritingMode::SIDEWAYS) { SpecifiedWritingMode::VerticalRl | SpecifiedWritingMode::VerticalLr => {
match inheritedbox_style.clone_text_orientation() { match inheritedbox_style.clone_text_orientation() {
TextOrientation::Mixed => {}, TextOrientation::Mixed => {},
TextOrientation::Upright => { TextOrientation::Upright => {
flags.insert(WritingMode::UPRIGHT); flags.insert(WritingMode::UPRIGHT);
}, },
TextOrientation::Sideways => { TextOrientation::Sideways => {
flags.insert(WritingMode::SIDEWAYS); flags.insert(WritingMode::SIDEWAYS);
}, },
} }
},
_ => {},
} }
} }
@ -115,7 +168,7 @@ impl WritingMode {
#[inline] #[inline]
pub fn is_inline_tb(&self) -> bool { pub fn is_inline_tb(&self) -> bool {
// https://drafts.csswg.org/css-writing-modes-3/#logical-to-physical // https://drafts.csswg.org/css-writing-modes-3/#logical-to-physical
self.intersects(WritingMode::RTL) == self.intersects(WritingMode::LINE_INVERTED) !self.intersects(WritingMode::INLINE_REVERSED)
} }
#[inline] #[inline]

View file

@ -44,8 +44,8 @@ pub enum Evaluator {
Integer(MediaFeatureEvaluator<u32>), Integer(MediaFeatureEvaluator<u32>),
Float(MediaFeatureEvaluator<f32>), Float(MediaFeatureEvaluator<f32>),
BoolInteger(MediaFeatureEvaluator<bool>), BoolInteger(MediaFeatureEvaluator<bool>),
/// An integer ratio, such as the one from device-pixel-ratio. /// A non-negative number ratio, such as the one from device-pixel-ratio.
IntRatio(MediaFeatureEvaluator<AspectRatio>), NumberRatio(MediaFeatureEvaluator<AspectRatio>),
/// A resolution. /// A resolution.
Resolution(MediaFeatureEvaluator<Resolution>), Resolution(MediaFeatureEvaluator<Resolution>),
/// A keyword value. /// A keyword value.

View file

@ -16,6 +16,8 @@ use crate::parser::{Parse, ParserContext};
use crate::servo::media_queries::MEDIA_FEATURES; use crate::servo::media_queries::MEDIA_FEATURES;
use crate::str::{starts_with_ignore_ascii_case, string_as_ascii_lowercase}; use crate::str::{starts_with_ignore_ascii_case, string_as_ascii_lowercase};
use crate::values::computed::{self, ToComputedValue}; use crate::values::computed::{self, ToComputedValue};
#[cfg(feature = "gecko")]
use crate::values::specified::NonNegativeNumber;
use crate::values::specified::{Integer, Length, Number, Resolution}; use crate::values::specified::{Integer, Length, Number, Resolution};
use crate::values::{serialize_atom_identifier, CSSFloat}; use crate::values::{serialize_atom_identifier, CSSFloat};
use crate::{Atom, Zero}; use crate::{Atom, Zero};
@ -25,8 +27,8 @@ use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
/// An aspect ratio, with a numerator and denominator. /// An aspect ratio, with a numerator and denominator.
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToShmem)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToShmem)]
pub struct AspectRatio(pub u32, pub u32); pub struct AspectRatio(pub CSSFloat, pub CSSFloat);
impl ToCss for AspectRatio { impl ToCss for AspectRatio {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
@ -41,9 +43,9 @@ impl ToCss for AspectRatio {
impl PartialOrd for AspectRatio { impl PartialOrd for AspectRatio {
fn partial_cmp(&self, other: &AspectRatio) -> Option<Ordering> { fn partial_cmp(&self, other: &AspectRatio) -> Option<Ordering> {
u64::partial_cmp( f64::partial_cmp(
&(self.0 as u64 * other.1 as u64), &(self.0 as f64 * other.1 as f64),
&(self.1 as u64 * other.0 as u64), &(self.1 as f64 * other.0 as f64),
) )
} }
} }
@ -429,9 +431,11 @@ impl MediaFeatureExpression {
eval(device, expect!(Integer).cloned(), self.range_or_operator) eval(device, expect!(Integer).cloned(), self.range_or_operator)
}, },
Evaluator::Float(eval) => eval(device, expect!(Float).cloned(), self.range_or_operator), Evaluator::Float(eval) => eval(device, expect!(Float).cloned(), self.range_or_operator),
Evaluator::IntRatio(eval) => { Evaluator::NumberRatio(eval) => eval(
eval(device, expect!(IntRatio).cloned(), self.range_or_operator) device,
}, expect!(NumberRatio).cloned(),
self.range_or_operator,
),
Evaluator::Resolution(eval) => { Evaluator::Resolution(eval) => {
let computed = expect!(Resolution).map(|specified| { let computed = expect!(Resolution).map(|specified| {
computed::Context::for_media_query_evaluation(device, quirks_mode, |context| { computed::Context::for_media_query_evaluation(device, quirks_mode, |context| {
@ -456,7 +460,7 @@ impl MediaFeatureExpression {
/// A value found or expected in a media expression. /// A value found or expected in a media expression.
/// ///
/// FIXME(emilio): How should calc() serialize in the Number / Integer / /// FIXME(emilio): How should calc() serialize in the Number / Integer /
/// BoolInteger / IntRatio case, as computed or as specified value? /// BoolInteger / NumberRatio case, as computed or as specified value?
/// ///
/// If the first, this would need to store the relevant values. /// If the first, this would need to store the relevant values.
/// ///
@ -471,9 +475,9 @@ pub enum MediaExpressionValue {
Float(CSSFloat), Float(CSSFloat),
/// A boolean value, specified as an integer (i.e., either 0 or 1). /// A boolean value, specified as an integer (i.e., either 0 or 1).
BoolInteger(bool), BoolInteger(bool),
/// Two integers separated by '/', with optional whitespace on either side /// A single non-negative number or two non-negative numbers separated by '/',
/// of the '/'. /// with optional whitespace on either side of the '/'.
IntRatio(AspectRatio), NumberRatio(AspectRatio),
/// A resolution. /// A resolution.
Resolution(Resolution), Resolution(Resolution),
/// An enumerated value, defined by the variant keyword table in the /// An enumerated value, defined by the variant keyword table in the
@ -493,7 +497,7 @@ impl MediaExpressionValue {
MediaExpressionValue::Integer(v) => v.to_css(dest), MediaExpressionValue::Integer(v) => v.to_css(dest),
MediaExpressionValue::Float(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(ratio) => ratio.to_css(dest), MediaExpressionValue::NumberRatio(ratio) => ratio.to_css(dest),
MediaExpressionValue::Resolution(ref r) => r.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) => match for_expr.feature().evaluator { MediaExpressionValue::Enumerated(value) => match for_expr.feature().evaluator {
@ -529,11 +533,26 @@ impl MediaExpressionValue {
let number = Number::parse(context, input)?; let number = Number::parse(context, input)?;
MediaExpressionValue::Float(number.get()) MediaExpressionValue::Float(number.get())
}, },
Evaluator::IntRatio(..) => { Evaluator::NumberRatio(..) => {
#[cfg(feature = "gecko")]
{
if static_prefs::pref!("layout.css.aspect-ratio-number.enabled") {
let a = NonNegativeNumber::parse(context, input)?.0.get();
let b = match input.try_parse(|input| input.expect_delim('/')) {
Ok(()) => NonNegativeNumber::parse(context, input)?.0.get(),
_ => 1.0,
};
return Ok(MediaExpressionValue::NumberRatio(AspectRatio(a, b)));
}
}
let a = Integer::parse_positive(context, input)?; let a = Integer::parse_positive(context, input)?;
input.expect_delim('/')?; input.expect_delim('/')?;
let b = Integer::parse_positive(context, input)?; let b = Integer::parse_positive(context, input)?;
MediaExpressionValue::IntRatio(AspectRatio(a.value() as u32, b.value() as u32)) MediaExpressionValue::NumberRatio(AspectRatio(
a.value() as CSSFloat,
b.value() as CSSFloat,
))
}, },
Evaluator::Resolution(..) => { Evaluator::Resolution(..) => {
MediaExpressionValue::Resolution(Resolution::parse(context, input)?) MediaExpressionValue::Resolution(Resolution::parse(context, input)?)

View file

@ -0,0 +1,128 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# The following properties are under development, so they are not in this list.
# FIXME: We should handle the developing properties properly by Bug 1577358:
# "backdrop-filter",
# "text-decoration-skip-ink",
# "column-span",
# "offset-distance",
# "offset-path",
# "offset-rotate"
COUNTED_UNKNOWN_PROPERTIES = [
"-webkit-font-smoothing",
"zoom",
"-webkit-tap-highlight-color",
"speak",
"text-size-adjust",
"-webkit-font-feature-settings",
"-webkit-user-drag",
"size",
"-webkit-clip-path",
"orphans",
"widows",
"-webkit-user-modify",
"-webkit-margin-before",
"-webkit-margin-after",
"tab-size",
"-webkit-margin-start",
"-webkit-column-break-inside",
"-webkit-padding-start",
"-webkit-margin-end",
"-webkit-box-reflect",
"-webkit-print-color-adjust",
"-webkit-mask-box-image",
"-webkit-line-break",
"-webkit-text-security",
"alignment-baseline",
"-webkit-writing-mode",
"baseline-shift",
"-webkit-hyphenate-character",
"page",
"text-underline-position",
"-webkit-highlight",
"background-repeat-x",
"-webkit-padding-end",
"background-repeat-y",
"-webkit-text-emphasis-color",
"-webkit-margin-top-collapse",
"-webkit-rtl-ordering",
"-webkit-padding-before",
"-webkit-text-decorations-in-effect",
"-webkit-border-vertical-spacing",
"-webkit-locale",
"-webkit-padding-after",
"-webkit-border-horizontal-spacing",
"color-rendering",
"-webkit-column-break-before",
"-webkit-transform-origin-x",
"-webkit-transform-origin-y",
"-webkit-text-emphasis-position",
"buffered-rendering",
"-webkit-text-orientation",
"-webkit-text-combine",
"-webkit-text-emphasis-style",
"-webkit-text-emphasis",
"d",
"-webkit-mask-box-image-width",
"-webkit-mask-box-image-source",
"-webkit-mask-box-image-outset",
"-webkit-mask-box-image-slice",
"-webkit-mask-box-image-repeat",
"-webkit-margin-after-collapse",
"-webkit-border-before-color",
"-webkit-border-before-width",
"-webkit-perspective-origin-x",
"-webkit-perspective-origin-y",
"-webkit-margin-before-collapse",
"-webkit-border-before-style",
"scroll-snap-stop",
"-webkit-margin-bottom-collapse",
"-webkit-ruby-position",
"-webkit-column-break-after",
"-webkit-margin-collapse",
"offset",
"-webkit-border-before",
"-webkit-border-end",
"-webkit-border-after",
"-webkit-border-start",
"-webkit-min-logical-width",
"-webkit-logical-height",
"-webkit-transform-origin-z",
"-webkit-font-size-delta",
"-webkit-logical-width",
"-webkit-max-logical-width",
"-webkit-min-logical-height",
"-webkit-max-logical-height",
"-webkit-border-end-color",
"-webkit-border-end-width",
"-webkit-border-start-color",
"-webkit-border-start-width",
"-webkit-border-after-color",
"-webkit-border-after-width",
"-webkit-border-end-style",
"-webkit-border-after-style",
"-webkit-border-start-style",
"-webkit-mask-repeat-x",
"-webkit-mask-repeat-y",
"user-zoom",
"min-zoom",
"-webkit-box-decoration-break",
"orientation",
"max-zoom",
"-webkit-app-region",
"-webkit-column-rule",
"-webkit-column-span",
"-webkit-column-gap",
"-webkit-shape-outside",
"-webkit-column-rule-width",
"-webkit-column-count",
"-webkit-opacity",
"-webkit-column-width",
"-webkit-shape-image-threshold",
"-webkit-column-rule-style",
"-webkit-columns",
"-webkit-column-rule-color",
"-webkit-shape-margin",
]

View file

@ -3,6 +3,7 @@
# file, You can obtain one at https://mozilla.org/MPL/2.0/. # file, You can obtain one at https://mozilla.org/MPL/2.0/.
import re import re
from counted_unknown_properties import COUNTED_UNKNOWN_PROPERTIES
PHYSICAL_SIDES = ["top", "right", "bottom", "left"] PHYSICAL_SIDES = ["top", "right", "bottom", "left"]
LOGICAL_SIDES = ["block-start", "block-end", "inline-start", "inline-end"] LOGICAL_SIDES = ["block-start", "block-end", "inline-start", "inline-end"]
@ -574,6 +575,7 @@ class PropertiesData(object):
self.shorthands = [] self.shorthands = []
self.shorthands_by_name = {} self.shorthands_by_name = {}
self.shorthand_aliases = [] self.shorthand_aliases = []
self.counted_unknown_properties = [CountedUnknownProperty(p) for p in COUNTED_UNKNOWN_PROPERTIES]
def new_style_struct(self, *args, **kwargs): def new_style_struct(self, *args, **kwargs):
style_struct = StyleStruct(*args, **kwargs) style_struct = StyleStruct(*args, **kwargs)
@ -794,3 +796,10 @@ class PropertyRestrictions:
+ PropertyRestrictions.shorthand(data, "background") + PropertyRestrictions.shorthand(data, "background")
+ PropertyRestrictions.shorthand(data, "outline") + PropertyRestrictions.shorthand(data, "outline")
+ PropertyRestrictions.shorthand(data, "font")) + PropertyRestrictions.shorthand(data, "font"))
class CountedUnknownProperty:
def __init__(self, name):
self.name = name
self.ident = to_rust_ident(name)
self.camel_case = to_camel_case(self.ident)

View file

@ -6,34 +6,36 @@
#![deny(missing_docs)] #![deny(missing_docs)]
use super::*;
use crate::context::QuirksMode; use crate::context::QuirksMode;
use cssparser::{DeclarationListParser, parse_important, ParserInput, CowRcStr}; use crate::custom_properties::{CssEnvironment, CustomPropertiesBuilder};
use cssparser::{Parser, AtRuleParser, DeclarationParser, Delimiter, ParseErrorKind}; use crate::error_reporting::{ContextualParseError, ParseErrorReporter};
use crate::custom_properties::{CustomPropertiesBuilder, CssEnvironment};
use crate::error_reporting::{ParseErrorReporter, ContextualParseError};
use itertools::Itertools;
use crate::parser::ParserContext; use crate::parser::ParserContext;
use crate::properties::animated_properties::{AnimationValue, AnimationValueMap}; use crate::properties::animated_properties::{AnimationValue, AnimationValueMap};
use crate::selector_parser::SelectorImpl;
use crate::shared_lock::Locked; use crate::shared_lock::Locked;
use crate::str::{CssString, CssStringBorrow, CssStringWriter};
use crate::stylesheets::{CssRuleType, Origin, UrlExtraData};
use crate::values::computed::Context;
use cssparser::{parse_important, CowRcStr, DeclarationListParser, ParserInput};
use cssparser::{AtRuleParser, DeclarationParser, Delimiter, ParseErrorKind, Parser};
use itertools::Itertools;
use selectors::SelectorList;
use smallbitvec::{self, SmallBitVec}; use smallbitvec::{self, SmallBitVec};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use std::iter::{DoubleEndedIterator, Zip}; use std::iter::{DoubleEndedIterator, Zip};
use std::slice::Iter; use std::slice::Iter;
use crate::str::{CssString, CssStringBorrow, CssStringWriter};
use style_traits::{CssWriter, ParseError, ParsingMode, StyleParseErrorKind, ToCss}; use style_traits::{CssWriter, ParseError, ParsingMode, StyleParseErrorKind, ToCss};
use crate::stylesheets::{CssRuleType, Origin, UrlExtraData};
use super::*;
use crate::values::computed::Context;
use crate::selector_parser::SelectorImpl;
use selectors::SelectorList;
/// The animation rules. /// The animation rules.
/// ///
/// The first one is for Animation cascade level, and the second one is for /// The first one is for Animation cascade level, and the second one is for
/// Transition cascade level. /// Transition cascade level.
pub struct AnimationRules(pub Option<Arc<Locked<PropertyDeclarationBlock>>>, pub struct AnimationRules(
pub Option<Arc<Locked<PropertyDeclarationBlock>>>); pub Option<Arc<Locked<PropertyDeclarationBlock>>>,
pub Option<Arc<Locked<PropertyDeclarationBlock>>>,
);
impl AnimationRules { impl AnimationRules {
/// Returns whether these animation rules represents an actual rule or not. /// Returns whether these animation rules represents an actual rule or not.
@ -122,8 +124,16 @@ impl<'a> Iterator for DeclarationImportanceIterator<'a> {
#[inline] #[inline]
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|(decl, important)| self.iter.next().map(|(decl, important)| {
(decl, if important { Importance::Important } else { Importance::Normal })) (
decl,
if important {
Importance::Important
} else {
Importance::Normal
},
)
})
} }
#[inline] #[inline]
@ -135,13 +145,21 @@ impl<'a> Iterator for DeclarationImportanceIterator<'a> {
impl<'a> DoubleEndedIterator for DeclarationImportanceIterator<'a> { impl<'a> DoubleEndedIterator for DeclarationImportanceIterator<'a> {
#[inline(always)] #[inline(always)]
fn next_back(&mut self) -> Option<Self::Item> { fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back().map(|(decl, important)| self.iter.next_back().map(|(decl, important)| {
(decl, if important { Importance::Important } else { Importance::Normal })) (
decl,
if important {
Importance::Important
} else {
Importance::Normal
},
)
})
} }
} }
/// Iterator for AnimationValue to be generated from PropertyDeclarationBlock. /// Iterator for AnimationValue to be generated from PropertyDeclarationBlock.
pub struct AnimationValueIterator<'a, 'cx, 'cx_a:'cx> { pub struct AnimationValueIterator<'a, 'cx, 'cx_a: 'cx> {
iter: DeclarationImportanceIterator<'a>, iter: DeclarationImportanceIterator<'a>,
context: &'cx mut Context<'cx_a>, context: &'cx mut Context<'cx_a>,
default_values: &'a ComputedValues, default_values: &'a ComputedValues,
@ -149,7 +167,7 @@ pub struct AnimationValueIterator<'a, 'cx, 'cx_a:'cx> {
extra_custom_properties: Option<&'a Arc<crate::custom_properties::CustomPropertiesMap>>, extra_custom_properties: Option<&'a Arc<crate::custom_properties::CustomPropertiesMap>>,
} }
impl<'a, 'cx, 'cx_a:'cx> AnimationValueIterator<'a, 'cx, 'cx_a> { impl<'a, 'cx, 'cx_a: 'cx> AnimationValueIterator<'a, 'cx, 'cx_a> {
fn new( fn new(
declarations: &'a PropertyDeclarationBlock, declarations: &'a PropertyDeclarationBlock,
context: &'cx mut Context<'cx_a>, context: &'cx mut Context<'cx_a>,
@ -165,7 +183,7 @@ impl<'a, 'cx, 'cx_a:'cx> AnimationValueIterator<'a, 'cx, 'cx_a> {
} }
} }
impl<'a, 'cx, 'cx_a:'cx> Iterator for AnimationValueIterator<'a, 'cx, 'cx_a> { impl<'a, 'cx, 'cx_a: 'cx> Iterator for AnimationValueIterator<'a, 'cx, 'cx_a> {
type Item = AnimationValue; type Item = AnimationValue;
#[inline] #[inline]
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
@ -256,7 +274,7 @@ impl PropertyDeclarationBlock {
/// Return an iterator of (AnimatableLonghand, AnimationValue). /// Return an iterator of (AnimatableLonghand, AnimationValue).
#[inline] #[inline]
pub fn to_animation_value_iter<'a, 'cx, 'cx_a:'cx>( pub fn to_animation_value_iter<'a, 'cx, 'cx_a: 'cx>(
&'a self, &'a self,
context: &'cx mut Context<'cx_a>, context: &'cx mut Context<'cx_a>,
default_values: &'a ComputedValues, default_values: &'a ComputedValues,
@ -300,7 +318,10 @@ impl PropertyDeclarationBlock {
/// NOTE: This is linear time in the case of custom properties or in the /// NOTE: This is linear time in the case of custom properties or in the
/// case the longhand is actually in the declaration block. /// case the longhand is actually in the declaration block.
#[inline] #[inline]
pub fn get(&self, property: PropertyDeclarationId) -> Option<(&PropertyDeclaration, Importance)> { pub fn get(
&self,
property: PropertyDeclarationId,
) -> Option<(&PropertyDeclaration, Importance)> {
if let PropertyDeclarationId::Longhand(id) = property { if let PropertyDeclarationId::Longhand(id) = property {
if !self.contains(id) { if !self.contains(id) {
return None; return None;
@ -350,9 +371,7 @@ impl PropertyDeclarationBlock {
// We don't print !important when serializing individual properties, // We don't print !important when serializing individual properties,
// so we treat this as a normal-importance property // so we treat this as a normal-importance property
match shorthand.get_shorthand_appendable_value(list.iter().cloned()) { match shorthand.get_shorthand_appendable_value(list.iter().cloned()) {
Some(appendable_value) => { Some(appendable_value) => append_declaration_value(dest, appendable_value),
append_declaration_value(dest, appendable_value)
}
None => return Ok(()), None => return Ok(()),
} }
} }
@ -360,7 +379,11 @@ impl PropertyDeclarationBlock {
/// Find the value of the given property in this block and serialize it /// Find the value of the given property in this block and serialize it
/// ///
/// <https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-getpropertyvalue> /// <https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-getpropertyvalue>
pub fn property_value_to_css(&self, property: &PropertyId, dest: &mut CssStringWriter) -> fmt::Result { pub fn property_value_to_css(
&self,
property: &PropertyId,
dest: &mut CssStringWriter,
) -> fmt::Result {
// Step 1.1: done when parsing a string to PropertyId // Step 1.1: done when parsing a string to PropertyId
// Step 1.2 // Step 1.2
@ -394,11 +417,12 @@ impl PropertyDeclarationBlock {
} else { } else {
Importance::Normal Importance::Normal
} }
} },
Err(longhand_or_custom) => { Err(longhand_or_custom) => {
// Step 3 // Step 3
self.get(longhand_or_custom).map_or(Importance::Normal, |(_, importance)| importance) self.get(longhand_or_custom)
} .map_or(Importance::Normal, |(_, importance)| importance)
},
} }
} }
@ -407,7 +431,9 @@ impl PropertyDeclarationBlock {
/// and it doesn't exist in the block, and returns false otherwise. /// and it doesn't exist in the block, and returns false otherwise.
#[inline] #[inline]
fn is_definitely_new(&self, decl: &PropertyDeclaration) -> bool { fn is_definitely_new(&self, decl: &PropertyDeclaration) -> bool {
decl.id().as_longhand().map_or(false, |id| !self.longhands.contains(id)) decl.id()
.as_longhand()
.map_or(false, |id| !self.longhands.contains(id))
} }
/// Adds or overrides the declaration for a given property in this block. /// Adds or overrides the declaration for a given property in this block.
@ -421,11 +447,11 @@ impl PropertyDeclarationBlock {
) -> bool { ) -> bool {
let all_shorthand_len = match drain.all_shorthand { let all_shorthand_len = match drain.all_shorthand {
AllShorthand::NotSet => 0, AllShorthand::NotSet => 0,
AllShorthand::CSSWideKeyword(_) | AllShorthand::CSSWideKeyword(_) | AllShorthand::WithVariables(_) => {
AllShorthand::WithVariables(_) => shorthands::ALL_SHORTHAND_MAX_LEN, shorthands::ALL_SHORTHAND_MAX_LEN
},
}; };
let push_calls_count = let push_calls_count = drain.declarations.len() + all_shorthand_len;
drain.declarations.len() + all_shorthand_len;
// With deduplication the actual length increase may be less than this. // With deduplication the actual length increase may be less than this.
self.declarations.reserve(push_calls_count); self.declarations.reserve(push_calls_count);
@ -434,9 +460,12 @@ impl PropertyDeclarationBlock {
for decl in &mut drain.declarations { for decl in &mut drain.declarations {
changed |= self.push(decl, importance); changed |= self.push(decl, importance);
} }
drain.all_shorthand.declarations().fold(changed, |changed, decl| { drain
changed | self.push(decl, importance) .all_shorthand
}) .declarations()
.fold(changed, |changed, decl| {
changed | self.push(decl, importance)
})
} }
/// Adds or overrides the declaration for a given property in this block. /// Adds or overrides the declaration for a given property in this block.
@ -444,11 +473,7 @@ impl PropertyDeclarationBlock {
/// Returns whether the declaration has changed. /// Returns whether the declaration has changed.
/// ///
/// This is only used for parsing and internal use. /// This is only used for parsing and internal use.
pub fn push( pub fn push(&mut self, declaration: PropertyDeclaration, importance: Importance) -> bool {
&mut self,
declaration: PropertyDeclaration,
importance: Importance,
) -> bool {
if !self.is_definitely_new(&declaration) { if !self.is_definitely_new(&declaration) {
let mut index_to_remove = None; let mut index_to_remove = None;
for (i, slot) in self.declarations.iter_mut().enumerate() { for (i, slot) in self.declarations.iter_mut().enumerate() {
@ -498,78 +523,92 @@ impl PropertyDeclarationBlock {
// Check whether we are updating for an all shorthand change. // Check whether we are updating for an all shorthand change.
if !matches!(source_declarations.all_shorthand, AllShorthand::NotSet) { if !matches!(source_declarations.all_shorthand, AllShorthand::NotSet) {
debug_assert!(source_declarations.declarations.is_empty()); debug_assert!(source_declarations.declarations.is_empty());
return source_declarations.all_shorthand.declarations().any(|decl| { return source_declarations
self.is_definitely_new(&decl) || .all_shorthand
self.declarations.iter().enumerate() .declarations()
.find(|&(_, ref d)| d.id() == decl.id()) .any(|decl| {
.map_or(true, |(i, d)| { self.is_definitely_new(&decl) ||
let important = self.declarations_importance[i]; self.declarations
*d != decl || important != importance.important() .iter()
}) .enumerate()
}); .find(|&(_, ref d)| d.id() == decl.id())
.map_or(true, |(i, d)| {
let important = self.declarations_importance[i];
*d != decl || important != importance.important()
})
});
} }
// Fill `updates` with update information. // Fill `updates` with update information.
let mut any_update = false; let mut any_update = false;
let new_count = &mut updates.new_count; let new_count = &mut updates.new_count;
let any_removal = &mut updates.any_removal; let any_removal = &mut updates.any_removal;
let updates = &mut updates.updates; let updates = &mut updates.updates;
updates.extend(source_declarations.declarations.iter().map(|declaration| { updates.extend(
if self.is_definitely_new(declaration) { source_declarations
return DeclarationUpdate::Append; .declarations
} .iter()
let longhand_id = declaration.id().as_longhand(); .map(|declaration| {
if let Some(longhand_id) = longhand_id { if self.is_definitely_new(declaration) {
if let Some(logical_group) = longhand_id.logical_group() { return DeclarationUpdate::Append;
let mut needs_append = false; }
for (pos, decl) in self.declarations.iter().enumerate().rev() { let longhand_id = declaration.id().as_longhand();
let id = match decl.id().as_longhand() { if let Some(longhand_id) = longhand_id {
Some(id) => id, if let Some(logical_group) = longhand_id.logical_group() {
None => continue, let mut needs_append = false;
}; for (pos, decl) in self.declarations.iter().enumerate().rev() {
if id == longhand_id { let id = match decl.id().as_longhand() {
if needs_append { Some(id) => id,
return DeclarationUpdate::AppendAndRemove { pos }; None => continue,
};
if id == longhand_id {
if needs_append {
return DeclarationUpdate::AppendAndRemove { pos };
}
let important = self.declarations_importance[pos];
if decl == declaration && important == importance.important() {
return DeclarationUpdate::None;
}
return DeclarationUpdate::UpdateInPlace { pos };
}
if !needs_append &&
id.logical_group() == Some(logical_group) &&
id.is_logical() != longhand_id.is_logical()
{
needs_append = true;
}
} }
unreachable!("Longhand should be found in loop above");
}
}
self.declarations
.iter()
.enumerate()
.find(|&(_, ref decl)| decl.id() == declaration.id())
.map_or(DeclarationUpdate::Append, |(pos, decl)| {
let important = self.declarations_importance[pos]; let important = self.declarations_importance[pos];
if decl == declaration && important == importance.important() { if decl == declaration && important == importance.important() {
return DeclarationUpdate::None; DeclarationUpdate::None
} else {
DeclarationUpdate::UpdateInPlace { pos }
} }
return DeclarationUpdate::UpdateInPlace { pos }; })
}
if !needs_append &&
id.logical_group() == Some(logical_group) &&
id.is_logical() != longhand_id.is_logical() {
needs_append = true;
}
}
unreachable!("Longhand should be found in loop above");
}
}
self.declarations.iter().enumerate()
.find(|&(_, ref decl)| decl.id() == declaration.id())
.map_or(DeclarationUpdate::Append, |(pos, decl)| {
let important = self.declarations_importance[pos];
if decl == declaration && important == importance.important() {
DeclarationUpdate::None
} else {
DeclarationUpdate::UpdateInPlace { pos }
}
}) })
}).inspect(|update| { .inspect(|update| {
if matches!(update, DeclarationUpdate::None) { if matches!(update, DeclarationUpdate::None) {
return; return;
} }
any_update = true; any_update = true;
match update { match update {
DeclarationUpdate::Append => { DeclarationUpdate::Append => {
*new_count += 1; *new_count += 1;
} },
DeclarationUpdate::AppendAndRemove { .. } => { DeclarationUpdate::AppendAndRemove { .. } => {
*any_removal = true; *any_removal = true;
} },
_ => {} _ => {},
} }
})); }),
);
any_update any_update
} }
@ -590,8 +629,12 @@ impl PropertyDeclarationBlock {
self.declarations_importance.push(important); self.declarations_importance.push(important);
self.longhands.insert(longhand_id); self.longhands.insert(longhand_id);
} else { } else {
let (idx, slot) = self.declarations.iter_mut() let (idx, slot) = self
.enumerate().find(|&(_, ref d)| d.id() == decl.id()).unwrap(); .declarations
.iter_mut()
.enumerate()
.find(|&(_, ref d)| d.id() == decl.id())
.unwrap();
*slot = decl; *slot = decl;
self.declarations_importance.set(idx, important); self.declarations_importance.set(idx, important);
} }
@ -607,19 +650,24 @@ impl PropertyDeclarationBlock {
pos: usize, pos: usize,
remove: bool, remove: bool,
} }
let mut updates_and_removals: SubpropertiesVec<UpdateOrRemoval> = let mut updates_and_removals: SubpropertiesVec<UpdateOrRemoval> = updates
updates.updates.iter_mut().filter_map(|item| { .updates
.iter_mut()
.filter_map(|item| {
let (pos, remove) = match *item { let (pos, remove) = match *item {
DeclarationUpdate::UpdateInPlace { pos } => (pos, false), DeclarationUpdate::UpdateInPlace { pos } => (pos, false),
DeclarationUpdate::AppendAndRemove { pos } => (pos, true), DeclarationUpdate::AppendAndRemove { pos } => (pos, true),
_ => return None, _ => return None,
}; };
Some(UpdateOrRemoval { item, pos, remove }) Some(UpdateOrRemoval { item, pos, remove })
}).collect(); })
.collect();
// Execute removals. It's important to do it in reverse index order, // Execute removals. It's important to do it in reverse index order,
// so that removing doesn't invalidate following positions. // so that removing doesn't invalidate following positions.
updates_and_removals.sort_unstable_by_key(|update| update.pos); updates_and_removals.sort_unstable_by_key(|update| update.pos);
updates_and_removals.iter().rev() updates_and_removals
.iter()
.rev()
.filter(|update| update.remove) .filter(|update| update.remove)
.for_each(|update| { .for_each(|update| {
self.declarations.remove(update.pos); self.declarations.remove(update.pos);
@ -637,7 +685,7 @@ impl PropertyDeclarationBlock {
DeclarationUpdate::UpdateInPlace { pos: update.pos } DeclarationUpdate::UpdateInPlace { pos: update.pos }
); );
*update.item = DeclarationUpdate::UpdateInPlace { *update.item = DeclarationUpdate::UpdateInPlace {
pos: update.pos - removed_count pos: update.pos - removed_count,
}; };
} }
} }
@ -645,18 +693,17 @@ impl PropertyDeclarationBlock {
for (decl, update) in drain.declarations.zip_eq(updates.updates.iter()) { for (decl, update) in drain.declarations.zip_eq(updates.updates.iter()) {
match *update { match *update {
DeclarationUpdate::None => {}, DeclarationUpdate::None => {},
DeclarationUpdate::Append | DeclarationUpdate::Append | DeclarationUpdate::AppendAndRemove { .. } => {
DeclarationUpdate::AppendAndRemove { .. } => {
if let Some(id) = decl.id().as_longhand() { if let Some(id) = decl.id().as_longhand() {
self.longhands.insert(id); self.longhands.insert(id);
} }
self.declarations.push(decl); self.declarations.push(decl);
self.declarations_importance.push(important); self.declarations_importance.push(important);
} },
DeclarationUpdate::UpdateInPlace { pos } => { DeclarationUpdate::UpdateInPlace { pos } => {
self.declarations[pos] = decl; self.declarations[pos] = decl;
self.declarations_importance.set(pos, important); self.declarations_importance.set(pos, important);
} },
} }
} }
updates.updates.clear(); updates.updates.clear();
@ -665,19 +712,16 @@ impl PropertyDeclarationBlock {
/// Returns the first declaration that would be removed by removing /// Returns the first declaration that would be removed by removing
/// `property`. /// `property`.
#[inline] #[inline]
pub fn first_declaration_to_remove( pub fn first_declaration_to_remove(&self, property: &PropertyId) -> Option<usize> {
&self,
property: &PropertyId,
) -> Option<usize> {
if let Some(id) = property.longhand_id() { if let Some(id) = property.longhand_id() {
if !self.longhands.contains(id) { if !self.longhands.contains(id) {
return None; return None;
} }
} }
self.declarations.iter().position(|declaration| { self.declarations
declaration.id().is_or_is_longhand_of(property) .iter()
}) .position(|declaration| declaration.id().is_or_is_longhand_of(property))
} }
/// Removes a given declaration at a given index. /// Removes a given declaration at a given index.
@ -698,16 +742,14 @@ impl PropertyDeclarationBlock {
/// `first_declaration` needs to be the result of /// `first_declaration` needs to be the result of
/// `first_declaration_to_remove`. /// `first_declaration_to_remove`.
#[inline] #[inline]
pub fn remove_property( pub fn remove_property(&mut self, property: &PropertyId, first_declaration: usize) {
&mut self,
property: &PropertyId,
first_declaration: usize,
) {
debug_assert_eq!( debug_assert_eq!(
Some(first_declaration), Some(first_declaration),
self.first_declaration_to_remove(property) self.first_declaration_to_remove(property)
); );
debug_assert!(self.declarations[first_declaration].id().is_or_is_longhand_of(property)); debug_assert!(self.declarations[first_declaration]
.id()
.is_or_is_longhand_of(property));
self.remove_declaration_at(first_declaration); self.remove_declaration_at(first_declaration);
@ -776,16 +818,16 @@ impl PropertyDeclarationBlock {
// getKeyframes() implementation for CSS animations, if // getKeyframes() implementation for CSS animations, if
// |computed_values| is supplied, we use it to expand such variable // |computed_values| is supplied, we use it to expand such variable
// declarations. This will be fixed properly in Gecko bug 1391537. // declarations. This will be fixed properly in Gecko bug 1391537.
( (&PropertyDeclaration::WithVariables(ref declaration), Some(ref _computed_values)) => {
&PropertyDeclaration::WithVariables(ref declaration), declaration
Some(ref _computed_values), .value
) => { .substitute_variables(
declaration.value.substitute_variables( declaration.id,
declaration.id, custom_properties.as_ref(),
custom_properties.as_ref(), QuirksMode::NoQuirks,
QuirksMode::NoQuirks, &env,
&env, )
).to_css(dest) .to_css(dest)
}, },
(ref d, _) => d.to_css(dest), (ref d, _) => d.to_css(dest),
} }
@ -798,8 +840,8 @@ impl PropertyDeclarationBlock {
let mut longhands = LonghandIdSet::new(); let mut longhands = LonghandIdSet::new();
for (property, animation_value) in animation_value_map.iter() { for (property, animation_value) in animation_value_map.iter() {
longhands.insert(*property); longhands.insert(*property);
declarations.push(animation_value.uncompute()); declarations.push(animation_value.uncompute());
} }
PropertyDeclarationBlock { PropertyDeclarationBlock {
@ -814,13 +856,12 @@ impl PropertyDeclarationBlock {
pub fn has_css_wide_keyword(&self, property: &PropertyId) -> bool { pub fn has_css_wide_keyword(&self, property: &PropertyId) -> bool {
if let Some(id) = property.longhand_id() { if let Some(id) = property.longhand_id() {
if !self.longhands.contains(id) { if !self.longhands.contains(id) {
return false return false;
} }
} }
self.declarations.iter().any(|decl| self.declarations.iter().any(|decl| {
decl.id().is_or_is_longhand_of(property) && decl.id().is_or_is_longhand_of(property) && decl.get_css_wide_keyword().is_some()
decl.get_css_wide_keyword().is_some() })
)
} }
/// Returns a custom properties map which is the result of cascading custom /// Returns a custom properties map which is the result of cascading custom
@ -844,10 +885,7 @@ impl PropertyDeclarationBlock {
inherited_custom_properties: Option<&Arc<crate::custom_properties::CustomPropertiesMap>>, inherited_custom_properties: Option<&Arc<crate::custom_properties::CustomPropertiesMap>>,
environment: &CssEnvironment, environment: &CssEnvironment,
) -> Option<Arc<crate::custom_properties::CustomPropertiesMap>> { ) -> Option<Arc<crate::custom_properties::CustomPropertiesMap>> {
let mut builder = CustomPropertiesBuilder::new( let mut builder = CustomPropertiesBuilder::new(inherited_custom_properties, environment);
inherited_custom_properties,
environment,
);
for declaration in self.normal_declaration_iter() { for declaration in self.normal_declaration_iter() {
if let PropertyDeclaration::Custom(ref declaration) = *declaration { if let PropertyDeclaration::Custom(ref declaration) = *declaration {
@ -899,7 +937,7 @@ impl PropertyDeclarationBlock {
&mut is_first_serialization, &mut is_first_serialization,
)?; )?;
continue; continue;
} },
}; };
// Step 3.2 // Step 3.2
@ -928,22 +966,19 @@ impl PropertyDeclarationBlock {
let mut important_count = 0; let mut important_count = 0;
let mut found_system = None; let mut found_system = None;
let is_system_font = let is_system_font = shorthand == ShorthandId::Font &&
shorthand == ShorthandId::Font && self.declarations.iter().any(|l| match l.id() {
self.declarations.iter().any(|l| { PropertyDeclarationId::Longhand(id) => {
match l.id() { if already_serialized.contains(id.into()) {
PropertyDeclarationId::Longhand(id) => { return false;
if already_serialized.contains(id.into()) { }
return false;
}
l.get_system().is_some() l.get_system().is_some()
} },
PropertyDeclarationId::Custom(..) => { PropertyDeclarationId::Custom(..) => {
debug_assert!(l.get_system().is_none()); debug_assert!(l.get_system().is_none());
false false
} },
}
}); });
if is_system_font { if is_system_font {
@ -951,7 +986,7 @@ impl PropertyDeclarationBlock {
if longhand.get_system().is_some() || longhand.is_default_line_height() { if longhand.get_system().is_some() || longhand.is_default_line_height() {
current_longhands.push(longhand); current_longhands.push(longhand);
if found_system.is_none() { if found_system.is_none() {
found_system = longhand.get_system(); found_system = longhand.get_system();
} }
if importance.important() { if importance.important() {
important_count += 1; important_count += 1;
@ -967,11 +1002,11 @@ impl PropertyDeclarationBlock {
if importance.important() { if importance.important() {
important_count += 1; important_count += 1;
} }
} },
None => { None => {
contains_all_longhands = false; contains_all_longhands = false;
break; break;
} },
} }
} }
@ -994,23 +1029,30 @@ impl PropertyDeclarationBlock {
// Substep 5 - Let value be the result of invoking serialize // Substep 5 - Let value be the result of invoking serialize
// a CSS value of current longhands. // a CSS value of current longhands.
let appendable_value = let appendable_value = match shorthand
match shorthand.get_shorthand_appendable_value(current_longhands.iter().cloned()) { .get_shorthand_appendable_value(current_longhands.iter().cloned())
None => continue, {
Some(appendable_value) => appendable_value, None => continue,
}; Some(appendable_value) => appendable_value,
};
// We avoid re-serializing if we're already an // We avoid re-serializing if we're already an
// AppendableValue::Css. // AppendableValue::Css.
let mut v = CssString::new(); let mut v = CssString::new();
let value = match (appendable_value, found_system) { let value = match (appendable_value, found_system) {
(AppendableValue::Css { css, with_variables }, _) => { (
AppendableValue::Css {
css,
with_variables,
},
_,
) => {
debug_assert!(!css.is_empty()); debug_assert!(!css.is_empty());
AppendableValue::Css { AppendableValue::Css {
css: css, css: css,
with_variables: with_variables, with_variables: with_variables,
} }
} },
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
(_, Some(sys)) => { (_, Some(sys)) => {
sys.to_css(&mut CssWriter::new(&mut v))?; sys.to_css(&mut CssWriter::new(&mut v))?;
@ -1018,7 +1060,7 @@ impl PropertyDeclarationBlock {
css: CssStringBorrow::from(&v), css: CssStringBorrow::from(&v),
with_variables: false, with_variables: false,
} }
} },
(other, _) => { (other, _) => {
append_declaration_value(&mut v, other)?; append_declaration_value(&mut v, other)?;
@ -1031,7 +1073,7 @@ impl PropertyDeclarationBlock {
css: CssStringBorrow::from(&v), css: CssStringBorrow::from(&v),
with_variables: false, with_variables: false,
} }
} },
}; };
// Substeps 7 and 8 // Substeps 7 and 8
@ -1091,7 +1133,8 @@ impl PropertyDeclarationBlock {
/// A convenient enum to represent different kinds of stuff that can represent a /// A convenient enum to represent different kinds of stuff that can represent a
/// _value_ in the serialization of a property declaration. /// _value_ in the serialization of a property declaration.
pub enum AppendableValue<'a, I> pub enum AppendableValue<'a, I>
where I: Iterator<Item=&'a PropertyDeclaration>, where
I: Iterator<Item = &'a PropertyDeclaration>,
{ {
/// A given declaration, of which we'll serialize just the value. /// A given declaration, of which we'll serialize just the value.
Declaration(&'a PropertyDeclaration), Declaration(&'a PropertyDeclaration),
@ -1107,14 +1150,11 @@ pub enum AppendableValue<'a, I>
css: CssStringBorrow<'a>, css: CssStringBorrow<'a>,
/// Whether the original serialization contained variables or not. /// Whether the original serialization contained variables or not.
with_variables: bool, with_variables: bool,
} },
} }
/// Potentially appends whitespace after the first (property: value;) pair. /// Potentially appends whitespace after the first (property: value;) pair.
fn handle_first_serialization<W>( fn handle_first_serialization<W>(dest: &mut W, is_first_serialization: &mut bool) -> fmt::Result
dest: &mut W,
is_first_serialization: &mut bool,
) -> fmt::Result
where where
W: Write, W: Write,
{ {
@ -1132,18 +1172,14 @@ pub fn append_declaration_value<'a, I>(
appendable_value: AppendableValue<'a, I>, appendable_value: AppendableValue<'a, I>,
) -> fmt::Result ) -> fmt::Result
where where
I: Iterator<Item=&'a PropertyDeclaration>, I: Iterator<Item = &'a PropertyDeclaration>,
{ {
match appendable_value { match appendable_value {
AppendableValue::Css { css, .. } => { AppendableValue::Css { css, .. } => css.append_to(dest),
css.append_to(dest) AppendableValue::Declaration(decl) => decl.to_css(dest),
},
AppendableValue::Declaration(decl) => {
decl.to_css(dest)
},
AppendableValue::DeclarationsForShorthand(shorthand, decls) => { AppendableValue::DeclarationsForShorthand(shorthand, decls) => {
shorthand.longhands_to_css(decls, &mut CssWriter::new(dest)) shorthand.longhands_to_css(decls, &mut CssWriter::new(dest))
} },
} }
} }
@ -1153,10 +1189,10 @@ pub fn append_serialization<'a, I, N>(
property_name: &N, property_name: &N,
appendable_value: AppendableValue<'a, I>, appendable_value: AppendableValue<'a, I>,
importance: Importance, importance: Importance,
is_first_serialization: &mut bool is_first_serialization: &mut bool,
) -> fmt::Result ) -> fmt::Result
where where
I: Iterator<Item=&'a PropertyDeclaration>, I: Iterator<Item = &'a PropertyDeclaration>,
N: ToCss, N: ToCss,
{ {
handle_first_serialization(dest, is_first_serialization)?; handle_first_serialization(dest, is_first_serialization)?;
@ -1176,7 +1212,7 @@ where
if !with_variables { if !with_variables {
dest.write_str(" ")? dest.write_str(" ")?
} }
} },
// Currently append_serialization is only called with a Css or // Currently append_serialization is only called with a Css or
// a Declaration AppendableValue. // a Declaration AppendableValue.
AppendableValue::DeclarationsForShorthand(..) => unreachable!(), AppendableValue::DeclarationsForShorthand(..) => unreachable!(),
@ -1228,7 +1264,7 @@ pub fn parse_one_declaration_into(
url_data: &UrlExtraData, url_data: &UrlExtraData,
error_reporter: Option<&dyn ParseErrorReporter>, error_reporter: Option<&dyn ParseErrorReporter>,
parsing_mode: ParsingMode, parsing_mode: ParsingMode,
quirks_mode: QuirksMode quirks_mode: QuirksMode,
) -> Result<(), ()> { ) -> Result<(), ()> {
let context = ParserContext::new( let context = ParserContext::new(
Origin::Author, Origin::Author,
@ -1249,20 +1285,22 @@ pub fn parse_one_declaration_into(
let mut input = ParserInput::new(input); let mut input = ParserInput::new(input);
let mut parser = Parser::new(&mut input); let mut parser = Parser::new(&mut input);
let start_position = parser.position(); let start_position = parser.position();
parser.parse_entirely(|parser| { parser
PropertyDeclaration::parse_into(declarations, id, &context, parser) .parse_entirely(|parser| {
}).map_err(|err| { PropertyDeclaration::parse_into(declarations, id, &context, parser)
if context.error_reporting_enabled() { })
report_one_css_error( .map_err(|err| {
&context, if context.error_reporting_enabled() {
None, report_one_css_error(
None, &context,
err, None,
parser.slice_from(start_position), None,
property_id_for_error_reporting, err,
) parser.slice_from(start_position),
} property_id_for_error_reporting,
}) )
}
})
} }
/// A struct to parse property declarations. /// A struct to parse property declarations.
@ -1273,7 +1311,6 @@ struct PropertyDeclarationParser<'a, 'b: 'a> {
last_parsed_property_id: Option<PropertyId>, last_parsed_property_id: Option<PropertyId>,
} }
/// Default methods reject all at rules. /// Default methods reject all at rules.
impl<'a, 'b, 'i> AtRuleParser<'i> for PropertyDeclarationParser<'a, 'b> { impl<'a, 'b, 'i> AtRuleParser<'i> for PropertyDeclarationParser<'a, 'b> {
type PreludeNoBlock = (); type PreludeNoBlock = ();
@ -1284,8 +1321,7 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for PropertyDeclarationParser<'a, 'b> {
/// Based on NonMozillaVendorIdentifier from Gecko's CSS parser. /// Based on NonMozillaVendorIdentifier from Gecko's CSS parser.
fn is_non_mozilla_vendor_identifier(name: &str) -> bool { fn is_non_mozilla_vendor_identifier(name: &str) -> bool {
(name.starts_with("-") && !name.starts_with("-moz-")) || (name.starts_with("-") && !name.starts_with("-moz-")) || name.starts_with("_")
name.starts_with("_")
} }
impl<'a, 'b, 'i> DeclarationParser<'i> for PropertyDeclarationParser<'a, 'b> { impl<'a, 'b, 'i> DeclarationParser<'i> for PropertyDeclarationParser<'a, 'b> {
@ -1301,10 +1337,8 @@ impl<'a, 'b, 'i> DeclarationParser<'i> for PropertyDeclarationParser<'a, 'b> {
Ok(id) => id, Ok(id) => id,
Err(..) => { Err(..) => {
self.last_parsed_property_id = None; self.last_parsed_property_id = None;
return Err(input.new_custom_error( return Err(input.new_custom_error(StyleParseErrorKind::UnknownProperty(name)));
StyleParseErrorKind::UnknownProperty(name) },
));
}
}; };
if self.context.error_reporting_enabled() { if self.context.error_reporting_enabled() {
self.last_parsed_property_id = Some(id.clone()); self.last_parsed_property_id = Some(id.clone());
@ -1344,10 +1378,8 @@ fn report_one_css_error<'i>(
fn all_properties_in_block(block: &PropertyDeclarationBlock, property: &PropertyId) -> bool { fn all_properties_in_block(block: &PropertyDeclarationBlock, property: &PropertyId) -> bool {
match *property { match *property {
PropertyId::LonghandAlias(id, _) | PropertyId::LonghandAlias(id, _) | PropertyId::Longhand(id) => block.contains(id),
PropertyId::Longhand(id) => block.contains(id), PropertyId::ShorthandAlias(id, _) | PropertyId::Shorthand(id) => {
PropertyId::ShorthandAlias(id, _) |
PropertyId::Shorthand(id) => {
id.longhands().all(|longhand| block.contains(longhand)) id.longhands().all(|longhand| block.contains(longhand))
}, },
// NOTE(emilio): We could do this, but it seems of limited utility, // NOTE(emilio): We could do this, but it seems of limited utility,
@ -1382,7 +1414,9 @@ fn report_one_css_error<'i>(
} }
} }
error = match *property { error = match *property {
PropertyId::Custom(ref c) => StyleParseErrorKind::new_invalid(format!("--{}", c), error), PropertyId::Custom(ref c) => {
StyleParseErrorKind::new_invalid(format!("--{}", c), error)
},
_ => StyleParseErrorKind::new_invalid(property.non_custom_id().unwrap().name(), error), _ => StyleParseErrorKind::new_invalid(property.non_custom_id().unwrap().name(), error),
}; };
} }
@ -1409,7 +1443,7 @@ fn report_css_errors(
pub fn parse_property_declaration_list( pub fn parse_property_declaration_list(
context: &ParserContext, context: &ParserContext,
input: &mut Parser, input: &mut Parser,
selectors: Option<&SelectorList<SelectorImpl>> selectors: Option<&SelectorList<SelectorImpl>>,
) -> PropertyDeclarationBlock { ) -> PropertyDeclarationBlock {
let mut declarations = SourcePropertyDeclaration::new(); let mut declarations = SourcePropertyDeclaration::new();
let mut block = PropertyDeclarationBlock::new(); let mut block = PropertyDeclarationBlock::new();
@ -1423,11 +1457,8 @@ pub fn parse_property_declaration_list(
while let Some(declaration) = iter.next() { while let Some(declaration) = iter.next() {
match declaration { match declaration {
Ok(importance) => { Ok(importance) => {
block.extend( block.extend(iter.parser.declarations.drain(), importance);
iter.parser.declarations.drain(), },
importance,
);
}
Err((error, slice)) => { Err((error, slice)) => {
iter.parser.declarations.clear(); iter.parser.declarations.clear();
@ -1435,7 +1466,7 @@ pub fn parse_property_declaration_list(
let property = iter.parser.last_parsed_property_id.take(); let property = iter.parser.last_parsed_property_id.take();
errors.push((error, slice, property)); errors.push((error, slice, property));
} }
} },
} }
} }

View file

@ -321,18 +321,6 @@ impl ${style_struct.gecko_struct_name} {
} }
</%def> </%def>
<%def name="impl_coord_copy(ident, gecko_ffi_name)">
#[allow(non_snake_case)]
pub fn copy_${ident}_from(&mut self, other: &Self) {
self.gecko.${gecko_ffi_name}.copy_from(&other.gecko.${gecko_ffi_name});
}
#[allow(non_snake_case)]
pub fn reset_${ident}(&mut self, other: &Self) {
self.copy_${ident}_from(other)
}
</%def>
<%! <%!
def get_gecko_property(ffi_name, self_param = "self"): def get_gecko_property(ffi_name, self_param = "self"):
return "%s.gecko.%s" % (self_param, ffi_name) return "%s.gecko.%s" % (self_param, ffi_name)
@ -357,10 +345,7 @@ def set_gecko_property(ffi_name, expr):
</%def> </%def>
<%def name="impl_keyword_clone(ident, gecko_ffi_name, keyword, cast_type='u8')"> <%def name="impl_keyword_clone(ident, gecko_ffi_name, keyword, cast_type='u8')">
// FIXME: We introduced non_upper_case_globals for -moz-appearance only #[allow(non_snake_case)]
// since the prefix of Gecko value starts with ThemeWidgetType_NS_THEME.
// We should remove this after fix bug 1371809.
#[allow(non_snake_case, non_upper_case_globals)]
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
use crate::properties::longhands::${ident}::computed_value::T as Keyword; use crate::properties::longhands::${ident}::computed_value::T as Keyword;
// FIXME(bholley): Align binary representations and ditch |match| for cast + static_asserts // FIXME(bholley): Align binary representations and ditch |match| for cast + static_asserts
@ -1146,7 +1131,7 @@ fn static_assert() {
} }
pub fn set_font_size(&mut self, v: FontSize) { pub fn set_font_size(&mut self, v: FontSize) {
use crate::values::generics::font::KeywordSize; use crate::values::specified::font::KeywordSize;
let size = v.size(); let size = v.size();
self.gecko.mScriptUnconstrainedSize = size.0; self.gecko.mScriptUnconstrainedSize = size.0;
@ -1167,7 +1152,7 @@ fn static_assert() {
KeywordSize::XXXLarge => structs::NS_STYLE_FONT_SIZE_XXXLARGE, KeywordSize::XXXLarge => structs::NS_STYLE_FONT_SIZE_XXXLARGE,
} as u8; } as u8;
self.gecko.mFontSizeFactor = info.factor; self.gecko.mFontSizeFactor = info.factor;
self.gecko.mFontSizeOffset = info.offset.0.to_i32_au(); self.gecko.mFontSizeOffset = info.offset.to_i32_au();
} else { } else {
self.gecko.mFontSizeKeyword = structs::NS_STYLE_FONT_SIZE_NO_KEYWORD as u8; self.gecko.mFontSizeKeyword = structs::NS_STYLE_FONT_SIZE_NO_KEYWORD as u8;
self.gecko.mFontSizeFactor = 1.; self.gecko.mFontSizeFactor = 1.;
@ -1176,7 +1161,7 @@ fn static_assert() {
} }
pub fn clone_font_size(&self) -> FontSize { pub fn clone_font_size(&self) -> FontSize {
use crate::values::generics::font::{KeywordInfo, KeywordSize}; use crate::values::specified::font::{KeywordInfo, KeywordSize};
let size = Au(self.gecko.mSize).into(); let size = Au(self.gecko.mSize).into();
let kw = match self.gecko.mFontSizeKeyword as u32 { let kw = match self.gecko.mFontSizeKeyword as u32 {
structs::NS_STYLE_FONT_SIZE_XXSMALL => KeywordSize::XXSmall, structs::NS_STYLE_FONT_SIZE_XXSMALL => KeywordSize::XXSmall,
@ -1259,6 +1244,8 @@ fn static_assert() {
${impl_simple_type_with_conversion("font_synthesis", "mFont.synthesis")} ${impl_simple_type_with_conversion("font_synthesis", "mFont.synthesis")}
${impl_simple("font_variant_alternates", "mFont.variantAlternates")}
pub fn set_font_size_adjust(&mut self, v: longhands::font_size_adjust::computed_value::T) { pub fn set_font_size_adjust(&mut self, v: longhands::font_size_adjust::computed_value::T) {
use crate::properties::longhands::font_size_adjust::computed_value::T; use crate::properties::longhands::font_size_adjust::computed_value::T;
match v { match v {
@ -1331,122 +1318,6 @@ fn static_assert() {
${impl_simple("_moz_script_level", "mScriptLevel")} ${impl_simple("_moz_script_level", "mScriptLevel")}
<% impl_simple_type_with_conversion("font_language_override", "mFont.languageOverride") %> <% impl_simple_type_with_conversion("font_language_override", "mFont.languageOverride") %>
pub fn set_font_variant_alternates(
&mut self,
v: values::computed::font::FontVariantAlternates,
) {
use crate::gecko_bindings::bindings::{Gecko_ClearAlternateValues, Gecko_AppendAlternateValues};
% for value in "normal swash stylistic ornaments annotation styleset character_variant historical".split():
use crate::gecko_bindings::structs::NS_FONT_VARIANT_ALTERNATES_${value.upper()};
% endfor
use crate::values::specified::font::VariantAlternates;
unsafe {
Gecko_ClearAlternateValues(&mut self.gecko.mFont, v.len());
}
if v.0.is_empty() {
self.gecko.mFont.variantAlternates = NS_FONT_VARIANT_ALTERNATES_NORMAL as u16;
return;
}
for val in v.0.iter() {
match *val {
% for value in "Swash Stylistic Ornaments Annotation".split():
VariantAlternates::${value}(ref ident) => {
self.gecko.mFont.variantAlternates |= NS_FONT_VARIANT_ALTERNATES_${value.upper()} as u16;
unsafe {
Gecko_AppendAlternateValues(&mut self.gecko.mFont,
NS_FONT_VARIANT_ALTERNATES_${value.upper()},
ident.0.as_ptr());
}
},
% endfor
% for value in "styleset character_variant".split():
VariantAlternates::${to_camel_case(value)}(ref slice) => {
self.gecko.mFont.variantAlternates |= NS_FONT_VARIANT_ALTERNATES_${value.upper()} as u16;
for ident in slice.iter() {
unsafe {
Gecko_AppendAlternateValues(&mut self.gecko.mFont,
NS_FONT_VARIANT_ALTERNATES_${value.upper()},
ident.0.as_ptr());
}
}
},
% endfor
VariantAlternates::HistoricalForms => {
self.gecko.mFont.variantAlternates |= NS_FONT_VARIANT_ALTERNATES_HISTORICAL as u16;
}
}
}
}
#[allow(non_snake_case)]
pub fn copy_font_variant_alternates_from(&mut self, other: &Self) {
use crate::gecko_bindings::bindings::Gecko_CopyAlternateValuesFrom;
self.gecko.mFont.variantAlternates = other.gecko.mFont.variantAlternates;
unsafe {
Gecko_CopyAlternateValuesFrom(&mut self.gecko.mFont, &other.gecko.mFont);
}
}
pub fn reset_font_variant_alternates(&mut self, other: &Self) {
self.copy_font_variant_alternates_from(other)
}
pub fn clone_font_variant_alternates(&self) -> values::computed::font::FontVariantAlternates {
% for value in "normal swash stylistic ornaments annotation styleset character_variant historical".split():
use crate::gecko_bindings::structs::NS_FONT_VARIANT_ALTERNATES_${value.upper()};
% endfor
use crate::values::specified::font::VariantAlternates;
use crate::values::specified::font::VariantAlternatesList;
use crate::values::CustomIdent;
if self.gecko.mFont.variantAlternates == NS_FONT_VARIANT_ALTERNATES_NORMAL as u16 {
return VariantAlternatesList(vec![].into_boxed_slice());
}
let mut alternates = Vec::with_capacity(self.gecko.mFont.alternateValues.len());
if self.gecko.mFont.variantAlternates & (NS_FONT_VARIANT_ALTERNATES_HISTORICAL as u16) != 0 {
alternates.push(VariantAlternates::HistoricalForms);
}
<%
property_need_ident_list = "styleset character_variant".split()
%>
% for value in property_need_ident_list:
let mut ${value}_list = Vec::new();
% endfor
for gecko_alternate_value in self.gecko.mFont.alternateValues.iter() {
let ident = Atom::from(gecko_alternate_value.value.to_string());
match gecko_alternate_value.alternate {
% for value in "Swash Stylistic Ornaments Annotation".split():
NS_FONT_VARIANT_ALTERNATES_${value.upper()} => {
alternates.push(VariantAlternates::${value}(CustomIdent(ident)));
},
% endfor
% for value in property_need_ident_list:
NS_FONT_VARIANT_ALTERNATES_${value.upper()} => {
${value}_list.push(CustomIdent(ident));
},
% endfor
_ => {
panic!("Found unexpected value for font-variant-alternates");
}
}
}
% for value in property_need_ident_list:
if !${value}_list.is_empty() {
alternates.push(VariantAlternates::${to_camel_case(value)}(${value}_list.into_boxed_slice()));
}
% endfor
VariantAlternatesList(alternates.into_boxed_slice())
}
${impl_simple_type_with_conversion("font_variant_ligatures", "mFont.variantLigatures")} ${impl_simple_type_with_conversion("font_variant_ligatures", "mFont.variantLigatures")}
${impl_simple_type_with_conversion("font_variant_east_asian", "mFont.variantEastAsian")} ${impl_simple_type_with_conversion("font_variant_east_asian", "mFont.variantEastAsian")}
${impl_simple_type_with_conversion("font_variant_numeric", "mFont.variantNumeric")} ${impl_simple_type_with_conversion("font_variant_numeric", "mFont.variantNumeric")}
@ -2291,7 +2162,7 @@ fn static_assert() {
</%self:impl_trait> </%self:impl_trait>
<%self:impl_trait style_struct_name="List" <%self:impl_trait style_struct_name="List"
skip_longhands="list-style-image list-style-type -moz-image-region"> skip_longhands="list-style-image list-style-type">
pub fn set_list_style_image(&mut self, image: longhands::list_style_image::computed_value::T) { pub fn set_list_style_image(&mut self, image: longhands::list_style_image::computed_value::T) {
match image { match image {
@ -2328,10 +2199,15 @@ fn static_assert() {
} }
pub fn set_list_style_type(&mut self, v: longhands::list_style_type::computed_value::T) { pub fn set_list_style_type(&mut self, v: longhands::list_style_type::computed_value::T) {
use crate::gecko_bindings::bindings::Gecko_SetCounterStyleToName;
use crate::gecko_bindings::bindings::Gecko_SetCounterStyleToString; use crate::gecko_bindings::bindings::Gecko_SetCounterStyleToString;
use nsstring::{nsACString, nsCStr}; use nsstring::{nsACString, nsCStr};
use self::longhands::list_style_type::computed_value::T; use self::longhands::list_style_type::computed_value::T;
match v { match v {
T::None => unsafe {
Gecko_SetCounterStyleToName(&mut self.gecko.mCounterStyle,
atom!("none").into_addrefed());
}
T::CounterStyle(s) => s.to_gecko_value(&mut self.gecko.mCounterStyle), T::CounterStyle(s) => s.to_gecko_value(&mut self.gecko.mCounterStyle),
T::String(s) => unsafe { T::String(s) => unsafe {
Gecko_SetCounterStyleToString(&mut self.gecko.mCounterStyle, Gecko_SetCounterStyleToString(&mut self.gecko.mCounterStyle,
@ -2353,199 +2229,30 @@ fn static_assert() {
pub fn clone_list_style_type(&self) -> longhands::list_style_type::computed_value::T { pub fn clone_list_style_type(&self) -> longhands::list_style_type::computed_value::T {
use self::longhands::list_style_type::computed_value::T; use self::longhands::list_style_type::computed_value::T;
use crate::values::Either; use crate::values::Either;
use crate::values::generics::CounterStyleOrNone; use crate::values::generics::CounterStyle;
use crate::gecko_bindings::bindings;
let result = CounterStyleOrNone::from_gecko_value(&self.gecko.mCounterStyle); let name = unsafe {
bindings::Gecko_CounterStyle_GetName(&self.gecko.mCounterStyle)
};
if !name.is_null() {
let name = unsafe { Atom::from_raw(name) };
if name == atom!("none") {
return T::None;
}
}
let result = CounterStyle::from_gecko_value(&self.gecko.mCounterStyle);
match result { match result {
Either::First(counter_style) => T::CounterStyle(counter_style), Either::First(counter_style) => T::CounterStyle(counter_style),
Either::Second(string) => T::String(string), Either::Second(string) => T::String(string),
} }
} }
#[allow(non_snake_case)]
pub fn set__moz_image_region(&mut self, v: longhands::_moz_image_region::computed_value::T) {
use crate::values::Either;
use crate::values::generics::length::LengthPercentageOrAuto::*;
match v {
Either::Second(_auto) => {
self.gecko.mImageRegion.x = 0;
self.gecko.mImageRegion.y = 0;
self.gecko.mImageRegion.width = 0;
self.gecko.mImageRegion.height = 0;
}
Either::First(rect) => {
self.gecko.mImageRegion.x = match rect.left {
LengthPercentage(v) => v.to_i32_au(),
Auto => 0,
};
self.gecko.mImageRegion.y = match rect.top {
LengthPercentage(v) => v.to_i32_au(),
Auto => 0,
};
self.gecko.mImageRegion.height = match rect.bottom {
LengthPercentage(value) => (Au::from(value) - Au(self.gecko.mImageRegion.y)).0,
Auto => 0,
};
self.gecko.mImageRegion.width = match rect.right {
LengthPercentage(value) => (Au::from(value) - Au(self.gecko.mImageRegion.x)).0,
Auto => 0,
};
}
}
}
#[allow(non_snake_case)]
pub fn clone__moz_image_region(&self) -> longhands::_moz_image_region::computed_value::T {
use crate::values::{Auto, Either};
use crate::values::generics::length::LengthPercentageOrAuto::*;
use crate::values::computed::ClipRect;
// There is no ideal way to detect auto type for structs::nsRect and its components, so
// if all components are zero, we use Auto.
if self.gecko.mImageRegion.x == 0 &&
self.gecko.mImageRegion.y == 0 &&
self.gecko.mImageRegion.width == 0 &&
self.gecko.mImageRegion.height == 0 {
return Either::Second(Auto);
}
Either::First(ClipRect {
top: LengthPercentage(Au(self.gecko.mImageRegion.y).into()),
right: LengthPercentage(Au(self.gecko.mImageRegion.width + self.gecko.mImageRegion.x).into()),
bottom: LengthPercentage(Au(self.gecko.mImageRegion.height + self.gecko.mImageRegion.y).into()),
left: LengthPercentage(Au(self.gecko.mImageRegion.x).into()),
})
}
${impl_simple_copy('_moz_image_region', 'mImageRegion')}
</%self:impl_trait> </%self:impl_trait>
<%self:impl_trait style_struct_name="Table" skip_longhands="-x-span"> <%self:impl_trait style_struct_name="Table">
#[allow(non_snake_case)]
pub fn set__x_span(&mut self, v: longhands::_x_span::computed_value::T) {
self.gecko.mSpan = v.0
}
#[allow(non_snake_case)]
pub fn clone__x_span(&self) -> longhands::_x_span::computed_value::T {
longhands::_x_span::computed_value::T(
self.gecko.mSpan
)
}
${impl_simple_copy('_x_span', 'mSpan')}
</%self:impl_trait> </%self:impl_trait>
<%self:impl_trait style_struct_name="Effects" skip_longhands="clip"> <%self:impl_trait style_struct_name="Effects">
pub fn set_clip(&mut self, v: longhands::clip::computed_value::T) {
use crate::gecko_bindings::structs::NS_STYLE_CLIP_AUTO;
use crate::gecko_bindings::structs::NS_STYLE_CLIP_RECT;
use crate::gecko_bindings::structs::NS_STYLE_CLIP_LEFT_AUTO;
use crate::gecko_bindings::structs::NS_STYLE_CLIP_TOP_AUTO;
use crate::gecko_bindings::structs::NS_STYLE_CLIP_RIGHT_AUTO;
use crate::gecko_bindings::structs::NS_STYLE_CLIP_BOTTOM_AUTO;
use crate::values::generics::length::LengthPercentageOrAuto::*;
use crate::values::Either;
match v {
Either::First(rect) => {
self.gecko.mClipFlags = NS_STYLE_CLIP_RECT as u8;
self.gecko.mClip.x = match rect.left {
LengthPercentage(l) => l.to_i32_au(),
Auto => {
self.gecko.mClipFlags |= NS_STYLE_CLIP_LEFT_AUTO as u8;
0
}
};
self.gecko.mClip.y = match rect.top {
LengthPercentage(l) => l.to_i32_au(),
Auto => {
self.gecko.mClipFlags |= NS_STYLE_CLIP_TOP_AUTO as u8;
0
}
};
self.gecko.mClip.height = match rect.bottom {
LengthPercentage(l) => (Au::from(l) - Au(self.gecko.mClip.y)).0,
Auto => {
self.gecko.mClipFlags |= NS_STYLE_CLIP_BOTTOM_AUTO as u8;
1 << 30 // NS_MAXSIZE
}
};
self.gecko.mClip.width = match rect.right {
LengthPercentage(l) => (Au::from(l) - Au(self.gecko.mClip.x)).0,
Auto => {
self.gecko.mClipFlags |= NS_STYLE_CLIP_RIGHT_AUTO as u8;
1 << 30 // NS_MAXSIZE
}
};
},
Either::Second(_auto) => {
self.gecko.mClipFlags = NS_STYLE_CLIP_AUTO as u8;
self.gecko.mClip.x = 0;
self.gecko.mClip.y = 0;
self.gecko.mClip.width = 0;
self.gecko.mClip.height = 0;
}
}
}
pub fn copy_clip_from(&mut self, other: &Self) {
self.gecko.mClip = other.gecko.mClip;
self.gecko.mClipFlags = other.gecko.mClipFlags;
}
pub fn reset_clip(&mut self, other: &Self) {
self.copy_clip_from(other)
}
pub fn clone_clip(&self) -> longhands::clip::computed_value::T {
use crate::gecko_bindings::structs::NS_STYLE_CLIP_AUTO;
use crate::gecko_bindings::structs::NS_STYLE_CLIP_BOTTOM_AUTO;
use crate::gecko_bindings::structs::NS_STYLE_CLIP_LEFT_AUTO;
use crate::gecko_bindings::structs::NS_STYLE_CLIP_RIGHT_AUTO;
use crate::gecko_bindings::structs::NS_STYLE_CLIP_TOP_AUTO;
use crate::values::generics::length::LengthPercentageOrAuto::*;
use crate::values::computed::{ClipRect, ClipRectOrAuto};
use crate::values::Either;
if self.gecko.mClipFlags == NS_STYLE_CLIP_AUTO as u8 {
return ClipRectOrAuto::auto()
}
let left = if self.gecko.mClipFlags & NS_STYLE_CLIP_LEFT_AUTO as u8 != 0 {
debug_assert_eq!(self.gecko.mClip.x, 0);
Auto
} else {
LengthPercentage(Au(self.gecko.mClip.x).into())
};
let top = if self.gecko.mClipFlags & NS_STYLE_CLIP_TOP_AUTO as u8 != 0 {
debug_assert_eq!(self.gecko.mClip.y, 0);
Auto
} else {
LengthPercentage(Au(self.gecko.mClip.y).into())
};
let bottom = if self.gecko.mClipFlags & NS_STYLE_CLIP_BOTTOM_AUTO as u8 != 0 {
debug_assert_eq!(self.gecko.mClip.height, 1 << 30); // NS_MAXSIZE
Auto
} else {
LengthPercentage(Au(self.gecko.mClip.y + self.gecko.mClip.height).into())
};
let right = if self.gecko.mClipFlags & NS_STYLE_CLIP_RIGHT_AUTO as u8 != 0 {
debug_assert_eq!(self.gecko.mClip.width, 1 << 30); // NS_MAXSIZE
Auto
} else {
LengthPercentage(Au(self.gecko.mClip.x + self.gecko.mClip.width).into())
};
Either::First(ClipRect { top, right, bottom, left })
}
</%self:impl_trait> </%self:impl_trait>
<%self:impl_trait style_struct_name="InheritedBox"> <%self:impl_trait style_struct_name="InheritedBox">
@ -2725,18 +2432,7 @@ clip-path
</%self:impl_trait> </%self:impl_trait>
<%self:impl_trait style_struct_name="InheritedSVG" <%self:impl_trait style_struct_name="InheritedSVG"
skip_longhands="paint-order stroke-dasharray"> skip_longhands="stroke-dasharray">
pub fn set_paint_order(&mut self, v: longhands::paint_order::computed_value::T) {
self.gecko.mPaintOrder = v.0;
}
${impl_simple_copy('paint_order', 'mPaintOrder')}
pub fn clone_paint_order(&self) -> longhands::paint_order::computed_value::T {
use crate::properties::longhands::paint_order::computed_value::T;
T(self.gecko.mPaintOrder)
}
pub fn set_stroke_dasharray(&mut self, v: longhands::stroke_dasharray::computed_value::T) { pub fn set_stroke_dasharray(&mut self, v: longhands::stroke_dasharray::computed_value::T) {
use crate::gecko_bindings::structs::nsStyleSVG_STROKE_DASHARRAY_CONTEXT as CONTEXT_VALUE; use crate::gecko_bindings::structs::nsStyleSVG_STROKE_DASHARRAY_CONTEXT as CONTEXT_VALUE;
use crate::values::generics::svg::SVGStrokeDashArray; use crate::values::generics::svg::SVGStrokeDashArray;
@ -2883,8 +2579,7 @@ clip-path
${impl_simple('column_rule_style', 'mColumnRuleStyle')} ${impl_simple('column_rule_style', 'mColumnRuleStyle')}
</%self:impl_trait> </%self:impl_trait>
<%self:impl_trait style_struct_name="Counters" <%self:impl_trait style_struct_name="Counters" skip_longhands="content">
skip_longhands="content counter-increment counter-reset counter-set">
pub fn ineffective_content_property(&self) -> bool { pub fn ineffective_content_property(&self) -> bool {
self.gecko.mContents.is_empty() self.gecko.mContents.is_empty()
} }
@ -2892,7 +2587,7 @@ clip-path
pub fn set_content(&mut self, v: longhands::content::computed_value::T) { pub fn set_content(&mut self, v: longhands::content::computed_value::T) {
use crate::values::CustomIdent; use crate::values::CustomIdent;
use crate::values::generics::counters::{Content, ContentItem}; use crate::values::generics::counters::{Content, ContentItem};
use crate::values::generics::CounterStyleOrNone; use crate::values::generics::CounterStyle;
use crate::gecko_bindings::structs::nsStyleContentData; use crate::gecko_bindings::structs::nsStyleContentData;
use crate::gecko_bindings::structs::nsStyleContentAttr; use crate::gecko_bindings::structs::nsStyleContentAttr;
use crate::gecko_bindings::structs::StyleContentType; use crate::gecko_bindings::structs::StyleContentType;
@ -2913,7 +2608,7 @@ clip-path
content_type: StyleContentType, content_type: StyleContentType,
name: CustomIdent, name: CustomIdent,
sep: &str, sep: &str,
style: CounterStyleOrNone, style: CounterStyle,
) { ) {
debug_assert!(content_type == StyleContentType::Counter || debug_assert!(content_type == StyleContentType::Counter ||
content_type == StyleContentType::Counters); content_type == StyleContentType::Counters);
@ -3043,7 +2738,7 @@ clip-path
use crate::gecko_bindings::structs::StyleContentType; use crate::gecko_bindings::structs::StyleContentType;
use crate::values::generics::counters::{Content, ContentItem}; use crate::values::generics::counters::{Content, ContentItem};
use crate::values::{CustomIdent, Either}; use crate::values::{CustomIdent, Either};
use crate::values::generics::CounterStyleOrNone; use crate::values::generics::CounterStyle;
use crate::values::specified::Attr; use crate::values::specified::Attr;
if self.gecko.mContents.is_empty() { if self.gecko.mContents.is_empty() {
@ -3088,7 +2783,7 @@ clip-path
Atom::from_raw(gecko_function.mIdent.mRawPtr) Atom::from_raw(gecko_function.mIdent.mRawPtr)
}); });
let style = let style =
CounterStyleOrNone::from_gecko_value(&gecko_function.mCounterStyle); CounterStyle::from_gecko_value(&gecko_function.mCounterStyle);
let style = match style { let style = match style {
Either::First(counter_style) => counter_style, Either::First(counter_style) => counter_style,
Either::Second(_) => Either::Second(_) =>
@ -3115,70 +2810,13 @@ clip-path
}).collect::<Vec<_>>().into_boxed_slice() }).collect::<Vec<_>>().into_boxed_slice()
) )
} }
% for counter_property in ["Increment", "Reset", "Set"]:
pub fn set_counter_${counter_property.lower()}(
&mut self,
v: longhands::counter_${counter_property.lower()}::computed_value::T
) {
unsafe {
bindings::Gecko_ClearAndResizeCounter${counter_property}s(&mut *self.gecko, v.len() as u32);
for (i, pair) in v.0.into_vec().into_iter().enumerate() {
self.gecko.m${counter_property}s[i].mCounter.set_move(
RefPtr::from_addrefed(pair.name.0.into_addrefed())
);
self.gecko.m${counter_property}s[i].mValue = pair.value;
}
}
}
pub fn copy_counter_${counter_property.lower()}_from(&mut self, other: &Self) {
unsafe {
bindings::Gecko_CopyCounter${counter_property}sFrom(&mut *self.gecko, &*other.gecko)
}
}
pub fn reset_counter_${counter_property.lower()}(&mut self, other: &Self) {
self.copy_counter_${counter_property.lower()}_from(other)
}
pub fn clone_counter_${counter_property.lower()}(
&self
) -> longhands::counter_${counter_property.lower()}::computed_value::T {
use crate::values::generics::counters::CounterPair;
use crate::values::CustomIdent;
longhands::counter_${counter_property.lower()}::computed_value::T::new(
self.gecko.m${counter_property}s.iter().map(|ref gecko_counter| {
CounterPair {
name: CustomIdent(unsafe {
Atom::from_raw(gecko_counter.mCounter.mRawPtr)
}),
value: gecko_counter.mValue,
}
}).collect()
)
}
% endfor
</%self:impl_trait> </%self:impl_trait>
<%self:impl_trait style_struct_name="UI" skip_longhands="-moz-force-broken-image-icon"> <%self:impl_trait style_struct_name="UI" skip_longhands="-moz-force-broken-image-icon">
${impl_simple_type_with_conversion("_moz_force_broken_image_icon", "mForceBrokenImageIcon")} ${impl_simple_type_with_conversion("_moz_force_broken_image_icon", "mForceBrokenImageIcon")}
</%self:impl_trait> </%self:impl_trait>
<%self:impl_trait style_struct_name="XUL" <%self:impl_trait style_struct_name="XUL">
skip_longhands="-moz-box-ordinal-group">
#[allow(non_snake_case)]
pub fn set__moz_box_ordinal_group(&mut self, v: i32) {
self.gecko.mBoxOrdinal = v as u32;
}
${impl_simple_copy("_moz_box_ordinal_group", "mBoxOrdinal")}
#[allow(non_snake_case)]
pub fn clone__moz_box_ordinal_group(&self) -> i32 {
self.gecko.mBoxOrdinal as i32
}
</%self:impl_trait> </%self:impl_trait>
% for style_struct in data.style_structs: % for style_struct in data.style_structs:

View file

@ -80,7 +80,7 @@ ${helpers.predefined_type(
engines="gecko", engines="gecko",
initial_value="computed::FontSizeAdjust::none()", initial_value="computed::FontSizeAdjust::none()",
initial_specified_value="specified::FontSizeAdjust::none()", initial_specified_value="specified::FontSizeAdjust::none()",
animation_value_type="ComputedValue", animation_value_type="FontSizeAdjust",
spec="https://drafts.csswg.org/css-fonts/#propdef-font-size-adjust", spec="https://drafts.csswg.org/css-fonts/#propdef-font-size-adjust",
)} )}
@ -401,7 +401,7 @@ ${helpers.predefined_type(
is_system_font: true, is_system_font: true,
}, },
font_size: FontSize { font_size: FontSize {
size: cx.maybe_zoom_text(Au(system.size).into()), size: NonNegative(cx.maybe_zoom_text(Au(system.size).into())),
keyword_info: None keyword_info: None
}, },
font_weight, font_weight,

View file

@ -76,6 +76,7 @@ ${helpers.predefined_type(
"ClipRectOrAuto", "ClipRectOrAuto",
"computed::ClipRectOrAuto::auto()", "computed::ClipRectOrAuto::auto()",
engines="gecko", engines="gecko",
gecko_ffi_name="mImageRegion",
animation_value_type="ComputedValue", animation_value_type="ComputedValue",
boxed=True, boxed=True,
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-image-region)", spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-image-region)",

View file

@ -18,8 +18,8 @@ ${helpers.single_keyword(
${helpers.predefined_type( ${helpers.predefined_type(
"-x-span", "-x-span",
"XSpan", "Integer",
"computed::XSpan(1)", "1",
engines="gecko", engines="gecko",
spec="Internal-only (for `<col span>` pres attr)", spec="Internal-only (for `<col span>` pres attr)",
animation_value_type="none", animation_value_type="none",

View file

@ -38,6 +38,7 @@ use style_traits::{CssWriter, KeywordsCollectFn, ParseError, ParsingMode};
use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss}; use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss};
use to_shmem::impl_trivial_to_shmem; use to_shmem::impl_trivial_to_shmem;
use crate::stylesheets::{CssRuleType, Origin, UrlExtraData}; use crate::stylesheets::{CssRuleType, Origin, UrlExtraData};
use crate::use_counters::UseCounters;
use crate::values::generics::text::LineHeight; use crate::values::generics::text::LineHeight;
use crate::values::{computed, resolved}; use crate::values::{computed, resolved};
use crate::values::computed::NonNegativeLength; use crate::values::computed::NonNegativeLength;
@ -427,6 +428,9 @@ pub struct NonCustomPropertyId(usize);
pub const NON_CUSTOM_PROPERTY_ID_COUNT: usize = pub const NON_CUSTOM_PROPERTY_ID_COUNT: usize =
${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())}; ${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())};
/// The length of all counted unknown properties.
pub const COUNTED_UNKNOWN_PROPERTY_COUNT: usize = ${len(data.counted_unknown_properties)};
% if engine == "gecko": % if engine == "gecko":
#[allow(dead_code)] #[allow(dead_code)]
unsafe fn static_assert_nscsspropertyid() { unsafe fn static_assert_nscsspropertyid() {
@ -1788,6 +1792,45 @@ impl ToCss for PropertyId {
} }
} }
/// The counted unknown property list which is used for css use counters.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[repr(u8)]
pub enum CountedUnknownProperty {
% for prop in data.counted_unknown_properties:
/// ${prop.name}
${prop.camel_case},
% endfor
}
impl CountedUnknownProperty {
/// Parse the counted unknown property.
pub fn parse_for_test(property_name: &str) -> Option<Self> {
ascii_case_insensitive_phf_map! {
unknown_id -> CountedUnknownProperty = {
% for property in data.counted_unknown_properties:
"${property.name}" => CountedUnknownProperty::${property.camel_case},
% endfor
}
}
unknown_id(property_name).cloned()
}
/// Returns the underlying index, used for use counter.
pub fn bit(self) -> usize {
self as usize
}
}
#[cfg(feature = "gecko")]
fn is_counted_unknown_use_counters_enabled() -> bool {
static_prefs::pref!("layout.css.use-counters-unimplemented.enabled")
}
#[cfg(feature = "servo")]
fn is_counted_unknown_use_counters_enabled() -> bool {
false
}
impl PropertyId { impl PropertyId {
/// Return the longhand id that this property id represents. /// Return the longhand id that this property id represents.
#[inline] #[inline]
@ -1801,16 +1844,30 @@ impl PropertyId {
/// Returns a given property from the string `s`. /// Returns a given property from the string `s`.
/// ///
/// Returns Err(()) for unknown non-custom properties. /// Returns Err(()) for unknown properties.
fn parse_unchecked(property_name: &str) -> Result<Self, ()> { fn parse_unchecked(
property_name: &str,
use_counters: Option< &UseCounters>,
) -> Result<Self, ()> {
// A special id for css use counters.
// ShorthandAlias is not used in the Servo build.
// That's why we need to allow dead_code.
#[allow(dead_code)]
pub enum StaticId {
Longhand(LonghandId),
Shorthand(ShorthandId),
LonghandAlias(LonghandId, AliasId),
ShorthandAlias(ShorthandId, AliasId),
CountedUnknown(CountedUnknownProperty),
}
ascii_case_insensitive_phf_map! { ascii_case_insensitive_phf_map! {
property_id -> PropertyId = { static_id -> StaticId = {
% for (kind, properties) in [("Longhand", data.longhands), ("Shorthand", data.shorthands)]: % for (kind, properties) in [("Longhand", data.longhands), ("Shorthand", data.shorthands)]:
% for property in properties: % for property in properties:
"${property.name}" => PropertyId::${kind}(${kind}Id::${property.camel_case}), "${property.name}" => StaticId::${kind}(${kind}Id::${property.camel_case}),
% for alias in property.alias: % for alias in property.alias:
"${alias.name}" => { "${alias.name}" => {
PropertyId::${kind}Alias( StaticId::${kind}Alias(
${kind}Id::${property.camel_case}, ${kind}Id::${property.camel_case},
AliasId::${alias.camel_case}, AliasId::${alias.camel_case},
) )
@ -1818,11 +1875,31 @@ impl PropertyId {
% endfor % endfor
% endfor % endfor
% endfor % endfor
% for property in data.counted_unknown_properties:
"${property.name}" => {
StaticId::CountedUnknown(CountedUnknownProperty::${property.camel_case})
},
% endfor
} }
} }
if let Some(id) = property_id(property_name) { if let Some(id) = static_id(property_name) {
return Ok(id.clone()) return Ok(match *id {
StaticId::Longhand(id) => PropertyId::Longhand(id),
StaticId::Shorthand(id) => PropertyId::Shorthand(id),
StaticId::LonghandAlias(id, alias) => PropertyId::LonghandAlias(id, alias),
StaticId::ShorthandAlias(id, alias) => PropertyId::ShorthandAlias(id, alias),
StaticId::CountedUnknown(unknown_prop) => {
if is_counted_unknown_use_counters_enabled() {
if let Some(counters) = use_counters {
counters.counted_unknown_properties.record(unknown_prop);
}
}
// Always return Err(()) because these aren't valid custom property names.
return Err(());
}
});
} }
let name = crate::custom_properties::parse_name(property_name)?; let name = crate::custom_properties::parse_name(property_name)?;
@ -1833,7 +1910,7 @@ impl PropertyId {
/// enabled for all content. /// enabled for all content.
#[inline] #[inline]
pub fn parse_enabled_for_all_content(name: &str) -> Result<Self, ()> { pub fn parse_enabled_for_all_content(name: &str) -> Result<Self, ()> {
let id = Self::parse_unchecked(name)?; let id = Self::parse_unchecked(name, None)?;
if !id.enabled_for_all_content() { if !id.enabled_for_all_content() {
return Err(()); return Err(());
@ -1847,7 +1924,7 @@ impl PropertyId {
/// allowed in this context. /// allowed in this context.
#[inline] #[inline]
pub fn parse(name: &str, context: &ParserContext) -> Result<Self, ()> { pub fn parse(name: &str, context: &ParserContext) -> Result<Self, ()> {
let id = Self::parse_unchecked(name)?; let id = Self::parse_unchecked(name, context.use_counters)?;
if !id.allowed_in(context) { if !id.allowed_in(context) {
return Err(()); return Err(());
@ -1865,7 +1942,7 @@ impl PropertyId {
name: &str, name: &str,
context: &ParserContext, context: &ParserContext,
) -> Result<Self, ()> { ) -> Result<Self, ()> {
let id = Self::parse_unchecked(name)?; let id = Self::parse_unchecked(name, None)?;
if !id.allowed_in_ignoring_rule_type(context) { if !id.allowed_in_ignoring_rule_type(context) {
return Err(()); return Err(());

View file

@ -61,31 +61,23 @@
let position = unwrap_or_initial!(list_style_position, position); let position = unwrap_or_initial!(list_style_position, position);
fn list_style_type_none() -> list_style_type::SpecifiedValue {
% if engine == "gecko":
use crate::values::generics::CounterStyleOrNone;
list_style_type::SpecifiedValue::CounterStyle(CounterStyleOrNone::None)
% else:
list_style_type::SpecifiedValue::None
% endif
}
// If there are two `none`s, then we can't have a type or image; if there is one `none`, // If there are two `none`s, then we can't have a type or image; if there is one `none`,
// then we can't have both a type *and* an image; if there is no `none` then we're fine as // then we can't have both a type *and* an image; if there is no `none` then we're fine as
// long as we parsed something. // long as we parsed something.
use self::list_style_type::SpecifiedValue as ListStyleType;
match (any, nones, list_style_type, image) { match (any, nones, list_style_type, image) {
(true, 2, None, None) => { (true, 2, None, None) => {
Ok(expanded! { Ok(expanded! {
list_style_position: position, list_style_position: position,
list_style_image: ImageUrlOrNone::none(), list_style_image: ImageUrlOrNone::none(),
list_style_type: list_style_type_none(), list_style_type: ListStyleType::None,
}) })
} }
(true, 1, None, Some(image)) => { (true, 1, None, Some(image)) => {
Ok(expanded! { Ok(expanded! {
list_style_position: position, list_style_position: position,
list_style_image: image, list_style_image: image,
list_style_type: list_style_type_none(), list_style_type: ListStyleType::None,
}) })
} }
(true, 1, Some(list_style_type), None) => { (true, 1, Some(list_style_type), None) => {
@ -99,7 +91,7 @@
Ok(expanded! { Ok(expanded! {
list_style_position: position, list_style_position: position,
list_style_image: ImageUrlOrNone::none(), list_style_image: ImageUrlOrNone::none(),
list_style_type: list_style_type_none(), list_style_type: ListStyleType::None,
}) })
} }
(true, 0, list_style_type, image) => { (true, 0, list_style_type, image) => {

View file

@ -73,26 +73,51 @@
} }
impl<'a> ToCss for LonghandsToSerialize<'a> { impl<'a> ToCss for LonghandsToSerialize<'a> {
#[allow(unused)]
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.text_decoration_line.to_css(dest)?; use crate::values::specified::TextDecorationLine;
let (is_solid_style, is_current_color, is_auto_thickness) =
(
% if engine == "gecko":
*self.text_decoration_style == text_decoration_style::SpecifiedValue::Solid,
*self.text_decoration_color == specified::Color::CurrentColor,
self.text_decoration_thickness.map_or(true, |t| t.is_auto())
% else:
true, true, true
% endif
);
let mut has_value = false;
let is_none = *self.text_decoration_line == TextDecorationLine::none();
if (is_solid_style && is_current_color && is_auto_thickness) || !is_none {
self.text_decoration_line.to_css(dest)?;
has_value = true;
}
% if engine == "gecko": % if engine == "gecko":
if *self.text_decoration_style != text_decoration_style::SpecifiedValue::Solid { if !is_solid_style {
if has_value {
dest.write_str(" ")?; dest.write_str(" ")?;
self.text_decoration_style.to_css(dest)?;
} }
self.text_decoration_style.to_css(dest)?;
has_value = true;
}
if *self.text_decoration_color != specified::Color::CurrentColor { if !is_current_color {
if has_value {
dest.write_str(" ")?; dest.write_str(" ")?;
self.text_decoration_color.to_css(dest)?;
} }
self.text_decoration_color.to_css(dest)?;
has_value = true;
}
if let Some(text_decoration_thickness) = self.text_decoration_thickness { if !is_auto_thickness {
if !text_decoration_thickness.is_auto() { if has_value {
dest.write_str(" ")?; dest.write_str(" ")?;
self.text_decoration_thickness.to_css(dest)?;
}
} }
self.text_decoration_thickness.to_css(dest)?;
}
% endif % endif
Ok(()) Ok(())

View file

@ -15,6 +15,9 @@ use std::ops::DerefMut;
/// ///
/// We use this on Servo to construct thread-local contexts, but clear them once /// We use this on Servo to construct thread-local contexts, but clear them once
/// we're done with restyling. /// we're done with restyling.
///
/// Note that the cleanup is done on the thread that owns the scoped TLS, thus
/// the Send bound.
pub struct ScopedTLS<'scope, T: Send> { pub struct ScopedTLS<'scope, T: Send> {
pool: &'scope rayon::ThreadPool, pool: &'scope rayon::ThreadPool,
slots: Box<[RefCell<Option<T>>]>, slots: Box<[RefCell<Option<T>>]>,

View file

@ -82,7 +82,7 @@ use servo_arc::Arc;
use smallbitvec::SmallBitVec; use smallbitvec::SmallBitVec;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::mem; use std::mem::{self, ManuallyDrop};
use std::ops::Deref; use std::ops::Deref;
use std::ptr::NonNull; use std::ptr::NonNull;
use uluru::{Entry, LRUCache}; use uluru::{Entry, LRUCache};
@ -477,10 +477,9 @@ type TypelessSharingCache = SharingCacheBase<FakeCandidate>;
type StoredSharingCache = Arc<AtomicRefCell<TypelessSharingCache>>; type StoredSharingCache = Arc<AtomicRefCell<TypelessSharingCache>>;
thread_local! { thread_local! {
// TODO(emilio): Looks like a few of these should just be Rc<RefCell<>> or // See the comment on bloom.rs about why do we leak this.
// something. No need for atomics in the thread-local code. static SHARING_CACHE_KEY: ManuallyDrop<StoredSharingCache> =
static SHARING_CACHE_KEY: StoredSharingCache = ManuallyDrop::new(Arc::new_leaked(Default::default()));
Arc::new_leaked(AtomicRefCell::new(TypelessSharingCache::default()));
} }
/// An LRU cache of the last few nodes seen, so that we can aggressively try to /// An LRU cache of the last few nodes seen, so that we can aggressively try to
@ -533,7 +532,7 @@ impl<E: TElement> StyleSharingCache<E> {
mem::align_of::<SharingCache<E>>(), mem::align_of::<SharingCache<E>>(),
mem::align_of::<TypelessSharingCache>() mem::align_of::<TypelessSharingCache>()
); );
let cache_arc = SHARING_CACHE_KEY.with(|c| c.clone()); let cache_arc = SHARING_CACHE_KEY.with(|c| Arc::clone(&*c));
let cache = let cache =
OwningHandle::new_with_fn(cache_arc, |x| unsafe { x.as_ref() }.unwrap().borrow_mut()); OwningHandle::new_with_fn(cache_arc, |x| unsafe { x.as_ref() }.unwrap().borrow_mut());
debug_assert!(cache.is_empty()); debug_assert!(cache.is_empty());

View file

@ -283,6 +283,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
fn adjust_for_text_combine_upright(&mut self) { fn adjust_for_text_combine_upright(&mut self) {
use crate::computed_values::text_combine_upright::T as TextCombineUpright; use crate::computed_values::text_combine_upright::T as TextCombineUpright;
use crate::computed_values::writing_mode::T as WritingMode; use crate::computed_values::writing_mode::T as WritingMode;
use crate::logical_geometry;
let writing_mode = self.style.get_inherited_box().clone_writing_mode(); let writing_mode = self.style.get_inherited_box().clone_writing_mode();
let text_combine_upright = self.style.get_inherited_text().clone_text_combine_upright(); let text_combine_upright = self.style.get_inherited_text().clone_text_combine_upright();
@ -294,6 +295,8 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
self.style self.style
.mutate_inherited_box() .mutate_inherited_box()
.set_writing_mode(WritingMode::HorizontalTb); .set_writing_mode(WritingMode::HorizontalTb);
self.style.writing_mode =
logical_geometry::WritingMode::new(self.style.get_inherited_box());
} }
} }

View file

@ -6,6 +6,7 @@
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use crate::gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI}; use crate::gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI};
use crate::properties::{CountedUnknownProperty, COUNTED_UNKNOWN_PROPERTY_COUNT};
use crate::properties::{NonCustomPropertyId, NON_CUSTOM_PROPERTY_ID_COUNT}; use crate::properties::{NonCustomPropertyId, NON_CUSTOM_PROPERTY_ID_COUNT};
use std::cell::Cell; use std::cell::Cell;
@ -15,46 +16,62 @@ const BITS_PER_ENTRY: usize = 64;
#[cfg(target_pointer_width = "32")] #[cfg(target_pointer_width = "32")]
const BITS_PER_ENTRY: usize = 32; const BITS_PER_ENTRY: usize = 32;
/// One bit per each non-custom CSS property.
#[derive(Default)]
pub struct CountedUnknownPropertyUseCounters {
storage: [Cell<usize>; (COUNTED_UNKNOWN_PROPERTY_COUNT - 1 + BITS_PER_ENTRY) / BITS_PER_ENTRY],
}
/// One bit per each non-custom CSS property. /// One bit per each non-custom CSS property.
#[derive(Default)] #[derive(Default)]
pub struct NonCustomPropertyUseCounters { pub struct NonCustomPropertyUseCounters {
storage: [Cell<usize>; (NON_CUSTOM_PROPERTY_ID_COUNT - 1 + BITS_PER_ENTRY) / BITS_PER_ENTRY], storage: [Cell<usize>; (NON_CUSTOM_PROPERTY_ID_COUNT - 1 + BITS_PER_ENTRY) / BITS_PER_ENTRY],
} }
impl NonCustomPropertyUseCounters { macro_rules! property_use_counters_methods {
/// Returns the bucket a given property belongs in, and the bitmask for that ($id: ident) => {
/// property. /// Returns the bucket a given property belongs in, and the bitmask for that
#[inline(always)] /// property.
fn bucket_and_pattern(id: NonCustomPropertyId) -> (usize, usize) { #[inline(always)]
let bit = id.bit(); fn bucket_and_pattern(id: $id) -> (usize, usize) {
let bucket = bit / BITS_PER_ENTRY; let bit = id.bit();
let bit_in_bucket = bit % BITS_PER_ENTRY; let bucket = bit / BITS_PER_ENTRY;
(bucket, 1 << bit_in_bucket) let bit_in_bucket = bit % BITS_PER_ENTRY;
} (bucket, 1 << bit_in_bucket)
/// Record that a given non-custom property ID has been parsed.
#[inline]
pub fn record(&self, id: NonCustomPropertyId) {
let (bucket, pattern) = Self::bucket_and_pattern(id);
let bucket = &self.storage[bucket];
bucket.set(bucket.get() | pattern)
}
/// Returns whether a given non-custom property ID has been recorded
/// earlier.
#[inline]
pub fn recorded(&self, id: NonCustomPropertyId) -> bool {
let (bucket, pattern) = Self::bucket_and_pattern(id);
self.storage[bucket].get() & pattern != 0
}
/// Merge `other` into `self`.
#[inline]
fn merge(&self, other: &Self) {
for (bucket, other_bucket) in self.storage.iter().zip(other.storage.iter()) {
bucket.set(bucket.get() | other_bucket.get())
} }
}
/// Record that a given property ID has been parsed.
#[inline]
pub fn record(&self, id: $id) {
let (bucket, pattern) = Self::bucket_and_pattern(id);
let bucket = &self.storage[bucket];
bucket.set(bucket.get() | pattern)
}
/// Returns whether a given property ID has been recorded
/// earlier.
#[inline]
pub fn recorded(&self, id: $id) -> bool {
let (bucket, pattern) = Self::bucket_and_pattern(id);
self.storage[bucket].get() & pattern != 0
}
/// Merge `other` into `self`.
#[inline]
fn merge(&self, other: &Self) {
for (bucket, other_bucket) in self.storage.iter().zip(other.storage.iter()) {
bucket.set(bucket.get() | other_bucket.get())
}
}
};
}
impl CountedUnknownPropertyUseCounters {
property_use_counters_methods!(CountedUnknownProperty);
}
impl NonCustomPropertyUseCounters {
property_use_counters_methods!(NonCustomPropertyId);
} }
/// The use-counter data related to a given document we want to store. /// The use-counter data related to a given document we want to store.
@ -63,6 +80,8 @@ pub struct UseCounters {
/// The counters for non-custom properties that have been parsed in the /// The counters for non-custom properties that have been parsed in the
/// document's stylesheets. /// document's stylesheets.
pub non_custom_properties: NonCustomPropertyUseCounters, pub non_custom_properties: NonCustomPropertyUseCounters,
/// The counters for css properties which we haven't implemented yet.
pub counted_unknown_properties: CountedUnknownPropertyUseCounters,
} }
impl UseCounters { impl UseCounters {
@ -72,7 +91,9 @@ impl UseCounters {
#[inline] #[inline]
pub fn merge(&self, other: &Self) { pub fn merge(&self, other: &Self) {
self.non_custom_properties self.non_custom_properties
.merge(&other.non_custom_properties) .merge(&other.non_custom_properties);
self.counted_unknown_properties
.merge(&other.counted_unknown_properties);
} }
} }

View file

@ -9,11 +9,15 @@ use crate::gecko_bindings::sugar::refptr::RefPtr;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use crate::gecko_bindings::{bindings, structs}; use crate::gecko_bindings::{bindings, structs};
use crate::values::animated::{ToAnimatedValue, ToAnimatedZero}; use crate::values::animated::{ToAnimatedValue, ToAnimatedZero};
use crate::values::computed::{Angle, Context, Integer, NonNegativeLength, NonNegativePercentage}; use crate::values::computed::{
Angle, Context, Integer, Length, NonNegativeLength, NonNegativePercentage,
};
use crate::values::computed::{Number, Percentage, ToComputedValue}; use crate::values::computed::{Number, Percentage, ToComputedValue};
use crate::values::generics::font as generics;
use crate::values::generics::font::{FeatureTagValue, FontSettings, VariationValue}; use crate::values::generics::font::{FeatureTagValue, FontSettings, VariationValue};
use crate::values::specified::font::{self as specified, MAX_FONT_WEIGHT, MIN_FONT_WEIGHT}; use crate::values::generics::{font as generics, NonNegative};
use crate::values::specified::font::{
self as specified, KeywordInfo, MAX_FONT_WEIGHT, MIN_FONT_WEIGHT,
};
use crate::values::specified::length::{FontBaseSize, NoCalcLength}; use crate::values::specified::length::{FontBaseSize, NoCalcLength};
use crate::values::CSSFloat; use crate::values::CSSFloat;
use crate::Atom; use crate::Atom;
@ -88,9 +92,6 @@ pub struct FontSize {
pub keyword_info: Option<KeywordInfo>, pub keyword_info: Option<KeywordInfo>,
} }
/// Additional information for computed keyword-derived font sizes.
pub type KeywordInfo = generics::KeywordInfo<NonNegativeLength>;
impl FontWeight { impl FontWeight {
/// Value for normal /// Value for normal
pub fn normal() -> Self { pub fn normal() -> Self {
@ -162,17 +163,17 @@ impl FontSize {
} }
impl ToAnimatedValue for FontSize { impl ToAnimatedValue for FontSize {
type AnimatedValue = NonNegativeLength; type AnimatedValue = Length;
#[inline] #[inline]
fn to_animated_value(self) -> Self::AnimatedValue { fn to_animated_value(self) -> Self::AnimatedValue {
self.size self.size.0
} }
#[inline] #[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self { fn from_animated_value(animated: Self::AnimatedValue) -> Self {
FontSize { FontSize {
size: animated.clamp(), size: NonNegative(animated.clamp_to_non_negative()),
keyword_info: None, keyword_info: None,
} }
} }
@ -647,10 +648,10 @@ impl ToAnimatedValue for FontSizeAdjust {
pub type FontVariantAlternates = specified::VariantAlternatesList; pub type FontVariantAlternates = specified::VariantAlternatesList;
impl FontVariantAlternates { impl FontVariantAlternates {
#[inline]
/// Get initial value with VariantAlternatesList /// Get initial value with VariantAlternatesList
#[inline]
pub fn get_initial_value() -> Self { pub fn get_initial_value() -> Self {
specified::VariantAlternatesList(vec![].into_boxed_slice()) Self::default()
} }
} }

View file

@ -297,7 +297,7 @@ impl specified::CalcLengthPercentage {
) -> LengthPercentage { ) -> LengthPercentage {
self.to_computed_value_with_zoom( self.to_computed_value_with_zoom(
context, context,
|abs| context.maybe_zoom_text(abs.into()).0, |abs| context.maybe_zoom_text(abs.into()),
base_size, base_size,
) )
} }
@ -360,8 +360,8 @@ impl LengthPercentage {
self.unclamped_length().px() == 0.0 && self.percentage.0 == 0.0 self.unclamped_length().px() == 0.0 && self.percentage.0 == 0.0
} }
// CSSFloat doesn't implement Hash, so does CSSPixelLength. Therefore, we still use Au as the // CSSFloat doesn't implement Hash, so does CSSPixelLength. Therefore, we
// hash key. // still use Au as the hash key.
#[allow(missing_docs)] #[allow(missing_docs)]
pub fn to_hash_key(&self) -> (Au, NotNan<f32>) { pub fn to_hash_key(&self) -> (Au, NotNan<f32>) {
( (
@ -840,14 +840,6 @@ impl NonNegativeLength {
self self
} }
} }
/// Scale this NonNegativeLength.
/// We scale NonNegativeLength by zero if the factor is negative because it doesn't
/// make sense to scale a negative factor on a non-negative length.
#[inline]
pub fn scale_by(&self, factor: f32) -> Self {
Self::new(self.0.px() * factor.max(0.))
}
} }
impl From<Length> for NonNegativeLength { impl From<Length> for NonNegativeLength {

View file

@ -75,7 +75,6 @@ pub use self::resolution::Resolution;
pub use self::svg::MozContextProperties; pub use self::svg::MozContextProperties;
pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind}; pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind};
pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth}; pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
pub use self::table::XSpan;
pub use self::text::{InitialLetter, LetterSpacing, LineBreak, LineHeight}; pub use self::text::{InitialLetter, LetterSpacing, LineBreak, LineHeight};
pub use self::text::{OverflowWrap, TextOverflow, WordBreak, WordSpacing}; pub use self::text::{OverflowWrap, TextOverflow, WordBreak, WordSpacing};
pub use self::text::{TextAlign, TextEmphasisPosition, TextEmphasisStyle}; pub use self::text::{TextAlign, TextEmphasisPosition, TextEmphasisStyle};
@ -116,7 +115,6 @@ pub mod position;
pub mod rect; pub mod rect;
pub mod resolution; pub mod resolution;
pub mod svg; pub mod svg;
pub mod table;
pub mod text; pub mod text;
pub mod time; pub mod time;
pub mod transform; pub mod transform;
@ -230,7 +228,7 @@ impl<'a> Context<'a> {
/// Apply text-zoom if enabled. /// Apply text-zoom if enabled.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub fn maybe_zoom_text(&self, size: NonNegativeLength) -> NonNegativeLength { pub fn maybe_zoom_text(&self, size: CSSPixelLength) -> CSSPixelLength {
// We disable zoom for <svg:text> by unsetting the // We disable zoom for <svg:text> by unsetting the
// -x-text-zoom property, which leads to a false value // -x-text-zoom property, which leads to a false value
// in mAllowZoom // in mAllowZoom
@ -243,7 +241,7 @@ impl<'a> Context<'a> {
/// (Servo doesn't do text-zoom) /// (Servo doesn't do text-zoom)
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
pub fn maybe_zoom_text(&self, size: NonNegativeLength) -> NonNegativeLength { pub fn maybe_zoom_text(&self, size: CSSPixelLength) -> CSSPixelLength {
size size
} }
} }
@ -685,11 +683,11 @@ impl From<CSSInteger> for PositiveInteger {
/// A computed positive `<integer>` value or `none`. /// A computed positive `<integer>` value or `none`.
pub type PositiveIntegerOrNone = Either<PositiveInteger, None_>; pub type PositiveIntegerOrNone = Either<PositiveInteger, None_>;
/// rect(...) /// rect(...) | auto
pub type ClipRect = generics::ClipRect<LengthOrAuto>; pub type ClipRect = generics::GenericClipRect<LengthOrAuto>;
/// rect(...) | auto /// rect(...) | auto
pub type ClipRectOrAuto = Either<ClipRect, Auto>; pub type ClipRectOrAuto = generics::GenericClipRectOrAuto<ClipRect>;
/// The computed value of a grid `<track-breadth>` /// The computed value of a grid `<track-breadth>`
pub type TrackBreadth = GenericTrackBreadth<LengthPercentage>; pub type TrackBreadth = GenericTrackBreadth<LengthPercentage>;
@ -709,18 +707,3 @@ pub type GridLine = GenericGridLine<Integer>;
/// `<grid-template-rows> | <grid-template-columns>` /// `<grid-template-rows> | <grid-template-columns>`
pub type GridTemplateComponent = GenericGridTemplateComponent<LengthPercentage, Integer>; pub type GridTemplateComponent = GenericGridTemplateComponent<LengthPercentage, Integer>;
impl ClipRectOrAuto {
/// Return an auto (default for clip-rect and image-region) value
pub fn auto() -> Self {
Either::Second(Auto)
}
/// Check if it is auto
pub fn is_auto(&self) -> bool {
match *self {
Either::Second(_) => true,
_ => false,
}
}
}

View file

@ -1,7 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! Computed types for table properties.
pub use crate::values::specified::table::XSpan;

View file

@ -198,8 +198,6 @@ impl TextDecorationsInEffect {
} }
/// Computed value for the text-emphasis-style property /// Computed value for the text-emphasis-style property
///
/// cbindgen:derive-tagged-enum-copy-constructor=true
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss, ToResolvedValue)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss, ToResolvedValue)]
#[allow(missing_docs)] #[allow(missing_docs)]
#[repr(C, u8)] #[repr(C, u8)]

View file

@ -7,7 +7,7 @@
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
use crate::computed_values::list_style_type::T as ListStyleType; use crate::computed_values::list_style_type::T as ListStyleType;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use crate::values::generics::CounterStyleOrNone; use crate::values::generics::CounterStyle;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use crate::values::specified::Attr; use crate::values::specified::Attr;
use crate::values::CustomIdent; use crate::values::CustomIdent;
@ -25,12 +25,14 @@ use std::ops::Deref;
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,
)] )]
pub struct CounterPair<Integer> { #[repr(C)]
pub struct GenericCounterPair<Integer> {
/// The name of the counter. /// The name of the counter.
pub name: CustomIdent, pub name: CustomIdent,
/// The value of the counter / increment / etc. /// The value of the counter / increment / etc.
pub value: Integer, pub value: Integer,
} }
pub use self::GenericCounterPair as CounterPair;
/// A generic value for the `counter-increment` property. /// A generic value for the `counter-increment` property.
#[derive( #[derive(
@ -45,13 +47,15 @@ pub struct CounterPair<Integer> {
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,
)] )]
pub struct CounterIncrement<I>(pub Counters<I>); #[repr(transparent)]
pub struct GenericCounterIncrement<I>(pub GenericCounters<I>);
pub use self::GenericCounterIncrement as CounterIncrement;
impl<I> CounterIncrement<I> { impl<I> CounterIncrement<I> {
/// Returns a new value for `counter-increment`. /// Returns a new value for `counter-increment`.
#[inline] #[inline]
pub fn new(counters: Vec<CounterPair<I>>) -> Self { pub fn new(counters: Vec<CounterPair<I>>) -> Self {
CounterIncrement(Counters(counters.into_boxed_slice())) CounterIncrement(Counters(counters.into()))
} }
} }
@ -77,13 +81,15 @@ impl<I> Deref for CounterIncrement<I> {
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,
)] )]
pub struct CounterSetOrReset<I>(pub Counters<I>); #[repr(transparent)]
pub struct GenericCounterSetOrReset<I>(pub GenericCounters<I>);
pub use self::GenericCounterSetOrReset as CounterSetOrReset;
impl<I> CounterSetOrReset<I> { impl<I> CounterSetOrReset<I> {
/// Returns a new value for `counter-set` / `counter-reset`. /// Returns a new value for `counter-set` / `counter-reset`.
#[inline] #[inline]
pub fn new(counters: Vec<CounterPair<I>>) -> Self { pub fn new(counters: Vec<CounterPair<I>>) -> Self {
CounterSetOrReset(Counters(counters.into_boxed_slice())) CounterSetOrReset(Counters(counters.into()))
} }
} }
@ -111,23 +117,17 @@ impl<I> Deref for CounterSetOrReset<I> {
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,
)] )]
pub struct Counters<I>(#[css(iterable, if_empty = "none")] Box<[CounterPair<I>]>); #[repr(transparent)]
pub struct GenericCounters<I>(
impl<I> Counters<I> { #[css(iterable, if_empty = "none")] crate::OwnedSlice<GenericCounterPair<I>>,
/// Move out the Box into a vector. This could just return the Box<>, but );
/// Vec<> is a bit more convenient because Box<[T]> doesn't implement pub use self::GenericCounters as Counters;
/// IntoIter: https://github.com/rust-lang/rust/issues/59878
#[inline]
pub fn into_vec(self) -> Vec<CounterPair<I>> {
self.0.into_vec()
}
}
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
type CounterStyleType = ListStyleType; type CounterStyleType = ListStyleType;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
type CounterStyleType = CounterStyleOrNone; type CounterStyleType = CounterStyle;
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
#[inline] #[inline]
@ -138,7 +138,7 @@ fn is_decimal(counter_type: &CounterStyleType) -> bool {
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
#[inline] #[inline]
fn is_decimal(counter_type: &CounterStyleType) -> bool { fn is_decimal(counter_type: &CounterStyleType) -> bool {
*counter_type == CounterStyleOrNone::decimal() *counter_type == CounterStyle::decimal()
} }
/// The specified value for the `content` property. /// The specified value for the `content` property.

View file

@ -34,8 +34,6 @@ pub struct GenericBoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength> {
pub use self::GenericBoxShadow as BoxShadow; pub use self::GenericBoxShadow as BoxShadow;
/// A generic value for a single `filter`. /// A generic value for a single `filter`.
///
/// cbindgen:derive-tagged-enum-copy-constructor=true
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[animation(no_bound(U))] #[animation(no_bound(U))]
#[derive( #[derive(

View file

@ -5,14 +5,13 @@
//! Generic types for font stuff. //! Generic types for font stuff.
use crate::parser::{Parse, ParserContext}; use crate::parser::{Parse, ParserContext};
use app_units::Au;
use byteorder::{BigEndian, ReadBytesExt}; use byteorder::{BigEndian, ReadBytesExt};
use cssparser::Parser; use cssparser::Parser;
use num_traits::One; use num_traits::One;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use std::io::Cursor; use std::io::Cursor;
use style_traits::{CssWriter, KeywordsCollectFn, ParseError}; use style_traits::{CssWriter, ParseError};
use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss}; use style_traits::{StyleParseErrorKind, ToCss};
/// https://drafts.csswg.org/css-fonts-4/#feature-tag-value /// https://drafts.csswg.org/css-fonts-4/#feature-tag-value
#[derive( #[derive(
@ -172,105 +171,6 @@ impl Parse for FontTag {
} }
} }
#[derive(
Animate,
Clone,
ComputeSquaredDistance,
Copy,
Debug,
MallocSizeOf,
PartialEq,
ToAnimatedValue,
ToAnimatedZero,
ToCss,
ToShmem,
)]
/// Additional information for keyword-derived font sizes.
pub struct KeywordInfo<Length> {
/// The keyword used
pub kw: KeywordSize,
/// A factor to be multiplied by the computed size of the keyword
#[css(skip)]
pub factor: f32,
/// An additional Au offset to add to the kw*factor in the case of calcs
#[css(skip)]
pub offset: Length,
}
impl<L> KeywordInfo<L>
where
Au: Into<L>,
{
/// KeywordInfo value for font-size: medium
pub fn medium() -> Self {
KeywordSize::Medium.into()
}
}
impl<L> From<KeywordSize> for KeywordInfo<L>
where
Au: Into<L>,
{
fn from(x: KeywordSize) -> Self {
KeywordInfo {
kw: x,
factor: 1.,
offset: Au(0).into(),
}
}
}
impl<L> SpecifiedValueInfo for KeywordInfo<L> {
fn collect_completion_keywords(f: KeywordsCollectFn) {
<KeywordSize as SpecifiedValueInfo>::collect_completion_keywords(f);
}
}
/// CSS font keywords
#[derive(
Animate,
Clone,
ComputeSquaredDistance,
Copy,
Debug,
MallocSizeOf,
Parse,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToAnimatedZero,
ToCss,
ToShmem,
)]
#[allow(missing_docs)]
pub enum KeywordSize {
#[css(keyword = "xx-small")]
XXSmall,
XSmall,
Small,
Medium,
Large,
XLarge,
#[css(keyword = "xx-large")]
XXLarge,
#[css(keyword = "xxx-large")]
XXXLarge,
}
impl KeywordSize {
/// Convert to an HTML <font size> value
#[inline]
pub fn html_size(self) -> u8 {
self as u8
}
}
impl Default for KeywordSize {
fn default() -> Self {
KeywordSize::Medium
}
}
/// A generic value for the `font-style` property. /// A generic value for the `font-style` property.
/// ///
/// https://drafts.csswg.org/css-fonts-4/#font-style-prop /// https://drafts.csswg.org/css-fonts-4/#font-style-prop

View file

@ -185,8 +185,6 @@ impl Parse for GridLine<specified::Integer> {
/// avoid re-implementing it for the computed type. /// avoid re-implementing it for the computed type.
/// ///
/// <https://drafts.csswg.org/css-grid/#typedef-track-breadth> /// <https://drafts.csswg.org/css-grid/#typedef-track-breadth>
///
/// cbindgen:derive-tagged-enum-copy-constructor=true
#[derive( #[derive(
Animate, Animate,
Clone, Clone,
@ -230,8 +228,6 @@ impl<L> TrackBreadth<L> {
/// generic only to avoid code bloat. It only takes `<length-percentage>` /// generic only to avoid code bloat. It only takes `<length-percentage>`
/// ///
/// <https://drafts.csswg.org/css-grid/#typedef-track-size> /// <https://drafts.csswg.org/css-grid/#typedef-track-size>
///
/// cbindgen:derive-tagged-enum-copy-constructor=true
#[derive( #[derive(
Clone, Clone,
Debug, Debug,
@ -494,8 +490,6 @@ impl<L: ToCss, I: ToCss> ToCss for TrackRepeat<L, I> {
} }
/// Track list values. Can be <track-size> or <track-repeat> /// Track list values. Can be <track-size> or <track-repeat>
///
/// cbindgen:derive-tagged-enum-copy-constructor=true
#[derive( #[derive(
Animate, Animate,
Clone, Clone,
@ -729,8 +723,6 @@ impl ToCss for LineNameList {
} }
/// Variants for `<grid-template-rows> | <grid-template-columns>` /// Variants for `<grid-template-rows> | <grid-template-columns>`
///
/// cbindgen:derive-tagged-enum-copy-constructor=true
#[derive( #[derive(
Animate, Animate,
Clone, Clone,

View file

@ -92,13 +92,10 @@ impl SymbolsType {
/// <https://drafts.csswg.org/css-counter-styles/#typedef-counter-style> /// <https://drafts.csswg.org/css-counter-styles/#typedef-counter-style>
/// ///
/// Since wherever <counter-style> is used, 'none' is a valid value as /// Note that 'none' is not a valid name.
/// well, we combine them into one type to make code simpler.
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
#[derive(Clone, Debug, Eq, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem)] #[derive(Clone, Debug, Eq, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem)]
pub enum CounterStyleOrNone { pub enum CounterStyle {
/// `none`
None,
/// `<counter-style-name>` /// `<counter-style-name>`
Name(CustomIdent), Name(CustomIdent),
/// `symbols()` /// `symbols()`
@ -111,28 +108,25 @@ fn is_symbolic(symbols_type: &SymbolsType) -> bool {
*symbols_type == SymbolsType::Symbolic *symbols_type == SymbolsType::Symbolic
} }
impl CounterStyleOrNone { impl CounterStyle {
/// disc value /// disc value
pub fn disc() -> Self { pub fn disc() -> Self {
CounterStyleOrNone::Name(CustomIdent(atom!("disc"))) CounterStyle::Name(CustomIdent(atom!("disc")))
} }
/// decimal value /// decimal value
pub fn decimal() -> Self { pub fn decimal() -> Self {
CounterStyleOrNone::Name(CustomIdent(atom!("decimal"))) CounterStyle::Name(CustomIdent(atom!("decimal")))
} }
} }
impl Parse for CounterStyleOrNone { impl Parse for CounterStyle {
fn parse<'i, 't>( fn parse<'i, 't>(
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
if let Ok(name) = input.try(|i| parse_counter_style_name(i)) { if let Ok(name) = input.try(|i| parse_counter_style_name(i)) {
return Ok(CounterStyleOrNone::Name(name)); return Ok(CounterStyle::Name(name));
}
if input.try(|i| i.expect_ident_matching("none")).is_ok() {
return Ok(CounterStyleOrNone::None);
} }
input.expect_function_matching("symbols")?; input.expect_function_matching("symbols")?;
input.parse_nested_block(|input| { input.parse_nested_block(|input| {
@ -151,12 +145,12 @@ impl Parse for CounterStyleOrNone {
if symbols.0.iter().any(|sym| !sym.is_allowed_in_symbols()) { if symbols.0.iter().any(|sym| !sym.is_allowed_in_symbols()) {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
} }
Ok(CounterStyleOrNone::Symbols(symbols_type, symbols)) Ok(CounterStyle::Symbols(symbols_type, symbols))
}) })
} }
} }
impl SpecifiedValueInfo for CounterStyleOrNone { impl SpecifiedValueInfo for CounterStyle {
fn collect_completion_keywords(f: KeywordsCollectFn) { fn collect_completion_keywords(f: KeywordsCollectFn) {
// XXX The best approach for implementing this is probably // XXX The best approach for implementing this is probably
// having a CounterStyleName type wrapping CustomIdent, and // having a CounterStyleName type wrapping CustomIdent, and
@ -165,7 +159,7 @@ impl SpecifiedValueInfo for CounterStyleOrNone {
// approach here. // approach here.
macro_rules! predefined { macro_rules! predefined {
($($name:expr,)+) => { ($($name:expr,)+) => {
f(&["none", "symbols", $($name,)+]); f(&["symbols", $($name,)+]);
} }
} }
include!("../../counter_style/predefined.rs"); include!("../../counter_style/predefined.rs");
@ -272,9 +266,53 @@ pub struct ZeroToOne<T>(pub T);
ToShmem, ToShmem,
)] )]
#[css(function = "rect", comma)] #[css(function = "rect", comma)]
pub struct ClipRect<LengthOrAuto> { #[repr(C)]
pub struct GenericClipRect<LengthOrAuto> {
pub top: LengthOrAuto, pub top: LengthOrAuto,
pub right: LengthOrAuto, pub right: LengthOrAuto,
pub bottom: LengthOrAuto, pub bottom: LengthOrAuto,
pub left: LengthOrAuto, pub left: LengthOrAuto,
} }
pub use self::GenericClipRect as ClipRect;
/// Either a clip-rect or `auto`.
#[allow(missing_docs)]
#[derive(
Animate,
Clone,
ComputeSquaredDistance,
Copy,
Debug,
MallocSizeOf,
Parse,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToAnimatedZero,
ToComputedValue,
ToCss,
ToResolvedValue,
ToShmem,
)]
#[repr(C, u8)]
pub enum GenericClipRectOrAuto<R> {
Auto,
Rect(R),
}
pub use self::GenericClipRectOrAuto as ClipRectOrAuto;
impl<L> ClipRectOrAuto<L> {
/// Returns the `auto` value.
#[inline]
pub fn auto() -> Self {
ClipRectOrAuto::Auto
}
/// Returns whether this value is the `auto` value.
#[inline]
pub fn is_auto(&self) -> bool {
matches!(*self, ClipRectOrAuto::Auto)
}
}

View file

@ -9,7 +9,6 @@ use cssparser::Parser;
use style_traits::ParseError; use style_traits::ParseError;
/// The fallback of an SVG paint server value. /// The fallback of an SVG paint server value.
/// cbindgen:derive-tagged-enum-copy-constructor=true
#[derive( #[derive(
Animate, Animate,
Clone, Clone,
@ -43,8 +42,6 @@ pub use self::GenericSVGPaintFallback as SVGPaintFallback;
/// An SVG paint value /// An SVG paint value
/// ///
/// <https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint> /// <https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint>
///
/// cbindgen:derive-tagged-enum-copy-constructor=true
#[animation(no_bound(Url))] #[animation(no_bound(Url))]
#[derive( #[derive(
Animate, Animate,
@ -84,8 +81,6 @@ impl<C, U> Default for SVGPaint<C, U> {
/// ///
/// Whereas the spec only allows PaintServer to have a fallback, Gecko lets the /// Whereas the spec only allows PaintServer to have a fallback, Gecko lets the
/// context properties have a fallback as well. /// context properties have a fallback as well.
///
/// cbindgen:derive-tagged-enum-copy-constructor=true
#[animation(no_bound(U))] #[animation(no_bound(U))]
#[derive( #[derive(
Animate, Animate,

View file

@ -151,7 +151,6 @@ fn is_same<N: PartialEq>(x: &N, y: &N) -> bool {
)] )]
#[repr(C, u8)] #[repr(C, u8)]
/// A single operation in the list of a `transform` value /// A single operation in the list of a `transform` value
/// cbindgen:derive-tagged-enum-copy-constructor=true
pub enum GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage> pub enum GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>
where where
Angle: Zero, Angle: Zero,

View file

@ -5,8 +5,6 @@
//! Generic types for url properties. //! Generic types for url properties.
/// An image url or none, used for example in list-style-image /// An image url or none, used for example in list-style-image
///
/// cbindgen:derive-tagged-enum-copy-constructor=true
#[derive( #[derive(
Animate, Animate,
Clone, Clone,

View file

@ -105,16 +105,12 @@ pub enum DisplayInside {
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
MozGrid, MozGrid,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
MozInlineGrid,
#[cfg(feature = "gecko")]
MozGridGroup, MozGridGroup,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
MozGridLine, MozGridLine,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
MozStack, MozStack,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
MozInlineStack,
#[cfg(feature = "gecko")]
MozDeck, MozDeck,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
MozGroupbox, MozGroupbox,
@ -243,16 +239,12 @@ impl Display {
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub const MozGrid: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozGrid); pub const MozGrid: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozGrid);
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub const MozInlineGrid: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozInlineGrid);
#[cfg(feature = "gecko")]
pub const MozGridGroup: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozGridGroup); pub const MozGridGroup: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozGridGroup);
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub const MozGridLine: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozGridLine); pub const MozGridLine: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozGridLine);
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub const MozStack: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozStack); pub const MozStack: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozStack);
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub const MozInlineStack: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozInlineStack);
#[cfg(feature = "gecko")]
pub const MozDeck: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozDeck); pub const MozDeck: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozDeck);
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub const MozGroupbox: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozGroupbox); pub const MozGroupbox: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozGroupbox);
@ -422,7 +414,6 @@ impl Display {
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
DisplayOutside::XUL => match self.inside() { DisplayOutside::XUL => match self.inside() {
DisplayInside::MozBox => Display::MozInlineBox, DisplayInside::MozBox => Display::MozInlineBox,
DisplayInside::MozStack => Display::MozInlineStack,
_ => *self, _ => *self,
}, },
_ => *self, _ => *self,
@ -469,10 +460,6 @@ impl ToCss for Display {
Display::WebkitInlineBox => dest.write_str("-webkit-inline-box"), Display::WebkitInlineBox => dest.write_str("-webkit-inline-box"),
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
Display::MozInlineBox => dest.write_str("-moz-inline-box"), Display::MozInlineBox => dest.write_str("-moz-inline-box"),
#[cfg(feature = "gecko")]
Display::MozInlineGrid => dest.write_str("-moz-inline-grid"),
#[cfg(feature = "gecko")]
Display::MozInlineStack => dest.write_str("-moz-inline-stack"),
#[cfg(any(feature = "servo-layout-2013", feature = "gecko"))] #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
Display::TableCaption => dest.write_str("table-caption"), Display::TableCaption => dest.write_str("table-caption"),
_ => match (outside, inside) { _ => match (outside, inside) {
@ -662,16 +649,12 @@ impl Parse for Display {
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
"-moz-grid" if moz_display_values_enabled(context) => Display::MozGrid, "-moz-grid" if moz_display_values_enabled(context) => Display::MozGrid,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
"-moz-inline-grid" if moz_display_values_enabled(context) => Display::MozInlineGrid,
#[cfg(feature = "gecko")]
"-moz-grid-group" if moz_display_values_enabled(context) => Display::MozGridGroup, "-moz-grid-group" if moz_display_values_enabled(context) => Display::MozGridGroup,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
"-moz-grid-line" if moz_display_values_enabled(context) => Display::MozGridLine, "-moz-grid-line" if moz_display_values_enabled(context) => Display::MozGridLine,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
"-moz-stack" if moz_display_values_enabled(context) => Display::MozStack, "-moz-stack" if moz_display_values_enabled(context) => Display::MozStack,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
"-moz-inline-stack" if moz_display_values_enabled(context) => Display::MozInlineStack,
#[cfg(feature = "gecko")]
"-moz-deck" if moz_display_values_enabled(context) => Display::MozDeck, "-moz-deck" if moz_display_values_enabled(context) => Display::MozDeck,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
"-moz-groupbox" if moz_display_values_enabled(context) => Display::MozGroupbox, "-moz-groupbox" if moz_display_values_enabled(context) => Display::MozGroupbox,
@ -688,6 +671,7 @@ impl SpecifiedValueInfo for Display {
"contents", "contents",
"flex", "flex",
"flow-root", "flow-root",
"flow-root list-item",
"grid", "grid",
"inline", "inline",
"inline-block", "inline-block",

View file

@ -8,11 +8,11 @@
use crate::computed_values::list_style_type::T as ListStyleType; use crate::computed_values::list_style_type::T as ListStyleType;
use crate::parser::{Parse, ParserContext}; use crate::parser::{Parse, ParserContext};
use crate::values::generics::counters as generics; use crate::values::generics::counters as generics;
use crate::values::generics::counters::CounterIncrement as GenericCounterIncrement;
use crate::values::generics::counters::CounterPair; use crate::values::generics::counters::CounterPair;
use crate::values::generics::counters::CounterSetOrReset as GenericCounterSetOrReset; use crate::values::generics::counters::GenericCounterIncrement;
use crate::values::generics::counters::GenericCounterSetOrReset;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use crate::values::generics::CounterStyleOrNone; use crate::values::generics::CounterStyle;
use crate::values::specified::url::SpecifiedImageUrl; use crate::values::specified::url::SpecifiedImageUrl;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use crate::values::specified::Attr; use crate::values::specified::Attr;
@ -98,13 +98,13 @@ impl Content {
} }
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
fn parse_counter_style(context: &ParserContext, input: &mut Parser) -> CounterStyleOrNone { fn parse_counter_style(context: &ParserContext, input: &mut Parser) -> CounterStyle {
input input
.try(|input| { .try(|input| {
input.expect_comma()?; input.expect_comma()?;
CounterStyleOrNone::parse(context, input) CounterStyle::parse(context, input)
}) })
.unwrap_or(CounterStyleOrNone::decimal()) .unwrap_or(CounterStyle::decimal())
} }
} }

View file

@ -11,9 +11,9 @@ use crate::properties::longhands::system_font::SystemFont;
use crate::values::computed::font::{FamilyName, FontFamilyList, FontStyleAngle, SingleFontFamily}; use crate::values::computed::font::{FamilyName, FontFamilyList, FontStyleAngle, SingleFontFamily};
use crate::values::computed::{font as computed, Length, NonNegativeLength}; use crate::values::computed::{font as computed, Length, NonNegativeLength};
use crate::values::computed::{Angle as ComputedAngle, Percentage as ComputedPercentage}; use crate::values::computed::{Angle as ComputedAngle, Percentage as ComputedPercentage};
use crate::values::computed::{Context, ToComputedValue}; use crate::values::computed::{CSSPixelLength, Context, ToComputedValue};
use crate::values::generics::font::VariationValue;
use crate::values::generics::font::{self as generics, FeatureTagValue, FontSettings, FontTag}; use crate::values::generics::font::{self as generics, FeatureTagValue, FontSettings, FontTag};
use crate::values::generics::font::{KeywordSize, VariationValue};
use crate::values::generics::NonNegative; use crate::values::generics::NonNegative;
use crate::values::specified::length::{FontBaseSize, AU_PER_PT, AU_PER_PX}; use crate::values::specified::length::{FontBaseSize, AU_PER_PT, AU_PER_PX};
use crate::values::specified::{AllowQuirks, Angle, Integer, LengthPercentage}; use crate::values::specified::{AllowQuirks, Angle, Integer, LengthPercentage};
@ -481,6 +481,115 @@ impl ToComputedValue for FontStretch {
} }
} }
/// CSS font keywords
#[derive(
Animate,
Clone,
ComputeSquaredDistance,
Copy,
Debug,
MallocSizeOf,
Parse,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToAnimatedZero,
ToCss,
ToShmem,
)]
#[allow(missing_docs)]
pub enum KeywordSize {
#[css(keyword = "xx-small")]
XXSmall,
XSmall,
Small,
Medium,
Large,
XLarge,
#[css(keyword = "xx-large")]
XXLarge,
#[css(keyword = "xxx-large")]
XXXLarge,
}
impl KeywordSize {
/// Convert to an HTML <font size> value
#[inline]
pub fn html_size(self) -> u8 {
self as u8
}
}
impl Default for KeywordSize {
fn default() -> Self {
KeywordSize::Medium
}
}
#[derive(
Animate,
Clone,
ComputeSquaredDistance,
Copy,
Debug,
MallocSizeOf,
PartialEq,
ToAnimatedValue,
ToAnimatedZero,
ToCss,
ToShmem,
)]
/// Additional information for keyword-derived font sizes.
pub struct KeywordInfo {
/// The keyword used
pub kw: KeywordSize,
/// A factor to be multiplied by the computed size of the keyword
#[css(skip)]
pub factor: f32,
/// An additional fixed offset to add to the kw * factor in the case of
/// `calc()`.
#[css(skip)]
pub offset: CSSPixelLength,
}
impl KeywordInfo {
/// KeywordInfo value for font-size: medium
pub fn medium() -> Self {
Self::new(KeywordSize::Medium)
}
fn new(kw: KeywordSize) -> Self {
KeywordInfo {
kw,
factor: 1.,
offset: CSSPixelLength::new(0.),
}
}
/// Computes the final size for this font-size keyword, accounting for
/// text-zoom.
fn to_computed_value(&self, context: &Context) -> CSSPixelLength {
let base = context.maybe_zoom_text(self.kw.to_computed_value(context).0);
base * self.factor + context.maybe_zoom_text(self.offset)
}
/// Given a parent keyword info (self), apply an additional factor/offset to
/// it.
pub fn compose(self, factor: f32, offset: CSSPixelLength) -> Self {
KeywordInfo {
kw: self.kw,
factor: self.factor * factor,
offset: self.offset * factor + offset,
}
}
}
impl SpecifiedValueInfo for KeywordInfo {
fn collect_completion_keywords(f: KeywordsCollectFn) {
<KeywordSize as SpecifiedValueInfo>::collect_completion_keywords(f);
}
}
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
/// A specified font-size value /// A specified font-size value
pub enum FontSize { pub enum FontSize {
@ -652,27 +761,6 @@ impl ToComputedValue for FontSizeAdjust {
} }
} }
/// Additional information for specified keyword-derived font sizes.
pub type KeywordInfo = generics::KeywordInfo<NonNegativeLength>;
impl KeywordInfo {
/// Computes the final size for this font-size keyword, accounting for
/// text-zoom.
pub fn to_computed_value(&self, context: &Context) -> NonNegativeLength {
let base = context.maybe_zoom_text(self.kw.to_computed_value(context));
base.scale_by(self.factor) + context.maybe_zoom_text(self.offset)
}
/// Given a parent keyword info (self), apply an additional factor/offset to it
pub fn compose(self, factor: f32, offset: NonNegativeLength) -> Self {
KeywordInfo {
kw: self.kw,
factor: self.factor * factor,
offset: self.offset.scale_by(factor) + offset,
}
}
}
/// This is the ratio applied for font-size: larger /// This is the ratio applied for font-size: larger
/// and smaller by both Firefox and Chrome /// and smaller by both Firefox and Chrome
const LARGER_FONT_SIZE_RATIO: f32 = 1.2; const LARGER_FONT_SIZE_RATIO: f32 = 1.2;
@ -789,20 +877,17 @@ impl ToComputedValue for KeywordSize {
impl FontSize { impl FontSize {
/// <https://html.spec.whatwg.org/multipage/#rules-for-parsing-a-legacy-font-size> /// <https://html.spec.whatwg.org/multipage/#rules-for-parsing-a-legacy-font-size>
pub fn from_html_size(size: u8) -> Self { pub fn from_html_size(size: u8) -> Self {
FontSize::Keyword( FontSize::Keyword(KeywordInfo::new(match size {
match size { // If value is less than 1, let it be 1.
// If value is less than 1, let it be 1. 0 | 1 => KeywordSize::XSmall,
0 | 1 => KeywordSize::XSmall, 2 => KeywordSize::Small,
2 => KeywordSize::Small, 3 => KeywordSize::Medium,
3 => KeywordSize::Medium, 4 => KeywordSize::Large,
4 => KeywordSize::Large, 5 => KeywordSize::XLarge,
5 => KeywordSize::XLarge, 6 => KeywordSize::XXLarge,
6 => KeywordSize::XXLarge, // If value is greater than 7, let it be 7.
// If value is greater than 7, let it be 7. _ => KeywordSize::XXXLarge,
_ => KeywordSize::XXXLarge, }))
}
.into(),
)
} }
/// Compute it against a given base font size /// Compute it against a given base font size
@ -819,7 +904,7 @@ impl FontSize {
.get_parent_font() .get_parent_font()
.clone_font_size() .clone_font_size()
.keyword_info .keyword_info
.map(|i| i.compose(factor, Au(0).into())) .map(|i| i.compose(factor, CSSPixelLength::new(0.)))
}; };
let mut info = None; let mut info = None;
let size = match *self { let size = match *self {
@ -829,17 +914,15 @@ impl FontSize {
// Tack the em unit onto the factor // Tack the em unit onto the factor
info = compose_keyword(em); info = compose_keyword(em);
} }
value.to_computed_value(context, base_size).into() value.to_computed_value(context, base_size)
}, },
FontSize::Length(LengthPercentage::Length(NoCalcLength::ServoCharacterWidth( FontSize::Length(LengthPercentage::Length(NoCalcLength::ServoCharacterWidth(
value, value,
))) => value.to_computed_value(base_size.resolve(context)).into(), ))) => value.to_computed_value(base_size.resolve(context)),
FontSize::Length(LengthPercentage::Length(NoCalcLength::Absolute(ref l))) => { FontSize::Length(LengthPercentage::Length(NoCalcLength::Absolute(ref l))) => {
context.maybe_zoom_text(l.to_computed_value(context).into()) context.maybe_zoom_text(l.to_computed_value(context))
},
FontSize::Length(LengthPercentage::Length(ref l)) => {
l.to_computed_value(context).into()
}, },
FontSize::Length(LengthPercentage::Length(ref l)) => l.to_computed_value(context),
FontSize::Length(LengthPercentage::Percentage(pc)) => { FontSize::Length(LengthPercentage::Percentage(pc)) => {
// If the parent font was keyword-derived, this is too. // If the parent font was keyword-derived, this is too.
// Tack the % onto the factor // Tack the % onto the factor
@ -871,29 +954,32 @@ impl FontSize {
context, context,
FontBaseSize::InheritedStyleButStripEmUnits, FontBaseSize::InheritedStyleButStripEmUnits,
) )
.length_component(); .unclamped_length();
info = parent.keyword_info.map(|i| i.compose(ratio, abs.into())); info = parent.keyword_info.map(|i| i.compose(ratio, abs));
} }
let calc = calc.to_computed_value_zoomed(context, base_size); let calc = calc.to_computed_value_zoomed(context, base_size);
calc.to_used_value(base_size.resolve(context)).into() // FIXME(emilio): we _could_ use clamp_to_non_negative()
// everywhere, without affecting behavior in theory, since the
// others should reject negatives during parsing. But SMIL
// allows parsing negatives, and relies on us _not_ doing that
// clamping. That's so bonkers :(
CSSPixelLength::from(calc.to_used_value(base_size.resolve(context)))
.clamp_to_non_negative()
}, },
FontSize::Keyword(i) => { FontSize::Keyword(i) => {
// As a specified keyword, this is keyword derived // As a specified keyword, this is keyword derived
info = Some(i); info = Some(i);
i.to_computed_value(context) i.to_computed_value(context).clamp_to_non_negative()
}, },
FontSize::Smaller => { FontSize::Smaller => {
info = compose_keyword(1. / LARGER_FONT_SIZE_RATIO); info = compose_keyword(1. / LARGER_FONT_SIZE_RATIO);
FontRelativeLength::Em(1. / LARGER_FONT_SIZE_RATIO) FontRelativeLength::Em(1. / LARGER_FONT_SIZE_RATIO)
.to_computed_value(context, base_size) .to_computed_value(context, base_size)
.into()
}, },
FontSize::Larger => { FontSize::Larger => {
info = compose_keyword(LARGER_FONT_SIZE_RATIO); info = compose_keyword(LARGER_FONT_SIZE_RATIO);
FontRelativeLength::Em(LARGER_FONT_SIZE_RATIO) FontRelativeLength::Em(LARGER_FONT_SIZE_RATIO).to_computed_value(context, base_size)
.to_computed_value(context, base_size)
.into()
}, },
FontSize::System(_) => { FontSize::System(_) => {
@ -903,12 +989,18 @@ impl FontSize {
} }
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
{ {
context.cached_system_font.as_ref().unwrap().font_size.size context
.cached_system_font
.as_ref()
.unwrap()
.font_size
.size
.0
} }
}, },
}; };
computed::FontSize { computed::FontSize {
size: size, size: NonNegative(size),
keyword_info: info, keyword_info: info,
} }
} }
@ -952,7 +1044,7 @@ impl FontSize {
} }
if let Ok(kw) = input.try(KeywordSize::parse) { if let Ok(kw) = input.try(KeywordSize::parse) {
return Ok(FontSize::Keyword(kw.into())); return Ok(FontSize::Keyword(KeywordInfo::new(kw)));
} }
try_match_ident_ignore_ascii_case! { input, try_match_ident_ignore_ascii_case! { input,
@ -998,6 +1090,7 @@ bitflags! {
#[derive( #[derive(
Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToResolvedValue, ToShmem, Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToResolvedValue, ToShmem,
)] )]
#[repr(C, u8)]
/// Set of variant alternates /// Set of variant alternates
pub enum VariantAlternates { pub enum VariantAlternates {
/// Enables display of stylistic alternates /// Enables display of stylistic alternates
@ -1005,10 +1098,10 @@ pub enum VariantAlternates {
Stylistic(CustomIdent), Stylistic(CustomIdent),
/// Enables display with stylistic sets /// Enables display with stylistic sets
#[css(comma, function)] #[css(comma, function)]
Styleset(#[css(iterable)] Box<[CustomIdent]>), Styleset(#[css(iterable)] crate::OwnedSlice<CustomIdent>),
/// Enables display of specific character variants /// Enables display of specific character variants
#[css(comma, function)] #[css(comma, function)]
CharacterVariant(#[css(iterable)] Box<[CustomIdent]>), CharacterVariant(#[css(iterable)] crate::OwnedSlice<CustomIdent>),
/// Enables display of swash glyphs /// Enables display of swash glyphs
#[css(function)] #[css(function)]
Swash(CustomIdent), Swash(CustomIdent),
@ -1023,11 +1116,20 @@ pub enum VariantAlternates {
} }
#[derive( #[derive(
Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToResolvedValue, ToShmem, Clone,
Debug,
Default,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToCss,
ToResolvedValue,
ToShmem,
)] )]
#[repr(transparent)]
/// List of Variant Alternates /// List of Variant Alternates
pub struct VariantAlternatesList( pub struct VariantAlternatesList(
#[css(if_empty = "normal", iterable)] pub Box<[VariantAlternates]>, #[css(if_empty = "normal", iterable)] crate::OwnedSlice<VariantAlternates>,
); );
impl VariantAlternatesList { impl VariantAlternatesList {
@ -1059,7 +1161,7 @@ impl FontVariantAlternates {
#[inline] #[inline]
/// Get initial specified value with VariantAlternatesList /// Get initial specified value with VariantAlternatesList
pub fn get_initial_specified_value() -> Self { pub fn get_initial_specified_value() -> Self {
FontVariantAlternates::Value(VariantAlternatesList(vec![].into_boxed_slice())) FontVariantAlternates::Value(Default::default())
} }
system_font_methods!(FontVariantAlternates, font_variant_alternates); system_font_methods!(FontVariantAlternates, font_variant_alternates);
@ -1093,16 +1195,14 @@ impl Parse for FontVariantAlternates {
_: &ParserContext, _: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<FontVariantAlternates, ParseError<'i>> { ) -> Result<FontVariantAlternates, ParseError<'i>> {
let mut alternates = Vec::new();
if input if input
.try(|input| input.expect_ident_matching("normal")) .try(|input| input.expect_ident_matching("normal"))
.is_ok() .is_ok()
{ {
return Ok(FontVariantAlternates::Value(VariantAlternatesList( return Ok(FontVariantAlternates::Value(Default::default()));
alternates.into_boxed_slice(),
)));
} }
let mut alternates = Vec::new();
let mut parsed_alternates = VariantAlternatesParsingFlags::empty(); let mut parsed_alternates = VariantAlternatesParsingFlags::empty();
macro_rules! check_if_parsed( macro_rules! check_if_parsed(
($input:expr, $flag:path) => ( ($input:expr, $flag:path) => (
@ -1156,7 +1256,7 @@ impl Parse for FontVariantAlternates {
let location = i.current_source_location(); let location = i.current_source_location();
CustomIdent::from_ident(location, i.expect_ident()?, &[]) CustomIdent::from_ident(location, i.expect_ident()?, &[])
})?; })?;
alternates.push(VariantAlternates::Styleset(idents.into_boxed_slice())); alternates.push(VariantAlternates::Styleset(idents.into()));
Ok(()) Ok(())
}, },
"character-variant" => { "character-variant" => {
@ -1165,7 +1265,7 @@ impl Parse for FontVariantAlternates {
let location = i.current_source_location(); let location = i.current_source_location();
CustomIdent::from_ident(location, i.expect_ident()?, &[]) CustomIdent::from_ident(location, i.expect_ident()?, &[])
})?; })?;
alternates.push(VariantAlternates::CharacterVariant(idents.into_boxed_slice())); alternates.push(VariantAlternates::CharacterVariant(idents.into()));
Ok(()) Ok(())
}, },
_ => return Err(i.new_custom_error(StyleParseErrorKind::UnspecifiedError)), _ => return Err(i.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
@ -1179,7 +1279,7 @@ impl Parse for FontVariantAlternates {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
} }
Ok(FontVariantAlternates::Value(VariantAlternatesList( Ok(FontVariantAlternates::Value(VariantAlternatesList(
alternates.into_boxed_slice(), alternates.into(),
))) )))
} }
} }

View file

@ -6,7 +6,7 @@
use crate::parser::{Parse, ParserContext}; use crate::parser::{Parse, ParserContext};
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use crate::values::generics::CounterStyleOrNone; use crate::values::generics::CounterStyle;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use crate::values::CustomIdent; use crate::values::CustomIdent;
use cssparser::{Parser, Token}; use cssparser::{Parser, Token};
@ -27,8 +27,10 @@ use style_traits::{ParseError, StyleParseErrorKind};
ToShmem, ToShmem,
)] )]
pub enum ListStyleType { pub enum ListStyleType {
/// <counter-style> | none /// `none`
CounterStyle(CounterStyleOrNone), None,
/// <counter-style>
CounterStyle(CounterStyle),
/// <string> /// <string>
String(String), String(String),
} }
@ -38,7 +40,7 @@ impl ListStyleType {
/// Initial specified value for `list-style-type`. /// Initial specified value for `list-style-type`.
#[inline] #[inline]
pub fn disc() -> Self { pub fn disc() -> Self {
ListStyleType::CounterStyle(CounterStyleOrNone::disc()) ListStyleType::CounterStyle(CounterStyle::disc())
} }
/// Convert from gecko keyword to list-style-type. /// Convert from gecko keyword to list-style-type.
@ -50,10 +52,10 @@ impl ListStyleType {
use crate::gecko_bindings::structs; use crate::gecko_bindings::structs;
if value == structs::NS_STYLE_LIST_STYLE_NONE { if value == structs::NS_STYLE_LIST_STYLE_NONE {
return ListStyleType::CounterStyle(CounterStyleOrNone::None); return ListStyleType::None;
} }
ListStyleType::CounterStyle(CounterStyleOrNone::Name(CustomIdent(match value { ListStyleType::CounterStyle(CounterStyle::Name(CustomIdent(match value {
structs::NS_STYLE_LIST_STYLE_DISC => atom!("disc"), structs::NS_STYLE_LIST_STYLE_DISC => atom!("disc"),
structs::NS_STYLE_LIST_STYLE_CIRCLE => atom!("circle"), structs::NS_STYLE_LIST_STYLE_CIRCLE => atom!("circle"),
structs::NS_STYLE_LIST_STYLE_SQUARE => atom!("square"), structs::NS_STYLE_LIST_STYLE_SQUARE => atom!("square"),
@ -73,10 +75,12 @@ impl Parse for ListStyleType {
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
if let Ok(style) = input.try(|i| CounterStyleOrNone::parse(context, i)) { if let Ok(style) = input.try(|i| CounterStyle::parse(context, i)) {
return Ok(ListStyleType::CounterStyle(style)); return Ok(ListStyleType::CounterStyle(style));
} }
if input.try(|i| i.expect_ident_matching("none")).is_ok() {
return Ok(ListStyleType::None);
}
Ok(ListStyleType::String( Ok(ListStyleType::String(
input.expect_string()?.as_ref().to_owned(), input.expect_string()?.as_ref().to_owned(),
)) ))
@ -126,8 +130,6 @@ pub struct QuoteList(
/// Specified and computed `quotes` property: `auto`, `none`, or a list /// Specified and computed `quotes` property: `auto`, `none`, or a list
/// of characters. /// of characters.
///
/// cbindgen:derive-tagged-enum-copy-constructor=true
#[derive( #[derive(
Clone, Clone,
Debug, Debug,

View file

@ -13,7 +13,7 @@ use super::generics::grid::{GridLine as GenericGridLine, TrackBreadth as Generic
use super::generics::grid::{TrackList as GenericTrackList, TrackSize as GenericTrackSize}; use super::generics::grid::{TrackList as GenericTrackList, TrackSize as GenericTrackSize};
use super::generics::transform::IsParallelTo; use super::generics::transform::IsParallelTo;
use super::generics::{self, GreaterThanOrEqualToOne, NonNegative}; use super::generics::{self, GreaterThanOrEqualToOne, NonNegative};
use super::{Auto, CSSFloat, CSSInteger, Either, None_}; use super::{CSSFloat, CSSInteger, Either, None_};
use crate::context::QuirksMode; use crate::context::QuirksMode;
use crate::parser::{Parse, ParserContext}; use crate::parser::{Parse, ParserContext};
use crate::values::serialize_atom_identifier; use crate::values::serialize_atom_identifier;
@ -78,7 +78,6 @@ pub use self::svg::MozContextProperties;
pub use self::svg::{SVGLength, SVGOpacity, SVGPaint}; pub use self::svg::{SVGLength, SVGOpacity, SVGPaint};
pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth}; pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
pub use self::svg_path::SVGPathData; pub use self::svg_path::SVGPathData;
pub use self::table::XSpan;
pub use self::text::{InitialLetter, LetterSpacing, LineBreak, LineHeight, TextAlign}; pub use self::text::{InitialLetter, LetterSpacing, LineBreak, LineHeight, TextAlign};
pub use self::text::{OverflowWrap, TextEmphasisPosition, TextEmphasisStyle, WordBreak}; pub use self::text::{OverflowWrap, TextEmphasisPosition, TextEmphasisStyle, WordBreak};
pub use self::text::{TextAlignKeyword, TextDecorationLine, TextOverflow, WordSpacing}; pub use self::text::{TextAlignKeyword, TextDecorationLine, TextOverflow, WordSpacing};
@ -122,7 +121,6 @@ pub mod resolution;
pub mod source_size_list; pub mod source_size_list;
pub mod svg; pub mod svg;
pub mod svg_path; pub mod svg_path;
pub mod table;
pub mod text; pub mod text;
pub mod time; pub mod time;
pub mod transform; pub mod transform;
@ -641,7 +639,7 @@ pub type GridLine = GenericGridLine<Integer>;
pub type GridTemplateComponent = GenericGridTemplateComponent<LengthPercentage, Integer>; pub type GridTemplateComponent = GenericGridTemplateComponent<LengthPercentage, Integer>;
/// rect(...) /// rect(...)
pub type ClipRect = generics::ClipRect<LengthOrAuto>; pub type ClipRect = generics::GenericClipRect<LengthOrAuto>;
impl Parse for ClipRect { impl Parse for ClipRect {
fn parse<'i, 't>( fn parse<'i, 't>(
@ -654,7 +652,7 @@ impl Parse for ClipRect {
impl ClipRect { impl ClipRect {
/// Parses a rect(<top>, <left>, <bottom>, <right>), allowing quirks. /// Parses a rect(<top>, <left>, <bottom>, <right>), allowing quirks.
pub fn parse_quirky<'i, 't>( fn parse_quirky<'i, 't>(
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks, allow_quirks: AllowQuirks,
@ -698,7 +696,7 @@ impl ClipRect {
} }
/// rect(...) | auto /// rect(...) | auto
pub type ClipRectOrAuto = Either<ClipRect, Auto>; pub type ClipRectOrAuto = generics::GenericClipRectOrAuto<ClipRect>;
impl ClipRectOrAuto { impl ClipRectOrAuto {
/// Parses a ClipRect or Auto, allowing quirks. /// Parses a ClipRect or Auto, allowing quirks.
@ -708,10 +706,10 @@ impl ClipRectOrAuto {
allow_quirks: AllowQuirks, allow_quirks: AllowQuirks,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
if let Ok(v) = input.try(|i| ClipRect::parse_quirky(context, i, allow_quirks)) { if let Ok(v) = input.try(|i| ClipRect::parse_quirky(context, i, allow_quirks)) {
Ok(Either::First(v)) return Ok(generics::GenericClipRectOrAuto::Rect(v));
} else {
Auto::parse(context, input).map(Either::Second)
} }
input.expect_ident_matching("auto")?;
Ok(generics::GenericClipRectOrAuto::Auto)
} }
} }

View file

@ -15,7 +15,6 @@ use style_traits::{ParseError, StyleParseErrorKind};
/// The offset-path value. /// The offset-path value.
/// ///
/// https://drafts.fxtf.org/motion-1/#offset-path-property /// https://drafts.fxtf.org/motion-1/#offset-path-property
/// cbindgen:derive-tagged-enum-copy-constructor=true
#[derive( #[derive(
Animate, Animate,
Clone, Clone,

View file

@ -707,8 +707,6 @@ fn is_name_code_point(c: char) -> bool {
/// The syntax of this property also provides a visualization of the structure /// The syntax of this property also provides a visualization of the structure
/// of the grid, making the overall layout of the grid container easier to /// of the grid, making the overall layout of the grid container easier to
/// understand. /// understand.
///
/// cbindgen:derive-tagged-enum-copy-constructor=true
#[repr(C, u8)] #[repr(C, u8)]
#[derive( #[derive(
Clone, Clone,

View file

@ -106,13 +106,13 @@ pub enum PaintOrder {
} }
/// Number of non-normal components /// Number of non-normal components
const PAINT_ORDER_COUNT: u8 = 3; pub const PAINT_ORDER_COUNT: u8 = 3;
/// Number of bits for each component /// Number of bits for each component
const PAINT_ORDER_SHIFT: u8 = 2; pub const PAINT_ORDER_SHIFT: u8 = 2;
/// Mask with above bits set /// Mask with above bits set
const PAINT_ORDER_MASK: u8 = 0b11; pub const PAINT_ORDER_MASK: u8 = 0b11;
/// The specified value is tree `PaintOrder` values packed into the /// The specified value is tree `PaintOrder` values packed into the
/// bitfields below, as a six-bit field, of 3 two-bit pairs /// bitfields below, as a six-bit field, of 3 two-bit pairs
@ -135,6 +135,7 @@ const PAINT_ORDER_MASK: u8 = 0b11;
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,
)] )]
#[repr(transparent)]
pub struct SVGPaintOrder(pub u8); pub struct SVGPaintOrder(pub u8);
impl SVGPaintOrder { impl SVGPaintOrder {
@ -146,7 +147,7 @@ impl SVGPaintOrder {
/// Get variant of `paint-order` /// Get variant of `paint-order`
pub fn order_at(&self, pos: u8) -> PaintOrder { pub fn order_at(&self, pos: u8) -> PaintOrder {
// Safe because PaintOrder covers all possible patterns. // Safe because PaintOrder covers all possible patterns.
unsafe { ::std::mem::transmute((self.0 >> pos * PAINT_ORDER_SHIFT) & PAINT_ORDER_MASK) } unsafe { std::mem::transmute((self.0 >> pos * PAINT_ORDER_SHIFT) & PAINT_ORDER_MASK) }
} }
} }

View file

@ -1,34 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! Specified types for table properties.
use crate::parser::{Parse, ParserContext};
use cssparser::Parser;
use style_traits::{ParseError, StyleParseErrorKind};
#[derive(
Clone,
Copy,
Debug,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToComputedValue,
ToCss,
ToResolvedValue,
ToShmem,
)]
/// span. for `<col span>` pres attr
pub struct XSpan(#[css(skip)] pub i32);
impl Parse for XSpan {
// never parse it, only set via presentation attribute
fn parse<'i, 't>(
_: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<XSpan, ParseError<'i>> {
Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
}
}

View file

@ -89,9 +89,7 @@ impl ToComputedValue for LineHeight {
GenericLineHeight::Length(ref non_negative_lp) => { GenericLineHeight::Length(ref non_negative_lp) => {
let result = match non_negative_lp.0 { let result = match non_negative_lp.0 {
LengthPercentage::Length(NoCalcLength::Absolute(ref abs)) => { LengthPercentage::Length(NoCalcLength::Absolute(ref abs)) => {
context context.maybe_zoom_text(abs.to_computed_value(context))
.maybe_zoom_text(abs.to_computed_value(context).into())
.0
}, },
LengthPercentage::Length(ref length) => length.to_computed_value(context), LengthPercentage::Length(ref length) => length.to_computed_value(context),
LengthPercentage::Percentage(ref p) => FontRelativeLength::Em(p.0) LengthPercentage::Percentage(ref p) => FontRelativeLength::Em(p.0)
@ -133,7 +131,6 @@ impl ToComputedValue for LineHeight {
} }
/// A generic value for the `text-overflow` property. /// A generic value for the `text-overflow` property.
/// cbindgen:derive-tagged-enum-copy-constructor=true
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
#[repr(C, u8)] #[repr(C, u8)]
pub enum TextOverflowSide { pub enum TextOverflowSide {