Bug 1330882 - Part 4: Making the window.open() can only open rounded windows and the inner window will be automatically rounded after setting size through innerWidth/Height and outerWidth/Height when fingerprinting resistance is enabled. r=smaug

This patch makes the size of inner windows will be automatically rounded for
either window.open() with window features or setting window size through
innerWidth/Height and outerWidth/Height when fingerprinting resistance is
enabled. If the given value is greater the maximum available rounded size, then
it will be set to the maximum value. Otherwise, the size will be set to the
nearest upper 200x100.

This patch also adds one helper function in nsContentUtils for calculating the
rounded window dimensions.

MozReview-Commit-ID: J2r3951vuNN

--HG--
extra : rebase_source : a44b19bdf2ce7e90fc831ddc2b85a86d594cb0c3
This commit is contained in:
Tim Huang 2017-03-29 15:43:56 +08:00
Родитель 5ef6d9b620
Коммит 3b43737132
5 изменённых файлов: 274 добавлений и 56 удалений

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

@ -293,6 +293,9 @@ bool nsContentUtils::sPrivacyResistFingerprinting = false;
bool nsContentUtils::sSendPerformanceTimingNotifications = false;
bool nsContentUtils::sUseActivityCursor = false;
int32_t nsContentUtils::sPrivacyMaxInnerWidth = 1000;
int32_t nsContentUtils::sPrivacyMaxInnerHeight = 1000;
uint32_t nsContentUtils::sHandlingInputTimeout = 1000;
uint32_t nsContentUtils::sCookiesLifetimePolicy = nsICookieService::ACCEPT_NORMALLY;
@ -591,6 +594,14 @@ nsContentUtils::Init()
Preferences::AddBoolVarCache(&sPrivacyResistFingerprinting,
"privacy.resistFingerprinting", false);
Preferences::AddIntVarCache(&sPrivacyMaxInnerWidth,
"privacy.window.maxInnerWidth",
1000);
Preferences::AddIntVarCache(&sPrivacyMaxInnerHeight,
"privacy.window.maxInnerHeight",
1000);
Preferences::AddUintVarCache(&sHandlingInputTimeout,
"dom.event.handling-user-input-time-limit",
1000);
@ -2154,6 +2165,77 @@ nsContentUtils::ShouldResistFingerprinting(nsIDocShell* aDocShell)
return !isChrome && sPrivacyResistFingerprinting;
}
/* static */
void
nsContentUtils::CalcRoundedWindowSizeForResistingFingerprinting(int32_t aChromeWidth,
int32_t aChromeHeight,
int32_t aScreenWidth,
int32_t aScreenHeight,
int32_t aInputWidth,
int32_t aInputHeight,
bool aSetOuterWidth,
bool aSetOuterHeight,
int32_t* aOutputWidth,
int32_t* aOutputHeight)
{
MOZ_ASSERT(aOutputWidth);
MOZ_ASSERT(aOutputHeight);
int32_t availContentWidth = 0;
int32_t availContentHeight = 0;
availContentWidth = std::min(sPrivacyMaxInnerWidth,
aScreenWidth - aChromeWidth);
#ifdef MOZ_WIDGET_GTK
// In the GTK window, it will not report outside system decorations
// when we get available window size, see Bug 581863. So, we leave a
// 40 pixels space for them when calculating the available content
// height. It is not necessary for the width since the content width
// is usually pretty much the same as the chrome width.
availContentHeight = std::min(sPrivacyMaxInnerHeight,
(-40 + aScreenHeight) - aChromeHeight);
#else
availContentHeight = std::min(sPrivacyMaxInnerHeight,
aScreenHeight - aChromeHeight);
#endif
// Ideally, we'd like to round window size to 1000x1000, but the
// screen space could be too small to accommodate this size in some
// cases. If it happens, we would round the window size to the nearest
// 200x100.
availContentWidth = availContentWidth - (availContentWidth % 200);
availContentHeight = availContentHeight - (availContentHeight % 100);
// If aIsOuter is true, we are setting the outer window. So we
// have to consider the chrome UI.
int32_t chromeOffsetWidth = aSetOuterWidth ? aChromeWidth : 0;
int32_t chromeOffsetHeight = aSetOuterHeight ? aChromeHeight : 0;
int32_t resultWidth = 0, resultHeight = 0;
// if the original size is greater than the maximum available size, we set
// it to the maximum size. And if the original value is less than the
// minimum rounded size, we set it to the minimum 200x100.
if (aInputWidth > (availContentWidth + chromeOffsetWidth)) {
resultWidth = availContentWidth + chromeOffsetWidth;
} else if (aInputWidth < (200 + chromeOffsetWidth)) {
resultWidth = 200 + chromeOffsetWidth;
} else {
// Otherwise, we round the window to the nearest upper rounded 200x100.
resultWidth = NSToIntCeil((aInputWidth - chromeOffsetWidth) / 200.0) * 200 + chromeOffsetWidth;
}
if (aInputHeight > (availContentHeight + chromeOffsetHeight)) {
resultHeight = availContentHeight + chromeOffsetHeight;
} else if (aInputHeight < (100 + chromeOffsetHeight)) {
resultHeight = 100 + chromeOffsetHeight;
} else {
resultHeight = NSToIntCeil((aInputHeight - chromeOffsetHeight) / 100.0) * 100 + chromeOffsetHeight;
}
*aOutputWidth = resultWidth;
*aOutputHeight = resultHeight;
}
bool
nsContentUtils::ThreadsafeIsCallerChrome()
{

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

@ -268,6 +268,22 @@ public:
static bool ShouldResistFingerprinting();
static bool ShouldResistFingerprinting(nsIDocShell* aDocShell);
// A helper function to calculate the rounded window size for fingerprinting
// resistance. The rounded size is based on the chrome UI size and available
// screen size. If the inputWidth/Height is greater than the available content
// size, this will report the available content size. Otherwise, it will
// round the size to the nearest upper 200x100.
static void CalcRoundedWindowSizeForResistingFingerprinting(int32_t aChromeWidth,
int32_t aChromeHeight,
int32_t aScreenWidth,
int32_t aScreenHeight,
int32_t aInputWidth,
int32_t aInputHeight,
bool aSetOuterWidth,
bool aSetOuterHeight,
int32_t* aOutputWidth,
int32_t* aOutputHeight);
/**
* Returns the parent node of aChild crossing document boundaries.
* Uses the parent node in the composed document.
@ -2934,6 +2950,9 @@ private:
static uint32_t sCookiesLifetimePolicy;
static uint32_t sCookiesBehavior;
static int32_t sPrivacyMaxInnerWidth;
static int32_t sPrivacyMaxInnerHeight;
static nsHtml5StringParser* sHTMLFragmentParser;
static nsIParser* sXMLFragmentParser;
static nsIFragmentContentSink* sXMLFragmentSink;

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

@ -14798,6 +14798,101 @@ nsGlobalWindow::SetReplaceableWindowCoord(JSContext* aCx,
return;
}
if (nsContentUtils::ShouldResistFingerprinting(GetDocShell())) {
bool innerWidthSpecified = false;
bool innerHeightSpecified = false;
bool outerWidthSpecified = false;
bool outerHeightSpecified = false;
if (strcmp(aPropName, "innerWidth") == 0) {
innerWidthSpecified = true;
} else if (strcmp(aPropName, "innerHeight") == 0) {
innerHeightSpecified = true;
} else if (strcmp(aPropName, "outerWidth") == 0) {
outerWidthSpecified = true;
} else if (strcmp(aPropName, "outerHeight") == 0) {
outerHeightSpecified = true;
}
if (innerWidthSpecified || innerHeightSpecified ||
outerWidthSpecified || outerHeightSpecified)
{
nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = outer->GetTreeOwnerWindow();
nsCOMPtr<nsIScreen> screen;
nsCOMPtr<nsIScreenManager> screenMgr(
do_GetService("@mozilla.org/gfx/screenmanager;1"));
int32_t winLeft = 0;
int32_t winTop = 0;
int32_t winWidth = 0;
int32_t winHeight = 0;
double scale = 1.0;
if (treeOwnerAsWin && screenMgr) {
// Acquire current window size.
treeOwnerAsWin->GetUnscaledDevicePixelsPerCSSPixel(&scale);
treeOwnerAsWin->GetPositionAndSize(&winLeft, &winTop, &winWidth, &winHeight);
winLeft = NSToIntRound(winHeight / scale);
winTop = NSToIntRound(winWidth / scale);
winWidth = NSToIntRound(winWidth / scale);
winHeight = NSToIntRound(winHeight / scale);
// Acquire content window size.
CSSIntSize contentSize;
outer->GetInnerSize(contentSize);
screenMgr->ScreenForRect(winLeft, winTop, winWidth, winHeight,
getter_AddRefs(screen));
if (screen) {
int32_t* targetContentWidth = nullptr;
int32_t* targetContentHeight = nullptr;
int32_t screenWidth = 0;
int32_t screenHeight = 0;
int32_t chromeWidth = 0;
int32_t chromeHeight = 0;
int32_t inputWidth = 0;
int32_t inputHeight = 0;
int32_t unused = 0;
// Get screen dimensions (in device pixels)
screen->GetAvailRect(&unused, &unused, &screenWidth,
&screenHeight);
// Convert them to CSS pixels
screenWidth = NSToIntRound(screenWidth / scale);
screenHeight = NSToIntRound(screenHeight / scale);
// Calculate the chrome UI size.
chromeWidth = winWidth - contentSize.width;
chromeHeight = winHeight - contentSize.height;
if (innerWidthSpecified || outerWidthSpecified) {
inputWidth = value;
targetContentWidth = &value;
targetContentHeight = &unused;
} else if (innerHeightSpecified || outerHeightSpecified) {
inputHeight = value;
targetContentWidth = &unused;
targetContentHeight = &value;
}
nsContentUtils::CalcRoundedWindowSizeForResistingFingerprinting(
chromeWidth,
chromeHeight,
screenWidth,
screenHeight,
inputWidth,
inputHeight,
outerWidthSpecified,
outerHeightSpecified,
targetContentWidth,
targetContentHeight
);
}
}
}
}
(this->*aSetter)(value, aCallerType, aError);
}

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

@ -2405,22 +2405,52 @@ nsWindowWatcher::SizeOpenedWindow(nsIDocShellTreeOwner* aTreeOwner,
screenHeight = NSToIntRound(screenHeight / scale);
if (aSizeSpec.SizeSpecified()) {
/* Unlike position, force size out-of-bounds check only if
size actually was specified. Otherwise, intrinsically sized
windows are broken. */
if (height < 100) {
height = 100;
winHeight = height + (sizeChromeHeight ? 0 : chromeHeight);
}
if (winHeight > screenHeight) {
height = screenHeight - (sizeChromeHeight ? 0 : chromeHeight);
}
if (width < 100) {
width = 100;
winWidth = width + (sizeChromeWidth ? 0 : chromeWidth);
}
if (winWidth > screenWidth) {
width = screenWidth - (sizeChromeWidth ? 0 : chromeWidth);
if (!nsContentUtils::ShouldResistFingerprinting()) {
/* Unlike position, force size out-of-bounds check only if
size actually was specified. Otherwise, intrinsically sized
windows are broken. */
if (height < 100) {
height = 100;
winHeight = height + (sizeChromeHeight ? 0 : chromeHeight);
}
if (winHeight > screenHeight) {
height = screenHeight - (sizeChromeHeight ? 0 : chromeHeight);
}
if (width < 100) {
width = 100;
winWidth = width + (sizeChromeWidth ? 0 : chromeWidth);
}
if (winWidth > screenWidth) {
width = screenWidth - (sizeChromeWidth ? 0 : chromeWidth);
}
} else {
int32_t targetContentWidth = 0;
int32_t targetContentHeight = 0;
nsContentUtils::CalcRoundedWindowSizeForResistingFingerprinting(
chromeWidth,
chromeHeight,
screenWidth,
screenHeight,
width,
height,
sizeChromeWidth,
sizeChromeHeight,
&targetContentWidth,
&targetContentHeight
);
if (aSizeSpec.mInnerWidthSpecified ||
aSizeSpec.mOuterWidthSpecified) {
width = targetContentWidth;
winWidth = width + (sizeChromeWidth ? 0 : chromeWidth);
}
if (aSizeSpec.mInnerHeightSpecified ||
aSizeSpec.mOuterHeightSpecified) {
height = targetContentHeight;
winHeight = height + (sizeChromeHeight ? 0 : chromeHeight);
}
}
}

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

@ -1029,10 +1029,12 @@ NS_IMETHODIMP nsXULWindow::ForceRoundedDimensions()
return NS_OK;
}
int32_t windowWidth, windowHeight;
int32_t availWidthCSS, availHeightCSS;
int32_t contentWidthCSS, contentHeightCSS;
int32_t contentWidth, contentHeight;
int32_t availWidthCSS = 0;
int32_t availHeightCSS = 0;
int32_t contentWidthCSS = 0;
int32_t contentHeightCSS = 0;
int32_t windowWidthCSS = 0;
int32_t windowHeightCSS = 0;
double devicePerCSSPixels = 1.0;
GetUnscaledDevicePixelsPerCSSPixel(&devicePerCSSPixels);
@ -1043,48 +1045,38 @@ NS_IMETHODIMP nsXULWindow::ForceRoundedDimensions()
// size first. So, here, we size it to its available size.
SetSpecifiedSize(availWidthCSS, availHeightCSS);
GetSize(&windowWidth, &windowHeight); // device pixels
// Get the current window size for calculating chrome UI size.
GetSize(&windowWidthCSS, &windowHeightCSS); // device pixels
windowWidthCSS = NSToIntRound(windowWidthCSS / devicePerCSSPixels);
windowHeightCSS = NSToIntRound(windowHeightCSS / devicePerCSSPixels);
int32_t availWidth = NSToIntRound(devicePerCSSPixels *
availWidthCSS); // device pixels
int32_t availHeight = NSToIntRound(devicePerCSSPixels *
availHeightCSS); // device pixels
// Get the content size for calculating chrome UI size.
GetPrimaryContentSize(&contentWidthCSS, &contentHeightCSS);
contentWidth = NSToIntRound(devicePerCSSPixels *
contentWidthCSS); // device pixels
contentHeight = NSToIntRound(devicePerCSSPixels *
contentHeightCSS); // device pixels
// Calculate the chrome UI size.
int32_t chromeWidth = 0, chromeHeight = 0;
chromeWidth = windowWidthCSS - contentWidthCSS;
chromeHeight = windowHeightCSS - contentHeightCSS;
// Acquire the chrome UI size.
int32_t chromeWidth = windowWidth - contentWidth;
int32_t chromeHeight = windowHeight - contentHeight;
int32_t targetContentWidth = 0, targetContentHeight = 0;
int maxInnerWidth = Preferences::GetInt("privacy.window.maxInnerWidth",
1000);
int maxInnerHeight = Preferences::GetInt("privacy.window.maxInnerHeight",
1000);
// Here, we use the available screen dimensions as the input dimensions to
// force the window to be rounded as the maximum available content size.
nsContentUtils::CalcRoundedWindowSizeForResistingFingerprinting(
chromeWidth,
chromeHeight,
availWidthCSS,
availHeightCSS,
availWidthCSS,
availHeightCSS,
false, // aSetOuterWidth
false, // aSetOuterHeight
&targetContentWidth,
&targetContentHeight
);
// In the GTK window, it will not report outside system decorations when we
// get available window size, see Bug 581863. So, we leave a five percent
// space for them when calculating the available content height. It is not
// necessary for the width since the content width is usually pretty much
// the same as the chrome width.
int32_t availForContentWidthCSS =
std::min(maxInnerWidth, NSToIntRound((availWidth - chromeWidth) /
devicePerCSSPixels));
int32_t availForContentHeightCSS =
std::min(maxInnerHeight, NSToIntRound((0.95 * availHeight - chromeHeight) /
devicePerCSSPixels));
// Ideally, we'd like to round window size to 1000x1000, but the screen space
// could be too small to accommodate this size in some cases. If it happens,
// we would round the window size to the nearest 200x100.
int32_t targetContentWidth =
NSToIntRound(devicePerCSSPixels *
(availForContentWidthCSS - (availForContentWidthCSS % 200)));
int32_t targetContentHeight =
NSToIntRound(devicePerCSSPixels *
(availForContentHeightCSS - (availForContentHeightCSS % 100)));
targetContentWidth = NSToIntRound(targetContentWidth * devicePerCSSPixels);
targetContentHeight = NSToIntRound(targetContentHeight * devicePerCSSPixels);
SetPrimaryContentSize(targetContentWidth, targetContentHeight);