Changeset 289698 in webkit


Ignore:
Timestamp:
Feb 12, 2022 11:25:51 AM (5 months ago)
Author:
Patrick Angle
Message:

Web Inspector: [Flexbox] Show item bounds, gaps, and free space in flex overlays
https://bugs.webkit.org/show_bug.cgi?id=236410

Reviewed by Devin Rousso.

  • inspector/InspectorInstrumentation.cpp:

(WebCore::InspectorInstrumentation::flexibleBoxRendererBeganLayoutImpl):
(WebCore::InspectorInstrumentation::flexibleBoxRendererWrappedToNextLineImpl):
(WebCore::InspectorInstrumentation::instrumentingAgents):

  • inspector/InspectorInstrumentation.h:

(WebCore::InspectorInstrumentation::flexibleBoxRendererBeganLayout):
(WebCore::InspectorInstrumentation::flexibleBoxRendererWrappedToNextLine):

  • inspector/agents/InspectorDOMAgent.cpp:

(WebCore::InspectorDOMAgent::willDestroyFrontendAndBackend):
(WebCore::InspectorDOMAgent::reset):
(WebCore::InspectorDOMAgent::flexibleBoxRendererBeganLayout):
(WebCore::InspectorDOMAgent::flexibleBoxRendererWrappedToNextLine):
(WebCore::InspectorDOMAgent::flexibleBoxRendererCachedItemsAtStartOfLine):

  • inspector/agents/InspectorDOMAgent.h:
  • Add instrumentation points specifically for flexbox renderers to keep track of which items start a new line

inside flex containers. The start of the first line is not recorded because it will always be zero.

(WebCore::InspectorDOMAgent::didCreateFrontendAndBackend):

  • Force a layout of the document to ensure that our collection of flexbox line starts is correctly populated

when attaching an inspector, since without an inspector this information is not kept beyond layout.

  • inspector/InspectorOverlay.cpp:

(WebCore::drawLayoutPattern):

  • Generalize drawLayoutHatching to support different line styles in order to support the new stippling fill.
  • In order to support "flipping" the pattern we now use a rectangle encompassing the provided quad as the edges

we follow for filling the pattern (the existing clipping ensures that the final product is still within the
quad). This also resolves an issue that could occur in transformed containers (non-rectangular) where the
spacing was inconsistent at different rotations/perspectives.

(WebCore::drawLayoutStippling):

  • A new dot-pattern effect similar to hatching, but using small dots to fill the space instead.

(WebCore::drawLayoutHatching):

  • Updated to use the new generic drawLayoutPattern helper.

(WebCore::InspectorOverlay::drawFlexOverlay):
(WebCore::InspectorOverlay::buildFlexOverlay):

  • Handle iterating through the flex children to show their bounds as well as the spacing/gaps between them.

Almost all this work is done in relative terms, like leading/trailing/cross-axis/main-axis to make it easier to
reason about what should happen for different writing modes, text direction, flex direction, and flex wrapping.
To accomplish this coordinates of children are read through special corrected* helper functions that take in
to account the determined direction, main-axis reversal, and cross axis-reversal from all of the relevant
properties. This means there are only 8 (23) actual permutations of flex layout (since the layout inside each
individual child is irrelevant here). Throughout we are working with flex children frames that are relative to
their parent, which saves us from having to deal with transforms until after we have constructed most of our
overlay representation, only needing to be passed through childQuadToRootQuad before being added to the
appropriate part of the highlight object.

  • inspector/InspectorOverlay.h:

(WebCore::InspectorOverlay::Highlight::FlexHighlightOverlay::encode const):
(WebCore::InspectorOverlay::Highlight::FlexHighlightOverlay::decode):

  • rendering/RenderBox.h:

(WebCore::RenderBox::marginBox const):

  • Add a way to get the entire margin box instead of its individual components.
  • rendering/RenderFlexibleBox.cpp:

(WebCore::RenderFlexibleBox::layoutFlexItems):

  • rendering/RenderFlexibleBox.h:
  • Make getting the computed inter-item and inter-line gap public so we can use them in the overlay.
  • Add instrumentation calls to keep track of the indexes of items that start a new line during layout when an

Inspector is attached.

  • platform/LayoutUnit.h:

(WebCore::operator!=):

