Bug 1255138 - Window resize support from JS for e10s. r=mconley

This commit is contained in:
Gabor Krizsanits 2016-05-11 11:44:57 +02:00
Родитель 881002d2ea
Коммит 2585c3f697
12 изменённых файлов: 238 добавлений и 54 удалений

Просмотреть файл

@ -25,6 +25,9 @@ interface nsITabChild : nsISupports
in CommandsArrayRef enabledCommands,
in CommandsArrayRef disabledCommands);
[noscript] void remoteSizeShellTo(in int32_t width, in int32_t height,
in int32_t shellItemWidth, in int32_t shellItemHeight);
readonly attribute uint64_t tabId;
};

Просмотреть файл

@ -159,6 +159,21 @@ parent:
*/
async MoveFocus(bool forward, bool forDocumentNavigation);
/**
* SizeShellTo request propagation to parent.
*
* aFlag Can indicate if one of the dimensions should be ignored.
* If only one dimension has changed it has to be indicated
* by the nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_* flags.
* aShellItemWidth,
* aShellItemHeight On parent side we won't be able to decide the dimensions
* of the shell item parameter in the original SizeShellTo
* call so we send over its dimensions that will be used
* for the actual resize.
**/
async SizeShellTo(uint32_t aFlag, int32_t aWidth, int32_t aHeight,
int32_t aShellItemWidth, int32_t aShellItemHeight);
async Event(RemoteDOMEvent aEvent);
sync SyncMessage(nsString aMessage, ClonedMessageData aData,

Просмотреть файл

@ -52,6 +52,7 @@
#include "nsContentUtils.h"
#include "nsDocShell.h"
#include "nsEmbedCID.h"
#include "nsGlobalWindow.h"
#include <algorithm>
#ifdef MOZ_CRASHREPORTER
#include "nsExceptionHandler.h"
@ -943,7 +944,30 @@ TabChild::DestroyBrowserWindow()
}
NS_IMETHODIMP
TabChild::SizeBrowserTo(int32_t aCX, int32_t aCY)
TabChild::RemoteSizeShellTo(int32_t aWidth, int32_t aHeight,
int32_t aShellItemWidth, int32_t aShellItemHeight)
{
nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation());
nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(ourDocShell));
int32_t width, height;
docShellAsWin->GetSize(&width, &height);
uint32_t flags = 0;
if (width == aWidth) {
flags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CX;
}
if (height == aHeight) {
flags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CY;
}
bool sent = SendSizeShellTo(flags, aWidth, aHeight, aShellItemWidth, aShellItemHeight);
return sent ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
TabChild::SizeBrowserTo(int32_t aWidth, int32_t aHeight)
{
NS_WARNING("TabChild::SizeBrowserTo not supported in TabChild");
@ -987,9 +1011,37 @@ TabChild::SetStatusWithContext(uint32_t aStatusType,
NS_IMETHODIMP
TabChild::SetDimensions(uint32_t aFlags, int32_t aX, int32_t aY,
int32_t aCx, int32_t aCy)
int32_t aCx, int32_t aCy)
{
Unused << PBrowserChild::SendSetDimensions(aFlags, aX, aY, aCx, aCy);
// The parent is in charge of the dimension changes. If JS code wants to
// change the dimensions (moveTo, screenX, etc.) we send a message to the
// parent about the new requested dimension, the parent does the resize/move
// then send a message to the child to update itself. For APIs like screenX
// this function is called with the current value for the non-changed values.
// In a series of calls like window.screenX = 10; window.screenY = 10; for
// the second call, since screenX is not yet updated we might accidentally
// reset back screenX to it's old value. To avoid this if a parameter did not
// change we want the parent to ignore its value.
int32_t x, y, cx, cy;
GetDimensions(aFlags, &x, &y, &cx, &cy);
if (x == aX) {
aFlags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_X;
}
if (y == aY) {
aFlags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_Y;
}
if (cx == aCx) {
aFlags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CX;
}
if (cy == aCy) {
aFlags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CY;
}
Unused << SendSetDimensions(aFlags, aX, aY, aCx, aCy);
return NS_OK;
}

Просмотреть файл

@ -619,6 +619,37 @@ TabParent::RecvMoveFocus(const bool& aForward, const bool& aForDocumentNavigatio
return true;
}
bool
TabParent::RecvSizeShellTo(const uint32_t& aFlags, const int32_t& aWidth, const int32_t& aHeight,
const int32_t& aShellItemWidth, const int32_t& aShellItemHeight)
{
NS_ENSURE_TRUE(mFrameElement, true);
nsCOMPtr<nsIDocShell> docShell = mFrameElement->OwnerDoc()->GetDocShell();
NS_ENSURE_TRUE(docShell, true);
nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
nsresult rv = docShell->GetTreeOwner(getter_AddRefs(treeOwner));
NS_ENSURE_SUCCESS(rv, true);
int32_t width = aWidth;
int32_t height = aHeight;
if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CX) {
width = mDimensions.width;
}
if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CY) {
height = mDimensions.height;
}
nsCOMPtr<nsIXULWindow> xulWin(do_GetInterface(treeOwner));
NS_ENSURE_TRUE(xulWin, true);
xulWin->SizeShellToWithLimit(width, height, aShellItemWidth, aShellItemHeight);
return true;
}
bool
TabParent::RecvEvent(const RemoteDOMEvent& aEvent)
{
@ -814,19 +845,44 @@ TabParent::RecvSetDimensions(const uint32_t& aFlags,
nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = do_QueryInterface(treeOwner);
NS_ENSURE_TRUE(treeOwnerAsWin, true);
// We only care about the parameters that actually changed, see more
// details in TabChild::SetDimensions.
int32_t unused;
int32_t x = aX;
if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_X) {
treeOwnerAsWin->GetPosition(&x, &unused);
}
int32_t y = aY;
if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_Y) {
treeOwnerAsWin->GetPosition(&unused, &y);
}
int32_t cx = aCx;
if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CX) {
treeOwnerAsWin->GetSize(&cx, &unused);
}
int32_t cy = aCy;
if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CY) {
treeOwnerAsWin->GetSize(&unused, &cy);
}
if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION &&
aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER) {
treeOwnerAsWin->SetPositionAndSize(aX, aY, aCx, aCy, true);
treeOwnerAsWin->SetPositionAndSize(x, y, cx, cy, true);
return true;
}
if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION) {
treeOwnerAsWin->SetPosition(aX, aY);
treeOwnerAsWin->SetPosition(x, y);
mUpdatedDimensions = false;
UpdatePosition();
return true;
}
if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER) {
treeOwnerAsWin->SetSize(aCx, aCy, true);
treeOwnerAsWin->SetSize(cx, cy, true);
return true;
}

