Bug 706198 - Disable font inflation on sites optimized for mobile to avoid strangely inflated text. [r=mbrubeck,dbaron]

--HG--
extra : rebase_source : 60d764b0a76ae87515a3e669ba76adc61926c862
This commit is contained in:
Scott Johnson 2012-01-30 16:52:11 -06:00
parent aac30e3ab9
commit f1c74e3e8a
9 changed files with 377 additions and 3 deletions

View File

@ -178,6 +178,48 @@ enum EventNameType {
EventNameType_All = 0xFFFF
};
/**
* Information retrieved from the <meta name="viewport"> tag. See
* GetViewportInfo for more information on this functionality.
*/
struct ViewportInfo
{
// Default zoom indicates the level at which the display is 'zoomed in'
// initially for the user, upon loading of the page.
double defaultZoom;
// The minimum zoom level permitted by the page.
double minZoom;
// The maximum zoom level permitted by the page.
double maxZoom;
// The width of the viewport, specified by the <meta name="viewport"> tag,
// in CSS pixels.
PRUint32 width;
// The height of the viewport, specified by the <meta name="viewport"> tag,
// in CSS pixels.
PRUint32 height;
// Whether or not we should automatically size the viewport to the device's
// width. This is true if the document has been optimized for mobile, and
// the width property of a specified <meta name="viewport"> tag is either
// not specified, or is set to the special value 'device-width'.
bool autoSize;
// Whether or not the user can zoom in and out on the page. Default is true.
bool allowZoom;
// This is a holdover from e10s fennec, and might be removed in the future.
// It's a hack to work around bugs that didn't allow zooming of documents
// from within the parent process. It is still used in native Fennec for XUL
// documents, but it should probably be removed.
// Currently, from, within GetViewportInfo(), This is only set to false
// if the document is a XUL document.
bool autoScale;
};
struct EventNameMapping
{
nsIAtom* mAtom;
@ -1489,6 +1531,18 @@ public:
return sScriptBlockerCount == 0;
}
/**
* Retrieve information about the viewport as a data structure.
* This will return information in the viewport META data section
* of the document. This can be used in lieu of ProcessViewportInfo(),
* which places the viewport information in the document header instead
* of returning it directly.
*
* NOTE: If the site is optimized for mobile (via the doctype), this
* will return viewport information that specifies default information.
*/
static ViewportInfo GetViewportInfo(nsIDocument* aDocument);
/* Process viewport META data. This gives us information for the scale
* and zoom of a page on mobile devices. We stick the information in
* the document header and use it later on after rendering.

View File

@ -211,6 +211,8 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
#include "mozilla/Preferences.h"
#include "nsWrapperCacheInlines.h"
#include "nsIDOMDocumentType.h"
#include "nsIDOMWindowUtils.h"
#include "nsCharSeparatedTokenizer.h"
#include "nsUnicharUtils.h"
@ -221,6 +223,17 @@ using namespace mozilla;
const char kLoadAsData[] = "loadAsData";
/**
* Default values for the ViewportInfo structure.
*/
static const float kViewportMinScale = 0.0;
static const float kViewportMaxScale = 10.0;
static const PRUint32 kViewportMinWidth = 200;
static const PRUint32 kViewportMaxWidth = 10000;
static const PRUint32 kViewportMinHeight = 223;
static const PRUint32 kViewportMaxHeight = 10000;
static const PRInt32 kViewportDefaultScreenWidth = 980;
static const char kJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
static NS_DEFINE_CID(kParserServiceCID, NS_PARSERSERVICE_CID);
static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
@ -4554,6 +4567,198 @@ static void ProcessViewportToken(nsIDocument *aDocument,
#define IS_SEPARATOR(c) ((c == '=') || (c == ',') || (c == ';') || \
(c == '\t') || (c == '\n') || (c == '\r'))
/* static */
ViewportInfo
nsContentUtils::GetViewportInfo(nsIDocument *aDocument)
{
ViewportInfo ret;
ret.defaultZoom = 1.0;
ret.autoSize = true;
ret.allowZoom = true;
ret.autoScale = true;
// If the docType specifies that we are on a site optimized for mobile,
// then we want to return specially crafted defaults for the viewport info.
nsCOMPtr<nsIDOMDocument>
domDoc(do_QueryInterface(aDocument));
nsCOMPtr<nsIDOMDocumentType> docType;
nsresult rv = domDoc->GetDoctype(getter_AddRefs(docType));
if (NS_SUCCEEDED(rv) && docType) {
nsAutoString docId;
rv = docType->GetPublicId(docId);
if (NS_SUCCEEDED(rv)) {
if ((docId.Find("WAP") != -1) ||
(docId.Find("Mobile") != -1) ||
(docId.Find("WML") != -1))
{
return ret;
}
}
}
if (aDocument->IsXUL()) {
ret.autoScale = false;
return ret;
}
nsIDOMWindow* window = aDocument->GetWindow();
nsCOMPtr<nsIDOMWindowUtils> windowUtils(do_GetInterface(window));
if (!windowUtils) {
return ret;
}
nsAutoString handheldFriendly;
aDocument->GetHeaderData(nsGkAtoms::handheldFriendly, handheldFriendly);
if (handheldFriendly.EqualsLiteral("true")) {
return ret;
}
PRInt32 errorCode;
nsAutoString minScaleStr;
aDocument->GetHeaderData(nsGkAtoms::minimum_scale, minScaleStr);
float scaleMinFloat = minScaleStr.ToFloat(&errorCode);
if (errorCode) {
scaleMinFloat = kViewportMinScale;
}
scaleMinFloat = NS_MIN(scaleMinFloat, kViewportMaxScale);
scaleMinFloat = NS_MAX(scaleMinFloat, kViewportMinScale);
nsAutoString maxScaleStr;
aDocument->GetHeaderData(nsGkAtoms::maximum_scale, maxScaleStr);
// We define a special error code variable for the scale and max scale,
// because they are used later (see the width calculations).
PRInt32 scaleMaxErrorCode;
float scaleMaxFloat = maxScaleStr.ToFloat(&scaleMaxErrorCode);
if (scaleMaxErrorCode) {
scaleMaxFloat = kViewportMaxScale;
}
scaleMaxFloat = NS_MIN(scaleMaxFloat, kViewportMaxScale);
scaleMaxFloat = NS_MAX(scaleMaxFloat, kViewportMinScale);
nsAutoString scaleStr;
aDocument->GetHeaderData(nsGkAtoms::viewport_initial_scale, scaleStr);
PRInt32 scaleErrorCode;
float scaleFloat = scaleStr.ToFloat(&scaleErrorCode);
scaleFloat = NS_MIN(scaleFloat, scaleMaxFloat);
scaleFloat = NS_MAX(scaleFloat, scaleMinFloat);
nsAutoString widthStr, heightStr;
aDocument->GetHeaderData(nsGkAtoms::viewport_height, heightStr);
aDocument->GetHeaderData(nsGkAtoms::viewport_width, widthStr);
bool autoSize = false;
if (widthStr.EqualsLiteral("device-width")) {
autoSize = true;
}
if (widthStr.IsEmpty() &&
(heightStr.EqualsLiteral("device-height") ||
scaleFloat == 1.0))
{
autoSize = true;
}
// XXXjwir3:
// See bug 706918, comment 23 for more information on this particular section
// of the code. We're using "screen size" in place of the size of the content
// area, because on mobile, these are close or equal. This will work for our
// purposes (bug 706198), but it will need to be changed in the future to be
// more correct when we bring the rest of the viewport code into platform.
// We actually want the size of the content area, in the event that we don't
// have any metadata about the width and/or height. On mobile, the screen size
// and the size of the content area are very close, or the same value.
// In XUL fennec, the content area is the size of the <browser> widget, but
// in native fennec, the content area is the size of the Gecko LayerView
// object.
// TODO:
// Once bug 716575 has been resolved, this code should be changed so that it
// does the right thing on all platforms.
nsresult result;
PRInt32 screenLeft, screenTop, screenWidth, screenHeight;
nsCOMPtr<nsIScreenManager> screenMgr =
do_GetService("@mozilla.org/gfx/screenmanager;1", &result);
nsCOMPtr<nsIScreen> screen;
screenMgr->GetPrimaryScreen(getter_AddRefs(screen));
screen->GetRect(&screenLeft, &screenTop, &screenWidth, &screenHeight);
PRUint32 width = widthStr.ToInteger(&errorCode);
if (errorCode) {
if (autoSize) {
width = screenWidth;
} else {
width = Preferences::GetInt("browser.viewport.desktopWidth", 0);
}
}
width = NS_MIN(width, kViewportMaxWidth);
width = NS_MAX(width, kViewportMinWidth);
// Also recalculate the default zoom, if it wasn't specified in the metadata,
// and the width is specified.
if (scaleStr.IsEmpty() && !widthStr.IsEmpty()) {
scaleFloat = NS_MAX(scaleFloat, (float)(screenWidth/width));
}
PRUint32 height = heightStr.ToInteger(&errorCode);
if (errorCode) {
height = width * ((float)screenHeight / screenWidth);
}
// If height was provided by the user, but width wasn't, then we should
// calculate the width.
if (widthStr.IsEmpty() && !heightStr.IsEmpty()) {
width = (PRUint32) ((height * screenWidth) / screenHeight);
}
height = NS_MIN(height, kViewportMaxHeight);
height = NS_MAX(height, kViewportMinHeight);
// We need to perform a conversion, but only if the initial or maximum
// scale were set explicitly by the user.
if (!scaleStr.IsEmpty() && !scaleErrorCode) {
width = NS_MAX(width, (PRUint32)(screenWidth / scaleFloat));
height = NS_MAX(height, (PRUint32)(screenHeight / scaleFloat));
} else if (!maxScaleStr.IsEmpty() && !scaleMaxErrorCode) {
width = NS_MAX(width, (PRUint32)(screenWidth / scaleMaxFloat));
height = NS_MAX(height, (PRUint32)(screenHeight / scaleMaxFloat));
}
bool allowZoom = true;
nsAutoString userScalable;
aDocument->GetHeaderData(nsGkAtoms::viewport_user_scalable, userScalable);
if ((userScalable.EqualsLiteral("0")) ||
(userScalable.EqualsLiteral("no")) ||
(userScalable.EqualsLiteral("false"))) {
allowZoom = false;
}
ret.allowZoom = allowZoom;
ret.width = width;
ret.height = height;
ret.defaultZoom = scaleFloat;
ret.minZoom = scaleMinFloat;
ret.maxZoom = scaleMaxFloat;
ret.autoSize = autoSize;
return ret;
}
/* static */
nsresult
nsContentUtils::ProcessViewportInfo(nsIDocument *aDocument,

View File

@ -4804,7 +4804,18 @@ nsLayoutUtils::FontSizeInflationFor(const nsIFrame *aFrame,
/* static */ bool
nsLayoutUtils::FontSizeInflationEnabled(nsPresContext *aPresContext)
{
return (sFontSizeInflationEmPerLine != 0 ||
sFontSizeInflationMinTwips != 0) &&
!aPresContext->IsChrome();
if ((sFontSizeInflationEmPerLine == 0 &&
sFontSizeInflationMinTwips == 0) ||
aPresContext->IsChrome()) {
return false;
}
ViewportInfo vInf =
nsContentUtils::GetViewportInfo(aPresContext->PresShell()->GetDocument());
if (vInf.defaultZoom >= 1.0 || vInf.autoSize) {
return false;
}
return true;
}

View File

@ -0,0 +1,20 @@
<!--
Without the patch for bug 706198, this website should not show up as inflated. That means
that with a 450px container, the minimum font size with 15em per line should be 30px.
So, we map 0px-45px into 30px-45px, and thus 12px gets mapped to 34px.
With the patch, the text should be uninflated, which means that 12px should still be
12px.
-->
<!DOCTYPE html>
<html>
<head>
<meta content='True' name='HandheldFriendly' />
<style>
p { font-size: 12px; line-height: 1.0;}
</style>
<body>
<p>Some uninflated text.</p>
</body>
</head>
</html>

View File

@ -0,0 +1,20 @@
<!--
Without the patch for bug 706198, this website should not show up as inflated. That means
that with a 450px container, the minimum font size with 15em per line should be 30px.
So, we map 0px-45px into 30px-45px, and thus 12px gets mapped to 34px.
With the patch, the text should be uninflated, which means that 12px should still be
12px.
-->
<!DOCTYPE html>
<html>
<head>
<meta content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' name='viewport' />
<style>
p { font-size: 12px; line-height: 1.0;}
</style>
<body>
<p>Some uninflated text.</p>
</body>
</head>
</html>

View File

@ -0,0 +1,20 @@
<!--
Without the patch for bug 706198, this website should not show up as inflated. That means
that with a 450px container, the minimum font size with 15em per line should be 30px.
So, we map 0px-45px into 30px-45px, and thus 12px gets mapped to 34px.
With the patch, the text should be uninflated, which means that 12px should still be
12px.
-->
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=320"/>
<style>
p { font-size: 12px; line-height: 1.0;}
</style>
<body>
<p>Some uninflated text.</p>
</body>
</head>
</html>

View File

@ -0,0 +1,19 @@
<!--
Without the patch for bug 706198, this website should not show up as inflated. That means
that with a 450px container, the minimum font size with 15em per line should be 30px.
So, we map 0px-45px into 30px-45px, and thus 12px gets mapped to 34px.
With the patch, the text should be uninflated, which means that 12px should still be
12px.
-->
<!DOCTYPE html>
<html>
<head>
<style>
p { font-size: 12px; line-height: 1.0;}
</style>
<body>
<p>Some uninflated text.</p>
</body>
</head>
</html>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
<!--
Without the patch for bug 706198, this website should not show up as inflated. That means
that with a 450px container, the minimum font size with 15em per line should be 30px.
So, we map 0px-45px into 30px-45px, and thus 12px gets mapped to 34px.
With the patch, the text should be uninflated, which means that 12px should still be
12px.
-->
<html>
<head>
<style>
p { font-size: 12px; line-height: 1.0;}
</style>
<body>
<p>Some uninflated text.</p>
</body>
</head>
</html>

View File

@ -61,6 +61,10 @@ var gTests = [
"!= select-combobox-2.html select-combobox-2.html",
"!= input-checkbox.html input-checkbox.html",
"!= input-radio.html input-radio.html",
"== disable-fontinfl-on-mobile.html disable-fontinfl-on-mobile-ref.html",
"== disable-fontinfl-on-mobile-2.html disable-fontinfl-on-mobile-ref.html",
"== disable-fontinfl-on-mobile-3.html disable-fontinfl-on-mobile-ref.html",
"== disable-fontinfl-on-mobile-4.html disable-fontinfl-on-mobile-ref.html",
];
// Maintain a reference count of how many things we're waiting for until