Skip to content

Commit

Permalink
[macOS] Crash when presenting a datalist dropdown for a transformed e…
Browse files Browse the repository at this point in the history
…lement

https://bugs.webkit.org/show_bug.cgi?id=256029
rdar://105190475

Reviewed by Wenson Hsieh.

AppKit throws an exception when an `NSWindow` is constructed with an
invalid frame. The `<datalist>` dropdown is an `NSWindow` with a frame derived
from the rect of its associated element. When this element is off-screen or
abnormally large, the frame used for the window may be invalid.

Fix by ensuring the frame can never be outside the screen.

* LayoutTests/fast/forms/datalist/datalist-dropdown-transformed-element-crash-expected.txt: Added.
* LayoutTests/fast/forms/datalist/datalist-dropdown-transformed-element-crash.html: Added.
* Source/WebKit/UIProcess/mac/WebDataListSuggestionsDropdownMac.mm:
(-[WKDataListSuggestionsController dropdownRectForElementRect:]):

1. Use the presenting window's screen, rather than the main screen for correctness.
2. Take the intersection of the screen's visible frame and the element's visible frame to avoid using an invalid rect.
3. Ensure the minimum origin of the window is (0, 0).

Canonical link: https://commits.webkit.org/259548.702@safari-7615-branch
  • Loading branch information
pxlcoder committed Apr 28, 2023
1 parent 242b34d commit d7114d6
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
PASS if no crash.

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<style>
* { transform: skew(180deg, 90deg); }
</style>
<script>

if (window.testRunner)
testRunner.dumpAsText();

function load() {
input.focus();
document.execCommand("insertHTML", false, "A");
}

</script>
<body onload="load()">
<div>PASS if no crash.</div>
<input id="input" list="list">
<datalist id="list">
<option id="option">AAAAAAAAAA</option>
</datalist>
</body>
18 changes: 12 additions & 6 deletions Source/WebKit/UIProcess/mac/WebDataListSuggestionsDropdownMac.mm
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,13 @@ - (void)invalidate

- (NSRect)dropdownRectForElementRect:(const WebCore::IntRect&)rect
{
NSRect windowRect = [[_presentingView window] convertRectToScreen:[_presentingView convertRect:rect toView:nil]];
NSWindow *presentingWindow = [_presentingView window];
NSRect screenRect = presentingWindow.screen.visibleFrame;
NSRect windowRect = [presentingWindow convertRectToScreen:[_presentingView convertRect:rect toView:nil]];

windowRect = CGRectIntersection(windowRect, screenRect);
if (CGRectIsNull(windowRect))
return NSZeroRect;

CGFloat totalCellHeight = 0;
for (auto& suggestion : _suggestions)
Expand All @@ -449,11 +455,11 @@ - (NSRect)dropdownRectForElementRect:(const WebCore::IntRect&)rect
if (_suggestions.size() > 1)
totalIntercellSpacingAndPadding += (_suggestions.size() - 1) * [_table intercellSpacing].height;

CGSize mainScreenFrameSize = NSScreen.mainScreen.frame.size;
CGFloat width = std::min<CGFloat>(rect.width(), mainScreenFrameSize.width);
CGFloat height = std::min<CGFloat>(totalIntercellSpacingAndPadding + std::min(totalCellHeight, maximumTotalHeightForDropdownCells), mainScreenFrameSize.height);
CGFloat originX = std::max<CGFloat>(NSMinX(windowRect), std::numeric_limits<int>::min());
CGFloat originY = std::max<CGFloat>(NSMinY(windowRect) - height - dropdownTopMargin, std::numeric_limits<int>::min());
CGFloat width = std::min<CGFloat>(rect.width(), screenRect.size.width);
CGFloat height = std::min<CGFloat>(totalIntercellSpacingAndPadding + std::min(totalCellHeight, maximumTotalHeightForDropdownCells), screenRect.size.height);
CGFloat originX = std::max<CGFloat>(NSMinX(windowRect), 0);
CGFloat originY = std::max<CGFloat>(NSMinY(windowRect) - height - dropdownTopMargin, 0);

return NSMakeRect(originX, originY, width, height);
}

Expand Down

0 comments on commit d7114d6

Please sign in to comment.