Skip to content

Commit d9149b6

Browse files
committed
[CSS @starting-style] entry animation is only respected on first transition
rdar://163928932 https://bugs.webkit.org/show_bug.cgi?id=301510 Reviewed by Antti Koivisto. Fixed some issues with the interaction between CSS animations/transitions and anchor positioning: * The style to be saved when deferring updating/applying animations should also be the starting style, in addition to the previous render style. * Updating/applying animations should be deferred until a position option is chosen. * LayoutTests/imported/w3c/web-platform-tests/css/css-transitions/after-change-style-inherited-try-fallback-expected.txt: * Source/WebCore/style/StyleTreeResolver.cpp: (WebCore::Style::TreeResolver::createAnimatedElementUpdate): (WebCore::Style::TreeResolver::resolve): (WebCore::Style::TreeResolver::saveBeforeResolutionStyleForInterleaving): (WebCore::Style::TreeResolver::isTryingPositionOption const): * Source/WebCore/style/StyleTreeResolver.h: Canonical link: https://commits.webkit.org/305371@main
1 parent 5583c5d commit d9149b6

File tree

3 files changed

+29
-13
lines changed

3 files changed

+29
-13
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11

2-
FAIL Position fallback correctly applied to after-change style assert_equals: Transitioning from !important width to fallback width expected 250 but got 200
2+
FAIL Position fallback correctly applied to after-change style assert_equals: #inner halfway between black and lime expected "rgb(0, 128, 0)" but got "rgb(64, 64, 0)"
33