Просмотреть файл

@ -161,6 +161,12 @@ public:
virtual bool RecvMoveFocus(const bool& aForward,
const bool& aForDocumentNavigation) override;
virtual bool RecvSizeShellTo(const uint32_t& aFlags,
const int32_t& aWidth,
const int32_t& aHeight,
const int32_t& aShellItemWidth,
const int32_t& aShellItemHeight) override;
virtual bool RecvEvent(const RemoteDOMEvent& aEvent) override;
virtual bool RecvReplyKeyEvent(const WidgetKeyboardEvent& aEvent) override;

Просмотреть файл

@ -160,9 +160,9 @@ skip-if = toolkit == 'android' #bug 775227
[test_onerror_message.html]
[test_protochains.html]
[test_resize_move_windows.html]
skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s #Windows can't change size and position on Android # b2g(Windows can't change size and position on B2G) b2g-debug(Windows can't change size and position on B2G) b2g-desktop(Windows can't change size and position on B2G)
skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || os == 'linux' #Windows can't change size and position on Android # b2g(Windows can't change size and position on B2G) b2g-debug(Windows can't change size and position on B2G) b2g-desktop(Windows can't change size and position on B2G)
[test_sizetocontent_clamp.html]
skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s #Windows can't change size on Android # b2g(Windows can't change size on B2G) b2g-debug(Windows can't change size on B2G) b2g-desktop(Windows can't change size on B2G)
skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' #Windows can't change size on Android # b2g(Windows can't change size on B2G) b2g-debug(Windows can't change size on B2G) b2g-desktop(Windows can't change size on B2G)
[test_toJSON.html]
[test_window_bar.html]
skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android'

Просмотреть файл

