Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: 8e50dd5daa89220c06096dc5961f86e225c165f7
      
https://github.com/WebKit/WebKit/commit/8e50dd5daa89220c06096dc5961f86e225c165f7
  Author: Sammy Gill <[email protected]>
  Date:   2025-03-18 (Tue, 18 Mar 2025)

  Changed paths:
    A 
LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/percent-height-flex-items-cross-sizes-with-mutations-expected.txt
    A 
LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/percent-height-flex-items-cross-sizes-with-mutations.html
    A PerformanceTests/Layout/flexbox-percent-height-cross-size-caching.html
    M Source/WebCore/rendering/RenderFlexibleBox.cpp
    M Source/WebCore/rendering/RenderFlexibleBox.h
    M Source/WebCore/rendering/RenderGrid.cpp

  Log Message:
  -----------
  [Flex] Try to use cached logical height for flex item's hypothetical cross 
size.
rdar://132034177
https://bugs.webkit.org/show_bug.cgi?id=276796

Reviewed by Alan Baradlay.

Currently, in RenderFlexibleBox::layoutAndPlaceFlexItems, we currently
call setNeedsLayout on a flex item if it has a relative logical height
(e.g. % min-height). In some cases, this can result in us doing some extra
work on subsequent layouts when we may not need to. Consider the
following piece of content:

<div style="display: flex;">
  <some-potentially-expensive-flex-item style="height: 
100%;"></some-potentially-expensive-flex-item>
  <div>foobar</div>
</div>

In this example, when we run flex layout, we do the following for each of
the flex items:

1.) Compute the main axis size
2.) Compute the hypothetical cross size
3.) Perform stretch alignment

For this type of content, we need to call layout() on each of the flex
items during both 2 and 3, and we should also note that calling layout on
<some-potentially-expensive-flex-item> may be "expensive," for a variety
of reasons. On a subsequent layout, for example, if we change the content
inside the <div>, we end up calling setNeedsLayout() on the first flex
item due to its % logical height and perform layout on it in order to
compute its hypothetical cross axis size again. During this process, we
unfortunately end up losing the item's stretched size and so must
stretch it again, which requires calling layout() on it one final time.

This patch attempts to mitigate this less than ideal behavior by
attempting to reuse a previously stored hypothetical cross axis size on
a subsequent layout. Rather than invalidating the flex item and
attempting to recompute it due to the % logical height, we can use the
previous value because the flexbox itself has an indefinite logical
height. This causes the flex items' % logical height to behave as auto,
and the resulting size will be based just off of its content.

RenderFlexibleBox already seems to cache the logical heights for its
flex items within a map called m_intrinsicContentLogicalHeights. This
cache is populated when a renderer goes through layout as one of its
first steps inside of updateLogicalHeight(). Inside of
RenderFlexibleBox::layoutAndPlaceItems: we will try not to invalidate the
flex item if the following are true for flex items with a relative
logical height:

1.) The main axis direction is the same as the flex item's inline direction
2.) The flexbox has an indefinite logical height
3.) We have a previously cached value for the cross size

Note that if the flex item's content may have been mutated, we will still
call layout on it due to the mutation, but during layout, we will end up
updating the cached value.

When the flexbox code needs the cross size of the flex item, for example,
to determine the size of the line, it will use
crossAxisIntrinsicExtentForFlexItem, which checks to see if it has a
cached cross size to use.

In order to use this cached size correctly we also needed to add some
extra invalidation when certain types of mutations occur. In this patch
we started removing percent logical height items from the cache in two
scenarios:

1.) When the computed logical height of the flexbox changes
2.) When a flexbox goes from being stretched to no longer stretching in
cases where itself participates in a flex or grid formatting context.

In order to accomplish 2 we allow RenderFlexibleBox to keep track of a
new bit that represents this type of damage. This bit will be set by
callers, in this case RenderFlexibleBox and RenderGrid, to inform the
flexbox that it is no longer being stretched. During flex layout it will
check to see if this bit is set and prune from the cache if it is.

On my M4 Max the included performance test went from ~590 runs/s to ~87K
runs/s.

I also included a new testcase which attempts to exercise this logic to
make sure we are computing the correct sizes and invalidating the cache
properly. This testcase includes a variety of subtests in which the
content is mutated in different ways.

* 
LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/percent-height-flex-items-cross-sizes-with-mutations-expected.txt:
 Added.
* 
LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/percent-height-flex-items-cross-sizes-with-mutations.html:
 Added.
* PerformanceTests/Layout/flexbox-percent-height-cross-size-caching.html: Added.
* Source/WebCore/rendering/RenderFlexibleBox.cpp:
(WebCore::RenderFlexibleBox::styleDidChange):
(WebCore::RenderFlexibleBox::layoutBlock):
(WebCore::RenderFlexibleBox::removePercentLogicalHeightFlexItemsFromIntrinsicLogicalHeightCache):
(WebCore::RenderFlexibleBox::layoutAndPlaceFlexItems):
(WebCore::RenderFlexibleBox::clearNeedsLayout):
(WebCore::RenderFlexibleBox::setNoLongerStretching):
(WebCore::updateFlexItemDirtyBitsBeforeLayout): Deleted.
* Source/WebCore/rendering/RenderFlexibleBox.h:
* Source/WebCore/rendering/RenderGrid.cpp:
(WebCore::RenderGrid::styleDidChange):

Canonical link: https://commits.webkit.org/292314@main



To unsubscribe from these emails, change your notification settings at 
https://github.com/WebKit/WebKit/settings/notifications
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to