Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Source/WebCore/dom/Document.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2760,9 +2760,9 @@ auto Document::updateLayout(OptionSet<LayoutOptions> layoutOptions, const Elemen
} else
context = nullptr;
}
if (frameView->layoutContext().isLayoutPending() || renderView()->needsLayout()) {
if (frameView->layoutContext().needsLayout()) {
ContentVisibilityForceLayoutScope scope(*renderView(), context);
frameView->layoutContext().layout();
frameView->layoutContext().layout(layoutOptions.contains(LayoutOptions::CanDeferUpdateLayerPositions));
result = UpdateLayoutResult::ChangesDone;
}

Expand Down
5 changes: 5 additions & 0 deletions Source/WebCore/dom/Document.h
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,11 @@ enum class LayoutOptions : uint8_t {
ContentVisibilityForceLayout = 1 << 2,
UpdateCompositingLayers = 1 << 3,
DoNotLayoutAncestorDocuments = 1 << 4,
// Doesn't call RenderLayer::recursiveUpdateLayerPositionsAfterLayout if
// possible. The caller should use a LocalFrameView::AutoPreventLayerAccess
// for the scope that layout is expected to be flushed to stop any access to
// the stale RenderLayers.
CanDeferUpdateLayerPositions = 1 << 5
};

enum class HttpEquivPolicy : uint8_t {
Expand Down
3 changes: 2 additions & 1 deletion Source/WebCore/dom/Element.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1906,7 +1906,8 @@ std::optional<std::pair<CheckedPtr<RenderObject>, FloatRect>> Element::boundingA
FloatRect Element::boundingClientRect()
{
Ref document = this->document();
document->updateLayoutIgnorePendingStylesheets({ LayoutOptions::ContentVisibilityForceLayout }, this);
document->updateLayoutIgnorePendingStylesheets({ LayoutOptions::ContentVisibilityForceLayout , LayoutOptions::CanDeferUpdateLayerPositions }, this);
LocalFrameView::AutoPreventLayerAccess preventAccess(*document->view());
auto pair = boundingAbsoluteRectWithoutLayout();
if (!pair)
return { };
Expand Down
1 change: 1 addition & 0 deletions Source/WebCore/dom/MouseRelatedEvent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "LocalFrame.h"
#include "LocalFrameView.h"
#include "RenderLayer.h"
#include "RenderLayerInlines.h"
#include "RenderObject.h"
#include <wtf/IsoMallocInlines.h>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#include "Page.h"
#include "PageGroup.h"
#include "RenderLayer.h"
#include "RenderLayerInlines.h"
#include "RenderVideo.h"
#include "RenderView.h"
#include "Settings.h"
Expand Down
43 changes: 40 additions & 3 deletions Source/WebCore/page/LocalFrameView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1110,6 +1110,7 @@ void LocalFrameView::topContentInsetDidChange(float newTopContentInset)
if (platformWidget())
platformSetTopContentInset(newTopContentInset);

renderView->setNeedsLayout();
layoutContext().layout();
// Every scroll that happens as the result of content inset change is programmatic.
auto oldScrollType = currentScrollType();
Expand Down Expand Up @@ -1300,12 +1301,40 @@ void LocalFrameView::willDoLayout(SingleThreadWeakPtr<RenderElement> layoutRoot)
forceLayoutParentViewIfNeeded();
}

void LocalFrameView::didLayout(SingleThreadWeakPtr<RenderElement> layoutRoot, bool didRunSimplifiedLayout)
bool LocalFrameView::hasPendingUpdateLayerPositions() const
{
return !!m_pendingUpdateLayerPositions;
}

void LocalFrameView::flushUpdateLayerPositions()
{
if (!m_pendingUpdateLayerPositions)
return;

UpdateLayerPositions updateLayerPositions = *std::exchange(m_pendingUpdateLayerPositions, std::nullopt);

WeakPtr layoutRoot = updateLayerPositions.layoutRoot;
if (!layoutRoot)
layoutRoot = renderView();

if (layoutRoot) {
CheckedPtr enclosingLayer = layoutRoot->enclosingLayer();
enclosingLayer->updateLayerPositionsAfterLayout(updateLayerPositions.layoutIdentifier, !is<RenderView>(*layoutRoot), updateLayerPositions.needsFullRepaint, updateLayerPositions.didRunSimplifiedLayout ? RenderLayer::CanUseSimplifiedRepaintPass::Yes : RenderLayer::CanUseSimplifiedRepaintPass::No);
}
}

void LocalFrameView::didLayout(SingleThreadWeakPtr<RenderElement> layoutRoot, bool didRunSimplifiedLayout, bool canDeferUpdateLayerPositions)
{
ScriptDisallowedScope::InMainThread scriptDisallowedScope;

auto* layoutRootEnclosingLayer = layoutRoot->enclosingLayer();
layoutRootEnclosingLayer->updateLayerPositionsAfterLayout(!is<RenderView>(*layoutRoot), layoutContext().needsFullRepaint(), didRunSimplifiedLayout ? RenderLayer::CanUseSimplifiedRepaintPass::Yes : RenderLayer::CanUseSimplifiedRepaintPass::No);
UpdateLayerPositions updateLayerPositions { layoutRoot, layoutContext().layoutIdentifier(), layoutContext().needsFullRepaint(), didRunSimplifiedLayout };
if (!m_pendingUpdateLayerPositions || !m_pendingUpdateLayerPositions->merge(updateLayerPositions)) {
flushUpdateLayerPositions();
m_pendingUpdateLayerPositions = updateLayerPositions;
}

if (!canDeferUpdateLayerPositions)
flushUpdateLayerPositions();

m_updateCompositingLayersIsPending = true;

Expand Down Expand Up @@ -2960,11 +2989,19 @@ void LocalFrameView::updateLayerPositionsAfterScrolling()
if (!layoutContext().isLayoutNested() && hasViewportConstrainedObjects()) {
if (auto* renderView = this->renderView()) {
updateWidgetPositions();
flushUpdateLayerPositions();
renderView->layer()->updateLayerPositionsAfterDocumentScroll();
}
}
}

void LocalFrameView::updateLayerPositionsAfterOverflowScroll(RenderLayer& layer)
{
flushUpdateLayerPositions();
layer.updateLayerPositionsAfterOverflowScroll();
scheduleUpdateWidgetPositions();
}

ScrollingCoordinator* LocalFrameView::scrollingCoordinator() const
{
return m_frame->page() ? m_frame->page()->scrollingCoordinator() : nullptr;
Expand Down
56 changes: 55 additions & 1 deletion Source/WebCore/page/LocalFrameView.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ class LocalFrameView final : public FrameView {
CheckedRef<const LocalFrameViewLayoutContext> checkedLayoutContext() const;
CheckedRef<LocalFrameViewLayoutContext> checkedLayoutContext();

bool hasPendingUpdateLayerPositions() const;
void flushUpdateLayerPositions();

WEBCORE_EXPORT bool didFirstLayout() const;

WEBCORE_EXPORT bool needsLayout() const;
Expand Down Expand Up @@ -279,6 +282,7 @@ class LocalFrameView final : public FrameView {
void cancelScheduledScrolls();
void scrollToFocusedElementImmediatelyIfNeeded();
void updateLayerPositionsAfterScrolling() final;
void updateLayerPositionsAfterOverflowScroll(RenderLayer&);
void updateCompositingLayersAfterScrolling() final;
static WEBCORE_EXPORT bool scrollRectToVisible(const LayoutRect& absoluteRect, const RenderObject&, bool insideFixed, const ScrollRectToVisibleOptions&);

Expand Down Expand Up @@ -726,6 +730,33 @@ class LocalFrameView final : public FrameView {

FrameIdentifier rootFrameID() const final;

#if ASSERT_ENABLED
struct AutoPreventLayerAccess {
AutoPreventLayerAccess(LocalFrameView& view)
: frameView(view)
, oldPreventLayerAccess(view.layerAccessPrevented())
{
view.setLayerAcessPrevented(true);
}

~AutoPreventLayerAccess()
{
frameView->setLayerAcessPrevented(oldPreventLayerAccess);
}

private:
CheckedPtr<LocalFrameView> frameView;
bool oldPreventLayerAccess { false };
};

void setLayerAcessPrevented(bool prevented) { m_layerAccessPrevented = prevented; }
bool layerAccessPrevented() const { return m_layerAccessPrevented; }
#else
struct AutoPreventLayerAccess {
AutoPreventLayerAccess(LocalFrameView&) { }
};
#endif

private:
explicit LocalFrameView(LocalFrame&);

Expand Down Expand Up @@ -890,7 +921,7 @@ class LocalFrameView final : public FrameView {
RenderElement* viewportRenderer() const;

void willDoLayout(SingleThreadWeakPtr<RenderElement> layoutRoot);
void didLayout(SingleThreadWeakPtr<RenderElement> layoutRoot, bool didRunSimplifiedLayout);
void didLayout(SingleThreadWeakPtr<RenderElement> layoutRoot, bool didRunSimplifiedLayout, bool canDeferUpdateLayerPositions);

FloatSize calculateSizeForCSSViewportUnitsOverride(std::optional<OverrideViewportSize>) const;

Expand Down Expand Up @@ -994,6 +1025,26 @@ class LocalFrameView final : public FrameView {
std::unique_ptr<ScrollableAreaSet> m_scrollableAreasForAnimatedScroll;
std::unique_ptr<SingleThreadWeakHashSet<RenderLayerModelObject>> m_viewportConstrainedObjects;

struct UpdateLayerPositions {
bool merge(const UpdateLayerPositions& other)
{
// FIXME: If one is an ancestor of the other we can also probably combine them.
if (layoutRoot != other.layoutRoot)
return false;

needsFullRepaint |= other.needsFullRepaint;
if (!other.didRunSimplifiedLayout)
didRunSimplifiedLayout = false;
return true;
}

SingleThreadWeakPtr<RenderElement> layoutRoot;
RenderElement::LayoutIdentifier layoutIdentifier : 12 { 0 };
bool needsFullRepaint { false };
bool didRunSimplifiedLayout { true };
};
std::optional<UpdateLayerPositions> m_pendingUpdateLayerPositions;

OptionSet<LayoutMilestone> m_milestonesPendingPaint;

static const unsigned visualCharacterThreshold = 200;
Expand Down Expand Up @@ -1052,6 +1103,9 @@ class LocalFrameView final : public FrameView {
bool m_inUpdateEmbeddedObjects { false };
bool m_scheduledToScrollToAnchor { false };
bool m_updateCompositingLayersIsPending { false };
#if ASSERT_ENABLED
bool m_layerAccessPrevented { false };
#endif
};

inline void LocalFrameView::incrementVisuallyNonEmptyPixelCount(const IntSize& size)
Expand Down
23 changes: 14 additions & 9 deletions Source/WebCore/page/LocalFrameViewLayoutContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,13 +141,13 @@ UpdateScrollInfoAfterLayoutTransaction& LocalFrameViewLayoutContext::updateScrol
return *m_updateScrollInfoAfterLayoutTransaction;
}

void LocalFrameViewLayoutContext::layout()
void LocalFrameViewLayoutContext::layout(bool canDeferUpdateLayerPositions)
{
LOG_WITH_STREAM(Layout, stream << "LocalFrameView " << &view() << " LocalFrameViewLayoutContext::layout() with size " << view().layoutSize());

Ref protectedView(view());

performLayout();
performLayout(canDeferUpdateLayerPositions);

if (view().hasOneRef())
return;
Expand All @@ -159,14 +159,14 @@ void LocalFrameViewLayoutContext::layout()
if (!needsLayout())
break;

performLayout();
performLayout(canDeferUpdateLayerPositions);

if (view().hasOneRef())
return;
}
}

void LocalFrameViewLayoutContext::performLayout()
void LocalFrameViewLayoutContext::performLayout(bool canDeferUpdateLayerPositions)
{
Ref frame = this->frame();
RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!document()->inRenderTreeUpdate());
Expand Down Expand Up @@ -269,14 +269,14 @@ void LocalFrameViewLayoutContext::performLayout()
if (m_needsFullRepaint)
renderView()->repaintRootContents();
ASSERT(!layoutRoot->needsLayout());
protectedView()->didLayout(layoutRoot, isSimplifiedLayout);
runOrScheduleAsynchronousTasks();
protectedView()->didLayout(layoutRoot, isSimplifiedLayout, canDeferUpdateLayerPositions);
runOrScheduleAsynchronousTasks(canDeferUpdateLayerPositions);
}
InspectorInstrumentation::didLayout(frame, *layoutRoot);
DebugPageOverlays::didLayout(frame);
}

void LocalFrameViewLayoutContext::runOrScheduleAsynchronousTasks()
void LocalFrameViewLayoutContext::runOrScheduleAsynchronousTasks(bool canDeferUpdateLayerPositions)
{
if (m_postLayoutTaskTimer.isActive())
return;
Expand All @@ -295,10 +295,10 @@ void LocalFrameViewLayoutContext::runOrScheduleAsynchronousTasks()
}

runPostLayoutTasks();
if (needsLayout()) {
if (needsLayoutInternal()) {
// If runPostLayoutTasks() made us layout again, let's defer the tasks until after we return.
m_postLayoutTaskTimer.startOneShot(0_s);
layout();
layout(canDeferUpdateLayerPositions);
}
}

Expand Down Expand Up @@ -331,6 +331,11 @@ void LocalFrameViewLayoutContext::reset()
}

bool LocalFrameViewLayoutContext::needsLayout() const
{
return needsLayoutInternal() || protectedView()->hasPendingUpdateLayerPositions();
}

bool LocalFrameViewLayoutContext::needsLayoutInternal() const
{
// This can return true in cases where the document does not have a body yet.
// Document::shouldScheduleLayout takes care of preventing us from scheduling
Expand Down
8 changes: 5 additions & 3 deletions Source/WebCore/page/LocalFrameViewLayoutContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class LocalFrameViewLayoutContext final : public CanMakeCheckedPtr<LocalFrameVie
LocalFrameViewLayoutContext(LocalFrameView&);
~LocalFrameViewLayoutContext();

WEBCORE_EXPORT void layout();
WEBCORE_EXPORT void layout(bool canDeferUpdateLayerPositions = false);
bool needsLayout() const;

// We rely on the side-effects of layout, like compositing updates, to update state in various subsystems
Expand Down Expand Up @@ -143,13 +143,15 @@ class LocalFrameViewLayoutContext final : public CanMakeCheckedPtr<LocalFrameVie
friend class LayoutStateDisabler;
friend class SubtreeLayoutStateMaintainer;

void performLayout();
bool needsLayoutInternal() const;

void performLayout(bool canDeferUpdateLayerPositions);
bool canPerformLayout() const;
bool isLayoutSchedulingEnabled() const { return m_layoutSchedulingIsEnabled; }

void layoutTimerFired();
void runPostLayoutTasks();
void runOrScheduleAsynchronousTasks();
void runOrScheduleAsynchronousTasks(bool canDeferUpdateLayerPositions);
bool inAsynchronousTasks() const { return m_inAsynchronousTasks; }

void setSubtreeLayoutRoot(RenderElement&);
Expand Down
4 changes: 2 additions & 2 deletions Source/WebCore/rendering/RenderElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1098,9 +1098,9 @@ void RenderElement::willBeRemovedFromTree()
RenderObject::willBeRemovedFromTree();
}

bool RenderElement::didVisitDuringLastLayout() const
bool RenderElement::didVisitSinceLayout(LayoutIdentifier identifier) const
{
return layoutIdentifier() == view().frameView().layoutContext().layoutIdentifier();
return layoutIdentifier() >= identifier;
}

inline void RenderElement::clearSubtreeLayoutRootIfNeeded() const
Expand Down
2 changes: 1 addition & 1 deletion Source/WebCore/rendering/RenderElement.h
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ class RenderElement : public RenderObject {
using LayoutIdentifier = unsigned;
void setLayoutIdentifier(LayoutIdentifier layoutIdentifier) { m_layoutIdentifier = layoutIdentifier; }
LayoutIdentifier layoutIdentifier() const { return m_layoutIdentifier; }
bool didVisitDuringLastLayout() const;
bool didVisitSinceLayout(LayoutIdentifier) const;

protected:
RenderElement(Type, Element&, RenderStyle&&, OptionSet<TypeFlag>, TypeSpecificFlags);
Expand Down
12 changes: 6 additions & 6 deletions Source/WebCore/rendering/RenderLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -968,10 +968,10 @@ void RenderLayer::willUpdateLayerPositions()
void RenderLayer::updateLayerPositionsAfterStyleChange()
{
willUpdateLayerPositions();
recursiveUpdateLayerPositions(flagsForUpdateLayerPositions(*this));
recursiveUpdateLayerPositions(0, flagsForUpdateLayerPositions(*this));
}

void RenderLayer::updateLayerPositionsAfterLayout(bool isRelayoutingSubtree, bool didFullRepaint, CanUseSimplifiedRepaintPass canUseSimplifiedRepaintPass)
void RenderLayer::updateLayerPositionsAfterLayout(RenderElement::LayoutIdentifier layoutIdentifier, bool isRelayoutingSubtree, bool didFullRepaint, CanUseSimplifiedRepaintPass canUseSimplifiedRepaintPass)
{
auto updateLayerPositionFlags = [&](bool isRelayoutingSubtree, bool didFullRepaint) {
auto flags = flagsForUpdateLayerPositions(*this);
Expand All @@ -987,10 +987,10 @@ void RenderLayer::updateLayerPositionsAfterLayout(bool isRelayoutingSubtree, boo
LOG(Compositing, "RenderLayer %p updateLayerPositionsAfterLayout", this);
willUpdateLayerPositions();

recursiveUpdateLayerPositions(updateLayerPositionFlags(isRelayoutingSubtree, didFullRepaint), canUseSimplifiedRepaintPass);
recursiveUpdateLayerPositions(layoutIdentifier, updateLayerPositionFlags(isRelayoutingSubtree, didFullRepaint), canUseSimplifiedRepaintPass);
}

void RenderLayer::recursiveUpdateLayerPositions(OptionSet<UpdateLayerPositionsFlag> flags, CanUseSimplifiedRepaintPass canUseSimplifiedRepaintPass)
void RenderLayer::recursiveUpdateLayerPositions(RenderElement::LayoutIdentifier layoutIdentifier, OptionSet<UpdateLayerPositionsFlag> flags, CanUseSimplifiedRepaintPass canUseSimplifiedRepaintPass)
{
updateLayerPosition(&flags);
if (m_scrollableArea)
Expand Down Expand Up @@ -1032,7 +1032,7 @@ void RenderLayer::recursiveUpdateLayerPositions(OptionSet<UpdateLayerPositionsFl
auto mayNeedRepaintRectUpdate = [&] {
if (canUseSimplifiedRepaintPass == CanUseSimplifiedRepaintPass::No)
return true;
if (!renderer().didVisitDuringLastLayout())
if (!renderer().didVisitSinceLayout(layoutIdentifier))
return false;
if (auto* renderBox = this->renderBox(); renderBox && renderBox->hasRenderOverflow() && renderBox->hasTransformRelatedProperty()) {
// Disable optimization for subtree when dealing with overflow as RenderLayer is not sized to enclose overflow.
Expand Down Expand Up @@ -1100,7 +1100,7 @@ void RenderLayer::recursiveUpdateLayerPositions(OptionSet<UpdateLayerPositionsFl
flags.add(SeenCompositedScrollingLayer);

for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
child->recursiveUpdateLayerPositions(flags, canUseSimplifiedRepaintPass);
child->recursiveUpdateLayerPositions(layoutIdentifier, flags, canUseSimplifiedRepaintPass);

if (m_scrollableArea)
m_scrollableArea->updateMarqueePosition();
Expand Down
Loading