Title: [274822] trunk/Source
Revision
274822
Author
[email protected]
Date
2021-03-22 17:05:45 -0700 (Mon, 22 Mar 2021)

Log Message

Web Inspector: Port grid overlay drawing to iOS
https://bugs.webkit.org/show_bug.cgi?id=223396

Reviewed by BJ Burg.

Source/WebCore:

Enable Grid Overlays to be drawn on iOS be including computed overlay objects in the
`InspectorOverlay::Highlight`. Some refactoring was also done to reduce code duplication in the normal and iOS
paths.

* Headers.cmake:
* WebCore.xcodeproj/project.pbxproj:
- FloatLine should be accessible from `WebKit::*`
* inspector/InspectorOverlay.cpp:
(WebCore::InspectorOverlay::paint):
(WebCore::InspectorOverlay::getHighlight):
- Add `GridHighlightOverlay`s to the highlight object for iOS.
(WebCore::InspectorOverlay::drawGridOverlay):
(WebCore::buildLabel):
(WebCore::InspectorOverlay::buildGridOverlay):
- Refactored actual drawing into a separate method to reduce the amount of code duplication needed between the
normal path and the iOS path.
* inspector/InspectorOverlay.h:
(WebCore::InspectorOverlay::Highlight::GridHighlightOverlay::encode const):
(WebCore::InspectorOverlay::Highlight::GridHighlightOverlay::decode):
(WebCore::InspectorOverlay::Highlight::GridHighlightOverlay::Label::encode const):
(WebCore::InspectorOverlay::Highlight::GridHighlightOverlay::Label::decode):
(WebCore::InspectorOverlay::Highlight::GridHighlightOverlay::Area::encode const):
(WebCore::InspectorOverlay::Highlight::GridHighlightOverlay::Area::decode):
- Support encode/decode for sending new Highlight components to the UIProcess.
* platform/graphics/FloatLine.h:
(WebCore::FloatLine::encode const):
(WebCore::FloatLine::decode):
- Support encode/decode as part of serialization of `InspectorOverlay::Highlight`

Source/WebKit:

Port drawing routines from `WebCore::InspectorOverlay` to use `CALayer`s on iOS to enable drawing grid overlays
on iOS. Drawing logic is, as much as possible, equivalent to that defined in `WebCore::InspectorOverlay`, with
changes to fit the CALayer model.

* UIProcess/Inspector/ios/WKInspectorHighlightView.h:
* UIProcess/Inspector/ios/WKInspectorHighlightView.mm:
(-[WKInspectorHighlightView initWithFrame:]):
(-[WKInspectorHighlightView _removeAllLayers]):
(-[WKInspectorHighlightView _createLayers:]):
(layerPath):
- Path should be closed so that objects being stroked are stroked on all edges.
(-[WKInspectorHighlightView _layoutForNodeListHighlight:]):
(-[WKInspectorHighlightView _layoutForRectsHighlight:]):
(-[WKInspectorHighlightView _createGridOverlayLayers:scale:]):
(createLayoutHatchingLayer):
(createLayoutLabelLayer):
(-[WKInspectorHighlightView _createGridOverlayLayer:scale:]):
- Create layers for the grid overlays.
(-[WKInspectorHighlightView update:scale:]):
- Obtain the view scale so that `CATextLayer`s can have the correct content scale set.
(-[WKInspectorHighlightView update:]): Deleted.
* UIProcess/ios/WKContentView.mm:
(-[WKContentView _showInspectorHighlight:]):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (274821 => 274822)


--- trunk/Source/WebCore/ChangeLog	2021-03-23 00:05:29 UTC (rev 274821)
+++ trunk/Source/WebCore/ChangeLog	2021-03-23 00:05:45 UTC (rev 274822)
@@ -1,3 +1,39 @@
+2021-03-22  Patrick Angle  <[email protected]>
+
+        Web Inspector: Port grid overlay drawing to iOS
+        https://bugs.webkit.org/show_bug.cgi?id=223396
+
+        Reviewed by BJ Burg.
+
+        Enable Grid Overlays to be drawn on iOS be including computed overlay objects in the
+        `InspectorOverlay::Highlight`. Some refactoring was also done to reduce code duplication in the normal and iOS
+        paths.
+
+        * Headers.cmake:
+        * WebCore.xcodeproj/project.pbxproj:
+        - FloatLine should be accessible from `WebKit::*`
+        * inspector/InspectorOverlay.cpp:
+        (WebCore::InspectorOverlay::paint):
+        (WebCore::InspectorOverlay::getHighlight):
+        - Add `GridHighlightOverlay`s to the highlight object for iOS.
+        (WebCore::InspectorOverlay::drawGridOverlay):
+        (WebCore::buildLabel):
+        (WebCore::InspectorOverlay::buildGridOverlay):
+        - Refactored actual drawing into a separate method to reduce the amount of code duplication needed between the
+        normal path and the iOS path.
+        * inspector/InspectorOverlay.h:
+        (WebCore::InspectorOverlay::Highlight::GridHighlightOverlay::encode const):
+        (WebCore::InspectorOverlay::Highlight::GridHighlightOverlay::decode):
+        (WebCore::InspectorOverlay::Highlight::GridHighlightOverlay::Label::encode const):
+        (WebCore::InspectorOverlay::Highlight::GridHighlightOverlay::Label::decode):
+        (WebCore::InspectorOverlay::Highlight::GridHighlightOverlay::Area::encode const):
+        (WebCore::InspectorOverlay::Highlight::GridHighlightOverlay::Area::decode):
+        - Support encode/decode for sending new Highlight components to the UIProcess.
+        * platform/graphics/FloatLine.h:
+        (WebCore::FloatLine::encode const):
+        (WebCore::FloatLine::decode):
+        - Support encode/decode as part of serialization of `InspectorOverlay::Highlight`
+
 2021-03-22  Ada Chan  <[email protected]>
 
         [WebXR] Enumerate XR devices via ChromeClient in WebXRSystem

Modified: trunk/Source/WebCore/Headers.cmake (274821 => 274822)


--- trunk/Source/WebCore/Headers.cmake	2021-03-23 00:05:29 UTC (rev 274821)
+++ trunk/Source/WebCore/Headers.cmake	2021-03-23 00:05:45 UTC (rev 274822)
@@ -1188,6 +1188,7 @@
     platform/graphics/DisplayRefreshMonitorClient.h
     platform/graphics/DisplayRefreshMonitorManager.h
     platform/graphics/ExtensionsGL.h
