mirror of
https://github.com/servo/servo.git
synced 2025-07-03 05:23:38 +01:00
Auto merge of #21188 - emilio:gecko-sync, r=emilio
style: Sync changes from mozilla-central. https://bugzilla.mozilla.org/show_bug.cgi?id=1476054 See each individual commit for details. I skipped the import of bug 1467277, which can't be done until euclid is updated everywhere.
This commit is contained in:
commit
bd6f3cb5ee
25 changed files with 376 additions and 751 deletions
|
@ -693,6 +693,90 @@ impl MallocSizeOf for selectors::parser::AncestorHashes {
|
|||
}
|
||||
}
|
||||
|
||||
impl<Impl: selectors::parser::SelectorImpl> MallocSizeOf
|
||||
for selectors::parser::Selector<Impl>
|
||||
where
|
||||
Impl::NonTSPseudoClass: MallocSizeOf,
|
||||
Impl::PseudoElement: MallocSizeOf,
|
||||
{
|
||||
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
|
||||
let mut n = 0;
|
||||
|
||||
// It's OK to measure this ThinArc directly because it's the
|
||||
// "primary" reference. (The secondary references are on the
|
||||
// Stylist.)
|
||||
n += unsafe { ops.malloc_size_of(self.thin_arc_heap_ptr()) };
|
||||
for component in self.iter_raw_match_order() {
|
||||
n += component.size_of(ops);
|
||||
}
|
||||
|
||||
n
|
||||
}
|
||||
}
|
||||
|
||||
impl<Impl: selectors::parser::SelectorImpl> MallocSizeOf
|
||||
for selectors::parser::Component<Impl>
|
||||
where
|
||||
Impl::NonTSPseudoClass: MallocSizeOf,
|
||||
Impl::PseudoElement: MallocSizeOf,
|
||||
{
|
||||
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
|
||||
use selectors::parser::Component;
|
||||
|
||||
match self {
|
||||
Component::AttributeOther(ref attr_selector) => {
|
||||
attr_selector.size_of(ops)
|
||||
}
|
||||
Component::Negation(ref components) => {
|
||||
components.size_of(ops)
|
||||
}
|
||||
Component::NonTSPseudoClass(ref pseudo) => {
|
||||
(*pseudo).size_of(ops)
|
||||
}
|
||||
Component::Slotted(ref selector) |
|
||||
Component::Host(Some(ref selector)) => {
|
||||
selector.size_of(ops)
|
||||
}
|
||||
Component::PseudoElement(ref pseudo) => {
|
||||
(*pseudo).size_of(ops)
|
||||
}
|
||||
Component::Combinator(..) |
|
||||
Component::ExplicitAnyNamespace |
|
||||
Component::ExplicitNoNamespace |
|
||||
Component::DefaultNamespace(..) |
|
||||
Component::Namespace(..) |
|
||||
Component::ExplicitUniversalType |
|
||||
Component::LocalName(..) |
|
||||
Component::ID(..) |
|
||||
Component::Class(..) |
|
||||
Component::AttributeInNoNamespaceExists { .. } |
|
||||
Component::AttributeInNoNamespace { .. } |
|
||||
Component::FirstChild |
|
||||
Component::LastChild |
|
||||
Component::OnlyChild |
|
||||
Component::Root |
|
||||
Component::Empty |
|
||||
Component::Scope |
|
||||
Component::NthChild(..) |
|
||||
Component::NthLastChild(..) |
|
||||
Component::NthOfType(..) |
|
||||
Component::NthLastOfType(..) |
|
||||
Component::FirstOfType |
|
||||
Component::LastOfType |
|
||||
Component::OnlyOfType |
|
||||
Component::Host(None) => 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Impl: selectors::parser::SelectorImpl> MallocSizeOf
|
||||
for selectors::attr::AttrSelectorWithNamespace<Impl>
|
||||
{
|
||||
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
impl MallocSizeOf for Void {
|
||||
#[inline]
|
||||
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
|
||||
|
|
|
@ -17,7 +17,7 @@ use dom_struct::dom_struct;
|
|||
use servo_arc::Arc;
|
||||
use servo_url::ServoUrl;
|
||||
use style::attr::AttrValue;
|
||||
use style::properties::{DeclarationSource, Importance, PropertyDeclarationBlock, PropertyId, LonghandId, ShorthandId};
|
||||
use style::properties::{DeclarationPushMode, Importance, PropertyDeclarationBlock, PropertyId, LonghandId, ShorthandId};
|
||||
use style::properties::{parse_one_declaration_into, parse_style_attribute, SourcePropertyDeclaration};
|
||||
use style::selector_parser::PseudoElement;
|
||||
use style::shared_lock::Locked;
|
||||
|
@ -302,7 +302,7 @@ impl CSSStyleDeclaration {
|
|||
*changed = pdb.extend(
|
||||
declarations.drain(),
|
||||
importance,
|
||||
DeclarationSource::CssOm,
|
||||
DeclarationPushMode::Update,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/// Gecko's pseudo-element definition.
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
|
||||
pub enum PseudoElement {
|
||||
% for pseudo in PSEUDOS:
|
||||
/// ${pseudo.value}
|
||||
|
|
|
@ -40,7 +40,7 @@ macro_rules! pseudo_class_name {
|
|||
(bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*],
|
||||
string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => {
|
||||
/// Our representation of a non tree-structural pseudo-class.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)]
|
||||
pub enum NonTSPseudoClass {
|
||||
$(
|
||||
#[doc = $css]
|
||||
|
|
|
@ -285,7 +285,6 @@ class Longhand(object):
|
|||
"FontSynthesis",
|
||||
"FontWeight",
|
||||
"GridAutoFlow",
|
||||
"ImageOrientation",
|
||||
"InitialLetter",
|
||||
"Integer",
|
||||
"JustifyContent",
|
||||
|
|
|
@ -39,13 +39,21 @@ impl AnimationRules {
|
|||
}
|
||||
}
|
||||
|
||||
/// Whether a given declaration comes from CSS parsing, or from CSSOM.
|
||||
/// Enum for how a given declaration should be pushed into a declaration block.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
|
||||
pub enum DeclarationSource {
|
||||
/// The declaration was obtained from CSS parsing of sheets and such.
|
||||
pub enum DeclarationPushMode {
|
||||
/// Mode used when declarations were obtained from CSS parsing.
|
||||
/// If there is an existing declaration of the same property with a higher
|
||||
/// importance, the new declaration will be discarded. Otherwise, it will
|
||||
/// be appended to the end of the declaration block.
|
||||
Parsing,
|
||||
/// The declaration was obtained from CSSOM.
|
||||
CssOm,
|
||||
/// In this mode, if there is an existing declaration of the same property,
|
||||
/// the value is updated in-place. Otherwise it's appended. This is one
|
||||
/// possible behavior of CSSOM.
|
||||
Update,
|
||||
/// In this mode, the new declaration is always pushed to the end of the
|
||||
/// declaration block. This is another possible behavior of CSSOM.
|
||||
Append,
|
||||
}
|
||||
|
||||
/// A declaration [importance][importance].
|
||||
|
@ -410,18 +418,57 @@ impl PropertyDeclarationBlock {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns whether the property is definitely new for this declaration
|
||||
/// block. It returns true when the declaration is a non-custom longhand
|
||||
/// and it doesn't exist in the block, and returns false otherwise.
|
||||
#[inline]
|
||||
fn is_definitely_new(&self, decl: &PropertyDeclaration) -> bool {
|
||||
match decl.id() {
|
||||
PropertyDeclarationId::Longhand(id) => !self.longhands.contains(id),
|
||||
PropertyDeclarationId::Custom(..) => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether calling extend with `DeclarationPushMode::Update`
|
||||
/// will cause this declaration block to change.
|
||||
pub fn will_change_in_update_mode(
|
||||
&self,
|
||||
source_declarations: &SourcePropertyDeclaration,
|
||||
importance: Importance,
|
||||
) -> bool {
|
||||
// XXX The type of parameter seems to be necessary because otherwise
|
||||
// the compiler complains about `decl` not living long enough in the
|
||||
// all_shorthand expression. Why?
|
||||
let needs_update = |decl: &_| {
|
||||
if self.is_definitely_new(decl) {
|
||||
return true;
|
||||
}
|
||||
self.declarations.iter().enumerate()
|
||||
.find(|&(_, ref slot)| slot.id() == decl.id())
|
||||
.map_or(true, |(i, slot)| {
|
||||
let important = self.declarations_importance[i];
|
||||
*slot != *decl || important != importance.important()
|
||||
})
|
||||
};
|
||||
source_declarations.declarations.iter().any(&needs_update) ||
|
||||
source_declarations.all_shorthand.declarations().any(|decl| needs_update(&decl))
|
||||
}
|
||||
|
||||
/// Adds or overrides the declaration for a given property in this block.
|
||||
///
|
||||
/// See the documentation of `push` to see what impact `source` has when the
|
||||
/// property is already there.
|
||||
///
|
||||
/// When calling with `DeclarationPushMode::Update`, this should not change
|
||||
/// anything if `will_change_in_update_mode` returns false.
|
||||
pub fn extend(
|
||||
&mut self,
|
||||
mut drain: SourcePropertyDeclarationDrain,
|
||||
importance: Importance,
|
||||
source: DeclarationSource,
|
||||
mode: DeclarationPushMode,
|
||||
) -> bool {
|
||||
match source {
|
||||
DeclarationSource::Parsing => {
|
||||
match mode {
|
||||
DeclarationPushMode::Parsing => {
|
||||
let all_shorthand_len = match drain.all_shorthand {
|
||||
AllShorthand::NotSet => 0,
|
||||
AllShorthand::CSSWideKeyword(_) |
|
||||
|
@ -433,7 +480,7 @@ impl PropertyDeclarationBlock {
|
|||
// With deduplication the actual length increase may be less than this.
|
||||
self.declarations.reserve(push_calls_count);
|
||||
}
|
||||
DeclarationSource::CssOm => {
|
||||
_ => {
|
||||
// Don't bother reserving space, since it's usually the case
|
||||
// that CSSOM just overrides properties and we don't need to use
|
||||
// more memory. See bug 1424346 for an example where this
|
||||
|
@ -448,75 +495,35 @@ impl PropertyDeclarationBlock {
|
|||
changed |= self.push(
|
||||
decl,
|
||||
importance,
|
||||
source,
|
||||
mode,
|
||||
);
|
||||
}
|
||||
match drain.all_shorthand {
|
||||
AllShorthand::NotSet => {}
|
||||
AllShorthand::CSSWideKeyword(keyword) => {
|
||||
for id in ShorthandId::All.longhands() {
|
||||
let decl = PropertyDeclaration::CSSWideKeyword(
|
||||
WideKeywordDeclaration { id, keyword },
|
||||
);
|
||||
changed |= self.push(
|
||||
decl,
|
||||
importance,
|
||||
source,
|
||||
);
|
||||
}
|
||||
}
|
||||
AllShorthand::WithVariables(unparsed) => {
|
||||
for id in ShorthandId::All.longhands() {
|
||||
let decl = PropertyDeclaration::WithVariables(
|
||||
VariableDeclaration { id, value: unparsed.clone() },
|
||||
);
|
||||
changed |= self.push(
|
||||
decl,
|
||||
importance,
|
||||
source,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
changed
|
||||
drain.all_shorthand.declarations().fold(changed, |changed, decl| {
|
||||
changed | self.push(decl, importance, mode)
|
||||
})
|
||||
}
|
||||
|
||||
/// Adds or overrides the declaration for a given property in this block.
|
||||
///
|
||||
/// Depending on the value of `source`, this has a different behavior in the
|
||||
/// Depending on the value of `mode`, this has a different behavior in the
|
||||
/// presence of another declaration with the same ID in the declaration
|
||||
/// block.
|
||||
///
|
||||
/// * For `DeclarationSource::Parsing`, this will not override a
|
||||
/// declaration with more importance, and will ensure that, if inserted,
|
||||
/// it's inserted at the end of the declaration block.
|
||||
///
|
||||
/// * For `DeclarationSource::CssOm`, this will override importance.
|
||||
///
|
||||
/// Returns whether the declaration has changed.
|
||||
pub fn push(
|
||||
&mut self,
|
||||
declaration: PropertyDeclaration,
|
||||
importance: Importance,
|
||||
source: DeclarationSource,
|
||||
mode: DeclarationPushMode,
|
||||
) -> bool {
|
||||
let longhand_id = match declaration.id() {
|
||||
PropertyDeclarationId::Longhand(id) => Some(id),
|
||||
PropertyDeclarationId::Custom(..) => None,
|
||||
};
|
||||
|
||||
let definitely_new = longhand_id.map_or(false, |id| {
|
||||
!self.longhands.contains(id)
|
||||
});
|
||||
|
||||
if !definitely_new {
|
||||
if !self.is_definitely_new(&declaration) {
|
||||
let mut index_to_remove = None;
|
||||
for (i, slot) in self.declarations.iter_mut().enumerate() {
|
||||
if slot.id() != declaration.id() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if matches!(source, DeclarationSource::Parsing) {
|
||||
if matches!(mode, DeclarationPushMode::Parsing) {
|
||||
let important = self.declarations_importance[i];
|
||||
|
||||
// For declarations from parsing, non-important declarations
|
||||
|
@ -541,6 +548,15 @@ impl PropertyDeclarationBlock {
|
|||
}
|
||||
}
|
||||
}
|
||||
if matches!(mode, DeclarationPushMode::Update) {
|
||||
let important = self.declarations_importance[i];
|
||||
if *slot == declaration && important == importance.important() {
|
||||
return false;
|
||||
}
|
||||
*slot = declaration;
|
||||
self.declarations_importance.set(i, importance.important());
|
||||
return true;
|
||||
}
|
||||
|
||||
index_to_remove = Some(i);
|
||||
break;
|
||||
|
@ -555,7 +571,7 @@ impl PropertyDeclarationBlock {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(id) = longhand_id {
|
||||
if let PropertyDeclarationId::Longhand(id) = declaration.id() {
|
||||
self.longhands.insert(id);
|
||||
}
|
||||
self.declarations.push(declaration);
|
||||
|
@ -1209,7 +1225,7 @@ pub fn parse_property_declaration_list(
|
|||
block.extend(
|
||||
iter.parser.declarations.drain(),
|
||||
importance,
|
||||
DeclarationSource::Parsing,
|
||||
DeclarationPushMode::Parsing,
|
||||
);
|
||||
}
|
||||
Err((error, slice)) => {
|
||||
|
|
|
@ -83,7 +83,6 @@ pub struct ComputedValues(::gecko_bindings::structs::mozilla::ComputedStyle);
|
|||
impl ComputedValues {
|
||||
pub fn new(
|
||||
device: &Device,
|
||||
parent: Option<<&ComputedValues>,
|
||||
pseudo: Option<<&PseudoElement>,
|
||||
custom_properties: Option<Arc<CustomPropertiesMap>>,
|
||||
writing_mode: WritingMode,
|
||||
|
@ -105,7 +104,6 @@ impl ComputedValues {
|
|||
% endfor
|
||||
).to_outer(
|
||||
device.pres_context(),
|
||||
parent,
|
||||
pseudo.map(|p| p.pseudo_info())
|
||||
)
|
||||
}
|
||||
|
@ -120,7 +118,7 @@ impl ComputedValues {
|
|||
% for style_struct in data.style_structs:
|
||||
style_structs::${style_struct.name}::default(pres_context),
|
||||
% endfor
|
||||
).to_outer(pres_context, None, None)
|
||||
).to_outer(pres_context, None)
|
||||
}
|
||||
|
||||
pub fn pseudo(&self) -> Option<PseudoElement> {
|
||||
|
@ -195,7 +193,6 @@ impl Clone for ComputedValuesInner {
|
|||
}
|
||||
|
||||
type PseudoInfo = (*mut structs::nsAtom, structs::CSSPseudoElementType);
|
||||
type ParentComputedStyleInfo<'a> = Option< &'a ComputedValues>;
|
||||
|
||||
impl ComputedValuesInner {
|
||||
pub fn new(custom_properties: Option<Arc<CustomPropertiesMap>>,
|
||||
|
@ -222,7 +219,6 @@ impl ComputedValuesInner {
|
|||
fn to_outer(
|
||||
self,
|
||||
pres_context: RawGeckoPresContextBorrowed,
|
||||
parent: ParentComputedStyleInfo,
|
||||
info: Option<PseudoInfo>
|
||||
) -> Arc<ComputedValues> {
|
||||
let (tag, ty) = if let Some(info) = info {
|
||||
|
@ -231,21 +227,24 @@ impl ComputedValuesInner {
|
|||
(ptr::null_mut(), structs::CSSPseudoElementType::NotPseudo)
|
||||
};
|
||||
|
||||
unsafe { self.to_outer_helper(pres_context, parent, ty, tag) }
|
||||
unsafe { self.to_outer_helper(pres_context, ty, tag) }
|
||||
}
|
||||
|
||||
unsafe fn to_outer_helper(
|
||||
self,
|
||||
pres_context: bindings::RawGeckoPresContextBorrowed,
|
||||
parent: ParentComputedStyleInfo,
|
||||
pseudo_ty: structs::CSSPseudoElementType,
|
||||
pseudo_tag: *mut structs::nsAtom
|
||||
) -> Arc<ComputedValues> {
|
||||
let arc = {
|
||||
let arc: Arc<ComputedValues> = Arc::new(uninitialized());
|
||||
bindings::Gecko_ComputedStyle_Init(&arc.0 as *const _ as *mut _,
|
||||
parent, pres_context,
|
||||
&self, pseudo_ty, pseudo_tag);
|
||||
bindings::Gecko_ComputedStyle_Init(
|
||||
&arc.0 as *const _ as *mut _,
|
||||
pres_context,
|
||||
&self,
|
||||
pseudo_ty,
|
||||
pseudo_tag
|
||||
);
|
||||
// We're simulating a move by having C++ do a memcpy and then forgetting
|
||||
// it on this end.
|
||||
forget(self);
|
||||
|
@ -668,14 +667,14 @@ def set_gecko_property(ffi_name, expr):
|
|||
SVGPaintKind::Color(color) => {
|
||||
paint.mType = nsStyleSVGPaintType::eStyleSVGPaintType_Color;
|
||||
unsafe {
|
||||
*paint.mPaint.mColor.as_mut() = convert_rgba_to_nscolor(&color);
|
||||
*paint.mPaint.mColor.as_mut() = color.into();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
paint.mFallbackType = match fallback {
|
||||
Some(Either::First(color)) => {
|
||||
paint.mFallbackColor = convert_rgba_to_nscolor(&color);
|
||||
paint.mFallbackColor = color.into();
|
||||
nsStyleSVGFallbackType::eStyleSVGFallbackType_Color
|
||||
},
|
||||
Some(Either::Second(_)) => {
|
||||
|
@ -710,7 +709,7 @@ def set_gecko_property(ffi_name, expr):
|
|||
|
||||
let fallback = match paint.mFallbackType {
|
||||
nsStyleSVGFallbackType::eStyleSVGFallbackType_Color => {
|
||||
Some(Either::First(convert_nscolor_to_rgba(paint.mFallbackColor)))
|
||||
Some(Either::First(paint.mFallbackColor.into()))
|
||||
},
|
||||
nsStyleSVGFallbackType::eStyleSVGFallbackType_None => {
|
||||
Some(Either::Second(None_))
|
||||
|
@ -729,7 +728,8 @@ def set_gecko_property(ffi_name, expr):
|
|||
})
|
||||
}
|
||||
nsStyleSVGPaintType::eStyleSVGPaintType_Color => {
|
||||
unsafe { SVGPaintKind::Color(convert_nscolor_to_rgba(*paint.mPaint.mColor.as_ref())) }
|
||||
let col = unsafe { *paint.mPaint.mColor.as_ref() };
|
||||
SVGPaintKind::Color(col.into())
|
||||
}
|
||||
};
|
||||
SVGPaint {
|
||||
|
@ -3083,6 +3083,17 @@ fn static_assert() {
|
|||
|
||||
<%call expr="impl_keyword_clone('display', 'mDisplay', display_keyword)"></%call>
|
||||
|
||||
<% float_keyword = Keyword("float", "Left Right None", gecko_enum_prefix="StyleFloat") %>
|
||||
${impl_keyword('float', 'mFloat', float_keyword)}
|
||||
|
||||
<% clear_keyword = Keyword(
|
||||
"clear",
|
||||
"Left Right None Both",
|
||||
gecko_enum_prefix="StyleClear",
|
||||
gecko_inexhaustive=True,
|
||||
) %>
|
||||
${impl_keyword('clear', 'mBreakType', clear_keyword)}
|
||||
|
||||
<% overflow_x = data.longhands_by_name["overflow-x"] %>
|
||||
pub fn set_overflow_y(&mut self, v: longhands::overflow_y::computed_value::T) {
|
||||
use properties::longhands::overflow_x::computed_value::T as BaseType;
|
||||
|
@ -4533,64 +4544,7 @@ fn static_assert() {
|
|||
|
||||
</%self:impl_trait>
|
||||
|
||||
<%self:impl_trait style_struct_name="InheritedBox"
|
||||
skip_longhands="image-orientation">
|
||||
// FIXME: Gecko uses a tricky way to store computed value of image-orientation
|
||||
// within an u8. We could inline following glue codes by implementing all
|
||||
// those tricky parts for Servo as well. But, it's not done yet just for
|
||||
// convenience.
|
||||
pub fn set_image_orientation(&mut self, v: longhands::image_orientation::computed_value::T) {
|
||||
use properties::longhands::image_orientation::computed_value::T;
|
||||
match v {
|
||||
T::FromImage => {
|
||||
unsafe {
|
||||
bindings::Gecko_SetImageOrientationAsFromImage(&mut self.gecko);
|
||||
}
|
||||
},
|
||||
T::AngleWithFlipped(ref orientation, flipped) => {
|
||||
unsafe {
|
||||
bindings::Gecko_SetImageOrientation(&mut self.gecko, *orientation as u8, flipped);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn copy_image_orientation_from(&mut self, other: &Self) {
|
||||
unsafe {
|
||||
bindings::Gecko_CopyImageOrientationFrom(&mut self.gecko, &other.gecko);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset_image_orientation(&mut self, other: &Self) {
|
||||
self.copy_image_orientation_from(other)
|
||||
}
|
||||
|
||||
pub fn clone_image_orientation(&self) -> longhands::image_orientation::computed_value::T {
|
||||
use gecko_bindings::structs::nsStyleImageOrientation_Angles;
|
||||
use properties::longhands::image_orientation::computed_value::T;
|
||||
use values::computed::Orientation;
|
||||
|
||||
let gecko_orientation = self.gecko.mImageOrientation.mOrientation;
|
||||
if gecko_orientation & structs::nsStyleImageOrientation_Bits_FROM_IMAGE_MASK as u8 != 0 {
|
||||
T::FromImage
|
||||
} else {
|
||||
const ANGLE0: u8 = nsStyleImageOrientation_Angles::ANGLE_0 as u8;
|
||||
const ANGLE90: u8 = nsStyleImageOrientation_Angles::ANGLE_90 as u8;
|
||||
const ANGLE180: u8 = nsStyleImageOrientation_Angles::ANGLE_180 as u8;
|
||||
const ANGLE270: u8 = nsStyleImageOrientation_Angles::ANGLE_270 as u8;
|
||||
|
||||
let flip = gecko_orientation & structs::nsStyleImageOrientation_Bits_FLIP_MASK as u8 != 0;
|
||||
let orientation =
|
||||
match gecko_orientation & structs::nsStyleImageOrientation_Bits_ORIENTATION_MASK as u8 {
|
||||
ANGLE0 => Orientation::Angle0,
|
||||
ANGLE90 => Orientation::Angle90,
|
||||
ANGLE180 => Orientation::Angle180,
|
||||
ANGLE270 => Orientation::Angle270,
|
||||
_ => unreachable!()
|
||||
};
|
||||
T::AngleWithFlipped(orientation, flip)
|
||||
}
|
||||
}
|
||||
<%self:impl_trait style_struct_name="InheritedBox">
|
||||
</%self:impl_trait>
|
||||
|
||||
<%self:impl_trait style_struct_name="InheritedTable"
|
||||
|
|
|
@ -29,7 +29,7 @@ use hash::FnvHashMap;
|
|||
use super::ComputedValues;
|
||||
use values::CSSFloat;
|
||||
use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
|
||||
use values::animated::color::RGBA as AnimatedRGBA;
|
||||
use values::animated::color::Color as AnimatedColor;
|
||||
use values::animated::effects::Filter as AnimatedFilter;
|
||||
#[cfg(feature = "gecko")] use values::computed::TransitionProperty;
|
||||
use values::computed::{Angle, CalcLengthOrPercentage};
|
||||
|
@ -2674,10 +2674,10 @@ impl ComputeSquaredDistance for ComputedTransform {
|
|||
}
|
||||
|
||||
/// Animated SVGPaint
|
||||
pub type IntermediateSVGPaint = SVGPaint<AnimatedRGBA, ComputedUrl>;
|
||||
pub type IntermediateSVGPaint = SVGPaint<AnimatedColor, ComputedUrl>;
|
||||
|
||||
/// Animated SVGPaintKind
|
||||
pub type IntermediateSVGPaintKind = SVGPaintKind<AnimatedRGBA, ComputedUrl>;
|
||||
pub type IntermediateSVGPaintKind = SVGPaintKind<AnimatedColor, ComputedUrl>;
|
||||
|
||||
impl ToAnimatedZero for IntermediateSVGPaint {
|
||||
#[inline]
|
||||
|
|
|
@ -76,11 +76,12 @@ ${helpers.single_keyword(
|
|||
spec="https://drafts.csswg.org/css-images/#propdef-image-rendering",
|
||||
)}
|
||||
|
||||
${helpers.predefined_type("image-orientation",
|
||||
"ImageOrientation",
|
||||
"computed::ImageOrientation::zero()",
|
||||
products="gecko",
|
||||
animation_value_type="discrete",
|
||||
gecko_pref="layout.css.image-orientation.enabled",
|
||||
spec="https://drafts.csswg.org/css-images/#propdef-image-orientation, \
|
||||
/// additional values in https://developer.mozilla.org/en-US/docs/Web/CSS/image-orientation")}
|
||||
${helpers.single_keyword(
|
||||
"image-orientation",
|
||||
"none from-image",
|
||||
products="gecko",
|
||||
gecko_enum_prefix="StyleImageOrientation",
|
||||
animation_value_type="discrete",
|
||||
gecko_pref="layout.css.image-orientation.enabled",
|
||||
spec="https://drafts.csswg.org/css-images/#propdef-image-orientation",
|
||||
)}
|
||||
|
|
|
@ -2222,6 +2222,49 @@ enum AllShorthand {
|
|||
WithVariables(Arc<UnparsedValue>)
|
||||
}
|
||||
|
||||
impl AllShorthand {
|
||||
/// Iterates property declarations from the given all shorthand value.
|
||||
#[inline]
|
||||
fn declarations(&self) -> AllShorthandDeclarationIterator {
|
||||
AllShorthandDeclarationIterator {
|
||||
all_shorthand: self,
|
||||
longhands: ShorthandId::All.longhands(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct AllShorthandDeclarationIterator<'a> {
|
||||
all_shorthand: &'a AllShorthand,
|
||||
longhands: NonCustomPropertyIterator<LonghandId>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for AllShorthandDeclarationIterator<'a> {
|
||||
type Item = PropertyDeclaration;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match *self.all_shorthand {
|
||||
AllShorthand::NotSet => None,
|
||||
AllShorthand::CSSWideKeyword(ref keyword) => {
|
||||
Some(PropertyDeclaration::CSSWideKeyword(
|
||||
WideKeywordDeclaration {
|
||||
id: self.longhands.next()?,
|
||||
keyword: *keyword
|
||||
}
|
||||
))
|
||||
}
|
||||
AllShorthand::WithVariables(ref unparsed) => {
|
||||
Some(PropertyDeclaration::WithVariables(
|
||||
VariableDeclaration {
|
||||
id: self.longhands.next()?,
|
||||
value: unparsed.clone()
|
||||
}
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
pub use gecko_properties::style_structs;
|
||||
|
||||
|
@ -2677,7 +2720,6 @@ impl ComputedValues {
|
|||
/// Create a new refcounted `ComputedValues`
|
||||
pub fn new(
|
||||
_: &Device,
|
||||
_: Option<<&ComputedValues>,
|
||||
_: Option<<&PseudoElement>,
|
||||
custom_properties: Option<Arc<::custom_properties::CustomPropertiesMap>>,
|
||||
writing_mode: WritingMode,
|
||||
|
@ -3085,10 +3127,6 @@ pub struct StyleBuilder<'a> {
|
|||
/// The style we're getting reset structs from.
|
||||
reset_style: &'a ComputedValues,
|
||||
|
||||
/// The style we're inheriting from explicitly, or none if we're the root of
|
||||
/// a subtree.
|
||||
parent_style: Option<<&'a ComputedValues>,
|
||||
|
||||
/// The rule node representing the ordered list of rules matched for this
|
||||
/// node.
|
||||
pub rules: Option<StrongRuleNode>,
|
||||
|
@ -3156,7 +3194,6 @@ impl<'a> StyleBuilder<'a> {
|
|||
|
||||
StyleBuilder {
|
||||
device,
|
||||
parent_style,
|
||||
inherited_style,
|
||||
inherited_style_ignoring_first_line,
|
||||
reset_style,
|
||||
|
@ -3200,7 +3237,6 @@ impl<'a> StyleBuilder<'a> {
|
|||
parent_style.unwrap().pseudo() != Some(PseudoElement::FirstLine));
|
||||
StyleBuilder {
|
||||
device,
|
||||
parent_style,
|
||||
inherited_style,
|
||||
// None of our callers pass in ::first-line parent styles.
|
||||
inherited_style_ignoring_first_line: inherited_style,
|
||||
|
@ -3442,7 +3478,6 @@ impl<'a> StyleBuilder<'a> {
|
|||
pub fn build(self) -> Arc<ComputedValues> {
|
||||
ComputedValues::new(
|
||||
self.device,
|
||||
self.parent_style,
|
||||
self.pseudo,
|
||||
self.custom_properties,
|
||||
self.writing_mode,
|
||||
|
@ -3768,14 +3803,6 @@ where
|
|||
PropertyDeclarationId::Custom(..) => continue,
|
||||
};
|
||||
|
||||
// Only a few properties are allowed to depend on the visited state
|
||||
// of links. When cascading visited styles, we can save time by
|
||||
// only processing these properties.
|
||||
if flags.contains(CascadeFlags::VISITED_DEPENDENT_ONLY) &&
|
||||
!longhand_id.is_visited_dependent() {
|
||||
continue
|
||||
}
|
||||
|
||||
if !apply_reset && !longhand_id.inherited() {
|
||||
continue;
|
||||
}
|
||||
|
@ -3795,6 +3822,14 @@ where
|
|||
continue
|
||||
}
|
||||
|
||||
// Only a few properties are allowed to depend on the visited state
|
||||
// of links. When cascading visited styles, we can save time by
|
||||
// only processing these properties.
|
||||
if flags.contains(CascadeFlags::VISITED_DEPENDENT_ONLY) &&
|
||||
!physical_longhand_id.is_visited_dependent() {
|
||||
continue
|
||||
}
|
||||
|
||||
let mut declaration = match *declaration {
|
||||
PropertyDeclaration::WithVariables(ref declaration) => {
|
||||
if !declaration.id.inherited() {
|
||||
|
|
|
@ -172,7 +172,7 @@ impl<T> PerPseudoElementMap<T> {
|
|||
}
|
||||
|
||||
/// Values for the :dir() pseudo class
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)]
|
||||
pub enum Direction {
|
||||
/// left-to-right semantic directionality
|
||||
Ltr,
|
||||
|
|
|
@ -8,7 +8,7 @@ use cssparser::{AtRuleParser, CowRcStr, Parser, ParserInput, QualifiedRuleParser
|
|||
use cssparser::{parse_one_rule, DeclarationListParser, DeclarationParser, SourceLocation, Token};
|
||||
use error_reporting::ContextualParseError;
|
||||
use parser::ParserContext;
|
||||
use properties::{DeclarationSource, Importance, PropertyDeclaration};
|
||||
use properties::{DeclarationPushMode, Importance, PropertyDeclaration};
|
||||
use properties::{LonghandId, PropertyDeclarationBlock, PropertyId};
|
||||
use properties::{PropertyDeclarationId, SourcePropertyDeclaration};
|
||||
use properties::LonghandIdSet;
|
||||
|
@ -554,7 +554,7 @@ impl<'a, 'i> QualifiedRuleParser<'i> for KeyframeListParser<'a> {
|
|||
block.extend(
|
||||
iter.parser.declarations.drain(),
|
||||
Importance::Normal,
|
||||
DeclarationSource::Parsing,
|
||||
DeclarationPushMode::Parsing,
|
||||
);
|
||||
},
|
||||
Err((error, slice)) => {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
use cssparser::SourceLocation;
|
||||
#[cfg(feature = "gecko")]
|
||||
use malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps};
|
||||
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
||||
#[cfg(feature = "gecko")]
|
||||
use malloc_size_of::MallocUnconditionalShallowSizeOf;
|
||||
use properties::PropertyDeclarationBlock;
|
||||
|
@ -50,20 +50,9 @@ impl StyleRule {
|
|||
#[cfg(feature = "gecko")]
|
||||
pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize {
|
||||
let mut n = 0;
|
||||
|
||||
// We may add measurement of things hanging off the embedded Components
|
||||
// later.
|
||||
n += self.selectors.0.shallow_size_of(ops);
|
||||
for selector in self.selectors.0.iter() {
|
||||
// It's safe to measure this ThinArc directly because it's the
|
||||
// "primary" reference. (The secondary references are on the
|
||||
// Stylist.)
|
||||
n += unsafe { ops.malloc_size_of(selector.thin_arc_heap_ptr()) };
|
||||
}
|
||||
|
||||
n += self.selectors.0.size_of(ops);
|
||||
n += self.block.unconditional_shallow_size_of(ops) +
|
||||
self.block.read_with(guard).size_of(ops);
|
||||
|
||||
n
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1175,7 +1175,6 @@ impl Stylist {
|
|||
pseudo_element.is_some()
|
||||
);
|
||||
|
||||
let only_default_rules = rule_inclusion == RuleInclusion::DefaultOnly;
|
||||
let matches_user_rules = rule_hash_target.matches_user_and_author_rules();
|
||||
let matches_author_rules =
|
||||
matches_user_rules && self.author_styles_enabled == AuthorStylesEnabled::Yes;
|
||||
|
@ -1220,7 +1219,11 @@ impl Stylist {
|
|||
}
|
||||
}
|
||||
|
||||
if pseudo_element.is_none() && !only_default_rules {
|
||||
if rule_inclusion == RuleInclusion::DefaultOnly {
|
||||
return;
|
||||
}
|
||||
|
||||
if pseudo_element.is_none() {
|
||||
// Presentational hints.
|
||||
//
|
||||
// These go before author rules, but after user rules, see:
|
||||
|
@ -1230,8 +1233,8 @@ impl Stylist {
|
|||
context.visited_handling(),
|
||||
applicable_declarations,
|
||||
);
|
||||
if applicable_declarations.len() != length_before_preshints {
|
||||
if cfg!(debug_assertions) {
|
||||
if cfg!(debug_assertions) {
|
||||
if applicable_declarations.len() != length_before_preshints {
|
||||
for declaration in &applicable_declarations[length_before_preshints..] {
|
||||
assert_eq!(declaration.level(), CascadeLevel::PresHints);
|
||||
}
|
||||
|
@ -1248,7 +1251,7 @@ impl Stylist {
|
|||
// particular, normally document rules override ::slotted() rules, but
|
||||
// for !important it should be the other way around. So probably we need
|
||||
// to add some sort of AuthorScoped cascade level or something.
|
||||
if matches_author_rules && !only_default_rules {
|
||||
if matches_author_rules {
|
||||
if let Some(shadow) = rule_hash_target.shadow_root() {
|
||||
if let Some(map) = shadow.style_data().host_rules(pseudo_element) {
|
||||
context.with_shadow_host(Some(rule_hash_target), |context| {
|
||||
|
@ -1315,10 +1318,8 @@ impl Stylist {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME(emilio): It looks very wrong to match XBL rules even for
|
||||
// getDefaultComputedStyle!
|
||||
//
|
||||
// Also, this doesn't account for the author_styles_enabled stuff.
|
||||
// FIXME(emilio): This doesn't account for the author_styles_enabled
|
||||
// stuff...
|
||||
let cut_xbl_binding_inheritance =
|
||||
element.each_xbl_cascade_data(|cascade_data, quirks_mode| {
|
||||
if let Some(map) = cascade_data.normal_rules(pseudo_element) {
|
||||
|
@ -1349,7 +1350,7 @@ impl Stylist {
|
|||
|
||||
match_document_author_rules &= !cut_xbl_binding_inheritance;
|
||||
|
||||
if match_document_author_rules && !only_default_rules {
|
||||
if match_document_author_rules {
|
||||
// Author normal rules.
|
||||
if let Some(map) = self.cascade_data.author.normal_rules(pseudo_element) {
|
||||
map.get_all_matching_rules(
|
||||
|
@ -1364,47 +1365,43 @@ impl Stylist {
|
|||
}
|
||||
}
|
||||
|
||||
if !only_default_rules {
|
||||
// Style attribute ("Normal override declarations").
|
||||
if let Some(sa) = style_attribute {
|
||||
applicable_declarations.push(ApplicableDeclarationBlock::from_declarations(
|
||||
sa.clone_arc(),
|
||||
CascadeLevel::StyleAttributeNormal,
|
||||
));
|
||||
}
|
||||
// Style attribute ("Normal override declarations").
|
||||
if let Some(sa) = style_attribute {
|
||||
applicable_declarations.push(ApplicableDeclarationBlock::from_declarations(
|
||||
sa.clone_arc(),
|
||||
CascadeLevel::StyleAttributeNormal,
|
||||
));
|
||||
}
|
||||
|
||||
// Declarations from SVG SMIL animation elements.
|
||||
if let Some(so) = smil_override {
|
||||
applicable_declarations.push(ApplicableDeclarationBlock::from_declarations(
|
||||
so.clone_arc(),
|
||||
CascadeLevel::SMILOverride,
|
||||
));
|
||||
}
|
||||
// Declarations from SVG SMIL animation elements.
|
||||
if let Some(so) = smil_override {
|
||||
applicable_declarations.push(ApplicableDeclarationBlock::from_declarations(
|
||||
so.clone_arc(),
|
||||
CascadeLevel::SMILOverride,
|
||||
));
|
||||
}
|
||||
|
||||
// The animations sheet (CSS animations, script-generated
|
||||
// animations, and CSS transitions that are no longer tied to CSS
|
||||
// markup).
|
||||
if let Some(anim) = animation_rules.0 {
|
||||
applicable_declarations.push(ApplicableDeclarationBlock::from_declarations(
|
||||
anim.clone(),
|
||||
CascadeLevel::Animations,
|
||||
));
|
||||
}
|
||||
// The animations sheet (CSS animations, script-generated
|
||||
// animations, and CSS transitions that are no longer tied to CSS
|
||||
// markup).
|
||||
if let Some(anim) = animation_rules.0 {
|
||||
applicable_declarations.push(ApplicableDeclarationBlock::from_declarations(
|
||||
anim.clone(),
|
||||
CascadeLevel::Animations,
|
||||
));
|
||||
}
|
||||
|
||||
//
|
||||
// !important rules are handled during rule tree insertion.
|
||||
//
|
||||
|
||||
if !only_default_rules {
|
||||
// The transitions sheet (CSS transitions that are tied to CSS
|
||||
// markup).
|
||||
if let Some(anim) = animation_rules.1 {
|
||||
applicable_declarations.push(ApplicableDeclarationBlock::from_declarations(
|
||||
anim.clone(),
|
||||
CascadeLevel::Transitions,
|
||||
));
|
||||
}
|
||||
// The transitions sheet (CSS transitions that are tied to CSS
|
||||
// markup).
|
||||
if let Some(anim) = animation_rules.1 {
|
||||
applicable_declarations.push(ApplicableDeclarationBlock::from_declarations(
|
||||
anim.clone(),
|
||||
CascadeLevel::Transitions,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -126,11 +126,11 @@ impl Animate for Color {
|
|||
let (this_weight, other_weight) = procedure.weights();
|
||||
|
||||
Ok(match (*self, *other, procedure) {
|
||||
// Any interpolation of currentColor with currentColor returns currentColor.
|
||||
(Foreground, Foreground, Procedure::Interpolate { .. }) => Color::currentcolor(),
|
||||
// Any interpolation of currentcolor with currentcolor returns currentcolor.
|
||||
(Foreground, Foreground, Procedure::Interpolate { .. }) => Foreground,
|
||||
// Animating two numeric colors.
|
||||
(Numeric(c1), Numeric(c2), _) => Numeric(c1.animate(&c2, procedure)?),
|
||||
// Combinations of numeric color and currentColor
|
||||
// Combinations of numeric color and currentcolor
|
||||
(Foreground, Numeric(color), _) => Self::with_ratios(
|
||||
color,
|
||||
ComplexColorRatios {
|
||||
|
@ -146,7 +146,7 @@ impl Animate for Color {
|
|||
},
|
||||
),
|
||||
|
||||
// Any other animation of currentColor with currentColor.
|
||||
// Any other animation of currentcolor with currentcolor.
|
||||
(Foreground, Foreground, _) => Self::with_ratios(
|
||||
RGBA::transparent(),
|
||||
ComplexColorRatios {
|
||||
|
@ -157,20 +157,72 @@ impl Animate for Color {
|
|||
|
||||
// Defer to complex calculations
|
||||
_ => {
|
||||
// For interpolating between two complex colors, we need to
|
||||
// generate colors with effective alpha value.
|
||||
let self_color = self.effective_intermediate_rgba();
|
||||
let other_color = other.effective_intermediate_rgba();
|
||||
let color = self_color.animate(&other_color, procedure)?;
|
||||
// Then we compute the final background ratio, and derive
|
||||
// the final alpha value from the effective alpha value.
|
||||
let self_ratios = self.effective_ratios();
|
||||
let other_ratios = other.effective_ratios();
|
||||
let ratios = self_ratios.animate(&other_ratios, procedure)?;
|
||||
let alpha = color.alpha / ratios.bg;
|
||||
let color = RGBA { alpha, ..color };
|
||||
// Compute the "scaled" contribution for `color`.
|
||||
fn scaled_rgba(color: &Color) -> RGBA {
|
||||
match *color {
|
||||
GenericColor::Numeric(color) => color,
|
||||
GenericColor::Foreground => 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,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Self::with_ratios(color, ratios)
|
||||
// Each `Color`, represents a complex combination of foreground color and
|
||||
// background color where fg and bg represent the overall
|
||||
// contributions. ie:
|
||||
//
|
||||
// color = { bg * mColor, fg * foreground }
|
||||
// = { bg_color , fg_color }
|
||||
// = bg_color + fg_color
|
||||
//
|
||||
// where `foreground` is `currentcolor`, and `bg_color`,
|
||||
// `fg_color` are the scaled background and foreground
|
||||
// contributions.
|
||||
//
|
||||
// Each operation, lerp, addition, or accumulate, can be
|
||||
// represented as a scaled-addition each complex color. ie:
|
||||
//
|
||||
// p * col1 + q * col2
|
||||
//
|
||||
// where p = (1 - a), q = a for lerp(a), p = 1, q = 1 for
|
||||
// addition, etc.
|
||||
//
|
||||
// Therefore:
|
||||
//
|
||||
// col1 op col2
|
||||
// = p * col1 + q * col2
|
||||
// = p * { bg_color1, fg_color1 } + q * { bg_color2, fg_color2 }
|
||||
// = p * (bg_color1 + fg_color1) + q * (bg_color2 + fg_color2)
|
||||
// = p * bg_color1 + p * fg_color1 + q * bg_color2 + p * fg_color2
|
||||
// = (p * bg_color1 + q * bg_color2) + (p * fg_color1 + q * fg_color2)
|
||||
// = (bg_color1 op bg_color2) + (fg_color1 op fg_color2)
|
||||
//
|
||||
// fg_color1 op fg_color2 is equivalent to (fg1 op fg2) * foreground,
|
||||
// so the final color is:
|
||||
//
|
||||
// = { bg_color, fg_color }
|
||||
// = { 1 * (bg_color1 op bg_color2), (fg1 op fg2) * foreground }
|
||||
|
||||
// To perform the operation on two complex colors, we need to
|
||||
// generate the scaled contributions of each background color
|
||||
// component.
|
||||
let bg_color1 = scaled_rgba(self);
|
||||
let bg_color2 = scaled_rgba(other);
|
||||
// Perform bg_color1 op bg_color2
|
||||
let bg_color = bg_color1.animate(&bg_color2, procedure)?;
|
||||
|
||||
// Calculate the final foreground color ratios; perform
|
||||
// animation on effective fg ratios.
|
||||
let ComplexColorRatios { fg: fg1, .. } = self.effective_ratios();
|
||||
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 })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! Computed values for inherited box
|
||||
|
||||
use std::fmt::{self, Write};
|
||||
use style_traits::{CssWriter, ToCss};
|
||||
use values::specified::Angle;
|
||||
|
||||
/// An angle rounded and normalized per https://drafts.csswg.org/css-images/#propdef-image-orientation
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq)]
|
||||
pub enum Orientation {
|
||||
Angle0 = 0,
|
||||
Angle90,
|
||||
Angle180,
|
||||
Angle270,
|
||||
}
|
||||
|
||||
impl Orientation {
|
||||
/// Get the actual angle that this orientation value represents.
|
||||
pub fn angle(&self) -> Angle {
|
||||
match *self {
|
||||
Orientation::Angle0 => Angle::from_degrees(0.0, false),
|
||||
Orientation::Angle90 => Angle::from_degrees(90.0, false),
|
||||
Orientation::Angle180 => Angle::from_degrees(180.0, false),
|
||||
Orientation::Angle270 => Angle::from_degrees(270.0, false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCss for Orientation {
|
||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||
where
|
||||
W: Write,
|
||||
{
|
||||
// Should agree with Angle::to_css.
|
||||
match *self {
|
||||
Orientation::Angle0 => dest.write_str("0deg"),
|
||||
Orientation::Angle90 => dest.write_str("90deg"),
|
||||
Orientation::Angle180 => dest.write_str("180deg"),
|
||||
Orientation::Angle270 => dest.write_str("270deg"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// https://drafts.csswg.org/css-images/#propdef-image-orientation
|
||||
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq)]
|
||||
pub enum ImageOrientation {
|
||||
/// 'from-image'
|
||||
FromImage,
|
||||
|
||||
/// '<angle>' | '<angle>? flip'
|
||||
AngleWithFlipped(Orientation, bool),
|
||||
}
|
||||
|
||||
impl ImageOrientation {
|
||||
#[allow(missing_docs)]
|
||||
pub fn zero() -> Self {
|
||||
ImageOrientation::AngleWithFlipped(Orientation::Angle0, false)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCss for ImageOrientation {
|
||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||
where
|
||||
W: Write,
|
||||
{
|
||||
match *self {
|
||||
ImageOrientation::FromImage => dest.write_str("from-image"),
|
||||
ImageOrientation::AngleWithFlipped(angle, flipped) => {
|
||||
angle.to_css(dest)?;
|
||||
if flipped {
|
||||
dest.write_str(" flip")?;
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
|
@ -52,7 +52,6 @@ pub use self::counters::{Content, ContentItem, CounterIncrement, CounterReset};
|
|||
pub use self::effects::{BoxShadow, Filter, SimpleShadow};
|
||||
pub use self::flex::FlexBasis;
|
||||
pub use self::image::{Gradient, GradientItem, Image, ImageLayer, LineDirection, MozImageRect};
|
||||
pub use self::inherited_box::{ImageOrientation, Orientation};
|
||||
#[cfg(feature = "gecko")]
|
||||
pub use self::gecko::ScrollSnapPoint;
|
||||
pub use self::rect::LengthOrNumberRect;
|
||||
|
@ -99,7 +98,6 @@ pub mod font;
|
|||
#[cfg(feature = "gecko")]
|
||||
pub mod gecko;
|
||||
pub mod image;
|
||||
pub mod inherited_box;
|
||||
pub mod length;
|
||||
pub mod list;
|
||||
pub mod outline;
|
||||
|
|
|
@ -9,6 +9,7 @@ use values::RGBA;
|
|||
use values::computed::{LengthOrPercentage, NonNegativeLength};
|
||||
use values::computed::{NonNegativeLengthOrPercentage, NonNegativeNumber, Number};
|
||||
use values::computed::Opacity;
|
||||
use values::computed::color::Color;
|
||||
use values::computed::url::ComputedUrl;
|
||||
use values::generics::svg as generic;
|
||||
|
||||
|
@ -17,9 +18,9 @@ pub use values::specified::SVGPaintOrder;
|
|||
pub use values::specified::MozContextProperties;
|
||||
|
||||
/// Computed SVG Paint value
|
||||
pub type SVGPaint = generic::SVGPaint<RGBA, ComputedUrl>;
|
||||
pub type SVGPaint = generic::SVGPaint<Color, ComputedUrl>;
|
||||
/// Computed SVG Paint Kind value
|
||||
pub type SVGPaintKind = generic::SVGPaintKind<RGBA, ComputedUrl>;
|
||||
pub type SVGPaintKind = generic::SVGPaintKind<Color, ComputedUrl>;
|
||||
|
||||
impl Default for SVGPaint {
|
||||
fn default() -> Self {
|
||||
|
@ -33,7 +34,7 @@ impl Default for SVGPaint {
|
|||
impl SVGPaint {
|
||||
/// Opaque black color
|
||||
pub fn black() -> Self {
|
||||
let rgba = RGBA::from_floats(0., 0., 0., 1.);
|
||||
let rgba = RGBA::from_floats(0., 0., 0., 1.).into();
|
||||
SVGPaint {
|
||||
kind: generic::SVGPaintKind::Color(rgba),
|
||||
fallback: None,
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
/// Ratios representing the contribution of color and currentcolor to
|
||||
/// the final color value.
|
||||
#[derive(Animate, Clone, Copy, Debug, MallocSizeOf, PartialEq, ToAnimatedValue)]
|
||||
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToAnimatedValue)]
|
||||
pub struct ComplexColorRatios {
|
||||
/// Numeric color contribution.
|
||||
pub bg: f32,
|
||||
|
|
|
@ -1,158 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! Specified values for inherited box
|
||||
|
||||
use cssparser::Parser;
|
||||
use parser::{Parse, ParserContext};
|
||||
use std::f64::consts::PI;
|
||||
use std::fmt::{self, Write};
|
||||
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
|
||||
use values::computed;
|
||||
use values::computed::{Context, Orientation, ToComputedValue};
|
||||
use values::specified::Angle;
|
||||
|
||||
/// The specified value of the `image-orientation` property.
|
||||
/// https://drafts.csswg.org/css-images/#propdef-image-orientation
|
||||
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo)]
|
||||
pub struct ImageOrientation {
|
||||
/// The angle specified, if any
|
||||
pub angle: Option<Angle>,
|
||||
|
||||
/// Whether or not "flip" was specified
|
||||
#[value_info(other_values = "flip,from-image")]
|
||||
pub flipped: bool,
|
||||
}
|
||||
|
||||
impl ToCss for ImageOrientation {
|
||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||
where
|
||||
W: Write,
|
||||
{
|
||||
if let Some(angle) = self.angle {
|
||||
angle.to_css(dest)?;
|
||||
if self.flipped {
|
||||
dest.write_str(" flip")
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
} else {
|
||||
if self.flipped {
|
||||
dest.write_str("flip")
|
||||
} else {
|
||||
dest.write_str("from-image")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const TWO_PI: f64 = 2.0 * PI;
|
||||
|
||||
// According to CSS Content Module Level 3:
|
||||
// The computed value of the property is calculated by rounding the specified angle
|
||||
// to the nearest quarter-turn, rounding away from 0, then moduloing the value by 1 turn.
|
||||
// This mirrors the Gecko implementation in
|
||||
// nsStyleImageOrientation::CreateAsAngleAndFlip.
|
||||
#[inline]
|
||||
fn orientation_of_angle(angle: &computed::Angle) -> Orientation {
|
||||
// Note that `angle` can be negative.
|
||||
let mut rounded_angle = angle.radians64() % TWO_PI;
|
||||
if rounded_angle < 0.0 {
|
||||
// This computation introduces rounding error. Gecko previously
|
||||
// didn't handle the negative case correctly; by branching we can
|
||||
// match Gecko's behavior when it was correct.
|
||||
rounded_angle += TWO_PI;
|
||||
}
|
||||
if rounded_angle < 0.25 * PI {
|
||||
return Orientation::Angle0;
|
||||
}
|
||||
if rounded_angle < 0.75 * PI {
|
||||
return Orientation::Angle90;
|
||||
}
|
||||
if rounded_angle < 1.25 * PI {
|
||||
return Orientation::Angle180;
|
||||
}
|
||||
if rounded_angle < 1.75 * PI {
|
||||
return Orientation::Angle270;
|
||||
}
|
||||
Orientation::Angle0
|
||||
}
|
||||
|
||||
impl ToComputedValue for ImageOrientation {
|
||||
type ComputedValue = computed::ImageOrientation;
|
||||
|
||||
#[inline]
|
||||
fn to_computed_value(&self, context: &Context) -> computed::ImageOrientation {
|
||||
if let Some(ref angle) = self.angle {
|
||||
let angle = angle.to_computed_value(context);
|
||||
let orientation = orientation_of_angle(&angle);
|
||||
computed::ImageOrientation::AngleWithFlipped(orientation, self.flipped)
|
||||
} else {
|
||||
if self.flipped {
|
||||
computed::ImageOrientation::zero()
|
||||
} else {
|
||||
computed::ImageOrientation::FromImage
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_computed_value(computed: &computed::ImageOrientation) -> Self {
|
||||
match *computed {
|
||||
computed::ImageOrientation::FromImage => ImageOrientation {
|
||||
angle: None,
|
||||
flipped: false,
|
||||
},
|
||||
|
||||
computed::ImageOrientation::AngleWithFlipped(ref orientation, flipped) => {
|
||||
ImageOrientation {
|
||||
angle: Some(orientation.angle()),
|
||||
flipped: flipped,
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for ImageOrientation {
|
||||
// from-image | <angle> | [<angle>? flip]
|
||||
fn parse<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if input
|
||||
.try(|input| input.expect_ident_matching("from-image"))
|
||||
.is_ok()
|
||||
{
|
||||
// Handle from-image
|
||||
Ok(ImageOrientation {
|
||||
angle: None,
|
||||
flipped: false,
|
||||
})
|
||||
} else if input
|
||||
.try(|input| input.expect_ident_matching("flip"))
|
||||
.is_ok()
|
||||
{
|
||||
// Handle flip
|
||||
Ok(ImageOrientation {
|
||||
angle: Some(Angle::zero()),
|
||||
flipped: true,
|
||||
})
|
||||
} else {
|
||||
// Handle <angle> | <angle> flip
|
||||
let angle = input.try(|input| Angle::parse(context, input)).ok();
|
||||
if angle.is_none() {
|
||||
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||
}
|
||||
|
||||
let flipped = input
|
||||
.try(|input| input.expect_ident_matching("flip"))
|
||||
.is_ok();
|
||||
Ok(ImageOrientation {
|
||||
angle: angle,
|
||||
flipped: flipped,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
|
@ -49,7 +49,6 @@ pub use self::flex::FlexBasis;
|
|||
pub use self::gecko::ScrollSnapPoint;
|
||||
pub use self::image::{ColorStop, EndingShape as GradientEndingShape, Gradient};
|
||||
pub use self::image::{GradientItem, GradientKind, Image, ImageLayer, MozImageRect};
|
||||
pub use self::inherited_box::ImageOrientation;
|
||||
pub use self::length::{AbsoluteLength, CalcLengthOrPercentage, CharacterWidth};
|
||||
pub use self::length::{FontRelativeLength, Length, LengthOrNumber};
|
||||
pub use self::length::{LengthOrPercentage, LengthOrPercentageOrAuto};
|
||||
|
@ -99,7 +98,6 @@ pub mod font;
|
|||
pub mod gecko;
|
||||
pub mod grid;
|
||||
pub mod image;
|
||||
pub mod inherited_box;
|
||||
pub mod length;
|
||||
pub mod list;
|
||||
pub mod outline;
|
||||
|
|
|
@ -13,14 +13,14 @@ use values::CustomIdent;
|
|||
use values::generics::svg as generic;
|
||||
use values::specified::{LengthOrPercentage, NonNegativeLengthOrPercentage, NonNegativeNumber};
|
||||
use values::specified::{Number, Opacity};
|
||||
use values::specified::color::RGBAColor;
|
||||
use values::specified::color::Color;
|
||||
use values::specified::url::SpecifiedUrl;
|
||||
|
||||
/// Specified SVG Paint value
|
||||
pub type SVGPaint = generic::SVGPaint<RGBAColor, SpecifiedUrl>;
|
||||
pub type SVGPaint = generic::SVGPaint<Color, SpecifiedUrl>;
|
||||
|
||||
/// Specified SVG Paint Kind value
|
||||
pub type SVGPaintKind = generic::SVGPaintKind<RGBAColor, SpecifiedUrl>;
|
||||
pub type SVGPaintKind = generic::SVGPaintKind<Color, SpecifiedUrl>;
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
fn is_context_value_enabled() -> bool {
|
||||
|
|
|
@ -1,259 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use cssparser::SourceLocation;
|
||||
use servo_arc::Arc;
|
||||
use style::properties::{LonghandId, LonghandIdSet, PropertyDeclaration, PropertyDeclarationBlock, Importance};
|
||||
use style::properties::DeclarationSource;
|
||||
use style::shared_lock::SharedRwLock;
|
||||
use style::stylesheets::keyframes_rule::{Keyframe, KeyframesAnimation, KeyframePercentage, KeyframeSelector};
|
||||
use style::stylesheets::keyframes_rule::{KeyframesStep, KeyframesStepValue};
|
||||
use style::values::specified::{LengthOrPercentageOrAuto, NoCalcLength};
|
||||
|
||||
macro_rules! longhand_set {
|
||||
($($word:ident),+) => {{
|
||||
let mut set = LonghandIdSet::new();
|
||||
$(
|
||||
set.insert(LonghandId::$word);
|
||||
)+
|
||||
set
|
||||
}}
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_empty_keyframe() {
|
||||
let shared_lock = SharedRwLock::new();
|
||||
let keyframes = vec![];
|
||||
let animation = KeyframesAnimation::from_keyframes(&keyframes,
|
||||
/* vendor_prefix = */ None,
|
||||
&shared_lock.read());
|
||||
let expected = KeyframesAnimation {
|
||||
steps: vec![],
|
||||
properties_changed: LonghandIdSet::new(),
|
||||
vendor_prefix: None,
|
||||
};
|
||||
|
||||
assert_eq!(format!("{:#?}", animation), format!("{:#?}", expected));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_no_property_in_keyframe() {
|
||||
let shared_lock = SharedRwLock::new();
|
||||
let dummy_location = SourceLocation { line: 0, column: 0 };
|
||||
let keyframes = vec![
|
||||
Arc::new(shared_lock.wrap(Keyframe {
|
||||
selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(1.)]),
|
||||
block: Arc::new(shared_lock.wrap(PropertyDeclarationBlock::new())),
|
||||
source_location: dummy_location,
|
||||
})),
|
||||
];
|
||||
let animation = KeyframesAnimation::from_keyframes(&keyframes,
|
||||
/* vendor_prefix = */ None,
|
||||
&shared_lock.read());
|
||||
let expected = KeyframesAnimation {
|
||||
steps: vec![],
|
||||
properties_changed: LonghandIdSet::new(),
|
||||
vendor_prefix: None,
|
||||
};
|
||||
|
||||
assert_eq!(format!("{:#?}", animation), format!("{:#?}", expected));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_missing_property_in_initial_keyframe() {
|
||||
let shared_lock = SharedRwLock::new();
|
||||
let declarations_on_initial_keyframe =
|
||||
Arc::new(shared_lock.wrap(PropertyDeclarationBlock::with_one(
|
||||
PropertyDeclaration::Width(
|
||||
LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(20f32))),
|
||||
Importance::Normal
|
||||
)));
|
||||
|
||||
let declarations_on_final_keyframe =
|
||||
Arc::new(shared_lock.wrap({
|
||||
let mut block = PropertyDeclarationBlock::new();
|
||||
block.push(
|
||||
PropertyDeclaration::Width(
|
||||
LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(20f32))),
|
||||
Importance::Normal,
|
||||
DeclarationSource::Parsing,
|
||||
);
|
||||
block.push(
|
||||
PropertyDeclaration::Height(
|
||||
LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(20f32))),
|
||||
Importance::Normal,
|
||||
DeclarationSource::Parsing,
|
||||
);
|
||||
block
|
||||
}));
|
||||
|
||||
let dummy_location = SourceLocation { line: 0, column: 0 };
|
||||
let keyframes = vec![
|
||||
Arc::new(shared_lock.wrap(Keyframe {
|
||||
selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(0.)]),
|
||||
block: declarations_on_initial_keyframe.clone(),
|
||||
source_location: dummy_location,
|
||||
})),
|
||||
|
||||
Arc::new(shared_lock.wrap(Keyframe {
|
||||
selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(1.)]),
|
||||
block: declarations_on_final_keyframe.clone(),
|
||||
source_location: dummy_location,
|
||||
})),
|
||||
];
|
||||
let animation = KeyframesAnimation::from_keyframes(&keyframes,
|
||||
/* vendor_prefix = */ None,
|
||||
&shared_lock.read());
|
||||
let expected = KeyframesAnimation {
|
||||
steps: vec![
|
||||
KeyframesStep {
|
||||
start_percentage: KeyframePercentage(0.),
|
||||
value: KeyframesStepValue::Declarations { block: declarations_on_initial_keyframe },
|
||||
declared_timing_function: false,
|
||||
},
|
||||
KeyframesStep {
|
||||
start_percentage: KeyframePercentage(1.),
|
||||
value: KeyframesStepValue::Declarations { block: declarations_on_final_keyframe },
|
||||
declared_timing_function: false,
|
||||
},
|
||||
],
|
||||
properties_changed: longhand_set!(Width, Height),
|
||||
vendor_prefix: None,
|
||||
};
|
||||
|
||||
assert_eq!(format!("{:#?}", animation), format!("{:#?}", expected));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_missing_property_in_final_keyframe() {
|
||||
let shared_lock = SharedRwLock::new();
|
||||
let declarations_on_initial_keyframe =
|
||||
Arc::new(shared_lock.wrap({
|
||||
let mut block = PropertyDeclarationBlock::new();
|
||||
block.push(
|
||||
PropertyDeclaration::Width(
|
||||
LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(20f32))),
|
||||
Importance::Normal,
|
||||
DeclarationSource::Parsing,
|
||||
);
|
||||
block.push(
|
||||
PropertyDeclaration::Height(
|
||||
LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(20f32))),
|
||||
Importance::Normal,
|
||||
DeclarationSource::Parsing,
|
||||
);
|
||||
block
|
||||
}));
|
||||
|
||||
let declarations_on_final_keyframe =
|
||||
Arc::new(shared_lock.wrap(PropertyDeclarationBlock::with_one(
|
||||
PropertyDeclaration::Height(
|
||||
LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(20f32))),
|
||||
Importance::Normal,
|
||||
)));
|
||||
|
||||
let dummy_location = SourceLocation { line: 0, column: 0 };
|
||||
let keyframes = vec![
|
||||
Arc::new(shared_lock.wrap(Keyframe {
|
||||
selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(0.)]),
|
||||
block: declarations_on_initial_keyframe.clone(),
|
||||
source_location: dummy_location,
|
||||
})),
|
||||
|
||||
Arc::new(shared_lock.wrap(Keyframe {
|
||||
selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(1.)]),
|
||||
block: declarations_on_final_keyframe.clone(),
|
||||
source_location: dummy_location,
|
||||
})),
|
||||
];
|
||||
let animation = KeyframesAnimation::from_keyframes(&keyframes,
|
||||
/* vendor_prefix = */ None,
|
||||
&shared_lock.read());
|
||||
let expected = KeyframesAnimation {
|
||||
steps: vec![
|
||||
KeyframesStep {
|
||||
start_percentage: KeyframePercentage(0.),
|
||||
value: KeyframesStepValue::Declarations { block: declarations_on_initial_keyframe },
|
||||
declared_timing_function: false,
|
||||
},
|
||||
KeyframesStep {
|
||||
start_percentage: KeyframePercentage(1.),
|
||||
value: KeyframesStepValue::Declarations { block: declarations_on_final_keyframe },
|
||||
declared_timing_function: false,
|
||||
},
|
||||
],
|
||||
properties_changed: longhand_set!(Width, Height),
|
||||
vendor_prefix: None,
|
||||
};
|
||||
|
||||
assert_eq!(format!("{:#?}", animation), format!("{:#?}", expected));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_missing_keyframe_in_both_of_initial_and_final_keyframe() {
|
||||
let shared_lock = SharedRwLock::new();
|
||||
let declarations =
|
||||
Arc::new(shared_lock.wrap({
|
||||
let mut block = PropertyDeclarationBlock::new();
|
||||
block.push(
|
||||
PropertyDeclaration::Width(
|
||||
LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(20f32))),
|
||||
Importance::Normal,
|
||||
DeclarationSource::Parsing,
|
||||
);
|
||||
block.push(
|
||||
PropertyDeclaration::Height(
|
||||
LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(20f32))),
|
||||
Importance::Normal,
|
||||
DeclarationSource::Parsing,
|
||||
);
|
||||
block
|
||||
}));
|
||||
|
||||
let dummy_location = SourceLocation { line: 0, column: 0 };
|
||||
let keyframes = vec![
|
||||
Arc::new(shared_lock.wrap(Keyframe {
|
||||
selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(0.)]),
|
||||
block: Arc::new(shared_lock.wrap(PropertyDeclarationBlock::new())),
|
||||
source_location: dummy_location,
|
||||
})),
|
||||
Arc::new(shared_lock.wrap(Keyframe {
|
||||
selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(0.5)]),
|
||||
block: declarations.clone(),
|
||||
source_location: dummy_location,
|
||||
})),
|
||||
];
|
||||
let animation = KeyframesAnimation::from_keyframes(&keyframes,
|
||||
/* vendor_prefix = */ None,
|
||||
&shared_lock.read());
|
||||
let expected = KeyframesAnimation {
|
||||
steps: vec![
|
||||
KeyframesStep {
|
||||
start_percentage: KeyframePercentage(0.),
|
||||
value: KeyframesStepValue::Declarations {
|
||||
block: Arc::new(shared_lock.wrap(
|
||||
// XXX: Should we use ComputedValues in this case?
|
||||
PropertyDeclarationBlock::new()
|
||||
))
|
||||
},
|
||||
declared_timing_function: false,
|
||||
},
|
||||
KeyframesStep {
|
||||
start_percentage: KeyframePercentage(0.5),
|
||||
value: KeyframesStepValue::Declarations { block: declarations },
|
||||
declared_timing_function: false,
|
||||
},
|
||||
KeyframesStep {
|
||||
start_percentage: KeyframePercentage(1.),
|
||||
value: KeyframesStepValue::ComputedValues,
|
||||
declared_timing_function: false,
|
||||
}
|
||||
],
|
||||
properties_changed: longhand_set!(Width, Height),
|
||||
vendor_prefix: None,
|
||||
};
|
||||
|
||||
assert_eq!(format!("{:#?}", animation), format!("{:#?}", expected));
|
||||
}
|
|
@ -25,7 +25,6 @@ extern crate test;
|
|||
mod animated_properties;
|
||||
mod attr;
|
||||
mod custom_properties;
|
||||
mod keyframes;
|
||||
mod logical_geometry;
|
||||
mod parsing;
|
||||
mod properties;
|
||||
|
|
|
@ -17,7 +17,7 @@ use std::sync::atomic::AtomicBool;
|
|||
use style::context::QuirksMode;
|
||||
use style::error_reporting::{ParseErrorReporter, ContextualParseError};
|
||||
use style::media_queries::MediaList;
|
||||
use style::properties::{CSSWideKeyword, CustomDeclaration, DeclarationSource};
|
||||
use style::properties::{CSSWideKeyword, CustomDeclaration, DeclarationPushMode};
|
||||
use style::properties::{DeclaredValueOwned, Importance};
|
||||
use style::properties::{PropertyDeclaration, PropertyDeclarationBlock};
|
||||
use style::properties::longhands::{self, animation_timing_function};
|
||||
|
@ -34,7 +34,7 @@ pub fn block_from<I>(iterable: I) -> PropertyDeclarationBlock
|
|||
where I: IntoIterator<Item=(PropertyDeclaration, Importance)> {
|
||||
let mut block = PropertyDeclarationBlock::new();
|
||||
for (d, i) in iterable {
|
||||
block.push(d, i, DeclarationSource::CssOm);
|
||||
block.push(d, i, DeclarationPushMode::Append);
|
||||
}
|
||||
block
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue