Diff
Modified: trunk/Source/WebCore/ChangeLog (292207 => 292208)
--- trunk/Source/WebCore/ChangeLog 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Source/WebCore/ChangeLog 2022-04-01 08:17:36 UTC (rev 292208)
@@ -1,3 +1,64 @@
+2022-04-01 Tim Horton <timothy_hor...@apple.com>
+
+ Add a debug overlay for interaction regions
+ https://bugs.webkit.org/show_bug.cgi?id=238187
+
+ Reviewed by Wenson Hsieh.
+
+ * Sources.txt:
+ * WebCore.xcodeproj/project.pbxproj:
+ * dom/Node.cpp:
+ (WebCore::Node::willRespondToTouchEvents):
+ * dom/Node.h:
+ Expose `willRespondToTouchEvents`, similar to `willRespondToMouseMoveEvents`.
+
+ * page/DebugOverlayRegions.h:
+ * page/DebugPageOverlays.cpp:
+ (WebCore::InteractionRegionOverlay::updateRegion):
+ (WebCore::pathsForRegion):
+ (WebCore::InteractionRegionOverlay::activeRegion):
+ (WebCore::drawCheckbox):
+ (WebCore::InteractionRegionOverlay::rectForSettingAtIndex):
+ (WebCore::InteractionRegionOverlay::valueForSetting):
+ (WebCore::InteractionRegionOverlay::drawSettings):
+ (WebCore::InteractionRegionOverlay::drawRect):
+ (WebCore::InteractionRegionOverlay::mouseEvent):
+ (WebCore::RegionOverlay::create):
+ (WebCore::DebugPageOverlays::updateOverlayRegionVisibility):
+ * page/DebugPageOverlays.h:
+ (WebCore::DebugPageOverlays::didLayout):
+ (WebCore::DebugPageOverlays::didChangeEventHandlers):
+ (WebCore::DebugPageOverlays::doAfterUpdateRendering):
+ Add an overlay for indicating interaction regions.
+
+ * page/FrameSnapshotting.cpp:
+ (WebCore::styleContainsComplexBackground):
+ (WebCore::estimatedBackgroundColorForRange):
+ * page/FrameSnapshotting.h:
+ * page/TextIndicator.cpp:
+ (WebCore::styleContainsComplexBackground): Deleted.
+ (WebCore::estimatedBackgroundColorForRange): Deleted.
+ Move `estimatedBackgroundColorForRange` from TextIndicator to
+ FrameSnapshotting for ease of reuse.
+
+ * page/InteractionRegion.cpp: Added.
+ (WebCore::absoluteBoundingRectForRange):
+ (WebCore::regionForElement):
+ (WebCore::cursorTypeForElement):
+ (WebCore::interactionRegions):
+ * page/InteractionRegion.h: Added.
+ (WebCore::InteractionRegion::encode const):
+ (WebCore::InteractionRegion::decode):
+ Add InteractionRegion, which keeps track of the location of and metadata
+ about interaction regions.
+
+ * platform/graphics/LayoutSize.h:
+ (WebCore::LayoutSize::minDimension const):
+ (WebCore::LayoutSize::maxDimension const):
+ * platform/graphics/RoundedRect.h:
+ (WebCore::RoundedRect::Radii::minimumRadius const):
+ Add minimumRadius() to Radii.
+
2022-04-01 Youenn Fablet <you...@apple.com>
Persistent notifications should work in document scopes as well as service worker global scopes
Modified: trunk/Source/WebCore/Headers.cmake (292207 => 292208)
--- trunk/Source/WebCore/Headers.cmake 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Source/WebCore/Headers.cmake 2022-04-01 08:17:36 UTC (rev 292208)
@@ -1127,6 +1127,7 @@
page/GlobalFrameIdentifier.h
page/GlobalWindowIdentifier.h
page/ImageAnalysisQueue.h
+ page/InteractionRegion.h
page/LayoutMilestone.h
page/MediaCanStartListener.h
page/MediaControlsContextMenuItem.h
Modified: trunk/Source/WebCore/Sources.txt (292207 => 292208)
--- trunk/Source/WebCore/Sources.txt 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Source/WebCore/Sources.txt 2022-04-01 08:17:36 UTC (rev 292208)
@@ -1753,6 +1753,7 @@
page/History.cpp
page/ImageAnalysisQueue.cpp
page/ImageOverlayController.cpp
+page/InteractionRegion.cpp
page/IntersectionObserver.cpp
page/IntersectionObserverEntry.cpp
page/Location.cpp
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (292207 => 292208)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2022-04-01 08:17:36 UTC (rev 292208)
@@ -888,6 +888,7 @@
2D9F0E1314FF1CBF00BA0FF7 /* linearSRGB.icc in Resources */ = {isa = PBXBuildFile; fileRef = 2D9F0E1214FF1CBF00BA0FF7 /* linearSRGB.icc */; };
2DA397E5265C737500468F33 /* NullGraphicsContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DA397E3265C737400468F33 /* NullGraphicsContext.h */; settings = {ATTRIBUTES = (Private, ); }; };
2DAF343D1EA7E0F100382CD3 /* ConstantPropertyMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DAF343B1EA7E0F100382CD3 /* ConstantPropertyMap.h */; };
+ 2DC05CA827D80956004ED403 /* InteractionRegion.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DC05CA327D7F6B5004ED403 /* InteractionRegion.h */; settings = {ATTRIBUTES = (Private, ); }; };
2DC8D39825F2FE9700CFCBAB /* Model.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DC8D39725F2FE9400CFCBAB /* Model.h */; settings = {ATTRIBUTES = (Private, ); }; };
2DD5A7271EBEE47D009BA597 /* CompositionUnderline.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DD5A7261EBEE47D009BA597 /* CompositionUnderline.h */; settings = {ATTRIBUTES = (Private, ); }; };
2DD8714B265F4366005F997C /* BifurcatedGraphicsContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DD87149265F4365005F997C /* BifurcatedGraphicsContext.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -8177,6 +8178,8 @@
2DAAE32D19DCAF6000E002D2 /* MockPageOverlayClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MockPageOverlayClient.h; sourceTree = "<group>"; };
2DAF343A1EA7E0F100382CD3 /* ConstantPropertyMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConstantPropertyMap.cpp; sourceTree = "<group>"; };
2DAF343B1EA7E0F100382CD3 /* ConstantPropertyMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConstantPropertyMap.h; sourceTree = "<group>"; };
+ 2DC05CA327D7F6B5004ED403 /* InteractionRegion.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InteractionRegion.h; sourceTree = "<group>"; };
+ 2DC05CA727D80217004ED403 /* InteractionRegion.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = InteractionRegion.cpp; sourceTree = "<group>"; };
2DC8D39625F2FE9300CFCBAB /* Model.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Model.cpp; sourceTree = "<group>"; };
2DC8D39725F2FE9400CFCBAB /* Model.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Model.h; sourceTree = "<group>"; };
2DD5A7261EBEE47D009BA597 /* CompositionUnderline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CompositionUnderline.h; sourceTree = "<group>"; };
@@ -24272,6 +24275,8 @@
F46D539D273EECF70009FA80 /* ImageAnalysisQueue.h */,
F482434A260C32F10022497C /* ImageOverlayController.cpp */,
F4824348260C32F10022497C /* ImageOverlayController.h */,
+ 2DC05CA727D80217004ED403 /* InteractionRegion.cpp */,
+ 2DC05CA327D7F6B5004ED403 /* InteractionRegion.h */,
0F4710D51DB6FE22002DCEC3 /* IntersectionObserver.cpp */,
0F4710D61DB6FE22002DCEC3 /* IntersectionObserver.h */,
0F4710D71DB6FE22002DCEC3 /* IntersectionObserver.idl */,
@@ -35292,6 +35297,7 @@
A593CF8B1840535200BFCE27 /* InspectorWebAgentBase.h in Headers */,
A5B81CB41FAA44620037D1E6 /* InspectorWorkerAgent.h in Headers */,
F3ABFE0C130E9DA000E7F7D1 /* InstrumentingAgents.h in Headers */,
+ 2DC05CA827D80956004ED403 /* InteractionRegion.h in Headers */,
0F4710DC1DB6FE22002DCEC3 /* IntersectionObserver.h in Headers */,
0F8B45721DC3FBA300443C3F /* IntersectionObserverCallback.h in Headers */,
0F4710DF1DB6FE22002DCEC3 /* IntersectionObserverEntry.h in Headers */,
Modified: trunk/Source/WebCore/dom/Node.cpp (292207 => 292208)
--- trunk/Source/WebCore/dom/Node.cpp 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Source/WebCore/dom/Node.cpp 2022-04-01 08:17:36 UTC (rev 292208)
@@ -2510,6 +2510,13 @@
return hasEventListeners(eventNames().mousemoveEvent) || hasEventListeners(eventNames().mouseoverEvent) || hasEventListeners(eventNames().mouseoutEvent);
}
+bool Node::willRespondToTouchEvents()
+{
+ return eventTypes().containsIf([&](const auto& type) {
+ return eventNames().isTouchRelatedEventType(type, *this);
+ });
+}
+
bool Node::willRespondToMouseClickEvents()
{
// FIXME: Why is the iOS code path different from the non-iOS code path?
Modified: trunk/Source/WebCore/dom/Node.h (292207 => 292208)
--- trunk/Source/WebCore/dom/Node.h 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Source/WebCore/dom/Node.h 2022-04-01 08:17:36 UTC (rev 292208)
@@ -275,7 +275,7 @@
void setSelfOrAncestorHasDirAutoAttribute(bool flag) { setNodeFlag(NodeFlag::SelfOrAncestorHasDirAuto, flag); }
// Returns the enclosing event parent Element (or self) that, when clicked, would trigger a navigation.
- Element* enclosingLinkEventParentOrSelf();
+ WEBCORE_EXPORT Element* enclosingLinkEventParentOrSelf();
// These low-level calls give the caller responsibility for maintaining the integrity of the tree.
void setPreviousSibling(Node* previous) { m_previous = previous; }
@@ -457,6 +457,7 @@
virtual bool willRespondToMouseMoveEvents();
virtual bool willRespondToMouseClickEvents();
virtual bool willRespondToMouseWheelEvents();
+ virtual bool willRespondToTouchEvents();
WEBCORE_EXPORT unsigned short compareDocumentPosition(Node&);
Modified: trunk/Source/WebCore/page/DebugOverlayRegions.h (292207 => 292208)
--- trunk/Source/WebCore/page/DebugOverlayRegions.h 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Source/WebCore/page/DebugOverlayRegions.h 2022-04-01 08:17:36 UTC (rev 292208)
@@ -34,6 +34,7 @@
WheelEventHandlerRegion = 1 << 1,
TouchActionRegion = 1 << 2,
EditableElementRegion = 1 << 3,
+ InteractionRegion = 1 << 4,
};
}
@@ -46,7 +47,8 @@
WebCore::DebugOverlayRegions::NonFastScrollableRegion,
WebCore::DebugOverlayRegions::WheelEventHandlerRegion,
WebCore::DebugOverlayRegions::TouchActionRegion,
- WebCore::DebugOverlayRegions::EditableElementRegion
+ WebCore::DebugOverlayRegions::EditableElementRegion,
+ WebCore::DebugOverlayRegions::InteractionRegion
>;
};
Modified: trunk/Source/WebCore/page/DebugPageOverlays.cpp (292207 => 292208)
--- trunk/Source/WebCore/page/DebugPageOverlays.cpp 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Source/WebCore/page/DebugPageOverlays.cpp 2022-04-01 08:17:36 UTC (rev 292208)
@@ -27,12 +27,18 @@
#include "DebugPageOverlays.h"
#include "ColorHash.h"
+#include "Cursor.h"
#include "ElementIterator.h"
+#include "FloatRoundedRect.h"
#include "FrameView.h"
+#include "Gradient.h"
#include "GraphicsContext.h"
+#include "InteractionRegion.h"
#include "Page.h"
#include "PageOverlay.h"
#include "PageOverlayController.h"
+#include "PathUtilities.h"
+#include "PlatformMouseEvent.h"
#include "Region.h"
#include "ScrollingCoordinator.h"
#include "Settings.h"
@@ -59,8 +65,8 @@
void willMoveToPage(PageOverlay&, Page*) final;
void didMoveToPage(PageOverlay&, Page*) final;
void drawRect(PageOverlay&, GraphicsContext&, const IntRect& dirtyRect) override;
- bool mouseEvent(PageOverlay&, const PlatformMouseEvent&) final;
- void didScrollFrame(PageOverlay&, Frame&) final;
+ bool mouseEvent(PageOverlay&, const PlatformMouseEvent&) override;
+ void didScrollFrame(PageOverlay&, Frame&) override;
protected:
// Returns true if the region changed.
@@ -74,6 +80,8 @@
bool m_regionChanged { true };
};
+#pragma mark - MouseWheelRegionOverlay
+
class MouseWheelRegionOverlay final : public RegionOverlay {
public:
static Ref<MouseWheelRegionOverlay> create(Page& page)
@@ -115,6 +123,8 @@
#endif
}
+#pragma mark - NonFastScrollableRegionOverlay
+
class NonFastScrollableRegionOverlay final : public RegionOverlay {
public:
static Ref<NonFastScrollableRegionOverlay> create(Page& page)
@@ -219,6 +229,329 @@
drawRegion(context, m_eventTrackingRegions.asynchronousDispatchRegion, m_color, bounds);
}
+#pragma mark - InteractionRegionOverlay
+
+class InteractionRegionOverlay final : public RegionOverlay {
+public:
+ static Ref<InteractionRegionOverlay> create(Page& page)
+ {
+ return adoptRef(*new InteractionRegionOverlay(page));
+ }
+
+private:
+ explicit InteractionRegionOverlay(Page& page)
+ : RegionOverlay(page, Color::green.colorWithAlphaByte(102))
+ {
+ }
+
+ bool updateRegion() final;
+ void drawRect(PageOverlay&, GraphicsContext&, const IntRect& dirtyRect) final;
+
+ void drawSettings(GraphicsContext&);
+
+ bool mouseEvent(PageOverlay&, const PlatformMouseEvent&) final;
+
+ FloatRect rectForSettingAtIndex(unsigned);
+ bool valueForSetting(const String&);
+
+ std::optional<InteractionRegion> activeRegion();
+
+ struct Setting {
+ String key;
+ String name;
+ bool value;
+ };
+
+ FixedVector<Setting> m_settings {
+ { "constrain"_s, "Constrain to Regions"_s, true },
+ { "clip"_s, "Clip to Regions"_s, true },
+ { "wash"_s, "Draw Wash"_s, false },
+ { "contextualColor"_s, "Contextual Color"_s, true },
+ { "contextualSize"_s, "Contextual Size"_s, true },
+ { "cursor"_s, "Show Cursor"_s, true },
+ { "hover"_s, "CSS Hover"_s, false },
+ { "regions"_s, "Show Regions"_s, false }
+ };
+
+ Vector<InteractionRegion> m_regions;
+ IntPoint m_mouseLocationInContentCoordinates;
+};
+
+bool InteractionRegionOverlay::updateRegion()
+{
+ m_overlay->setNeedsDisplay();
+ m_regions = interactionRegions(m_page, { { 0, 0 }, m_page.mainFrame().view()->contentsSize() });
+
+ return true;
+}
+
+static Vector<Path> pathsForRegion(const InteractionRegion& region)
+{
+ static constexpr float padding = 3;
+ static constexpr float radius = 4;
+
+ Vector<FloatRect> rects;
+ for (auto rect : region.rectsInContentCoordinates) {
+ if (region.isInline)
+ rect.inflate(padding);
+ rects.append(rect);
+ }
+ return PathUtilities::pathsWithShrinkWrappedRects(rects, std::max(region.borderRadius, radius));
+}
+
+std::optional<InteractionRegion> InteractionRegionOverlay::activeRegion()
+{
+ std::optional<InteractionRegion> hitRegion;
+ float hitRegionArea = 0;
+
+ for (const auto& region : m_regions) {
+ float area = 0;
+ FloatRect boundingRect;
+ for (const auto& rect : region.rectsInContentCoordinates) {
+ if (boundingRect.isEmpty())
+ boundingRect = rect;
+ else
+ boundingRect.unite(rect);
+ area += rect.area();
+ }
+
+ if (!boundingRect.contains(m_mouseLocationInContentCoordinates))
+ continue;
+
+ auto paths = pathsForRegion(region);
+ bool didHitRegion = false;
+ for (const auto& path : paths) {
+ if (path.contains(m_mouseLocationInContentCoordinates)) {
+ didHitRegion = true;
+ break;
+ }
+ }
+
+ if (!didHitRegion)
+ continue;
+
+ if (area > m_page.mainFrame().view()->layoutSize().area() / 2)
+ continue;
+
+ if (didHitRegion && (!hitRegion || area < hitRegionArea)) {
+ hitRegion = region;
+ hitRegionArea = area;
+ }
+ }
+
+ return hitRegion;
+}
+
+static void drawCheckbox(const String& text, GraphicsContext& context, const FontCascade& font, const FloatRect& box, bool state)
+{
+ static constexpr float lineHeight = 14;
+ static constexpr float checkboxVerticalPadding = 2;
+ static constexpr float textHorizontalPadding = 4;
+
+ FloatRect checkboxRect { box.location() + FloatSize { 0, checkboxVerticalPadding }, FloatSize { lineHeight, lineHeight } };
+
+ TextRun textRun = TextRun(text);
+ context.setFillColor(Color::black);
+ context.drawText(font, textRun, box.location() + FloatSize { checkboxRect.width() + textHorizontalPadding, lineHeight });
+
+ Path checkboxPath;
+ checkboxPath.addRoundedRect(FloatRoundedRect { checkboxRect, FloatRoundedRect::Radii { 3 } });
+
+ if (state) {
+ context.setFillColor(Color::darkGray);
+ context.fillPath(checkboxPath);
+ }
+
+ context.setStrokeColor(Color::black.colorWithAlphaByte(127));
+ context.setStrokeThickness(1);
+ context.strokePath(checkboxPath);
+}
+
+FloatRect InteractionRegionOverlay::rectForSettingAtIndex(unsigned index)
+{
+ auto viewSize = m_page.mainFrame().view()->layoutSize();
+ static constexpr float settingsWidth = 150;
+ static constexpr float rowHeight = 16;
+ return {
+ FloatPoint { viewSize.width() - settingsWidth - 14, 10 }
+ + FloatSize { 4, rowHeight * index + 2 },
+ FloatSize { settingsWidth, rowHeight }
+ };
+}
+
+bool InteractionRegionOverlay::valueForSetting(const String& name)
+{
+ for (const auto& setting : m_settings) {
+ if (name == setting.key)
+ return setting.value;
+ }
+
+ ASSERT_NOT_REACHED();
+ return false;
+}
+
+void InteractionRegionOverlay::drawSettings(GraphicsContext& context)
+{
+ GraphicsContextStateSaver stateSaver(context);
+
+ FloatRect rect = rectForSettingAtIndex(0);
+ for (unsigned i = 1; i < m_settings.size(); i++)
+ rect.unite(rectForSettingAtIndex(i));
+
+ rect.expand(FloatBoxExtent { 4, 4, 4, 4 });
+
+ {
+ GraphicsContextStateSaver stateSaver(context);
+ context.setShadow({ }, 5, Color(Color::black).colorWithAlpha(0.5));
+ context.fillRoundedRect(FloatRoundedRect { rect, FloatRoundedRect::Radii { 6 } }, Color(Color::white).colorWithAlpha(0.85));
+ }
+
+ FontCascadeDescription fontDescription;
+ fontDescription.setOneFamily("Helvetica");
+ fontDescription.setSpecifiedSize(12);
+ fontDescription.setComputedSize(12);
+ fontDescription.setWeight(FontSelectionValue(500));
+ FontCascade font(WTFMove(fontDescription), 0, 0);
+ font.update(nullptr);
+
+ for (unsigned i = 0; i < m_settings.size(); i++) {
+ const auto& setting = m_settings[i];
+ drawCheckbox(setting.name, context, font, rectForSettingAtIndex(i), setting.value);
+ }
+}
+
+void InteractionRegionOverlay::drawRect(PageOverlay&, GraphicsContext& context, const IntRect& dirtyRect)
+{
+ GraphicsContextStateSaver stateSaver(context);
+
+ context.clearRect(dirtyRect);
+
+ if (valueForSetting("regions")) {
+ context.setStrokeThickness(2);
+ context.setStrokeColor(Color::green);
+
+ for (const auto& region : m_regions) {
+ for (const auto& rect : region.rectsInContentCoordinates)
+ context.strokeRect(rect, 2);
+ }
+ }
+
+ auto region = activeRegion();
+
+ if (region || !valueForSetting("constrain")) {
+ auto gradientData = [&] (float radius) {
+ Gradient::RadialData gradientData;
+ gradientData.point0 = m_mouseLocationInContentCoordinates;
+ gradientData.point1 = m_mouseLocationInContentCoordinates;
+ gradientData.startRadius = 0;
+ gradientData.endRadius = radius;
+ gradientData.aspectRatio = 1;
+ return gradientData;
+ };
+
+ auto makeGradient = [&] (bool hasLightBackground, Gradient::RadialData gradientData) {
+ auto gradient = Gradient::create(WTFMove(gradientData), { ColorInterpolationMethod::SRGB { }, AlphaPremultiplication::Unpremultiplied });
+ if (region && valueForSetting("wash") && valueForSetting("clip")) {
+ gradient->addColorStop({ 0.1, Color(Color::white).colorWithAlpha(0.5) });
+ gradient->addColorStop({ 1, hasLightBackground ? Color(Color::black).colorWithAlpha(0.05) : Color(Color::white).colorWithAlpha(0.1) });
+ } else if (!valueForSetting("clip") || !valueForSetting("constrain")) {
+ gradient->addColorStop({ 0.1, Color(Color::white).colorWithAlpha(0.2) });
+ gradient->addColorStop({ 1, Color(Color::white).colorWithAlpha(0) });
+ } else {
+ gradient->addColorStop({ 0.1, Color(Color::white).colorWithAlpha(0.5) });
+ gradient->addColorStop({ 1, Color(Color::white).colorWithAlpha(0) });
+ }
+
+ return gradient;
+ };
+
+ constexpr float defaultRadius = 50;
+ bool shouldClip = valueForSetting("clip");
+ Vector<Path> clipPaths;
+
+ if (shouldClip)
+ clipPaths = pathsForRegion(*region);
+
+ bool shouldUseBackdropGradient = !shouldClip || !region || (!valueForSetting("wash") && valueForSetting("clip"));
+
+ if (shouldUseBackdropGradient) {
+ if (shouldClip) {
+ for (const auto& path : clipPaths) {
+ float radius = valueForSetting("contextualSize") ? 1.5 * path.boundingRect().size().minDimension() : defaultRadius;
+ auto backdropGradient = Gradient::create(gradientData(radius * 1.5), { ColorInterpolationMethod::SRGB { }, AlphaPremultiplication::Unpremultiplied });
+ backdropGradient->addColorStop({ 0.1, Color(Color::black).colorWithAlpha(0.2) });
+ backdropGradient->addColorStop({ 1, Color(Color::black).colorWithAlpha(0) });
+
+ context.setFillGradient(WTFMove(backdropGradient));
+ context.fillPath(path);
+ }
+ } else {
+ auto backdropGradient = Gradient::create(gradientData(defaultRadius * 2), { ColorInterpolationMethod::SRGB { }, AlphaPremultiplication::Unpremultiplied });
+ backdropGradient->addColorStop({ 0.1, Color(Color::black).colorWithAlpha(0.2) });
+ backdropGradient->addColorStop({ 1, Color(Color::black).colorWithAlpha(0) });
+
+ context.setFillGradient(WTFMove(backdropGradient));
+ context.fillRect(dirtyRect);
+ }
+ }
+
+ bool hasLightBackground = false;
+ if (!shouldUseBackdropGradient && valueForSetting("contextualColor"))
+ hasLightBackground = region->hasLightBackground;
+
+ if (shouldClip) {
+ for (const auto& path : clipPaths) {
+ float radius = valueForSetting("contextualSize") ? 1.5 * path.boundingRect().size().minDimension() : defaultRadius;
+ context.setFillGradient(makeGradient(hasLightBackground, gradientData(radius)));
+ context.fillPath(path);
+ }
+ } else {
+ context.setFillGradient(makeGradient(hasLightBackground, gradientData(defaultRadius)));
+ context.fillRect(dirtyRect);
+ }
+ }
+
+ stateSaver.restore();
+
+ drawSettings(context);
+}
+
+bool InteractionRegionOverlay::mouseEvent(PageOverlay& overlay, const PlatformMouseEvent& event)
+{
+ auto mainFrameView = m_page.mainFrame().view();
+
+ std::optional<Cursor> cursorToSet;
+
+ if (!valueForSetting("cursor"))
+ cursorToSet = noneCursor();
+ else if (!valueForSetting("hover"))
+ cursorToSet = pointerCursor();
+
+ auto eventInContentsCoordinates = mainFrameView->windowToContents(event.position());
+ for (unsigned i = 0; i < m_settings.size(); i++) {
+ if (!rectForSettingAtIndex(i).contains(eventInContentsCoordinates))
+ continue;
+ cursorToSet = handCursor();
+ if (event.button() == LeftButton && event.type() == PlatformEvent::MousePressed) {
+ m_settings[i].value = !m_settings[i].value;
+ return true;
+ }
+ }
+
+ if (cursorToSet)
+ mainFrameView->setCursor(*cursorToSet);
+
+ m_mouseLocationInContentCoordinates = eventInContentsCoordinates;
+ overlay.setNeedsDisplay();
+
+ if (event.type() == PlatformEvent::MouseMoved && !event.buttons() && !valueForSetting("hover"))
+ return true;
+
+ return false;
+}
+
+#pragma mark - RegionOverlay
+
Ref<RegionOverlay> RegionOverlay::create(Page& page, DebugPageOverlays::RegionType regionType)
{
switch (regionType) {
@@ -226,6 +559,8 @@
return MouseWheelRegionOverlay::create(page);
case DebugPageOverlays::RegionType::NonFastScrollableRegion:
return NonFastScrollableRegionOverlay::create(page);
+ case DebugPageOverlays::RegionType::InteractionRegion:
+ return InteractionRegionOverlay::create(page);
}
ASSERT_NOT_REACHED();
return MouseWheelRegionOverlay::create(page);
@@ -296,6 +631,8 @@
m_regionChanged = false;
}
+#pragma mark - DebugPageOverlays
+
DebugPageOverlays& DebugPageOverlays::singleton()
{
if (!sharedDebugOverlays)
@@ -379,6 +716,11 @@
showRegionOverlay(page, RegionType::WheelEventHandlers);
else
hideRegionOverlay(page, RegionType::WheelEventHandlers);
+
+ if (visibleRegions.contains(DebugOverlayRegions::InteractionRegion))
+ showRegionOverlay(page, RegionType::InteractionRegion);
+ else
+ hideRegionOverlay(page, RegionType::InteractionRegion);
}
void DebugPageOverlays::settingsChanged(Page& page)
Modified: trunk/Source/WebCore/page/DebugPageOverlays.h (292207 => 292208)
--- trunk/Source/WebCore/page/DebugPageOverlays.h 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Source/WebCore/page/DebugPageOverlays.h 2022-04-01 08:17:36 UTC (rev 292208)
@@ -43,8 +43,9 @@
enum class RegionType {
WheelEventHandlers,
NonFastScrollableRegion,
+ InteractionRegion,
};
- static constexpr unsigned NumberOfRegionTypes = static_cast<unsigned>(RegionType::NonFastScrollableRegion) + 1;
+ static constexpr unsigned NumberOfRegionTypes = static_cast<unsigned>(RegionType::InteractionRegion) + 1;
static void didLayout(Frame&);
static void didChangeEventHandlers(Frame&);
@@ -93,6 +94,7 @@
sharedDebugOverlays->regionChanged(frame, RegionType::WheelEventHandlers);
sharedDebugOverlays->regionChanged(frame, RegionType::NonFastScrollableRegion);
+ sharedDebugOverlays->regionChanged(frame, RegionType::InteractionRegion);
}
inline void DebugPageOverlays::didChangeEventHandlers(Frame& frame)
@@ -101,6 +103,7 @@
sharedDebugOverlays->regionChanged(frame, RegionType::WheelEventHandlers);
sharedDebugOverlays->regionChanged(frame, RegionType::NonFastScrollableRegion);
+ sharedDebugOverlays->regionChanged(frame, RegionType::InteractionRegion);
}
inline void DebugPageOverlays::doAfterUpdateRendering(Page& page)
@@ -110,6 +113,7 @@
sharedDebugOverlays->updateRegionIfNecessary(page, RegionType::WheelEventHandlers);
sharedDebugOverlays->updateRegionIfNecessary(page, RegionType::NonFastScrollableRegion);
+ sharedDebugOverlays->updateRegionIfNecessary(page, RegionType::InteractionRegion);
}
} // namespace WebCore
Modified: trunk/Source/WebCore/page/FrameSnapshotting.cpp (292207 => 292208)
--- trunk/Source/WebCore/page/FrameSnapshotting.cpp 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Source/WebCore/page/FrameSnapshotting.cpp 2022-04-01 08:17:36 UTC (rev 292208)
@@ -31,14 +31,17 @@
#include "config.h"
#include "FrameSnapshotting.h"
+#include "ColorBlending.h"
#include "Document.h"
#include "FloatRect.h"
#include "Frame.h"
#include "FrameSelection.h"
#include "FrameView.h"
+#include "GeometryUtilities.h"
#include "GraphicsContext.h"
#include "ImageBuffer.h"
#include "Page.h"
+#include "RenderAncestorIterator.h"
#include "RenderObject.h"
#include "Settings.h"
@@ -158,4 +161,50 @@
return snapshotFrameRect(frame, snappedIntRect(node.renderer()->paintingRootRect(topLevelRect)), WTFMove(options));
}
+static bool styleContainsComplexBackground(const RenderStyle& style)
+{
+ return style.hasBlendMode() || style.hasBackgroundImage() || style.hasBackdropFilter();
+}
+
+Color estimatedBackgroundColorForRange(const SimpleRange& range, const Frame& frame)
+{
+ auto estimatedBackgroundColor = frame.view() ? frame.view()->documentBackgroundColor() : Color::transparentBlack;
+
+ RenderElement* renderer = nullptr;
+ auto commonAncestor = commonInclusiveAncestor<ComposedTree>(range);
+ while (commonAncestor) {
+ if (is<RenderElement>(commonAncestor->renderer())) {
+ renderer = downcast<RenderElement>(commonAncestor->renderer());
+ break;
+ }
+ commonAncestor = commonAncestor->parentOrShadowHostElement();
+ }
+
+ auto boundingRectForRange = enclosingIntRect(unionRectIgnoringZeroRects(RenderObject::absoluteBorderAndTextRects(range, {
+ RenderObject::BoundingRectBehavior::RespectClipping,
+ RenderObject::BoundingRectBehavior::UseVisibleBounds,
+ RenderObject::BoundingRectBehavior::IgnoreTinyRects,
+ })));
+
+ Vector<Color> parentRendererBackgroundColors;
+ for (auto& ancestor : lineageOfType<RenderElement>(*renderer)) {
+ auto absoluteBoundingBox = ancestor.absoluteBoundingBoxRect();
+ auto& style = ancestor.style();
+ if (!absoluteBoundingBox.contains(boundingRectForRange) || !style.hasBackground())
+ continue;
+
+ if (styleContainsComplexBackground(style))
+ return estimatedBackgroundColor;
+
+ auto visitedDependentBackgroundColor = style.visitedDependentColor(CSSPropertyBackgroundColor);
+ if (visitedDependentBackgroundColor != Color::transparentBlack)
+ parentRendererBackgroundColors.append(visitedDependentBackgroundColor);
+ }
+ parentRendererBackgroundColors.reverse();
+ for (const auto& backgroundColor : parentRendererBackgroundColors)
+ estimatedBackgroundColor = blendSourceOver(estimatedBackgroundColor, backgroundColor);
+
+ return estimatedBackgroundColor;
+}
+
} // namespace WebCore
Modified: trunk/Source/WebCore/page/FrameSnapshotting.h (292207 => 292208)
--- trunk/Source/WebCore/page/FrameSnapshotting.h 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Source/WebCore/page/FrameSnapshotting.h 2022-04-01 08:17:36 UTC (rev 292208)
@@ -63,4 +63,6 @@
RefPtr<ImageBuffer> snapshotNode(Frame&, Node&, SnapshotOptions&&);
WEBCORE_EXPORT RefPtr<ImageBuffer> snapshotSelection(Frame&, SnapshotOptions&&);
+Color estimatedBackgroundColorForRange(const SimpleRange&, const Frame&);
+
} // namespace WebCore
Added: trunk/Source/WebCore/page/InteractionRegion.cpp (0 => 292208)
--- trunk/Source/WebCore/page/InteractionRegion.cpp (rev 0)
+++ trunk/Source/WebCore/page/InteractionRegion.cpp 2022-04-01 08:17:36 UTC (rev 292208)
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "InteractionRegion.h"
+
+#include "Document.h"
+#include "Frame.h"
+#include "FrameSnapshotting.h"
+#include "FrameView.h"
+#include "GeometryUtilities.h"
+#include "HTMLAnchorElement.h"
+#include "HTMLFormControlElement.h"
+#include "HitTestResult.h"
+#include "Page.h"
+#include "PathUtilities.h"
+#include "PlatformMouseEvent.h"
+#include "SimpleRange.h"
+#include <wtf/NeverDestroyed.h>
+
+namespace WebCore {
+
+InteractionRegion::~InteractionRegion() = default;
+
+static FloatRect absoluteBoundingRectForRange(const SimpleRange& range)
+{
+ return unionRectIgnoringZeroRects(RenderObject::absoluteBorderAndTextRects(range, {
+ RenderObject::BoundingRectBehavior::RespectClipping,
+ RenderObject::BoundingRectBehavior::UseVisibleBounds,
+ RenderObject::BoundingRectBehavior::IgnoreTinyRects,
+ }));
+}
+
+static std::optional<InteractionRegion> regionForElement(Element& element)
+{
+ auto& frameView = *element.document().frame()->view();
+ auto& mainFrameView = *element.document().frame()->mainFrame().view();
+
+ IntRect frameClipRect;
+#if PLATFORM(IOS_FAMILY)
+ frameClipRect = enclosingIntRect(frameView.exposedContentRect());
+#else
+ if (auto viewExposedRect = frameView.viewExposedRect())
+ frameClipRect = enclosingIntRect(*viewExposedRect);
+ else
+ frameClipRect = frameView.visibleContentRect();
+#endif
+
+ auto* renderer = element.renderer();
+ if (!renderer)
+ return std::nullopt;
+
+ Vector<FloatRect> rectsInContentsCoordinates;
+
+ InteractionRegion region;
+
+ auto linkRange = makeRangeSelectingNode(element);
+
+ if (linkRange)
+ region.hasLightBackground = estimatedBackgroundColorForRange(*linkRange, *element.document().frame()).luminance() > 0.5;
+
+ if (linkRange && renderer->isInline() && !renderer->isReplacedOrInlineBlock()) {
+ region.isInline = true;
+
+ OptionSet<RenderObject::BoundingRectBehavior> behavior { RenderObject::BoundingRectBehavior::RespectClipping };
+ rectsInContentsCoordinates = RenderObject::absoluteTextRects(*linkRange, behavior).map([&](auto rect) -> FloatRect {
+ return rect;
+ });
+
+ if (rectsInContentsCoordinates.isEmpty()) {
+ auto boundingRectForRange = absoluteBoundingRectForRange(*linkRange);
+ if (!boundingRectForRange.isEmpty())
+ rectsInContentsCoordinates = { boundingRectForRange };
+ }
+ }
+
+ if (rectsInContentsCoordinates.isEmpty())
+ rectsInContentsCoordinates = { renderer->absoluteBoundingBoxRect() };
+
+ if (is<RenderBox>(*renderer)) {
+ RoundedRect::Radii borderRadii = downcast<RenderBox>(*renderer).borderRadii();
+ region.borderRadius = borderRadii.minimumRadius();
+ }
+
+ region.rectsInContentCoordinates = rectsInContentsCoordinates.map([&](auto rect) {
+ auto contentsRect = rect;
+
+ if (&frameView != &mainFrameView)
+ contentsRect.intersect(frameClipRect);
+
+ return contentsRect;
+ });
+
+ return WTFMove(region);
+}
+
+static CursorType cursorTypeForElement(Element& element)
+{
+ auto* renderer = element.renderer();
+ auto* style = renderer ? &renderer->style() : nullptr;
+ auto cursorType = style ? style->cursor() : CursorType::Auto;
+
+ if (cursorType == CursorType::Auto && element.enclosingLinkEventParentOrSelf() && element.isLink())
+ cursorType = CursorType::Pointer;
+
+ return cursorType;
+}
+
+Vector<InteractionRegion> interactionRegions(Page& page, FloatRect rect)
+{
+ Ref frame(page.mainFrame());
+ RefPtr frameView = frame->view();
+
+ if (!frameView)
+ return { };
+
+ frameView->updateLayoutAndStyleIfNeededRecursive();
+
+ RefPtr document = frame->document();
+ if (!document)
+ return { };
+
+ auto result = HitTestResult { LayoutRect(rect) };
+ HitTestRequest request({
+ HitTestRequest::Type::ReadOnly,
+ HitTestRequest::Type::Active,
+ HitTestRequest::Type::AllowVisibleChildFrameContentOnly,
+ HitTestRequest::Type::CollectMultipleElements
+ });
+ document->hitTest(request, result);
+
+ Vector<InteractionRegion> regions;
+
+ for (const auto& node : result.listBasedTestResult()) {
+ if (!is<Element>(node.get()))
+ continue;
+ auto& element = downcast<Element>(node.get());
+
+ if (!element.willRespondToMouseClickEvents() && !element.willRespondToTouchEvents())
+ continue;
+
+ if (cursorTypeForElement(element) != CursorType::Pointer && !is<HTMLFormControlElement>(element))
+ continue;
+
+ auto region = regionForElement(element);
+ if (region)
+ regions.append(*region);
+ }
+
+ return regions;
+}
+
+}
Added: trunk/Source/WebCore/page/InteractionRegion.h (0 => 292208)
--- trunk/Source/WebCore/page/InteractionRegion.h (rev 0)
+++ trunk/Source/WebCore/page/InteractionRegion.h 2022-04-01 08:17:36 UTC (rev 292208)
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "FloatRect.h"
+
+namespace IPC {
+class Decoder;
+class Encoder;
+}
+
+namespace WebCore {
+
+class Page;
+
+struct InteractionRegion {
+ Vector<FloatRect> rectsInContentCoordinates;
+ bool isInline { false };
+ bool hasLightBackground { false };
+ float borderRadius { 0 };
+
+ WEBCORE_EXPORT ~InteractionRegion();
+
+ template<class Encoder> void encode(Encoder&) const;
+ template<class Decoder> static std::optional<InteractionRegion> decode(Decoder&);
+};
+
+WEBCORE_EXPORT Vector<InteractionRegion> interactionRegions(Page&, FloatRect rectInContentCoordinates);
+
+template<class Encoder>
+void InteractionRegion::encode(Encoder& encoder) const
+{
+ encoder << rectsInContentCoordinates;
+ encoder << isInline;
+ encoder << hasLightBackground;
+ encoder << borderRadius;
+}
+
+template<class Decoder>
+std::optional<InteractionRegion> InteractionRegion::decode(Decoder& decoder)
+{
+ std::optional<Vector<FloatRect>> rectsInContentCoordinates;
+ decoder >> rectsInContentCoordinates;
+ if (!rectsInContentCoordinates)
+ return std::nullopt;
+
+ std::optional<bool> isInline;
+ decoder >> isInline;
+ if (!isInline)
+ return std::nullopt;
+
+ std::optional<bool> hasLightBackground;
+ decoder >> hasLightBackground;
+ if (!hasLightBackground)
+ return std::nullopt;
+
+ std::optional<float> borderRadius;
+ decoder >> borderRadius;
+ if (!borderRadius)
+ return std::nullopt;
+
+ return { {
+ WTFMove(*rectsInContentCoordinates),
+ WTFMove(*isInline),
+ WTFMove(*hasLightBackground),
+ WTFMove(*borderRadius)
+ } };
+}
+
+}
Modified: trunk/Source/WebCore/page/TextIndicator.cpp (292207 => 292208)
--- trunk/Source/WebCore/page/TextIndicator.cpp 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Source/WebCore/page/TextIndicator.cpp 2022-04-01 08:17:36 UTC (rev 292208)
@@ -175,11 +175,6 @@
return true;
}
-static bool styleContainsComplexBackground(const RenderStyle& style)
-{
- return style.hasBlendMode() || style.hasBackgroundImage() || style.hasBackdropFilter();
-}
-
static HashSet<Color> estimatedTextColorsForRange(const SimpleRange& range)
{
HashSet<Color> colors;
@@ -203,42 +198,6 @@
}));
}
-static Color estimatedBackgroundColorForRange(const SimpleRange& range, const Frame& frame)
-{
- auto estimatedBackgroundColor = frame.view() ? frame.view()->documentBackgroundColor() : Color::transparentBlack;
-
- RenderElement* renderer = nullptr;
- auto commonAncestor = commonInclusiveAncestor<ComposedTree>(range);
- while (commonAncestor) {
- if (is<RenderElement>(commonAncestor->renderer())) {
- renderer = downcast<RenderElement>(commonAncestor->renderer());
- break;
- }
- commonAncestor = commonAncestor->parentOrShadowHostElement();
- }
-
- auto boundingRectForRange = enclosingIntRect(absoluteBoundingRectForRange(range));
- Vector<Color> parentRendererBackgroundColors;
- for (; !!renderer; renderer = renderer->parent()) {
- auto absoluteBoundingBox = renderer->absoluteBoundingBoxRect();
- auto& style = renderer->style();
- if (!absoluteBoundingBox.contains(boundingRectForRange) || !style.hasBackground())
- continue;
-
- if (styleContainsComplexBackground(style))
- return estimatedBackgroundColor;
-
- auto visitedDependentBackgroundColor = style.visitedDependentColor(CSSPropertyBackgroundColor);
- if (visitedDependentBackgroundColor != Color::transparentBlack)
- parentRendererBackgroundColors.append(visitedDependentBackgroundColor);
- }
- parentRendererBackgroundColors.reverse();
- for (const auto& backgroundColor : parentRendererBackgroundColors)
- estimatedBackgroundColor = blendSourceOver(estimatedBackgroundColor, backgroundColor);
-
- return estimatedBackgroundColor;
-}
-
static bool hasAnyIllegibleColors(TextIndicatorData& data, const Color& backgroundColor, HashSet<Color>&& textColors)
{
if (data.options.contains(TextIndicatorOption::PaintAllContent))
Modified: trunk/Source/WebCore/platform/graphics/LayoutSize.h (292207 => 292208)
--- trunk/Source/WebCore/platform/graphics/LayoutSize.h 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Source/WebCore/platform/graphics/LayoutSize.h 2022-04-01 08:17:36 UTC (rev 292208)
@@ -58,6 +58,9 @@
LayoutUnit width() const { return m_width; }
LayoutUnit height() const { return m_height; }
+ LayoutUnit minDimension() const { return std::min(m_width, m_height); }
+ LayoutUnit maxDimension() const { return std::max(m_width, m_height); }
+
template<typename T> void setWidth(T width) { m_width = width; }
template<typename T> void setHeight(T height) { m_height = height; }
Modified: trunk/Source/WebCore/platform/graphics/RoundedRect.h (292207 => 292208)
--- trunk/Source/WebCore/platform/graphics/RoundedRect.h 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Source/WebCore/platform/graphics/RoundedRect.h 2022-04-01 08:17:36 UTC (rev 292208)
@@ -71,6 +71,8 @@
Radii transposedRadii() const { return Radii(m_topLeft.transposedSize(), m_topRight.transposedSize(), m_bottomLeft.transposedSize(), m_bottomRight.transposedSize()); }
+ LayoutUnit minimumRadius() const { return std::min({ m_topLeft.minDimension(), m_topRight.minDimension(), m_bottomLeft.minDimension(), m_bottomRight.minDimension() }); }
+
private:
LayoutSize m_topLeft;
LayoutSize m_topRight;
Modified: trunk/Source/WebKit/ChangeLog (292207 => 292208)
--- trunk/Source/WebKit/ChangeLog 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Source/WebKit/ChangeLog 2022-04-01 08:17:36 UTC (rev 292208)
@@ -1,3 +1,34 @@
+2022-04-01 Tim Horton <timothy_hor...@apple.com>
+
+ Add a debug overlay for interaction regions
+ https://bugs.webkit.org/show_bug.cgi?id=238187
+
+ Reviewed by Wenson Hsieh.
+
+ * Shared/mac/MediaFormatReader/MediaFormatReader.cpp:
+ Unified source fixes.
+
+ * UIProcess/API/Cocoa/WKPreferencesPrivate.h:
+ Add plumbing for a new debug overlay.
+
+ * UIProcess/WebPageProxy.cpp:
+ (WebKit::WebPageProxy::interactionRegions):
+ (WebKit::WebPageProxy::interactableRegionsInRootViewCoordinates): Deleted.
+ * UIProcess/WebPageProxy.h:
+ * UIProcess/ios/WKContentViewInteraction.mm:
+ (-[WKContentView interactionRegionsForHoverPlatter:inRect:completionHandler:]):
+ (-[WKContentView interactableRegionsForHoverPlatter:inRect:completionHandler:]): Deleted.
+ * UIProcess/ios/WKHoverPlatter.h:
+ * UIProcess/ios/WKHoverPlatter.mm:
+ (-[WKHoverPlatter updateDebugIndicator]):
+ * WebProcess/WebPage/WebPage.cpp:
+ (WebKit::WebPage::interactionRegions):
+ Move interactionRegions() from WebPage to WebCore::InteractionRegion.
+
+ (WebKit::WebPage::interactableRegionsInRootViewCoordinates): Deleted.
+ * WebProcess/WebPage/WebPage.h:
+ * WebProcess/WebPage/WebPage.messages.in:
+
2022-04-01 Youenn Fablet <you...@apple.com>
Persistent notifications should work in document scopes as well as service worker global scopes
Modified: trunk/Source/WebKit/Shared/mac/MediaFormatReader/MediaFormatReader.cpp (292207 => 292208)
--- trunk/Source/WebKit/Shared/mac/MediaFormatReader/MediaFormatReader.cpp 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Source/WebKit/Shared/mac/MediaFormatReader/MediaFormatReader.cpp 2022-04-01 08:17:36 UTC (rev 292208)
@@ -36,9 +36,11 @@
#include <WebCore/InbandTextTrackPrivate.h>
#include <WebCore/MediaSample.h>
#include <WebCore/MediaSampleAVFObjC.h>
+#include <WebCore/SharedBuffer.h>
#include <WebCore/SourceBufferParserWebM.h>
#include <WebCore/VideoTrackPrivate.h>
#include <pal/avfoundation/MediaTimeAVFoundation.h>
+#include <pal/cf/CoreMediaSoftLink.h>
#include <wtf/LoggerHelper.h>
#include <wtf/NeverDestroyed.h>
#include <wtf/WorkQueue.h>
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h (292207 => 292208)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h 2022-04-01 08:17:36 UTC (rev 292208)
@@ -37,6 +37,7 @@
_WKWheelEventHandlerRegion = 1 << 1,
_WKTouchActionRegion = 1 << 2,
_WKEditableElementRegion = 1 << 3,
+ _WKInteractionRegion WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA)) = 1 << 4,
} WK_API_AVAILABLE(macos(10.11), ios(9.0));
typedef NS_OPTIONS(NSUInteger, _WKJavaScriptRuntimeFlags) {
Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.cpp (292207 => 292208)
--- trunk/Source/WebKit/UIProcess/WebPageProxy.cpp 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.cpp 2022-04-01 08:17:36 UTC (rev 292208)
@@ -11282,9 +11282,9 @@
return m_configuration->captivePortalModeEnabled();
}
-void WebPageProxy::interactableRegionsInRootViewCoordinates(FloatRect rect, CompletionHandler<void(Vector<FloatRect>)>&& completionHandler)
+void WebPageProxy::interactionRegions(FloatRect rectInContentCoordinates, CompletionHandler<void(Vector<InteractionRegion>)>&& completionHandler)
{
- sendWithAsyncReply(Messages::WebPage::InteractableRegionsInRootViewCoordinates(rect), WTFMove(completionHandler));
+ sendWithAsyncReply(Messages::WebPage::InteractionRegions(rectInContentCoordinates), WTFMove(completionHandler));
}
#if PLATFORM(COCOA)
Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.h (292207 => 292208)
--- trunk/Source/WebKit/UIProcess/WebPageProxy.h 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.h 2022-04-01 08:17:36 UTC (rev 292208)
@@ -299,6 +299,7 @@
struct ExceptionDetails;
struct FileChooserSettings;
struct GlobalWindowIdentifier;
+struct InteractionRegion;
struct LinkIcon;
struct MediaStreamRequest;
struct MediaUsageInfo;
@@ -2082,7 +2083,7 @@
void classifyModalContainerControls(Vector<String>&& texts, CompletionHandler<void(Vector<WebCore::ModalContainerControlType>&&)>&&);
void decidePolicyForModalContainer(OptionSet<WebCore::ModalContainerControlType>, CompletionHandler<void(WebCore::ModalContainerDecision)>&&);
- void interactableRegionsInRootViewCoordinates(WebCore::FloatRect, CompletionHandler<void(Vector<WebCore::FloatRect>)>&&);
+ void interactionRegions(WebCore::FloatRect rectInContentCoordinates, CompletionHandler<void(Vector<WebCore::InteractionRegion>)>&&);
#if ENABLE(SERVICE_WORKER)
void setServiceWorkerOpenWindowCompletionCallback(CompletionHandler<void(bool)>&& completionCallback)
Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm (292207 => 292208)
--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm 2022-04-01 08:17:36 UTC (rev 292208)
@@ -9994,10 +9994,10 @@
[self doAfterPositionInformationUpdate:completionHandler forRequest:request];
}
-- (void)interactableRegionsForHoverPlatter:(WKHoverPlatter *)platter inRect:(WebCore::FloatRect)rect completionHandler:(void (^)(Vector<WebCore::FloatRect>))completionHandler
+- (void)interactionRegionsForHoverPlatter:(WKHoverPlatter *)platter inRect:(WebCore::FloatRect)rectInContentCoordinates completionHandler:(void (^)(Vector<WebCore::InteractionRegion>))completionHandler
{
- _page->interactableRegionsInRootViewCoordinates(rect, [completionHandler = makeBlockPtr(completionHandler)] (Vector<WebCore::FloatRect> rects) {
- completionHandler(rects);
+ _page->interactionRegions(rectInContentCoordinates, [completionHandler = makeBlockPtr(completionHandler)] (Vector<WebCore::InteractionRegion> regions) {
+ completionHandler(regions);
});
}
Modified: trunk/Source/WebKit/UIProcess/ios/WKHoverPlatter.h (292207 => 292208)
--- trunk/Source/WebKit/UIProcess/ios/WKHoverPlatter.h 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Source/WebKit/UIProcess/ios/WKHoverPlatter.h 2022-04-01 08:17:36 UTC (rev 292208)
@@ -29,6 +29,7 @@
namespace WebCore {
class FloatRect;
+struct InteractionRegion;
}
namespace WebKit {
@@ -44,7 +45,7 @@
@required
- (void)positionInformationForHoverPlatter:(WKHoverPlatter *)hoverPlatter withRequest:(WebKit::InteractionInformationRequest&)request completionHandler:(void (^)(WebKit::InteractionInformationAtPosition))completionHandler;
-- (void)interactableRegionsForHoverPlatter:(WKHoverPlatter *)hoverPlatter inRect:(WebCore::FloatRect)rect completionHandler:(void (^)(Vector<WebCore::FloatRect>))completionHandler;
+- (void)interactionRegionsForHoverPlatter:(WKHoverPlatter *)hoverPlatter inRect:(WebCore::FloatRect)rectInContentCoordinates completionHandler:(void (^)(Vector<WebCore::InteractionRegion>))completionHandler;
@end
Modified: trunk/Source/WebKit/UIProcess/ios/WKHoverPlatter.mm (292207 => 292208)
--- trunk/Source/WebKit/UIProcess/ios/WKHoverPlatter.mm 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Source/WebKit/UIProcess/ios/WKHoverPlatter.mm 2022-04-01 08:17:36 UTC (rev 292208)
@@ -30,6 +30,7 @@
#import "WKHoverPlatterParameters.h"
#import <UIKit/UIKit.h>
+#import <WebCore/InteractionRegion.h>
#import <WebCore/PathUtilities.h>
#import <WebCore/WebCoreCALayerExtras.h>
#import <pal/spi/cocoa/QuartzCoreSPI.h>
@@ -247,15 +248,17 @@
[linkHighlightLayer web_disableAllActions];
[[_view layer] addSublayer:linkHighlightLayer.get()];
- [_delegate interactableRegionsForHoverPlatter:self inRect:searchBoundingRect completionHandler:makeBlockPtr([self, strongSelf = retainPtr(self)] (Vector<WebCore::FloatRect> rects) {
+ [_delegate interactionRegionsForHoverPlatter:self inRect:searchBoundingRect completionHandler:makeBlockPtr([self, strongSelf = retainPtr(self)] (Vector<WebCore::InteractionRegion> regions) {
if (!_linkCountLayer && !_linkHighlightLayer)
return;
- [_linkCountLayer setString:[NSString stringWithFormat:@"%zu", rects.size()]];
+ [_linkCountLayer setString:[NSString stringWithFormat:@"%zu", regions.size()]];
WebCore::Path path;
- for (const auto& rect : rects)
- path.addRect(rect);
+ for (const auto& region : regions) {
+ for (const auto& rect : region.rectsInContentCoordinates)
+ path.addRect(rect);
+ }
[_linkHighlightLayer setPath:path.platformPath()];
}).get()];
Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp (292207 => 292208)
--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp 2022-04-01 08:17:36 UTC (rev 292208)
@@ -6408,41 +6408,9 @@
sendEditorStateUpdate();
}
-void WebPage::interactableRegionsInRootViewCoordinates(FloatRect rect, CompletionHandler<void(Vector<FloatRect>)>&& completionHandler)
+void WebPage::interactionRegions(FloatRect rectInContentCoordinates, CompletionHandler<void(Vector<InteractionRegion>)>&& completionHandler)
{
- Ref frame(m_page->mainFrame());
-
- if (RefPtr frameView = frame->view())
- frameView->updateLayoutAndStyleIfNeededRecursive();
-
- auto result = HitTestResult { LayoutRect(rect) };
- RefPtr document = frame->document();
- if (!document) {
- completionHandler({ });
- return;
- }
-
- HitTestRequest request({
- HitTestRequest::Type::ReadOnly,
- HitTestRequest::Type::AllowVisibleChildFrameContentOnly,
- HitTestRequest::Type::CollectMultipleElements
- });
- document->hitTest(request, result);
-
- Vector<FloatRect> rects;
-
- for (const auto& node : result.listBasedTestResult()) {
- if (!is<Element>(node.get()))
- continue;
- auto& element = downcast<Element>(node.get());
-
- if (!node->willRespondToMouseClickEvents())
- continue;
-
- rects.append(element.boundingBoxInRootViewCoordinates());
- }
-
- completionHandler(rects);
+ completionHandler(WebCore::interactionRegions(*m_page, rectInContentCoordinates));
}
void WebPage::setAlwaysShowsHorizontalScroller(bool alwaysShowsHorizontalScroller)
Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.h (292207 => 292208)
--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.h 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.h 2022-04-01 08:17:36 UTC (rev 292208)
@@ -247,6 +247,7 @@
struct ElementContext;
struct GlobalFrameIdentifier;
struct GlobalWindowIdentifier;
+struct InteractionRegion;
struct KeypressCommand;
struct MediaUsageInfo;
struct PromisedAttachmentInfo;
@@ -942,7 +943,7 @@
void didUpdateComposition();
void didEndUserTriggeredSelectionChanges();
- void interactableRegionsInRootViewCoordinates(WebCore::FloatRect, CompletionHandler<void(Vector<WebCore::FloatRect>)>&&);
+ void interactionRegions(WebCore::FloatRect rectInContentCoordinates, CompletionHandler<void(Vector<WebCore::InteractionRegion>)>&&);
#if PLATFORM(COCOA)
void platformInitializeAccessibility();
Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in (292207 => 292208)
--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in 2022-04-01 08:17:36 UTC (rev 292208)
@@ -681,5 +681,5 @@
ScrollToRect(WebCore::FloatRect targetRect, WebCore::FloatPoint origin)
- InteractableRegionsInRootViewCoordinates(WebCore::FloatRect rect) -> (Vector<WebCore::FloatRect> rects)
+ InteractionRegions(WebCore::FloatRect rectInContentCoordinates) -> (Vector<WebCore::InteractionRegion> regions)
}
Modified: trunk/Tools/ChangeLog (292207 => 292208)
--- trunk/Tools/ChangeLog 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Tools/ChangeLog 2022-04-01 08:17:36 UTC (rev 292208)
@@ -1,3 +1,19 @@
+2022-04-01 Tim Horton <timothy_hor...@apple.com>
+
+ Add a debug overlay for interaction regions
+ https://bugs.webkit.org/show_bug.cgi?id=238187
+
+ Reviewed by Wenson Hsieh.
+
+ * MiniBrowser/mac/SettingsController.h:
+ * MiniBrowser/mac/SettingsController.m:
+ (-[SettingsController _populateMenu]):
+ (-[SettingsController interactionRegionOverlayVisible]):
+ (-[SettingsController preferenceKeyForRegionOverlayTag:]):
+ * MiniBrowser/mac/WK2BrowserWindowController.m:
+ (-[WK2BrowserWindowController didChangeSettings]):
+ Add a switch for the new debug overlay in MiniBrowser.
+
2022-03-31 Chris Dumez <cdu...@apple.com>
Prepare WebKit/ & WebKitLegacy/ for making the String(const char*) constructor explicit
Modified: trunk/Tools/MiniBrowser/mac/SettingsController.h (292207 => 292208)
--- trunk/Tools/MiniBrowser/mac/SettingsController.h 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Tools/MiniBrowser/mac/SettingsController.h 2022-04-01 08:17:36 UTC (rev 292208)
@@ -43,6 +43,7 @@
@property (nonatomic, readonly) BOOL resourceUsageOverlayVisible;
@property (nonatomic, readonly) BOOL nonFastScrollableRegionOverlayVisible;
@property (nonatomic, readonly) BOOL wheelEventHandlerRegionOverlayVisible;
+@property (nonatomic, readonly) BOOL interactionRegionOverlayVisible;
@property (nonatomic, readonly) BOOL useUISideCompositing;
@property (nonatomic, readonly) BOOL perWindowWebProcessesDisabled;
@property (nonatomic, readonly) BOOL acceleratedDrawingEnabled;
Modified: trunk/Tools/MiniBrowser/mac/SettingsController.m (292207 => 292208)
--- trunk/Tools/MiniBrowser/mac/SettingsController.m 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Tools/MiniBrowser/mac/SettingsController.m 2022-04-01 08:17:36 UTC (rev 292208)
@@ -57,6 +57,7 @@
static NSString * const NonFastScrollableRegionOverlayVisiblePreferenceKey = @"NonFastScrollableRegionOverlayVisible";
static NSString * const WheelEventHandlerRegionOverlayVisiblePreferenceKey = @"WheelEventHandlerRegionOverlayVisible";
+static NSString * const InteractionRegionOverlayVisiblePreferenceKey = @"InteractionRegionOverlayVisible";
static NSString * const UseTransparentWindowsPreferenceKey = @"UseTransparentWindows";
static NSString * const UsePaginatedModePreferenceKey = @"UsePaginatedMode";
@@ -77,6 +78,7 @@
typedef NS_ENUM(NSInteger, DebugOverylayMenuItemTag) {
NonFastScrollableRegionOverlayTag = 100,
WheelEventHandlerRegionOverlayTag,
+ InteractionRegionOverlayTag,
ExperimentalFeatureTag,
InternalDebugFeatureTag,
};
@@ -195,6 +197,12 @@
[wheelEventHandlerRegionItem setTag:WheelEventHandlerRegionOverlayTag];
[wheelEventHandlerRegionItem setTarget:self];
[debugOverlaysMenu addItem:[wheelEventHandlerRegionItem autorelease]];
+
+ NSMenuItem *interactionRegionItem = [[NSMenuItem alloc] initWithTitle:@"Interaction Region" action:@selector(toggleDebugOverlay:) keyEquivalent:@""];
+ [interactionRegionItem setTag:InteractionRegionOverlayTag];
+ [interactionRegionItem setTarget:self];
+ [debugOverlaysMenu addItem:[interactionRegionItem autorelease]];
+
[debugOverlaysMenu release];
[_menu addItem:debugOverlaysSubmenuItem];
@@ -711,6 +719,11 @@
return [[NSUserDefaults standardUserDefaults] boolForKey:WheelEventHandlerRegionOverlayVisiblePreferenceKey];
}
+- (BOOL)interactionRegionOverlayVisible
+{
+ return [[NSUserDefaults standardUserDefaults] boolForKey:InteractionRegionOverlayVisiblePreferenceKey];
+}
+
- (NSString *)preferenceKeyForRegionOverlayTag:(NSUInteger)tag
{
switch (tag) {
@@ -719,6 +732,9 @@
case WheelEventHandlerRegionOverlayTag:
return WheelEventHandlerRegionOverlayVisiblePreferenceKey;
+
+ case InteractionRegionOverlayTag:
+ return InteractionRegionOverlayVisiblePreferenceKey;
}
return nil;
}
Modified: trunk/Tools/MiniBrowser/mac/WK2BrowserWindowController.m (292207 => 292208)
--- trunk/Tools/MiniBrowser/mac/WK2BrowserWindowController.m 2022-04-01 08:03:27 UTC (rev 292207)
+++ trunk/Tools/MiniBrowser/mac/WK2BrowserWindowController.m 2022-04-01 08:17:36 UTC (rev 292208)
@@ -521,6 +521,8 @@
visibleOverlayRegions |= _WKNonFastScrollableRegion;
if (settings.wheelEventHandlerRegionOverlayVisible)
visibleOverlayRegions |= _WKWheelEventHandlerRegion;
+ if (settings.interactionRegionOverlayVisible)
+ visibleOverlayRegions |= _WKInteractionRegion;
preferences._visibleDebugOverlayRegions = visibleOverlayRegions;