+    platform/graphics/FloatLine.h
     platform/graphics/FloatPoint.h
     platform/graphics/FloatPoint3D.h
     platform/graphics/FloatQuad.h

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (274821 => 274822)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-03-23 00:05:29 UTC (rev 274821)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-03-23 00:05:45 UTC (rev 274822)
@@ -862,7 +862,7 @@
 		2E4346550F546A8200B0F1BA /* WorkerThread.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E4346430F546A8200B0F1BA /* WorkerThread.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		2E75841E12779ADA0062628B /* FileReaderLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E75841B12779ADA0062628B /* FileReaderLoader.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		2E75841F12779ADA0062628B /* FileReaderLoaderClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E75841C12779ADA0062628B /* FileReaderLoaderClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
-		2E888CAA25F6A4110057914A /* FloatLine.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E888CA825F6A4110057914A /* FloatLine.h */; };
+		2E888CAA25F6A4110057914A /* FloatLine.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E888CA825F6A4110057914A /* FloatLine.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		2E94F43C119207DA00B7F75D /* JSFileReader.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E94F43A119207DA00B7F75D /* JSFileReader.h */; };
 		2E9B5D8F1B66A94E008C6A24 /* WheelEventDeltaFilterMac.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E9B5D8E1B66A94E008C6A24 /* WheelEventDeltaFilterMac.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		2EA768040FE7126400AB9C8A /* WorkerScriptLoaderClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EA768030FE7126400AB9C8A /* WorkerScriptLoaderClient.h */; settings = {ATTRIBUTES = (Private, ); }; };

Modified: trunk/Source/WebCore/inspector/InspectorOverlay.cpp (274821 => 274822)


--- trunk/Source/WebCore/inspector/InspectorOverlay.cpp	2021-03-23 00:05:29 UTC (rev 274821)
+++ trunk/Source/WebCore/inspector/InspectorOverlay.cpp	2021-03-23 00:05:45 UTC (rev 274822)
@@ -427,8 +427,10 @@
         rulerExclusion.titlePath = nodeRulerExclusion.titlePath;
     }
 
-    for (const InspectorOverlay::Grid& gridOverlay : m_activeGridOverlays)
-        drawGridOverlay(context, gridOverlay);
+    for (const InspectorOverlay::Grid& gridOverlay : m_activeGridOverlays) {
+        if (auto gridHighlightOverlay = buildGridOverlay(gridOverlay))
+            drawGridOverlay(context, *gridHighlightOverlay);
+    }
 
     if (!m_paintRects.isEmpty())
         drawPaintRects(context, m_paintRects);
@@ -437,12 +439,12 @@
         drawRulers(context, rulerExclusion);
 }
 
-void InspectorOverlay::getHighlight(InspectorOverlay::Highlight& highlight, InspectorOverlay::CoordinateSystem coordinateSystem) const
+void InspectorOverlay::getHighlight(InspectorOverlay::Highlight& highlight, InspectorOverlay::CoordinateSystem coordinateSystem)
 {
-    if (!m_highlightNode && !m_highlightQuad && !m_highlightNodeList)
+    if (!m_highlightNode && !m_highlightQuad && !m_highlightNodeList && !m_activeGridOverlays.size())
         return;
 
-    highlight.type = InspectorOverlay::Highlight::Type::Rects;
+    highlight.type = InspectorOverlay::Highlight::Type::None;
     if (m_highlightNode)
         buildNodeHighlight(*m_highlightNode, m_nodeHighlightConfig, highlight, coordinateSystem);
     else if (m_highlightNodeList) {
@@ -454,8 +456,15 @@
                 highlight.quads.appendVector(nodeHighlight.quads);
         }
         highlight.type = InspectorOverlay::Highlight::Type::NodeList;
-    } else
+    } else if (m_highlightQuad) {
+        highlight.type = InspectorOverlay::Highlight::Type::Rects;
         buildQuadHighlight(*m_highlightQuad, m_quadHighlightConfig, highlight);
+    }
+    constexpr bool offsetBoundsByScroll = true;
+    for (const InspectorOverlay::Grid& gridOverlay : m_activeGridOverlays) {
+        if (auto gridHighlightOverlay = buildGridOverlay(gridOverlay, offsetBoundsByScroll))
+            highlight.gridHighlightOverlays.append(*gridHighlightOverlay);
+    }
 }
 
 void InspectorOverlay::hideHighlight()
@@ -1281,6 +1290,37 @@
     context.drawText(font, TextRun(label), textPosition);
 }
 
+void InspectorOverlay::drawGridOverlay(GraphicsContext& context, const InspectorOverlay::Highlight::GridHighlightOverlay& gridOverlay)
+{
+    constexpr auto translucentLabelBackgroundColor = Color::white.colorWithAlphaByte(153);
+
+    GraphicsContextStateSaver saver(context);
+    context.setStrokeThickness(1);
+    context.setStrokeColor(gridOverlay.color);
+
+    Path gridLinesPath;
+    for (auto gridLine : gridOverlay.gridLines) {
+        gridLinesPath.moveTo(gridLine.start());
+        gridLinesPath.addLineTo(gridLine.end());
+    }
+    context.strokePath(gridLinesPath);
+
+    for (auto gapQuad : gridOverlay.gaps)
+        drawLayoutHatching(context, gapQuad);
+
+    context.setStrokeThickness(3);
+    for (auto area : gridOverlay.areas)
+        context.strokePath(quadToPath(area.quad));
+
+    // Draw labels on top of all other lines.
+    context.setStrokeThickness(1);
+    for (auto area : gridOverlay.areas)
+        drawLayoutLabel(context, area.name, area.quad.p1(), LabelArrowDirection::None, translucentLabelBackgroundColor, area.quad.boundingBox().width());
+
+    for (auto label : gridOverlay.labels)
+        drawLayoutLabel(context, label.text, label.location, label.arrowDirection, label.backgroundColor);
+}
+
 static Vector<String> authoredGridTrackSizes(Node* node, GridTrackSizingDirection direction, unsigned expectedTrackCount)
 {
     if (!is<Element>(node))
@@ -1379,14 +1419,24 @@
     return combinedGridLineNames;
 }
 