Source/WebCore/style/StyleTreeResolver.cpp

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,11 @@ ElementUpdate TreeResolver::createAnimatedElementUpdate(ResolvedStyle&& resolved
762762

763763
std::unique_ptr<RenderStyle> startingStyle;
764764

765+
// The style of the styleable is constantly in flux during anchor resolution and/or trying
766+
// position options. Hence we skip updating/applying animations until both processes are
767+
// complete and the style is stable.
768+
auto skipAnimationForAnchorPosition = hasUnresolvedAnchorPosition(styleable) || isTryingPositionOption(styleable);
769+
765770
auto* oldStyle = [&]() -> const RenderStyle* {
766771
if (auto* styleBefore = beforeResolutionStyle(element, styleable.pseudoElementIdentifier))
767772
return styleBefore;
@@ -775,16 +780,22 @@ ElementUpdate TreeResolver::createAnimatedElementUpdate(ResolvedStyle&& resolved
775780
return nullptr;
776781
}();
777782

783+
if (skipAnimationForAnchorPosition) {
784+
// A styleable gets its style resolved multiple times for anchor positioning.
785+
// Therefore when updating animation is deferred, save the old style so it's restored
786+
// (using beforeResolutionStyle) and can be used when animation is finally updated/applied.
787+
saveBeforeResolutionStyleForInterleaving(styleable.element, oldStyle);
788+
}
789+
778790
auto unanimatedDisplay = resolvedStyle.style->display();
779-
auto hasUnresolvedAnchorPosition = this->hasUnresolvedAnchorPosition(styleable);
780791

781792
WeakStyleOriginatedAnimations newStyleOriginatedAnimations;
782793

783794
auto updateAnimations = [&] {
784795
if (document.backForwardCacheState() != Document::NotInBackForwardCache || document.printing())
785796
return;
786797

787-
if (hasUnresolvedAnchorPosition)
798+
if (skipAnimationForAnchorPosition)
788799
return;
789800

790801
if (oldStyle && (oldStyle->hasTransitions() || resolvedStyle.style->hasTransitions()))
@@ -809,7 +820,7 @@ ElementUpdate TreeResolver::createAnimatedElementUpdate(ResolvedStyle&& resolved
809820
};
810821

811822
auto applyAnimations = [&]() -> std::pair<std::unique_ptr<RenderStyle>, OptionSet<AnimationImpact>> {
812-
if (hasUnresolvedAnchorPosition) {
823+
if (skipAnimationForAnchorPosition) {
813824
auto newStyle = WTF::move(resolvedStyle.style);
814825
ASSERT(newStyle);
815826

@@ -1449,7 +1460,6 @@ std::unique_ptr<Update> TreeResolver::resolve()
14491460
if (elementAndState.value->stage < AnchorPositionResolutionStage::Resolved) {
14501461
const_cast<Element&>(*elementAndState.key.first).invalidateForResumingAnchorPositionedElementResolution();
14511462
m_needsInterleavedLayout = true;
1452-
saveBeforeResolutionStyleForInterleaving(*elementAndState.key.first);
14531463
}
14541464
}
14551465

@@ -1458,7 +1468,6 @@ std::unique_ptr<Update> TreeResolver::resolve()
14581468
ASSERT(styleable.first);
14591469
const_cast<Element&>(*styleable.first).invalidateForResumingAnchorPositionedElementResolution();
14601470
m_needsInterleavedLayout = true;
1461-
saveBeforeResolutionStyleForInterleaving(*styleable.first);
14621471
}
14631472
}
14641473

@@ -1848,13 +1857,9 @@ const RenderStyle* TreeResolver::beforeResolutionStyle(const Element& element, s
18481857
return resolvePseudoStyle(element.renderOrDisplayContentsStyle());
18491858
}
18501859

1851-
void TreeResolver::saveBeforeResolutionStyleForInterleaving(const Element& element)
1860+
void TreeResolver::saveBeforeResolutionStyleForInterleaving(const Element& element, const RenderStyle* style)
18521861
{
1853-
m_savedBeforeResolutionStylesForInterleaving.ensure(element, [&]() -> std::unique_ptr<RenderStyle> {
1854-
if (auto* style = element.renderOrDisplayContentsStyle())
1855-
return makeUnique<RenderStyle>(RenderStyle::cloneIncludingPseudoElements(*style));
1856-
return { };
1857-
});
1862+
m_savedBeforeResolutionStylesForInterleaving.add(element, style ? RenderStyle::clonePtr(*style) : nullptr);
18581863
}
18591864

18601865
bool TreeResolver::hasUnresolvedAnchorPosition(const Styleable& styleable) const
@@ -1875,6 +1880,14 @@ bool TreeResolver::hasResolvedAnchorPosition(const Styleable& styleable) const
18751880
return false;
18761881
}
18771882

1883+
bool TreeResolver::isTryingPositionOption(const Styleable& styleable) const
1884+
{
1885+
if (auto it = m_positionOptions.find({ styleable.element, styleable.pseudoElementIdentifier }); it != m_positionOptions.end())
1886+
return !it->value.chosen;
1887+
1888+
return false;
1889+
}
1890+
18781891
void TreeResolver::collectChangedAnchorNames(const RenderStyle& newStyle, const RenderStyle* currentStyle)
18791892
{
18801893
// A changed anchor name is either a name being added, a name being removed, or a name whose interpretation changes.

Source/WebCore/style/StyleTreeResolver.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,10 +184,13 @@ class TreeResolver {
184184
// This returns the style that was in effect (applied to the render tree) before we started the style resolution.
185185
// Layout interleaving may cause different styles to be applied during the style resolution.
186186
const RenderStyle* beforeResolutionStyle(const Element&, std::optional<PseudoElementIdentifier>);
187-
void saveBeforeResolutionStyleForInterleaving(const Element&);
187+
void saveBeforeResolutionStyleForInterleaving(const Element&, const RenderStyle*);
188188

189189
bool hasUnresolvedAnchorPosition(const Styleable&) const;
190190
bool hasResolvedAnchorPosition(const Styleable&) const;
191+
// Returns true if (1) the styleable specifies position fallbacks and
192+
// (2) we're in the middle of trying position options.
193+
bool isTryingPositionOption(const Styleable&) const;
191194

192195
void collectChangedAnchorNames(const RenderStyle&, const RenderStyle* currentStyle);
193196

0 commit comments

Comments
 (0)