@ -237,9 +237,6 @@ function checkChangeIsEnabled(aWindow, aNext)
function outerChangeTest() {
isnot(aWindow.outerWidth, oWidth, "Window outerWidth should have changed");
isnot(aWindow.outerHeight, oHeight, "Window outerHeight should have changed");
aWindow.outerWidth = oWidth;
aWindow.outerHeight = oHeight;
}
/**
@ -247,31 +244,22 @@ function checkChangeIsEnabled(aWindow, aNext)
*/
prevWidth = aWindow.innerWidth;
prevHeight = aWindow.innerHeight;
aWindow.innerWidth = getNewWidth(aWindow);
aWindow.innerHeight = getNewHeight(aWindow);
hitEventLoop(sizeChangeCondition, sizeChangeTest, hits)
.then(function() {
aWindow.resizeTo(getNewWidth(aWindow), getNewHeight(aWindow));
})
.then(function() {
return hitEventLoop(sizeChangeCondition, sizeChangeTest, hits);
})
.then(function () {
aWindow.resizeBy(getNewWidth(aWindow) - aWindow.innerWidth,
getNewHeight(aWindow) - aWindow.innerHeight);
})
.then(function() {
return hitEventLoop(sizeChangeCondition, sizeChangeTest, hits);
})
.then(function () {
prevWidth = aWindow.innerWidth = getNewWidth(aWindow);
prevHeight = aWindow.innerHeight = getNewHeight(aWindow);
aWindow.sizeToContent();
})
.then(function() {
hitEventLoop(sizeChangeCondition, sizeChangeTest, hits);
aWindow.sizeToContent();
return hitEventLoop(sizeChangeCondition, sizeChangeTest, hits);
})
.then(function() {
/**
@ -282,8 +270,6 @@ function checkChangeIsEnabled(aWindow, aNext)
aWindow.screenX = getNewX(aWindow);
aWindow.screenY = getNewY(aWindow);
})
.then(function() {
return hitEventLoop(posChangeCondition, posChangeTest, hits);
})
.then(function() {
@ -291,8 +277,6 @@ function checkChangeIsEnabled(aWindow, aNext)
prevY = aWindow.screenY;
aWindow.moveTo(getNewX(aWindow), getNewY(aWindow));
})
.then(function() {
return hitEventLoop(posChangeCondition, posChangeTest, hits);
})
.then(function() {
@ -301,8 +285,6 @@ function checkChangeIsEnabled(aWindow, aNext)
aWindow.moveBy(getNewX(aWindow) - aWindow.screenX,
getNewY(aWindow) - aWindow.screenY);
})
.then(function() {
return hitEventLoop(posChangeCondition, posChangeTest, hits);
})
.then(function() {
@ -314,8 +296,17 @@ function checkChangeIsEnabled(aWindow, aNext)
aWindow.outerWidth = oWidth * 2;
aWindow.outerHeight = oHeight * 2;
return hitEventLoop(outerChangeCondition, outerChangeTest, hits);
})
.then(function() {
let origWidth = oWidth;
let origHeight = oHeight;
oWidth = aWindow.outerWidth;
oHeight = aWindow.outerHeight;
aWindow.outerWidth = origWidth;
aWindow.outerHeight = origHeight;
return hitEventLoop(outerChangeCondition, outerChangeTest, hits);
})
.then(aNext);

Просмотреть файл

@ -35,25 +35,24 @@ var isWin8 = (navigator.userAgent.indexOf("Windows NT 6.2") != -1);
var innerWidthMin = (isWin8 ? 120 : 100);
var innerWidthMax = (isWin8 ? 125 : 100);
var isExecuted = false;
function test() {
var w = window.open('data:text/html,null', null, 'width=300,height=300');
var nbResize = 0;
SimpleTest.waitForFocus(function() {
w.onresize = function() {
nbResize++;
if (nbResize == 1) {
if (w.innerWidth > 300 - epsilon || isExecuted) {
return;
}
ok(w.innerWidth + epsilon >= innerWidthMin && w.innerWidth - epsilon <= innerWidthMax,
"innerWidth should be between " + innerWidthMin + " and " + innerWidthMax);
ok(w.innerHeight + epsilon >= 100 && w.innerHeight - epsilon <= 100,
"innerHeight should be around 100");
isExecuted = true;
// It's not clear why 2 events are coming...
is(nbResize, 2, "We should get 2 events.");
ok(w.innerWidth + epsilon >= innerWidthMin && w.innerWidth - epsilon <= innerWidthMax,
"innerWidth should be between " + innerWidthMin + " and " + innerWidthMax + " but it was: " + w.innerWidth);
ok(w.innerHeight + epsilon >= 100 && w.innerHeight - epsilon <= 100,
"innerHeight should be around 100" + " but it was: " + w.innerHeight);
w.close();

Просмотреть файл

@ -57,6 +57,7 @@
#include "nsPIWindowWatcher.h"
#include "nsIPrompt.h"
#include "nsITabParent.h"
#include "nsITabChild.h"
#include "nsRect.h"
#include "nsIWebBrowserChromeFocus.h"
#include "nsIContent.h"
@ -455,6 +456,19 @@ nsDocShellTreeOwner::SizeShellTo(nsIDocShellTreeItem* aShellItem,
}
if (aShellItem == mWebBrowser->mDocShell) {
nsCOMPtr<nsITabChild> tabChild = do_QueryInterface(webBrowserChrome);
if (tabChild) {
// The XUL window to resize is in the parent process, but there we
// won't be able to get aShellItem to do the hack in nsXULWindow::SizeShellTo,
// so let's send the width and height of aShellItem too.
nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(aShellItem));
NS_ENSURE_TRUE(shellAsWin, NS_ERROR_FAILURE);
int32_t width = 0;
int32_t height = 0;
shellAsWin->GetSize(&width, &height);
return tabChild->RemoteSizeShellTo(aCX, aCY, width, height);
}
return webBrowserChrome->SizeBrowserTo(aCX, aCY);
}
@ -578,7 +592,8 @@ NS_IMETHODIMP
nsDocShellTreeOwner::SetPositionDesktopPix(int32_t aX, int32_t aY)
{
if (mWebBrowser) {
return mWebBrowser->SetPositionDesktopPix(aX, aY);
nsresult rv = mWebBrowser->SetPositionDesktopPix(aX, aY);
NS_ENSURE_SUCCESS(rv, rv);
}
double scale = 1.0;

Просмотреть файл

@ -46,6 +46,35 @@ interface nsIEmbeddingSiteWindow : nsISupports
*/
const unsigned long DIM_FLAGS_SIZE_OUTER = 4;
/**
* Flag indicates that the x parameter should be ignored.
*
* @see setDimensions
*/
const unsigned long DIM_FLAGS_IGNORE_X = 8;
/**
* Flag indicates that the y parameter should be ignored.
*
* @see setDimensions
*/
const unsigned long DIM_FLAGS_IGNORE_Y = 16;
/**
* Flag indicates that the cx parameter should be ignored.
*
* @see setDimensions
*/
const unsigned long DIM_FLAGS_IGNORE_CX = 32;
/**
* Flag indicates that the cy parameter should be ignored.
*
* @see setDimensions
*/
const unsigned long DIM_FLAGS_IGNORE_CY = 64;
/**
* Sets the dimensions for the window; the position & size. The
* flags to indicate what the caller wants to set and whether the size
@ -54,6 +83,9 @@ interface nsIEmbeddingSiteWindow : nsISupports
* surrounding chrome, window frame, title bar, and so on.
*
* @param flags Combination of position, inner and outer size flags.
* The ignore flags are telling the parent to use the
* current values for those dimensions and ignore the
* corresponding parameters the child sends.
* @param x Left hand corner of the outer area.
* @param y Top corner of the outer area.
* @param cx Width of the inner or outer area.

Просмотреть файл

@ -134,4 +134,13 @@ interface nsIXULWindow : nsISupports
* docshell could cause problems.
*/
[noscript] void applyChromeFlags();
/**
* Sometimes the child's nsDocShellTreeOwner needs to propogate a SizeShellTo call to the parent. But the
* shellItem argument of the call will not be available on the parent side, so we pass its dimensions here.
* Note: this is an internal method, other consumers should never call this.
*/
[noscript, notxpcom] void sizeShellToWithLimit(in int32_t aCx, in int32_t aCy,
in int32_t shellItemCx, in int32_t shellItemCy);
};

Просмотреть файл

@ -1815,22 +1815,7 @@ NS_IMETHODIMP nsXULWindow::SizeShellTo(nsIDocShellTreeItem* aShellItem,
int32_t height = 0;
shellAsWin->GetSize(&width, &height);
int32_t widthDelta = aCX - width;
int32_t heightDelta = aCY - height;
if (widthDelta || heightDelta) {
int32_t winCX = 0;
int32_t winCY = 0;
GetSize(&winCX, &winCY);
// There's no point in trying to make the window smaller than the
// desired docshell size --- that's not likely to work. This whole
// function assumes that the outer docshell is adding some constant
// "border" chrome to aShellItem.
winCX = std::max(winCX + widthDelta, aCX);
winCY = std::max(winCY + heightDelta, aCY);
SetSize(winCX, winCY, true);
}
SizeShellToWithLimit(aCX, aCY, width, height);
return NS_OK;
}
@ -2196,6 +2181,27 @@ NS_IMETHODIMP nsXULWindow::SetXULBrowserWindow(nsIXULBrowserWindow * aXULBrowser
return NS_OK;
}
void nsXULWindow::SizeShellToWithLimit(int32_t aCX, int32_t aCY,
int32_t shellItemCx, int32_t shellItemCy)
{
int32_t widthDelta = aCX - shellItemCx;
int32_t heightDelta = aCY - shellItemCy;
if (widthDelta || heightDelta) {
int32_t winCX = 0;
int32_t winCY = 0;
GetSize(&winCX, &winCY);
// There's no point in trying to make the window smaller than the
// desired docshell size --- that's not likely to work. This whole
// function assumes that the outer docshell is adding some constant
// "border" chrome to aShellItem.
winCX = std::max(winCX + widthDelta, aCX);
winCY = std::max(winCY + heightDelta, aCY);
SetSize(winCX, winCY, true);
}
}
//*****************************************************************************
//*** nsContentShellInfo: Object Management
//*****************************************************************************