-void InspectorOverlay::drawGridOverlay(GraphicsContext& context, const InspectorOverlay::Grid& gridOverlay)
+static InspectorOverlay::Highlight::GridHighlightOverlay::Label buildLabel(String text, FloatPoint location, Color backgroundColor, InspectorOverlay::LabelArrowDirection arrowDirection)
 {
+    InspectorOverlay::Highlight::GridHighlightOverlay::Label label;
+    label.text = text;
+    label.location = location;
+    label.backgroundColor = backgroundColor;
+    label.arrowDirection = arrowDirection;
+    return label;
+}
+
+Optional<InspectorOverlay::Highlight::GridHighlightOverlay> InspectorOverlay::buildGridOverlay(const InspectorOverlay::Grid& gridOverlay, bool offsetBoundsByScroll)
+{
     // If the node WeakPtr has been cleared, then the node is gone and there's nothing to draw.
     if (!gridOverlay.gridNode) {
         m_activeGridOverlays.removeAllMatching([&] (const InspectorOverlay::Grid& gridOverlay) {
             return !gridOverlay.gridNode;
         });
-        return;
+        return { };
     }
     
     // Always re-check because the node's renderer may have changed since being added.
@@ -1395,21 +1445,23 @@
     auto renderer = node->renderer();
     if (!is<RenderGrid>(renderer)) {
         removeGridOverlayForNode(*node);
-        return;
+        return { };
     }
-    
+
     constexpr auto translucentLabelBackgroundColor = Color::white.colorWithAlphaByte(153);
     
     FrameView* pageView = m_page.mainFrame().view();
     if (!pageView)
-        return;
+        return { };
     FloatRect viewportBounds = { { 0, 0 }, pageView->sizeForVisibleContent() };
+    if (offsetBoundsByScroll)
+        viewportBounds.setLocation(pageView->scrollPosition());
     
     auto& renderGrid = *downcast<RenderGrid>(renderer);
     auto columnPositions = renderGrid.columnPositions();
     auto rowPositions = renderGrid.rowPositions();
     if (!columnPositions.size() || !rowPositions.size())
-        return;
+        return { };
     
     float gridStartX = columnPositions[0];
     float gridEndX = columnPositions[columnPositions.size() - 1];
@@ -1418,7 +1470,7 @@
 
     Frame* containingFrame = node->document().frame();
     if (!containingFrame)
-        return;
+        return { };
     FrameView* containingView = containingFrame->view();
 
     auto columnLineAt = [&](int x) -> FloatLine {
@@ -1433,11 +1485,10 @@
             localPointToRootPoint(containingView, renderGrid.localToContainerPoint(FloatPoint(gridEndX, y), nullptr)),
         };
     };
-    
-    GraphicsContextStateSaver saver(context);
-    context.setStrokeThickness(1);
-    context.setStrokeColor(gridOverlay.config.gridColor);
 
+    InspectorOverlay::Highlight::GridHighlightOverlay gridHighlightOverlay;
+    gridHighlightOverlay.color = gridOverlay.config.gridColor;
+
     // Draw columns and rows.
     auto columnWidths = renderGrid.trackSizesForComputedStyle(GridTrackSizingDirection::ForColumns);
     auto columnLineNames = gridLineNames(node->renderStyle(), GridTrackSizingDirection::ForColumns, columnPositions.size());
@@ -1446,19 +1497,16 @@
     for (unsigned i = 0; i < columnPositions.size(); ++i) {
         auto columnStartLine = columnLineAt(columnPositions[i]);
 
-        Path columnPaths;
         if (gridOverlay.config.showExtendedGridLines) {
             auto extendedLine = columnStartLine.extendedToBounds(viewportBounds);
-            columnPaths.moveTo(extendedLine.start());
-            columnPaths.addLineTo(extendedLine.end());
+            gridHighlightOverlay.gridLines.append(extendedLine);
         } else {
-            columnPaths.moveTo(columnStartLine.start());
-            columnPaths.addLineTo(columnStartLine.end());
+            gridHighlightOverlay.gridLines.append(columnStartLine);
         }
         
         FloatPoint gapLabelPosition = columnStartLine.start();
         if (i) {
-            drawLayoutHatching(context, { previousColumnEndLine.start(), columnStartLine.start(), columnStartLine.end(), previousColumnEndLine.end() });
+            gridHighlightOverlay.gaps.append({ previousColumnEndLine.start(), columnStartLine.start(), columnStartLine.end(), previousColumnEndLine.end() });
             FloatLine lineBetweenColumnTops = { columnStartLine.start(), previousColumnEndLine.start() };
             gapLabelPosition = lineBetweenColumnTops.pointAtRelativeDistance(0.5);
         }
@@ -1469,11 +1517,9 @@
 
             if (gridOverlay.config.showExtendedGridLines) {
                 auto extendedLine = columnEndLine.extendedToBounds(viewportBounds);
-                columnPaths.moveTo(extendedLine.start());
-                columnPaths.addLineTo(extendedLine.end());
+                gridHighlightOverlay.gridLines.append(extendedLine);
             } else {
-                columnPaths.moveTo(columnEndLine.start());
-                columnPaths.addLineTo(columnEndLine.end());
+                gridHighlightOverlay.gridLines.append(columnEndLine);
             }
             previousColumnEndLine = columnEndLine;
             
@@ -1493,13 +1539,11 @@
                 }
                 
                 FloatLine trackTopLine = { columnStartLine.start(), columnEndLine.start() };
-                drawLayoutLabel(context, trackSizeLabel, trackTopLine.pointAtRelativeDistance(0.5), LabelArrowDirection::Up, translucentLabelBackgroundColor);
+                gridHighlightOverlay.labels.append(buildLabel(trackSizeLabel, trackTopLine.pointAtRelativeDistance(0.5), translucentLabelBackgroundColor, LabelArrowDirection::Up));
             }
         } else
             previousColumnEndLine = columnStartLine;
-        
-        context.strokePath(columnPaths);
-        
+
         StringBuilder lineLabel;
         if (gridOverlay.config.showLineNumbers)
             lineLabel.append(i + 1, thinSpace, bullet, thinSpace, -static_cast<int>(columnPositions.size() - i));
@@ -1512,7 +1556,7 @@
         }
         // FIXME: <webkit.org/b/221972> Layout labels can be drawn outside the viewport, and a best effort should be made to keep them in the viewport while the grid is in the viewport.
         if (!lineLabel.isEmpty())
-            drawLayoutLabel(context, lineLabel.toString(), gapLabelPosition, LabelArrowDirection::Down);
+            gridHighlightOverlay.labels.append(buildLabel(lineLabel.toString(), gapLabelPosition, Color::white, LabelArrowDirection::Down));
     }
 
     auto rowHeights = renderGrid.trackSizesForComputedStyle(GridTrackSizingDirection::ForRows);
