mirror of
https://github.com/servo/servo.git
synced 2025-08-04 21:20:23 +01:00
Auto merge of #29748 - Loirooriol:sync, r=mrobinson
Backport several style changes from Gecko <!-- Please describe your changes on the following line: --> --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [ ] These changes fix #___ (GitHub issue number if applicable) <!-- Either: --> - [X] There are tests for these changes OR - [ ] These changes do not require tests because ___ <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
This commit is contained in:
commit
2426a38a4d
101 changed files with 2063 additions and 1553 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -6177,6 +6177,7 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"malloc_size_of",
|
"malloc_size_of",
|
||||||
"malloc_size_of_derive",
|
"malloc_size_of_derive",
|
||||||
|
"mime",
|
||||||
"new_debug_unreachable",
|
"new_debug_unreachable",
|
||||||
"num-derive",
|
"num-derive",
|
||||||
"num-integer",
|
"num-integer",
|
||||||
|
|
|
@ -272,8 +272,8 @@ impl<'a, 'b> ResolveGeneratedContentFragmentMutator<'a, 'b> {
|
||||||
self.traversal.quote -= 1
|
self.traversal.quote -= 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
GeneratedContentInfo::ContentItem(ContentItem::Url(..)) => {
|
GeneratedContentInfo::ContentItem(ContentItem::Image(..)) => {
|
||||||
unreachable!("Servo doesn't parse content: url(..) yet")
|
unreachable!("Servo doesn't parse content: url(..) nor image-set(..) yet")
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -354,9 +354,9 @@ where
|
||||||
attr_val.map_or("".to_string(), |s| s.to_string()),
|
attr_val.map_or("".to_string(), |s| s.to_string()),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
ContentItem::Url(image_url) => {
|
ContentItem::Image(image) => {
|
||||||
if let Some(replaced_content) =
|
if let Some(replaced_content) =
|
||||||
ReplacedContent::from_image_url(element, context, image_url)
|
ReplacedContent::from_image(element, context, image)
|
||||||
{
|
{
|
||||||
vec.push(PseudoElementContentItem::Replaced(replaced_content));
|
vec.push(PseudoElementContentItem::Replaced(replaced_content));
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ use std::fmt;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use style::properties::ComputedValues;
|
use style::properties::ComputedValues;
|
||||||
use style::servo::url::ComputedUrl;
|
use style::servo::url::ComputedUrl;
|
||||||
|
use style::values::computed::image::Image as ComputedImage;
|
||||||
use style::values::computed::{Length, LengthOrAuto};
|
use style::values::computed::{Length, LengthOrAuto};
|
||||||
use style::values::CSSFloat;
|
use style::values::CSSFloat;
|
||||||
use style::Zero;
|
use style::Zero;
|
||||||
|
@ -184,6 +185,17 @@ impl ReplacedContent {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_image<'dom>(
|
||||||
|
element: impl NodeExt<'dom>,
|
||||||
|
context: &LayoutContext,
|
||||||
|
image: &ComputedImage,
|
||||||
|
) -> Option<Self> {
|
||||||
|
match image {
|
||||||
|
ComputedImage::Url(image_url) => Self::from_image_url(element, context, image_url),
|
||||||
|
_ => None, // TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn flow_relative_intrinsic_size(&self, style: &ComputedValues) -> Vec2<Option<Length>> {
|
fn flow_relative_intrinsic_size(&self, style: &ComputedValues) -> Vec2<Option<Length>> {
|
||||||
let intrinsic_size = PhysicalSize::new(self.intrinsic.width, self.intrinsic.height);
|
let intrinsic_size = PhysicalSize::new(self.intrinsic.width, self.intrinsic.height);
|
||||||
Vec2::from_physical_size(&intrinsic_size, style.writing_mode)
|
Vec2::from_physical_size(&intrinsic_size, style.writing_mode)
|
||||||
|
|
|
@ -96,7 +96,7 @@ use std::time::Duration;
|
||||||
use style::animation::{AnimationSetKey, DocumentAnimationSet, ElementAnimationSet};
|
use style::animation::{AnimationSetKey, DocumentAnimationSet, ElementAnimationSet};
|
||||||
use style::context::SharedStyleContext;
|
use style::context::SharedStyleContext;
|
||||||
use style::context::{QuirksMode, RegisteredSpeculativePainter, RegisteredSpeculativePainters};
|
use style::context::{QuirksMode, RegisteredSpeculativePainter, RegisteredSpeculativePainters};
|
||||||
use style::dom::{ShowSubtree, ShowSubtreeDataAndPrimaryValues, TDocument, TElement, TNode};
|
use style::dom::{ShowSubtree, ShowSubtreeDataAndPrimaryValues, TElement, TNode};
|
||||||
use style::driver;
|
use style::driver;
|
||||||
use style::error_reporting::RustLogReporter;
|
use style::error_reporting::RustLogReporter;
|
||||||
use style::global_style_data::{GLOBAL_STYLE_DATA, STYLE_THREAD_POOL};
|
use style::global_style_data::{GLOBAL_STYLE_DATA, STYLE_THREAD_POOL};
|
||||||
|
@ -1285,11 +1285,7 @@ impl LayoutThread {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Flush shadow roots stylesheets if dirty.
|
// Flush shadow roots stylesheets if dirty.
|
||||||
document.flush_shadow_roots_stylesheets(
|
document.flush_shadow_roots_stylesheets(&mut self.stylist, guards.author.clone());
|
||||||
&self.stylist.device(),
|
|
||||||
document.quirks_mode(),
|
|
||||||
guards.author.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let restyles = std::mem::take(&mut data.pending_restyles);
|
let restyles = std::mem::take(&mut data.pending_restyles);
|
||||||
debug!("Draining restyles: {}", restyles.len());
|
debug!("Draining restyles: {}", restyles.len());
|
||||||
|
|
|
@ -82,7 +82,7 @@ use style::animation::DocumentAnimationSet;
|
||||||
use style::context::{
|
use style::context::{
|
||||||
QuirksMode, RegisteredSpeculativePainter, RegisteredSpeculativePainters, SharedStyleContext,
|
QuirksMode, RegisteredSpeculativePainter, RegisteredSpeculativePainters, SharedStyleContext,
|
||||||
};
|
};
|
||||||
use style::dom::{TDocument, TElement, TNode};
|
use style::dom::{TElement, TNode};
|
||||||
use style::driver;
|
use style::driver;
|
||||||
use style::error_reporting::RustLogReporter;
|
use style::error_reporting::RustLogReporter;
|
||||||
use style::global_style_data::{GLOBAL_STYLE_DATA, STYLE_THREAD_POOL};
|
use style::global_style_data::{GLOBAL_STYLE_DATA, STYLE_THREAD_POOL};
|
||||||
|
@ -943,11 +943,7 @@ impl LayoutThread {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush shadow roots stylesheets if dirty.
|
// Flush shadow roots stylesheets if dirty.
|
||||||
document.flush_shadow_roots_stylesheets(
|
document.flush_shadow_roots_stylesheets(&mut self.stylist, guards.author.clone());
|
||||||
&self.stylist.device(),
|
|
||||||
document.quirks_mode(),
|
|
||||||
guards.author.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let restyles = std::mem::take(&mut data.pending_restyles);
|
let restyles = std::mem::take(&mut data.pending_restyles);
|
||||||
debug!("Draining restyles: {}", restyles.len());
|
debug!("Draining restyles: {}", restyles.len());
|
||||||
|
|
|
@ -461,6 +461,8 @@ impl GroupedClassifier {
|
||||||
fn image_classifer() -> GroupedClassifier {
|
fn image_classifer() -> GroupedClassifier {
|
||||||
GroupedClassifier {
|
GroupedClassifier {
|
||||||
byte_matchers: vec![
|
byte_matchers: vec![
|
||||||
|
// Keep this in sync with 'is_supported_mime_type' from
|
||||||
|
// components/style/servo/media_queries.rs
|
||||||
Box::new(ByteMatcher::image_x_icon()),
|
Box::new(ByteMatcher::image_x_icon()),
|
||||||
Box::new(ByteMatcher::image_x_icon_cursor()),
|
Box::new(ByteMatcher::image_x_icon_cursor()),
|
||||||
Box::new(ByteMatcher::image_bmp()),
|
Box::new(ByteMatcher::image_bmp()),
|
||||||
|
|
|
@ -20,11 +20,10 @@ use servo_arc::Arc;
|
||||||
use servo_atoms::Atom;
|
use servo_atoms::Atom;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use style::context::QuirksMode;
|
|
||||||
use style::invalidation::media_queries::{MediaListKey, ToMediaListKey};
|
use style::invalidation::media_queries::{MediaListKey, ToMediaListKey};
|
||||||
use style::media_queries::MediaList;
|
use style::media_queries::MediaList;
|
||||||
use style::shared_lock::{SharedRwLock as StyleSharedRwLock, SharedRwLockReadGuard};
|
use style::shared_lock::{SharedRwLock as StyleSharedRwLock, SharedRwLockReadGuard};
|
||||||
use style::stylesheets::{CssRule, Origin, Stylesheet};
|
use style::stylesheets::{Stylesheet, StylesheetContents};
|
||||||
|
|
||||||
#[derive(Clone, JSTraceable, MallocSizeOf)]
|
#[derive(Clone, JSTraceable, MallocSizeOf)]
|
||||||
#[unrooted_must_root_lint::must_root]
|
#[unrooted_must_root_lint::must_root]
|
||||||
|
@ -48,19 +47,11 @@ impl PartialEq for StyleSheetInDocument {
|
||||||
|
|
||||||
impl ToMediaListKey for StyleSheetInDocument {
|
impl ToMediaListKey for StyleSheetInDocument {
|
||||||
fn to_media_list_key(&self) -> MediaListKey {
|
fn to_media_list_key(&self) -> MediaListKey {
|
||||||
self.sheet.to_media_list_key()
|
self.sheet.contents.to_media_list_key()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::style::stylesheets::StylesheetInDocument for StyleSheetInDocument {
|
impl ::style::stylesheets::StylesheetInDocument for StyleSheetInDocument {
|
||||||
fn origin(&self, guard: &SharedRwLockReadGuard) -> Origin {
|
|
||||||
self.sheet.origin(guard)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn quirks_mode(&self, guard: &SharedRwLockReadGuard) -> QuirksMode {
|
|
||||||
self.sheet.quirks_mode(guard)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn enabled(&self) -> bool {
|
fn enabled(&self) -> bool {
|
||||||
self.sheet.enabled()
|
self.sheet.enabled()
|
||||||
}
|
}
|
||||||
|
@ -69,8 +60,8 @@ impl ::style::stylesheets::StylesheetInDocument for StyleSheetInDocument {
|
||||||
self.sheet.media(guard)
|
self.sheet.media(guard)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule] {
|
fn contents(&self) -> &StylesheetContents {
|
||||||
self.sheet.rules(guard)
|
self.sheet.contents()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3525,11 +3525,11 @@ impl Element {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_write_state(&self) -> bool {
|
pub fn read_write_state(&self) -> bool {
|
||||||
self.state.get().contains(ElementState::IN_READ_WRITE_STATE)
|
self.state.get().contains(ElementState::IN_READWRITE_STATE)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_read_write_state(&self, value: bool) {
|
pub fn set_read_write_state(&self, value: bool) {
|
||||||
self.set_state(ElementState::IN_READ_WRITE_STATE, value)
|
self.set_state(ElementState::IN_READWRITE_STATE, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn placeholder_shown_state(&self) -> bool {
|
pub fn placeholder_shown_state(&self) -> bool {
|
||||||
|
|
|
@ -297,7 +297,7 @@ impl HTMLInputElement {
|
||||||
.clone();
|
.clone();
|
||||||
HTMLInputElement {
|
HTMLInputElement {
|
||||||
htmlelement: HTMLElement::new_inherited_with_state(
|
htmlelement: HTMLElement::new_inherited_with_state(
|
||||||
ElementState::IN_ENABLED_STATE | ElementState::IN_READ_WRITE_STATE,
|
ElementState::IN_ENABLED_STATE | ElementState::IN_READWRITE_STATE,
|
||||||
local_name,
|
local_name,
|
||||||
prefix,
|
prefix,
|
||||||
document,
|
document,
|
||||||
|
|
|
@ -148,7 +148,7 @@ impl HTMLTextAreaElement {
|
||||||
.clone();
|
.clone();
|
||||||
HTMLTextAreaElement {
|
HTMLTextAreaElement {
|
||||||
htmlelement: HTMLElement::new_inherited_with_state(
|
htmlelement: HTMLElement::new_inherited_with_state(
|
||||||
ElementState::IN_ENABLED_STATE | ElementState::IN_READ_WRITE_STATE,
|
ElementState::IN_ENABLED_STATE | ElementState::IN_READWRITE_STATE,
|
||||||
local_name,
|
local_name,
|
||||||
prefix,
|
prefix,
|
||||||
document,
|
document,
|
||||||
|
|
|
@ -19,15 +19,13 @@ use crate::dom::stylesheetlist::{StyleSheetList, StyleSheetListOwner};
|
||||||
use crate::dom::window::Window;
|
use crate::dom::window::Window;
|
||||||
use crate::stylesheet_set::StylesheetSetRef;
|
use crate::stylesheet_set::StylesheetSetRef;
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
use selectors::context::QuirksMode;
|
|
||||||
use servo_arc::Arc;
|
use servo_arc::Arc;
|
||||||
use servo_atoms::Atom;
|
use servo_atoms::Atom;
|
||||||
use style::author_styles::AuthorStyles;
|
use style::author_styles::AuthorStyles;
|
||||||
use style::dom::TElement;
|
use style::dom::TElement;
|
||||||
use style::media_queries::Device;
|
|
||||||
use style::shared_lock::SharedRwLockReadGuard;
|
use style::shared_lock::SharedRwLockReadGuard;
|
||||||
use style::stylesheets::Stylesheet;
|
use style::stylesheets::Stylesheet;
|
||||||
use style::stylist::CascadeData;
|
use style::stylist::{CascadeData, Stylist};
|
||||||
|
|
||||||
/// Whether a shadow root hosts an User Agent widget.
|
/// Whether a shadow root hosts an User Agent widget.
|
||||||
#[derive(JSTraceable, MallocSizeOf, PartialEq)]
|
#[derive(JSTraceable, MallocSizeOf, PartialEq)]
|
||||||
|
@ -245,8 +243,7 @@ pub trait LayoutShadowRootHelpers<'dom> {
|
||||||
fn get_style_data_for_layout(self) -> &'dom CascadeData;
|
fn get_style_data_for_layout(self) -> &'dom CascadeData;
|
||||||
unsafe fn flush_stylesheets<E: TElement>(
|
unsafe fn flush_stylesheets<E: TElement>(
|
||||||
self,
|
self,
|
||||||
device: &Device,
|
stylist: &mut Stylist,
|
||||||
quirks_mode: QuirksMode,
|
|
||||||
guard: &SharedRwLockReadGuard,
|
guard: &SharedRwLockReadGuard,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -277,13 +274,12 @@ impl<'dom> LayoutShadowRootHelpers<'dom> for LayoutDom<'dom, ShadowRoot> {
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
unsafe fn flush_stylesheets<E: TElement>(
|
unsafe fn flush_stylesheets<E: TElement>(
|
||||||
self,
|
self,
|
||||||
device: &Device,
|
stylist: &mut Stylist,
|
||||||
quirks_mode: QuirksMode,
|
|
||||||
guard: &SharedRwLockReadGuard,
|
guard: &SharedRwLockReadGuard,
|
||||||
) {
|
) {
|
||||||
let author_styles = self.unsafe_get().author_styles.borrow_mut_for_layout();
|
let author_styles = self.unsafe_get().author_styles.borrow_mut_for_layout();
|
||||||
if author_styles.stylesheets.dirty() {
|
if author_styles.stylesheets.dirty() {
|
||||||
author_styles.flush::<E>(device, quirks_mode, guard);
|
author_styles.flush::<E>(stylist, guard);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,10 @@ use script_layout_interface::wrapper_traits::LayoutDataTrait;
|
||||||
use selectors::matching::QuirksMode;
|
use selectors::matching::QuirksMode;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use style::dom::{TDocument, TNode};
|
use style::dom::{TDocument, TNode};
|
||||||
use style::media_queries::Device;
|
|
||||||
use style::shared_lock::{
|
use style::shared_lock::{
|
||||||
SharedRwLock as StyleSharedRwLock, SharedRwLockReadGuard as StyleSharedRwLockReadGuard,
|
SharedRwLock as StyleSharedRwLock, SharedRwLockReadGuard as StyleSharedRwLockReadGuard,
|
||||||
};
|
};
|
||||||
|
use style::stylist::Stylist;
|
||||||
|
|
||||||
// A wrapper around documents that ensures ayout can only ever access safe properties.
|
// A wrapper around documents that ensures ayout can only ever access safe properties.
|
||||||
pub struct ServoLayoutDocument<'dom, LayoutDataType: LayoutDataTrait> {
|
pub struct ServoLayoutDocument<'dom, LayoutDataType: LayoutDataTrait> {
|
||||||
|
@ -90,8 +90,7 @@ impl<'ld, LayoutDataType: LayoutDataTrait> ServoLayoutDocument<'ld, LayoutDataTy
|
||||||
|
|
||||||
pub fn flush_shadow_roots_stylesheets(
|
pub fn flush_shadow_roots_stylesheets(
|
||||||
&self,
|
&self,
|
||||||
device: &Device,
|
stylist: &mut Stylist,
|
||||||
quirks_mode: QuirksMode,
|
|
||||||
guard: &StyleSharedRwLockReadGuard,
|
guard: &StyleSharedRwLockReadGuard,
|
||||||
) {
|
) {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -100,7 +99,7 @@ impl<'ld, LayoutDataType: LayoutDataTrait> ServoLayoutDocument<'ld, LayoutDataTy
|
||||||
}
|
}
|
||||||
self.document.flush_shadow_roots_stylesheets();
|
self.document.flush_shadow_roots_stylesheets();
|
||||||
for shadow_root in self.shadow_roots() {
|
for shadow_root in self.shadow_roots() {
|
||||||
shadow_root.flush_stylesheets(device, quirks_mode, guard);
|
shadow_root.flush_stylesheets(stylist, guard);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,11 @@ use crate::dom::shadowroot::{LayoutShadowRootHelpers, ShadowRoot};
|
||||||
use crate::layout_dom::ServoLayoutElement;
|
use crate::layout_dom::ServoLayoutElement;
|
||||||
use crate::layout_dom::ServoLayoutNode;
|
use crate::layout_dom::ServoLayoutNode;
|
||||||
use script_layout_interface::wrapper_traits::LayoutDataTrait;
|
use script_layout_interface::wrapper_traits::LayoutDataTrait;
|
||||||
use selectors::matching::QuirksMode;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use style::dom::TShadowRoot;
|
use style::dom::TShadowRoot;
|
||||||
use style::media_queries::Device;
|
|
||||||
use style::shared_lock::SharedRwLockReadGuard as StyleSharedRwLockReadGuard;
|
use style::shared_lock::SharedRwLockReadGuard as StyleSharedRwLockReadGuard;
|
||||||
use style::stylist::CascadeData;
|
use style::stylist::{CascadeData, Stylist};
|
||||||
|
|
||||||
pub struct ServoShadowRoot<'dom, LayoutDataType: LayoutDataTrait> {
|
pub struct ServoShadowRoot<'dom, LayoutDataType: LayoutDataTrait> {
|
||||||
/// The wrapped private DOM ShadowRoot.
|
/// The wrapped private DOM ShadowRoot.
|
||||||
|
@ -74,11 +72,10 @@ impl<'dom, LayoutDataType: LayoutDataTrait> ServoShadowRoot<'dom, LayoutDataType
|
||||||
|
|
||||||
pub unsafe fn flush_stylesheets(
|
pub unsafe fn flush_stylesheets(
|
||||||
&self,
|
&self,
|
||||||
device: &Device,
|
stylist: &mut Stylist,
|
||||||
quirks_mode: QuirksMode,
|
|
||||||
guard: &StyleSharedRwLockReadGuard,
|
guard: &StyleSharedRwLockReadGuard,
|
||||||
) {
|
) {
|
||||||
self.shadow_root
|
self.shadow_root
|
||||||
.flush_stylesheets::<ServoLayoutElement<LayoutDataType>>(device, quirks_mode, guard)
|
.flush_stylesheets::<ServoLayoutElement<LayoutDataType>>(stylist, guard)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -212,6 +212,12 @@ macro_rules! with_all_bounds {
|
||||||
|
|
||||||
/// pseudo-elements
|
/// pseudo-elements
|
||||||
type PseudoElement: $($CommonBounds)* + PseudoElement<Impl = Self>;
|
type PseudoElement: $($CommonBounds)* + PseudoElement<Impl = Self>;
|
||||||
|
|
||||||
|
/// Whether attribute hashes should be collected for filtering
|
||||||
|
/// purposes.
|
||||||
|
fn should_collect_attr_hash(_name: &Self::LocalName) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -482,6 +488,34 @@ where
|
||||||
Component::Class(ref class) if quirks_mode != QuirksMode::Quirks => {
|
Component::Class(ref class) if quirks_mode != QuirksMode::Quirks => {
|
||||||
class.precomputed_hash()
|
class.precomputed_hash()
|
||||||
},
|
},
|
||||||
|
Component::AttributeInNoNamespace { ref local_name, .. }
|
||||||
|
if Impl::should_collect_attr_hash(local_name) =>
|
||||||
|
{
|
||||||
|
// AttributeInNoNamespace is only used when local_name ==
|
||||||
|
// local_name_lower.
|
||||||
|
local_name.precomputed_hash()
|
||||||
|
},
|
||||||
|
Component::AttributeInNoNamespaceExists {
|
||||||
|
ref local_name,
|
||||||
|
ref local_name_lower,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
// Only insert the local-name into the filter if it's all
|
||||||
|
// lowercase. Otherwise we would need to test both hashes, and
|
||||||
|
// our data structures aren't really set up for that.
|
||||||
|
if local_name != local_name_lower || !Impl::should_collect_attr_hash(local_name) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
local_name.precomputed_hash()
|
||||||
|
},
|
||||||
|
Component::AttributeOther(ref selector) => {
|
||||||
|
if selector.local_name != selector.local_name_lower ||
|
||||||
|
!Impl::should_collect_attr_hash(&selector.local_name)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
selector.local_name.precomputed_hash()
|
||||||
|
},
|
||||||
Component::Is(ref list) | Component::Where(ref list) => {
|
Component::Is(ref list) | Component::Where(ref list) => {
|
||||||
// :where and :is OR their selectors, so we can't put any hash
|
// :where and :is OR their selectors, so we can't put any hash
|
||||||
// in the filter if there's more than one selector, as that'd
|
// in the filter if there's more than one selector, as that'd
|
||||||
|
@ -825,7 +859,7 @@ impl<'a, Impl: 'a + SelectorImpl> SelectorIter<'a, Impl> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn is_featureless_host_selector(&mut self) -> bool {
|
pub(crate) fn is_featureless_host_selector(&mut self) -> bool {
|
||||||
self.selector_length() > 0 &&
|
self.selector_length() > 0 &&
|
||||||
self.all(|component| matches!(*component, Component::Host(..))) &&
|
self.all(|component| component.is_host()) &&
|
||||||
self.next_sequence().is_none()
|
self.next_sequence().is_none()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1089,10 +1123,17 @@ pub enum Component<Impl: SelectorImpl> {
|
||||||
|
|
||||||
impl<Impl: SelectorImpl> Component<Impl> {
|
impl<Impl: SelectorImpl> Component<Impl> {
|
||||||
/// Returns true if this is a combinator.
|
/// Returns true if this is a combinator.
|
||||||
|
#[inline]
|
||||||
pub fn is_combinator(&self) -> bool {
|
pub fn is_combinator(&self) -> bool {
|
||||||
matches!(*self, Component::Combinator(_))
|
matches!(*self, Component::Combinator(_))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if this is a :host() selector.
|
||||||
|
#[inline]
|
||||||
|
pub fn is_host(&self) -> bool {
|
||||||
|
matches!(*self, Component::Host(..))
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the value as a combinator if applicable, None otherwise.
|
/// Returns the value as a combinator if applicable, None otherwise.
|
||||||
pub fn as_combinator(&self) -> Option<Combinator> {
|
pub fn as_combinator(&self) -> Option<Combinator> {
|
||||||
match *self {
|
match *self {
|
||||||
|
|
|
@ -50,6 +50,7 @@ lazy_static = "1"
|
||||||
log = { version = "0.4", features = ["std"] }
|
log = { version = "0.4", features = ["std"] }
|
||||||
malloc_size_of = { path = "../malloc_size_of" }
|
malloc_size_of = { path = "../malloc_size_of" }
|
||||||
malloc_size_of_derive = "0.1"
|
malloc_size_of_derive = "0.1"
|
||||||
|
mime = "0.3.13"
|
||||||
new_debug_unreachable = "1.0"
|
new_debug_unreachable = "1.0"
|
||||||
num-derive = "0.3"
|
num-derive = "0.3"
|
||||||
num-integer = "0.1"
|
num-integer = "0.1"
|
||||||
|
|
|
@ -5,16 +5,16 @@
|
||||||
//! A set of author stylesheets and their computed representation, such as the
|
//! A set of author stylesheets and their computed representation, such as the
|
||||||
//! ones used for ShadowRoot.
|
//! ones used for ShadowRoot.
|
||||||
|
|
||||||
use crate::context::QuirksMode;
|
|
||||||
use crate::dom::TElement;
|
use crate::dom::TElement;
|
||||||
#[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::invalidation::media_queries::ToMediaListKey;
|
use crate::invalidation::media_queries::ToMediaListKey;
|
||||||
use crate::media_queries::Device;
|
|
||||||
use crate::shared_lock::SharedRwLockReadGuard;
|
use crate::shared_lock::SharedRwLockReadGuard;
|
||||||
|
use crate::stylist::Stylist;
|
||||||
use crate::stylesheet_set::AuthorStylesheetSet;
|
use crate::stylesheet_set::AuthorStylesheetSet;
|
||||||
use crate::stylesheets::StylesheetInDocument;
|
use crate::stylesheets::StylesheetInDocument;
|
||||||
use crate::stylist::CascadeData;
|
use crate::stylist::CascadeData;
|
||||||
|
use servo_arc::Arc;
|
||||||
|
|
||||||
/// A set of author stylesheets and their computed representation, such as the
|
/// A set of author stylesheets and their computed representation, such as the
|
||||||
/// ones used for ShadowRoot.
|
/// ones used for ShadowRoot.
|
||||||
|
@ -27,7 +27,14 @@ where
|
||||||
/// and all that stuff.
|
/// and all that stuff.
|
||||||
pub stylesheets: AuthorStylesheetSet<S>,
|
pub stylesheets: AuthorStylesheetSet<S>,
|
||||||
/// The actual cascade data computed from the stylesheets.
|
/// The actual cascade data computed from the stylesheets.
|
||||||
pub data: CascadeData,
|
#[ignore_malloc_size_of = "Measured as part of the stylist"]
|
||||||
|
pub data: Arc<CascadeData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref EMPTY_CASCADE_DATA: Arc<CascadeData> = {
|
||||||
|
Arc::new_leaked(CascadeData::new())
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> AuthorStyles<S>
|
impl<S> AuthorStyles<S>
|
||||||
|
@ -39,7 +46,7 @@ where
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
stylesheets: AuthorStylesheetSet::new(),
|
stylesheets: AuthorStylesheetSet::new(),
|
||||||
data: CascadeData::new(),
|
data: EMPTY_CASCADE_DATA.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,8 +57,7 @@ where
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn flush<E>(
|
pub fn flush<E>(
|
||||||
&mut self,
|
&mut self,
|
||||||
device: &Device,
|
stylist: &mut Stylist,
|
||||||
quirks_mode: QuirksMode,
|
|
||||||
guard: &SharedRwLockReadGuard,
|
guard: &SharedRwLockReadGuard,
|
||||||
) where
|
) where
|
||||||
E: TElement,
|
E: TElement,
|
||||||
|
@ -61,10 +67,10 @@ where
|
||||||
.stylesheets
|
.stylesheets
|
||||||
.flush::<E>(/* host = */ None, /* snapshot_map = */ None);
|
.flush::<E>(/* host = */ None, /* snapshot_map = */ None);
|
||||||
|
|
||||||
// Ignore OOM.
|
let result = stylist.rebuild_author_data(&self.data, flusher.sheets, guard);
|
||||||
let _ = self
|
if let Ok(Some(new_data)) = result {
|
||||||
.data
|
self.data = new_data;
|
||||||
.rebuild(device, quirks_mode, flusher.sheets, guard);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -102,6 +102,16 @@ impl<E: TElement> PushedElement<E> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns whether the attribute name is excluded from the bloom filter.
|
||||||
|
///
|
||||||
|
/// We do this for attributes that are very common but not commonly used in
|
||||||
|
/// selectors.
|
||||||
|
#[inline]
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
pub fn is_attr_name_excluded_from_filter(atom: &crate::Atom) -> bool {
|
||||||
|
*atom == atom!("class") || *atom == atom!("id") || *atom == atom!("style")
|
||||||
|
}
|
||||||
|
|
||||||
fn each_relevant_element_hash<E, F>(element: E, mut f: F)
|
fn each_relevant_element_hash<E, F>(element: E, mut f: F)
|
||||||
where
|
where
|
||||||
E: TElement,
|
E: TElement,
|
||||||
|
@ -115,6 +125,15 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
element.each_class(|class| f(class.get_hash()));
|
element.each_class(|class| f(class.get_hash()));
|
||||||
|
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
if static_prefs::pref!("layout.css.bloom-filter-attribute-names.enabled") {
|
||||||
|
element.each_attr_name(|name| {
|
||||||
|
if !is_attr_name_excluded_from_filter(name) {
|
||||||
|
f(name.get_hash())
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: TElement> Drop for StyleBloom<E> {
|
impl<E: TElement> Drop for StyleBloom<E> {
|
||||||
|
|
|
@ -116,21 +116,6 @@ impl Default for StyleSystemOptions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StyleSystemOptions {
|
|
||||||
#[cfg(feature = "servo")]
|
|
||||||
/// On Gecko's nightly build?
|
|
||||||
pub fn is_nightly(&self) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
/// On Gecko's nightly build?
|
|
||||||
#[inline]
|
|
||||||
pub fn is_nightly(&self) -> bool {
|
|
||||||
structs::GECKO_IS_NIGHTLY
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A shared style context.
|
/// A shared style context.
|
||||||
///
|
///
|
||||||
/// There's exactly one of these during a given restyle traversal, and it's
|
/// There's exactly one of these during a given restyle traversal, and it's
|
||||||
|
|
|
@ -519,6 +519,12 @@ pub trait TElement:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Internal iterator for the attribute names of this element.
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
fn each_attr_name<F>(&self, callback: F)
|
||||||
|
where
|
||||||
|
F: FnMut(&AtomIdent);
|
||||||
|
|
||||||
/// Internal iterator for the part names that this element exports for a
|
/// Internal iterator for the part names that this element exports for a
|
||||||
/// given part name.
|
/// given part name.
|
||||||
fn each_exported_part<F>(&self, _name: &AtomIdent, _callback: F)
|
fn each_exported_part<F>(&self, _name: &AtomIdent, _callback: F)
|
||||||
|
|
|
@ -54,86 +54,79 @@ bitflags! {
|
||||||
/// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-broken
|
/// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-broken
|
||||||
const IN_BROKEN_STATE = 1 << 14;
|
const IN_BROKEN_STATE = 1 << 14;
|
||||||
/// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-loading
|
/// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-loading
|
||||||
const IN_LOADING_STATE = 1 << 17;
|
const IN_LOADING_STATE = 1 << 15;
|
||||||
/// <https://html.spec.whatwg.org/multipage/#selector-required>
|
/// <https://html.spec.whatwg.org/multipage/#selector-required>
|
||||||
const IN_REQUIRED_STATE = 1 << 21;
|
const IN_REQUIRED_STATE = 1 << 16;
|
||||||
/// <https://html.spec.whatwg.org/multipage/#selector-optional>
|
/// <https://html.spec.whatwg.org/multipage/#selector-optional>
|
||||||
const IN_OPTIONAL_STATE = 1 << 22;
|
const IN_OPTIONAL_STATE = 1 << 17;
|
||||||
/// <https://html.spec.whatwg.org/multipage/#selector-read-write>
|
|
||||||
const IN_READ_WRITE_STATE = 1 << 22;
|
|
||||||
/// <https://html.spec.whatwg.org/multipage/#selector-defined>
|
/// <https://html.spec.whatwg.org/multipage/#selector-defined>
|
||||||
const IN_DEFINED_STATE = 1 << 23;
|
const IN_DEFINED_STATE = 1 << 18;
|
||||||
/// <https://html.spec.whatwg.org/multipage/#selector-visited>
|
/// <https://html.spec.whatwg.org/multipage/#selector-visited>
|
||||||
const IN_VISITED_STATE = 1 << 24;
|
const IN_VISITED_STATE = 1 << 19;
|
||||||
/// <https://html.spec.whatwg.org/multipage/#selector-link>
|
/// <https://html.spec.whatwg.org/multipage/#selector-link>
|
||||||
const IN_UNVISITED_STATE = 1 << 25;
|
const IN_UNVISITED_STATE = 1 << 20;
|
||||||
/// <https://drafts.csswg.org/selectors-4/#the-any-link-pseudo>
|
/// <https://drafts.csswg.org/selectors-4/#the-any-link-pseudo>
|
||||||
const IN_VISITED_OR_UNVISITED_STATE = ElementState::IN_VISITED_STATE.bits |
|
const IN_VISITED_OR_UNVISITED_STATE = ElementState::IN_VISITED_STATE.bits |
|
||||||
ElementState::IN_UNVISITED_STATE.bits;
|
ElementState::IN_UNVISITED_STATE.bits;
|
||||||
/// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-drag-over
|
/// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-drag-over
|
||||||
const IN_DRAGOVER_STATE = 1 << 26;
|
const IN_DRAGOVER_STATE = 1 << 21;
|
||||||
/// <https://html.spec.whatwg.org/multipage/#selector-in-range>
|
/// <https://html.spec.whatwg.org/multipage/#selector-in-range>
|
||||||
const IN_INRANGE_STATE = 1 << 27;
|
const IN_INRANGE_STATE = 1 << 22;
|
||||||
/// <https://html.spec.whatwg.org/multipage/#selector-out-of-range>
|
/// <https://html.spec.whatwg.org/multipage/#selector-out-of-range>
|
||||||
const IN_OUTOFRANGE_STATE = 1 << 28;
|
const IN_OUTOFRANGE_STATE = 1 << 23;
|
||||||
/// <https://html.spec.whatwg.org/multipage/#selector-read-only>
|
/// <https://html.spec.whatwg.org/multipage/#selector-read-only>
|
||||||
const IN_READONLY_STATE = 1 << 29;
|
const IN_READONLY_STATE = 1 << 24;
|
||||||
/// <https://html.spec.whatwg.org/multipage/#selector-read-write>
|
/// <https://html.spec.whatwg.org/multipage/#selector-read-write>
|
||||||
const IN_READWRITE_STATE = 1 << 30;
|
const IN_READWRITE_STATE = 1 << 25;
|
||||||
/// <https://html.spec.whatwg.org/multipage/#selector-default>
|
/// <https://html.spec.whatwg.org/multipage/#selector-default>
|
||||||
const IN_DEFAULT_STATE = 1 << 31;
|
const IN_DEFAULT_STATE = 1 << 26;
|
||||||
/// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-submit-invalid
|
/// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-submit-invalid
|
||||||
const IN_MOZ_SUBMITINVALID_STATE = 1 << 32;
|
const IN_MOZ_SUBMITINVALID_STATE = 1 << 27;
|
||||||
/// Non-standard & undocumented.
|
/// Non-standard & undocumented.
|
||||||
const IN_OPTIMUM_STATE = 1 << 33;
|
const IN_OPTIMUM_STATE = 1 << 28;
|
||||||
/// Non-standard & undocumented.
|
/// Non-standard & undocumented.
|
||||||
const IN_SUB_OPTIMUM_STATE = 1 << 34;
|
const IN_SUB_OPTIMUM_STATE = 1 << 29;
|
||||||
/// Non-standard & undocumented.
|
/// Non-standard & undocumented.
|
||||||
const IN_SUB_SUB_OPTIMUM_STATE = 1 << 35;
|
const IN_SUB_SUB_OPTIMUM_STATE = 1 << 30;
|
||||||
/// Non-standard & undocumented.
|
/// Non-standard & undocumented.
|
||||||
const IN_DEVTOOLS_HIGHLIGHTED_STATE = 1 << 36;
|
const IN_INCREMENT_SCRIPT_LEVEL_STATE = 1 << 31;
|
||||||
/// Non-standard & undocumented.
|
/// <https://drafts.csswg.org/selectors-4/#the-focus-visible-pseudo>
|
||||||
const IN_STYLEEDITOR_TRANSITIONING_STATE = 1 << 37;
|
const IN_FOCUSRING_STATE = 1 << 32;
|
||||||
/// Non-standard & undocumented.
|
|
||||||
const IN_INCREMENT_SCRIPT_LEVEL_STATE = 1 << 38;
|
|
||||||
/// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-focusring
|
|
||||||
///
|
|
||||||
/// But also https://drafts.csswg.org/selectors-4/#the-focus-visible-pseudo
|
|
||||||
const IN_FOCUSRING_STATE = 1 << 39;
|
|
||||||
/// <https://drafts.csswg.org/selectors-4/#the-focus-within-pseudo>
|
/// <https://drafts.csswg.org/selectors-4/#the-focus-within-pseudo>
|
||||||
const IN_FOCUS_WITHIN_STATE = 1 << 43;
|
const IN_FOCUS_WITHIN_STATE = 1 << 33;
|
||||||
/// :dir matching; the states are used for dynamic change detection.
|
/// :dir matching; the states are used for dynamic change detection.
|
||||||
/// State that elements that match :dir(ltr) are in.
|
/// State that elements that match :dir(ltr) are in.
|
||||||
const IN_LTR_STATE = 1 << 44;
|
const IN_LTR_STATE = 1 << 34;
|
||||||
/// State that elements that match :dir(rtl) are in.
|
/// State that elements that match :dir(rtl) are in.
|
||||||
const IN_RTL_STATE = 1 << 45;
|
const IN_RTL_STATE = 1 << 35;
|
||||||
/// State that HTML elements that have a "dir" attr are in.
|
/// State that HTML elements that have a "dir" attr are in.
|
||||||
const IN_HAS_DIR_ATTR_STATE = 1 << 46;
|
const IN_HAS_DIR_ATTR_STATE = 1 << 36;
|
||||||
/// State that HTML elements with dir="ltr" (or something
|
/// State that HTML elements with dir="ltr" (or something
|
||||||
/// case-insensitively equal to "ltr") are in.
|
/// case-insensitively equal to "ltr") are in.
|
||||||
const IN_HAS_DIR_ATTR_LTR_STATE = 1 << 47;
|
const IN_HAS_DIR_ATTR_LTR_STATE = 1 << 37;
|
||||||
/// State that HTML elements with dir="rtl" (or something
|
/// State that HTML elements with dir="rtl" (or something
|
||||||
/// case-insensitively equal to "rtl") are in.
|
/// case-insensitively equal to "rtl") are in.
|
||||||
const IN_HAS_DIR_ATTR_RTL_STATE = 1 << 48;
|
const IN_HAS_DIR_ATTR_RTL_STATE = 1 << 38;
|
||||||
/// State that HTML <bdi> elements without a valid-valued "dir" attr or
|
/// State that HTML <bdi> elements without a valid-valued "dir" attr or
|
||||||
/// any HTML elements (including <bdi>) with dir="auto" (or something
|
/// any HTML elements (including <bdi>) with dir="auto" (or something
|
||||||
/// case-insensitively equal to "auto") are in.
|
/// case-insensitively equal to "auto") are in.
|
||||||
const IN_HAS_DIR_ATTR_LIKE_AUTO_STATE = 1 << 49;
|
const IN_HAS_DIR_ATTR_LIKE_AUTO_STATE = 1 << 39;
|
||||||
/// Non-standard & undocumented.
|
/// Non-standard & undocumented.
|
||||||
const IN_AUTOFILL_STATE = 1 << 50;
|
const IN_AUTOFILL_STATE = 1 << 40;
|
||||||
/// Non-standard & undocumented.
|
/// Non-standard & undocumented.
|
||||||
const IN_AUTOFILL_PREVIEW_STATE = 1 << 51;
|
const IN_AUTOFILL_PREVIEW_STATE = 1 << 41;
|
||||||
/// State that dialog element is modal, for centered alignment
|
/// State that dialog element is modal, for centered alignment
|
||||||
///
|
/// <https://html.spec.whatwg.org/multipage/#centered-alignment>
|
||||||
/// https://html.spec.whatwg.org/multipage/#centered-alignment
|
const IN_MODAL_DIALOG_STATE = 1 << 42;
|
||||||
const IN_MODAL_DIALOG_STATE = 1 << 53;
|
/// <https://html.spec.whatwg.org/multipage/#inert-subtrees>
|
||||||
|
const IN_MOZINERT_STATE = 1 << 43;
|
||||||
/// https://html.spec.whatwg.org/multipage/#inert-subtrees
|
|
||||||
const IN_MOZINERT_STATE = 1 << 54;
|
|
||||||
/// State for the topmost dialog element in top layer
|
/// State for the topmost dialog element in top layer
|
||||||
const IN_TOPMOST_MODAL_DIALOG_STATE = 1 << 55;
|
const IN_TOPMOST_MODAL_DIALOG_STATE = 1 << 44;
|
||||||
/// Non-standard & undocumented.
|
/// Initially used for the devtools highlighter, but now somehow only
|
||||||
const IN_HANDLER_NOPLUGINS = 1 << 56;
|
/// used for the devtools accessibility inspector.
|
||||||
|
const IN_DEVTOOLS_HIGHLIGHTED_STATE = 1 << 45;
|
||||||
|
/// Used for the devtools style editor. Probably should go away.
|
||||||
|
const IN_STYLEEDITOR_TRANSITIONING_STATE = 1 << 46;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,8 @@ pub enum ContextualParseError<'a> {
|
||||||
InvalidMediaRule(&'a str, ParseError<'a>),
|
InvalidMediaRule(&'a str, ParseError<'a>),
|
||||||
/// A value was not recognized.
|
/// A value was not recognized.
|
||||||
UnsupportedValue(&'a str, ParseError<'a>),
|
UnsupportedValue(&'a str, ParseError<'a>),
|
||||||
|
/// A never-matching `:host` selector was found.
|
||||||
|
NeverMatchingHostSelector(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> fmt::Display for ContextualParseError<'a> {
|
impl<'a> fmt::Display for ContextualParseError<'a> {
|
||||||
|
@ -210,6 +212,9 @@ impl<'a> fmt::Display for ContextualParseError<'a> {
|
||||||
parse_error_to_str(err, f)
|
parse_error_to_str(err, f)
|
||||||
},
|
},
|
||||||
ContextualParseError::UnsupportedValue(_value, ref err) => parse_error_to_str(err, f),
|
ContextualParseError::UnsupportedValue(_value, ref err) => parse_error_to_str(err, f),
|
||||||
|
ContextualParseError::NeverMatchingHostSelector(ref selector) => {
|
||||||
|
write!(f, ":host selector is not featureless: {}", selector)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,13 @@ use crate::values::specified::font::SpecifiedFontStyle;
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
use crate::values::specified::font::SpecifiedFontVariationSettings;
|
use crate::values::specified::font::SpecifiedFontVariationSettings;
|
||||||
use crate::values::specified::font::{AbsoluteFontWeight, FontStretch};
|
use crate::values::specified::font::{AbsoluteFontWeight, FontStretch};
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
use crate::values::specified::font::MetricsOverride;
|
||||||
use crate::values::specified::url::SpecifiedUrl;
|
use crate::values::specified::url::SpecifiedUrl;
|
||||||
use crate::values::specified::Angle;
|
use crate::values::specified::Angle;
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
|
use crate::values::specified::NonNegativePercentage;
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
use cssparser::UnicodeRange;
|
use cssparser::UnicodeRange;
|
||||||
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser};
|
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser};
|
||||||
use cssparser::{CowRcStr, SourceLocation};
|
use cssparser::{CowRcStr, SourceLocation};
|
||||||
|
@ -194,7 +198,7 @@ impl FontStretchRange {
|
||||||
fn compute_stretch(s: &FontStretch) -> f32 {
|
fn compute_stretch(s: &FontStretch) -> f32 {
|
||||||
match *s {
|
match *s {
|
||||||
FontStretch::Keyword(ref kw) => kw.compute().0,
|
FontStretch::Keyword(ref kw) => kw.compute().0,
|
||||||
FontStretch::Stretch(ref p) => p.get(),
|
FontStretch::Stretch(ref p) => p.0.get(),
|
||||||
FontStretch::System(..) => unreachable!(),
|
FontStretch::System(..) => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -418,6 +422,18 @@ macro_rules! is_descriptor_enabled {
|
||||||
("font-variation-settings") => {
|
("font-variation-settings") => {
|
||||||
static_prefs::pref!("layout.css.font-variations.enabled")
|
static_prefs::pref!("layout.css.font-variations.enabled")
|
||||||
};
|
};
|
||||||
|
("ascent-override") => {
|
||||||
|
static_prefs::pref!("layout.css.font-metrics-overrides.enabled")
|
||||||
|
};
|
||||||
|
("descent-override") => {
|
||||||
|
static_prefs::pref!("layout.css.font-metrics-overrides.enabled")
|
||||||
|
};
|
||||||
|
("line-gap-override") => {
|
||||||
|
static_prefs::pref!("layout.css.font-metrics-overrides.enabled")
|
||||||
|
};
|
||||||
|
("size-adjust") => {
|
||||||
|
static_prefs::pref!("layout.css.size-adjust.enabled")
|
||||||
|
};
|
||||||
($name:tt) => {
|
($name:tt) => {
|
||||||
true
|
true
|
||||||
};
|
};
|
||||||
|
@ -576,6 +592,18 @@ font_face_descriptors! {
|
||||||
|
|
||||||
/// The language override of this font face.
|
/// The language override of this font face.
|
||||||
"font-language-override" language_override / mFontLanguageOverride: font_language_override::SpecifiedValue,
|
"font-language-override" language_override / mFontLanguageOverride: font_language_override::SpecifiedValue,
|
||||||
|
|
||||||
|
/// The ascent override for this font face.
|
||||||
|
"ascent-override" ascent_override / mAscentOverride: MetricsOverride,
|
||||||
|
|
||||||
|
/// The descent override for this font face.
|
||||||
|
"descent-override" descent_override / mDescentOverride: MetricsOverride,
|
||||||
|
|
||||||
|
/// The line-gap override for this font face.
|
||||||
|
"line-gap-override" line_gap_override / mLineGapOverride: MetricsOverride,
|
||||||
|
|
||||||
|
/// The size adjustment for this font face.
|
||||||
|
"size-adjust" size_adjust / mSizeAdjust: NonNegativePercentage,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
//! Data needed to style a Gecko document.
|
//! Data needed to style a Gecko document.
|
||||||
|
|
||||||
use crate::context::QuirksMode;
|
|
||||||
use crate::dom::TElement;
|
use crate::dom::TElement;
|
||||||
use crate::gecko_bindings::bindings;
|
use crate::gecko_bindings::bindings;
|
||||||
use crate::gecko_bindings::structs::{self, RawServoStyleSet, ServoStyleSetSizes};
|
use crate::gecko_bindings::structs::{self, RawServoStyleSet, ServoStyleSetSizes};
|
||||||
|
@ -15,7 +14,7 @@ use crate::media_queries::{Device, MediaList};
|
||||||
use crate::properties::ComputedValues;
|
use crate::properties::ComputedValues;
|
||||||
use crate::selector_parser::SnapshotMap;
|
use crate::selector_parser::SnapshotMap;
|
||||||
use crate::shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
|
use crate::shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
|
||||||
use crate::stylesheets::{CssRule, Origin, StylesheetContents, StylesheetInDocument};
|
use crate::stylesheets::{StylesheetContents, StylesheetInDocument};
|
||||||
use crate::stylist::Stylist;
|
use crate::stylist::Stylist;
|
||||||
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
|
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
|
||||||
use malloc_size_of::MallocSizeOfOps;
|
use malloc_size_of::MallocSizeOfOps;
|
||||||
|
@ -69,16 +68,6 @@ impl GeckoStyleSheet {
|
||||||
fn inner(&self) -> &StyleSheetInfo {
|
fn inner(&self) -> &StyleSheetInfo {
|
||||||
unsafe { &*(self.raw().mInner as *const StyleSheetInfo) }
|
unsafe { &*(self.raw().mInner as *const StyleSheetInfo) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the StylesheetContents for this stylesheet.
|
|
||||||
pub fn contents(&self) -> &StylesheetContents {
|
|
||||||
debug_assert!(!self.inner().mContents.mRawPtr.is_null());
|
|
||||||
unsafe {
|
|
||||||
let contents =
|
|
||||||
(&**StylesheetContents::as_arc(&&*self.inner().mContents.mRawPtr)) as *const _;
|
|
||||||
&*contents
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for GeckoStyleSheet {
|
impl Drop for GeckoStyleSheet {
|
||||||
|
@ -95,14 +84,6 @@ impl Clone for GeckoStyleSheet {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StylesheetInDocument for GeckoStyleSheet {
|
impl StylesheetInDocument for GeckoStyleSheet {
|
||||||
fn origin(&self, _guard: &SharedRwLockReadGuard) -> Origin {
|
|
||||||
self.contents().origin
|
|
||||||
}
|
|
||||||
|
|
||||||
fn quirks_mode(&self, _guard: &SharedRwLockReadGuard) -> QuirksMode {
|
|
||||||
self.contents().quirks_mode
|
|
||||||
}
|
|
||||||
|
|
||||||
fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
|
fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
|
||||||
use crate::gecko_bindings::structs::mozilla::dom::MediaList as DomMediaList;
|
use crate::gecko_bindings::structs::mozilla::dom::MediaList as DomMediaList;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
@ -120,13 +101,19 @@ impl StylesheetInDocument for GeckoStyleSheet {
|
||||||
|
|
||||||
// All the stylesheets Servo knows about are enabled, because that state is
|
// All the stylesheets Servo knows about are enabled, because that state is
|
||||||
// handled externally by Gecko.
|
// handled externally by Gecko.
|
||||||
|
#[inline]
|
||||||
fn enabled(&self) -> bool {
|
fn enabled(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule] {
|
fn contents(&self) -> &StylesheetContents {
|
||||||
self.contents().rules(guard)
|
debug_assert!(!self.inner().mContents.mRawPtr.is_null());
|
||||||
|
unsafe {
|
||||||
|
let contents =
|
||||||
|
(&**StylesheetContents::as_arc(&&*self.inner().mContents.mRawPtr)) as *const _;
|
||||||
|
&*contents
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -275,10 +275,6 @@ enum PrefersReducedMotion {
|
||||||
Reduce,
|
Reduce,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn color_scheme_no_preference_enabled(_: &crate::parser::ParserContext) -> bool {
|
|
||||||
static_prefs::pref!("layout.css.prefers-color-scheme-no-preference.enabled")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Values for the prefers-color-scheme media feature.
|
/// Values for the prefers-color-scheme media feature.
|
||||||
#[derive(Clone, Copy, Debug, FromPrimitive, Parse, PartialEq, ToCss)]
|
#[derive(Clone, Copy, Debug, FromPrimitive, Parse, PartialEq, ToCss)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
|
@ -286,8 +282,6 @@ fn color_scheme_no_preference_enabled(_: &crate::parser::ParserContext) -> bool
|
||||||
pub enum PrefersColorScheme {
|
pub enum PrefersColorScheme {
|
||||||
Light,
|
Light,
|
||||||
Dark,
|
Dark,
|
||||||
#[parse(condition = "color_scheme_no_preference_enabled")]
|
|
||||||
NoPreference,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://drafts.csswg.org/mediaqueries-5/#prefers-reduced-motion
|
/// https://drafts.csswg.org/mediaqueries-5/#prefers-reduced-motion
|
||||||
|
@ -408,7 +402,46 @@ fn eval_prefers_color_scheme(device: &Device, query_value: Option<PrefersColorSc
|
||||||
unsafe { bindings::Gecko_MediaFeatures_PrefersColorScheme(device.document()) };
|
unsafe { bindings::Gecko_MediaFeatures_PrefersColorScheme(device.document()) };
|
||||||
match query_value {
|
match query_value {
|
||||||
Some(v) => prefers_color_scheme == v,
|
Some(v) => prefers_color_scheme == v,
|
||||||
None => prefers_color_scheme != PrefersColorScheme::NoPreference,
|
None => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Values for the -moz-toolbar-prefers-color-scheme media feature.
|
||||||
|
#[derive(Clone, Copy, Debug, FromPrimitive, Parse, PartialEq, ToCss)]
|
||||||
|
#[repr(u8)]
|
||||||
|
enum ToolbarPrefersColorScheme {
|
||||||
|
Dark,
|
||||||
|
Light,
|
||||||
|
System,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The color-scheme of the toolbar in the current Firefox theme. This is based
|
||||||
|
/// on a pref managed by the front-end.
|
||||||
|
fn eval_toolbar_prefers_color_scheme(d: &Device, query_value: Option<ToolbarPrefersColorScheme>) -> bool {
|
||||||
|
let toolbar_value = match static_prefs::pref!("browser.theme.toolbar-theme") {
|
||||||
|
0 => ToolbarPrefersColorScheme::Dark,
|
||||||
|
1 => ToolbarPrefersColorScheme::Light,
|
||||||
|
_ => ToolbarPrefersColorScheme::System,
|
||||||
|
};
|
||||||
|
|
||||||
|
let query_value = match query_value {
|
||||||
|
Some(v) => v,
|
||||||
|
None => return true,
|
||||||
|
};
|
||||||
|
|
||||||
|
if query_value == toolbar_value {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if toolbar_value != ToolbarPrefersColorScheme::System {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// System might match light and dark as well.
|
||||||
|
match query_value {
|
||||||
|
ToolbarPrefersColorScheme::Dark => eval_prefers_color_scheme(d, Some(PrefersColorScheme::Dark)),
|
||||||
|
ToolbarPrefersColorScheme::Light => eval_prefers_color_scheme(d, Some(PrefersColorScheme::Light)),
|
||||||
|
ToolbarPrefersColorScheme::System => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -541,22 +574,6 @@ fn eval_moz_is_resource_document(
|
||||||
query_value.map_or(is_resource_doc, |v| v == is_resource_doc)
|
query_value.map_or(is_resource_doc, |v| v == is_resource_doc)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_system_metric(
|
|
||||||
device: &Device,
|
|
||||||
query_value: Option<bool>,
|
|
||||||
metric: Atom,
|
|
||||||
accessible_from_content: bool,
|
|
||||||
) -> bool {
|
|
||||||
let supports_metric = unsafe {
|
|
||||||
bindings::Gecko_MediaFeatures_HasSystemMetric(
|
|
||||||
device.document(),
|
|
||||||
metric.as_ptr(),
|
|
||||||
accessible_from_content,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
query_value.map_or(supports_metric, |v| v == supports_metric)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval_moz_os_version(
|
fn eval_moz_os_version(
|
||||||
device: &Device,
|
device: &Device,
|
||||||
query_value: Option<Atom>,
|
query_value: Option<Atom>,
|
||||||
|
@ -573,15 +590,63 @@ fn eval_moz_os_version(
|
||||||
query_value.as_ptr() == os_version
|
query_value.as_ptr() == os_version
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! system_metric_feature {
|
fn get_lnf_int(int_id: i32) -> i32 {
|
||||||
($feature_name:expr) => {{
|
unsafe { bindings::Gecko_GetLookAndFeelInt(int_id) }
|
||||||
fn __eval(device: &Device, query_value: Option<bool>, _: Option<RangeOrOperator>) -> bool {
|
}
|
||||||
eval_system_metric(
|
|
||||||
device,
|
fn get_lnf_int_as_bool(int_id: i32) -> bool {
|
||||||
query_value,
|
get_lnf_int(int_id) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_scrollbar_start_backward(int_id: i32) -> bool {
|
||||||
|
(get_lnf_int(int_id) & bindings::LookAndFeel_eScrollArrow_StartBackward as i32) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_scrollbar_start_forward(int_id: i32) -> bool {
|
||||||
|
(get_lnf_int(int_id) & bindings::LookAndFeel_eScrollArrow_StartForward as i32) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_scrollbar_end_backward(int_id: i32) -> bool {
|
||||||
|
(get_lnf_int(int_id) & bindings::LookAndFeel_eScrollArrow_EndBackward as i32) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_scrollbar_end_forward(int_id: i32) -> bool {
|
||||||
|
(get_lnf_int(int_id) & bindings::LookAndFeel_eScrollArrow_EndForward as i32) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! lnf_int_feature {
|
||||||
|
($feature_name:expr, $int_id:ident, $get_value:ident) => {{
|
||||||
|
fn __eval(_: &Device, query_value: Option<bool>, _: Option<RangeOrOperator>) -> bool {
|
||||||
|
let value = $get_value(bindings::LookAndFeel_IntID::$int_id as i32);
|
||||||
|
query_value.map_or(value, |v| v == value)
|
||||||
|
}
|
||||||
|
|
||||||
|
feature!(
|
||||||
$feature_name,
|
$feature_name,
|
||||||
/* accessible_from_content = */ false,
|
AllowsRanges::No,
|
||||||
|
Evaluator::BoolInteger(__eval),
|
||||||
|
ParsingRequirements::CHROME_AND_UA_ONLY,
|
||||||
)
|
)
|
||||||
|
}};
|
||||||
|
($feature_name:expr, $int_id:ident) => {{
|
||||||
|
lnf_int_feature!($feature_name, $int_id, get_lnf_int_as_bool)
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// bool pref-based features are an slightly less convenient to start using
|
||||||
|
/// version of @supports -moz-bool-pref, but with some benefits, mainly that
|
||||||
|
/// they can support dynamic changes, and don't require a pref lookup every time
|
||||||
|
/// they're used.
|
||||||
|
///
|
||||||
|
/// In order to use them you need to make sure that the pref defined as a static
|
||||||
|
/// pref, with `rust: true`. The feature name needs to be defined in
|
||||||
|
/// `StaticAtoms.py` just like the others. In order to support dynamic changes,
|
||||||
|
/// you also need to add them to kMediaQueryPrefs in nsXPLookAndFeel.cpp
|
||||||
|
macro_rules! bool_pref_feature {
|
||||||
|
($feature_name:expr, $pref:tt) => {{
|
||||||
|
fn __eval(_: &Device, query_value: Option<bool>, _: Option<RangeOrOperator>) -> bool {
|
||||||
|
let value = static_prefs::pref!($pref);
|
||||||
|
query_value.map_or(value, |v| v == value)
|
||||||
}
|
}
|
||||||
|
|
||||||
feature!(
|
feature!(
|
||||||
|
@ -598,7 +663,7 @@ macro_rules! system_metric_feature {
|
||||||
/// to support new types in these entries and (2) ensuring that either
|
/// to support new types in these entries and (2) ensuring that either
|
||||||
/// nsPresContext::MediaFeatureValuesChanged is called when the value that
|
/// nsPresContext::MediaFeatureValuesChanged is called when the value that
|
||||||
/// would be returned by the evaluator function could change.
|
/// would be returned by the evaluator function could change.
|
||||||
pub static MEDIA_FEATURES: [MediaFeatureDescription; 56] = [
|
pub static MEDIA_FEATURES: [MediaFeatureDescription; 62] = [
|
||||||
feature!(
|
feature!(
|
||||||
atom!("width"),
|
atom!("width"),
|
||||||
AllowsRanges::Yes,
|
AllowsRanges::Yes,
|
||||||
|
@ -808,27 +873,40 @@ pub static MEDIA_FEATURES: [MediaFeatureDescription; 56] = [
|
||||||
Evaluator::BoolInteger(eval_moz_non_native_content_theme),
|
Evaluator::BoolInteger(eval_moz_non_native_content_theme),
|
||||||
ParsingRequirements::CHROME_AND_UA_ONLY,
|
ParsingRequirements::CHROME_AND_UA_ONLY,
|
||||||
),
|
),
|
||||||
system_metric_feature!(atom!("-moz-scrollbar-start-backward")),
|
feature!(
|
||||||
system_metric_feature!(atom!("-moz-scrollbar-start-forward")),
|
atom!("-moz-toolbar-prefers-color-scheme"),
|
||||||
system_metric_feature!(atom!("-moz-scrollbar-end-backward")),
|
AllowsRanges::No,
|
||||||
system_metric_feature!(atom!("-moz-scrollbar-end-forward")),
|
keyword_evaluator!(eval_toolbar_prefers_color_scheme, ToolbarPrefersColorScheme),
|
||||||
system_metric_feature!(atom!("-moz-scrollbar-thumb-proportional")),
|
ParsingRequirements::CHROME_AND_UA_ONLY,
|
||||||
system_metric_feature!(atom!("-moz-overlay-scrollbars")),
|
),
|
||||||
system_metric_feature!(atom!("-moz-windows-default-theme")),
|
|
||||||
system_metric_feature!(atom!("-moz-mac-graphite-theme")),
|
lnf_int_feature!(atom!("-moz-scrollbar-start-backward"), ScrollArrowStyle, get_scrollbar_start_backward),
|
||||||
system_metric_feature!(atom!("-moz-mac-big-sur-theme")),
|
lnf_int_feature!(atom!("-moz-scrollbar-start-forward"), ScrollArrowStyle, get_scrollbar_start_forward),
|
||||||
system_metric_feature!(atom!("-moz-windows-accent-color-in-titlebar")),
|
lnf_int_feature!(atom!("-moz-scrollbar-end-backward"), ScrollArrowStyle, get_scrollbar_end_backward),
|
||||||
system_metric_feature!(atom!("-moz-windows-compositor")),
|
lnf_int_feature!(atom!("-moz-scrollbar-end-forward"), ScrollArrowStyle, get_scrollbar_end_forward),
|
||||||
system_metric_feature!(atom!("-moz-windows-classic")),
|
lnf_int_feature!(atom!("-moz-scrollbar-thumb-proportional"), ScrollSliderStyle),
|
||||||
system_metric_feature!(atom!("-moz-windows-glass")),
|
lnf_int_feature!(atom!("-moz-overlay-scrollbars"), UseOverlayScrollbars),
|
||||||
system_metric_feature!(atom!("-moz-menubar-drag")),
|
lnf_int_feature!(atom!("-moz-menubar-drag"), MenuBarDrag),
|
||||||
system_metric_feature!(atom!("-moz-swipe-animation-enabled")),
|
lnf_int_feature!(atom!("-moz-windows-default-theme"), WindowsDefaultTheme),
|
||||||
system_metric_feature!(atom!("-moz-gtk-csd-available")),
|
lnf_int_feature!(atom!("-moz-mac-graphite-theme"), MacGraphiteTheme),
|
||||||
system_metric_feature!(atom!("-moz-gtk-csd-hide-titlebar-by-default")),
|
lnf_int_feature!(atom!("-moz-mac-big-sur-theme"), MacBigSurTheme),
|
||||||
system_metric_feature!(atom!("-moz-gtk-csd-transparent-background")),
|
lnf_int_feature!(atom!("-moz-windows-accent-color-in-titlebar"), WindowsAccentColorInTitlebar),
|
||||||
system_metric_feature!(atom!("-moz-gtk-csd-minimize-button")),
|
lnf_int_feature!(atom!("-moz-windows-compositor"), DWMCompositor),
|
||||||
system_metric_feature!(atom!("-moz-gtk-csd-maximize-button")),
|
lnf_int_feature!(atom!("-moz-windows-classic"), WindowsClassic),
|
||||||
system_metric_feature!(atom!("-moz-gtk-csd-close-button")),
|
lnf_int_feature!(atom!("-moz-windows-glass"), WindowsGlass),
|
||||||
system_metric_feature!(atom!("-moz-gtk-csd-reversed-placement")),
|
lnf_int_feature!(atom!("-moz-swipe-animation-enabled"), SwipeAnimationEnabled),
|
||||||
system_metric_feature!(atom!("-moz-system-dark-theme")),
|
lnf_int_feature!(atom!("-moz-gtk-csd-available"), GTKCSDAvailable),
|
||||||
|
lnf_int_feature!(atom!("-moz-gtk-csd-hide-titlebar-by-default"), GTKCSDHideTitlebarByDefault),
|
||||||
|
lnf_int_feature!(atom!("-moz-gtk-csd-transparent-background"), GTKCSDTransparentBackground),
|
||||||
|
lnf_int_feature!(atom!("-moz-gtk-csd-minimize-button"), GTKCSDMinimizeButton),
|
||||||
|
lnf_int_feature!(atom!("-moz-gtk-csd-maximize-button"), GTKCSDMaximizeButton),
|
||||||
|
lnf_int_feature!(atom!("-moz-gtk-csd-close-button"), GTKCSDCloseButton),
|
||||||
|
lnf_int_feature!(atom!("-moz-gtk-csd-reversed-placement"), GTKCSDReversedPlacement),
|
||||||
|
lnf_int_feature!(atom!("-moz-system-dark-theme"), SystemUsesDarkTheme),
|
||||||
|
|
||||||
|
bool_pref_feature!(atom!("-moz-proton"), "browser.proton.enabled"),
|
||||||
|
bool_pref_feature!(atom!("-moz-proton-modals"), "browser.proton.modals.enabled"),
|
||||||
|
bool_pref_feature!(atom!("-moz-proton-contextmenus"), "browser.proton.contextmenus.enabled"),
|
||||||
|
bool_pref_feature!(atom!("-moz-proton-doorhangers"), "browser.proton.doorhangers.enabled"),
|
||||||
|
bool_pref_feature!(atom!("-moz-proton-places-tooltip"), "browser.proton.places-tooltip.enabled"),
|
||||||
];
|
];
|
||||||
|
|
|
@ -432,4 +432,11 @@ impl Device {
|
||||||
};
|
};
|
||||||
SideOffsets2D::new(top, right, bottom, left)
|
SideOffsets2D::new(top, right, bottom, left)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the given MIME type is supported
|
||||||
|
pub fn is_supported_mime_type(&self, mime_type: &str) -> bool {
|
||||||
|
unsafe {
|
||||||
|
bindings::Gecko_IsSupportedImageMimeType(mime_type.as_ptr(), mime_type.len() as u32)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -247,6 +247,11 @@ impl ::selectors::SelectorImpl for SelectorImpl {
|
||||||
|
|
||||||
type PseudoElement = PseudoElement;
|
type PseudoElement = PseudoElement;
|
||||||
type NonTSPseudoClass = NonTSPseudoClass;
|
type NonTSPseudoClass = NonTSPseudoClass;
|
||||||
|
|
||||||
|
fn should_collect_attr_hash(name: &AtomIdent) -> bool {
|
||||||
|
static_prefs::pref!("layout.css.bloom-filter-attribute-names.enabled") &&
|
||||||
|
!crate::bloom::is_attr_name_excluded_from_filter(name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SelectorParser<'a> {
|
impl<'a> SelectorParser<'a> {
|
||||||
|
|
|
@ -570,7 +570,7 @@ impl<'le> GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn attrs(&self) -> &[structs::AttrArray_InternalAttr] {
|
fn non_mapped_attrs(&self) -> &[structs::AttrArray_InternalAttr] {
|
||||||
unsafe {
|
unsafe {
|
||||||
let attrs = match self.0.mAttrs.mImpl.mPtr.as_ref() {
|
let attrs = match self.0.mAttrs.mImpl.mPtr.as_ref() {
|
||||||
Some(attrs) => attrs,
|
Some(attrs) => attrs,
|
||||||
|
@ -581,12 +581,29 @@ impl<'le> GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn mapped_attrs(&self) -> &[structs::AttrArray_InternalAttr] {
|
||||||
|
unsafe {
|
||||||
|
let attrs = match self.0.mAttrs.mImpl.mPtr.as_ref() {
|
||||||
|
Some(attrs) => attrs,
|
||||||
|
None => return &[],
|
||||||
|
};
|
||||||
|
|
||||||
|
let attrs = match attrs.mMappedAttrs.as_ref() {
|
||||||
|
Some(attrs) => attrs,
|
||||||
|
None => return &[],
|
||||||
|
};
|
||||||
|
|
||||||
|
attrs.mBuffer.as_slice(attrs.mAttrCount as usize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn get_part_attr(&self) -> Option<&structs::nsAttrValue> {
|
fn get_part_attr(&self) -> Option<&structs::nsAttrValue> {
|
||||||
if !self.has_part_attr() {
|
if !self.has_part_attr() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
snapshot_helpers::find_attr(self.attrs(), &atom!("part"))
|
snapshot_helpers::find_attr(self.non_mapped_attrs(), &atom!("part"))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -602,7 +619,7 @@ impl<'le> GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
snapshot_helpers::find_attr(self.attrs(), &atom!("class"))
|
snapshot_helpers::find_attr(self.non_mapped_attrs(), &atom!("class"))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -1167,7 +1184,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn exports_any_part(&self) -> bool {
|
fn exports_any_part(&self) -> bool {
|
||||||
snapshot_helpers::find_attr(self.attrs(), &atom!("exportparts")).is_some()
|
snapshot_helpers::find_attr(self.non_mapped_attrs(), &atom!("exportparts")).is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(emilio): we should probably just return a reference to the Atom.
|
// FIXME(emilio): we should probably just return a reference to the Atom.
|
||||||
|
@ -1177,7 +1194,25 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
snapshot_helpers::get_id(self.attrs())
|
snapshot_helpers::get_id(self.non_mapped_attrs())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn each_attr_name<F>(&self, mut callback: F)
|
||||||
|
where
|
||||||
|
F: FnMut(&AtomIdent),
|
||||||
|
{
|
||||||
|
for attr in self.non_mapped_attrs().iter().chain(self.mapped_attrs().iter()) {
|
||||||
|
let is_nodeinfo = attr.mName.mBits & 1 != 0;
|
||||||
|
unsafe {
|
||||||
|
let atom = if is_nodeinfo {
|
||||||
|
let node_info = &*((attr.mName.mBits & !1) as *const structs::NodeInfo);
|
||||||
|
node_info.mInner.mName
|
||||||
|
} else {
|
||||||
|
attr.mName.mBits as *const nsAtom
|
||||||
|
};
|
||||||
|
AtomIdent::with(atom, |a| callback(a))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn each_class<F>(&self, callback: F)
|
fn each_class<F>(&self, callback: F)
|
||||||
|
@ -1197,7 +1232,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
where
|
where
|
||||||
F: FnMut(&AtomIdent),
|
F: FnMut(&AtomIdent),
|
||||||
{
|
{
|
||||||
snapshot_helpers::each_exported_part(self.attrs(), name, callback)
|
snapshot_helpers::each_exported_part(self.non_mapped_attrs(), name, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn each_part<F>(&self, callback: F)
|
fn each_part<F>(&self, callback: F)
|
||||||
|
@ -2058,7 +2093,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let element_id = match snapshot_helpers::get_id(self.attrs()) {
|
let element_id = match snapshot_helpers::get_id(self.non_mapped_attrs()) {
|
||||||
Some(id) => id,
|
Some(id) => id,
|
||||||
None => return false,
|
None => return false,
|
||||||
};
|
};
|
||||||
|
@ -2078,7 +2113,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn imported_part(&self, name: &AtomIdent) -> Option<AtomIdent> {
|
fn imported_part(&self, name: &AtomIdent) -> Option<AtomIdent> {
|
||||||
snapshot_helpers::imported_part(self.attrs(), name)
|
snapshot_helpers::imported_part(self.non_mapped_attrs(), name)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
|
|
@ -185,7 +185,7 @@ pub struct DocumentStateDependency {
|
||||||
/// In particular, we want to lookup as few things as possible to get the fewer
|
/// In particular, we want to lookup as few things as possible to get the fewer
|
||||||
/// selectors the better, so this looks up by id, class, or looks at the list of
|
/// selectors the better, so this looks up by id, class, or looks at the list of
|
||||||
/// state/other attribute affecting selectors.
|
/// state/other attribute affecting selectors.
|
||||||
#[derive(Debug, MallocSizeOf)]
|
#[derive(Clone, Debug, MallocSizeOf)]
|
||||||
pub struct InvalidationMap {
|
pub struct InvalidationMap {
|
||||||
/// A map from a given class name to all the selectors with that class
|
/// A map from a given class name to all the selectors with that class
|
||||||
/// selector.
|
/// selector.
|
||||||
|
|
|
@ -20,10 +20,10 @@ pub trait InvalidationProcessor<'a, E>
|
||||||
where
|
where
|
||||||
E: TElement,
|
E: TElement,
|
||||||
{
|
{
|
||||||
/// Whether an invalidation that contains only an eager pseudo-element
|
/// Whether an invalidation that contains only a pseudo-element selector
|
||||||
/// selector like ::before or ::after triggers invalidation of the element
|
/// like ::before or ::after triggers invalidation of the element that would
|
||||||
/// that would originate it.
|
/// originate it.
|
||||||
fn invalidates_on_eager_pseudo_element(&self) -> bool {
|
fn invalidates_on_pseudo_element(&self) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -878,77 +878,33 @@ where
|
||||||
.selector
|
.selector
|
||||||
.combinator_at_parse_order(next_invalidation.offset - 1);
|
.combinator_at_parse_order(next_invalidation.offset - 1);
|
||||||
|
|
||||||
if matches!(next_combinator, Combinator::PseudoElement) {
|
if matches!(next_combinator, Combinator::PseudoElement) &&
|
||||||
// This will usually be the very next component, except for
|
self.processor.invalidates_on_pseudo_element()
|
||||||
// the fact that we store compound selectors the other way
|
{
|
||||||
// around, so there could also be state pseudo-classes.
|
// We need to invalidate the element whenever pseudos change, for
|
||||||
let pseudo = next_invalidation
|
// two reasons:
|
||||||
.dependency
|
|
||||||
.selector
|
|
||||||
.iter_raw_parse_order_from(next_invalidation.offset)
|
|
||||||
.flat_map(|c| {
|
|
||||||
if let Component::PseudoElement(ref pseudo) = *c {
|
|
||||||
return Some(pseudo);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Would be nice to make this a diagnostic_assert! of
|
|
||||||
// sorts.
|
|
||||||
debug_assert!(
|
|
||||||
c.maybe_allowed_after_pseudo_element(),
|
|
||||||
"Someone seriously messed up selector parsing: \
|
|
||||||
{:?} at offset {:?}: {:?}",
|
|
||||||
next_invalidation.dependency,
|
|
||||||
next_invalidation.offset,
|
|
||||||
c,
|
|
||||||
);
|
|
||||||
|
|
||||||
None
|
|
||||||
})
|
|
||||||
.next()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// FIXME(emilio): This is not ideal, and could not be
|
|
||||||
// accurate if we ever have stateful element-backed eager
|
|
||||||
// pseudos.
|
|
||||||
//
|
//
|
||||||
// Ideally, we'd just remove element-backed eager pseudos
|
// * Eager pseudo styles are stored as part of the originating
|
||||||
// altogether, given they work fine without it. Only gotcha
|
// element's computed style.
|
||||||
// is that we wouldn't style them in parallel, which may or
|
|
||||||
// may not be an issue.
|
|
||||||
//
|
//
|
||||||
// Also, this could be more fine grained now (perhaps a
|
// * Lazy pseudo-styles might be cached on the originating
|
||||||
// RESTYLE_PSEUDOS hint?).
|
// element's pseudo-style cache.
|
||||||
//
|
//
|
||||||
// Note that we'll also restyle the pseudo-element because
|
// This could be more fine-grained (perhaps with a RESTYLE_PSEUDOS
|
||||||
// it would match this invalidation.
|
// hint?).
|
||||||
if self.processor.invalidates_on_eager_pseudo_element() {
|
//
|
||||||
if pseudo.is_eager() {
|
// Note that we'll also restyle the pseudo-element because it would
|
||||||
|
// match this invalidation.
|
||||||
|
//
|
||||||
|
// FIXME: For non-element-backed pseudos this is still not quite
|
||||||
|
// correct. For example for ::selection even though we invalidate
|
||||||
|
// the style properly there's nothing that triggers a repaint
|
||||||
|
// necessarily. Though this matches old Gecko behavior, and the
|
||||||
|
// ::selection implementation needs to change significantly anyway
|
||||||
|
// to implement https://github.com/w3c/csswg-drafts/issues/2474 for
|
||||||
|
// example.
|
||||||
invalidated_self = true;
|
invalidated_self = true;
|
||||||
}
|
}
|
||||||
// If we start or stop matching some marker rules, and
|
|
||||||
// don't have a marker, then we need to restyle the
|
|
||||||
// element to potentially create one.
|
|
||||||
//
|
|
||||||
// Same caveats as for other eager pseudos apply, this
|
|
||||||
// could be more fine-grained.
|
|
||||||
if pseudo.is_marker() && self.element.marker_pseudo_element().is_none() {
|
|
||||||
invalidated_self = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: ::selection doesn't generate elements, so the
|
|
||||||
// regular invalidation doesn't work for it. We store
|
|
||||||
// the cached selection style holding off the originating
|
|
||||||
// element, so we need to restyle it in order to invalidate
|
|
||||||
// it. This is still not quite correct, since nothing
|
|
||||||
// triggers a repaint necessarily, but matches old Gecko
|
|
||||||
// behavior, and the ::selection implementation needs to
|
|
||||||
// change significantly anyway to implement
|
|
||||||
// https://github.com/w3c/csswg-drafts/issues/2474.
|
|
||||||
if pseudo.is_selection() {
|
|
||||||
invalidated_self = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
" > Invalidation matched, next: {:?}, ({:?})",
|
" > Invalidation matched, next: {:?}, ({:?})",
|
||||||
|
|
|
@ -158,10 +158,10 @@ impl<'a, 'b: 'a, E: 'a> InvalidationProcessor<'a, E>
|
||||||
where
|
where
|
||||||
E: TElement,
|
E: TElement,
|
||||||
{
|
{
|
||||||
/// We need to invalidate style on an eager pseudo-element, in order to
|
/// We need to invalidate style on pseudo-elements, in order to process
|
||||||
/// process changes that could otherwise end up in ::before or ::after
|
/// changes that could otherwise end up in ::before or ::after content being
|
||||||
/// content being generated.
|
/// generated, and invalidate lazy pseudo caches.
|
||||||
fn invalidates_on_eager_pseudo_element(&self) -> bool {
|
fn invalidates_on_pseudo_element(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ use crate::context::QuirksMode;
|
||||||
use crate::media_queries::Device;
|
use crate::media_queries::Device;
|
||||||
use crate::shared_lock::SharedRwLockReadGuard;
|
use crate::shared_lock::SharedRwLockReadGuard;
|
||||||
use crate::stylesheets::{DocumentRule, ImportRule, MediaRule};
|
use crate::stylesheets::{DocumentRule, ImportRule, MediaRule};
|
||||||
use crate::stylesheets::{NestedRuleIterationCondition, Stylesheet, SupportsRule};
|
use crate::stylesheets::{NestedRuleIterationCondition, StylesheetContents, SupportsRule};
|
||||||
use fxhash::FxHashSet;
|
use fxhash::FxHashSet;
|
||||||
|
|
||||||
/// A key for a given media query result.
|
/// A key for a given media query result.
|
||||||
|
@ -43,13 +43,13 @@ pub trait ToMediaListKey: Sized {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToMediaListKey for Stylesheet {}
|
impl ToMediaListKey for StylesheetContents {}
|
||||||
impl ToMediaListKey for ImportRule {}
|
impl ToMediaListKey for ImportRule {}
|
||||||
impl ToMediaListKey for MediaRule {}
|
impl ToMediaListKey for MediaRule {}
|
||||||
|
|
||||||
/// A struct that holds the result of a media query evaluation pass for the
|
/// A struct that holds the result of a media query evaluation pass for the
|
||||||
/// media queries that evaluated successfully.
|
/// media queries that evaluated successfully.
|
||||||
#[derive(Debug, MallocSizeOf, PartialEq)]
|
#[derive(Clone, Debug, MallocSizeOf, PartialEq)]
|
||||||
pub struct EffectiveMediaQueryResults {
|
pub struct EffectiveMediaQueryResults {
|
||||||
/// The set of media lists that matched last time.
|
/// The set of media lists that matched last time.
|
||||||
set: FxHashSet<MediaListKey>,
|
set: FxHashSet<MediaListKey>,
|
||||||
|
|
|
@ -196,23 +196,37 @@ fn consume_operation_or_colon(input: &mut Parser) -> Result<Option<Operator>, ()
|
||||||
_ => return Err(()),
|
_ => return Err(()),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(Some(match first_delim {
|
let operator = match first_delim {
|
||||||
'=' => Operator::Equal,
|
'=' => return Ok(Some(Operator::Equal)),
|
||||||
'>' => {
|
'>' => Operator::GreaterThan,
|
||||||
if input.try_parse(|i| i.expect_delim('=')).is_ok() {
|
'<' => Operator::LessThan,
|
||||||
Operator::GreaterThanEqual
|
|
||||||
} else {
|
|
||||||
Operator::GreaterThan
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'<' => {
|
|
||||||
if input.try_parse(|i| i.expect_delim('=')).is_ok() {
|
|
||||||
Operator::LessThanEqual
|
|
||||||
} else {
|
|
||||||
Operator::LessThan
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => return Err(()),
|
_ => return Err(()),
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://drafts.csswg.org/mediaqueries-4/#mq-syntax:
|
||||||
|
//
|
||||||
|
// No whitespace is allowed between the “<” or “>”
|
||||||
|
// <delim-token>s and the following “=” <delim-token>, if it’s
|
||||||
|
// present.
|
||||||
|
//
|
||||||
|
// TODO(emilio): Maybe we should ignore comments as well?
|
||||||
|
// https://github.com/w3c/csswg-drafts/issues/6248
|
||||||
|
let parsed_equal = input.try_parse(|i| {
|
||||||
|
let t = i.next_including_whitespace().map_err(|_| ())?;
|
||||||
|
if !matches!(t, Token::Delim('=')) {
|
||||||
|
return Err(())
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}).is_ok();
|
||||||
|
|
||||||
|
if !parsed_equal {
|
||||||
|
return Ok(Some(operator));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Some(match operator {
|
||||||
|
Operator::GreaterThan => Operator::GreaterThanEqual,
|
||||||
|
Operator::LessThan => Operator::LessThanEqual,
|
||||||
|
_ => unreachable!(),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,7 +235,11 @@ fn disabled_by_pref(feature: &Atom, context: &ParserContext) -> bool {
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
{
|
{
|
||||||
if *feature == atom!("forced-colors") {
|
if *feature == atom!("forced-colors") {
|
||||||
return !static_prefs::pref!("layout.css.forced-colors.enabled");
|
// forced-colors is always enabled in the ua and chrome. On
|
||||||
|
// the web it is hidden behind a preference, which is defaulted
|
||||||
|
// to 'true' as of bug 1659511.
|
||||||
|
return !context.in_ua_or_chrome_sheet() &&
|
||||||
|
!static_prefs::pref!("layout.css.forced-colors.enabled");
|
||||||
}
|
}
|
||||||
// prefers-contrast is always enabled in the ua and chrome. On
|
// prefers-contrast is always enabled in the ua and chrome. On
|
||||||
// the web it is hidden behind a preference.
|
// the web it is hidden behind a preference.
|
||||||
|
|
|
@ -37,6 +37,7 @@ STYLE_STRUCT_LIST = [
|
||||||
"list",
|
"list",
|
||||||
"margin",
|
"margin",
|
||||||
"outline",
|
"outline",
|
||||||
|
"page",
|
||||||
"padding",
|
"padding",
|
||||||
"position",
|
"position",
|
||||||
"svg",
|
"svg",
|
||||||
|
|
|
@ -379,13 +379,15 @@ where
|
||||||
type DeclarationsToApplyUnlessOverriden = SmallVec<[PropertyDeclaration; 2]>;
|
type DeclarationsToApplyUnlessOverriden = SmallVec<[PropertyDeclaration; 2]>;
|
||||||
|
|
||||||
fn tweak_when_ignoring_colors(
|
fn tweak_when_ignoring_colors(
|
||||||
builder: &StyleBuilder,
|
context: &computed::Context,
|
||||||
longhand_id: LonghandId,
|
longhand_id: LonghandId,
|
||||||
origin: Origin,
|
origin: Origin,
|
||||||
declaration: &mut Cow<PropertyDeclaration>,
|
declaration: &mut Cow<PropertyDeclaration>,
|
||||||
declarations_to_apply_unless_overriden: &mut DeclarationsToApplyUnlessOverriden,
|
declarations_to_apply_unless_overriden: &mut DeclarationsToApplyUnlessOverriden,
|
||||||
) {
|
) {
|
||||||
use crate::values::specified::Color;
|
use crate::values::specified::Color;
|
||||||
|
use crate::values::computed::ToComputedValue;
|
||||||
|
use cssparser::RGBA;
|
||||||
|
|
||||||
if !longhand_id.ignored_when_document_colors_disabled() {
|
if !longhand_id.ignored_when_document_colors_disabled() {
|
||||||
return;
|
return;
|
||||||
|
@ -399,39 +401,25 @@ fn tweak_when_ignoring_colors(
|
||||||
// Don't override background-color on ::-moz-color-swatch. It is set as an
|
// Don't override background-color on ::-moz-color-swatch. It is set as an
|
||||||
// author style (via the style attribute), but it's pretty important for it
|
// author style (via the style attribute), but it's pretty important for it
|
||||||
// to show up for obvious reasons :)
|
// to show up for obvious reasons :)
|
||||||
if builder.pseudo.map_or(false, |p| p.is_color_swatch()) &&
|
if context.builder.pseudo.map_or(false, |p| p.is_color_swatch()) &&
|
||||||
longhand_id == LonghandId::BackgroundColor
|
longhand_id == LonghandId::BackgroundColor
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alpha_channel(color: &Color) -> u8 {
|
fn alpha_channel(color: &Color, context: &computed::Context) -> u8 {
|
||||||
match *color {
|
// We assume here currentColor is opaque.
|
||||||
// Seems safe enough to assume that the default color and system
|
let color = color.to_computed_value(context).to_rgba(RGBA::new(0, 0, 0, 255));
|
||||||
// colors are opaque in HCM, though maybe we shouldn't asume the
|
color.alpha
|
||||||
// later?
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
Color::InheritFromBodyQuirk | Color::System(..) => 255,
|
|
||||||
// We don't have the actual color here, but since except for color:
|
|
||||||
// transparent we force opaque text colors, it seems sane to do
|
|
||||||
// this. You can technically fool this bit of code with:
|
|
||||||
//
|
|
||||||
// color: transparent; background-color: currentcolor;
|
|
||||||
//
|
|
||||||
// but this is best-effort, and that seems unlikely to happen in
|
|
||||||
// practice.
|
|
||||||
Color::CurrentColor => 255,
|
|
||||||
// Complex colors are results of interpolation only and probably
|
|
||||||
// shouldn't show up around here in HCM, but we've always treated
|
|
||||||
// them as opaque effectively so keep doing it.
|
|
||||||
Color::Complex { .. } => 255,
|
|
||||||
Color::Numeric { ref parsed, .. } => parsed.alpha,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A few special-cases ahead.
|
// A few special-cases ahead.
|
||||||
match **declaration {
|
match **declaration {
|
||||||
PropertyDeclaration::BackgroundColor(ref color) => {
|
PropertyDeclaration::BackgroundColor(ref color) => {
|
||||||
|
// We honor system colors.
|
||||||
|
if color.is_system() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// For background-color, we revert or initial-with-preserved-alpha
|
// For background-color, we revert or initial-with-preserved-alpha
|
||||||
// otherwise, this is needed to preserve semi-transparent
|
// otherwise, this is needed to preserve semi-transparent
|
||||||
// backgrounds.
|
// backgrounds.
|
||||||
|
@ -440,24 +428,27 @@ fn tweak_when_ignoring_colors(
|
||||||
// should consider not doing that even if it causes some issues like
|
// should consider not doing that even if it causes some issues like
|
||||||
// bug 1625036, or finding a performant way to preserve the original
|
// bug 1625036, or finding a performant way to preserve the original
|
||||||
// widget background color's rgb channels but not alpha...
|
// widget background color's rgb channels but not alpha...
|
||||||
let alpha = alpha_channel(color);
|
let alpha = alpha_channel(color, context);
|
||||||
if alpha != 0 {
|
if alpha != 0 {
|
||||||
let mut color = builder.device.default_background_color();
|
let mut color = context.builder.device.default_background_color();
|
||||||
color.alpha = alpha;
|
color.alpha = alpha;
|
||||||
declarations_to_apply_unless_overriden
|
declarations_to_apply_unless_overriden
|
||||||
.push(PropertyDeclaration::BackgroundColor(color.into()))
|
.push(PropertyDeclaration::BackgroundColor(color.into()))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
PropertyDeclaration::Color(ref color) => {
|
PropertyDeclaration::Color(ref color) => {
|
||||||
// We honor color: transparent, and "revert-or-initial" otherwise.
|
// We honor color: transparent and system colors.
|
||||||
if alpha_channel(&color.0) == 0 {
|
if color.0.is_system() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if alpha_channel(&color.0, context) == 0 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// If the inherited color would be transparent, but we would
|
// If the inherited color would be transparent, but we would
|
||||||
// override this with a non-transparent color, then override it with
|
// override this with a non-transparent color, then override it with
|
||||||
// the default color. Otherwise just let it inherit through.
|
// the default color. Otherwise just let it inherit through.
|
||||||
if builder.get_parent_inherited_text().clone_color().alpha == 0 {
|
if context.builder.get_parent_inherited_text().clone_color().alpha == 0 {
|
||||||
let color = builder.device.default_color();
|
let color = context.builder.device.default_color();
|
||||||
declarations_to_apply_unless_overriden.push(PropertyDeclaration::Color(
|
declarations_to_apply_unless_overriden.push(PropertyDeclaration::Color(
|
||||||
specified::ColorPropertyValue(color.into()),
|
specified::ColorPropertyValue(color.into()),
|
||||||
))
|
))
|
||||||
|
@ -631,7 +622,7 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
|
||||||
// properties that are marked as ignored in that mode.
|
// properties that are marked as ignored in that mode.
|
||||||
if ignore_colors {
|
if ignore_colors {
|
||||||
tweak_when_ignoring_colors(
|
tweak_when_ignoring_colors(
|
||||||
&self.context.builder,
|
&self.context,
|
||||||
longhand_id,
|
longhand_id,
|
||||||
origin,
|
origin,
|
||||||
&mut declaration,
|
&mut declaration,
|
||||||
|
|
|
@ -19,7 +19,6 @@ COUNTED_UNKNOWN_PROPERTIES = [
|
||||||
"text-size-adjust",
|
"text-size-adjust",
|
||||||
"-webkit-font-feature-settings",
|
"-webkit-font-feature-settings",
|
||||||
"-webkit-user-drag",
|
"-webkit-user-drag",
|
||||||
"size",
|
|
||||||
"-webkit-clip-path",
|
"-webkit-clip-path",
|
||||||
"orphans",
|
"orphans",
|
||||||
"widows",
|
"widows",
|
||||||
|
|
|
@ -261,6 +261,11 @@ class Property(object):
|
||||||
self.extra_prefixes = parse_property_aliases(extra_prefixes)
|
self.extra_prefixes = parse_property_aliases(extra_prefixes)
|
||||||
self.flags = flags.split() if flags else []
|
self.flags = flags.split() if flags else []
|
||||||
|
|
||||||
|
def rule_types_allowed_names(self):
|
||||||
|
for name in RULE_VALUES:
|
||||||
|
if self.rule_types_allowed & RULE_VALUES[name] != 0:
|
||||||
|
yield name
|
||||||
|
|
||||||
def experimental(self, engine):
|
def experimental(self, engine):
|
||||||
if engine == "gecko":
|
if engine == "gecko":
|
||||||
return bool(self.gecko_pref)
|
return bool(self.gecko_pref)
|
||||||
|
@ -478,6 +483,7 @@ class Longhand(Property):
|
||||||
"LineBreak",
|
"LineBreak",
|
||||||
"MasonryAutoFlow",
|
"MasonryAutoFlow",
|
||||||
"MozForceBrokenImageIcon",
|
"MozForceBrokenImageIcon",
|
||||||
|
"text::MozControlCharacterVisibility",
|
||||||
"MozListReversed",
|
"MozListReversed",
|
||||||
"MathDepth",
|
"MathDepth",
|
||||||
"MozScriptMinSize",
|
"MozScriptMinSize",
|
||||||
|
@ -495,6 +501,7 @@ class Longhand(Property):
|
||||||
"Percentage",
|
"Percentage",
|
||||||
"PositiveIntegerOrNone",
|
"PositiveIntegerOrNone",
|
||||||
"Resize",
|
"Resize",
|
||||||
|
"RubyPosition",
|
||||||
"SVGOpacity",
|
"SVGOpacity",
|
||||||
"SVGPaintOrder",
|
"SVGPaintOrder",
|
||||||
"ScrollSnapAlign",
|
"ScrollSnapAlign",
|
||||||
|
@ -505,6 +512,7 @@ class Longhand(Property):
|
||||||
"TextAlignLast",
|
"TextAlignLast",
|
||||||
"TextDecorationLine",
|
"TextDecorationLine",
|
||||||
"TextEmphasisPosition",
|
"TextEmphasisPosition",
|
||||||
|
"TextJustify",
|
||||||
"TextTransform",
|
"TextTransform",
|
||||||
"TextUnderlinePosition",
|
"TextUnderlinePosition",
|
||||||
"TouchAction",
|
"TouchAction",
|
||||||
|
@ -597,6 +605,11 @@ class Alias(object):
|
||||||
def type():
|
def type():
|
||||||
return "alias"
|
return "alias"
|
||||||
|
|
||||||
|
def rule_types_allowed_names(self):
|
||||||
|
for name in RULE_VALUES:
|
||||||
|
if self.rule_types_allowed & RULE_VALUES[name] != 0:
|
||||||
|
yield name
|
||||||
|
|
||||||
def experimental(self, engine):
|
def experimental(self, engine):
|
||||||
if engine == "gecko":
|
if engine == "gecko":
|
||||||
return bool(self.gecko_pref)
|
return bool(self.gecko_pref)
|
||||||
|
@ -866,6 +879,7 @@ class PropertyRestrictions:
|
||||||
def marker(data):
|
def marker(data):
|
||||||
return set(
|
return set(
|
||||||
[
|
[
|
||||||
|
"white-space",
|
||||||
"color",
|
"color",
|
||||||
"text-combine-upright",
|
"text-combine-upright",
|
||||||
"text-transform",
|
"text-transform",
|
||||||
|
|
|
@ -781,6 +781,9 @@ fn static_assert() {
|
||||||
% endfor
|
% endfor
|
||||||
</%self:impl_trait>
|
</%self:impl_trait>
|
||||||
|
|
||||||
|
<%self:impl_trait style_struct_name="Page">
|
||||||
|
</%self:impl_trait>
|
||||||
|
|
||||||
<% skip_position_longhands = " ".join(x.ident for x in SIDES) %>
|
<% skip_position_longhands = " ".join(x.ident for x in SIDES) %>
|
||||||
<%self:impl_trait style_struct_name="Position"
|
<%self:impl_trait style_struct_name="Position"
|
||||||
skip_longhands="${skip_position_longhands}
|
skip_longhands="${skip_position_longhands}
|
||||||
|
|
|
@ -554,7 +554,7 @@
|
||||||
keyword = keyword=Keyword(name, values, **keyword_kwargs)
|
keyword = keyword=Keyword(name, values, **keyword_kwargs)
|
||||||
%>
|
%>
|
||||||
<%call expr="longhand(name, keyword=Keyword(name, values, **keyword_kwargs), **kwargs)">
|
<%call expr="longhand(name, keyword=Keyword(name, values, **keyword_kwargs), **kwargs)">
|
||||||
use crate::properties::longhands::system_font::SystemFont;
|
use crate::values::specified::font::SystemFont;
|
||||||
|
|
||||||
pub mod computed_value {
|
pub mod computed_value {
|
||||||
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
|
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
|
||||||
|
@ -707,8 +707,7 @@
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="single_keyword(name, values, vector=False,
|
<%def name="single_keyword(name, values, vector=False,
|
||||||
extra_specified=None, needs_conversion=False,
|
needs_conversion=False, **kwargs)">
|
||||||
gecko_pref_controlled_initial_value=None, **kwargs)">
|
|
||||||
<%
|
<%
|
||||||
keyword_kwargs = {a: kwargs.pop(a, None) for a in [
|
keyword_kwargs = {a: kwargs.pop(a, None) for a in [
|
||||||
'gecko_constant_prefix',
|
'gecko_constant_prefix',
|
||||||
|
@ -725,11 +724,13 @@
|
||||||
]}
|
]}
|
||||||
%>
|
%>
|
||||||
|
|
||||||
<%def name="inner_body(keyword, extra_specified=None, needs_conversion=False,
|
<%def name="inner_body(keyword, needs_conversion=False)">
|
||||||
gecko_pref_controlled_initial_value=None)">
|
pub use self::computed_value::T as SpecifiedValue;
|
||||||
<%def name="variants(variants, include_aliases)">
|
pub mod computed_value {
|
||||||
% for variant in variants:
|
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
|
||||||
% if include_aliases:
|
#[derive(Clone, Copy, Debug, Eq, FromPrimitive, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, ToResolvedValue, ToShmem)]
|
||||||
|
pub enum T {
|
||||||
|
% for variant in keyword.values_for(engine):
|
||||||
<%
|
<%
|
||||||
aliases = []
|
aliases = []
|
||||||
for alias, v in keyword.aliases_for(engine).items():
|
for alias, v in keyword.aliases_for(engine).items():
|
||||||
|
@ -739,56 +740,16 @@
|
||||||
% if aliases:
|
% if aliases:
|
||||||
#[parse(aliases = "${','.join(sorted(aliases))}")]
|
#[parse(aliases = "${','.join(sorted(aliases))}")]
|
||||||
% endif
|
% endif
|
||||||
% endif
|
|
||||||
${to_camel_case(variant)},
|
${to_camel_case(variant)},
|
||||||
% endfor
|
% endfor
|
||||||
</%def>
|
|
||||||
% if extra_specified:
|
|
||||||
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
|
|
||||||
#[derive(
|
|
||||||
Clone,
|
|
||||||
Copy,
|
|
||||||
Debug,
|
|
||||||
Eq,
|
|
||||||
MallocSizeOf,
|
|
||||||
Parse,
|
|
||||||
PartialEq,
|
|
||||||
SpecifiedValueInfo,
|
|
||||||
ToCss,
|
|
||||||
ToShmem,
|
|
||||||
)]
|
|
||||||
pub enum SpecifiedValue {
|
|
||||||
${variants(keyword.values_for(engine) + extra_specified.split(), bool(extra_specified))}
|
|
||||||
}
|
|
||||||
% else:
|
|
||||||
pub use self::computed_value::T as SpecifiedValue;
|
|
||||||
% endif
|
|
||||||
pub mod computed_value {
|
|
||||||
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, FromPrimitive, MallocSizeOf, PartialEq, ToCss, ToResolvedValue)]
|
|
||||||
% if not extra_specified:
|
|
||||||
#[derive(Parse, SpecifiedValueInfo, ToComputedValue, ToShmem)]
|
|
||||||
% endif
|
|
||||||
pub enum T {
|
|
||||||
${variants(data.longhands_by_name[name].keyword.values_for(engine), not extra_specified)}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_initial_value() -> computed_value::T {
|
pub fn get_initial_value() -> computed_value::T {
|
||||||
% if engine == "gecko" and gecko_pref_controlled_initial_value:
|
|
||||||
if static_prefs::pref!("${gecko_pref_controlled_initial_value.split('=')[0]}") {
|
|
||||||
return computed_value::T::${to_camel_case(gecko_pref_controlled_initial_value.split('=')[1])};
|
|
||||||
}
|
|
||||||
% endif
|
|
||||||
computed_value::T::${to_camel_case(values.split()[0])}
|
computed_value::T::${to_camel_case(values.split()[0])}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_initial_specified_value() -> SpecifiedValue {
|
pub fn get_initial_specified_value() -> SpecifiedValue {
|
||||||
% if engine == "gecko" and gecko_pref_controlled_initial_value:
|
|
||||||
if static_prefs::pref!("${gecko_pref_controlled_initial_value.split('=')[0]}") {
|
|
||||||
return SpecifiedValue::${to_camel_case(gecko_pref_controlled_initial_value.split('=')[1])};
|
|
||||||
}
|
|
||||||
% endif
|
|
||||||
SpecifiedValue::${to_camel_case(values.split()[0])}
|
SpecifiedValue::${to_camel_case(values.split()[0])}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -799,10 +760,7 @@
|
||||||
|
|
||||||
% if needs_conversion:
|
% if needs_conversion:
|
||||||
<%
|
<%
|
||||||
conversion_values = keyword.values_for(engine)
|
conversion_values = keyword.values_for(engine) + list(keyword.aliases_for(engine).keys())
|
||||||
if extra_specified:
|
|
||||||
conversion_values += extra_specified.split()
|
|
||||||
conversion_values += keyword.aliases_for(engine).keys()
|
|
||||||
%>
|
%>
|
||||||
${gecko_keyword_conversion(keyword, values=conversion_values)}
|
${gecko_keyword_conversion(keyword, values=conversion_values)}
|
||||||
% endif
|
% endif
|
||||||
|
@ -817,8 +775,7 @@
|
||||||
% else:
|
% else:
|
||||||
<%call expr="longhand(name, keyword=Keyword(name, values, **keyword_kwargs), **kwargs)">
|
<%call expr="longhand(name, keyword=Keyword(name, values, **keyword_kwargs), **kwargs)">
|
||||||
${inner_body(Keyword(name, values, **keyword_kwargs),
|
${inner_body(Keyword(name, values, **keyword_kwargs),
|
||||||
extra_specified=extra_specified, needs_conversion=needs_conversion,
|
needs_conversion=needs_conversion)}
|
||||||
gecko_pref_controlled_initial_value=gecko_pref_controlled_initial_value)}
|
|
||||||
% if caller:
|
% if caller:
|
||||||
${caller.body()}
|
${caller.body()}
|
||||||
% endif
|
% endif
|
||||||
|
|
|
@ -48,7 +48,6 @@ ${helpers.single_keyword(
|
||||||
engines="gecko servo-2013 servo-2020"
|
engines="gecko servo-2013 servo-2020"
|
||||||
animation_value_type="discrete"
|
animation_value_type="discrete"
|
||||||
gecko_enum_prefix="StylePositionProperty"
|
gecko_enum_prefix="StylePositionProperty"
|
||||||
flags="CREATES_STACKING_CONTEXT ABSPOS_CB"
|
|
||||||
spec="https://drafts.csswg.org/css-position/#position-property"
|
spec="https://drafts.csswg.org/css-position/#position-property"
|
||||||
servo_restyle_damage="rebuild_and_reflow"
|
servo_restyle_damage="rebuild_and_reflow"
|
||||||
>
|
>
|
||||||
|
@ -330,7 +329,7 @@ ${helpers.predefined_type(
|
||||||
engines="gecko servo-2013 servo-2020",
|
engines="gecko servo-2013 servo-2020",
|
||||||
extra_prefixes=transform_extra_prefixes,
|
extra_prefixes=transform_extra_prefixes,
|
||||||
animation_value_type="ComputedValue",
|
animation_value_type="ComputedValue",
|
||||||
flags="CREATES_STACKING_CONTEXT FIXPOS_CB CAN_ANIMATE_ON_COMPOSITOR",
|
flags="CAN_ANIMATE_ON_COMPOSITOR",
|
||||||
spec="https://drafts.csswg.org/css-transforms/#propdef-transform",
|
spec="https://drafts.csswg.org/css-transforms/#propdef-transform",
|
||||||
servo_restyle_damage="reflow_out_of_flow",
|
servo_restyle_damage="reflow_out_of_flow",
|
||||||
)}
|
)}
|
||||||
|
@ -342,7 +341,7 @@ ${helpers.predefined_type(
|
||||||
engines="gecko servo-2013",
|
engines="gecko servo-2013",
|
||||||
animation_value_type="ComputedValue",
|
animation_value_type="ComputedValue",
|
||||||
boxed=True,
|
boxed=True,
|
||||||
flags="CREATES_STACKING_CONTEXT FIXPOS_CB CAN_ANIMATE_ON_COMPOSITOR",
|
flags="CAN_ANIMATE_ON_COMPOSITOR",
|
||||||
gecko_pref="layout.css.individual-transform.enabled",
|
gecko_pref="layout.css.individual-transform.enabled",
|
||||||
spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms",
|
spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms",
|
||||||
servo_restyle_damage = "reflow_out_of_flow",
|
servo_restyle_damage = "reflow_out_of_flow",
|
||||||
|
@ -355,7 +354,7 @@ ${helpers.predefined_type(
|
||||||
engines="gecko servo-2013",
|
engines="gecko servo-2013",
|
||||||
animation_value_type="ComputedValue",
|
animation_value_type="ComputedValue",
|
||||||
boxed=True,
|
boxed=True,
|
||||||
flags="CREATES_STACKING_CONTEXT FIXPOS_CB CAN_ANIMATE_ON_COMPOSITOR",
|
flags="CAN_ANIMATE_ON_COMPOSITOR",
|
||||||
gecko_pref="layout.css.individual-transform.enabled",
|
gecko_pref="layout.css.individual-transform.enabled",
|
||||||
spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms",
|
spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms",
|
||||||
servo_restyle_damage = "reflow_out_of_flow",
|
servo_restyle_damage = "reflow_out_of_flow",
|
||||||
|
@ -368,7 +367,7 @@ ${helpers.predefined_type(
|
||||||
engines="gecko servo-2013",
|
engines="gecko servo-2013",
|
||||||
animation_value_type="ComputedValue",
|
animation_value_type="ComputedValue",
|
||||||
boxed=True,
|
boxed=True,
|
||||||
flags="CREATES_STACKING_CONTEXT FIXPOS_CB CAN_ANIMATE_ON_COMPOSITOR",
|
flags="CAN_ANIMATE_ON_COMPOSITOR",
|
||||||
gecko_pref="layout.css.individual-transform.enabled",
|
gecko_pref="layout.css.individual-transform.enabled",
|
||||||
spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms",
|
spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms",
|
||||||
servo_restyle_damage="reflow_out_of_flow",
|
servo_restyle_damage="reflow_out_of_flow",
|
||||||
|
@ -382,7 +381,7 @@ ${helpers.predefined_type(
|
||||||
engines="gecko",
|
engines="gecko",
|
||||||
animation_value_type="ComputedValue",
|
animation_value_type="ComputedValue",
|
||||||
gecko_pref="layout.css.motion-path.enabled",
|
gecko_pref="layout.css.motion-path.enabled",
|
||||||
flags="CREATES_STACKING_CONTEXT FIXPOS_CB CAN_ANIMATE_ON_COMPOSITOR",
|
flags="CAN_ANIMATE_ON_COMPOSITOR",
|
||||||
spec="https://drafts.fxtf.org/motion-1/#offset-path-property",
|
spec="https://drafts.fxtf.org/motion-1/#offset-path-property",
|
||||||
servo_restyle_damage="reflow_out_of_flow"
|
servo_restyle_damage="reflow_out_of_flow"
|
||||||
)}
|
)}
|
||||||
|
@ -477,7 +476,6 @@ ${helpers.single_keyword(
|
||||||
"auto isolate",
|
"auto isolate",
|
||||||
engines="gecko",
|
engines="gecko",
|
||||||
spec="https://drafts.fxtf.org/compositing/#isolation",
|
spec="https://drafts.fxtf.org/compositing/#isolation",
|
||||||
flags="CREATES_STACKING_CONTEXT",
|
|
||||||
gecko_enum_prefix="StyleIsolation",
|
gecko_enum_prefix="StyleIsolation",
|
||||||
animation_value_type="discrete",
|
animation_value_type="discrete",
|
||||||
)}
|
)}
|
||||||
|
@ -530,7 +528,6 @@ ${helpers.predefined_type(
|
||||||
gecko_ffi_name="mChildPerspective",
|
gecko_ffi_name="mChildPerspective",
|
||||||
spec="https://drafts.csswg.org/css-transforms/#perspective",
|
spec="https://drafts.csswg.org/css-transforms/#perspective",
|
||||||
extra_prefixes=transform_extra_prefixes,
|
extra_prefixes=transform_extra_prefixes,
|
||||||
flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
|
|
||||||
animation_value_type="AnimatedPerspective",
|
animation_value_type="AnimatedPerspective",
|
||||||
servo_restyle_damage = "reflow_out_of_flow",
|
servo_restyle_damage = "reflow_out_of_flow",
|
||||||
)}
|
)}
|
||||||
|
@ -574,7 +571,6 @@ ${helpers.predefined_type(
|
||||||
engines="gecko servo-2013 servo-2020",
|
engines="gecko servo-2013 servo-2020",
|
||||||
spec="https://drafts.csswg.org/css-transforms-2/#transform-style-property",
|
spec="https://drafts.csswg.org/css-transforms-2/#transform-style-property",
|
||||||
extra_prefixes=transform_extra_prefixes,
|
extra_prefixes=transform_extra_prefixes,
|
||||||
flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
|
|
||||||
animation_value_type="discrete",
|
animation_value_type="discrete",
|
||||||
servo_restyle_damage = "reflow_out_of_flow",
|
servo_restyle_damage = "reflow_out_of_flow",
|
||||||
)}
|
)}
|
||||||
|
@ -598,7 +594,6 @@ ${helpers.predefined_type(
|
||||||
"specified::Contain::empty()",
|
"specified::Contain::empty()",
|
||||||
engines="gecko",
|
engines="gecko",
|
||||||
animation_value_type="none",
|
animation_value_type="none",
|
||||||
flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
|
|
||||||
spec="https://drafts.csswg.org/css-contain/#contain-property",
|
spec="https://drafts.csswg.org/css-contain/#contain-property",
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ ${helpers.predefined_type(
|
||||||
"1.0",
|
"1.0",
|
||||||
engines="gecko servo-2013 servo-2020",
|
engines="gecko servo-2013 servo-2020",
|
||||||
animation_value_type="ComputedValue",
|
animation_value_type="ComputedValue",
|
||||||
flags="CREATES_STACKING_CONTEXT CAN_ANIMATE_ON_COMPOSITOR",
|
flags="CAN_ANIMATE_ON_COMPOSITOR",
|
||||||
spec="https://drafts.csswg.org/css-color/#transparency",
|
spec="https://drafts.csswg.org/css-color/#transparency",
|
||||||
servo_restyle_damage = "reflow_out_of_flow",
|
servo_restyle_damage = "reflow_out_of_flow",
|
||||||
)}
|
)}
|
||||||
|
@ -56,7 +56,6 @@ ${helpers.predefined_type(
|
||||||
animation_value_type="AnimatedFilterList",
|
animation_value_type="AnimatedFilterList",
|
||||||
vector_animation_type="with_zero",
|
vector_animation_type="with_zero",
|
||||||
extra_prefixes="webkit",
|
extra_prefixes="webkit",
|
||||||
flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
|
|
||||||
spec="https://drafts.fxtf.org/filters/#propdef-filter",
|
spec="https://drafts.fxtf.org/filters/#propdef-filter",
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
@ -71,7 +70,6 @@ ${helpers.predefined_type(
|
||||||
separator="Space",
|
separator="Space",
|
||||||
animation_value_type="AnimatedFilterList",
|
animation_value_type="AnimatedFilterList",
|
||||||
vector_animation_type="with_zero",
|
vector_animation_type="with_zero",
|
||||||
flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
|
|
||||||
gecko_pref="layout.css.backdrop-filter.enabled",
|
gecko_pref="layout.css.backdrop-filter.enabled",
|
||||||
spec="https://drafts.fxtf.org/filter-effects-2/#propdef-backdrop-filter",
|
spec="https://drafts.fxtf.org/filter-effects-2/#propdef-backdrop-filter",
|
||||||
)}
|
)}
|
||||||
|
@ -84,6 +82,5 @@ ${helpers.single_keyword(
|
||||||
engines="gecko servo-2013 servo-2020",
|
engines="gecko servo-2013 servo-2020",
|
||||||
gecko_enum_prefix="StyleBlend",
|
gecko_enum_prefix="StyleBlend",
|
||||||
animation_value_type="discrete",
|
animation_value_type="discrete",
|
||||||
flags="CREATES_STACKING_CONTEXT",
|
|
||||||
spec="https://drafts.fxtf.org/compositing/#propdef-mix-blend-mode",
|
spec="https://drafts.fxtf.org/compositing/#propdef-mix-blend-mode",
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -288,7 +288,7 @@ ${helpers.predefined_type(
|
||||||
)}
|
)}
|
||||||
|
|
||||||
% if engine == "gecko":
|
% if engine == "gecko":
|
||||||
pub mod system_font {
|
pub mod system_font {
|
||||||
//! We deal with system fonts here
|
//! We deal with system fonts here
|
||||||
//!
|
//!
|
||||||
//! System fonts can only be set as a group via the font shorthand.
|
//! System fonts can only be set as a group via the font shorthand.
|
||||||
|
@ -309,19 +309,13 @@ ${helpers.predefined_type(
|
||||||
//! variable reference. We may want to improve this behavior at some
|
//! variable reference. We may want to improve this behavior at some
|
||||||
//! point. See also https://github.com/w3c/csswg-drafts/issues/1586.
|
//! point. See also https://github.com/w3c/csswg-drafts/issues/1586.
|
||||||
|
|
||||||
use cssparser::{Parser, ToCss};
|
|
||||||
use crate::values::computed::font::GenericFontFamily;
|
use crate::values::computed::font::GenericFontFamily;
|
||||||
use crate::properties::longhands;
|
use crate::properties::longhands;
|
||||||
use std::fmt;
|
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use style_traits::ParseError;
|
|
||||||
use crate::values::computed::{ToComputedValue, Context};
|
use crate::values::computed::{ToComputedValue, Context};
|
||||||
|
use crate::values::specified::font::SystemFont;
|
||||||
|
|
||||||
<%
|
<%
|
||||||
system_fonts = """caption icon menu message-box small-caption status-bar
|
|
||||||
-moz-window -moz-document -moz-workspace -moz-desktop
|
|
||||||
-moz-info -moz-dialog -moz-button -moz-pull-down-menu
|
|
||||||
-moz-list -moz-field""".split()
|
|
||||||
kw_font_props = """font_variant_caps
|
kw_font_props = """font_variant_caps
|
||||||
font_kerning font_variant_position font_variant_ligatures
|
font_kerning font_variant_position font_variant_ligatures
|
||||||
font_variant_east_asian font_variant_numeric
|
font_variant_east_asian font_variant_numeric
|
||||||
|
@ -329,13 +323,6 @@ ${helpers.predefined_type(
|
||||||
kw_cast = """font_variant_caps font_kerning font_variant_position
|
kw_cast = """font_variant_caps font_kerning font_variant_position
|
||||||
font_optical_sizing""".split()
|
font_optical_sizing""".split()
|
||||||
%>
|
%>
|
||||||
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq,
|
|
||||||
SpecifiedValueInfo, ToCss, ToShmem)]
|
|
||||||
pub enum SystemFont {
|
|
||||||
% for font in system_fonts:
|
|
||||||
${to_camel_case(font)},
|
|
||||||
% endfor
|
|
||||||
}
|
|
||||||
|
|
||||||
// ComputedValues are compared at times
|
// ComputedValues are compared at times
|
||||||
// so we need these impls. We don't want to
|
// so we need these impls. We don't want to
|
||||||
|
@ -360,26 +347,18 @@ ${helpers.predefined_type(
|
||||||
|
|
||||||
fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
|
fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
|
||||||
use crate::gecko_bindings::bindings;
|
use crate::gecko_bindings::bindings;
|
||||||
use crate::gecko_bindings::structs::{LookAndFeel_FontID, nsFont};
|
use crate::gecko_bindings::structs::nsFont;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use crate::values::computed::Percentage;
|
use crate::values::computed::Percentage;
|
||||||
use crate::values::specified::font::KeywordInfo;
|
use crate::values::specified::font::KeywordInfo;
|
||||||
use crate::values::computed::font::{FontFamily, FontSize, FontStretch, FontStyle, FontFamilyList};
|
use crate::values::computed::font::{FontFamily, FontSize, FontStretch, FontStyle, FontFamilyList};
|
||||||
use crate::values::generics::NonNegative;
|
use crate::values::generics::NonNegative;
|
||||||
|
|
||||||
let id = match *self {
|
|
||||||
% for font in system_fonts:
|
|
||||||
SystemFont::${to_camel_case(font)} => {
|
|
||||||
LookAndFeel_FontID::${to_camel_case(font.replace("-moz-", ""))}
|
|
||||||
}
|
|
||||||
% endfor
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut system = mem::MaybeUninit::<nsFont>::uninit();
|
let mut system = mem::MaybeUninit::<nsFont>::uninit();
|
||||||
let system = unsafe {
|
let system = unsafe {
|
||||||
bindings::Gecko_nsFont_InitSystem(
|
bindings::Gecko_nsFont_InitSystem(
|
||||||
system.as_mut_ptr(),
|
system.as_mut_ptr(),
|
||||||
id as i32,
|
*self,
|
||||||
cx.style().get_font().gecko(),
|
cx.style().get_font().gecko(),
|
||||||
cx.device().document()
|
cx.device().document()
|
||||||
);
|
);
|
||||||
|
@ -455,41 +434,7 @@ ${helpers.predefined_type(
|
||||||
pub default_font_type: GenericFontFamily,
|
pub default_font_type: GenericFontFamily,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SystemFont {
|
}
|
||||||
pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
|
|
||||||
try_match_ident_ignore_ascii_case! { input,
|
|
||||||
% for font in system_fonts:
|
|
||||||
"${font}" => Ok(SystemFont::${to_camel_case(font)}),
|
|
||||||
% endfor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToCss for SystemFont {
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
// We may want to do something better in the future, see
|
|
||||||
// w3c/csswg-drafts#1586.
|
|
||||||
dest.write_str("-moz-use-system-font")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
% else:
|
|
||||||
pub mod system_font {
|
|
||||||
use cssparser::Parser;
|
|
||||||
|
|
||||||
// We don't parse system fonts, but in the interest of not littering
|
|
||||||
// a lot of code with `if engine == "gecko"` conditionals, we have a
|
|
||||||
// dummy system font module that does nothing
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
|
|
||||||
/// void enum for system font, can never exist
|
|
||||||
pub enum SystemFont {}
|
|
||||||
impl SystemFont {
|
|
||||||
pub fn parse(_: &mut Parser) -> Result<Self, ()> {
|
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
${helpers.single_keyword(
|
${helpers.single_keyword(
|
||||||
|
|
|
@ -84,8 +84,7 @@ ${helpers.single_keyword(
|
||||||
|
|
||||||
${helpers.single_keyword(
|
${helpers.single_keyword(
|
||||||
"image-orientation",
|
"image-orientation",
|
||||||
"none from-image",
|
"from-image none",
|
||||||
gecko_pref_controlled_initial_value="layout.css.image-orientation.initial-from-image=from-image",
|
|
||||||
engines="gecko",
|
engines="gecko",
|
||||||
gecko_enum_prefix="StyleImageOrientation",
|
gecko_enum_prefix="StyleImageOrientation",
|
||||||
animation_value_type="discrete",
|
animation_value_type="discrete",
|
||||||
|
|
|
@ -96,45 +96,16 @@ ${helpers.predefined_type(
|
||||||
servo_restyle_damage="rebuild_and_reflow",
|
servo_restyle_damage="rebuild_and_reflow",
|
||||||
)}
|
)}
|
||||||
|
|
||||||
// TODO(pcwalton): Support `text-justify: distribute`.
|
${helpers.predefined_type(
|
||||||
<%helpers:single_keyword
|
"text-justify",
|
||||||
name="text-justify"
|
"TextJustify",
|
||||||
values="auto none inter-word"
|
"computed::TextJustify::Auto",
|
||||||
engines="gecko servo-2013 servo-2020",
|
engines="gecko servo-2013 servo-2020",
|
||||||
servo_2020_pref="layout.2020.unimplemented",
|
servo_2020_pref="layout.2020.unimplemented",
|
||||||
extra_gecko_values="inter-character"
|
animation_value_type="discrete",
|
||||||
extra_specified="${'distribute' if engine == 'gecko' else ''}"
|
spec="https://drafts.csswg.org/css-text/#propdef-text-justify",
|
||||||
gecko_enum_prefix="StyleTextJustify"
|
servo_restyle_damage="rebuild_and_reflow",
|
||||||
animation_value_type="discrete"
|
)}
|
||||||
spec="https://drafts.csswg.org/css-text/#propdef-text-justify"
|
|
||||||
servo_restyle_damage="rebuild_and_reflow"
|
|
||||||
>
|
|
||||||
% if engine == 'gecko':
|
|
||||||
impl ToComputedValue for SpecifiedValue {
|
|
||||||
type ComputedValue = computed_value::T;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_computed_value(&self, _: &Context) -> computed_value::T {
|
|
||||||
match *self {
|
|
||||||
% for value in "Auto None InterCharacter InterWord".split():
|
|
||||||
SpecifiedValue::${value} => computed_value::T::${value},
|
|
||||||
% endfor
|
|
||||||
// https://drafts.csswg.org/css-text-3/#valdef-text-justify-distribute
|
|
||||||
SpecifiedValue::Distribute => computed_value::T::InterCharacter,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn from_computed_value(computed: &computed_value::T) -> SpecifiedValue {
|
|
||||||
match *computed {
|
|
||||||
% for value in "Auto None InterCharacter InterWord".split():
|
|
||||||
computed_value::T::${value} => SpecifiedValue::${value},
|
|
||||||
% endfor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
% endif
|
|
||||||
</%helpers:single_keyword>
|
|
||||||
|
|
||||||
${helpers.predefined_type(
|
${helpers.predefined_type(
|
||||||
"text-align-last",
|
"text-align-last",
|
||||||
|
@ -329,13 +300,13 @@ ${helpers.single_keyword(
|
||||||
spec="https://drafts.csswg.org/css-ruby/#ruby-align-property",
|
spec="https://drafts.csswg.org/css-ruby/#ruby-align-property",
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${helpers.single_keyword(
|
${helpers.predefined_type(
|
||||||
"ruby-position",
|
"ruby-position",
|
||||||
"over under",
|
"RubyPosition",
|
||||||
|
"computed::RubyPosition::AlternateOver",
|
||||||
engines="gecko",
|
engines="gecko",
|
||||||
animation_value_type="discrete",
|
|
||||||
spec="https://drafts.csswg.org/css-ruby/#ruby-position-property",
|
spec="https://drafts.csswg.org/css-ruby/#ruby-position-property",
|
||||||
gecko_enum_prefix="StyleRubyPosition",
|
animation_value_type="discrete",
|
||||||
)}
|
)}
|
||||||
|
|
||||||
// CSS Writing Modes Module Level 3
|
// CSS Writing Modes Module Level 3
|
||||||
|
@ -360,15 +331,13 @@ ${helpers.single_keyword(
|
||||||
servo_restyle_damage="rebuild_and_reflow",
|
servo_restyle_damage="rebuild_and_reflow",
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${helpers.single_keyword(
|
${helpers.predefined_type(
|
||||||
"-moz-control-character-visibility",
|
"-moz-control-character-visibility",
|
||||||
"hidden visible",
|
"text::MozControlCharacterVisibility",
|
||||||
|
"Default::default()",
|
||||||
engines="gecko",
|
engines="gecko",
|
||||||
gecko_enum_prefix="StyleControlCharacterVisibility",
|
|
||||||
gecko_pref_controlled_initial_value="layout.css.control-characters.visible=visible",
|
|
||||||
animation_value_type="none",
|
animation_value_type="none",
|
||||||
gecko_ffi_name="mControlCharacterVisibility",
|
spec="Nonstandard"
|
||||||
spec="Nonstandard",
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
// text underline offset
|
// text underline offset
|
||||||
|
|
|
@ -73,13 +73,26 @@ ${helpers.single_keyword(
|
||||||
|
|
||||||
${helpers.predefined_type(
|
${helpers.predefined_type(
|
||||||
"caret-color",
|
"caret-color",
|
||||||
|
"color::CaretColor",
|
||||||
|
"generics::color::CaretColor::auto()",
|
||||||
|
engines="gecko",
|
||||||
|
spec="https://drafts.csswg.org/css-ui/#caret-color",
|
||||||
|
animation_value_type="CaretColor",
|
||||||
|
boxed=True,
|
||||||
|
ignored_when_colors_disabled=True,
|
||||||
|
)}
|
||||||
|
|
||||||
|
${helpers.predefined_type(
|
||||||
|
"accent-color",
|
||||||
"ColorOrAuto",
|
"ColorOrAuto",
|
||||||
"generics::color::ColorOrAuto::Auto",
|
"generics::color::ColorOrAuto::Auto",
|
||||||
engines="gecko",
|
engines="gecko",
|
||||||
spec="https://drafts.csswg.org/css-ui/#caret-color",
|
spec="https://drafts.csswg.org/css-ui-4/#widget-accent",
|
||||||
animation_value_type="AnimatedCaretColor",
|
gecko_pref="layout.css.accent-color.enabled",
|
||||||
|
animation_value_type="ColorOrAuto",
|
||||||
boxed=True,
|
boxed=True,
|
||||||
ignored_when_colors_disabled=True,
|
ignored_when_colors_disabled=True,
|
||||||
|
has_effect_on_gecko_scrollbars=False,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${helpers.predefined_type(
|
${helpers.predefined_type(
|
||||||
|
|
|
@ -51,6 +51,7 @@ ${helpers.predefined_type(
|
||||||
engines="gecko",
|
engines="gecko",
|
||||||
boxed=True,
|
boxed=True,
|
||||||
animation_value_type="BorderCornerRadius",
|
animation_value_type="BorderCornerRadius",
|
||||||
|
gecko_pref="layout.css.moz-outline-radius.enabled",
|
||||||
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-outline-radius)",
|
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-outline-radius)",
|
||||||
)}
|
)}
|
||||||
% endfor
|
% endfor
|
||||||
|
|
21
components/style/properties/longhands/page.mako.rs
Normal file
21
components/style/properties/longhands/page.mako.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
<%namespace name="helpers" file="/helpers.mako.rs" />
|
||||||
|
<% from data import PAGE_RULE %>
|
||||||
|
|
||||||
|
<% data.new_style_struct("Page", inherited=False) %>
|
||||||
|
|
||||||
|
${helpers.predefined_type(
|
||||||
|
"size",
|
||||||
|
"PageSize",
|
||||||
|
"computed::PageSize::auto()",
|
||||||
|
engines="gecko",
|
||||||
|
gecko_pref="layout.css.page-size.enabled",
|
||||||
|
initial_specified_value="specified::PageSize::auto()",
|
||||||
|
spec="https://drafts.csswg.org/css-page-3/#page-size-prop",
|
||||||
|
boxed=True,
|
||||||
|
animation_value_type="none",
|
||||||
|
rule_types_allowed=PAGE_RULE,
|
||||||
|
)}
|
|
@ -60,7 +60,6 @@ ${helpers.predefined_type(
|
||||||
"computed::ZIndex::auto()",
|
"computed::ZIndex::auto()",
|
||||||
engines="gecko servo-2013 servo-2020",
|
engines="gecko servo-2013 servo-2020",
|
||||||
spec="https://www.w3.org/TR/CSS2/visuren.html#z-index",
|
spec="https://www.w3.org/TR/CSS2/visuren.html#z-index",
|
||||||
flags="CREATES_STACKING_CONTEXT",
|
|
||||||
animation_value_type="ComputedValue",
|
animation_value_type="ComputedValue",
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,6 @@ ${helpers.predefined_type(
|
||||||
"generics::basic_shape::ClipPath::None",
|
"generics::basic_shape::ClipPath::None",
|
||||||
engines="gecko",
|
engines="gecko",
|
||||||
animation_value_type="basic_shape::ClipPath",
|
animation_value_type="basic_shape::ClipPath",
|
||||||
flags="CREATES_STACKING_CONTEXT",
|
|
||||||
spec="https://drafts.fxtf.org/css-masking/#propdef-clip-path",
|
spec="https://drafts.fxtf.org/css-masking/#propdef-clip-path",
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
@ -183,7 +182,6 @@ ${helpers.predefined_type(
|
||||||
vector=True,
|
vector=True,
|
||||||
extra_prefixes="webkit",
|
extra_prefixes="webkit",
|
||||||
animation_value_type="discrete",
|
animation_value_type="discrete",
|
||||||
flags="CREATES_STACKING_CONTEXT",
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${helpers.predefined_type(
|
${helpers.predefined_type(
|
||||||
|
|
|
@ -53,7 +53,7 @@ ${helpers.single_keyword(
|
||||||
|
|
||||||
${helpers.single_keyword(
|
${helpers.single_keyword(
|
||||||
"-moz-window-shadow",
|
"-moz-window-shadow",
|
||||||
"default none menu tooltip sheet",
|
"default none menu tooltip sheet cliprounded",
|
||||||
engines="gecko",
|
engines="gecko",
|
||||||
gecko_ffi_name="mWindowShadow",
|
gecko_ffi_name="mWindowShadow",
|
||||||
gecko_enum_prefix="StyleWindowShadow",
|
gecko_enum_prefix="StyleWindowShadow",
|
||||||
|
|
|
@ -32,7 +32,6 @@ use crate::computed_value_flags::*;
|
||||||
use crate::hash::FxHashMap;
|
use crate::hash::FxHashMap;
|
||||||
use crate::media_queries::Device;
|
use crate::media_queries::Device;
|
||||||
use crate::parser::ParserContext;
|
use crate::parser::ParserContext;
|
||||||
use crate::properties::longhands::system_font::SystemFont;
|
|
||||||
use crate::selector_parser::PseudoElement;
|
use crate::selector_parser::PseudoElement;
|
||||||
#[cfg(feature = "servo")] use servo_config::prefs;
|
#[cfg(feature = "servo")] use servo_config::prefs;
|
||||||
use style_traits::{CssWriter, KeywordsCollectFn, ParseError, ParsingMode};
|
use style_traits::{CssWriter, KeywordsCollectFn, ParseError, ParsingMode};
|
||||||
|
@ -44,6 +43,7 @@ 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;
|
||||||
use crate::values::serialize_atom_name;
|
use crate::values::serialize_atom_name;
|
||||||
|
use crate::values::specified::font::SystemFont;
|
||||||
use crate::rule_tree::StrongRuleNode;
|
use crate::rule_tree::StrongRuleNode;
|
||||||
use crate::Zero;
|
use crate::Zero;
|
||||||
use crate::str::{CssString, CssStringWriter};
|
use crate::str::{CssString, CssStringWriter};
|
||||||
|
@ -1068,28 +1068,20 @@ impl CSSWideKeyword {
|
||||||
bitflags! {
|
bitflags! {
|
||||||
/// A set of flags for properties.
|
/// A set of flags for properties.
|
||||||
pub struct PropertyFlags: u16 {
|
pub struct PropertyFlags: u16 {
|
||||||
/// This property requires a stacking context.
|
|
||||||
const CREATES_STACKING_CONTEXT = 1 << 0;
|
|
||||||
/// This property has values that can establish a containing block for
|
|
||||||
/// fixed positioned and absolutely positioned elements.
|
|
||||||
const FIXPOS_CB = 1 << 1;
|
|
||||||
/// This property has values that can establish a containing block for
|
|
||||||
/// absolutely positioned elements.
|
|
||||||
const ABSPOS_CB = 1 << 2;
|
|
||||||
/// This longhand property applies to ::first-letter.
|
/// This longhand property applies to ::first-letter.
|
||||||
const APPLIES_TO_FIRST_LETTER = 1 << 3;
|
const APPLIES_TO_FIRST_LETTER = 1 << 1;
|
||||||
/// This longhand property applies to ::first-line.
|
/// This longhand property applies to ::first-line.
|
||||||
const APPLIES_TO_FIRST_LINE = 1 << 4;
|
const APPLIES_TO_FIRST_LINE = 1 << 2;
|
||||||
/// This longhand property applies to ::placeholder.
|
/// This longhand property applies to ::placeholder.
|
||||||
const APPLIES_TO_PLACEHOLDER = 1 << 5;
|
const APPLIES_TO_PLACEHOLDER = 1 << 3;
|
||||||
/// This longhand property applies to ::cue.
|
/// This longhand property applies to ::cue.
|
||||||
const APPLIES_TO_CUE = 1 << 6;
|
const APPLIES_TO_CUE = 1 << 4;
|
||||||
/// This longhand property applies to ::marker.
|
/// This longhand property applies to ::marker.
|
||||||
const APPLIES_TO_MARKER = 1 << 7;
|
const APPLIES_TO_MARKER = 1 << 5;
|
||||||
/// This property is a legacy shorthand.
|
/// This property is a legacy shorthand.
|
||||||
///
|
///
|
||||||
/// https://drafts.csswg.org/css-cascade/#legacy-shorthand
|
/// https://drafts.csswg.org/css-cascade/#legacy-shorthand
|
||||||
const IS_LEGACY_SHORTHAND = 1 << 8;
|
const IS_LEGACY_SHORTHAND = 1 << 6;
|
||||||
|
|
||||||
/* The following flags are currently not used in Rust code, they
|
/* The following flags are currently not used in Rust code, they
|
||||||
* only need to be listed in corresponding properties so that
|
* only need to be listed in corresponding properties so that
|
||||||
|
@ -1757,7 +1749,21 @@ impl UnparsedValue {
|
||||||
shorthand_cache.insert((shorthand, longhand), declaration);
|
shorthand_cache.insert((shorthand, longhand), declaration);
|
||||||
}
|
}
|
||||||
|
|
||||||
Cow::Borrowed(&shorthand_cache[&(shorthand, longhand_id)])
|
let key = (shorthand, longhand_id);
|
||||||
|
match shorthand_cache.get(&key) {
|
||||||
|
Some(decl) => Cow::Borrowed(decl),
|
||||||
|
None => {
|
||||||
|
// FIXME: We should always have the key here but it seems
|
||||||
|
// sometimes we don't, see bug 1696409.
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
{
|
||||||
|
if structs::GECKO_IS_NIGHTLY {
|
||||||
|
panic!("Expected {:?} to be in the cache but it was not!", key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
invalid_at_computed_value_time()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,11 +34,11 @@
|
||||||
use crate::parser::Parse;
|
use crate::parser::Parse;
|
||||||
use crate::properties::longhands::{font_family, font_style, font_weight, font_stretch};
|
use crate::properties::longhands::{font_family, font_style, font_weight, font_stretch};
|
||||||
use crate::properties::longhands::font_variant_caps;
|
use crate::properties::longhands::font_variant_caps;
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
use crate::properties::longhands::system_font::SystemFont;
|
|
||||||
use crate::values::specified::text::LineHeight;
|
use crate::values::specified::text::LineHeight;
|
||||||
use crate::values::specified::FontSize;
|
use crate::values::specified::FontSize;
|
||||||
use crate::values::specified::font::{FontStretch, FontStretchKeyword};
|
use crate::values::specified::font::{FontStretch, FontStretchKeyword};
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
use crate::values::specified::font::SystemFont;
|
||||||
|
|
||||||
<%
|
<%
|
||||||
gecko_sub_properties = "kerning language_override size_adjust \
|
gecko_sub_properties = "kerning language_override size_adjust \
|
||||||
|
@ -197,7 +197,7 @@
|
||||||
let font_stretch = match *self.font_stretch {
|
let font_stretch = match *self.font_stretch {
|
||||||
FontStretch::Keyword(kw) => kw,
|
FontStretch::Keyword(kw) => kw,
|
||||||
FontStretch::Stretch(percentage) => {
|
FontStretch::Stretch(percentage) => {
|
||||||
match FontStretchKeyword::from_percentage(percentage.get()) {
|
match FontStretchKeyword::from_percentage(percentage.0.get()) {
|
||||||
Some(kw) => kw,
|
Some(kw) => kw,
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
}
|
}
|
||||||
|
@ -289,7 +289,9 @@
|
||||||
% for p in subprops_for_value_info:
|
% for p in subprops_for_value_info:
|
||||||
${p}::collect_completion_keywords(f);
|
${p}::collect_completion_keywords(f);
|
||||||
% endfor
|
% endfor
|
||||||
<longhands::system_font::SystemFont as SpecifiedValueInfo>::collect_completion_keywords(f);
|
% if engine == "gecko":
|
||||||
|
<SystemFont as SpecifiedValueInfo>::collect_completion_keywords(f);
|
||||||
|
% endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</%helpers:shorthand>
|
</%helpers:shorthand>
|
||||||
|
|
|
@ -83,6 +83,7 @@
|
||||||
<%helpers:shorthand
|
<%helpers:shorthand
|
||||||
name="-moz-outline-radius"
|
name="-moz-outline-radius"
|
||||||
engines="gecko"
|
engines="gecko"
|
||||||
|
gecko_pref="layout.css.moz-outline-radius.enabled"
|
||||||
sub_properties="${' '.join(
|
sub_properties="${' '.join(
|
||||||
'-moz-outline-radius-%s' % corner
|
'-moz-outline-radius-%s' % corner
|
||||||
for corner in ['topleft', 'topright', 'bottomright', 'bottomleft']
|
for corner in ['topleft', 'topright', 'bottomright', 'bottomleft']
|
||||||
|
|
|
@ -94,7 +94,7 @@ pub trait SelectorMapEntry: Sized + Clone {
|
||||||
/// * https://bugzilla.mozilla.org/show_bug.cgi?id=681755
|
/// * https://bugzilla.mozilla.org/show_bug.cgi?id=681755
|
||||||
///
|
///
|
||||||
/// TODO: Tune the initial capacity of the HashMap
|
/// TODO: Tune the initial capacity of the HashMap
|
||||||
#[derive(Debug, MallocSizeOf)]
|
#[derive(Clone, Debug, MallocSizeOf)]
|
||||||
pub struct SelectorMap<T: 'static> {
|
pub struct SelectorMap<T: 'static> {
|
||||||
/// Rules that have `:root` selectors.
|
/// Rules that have `:root` selectors.
|
||||||
pub root: SmallVec<[T; 1]>,
|
pub root: SmallVec<[T; 1]>,
|
||||||
|
@ -615,7 +615,7 @@ fn find_bucket<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrapper for PrecomputedHashMap that does ASCII-case-insensitive lookup in quirks mode.
|
/// Wrapper for PrecomputedHashMap that does ASCII-case-insensitive lookup in quirks mode.
|
||||||
#[derive(Debug, MallocSizeOf)]
|
#[derive(Clone, Debug, MallocSizeOf)]
|
||||||
pub struct MaybeCaseInsensitiveHashMap<K: PrecomputedHash + Hash + Eq, V: 'static>(
|
pub struct MaybeCaseInsensitiveHashMap<K: PrecomputedHash + Hash + Eq, V: 'static>(
|
||||||
PrecomputedHashMap<K, V>,
|
PrecomputedHashMap<K, V>,
|
||||||
);
|
);
|
||||||
|
|
|
@ -108,7 +108,7 @@ pub enum PseudoElementCascadeType {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A per-pseudo map, from a given pseudo to a `T`.
|
/// A per-pseudo map, from a given pseudo to a `T`.
|
||||||
#[derive(MallocSizeOf)]
|
#[derive(Clone, MallocSizeOf)]
|
||||||
pub struct PerPseudoElementMap<T> {
|
pub struct PerPseudoElementMap<T> {
|
||||||
entries: [Option<T>; PSEUDO_COUNT],
|
entries: [Option<T>; PSEUDO_COUNT],
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ use app_units::Au;
|
||||||
use cssparser::RGBA;
|
use cssparser::RGBA;
|
||||||
use euclid::default::Size2D as UntypedSize2D;
|
use euclid::default::Size2D as UntypedSize2D;
|
||||||
use euclid::{Scale, SideOffsets2D, Size2D};
|
use euclid::{Scale, SideOffsets2D, Size2D};
|
||||||
|
use mime::Mime;
|
||||||
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
|
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
|
||||||
use style_traits::viewport::ViewportConstraints;
|
use style_traits::viewport::ViewportConstraints;
|
||||||
use style_traits::{CSSPixel, DevicePixel};
|
use style_traits::{CSSPixel, DevicePixel};
|
||||||
|
@ -202,6 +203,23 @@ impl Device {
|
||||||
pub fn safe_area_insets(&self) -> SideOffsets2D<f32, CSSPixel> {
|
pub fn safe_area_insets(&self) -> SideOffsets2D<f32, CSSPixel> {
|
||||||
SideOffsets2D::zero()
|
SideOffsets2D::zero()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the given MIME type is supported
|
||||||
|
pub fn is_supported_mime_type(&self, mime_type: &str) -> bool {
|
||||||
|
match mime_type.parse::<Mime>() {
|
||||||
|
Ok(m) => {
|
||||||
|
// Keep this in sync with 'image_classifer' from
|
||||||
|
// components/net/mime_classifier.rs
|
||||||
|
m == mime::IMAGE_BMP
|
||||||
|
|| m == mime::IMAGE_GIF
|
||||||
|
|| m == mime::IMAGE_PNG
|
||||||
|
|| m == mime::IMAGE_JPEG
|
||||||
|
|| m == "image/x-icon"
|
||||||
|
|| m == "image/webp"
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://drafts.csswg.org/mediaqueries-4/#width
|
/// https://drafts.csswg.org/mediaqueries-4/#width
|
||||||
|
|
|
@ -372,7 +372,7 @@ impl NonTSPseudoClass {
|
||||||
Disabled => ElementState::IN_DISABLED_STATE,
|
Disabled => ElementState::IN_DISABLED_STATE,
|
||||||
Checked => ElementState::IN_CHECKED_STATE,
|
Checked => ElementState::IN_CHECKED_STATE,
|
||||||
Indeterminate => ElementState::IN_INDETERMINATE_STATE,
|
Indeterminate => ElementState::IN_INDETERMINATE_STATE,
|
||||||
ReadOnly | ReadWrite => ElementState::IN_READ_WRITE_STATE,
|
ReadOnly | ReadWrite => ElementState::IN_READWRITE_STATE,
|
||||||
PlaceholderShown => ElementState::IN_PLACEHOLDER_SHOWN_STATE,
|
PlaceholderShown => ElementState::IN_PLACEHOLDER_SHOWN_STATE,
|
||||||
Target => ElementState::IN_TARGET_STATE,
|
Target => ElementState::IN_TARGET_STATE,
|
||||||
|
|
||||||
|
|
|
@ -184,7 +184,9 @@ pub struct SheetCollectionFlusher<'a, S>
|
||||||
where
|
where
|
||||||
S: StylesheetInDocument + PartialEq + 'static,
|
S: StylesheetInDocument + PartialEq + 'static,
|
||||||
{
|
{
|
||||||
iter: slice::IterMut<'a, StylesheetSetEntry<S>>,
|
// TODO: This can be made an iterator again once
|
||||||
|
// https://github.com/rust-lang/rust/pull/82771 lands on stable.
|
||||||
|
entries: &'a mut [StylesheetSetEntry<S>],
|
||||||
validity: DataValidity,
|
validity: DataValidity,
|
||||||
dirty: bool,
|
dirty: bool,
|
||||||
}
|
}
|
||||||
|
@ -204,32 +206,42 @@ where
|
||||||
pub fn data_validity(&self) -> DataValidity {
|
pub fn data_validity(&self) -> DataValidity {
|
||||||
self.validity
|
self.validity
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator over the remaining list of sheets to consume.
|
||||||
|
pub fn sheets<'b>(&'b self) -> impl Iterator<Item = &'b S> {
|
||||||
|
self.entries.iter().map(|entry| &entry.sheet)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, S> Iterator for SheetCollectionFlusher<'a, S>
|
impl<'a, S> SheetCollectionFlusher<'a, S>
|
||||||
where
|
where
|
||||||
S: StylesheetInDocument + PartialEq + 'static,
|
S: StylesheetInDocument + PartialEq + 'static,
|
||||||
{
|
{
|
||||||
type Item = (&'a S, SheetRebuildKind);
|
/// Iterates over all sheets and values that we have to invalidate.
|
||||||
|
///
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
/// TODO(emilio): This would be nicer as an iterator but we can't do that
|
||||||
loop {
|
/// until https://github.com/rust-lang/rust/pull/82771 stabilizes.
|
||||||
let potential_sheet = self.iter.next()?;
|
///
|
||||||
|
/// Since we don't have a good use-case for partial iteration, this does the
|
||||||
|
/// trick for now.
|
||||||
|
pub fn each(self, mut callback: impl FnMut(&S, SheetRebuildKind) -> bool) {
|
||||||
|
for potential_sheet in self.entries.iter_mut() {
|
||||||
let committed = mem::replace(&mut potential_sheet.committed, true);
|
let committed = mem::replace(&mut potential_sheet.committed, true);
|
||||||
if !committed {
|
let rebuild_kind = if !committed {
|
||||||
// If the sheet was uncommitted, we need to do a full rebuild
|
// If the sheet was uncommitted, we need to do a full rebuild
|
||||||
// anyway.
|
// anyway.
|
||||||
return Some((&potential_sheet.sheet, SheetRebuildKind::Full));
|
SheetRebuildKind::Full
|
||||||
}
|
} else {
|
||||||
|
match self.validity {
|
||||||
let rebuild_kind = match self.validity {
|
|
||||||
DataValidity::Valid => continue,
|
DataValidity::Valid => continue,
|
||||||
DataValidity::CascadeInvalid => SheetRebuildKind::CascadeOnly,
|
DataValidity::CascadeInvalid => SheetRebuildKind::CascadeOnly,
|
||||||
DataValidity::FullyInvalid => SheetRebuildKind::Full,
|
DataValidity::FullyInvalid => SheetRebuildKind::Full,
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return Some((&potential_sheet.sheet, rebuild_kind));
|
if !callback(&potential_sheet.sheet, rebuild_kind) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -357,7 +369,7 @@ where
|
||||||
let validity = mem::replace(&mut self.data_validity, DataValidity::Valid);
|
let validity = mem::replace(&mut self.data_validity, DataValidity::Valid);
|
||||||
|
|
||||||
SheetCollectionFlusher {
|
SheetCollectionFlusher {
|
||||||
iter: self.entries.iter_mut(),
|
entries: &mut self.entries,
|
||||||
dirty,
|
dirty,
|
||||||
validity,
|
validity,
|
||||||
}
|
}
|
||||||
|
@ -408,7 +420,7 @@ macro_rules! sheet_set_methods {
|
||||||
) {
|
) {
|
||||||
debug!(concat!($set_name, "::append_stylesheet"));
|
debug!(concat!($set_name, "::append_stylesheet"));
|
||||||
self.collect_invalidations_for(device, &sheet, guard);
|
self.collect_invalidations_for(device, &sheet, guard);
|
||||||
let collection = self.collection_for(&sheet, guard);
|
let collection = self.collection_for(&sheet);
|
||||||
collection.append(sheet);
|
collection.append(sheet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,7 +435,7 @@ macro_rules! sheet_set_methods {
|
||||||
debug!(concat!($set_name, "::insert_stylesheet_before"));
|
debug!(concat!($set_name, "::insert_stylesheet_before"));
|
||||||
self.collect_invalidations_for(device, &sheet, guard);
|
self.collect_invalidations_for(device, &sheet, guard);
|
||||||
|
|
||||||
let collection = self.collection_for(&sheet, guard);
|
let collection = self.collection_for(&sheet);
|
||||||
collection.insert_before(sheet, &before_sheet);
|
collection.insert_before(sheet, &before_sheet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -437,7 +449,7 @@ macro_rules! sheet_set_methods {
|
||||||
debug!(concat!($set_name, "::remove_stylesheet"));
|
debug!(concat!($set_name, "::remove_stylesheet"));
|
||||||
self.collect_invalidations_for(device, &sheet, guard);
|
self.collect_invalidations_for(device, &sheet, guard);
|
||||||
|
|
||||||
let collection = self.collection_for(&sheet, guard);
|
let collection = self.collection_for(&sheet);
|
||||||
collection.remove(&sheet)
|
collection.remove(&sheet)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,7 +499,7 @@ macro_rules! sheet_set_methods {
|
||||||
RuleChangeKind::StyleRuleDeclarations => DataValidity::FullyInvalid,
|
RuleChangeKind::StyleRuleDeclarations => DataValidity::FullyInvalid,
|
||||||
};
|
};
|
||||||
|
|
||||||
let collection = self.collection_for(&sheet, guard);
|
let collection = self.collection_for(&sheet);
|
||||||
collection.set_data_validity_at_least(validity);
|
collection.set_data_validity_at_least(validity);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -505,12 +517,8 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collection_for(
|
fn collection_for(&mut self, sheet: &S) -> &mut SheetCollection<S> {
|
||||||
&mut self,
|
let origin = sheet.contents().origin;
|
||||||
sheet: &S,
|
|
||||||
guard: &SharedRwLockReadGuard,
|
|
||||||
) -> &mut SheetCollection<S> {
|
|
||||||
let origin = sheet.origin(guard);
|
|
||||||
self.collections.borrow_mut_for_origin(&origin)
|
self.collections.borrow_mut_for_origin(&origin)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -658,11 +666,7 @@ where
|
||||||
self.collection.len()
|
self.collection.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collection_for(
|
fn collection_for(&mut self, _sheet: &S) -> &mut SheetCollection<S> {
|
||||||
&mut self,
|
|
||||||
_sheet: &S,
|
|
||||||
_guard: &SharedRwLockReadGuard,
|
|
||||||
) -> &mut SheetCollection<S> {
|
|
||||||
&mut self.collection
|
&mut self.collection
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,12 +6,11 @@
|
||||||
//!
|
//!
|
||||||
//! [import]: https://drafts.csswg.org/css-cascade-3/#at-import
|
//! [import]: https://drafts.csswg.org/css-cascade-3/#at-import
|
||||||
|
|
||||||
use crate::context::QuirksMode;
|
|
||||||
use crate::media_queries::MediaList;
|
use crate::media_queries::MediaList;
|
||||||
use crate::shared_lock::{DeepCloneParams, DeepCloneWithLock};
|
use crate::shared_lock::{DeepCloneParams, DeepCloneWithLock};
|
||||||
use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
|
use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
|
||||||
use crate::str::CssStringWriter;
|
use crate::str::CssStringWriter;
|
||||||
use crate::stylesheets::{CssRule, Origin, StylesheetInDocument};
|
use crate::stylesheets::{CssRule, StylesheetInDocument};
|
||||||
use crate::values::CssUrl;
|
use crate::values::CssUrl;
|
||||||
use cssparser::SourceLocation;
|
use cssparser::SourceLocation;
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
|
@ -61,6 +60,19 @@ impl ImportSheet {
|
||||||
ImportSheet::Pending(_) => None,
|
ImportSheet::Pending(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the media list for this import rule.
|
||||||
|
pub fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
|
||||||
|
self.as_sheet().and_then(|s| s.media(guard))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the rule list for this import rule.
|
||||||
|
pub fn rules<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a [CssRule] {
|
||||||
|
match self.as_sheet() {
|
||||||
|
Some(s) => s.rules(guard),
|
||||||
|
None => &[],
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
|
@ -85,68 +97,20 @@ impl DeepCloneWithLock for ImportSheet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
impl StylesheetInDocument for ImportSheet {
|
|
||||||
fn origin(&self, _guard: &SharedRwLockReadGuard) -> Origin {
|
|
||||||
match *self {
|
|
||||||
ImportSheet::Sheet(ref s) => s.contents().origin,
|
|
||||||
ImportSheet::Pending(ref p) => p.origin,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn quirks_mode(&self, _guard: &SharedRwLockReadGuard) -> QuirksMode {
|
|
||||||
match *self {
|
|
||||||
ImportSheet::Sheet(ref s) => s.contents().quirks_mode,
|
|
||||||
ImportSheet::Pending(ref p) => p.quirks_mode,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn enabled(&self) -> bool {
|
|
||||||
match *self {
|
|
||||||
ImportSheet::Sheet(ref s) => s.enabled(),
|
|
||||||
ImportSheet::Pending(_) => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
|
|
||||||
match *self {
|
|
||||||
ImportSheet::Sheet(ref s) => s.media(guard),
|
|
||||||
ImportSheet::Pending(_) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule] {
|
|
||||||
match *self {
|
|
||||||
ImportSheet::Sheet(ref s) => s.contents().rules(guard),
|
|
||||||
ImportSheet::Pending(_) => &[],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A sheet that is held from an import rule.
|
/// A sheet that is held from an import rule.
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ImportSheet(pub ::servo_arc::Arc<crate::stylesheets::Stylesheet>);
|
pub struct ImportSheet(pub ::servo_arc::Arc<crate::stylesheets::Stylesheet>);
|
||||||
|
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
impl StylesheetInDocument for ImportSheet {
|
impl ImportSheet {
|
||||||
fn origin(&self, guard: &SharedRwLockReadGuard) -> Origin {
|
/// Returns the media list for this import rule.
|
||||||
self.0.origin(guard)
|
pub fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
|
||||||
}
|
|
||||||
|
|
||||||
fn quirks_mode(&self, guard: &SharedRwLockReadGuard) -> QuirksMode {
|
|
||||||
self.0.quirks_mode(guard)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn enabled(&self) -> bool {
|
|
||||||
self.0.enabled()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
|
|
||||||
self.0.media(guard)
|
self.0.media(guard)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule] {
|
/// Returns the rules for this import rule.
|
||||||
|
pub fn rules<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a [CssRule] {
|
||||||
self.0.rules(guard)
|
self.0.rules(guard)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ pub struct TopLevelRuleParser<'a> {
|
||||||
/// This won't contain any namespaces, and only nested parsers created with
|
/// This won't contain any namespaces, and only nested parsers created with
|
||||||
/// `ParserContext::new_with_rule_type` will.
|
/// `ParserContext::new_with_rule_type` will.
|
||||||
pub context: ParserContext<'a>,
|
pub context: ParserContext<'a>,
|
||||||
/// The current stajkj/te of the parser.
|
/// The current state of the parser.
|
||||||
pub state: State,
|
pub state: State,
|
||||||
/// Whether we have tried to parse was invalid due to being in the wrong
|
/// Whether we have tried to parse was invalid due to being in the wrong
|
||||||
/// place (e.g. an @import rule was found while in the `Body` state). Reset
|
/// place (e.g. an @import rule was found while in the `Body` state). Reset
|
||||||
|
@ -587,6 +587,38 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
fn check_for_useless_selector(
|
||||||
|
input: &mut Parser,
|
||||||
|
context: &ParserContext,
|
||||||
|
selectors: &SelectorList<SelectorImpl>,
|
||||||
|
) {
|
||||||
|
use cssparser::ToCss;
|
||||||
|
|
||||||
|
'selector_loop: for selector in selectors.0.iter() {
|
||||||
|
let mut current = selector.iter();
|
||||||
|
loop {
|
||||||
|
let mut found_host = false;
|
||||||
|
let mut found_non_host = false;
|
||||||
|
for component in &mut current {
|
||||||
|
if component.is_host() {
|
||||||
|
found_host = true;
|
||||||
|
} else {
|
||||||
|
found_non_host = true;
|
||||||
|
}
|
||||||
|
if found_host && found_non_host {
|
||||||
|
let location = input.current_source_location();
|
||||||
|
context.log_css_error(location, ContextualParseError::NeverMatchingHostSelector(selector.to_css_string()));
|
||||||
|
continue 'selector_loop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if current.next_sequence().is_none() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, 'b, 'i> QualifiedRuleParser<'i> for NestedRuleParser<'a, 'b> {
|
impl<'a, 'b, 'i> QualifiedRuleParser<'i> for NestedRuleParser<'a, 'b> {
|
||||||
type Prelude = SelectorList<SelectorImpl>;
|
type Prelude = SelectorList<SelectorImpl>;
|
||||||
type QualifiedRule = CssRule;
|
type QualifiedRule = CssRule;
|
||||||
|
@ -601,7 +633,11 @@ impl<'a, 'b, 'i> QualifiedRuleParser<'i> for NestedRuleParser<'a, 'b> {
|
||||||
namespaces: self.namespaces,
|
namespaces: self.namespaces,
|
||||||
url_data: Some(self.context.url_data),
|
url_data: Some(self.context.url_data),
|
||||||
};
|
};
|
||||||
SelectorList::parse(&selector_parser, input)
|
let selectors = SelectorList::parse(&selector_parser, input)?;
|
||||||
|
if self.context.error_reporting_enabled() {
|
||||||
|
check_for_useless_selector(input, &self.context, &selectors);
|
||||||
|
}
|
||||||
|
Ok(selectors)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_block<'t>(
|
fn parse_block<'t>(
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
use crate::context::QuirksMode;
|
use crate::context::QuirksMode;
|
||||||
use crate::media_queries::Device;
|
use crate::media_queries::Device;
|
||||||
use crate::shared_lock::SharedRwLockReadGuard;
|
use crate::shared_lock::SharedRwLockReadGuard;
|
||||||
use crate::stylesheets::StylesheetInDocument;
|
|
||||||
use crate::stylesheets::{CssRule, DocumentRule, ImportRule, MediaRule, SupportsRule};
|
use crate::stylesheets::{CssRule, DocumentRule, ImportRule, MediaRule, SupportsRule};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
@ -227,10 +226,13 @@ impl NestedRuleIterationCondition for EffectiveRules {
|
||||||
fn process_import(
|
fn process_import(
|
||||||
guard: &SharedRwLockReadGuard,
|
guard: &SharedRwLockReadGuard,
|
||||||
device: &Device,
|
device: &Device,
|
||||||
_quirks_mode: QuirksMode,
|
quirks_mode: QuirksMode,
|
||||||
rule: &ImportRule,
|
rule: &ImportRule,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
rule.stylesheet.is_effective_for_device(device, guard)
|
match rule.stylesheet.media(guard) {
|
||||||
|
Some(m) => m.evaluate(device, quirks_mode),
|
||||||
|
None => true,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_media(
|
fn process_media(
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
use crate::context::QuirksMode;
|
use crate::context::QuirksMode;
|
||||||
use crate::error_reporting::{ContextualParseError, ParseErrorReporter};
|
use crate::error_reporting::{ContextualParseError, ParseErrorReporter};
|
||||||
use crate::invalidation::media_queries::{MediaListKey, ToMediaListKey};
|
|
||||||
use crate::media_queries::{Device, MediaList};
|
use crate::media_queries::{Device, MediaList};
|
||||||
use crate::parser::ParserContext;
|
use crate::parser::ParserContext;
|
||||||
use crate::shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked};
|
use crate::shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked};
|
||||||
|
@ -102,10 +101,10 @@ impl StylesheetContents {
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
rules: CssRules::new(rules, &shared_lock),
|
rules: CssRules::new(rules, &shared_lock),
|
||||||
origin: origin,
|
origin,
|
||||||
url_data: RwLock::new(url_data),
|
url_data: RwLock::new(url_data),
|
||||||
namespaces: namespaces,
|
namespaces,
|
||||||
quirks_mode: quirks_mode,
|
quirks_mode,
|
||||||
source_map_url: RwLock::new(source_map_url),
|
source_map_url: RwLock::new(source_map_url),
|
||||||
source_url: RwLock::new(source_url),
|
source_url: RwLock::new(source_url),
|
||||||
}
|
}
|
||||||
|
@ -218,12 +217,6 @@ macro_rules! rule_filter {
|
||||||
|
|
||||||
/// A trait to represent a given stylesheet in a document.
|
/// A trait to represent a given stylesheet in a document.
|
||||||
pub trait StylesheetInDocument: ::std::fmt::Debug {
|
pub trait StylesheetInDocument: ::std::fmt::Debug {
|
||||||
/// Get the stylesheet origin.
|
|
||||||
fn origin(&self, guard: &SharedRwLockReadGuard) -> Origin;
|
|
||||||
|
|
||||||
/// Get the stylesheet quirks mode.
|
|
||||||
fn quirks_mode(&self, guard: &SharedRwLockReadGuard) -> QuirksMode;
|
|
||||||
|
|
||||||
/// Get whether this stylesheet is enabled.
|
/// Get whether this stylesheet is enabled.
|
||||||
fn enabled(&self) -> bool;
|
fn enabled(&self) -> bool;
|
||||||
|
|
||||||
|
@ -231,7 +224,12 @@ pub trait StylesheetInDocument: ::std::fmt::Debug {
|
||||||
fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList>;
|
fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList>;
|
||||||
|
|
||||||
/// Returns a reference to the list of rules in this stylesheet.
|
/// Returns a reference to the list of rules in this stylesheet.
|
||||||
fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule];
|
fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule] {
|
||||||
|
self.contents().rules(guard)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a reference to the contents of the stylesheet.
|
||||||
|
fn contents(&self) -> &StylesheetContents;
|
||||||
|
|
||||||
/// Return an iterator using the condition `C`.
|
/// Return an iterator using the condition `C`.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -243,18 +241,19 @@ pub trait StylesheetInDocument: ::std::fmt::Debug {
|
||||||
where
|
where
|
||||||
C: NestedRuleIterationCondition,
|
C: NestedRuleIterationCondition,
|
||||||
{
|
{
|
||||||
|
let contents = self.contents();
|
||||||
RulesIterator::new(
|
RulesIterator::new(
|
||||||
device,
|
device,
|
||||||
self.quirks_mode(guard),
|
contents.quirks_mode,
|
||||||
guard,
|
guard,
|
||||||
self.rules(guard).iter(),
|
contents.rules(guard).iter(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether the style-sheet applies for the current device.
|
/// Returns whether the style-sheet applies for the current device.
|
||||||
fn is_effective_for_device(&self, device: &Device, guard: &SharedRwLockReadGuard) -> bool {
|
fn is_effective_for_device(&self, device: &Device, guard: &SharedRwLockReadGuard) -> bool {
|
||||||
match self.media(guard) {
|
match self.media(guard) {
|
||||||
Some(medialist) => medialist.evaluate(device, self.quirks_mode(guard)),
|
Some(medialist) => medialist.evaluate(device, self.contents().quirks_mode),
|
||||||
None => true,
|
None => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -285,14 +284,6 @@ pub trait StylesheetInDocument: ::std::fmt::Debug {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StylesheetInDocument for Stylesheet {
|
impl StylesheetInDocument for Stylesheet {
|
||||||
fn origin(&self, _guard: &SharedRwLockReadGuard) -> Origin {
|
|
||||||
self.contents.origin
|
|
||||||
}
|
|
||||||
|
|
||||||
fn quirks_mode(&self, _guard: &SharedRwLockReadGuard) -> QuirksMode {
|
|
||||||
self.contents.quirks_mode
|
|
||||||
}
|
|
||||||
|
|
||||||
fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
|
fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
|
||||||
Some(self.media.read_with(guard))
|
Some(self.media.read_with(guard))
|
||||||
}
|
}
|
||||||
|
@ -302,8 +293,8 @@ impl StylesheetInDocument for Stylesheet {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule] {
|
fn contents(&self) -> &StylesheetContents {
|
||||||
self.contents.rules(guard)
|
&self.contents
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,21 +312,7 @@ impl PartialEq for DocumentStyleSheet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToMediaListKey for DocumentStyleSheet {
|
|
||||||
fn to_media_list_key(&self) -> MediaListKey {
|
|
||||||
self.0.to_media_list_key()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StylesheetInDocument for DocumentStyleSheet {
|
impl StylesheetInDocument for DocumentStyleSheet {
|
||||||
fn origin(&self, guard: &SharedRwLockReadGuard) -> Origin {
|
|
||||||
self.0.origin(guard)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn quirks_mode(&self, guard: &SharedRwLockReadGuard) -> QuirksMode {
|
|
||||||
self.0.quirks_mode(guard)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
|
fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
|
||||||
self.0.media(guard)
|
self.0.media(guard)
|
||||||
}
|
}
|
||||||
|
@ -345,8 +322,8 @@ impl StylesheetInDocument for DocumentStyleSheet {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule] {
|
fn contents(&self) -> &StylesheetContents {
|
||||||
self.0.rules(guard)
|
self.0.contents()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ use crate::element_state::{DocumentState, ElementState};
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
use crate::gecko_bindings::structs::{ServoStyleSetSizes, StyleRuleInclusion};
|
use crate::gecko_bindings::structs::{ServoStyleSetSizes, StyleRuleInclusion};
|
||||||
use crate::invalidation::element::invalidation_map::InvalidationMap;
|
use crate::invalidation::element::invalidation_map::InvalidationMap;
|
||||||
use crate::invalidation::media_queries::{EffectiveMediaQueryResults, ToMediaListKey};
|
use crate::invalidation::media_queries::EffectiveMediaQueryResults;
|
||||||
use crate::invalidation::stylesheets::RuleChangeKind;
|
use crate::invalidation::stylesheets::RuleChangeKind;
|
||||||
use crate::media_queries::Device;
|
use crate::media_queries::Device;
|
||||||
use crate::properties::{self, CascadeMode, ComputedValues};
|
use crate::properties::{self, CascadeMode, ComputedValues};
|
||||||
|
@ -60,17 +60,33 @@ pub type StylistSheet = crate::stylesheets::DocumentStyleSheet;
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub type StylistSheet = crate::gecko::data::GeckoStyleSheet;
|
pub type StylistSheet = crate::gecko::data::GeckoStyleSheet;
|
||||||
|
|
||||||
lazy_static! {
|
trait CascadeDataCacheEntry : Sized {
|
||||||
/// A cache of computed user-agent data, to be shared across documents.
|
/// Returns a reference to the cascade data.
|
||||||
static ref UA_CASCADE_DATA_CACHE: Mutex<UserAgentCascadeDataCache> =
|
fn cascade_data(&self) -> &CascadeData;
|
||||||
Mutex::new(UserAgentCascadeDataCache::new());
|
/// Rebuilds the cascade data for the new stylesheet collection. The
|
||||||
|
/// collection is guaranteed to be dirty.
|
||||||
|
fn rebuild<S>(
|
||||||
|
device: &Device,
|
||||||
|
quirks_mode: QuirksMode,
|
||||||
|
collection: SheetCollectionFlusher<S>,
|
||||||
|
guard: &SharedRwLockReadGuard,
|
||||||
|
old_entry: &Self,
|
||||||
|
) -> Result<Arc<Self>, FailedAllocationError>
|
||||||
|
where
|
||||||
|
S: StylesheetInDocument + PartialEq + 'static;
|
||||||
|
/// Measures heap memory usage.
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UserAgentCascadeDataCache {
|
struct CascadeDataCache<Entry> {
|
||||||
entries: Vec<Arc<UserAgentCascadeData>>,
|
entries: Vec<Arc<Entry>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserAgentCascadeDataCache {
|
impl<Entry> CascadeDataCache<Entry>
|
||||||
|
where
|
||||||
|
Entry: CascadeDataCacheEntry,
|
||||||
|
{
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self { entries: vec![] }
|
Self { entries: vec![] }
|
||||||
}
|
}
|
||||||
|
@ -79,53 +95,67 @@ impl UserAgentCascadeDataCache {
|
||||||
self.entries.len()
|
self.entries.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(emilio): This may need to be keyed on quirks-mode too, though there
|
// FIXME(emilio): This may need to be keyed on quirks-mode too, though for
|
||||||
// aren't class / id selectors on those sheets, usually, so it's probably
|
// UA sheets there aren't class / id selectors on those sheets, usually, so
|
||||||
// ok...
|
// it's probably ok... For the other cache the quirks mode shouldn't differ
|
||||||
fn lookup<'a, I, S>(
|
// so also should be fine.
|
||||||
|
fn lookup<'a, S>(
|
||||||
&'a mut self,
|
&'a mut self,
|
||||||
sheets: I,
|
|
||||||
device: &Device,
|
device: &Device,
|
||||||
quirks_mode: QuirksMode,
|
quirks_mode: QuirksMode,
|
||||||
|
collection: SheetCollectionFlusher<S>,
|
||||||
guard: &SharedRwLockReadGuard,
|
guard: &SharedRwLockReadGuard,
|
||||||
) -> Result<Arc<UserAgentCascadeData>, FailedAllocationError>
|
old_entry: &Entry,
|
||||||
|
) -> Result<Option<Arc<Entry>>, FailedAllocationError>
|
||||||
where
|
where
|
||||||
I: Iterator<Item = &'a S> + Clone,
|
S: StylesheetInDocument + PartialEq + 'static,
|
||||||
S: StylesheetInDocument + ToMediaListKey + PartialEq + 'static,
|
|
||||||
{
|
{
|
||||||
|
debug!("StyleSheetCache::lookup({})", self.len());
|
||||||
|
|
||||||
|
if !collection.dirty() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
let mut key = EffectiveMediaQueryResults::new();
|
let mut key = EffectiveMediaQueryResults::new();
|
||||||
debug!("UserAgentCascadeDataCache::lookup({:?})", device);
|
for sheet in collection.sheets() {
|
||||||
for sheet in sheets.clone() {
|
|
||||||
CascadeData::collect_applicable_media_query_results_into(device, sheet, guard, &mut key)
|
CascadeData::collect_applicable_media_query_results_into(device, sheet, guard, &mut key)
|
||||||
}
|
}
|
||||||
|
|
||||||
for entry in &self.entries {
|
for entry in &self.entries {
|
||||||
if entry.cascade_data.effective_media_query_results == key {
|
if std::ptr::eq(&**entry, old_entry) {
|
||||||
return Ok(entry.clone());
|
// Avoid reusing our old entry (this can happen if we get
|
||||||
|
// invalidated due to CSSOM mutations and our old stylesheet
|
||||||
|
// contents were already unique, for example). This old entry
|
||||||
|
// will be pruned from the cache with take_unused() afterwards.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if entry.cascade_data().effective_media_query_results != key {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if log_enabled!(log::Level::Debug) {
|
||||||
|
debug!("cache hit for:");
|
||||||
|
for sheet in collection.sheets() {
|
||||||
|
debug!(" > {:?}", sheet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// The line below ensures the "committed" bit is updated properly
|
||||||
let mut new_data = UserAgentCascadeData {
|
// below.
|
||||||
cascade_data: CascadeData::new(),
|
collection.each(|_, _| true);
|
||||||
precomputed_pseudo_element_decls: PrecomputedPseudoElementDeclarations::default(),
|
return Ok(Some(entry.clone()));
|
||||||
};
|
}
|
||||||
|
|
||||||
debug!("> Picking the slow path");
|
debug!("> Picking the slow path");
|
||||||
|
|
||||||
for sheet in sheets {
|
let new_entry = Entry::rebuild(
|
||||||
new_data.cascade_data.add_stylesheet(
|
|
||||||
device,
|
device,
|
||||||
quirks_mode,
|
quirks_mode,
|
||||||
sheet,
|
collection,
|
||||||
guard,
|
guard,
|
||||||
SheetRebuildKind::Full,
|
old_entry,
|
||||||
Some(&mut new_data.precomputed_pseudo_element_decls),
|
|
||||||
)?;
|
)?;
|
||||||
}
|
|
||||||
|
|
||||||
let new_data = Arc::new(new_data);
|
self.entries.push(new_entry.clone());
|
||||||
self.entries.push(new_data.clone());
|
Ok(Some(new_entry))
|
||||||
Ok(new_data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns all the cascade datas that are not being used (that is, that are
|
/// Returns all the cascade datas that are not being used (that is, that are
|
||||||
|
@ -135,7 +165,7 @@ impl UserAgentCascadeDataCache {
|
||||||
/// keep alive some other documents (like the SVG documents kept alive by
|
/// keep alive some other documents (like the SVG documents kept alive by
|
||||||
/// URL references), and thus we don't want to drop them while locking the
|
/// URL references), and thus we don't want to drop them while locking the
|
||||||
/// cache to not deadlock.
|
/// cache to not deadlock.
|
||||||
fn take_unused(&mut self) -> SmallVec<[Arc<UserAgentCascadeData>; 3]> {
|
fn take_unused(&mut self) -> SmallVec<[Arc<Entry>; 3]> {
|
||||||
let mut unused = SmallVec::new();
|
let mut unused = SmallVec::new();
|
||||||
for i in (0..self.entries.len()).rev() {
|
for i in (0..self.entries.len()).rev() {
|
||||||
// is_unique() returns false for static references, but we never
|
// is_unique() returns false for static references, but we never
|
||||||
|
@ -148,7 +178,7 @@ impl UserAgentCascadeDataCache {
|
||||||
unused
|
unused
|
||||||
}
|
}
|
||||||
|
|
||||||
fn take_all(&mut self) -> Vec<Arc<UserAgentCascadeData>> {
|
fn take_all(&mut self) -> Vec<Arc<Entry>> {
|
||||||
mem::replace(&mut self.entries, Vec::new())
|
mem::replace(&mut self.entries, Vec::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,6 +203,58 @@ pub fn add_size_of_ua_cache(ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSet
|
||||||
.add_size_of(ops, sizes);
|
.add_size_of(ops, sizes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
/// A cache of computed user-agent data, to be shared across documents.
|
||||||
|
static ref UA_CASCADE_DATA_CACHE: Mutex<UserAgentCascadeDataCache> =
|
||||||
|
Mutex::new(UserAgentCascadeDataCache::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CascadeDataCacheEntry for UserAgentCascadeData {
|
||||||
|
fn cascade_data(&self) -> &CascadeData {
|
||||||
|
&self.cascade_data
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rebuild<S>(
|
||||||
|
device: &Device,
|
||||||
|
quirks_mode: QuirksMode,
|
||||||
|
collection: SheetCollectionFlusher<S>,
|
||||||
|
guard: &SharedRwLockReadGuard,
|
||||||
|
_old: &Self,
|
||||||
|
) -> Result<Arc<Self>, FailedAllocationError>
|
||||||
|
where
|
||||||
|
S: StylesheetInDocument + PartialEq + 'static
|
||||||
|
{
|
||||||
|
// TODO: Maybe we should support incremental rebuilds, though they seem
|
||||||
|
// uncommon and rebuild() doesn't deal with
|
||||||
|
// precomputed_pseudo_element_decls for now so...
|
||||||
|
let mut new_data = Self {
|
||||||
|
cascade_data: CascadeData::new(),
|
||||||
|
precomputed_pseudo_element_decls: PrecomputedPseudoElementDeclarations::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
for sheet in collection.sheets() {
|
||||||
|
new_data.cascade_data.add_stylesheet(
|
||||||
|
device,
|
||||||
|
quirks_mode,
|
||||||
|
sheet,
|
||||||
|
guard,
|
||||||
|
SheetRebuildKind::Full,
|
||||||
|
Some(&mut new_data.precomputed_pseudo_element_decls),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Arc::new(new_data))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
|
||||||
|
self.cascade_data.add_size_of(ops, sizes);
|
||||||
|
sizes.mPrecomputedPseudos += self.precomputed_pseudo_element_decls.size_of(ops);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserAgentCascadeDataCache = CascadeDataCache<UserAgentCascadeData>;
|
||||||
|
|
||||||
type PrecomputedPseudoElementDeclarations = PerPseudoElementMap<Vec<ApplicableDeclarationBlock>>;
|
type PrecomputedPseudoElementDeclarations = PerPseudoElementMap<Vec<ApplicableDeclarationBlock>>;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -188,14 +270,6 @@ struct UserAgentCascadeData {
|
||||||
precomputed_pseudo_element_decls: PrecomputedPseudoElementDeclarations,
|
precomputed_pseudo_element_decls: PrecomputedPseudoElementDeclarations,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserAgentCascadeData {
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
|
|
||||||
self.cascade_data.add_size_of(ops, sizes);
|
|
||||||
sizes.mPrecomputedPseudos += self.precomputed_pseudo_element_decls.size_of(ops);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// All the computed information for all the stylesheets that apply to the
|
/// All the computed information for all the stylesheets that apply to the
|
||||||
/// document.
|
/// document.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -262,19 +336,29 @@ impl DocumentCascadeData {
|
||||||
guards: &StylesheetGuards,
|
guards: &StylesheetGuards,
|
||||||
) -> Result<(), FailedAllocationError>
|
) -> Result<(), FailedAllocationError>
|
||||||
where
|
where
|
||||||
S: StylesheetInDocument + ToMediaListKey + PartialEq + 'static,
|
S: StylesheetInDocument + PartialEq + 'static,
|
||||||
{
|
{
|
||||||
// First do UA sheets.
|
// First do UA sheets.
|
||||||
{
|
{
|
||||||
if flusher.flush_origin(Origin::UserAgent).dirty() {
|
let origin_flusher = flusher.flush_origin(Origin::UserAgent);
|
||||||
let origin_sheets = flusher.origin_sheets(Origin::UserAgent);
|
// Dirty check is just a minor optimization (no need to grab the
|
||||||
let _unused_cascade_datas = {
|
// lock if nothing has changed).
|
||||||
|
if origin_flusher.dirty() {
|
||||||
let mut ua_cache = UA_CASCADE_DATA_CACHE.lock().unwrap();
|
let mut ua_cache = UA_CASCADE_DATA_CACHE.lock().unwrap();
|
||||||
self.user_agent =
|
let new_data = ua_cache.lookup(
|
||||||
ua_cache.lookup(origin_sheets, device, quirks_mode, guards.ua_or_user)?;
|
device,
|
||||||
debug!("User agent data cache size {:?}", ua_cache.len());
|
quirks_mode,
|
||||||
ua_cache.take_unused()
|
origin_flusher,
|
||||||
};
|
guards.ua_or_user,
|
||||||
|
&self.user_agent,
|
||||||
|
)?;
|
||||||
|
if let Some(new_data) = new_data {
|
||||||
|
self.user_agent = new_data;
|
||||||
|
}
|
||||||
|
let _unused_entries = ua_cache.take_unused();
|
||||||
|
// See the comments in take_unused() as for why the following
|
||||||
|
// line.
|
||||||
|
std::mem::drop(ua_cache);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,6 +455,10 @@ pub struct Stylist {
|
||||||
/// The list of stylesheets.
|
/// The list of stylesheets.
|
||||||
stylesheets: StylistStylesheetSet,
|
stylesheets: StylistStylesheetSet,
|
||||||
|
|
||||||
|
/// A cache of CascadeDatas for AuthorStylesheetSets (i.e., shadow DOM).
|
||||||
|
#[cfg_attr(feature = "servo", ignore_malloc_size_of = "XXX: how to handle this?")]
|
||||||
|
author_data_cache: CascadeDataCache<CascadeData>,
|
||||||
|
|
||||||
/// If true, the quirks-mode stylesheet is applied.
|
/// If true, the quirks-mode stylesheet is applied.
|
||||||
#[cfg_attr(feature = "servo", ignore_malloc_size_of = "defined in selectors")]
|
#[cfg_attr(feature = "servo", ignore_malloc_size_of = "defined in selectors")]
|
||||||
quirks_mode: QuirksMode,
|
quirks_mode: QuirksMode,
|
||||||
|
@ -422,6 +510,7 @@ impl Stylist {
|
||||||
device,
|
device,
|
||||||
quirks_mode,
|
quirks_mode,
|
||||||
stylesheets: StylistStylesheetSet::new(),
|
stylesheets: StylistStylesheetSet::new(),
|
||||||
|
author_data_cache: CascadeDataCache::new(),
|
||||||
cascade_data: Default::default(),
|
cascade_data: Default::default(),
|
||||||
author_styles_enabled: AuthorStylesEnabled::Yes,
|
author_styles_enabled: AuthorStylesEnabled::Yes,
|
||||||
rule_tree: RuleTree::new(),
|
rule_tree: RuleTree::new(),
|
||||||
|
@ -447,6 +536,31 @@ impl Stylist {
|
||||||
self.cascade_data.iter_origins()
|
self.cascade_data.iter_origins()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Does what the name says, to prevent author_data_cache to grow without
|
||||||
|
/// bound.
|
||||||
|
pub fn remove_unique_author_data_cache_entries(&mut self) {
|
||||||
|
self.author_data_cache.take_unused();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rebuilds (if needed) the CascadeData given a sheet collection.
|
||||||
|
pub fn rebuild_author_data<S>(
|
||||||
|
&mut self,
|
||||||
|
old_data: &CascadeData,
|
||||||
|
collection: SheetCollectionFlusher<S>,
|
||||||
|
guard: &SharedRwLockReadGuard,
|
||||||
|
) -> Result<Option<Arc<CascadeData>>, FailedAllocationError>
|
||||||
|
where
|
||||||
|
S: StylesheetInDocument + PartialEq + 'static,
|
||||||
|
{
|
||||||
|
self.author_data_cache.lookup(
|
||||||
|
&self.device,
|
||||||
|
self.quirks_mode,
|
||||||
|
collection,
|
||||||
|
guard,
|
||||||
|
old_data,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Iterate over the extra data in origin order.
|
/// Iterate over the extra data in origin order.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iter_extra_data_origins(&self) -> ExtraStyleDataIterator {
|
pub fn iter_extra_data_origins(&self) -> ExtraStyleDataIterator {
|
||||||
|
@ -1355,6 +1469,7 @@ impl Stylist {
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
|
pub fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
|
||||||
self.cascade_data.add_size_of(ops, sizes);
|
self.cascade_data.add_size_of(ops, sizes);
|
||||||
|
self.author_data_cache.add_size_of(ops, sizes);
|
||||||
sizes.mRuleTree += self.rule_tree.size_of(ops);
|
sizes.mRuleTree += self.rule_tree.size_of(ops);
|
||||||
|
|
||||||
// We may measure other fields in the future if DMD says it's worth it.
|
// We may measure other fields in the future if DMD says it's worth it.
|
||||||
|
@ -1368,7 +1483,7 @@ impl Stylist {
|
||||||
|
|
||||||
/// This struct holds data which users of Stylist may want to extract
|
/// This struct holds data which users of Stylist may want to extract
|
||||||
/// from stylesheets which can be done at the same time as updating.
|
/// from stylesheets which can be done at the same time as updating.
|
||||||
#[derive(Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
|
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
|
||||||
pub struct ExtraStyleData {
|
pub struct ExtraStyleData {
|
||||||
/// A list of effective font-face rules and their origin.
|
/// A list of effective font-face rules and their origin.
|
||||||
|
@ -1388,11 +1503,6 @@ pub struct ExtraStyleData {
|
||||||
pub pages: Vec<Arc<Locked<PageRule>>>,
|
pub pages: Vec<Arc<Locked<PageRule>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
unsafe impl Sync for ExtraStyleData {}
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
unsafe impl Send for ExtraStyleData {}
|
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
impl ExtraStyleData {
|
impl ExtraStyleData {
|
||||||
/// Add the given @font-face rule.
|
/// Add the given @font-face rule.
|
||||||
|
@ -1633,7 +1743,7 @@ impl<'a> SelectorVisitor for StylistSelectorVisitor<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A set of rules for element and pseudo-elements.
|
/// A set of rules for element and pseudo-elements.
|
||||||
#[derive(Debug, Default, MallocSizeOf)]
|
#[derive(Clone, Debug, Default, MallocSizeOf)]
|
||||||
struct GenericElementAndPseudoRules<Map> {
|
struct GenericElementAndPseudoRules<Map> {
|
||||||
/// Rules from stylesheets at this `CascadeData`'s origin.
|
/// Rules from stylesheets at this `CascadeData`'s origin.
|
||||||
element_map: Map,
|
element_map: Map,
|
||||||
|
@ -1712,7 +1822,7 @@ impl PartElementAndPseudoRules {
|
||||||
///
|
///
|
||||||
/// FIXME(emilio): Consider renaming and splitting in `CascadeData` and
|
/// FIXME(emilio): Consider renaming and splitting in `CascadeData` and
|
||||||
/// `InvalidationData`? That'd make `clear_cascade_data()` clearer.
|
/// `InvalidationData`? That'd make `clear_cascade_data()` clearer.
|
||||||
#[derive(Debug, MallocSizeOf)]
|
#[derive(Debug, Clone, MallocSizeOf)]
|
||||||
pub struct CascadeData {
|
pub struct CascadeData {
|
||||||
/// The data coming from normal style rules that apply to elements at this
|
/// The data coming from normal style rules that apply to elements at this
|
||||||
/// cascade level.
|
/// cascade level.
|
||||||
|
@ -1822,7 +1932,7 @@ impl CascadeData {
|
||||||
guard: &SharedRwLockReadGuard,
|
guard: &SharedRwLockReadGuard,
|
||||||
) -> Result<(), FailedAllocationError>
|
) -> Result<(), FailedAllocationError>
|
||||||
where
|
where
|
||||||
S: StylesheetInDocument + ToMediaListKey + PartialEq + 'static,
|
S: StylesheetInDocument + PartialEq + 'static,
|
||||||
{
|
{
|
||||||
if !collection.dirty() {
|
if !collection.dirty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -1836,18 +1946,21 @@ impl CascadeData {
|
||||||
DataValidity::FullyInvalid => self.clear(),
|
DataValidity::FullyInvalid => self.clear(),
|
||||||
}
|
}
|
||||||
|
|
||||||
for (stylesheet, rebuild_kind) in collection {
|
let mut result = Ok(());
|
||||||
self.add_stylesheet(
|
|
||||||
|
collection.each(|stylesheet, rebuild_kind| {
|
||||||
|
result = self.add_stylesheet(
|
||||||
device,
|
device,
|
||||||
quirks_mode,
|
quirks_mode,
|
||||||
stylesheet,
|
stylesheet,
|
||||||
guard,
|
guard,
|
||||||
rebuild_kind,
|
rebuild_kind,
|
||||||
/* precomputed_pseudo_element_decls = */ None,
|
/* precomputed_pseudo_element_decls = */ None,
|
||||||
)?;
|
);
|
||||||
}
|
result.is_ok()
|
||||||
|
});
|
||||||
|
|
||||||
Ok(())
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the invalidation map.
|
/// Returns the invalidation map.
|
||||||
|
@ -1922,14 +2035,14 @@ impl CascadeData {
|
||||||
guard: &SharedRwLockReadGuard,
|
guard: &SharedRwLockReadGuard,
|
||||||
results: &mut EffectiveMediaQueryResults,
|
results: &mut EffectiveMediaQueryResults,
|
||||||
) where
|
) where
|
||||||
S: StylesheetInDocument + ToMediaListKey + 'static,
|
S: StylesheetInDocument + 'static,
|
||||||
{
|
{
|
||||||
if !stylesheet.enabled() || !stylesheet.is_effective_for_device(device, guard) {
|
if !stylesheet.enabled() || !stylesheet.is_effective_for_device(device, guard) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!(" + {:?}", stylesheet);
|
debug!(" + {:?}", stylesheet);
|
||||||
results.saw_effective(stylesheet);
|
results.saw_effective(stylesheet.contents());
|
||||||
|
|
||||||
for rule in stylesheet.effective_rules(device, guard) {
|
for rule in stylesheet.effective_rules(device, guard) {
|
||||||
match *rule {
|
match *rule {
|
||||||
|
@ -1959,16 +2072,17 @@ impl CascadeData {
|
||||||
mut precomputed_pseudo_element_decls: Option<&mut PrecomputedPseudoElementDeclarations>,
|
mut precomputed_pseudo_element_decls: Option<&mut PrecomputedPseudoElementDeclarations>,
|
||||||
) -> Result<(), FailedAllocationError>
|
) -> Result<(), FailedAllocationError>
|
||||||
where
|
where
|
||||||
S: StylesheetInDocument + ToMediaListKey + 'static,
|
S: StylesheetInDocument + 'static,
|
||||||
{
|
{
|
||||||
if !stylesheet.enabled() || !stylesheet.is_effective_for_device(device, guard) {
|
if !stylesheet.enabled() || !stylesheet.is_effective_for_device(device, guard) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let origin = stylesheet.origin(guard);
|
let contents = stylesheet.contents();
|
||||||
|
let origin = contents.origin;
|
||||||
|
|
||||||
if rebuild_kind.should_rebuild_invalidation() {
|
if rebuild_kind.should_rebuild_invalidation() {
|
||||||
self.effective_media_query_results.saw_effective(stylesheet);
|
self.effective_media_query_results.saw_effective(contents);
|
||||||
}
|
}
|
||||||
|
|
||||||
for rule in stylesheet.effective_rules(device, guard) {
|
for rule in stylesheet.effective_rules(device, guard) {
|
||||||
|
@ -2143,13 +2257,13 @@ impl CascadeData {
|
||||||
quirks_mode: QuirksMode,
|
quirks_mode: QuirksMode,
|
||||||
) -> bool
|
) -> bool
|
||||||
where
|
where
|
||||||
S: StylesheetInDocument + ToMediaListKey + 'static,
|
S: StylesheetInDocument + 'static,
|
||||||
{
|
{
|
||||||
use crate::invalidation::media_queries::PotentiallyEffectiveMediaRules;
|
use crate::invalidation::media_queries::PotentiallyEffectiveMediaRules;
|
||||||
|
|
||||||
let effective_now = stylesheet.is_effective_for_device(device, guard);
|
let effective_now = stylesheet.is_effective_for_device(device, guard);
|
||||||
|
|
||||||
let effective_then = self.effective_media_query_results.was_effective(stylesheet);
|
let effective_then = self.effective_media_query_results.was_effective(stylesheet.contents());
|
||||||
|
|
||||||
if effective_now != effective_then {
|
if effective_now != effective_then {
|
||||||
debug!(
|
debug!(
|
||||||
|
@ -2184,9 +2298,10 @@ impl CascadeData {
|
||||||
},
|
},
|
||||||
CssRule::Import(ref lock) => {
|
CssRule::Import(ref lock) => {
|
||||||
let import_rule = lock.read_with(guard);
|
let import_rule = lock.read_with(guard);
|
||||||
let effective_now = import_rule
|
let effective_now = match import_rule.stylesheet.media(guard) {
|
||||||
.stylesheet
|
Some(m) => m.evaluate(device, quirks_mode),
|
||||||
.is_effective_for_device(&device, guard);
|
None => true,
|
||||||
|
};
|
||||||
let effective_then = self
|
let effective_then = self
|
||||||
.effective_media_query_results
|
.effective_media_query_results
|
||||||
.was_effective(import_rule);
|
.was_effective(import_rule);
|
||||||
|
@ -2258,8 +2373,33 @@ impl CascadeData {
|
||||||
self.selectors_for_cache_revalidation.clear();
|
self.selectors_for_cache_revalidation.clear();
|
||||||
self.effective_media_query_results.clear();
|
self.effective_media_query_results.clear();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CascadeDataCacheEntry for CascadeData {
|
||||||
|
fn cascade_data(&self) -> &CascadeData {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rebuild<S>(
|
||||||
|
device: &Device,
|
||||||
|
quirks_mode: QuirksMode,
|
||||||
|
collection: SheetCollectionFlusher<S>,
|
||||||
|
guard: &SharedRwLockReadGuard,
|
||||||
|
old: &Self,
|
||||||
|
) -> Result<Arc<Self>, FailedAllocationError>
|
||||||
|
where
|
||||||
|
S: StylesheetInDocument + PartialEq + 'static
|
||||||
|
{
|
||||||
|
debug_assert!(collection.dirty(), "We surely need to do something?");
|
||||||
|
// If we're doing a full rebuild anyways, don't bother cloning the data.
|
||||||
|
let mut updatable_entry = match collection.data_validity() {
|
||||||
|
DataValidity::Valid | DataValidity::CascadeInvalid => old.clone(),
|
||||||
|
DataValidity::FullyInvalid => Self::new(),
|
||||||
|
};
|
||||||
|
updatable_entry.rebuild(device, quirks_mode, collection, guard)?;
|
||||||
|
Ok(Arc::new(updatable_entry))
|
||||||
|
}
|
||||||
|
|
||||||
/// Measures heap usage.
|
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
|
fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
|
||||||
self.normal_rules.add_size_of(ops, sizes);
|
self.normal_rules.add_size_of(ops, sizes);
|
||||||
|
|
|
@ -35,17 +35,14 @@ impl RGBA {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(red: f32, green: f32, blue: f32, alpha: f32) -> Self {
|
pub fn new(red: f32, green: f32, blue: f32, alpha: f32) -> Self {
|
||||||
RGBA {
|
RGBA {
|
||||||
red: red,
|
red,
|
||||||
green: green,
|
green,
|
||||||
blue: blue,
|
blue,
|
||||||
alpha: alpha,
|
alpha,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unlike Animate for computed colors, we don't clamp any component values.
|
|
||||||
///
|
|
||||||
/// FIXME(nox): Why do computed colors even implement Animate?
|
|
||||||
impl Animate for RGBA {
|
impl Animate for RGBA {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
||||||
|
@ -57,15 +54,11 @@ impl Animate for RGBA {
|
||||||
}
|
}
|
||||||
|
|
||||||
alpha = alpha.min(1.);
|
alpha = alpha.min(1.);
|
||||||
let red =
|
let red = (self.red * self.alpha).animate(&(other.red * other.alpha), procedure)?;
|
||||||
(self.red * self.alpha).animate(&(other.red * other.alpha), procedure)? * 1. / alpha;
|
let green = (self.green * self.alpha).animate(&(other.green * other.alpha), procedure)?;
|
||||||
let green = (self.green * self.alpha).animate(&(other.green * other.alpha), procedure)? *
|
let blue = (self.blue * self.alpha).animate(&(other.blue * other.alpha), procedure)?;
|
||||||
1. /
|
let inv = 1. / alpha;
|
||||||
alpha;
|
Ok(RGBA::new(red * inv, green * inv, blue * inv, alpha))
|
||||||
let blue =
|
|
||||||
(self.blue * self.alpha).animate(&(other.blue * other.alpha), procedure)? * 1. / alpha;
|
|
||||||
|
|
||||||
Ok(RGBA::new(red, green, blue, alpha))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,21 +90,75 @@ pub type Color = GenericColor<RGBA>;
|
||||||
|
|
||||||
impl Color {
|
impl Color {
|
||||||
fn effective_intermediate_rgba(&self) -> RGBA {
|
fn effective_intermediate_rgba(&self) -> RGBA {
|
||||||
match *self {
|
if self.ratios.bg == 0. {
|
||||||
GenericColor::Numeric(color) => color,
|
return RGBA::transparent();
|
||||||
GenericColor::CurrentColor => RGBA::transparent(),
|
}
|
||||||
GenericColor::Complex { color, ratios } => RGBA {
|
|
||||||
alpha: color.alpha * ratios.bg,
|
if self.ratios.bg == 1. {
|
||||||
..color.clone()
|
return self.color;
|
||||||
},
|
}
|
||||||
|
|
||||||
|
RGBA {
|
||||||
|
alpha: self.color.alpha * self.ratios.bg,
|
||||||
|
..self.color
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn effective_ratios(&self) -> ComplexColorRatios {
|
/// Mix two colors into one.
|
||||||
match *self {
|
pub fn mix(
|
||||||
GenericColor::Numeric(..) => ComplexColorRatios::NUMERIC,
|
left_color: &Color,
|
||||||
GenericColor::CurrentColor => ComplexColorRatios::CURRENT_COLOR,
|
left_weight: f32,
|
||||||
GenericColor::Complex { ratios, .. } => ratios,
|
right_color: &Color,
|
||||||
|
right_weight: f32,
|
||||||
|
) -> Self {
|
||||||
|
let left_bg = left_color.scaled_rgba();
|
||||||
|
let right_bg = right_color.scaled_rgba();
|
||||||
|
let alpha = (left_bg.alpha * left_weight +
|
||||||
|
right_bg.alpha * right_weight)
|
||||||
|
.min(1.);
|
||||||
|
|
||||||
|
let mut fg = 0.;
|
||||||
|
let mut red = 0.;
|
||||||
|
let mut green = 0.;
|
||||||
|
let mut blue = 0.;
|
||||||
|
|
||||||
|
let colors = [
|
||||||
|
(left_color, &left_bg, left_weight),
|
||||||
|
(right_color, &right_bg, right_weight),
|
||||||
|
];
|
||||||
|
|
||||||
|
for &(color, bg, weight) in &colors {
|
||||||
|
fg += color.ratios.fg * weight;
|
||||||
|
|
||||||
|
red += bg.red * bg.alpha * weight;
|
||||||
|
green += bg.green * bg.alpha * weight;
|
||||||
|
blue += bg.blue * bg.alpha * weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
let color = if alpha <= 0. {
|
||||||
|
RGBA::transparent()
|
||||||
|
} else {
|
||||||
|
let inv = 1. / alpha;
|
||||||
|
RGBA::new(red * inv, green * inv, blue * inv, alpha)
|
||||||
|
};
|
||||||
|
|
||||||
|
Self::new(color, ComplexColorRatios { bg: 1., fg })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scaled_rgba(&self) -> RGBA {
|
||||||
|
if self.ratios.bg == 0. {
|
||||||
|
return RGBA::transparent();
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.ratios.bg == 1. {
|
||||||
|
return self.color;
|
||||||
|
}
|
||||||
|
|
||||||
|
RGBA {
|
||||||
|
red: self.color.red * self.ratios.bg,
|
||||||
|
green: self.color.green * self.ratios.bg,
|
||||||
|
blue: self.color.blue * self.ratios.bg,
|
||||||
|
alpha: self.color.alpha * self.ratios.bg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,58 +166,51 @@ impl Color {
|
||||||
impl Animate for Color {
|
impl Animate for Color {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
||||||
use self::GenericColor::*;
|
let self_numeric = self.is_numeric();
|
||||||
|
let other_numeric = other.is_numeric();
|
||||||
|
|
||||||
// Common cases are interpolating between two numeric colors,
|
if self_numeric && other_numeric {
|
||||||
// two currentcolors, and a numeric color and a currentcolor.
|
return Ok(Self::rgba(self.color.animate(&other.color, procedure)?));
|
||||||
let (this_weight, other_weight) = procedure.weights();
|
}
|
||||||
|
|
||||||
Ok(match (*self, *other, procedure) {
|
let self_currentcolor = self.is_currentcolor();
|
||||||
// Any interpolation of currentcolor with currentcolor returns currentcolor.
|
let other_currentcolor = other.is_currentcolor();
|
||||||
(CurrentColor, CurrentColor, Procedure::Interpolate { .. }) => CurrentColor,
|
|
||||||
// Animating two numeric colors.
|
|
||||||
(Numeric(c1), Numeric(c2), _) => Numeric(c1.animate(&c2, procedure)?),
|
|
||||||
// Combinations of numeric color and currentcolor
|
|
||||||
(CurrentColor, Numeric(color), _) => Self::with_ratios(
|
|
||||||
color,
|
|
||||||
ComplexColorRatios {
|
|
||||||
bg: other_weight as f32,
|
|
||||||
fg: this_weight as f32,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(Numeric(color), CurrentColor, _) => Self::with_ratios(
|
|
||||||
color,
|
|
||||||
ComplexColorRatios {
|
|
||||||
bg: this_weight as f32,
|
|
||||||
fg: other_weight as f32,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
|
|
||||||
// Any other animation of currentcolor with currentcolor.
|
if self_currentcolor && other_currentcolor {
|
||||||
(CurrentColor, CurrentColor, _) => Self::with_ratios(
|
let (self_weight, other_weight) = procedure.weights();
|
||||||
|
return Ok(Self::new(
|
||||||
RGBA::transparent(),
|
RGBA::transparent(),
|
||||||
ComplexColorRatios {
|
ComplexColorRatios {
|
||||||
bg: 0.,
|
bg: 0.,
|
||||||
fg: (this_weight + other_weight) as f32,
|
fg: (self_weight + other_weight) as f32,
|
||||||
},
|
},
|
||||||
),
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME(emilio): Without these special cases tests fail, looks fairly
|
||||||
|
// sketchy!
|
||||||
|
if (self_currentcolor && other_numeric) || (self_numeric && other_currentcolor) {
|
||||||
|
let (self_weight, other_weight) = procedure.weights();
|
||||||
|
return Ok(if self_numeric {
|
||||||
|
Self::new(
|
||||||
|
self.color,
|
||||||
|
ComplexColorRatios {
|
||||||
|
bg: self_weight as f32,
|
||||||
|
fg: other_weight as f32,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Self::new(
|
||||||
|
other.color,
|
||||||
|
ComplexColorRatios {
|
||||||
|
bg: other_weight as f32,
|
||||||
|
fg: self_weight as f32,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Defer to complex calculations
|
|
||||||
_ => {
|
|
||||||
// Compute the "scaled" contribution for `color`.
|
// Compute the "scaled" contribution for `color`.
|
||||||
fn scaled_rgba(color: &Color) -> RGBA {
|
|
||||||
match *color {
|
|
||||||
GenericColor::Numeric(color) => color,
|
|
||||||
GenericColor::CurrentColor => RGBA::transparent(),
|
|
||||||
GenericColor::Complex { color, ratios } => RGBA {
|
|
||||||
red: color.red * ratios.bg,
|
|
||||||
green: color.green * ratios.bg,
|
|
||||||
blue: color.blue * ratios.bg,
|
|
||||||
alpha: color.alpha * ratios.bg,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Each `Color`, represents a complex combination of foreground color and
|
// Each `Color`, represents a complex combination of foreground color and
|
||||||
// background color where fg and bg represent the overall
|
// background color where fg and bg represent the overall
|
||||||
// contributions. ie:
|
// contributions. ie:
|
||||||
|
@ -206,53 +246,60 @@ impl Animate for Color {
|
||||||
//
|
//
|
||||||
// = { bg_color, fg_color }
|
// = { bg_color, fg_color }
|
||||||
// = { 1 * (bg_color1 op bg_color2), (fg1 op fg2) * foreground }
|
// = { 1 * (bg_color1 op bg_color2), (fg1 op fg2) * foreground }
|
||||||
|
//
|
||||||
// To perform the operation on two complex colors, we need to
|
// To perform the operation on two complex colors, we need to
|
||||||
// generate the scaled contributions of each background color
|
// generate the scaled contributions of each background color
|
||||||
// component.
|
// component.
|
||||||
let bg_color1 = scaled_rgba(self);
|
let bg_color1 = self.scaled_rgba();
|
||||||
let bg_color2 = scaled_rgba(other);
|
let bg_color2 = other.scaled_rgba();
|
||||||
|
|
||||||
// Perform bg_color1 op bg_color2
|
// Perform bg_color1 op bg_color2
|
||||||
let bg_color = bg_color1.animate(&bg_color2, procedure)?;
|
let bg_color = bg_color1.animate(&bg_color2, procedure)?;
|
||||||
|
|
||||||
// Calculate the final foreground color ratios; perform
|
// Calculate the final foreground color ratios; perform
|
||||||
// animation on effective fg ratios.
|
// animation on effective fg ratios.
|
||||||
let ComplexColorRatios { fg: fg1, .. } = self.effective_ratios();
|
let fg = self.ratios.fg.animate(&other.ratios.fg, procedure)?;
|
||||||
let ComplexColorRatios { fg: fg2, .. } = other.effective_ratios();
|
|
||||||
// Perform fg1 op fg2
|
|
||||||
let fg = fg1.animate(&fg2, procedure)?;
|
|
||||||
|
|
||||||
Self::with_ratios(bg_color, ComplexColorRatios { bg: 1., fg })
|
Ok(Self::new(bg_color, ComplexColorRatios { bg: 1., fg }))
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComputeSquaredDistance for Color {
|
impl ComputeSquaredDistance for Color {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
|
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
|
||||||
use self::GenericColor::*;
|
// All comments from the Animate impl also apply here.
|
||||||
|
let self_numeric = self.is_numeric();
|
||||||
|
let other_numeric = other.is_numeric();
|
||||||
|
|
||||||
// All comments from the Animate impl also applies here.
|
if self_numeric && other_numeric {
|
||||||
Ok(match (*self, *other) {
|
return self.color.compute_squared_distance(&other.color);
|
||||||
(CurrentColor, CurrentColor) => SquaredDistance::from_sqrt(0.),
|
}
|
||||||
(Numeric(c1), Numeric(c2)) => c1.compute_squared_distance(&c2)?,
|
|
||||||
(CurrentColor, Numeric(color)) | (Numeric(color), CurrentColor) => {
|
let self_currentcolor = self.is_currentcolor();
|
||||||
|
let other_currentcolor = other.is_currentcolor();
|
||||||
|
if self_currentcolor && other_currentcolor {
|
||||||
|
return Ok(SquaredDistance::from_sqrt(0.));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self_currentcolor && other_numeric) || (self_numeric && other_currentcolor) {
|
||||||
|
let color = if self_numeric {
|
||||||
|
&self.color
|
||||||
|
} else {
|
||||||
|
&other.color
|
||||||
|
};
|
||||||
// `computed_squared_distance` is symmetric.
|
// `computed_squared_distance` is symmetric.
|
||||||
color.compute_squared_distance(&RGBA::transparent())? +
|
return Ok(color.compute_squared_distance(&RGBA::transparent())? +
|
||||||
SquaredDistance::from_sqrt(1.)
|
SquaredDistance::from_sqrt(1.));
|
||||||
},
|
}
|
||||||
(_, _) => {
|
|
||||||
let self_color = self.effective_intermediate_rgba();
|
let self_color = self.effective_intermediate_rgba();
|
||||||
let other_color = other.effective_intermediate_rgba();
|
let other_color = other.effective_intermediate_rgba();
|
||||||
let self_ratios = self.effective_ratios();
|
let self_ratios = self.ratios;
|
||||||
let other_ratios = other.effective_ratios();
|
let other_ratios = other.ratios;
|
||||||
|
|
||||||
self_color.compute_squared_distance(&other_color)? +
|
Ok(self_color.compute_squared_distance(&other_color)? +
|
||||||
self_ratios.bg.compute_squared_distance(&other_ratios.bg)? +
|
self_ratios.bg.compute_squared_distance(&other_ratios.bg)? +
|
||||||
self_ratios.fg.compute_squared_distance(&other_ratios.fg)?
|
self_ratios.fg.compute_squared_distance(&other_ratios.fg)?)
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
use crate::values::animated::color::RGBA as AnimatedRGBA;
|
use crate::values::animated::color::RGBA as AnimatedRGBA;
|
||||||
use crate::values::animated::ToAnimatedValue;
|
use crate::values::animated::ToAnimatedValue;
|
||||||
use crate::values::generics::color::{Color as GenericColor, ColorOrAuto as GenericColorOrAuto};
|
use crate::values::generics::color::{GenericColor, GenericColorOrAuto, GenericCaretColor};
|
||||||
use cssparser::{Color as CSSParserColor, RGBA};
|
use cssparser::{Color as CSSParserColor, RGBA};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use style_traits::{CssWriter, ToCss};
|
use style_traits::{CssWriter, ToCss};
|
||||||
|
@ -29,13 +29,18 @@ impl Color {
|
||||||
/// Combine this complex color with the given foreground color into
|
/// Combine this complex color with the given foreground color into
|
||||||
/// a numeric RGBA color. It currently uses linear blending.
|
/// a numeric RGBA color. It currently uses linear blending.
|
||||||
pub fn to_rgba(&self, fg_color: RGBA) -> RGBA {
|
pub fn to_rgba(&self, fg_color: RGBA) -> RGBA {
|
||||||
let (color, ratios) = match *self {
|
// Common cases that the complex color is either pure numeric color or
|
||||||
// Common cases that the complex color is either pure numeric
|
// pure currentcolor.
|
||||||
// color or pure currentcolor.
|
if self.is_numeric() {
|
||||||
GenericColor::Numeric(color) => return color,
|
return self.color;
|
||||||
GenericColor::CurrentColor => return fg_color,
|
}
|
||||||
GenericColor::Complex { color, ratios } => (color, ratios),
|
|
||||||
};
|
if self.is_currentcolor() {
|
||||||
|
return fg_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ratios = &self.ratios;
|
||||||
|
let color = &self.color;
|
||||||
|
|
||||||
// For the more complicated case that the alpha value differs,
|
// For the more complicated case that the alpha value differs,
|
||||||
// we use the following formula to compute the components:
|
// we use the following formula to compute the components:
|
||||||
|
@ -59,13 +64,14 @@ impl Color {
|
||||||
if a <= 0. {
|
if a <= 0. {
|
||||||
return RGBA::transparent();
|
return RGBA::transparent();
|
||||||
}
|
}
|
||||||
let a = f32::min(a, 1.);
|
let a = a.min(1.);
|
||||||
|
|
||||||
let inverse_a = 1. / a;
|
let inv = 1. / a;
|
||||||
let r = (p1 * r1 + p2 * r2) * inverse_a;
|
|
||||||
let g = (p1 * g1 + p2 * g2) * inverse_a;
|
let r = (p1 * r1 + p2 * r2) * inv;
|
||||||
let b = (p1 * b1 + p2 * b2) * inverse_a;
|
let g = (p1 * g1 + p2 * g2) * inv;
|
||||||
return RGBA::from_floats(r, g, b, a);
|
let b = (p1 * b1 + p2 * b2) * inv;
|
||||||
|
RGBA::from_floats(r, g, b, a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,11 +80,13 @@ impl ToCss for Color {
|
||||||
where
|
where
|
||||||
W: fmt::Write,
|
W: fmt::Write,
|
||||||
{
|
{
|
||||||
match *self {
|
if self.is_currentcolor() {
|
||||||
GenericColor::Numeric(color) => color.to_css(dest),
|
return CSSParserColor::CurrentColor.to_css(dest);
|
||||||
GenericColor::CurrentColor => CSSParserColor::CurrentColor.to_css(dest),
|
|
||||||
_ => Ok(()),
|
|
||||||
}
|
}
|
||||||
|
if self.is_numeric() {
|
||||||
|
return self.color.to_css(dest);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,3 +112,6 @@ impl ToAnimatedValue for RGBA {
|
||||||
|
|
||||||
/// auto | <color>
|
/// auto | <color>
|
||||||
pub type ColorOrAuto = GenericColorOrAuto<Color>;
|
pub type ColorOrAuto = GenericColorOrAuto<Color>;
|
||||||
|
|
||||||
|
/// caret-color
|
||||||
|
pub type CaretColor = GenericCaretColor<Color>;
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
//! Computed values for counter properties
|
//! Computed values for counter properties
|
||||||
|
|
||||||
use crate::values::computed::url::ComputedImageUrl;
|
use crate::values::computed::image::Image;
|
||||||
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::CounterIncrement as GenericCounterIncrement;
|
||||||
use crate::values::generics::counters::CounterSetOrReset as GenericCounterSetOrReset;
|
use crate::values::generics::counters::CounterSetOrReset as GenericCounterSetOrReset;
|
||||||
|
@ -16,7 +16,7 @@ pub type CounterIncrement = GenericCounterIncrement<i32>;
|
||||||
pub type CounterSetOrReset = GenericCounterSetOrReset<i32>;
|
pub type CounterSetOrReset = GenericCounterSetOrReset<i32>;
|
||||||
|
|
||||||
/// A computed value for the `content` property.
|
/// A computed value for the `content` property.
|
||||||
pub type Content = generics::GenericContent<ComputedImageUrl>;
|
pub type Content = generics::GenericContent<Image>;
|
||||||
|
|
||||||
/// A computed content item.
|
/// A computed content item.
|
||||||
pub type ContentItem = generics::GenericContentItem<ComputedImageUrl>;
|
pub type ContentItem = generics::GenericContentItem<Image>;
|
||||||
|
|
|
@ -828,14 +828,14 @@ impl ToComputedValue for specified::MathDepth {
|
||||||
let parent = cx.builder.get_parent_font().clone_math_depth() as i32;
|
let parent = cx.builder.get_parent_font().clone_math_depth() as i32;
|
||||||
let style = cx.builder.get_parent_font().clone_math_style();
|
let style = cx.builder.get_parent_font().clone_math_style();
|
||||||
if style == MathStyleValue::Compact {
|
if style == MathStyleValue::Compact {
|
||||||
parent + 1
|
parent.saturating_add(1)
|
||||||
} else {
|
} else {
|
||||||
parent
|
parent
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
specified::MathDepth::Add(rel) => {
|
specified::MathDepth::Add(rel) => {
|
||||||
let parent = cx.builder.get_parent_font().clone_math_depth();
|
let parent = cx.builder.get_parent_font().clone_math_depth();
|
||||||
parent as i32 + rel.to_computed_value(cx)
|
(parent as i32).saturating_add(rel.to_computed_value(cx))
|
||||||
},
|
},
|
||||||
specified::MathDepth::Absolute(abs) => abs.to_computed_value(cx),
|
specified::MathDepth::Absolute(abs) => abs.to_computed_value(cx),
|
||||||
};
|
};
|
||||||
|
|
|
@ -74,9 +74,20 @@ impl ToComputedValue for specified::ImageSet {
|
||||||
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||||
let items = self.items.to_computed_value(context);
|
let items = self.items.to_computed_value(context);
|
||||||
let dpr = context.device().device_pixel_ratio().get();
|
let dpr = context.device().device_pixel_ratio().get();
|
||||||
|
|
||||||
|
// If no item have a supported MIME type, the behavior is undefined by the standard
|
||||||
|
// By default, we select the first item
|
||||||
|
let mut supported_image = false;
|
||||||
let mut selected_index = 0;
|
let mut selected_index = 0;
|
||||||
let mut selected_resolution = items[0].resolution.dppx();
|
let mut selected_resolution = items[0].resolution.dppx();
|
||||||
for (i, item) in items.iter().enumerate().skip(1) {
|
|
||||||
|
for (i, item) in items.iter().enumerate() {
|
||||||
|
|
||||||
|
// If the MIME type is not supported, we discard the ImageSetItem
|
||||||
|
if item.has_mime_type && !context.device().is_supported_mime_type(&item.mime_type) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let candidate_resolution = item.resolution.dppx();
|
let candidate_resolution = item.resolution.dppx();
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-images-4/#image-set-notation:
|
// https://drafts.csswg.org/css-images-4/#image-set-notation:
|
||||||
|
@ -97,7 +108,9 @@ impl ToComputedValue for specified::ImageSet {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
if better_candidate() {
|
// The first item with a supported MIME type is obviously the current best candidate
|
||||||
|
if !supported_image || better_candidate() {
|
||||||
|
supported_image = true;
|
||||||
selected_index = i;
|
selected_index = i;
|
||||||
selected_resolution = candidate_resolution;
|
selected_resolution = candidate_resolution;
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,7 +185,10 @@ impl Size {
|
||||||
GenericSize::Auto => false,
|
GenericSize::Auto => false,
|
||||||
GenericSize::LengthPercentage(ref lp) => lp.is_definitely_zero(),
|
GenericSize::LengthPercentage(ref lp) => lp.is_definitely_zero(),
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
GenericSize::ExtremumLength(..) => false,
|
GenericSize::MinContent |
|
||||||
|
GenericSize::MaxContent |
|
||||||
|
GenericSize::MozFitContent |
|
||||||
|
GenericSize::MozAvailable => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -495,37 +498,6 @@ pub type NonNegativeLengthPercentageOrNormal =
|
||||||
/// Either a non-negative `<length>` or a `<number>`.
|
/// Either a non-negative `<length>` or a `<number>`.
|
||||||
pub type NonNegativeLengthOrNumber = GenericLengthOrNumber<NonNegativeLength, NonNegativeNumber>;
|
pub type NonNegativeLengthOrNumber = GenericLengthOrNumber<NonNegativeLength, NonNegativeNumber>;
|
||||||
|
|
||||||
/// A type for possible values for min- and max- flavors of width, height,
|
|
||||||
/// block-size, and inline-size.
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
|
|
||||||
#[derive(
|
|
||||||
Clone,
|
|
||||||
Copy,
|
|
||||||
Debug,
|
|
||||||
Eq,
|
|
||||||
FromPrimitive,
|
|
||||||
MallocSizeOf,
|
|
||||||
Parse,
|
|
||||||
PartialEq,
|
|
||||||
SpecifiedValueInfo,
|
|
||||||
ToAnimatedValue,
|
|
||||||
ToAnimatedZero,
|
|
||||||
ToComputedValue,
|
|
||||||
ToCss,
|
|
||||||
ToResolvedValue,
|
|
||||||
ToShmem,
|
|
||||||
)]
|
|
||||||
#[repr(u8)]
|
|
||||||
pub enum ExtremumLength {
|
|
||||||
#[parse(aliases = "-moz-max-content")]
|
|
||||||
MaxContent,
|
|
||||||
#[parse(aliases = "-moz-min-content")]
|
|
||||||
MinContent,
|
|
||||||
MozFitContent,
|
|
||||||
MozAvailable,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A computed value for `min-width`, `min-height`, `width` or `height` property.
|
/// A computed value for `min-width`, `min-height`, `width` or `height` property.
|
||||||
pub type Size = GenericSize<NonNegativeLengthPercentage>;
|
pub type Size = GenericSize<NonNegativeLengthPercentage>;
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ pub use self::font::{FontVariantAlternates, FontWeight};
|
||||||
pub use self::font::{FontVariantEastAsian, FontVariationSettings};
|
pub use self::font::{FontVariantEastAsian, FontVariationSettings};
|
||||||
pub use self::font::{MathDepth, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom};
|
pub use self::font::{MathDepth, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom};
|
||||||
pub use self::image::{Gradient, Image, LineDirection, MozImageRect};
|
pub use self::image::{Gradient, Image, LineDirection, MozImageRect};
|
||||||
pub use self::length::{CSSPixelLength, ExtremumLength, NonNegativeLength};
|
pub use self::length::{CSSPixelLength, NonNegativeLength};
|
||||||
pub use self::length::{Length, LengthOrNumber, LengthPercentage, NonNegativeLengthOrNumber};
|
pub use self::length::{Length, LengthOrNumber, LengthPercentage, NonNegativeLengthOrNumber};
|
||||||
pub use self::length::{LengthOrAuto, LengthPercentageOrAuto, MaxSize, Size};
|
pub use self::length::{LengthOrAuto, LengthPercentageOrAuto, MaxSize, Size};
|
||||||
pub use self::length::{NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto};
|
pub use self::length::{NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto};
|
||||||
|
@ -87,9 +87,9 @@ 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::text::TextUnderlinePosition;
|
pub use self::text::TextUnderlinePosition;
|
||||||
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, RubyPosition, TextOverflow, WordBreak, WordSpacing};
|
||||||
pub use self::text::{TextAlign, TextAlignLast, TextEmphasisPosition, TextEmphasisStyle};
|
pub use self::text::{TextAlign, TextAlignLast, TextEmphasisPosition, TextEmphasisStyle};
|
||||||
pub use self::text::{TextDecorationLength, TextDecorationSkipInk};
|
pub use self::text::{TextDecorationLength, TextDecorationSkipInk, TextJustify};
|
||||||
pub use self::time::Time;
|
pub use self::time::Time;
|
||||||
pub use self::transform::{Rotate, Scale, Transform, TransformOperation};
|
pub use self::transform::{Rotate, Scale, Transform, TransformOperation};
|
||||||
pub use self::transform::{TransformOrigin, TransformStyle, Translate};
|
pub use self::transform::{TransformOrigin, TransformStyle, Translate};
|
||||||
|
|
|
@ -11,4 +11,4 @@ use crate::values::generics::size::Size2D;
|
||||||
pub use generics::page::Orientation;
|
pub use generics::page::Orientation;
|
||||||
pub use generics::page::PaperSize;
|
pub use generics::page::PaperSize;
|
||||||
/// Computed value of the @page size descriptor
|
/// Computed value of the @page size descriptor
|
||||||
pub type PageSize = generics::page::PageSize<Size2D<NonNegativeLength>>;
|
pub type PageSize = generics::page::GenericPageSize<Size2D<NonNegativeLength>>;
|
||||||
|
|
|
@ -18,10 +18,10 @@ use crate::Zero;
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
use style_traits::{CssWriter, ToCss};
|
use style_traits::{CssWriter, ToCss};
|
||||||
|
|
||||||
pub use crate::values::specified::text::{TextAlignLast, TextUnderlinePosition};
|
pub use crate::values::specified::text::{TextAlignLast, TextUnderlinePosition, MozControlCharacterVisibility};
|
||||||
pub use crate::values::specified::{LineBreak, OverflowWrap, WordBreak};
|
pub use crate::values::specified::{LineBreak, OverflowWrap, RubyPosition, WordBreak};
|
||||||
pub use crate::values::specified::{TextDecorationLine, TextEmphasisPosition};
|
pub use crate::values::specified::{TextDecorationLine, TextEmphasisPosition};
|
||||||
pub use crate::values::specified::{TextDecorationSkipInk, TextTransform};
|
pub use crate::values::specified::{TextDecorationSkipInk, TextJustify, TextTransform};
|
||||||
|
|
||||||
/// A computed value for the `initial-letter` property.
|
/// A computed value for the `initial-letter` property.
|
||||||
pub type InitialLetter = GenericInitialLetter<CSSFloat, CSSInteger>;
|
pub type InitialLetter = GenericInitialLetter<CSSFloat, CSSInteger>;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
//! Computed values for UI properties
|
//! Computed values for UI properties
|
||||||
|
|
||||||
use crate::values::computed::color::Color;
|
use crate::values::computed::color::Color;
|
||||||
use crate::values::computed::url::ComputedImageUrl;
|
use crate::values::computed::image::Image;
|
||||||
use crate::values::computed::Number;
|
use crate::values::computed::Number;
|
||||||
use crate::values::generics::ui as generics;
|
use crate::values::generics::ui as generics;
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ pub use crate::values::specified::ui::{MozForceBrokenImageIcon, UserSelect};
|
||||||
pub type Cursor = generics::GenericCursor<CursorImage>;
|
pub type Cursor = generics::GenericCursor<CursorImage>;
|
||||||
|
|
||||||
/// A computed value for item of `image cursors`.
|
/// A computed value for item of `image cursors`.
|
||||||
pub type CursorImage = generics::GenericCursorImage<ComputedImageUrl, Number>;
|
pub type CursorImage = generics::GenericCursorImage<Image, Number>;
|
||||||
|
|
||||||
/// A computed value for `scrollbar-color` property.
|
/// A computed value for `scrollbar-color` property.
|
||||||
pub type ScrollbarColor = generics::GenericScrollbarColor<Color>;
|
pub type ScrollbarColor = generics::GenericScrollbarColor<Color>;
|
||||||
|
|
|
@ -6,6 +6,11 @@
|
||||||
|
|
||||||
/// Ratios representing the contribution of color and currentcolor to
|
/// Ratios representing the contribution of color and currentcolor to
|
||||||
/// the final color value.
|
/// the final color value.
|
||||||
|
///
|
||||||
|
/// NOTE(emilio): For animated colors, the sum of these two might be more than
|
||||||
|
/// one (because the background color would've been scaled down already). So
|
||||||
|
/// beware that it is not generally safe to assume that if bg is 1 then fg is 0,
|
||||||
|
/// for example.
|
||||||
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, ToShmem)]
|
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, ToShmem)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct ComplexColorRatios {
|
pub struct ComplexColorRatios {
|
||||||
|
@ -22,59 +27,52 @@ impl ComplexColorRatios {
|
||||||
pub const CURRENT_COLOR: ComplexColorRatios = ComplexColorRatios { bg: 0., fg: 1. };
|
pub const CURRENT_COLOR: ComplexColorRatios = ComplexColorRatios { bg: 0., fg: 1. };
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This enum represents a combined color from a numeric color and
|
/// This struct represents a combined color from a numeric color and
|
||||||
/// the current foreground color (currentcolor keyword).
|
/// the current foreground color (currentcolor keyword).
|
||||||
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, ToShmem)]
|
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, ToShmem)]
|
||||||
#[repr(C, u8)]
|
#[repr(C)]
|
||||||
pub enum GenericColor<RGBA> {
|
pub struct GenericColor<RGBA> {
|
||||||
/// Numeric RGBA color.
|
|
||||||
Numeric(RGBA),
|
|
||||||
|
|
||||||
/// The current foreground color.
|
|
||||||
CurrentColor,
|
|
||||||
|
|
||||||
/// A linear combination of numeric color and currentcolor.
|
|
||||||
/// The formula is: `color * ratios.bg + currentcolor * ratios.fg`.
|
|
||||||
Complex {
|
|
||||||
/// The actual numeric color.
|
/// The actual numeric color.
|
||||||
color: RGBA,
|
pub color: RGBA,
|
||||||
/// The ratios of mixing between numeric and currentcolor.
|
/// The ratios of mixing between numeric and currentcolor.
|
||||||
ratios: ComplexColorRatios,
|
/// The formula is: `color * ratios.bg + currentcolor * ratios.fg`.
|
||||||
},
|
pub ratios: ComplexColorRatios,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use self::GenericColor as Color;
|
pub use self::GenericColor as Color;
|
||||||
|
|
||||||
|
impl Color<cssparser::RGBA> {
|
||||||
|
/// Returns a color value representing currentcolor.
|
||||||
|
pub fn currentcolor() -> Self {
|
||||||
|
Color {
|
||||||
|
color: cssparser::RGBA::transparent(),
|
||||||
|
ratios: ComplexColorRatios::CURRENT_COLOR,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<RGBA> Color<RGBA> {
|
impl<RGBA> Color<RGBA> {
|
||||||
/// Create a color based upon the specified ratios.
|
/// Create a color based upon the specified ratios.
|
||||||
pub fn with_ratios(color: RGBA, ratios: ComplexColorRatios) -> Self {
|
pub fn new(color: RGBA, ratios: ComplexColorRatios) -> Self {
|
||||||
if ratios == ComplexColorRatios::NUMERIC {
|
Self { color, ratios }
|
||||||
Color::Numeric(color)
|
|
||||||
} else if ratios == ComplexColorRatios::CURRENT_COLOR {
|
|
||||||
Color::CurrentColor
|
|
||||||
} else {
|
|
||||||
Color::Complex { color, ratios }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a numeric color representing the given RGBA value.
|
/// Returns a numeric color representing the given RGBA value.
|
||||||
pub fn rgba(color: RGBA) -> Self {
|
pub fn rgba(color: RGBA) -> Self {
|
||||||
Color::Numeric(color)
|
Self {
|
||||||
|
color,
|
||||||
|
ratios: ComplexColorRatios::NUMERIC,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a complex color value representing currentcolor.
|
|
||||||
pub fn currentcolor() -> Self {
|
|
||||||
Color::CurrentColor
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether it is a numeric color (no currentcolor component).
|
/// Whether it is a numeric color (no currentcolor component).
|
||||||
pub fn is_numeric(&self) -> bool {
|
pub fn is_numeric(&self) -> bool {
|
||||||
matches!(*self, Color::Numeric(..))
|
self.ratios == ComplexColorRatios::NUMERIC
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether it is a currentcolor value (no numeric color component).
|
/// Whether it is a currentcolor value (no numeric color component).
|
||||||
pub fn is_currentcolor(&self) -> bool {
|
pub fn is_currentcolor(&self) -> bool {
|
||||||
matches!(*self, Color::CurrentColor)
|
self.ratios == ComplexColorRatios::CURRENT_COLOR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,6 +96,7 @@ impl<RGBA> From<RGBA> for Color<RGBA> {
|
||||||
ToAnimatedValue,
|
ToAnimatedValue,
|
||||||
ToAnimatedZero,
|
ToAnimatedZero,
|
||||||
ToComputedValue,
|
ToComputedValue,
|
||||||
|
ToResolvedValue,
|
||||||
ToCss,
|
ToCss,
|
||||||
ToShmem,
|
ToShmem,
|
||||||
)]
|
)]
|
||||||
|
@ -110,3 +109,32 @@ pub enum GenericColorOrAuto<C> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use self::GenericColorOrAuto as ColorOrAuto;
|
pub use self::GenericColorOrAuto as ColorOrAuto;
|
||||||
|
|
||||||
|
/// Caret color is effectively a ColorOrAuto, but resolves `auto` to
|
||||||
|
/// currentColor.
|
||||||
|
#[derive(
|
||||||
|
Animate,
|
||||||
|
Clone,
|
||||||
|
ComputeSquaredDistance,
|
||||||
|
Copy,
|
||||||
|
Debug,
|
||||||
|
MallocSizeOf,
|
||||||
|
PartialEq,
|
||||||
|
SpecifiedValueInfo,
|
||||||
|
ToAnimatedValue,
|
||||||
|
ToAnimatedZero,
|
||||||
|
ToComputedValue,
|
||||||
|
ToCss,
|
||||||
|
ToShmem,
|
||||||
|
)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct GenericCaretColor<C>(pub GenericColorOrAuto<C>);
|
||||||
|
|
||||||
|
impl<C> GenericCaretColor<C> {
|
||||||
|
/// Returns the `auto` value.
|
||||||
|
pub fn auto() -> Self {
|
||||||
|
GenericCaretColor(GenericColorOrAuto::Auto)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use self::GenericCaretColor as CaretColor;
|
||||||
|
|
|
@ -148,18 +148,18 @@ fn is_decimal(counter_type: &CounterStyleType) -> bool {
|
||||||
Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, ToShmem,
|
Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, ToShmem,
|
||||||
)]
|
)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum GenericContent<ImageUrl> {
|
pub enum GenericContent<Image> {
|
||||||
/// `normal` reserved keyword.
|
/// `normal` reserved keyword.
|
||||||
Normal,
|
Normal,
|
||||||
/// `none` reserved keyword.
|
/// `none` reserved keyword.
|
||||||
None,
|
None,
|
||||||
/// Content items.
|
/// Content items.
|
||||||
Items(#[css(iterable)] crate::OwnedSlice<GenericContentItem<ImageUrl>>),
|
Items(#[css(iterable)] crate::OwnedSlice<GenericContentItem<Image>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use self::GenericContent as Content;
|
pub use self::GenericContent as Content;
|
||||||
|
|
||||||
impl<ImageUrl> Content<ImageUrl> {
|
impl<Image> Content<Image> {
|
||||||
/// Whether `self` represents list of items.
|
/// Whether `self` represents list of items.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_items(&self) -> bool {
|
pub fn is_items(&self) -> bool {
|
||||||
|
@ -180,14 +180,13 @@ impl<ImageUrl> Content<ImageUrl> {
|
||||||
Eq,
|
Eq,
|
||||||
MallocSizeOf,
|
MallocSizeOf,
|
||||||
PartialEq,
|
PartialEq,
|
||||||
SpecifiedValueInfo,
|
|
||||||
ToComputedValue,
|
ToComputedValue,
|
||||||
ToCss,
|
ToCss,
|
||||||
ToResolvedValue,
|
ToResolvedValue,
|
||||||
ToShmem,
|
ToShmem,
|
||||||
)]
|
)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum GenericContentItem<ImageUrl> {
|
pub enum GenericContentItem<I> {
|
||||||
/// Literal string content.
|
/// Literal string content.
|
||||||
String(crate::OwnedStr),
|
String(crate::OwnedStr),
|
||||||
/// `counter(name, style)`.
|
/// `counter(name, style)`.
|
||||||
|
@ -220,8 +219,8 @@ pub enum GenericContentItem<ImageUrl> {
|
||||||
/// `attr([namespace? `|`]? ident)`
|
/// `attr([namespace? `|`]? ident)`
|
||||||
#[cfg(any(feature = "gecko", feature = "servo-layout-2020"))]
|
#[cfg(any(feature = "gecko", feature = "servo-layout-2020"))]
|
||||||
Attr(Attr),
|
Attr(Attr),
|
||||||
/// `url(url)`
|
/// image-set(url) | url(url)
|
||||||
Url(ImageUrl),
|
Image(I),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use self::GenericContentItem as ContentItem;
|
pub use self::GenericContentItem as ContentItem;
|
||||||
|
|
|
@ -132,7 +132,7 @@ pub struct GenericImageSet<Image, Resolution> {
|
||||||
|
|
||||||
/// An optional percent and a cross fade image.
|
/// An optional percent and a cross fade image.
|
||||||
#[derive(
|
#[derive(
|
||||||
Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem, ToCss,
|
Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem,
|
||||||
)]
|
)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct GenericImageSetItem<Image, Resolution> {
|
pub struct GenericImageSetItem<Image, Resolution> {
|
||||||
|
@ -142,7 +142,33 @@ pub struct GenericImageSetItem<Image, Resolution> {
|
||||||
///
|
///
|
||||||
/// TODO: Skip serialization if it is 1x.
|
/// TODO: Skip serialization if it is 1x.
|
||||||
pub resolution: Resolution,
|
pub resolution: Resolution,
|
||||||
// TODO: type() function.
|
|
||||||
|
/// The `type(<string>)`
|
||||||
|
/// (Optional) Specify the image's MIME type
|
||||||
|
pub mime_type: crate::OwnedStr,
|
||||||
|
|
||||||
|
/// True if mime_type has been specified
|
||||||
|
pub has_mime_type: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: style_traits::ToCss, R: style_traits::ToCss> ToCss for GenericImageSetItem<I, R>
|
||||||
|
{
|
||||||
|
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||||
|
where
|
||||||
|
W: fmt::Write,
|
||||||
|
{
|
||||||
|
self.image.to_css(dest)?;
|
||||||
|
dest.write_str(" ")?;
|
||||||
|
self.resolution.to_css(dest)?;
|
||||||
|
|
||||||
|
if self.has_mime_type {
|
||||||
|
dest.write_str(" ")?;
|
||||||
|
dest.write_str("type(")?;
|
||||||
|
self.mime_type.to_css(dest)?;
|
||||||
|
dest.write_str(")")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use self::GenericImageSet as ImageSet;
|
pub use self::GenericImageSet as ImageSet;
|
||||||
|
|
|
@ -5,8 +5,6 @@
|
||||||
//! Generic types for CSS values related to length.
|
//! Generic types for CSS values related to length.
|
||||||
|
|
||||||
use crate::parser::{Parse, ParserContext};
|
use crate::parser::{Parse, ParserContext};
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
use crate::values::computed::ExtremumLength;
|
|
||||||
use crate::Zero;
|
use crate::Zero;
|
||||||
use cssparser::Parser;
|
use cssparser::Parser;
|
||||||
use style_traits::ParseError;
|
use style_traits::ParseError;
|
||||||
|
@ -153,7 +151,16 @@ pub enum GenericSize<LengthPercent> {
|
||||||
Auto,
|
Auto,
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
#[animation(error)]
|
#[animation(error)]
|
||||||
ExtremumLength(ExtremumLength),
|
MaxContent,
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
#[animation(error)]
|
||||||
|
MinContent,
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
#[animation(error)]
|
||||||
|
MozFitContent,
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
#[animation(error)]
|
||||||
|
MozAvailable,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use self::GenericSize as Size;
|
pub use self::GenericSize as Size;
|
||||||
|
@ -196,7 +203,18 @@ pub enum GenericMaxSize<LengthPercent> {
|
||||||
None,
|
None,
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
#[animation(error)]
|
#[animation(error)]
|
||||||
ExtremumLength(ExtremumLength),
|
#[parse(aliases = "-moz-max-content")]
|
||||||
|
MaxContent,
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
#[animation(error)]
|
||||||
|
#[parse(aliases = "-moz-min-content")]
|
||||||
|
MinContent,
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
#[animation(error)]
|
||||||
|
MozFitContent,
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
#[animation(error)]
|
||||||
|
MozAvailable,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use self::GenericMaxSize as MaxSize;
|
pub use self::GenericMaxSize as MaxSize;
|
||||||
|
|
|
@ -86,7 +86,7 @@ pub enum Orientation {
|
||||||
ToShmem,
|
ToShmem,
|
||||||
)]
|
)]
|
||||||
#[repr(C, u8)]
|
#[repr(C, u8)]
|
||||||
pub enum PageSize<S> {
|
pub enum GenericPageSize<S> {
|
||||||
/// Page dimensions.
|
/// Page dimensions.
|
||||||
Size(S),
|
Size(S),
|
||||||
/// Paper size with no orientation.
|
/// Paper size with no orientation.
|
||||||
|
@ -99,6 +99,8 @@ pub enum PageSize<S> {
|
||||||
Auto,
|
Auto,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub use self::GenericPageSize as PageSize;
|
||||||
|
|
||||||
impl<S> PageSize<S> {
|
impl<S> PageSize<S> {
|
||||||
/// `auto` value.
|
/// `auto` value.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -61,15 +61,14 @@ impl<Image: ToCss> ToCss for Cursor<Image> {
|
||||||
Debug,
|
Debug,
|
||||||
MallocSizeOf,
|
MallocSizeOf,
|
||||||
PartialEq,
|
PartialEq,
|
||||||
SpecifiedValueInfo,
|
|
||||||
ToComputedValue,
|
ToComputedValue,
|
||||||
ToResolvedValue,
|
ToResolvedValue,
|
||||||
ToShmem,
|
ToShmem,
|
||||||
)]
|
)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct GenericCursorImage<ImageUrl, Number> {
|
pub struct GenericCursorImage<Image, Number> {
|
||||||
/// The url to parse images from.
|
/// The url to parse images from.
|
||||||
pub url: ImageUrl,
|
pub image: Image,
|
||||||
/// Whether the image has a hotspot or not.
|
/// Whether the image has a hotspot or not.
|
||||||
pub has_hotspot: bool,
|
pub has_hotspot: bool,
|
||||||
/// The x coordinate.
|
/// The x coordinate.
|
||||||
|
@ -80,12 +79,12 @@ pub struct GenericCursorImage<ImageUrl, Number> {
|
||||||
|
|
||||||
pub use self::GenericCursorImage as CursorImage;
|
pub use self::GenericCursorImage as CursorImage;
|
||||||
|
|
||||||
impl<ImageUrl: ToCss, Number: ToCss> ToCss for CursorImage<ImageUrl, Number> {
|
impl<Image: ToCss, Number: ToCss> ToCss for CursorImage<Image, Number> {
|
||||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||||
where
|
where
|
||||||
W: Write,
|
W: Write,
|
||||||
{
|
{
|
||||||
self.url.to_css(dest)?;
|
self.image.to_css(dest)?;
|
||||||
if self.has_hotspot {
|
if self.has_hotspot {
|
||||||
dest.write_str(" ")?;
|
dest.write_str(" ")?;
|
||||||
self.hotspot_x.to_css(dest)?;
|
self.hotspot_x.to_css(dest)?;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
use super::{Context, ToResolvedValue};
|
use super::{Context, ToResolvedValue};
|
||||||
|
|
||||||
use crate::values::computed;
|
use crate::values::computed::color as computed;
|
||||||
use crate::values::generics::color as generics;
|
use crate::values::generics::color as generics;
|
||||||
|
|
||||||
impl ToResolvedValue for computed::Color {
|
impl ToResolvedValue for computed::Color {
|
||||||
|
@ -20,26 +20,26 @@ impl ToResolvedValue for computed::Color {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
|
fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
|
||||||
generics::Color::Numeric(resolved)
|
generics::Color::rgba(resolved)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToResolvedValue for computed::ColorOrAuto {
|
impl ToResolvedValue for computed::CaretColor {
|
||||||
// A resolved caret-color value is an rgba color, with auto resolving to
|
// A resolved caret-color value is an rgba color, with auto resolving to
|
||||||
// currentcolor.
|
// currentcolor.
|
||||||
type ResolvedValue = cssparser::RGBA;
|
type ResolvedValue = cssparser::RGBA;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
|
fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
|
||||||
let color = match self {
|
let color = match self.0 {
|
||||||
generics::ColorOrAuto::Color(color) => color,
|
generics::ColorOrAuto::Color(color) => color,
|
||||||
generics::ColorOrAuto::Auto => generics::Color::CurrentColor,
|
generics::ColorOrAuto::Auto => generics::Color::currentcolor(),
|
||||||
};
|
};
|
||||||
color.to_resolved_value(context)
|
color.to_resolved_value(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
|
fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
|
||||||
generics::ColorOrAuto::Color(computed::Color::from_resolved_value(resolved))
|
generics::CaretColor(generics::ColorOrAuto::Color(computed::Color::from_resolved_value(resolved)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
use crate::custom_properties::Name as CustomPropertyName;
|
use crate::custom_properties::Name as CustomPropertyName;
|
||||||
use crate::parser::{Parse, ParserContext};
|
use crate::parser::{Parse, ParserContext};
|
||||||
use crate::properties::{LonghandId, PropertyDeclarationId, PropertyFlags};
|
use crate::properties::{LonghandId, PropertyDeclarationId};
|
||||||
use crate::properties::{PropertyId, ShorthandId};
|
use crate::properties::{PropertyId, ShorthandId};
|
||||||
use crate::values::generics::box_::AnimationIterationCount as GenericAnimationIterationCount;
|
use crate::values::generics::box_::AnimationIterationCount as GenericAnimationIterationCount;
|
||||||
use crate::values::generics::box_::Perspective as GenericPerspective;
|
use crate::values::generics::box_::Perspective as GenericPerspective;
|
||||||
|
@ -1086,46 +1086,58 @@ bitflags! {
|
||||||
/// The change bits that we care about.
|
/// The change bits that we care about.
|
||||||
#[derive(Default, MallocSizeOf, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem)]
|
#[derive(Default, MallocSizeOf, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct WillChangeBits: u8 {
|
pub struct WillChangeBits: u16 {
|
||||||
/// Whether the stacking context will change.
|
/// Whether a property which can create a stacking context **on any
|
||||||
const STACKING_CONTEXT = 1 << 0;
|
/// box** will change.
|
||||||
/// Whether `transform` will change.
|
const STACKING_CONTEXT_UNCONDITIONAL = 1 << 0;
|
||||||
|
/// Whether `transform` or related properties will change.
|
||||||
const TRANSFORM = 1 << 1;
|
const TRANSFORM = 1 << 1;
|
||||||
/// Whether `scroll-position` will change.
|
/// Whether `scroll-position` will change.
|
||||||
const SCROLL = 1 << 2;
|
const SCROLL = 1 << 2;
|
||||||
|
/// Whether `contain` will change.
|
||||||
|
const CONTAIN = 1 << 3;
|
||||||
/// Whether `opacity` will change.
|
/// Whether `opacity` will change.
|
||||||
const OPACITY = 1 << 3;
|
const OPACITY = 1 << 4;
|
||||||
/// Fixed pos containing block.
|
/// Whether `perspective` will change.
|
||||||
const FIXPOS_CB = 1 << 4;
|
const PERSPECTIVE = 1 << 5;
|
||||||
/// Abs pos containing block.
|
/// Whether `z-index` will change.
|
||||||
const ABSPOS_CB = 1 << 5;
|
const Z_INDEX = 1 << 6;
|
||||||
|
/// Whether any property which creates a containing block for non-svg
|
||||||
|
/// text frames will change.
|
||||||
|
const FIXPOS_CB_NON_SVG = 1 << 7;
|
||||||
|
/// Whether the position property will change.
|
||||||
|
const POSITION = 1 << 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
fn change_bits_for_longhand(longhand: LonghandId) -> WillChangeBits {
|
fn change_bits_for_longhand(longhand: LonghandId) -> WillChangeBits {
|
||||||
let mut flags = match longhand {
|
match longhand {
|
||||||
LonghandId::Opacity => WillChangeBits::OPACITY,
|
LonghandId::Opacity => WillChangeBits::OPACITY,
|
||||||
LonghandId::Transform => WillChangeBits::TRANSFORM,
|
LonghandId::Contain => WillChangeBits::CONTAIN,
|
||||||
#[cfg(feature = "gecko")]
|
LonghandId::Perspective => WillChangeBits::PERSPECTIVE,
|
||||||
LonghandId::Translate | LonghandId::Rotate | LonghandId::Scale | LonghandId::OffsetPath => {
|
LonghandId::Position => {
|
||||||
WillChangeBits::TRANSFORM
|
WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL | WillChangeBits::POSITION
|
||||||
},
|
},
|
||||||
|
LonghandId::ZIndex => WillChangeBits::Z_INDEX,
|
||||||
|
LonghandId::Transform |
|
||||||
|
LonghandId::TransformStyle |
|
||||||
|
LonghandId::Translate |
|
||||||
|
LonghandId::Rotate |
|
||||||
|
LonghandId::Scale |
|
||||||
|
LonghandId::OffsetPath => WillChangeBits::TRANSFORM,
|
||||||
|
LonghandId::BackdropFilter | LonghandId::Filter => {
|
||||||
|
WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL | WillChangeBits::FIXPOS_CB_NON_SVG
|
||||||
|
},
|
||||||
|
LonghandId::MixBlendMode |
|
||||||
|
LonghandId::Isolation |
|
||||||
|
LonghandId::MaskImage |
|
||||||
|
LonghandId::ClipPath => WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL,
|
||||||
_ => WillChangeBits::empty(),
|
_ => WillChangeBits::empty(),
|
||||||
};
|
|
||||||
|
|
||||||
let property_flags = longhand.flags();
|
|
||||||
if property_flags.contains(PropertyFlags::CREATES_STACKING_CONTEXT) {
|
|
||||||
flags |= WillChangeBits::STACKING_CONTEXT;
|
|
||||||
}
|
}
|
||||||
if property_flags.contains(PropertyFlags::FIXPOS_CB) {
|
|
||||||
flags |= WillChangeBits::FIXPOS_CB;
|
|
||||||
}
|
|
||||||
if property_flags.contains(PropertyFlags::ABSPOS_CB) {
|
|
||||||
flags |= WillChangeBits::ABSPOS_CB;
|
|
||||||
}
|
|
||||||
flags
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
fn change_bits_for_maybe_property(ident: &str, context: &ParserContext) -> WillChangeBits {
|
fn change_bits_for_maybe_property(ident: &str, context: &ParserContext) -> WillChangeBits {
|
||||||
let id = match PropertyId::parse_ignoring_rule_type(ident, context) {
|
let id = match PropertyId::parse_ignoring_rule_type(ident, context) {
|
||||||
Ok(id) => id,
|
Ok(id) => id,
|
||||||
|
@ -1143,6 +1155,7 @@ fn change_bits_for_maybe_property(ident: &str, context: &ParserContext) -> WillC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
impl Parse for WillChange {
|
impl Parse for WillChange {
|
||||||
/// auto | <animateable-feature>#
|
/// auto | <animateable-feature>#
|
||||||
fn parse<'i, 't>(
|
fn parse<'i, 't>(
|
||||||
|
@ -1838,10 +1851,6 @@ pub enum Appearance {
|
||||||
#[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
|
#[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
|
||||||
MozMacSourceListSelection,
|
MozMacSourceListSelection,
|
||||||
#[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
|
#[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
|
||||||
MozMacVibrancyDark,
|
|
||||||
#[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
|
|
||||||
MozMacVibrancyLight,
|
|
||||||
#[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
|
|
||||||
MozMacVibrantTitlebarDark,
|
MozMacVibrantTitlebarDark,
|
||||||
#[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
|
#[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
|
||||||
MozMacVibrantTitlebarLight,
|
MozMacVibrantTitlebarLight,
|
||||||
|
|
|
@ -374,9 +374,9 @@ impl CalcNode {
|
||||||
rhs.negate();
|
rhs.negate();
|
||||||
sum.push(rhs);
|
sum.push(rhs);
|
||||||
},
|
},
|
||||||
ref t => {
|
_ => {
|
||||||
let t = t.clone();
|
input.reset(&start);
|
||||||
return Err(input.new_unexpected_token_error(t));
|
break;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -9,8 +9,9 @@ use super::AllowQuirks;
|
||||||
use crate::gecko_bindings::structs::nscolor;
|
use crate::gecko_bindings::structs::nscolor;
|
||||||
use crate::parser::{Parse, ParserContext};
|
use crate::parser::{Parse, ParserContext};
|
||||||
use crate::values::computed::{Color as ComputedColor, Context, ToComputedValue};
|
use crate::values::computed::{Color as ComputedColor, Context, ToComputedValue};
|
||||||
use crate::values::generics::color::{Color as GenericColor, ColorOrAuto as GenericColorOrAuto};
|
use crate::values::generics::color::{GenericColorOrAuto, GenericCaretColor};
|
||||||
use crate::values::specified::calc::CalcNode;
|
use crate::values::specified::calc::CalcNode;
|
||||||
|
use crate::values::specified::Percentage;
|
||||||
use cssparser::{AngleOrNumber, Color as CSSParserColor, Parser, Token, RGBA};
|
use cssparser::{AngleOrNumber, Color as CSSParserColor, Parser, Token, RGBA};
|
||||||
use cssparser::{BasicParseErrorKind, NumberOrPercentage, ParseErrorKind};
|
use cssparser::{BasicParseErrorKind, NumberOrPercentage, ParseErrorKind};
|
||||||
use itoa;
|
use itoa;
|
||||||
|
@ -19,6 +20,117 @@ use std::io::Write as IoWrite;
|
||||||
use style_traits::{CssType, CssWriter, KeywordsCollectFn, ParseError, StyleParseErrorKind};
|
use style_traits::{CssType, CssWriter, KeywordsCollectFn, ParseError, StyleParseErrorKind};
|
||||||
use style_traits::{SpecifiedValueInfo, ToCss, ValueParseErrorKind};
|
use style_traits::{SpecifiedValueInfo, ToCss, ValueParseErrorKind};
|
||||||
|
|
||||||
|
/// A restricted version of the css `color-mix()` function, which only supports
|
||||||
|
/// percentages and sRGB color-space interpolation.
|
||||||
|
///
|
||||||
|
/// https://drafts.csswg.org/css-color-5/#color-mix
|
||||||
|
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)]
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
pub struct ColorMix {
|
||||||
|
pub left: Color,
|
||||||
|
pub left_percentage: Percentage,
|
||||||
|
pub right: Color,
|
||||||
|
pub right_percentage: Percentage,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
#[inline]
|
||||||
|
fn allow_color_mix() -> bool {
|
||||||
|
static_prefs::pref!("layout.css.color-mix.enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "servo")]
|
||||||
|
#[inline]
|
||||||
|
fn allow_color_mix() -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(emilio): Syntax is still a bit in-flux, since [1] doesn't seem
|
||||||
|
// particularly complete, and disagrees with the examples.
|
||||||
|
//
|
||||||
|
// [1]: https://github.com/w3c/csswg-drafts/commit/a4316446112f9e814668c2caff7f826f512f8fed
|
||||||
|
impl Parse for ColorMix {
|
||||||
|
fn parse<'i, 't>(
|
||||||
|
context: &ParserContext,
|
||||||
|
input: &mut Parser<'i, 't>,
|
||||||
|
) -> Result<Self, ParseError<'i>> {
|
||||||
|
let enabled =
|
||||||
|
context.chrome_rules_enabled() || allow_color_mix();
|
||||||
|
|
||||||
|
if !enabled {
|
||||||
|
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||||
|
}
|
||||||
|
|
||||||
|
input.expect_function_matching("color-mix")?;
|
||||||
|
|
||||||
|
// NOTE(emilio): This implements the syntax described here for now,
|
||||||
|
// might need to get updated in the future.
|
||||||
|
//
|
||||||
|
// https://github.com/w3c/csswg-drafts/issues/6066#issuecomment-789836765
|
||||||
|
input.parse_nested_block(|input| {
|
||||||
|
input.expect_ident_matching("in")?;
|
||||||
|
// TODO: support multiple interpolation spaces.
|
||||||
|
input.expect_ident_matching("srgb")?;
|
||||||
|
input.expect_comma()?;
|
||||||
|
|
||||||
|
let left = Color::parse(context, input)?;
|
||||||
|
let left_percentage = input.try_parse(|input| Percentage::parse(context, input)).ok();
|
||||||
|
|
||||||
|
input.expect_comma()?;
|
||||||
|
|
||||||
|
let right = Color::parse(context, input)?;
|
||||||
|
let right_percentage = input
|
||||||
|
.try_parse(|input| Percentage::parse(context, input))
|
||||||
|
.unwrap_or_else(|_| {
|
||||||
|
Percentage::new(1.0 - left_percentage.map_or(0.5, |p| p.get()))
|
||||||
|
});
|
||||||
|
|
||||||
|
let left_percentage =
|
||||||
|
left_percentage.unwrap_or_else(|| Percentage::new(1.0 - right_percentage.get()));
|
||||||
|
Ok(ColorMix {
|
||||||
|
left,
|
||||||
|
left_percentage,
|
||||||
|
right,
|
||||||
|
right_percentage,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToCss for ColorMix {
|
||||||
|
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||||
|
where
|
||||||
|
W: Write,
|
||||||
|
{
|
||||||
|
fn can_omit(percent: &Percentage, other: &Percentage, is_left: bool) -> bool {
|
||||||
|
if percent.is_calc() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if percent.get() == 0.5 {
|
||||||
|
return other.get() == 0.5;
|
||||||
|
}
|
||||||
|
if is_left {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
(1.0 - percent.get() - other.get()).abs() <= f32::EPSILON
|
||||||
|
}
|
||||||
|
|
||||||
|
dest.write_str("color-mix(in srgb, ")?;
|
||||||
|
self.left.to_css(dest)?;
|
||||||
|
if !can_omit(&self.left_percentage, &self.right_percentage, true) {
|
||||||
|
dest.write_str(" ")?;
|
||||||
|
self.left_percentage.to_css(dest)?;
|
||||||
|
}
|
||||||
|
dest.write_str(", ")?;
|
||||||
|
self.right.to_css(dest)?;
|
||||||
|
if !can_omit(&self.right_percentage, &self.left_percentage, false) {
|
||||||
|
dest.write_str(" ")?;
|
||||||
|
self.right_percentage.to_css(dest)?;
|
||||||
|
}
|
||||||
|
dest.write_str(")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Specified color value
|
/// Specified color value
|
||||||
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)]
|
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)]
|
||||||
pub enum Color {
|
pub enum Color {
|
||||||
|
@ -36,6 +148,8 @@ pub enum Color {
|
||||||
/// A system color
|
/// A system color
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
System(SystemColor),
|
System(SystemColor),
|
||||||
|
/// A color mix.
|
||||||
|
ColorMix(Box<ColorMix>),
|
||||||
/// Quirksmode-only rule for inheriting color from the body
|
/// Quirksmode-only rule for inheriting color from the body
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
InheritFromBodyQuirk,
|
InheritFromBodyQuirk,
|
||||||
|
@ -72,8 +186,6 @@ pub enum SystemColor {
|
||||||
#[css(skip)]
|
#[css(skip)]
|
||||||
TextSelectForeground,
|
TextSelectForeground,
|
||||||
#[css(skip)]
|
#[css(skip)]
|
||||||
TextSelectForegroundCustom,
|
|
||||||
#[css(skip)]
|
|
||||||
TextSelectBackgroundDisabled,
|
TextSelectBackgroundDisabled,
|
||||||
#[css(skip)]
|
#[css(skip)]
|
||||||
TextSelectBackgroundAttention,
|
TextSelectBackgroundAttention,
|
||||||
|
@ -215,8 +327,6 @@ pub enum SystemColor {
|
||||||
|
|
||||||
/// Font smoothing background colors needed by the Mac OS X theme, based on
|
/// Font smoothing background colors needed by the Mac OS X theme, based on
|
||||||
/// -moz-appearance names.
|
/// -moz-appearance names.
|
||||||
MozMacVibrancyLight,
|
|
||||||
MozMacVibrancyDark,
|
|
||||||
MozMacVibrantTitlebarLight,
|
MozMacVibrantTitlebarLight,
|
||||||
MozMacVibrantTitlebarDark,
|
MozMacVibrantTitlebarDark,
|
||||||
MozMacMenupopup,
|
MozMacMenupopup,
|
||||||
|
@ -235,10 +345,6 @@ pub enum SystemColor {
|
||||||
#[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
|
#[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
|
||||||
MozAccentColorForeground,
|
MozAccentColorForeground,
|
||||||
|
|
||||||
/// Accent color for title bar.
|
|
||||||
MozWinAccentcolor,
|
|
||||||
/// Color from drawing text over the accent color.
|
|
||||||
MozWinAccentcolortext,
|
|
||||||
/// Media rebar text.
|
/// Media rebar text.
|
||||||
MozWinMediatext,
|
MozWinMediatext,
|
||||||
/// Communications rebar text.
|
/// Communications rebar text.
|
||||||
|
@ -338,8 +444,6 @@ impl<'a, 'b: 'a, 'i: 'a> ::cssparser::ColorComponentParser<'i> for ColorComponen
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_percentage<'t>(&self, input: &mut Parser<'i, 't>) -> Result<f32, ParseError<'i>> {
|
fn parse_percentage<'t>(&self, input: &mut Parser<'i, 't>) -> Result<f32, ParseError<'i>> {
|
||||||
use crate::values::specified::Percentage;
|
|
||||||
|
|
||||||
Ok(Percentage::parse(self.0, input)?.get())
|
Ok(Percentage::parse(self.0, input)?.get())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -398,6 +502,10 @@ impl Parse for Color {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Ok(mix) = input.try_parse(|i| ColorMix::parse(context, i)) {
|
||||||
|
return Ok(Color::ColorMix(Box::new(mix)));
|
||||||
|
}
|
||||||
|
|
||||||
match e.kind {
|
match e.kind {
|
||||||
ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken(t)) => {
|
ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken(t)) => {
|
||||||
Err(e.location.new_custom_error(StyleParseErrorKind::ValueError(
|
Err(e.location.new_custom_error(StyleParseErrorKind::ValueError(
|
||||||
|
@ -425,7 +533,9 @@ impl ToCss for Color {
|
||||||
Color::Numeric {
|
Color::Numeric {
|
||||||
parsed: ref rgba, ..
|
parsed: ref rgba, ..
|
||||||
} => rgba.to_css(dest),
|
} => rgba.to_css(dest),
|
||||||
|
// TODO: Could represent this as a color-mix() instead.
|
||||||
Color::Complex(_) => Ok(()),
|
Color::Complex(_) => Ok(()),
|
||||||
|
Color::ColorMix(ref mix) => mix.to_css(dest),
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
Color::System(system) => system.to_css(dest),
|
Color::System(system) => system.to_css(dest),
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
|
@ -447,6 +557,18 @@ fn parse_hash_color(value: &[u8]) -> Result<RGBA, ()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Color {
|
impl Color {
|
||||||
|
/// Returns whether this color is a system color.
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
pub fn is_system(&self) -> bool {
|
||||||
|
matches!(self, Color::System(..))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether this color is a system color.
|
||||||
|
#[cfg(feature = "servo")]
|
||||||
|
pub fn is_system(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns currentcolor value.
|
/// Returns currentcolor value.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn currentcolor() -> Color {
|
pub fn currentcolor() -> Color {
|
||||||
|
@ -562,17 +684,28 @@ impl Color {
|
||||||
///
|
///
|
||||||
/// If `context` is `None`, and the specified color requires data from
|
/// If `context` is `None`, and the specified color requires data from
|
||||||
/// the context to resolve, then `None` is returned.
|
/// the context to resolve, then `None` is returned.
|
||||||
pub fn to_computed_color(&self, _context: Option<&Context>) -> Option<ComputedColor> {
|
pub fn to_computed_color(&self, context: Option<&Context>) -> Option<ComputedColor> {
|
||||||
Some(match *self {
|
Some(match *self {
|
||||||
Color::CurrentColor => ComputedColor::currentcolor(),
|
Color::CurrentColor => ComputedColor::currentcolor(),
|
||||||
Color::Numeric { ref parsed, .. } => ComputedColor::rgba(*parsed),
|
Color::Numeric { ref parsed, .. } => ComputedColor::rgba(*parsed),
|
||||||
Color::Complex(ref complex) => *complex,
|
Color::Complex(ref complex) => *complex,
|
||||||
#[cfg(feature = "gecko")]
|
Color::ColorMix(ref mix) => {
|
||||||
Color::System(system) => system.compute(_context?),
|
use crate::values::animated::color::Color as AnimatedColor;
|
||||||
#[cfg(feature = "gecko")]
|
use crate::values::animated::ToAnimatedValue;
|
||||||
Color::InheritFromBodyQuirk => {
|
|
||||||
ComputedColor::rgba(_context?.device().body_text_color())
|
let left = mix.left.to_computed_color(context)?.to_animated_value();
|
||||||
|
let right = mix.right.to_computed_color(context)?.to_animated_value();
|
||||||
|
ToAnimatedValue::from_animated_value(AnimatedColor::mix(
|
||||||
|
&left,
|
||||||
|
mix.left_percentage.get(),
|
||||||
|
&right,
|
||||||
|
mix.right_percentage.get(),
|
||||||
|
))
|
||||||
},
|
},
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
Color::System(system) => system.compute(context?),
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
Color::InheritFromBodyQuirk => ComputedColor::rgba(context?.device().body_text_color()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -585,11 +718,13 @@ impl ToComputedValue for Color {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_computed_value(computed: &ComputedColor) -> Self {
|
fn from_computed_value(computed: &ComputedColor) -> Self {
|
||||||
match *computed {
|
if computed.is_numeric() {
|
||||||
GenericColor::Numeric(color) => Color::rgba(color),
|
return Color::rgba(computed.color);
|
||||||
GenericColor::CurrentColor => Color::currentcolor(),
|
|
||||||
GenericColor::Complex { .. } => Color::Complex(*computed),
|
|
||||||
}
|
}
|
||||||
|
if computed.is_currentcolor() {
|
||||||
|
return Color::currentcolor();
|
||||||
|
}
|
||||||
|
Color::Complex(*computed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -671,3 +806,15 @@ impl Parse for ColorPropertyValue {
|
||||||
|
|
||||||
/// auto | <color>
|
/// auto | <color>
|
||||||
pub type ColorOrAuto = GenericColorOrAuto<Color>;
|
pub type ColorOrAuto = GenericColorOrAuto<Color>;
|
||||||
|
|
||||||
|
/// caret-color
|
||||||
|
pub type CaretColor = GenericCaretColor<Color>;
|
||||||
|
|
||||||
|
impl Parse for CaretColor {
|
||||||
|
fn parse<'i, 't>(
|
||||||
|
context: &ParserContext,
|
||||||
|
input: &mut Parser<'i, 't>,
|
||||||
|
) -> Result<Self, ParseError<'i>> {
|
||||||
|
ColorOrAuto::parse(context, input).map(GenericCaretColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -11,15 +11,15 @@ use crate::values::generics::counters as generics;
|
||||||
use crate::values::generics::counters::CounterPair;
|
use crate::values::generics::counters::CounterPair;
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
use crate::values::generics::CounterStyle;
|
use crate::values::generics::CounterStyle;
|
||||||
use crate::values::specified::url::SpecifiedImageUrl;
|
use crate::values::specified::image::Image;
|
||||||
#[cfg(any(feature = "gecko", feature = "servo-layout-2020"))]
|
#[cfg(any(feature = "gecko", feature = "servo-layout-2020"))]
|
||||||
use crate::values::specified::Attr;
|
use crate::values::specified::Attr;
|
||||||
use crate::values::specified::Integer;
|
use crate::values::specified::Integer;
|
||||||
use crate::values::CustomIdent;
|
use crate::values::CustomIdent;
|
||||||
use cssparser::{Parser, Token};
|
use cssparser::{Parser, Token};
|
||||||
#[cfg(feature = "servo-layout-2013")]
|
#[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
|
||||||
use selectors::parser::SelectorParseErrorKind;
|
use selectors::parser::SelectorParseErrorKind;
|
||||||
use style_traits::{ParseError, StyleParseErrorKind};
|
use style_traits::{KeywordsCollectFn, ParseError, SpecifiedValueInfo, StyleParseErrorKind};
|
||||||
|
|
||||||
/// A specified value for the `counter-increment` property.
|
/// A specified value for the `counter-increment` property.
|
||||||
pub type CounterIncrement = generics::GenericCounterIncrement<Integer>;
|
pub type CounterIncrement = generics::GenericCounterIncrement<Integer>;
|
||||||
|
@ -83,10 +83,10 @@ fn parse_counters<'i, 't>(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The specified value for the `content` property.
|
/// The specified value for the `content` property.
|
||||||
pub type Content = generics::GenericContent<SpecifiedImageUrl>;
|
pub type Content = generics::GenericContent<Image>;
|
||||||
|
|
||||||
/// The specified value for a content item in the `content` property.
|
/// The specified value for a content item in the `content` property.
|
||||||
pub type ContentItem = generics::GenericContentItem<SpecifiedImageUrl>;
|
pub type ContentItem = generics::GenericContentItem<Image>;
|
||||||
|
|
||||||
impl Content {
|
impl Content {
|
||||||
#[cfg(feature = "servo-layout-2013")]
|
#[cfg(feature = "servo-layout-2013")]
|
||||||
|
@ -137,8 +137,8 @@ impl Parse for Content {
|
||||||
loop {
|
loop {
|
||||||
#[cfg(any(feature = "gecko", feature = "servo-layout-2020"))]
|
#[cfg(any(feature = "gecko", feature = "servo-layout-2020"))]
|
||||||
{
|
{
|
||||||
if let Ok(url) = input.try_parse(|i| SpecifiedImageUrl::parse(context, i)) {
|
if let Ok(image) = input.try_parse(|i| Image::parse_only_url(context, i)) {
|
||||||
content.push(generics::ContentItem::Url(url));
|
content.push(generics::ContentItem::Image(image));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,6 +171,7 @@ impl Parse for Content {
|
||||||
Ok(generics::ContentItem::Attr(Attr::parse_function(context, input)?))
|
Ok(generics::ContentItem::Attr(Attr::parse_function(context, input)?))
|
||||||
}),
|
}),
|
||||||
_ => {
|
_ => {
|
||||||
|
use style_traits::StyleParseErrorKind;
|
||||||
let name = name.clone();
|
let name = name.clone();
|
||||||
return Err(input.new_custom_error(
|
return Err(input.new_custom_error(
|
||||||
StyleParseErrorKind::UnexpectedFunction(name),
|
StyleParseErrorKind::UnexpectedFunction(name),
|
||||||
|
@ -213,3 +214,20 @@ impl Parse for Content {
|
||||||
Ok(generics::Content::Items(content.into()))
|
Ok(generics::Content::Items(content.into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<Image> SpecifiedValueInfo for generics::GenericContentItem<Image> {
|
||||||
|
fn collect_completion_keywords(f: KeywordsCollectFn) {
|
||||||
|
f(&[
|
||||||
|
"url",
|
||||||
|
"image-set",
|
||||||
|
"counter",
|
||||||
|
"counters",
|
||||||
|
"attr",
|
||||||
|
"open-quote",
|
||||||
|
"close-quote",
|
||||||
|
"no-open-quote",
|
||||||
|
"no-close-quote",
|
||||||
|
"-moz-alt-content",
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ use crate::context::QuirksMode;
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
use crate::gecko_bindings::bindings;
|
use crate::gecko_bindings::bindings;
|
||||||
use crate::parser::{Parse, ParserContext};
|
use crate::parser::{Parse, ParserContext};
|
||||||
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};
|
||||||
|
@ -19,7 +18,7 @@ use crate::values::generics::font::{self as generics, FeatureTagValue, FontSetti
|
||||||
use crate::values::generics::NonNegative;
|
use crate::values::generics::NonNegative;
|
||||||
use crate::values::specified::length::{FontBaseSize, PX_PER_PT};
|
use crate::values::specified::length::{FontBaseSize, PX_PER_PT};
|
||||||
use crate::values::specified::{AllowQuirks, Angle, Integer, LengthPercentage};
|
use crate::values::specified::{AllowQuirks, Angle, Integer, LengthPercentage};
|
||||||
use crate::values::specified::{NoCalcLength, NonNegativeNumber, Number, Percentage};
|
use crate::values::specified::{NoCalcLength, NonNegativeNumber, Number, NonNegativePercentage};
|
||||||
use crate::values::CustomIdent;
|
use crate::values::CustomIdent;
|
||||||
use crate::Atom;
|
use crate::Atom;
|
||||||
use cssparser::{Parser, Token};
|
use cssparser::{Parser, Token};
|
||||||
|
@ -65,6 +64,54 @@ macro_rules! system_font_methods {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// System fonts.
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(
|
||||||
|
Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem
|
||||||
|
)]
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
pub enum SystemFont {
|
||||||
|
Caption,
|
||||||
|
Icon,
|
||||||
|
Menu,
|
||||||
|
MessageBox,
|
||||||
|
SmallCaption,
|
||||||
|
StatusBar,
|
||||||
|
MozWindow,
|
||||||
|
MozDocument,
|
||||||
|
MozWorkspace,
|
||||||
|
MozDesktop,
|
||||||
|
MozInfo,
|
||||||
|
MozDialog,
|
||||||
|
MozButton,
|
||||||
|
MozPullDownMenu,
|
||||||
|
MozList,
|
||||||
|
MozField,
|
||||||
|
#[css(skip)]
|
||||||
|
End, // Just for indexing purposes.
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't parse system fonts in servo, but in the interest of not
|
||||||
|
// littering a lot of code with `if engine == "gecko"` conditionals,
|
||||||
|
// we have a dummy system font module that does nothing
|
||||||
|
|
||||||
|
#[derive(
|
||||||
|
Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem
|
||||||
|
)]
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
#[cfg(feature = "servo")]
|
||||||
|
/// void enum for system font, can never exist
|
||||||
|
pub enum SystemFont {}
|
||||||
|
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
#[cfg(feature = "servo")]
|
||||||
|
impl SystemFont {
|
||||||
|
pub fn parse(_: &mut Parser) -> Result<Self, ()> {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const DEFAULT_SCRIPT_MIN_SIZE_PT: u32 = 8;
|
const DEFAULT_SCRIPT_MIN_SIZE_PT: u32 = 8;
|
||||||
const DEFAULT_SCRIPT_SIZE_MULTIPLIER: f64 = 0.71;
|
const DEFAULT_SCRIPT_SIZE_MULTIPLIER: f64 = 0.71;
|
||||||
|
|
||||||
|
@ -359,13 +406,11 @@ impl ToComputedValue for FontStyle {
|
||||||
/// A value for the `font-stretch` property.
|
/// A value for the `font-stretch` property.
|
||||||
///
|
///
|
||||||
/// https://drafts.csswg.org/css-fonts-4/#font-stretch-prop
|
/// https://drafts.csswg.org/css-fonts-4/#font-stretch-prop
|
||||||
///
|
|
||||||
/// TODO(emilio): We could derive Parse if we had NonNegativePercentage.
|
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
|
#[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum FontStretch {
|
pub enum FontStretch {
|
||||||
Stretch(Percentage),
|
Stretch(NonNegativePercentage),
|
||||||
Keyword(FontStretchKeyword),
|
Keyword(FontStretchKeyword),
|
||||||
#[css(skip)]
|
#[css(skip)]
|
||||||
System(SystemFont),
|
System(SystemFont),
|
||||||
|
@ -452,32 +497,13 @@ impl FontStretch {
|
||||||
system_font_methods!(FontStretch, font_stretch);
|
system_font_methods!(FontStretch, font_stretch);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for FontStretch {
|
|
||||||
fn parse<'i, 't>(
|
|
||||||
context: &ParserContext,
|
|
||||||
input: &mut Parser<'i, 't>,
|
|
||||||
) -> Result<Self, ParseError<'i>> {
|
|
||||||
// From https://drafts.csswg.org/css-fonts-4/#font-stretch-prop:
|
|
||||||
//
|
|
||||||
// Values less than 0% are not allowed and are treated as parse
|
|
||||||
// errors.
|
|
||||||
if let Ok(percentage) =
|
|
||||||
input.try_parse(|input| Percentage::parse_non_negative(context, input))
|
|
||||||
{
|
|
||||||
return Ok(FontStretch::Stretch(percentage));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(FontStretch::Keyword(FontStretchKeyword::parse(input)?))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToComputedValue for FontStretch {
|
impl ToComputedValue for FontStretch {
|
||||||
type ComputedValue = computed::FontStretch;
|
type ComputedValue = computed::FontStretch;
|
||||||
|
|
||||||
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||||
match *self {
|
match *self {
|
||||||
FontStretch::Stretch(ref percentage) => {
|
FontStretch::Stretch(ref percentage) => {
|
||||||
computed::FontStretch(NonNegative(percentage.to_computed_value(context)))
|
computed::FontStretch(percentage.to_computed_value(context))
|
||||||
},
|
},
|
||||||
FontStretch::Keyword(ref kw) => computed::FontStretch(NonNegative(kw.compute())),
|
FontStretch::Keyword(ref kw) => computed::FontStretch(NonNegative(kw.compute())),
|
||||||
FontStretch::System(_) => self.compute_system(context),
|
FontStretch::System(_) => self.compute_system(context),
|
||||||
|
@ -485,7 +511,7 @@ impl ToComputedValue for FontStretch {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||||
FontStretch::Stretch(Percentage::from_computed_value(&(computed.0).0))
|
FontStretch::Stretch(NonNegativePercentage::from_computed_value(&NonNegative((computed.0).0)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2226,6 +2252,37 @@ impl Parse for VariationValue<Number> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A metrics override value for a @font-face descriptor
|
||||||
|
///
|
||||||
|
/// https://drafts.csswg.org/css-fonts/#font-metrics-override-desc
|
||||||
|
#[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
|
||||||
|
pub enum MetricsOverride {
|
||||||
|
/// A non-negative `<percentage>` of the computed font size
|
||||||
|
Override(NonNegativePercentage),
|
||||||
|
/// Normal metrics from the font.
|
||||||
|
Normal,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MetricsOverride {
|
||||||
|
#[inline]
|
||||||
|
/// Get default value with `normal`
|
||||||
|
pub fn normal() -> MetricsOverride {
|
||||||
|
MetricsOverride::Normal
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The ToComputedValue implementation, used for @font-face descriptors.
|
||||||
|
///
|
||||||
|
/// Valid override percentages must be non-negative; we return -1.0 to indicate
|
||||||
|
/// the absence of an override (i.e. 'normal').
|
||||||
|
#[inline]
|
||||||
|
pub fn compute(&self) -> ComputedPercentage {
|
||||||
|
match *self {
|
||||||
|
MetricsOverride::Normal => ComputedPercentage(-1.0),
|
||||||
|
MetricsOverride::Override(percent) => ComputedPercentage(percent.0.get()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
Clone,
|
Clone,
|
||||||
Copy,
|
Copy,
|
||||||
|
|
|
@ -181,7 +181,7 @@ impl Parse for Image {
|
||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
) -> Result<Image, ParseError<'i>> {
|
) -> Result<Image, ParseError<'i>> {
|
||||||
Image::parse_with_cors_mode(context, input, CorsMode::None, /* allow_none = */ true)
|
Image::parse_with_cors_mode(context, input, CorsMode::None, /* allow_none = */ true, /* only_url = */ false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,23 +191,32 @@ impl Image {
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
cors_mode: CorsMode,
|
cors_mode: CorsMode,
|
||||||
allow_none: bool,
|
allow_none: bool,
|
||||||
|
only_url: bool,
|
||||||
) -> Result<Image, ParseError<'i>> {
|
) -> Result<Image, ParseError<'i>> {
|
||||||
if allow_none && input.try_parse(|i| i.expect_ident_matching("none")).is_ok() {
|
if allow_none && input.try_parse(|i| i.expect_ident_matching("none")).is_ok() {
|
||||||
return Ok(generic::Image::None);
|
return Ok(generic::Image::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(url) = input
|
if let Ok(url) = input
|
||||||
.try_parse(|input| SpecifiedImageUrl::parse_with_cors_mode(context, input, cors_mode))
|
.try_parse(|input| SpecifiedImageUrl::parse_with_cors_mode(context, input, cors_mode))
|
||||||
{
|
{
|
||||||
return Ok(generic::Image::Url(url));
|
return Ok(generic::Image::Url(url));
|
||||||
}
|
}
|
||||||
if let Ok(gradient) = input.try_parse(|i| Gradient::parse(context, i)) {
|
|
||||||
return Ok(generic::Image::Gradient(Box::new(gradient)));
|
|
||||||
}
|
|
||||||
if image_set_enabled() {
|
if image_set_enabled() {
|
||||||
if let Ok(is) = input.try_parse(|input| ImageSet::parse(context, input, cors_mode)) {
|
if let Ok(is) = input.try_parse(|input| ImageSet::parse(context, input, cors_mode, only_url)) {
|
||||||
return Ok(generic::Image::ImageSet(Box::new(is)));
|
return Ok(generic::Image::ImageSet(Box::new(is)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if only_url {
|
||||||
|
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(gradient) = input.try_parse(|i| Gradient::parse(context, i)) {
|
||||||
|
return Ok(generic::Image::Gradient(Box::new(gradient)));
|
||||||
|
}
|
||||||
|
|
||||||
if cross_fade_enabled() {
|
if cross_fade_enabled() {
|
||||||
if let Ok(cf) = input.try_parse(|input| CrossFade::parse(context, input, cors_mode)) {
|
if let Ok(cf) = input.try_parse(|input| CrossFade::parse(context, input, cors_mode)) {
|
||||||
return Ok(generic::Image::CrossFade(Box::new(cf)));
|
return Ok(generic::Image::CrossFade(Box::new(cf)));
|
||||||
|
@ -264,6 +273,21 @@ impl Image {
|
||||||
input,
|
input,
|
||||||
CorsMode::Anonymous,
|
CorsMode::Anonymous,
|
||||||
/* allow_none = */ true,
|
/* allow_none = */ true,
|
||||||
|
/* only_url = */ false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Provides an alternate method for parsing, but only for urls.
|
||||||
|
pub fn parse_only_url<'i, 't>(
|
||||||
|
context: &ParserContext,
|
||||||
|
input: &mut Parser<'i, 't>,
|
||||||
|
) -> Result<Image, ParseError<'i>> {
|
||||||
|
Self::parse_with_cors_mode(
|
||||||
|
context,
|
||||||
|
input,
|
||||||
|
CorsMode::None,
|
||||||
|
/* allow_none = */ false,
|
||||||
|
/* only_url = */ true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -310,7 +334,7 @@ impl CrossFadeImage {
|
||||||
cors_mode: CorsMode,
|
cors_mode: CorsMode,
|
||||||
) -> Result<Self, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
if let Ok(image) = input.try_parse(|input| {
|
if let Ok(image) = input.try_parse(|input| {
|
||||||
Image::parse_with_cors_mode(context, input, cors_mode, /* allow_none = */ false)
|
Image::parse_with_cors_mode(context, input, cors_mode, /* allow_none = */ false, /* only_url = */ false)
|
||||||
}) {
|
}) {
|
||||||
return Ok(Self::Image(image));
|
return Ok(Self::Image(image));
|
||||||
}
|
}
|
||||||
|
@ -339,10 +363,11 @@ impl ImageSet {
|
||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
cors_mode: CorsMode,
|
cors_mode: CorsMode,
|
||||||
|
only_url: bool,
|
||||||
) -> Result<Self, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
input.expect_function_matching("image-set")?;
|
input.expect_function_matching("image-set")?;
|
||||||
let items = input.parse_nested_block(|input| {
|
let items = input.parse_nested_block(|input| {
|
||||||
input.parse_comma_separated(|input| ImageSetItem::parse(context, input, cors_mode))
|
input.parse_comma_separated(|input| ImageSetItem::parse(context, input, cors_mode, only_url))
|
||||||
})?;
|
})?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
selected_index: 0,
|
selected_index: 0,
|
||||||
|
@ -352,10 +377,18 @@ impl ImageSet {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ImageSetItem {
|
impl ImageSetItem {
|
||||||
|
fn parse_type<'i>(p: &mut Parser<'i, '_>) -> Result<crate::OwnedStr, ParseError<'i>> {
|
||||||
|
p.expect_function_matching("type")?;
|
||||||
|
p.parse_nested_block(|input| {
|
||||||
|
Ok(input.expect_string()?.as_ref().to_owned().into())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn parse<'i, 't>(
|
fn parse<'i, 't>(
|
||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
cors_mode: CorsMode,
|
cors_mode: CorsMode,
|
||||||
|
only_url: bool,
|
||||||
) -> Result<Self, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
let image = match input.try_parse(|i| i.expect_url_or_string()) {
|
let image = match input.try_parse(|i| i.expect_url_or_string()) {
|
||||||
Ok(url) => Image::Url(SpecifiedImageUrl::parse_from_string(
|
Ok(url) => Image::Url(SpecifiedImageUrl::parse_from_string(
|
||||||
|
@ -364,13 +397,23 @@ impl ImageSetItem {
|
||||||
cors_mode,
|
cors_mode,
|
||||||
)),
|
)),
|
||||||
Err(..) => Image::parse_with_cors_mode(
|
Err(..) => Image::parse_with_cors_mode(
|
||||||
context, input, cors_mode, /* allow_none = */ false,
|
context, input, cors_mode, /* allow_none = */ false, /* only_url = */ only_url
|
||||||
)?,
|
)?,
|
||||||
};
|
};
|
||||||
let resolution = input
|
|
||||||
.try_parse(|input| Resolution::parse(context, input))
|
let mut resolution = input.try_parse(|input| Resolution::parse(context, input)).ok();
|
||||||
.unwrap_or(Resolution::X(1.0));
|
let mime_type = input.try_parse(Self::parse_type).ok();
|
||||||
Ok(Self { image, resolution })
|
|
||||||
|
// Try to parse resolution after type().
|
||||||
|
if mime_type.is_some() && resolution.is_none() {
|
||||||
|
resolution = input.try_parse(|input| Resolution::parse(context, input)).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
let resolution = resolution.unwrap_or(Resolution::X(1.0));
|
||||||
|
let has_mime_type = mime_type.is_some();
|
||||||
|
let mime_type = mime_type.unwrap_or_default();
|
||||||
|
|
||||||
|
Ok(Self { image, resolution, has_mime_type, mime_type })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1226,6 +1226,27 @@ impl Parse for Size {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! parse_size_non_length {
|
||||||
|
($size:ident, $input:expr, $auto_or_none:expr => $auto_or_none_ident:ident) => {{
|
||||||
|
let size = $input.try_parse(|input| {
|
||||||
|
Ok(try_match_ident_ignore_ascii_case! { input,
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
"min-content" | "-moz-min-content" => $size::MinContent,
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
"max-content" | "-moz-max-content" => $size::MaxContent,
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
"-moz-fit-content" => $size::MozFitContent,
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
"-moz-available" => $size::MozAvailable,
|
||||||
|
$auto_or_none => $size::$auto_or_none_ident,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
if size.is_ok() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
impl Size {
|
impl Size {
|
||||||
/// Parses, with quirks.
|
/// Parses, with quirks.
|
||||||
pub fn parse_quirky<'i, 't>(
|
pub fn parse_quirky<'i, 't>(
|
||||||
|
@ -1233,16 +1254,7 @@ impl Size {
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
allow_quirks: AllowQuirks,
|
allow_quirks: AllowQuirks,
|
||||||
) -> Result<Self, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
#[cfg(feature = "gecko")]
|
parse_size_non_length!(Size, input, "auto" => Auto);
|
||||||
{
|
|
||||||
if let Ok(l) = input.try_parse(computed::ExtremumLength::parse) {
|
|
||||||
return Ok(GenericSize::ExtremumLength(l));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if input.try_parse(|i| i.expect_ident_matching("auto")).is_ok() {
|
|
||||||
return Ok(GenericSize::Auto);
|
|
||||||
}
|
|
||||||
|
|
||||||
let length = NonNegativeLengthPercentage::parse_quirky(context, input, allow_quirks)?;
|
let length = NonNegativeLengthPercentage::parse_quirky(context, input, allow_quirks)?;
|
||||||
Ok(GenericSize::LengthPercentage(length))
|
Ok(GenericSize::LengthPercentage(length))
|
||||||
|
@ -1274,16 +1286,7 @@ impl MaxSize {
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
allow_quirks: AllowQuirks,
|
allow_quirks: AllowQuirks,
|
||||||
) -> Result<Self, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
#[cfg(feature = "gecko")]
|
parse_size_non_length!(MaxSize, input, "none" => None);
|
||||||
{
|
|
||||||
if let Ok(l) = input.try_parse(computed::ExtremumLength::parse) {
|
|
||||||
return Ok(GenericMaxSize::ExtremumLength(l));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if input.try_parse(|i| i.expect_ident_matching("none")).is_ok() {
|
|
||||||
return Ok(GenericMaxSize::None);
|
|
||||||
}
|
|
||||||
|
|
||||||
let length = NonNegativeLengthPercentage::parse_quirky(context, input, allow_quirks)?;
|
let length = NonNegativeLengthPercentage::parse_quirky(context, input, allow_quirks)?;
|
||||||
Ok(GenericMaxSize::LengthPercentage(length))
|
Ok(GenericMaxSize::LengthPercentage(length))
|
||||||
|
|
|
@ -71,7 +71,7 @@ pub use self::list::Quotes;
|
||||||
pub use self::motion::{OffsetPath, OffsetRotate};
|
pub use self::motion::{OffsetPath, OffsetRotate};
|
||||||
pub use self::outline::OutlineStyle;
|
pub use self::outline::OutlineStyle;
|
||||||
pub use self::page::{Orientation, PageSize, PaperSize};
|
pub use self::page::{Orientation, PageSize, PaperSize};
|
||||||
pub use self::percentage::Percentage;
|
pub use self::percentage::{Percentage, NonNegativePercentage};
|
||||||
pub use self::position::AspectRatio;
|
pub use self::position::AspectRatio;
|
||||||
pub use self::position::{
|
pub use self::position::{
|
||||||
GridAutoFlow, GridTemplateAreas, MasonryAutoFlow, Position, PositionOrAuto,
|
GridAutoFlow, GridTemplateAreas, MasonryAutoFlow, Position, PositionOrAuto,
|
||||||
|
@ -86,10 +86,11 @@ pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
|
||||||
pub use self::svg_path::SVGPathData;
|
pub use self::svg_path::SVGPathData;
|
||||||
pub use self::text::TextAlignLast;
|
pub use self::text::TextAlignLast;
|
||||||
pub use self::text::TextUnderlinePosition;
|
pub use self::text::TextUnderlinePosition;
|
||||||
|
pub use self::text::RubyPosition;
|
||||||
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};
|
||||||
pub use self::text::{TextDecorationLength, TextDecorationSkipInk, TextTransform};
|
pub use self::text::{TextDecorationLength, TextDecorationSkipInk, TextJustify, TextTransform};
|
||||||
pub use self::time::Time;
|
pub use self::time::Time;
|
||||||
pub use self::transform::{Rotate, Scale, Transform};
|
pub use self::transform::{Rotate, Scale, Transform};
|
||||||
pub use self::transform::{TransformOrigin, TransformStyle, Translate};
|
pub use self::transform::{TransformOrigin, TransformStyle, Translate};
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
use crate::parser::{Parse, ParserContext};
|
use crate::parser::{Parse, ParserContext};
|
||||||
use crate::values::computed::percentage::Percentage as ComputedPercentage;
|
use crate::values::computed::percentage::Percentage as ComputedPercentage;
|
||||||
use crate::values::computed::{Context, ToComputedValue};
|
use crate::values::computed::{Context, ToComputedValue};
|
||||||
|
use crate::values::generics::NonNegative;
|
||||||
use crate::values::specified::calc::CalcNode;
|
use crate::values::specified::calc::CalcNode;
|
||||||
use crate::values::specified::Number;
|
use crate::values::specified::Number;
|
||||||
use crate::values::{serialize_percentage, CSSFloat};
|
use crate::values::{serialize_percentage, CSSFloat};
|
||||||
|
@ -172,3 +173,24 @@ impl ToComputedValue for Percentage {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpecifiedValueInfo for Percentage {}
|
impl SpecifiedValueInfo for Percentage {}
|
||||||
|
|
||||||
|
/// A wrapper of Percentage, whose value must be >= 0.
|
||||||
|
pub type NonNegativePercentage = NonNegative<Percentage>;
|
||||||
|
|
||||||
|
impl Parse for NonNegativePercentage {
|
||||||
|
#[inline]
|
||||||
|
fn parse<'i, 't>(
|
||||||
|
context: &ParserContext,
|
||||||
|
input: &mut Parser<'i, 't>,
|
||||||
|
) -> Result<Self, ParseError<'i>> {
|
||||||
|
Ok(NonNegative(Percentage::parse_non_negative(context, input)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NonNegativePercentage {
|
||||||
|
/// Convert to ComputedPercentage, for FontFaceRule size-adjust getter.
|
||||||
|
#[inline]
|
||||||
|
pub fn compute(&self) -> ComputedPercentage {
|
||||||
|
ComputedPercentage(self.0.get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ use selectors::parser::SelectorParseErrorKind;
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
use style_traits::values::SequenceWriter;
|
use style_traits::values::SequenceWriter;
|
||||||
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
|
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
|
||||||
|
use style_traits::{KeywordsCollectFn, SpecifiedValueInfo};
|
||||||
use unicode_segmentation::UnicodeSegmentation;
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
|
|
||||||
/// A specified type for the `initial-letter` property.
|
/// A specified type for the `initial-letter` property.
|
||||||
|
@ -1000,6 +1001,67 @@ pub enum WordBreak {
|
||||||
BreakWord,
|
BreakWord,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Values for the `text-justify` CSS property.
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(
|
||||||
|
Clone,
|
||||||
|
Copy,
|
||||||
|
Debug,
|
||||||
|
Eq,
|
||||||
|
MallocSizeOf,
|
||||||
|
Parse,
|
||||||
|
PartialEq,
|
||||||
|
SpecifiedValueInfo,
|
||||||
|
ToComputedValue,
|
||||||
|
ToCss,
|
||||||
|
ToResolvedValue,
|
||||||
|
ToShmem,
|
||||||
|
)]
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
pub enum TextJustify {
|
||||||
|
Auto,
|
||||||
|
None,
|
||||||
|
InterWord,
|
||||||
|
// See https://drafts.csswg.org/css-text-3/#valdef-text-justify-distribute
|
||||||
|
// and https://github.com/w3c/csswg-drafts/issues/6156 for the alias.
|
||||||
|
#[parse(aliases = "distribute")]
|
||||||
|
InterCharacter,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Values for the `-moz-control-character-visibility` CSS property.
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(
|
||||||
|
Clone,
|
||||||
|
Copy,
|
||||||
|
Debug,
|
||||||
|
Eq,
|
||||||
|
MallocSizeOf,
|
||||||
|
Parse,
|
||||||
|
PartialEq,
|
||||||
|
SpecifiedValueInfo,
|
||||||
|
ToComputedValue,
|
||||||
|
ToCss,
|
||||||
|
ToResolvedValue,
|
||||||
|
ToShmem,
|
||||||
|
)]
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
pub enum MozControlCharacterVisibility {
|
||||||
|
Hidden,
|
||||||
|
Visible,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
impl Default for MozControlCharacterVisibility {
|
||||||
|
fn default() -> Self {
|
||||||
|
if static_prefs::pref!("layout.css.control-characters.visible") {
|
||||||
|
Self::Visible
|
||||||
|
} else {
|
||||||
|
Self::Hidden
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Values for the `line-break` property.
|
/// Values for the `line-break` property.
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(
|
#[derive(
|
||||||
|
@ -1193,3 +1255,72 @@ impl ToCss for TextUnderlinePosition {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Values for `ruby-position` property
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(
|
||||||
|
Clone,
|
||||||
|
Copy,
|
||||||
|
Debug,
|
||||||
|
Eq,
|
||||||
|
MallocSizeOf,
|
||||||
|
PartialEq,
|
||||||
|
ToComputedValue,
|
||||||
|
ToResolvedValue,
|
||||||
|
ToShmem,
|
||||||
|
)]
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
pub enum RubyPosition {
|
||||||
|
AlternateOver,
|
||||||
|
AlternateUnder,
|
||||||
|
Over,
|
||||||
|
Under,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for RubyPosition {
|
||||||
|
fn parse<'i, 't>(
|
||||||
|
_context: &ParserContext,
|
||||||
|
input: &mut Parser<'i, 't>,
|
||||||
|
) -> Result<RubyPosition, ParseError<'i>> {
|
||||||
|
// Parse alternate before
|
||||||
|
let alternate = input.try_parse(|i| i.expect_ident_matching("alternate")).is_ok();
|
||||||
|
if alternate && input.is_exhausted() {
|
||||||
|
return Ok(RubyPosition::AlternateOver);
|
||||||
|
}
|
||||||
|
// Parse over / under
|
||||||
|
let over = try_match_ident_ignore_ascii_case! { input,
|
||||||
|
"over" => true,
|
||||||
|
"under" => false,
|
||||||
|
};
|
||||||
|
// Parse alternate after
|
||||||
|
let alternate = alternate ||
|
||||||
|
input.try_parse(|i| i.expect_ident_matching("alternate")).is_ok();
|
||||||
|
|
||||||
|
Ok(match (over, alternate) {
|
||||||
|
(true, true) => RubyPosition::AlternateOver,
|
||||||
|
(false, true) => RubyPosition::AlternateUnder,
|
||||||
|
(true, false) => RubyPosition::Over,
|
||||||
|
(false, false) => RubyPosition::Under,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToCss for RubyPosition {
|
||||||
|
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||||
|
where
|
||||||
|
W: Write,
|
||||||
|
{
|
||||||
|
dest.write_str(match self {
|
||||||
|
RubyPosition::AlternateOver => "alternate",
|
||||||
|
RubyPosition::AlternateUnder => "alternate under",
|
||||||
|
RubyPosition::Over => "over",
|
||||||
|
RubyPosition::Under => "under",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpecifiedValueInfo for RubyPosition {
|
||||||
|
fn collect_completion_keywords(f: KeywordsCollectFn) {
|
||||||
|
f(&["alternate", "over", "under"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -7,17 +7,17 @@
|
||||||
use crate::parser::{Parse, ParserContext};
|
use crate::parser::{Parse, ParserContext};
|
||||||
use crate::values::generics::ui as generics;
|
use crate::values::generics::ui as generics;
|
||||||
use crate::values::specified::color::Color;
|
use crate::values::specified::color::Color;
|
||||||
use crate::values::specified::url::SpecifiedImageUrl;
|
use crate::values::specified::image::Image;
|
||||||
use crate::values::specified::Number;
|
use crate::values::specified::Number;
|
||||||
use cssparser::Parser;
|
use cssparser::Parser;
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
|
use style_traits::{CssWriter, KeywordsCollectFn, ParseError, SpecifiedValueInfo, StyleParseErrorKind, ToCss};
|
||||||
|
|
||||||
/// A specified value for the `cursor` property.
|
/// A specified value for the `cursor` property.
|
||||||
pub type Cursor = generics::GenericCursor<CursorImage>;
|
pub type Cursor = generics::GenericCursor<CursorImage>;
|
||||||
|
|
||||||
/// A specified value for item of `image cursors`.
|
/// A specified value for item of `image cursors`.
|
||||||
pub type CursorImage = generics::GenericCursorImage<SpecifiedImageUrl, Number>;
|
pub type CursorImage = generics::GenericCursorImage<Image, Number>;
|
||||||
|
|
||||||
impl Parse for Cursor {
|
impl Parse for Cursor {
|
||||||
/// cursor: [<url> [<number> <number>]?]# [auto | default | ...]
|
/// cursor: [<url> [<number> <number>]?]# [auto | default | ...]
|
||||||
|
@ -47,7 +47,7 @@ impl Parse for CursorImage {
|
||||||
) -> Result<Self, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
use crate::Zero;
|
use crate::Zero;
|
||||||
|
|
||||||
let url = SpecifiedImageUrl::parse(context, input)?;
|
let image = Image::parse_only_url(context, input)?;
|
||||||
let mut has_hotspot = false;
|
let mut has_hotspot = false;
|
||||||
let mut hotspot_x = Number::zero();
|
let mut hotspot_x = Number::zero();
|
||||||
let mut hotspot_y = Number::zero();
|
let mut hotspot_y = Number::zero();
|
||||||
|
@ -59,7 +59,7 @@ impl Parse for CursorImage {
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
url,
|
image,
|
||||||
has_hotspot,
|
has_hotspot,
|
||||||
hotspot_x,
|
hotspot_x,
|
||||||
hotspot_y,
|
hotspot_y,
|
||||||
|
@ -67,6 +67,13 @@ impl Parse for CursorImage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This trait is manually implemented because we don't support the whole <image>
|
||||||
|
// syntax for cursors
|
||||||
|
impl SpecifiedValueInfo for CursorImage {
|
||||||
|
fn collect_completion_keywords(f: KeywordsCollectFn) {
|
||||||
|
f(&["url", "image-set"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
/// Specified value of `-moz-force-broken-image-icon`
|
/// Specified value of `-moz-force-broken-image-icon`
|
||||||
#[derive(
|
#[derive(
|
||||||
Clone,
|
Clone,
|
||||||
|
|
|
@ -91,6 +91,11 @@ packages = [
|
||||||
# Files that are ignored for all tidy and lint checks.
|
# Files that are ignored for all tidy and lint checks.
|
||||||
files = [
|
files = [
|
||||||
"./components/net/tests/parsable_mime/text",
|
"./components/net/tests/parsable_mime/text",
|
||||||
|
# These are ignored to avoid diverging from Gecko
|
||||||
|
"./components/style/properties/helpers.mako.rs",
|
||||||
|
"./components/style/stylesheets/rule_parser.rs",
|
||||||
|
"./components/style/stylist.rs",
|
||||||
|
"./components/style/values/computed/image.rs",
|
||||||
# Mako does not lend itself easily to splitting long lines
|
# Mako does not lend itself easily to splitting long lines
|
||||||
"./components/style/properties/helpers/animated_properties.mako.rs",
|
"./components/style/properties/helpers/animated_properties.mako.rs",
|
||||||
"./components/style/properties/shorthands/text.mako.rs",
|
"./components/style/properties/shorthands/text.mako.rs",
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
[clamp-length-computed.html]
|
|
||||||
[Property letter-spacing value 'clamp(10px, 35px , 30px)']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Property letter-spacing value 'clamp(10px, 35px /*foo*/, 30px)']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Property letter-spacing value 'clamp(10px /* foo */ , 35px, 30px)']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Property letter-spacing value 'clamp(10px , 35px, 30px)']
|
|
||||||
expected: FAIL
|
|
|
@ -1,7 +1,4 @@
|
||||||
[inheritance.html]
|
[inheritance.html]
|
||||||
[Property text-justify inherits]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Property text-align-all has initial value start]
|
[Property text-align-all has initial value start]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
[text-justify-computed-legacy.html]
|
|
||||||
[Property text-justify value 'distribute']
|
|
||||||
expected: FAIL
|
|
|
@ -1,7 +1,3 @@
|
||||||
[text-justify-computed.html]
|
[text-justify-computed.html]
|
||||||
[Property text-justify value 'inter-character' computes to 'inter-character']
|
[Property text-justify value 'inter-character' computes to 'inter-character']
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Property text-justify value 'inter-character']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[text-justify-valid.html]
|
|
||||||
[e.style['text-justify'\] = "inter-character" should set the property value]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
[distribute-alias.tentative.html]
|
|
||||||
[text-justify: distribute is a parse-time alias of inter-character]
|
|
||||||
expected: FAIL
|
|
|
@ -47,18 +47,6 @@
|
||||||
[CSS Transitions: property <text-justify> from [auto\] to [inter-character\] at (0.3) should be [inter-character\]]
|
[CSS Transitions: property <text-justify> from [auto\] to [inter-character\] at (0.3) should be [inter-character\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions: property <text-justify> from [auto\] to [inter-character\] at (0.5) should be [inter-character\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <text-justify> from [auto\] to [inter-character\] at (0.6) should be [inter-character\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <text-justify> from [auto\] to [inter-character\] at (1) should be [inter-character\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <text-justify> from [auto\] to [inter-character\] at (1.5) should be [inter-character\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <text-justify> from [auto\] to [inter-character\] at (-0.3) should be [inter-character\]]
|
[CSS Transitions with transition: all: property <text-justify> from [auto\] to [inter-character\] at (-0.3) should be [inter-character\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -68,39 +56,6 @@
|
||||||
[CSS Transitions with transition: all: property <text-justify> from [auto\] to [inter-character\] at (0.3) should be [inter-character\]]
|
[CSS Transitions with transition: all: property <text-justify> from [auto\] to [inter-character\] at (0.3) should be [inter-character\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <text-justify> from [auto\] to [inter-character\] at (0.5) should be [inter-character\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <text-justify> from [auto\] to [inter-character\] at (0.6) should be [inter-character\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <text-justify> from [auto\] to [inter-character\] at (1) should be [inter-character\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <text-justify> from [auto\] to [inter-character\] at (1.5) should be [inter-character\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <text-justify> from [auto\] to [inter-character\] at (-0.3) should be [auto\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <text-justify> from [auto\] to [inter-character\] at (0) should be [auto\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <text-justify> from [auto\] to [inter-character\] at (0.3) should be [auto\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <text-justify> from [auto\] to [inter-character\] at (0.5) should be [inter-character\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <text-justify> from [auto\] to [inter-character\] at (0.6) should be [inter-character\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <text-justify> from [auto\] to [inter-character\] at (1) should be [inter-character\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <text-justify> from [auto\] to [inter-character\] at (1.5) should be [inter-character\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Web Animations: property <text-justify> from [auto\] to [inter-character\] at (-0.3) should be [auto\]]
|
[Web Animations: property <text-justify> from [auto\] to [inter-character\] at (-0.3) should be [auto\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -131,60 +86,6 @@
|
||||||
[CSS Transitions: property <text-justify> from [inter-character\] to [distribute\] at (0.3) should be [distribute\]]
|
[CSS Transitions: property <text-justify> from [inter-character\] to [distribute\] at (0.3) should be [distribute\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions: property <text-justify> from [inter-character\] to [distribute\] at (0.5) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <text-justify> from [inter-character\] to [distribute\] at (0.6) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <text-justify> from [inter-character\] to [distribute\] at (1) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <text-justify> from [inter-character\] to [distribute\] at (1.5) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <text-justify> from [inter-character\] to [distribute\] at (-0.3) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <text-justify> from [inter-character\] to [distribute\] at (0) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <text-justify> from [inter-character\] to [distribute\] at (0.3) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <text-justify> from [inter-character\] to [distribute\] at (0.5) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <text-justify> from [inter-character\] to [distribute\] at (0.6) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <text-justify> from [inter-character\] to [distribute\] at (1) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <text-justify> from [inter-character\] to [distribute\] at (1.5) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <text-justify> from [inter-character\] to [distribute\] at (-0.3) should be [inter-character\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <text-justify> from [inter-character\] to [distribute\] at (0) should be [inter-character\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <text-justify> from [inter-character\] to [distribute\] at (0.3) should be [inter-character\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <text-justify> from [inter-character\] to [distribute\] at (0.5) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <text-justify> from [inter-character\] to [distribute\] at (0.6) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <text-justify> from [inter-character\] to [distribute\] at (1) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <text-justify> from [inter-character\] to [distribute\] at (1.5) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Web Animations: property <text-justify> from [inter-character\] to [distribute\] at (-0.3) should be [inter-character\]]
|
[Web Animations: property <text-justify> from [inter-character\] to [distribute\] at (-0.3) should be [inter-character\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -215,18 +116,6 @@
|
||||||
[CSS Transitions: property <text-justify> from [inter-word\] to [distribute\] at (0.3) should be [distribute\]]
|
[CSS Transitions: property <text-justify> from [inter-word\] to [distribute\] at (0.3) should be [distribute\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions: property <text-justify> from [inter-word\] to [distribute\] at (0.5) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <text-justify> from [inter-word\] to [distribute\] at (0.6) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <text-justify> from [inter-word\] to [distribute\] at (1) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <text-justify> from [inter-word\] to [distribute\] at (1.5) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <text-justify> from [inter-word\] to [distribute\] at (-0.3) should be [distribute\]]
|
[CSS Transitions with transition: all: property <text-justify> from [inter-word\] to [distribute\] at (-0.3) should be [distribute\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -236,39 +125,6 @@
|
||||||
[CSS Transitions with transition: all: property <text-justify> from [inter-word\] to [distribute\] at (0.3) should be [distribute\]]
|
[CSS Transitions with transition: all: property <text-justify> from [inter-word\] to [distribute\] at (0.3) should be [distribute\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <text-justify> from [inter-word\] to [distribute\] at (0.5) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <text-justify> from [inter-word\] to [distribute\] at (0.6) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <text-justify> from [inter-word\] to [distribute\] at (1) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <text-justify> from [inter-word\] to [distribute\] at (1.5) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <text-justify> from [inter-word\] to [distribute\] at (-0.3) should be [inter-word\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <text-justify> from [inter-word\] to [distribute\] at (0) should be [inter-word\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <text-justify> from [inter-word\] to [distribute\] at (0.3) should be [inter-word\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <text-justify> from [inter-word\] to [distribute\] at (0.5) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <text-justify> from [inter-word\] to [distribute\] at (0.6) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <text-justify> from [inter-word\] to [distribute\] at (1) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <text-justify> from [inter-word\] to [distribute\] at (1.5) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Web Animations: property <text-justify> from [inter-word\] to [distribute\] at (-0.3) should be [inter-word\]]
|
[Web Animations: property <text-justify> from [inter-word\] to [distribute\] at (-0.3) should be [inter-word\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -299,18 +155,6 @@
|
||||||
[CSS Transitions: property <text-justify> from [distribute\] to [none\] at (0.3) should be [none\]]
|
[CSS Transitions: property <text-justify> from [distribute\] to [none\] at (0.3) should be [none\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions: property <text-justify> from [distribute\] to [none\] at (0.5) should be [none\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <text-justify> from [distribute\] to [none\] at (0.6) should be [none\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <text-justify> from [distribute\] to [none\] at (1) should be [none\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <text-justify> from [distribute\] to [none\] at (1.5) should be [none\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <text-justify> from [distribute\] to [none\] at (-0.3) should be [none\]]
|
[CSS Transitions with transition: all: property <text-justify> from [distribute\] to [none\] at (-0.3) should be [none\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -320,39 +164,6 @@
|
||||||
[CSS Transitions with transition: all: property <text-justify> from [distribute\] to [none\] at (0.3) should be [none\]]
|
[CSS Transitions with transition: all: property <text-justify> from [distribute\] to [none\] at (0.3) should be [none\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <text-justify> from [distribute\] to [none\] at (0.5) should be [none\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <text-justify> from [distribute\] to [none\] at (0.6) should be [none\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <text-justify> from [distribute\] to [none\] at (1) should be [none\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <text-justify> from [distribute\] to [none\] at (1.5) should be [none\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <text-justify> from [distribute\] to [none\] at (-0.3) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <text-justify> from [distribute\] to [none\] at (0) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <text-justify> from [distribute\] to [none\] at (0.3) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <text-justify> from [distribute\] to [none\] at (0.5) should be [none\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <text-justify> from [distribute\] to [none\] at (0.6) should be [none\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <text-justify> from [distribute\] to [none\] at (1) should be [none\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <text-justify> from [distribute\] to [none\] at (1.5) should be [none\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Web Animations: property <text-justify> from [distribute\] to [none\] at (-0.3) should be [distribute\]]
|
[Web Animations: property <text-justify> from [distribute\] to [none\] at (-0.3) should be [distribute\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -373,39 +184,3 @@
|
||||||
|
|
||||||
[Web Animations: property <text-justify> from [distribute\] to [none\] at (1.5) should be [none\]]
|
[Web Animations: property <text-justify> from [distribute\] to [none\] at (1.5) should be [none\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions: property <text-justify> from [auto\] to [inter-character\] at (-0.3) should be [auto\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <text-justify> from [auto\] to [inter-character\] at (0) should be [auto\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <text-justify> from [auto\] to [inter-character\] at (0.3) should be [auto\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <text-justify> from [inter-character\] to [distribute\] at (-0.3) should be [inter-character\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <text-justify> from [inter-character\] to [distribute\] at (0) should be [inter-character\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <text-justify> from [inter-character\] to [distribute\] at (0.3) should be [inter-character\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <text-justify> from [inter-word\] to [distribute\] at (-0.3) should be [inter-word\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <text-justify> from [inter-word\] to [distribute\] at (0) should be [inter-word\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <text-justify> from [inter-word\] to [distribute\] at (0.3) should be [inter-word\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <text-justify> from [distribute\] to [none\] at (-0.3) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <text-justify> from [distribute\] to [none\] at (0) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <text-justify> from [distribute\] to [none\] at (0.3) should be [distribute\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -10,15 +10,3 @@
|
||||||
|
|
||||||
[Property letter-spacing value 'clamp(10px, 20px, 30px)' computes to '20px']
|
[Property letter-spacing value 'clamp(10px, 20px, 30px)' computes to '20px']
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Property letter-spacing value 'clamp(10px, 35px , 30px)']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Property letter-spacing value 'clamp(10px, 35px /*foo*/, 30px)']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Property letter-spacing value 'clamp(10px /* foo */ , 35px, 30px)']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Property letter-spacing value 'clamp(10px , 35px, 30px)']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue