Skip to content

Commit

Permalink
Handle transform changes causing overflow updates
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=243812

Reviewed by Simon Fraser.

Transform change requires at least SimplifiedLayout to re-compute overflow. It fixes cases where a box gets transformed out of the scrollable containing block's border box and becomes unreachable. It's similar to cases when a relatively positioned box is moved and triggers scrolling on its container.

* LayoutTests/TestExpectations:
* Source/WebCore/rendering/RenderElement.cpp:
(WebCore::RenderElement::adjustStyleDifference const):
setNeedsSimplifiedNormalFlowLayout: preserve the repaint behavior (StyleDifference::RecompositeLayer did not trigger repaint).

Canonical link: https://commits.webkit.org/255406@main
  • Loading branch information
alanbaradlay committed Oct 11, 2022
1 parent 6db040e commit fc01491
Show file tree
Hide file tree
Showing 6 changed files with 25 additions and 32 deletions.
1 change: 0 additions & 1 deletion LayoutTests/TestExpectations
Expand Up @@ -4223,7 +4223,6 @@ webkit.org/b/230080 imported/w3c/web-platform-tests/css/css-transforms/animation
webkit.org/b/230080 imported/w3c/web-platform-tests/css/css-transforms/backface-visibility-hidden-004.tentative.html [ ImageOnlyFailure ]
webkit.org/b/230080 imported/w3c/web-platform-tests/css/css-transforms/backface-visibility-hidden-005.tentative.html [ ImageOnlyFailure ]
webkit.org/b/230080 imported/w3c/web-platform-tests/css/css-transforms/backface-visibility-hidden-animated-002.html [ ImageOnlyFailure ]
webkit.org/b/230080 imported/w3c/web-platform-tests/css/css-transforms/change-scale-wide-range.html [ Pass ImageOnlyFailure ]
webkit.org/b/230080 imported/w3c/web-platform-tests/css/css-transforms/huge-length-tiny-scale.html [ ImageOnlyFailure ]
webkit.org/b/230080 imported/w3c/web-platform-tests/css/css-transforms/perspective-children-only-abspos.html [ ImageOnlyFailure ]
webkit.org/b/230080 imported/w3c/web-platform-tests/css/css-transforms/perspective-children-only-fixpos.html [ ImageOnlyFailure ]
Expand Down
Expand Up @@ -3,6 +3,7 @@

body {
background-color: red;
overflow: hidden;
}

