Bug 1947961 - Implement basic "update pseudo-element styles" steps. r=view-transitions-reviewers,boris
Pretty bare bones (some properties missing), but this allows the transition pseudo-elements to be in the right place. We need to implement live capturing / integrate nical's work to display the "new" image properly, but we'll get to that. Meanwhile this should be uncontroversial. Differential Revision: https://phabricator.services.mozilla.com/D238005
This commit is contained in:
@@ -4630,66 +4630,7 @@ static Element* SearchViewTransitionPseudo(const Element* aElement,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Element* root = vt->GetRoot();
|
return vt->FindPseudo(aRequest);
|
||||||
if (!root) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aRequest.mType == PseudoStyleType::viewTransition) {
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Linear search ::view-transition-group by |aRequest.mIdentifier|.
|
|
||||||
// Note: perhaps we can add a hashtable to improve the performance if it's
|
|
||||||
// common that there are a lot of view-transition-names.
|
|
||||||
Element* group = root->GetFirstElementChild();
|
|
||||||
for (; group; group = group->GetNextElementSibling()) {
|
|
||||||
MOZ_ASSERT(group->HasName(),
|
|
||||||
"The generated ::view-transition-group() should have a name");
|
|
||||||
nsAtom* name = group->GetParsedAttr(nsGkAtoms::name)->GetAtomValue();
|
|
||||||
if (name == aRequest.mIdentifier) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// No one specifies view-transition-name or we mismatch all names.
|
|
||||||
if (!group) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aRequest.mType == PseudoStyleType::viewTransitionGroup) {
|
|
||||||
return group;
|
|
||||||
}
|
|
||||||
|
|
||||||
Element* imagePair = group->GetFirstElementChild();
|
|
||||||
MOZ_ASSERT(imagePair, "::view-transition-image-pair() should exist always");
|
|
||||||
if (aRequest.mType == PseudoStyleType::viewTransitionImagePair) {
|
|
||||||
return imagePair;
|
|
||||||
}
|
|
||||||
|
|
||||||
Element* child = imagePair->GetFirstElementChild();
|
|
||||||
// Neither ::view-transition-old() nor ::view-transition-new() doesn't exist.
|
|
||||||
if (!child) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the first element matches our request.
|
|
||||||
const PseudoStyleType type = child->GetPseudoElementType();
|
|
||||||
if (type == aRequest.mType) {
|
|
||||||
return child;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since the second child is either ::view-transition-new() or nullptr, so we
|
|
||||||
// can reject viewTransitionOld request here.
|
|
||||||
if (aRequest.mType == PseudoStyleType::viewTransitionOld) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
child = child->GetNextElementSibling();
|
|
||||||
MOZ_ASSERT(aRequest.mType == PseudoStyleType::viewTransitionNew);
|
|
||||||
MOZ_ASSERT(!child || !child->GetNextElementSibling(),
|
|
||||||
"No more psuedo elements in this subtree");
|
|
||||||
return child;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Element* Element::GetPseudoElement(const PseudoStyleRequest& aRequest) const {
|
Element* Element::GetPseudoElement(const PseudoStyleRequest& aRequest) const {
|
||||||
|
|||||||
@@ -350,15 +350,31 @@ static already_AddRefed<Element> MakePseudo(Document& aDoc,
|
|||||||
return el.forget();
|
return el.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SetProp(StyleLockedDeclarationBlock* aDecls, Document* aDoc,
|
static bool SetProp(StyleLockedDeclarationBlock* aDecls, Document* aDoc,
|
||||||
const nsACString& aProp, const nsACString& aValue) {
|
nsCSSPropertyID aProp, const nsACString& aValue) {
|
||||||
Servo_DeclarationBlock_SetProperty(
|
return Servo_DeclarationBlock_SetPropertyById(
|
||||||
aDecls, &aProp, &aValue,
|
aDecls, aProp, &aValue,
|
||||||
/* is_important = */ false, aDoc->DefaultStyleAttrURLData(),
|
/* is_important = */ false, aDoc->DefaultStyleAttrURLData(),
|
||||||
StyleParsingMode::DEFAULT, eCompatibility_FullStandards,
|
StyleParsingMode::DEFAULT, eCompatibility_FullStandards,
|
||||||
aDoc->CSSLoader(), StyleCssRuleType::Style, {});
|
aDoc->CSSLoader(), StyleCssRuleType::Style, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool SetProp(StyleLockedDeclarationBlock* aDecls, Document*,
|
||||||
|
nsCSSPropertyID aProp, float aLength, nsCSSUnit aUnit) {
|
||||||
|
return Servo_DeclarationBlock_SetLengthValue(aDecls, aProp, aLength, aUnit);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool SetProp(StyleLockedDeclarationBlock* aDecls, Document*,
|
||||||
|
nsCSSPropertyID aProp, const CSSToCSSMatrix4x4Flagged& aM) {
|
||||||
|
MOZ_ASSERT(aProp == eCSSProperty_transform);
|
||||||
|
AutoTArray<StyleTransformOperation, 1> ops;
|
||||||
|
ops.AppendElement(
|
||||||
|
StyleTransformOperation::Matrix3D(StyleGenericMatrix3D<StyleNumber>{
|
||||||
|
aM._11, aM._12, aM._13, aM._14, aM._21, aM._22, aM._23, aM._24,
|
||||||
|
aM._31, aM._32, aM._33, aM._34, aM._41, aM._42, aM._43, aM._44}));
|
||||||
|
return Servo_DeclarationBlock_SetTransform(aDecls, aProp, &ops);
|
||||||
|
}
|
||||||
|
|
||||||
static StyleLockedDeclarationBlock* EnsureRule(
|
static StyleLockedDeclarationBlock* EnsureRule(
|
||||||
RefPtr<StyleLockedDeclarationBlock>& aRule) {
|
RefPtr<StyleLockedDeclarationBlock>& aRule) {
|
||||||
if (!aRule) {
|
if (!aRule) {
|
||||||
@@ -426,7 +442,7 @@ void ViewTransition::SetupTransitionPseudoElements() {
|
|||||||
MOZ_ASSERT(capturedElement.mNewElement);
|
MOZ_ASSERT(capturedElement.mNewElement);
|
||||||
// Set capturedElement's image animation name rule to a new ...
|
// Set capturedElement's image animation name rule to a new ...
|
||||||
auto* rule = EnsureRule(capturedElement.mNewRule);
|
auto* rule = EnsureRule(capturedElement.mNewRule);
|
||||||
SetProp(rule, mDocument, "animation-name"_ns,
|
SetProp(rule, mDocument, eCSSProperty_animation_name,
|
||||||
"-ua-view-transition-fade-in"_ns);
|
"-ua-view-transition-fade-in"_ns);
|
||||||
}
|
}
|
||||||
// If capturedElement's new element is not null, then:
|
// If capturedElement's new element is not null, then:
|
||||||
@@ -444,9 +460,21 @@ void ViewTransition::SetupTransitionPseudoElements() {
|
|||||||
// representing the following CSS, and append it to document’s dynamic
|
// representing the following CSS, and append it to document’s dynamic
|
||||||
// view transition style sheet:
|
// view transition style sheet:
|
||||||
MOZ_ASSERT(capturedElement.mOldState.mTriedImage);
|
MOZ_ASSERT(capturedElement.mOldState.mTriedImage);
|
||||||
auto* rule = EnsureRule(capturedElement.mOldRule);
|
SetProp(EnsureRule(capturedElement.mOldRule), mDocument,
|
||||||
SetProp(rule, mDocument, "animation-name"_ns,
|
eCSSProperty_animation_name, "-ua-view-transition-fade-out"_ns);
|
||||||
"-ua-view-transition-fade-out"_ns);
|
|
||||||
|
// Moved around from "update pseudo-element styles" because it's a one
|
||||||
|
// time operation.
|
||||||
|
auto* rule = EnsureRule(capturedElement.mGroupRule);
|
||||||
|
auto oldRect = CSSPixel::FromAppUnits(capturedElement.mOldState.mSize);
|
||||||
|
SetProp(rule, mDocument, eCSSProperty_width, oldRect.width,
|
||||||
|
eCSSUnit_Pixel);
|
||||||
|
SetProp(rule, mDocument, eCSSProperty_height, oldRect.height,
|
||||||
|
eCSSUnit_Pixel);
|
||||||
|
SetProp(rule, mDocument, eCSSProperty_transform,
|
||||||
|
capturedElement.mOldState.mTransform);
|
||||||
|
// TODO: writing-mode, direction, text-orientation, mix-blend-mode,
|
||||||
|
// backdrop-filter, color-scheme.
|
||||||
}
|
}
|
||||||
// If both of capturedElement's old image and new element are not null,
|
// If both of capturedElement's old image and new element are not null,
|
||||||
// then:
|
// then:
|
||||||
@@ -458,18 +486,20 @@ void ViewTransition::SetupTransitionPseudoElements() {
|
|||||||
// TODO(emilio): Group keyframes.
|
// TODO(emilio): Group keyframes.
|
||||||
// Set capturedElement's group animation name rule to ...
|
// Set capturedElement's group animation name rule to ...
|
||||||
SetProp(EnsureRule(capturedElement.mGroupRule), mDocument,
|
SetProp(EnsureRule(capturedElement.mGroupRule), mDocument,
|
||||||
"animation-name"_ns, dynamicAnimationName);
|
eCSSProperty_animation_name, dynamicAnimationName);
|
||||||
|
|
||||||
// Set capturedElement's image pair isolation rule to ...
|
// Set capturedElement's image pair isolation rule to ...
|
||||||
SetProp(EnsureRule(capturedElement.mImagePairRule), mDocument,
|
SetProp(EnsureRule(capturedElement.mImagePairRule), mDocument,
|
||||||
"isolation"_ns, "isolate"_ns);
|
eCSSProperty_isolation, "isolate"_ns);
|
||||||
|
|
||||||
// Set capturedElement's image animation name rule to ...
|
// Set capturedElement's image animation name rule to ...
|
||||||
SetProp(
|
SetProp(
|
||||||
EnsureRule(capturedElement.mOldRule), mDocument, "animation-name"_ns,
|
EnsureRule(capturedElement.mOldRule), mDocument,
|
||||||
|
eCSSProperty_animation_name,
|
||||||
"-ua-view-transition-fade-out, -ua-mix-blend-mode-plus-lighter"_ns);
|
"-ua-view-transition-fade-out, -ua-mix-blend-mode-plus-lighter"_ns);
|
||||||
SetProp(
|
SetProp(
|
||||||
EnsureRule(capturedElement.mNewRule), mDocument, "animation-name"_ns,
|
EnsureRule(capturedElement.mNewRule), mDocument,
|
||||||
|
eCSSProperty_animation_name,
|
||||||
"-ua-view-transition-fade-in, -ua-mix-blend-mode-plus-lighter"_ns);
|
"-ua-view-transition-fade-in, -ua-mix-blend-mode-plus-lighter"_ns);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -484,6 +514,60 @@ void ViewTransition::SetupTransitionPseudoElements() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://drafts.csswg.org/css-view-transitions-1/#style-transition-pseudo-elements-algorithm
|
||||||
|
bool ViewTransition::UpdatePseudoElementStyles(bool aNeedsInvalidation) {
|
||||||
|
// 1. For each transitionName -> capturedElement of transition's "named
|
||||||
|
// elements".
|
||||||
|
for (auto& entry : mNamedElements) {
|
||||||
|
nsAtom* transitionName = entry.GetKey();
|
||||||
|
CapturedElement& capturedElement = *entry.GetData();
|
||||||
|
// If capturedElement's new element is null, then:
|
||||||
|
// We already did this in SetupTransitionPseudoElements().
|
||||||
|
if (!capturedElement.mNewElement) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Otherwise.
|
||||||
|
// Return failure if any of the following conditions is true:
|
||||||
|
// * capturedElement's new element has a flat tree ancestor that skips its
|
||||||
|
// contents.
|
||||||
|
// * capturedElement's new element is not rendered.
|
||||||
|
// * capturedElement has more than one box fragment.
|
||||||
|
nsIFrame* frame = capturedElement.mNewElement->GetPrimaryFrame();
|
||||||
|
if (!frame || frame->IsHiddenByContentVisibilityOnAnyAncestor() ||
|
||||||
|
frame->GetPrevContinuation() || frame->GetNextContinuation()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto* rule = EnsureRule(capturedElement.mGroupRule);
|
||||||
|
// Let newRect be snapshot containing block if capturedElement is the
|
||||||
|
// document element, otherwise, capturedElement’s border box.
|
||||||
|
auto newRect = frame->Style()->IsRootElementStyle()
|
||||||
|
? SnapshotContainingBlockRect()
|
||||||
|
: frame->GetRect();
|
||||||
|
auto size = CSSPixel::FromAppUnits(newRect);
|
||||||
|
// NOTE(emilio): Intentionally not short-circuiting. Int cast is needed to
|
||||||
|
// silence warning.
|
||||||
|
bool changed = int(SetProp(rule, mDocument, eCSSProperty_width, size.width,
|
||||||
|
eCSSUnit_Pixel)) |
|
||||||
|
SetProp(rule, mDocument, eCSSProperty_height, size.height,
|
||||||
|
eCSSUnit_Pixel) |
|
||||||
|
SetProp(rule, mDocument, eCSSProperty_transform,
|
||||||
|
EffectiveTransform(frame));
|
||||||
|
// TODO: writing-mode, direction, text-orientation, mix-blend-mode,
|
||||||
|
// backdrop-filter, color-scheme.
|
||||||
|
if (changed && aNeedsInvalidation) {
|
||||||
|
auto* pseudo = FindPseudo(PseudoStyleRequest(
|
||||||
|
PseudoStyleType::viewTransitionGroup, transitionName));
|
||||||
|
MOZ_ASSERT(pseudo);
|
||||||
|
// TODO(emilio): Maybe we need something more than recascade? But I don't
|
||||||
|
// see how off-hand.
|
||||||
|
nsLayoutUtils::PostRestyleEvent(pseudo, RestyleHint::RECASCADE_SELF,
|
||||||
|
nsChangeHint(0));
|
||||||
|
}
|
||||||
|
// 5. TODO(emilio): Live capturing (probably nothing to do here)
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-view-transitions-1/#activate-view-transition
|
// https://drafts.csswg.org/css-view-transitions-1/#activate-view-transition
|
||||||
void ViewTransition::Activate() {
|
void ViewTransition::Activate() {
|
||||||
// Step 1: If transition's phase is "done", then return.
|
// Step 1: If transition's phase is "done", then return.
|
||||||
@@ -513,7 +597,15 @@ void ViewTransition::Activate() {
|
|||||||
// Step 6: Setup transition pseudo-elements for transition.
|
// Step 6: Setup transition pseudo-elements for transition.
|
||||||
SetupTransitionPseudoElements();
|
SetupTransitionPseudoElements();
|
||||||
|
|
||||||
// TODO(emilio): Step 7.
|
// Step 7: Update pseudo-element styles for transition.
|
||||||
|
// We don't need to invalidate the pseudo-element styles since we just
|
||||||
|
// generated them.
|
||||||
|
if (!UpdatePseudoElementStyles(/* aNeedsInvalidation = */ false)) {
|
||||||
|
// If failure is returned, then skip the view transition for transition
|
||||||
|
// with an "InvalidStateError" DOMException in transition's relevant Realm,
|
||||||
|
// and return.
|
||||||
|
return SkipTransition(SkipTransitionReason::PseudoUpdateFailure);
|
||||||
|
}
|
||||||
|
|
||||||
// Step 8: Set transition's phase to "animating".
|
// Step 8: Set transition's phase to "animating".
|
||||||
mPhase = Phase::Animating;
|
mPhase = Phase::Animating;
|
||||||
@@ -551,6 +643,69 @@ nsRect ViewTransition::SnapshotContainingBlockRect() const {
|
|||||||
return pc ? pc->GetVisibleArea() : nsRect();
|
return pc ? pc->GetVisibleArea() : nsRect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Element* ViewTransition::FindPseudo(const PseudoStyleRequest& aRequest) const {
|
||||||
|
Element* root = GetRoot();
|
||||||
|
if (!root) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aRequest.mType == PseudoStyleType::viewTransition) {
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Linear search ::view-transition-group by |aRequest.mIdentifier|.
|
||||||
|
// Note: perhaps we can add a hashtable to improve the performance if it's
|
||||||
|
// common that there are a lot of view-transition-names.
|
||||||
|
Element* group = root->GetFirstElementChild();
|
||||||
|
for (; group; group = group->GetNextElementSibling()) {
|
||||||
|
MOZ_ASSERT(group->HasName(),
|
||||||
|
"The generated ::view-transition-group() should have a name");
|
||||||
|
nsAtom* name = group->GetParsedAttr(nsGkAtoms::name)->GetAtomValue();
|
||||||
|
if (name == aRequest.mIdentifier) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No one specifies view-transition-name or we mismatch all names.
|
||||||
|
if (!group) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aRequest.mType == PseudoStyleType::viewTransitionGroup) {
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
Element* imagePair = group->GetFirstElementChild();
|
||||||
|
MOZ_ASSERT(imagePair, "::view-transition-image-pair() should exist always");
|
||||||
|
if (aRequest.mType == PseudoStyleType::viewTransitionImagePair) {
|
||||||
|
return imagePair;
|
||||||
|
}
|
||||||
|
|
||||||
|
Element* child = imagePair->GetFirstElementChild();
|
||||||
|
// Neither ::view-transition-old() nor ::view-transition-new() doesn't exist.
|
||||||
|
if (!child) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the first element matches our request.
|
||||||
|
const PseudoStyleType type = child->GetPseudoElementType();
|
||||||
|
if (type == aRequest.mType) {
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since the second child is either ::view-transition-new() or nullptr, so we
|
||||||
|
// can reject viewTransitionOld request here.
|
||||||
|
if (aRequest.mType == PseudoStyleType::viewTransitionOld) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
child = child->GetNextElementSibling();
|
||||||
|
MOZ_ASSERT(aRequest.mType == PseudoStyleType::viewTransitionNew);
|
||||||
|
MOZ_ASSERT(!child || !child->GetNextElementSibling(),
|
||||||
|
"No more psuedo elements in this subtree");
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
const StyleLockedDeclarationBlock* ViewTransition::GetDynamicRuleFor(
|
const StyleLockedDeclarationBlock* ViewTransition::GetDynamicRuleFor(
|
||||||
const Element& aElement) const {
|
const Element& aElement) const {
|
||||||
if (!aElement.HasName()) {
|
if (!aElement.HasName()) {
|
||||||
@@ -757,11 +912,20 @@ void ViewTransition::HandleFrame() {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// If the view tranimation is still animating after HandleFrame(),
|
// TODO(emilio): Step 5 (check CB resize)
|
||||||
// we have to periodically perform operations to check if it is still
|
|
||||||
// animating in the following ticks.
|
// Step 6: Update pseudo-element styles for transition.
|
||||||
|
if (!UpdatePseudoElementStyles(/* aNeedsInvalidation= */ true)) {
|
||||||
|
// If failure is returned, then skip the view transition for transition
|
||||||
|
// with an "InvalidStateError" DOMException in transition's relevant Realm,
|
||||||
|
// and return.
|
||||||
|
return SkipTransition(SkipTransitionReason::PseudoUpdateFailure);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the view transition is still animating after HandleFrame(), we have to
|
||||||
|
// periodically perform operations to check if it is still animating in the
|
||||||
|
// following ticks.
|
||||||
mDocument->EnsureViewTransitionOperationsHappen();
|
mDocument->EnsureViewTransitionOperationsHappen();
|
||||||
// TODO(emilio): Steps 5-6 (check CB size, update pseudo styles).
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool CheckForActiveAnimationsForEachPseudo(
|
static bool CheckForActiveAnimationsForEachPseudo(
|
||||||
@@ -978,6 +1142,10 @@ void ViewTransition::SkipTransition(
|
|||||||
readyPromise->MaybeRejectWithInvalidStateError(
|
readyPromise->MaybeRejectWithInvalidStateError(
|
||||||
"Skipped view transition due to viewport resize");
|
"Skipped view transition due to viewport resize");
|
||||||
break;
|
break;
|
||||||
|
case SkipTransitionReason::PseudoUpdateFailure:
|
||||||
|
readyPromise->MaybeRejectWithInvalidStateError(
|
||||||
|
"Skipped view transition due to hidden new element");
|
||||||
|
break;
|
||||||
case SkipTransitionReason::UpdateCallbackRejected:
|
case SkipTransitionReason::UpdateCallbackRejected:
|
||||||
readyPromise->MaybeReject(aUpdateCallbackRejectReason);
|
readyPromise->MaybeReject(aUpdateCallbackRejectReason);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ class nsITimer;
|
|||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
class ErrorResult;
|
class ErrorResult;
|
||||||
|
struct PseudoStyleRequest;
|
||||||
struct StyleLockedDeclarationBlock;
|
struct StyleLockedDeclarationBlock;
|
||||||
|
|
||||||
namespace gfx {
|
namespace gfx {
|
||||||
@@ -38,6 +39,7 @@ enum class SkipTransitionReason : uint8_t {
|
|||||||
UpdateCallbackRejected,
|
UpdateCallbackRejected,
|
||||||
DuplicateTransitionNameCapturingOldState,
|
DuplicateTransitionNameCapturingOldState,
|
||||||
DuplicateTransitionNameCapturingNewState,
|
DuplicateTransitionNameCapturingNewState,
|
||||||
|
PseudoUpdateFailure,
|
||||||
Resize,
|
Resize,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -68,6 +70,8 @@ class ViewTransition final : public nsISupports, public nsWrapperCache {
|
|||||||
Element* GetRoot() const { return mViewTransitionRoot; }
|
Element* GetRoot() const { return mViewTransitionRoot; }
|
||||||
gfx::DataSourceSurface* GetOldSurface(nsAtom* aName) const;
|
gfx::DataSourceSurface* GetOldSurface(nsAtom* aName) const;
|
||||||
|
|
||||||
|
Element* FindPseudo(const PseudoStyleRequest&) const;
|
||||||
|
|
||||||
const StyleLockedDeclarationBlock* GetDynamicRuleFor(const Element&) const;
|
const StyleLockedDeclarationBlock* GetDynamicRuleFor(const Element&) const;
|
||||||
|
|
||||||
nsIGlobalObject* GetParentObject() const;
|
nsIGlobalObject* GetParentObject() const;
|
||||||
@@ -87,6 +91,7 @@ class ViewTransition final : public nsISupports, public nsWrapperCache {
|
|||||||
[[nodiscard]] Maybe<SkipTransitionReason> CaptureOldState();
|
[[nodiscard]] Maybe<SkipTransitionReason> CaptureOldState();
|
||||||
[[nodiscard]] Maybe<SkipTransitionReason> CaptureNewState();
|
[[nodiscard]] Maybe<SkipTransitionReason> CaptureNewState();
|
||||||
void SetupTransitionPseudoElements();
|
void SetupTransitionPseudoElements();
|
||||||
|
[[nodiscard]] bool UpdatePseudoElementStyles(bool aNeedsInvalidation);
|
||||||
void ClearNamedElements();
|
void ClearNamedElements();
|
||||||
void HandleFrame();
|
void HandleFrame();
|
||||||
bool CheckForActiveAnimations() const;
|
bool CheckForActiveAnimations() const;
|
||||||
|
|||||||
@@ -172,6 +172,11 @@ trait ClosureHelper {
|
|||||||
fn invoke(&self, property_id: Option<NonCustomPropertyId>);
|
fn invoke(&self, property_id: Option<NonCustomPropertyId>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const NO_MUTATION_CLOSURE : DeclarationBlockMutationClosure = DeclarationBlockMutationClosure {
|
||||||
|
data: std::ptr::null_mut(),
|
||||||
|
function: None,
|
||||||
|
};
|
||||||
|
|
||||||
impl ClosureHelper for DeclarationBlockMutationClosure {
|
impl ClosureHelper for DeclarationBlockMutationClosure {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn invoke(&self, property_id: Option<NonCustomPropertyId>) {
|
fn invoke(&self, property_id: Option<NonCustomPropertyId>) {
|
||||||
@@ -5599,7 +5604,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetLengthValue(
|
|||||||
property: nsCSSPropertyID,
|
property: nsCSSPropertyID,
|
||||||
value: f32,
|
value: f32,
|
||||||
unit: structs::nsCSSUnit,
|
unit: structs::nsCSSUnit,
|
||||||
) {
|
) -> bool {
|
||||||
use style::properties::PropertyDeclaration;
|
use style::properties::PropertyDeclaration;
|
||||||
use style::values::generics::length::{LengthPercentageOrAuto, Size};
|
use style::values::generics::length::{LengthPercentageOrAuto, Size};
|
||||||
use style::values::generics::NonNegative;
|
use style::values::generics::NonNegative;
|
||||||
@@ -5660,7 +5665,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetLengthValue(
|
|||||||
_ => unreachable!("Unknown unit passed to SetLengthValue"),
|
_ => unreachable!("Unknown unit passed to SetLengthValue"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let prop = match_wrap_declared! { long,
|
let mut source_declarations = SourcePropertyDeclaration::with_one(match_wrap_declared! { long,
|
||||||
Width => Size::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
|
Width => Size::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
|
||||||
Height => Size::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
|
Height => Size::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
|
||||||
X => LengthPercentage::Length(nocalc),
|
X => LengthPercentage::Length(nocalc),
|
||||||
@@ -5671,10 +5676,14 @@ pub extern "C" fn Servo_DeclarationBlock_SetLengthValue(
|
|||||||
Rx => LengthPercentageOrAuto::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
|
Rx => LengthPercentageOrAuto::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
|
||||||
Ry => LengthPercentageOrAuto::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
|
Ry => LengthPercentageOrAuto::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
|
||||||
FontSize => FontSize::Length(LengthPercentage::Length(nocalc)),
|
FontSize => FontSize::Length(LengthPercentage::Length(nocalc)),
|
||||||
};
|
});
|
||||||
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
|
set_property_to_declarations(
|
||||||
decls.push(prop, Importance::Normal);
|
Some(long.into()),
|
||||||
})
|
declarations,
|
||||||
|
&mut source_declarations,
|
||||||
|
NO_MUTATION_CLOSURE,
|
||||||
|
Importance::Normal,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@@ -5682,7 +5691,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetTransform(
|
|||||||
declarations: &LockedDeclarationBlock,
|
declarations: &LockedDeclarationBlock,
|
||||||
property: nsCSSPropertyID,
|
property: nsCSSPropertyID,
|
||||||
ops: &nsTArray<computed::TransformOperation>,
|
ops: &nsTArray<computed::TransformOperation>,
|
||||||
) {
|
) -> bool {
|
||||||
use style::values::generics::transform::GenericTransform;
|
use style::values::generics::transform::GenericTransform;
|
||||||
use style::properties::PropertyDeclaration;
|
use style::properties::PropertyDeclaration;
|
||||||
let long = get_longhand_from_id!(property);
|
let long = get_longhand_from_id!(property);
|
||||||
@@ -5690,9 +5699,14 @@ pub extern "C" fn Servo_DeclarationBlock_SetTransform(
|
|||||||
let prop = match_wrap_declared! { long,
|
let prop = match_wrap_declared! { long,
|
||||||
Transform => v,
|
Transform => v,
|
||||||
};
|
};
|
||||||
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
|
let mut source_declarations = SourcePropertyDeclaration::with_one(prop);
|
||||||
decls.push(prop, Importance::Normal);
|
set_property_to_declarations(
|
||||||
})
|
Some(long.into()),
|
||||||
|
declarations,
|
||||||
|
&mut source_declarations,
|
||||||
|
NO_MUTATION_CLOSURE,
|
||||||
|
Importance::Normal,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
|||||||
Reference in New Issue
Block a user