@@ -1522,20 +1566,17 @@
     for (unsigned i = 0; i < rowPositions.size(); ++i) {
         auto rowStartLine = rowLineAt(rowPositions[i]);
 
-        Path rowPaths;
         if (gridOverlay.config.showExtendedGridLines) {
-            auto line = rowStartLine.extendedToBounds(viewportBounds);
-            rowPaths.moveTo(line.start());
-            rowPaths.addLineTo(line.end());
+            auto extendedLine = rowStartLine.extendedToBounds(viewportBounds);
+            gridHighlightOverlay.gridLines.append(extendedLine);
         } else {
-            rowPaths.moveTo(rowStartLine.start());
-            rowPaths.addLineTo(rowStartLine.end());
+            gridHighlightOverlay.gridLines.append(rowStartLine);
         }
-        
+
         FloatPoint gapLabelPosition = rowStartLine.start();
         if (i) {
             FloatLine lineBetweenRowStarts = { rowStartLine.start(), previousRowEndLine.start() };
-            drawLayoutHatching(context, { previousRowEndLine.start(), previousRowEndLine.end(), rowStartLine.end(), rowStartLine.start() });
+            gridHighlightOverlay.gaps.append({ previousRowEndLine.start(), previousRowEndLine.end(), rowStartLine.end(), rowStartLine.start() });
             gapLabelPosition = lineBetweenRowStarts.pointAtRelativeDistance(0.5);
         }
 
@@ -1542,17 +1583,15 @@
         if (i < rowHeights.size() && i < rowPositions.size()) {
             auto height = rowHeights[i];
             auto rowEndLine = rowLineAt(rowPositions[i] + height);
-            
+
             if (gridOverlay.config.showExtendedGridLines) {
                 auto extendedLine = rowEndLine.extendedToBounds(viewportBounds);
-                rowPaths.moveTo(extendedLine.start());
-                rowPaths.addLineTo(extendedLine.end());
+                gridHighlightOverlay.gridLines.append(extendedLine);
             } else {
-                rowPaths.moveTo(rowEndLine.start());
-                rowPaths.addLineTo(rowEndLine.end());
+                gridHighlightOverlay.gridLines.append(rowEndLine);
             }
             previousRowEndLine = rowEndLine;
-            
+
             if (gridOverlay.config.showTrackSizes) {
                 auto trackSizeLabel = String::number(roundf(height));
                 trackSizeLabel.append("px"_s);
@@ -1568,13 +1607,11 @@
                     }
                 }
                 FloatLine trackLeftLine = { rowStartLine.start(), rowEndLine.start() };
-                drawLayoutLabel(context, trackSizeLabel, trackLeftLine.pointAtRelativeDistance(0.5), LabelArrowDirection::Left, translucentLabelBackgroundColor);
+                gridHighlightOverlay.labels.append(buildLabel(trackSizeLabel, trackLeftLine.pointAtRelativeDistance(0.5), translucentLabelBackgroundColor, LabelArrowDirection::Left));
             }
         } else
             previousRowEndLine = rowStartLine;
 
-        context.strokePath(rowPaths);
-        
         StringBuilder lineLabel;
         if (gridOverlay.config.showLineNumbers)
             lineLabel.append(i + 1, thinSpace, bullet, thinSpace, -static_cast<int>(rowPositions.size() - i));
@@ -1587,9 +1624,9 @@
         }
         // FIXME: <webkit.org/b/221972> Layout labels can be drawn outside the viewport, and a best effort should be made to keep them in the viewport while the grid is in the viewport.
         if (!lineLabel.isEmpty())
-            drawLayoutLabel(context, lineLabel.toString(), gapLabelPosition, LabelArrowDirection::Right);
+            gridHighlightOverlay.labels.append(buildLabel(lineLabel.toString(), gapLabelPosition, Color::white, LabelArrowDirection::Right));
     }
-    
+
     if (gridOverlay.config.showAreaNames) {
         for (auto& gridArea : node->renderStyle()->namedGridArea()) {
             auto& name = gridArea.key;
@@ -1600,25 +1637,24 @@
             auto columnEndLine = columnLineAt(columnPositions[area.columns.endLine() - 1] + columnWidths[area.columns.endLine() - 1]);
             auto rowStartLine = rowLineAt(rowPositions[area.rows.startLine()] - rowPositions[0]);
             auto rowEndLine = rowLineAt(rowPositions[area.rows.endLine() - 1] + rowHeights[area.rows.endLine() - 1] - rowPositions[0]);
-            
+
             Optional<FloatPoint> topLeft = columnStartLine.intersectionWith(rowStartLine);
             Optional<FloatPoint> topRight = columnEndLine.intersectionWith(rowStartLine);
             Optional<FloatPoint> bottomRight = columnEndLine.intersectionWith(rowEndLine);
             Optional<FloatPoint> bottomLeft = columnStartLine.intersectionWith(rowEndLine);
-            
+
             // If any two lines are coincident with each other, they will not have an intersection, which can occur with extreme `transform: perspective(...)` values.
             if (!topLeft || !topRight || !bottomRight || !bottomLeft)
                 continue;
 
-            FloatQuad areaQuad = { *topLeft, *topRight, *bottomRight, *bottomLeft };
-
-            context.setStrokeThickness(3);
-            context.strokePath(quadToPath(areaQuad));
-
-            context.setStrokeThickness(1);
-            drawLayoutLabel(context, name, areaQuad.p1(), LabelArrowDirection::None, translucentLabelBackgroundColor, areaQuad.boundingBox().width());
+            InspectorOverlay::Highlight::GridHighlightOverlay::Area highlightOverlayArea;
+            highlightOverlayArea.name = name;
+            highlightOverlayArea.quad = { *topLeft, *topRight, *bottomRight, *bottomLeft };
+            gridHighlightOverlay.areas.append(highlightOverlayArea);
         }
     }
+
+    return { gridHighlightOverlay };
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/inspector/InspectorOverlay.h (274821 => 274822)


--- trunk/Source/WebCore/inspector/InspectorOverlay.h	2021-03-23 00:05:29 UTC (rev 274821)
+++ trunk/Source/WebCore/inspector/InspectorOverlay.h	2021-03-23 00:05:45 UTC (rev 274822)
@@ -30,6 +30,7 @@
 #pragma once
 
 #include "Color.h"
+#include "FloatLine.h"
 #include "FloatQuad.h"
 #include "FloatRect.h"
 #include "Path.h"
@@ -64,10 +65,19 @@
     InspectorOverlay(Page&, InspectorClient*);
     ~InspectorOverlay();
 