div {
Expand Down
42 changes: 23 additions & 19 deletions Source/WebCore/rendering/RenderElement.cpp
Expand Up @@ -257,20 +257,16 @@ const RenderStyle& RenderElement::firstLineStyle() const

StyleDifference RenderElement::adjustStyleDifference(StyleDifference diff, OptionSet<StyleDifferenceContextSensitiveProperty> contextSensitiveProperties) const
{
// If transform changed, and we are not composited, need to do a layout.
if (contextSensitiveProperties & StyleDifferenceContextSensitiveProperty::Transform) {
// FIXME: when transforms are taken into account for overflow, we will need to do a layout.
if (!hasLayer() || !downcast<RenderLayerModelObject>(*this).layer()->isComposited()) {
if (!hasLayer())
diff = std::max(diff, StyleDifference::Layout);
else {
// We need to set at least SimplifiedLayout, but if PositionedMovementOnly is already set
// then we actually need SimplifiedLayoutAndPositionedMovement.
diff = std::max(diff, (diff == StyleDifference::LayoutPositionedMovementOnly) ? StyleDifference::SimplifiedLayoutAndPositionedMovement : StyleDifference::SimplifiedLayout);
}

// Transform change requires at least SimplifiedLayout to re-compute scrollable overflow.
// e.g. translate a box outside of a scrollable containing block's content box should trigger scrollbars.
if (!hasLayer())
diff = std::max(diff, StyleDifference::Layout);
else if (diff == StyleDifference::LayoutPositionedMovementOnly) {
// Upgrading LayoutPositionedMovementOnly to SimplifiedLayout makes the positioning part of layout bits skipped (i.e. not an upgrade).
diff = StyleDifference::SimplifiedLayoutAndPositionedMovement;
} else
diff = std::max(diff, StyleDifference::RecompositeLayer);
diff = std::max(diff, StyleDifference::SimplifiedLayout);
}

if (contextSensitiveProperties & StyleDifferenceContextSensitiveProperty::Opacity) {
Expand Down Expand Up @@ -528,9 +524,9 @@ void RenderElement::setStyle(RenderStyle&& style, StyleDifference minimalStyleDi
setNeedsPositionedMovementLayout(&oldStyle);
else if (updatedDiff == StyleDifference::SimplifiedLayoutAndPositionedMovement) {
setNeedsPositionedMovementLayout(&oldStyle);
setNeedsSimplifiedNormalFlowLayout();
setNeedsSimplifiedNormalFlowLayout(&oldStyle);
} else if (updatedDiff == StyleDifference::SimplifiedLayout)
setNeedsSimplifiedNormalFlowLayout();
setNeedsSimplifiedNormalFlowLayout(&oldStyle);
}

if (!didRepaint && (updatedDiff == StyleDifference::RepaintLayer || shouldRepaintForStyleDifference(updatedDiff))) {
Expand Down Expand Up @@ -949,10 +945,10 @@ void RenderElement::styleDidChange(StyleDifference diff, const RenderStyle* oldS
if (diff == StyleDifference::Layout)
setNeedsLayoutAndPrefWidthsRecalc();
else
setNeedsSimplifiedNormalFlowLayout();
setNeedsSimplifiedNormalFlowLayout(oldStyle);
} else if (diff == StyleDifference::SimplifiedLayoutAndPositionedMovement) {
setNeedsPositionedMovementLayout(oldStyle);
setNeedsSimplifiedNormalFlowLayout();
setNeedsSimplifiedNormalFlowLayout(oldStyle);
} else if (diff == StyleDifference::LayoutPositionedMovementOnly)
setNeedsPositionedMovementLayout(oldStyle);

Expand Down Expand Up @@ -1102,15 +1098,23 @@ void RenderElement::clearChildNeedsLayout()
setNeedsPositionedMovementLayoutBit(false);
}

void RenderElement::setNeedsSimplifiedNormalFlowLayout()
void RenderElement::setNeedsSimplifiedNormalFlowLayout(const RenderStyle* oldStyle)
{
ASSERT(!isSetNeedsLayoutForbidden());
if (needsSimplifiedNormalFlowLayout())
return;
setNeedsSimplifiedNormalFlowLayoutBit(true);
markContainingBlocksForLayout();
if (hasLayer())
setLayerNeedsFullRepaint();
auto needsLayerRepaint = [&] {
if (!hasLayer() || !oldStyle)
return false;
auto isComposited = downcast<RenderLayerModelObject>(*this).layer()->isComposited();
if (style().diffRequiresLayerRepaint(*oldStyle, isComposited))
return true;
return !isComposited && style().hasTransform() && oldStyle->hasTransform() && style().transform() != oldStyle->transform();
};
if (needsLayerRepaint())
return setLayerNeedsFullRepaint();
}

static inline void paintPhase(RenderElement& element, PaintPhase phase, PaintInfo& paintInfo, const LayoutPoint& childPoint)
Expand Down
2 changes: 1 addition & 1 deletion Source/WebCore/rendering/RenderElement.h
Expand Up @@ -142,7 +142,7 @@ class RenderElement : public RenderObject {
void setChildNeedsLayout(MarkingBehavior = MarkContainingBlockChain);
void clearChildNeedsLayout();
void setNeedsPositionedMovementLayout(const RenderStyle* oldStyle);
void setNeedsSimplifiedNormalFlowLayout();
void setNeedsSimplifiedNormalFlowLayout(const RenderStyle* oldStyle);

virtual void paint(PaintInfo&, const LayoutPoint&) = 0;

Expand Down
9 changes: 0 additions & 9 deletions Source/WebCore/rendering/RenderFragmentedFlow.cpp
Expand Up @@ -824,15 +824,6 @@ void RenderFragmentedFlow::willBeDestroyed()
RenderBlockFlow::willBeDestroyed();
}

void RenderFragmentedFlow::markFragmentsForOverflowLayoutIfNeeded()
{
if (!hasFragments())
return;

for (auto& fragment : m_fragmentList)
fragment->setNeedsSimplifiedNormalFlowLayout();
}

void RenderFragmentedFlow::updateFragmentsFragmentedFlowPortionRect()
{
LayoutUnit logicalHeight;
Expand Down
2 changes: 0 additions & 2 deletions Source/WebCore/rendering/RenderFragmentedFlow.h
Expand Up @@ -131,8 +131,6 @@ class RenderFragmentedFlow: public RenderBlockFlow {
// Check if the object should be painted in this fragment and if the fragment is part of this flow thread.
bool objectShouldFragmentInFlowFragment(const RenderObject*, const RenderFragmentContainer*) const;

void markFragmentsForOverflowLayoutIfNeeded();

virtual bool addForcedFragmentBreak(const RenderBlock*, LayoutUnit, RenderBox* breakChild, bool isBefore, LayoutUnit* offsetBreakAdjustment = 0);
virtual void applyBreakAfterContent(LayoutUnit) { }

Expand Down

0 comments on commit fc01491

Please sign in to comment.