Bug 413277: Restrict window resizing to the size of the current screen on Mac OS X. r=josh a=josh

This commit is contained in:
Scott Greenlay 2010-10-22 12:34:16 -04:00
parent 25ccca1076
commit f83371fec8
3 changed files with 67 additions and 31 deletions

View File

@ -206,25 +206,23 @@ nsCocoaWindow::~nsCocoaWindow()
NS_OBJC_END_TRY_ABORT_BLOCK;
}
// Very large windows work in Cocoa, but can take a long time to
// process (multiple minutes), during which time the system is
// unresponsive and seems hung. Although it's likely that windows
// much larger than screen size are bugs, be conservative and only
// intervene if the values are so large as to hog the cpu.
#define SIZE_LIMIT 100000
static bool WindowSizeAllowed(PRInt32 aWidth, PRInt32 aHeight)
static void FitRectToVisibleAreaForScreen(nsIntRect &aRect, NSScreen *screen)
{
if (aWidth > SIZE_LIMIT) {
NS_ERROR(nsPrintfCString(256, "Requested Cocoa window width of %d is too much, max allowed is %d",
aWidth, SIZE_LIMIT).get());
return false;
nsIntRect screenBounds(nsCocoaUtils::CocoaRectToGeckoRect([screen visibleFrame]));
if (aRect.width > screenBounds.width) {
aRect.width = screenBounds.width;
}
if (aHeight > SIZE_LIMIT) {
NS_ERROR(nsPrintfCString(256, "Requested Cocoa window height of %d is too much, max allowed is %d",
aHeight, SIZE_LIMIT).get());
return false;
if (aRect.height > screenBounds.height) {
aRect.height = screenBounds.height;
}
if (aRect.x - screenBounds.x + aRect.width > screenBounds.width) {
aRect.x += screenBounds.width - (aRect.x - screenBounds.x + aRect.width);
}
if (aRect.y - screenBounds.y + aRect.height > screenBounds.height) {
aRect.y += screenBounds.height - (aRect.y - screenBounds.y + aRect.height);
}
return true;
}
// Some applications like Camino use native popup windows
@ -255,14 +253,14 @@ nsresult nsCocoaWindow::Create(nsIWidget *aParent,
// we have to provide an autorelease pool (see bug 559075).
nsAutoreleasePool localPool;
if (!WindowSizeAllowed(aRect.width, aRect.height))
return NS_ERROR_FAILURE;
nsIntRect newBounds = aRect;
FitRectToVisibleAreaForScreen(newBounds, [NSScreen mainScreen]);
// Set defaults which can be overriden from aInitData in BaseCreate
mWindowType = eWindowType_toplevel;
mBorderStyle = eBorderStyle_default;
Inherited::BaseCreate(aParent, aRect, aHandleEventFunction, aContext, aAppShell,
Inherited::BaseCreate(aParent, newBounds, aHandleEventFunction, aContext, aAppShell,
aToolkit, aInitData);
mParent = aParent;
@ -271,12 +269,12 @@ nsresult nsCocoaWindow::Create(nsIWidget *aParent,
if ((mWindowType == eWindowType_popup) && UseNativePopupWindows())
return NS_OK;
nsresult rv = CreateNativeWindow(nsCocoaUtils::GeckoRectToCocoaRect(aRect),
nsresult rv = CreateNativeWindow(nsCocoaUtils::GeckoRectToCocoaRect(newBounds),
mBorderStyle, PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
if (mWindowType == eWindowType_popup)
return CreatePopupContentView(aRect, aHandleEventFunction, aContext, aAppShell, aToolkit);
return CreatePopupContentView(newBounds, aHandleEventFunction, aContext, aAppShell, aToolkit);
return NS_OK;
@ -1126,17 +1124,17 @@ NS_IMETHODIMP nsCocoaWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRIn
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
if (!WindowSizeAllowed(aWidth, aHeight))
return NS_ERROR_FAILURE;
nsIntRect newBounds = nsIntRect(aX, aY, aWidth, aHeight);
FitRectToVisibleAreaForScreen(newBounds, [mWindow screen]);
nsIntRect windowBounds(nsCocoaUtils::CocoaRectToGeckoRect([mWindow frame]));
BOOL isMoving = (windowBounds.x != aX || windowBounds.y != aY);
BOOL isResizing = (windowBounds.width != aWidth || windowBounds.height != aHeight);
BOOL isMoving = (windowBounds.x != newBounds.x || windowBounds.y != newBounds.y);
BOOL isResizing = (windowBounds.width != newBounds.width || windowBounds.height != newBounds.height);
if (IsResizing() || !mWindow || (!isMoving && !isResizing))
return NS_OK;
mBounds = nsIntRect(aX, aY, aWidth, aHeight);
mBounds = newBounds;
NSRect newFrame = nsCocoaUtils::GeckoRectToCocoaRect(mBounds);
// We have to report the size event -first-, to make sure that content
@ -1171,10 +1169,7 @@ NS_IMETHODIMP nsCocoaWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRIn
NS_IMETHODIMP nsCocoaWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
if (!WindowSizeAllowed(aWidth, aHeight))
return NS_ERROR_FAILURE;
nsIntRect windowBounds(nsCocoaUtils::CocoaRectToGeckoRect([mWindow frame]));
return Resize(windowBounds.x, windowBounds.y, aWidth, aHeight, aRepaint);

View File

@ -81,12 +81,15 @@ _CHROME_FILES = test_bug343416.xul \
window_composition_text_querycontent.xul \
test_input_events_on_deactive_window.xul \
$(NULL)
# test_bug413277.html mac-only based on 604789, 605178
ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
_CHROME_FILES += native_menus_window.xul \
test_native_menus.xul \
native_mouse_mac_window.xul \
test_native_mouse_mac.xul \
test_bug413277.html \
test_bug428405.xul \
test_bug466599.xul \
test_bug485118.xul \

View File

@ -0,0 +1,38 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=413277
-->
<head>
<title>Test for Bug 413277</title>
<script type="text/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=413277">Mozilla Bug 413277</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="application/javascript">
var atts='width=100, height=100, top=100, screenY=100';
atts += ', left=100, screenX=100, toolbar=no';
atts += ', location=no, directories=no, status=no';
atts += ', menubar=no, scrollbars=no, resizable=no';
var newWindow = window.open('_blank', 'win_name', atts);
newWindow.resizeBy(1000000, 1000000);
SimpleTest.is(newWindow.outerWidth, newWindow.screen.availWidth, true);
SimpleTest.is(newWindow.outerHeight, newWindow.screen.availHeight, true);
SimpleTest.is(newWindow.screenY, newWindow.screen.availTop, true);
SimpleTest.is(newWindow.screenX, newWindow.screen.availLeft, true);
newWindow.close();
</script>
</pre>
</body>