+    enum class LabelArrowDirection {
+        None,
+        Down,
+        Up,
+        Left,
+        Right,
+    };
+
     struct Highlight {
         WTF_MAKE_STRUCT_FAST_ALLOCATED;
 
         enum class Type {
+            None, // Provides only non-quad information, including grid overlays.
             Node, // Provides 4 quads: margin, border, padding, content.
             NodeList, // Provides a list of nodes.
             Rects, // Provides a list of quads.
@@ -84,6 +94,45 @@
             bool usePageCoordinates;
         };
 
+        struct GridHighlightOverlay {
+            WTF_MAKE_STRUCT_FAST_ALLOCATED;
+
+            struct Label {
+                WTF_MAKE_STRUCT_FAST_ALLOCATED;
+                String text;
+                FloatPoint location;
+                Color backgroundColor;
+                LabelArrowDirection arrowDirection;
+
+#if PLATFORM(IOS_FAMILY)
+                template<class Encoder> void encode(Encoder&) const;
+                template<class Decoder> static Optional<InspectorOverlay::Highlight::GridHighlightOverlay::Label> decode(Decoder&);
+#endif
+            };
+
+            struct Area {
+                WTF_MAKE_STRUCT_FAST_ALLOCATED;
+                String name;
+                FloatQuad quad;
+
+#if PLATFORM(IOS_FAMILY)
+                template<class Encoder> void encode(Encoder&) const;
+                template<class Decoder> static Optional<InspectorOverlay::Highlight::GridHighlightOverlay::Area> decode(Decoder&);
+#endif
+            };
+
+            Color color;
+            Vector<FloatLine> gridLines;
+            Vector<FloatQuad> gaps;
+            Vector<Area> areas;
+            Vector<Label> labels;
+
+#if PLATFORM(IOS_FAMILY)
+            template<class Encoder> void encode(Encoder&) const;
+            template<class Decoder> static Optional<InspectorOverlay::Highlight::GridHighlightOverlay> decode(Decoder&);
+#endif
+        };
+
         void setDataFromConfig(const Config& config)
         {
             contentColor = config.content;
@@ -102,6 +151,7 @@
 
         Type type {Type::Node};
         Vector<FloatQuad> quads;
+        Vector<GridHighlightOverlay> gridHighlightOverlays;
         bool usePageCoordinates {true};
 
         using Bounds = FloatRect;
@@ -132,7 +182,7 @@
 
     void update();
     void paint(GraphicsContext&);
-    void getHighlight(Highlight&, CoordinateSystem) const;
+    void getHighlight(Highlight&, CoordinateSystem);
     bool shouldShowOverlay() const;
 
     void hideHighlight();
@@ -166,14 +216,6 @@
         Highlight::Bounds bounds;
         Path titlePath;
     };
-    
-    enum class LabelArrowDirection {
-        None,
-        Down,
-        Up,
-        Left,
-        Right,
-    };
 
     RulerExclusion drawNodeHighlight(GraphicsContext&, Node&);
     RulerExclusion drawQuadHighlight(GraphicsContext&, const FloatQuad&);
@@ -186,7 +228,8 @@
     void drawLayoutHatching(GraphicsContext&, FloatQuad);
     void drawLayoutLabel(GraphicsContext&, String, FloatPoint, LabelArrowDirection, Color backgroundColor = Color::white, float maximumWidth = 0);
 
-    void drawGridOverlay(GraphicsContext&, const InspectorOverlay::Grid&);
+    void drawGridOverlay(GraphicsContext&, const InspectorOverlay::Highlight::GridHighlightOverlay&);
+    Optional<InspectorOverlay::Highlight::GridHighlightOverlay> buildGridOverlay(const InspectorOverlay::Grid&, bool offsetBoundsByScroll = false);
 
     void updatePaintRectsTimerFired();
 
@@ -213,4 +256,75 @@
     bool m_showRulersDuringElementSelection { false };
 };
 
+#if PLATFORM(IOS_FAMILY)
+
+template<class Encoder> void InspectorOverlay::Highlight::GridHighlightOverlay::encode(Encoder& encoder) const
+{
+    encoder << color;
+    encoder << gridLines;
+    encoder << gaps;
+    encoder << areas;
+    encoder << labels;
+}
+
+template<class Decoder> Optional<InspectorOverlay::Highlight::GridHighlightOverlay> InspectorOverlay::Highlight::GridHighlightOverlay::decode(Decoder& decoder)
+{
+    InspectorOverlay::Highlight::GridHighlightOverlay gridHighlightOverlay;
+    if (!decoder.decode(gridHighlightOverlay.color))
+        return { };
+    if (!decoder.decode(gridHighlightOverlay.gridLines))
+        return { };
+    if (!decoder.decode(gridHighlightOverlay.gaps))
+        return { };
+    if (!decoder.decode(gridHighlightOverlay.areas))
+        return { };
+    if (!decoder.decode(gridHighlightOverlay.labels))
+        return { };
+    return { gridHighlightOverlay };
+}
+
+template<class Encoder> void InspectorOverlay::Highlight::GridHighlightOverlay::Label::encode(Encoder& encoder) const
+{
+    encoder << text;
+    encoder << location;
+    encoder << backgroundColor;
+    encoder << static_cast<uint32_t>(arrowDirection);
+}
+
+template<class Decoder> Optional<InspectorOverlay::Highlight::GridHighlightOverlay::Label> InspectorOverlay::Highlight::GridHighlightOverlay::Label::decode(Decoder& decoder)
+{
+    InspectorOverlay::Highlight::GridHighlightOverlay::Label label;
+    if (!decoder.decode(label.text))
+        return { };
+    if (!decoder.decode(label.location))
+        return { };
+    if (!decoder.decode(label.backgroundColor))
+        return { };
+
+    uint32_t arrowDirection;
+    if (!decoder.decode(arrowDirection))
+        return { };
+    label.arrowDirection = (InspectorOverlay::LabelArrowDirection)arrowDirection;
+
+    return { label };
+}
+
+template<class Encoder> void InspectorOverlay::Highlight::GridHighlightOverlay::Area::encode(Encoder& encoder) const
+{
+    encoder << name;
+    encoder << quad;
+}
+
+template<class Decoder> Optional<InspectorOverlay::Highlight::GridHighlightOverlay::Area> InspectorOverlay::Highlight::GridHighlightOverlay::Area::decode(Decoder& decoder)
+{
+    InspectorOverlay::Highlight::GridHighlightOverlay::Area area;
+    if (!decoder.decode(area.name))
+        return { };
+    if (!decoder.decode(area.quad))
+        return { };
+    return { area };
+}
+
+#endif
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/platform/graphics/FloatLine.h (274821 => 274822)


--- trunk/Source/WebCore/platform/graphics/FloatLine.h	2021-03-23 00:05:29 UTC (rev 274821)
+++ trunk/Source/WebCore/platform/graphics/FloatLine.h	2021-03-23 00:05:45 UTC (rev 274822)
@@ -50,10 +50,13 @@
     
     float length() const { return m_length; }
 
-    const FloatPoint pointAtAbsoluteDistance(float) const;
+    WEBCORE_EXPORT const FloatPoint pointAtAbsoluteDistance(float) const;
     const FloatPoint pointAtRelativeDistance(float) const;
     const FloatLine extendedToBounds(const FloatRect&) const;
     const Optional<FloatPoint> intersectionWith(const FloatLine&) const;
+
+    template<class Encoder> void encode(Encoder&) const;
+    template<class Decoder> static Optional<FloatLine> decode(Decoder&);
     
 private:
     FloatPoint m_start { 0, 0 };
@@ -61,4 +64,25 @@
     float m_length { 0 };
 };
 
+template<class Encoder> void FloatLine::encode(Encoder& encoder) const
+{
+    encoder << m_start;
+    encoder << m_end;
 }
+
+template<class Decoder> Optional<FloatLine> FloatLine::decode(Decoder& decoder)
+{
+    Optional<FloatPoint> start;
+    decoder >> start;
+    if (!start)
+        return WTF::nullopt;
+
+    Optional<FloatPoint> end;
+    decoder >> end;
+    if (!end)
+        return WTF::nullopt;
+
+    return {{ *start, *end }};
+}
+
+}

Modified: trunk/Source/WebKit/ChangeLog (274821 => 274822)