Location:
trunk/Source/WebCore
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r289697 r289698  
     12022-02-12  Patrick Angle  <pangle@apple.com>
     2
     3        Web Inspector: [Flexbox] Show item bounds, gaps, and free space in flex overlays
     4        https://bugs.webkit.org/show_bug.cgi?id=236410
     5
     6        Reviewed by Devin Rousso.
     7
     8        * inspector/InspectorInstrumentation.cpp:
     9        (WebCore::InspectorInstrumentation::flexibleBoxRendererBeganLayoutImpl):
     10        (WebCore::InspectorInstrumentation::flexibleBoxRendererWrappedToNextLineImpl):
     11        (WebCore::InspectorInstrumentation::instrumentingAgents):
     12        * inspector/InspectorInstrumentation.h:
     13        (WebCore::InspectorInstrumentation::flexibleBoxRendererBeganLayout):
     14        (WebCore::InspectorInstrumentation::flexibleBoxRendererWrappedToNextLine):
     15        * inspector/agents/InspectorDOMAgent.cpp:
     16        (WebCore::InspectorDOMAgent::willDestroyFrontendAndBackend):
     17        (WebCore::InspectorDOMAgent::reset):
     18        (WebCore::InspectorDOMAgent::flexibleBoxRendererBeganLayout):
     19        (WebCore::InspectorDOMAgent::flexibleBoxRendererWrappedToNextLine):
     20        (WebCore::InspectorDOMAgent::flexibleBoxRendererCachedItemsAtStartOfLine):
     21        * inspector/agents/InspectorDOMAgent.h:
     22        - Add instrumentation points specifically for flexbox renderers to keep track of which items start a new line
     23        inside flex containers. The start of the first line is not recorded because it will always be zero.
     24       
     25        (WebCore::InspectorDOMAgent::didCreateFrontendAndBackend):
     26        - Force a layout of the document to ensure that our collection of flexbox line starts is correctly populated
     27        when attaching an inspector, since without an inspector this information is not kept beyond layout.
     28
     29        * inspector/InspectorOverlay.cpp:
     30        (WebCore::drawLayoutPattern):
     31        - Generalize `drawLayoutHatching` to support different line styles in order to support the new stippling fill.
     32        - In order to support "flipping" the pattern we now use a rectangle encompassing the provided quad as the edges
     33        we follow for filling the pattern (the existing clipping ensures that the final product is still within the
     34        quad). This also resolves an issue that could occur in transformed containers (non-rectangular) where the
     35        spacing was inconsistent at different rotations/perspectives.
     36
     37        (WebCore::drawLayoutStippling):
     38        - A new dot-pattern effect similar to hatching, but using small dots to fill the space instead.
     39
     40        (WebCore::drawLayoutHatching):
     41        - Updated to use the new generic `drawLayoutPattern` helper.
     42       
     43        (WebCore::InspectorOverlay::drawFlexOverlay):
     44        (WebCore::InspectorOverlay::buildFlexOverlay):
     45        - Handle iterating through the flex children to show their bounds as well as the spacing/gaps between them.
     46        Almost all this work is done in relative terms, like leading/trailing/cross-axis/main-axis to make it easier to
     47        reason about what should happen for different writing modes, text direction, flex direction, and flex wrapping.
     48        To accomplish this coordinates of children are read through special `corrected*` helper functions that take in
     49        to account the determined direction, main-axis reversal, and cross axis-reversal from all of the relevant
     50        properties. This means there are only 8 (2^3) actual permutations of flex layout (since the layout inside each
     51        individual child is irrelevant here). Throughout we are working with flex children frames that are relative to
     52        their parent, which saves us from having to deal with transforms until after we have constructed most of our
     53        overlay representation, only needing to be passed through `childQuadToRootQuad` before being added to the
     54        appropriate part of the highlight object.
     55
     56        * inspector/InspectorOverlay.h:
     57        (WebCore::InspectorOverlay::Highlight::FlexHighlightOverlay::encode const):
     58        (WebCore::InspectorOverlay::Highlight::FlexHighlightOverlay::decode):
     59
     60        * rendering/RenderBox.h:
     61        (WebCore::RenderBox::marginBox const):
     62        - Add a way to get the entire margin box instead of its individual components.
     63
     64        * rendering/RenderFlexibleBox.cpp:
     65        (WebCore::RenderFlexibleBox::layoutFlexItems):
     66        * rendering/RenderFlexibleBox.h:
     67        - Make getting the computed inter-item and inter-line gap public so we can use them in the overlay.
     68        - Add instrumentation calls to keep track of the indexes of items that start a new line during layout when an
     69        Inspector is attached.
     70
     71        * platform/LayoutUnit.h:
     72        (WebCore::operator!=):
     73
    1742022-02-12  Jer Noble  <jer.noble@apple.com>
    275
  • trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp

    r288623 r289698  
    579579}
    580580
     581void InspectorInstrumentation::flexibleBoxRendererBeganLayoutImpl(InstrumentingAgents& instrumentingAgents, const RenderObject& renderer)
     582{
     583    if (auto* domAgent = instrumentingAgents.persistentDOMAgent())
     584        domAgent->flexibleBoxRendererBeganLayout(renderer);
     585}
     586
     587void InspectorInstrumentation::flexibleBoxRendererWrappedToNextLineImpl(InstrumentingAgents& instrumentingAgents, const RenderObject& renderer, size_t lineStartItemIndex)
     588{
     589    if (auto* domAgent = instrumentingAgents.persistentDOMAgent())
     590        domAgent->flexibleBoxRendererWrappedToNextLine(renderer, lineStartItemIndex);
     591}
     592
    581593void InspectorInstrumentation::willSendRequestImpl(InstrumentingAgents& instrumentingAgents, ResourceLoaderIdentifier identifier, DocumentLoader* loader, ResourceRequest& request, const ResourceResponse& redirectResponse, const CachedResource* cachedResource)
    582594{
     
    12731285}
    12741286
    1275 InstrumentingAgents* InspectorInstrumentation::instrumentingAgents(RenderObject& renderer)
     1287InstrumentingAgents* InspectorInstrumentation::instrumentingAgents(const RenderObject& renderer)
    12761288{
    12771289    return instrumentingAgents(renderer.frame());
  • trunk/Source/WebCore/inspector/InspectorInstrumentation.h

    r288623 r289698  
    192192    static void applyEmulatedMedia(Frame&, String&);
    193193
     194    static void flexibleBoxRendererBeganLayout(const RenderObject&);
     195    static void flexibleBoxRendererWrappedToNextLine(const RenderObject&, size_t lineStartItemIndex);
     196
    194197    static void willSendRequest(Frame*, ResourceLoaderIdentifier, DocumentLoader*, ResourceRequest&, const ResourceResponse& redirectResponse, const CachedResource*);
    195198    static void didLoadResourceFromMemoryCache(Page&, DocumentLoader*, CachedResource*);
     
    411414    static void applyEmulatedMediaImpl(InstrumentingAgents&, String&);
    412415
     416    static void flexibleBoxRendererBeganLayoutImpl(InstrumentingAgents&, const RenderObject&);
     417    static void flexibleBoxRendererWrappedToNextLineImpl(InstrumentingAgents&, const RenderObject&, size_t lineStartItemIndex);
     418
    413419    static void willSendRequestImpl(InstrumentingAgents&, ResourceLoaderIdentifier, DocumentLoader*, ResourceRequest&, const ResourceResponse& redirectResponse, const CachedResource*);
    414420    static void willSendRequestOfTypeImpl(InstrumentingAgents&, ResourceLoaderIdentifier, DocumentLoader*, ResourceRequest&, LoadType);
     
    524530    static InstrumentingAgents* instrumentingAgents(Document&);
    525531    static InstrumentingAgents* instrumentingAgents(Document*);
    526     static InstrumentingAgents* instrumentingAgents(RenderObject&);
     532    static InstrumentingAgents* instrumentingAgents(const RenderObject&);
    527533    static InstrumentingAgents* instrumentingAgents(WorkerOrWorkletGlobalScope*);
    528534};
     
    10411047}
    10421048
     1049inline void InspectorInstrumentation::flexibleBoxRendererBeganLayout(const RenderObject& renderer)
     1050{
     1051    FAST_RETURN_IF_NO_FRONTENDS(void());
     1052    if (auto* agents = instrumentingAgents(renderer))
     1053        flexibleBoxRendererBeganLayoutImpl(*agents, renderer);
     1054}
     1055
     1056inline void InspectorInstrumentation::flexibleBoxRendererWrappedToNextLine(const RenderObject& renderer, size_t lineStartItemIndex)
     1057{
     1058    FAST_RETURN_IF_NO_FRONTENDS(void());
     1059    if (auto* agents = instrumentingAgents(renderer))
     1060        flexibleBoxRendererWrappedToNextLineImpl(*agents, renderer, lineStartItemIndex);
     1061}
     1062
    10431063inline void InspectorInstrumentation::willSendRequest(Frame* frame, ResourceLoaderIdentifier identifier, DocumentLoader* loader, ResourceRequest& request, const ResourceResponse& redirectResponse, const CachedResource* cachedResource)
    10441064{
  • trunk/Source/WebCore/inspector/InspectorOverlay.cpp

    r289416 r289698  
    5252#include "GridPositionsResolver.h"
    5353#include "InspectorClient.h"
     54#include "InspectorController.h"
     55#include "InspectorDOMAgent.h"
    5456#include "IntPoint.h"
    5557#include "IntRect.h"
     
    5860#include "NodeList.h"
    5961#include "NodeRenderStyle.h"
     62#include "OrderIterator.h"
    6063#include "Page.h"
    6164#include "PseudoElement.h"
     
    6972#include "StyleGridData.h"
    7073#include "StyleResolver.h"
     74#include "TextDirection.h"
    7175#include <wtf/MathExtras.h>
    7276#include <wtf/text/StringBuilder.h>
     
    9599static constexpr UChar thinSpace = 0x2009;
    96100static constexpr UChar emSpace = 0x2003;
     101
     102enum class Flip : bool { No, Yes };
    97103
    98104static void truncateWithEllipsis(String& string, size_t length)
     
    12211227}
    12221228
    1223 static void drawLayoutHatching(GraphicsContext& context, FloatQuad quad)
     1229static void drawLayoutPattern(GraphicsContext& context, const FloatQuad& quad, int hatchSpacing, Flip flip)
    12241230{
    12251231    GraphicsContextStateSaver saver(context);
    12261232    context.clipPath(quadToPath(quad));
     1233
     1234    Path hatchPath;
     1235
     1236    auto boundingBox = quad.enclosingBoundingBox();
     1237
     1238    auto correctedLineForPoints = [&](const FloatPoint& start, const FloatPoint& end) {
     1239        return (flip == Flip::Yes) ? FloatLine(end, start) : FloatLine(start, end);
     1240    };
     1241
     1242    auto topSide = correctedLineForPoints(boundingBox.minXMinYCorner(), boundingBox.maxXMinYCorner());
     1243    auto leftSide = correctedLineForPoints(boundingBox.minXMinYCorner(), boundingBox.minXMaxYCorner());
     1244
     1245    // The opposite axis' length is used to determine how far to draw a hatch line in both dimensions, which keeps the lines at a 45deg angle.
     1246    if (topSide.length() > leftSide.length()) {
     1247        auto bottomSide = correctedLineForPoints(boundingBox.minXMaxYCorner(), boundingBox.maxXMaxYCorner());
     1248        // Move across the relative top of the area, starting left of `0, 0` to ensure that the tail of the previous hatch line is drawn while scrolling.
     1249        for (float x = -leftSide.length(); x < topSide.length(); x += hatchSpacing) {
     1250            hatchPath.moveTo(topSide.pointAtAbsoluteDistance(x));
     1251            hatchPath.addLineTo(bottomSide.pointAtAbsoluteDistance(x + leftSide.length()));
     1252        }
     1253    } else {
     1254        auto rightSide = correctedLineForPoints(boundingBox.maxXMinYCorner(), boundingBox.maxXMaxYCorner());
     1255        // Move down the relative left side of the area, starting above `0, 0` to ensure that the tail of the previous hatch line is drawn while scrolling.
     1256        for (float y = -topSide.length(); y < leftSide.length(); y += hatchSpacing) {
     1257            hatchPath.moveTo(leftSide.pointAtAbsoluteDistance(y));
     1258            hatchPath.addLineTo(rightSide.pointAtAbsoluteDistance(y + topSide.length()));
     1259        }
     1260    }
     1261
     1262    context.strokePath(hatchPath);
     1263}
     1264
     1265static void drawLayoutStippling(GraphicsContext& context, const FloatQuad& quad, float density)
     1266{
     1267    GraphicsContextStateSaver saver(context);
     1268    context.setStrokeThickness(1);
     1269    context.setStrokeStyle(StrokeStyle::DashedStroke);
     1270    context.setLineDash({ 1, density }, 1);
     1271
     1272    drawLayoutPattern(context, quad, density, Flip::No);
     1273}
     1274
     1275static void drawLayoutHatching(GraphicsContext& context, const FloatQuad& quad, Flip flip = Flip::No)
     1276{
     1277    GraphicsContextStateSaver saver(context);
    12271278    context.setStrokeThickness(0.5);
    12281279    context.setStrokeStyle(StrokeStyle::DashedStroke);
    12291280    context.setLineDash({ 2, 2 }, 2);
    1230        
    1231     constexpr auto hatchSpacing = 12;
    1232     Path hatchPath;
    1233    
    1234     FloatLine topSide = { quad.p1(), quad.p2() };
    1235     FloatLine leftSide = { quad.p1(), quad.p4() };
    1236    
    1237     // The opposite axis' length is used to determine how far to draw a hatch line in both dimensions, which keeps the lines at a 45deg angle.
    1238     if (topSide.length() > leftSide.length()) {
    1239         FloatLine bottomSide = { quad.p4(), quad.p3() };
    1240         // Move across the relative top of the quad, starting left of `0, 0` to ensure that the tail of the previous hatch line is drawn while scrolling.
    1241         for (float x = -leftSide.length(); x < topSide.length(); x += hatchSpacing) {
    1242             hatchPath.moveTo(topSide.pointAtAbsoluteDistance(x));
    1243             hatchPath.addLineTo(bottomSide.pointAtAbsoluteDistance(x + leftSide.length()));
    1244         }
    1245     } else {
    1246         FloatLine rightSide = { quad.p2(), quad.p3() };
    1247         // Move down the relative left side of the quad, starting above `0, 0` to ensure that the tail of the previous hatch line is drawn while scrolling.
    1248         for (float y = -topSide.length(); y < leftSide.length(); y += hatchSpacing) {
    1249             hatchPath.moveTo(leftSide.pointAtAbsoluteDistance(y));
    1250             hatchPath.addLineTo(rightSide.pointAtAbsoluteDistance(y + topSide.length()));
    1251         }
    1252     }
    1253    
    1254     context.strokePath(hatchPath);
     1281
     1282    constexpr auto defaultLayoutHatchSpacing = 12;
     1283    drawLayoutPattern(context, quad, defaultLayoutHatchSpacing, flip);
    12551284}
    12561285
     
    19942023    context.setStrokeColor(flexHighlightOverlay.color);
    19952024    context.strokePath(quadToPath(flexHighlightOverlay.containerBounds));
     2025
     2026    for (const auto& bounds : flexHighlightOverlay.itemBounds)
     2027        context.strokePath(quadToPath(bounds));
     2028
     2029    for (const auto& mainAxisGap : flexHighlightOverlay.mainAxisGaps) {
     2030        context.strokePath(quadToPath(mainAxisGap));
     2031        drawLayoutHatching(context, mainAxisGap);
     2032    }
     2033
     2034    {
     2035        GraphicsContextStateSaver mainAxisSpaceContextSaver(context);
     2036        context.setAlpha(0.5);
     2037
     2038        constexpr auto mainAxisSpaceDensity = 3;
     2039        for (auto mainAxisSpaceBetweenItemAndGap : flexHighlightOverlay.mainAxisSpaceBetweenItemsAndGaps)
     2040            drawLayoutStippling(context, mainAxisSpaceBetweenItemAndGap, mainAxisSpaceDensity);
     2041    }
     2042
     2043    for (const auto& crossAxisGap : flexHighlightOverlay.crossAxisGaps) {
     2044        context.strokePath(quadToPath(crossAxisGap));
     2045        drawLayoutHatching(context, crossAxisGap, Flip::Yes);
     2046    }
     2047
     2048    context.setAlpha(0.7);
     2049    constexpr auto spaceBetweenItemsAndCrossAxisSpaceStipplingDensity = 6;
     2050    for (const auto& crossAxisSpaceBetweenItemAndGap : flexHighlightOverlay.spaceBetweenItemsAndCrossAxisSpace)
     2051        drawLayoutStippling(context, crossAxisSpaceBetweenItemAndGap, spaceBetweenItemsAndCrossAxisSpaceStipplingDensity);
    19962052}
    19972053
     
    20172073    auto& renderFlex = *downcast<RenderFlexibleBox>(renderer);
    20182074
     2075    auto itemsAtStartOfLine = m_page.inspectorController().ensureDOMAgent().flexibleBoxRendererCachedItemsAtStartOfLine(renderFlex);
     2076
    20192077    Frame* containingFrame = node->document().frame();
    20202078    if (!containingFrame)
     
    20222080    FrameView* containingView = containingFrame->view();
    20232081
    2024     auto localQuadToRootQuad = [&](const FloatQuad& quad) -> FloatQuad {
    2025         return {
     2082    auto computedStyle = node->computedStyle();
     2083    if (!computedStyle)
     2084        return { };
     2085
     2086    auto wasRowDirection = !computedStyle->isColumnFlexDirection();
     2087    auto isFlippedBlocksWritingMode = computedStyle->isFlippedBlocksWritingMode();
     2088    auto isRightToLeftDirection = computedStyle->direction() == TextDirection::RTL;
     2089
     2090    auto isRowDirection = wasRowDirection ^ !computedStyle->isHorizontalWritingMode();
     2091    auto isMainAxisDirectionReversed = computedStyle->isReverseFlexDirection() ^ (wasRowDirection ? isRightToLeftDirection : isFlippedBlocksWritingMode);
     2092    auto isCrossAxisDirectionReversed = (computedStyle->flexWrap() == FlexWrap::Reverse) ^ (wasRowDirection ? isFlippedBlocksWritingMode : isRightToLeftDirection);
     2093
     2094    auto localQuadToRootQuad = [&](const FloatQuad& quad) {
     2095        return FloatQuad(
    20262096            localPointToRootPoint(containingView, quad.p1()),
    20272097            localPointToRootPoint(containingView, quad.p2()),
    20282098            localPointToRootPoint(containingView, quad.p3()),
    20292099            localPointToRootPoint(containingView, quad.p4())
    2030         };
     2100        );
     2101    };
     2102
     2103    auto childQuadToRootQuad = [&](const FloatQuad& quad) {
     2104        return FloatQuad(
     2105            localPointToRootPoint(containingView, renderFlex.localToContainerPoint(quad.p1(), nullptr)),
     2106            localPointToRootPoint(containingView, renderFlex.localToContainerPoint(quad.p2(), nullptr)),
     2107            localPointToRootPoint(containingView, renderFlex.localToContainerPoint(quad.p3(), nullptr)),
     2108            localPointToRootPoint(containingView, renderFlex.localToContainerPoint(quad.p4(), nullptr))
     2109        );
     2110    };
     2111
     2112    auto correctedMainAxisLeadingEdge = [&](const LayoutRect& rect) {
     2113        if (isRowDirection)
     2114            return isMainAxisDirectionReversed ? rect.maxX() : rect.x();
     2115        return isMainAxisDirectionReversed ? rect.maxY() : rect.y();
     2116    };
     2117
     2118    auto correctedMainAxisTrailingEdge = [&](const LayoutRect& rect) {
     2119        if (isRowDirection)
     2120            return isMainAxisDirectionReversed ? rect.x() : rect.maxX();
     2121        return isMainAxisDirectionReversed ? rect.y() : rect.maxY();
     2122    };
     2123
     2124    auto correctedCrossAxisLeadingEdge = [&](const LayoutRect& rect) {
     2125        if (isRowDirection)
     2126            return isCrossAxisDirectionReversed ? rect.maxY() : rect.y();
     2127        return isCrossAxisDirectionReversed ? rect.maxX() : rect.x();
     2128    };
     2129
     2130    auto correctedCrossAxisTrailingEdge = [&](const LayoutRect& rect) {
     2131        if (isRowDirection)
     2132            return isCrossAxisDirectionReversed ? rect.y() : rect.maxY();
     2133        return isCrossAxisDirectionReversed ? rect.x() : rect.maxX();
     2134    };
     2135
     2136    auto correctedCrossAxisMin = [&](float a, float b) {
     2137        return isCrossAxisDirectionReversed ? std::fmax(a, b) : std::fmin(a, b);
     2138    };
     2139
     2140    auto correctedCrossAxisMax = [&](float a, float b) {
     2141        return isCrossAxisDirectionReversed ? std::fmin(a, b) : std::fmax(a, b);
     2142    };
     2143
     2144    auto correctedPoint = [&](float mainAxisLocation, float crossAxisLocation) {
     2145        return isRowDirection ? FloatPoint(mainAxisLocation, crossAxisLocation) : FloatPoint(crossAxisLocation, mainAxisLocation);
     2146    };
     2147
     2148    auto populateHighlightForGapOrSpace = [&](float fromMainAxisEdge, float toMainAxisEdge, float fromCrossAxisEdge, float toCrossAxisEdge, Vector<FloatQuad>& gapsSet) {
     2149        gapsSet.append(childQuadToRootQuad({
     2150            correctedPoint(fromMainAxisEdge, fromCrossAxisEdge),
     2151            correctedPoint(toMainAxisEdge, fromCrossAxisEdge),
     2152            correctedPoint(toMainAxisEdge, toCrossAxisEdge),
     2153            correctedPoint(fromMainAxisEdge, toCrossAxisEdge),
     2154        }));
    20312155    };
    20322156
    20332157    InspectorOverlay::Highlight::FlexHighlightOverlay flexHighlightOverlay;
    20342158    flexHighlightOverlay.color = flexOverlay.config.flexColor;
    2035     flexHighlightOverlay.containerBounds = localQuadToRootQuad({ renderFlex.absoluteContentQuad() });
     2159    flexHighlightOverlay.containerBounds = localQuadToRootQuad(renderFlex.absoluteContentQuad());
     2160
     2161    float computedMainAxisGap = renderFlex.computeGap(RenderFlexibleBox::GapType::BetweenItems).toFloat();
     2162    float computedCrossAxisGap = renderFlex.computeGap(RenderFlexibleBox::GapType::BetweenLines).toFloat();
     2163
     2164    // For reasoning about the edges of the flex container, use the untransformed content rect moved to the origin of the
     2165    // inner top-left corner of padding, which is the same relative coordinate space that each item's `frameRect()` will be in.
     2166    auto containerRect = renderFlex.absoluteContentBox();
     2167    containerRect.setLocation({ renderFlex.paddingLeft() + renderFlex.borderLeft(), renderFlex.paddingTop() + renderFlex.borderTop() });
     2168
     2169    float containerMainAxisLeadingEdge = correctedMainAxisLeadingEdge(containerRect);
     2170    float containerMainAxisTrailingEdge = correctedMainAxisTrailingEdge(containerRect);
     2171
     2172    Vector<LayoutRect> currentLineChildrenRects;
     2173    float currentLineCrossAxisLeadingEdge = isCrossAxisDirectionReversed ? 0.0f : std::numeric_limits<float>::max();
     2174    float currentLineCrossAxisTrailingEdge = isCrossAxisDirectionReversed ? std::numeric_limits<float>::max() : 0.0f;
     2175    float previousLineCrossAxisTrailingEdge = correctedCrossAxisLeadingEdge(containerRect);
     2176
     2177    size_t currentChildIndex = 0;
     2178    auto childOrderIterator = renderFlex.orderIterator();
     2179    for (RenderBox* renderChild = childOrderIterator.first(); renderChild; renderChild = childOrderIterator.next()) {
     2180        if (childOrderIterator.shouldSkipChild(*renderChild))
     2181            continue;
     2182
     2183        // Build bounds for each child and collect children on the same logical line.
     2184        {
     2185            auto childRect = renderChild->frameRect();
     2186            renderFlex.flipForWritingMode(childRect);
     2187            childRect.expand(renderChild->marginBox());
     2188            flexHighlightOverlay.itemBounds.append(childQuadToRootQuad({ childRect }));
     2189
     2190            currentLineCrossAxisLeadingEdge = correctedCrossAxisMin(currentLineCrossAxisLeadingEdge, correctedCrossAxisLeadingEdge(childRect));
     2191            currentLineCrossAxisTrailingEdge = correctedCrossAxisMax(currentLineCrossAxisTrailingEdge, correctedCrossAxisTrailingEdge(childRect));
     2192
     2193            currentLineChildrenRects.append(WTFMove(childRect));
     2194            ++currentChildIndex;
     2195        }
     2196
     2197        // The remaining work can only be done once we have collected all of the children on the current line.
     2198        if (!itemsAtStartOfLine.contains(currentChildIndex))
     2199            continue;
     2200
     2201        float previousChildMainAxisTrailingEdge = correctedMainAxisLeadingEdge(containerRect);
     2202        for (const auto& childRect : currentLineChildrenRects) {
     2203            auto childMainAxisLeadingEdge = correctedMainAxisLeadingEdge(childRect);
     2204            auto childMainAxisTrailingEdge = correctedMainAxisTrailingEdge(childRect);
     2205            auto childCrossAxisLeadingEdge = correctedCrossAxisLeadingEdge(childRect);
     2206            auto childCrossAxisTrailingEdge = correctedCrossAxisTrailingEdge(childRect);
     2207
     2208            // Build bounds for space between the current item and the cross-axis space.
     2209            if (std::fabs(childCrossAxisLeadingEdge - currentLineCrossAxisLeadingEdge) > 1)
     2210                populateHighlightForGapOrSpace(childMainAxisLeadingEdge, childMainAxisTrailingEdge, currentLineCrossAxisLeadingEdge, childCrossAxisLeadingEdge, flexHighlightOverlay.spaceBetweenItemsAndCrossAxisSpace);
     2211            if (std::fabs(childCrossAxisTrailingEdge - currentLineCrossAxisTrailingEdge) > 1)
     2212                populateHighlightForGapOrSpace(childMainAxisLeadingEdge, childMainAxisTrailingEdge, currentLineCrossAxisTrailingEdge, childCrossAxisTrailingEdge, flexHighlightOverlay.spaceBetweenItemsAndCrossAxisSpace);
     2213
     2214            // Build bounds for gaps and space between the current item and previous item (or container edge).
     2215            if (computedMainAxisGap && previousChildMainAxisTrailingEdge != correctedMainAxisLeadingEdge(containerRect)) {
     2216                // Regardless of flipped axises, we need to do the below calculations from left to right or top to bottom.
     2217                float startEdge = std::fmin(previousChildMainAxisTrailingEdge, childMainAxisLeadingEdge);
     2218                float endEdge = std::fmax(previousChildMainAxisTrailingEdge, childMainAxisLeadingEdge);
     2219
     2220                float spaceBetweenEdgeAndGap = (endEdge - startEdge - computedMainAxisGap) / 2;
     2221
     2222                populateHighlightForGapOrSpace(startEdge, startEdge + spaceBetweenEdgeAndGap, currentLineCrossAxisLeadingEdge, currentLineCrossAxisTrailingEdge, flexHighlightOverlay.mainAxisSpaceBetweenItemsAndGaps);
     2223                populateHighlightForGapOrSpace(startEdge + spaceBetweenEdgeAndGap, endEdge - spaceBetweenEdgeAndGap, currentLineCrossAxisLeadingEdge, currentLineCrossAxisTrailingEdge, flexHighlightOverlay.mainAxisGaps);
     2224                populateHighlightForGapOrSpace(endEdge - spaceBetweenEdgeAndGap, endEdge, currentLineCrossAxisLeadingEdge, currentLineCrossAxisTrailingEdge, flexHighlightOverlay.mainAxisSpaceBetweenItemsAndGaps);
     2225            } else
     2226                populateHighlightForGapOrSpace(previousChildMainAxisTrailingEdge, childMainAxisLeadingEdge, currentLineCrossAxisLeadingEdge, currentLineCrossAxisTrailingEdge, flexHighlightOverlay.mainAxisSpaceBetweenItemsAndGaps);
     2227
     2228            previousChildMainAxisTrailingEdge = childMainAxisTrailingEdge;
     2229        }
     2230        populateHighlightForGapOrSpace(previousChildMainAxisTrailingEdge, containerMainAxisTrailingEdge, currentLineCrossAxisLeadingEdge, currentLineCrossAxisTrailingEdge, flexHighlightOverlay.mainAxisSpaceBetweenItemsAndGaps);
     2231
     2232        // Build gaps between the current line and the previous line.
     2233        if (computedCrossAxisGap && previousLineCrossAxisTrailingEdge != correctedCrossAxisLeadingEdge(containerRect)) {
     2234            // Regardless of flipped axises, we need to do the below calculations from left to right or top to bottom.
     2235            float startEdge = std::fmin(previousLineCrossAxisTrailingEdge, currentLineCrossAxisLeadingEdge);
     2236            float endEdge = std::fmax(previousLineCrossAxisTrailingEdge, currentLineCrossAxisLeadingEdge);
     2237
     2238            float spaceBetweenEdgeAndGap = (endEdge - startEdge - computedCrossAxisGap) / 2;
     2239
     2240            populateHighlightForGapOrSpace(containerMainAxisLeadingEdge, containerMainAxisTrailingEdge, startEdge + spaceBetweenEdgeAndGap, endEdge - spaceBetweenEdgeAndGap, flexHighlightOverlay.crossAxisGaps);
     2241        }
     2242
     2243        previousLineCrossAxisTrailingEdge = currentLineCrossAxisTrailingEdge;
     2244
     2245        currentLineChildrenRects.clear();
     2246        currentLineCrossAxisLeadingEdge = isCrossAxisDirectionReversed ? 0.0f : std::numeric_limits<float>::max();
     2247        currentLineCrossAxisTrailingEdge = isCrossAxisDirectionReversed ? std::numeric_limits<float>::max() : 0.0f;
     2248    }
    20362249
    20372250    return { flexHighlightOverlay };
  • trunk/Source/WebCore/inspector/InspectorOverlay.h

    r289416 r289698  
    4040#include <wtf/RefPtr.h>
    4141#include <wtf/Vector.h>
     42#include <wtf/WeakHashMap.h>
    4243#include <wtf/WeakPtr.h>
    4344#include <wtf/text/WTFString.h>
     
    147148            Color color;
    148149            FloatQuad containerBounds;
     150            Vector<FloatQuad> itemBounds;
     151            Vector<FloatQuad> mainAxisGaps;
     152            Vector<FloatQuad> mainAxisSpaceBetweenItemsAndGaps;
     153            Vector<FloatQuad> spaceBetweenItemsAndCrossAxisSpace;
     154            Vector<FloatQuad> crossAxisGaps;
    149155
    150156#if PLATFORM(IOS_FAMILY)
     
    304310    encoder << color;
    305311    encoder << containerBounds;
     312    encoder << itemBounds;
     313    encoder << mainAxisGaps;
     314    encoder << mainAxisSpaceBetweenItemsAndGaps;
     315    encoder << spaceBetweenItemsAndCrossAxisSpace;
     316    encoder << crossAxisGaps;
    306317}
    307318
     
    312323        return { };
    313324    if (!decoder.decode(flexHighlightOverlay.containerBounds))
     325        return { };
     326    if (!decoder.decode(flexHighlightOverlay.itemBounds))
     327        return { };
     328    if (!decoder.decode(flexHighlightOverlay.mainAxisGaps))
     329        return { };
     330    if (!decoder.decode(flexHighlightOverlay.mainAxisSpaceBetweenItemsAndGaps))
     331        return { };
     332    if (!decoder.decode(flexHighlightOverlay.spaceBetweenItemsAndCrossAxisSpace))
     333        return { };
     334    if (!decoder.decode(flexHighlightOverlay.crossAxisGaps))
    314335        return { };
    315336    return { flexHighlightOverlay };
  • trunk/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp

    r289416 r289698  
    9696#include "PseudoElement.h"
    9797#include "RenderGrid.h"
     98#include "RenderObject.h"
    9899#include "RenderStyle.h"
    99100#include "RenderStyleConstants.h"
     
    308309    m_document = m_inspectedPage.mainFrame().document();
    309310
     311    // Force a layout so that we can collect additional information from the layout process.
     312    if (m_document)
     313        m_document->updateLayout();
     314
    310315#if ENABLE(VIDEO)
    311316    if (m_document)
     
    330335
    331336    m_overlay->clearAllGridOverlays();
     337    m_overlay->clearAllFlexOverlays();
    332338
    333339    m_instrumentingAgents.setPersistentDOMAgent(nullptr);
     
    357363        m_revalidateStyleAttrTask->reset();
    358364    m_document = nullptr;
     365    m_flexibleBoxRendererCachedItemsAtStartOfLine.clear();
    359366
    360367    m_destroyedDetachedNodeIdentifiers.clear();
     
    27912798}
    27922799
     2800void InspectorDOMAgent::flexibleBoxRendererBeganLayout(const RenderObject& renderer)
     2801{
     2802    m_flexibleBoxRendererCachedItemsAtStartOfLine.remove(renderer);
     2803}
     2804
     2805void InspectorDOMAgent::flexibleBoxRendererWrappedToNextLine(const RenderObject& renderer, size_t lineStartItemIndex)
     2806{
     2807    m_flexibleBoxRendererCachedItemsAtStartOfLine.ensure(renderer, [] {
     2808        return Vector<size_t>();
     2809    }).iterator->value.append(lineStartItemIndex);
     2810}
     2811
     2812Vector<size_t> InspectorDOMAgent::flexibleBoxRendererCachedItemsAtStartOfLine(const RenderObject& renderer)
     2813{
     2814    return m_flexibleBoxRendererCachedItemsAtStartOfLine.get(renderer);
     2815}
     2816
    27932817RefPtr<JSC::Breakpoint> InspectorDOMAgent::breakpointForEventListener(EventTarget& target, const AtomString& eventType, EventListener& listener, bool capture)
    27942818{
  • trunk/Source/WebCore/inspector/agents/InspectorDOMAgent.h

    r289416 r289698  
    7373class Page;
    7474class PseudoElement;
     75class RenderObject;
    7576class RevalidateStyleAttributeTask;
    7677class ShadowRoot;
     
    183184    bool isEventListenerDisabled(EventTarget&, const AtomString& eventType, EventListener&, bool capture);
    184185    void eventDidResetAfterDispatch(const Event&);
     186    void flexibleBoxRendererBeganLayout(const RenderObject&);
     187    void flexibleBoxRendererWrappedToNextLine(const RenderObject&, size_t lineStartItemIndex);
    185188
    186189    // Callbacks that don't directly correspond to an instrumentation entry point.
     
    206209    InspectorHistory* history() { return m_history.get(); }
    207210    Vector<Document*> documents();
     211    Vector<size_t> flexibleBoxRendererCachedItemsAtStartOfLine(const RenderObject&);
    208212    void reset();
    209213
     
    270274    std::unique_ptr<InspectorHistory> m_history;
    271275    std::unique_ptr<DOMEditor> m_domEditor;
     276    WeakHashMap<RenderObject, Vector<size_t>> m_flexibleBoxRendererCachedItemsAtStartOfLine;
    272277
    273278    Vector<Inspector::Protocol::DOM::NodeId> m_destroyedDetachedNodeIdentifiers;
  • trunk/Source/WebCore/platform/LayoutUnit.h

    r283287 r289698  
    379379}
    380380
     381inline bool operator!=(const float a, const LayoutUnit& b)
     382{
     383    return LayoutUnit(a) != b;
     384}
     385
    381386inline bool operator!=(const LayoutUnit& a, float b)
    382387{
  • trunk/Source/WebCore/rendering/RenderBox.h

    r289606 r289698  
    263263    void setScrollPosition(const ScrollPosition&, const ScrollPositionChangeOptions&);
    264264
     265    const LayoutBoxExtent& marginBox() const { return m_marginBox; }
    265266    LayoutUnit marginTop() const override { return m_marginBox.top(); }
    266267    LayoutUnit marginBottom() const override { return m_marginBox.bottom(); }
  • trunk/Source/WebCore/rendering/RenderFlexibleBox.cpp

    r288492 r289698  
    11541154    size_t nextIndex = 0;
    11551155    size_t numLines = 0;
     1156    InspectorInstrumentation::flexibleBoxRendererBeganLayout(*this);
    11561157    while (flexAlgorithm.computeNextFlexLine(nextIndex, lineItems, sumFlexBaseSize, totalFlexGrow, totalFlexShrink, totalWeightedFlexShrink, sumHypotheticalMainSize)) {
    11571158        ++numLines;
     1159        InspectorInstrumentation::flexibleBoxRendererWrappedToNextLine(*this, nextIndex);
     1160
    11581161        LayoutUnit containerMainInnerSize = mainAxisContentExtent(sumHypotheticalMainSize);
    11591162        // availableFreeSpace is the initial amount of free space in this flexbox.
  • trunk/Source/WebCore/rendering/RenderFlexibleBox.h

    r287976 r289698  
    8787    // be laid out again.
    8888    bool setStaticPositionForPositionedLayout(const RenderBox&);
     89
     90    enum class GapType { BetweenLines, BetweenItems };
     91    LayoutUnit computeGap(GapType) const;
    8992
    9093protected:
     
    206209    void resetHasDefiniteHeight() { m_hasDefiniteHeight = SizeDefiniteness::Unknown; }
    207210
    208     enum class GapType { BetweenLines, BetweenItems };
    209     LayoutUnit computeGap(GapType) const;
    210 
    211211    // This is used to cache the preferred size for orthogonal flow children so we
    212212    // don't have to relayout to get it
     
    223223    // sizing of children.
    224224    HashSet<const RenderBox*> m_relaidOutChildren;
    225    
     225
    226226    mutable OrderIterator m_orderIterator { *this };
    227227    int m_numberOfInFlowChildrenOnFirstLine { -1 };
Note: See TracChangeset for help on using the changeset viewer.