Bug 1846516 - [css-properties-values-api] Use AnimatedPropertyID to communicate between Gecko and Servo. r=emilio,layout-reviewers,firefox-style-system-reviewers

Co-authored-by: Frederic Wang <fred.wang@free.fr>
Co-authored-by: Emilio Cobos Álvarez <emilio@crisal.io>

Depends on D191059

Differential Revision: https://phabricator.services.mozilla.com/D191322
This commit is contained in:
Zach Hoffman 2023-12-18 09:24:08 +00:00
parent cd5747dfbf
commit 7653a4f1c2
21 changed files with 246 additions and 129 deletions

View File

@ -870,9 +870,8 @@ void Animation::CommitStyles(ErrorResult& aRv) {
bool changed = false;
const AnimatedPropertyIDSet& properties = keyframeEffect->GetPropertySet();
for (const AnimatedPropertyID& property : properties) {
// TODO(zrhoffman, bug 1846516): Handle custom properties
RefPtr<StyleAnimationValue> computedValue =
Servo_AnimationValueMap_GetValue(animationValues.get(), property.mID)
Servo_AnimationValueMap_GetValue(animationValues.get(), &property)
.Consume();
if (computedValue) {
changed |= Servo_DeclarationBlock_SetPropertyToAnimationValue(

View File

@ -7,10 +7,10 @@
#ifndef mozilla_dom_Keyframe_h
#define mozilla_dom_Keyframe_h
#include "nsCSSPropertyID.h"
#include "nsCSSValue.h"
#include "nsTArray.h"
#include "mozilla/dom/BaseKeyframeTypesBinding.h" // CompositeOperationOrAuto
#include "mozilla/AnimatedPropertyID.h"
#include "mozilla/ServoStyleConsts.h"
#include "mozilla/Maybe.h"
#include "mozilla/RefPtr.h"
@ -22,15 +22,15 @@ struct StyleLockedDeclarationBlock;
* A property-value pair specified on a keyframe.
*/
struct PropertyValuePair {
explicit PropertyValuePair(nsCSSPropertyID aProperty)
explicit PropertyValuePair(const AnimatedPropertyID& aProperty)
: mProperty(aProperty) {}
PropertyValuePair(nsCSSPropertyID aProperty,
PropertyValuePair(const AnimatedPropertyID& aProperty,
RefPtr<StyleLockedDeclarationBlock>&& aValue)
: mProperty(aProperty), mServoDeclarationBlock(std::move(aValue)) {
MOZ_ASSERT(mServoDeclarationBlock, "Should be valid property value");
}
nsCSSPropertyID mProperty;
AnimatedPropertyID mProperty;
// The specified value when using the Servo backend.
RefPtr<StyleLockedDeclarationBlock> mServoDeclarationBlock;

View File

@ -287,8 +287,9 @@ void KeyframeEffect::ReplaceTransitionStartValue(AnimationValue&& aStartValue) {
// Check that the value we are about to substitute in is actually for the
// same property.
if (Servo_AnimationValue_GetPropertyId(aStartValue.mServo) !=
mProperties[0].mProperty.mID) {
AnimatedPropertyID property(eCSSProperty_UNKNOWN);
Servo_AnimationValue_GetPropertyId(aStartValue.mServo, &property);
if (property != mProperties[0].mProperty) {
return;
}
@ -587,7 +588,7 @@ void KeyframeEffect::EnsureBaseStyle(
}
RefPtr<StyleAnimationValue> baseValue =
Servo_ComputedValues_ExtractAnimationValue(aBaseComputedStyle,
aProperty.mProperty.mID)
&aProperty.mProperty)
.Consume();
mBaseValues.InsertOrUpdate(aProperty.mProperty.mID, std::move(baseValue));
}
@ -604,10 +605,9 @@ void KeyframeEffect::ComposeStyleRule(StyleAnimationValueMap& aAnimationValues,
const ComputedTiming& aComputedTiming) {
auto* opaqueTable =
reinterpret_cast<RawServoAnimationValueTable*>(&mBaseValues);
Servo_AnimationCompose(&aAnimationValues, opaqueTable,
aProperty.mProperty.mID, &aSegment,
&aProperty.mSegments.LastElement(), &aComputedTiming,
mEffectOptions.mIterationComposite);
Servo_AnimationCompose(&aAnimationValues, opaqueTable, &aProperty.mProperty,
&aSegment, &aProperty.mSegments.LastElement(),
&aComputedTiming, mEffectOptions.mIterationComposite);
}
void KeyframeEffect::ComposeStyle(StyleAnimationValueMap& aComposeResult,
@ -1287,7 +1287,7 @@ void KeyframeEffect::GetKeyframes(JSContext* aCx, nsTArray<JSObject*>& aResult,
// This workaround will be solved by bug 1391537.
if (isCSSAnimation) {
for (const PropertyValuePair& propertyValue : keyframe.mPropertyValues) {
if (propertyValue.mProperty ==
if (propertyValue.mProperty.mID ==
nsCSSPropertyID::eCSSPropertyExtra_variable) {
customProperties = propertyValue.mServoDeclarationBlock;
break;
@ -1299,17 +1299,17 @@ void KeyframeEffect::GetKeyframes(JSContext* aCx, nsTArray<JSObject*>& aResult,
for (const PropertyValuePair& propertyValue : keyframe.mPropertyValues) {
nsAutoCString stringValue;
// Don't serialize the custom properties for this keyframe.
if (propertyValue.mProperty ==
if (propertyValue.mProperty.mID ==
nsCSSPropertyID::eCSSPropertyExtra_variable) {
continue;
}
if (propertyValue.mServoDeclarationBlock) {
Servo_DeclarationBlock_SerializeOneValue(
propertyValue.mServoDeclarationBlock, propertyValue.mProperty,
propertyValue.mServoDeclarationBlock, &propertyValue.mProperty,
&stringValue, computedStyle, customProperties, rawData);
} else {
if (auto* value = mBaseValues.GetWeak(propertyValue.mProperty)) {
Servo_AnimationValue_Serialize(value, propertyValue.mProperty,
if (auto* value = mBaseValues.GetWeak(propertyValue.mProperty.mID)) {
Servo_AnimationValue_Serialize(value, &propertyValue.mProperty,
rawData, &stringValue);
}
}
@ -1322,7 +1322,15 @@ void KeyframeEffect::GetKeyframes(JSContext* aCx, nsTArray<JSObject*>& aResult,
// "offset" property in BaseKeyframe.)
// https://drafts.csswg.org/web-animations/#property-name-conversion
const char* name = nullptr;
switch (propertyValue.mProperty) {
nsAutoCString customName;
nsAutoCString identifier;
switch (propertyValue.mProperty.mID) {
case nsCSSPropertyID::eCSSPropertyExtra_variable:
customName.Append("--");
propertyValue.mProperty.mCustomName->ToUTF8String(identifier);
customName.Append(identifier);
name = customName.get();
break;
case nsCSSPropertyID::eCSSProperty_offset:
name = "cssOffset";
break;
@ -1330,7 +1338,7 @@ void KeyframeEffect::GetKeyframes(JSContext* aCx, nsTArray<JSObject*>& aResult,
// FIXME: Bug 1582314: Should handle cssFloat manually if we remove it
// from nsCSSProps::PropertyIDLName().
default:
name = nsCSSProps::PropertyIDLName(propertyValue.mProperty);
name = nsCSSProps::PropertyIDLName(propertyValue.mProperty.mID);
}
JS::Rooted<JS::Value> value(aCx);

View File

@ -334,7 +334,7 @@ nsTArray<AnimationProperty> KeyframeUtils::GetAnimationPropertiesFromKeyframes(
"Invalid computed offset");
KeyframeValueEntry* entry = entries.AppendElement();
entry->mOffset = frame.mComputedOffset;
entry->mProperty.mID = value.mProperty;
entry->mProperty = value.mProperty;
entry->mValue = value.mValue;
entry->mTimingFunction = frame.mTimingFunction;
// The following assumes that CompositeOperation is a strict subset of
@ -358,11 +358,7 @@ bool KeyframeUtils::IsAnimatableProperty(const AnimatedPropertyID& aProperty) {
if (aProperty.mID == eCSSProperty_display) {
return false;
}
// TODO(bug 1846516): handle custom property.
if (!aProperty.IsCustom()) {
return false;
}
return Servo_Property_IsAnimatable(aProperty.mID);
return Servo_Property_IsAnimatable(&aProperty);
}
// ------------------------------------------------------------------
@ -698,11 +694,11 @@ static Maybe<PropertyValuePair> MakePropertyValuePair(
ServoCSSParser::ParsingEnvironment env =
ServoCSSParser::GetParsingEnvironment(aDocument);
RefPtr<StyleLockedDeclarationBlock> servoDeclarationBlock =
ServoCSSParser::ParseProperty(aProperty.mID, aStringValue, env,
ServoCSSParser::ParseProperty(aProperty, aStringValue, env,
StyleParsingMode::DEFAULT);
if (servoDeclarationBlock) {
result.emplace(aProperty.mID, std::move(servoDeclarationBlock));
result.emplace(aProperty, std::move(servoDeclarationBlock));
} else {
ReportInvalidPropertyValueToConsole(aProperty, aStringValue, aDocument);
}
@ -741,7 +737,7 @@ static bool HasValidOffsets(const nsTArray<Keyframe>& aKeyframes) {
* a shorthand property.
*/
static void MarkAsComputeValuesFailureKey(PropertyValuePair& aPair) {
MOZ_ASSERT(nsCSSProps::IsShorthand(aPair.mProperty),
MOZ_ASSERT(nsCSSProps::IsShorthand(aPair.mProperty.mID),
"Only shorthand property values can be marked as failure values");
aPair.mSimulateComputeValuesFailure = true;

View File

@ -133,6 +133,7 @@
#include "mozilla/IMEStateManager.h"
#include "mozilla/IMEContentObserver.h"
#include "mozilla/WheelHandlingHelper.h"
#include "mozilla/AnimatedPropertyID.h"
#ifdef XP_WIN
# include <direct.h>
@ -3206,7 +3207,12 @@ nsDOMWindowUtils::GetUnanimatedComputedStyle(Element* aElement,
nsCSSProps::IsShorthand(propertyID)) {
return NS_ERROR_INVALID_ARG;
}
// TODO(bug 1846516): Handle custom properties.
AnimatedPropertyID* property;
if (propertyID == eCSSPropertyExtra_variable) {
property = new AnimatedPropertyID(NS_Atomize(aProperty));
} else {
property = new AnimatedPropertyID(propertyID);
}
switch (aFlushType) {
case FLUSH_NONE:
@ -3238,7 +3244,7 @@ nsDOMWindowUtils::GetUnanimatedComputedStyle(Element* aElement,
}
RefPtr<StyleAnimationValue> value =
Servo_ComputedValues_ExtractAnimationValue(computedStyle, propertyID)
Servo_ComputedValues_ExtractAnimationValue(computedStyle, property)
.Consume();
if (!value) {
return NS_ERROR_FAILURE;
@ -3247,7 +3253,7 @@ nsDOMWindowUtils::GetUnanimatedComputedStyle(Element* aElement,
return NS_ERROR_FAILURE;
}
nsAutoCString result;
Servo_AnimationValue_Serialize(value, propertyID,
Servo_AnimationValue_Serialize(value, property,
presShell->StyleSet()->RawData(), &result);
CopyUTF8toUTF16(result, aResult);
return NS_OK;

View File

@ -10,6 +10,7 @@
#include <utility>
#include "mozilla/AnimatedPropertyID.h"
#include "mozilla/SMILCSSValueType.h"
#include "mozilla/SMILValue.h"
#include "mozilla/ServoBindings.h"
@ -62,8 +63,11 @@ SMILValue SMILCSSProperty::GetBaseValue() const {
}
AnimationValue computedValue;
AnimatedPropertyID property(mPropID);
MOZ_ASSERT(!property.IsCustom(),
"Cannot animate custom properties with SMIL");
computedValue.mServo =
Servo_ComputedValues_ExtractAnimationValue(mBaseComputedStyle, mPropID)
Servo_ComputedValues_ExtractAnimationValue(mBaseComputedStyle, &property)
.Consume();
if (!computedValue.mServo) {
return baseValue;

View File

@ -19,9 +19,10 @@
#include "mozilla/dom/Nullable.h" // for dom::Nullable
#include "mozilla/layers/APZSampler.h" // for APZSampler
#include "mozilla/layers/CompositorThread.h" // for CompositorThreadHolder
#include "mozilla/LayerAnimationInfo.h" // for GetCSSPropertiesFor()
#include "mozilla/Maybe.h" // for Maybe<>
#include "mozilla/MotionPathUtils.h" // for ResolveMotionPath()
#include "mozilla/AnimatedPropertyID.h"
#include "mozilla/LayerAnimationInfo.h" // for GetCSSPropertiesFor()
#include "mozilla/Maybe.h" // for Maybe<>
#include "mozilla/MotionPathUtils.h" // for ResolveMotionPath()
#include "mozilla/ServoBindings.h" // for Servo_ComposeAnimationSegment, etc
#include "mozilla/StyleAnimationValue.h" // for StyleAnimationValue, etc
#include "nsCSSPropertyID.h" // for eCSSProperty_offset_path, etc
@ -626,8 +627,9 @@ gfx::Matrix4x4 AnimationHelper::ServoAnimationValueToMatrix4x4(
for (const auto& value : aValues) {
MOZ_ASSERT(value);
nsCSSPropertyID id = Servo_AnimationValue_GetPropertyId(value);
switch (id) {
AnimatedPropertyID property(eCSSProperty_UNKNOWN);
Servo_AnimationValue_GetPropertyId(value, &property);
switch (property.mID) {
case eCSSProperty_transform:
MOZ_ASSERT(!transform);
transform = Servo_AnimationValue_GetTransform(value);

View File

@ -681,11 +681,11 @@ double Gecko_GetPositionInSegment(const AnimationPropertySegment* aSegment,
}
const StyleAnimationValue* Gecko_AnimationGetBaseStyle(
const RawServoAnimationValueTable* aBaseStyles, nsCSSPropertyID aProperty) {
auto base = reinterpret_cast<
const nsRefPtrHashtable<nsUint32HashKey, StyleAnimationValue>*>(
aBaseStyles);
return base->GetWeak(aProperty);
const RawServoAnimationValueTable* aBaseStyles,
const mozilla::AnimatedPropertyID* aProperty) {
const auto* base = reinterpret_cast<const nsRefPtrHashtable<
nsGenericHashKey<AnimatedPropertyID>, StyleAnimationValue>*>(aBaseStyles);
return base->GetWeak(*aProperty);
}
void Gecko_FillAllImageLayers(nsStyleImageLayers* aLayers, uint32_t aMaxLen) {
@ -1161,7 +1161,8 @@ PropertyValuePair* Gecko_AppendPropertyValuePair(
MOZ_ASSERT(aProperties);
MOZ_ASSERT(aProperty == eCSSPropertyExtra_variable ||
!nsCSSProps::PropHasFlags(aProperty, CSSPropFlags::IsLogical));
return aProperties->AppendElement(PropertyValuePair{aProperty});
mozilla::AnimatedPropertyID property(aProperty);
return aProperties->AppendElement(PropertyValuePair{property});
}
void Gecko_GetComputedURLSpec(const StyleComputedUrl* aURL, nsCString* aOut) {

View File

@ -258,11 +258,13 @@ double Gecko_GetPositionInSegment(const mozilla::AnimationPropertySegment*,
// Get servo's AnimationValue for |aProperty| from the cached base style
// |aBaseStyles|.
// |aBaseStyles| is nsRefPtrHashtable<nsUint32HashKey, StyleAnimationValue>.
// |aBaseStyles| is nsRefPtrHashtable<nsGenericHashKey<AnimatedPropertyID>,
// StyleAnimationValue>.
// We use RawServoAnimationValueTableBorrowed to avoid exposing
// nsRefPtrHashtable in FFI.
const mozilla::StyleAnimationValue* Gecko_AnimationGetBaseStyle(
const RawServoAnimationValueTable* aBaseStyles, nsCSSPropertyID aProperty);
const RawServoAnimationValueTable* aBaseStyles,
const mozilla::AnimatedPropertyID* aProperty);
void Gecko_StyleTransition_SetUnsupportedProperty(
mozilla::StyleTransition* aTransition, nsAtom* aAtom);

View File

@ -7,6 +7,7 @@ headers = [
"COLRFonts.h",
"nsStyleConsts.h",
"mozilla/css/Loader.h",
"mozilla/AnimatedPropertyID.h",
"mozilla/css/SheetLoadData.h",
"mozilla/DeclarationBlock.h",
"mozilla/dom/AnimationEffectBinding.h",
@ -210,6 +211,7 @@ allowlist-types = [
"mozilla::Keyframe",
"mozilla::PropertyValuePair",
"mozilla::DeclarationBlockMutationClosure",
"mozilla::AnimatedPropertyID",
"mozilla::AnimationPropertySegment",
"mozilla::AnonymousCounterStyle",
"mozilla::AtomArray",

View File

@ -8,6 +8,7 @@
#include "ServoCSSParser.h"
#include "mozilla/AnimatedPropertyID.h"
#include "mozilla/ServoBindings.h"
#include "mozilla/ServoStyleSet.h"
#include "mozilla/dom/Document.h"
@ -36,8 +37,17 @@ already_AddRefed<StyleLockedDeclarationBlock> ServoCSSParser::ParseProperty(
nsCSSPropertyID aProperty, const nsACString& aValue,
const ParsingEnvironment& aParsingEnvironment,
const StyleParsingMode& aParsingMode) {
AnimatedPropertyID property(aProperty);
return ParseProperty(property, aValue, aParsingEnvironment, aParsingMode);
}
/* static */
already_AddRefed<StyleLockedDeclarationBlock> ServoCSSParser::ParseProperty(
const AnimatedPropertyID& aProperty, const nsACString& aValue,
const ParsingEnvironment& aParsingEnvironment,
const StyleParsingMode& aParsingMode) {
return Servo_ParseProperty(
aProperty, &aValue, aParsingEnvironment.mUrlExtraData,
&aProperty, &aValue, aParsingEnvironment.mUrlExtraData,
aParsingMode, aParsingEnvironment.mCompatMode,
aParsingEnvironment.mLoader, aParsingEnvironment.mRuleType)
.Consume();

View File

@ -22,6 +22,7 @@ class RefPtr;
namespace mozilla {
struct AnimatedPropertyID;
class ServoStyleSet;
struct URLExtraData;
struct StyleFontFamilyList;
@ -94,6 +95,10 @@ class ServoCSSParser {
nsCSSPropertyID aProperty, const nsACString& aValue,
const ParsingEnvironment& aParsingEnvironment,
const StyleParsingMode& aParsingMode);
static already_AddRefed<StyleLockedDeclarationBlock> ParseProperty(
const AnimatedPropertyID& aProperty, const nsACString& aValue,
const ParsingEnvironment& aParsingEnvironment,
const StyleParsingMode& aParsingMode);
/**
* Parse a animation timing function.

View File

@ -93,6 +93,7 @@ class ServoElementSnapshotTable;
template <typename T>
struct StyleForgottenArcSlicePtr;
struct AnimatedPropertyID;
struct AnimationPropertySegment;
struct AspectRatio;
struct ComputedTiming;

View File

@ -124,7 +124,9 @@ bool AnimationValue::IsOffsetPathUrl() const {
MatrixScales AnimationValue::GetScaleValue(const nsIFrame* aFrame) const {
using namespace nsStyleTransformMatrix;
switch (Servo_AnimationValue_GetPropertyId(mServo)) {
AnimatedPropertyID property(eCSSProperty_UNKNOWN);
Servo_AnimationValue_GetPropertyId(mServo, &property);
switch (property.mID) {
case eCSSProperty_scale: {
const StyleScale& scale = GetScaleProperty();
return scale.IsNone()
@ -159,7 +161,7 @@ void AnimationValue::SerializeSpecifiedValue(
const AnimatedPropertyID& aProperty,
const StylePerDocumentStyleData* aRawData, nsACString& aString) const {
MOZ_ASSERT(mServo);
Servo_AnimationValue_Serialize(mServo, aProperty.mID, aRawData, &aString);
Servo_AnimationValue_Serialize(mServo, &aProperty, aRawData, &aString);
}
bool AnimationValue::IsInterpolableWith(const AnimatedPropertyID& aProperty,
@ -211,8 +213,9 @@ AnimationValue AnimationValue::FromString(nsCSSPropertyID aProperty,
nsComputedDOMStyle::GetComputedStyle(aElement);
MOZ_ASSERT(computedStyle);
AnimatedPropertyID property(aProperty);
RefPtr<StyleLockedDeclarationBlock> declarations =
ServoCSSParser::ParseProperty(aProperty, aValue,
ServoCSSParser::ParseProperty(property, aValue,
ServoCSSParser::GetParsingEnvironment(doc),
StyleParsingMode::DEFAULT);

View File

@ -15,6 +15,7 @@
#include "mozilla/ServoBindingTypes.h"
#include "mozilla/ServoStyleConsts.h" // Servo_AnimationValue_Dump
#include "mozilla/DbgMacro.h"
#include "mozilla/AnimatedPropertyID.h"
#include "nsStringFwd.h"
#include "nsStringBuffer.h"
#include "nsCoord.h"
@ -131,7 +132,7 @@ inline std::ostream& operator<<(std::ostream& aOut,
}
struct PropertyStyleAnimationValuePair {
nsCSSPropertyID mProperty;
AnimatedPropertyID mProperty;
AnimationValue mValue;
};
} // namespace mozilla

View File

@ -169,7 +169,7 @@ bool nsTransitionManager::DoUpdateTransitions(
// or because the new value is not interpolable); a new transition
// would have anim->ToValue() matching currentValue.
!Servo_ComputedValues_TransitionValueMatches(
&aNewStyle, property.mID, anim->ToValue().mServo.get())) {
&aNewStyle, &property, anim->ToValue().mServo.get())) {
// Stop the transition.
DoCancelTransition(aElement, aPseudoType, aElementTransitions, i);
}
@ -189,7 +189,7 @@ static Keyframe& AppendKeyframe(double aOffset,
RefPtr<StyleLockedDeclarationBlock> decl =
Servo_AnimationValue_Uncompute(aValue.mServo).Consume();
frame.mPropertyValues.AppendElement(
PropertyValuePair(aProperty.mID, std::move(decl)));
PropertyValuePair(aProperty, std::move(decl)));
return frame;
}
@ -205,11 +205,7 @@ static nsTArray<Keyframe> GetTransitionKeyframes(
}
static bool IsTransitionable(const AnimatedPropertyID& aProperty) {
// TODO(bug 1846516): handle custom property.
if (aProperty.IsCustom()) {
return false;
}
return Servo_Property_IsTransitionable(aProperty.mID);
return Servo_Property_IsTransitionable(&aProperty);
}
static Maybe<CSSTransition::ReplacedTransitionProperties>
@ -321,7 +317,7 @@ bool nsTransitionManager::ConsiderInitiatingTransition(
AnimationValue startValue, endValue;
const StyleShouldTransitionResult result =
Servo_ComputedValues_ShouldTransition(
&aOldStyle, &aNewStyle, aProperty.mID,
&aOldStyle, &aNewStyle, &aProperty,
oldTransition ? oldTransition->ToValue().mServo.get() : nullptr,
&startValue.mServo, &endValue.mServo);

View File

@ -401,7 +401,6 @@ impl AnimationValue {
PropertyDeclarationId::Custom(_) => return None,
};
let property = property.to_physical(style.writing_mode);
Some(match property {
% for prop in data.longhands:
% if prop.animatable and not prop.logical:

View File

@ -18,6 +18,7 @@ use std::{ops, ptr};
use std::fmt::{self, Write};
use std::mem;
use crate::Atom;
use cssparser::{Parser, ParserInput, TokenSerializationType};
#[cfg(feature = "servo")] use euclid::SideOffsets2D;
#[cfg(feature = "gecko")] use crate::gecko_bindings::structs::{self, nsCSSPropertyID};
@ -2089,6 +2090,23 @@ impl PropertyId {
Some(NonCustomPropertyId::from_nscsspropertyid(id)?.to_property_id())
}
/// Returns a property id from Gecko's AnimatedPropertyID.
#[cfg(feature = "gecko")]
#[allow(non_upper_case_globals)]
#[inline]
pub fn from_gecko_animated_property_id(property: &structs::AnimatedPropertyID) -> Result<Self, ()> {
Ok(if property.mID == nsCSSPropertyID::eCSSPropertyExtra_variable {
if property.mCustomName.mRawPtr.is_null() {
return Err(());
}
PropertyId::Custom(unsafe {
Atom::from_raw(property.mCustomName.mRawPtr)
})
} else {
NonCustomPropertyId::from_nscsspropertyid(property.mID)?.to_property_id()
})
}
/// Returns true if the property is a shorthand or shorthand alias.
#[inline]
pub fn is_shorthand(&self) -> bool {

View File

@ -4,12 +4,14 @@
//! Structs used for property declarations.
use super::{LonghandId, PropertyId, ShorthandId};
use super::{LonghandId, NonCustomPropertyId, PropertyId, ShorthandId};
use crate::custom_properties::Name;
#[cfg(feature = "gecko")]
use crate::gecko_bindings::structs::nsCSSPropertyID;
use crate::gecko_bindings::structs::{nsCSSPropertyID, AnimatedPropertyID};
use crate::logical_geometry::WritingMode;
use crate::values::serialize_atom_name;
#[cfg(feature = "gecko")]
use crate::Atom;
use std::{
borrow::Cow,
fmt::{self, Write},
@ -32,12 +34,51 @@ impl OwnedPropertyDeclarationId {
self.as_borrowed().is_logical()
}
/// Returns whether this property is animatable.
#[inline]
pub fn is_animatable(&self) -> bool {
match self {
Self::Longhand(id) => id.is_animatable(),
// TODO(bug 1846516): This should return true.
Self::Custom(_) => false,
}
}
/// Returns the corresponding PropertyDeclarationId.
#[inline]
pub fn as_borrowed(&self) -> PropertyDeclarationId {
match self {
OwnedPropertyDeclarationId::Longhand(id) => PropertyDeclarationId::Longhand(*id),
OwnedPropertyDeclarationId::Custom(name) => PropertyDeclarationId::Custom(name),
Self::Longhand(id) => PropertyDeclarationId::Longhand(*id),
Self::Custom(name) => PropertyDeclarationId::Custom(name),
}
}
/// Returns whether this property is transitionable.
#[inline]
pub fn is_transitionable(&self) -> bool {
match self {
Self::Longhand(longhand) => NonCustomPropertyId::from(*longhand).is_transitionable(),
// TODO(bug 1846516): Implement this for custom properties.
Self::Custom(_) => false,
}
}
/// Convert an `AnimatedPropertyID` into an `OwnedPropertyDeclarationId`.
#[cfg(feature = "gecko")]
#[inline]
pub fn from_gecko_animated_property_id(property: &AnimatedPropertyID) -> Result<Self, ()> {
if property.mID == nsCSSPropertyID::eCSSPropertyExtra_variable {
if property.mCustomName.mRawPtr.is_null() {
Err(())
} else {
Ok(Self::Custom(unsafe {
Atom::from_raw(property.mCustomName.mRawPtr)
}))
}
} else if let Ok(longhand) = LonghandId::from_nscsspropertyid(property.mID) {
Ok(Self::Longhand(longhand))
} else {
Err(())
}
}
}
@ -60,7 +101,7 @@ impl<'a> ToCss for PropertyDeclarationId<'a> {
{
match *self {
PropertyDeclarationId::Longhand(id) => dest.write_str(id.name()),
PropertyDeclarationId::Custom(ref name) => {
PropertyDeclarationId::Custom(name) => {
dest.write_str("--")?;
serialize_atom_name(name, dest)
},
@ -156,6 +197,16 @@ impl<'a> PropertyDeclarationId<'a> {
}
}
/// Returns whether this property is animatable in a discrete way.
#[inline]
pub fn is_discrete_animatable(&self) -> bool {
match self {
Self::Longhand(longhand) => longhand.is_discrete_animatable(),
// TODO(bug 1846516): Implement this for custom properties.
Self::Custom(_) => false,
}
}
/// Converts from a to an adequate nsCSSPropertyID, returning
/// eCSSPropertyExtra_variable for custom properties.
#[cfg(feature = "gecko")]

View File

@ -309,6 +309,7 @@ renaming_overrides_prefixing = true
"RefPtr" = "RefPtr"
"nsCSSPropertyID" = "nsCSSPropertyID"
"nsCSSPropertyIDSet" = "nsCSSPropertyIDSet"
"AnimatedPropertyID" = "AnimatedPropertyID"
"nsCSSValueSharedList" = "nsCSSValueSharedList"
"AnimationPropertySegment" = "AnimationPropertySegment"
"RawServoAnimationValueTable" = "RawServoAnimationValueTable"

View File

@ -620,7 +620,7 @@ pub extern "C" fn Servo_ComposeAnimationSegment(
pub extern "C" fn Servo_AnimationCompose(
value_map: &mut AnimationValueMap,
base_values: &structs::RawServoAnimationValueTable,
css_property: nsCSSPropertyID,
css_property: &structs::AnimatedPropertyID,
segment: &structs::AnimationPropertySegment,
last_segment: &structs::AnimationPropertySegment,
computed_timing: &structs::ComputedTiming,
@ -630,13 +630,10 @@ pub extern "C" fn Servo_AnimationCompose(
use style::gecko_bindings::bindings::Gecko_GetPositionInSegment;
use style::gecko_bindings::bindings::Gecko_GetProgressFromComputedTiming;
// TODO(bug 1846516): Caller should be able to pass custom properties.
let property = OwnedPropertyDeclarationId::Longhand(
match LonghandId::from_nscsspropertyid(css_property) {
Some(longhand) if longhand.is_animatable() => longhand,
_ => return,
},
);
let property = match OwnedPropertyDeclarationId::from_gecko_animated_property_id(css_property) {
Some(property) if property.is_animatable() => property,
_ => return,
};
// We will need an underlying value if either of the endpoints is null...
let need_underlying_value = segment.mFromValue.mServo.mRawPtr.is_null() ||
@ -699,10 +696,21 @@ macro_rules! get_property_id_from_nscsspropertyid {
}};
}
macro_rules! get_property_id_from_animatedpropertyid {
($property_id: ident, $ret: expr) => {{
match PropertyId::from_gecko_animated_property_id($property_id) {
Ok(property_id) => property_id,
Err(()) => {
return $ret;
},
}
}};
}
#[no_mangle]
pub extern "C" fn Servo_AnimationValue_Serialize(
value: &AnimationValue,
property: nsCSSPropertyID,
property: &structs::AnimatedPropertyID,
raw_data: &PerDocumentStyleData,
buffer: &mut nsACString,
) {
@ -710,7 +718,7 @@ pub extern "C" fn Servo_AnimationValue_Serialize(
let data = raw_data.borrow();
let rv = PropertyDeclarationBlock::with_one(uncomputed_value, Importance::Normal)
.single_value_to_css(
&get_property_id_from_nscsspropertyid!(property, ()),
&get_property_id_from_animatedpropertyid!(property, ()),
buffer,
None,
None, /* No extra custom properties */
@ -1129,14 +1137,12 @@ pub unsafe extern "C" fn Servo_AnimationValueMap_Drop(value_map: *mut AnimationV
#[no_mangle]
pub extern "C" fn Servo_AnimationValueMap_GetValue(
value_map: &AnimationValueMap,
property_id: nsCSSPropertyID,
property_id: &structs::AnimatedPropertyID,
) -> Strong<AnimationValue> {
// TODO(bug 1846516): Caller should be able to pass custom properties.
let property =
OwnedPropertyDeclarationId::Longhand(match LonghandId::from_nscsspropertyid(property_id) {
Some(longhand) => longhand,
Err(()) => return Strong::null(),
});
let property = match OwnedPropertyDeclarationId::from_gecko_animated_property_id(property_id) {
Some(property) => property,
None => return Strong::null(),
};
value_map
.get(&property)
.map_or(Strong::null(), |value| Arc::new(value.clone()).into())
@ -1200,21 +1206,20 @@ pub struct ShouldTransitionResult {
pub extern "C" fn Servo_ComputedValues_ShouldTransition(
old: &ComputedValues,
new: &ComputedValues,
prop: nsCSSPropertyID,
prop: &structs::AnimatedPropertyID,
old_transition_value: Option<&AnimationValue>,
start: &mut structs::RefPtr<AnimationValue>,
end: &mut structs::RefPtr<AnimationValue>,
) -> ShouldTransitionResult {
// TODO(bug 1846516): Caller should be able to pass custom properties.
let prop = PropertyDeclarationId::Longhand({
let Some(prop) = LonghandId::from_nscsspropertyid(prop) else {
return Default::default();
};
if prop.is_discrete_animatable() && prop != LonghandId::Visibility {
return Default::default();
}
prop
});
let Some(prop) = OwnedPropertyDeclarationId::from_gecko_animated_property_id(prop) else {
return Default::default();
};
let prop = prop.as_borrowed();
if prop.is_discrete_animatable() &&
prop != PropertyDeclarationId::Longhand(LonghandId::Visibility)
{
return Default::default();
}
let Some(new_value) = AnimationValue::from_computed_values(prop, new) else {
return Default::default();
@ -1248,19 +1253,18 @@ pub extern "C" fn Servo_ComputedValues_ShouldTransition(
#[no_mangle]
pub extern "C" fn Servo_ComputedValues_TransitionValueMatches(
style: &ComputedValues,
prop: nsCSSPropertyID,
prop: &structs::AnimatedPropertyID,
transition_value: &AnimationValue,
) -> bool {
// TODO(bug 1846516): Caller should be able to pass custom properties.
let prop = PropertyDeclarationId::Longhand({
let Some(prop) = LonghandId::from_nscsspropertyid(prop) else {
return false;
};
if prop.is_discrete_animatable() && prop != LonghandId::Visibility {
return false;
}
prop
});
let Some(prop) = OwnedPropertyDeclarationId::from_gecko_animated_property_id(prop) else {
return false;
};
let prop = prop.as_borrowed();
if prop.is_discrete_animatable() &&
prop != PropertyDeclarationId::Longhand(LonghandId::Visibility)
{
return false;
}
let Some(value) = AnimationValue::from_computed_values(prop, style) else {
return false;
};
@ -1270,15 +1274,13 @@ pub extern "C" fn Servo_ComputedValues_TransitionValueMatches(
#[no_mangle]
pub extern "C" fn Servo_ComputedValues_ExtractAnimationValue(
computed_values: &ComputedValues,
property_id: nsCSSPropertyID,
property_id: &structs::AnimatedPropertyID,
) -> Strong<AnimationValue> {
// TODO(bug 1846516): Caller should be able to pass custom properties.
let property =
PropertyDeclarationId::Longhand(match LonghandId::from_nscsspropertyid(property_id) {
Ok(longhand) => longhand,
None => return Strong::null(),
});
match AnimationValue::from_computed_values(property, &computed_values) {
let property = match OwnedPropertyDeclarationId::from_gecko_animated_property_id(property_id) {
Some(property) => property,
None => return Strong::null(),
};
match AnimationValue::from_computed_values(property.as_borrowed(), &computed_values) {
Some(v) => Arc::new(v).into(),
None => Strong::null(),
}
@ -1416,13 +1418,15 @@ pub unsafe extern "C" fn Servo_Property_GetCSSValuesForProperty(
}
#[no_mangle]
pub extern "C" fn Servo_Property_IsAnimatable(prop: nsCSSPropertyID) -> bool {
NonCustomPropertyId::from_nscsspropertyid(prop).map_or(false, |p| p.is_animatable())
pub extern "C" fn Servo_Property_IsAnimatable(prop: &structs::AnimatedPropertyID) -> bool {
OwnedPropertyDeclarationId::from_gecko_animated_property_id(prop)
.map_or(false, |p| p.is_animatable())
}
#[no_mangle]
pub extern "C" fn Servo_Property_IsTransitionable(prop: nsCSSPropertyID) -> bool {
NonCustomPropertyId::from_nscsspropertyid(prop).map_or(false, |p| p.is_transitionable())
pub extern "C" fn Servo_Property_IsTransitionable(prop: &structs::AnimatedPropertyID) -> bool {
OwnedPropertyDeclarationId::from_gecko_animated_property_id(prop)
.map_or(false, |p| p.is_transitionable())
}
#[no_mangle]
@ -4497,7 +4501,7 @@ fn parse_property_into(
#[no_mangle]
pub unsafe extern "C" fn Servo_ParseProperty(
property: nsCSSPropertyID,
property: &structs::AnimatedPropertyID,
value: &nsACString,
data: *mut URLExtraData,
parsing_mode: ParsingMode,
@ -4505,7 +4509,7 @@ pub unsafe extern "C" fn Servo_ParseProperty(
loader: *mut Loader,
rule_type: CssRuleType,
) -> Strong<LockedDeclarationBlock> {
let id = get_property_id_from_nscsspropertyid!(property, Strong::null());
let id = get_property_id_from_animatedpropertyid!(property, Strong::null());
let mut declarations = SourcePropertyDeclaration::default();
let reporter = ErrorReporter::new(ptr::null_mut(), loader, data);
let data = UrlExtraData::from_ptr_ref(&data);
@ -4715,13 +4719,13 @@ pub extern "C" fn Servo_DeclarationBlock_GetCssText(
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_SerializeOneValue(
decls: &LockedDeclarationBlock,
property_id: nsCSSPropertyID,
property_id: &structs::AnimatedPropertyID,
buffer: &mut nsACString,
computed_values: Option<&ComputedValues>,
custom_properties: Option<&LockedDeclarationBlock>,
data: &PerDocumentStyleData,
) {
let property_id = get_property_id_from_nscsspropertyid!(property_id, ());
let property_id = get_property_id_from_animatedpropertyid!(property_id, ());
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
@ -6071,8 +6075,8 @@ pub extern "C" fn Servo_ReparentStyle(
#[cfg(feature = "gecko_debug")]
fn simulate_compute_values_failure(property: &PropertyValuePair) -> bool {
let p = property.mProperty;
let id = get_property_id_from_nscsspropertyid!(p, false);
let p = &property.mProperty;
let id = get_property_id_from_animatedpropertyid!(p, false);
id.as_shorthand().is_ok() && property.mSimulateComputeValuesFailure
}
@ -6125,8 +6129,8 @@ impl<'a> PrioritizedPropertyIter<'a> {
.iter()
.enumerate()
.map(|(index, pair)| {
let property = PropertyId::from_nscsspropertyid(pair.mProperty)
.unwrap_or(PropertyId::NonCustom(ShorthandId::All.into()));
let property = PropertyId::from_gecko_animated_property_id(&pair.mProperty)
.unwrap_or(PropertyId::Shorthand(ShorthandId::All));
PropertyAndIndex { property, index }
})
.collect();
@ -6199,7 +6203,7 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(
let mut custom_properties = ComputedCustomProperties::default();
for property in keyframe.mPropertyValues.iter() {
// Find the block for custom properties first.
if property.mProperty == nsCSSPropertyID::eCSSPropertyExtra_variable {
if property.mProperty.mID == nsCSSPropertyID::eCSSPropertyExtra_variable {
raw_custom_properties_block = unsafe { &*property.mServoDeclarationBlock.mRawPtr };
let guard = raw_custom_properties_block.read_with(&guard);
custom_properties = guard.cascade_custom_properties(&data.stylist, &context);
@ -6244,7 +6248,10 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(
ptr::write(
&mut animation_values[property_index],
structs::PropertyStyleAnimationValuePair {
mProperty: property.to_nscsspropertyid(),
mProperty: structs::AnimatedPropertyID {
mID: property.to_nscsspropertyid(),
mCustomName: structs::RefPtr::null(),
},
mValue: structs::AnimationValue {
mServo: value.map_or(structs::RefPtr::null(), |v| {
structs::RefPtr::from_arc(Arc::new(v))
@ -6257,7 +6264,7 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(
};
if property.mServoDeclarationBlock.mRawPtr.is_null() {
let property = LonghandId::from_nscsspropertyid(property.mProperty);
let property = LonghandId::from_nscsspropertyid(property.mProperty.mID);
if let Some(prop) = property {
maybe_append_animation_value(prop, None);
}
@ -6330,8 +6337,13 @@ pub extern "C" fn Servo_GetAnimationValues(
}
#[no_mangle]
pub extern "C" fn Servo_AnimationValue_GetPropertyId(value: &AnimationValue) -> nsCSSPropertyID {
value.id().to_nscsspropertyid()
pub extern "C" fn Servo_AnimationValue_GetPropertyId(
value: &AnimationValue,
property_id: &mut structs::AnimatedPropertyID,
) {
// TODO(bug 1846516): Support custom properties.
property_id.mID = value.id().to_nscsspropertyid();
property_id.mCustomName = structs::RefPtr::null();
}
#[no_mangle]