--- trunk/Source/WebKit/ChangeLog	2021-03-23 00:05:29 UTC (rev 274821)
+++ trunk/Source/WebKit/ChangeLog	2021-03-23 00:05:45 UTC (rev 274822)
@@ -1,3 +1,34 @@
+2021-03-22  Patrick Angle  <[email protected]>
+
+        Web Inspector: Port grid overlay drawing to iOS
+        https://bugs.webkit.org/show_bug.cgi?id=223396
+
+        Reviewed by BJ Burg.
+
+        Port drawing routines from `WebCore::InspectorOverlay` to use `CALayer`s on iOS to enable drawing grid overlays
+        on iOS. Drawing logic is, as much as possible, equivalent to that defined in `WebCore::InspectorOverlay`, with
+        changes to fit the CALayer model.
+
+        * UIProcess/Inspector/ios/WKInspectorHighlightView.h:
+        * UIProcess/Inspector/ios/WKInspectorHighlightView.mm:
+        (-[WKInspectorHighlightView initWithFrame:]):
+        (-[WKInspectorHighlightView _removeAllLayers]):
+        (-[WKInspectorHighlightView _createLayers:]):
+        (layerPath):
+        - Path should be closed so that objects being stroked are stroked on all edges.
+        (-[WKInspectorHighlightView _layoutForNodeListHighlight:]):
+        (-[WKInspectorHighlightView _layoutForRectsHighlight:]):
+        (-[WKInspectorHighlightView _createGridOverlayLayers:scale:]):
+        (createLayoutHatchingLayer):
+        (createLayoutLabelLayer):
+        (-[WKInspectorHighlightView _createGridOverlayLayer:scale:]):
+        - Create layers for the grid overlays.
+        (-[WKInspectorHighlightView update:scale:]):
+        - Obtain the view scale so that `CATextLayer`s can have the correct content scale set.
+        (-[WKInspectorHighlightView update:]): Deleted.
+        * UIProcess/ios/WKContentView.mm:
+        (-[WKContentView _showInspectorHighlight:]):
+
 2021-03-22  Peng Liu  <[email protected]>
 
         [GPUP] Add a "wallTime" field to struct RemoteMediaPlayerState

Modified: trunk/Source/WebKit/Shared/WebCoreArgumentCoders.cpp (274821 => 274822)


--- trunk/Source/WebKit/Shared/WebCoreArgumentCoders.cpp	2021-03-23 00:05:29 UTC (rev 274821)
+++ trunk/Source/WebKit/Shared/WebCoreArgumentCoders.cpp	2021-03-23 00:05:45 UTC (rev 274822)
@@ -1650,6 +1650,7 @@
     encoder << highlight.borderColor;
     encoder << highlight.marginColor;
     encoder << highlight.quads;
+    encoder << highlight.gridHighlightOverlays;
 }
 
 bool ArgumentCoder<InspectorOverlay::Highlight>::decode(Decoder& decoder, InspectorOverlay::Highlight& highlight)
@@ -1673,6 +1674,8 @@
         return false;
     if (!decoder.decode(highlight.quads))
         return false;
+    if (!decoder.decode(highlight.gridHighlightOverlays))
+        return false;
     return true;
 }
 

Modified: trunk/Source/WebKit/UIProcess/Inspector/ios/WKInspectorHighlightView.h (274821 => 274822)


--- trunk/Source/WebKit/UIProcess/Inspector/ios/WKInspectorHighlightView.h	2021-03-23 00:05:29 UTC (rev 274821)
+++ trunk/Source/WebKit/UIProcess/Inspector/ios/WKInspectorHighlightView.h	2021-03-23 00:05:45 UTC (rev 274822)
@@ -30,8 +30,9 @@
 
 @interface WKInspectorHighlightView : UIView {
     RetainPtr<NSMutableArray<CAShapeLayer *>> _layers;
+    RetainPtr<NSMutableArray<CALayer *>> _gridOverlayLayers;
 }
-- (void)update:(const WebCore::InspectorOverlay::Highlight&)highlight;
+- (void)update:(const WebCore::InspectorOverlay::Highlight&)highlight scale:(double)scale;
 @end
 
 #endif

Modified: trunk/Source/WebKit/UIProcess/Inspector/ios/WKInspectorHighlightView.mm (274821 => 274822)


--- trunk/Source/WebKit/UIProcess/Inspector/ios/WKInspectorHighlightView.mm	2021-03-23 00:05:29 UTC (rev 274821)
+++ trunk/Source/WebKit/UIProcess/Inspector/ios/WKInspectorHighlightView.mm	2021-03-23 00:05:45 UTC (rev 274822)
@@ -28,8 +28,12 @@
 
 #if PLATFORM(IOS_FAMILY)
 
+#import <WebCore/FloatLine.h>
 #import <WebCore/FloatQuad.h>
+#import <WebCore/FontCascade.h>
+#import <WebCore/FontCascadeDescription.h>
 #import <WebCore/GeometryUtilities.h>
+#import <WebCore/TextRun.h>
 
 @implementation WKInspectorHighlightView
 
@@ -38,6 +42,7 @@
     if (!(self = [super initWithFrame:frame]))
         return nil;
     _layers = adoptNS([[NSMutableArray alloc] init]);
+    _gridOverlayLayers = adoptNS([[NSMutableArray alloc] init]);
     return self;
 }
 
@@ -52,6 +57,9 @@
     for (CAShapeLayer *layer in _layers.get())
         [layer removeFromSuperlayer];
     [_layers removeAllObjects];
+    for (CALayer *layer in _gridOverlayLayers.get())
+        [layer removeFromSuperlayer];
+    [_gridOverlayLayers removeAllObjects];
 }
 
 - (void)_createLayers:(NSUInteger)numLayers
@@ -59,8 +67,6 @@
     if ([_layers count] == numLayers)
         return;
 
-    [self _removeAllLayers];
-
     for (NSUInteger i = 0; i < numLayers; ++i) {
         auto layer = adoptNS([[CAShapeLayer alloc] init]);
         [_layers addObject:layer.get()];
@@ -202,6 +208,7 @@
     CGPathAddLineToPoint(path.get(), 0, outerQuad.p4().x(), outerQuad.p4().y());
     CGPathAddLineToPoint(path.get(), 0, outerQuad.p3().x(), outerQuad.p3().y());
     CGPathAddLineToPoint(path.get(), 0, outerQuad.p2().x(), outerQuad.p2().y());
+    CGPathCloseSubpath(path.get());
     layer.path = path.get();
 }
 
@@ -235,10 +242,8 @@
 
 - (void)_layoutForNodeListHighlight:(const WebCore::InspectorOverlay::Highlight&)highlight
 {
-    if (!highlight.quads.size()) {
-        [self _removeAllLayers];
+    if (!highlight.quads.size())
         return;
-    }
 
     unsigned nodeCount = highlight.quads.size() / 4;
     [self _createLayers:nodeCount * 4];
@@ -250,10 +255,8 @@
 - (void)_layoutForRectsHighlight:(const WebCore::InspectorOverlay::Highlight&)highlight
 {
     NSUInteger numLayers = highlight.quads.size();
-    if (!numLayers) {
-        [self _removeAllLayers];
+    if (!numLayers)
         return;
-    }
 
     [self _createLayers:numLayers];
 
@@ -265,12 +268,209 @@
     }
 }
 
-- (void)update:(const WebCore::InspectorOverlay::Highlight&)highlight
+- (void)_createGridOverlayLayers:(const WebCore::InspectorOverlay::Highlight&)highlight scale:(double)scale
 {
+    for (auto gridOverlay : highlight.gridHighlightOverlays) {
+        auto layer = [self _createGridOverlayLayer:gridOverlay scale:scale];
+        [_gridOverlayLayers addObject:layer];
+        [self.layer addSublayer:layer];
+    }
+}
+
+static CALayer * createLayoutHatchingLayer(WebCore::FloatQuad quad, WebCore::Color strokeColor)
+{
+    CAShapeLayer *layer = [CAShapeLayer layer];
+
+    constexpr auto hatchSpacing = 12;
+    auto hatchPath = adoptCF(CGPathCreateMutable());
+
+    WebCore::FloatLine topSide = { quad.p1(), quad.p2() };
+    WebCore::FloatLine leftSide = { quad.p1(), quad.p4() };
+
+    // 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.
+    if (topSide.length() > leftSide.length()) {
+        WebCore::FloatLine bottomSide = { quad.p4(), quad.p3() };
+        // 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.
+        for (float x = -leftSide.length(); x < topSide.length(); x += hatchSpacing) {
+            auto startPoint = topSide.pointAtAbsoluteDistance(x);
+            auto endPoint = bottomSide.pointAtAbsoluteDistance(x + leftSide.length());
+            CGPathMoveToPoint(hatchPath.get(), 0, startPoint.x(), startPoint.y());
+            CGPathAddLineToPoint(hatchPath.get(), 0, endPoint.x(), endPoint.y());
+        }
+    } else {
+        WebCore::FloatLine rightSide = { quad.p2(), quad.p3() };
+        // 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.
+        for (float y = -topSide.length(); y < leftSide.length(); y += hatchSpacing) {
+            auto startPoint = leftSide.pointAtAbsoluteDistance(y);
+            auto endPoint = rightSide.pointAtAbsoluteDistance(y + topSide.length());
+            CGPathMoveToPoint(hatchPath.get(), 0, startPoint.x(), startPoint.y());
+            CGPathAddLineToPoint(hatchPath.get(), 0, endPoint.x(), endPoint.y());
+        }
+    }
+    layer.path = hatchPath.get();
+    layer.strokeColor = cachedCGColor(strokeColor);
+    layer.lineWidth = 0.5;
+    layer.lineDashPattern = @[[NSNumber numberWithInt:2], [NSNumber numberWithInt:2]];
+
+    CAShapeLayer *maskLayer = [CAShapeLayer layer];
+    layerPath(maskLayer, quad);
+    layer.mask = maskLayer;
+    return layer;
+}
+
+static CALayer * createLayoutLabelLayer(String label, WebCore::FloatPoint point, WebCore::InspectorOverlay::LabelArrowDirection direction, WebCore::Color backgroundColor, WebCore::Color strokeColor, double scale, float maximumWidth = 0)
+{
+    WebCore::FontCascadeDescription fontDescription;
+    fontDescription.setFamilies({ "system-ui" });
+    fontDescription.setWeight(WebCore::FontSelectionValue(500));
+    fontDescription.setComputedSize(12);
+
+    WebCore::FontCascade font(WTFMove(fontDescription), 0, 0);
+    font.update(nullptr);
+
+    constexpr auto padding = 4;
+    constexpr auto arrowSize = 4;
+    float textHeight = font.fontMetrics().floatHeight();
+
+    float textWidth = font.width(WebCore::TextRun(label));
+    if (maximumWidth && textWidth + (padding * 2) > maximumWidth) {
+        label.append("..."_s);
+        while (textWidth + (padding * 2) > maximumWidth && label.length() >= 4) {
+            // Remove the fourth from last character (the character before the ellipsis) and remeasure.
+            label.remove(label.length() - 4);
+            textWidth = font.width(WebCore::TextRun(label));
+        }
+    }
+
+    auto labelPath = adoptCF(CGPathCreateMutable());
+
+    // Note: Implementation Difference - The textPosition is the center of text, unlike WebCore::InspectorOverlay, where the textPosition is leftmost point on the baseline of the text.
+    WebCore::FloatPoint textPosition;
+
+    switch (direction) {
+    case WebCore::InspectorOverlay::LabelArrowDirection::Down:
+        CGPathMoveToPoint(labelPath.get(), 0, -(textWidth / 2) - padding, -textHeight - (padding * 2) - arrowSize);
+        CGPathAddLineToPoint(labelPath.get(), 0, -(textWidth / 2) - padding, -arrowSize);
+        CGPathAddLineToPoint(labelPath.get(), 0, -arrowSize, -arrowSize);
+        CGPathAddLineToPoint(labelPath.get(), 0, 0, 0);
+        CGPathAddLineToPoint(labelPath.get(), 0, arrowSize, -arrowSize);
+        CGPathAddLineToPoint(labelPath.get(), 0, (textWidth / 2) + padding, -arrowSize);
+        CGPathAddLineToPoint(labelPath.get(), 0, (textWidth / 2) + padding, -textHeight - (padding * 2) - arrowSize);
+        textPosition = WebCore::FloatPoint(0, -(textHeight / 2) - arrowSize - padding);
+        break;
+    case WebCore::InspectorOverlay::LabelArrowDirection::Up:
+        CGPathMoveToPoint(labelPath.get(), 0, -(textWidth / 2) - padding, textHeight + (padding * 2) + arrowSize);
+        CGPathAddLineToPoint(labelPath.get(), 0, -(textWidth / 2) - padding, arrowSize);
+        CGPathAddLineToPoint(labelPath.get(), 0, -arrowSize, arrowSize);
+        CGPathAddLineToPoint(labelPath.get(), 0, 0, 0);
+        CGPathAddLineToPoint(labelPath.get(), 0, arrowSize, arrowSize);
+        CGPathAddLineToPoint(labelPath.get(), 0, (textWidth / 2) + padding, arrowSize);
+        CGPathAddLineToPoint(labelPath.get(), 0, (textWidth / 2) + padding, textHeight + (padding * 2) + arrowSize);
+        textPosition = WebCore::FloatPoint(0, (textHeight / 2) + arrowSize + padding);
+        break;
+    case WebCore::InspectorOverlay::LabelArrowDirection::Right:
+        CGPathMoveToPoint(labelPath.get(), 0, -textWidth - (padding * 2) - arrowSize, (textHeight / 2) + padding);
+        CGPathAddLineToPoint(labelPath.get(), 0, -arrowSize, (textHeight / 2) + padding);
+        CGPathAddLineToPoint(labelPath.get(), 0, -arrowSize, arrowSize);
+        CGPathAddLineToPoint(labelPath.get(), 0, 0, 0);
+        CGPathAddLineToPoint(labelPath.get(), 0, -arrowSize, -arrowSize);
+        CGPathAddLineToPoint(labelPath.get(), 0, -arrowSize, -(textHeight / 2) - padding);
+        CGPathAddLineToPoint(labelPath.get(), 0, -textWidth - (padding * 2) - arrowSize, -(textHeight / 2) - padding);
+        textPosition = WebCore::FloatPoint(-(textWidth / 2) - arrowSize - padding, 0);
+        break;
+    case WebCore::InspectorOverlay::LabelArrowDirection::Left:
+        CGPathMoveToPoint(labelPath.get(), 0, textWidth + (padding * 2) + arrowSize, (textHeight / 2) + padding);
+        CGPathAddLineToPoint(labelPath.get(), 0, arrowSize, (textHeight / 2) + padding);
+        CGPathAddLineToPoint(labelPath.get(), 0, arrowSize, arrowSize);
+        CGPathAddLineToPoint(labelPath.get(), 0, 0, 0);
+        CGPathAddLineToPoint(labelPath.get(), 0, arrowSize, -arrowSize);
+        CGPathAddLineToPoint(labelPath.get(), 0, arrowSize, -(textHeight / 2) - padding);
+        CGPathAddLineToPoint(labelPath.get(), 0, textWidth + (padding * 2) + arrowSize, -(textHeight / 2) - padding);
+        textPosition = WebCore::FloatPoint((textWidth / 2) + arrowSize + padding, 0);
+        break;
+    case WebCore::InspectorOverlay::LabelArrowDirection::None:
+        CGPathMoveToPoint(labelPath.get(), 0, 0, 0);
+        CGPathAddLineToPoint(labelPath.get(), 0, 0, textHeight + (padding * 2));
+        CGPathAddLineToPoint(labelPath.get(), 0, textWidth + (padding * 2), textHeight + (padding * 2));
+        CGPathAddLineToPoint(labelPath.get(), 0, textWidth + (padding * 2), 0);
+        textPosition = WebCore::FloatPoint(padding + (textWidth / 2), padding + (textHeight / 2));
+        break;
+    }
+
+    CGPathCloseSubpath(labelPath.get());
+
+    CALayer *layer = [CALayer layer];
+
+    CAShapeLayer *labelPathLayer = [CAShapeLayer layer];
+    labelPathLayer.path = labelPath.get();
+    labelPathLayer.fillColor = cachedCGColor(backgroundColor);
+    labelPathLayer.strokeColor = cachedCGColor(strokeColor);
+    labelPathLayer.position = CGPointMake(point.x(), point.y());
+    [layer addSublayer:labelPathLayer];
+
+    CATextLayer *textLayer = [CATextLayer layer];
+    textLayer.frame = CGRectMake(0, 0, textWidth, textHeight);
+    textLayer.string = label;
+    textLayer.font = font.primaryFont().getCTFont();
+    textLayer.fontSize = 12;
+    textLayer.alignmentMode = kCAAlignmentLeft;
+    textLayer.foregroundColor = CGColorGetConstantColor(kCGColorBlack);
+    textLayer.position = CGPointMake(textPosition.x() + point.x(), textPosition.y() + point.y());
+    textLayer.contentsScale = [[UIScreen mainScreen] scale] * scale;
+    [layer addSublayer:textLayer];
+
+    return layer;
+}
+
+- (CALayer *)_createGridOverlayLayer:(const WebCore::InspectorOverlay::Highlight::GridHighlightOverlay&)overlay scale:(double)scale
+{
+    // Keep implementation roughly equivilent to `WebCore::InspectorOverlay::drawGridOverlay`.
+    CALayer *layer = [CALayer layer];
+
+    auto gridLinesPath = adoptCF(CGPathCreateMutable());
+    for (auto gridLine : overlay.gridLines) {
+        CGPathMoveToPoint(gridLinesPath.get(), 0, gridLine.start().x(), gridLine.start().y());
+        CGPathAddLineToPoint(gridLinesPath.get(), 0, gridLine.end().x(), gridLine.end().y());
+    }
+    CAShapeLayer *gridLinesLayer = [CAShapeLayer layer];
+    gridLinesLayer.path = gridLinesPath.get();
+    gridLinesLayer.lineWidth = 1;
+    gridLinesLayer.strokeColor = cachedCGColor(overlay.color);
+    [layer addSublayer:gridLinesLayer];
+
+    for (auto gapQuad : overlay.gaps)
+        [layer addSublayer:createLayoutHatchingLayer(gapQuad, overlay.color)];
+
+    for (auto area : overlay.areas) {
+        CAShapeLayer *areaLayer = [CAShapeLayer layer];
+        layerPath(areaLayer, area.quad);
+        areaLayer.lineWidth = 3;
+        areaLayer.fillColor = CGColorGetConstantColor(kCGColorClear);
+        areaLayer.strokeColor = cachedCGColor(overlay.color);
+        [layer addSublayer:areaLayer];
+    }
+
+    constexpr auto translucentLabelBackgroundColor = WebCore::Color::white.colorWithAlphaByte(153);
+
+    for (auto area : overlay.areas)
+        [layer addSublayer:createLayoutLabelLayer(area.name, area.quad.p1(), WebCore::InspectorOverlay::LabelArrowDirection::None, translucentLabelBackgroundColor, overlay.color, scale, area.quad.boundingBox().width())];
+
+    for (auto label : overlay.labels)
+        [layer addSublayer:createLayoutLabelLayer(label.text, label.location, label.arrowDirection, label.backgroundColor, overlay.color, scale)];
+
+    return layer;
+}
+
+- (void)update:(const WebCore::InspectorOverlay::Highlight&)highlight scale:(double)scale
+{
+    [self _removeAllLayers];
+
     if (highlight.type == WebCore::InspectorOverlay::Highlight::Type::Node || highlight.type == WebCore::InspectorOverlay::Highlight::Type::NodeList)
         [self _layoutForNodeListHighlight:highlight];
     else if (highlight.type == WebCore::InspectorOverlay::Highlight::Type::Rects)
         [self _layoutForRectsHighlight:highlight];
+
+    [self _createGridOverlayLayers:highlight scale:scale];
 }
 
 @end

Modified: trunk/Source/WebKit/UIProcess/ios/WKContentView.mm (274821 => 274822)


--- trunk/Source/WebKit/UIProcess/ios/WKContentView.mm	2021-03-23 00:05:29 UTC (rev 274821)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentView.mm	2021-03-23 00:05:45 UTC (rev 274822)
@@ -365,7 +365,7 @@
         [self insertSubview:_inspectorHighlightView.get() aboveSubview:_rootContentView.get()];
     }
 
-    [_inspectorHighlightView update:highlight];
+    [_inspectorHighlightView update:highlight scale:[self _contentZoomScale]];
 }
 
 - (void)_hideInspectorHighlight
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to