Merge last PGO-green changeset of mozilla-inbound to mozilla-central

This commit is contained in:
Ed Morley 2012-08-09 12:46:05 +01:00
Родитель 243160b7d0 f32ed5397d
Коммит b5f4776008
156 изменённых файлов: 3371 добавлений и 1420 удалений

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

@ -15,7 +15,7 @@ Cu.import("resource://gre/modules/Services.jsm");
function AlertsService() { }
AlertsService.prototype = {
classID: Components.ID("{5dce03b2-8faa-4b6e-9242-6ddb0411750c}"),
classID: Components.ID("{fe33c107-82a4-41d6-8c64-5353267e04c9}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAlertsService]),
showAlertNotification: function(aImageUrl, aTitle, aText, aTextClickable, aCookie, aAlertListener, aName) {

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

@ -7,8 +7,8 @@ contract @mozilla.org/b2g-camera-content;1 {eff4231b-abce-4f7f-a40a-d646e8fde3ce
category JavaScript-navigator-property mozCamera @mozilla.org/b2g-camera-content;1
# AlertsService.js
component {5dce03b2-8faa-4b6e-9242-6ddb0411750c} AlertsService.js
contract @mozilla.org/alerts-service;1 {5dce03b2-8faa-4b6e-9242-6ddb0411750c}
component {fe33c107-82a4-41d6-8c64-5353267e04c9} AlertsService.js
contract @mozilla.org/system-alerts-service;1 {fe33c107-82a4-41d6-8c64-5353267e04c9}
# ContentPermissionPrompt.js
component {8c719f03-afe0-4aac-91ff-6c215895d467} ContentPermissionPrompt.js

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

@ -18,9 +18,7 @@ Browser context menu tests.
/** Test for Login Manager: multiple login autocomplete. **/
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
Components.utils.import("resource://gre/modules/InlineSpellChecker.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
SpecialPowers.wrap(Components).utils.import("resource://gre/modules/InlineSpellChecker.jsm", window);
const Cc = Components.classes;
const Ci = Components.interfaces;
@ -729,7 +727,7 @@ function runTest(testNum) {
case 24:
// Context menu for selected text
if (Services.appinfo.OS == "Darwin") {
if (SpecialPowers.Services.appinfo.OS == "Darwin") {
// This test is only enabled on Mac due to bug 736399.
checkContextMenu(["context-copy", true,
"context-selectall", true,
@ -745,7 +743,7 @@ function runTest(testNum) {
case 25:
// Context menu for selected text which matches valid URL pattern
if (Services.appinfo.OS == "Darwin") {
if (SpecialPowers.Services.appinfo.OS == "Darwin") {
// This test is only enabled on Mac due to bug 736399.
checkContextMenu(["context-openlinkincurrent", true,
"context-openlinkintab", true,
@ -790,8 +788,7 @@ var text, link, mailto, input, img, canvas, video_ok, video_bad, video_bad2,
inputspell, pagemenu, dom_full_screen, plainTextItems, audio_in_video;
function startTest() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
chromeWin = subwindow
chromeWin = SpecialPowers.wrap(subwindow)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)

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

@ -26,6 +26,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=462856
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
const Cc = SpecialPowers.wrap(Components).classes;
var numFinished = 0;
@ -34,18 +35,17 @@ window.addEventListener("message", function(event) {
if (++numFinished == 3) {
// Clean up after ourself
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var pm = Components.classes["@mozilla.org/permissionmanager;1"].
var pm = Cc["@mozilla.org/permissionmanager;1"].
getService(Components.interfaces.nsIPermissionManager);
var ioService = Components.classes["@mozilla.org/network/io-service;1"]
var ioService = Cc["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var uri1 = ioService.newURI(frames.testFrame.location, null, null);
var uri2 = ioService.newURI(frames.testFrame3.location, null, null);
var principal1 = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
var principal1 = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(Components.interfaces.nsIScriptSecurityManager)
.getNoAppCodebasePrincipal(uri1);
var principal2 = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
var principal2 = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(Components.interfaces.nsIScriptSecurityManager)
.getNoAppCodebasePrincipal(uri2);
@ -108,8 +108,7 @@ function loaded() {
// Click the notification bar's "Allow" button. This should kick
// off updates, which will eventually lead to getting messages from
// the children.
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"].
var wm = SpecialPowers.wrap(Components).classes["@mozilla.org/appshell/window-mediator;1"].
getService(Components.interfaces.nsIWindowMediator);
var win = wm.getMostRecentWindow("navigator:browser");
var notificationBox = win.gBrowser.getNotificationBox();
@ -117,7 +116,7 @@ function loaded() {
var notification = notificationBox.getNotificationWithValue("offline-app-requested-mochi.test");
notification.childNodes[0].click();
notification = notificationBox.getNotificationWithValue("offline-app-requested-example.com");
notification = SpecialPowers.wrap(notificationBox).getNotificationWithValue("offline-app-requested-example.com");
notification.childNodes[0].click();
}

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

@ -32,15 +32,13 @@ SimpleTest.waitForExplicitFinish();
function finishTest() {
// Clean up after ourselves.
netscape.security.PrivilegeManager
.enablePrivilege("UniversalXPConnect");
var pm = Components.classes["@mozilla.org/permissionmanager;1"].
var Cc = SpecialPowers.wrap(Components).classes;
var pm = Cc["@mozilla.org/permissionmanager;1"].
getService(Components.interfaces.nsIPermissionManager);
var uri = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService)
var uri = Cc["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService)
.newURI(window.frames[0].location, null, null);
var principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
var principal = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(Components.interfaces.nsIScriptSecurityManager)
.getNoAppCodebasePrincipal(uri);
@ -70,8 +68,6 @@ function handleMessageEvents(event) {
// successfully reloaded), or the string "error" appears
// in the iframe, as in the case of bug 501422.
intervalID = setInterval(function() {
netscape.security.PrivilegeManager
.enablePrivilege("UniversalXPConnect");
// Sometimes document.body may not exist, and trying to access
// it will throw an exception, so handle this case.
try {
@ -103,8 +99,7 @@ function loaded() {
// Click the notification bar's "Allow" button. This should kick
// off updates, which will eventually lead to getting messages from
// the iframe.
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"].
var wm = SpecialPowers.wrap(Components).classes["@mozilla.org/appshell/window-mediator;1"].
getService(Components.interfaces.nsIWindowMediator);
var win = wm.getMostRecentWindow("navigator:browser");
var notificationBox = win.gBrowser.getNotificationBox();

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

@ -20,8 +20,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=589543
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var doc = $("testFrame").contentDocument;
var doc = SpecialPowers.wrap($("testFrame").contentDocument);
var daddy = doc.getElementById("feedSubscribeLine");
var popup = doc.getAnonymousElementByAttribute(daddy, "anonid", "handlersMenuPopup");
isnot(popup, null, "Feed preview should have a handlers popup");

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

@ -18,11 +18,13 @@ let webappsUI = {
init: function webappsUI_init() {
Services.obs.addObserver(this, "webapps-ask-install", false);
Services.obs.addObserver(this, "webapps-launch", false);
Services.obs.addObserver(this, "webapps-uninstall", false);
},
uninit: function webappsUI_uninit() {
Services.obs.removeObserver(this, "webapps-ask-install");
Services.obs.removeObserver(this, "webapps-launch");
Services.obs.removeObserver(this, "webapps-uninstall");
},
observe: function webappsUI_observe(aSubject, aTopic, aData) {
@ -37,6 +39,9 @@ let webappsUI = {
case "webapps-launch":
WebappOSUtils.launch(data);
break;
case "webapps-uninstall":
WebappOSUtils.uninstall(data);
break;
}
},

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

@ -13,6 +13,7 @@
#include "prenv.h"
#include "mozIApplication.h"
#include "nsIDOMHTMLIFrameElement.h"
#include "nsIDOMHTMLFrameElement.h"
#include "nsIDOMMozBrowserFrame.h"
@ -31,6 +32,7 @@
#include "nsIDocShellTreeNode.h"
#include "nsIDocShellTreeOwner.h"
#include "nsIDocShellLoadInfo.h"
#include "nsIDOMApplicationRegistry.h"
#include "nsIBaseWindow.h"
#include "nsContentUtils.h"
#include "nsIXPConnect.h"
@ -1973,9 +1975,8 @@ nsFrameLoader::TryRemoteBrowser()
return false;
}
PRUint32 appId = 0;
bool isBrowserElement = false;
nsCOMPtr<mozIApplication> app;
if (OwnerIsBrowserFrame()) {
isBrowserElement = true;
@ -1989,24 +1990,21 @@ nsFrameLoader::TryRemoteBrowser()
return false;
}
appsService->GetAppLocalIdByManifestURL(manifest, &appId);
// If the frame is actually an app, we should not mark it as a browser.
if (appId != nsIScriptSecurityManager::NO_APP_ID) {
nsCOMPtr<mozIDOMApplication> domApp;
appsService->GetAppByManifestURL(manifest, getter_AddRefs(domApp));
// If the frame is actually an app, we should not mark it as a
// browser. This is to identify the data store: since <app>s
// and <browser>s-within-<app>s have different stores, we want
// to ensure the <app> uses its store, not the one for its
// <browser>s.
app = do_QueryInterface(domApp);
if (app) {
isBrowserElement = false;
}
}
}
// If our owner has no app manifest URL, then this is equivalent to
// ContentParent::GetNewOrUsed().
nsAutoString appManifest;
GetOwnerAppManifestURL(appManifest);
ContentParent* parent = ContentParent::GetForApp(appManifest);
NS_ASSERTION(parent->IsAlive(), "Process parent should be alive; something is very wrong!");
mRemoteBrowser = parent->CreateTab(chromeFlags, isBrowserElement, appId);
if (mRemoteBrowser) {
if ((mRemoteBrowser = ContentParent::CreateBrowser(app, isBrowserElement))) {
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(mOwnerContent);
mRemoteBrowser->SetOwnerElement(element);
@ -2019,8 +2017,8 @@ nsFrameLoader::TryRemoteBrowser()
nsCOMPtr<nsIBrowserDOMWindow> browserDOMWin;
rootChromeWin->GetBrowserDOMWindow(getter_AddRefs(browserDOMWin));
mRemoteBrowser->SetBrowserDOMWindow(browserDOMWin);
mChildHost = parent;
mChildHost = static_cast<ContentParent*>(mRemoteBrowser->Manager());
}
return true;
}

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

@ -32,15 +32,14 @@ function afterLoad() {
iframeDoc.getElementById("password").value = "123456";
iframeDoc.getElementById("hidden").value = "gecko";
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var file = Components.classes["@mozilla.org/file/directory_service;1"]
var file = SpecialPowers.wrap(Components).classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties)
.get("TmpD", Components.interfaces.nsILocalFile);
file.append("345339_test.file");
file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0666);
filePath = file.path;
iframeDoc.getElementById("file").value = filePath;
SpecialPowers.wrap(iframeDoc).getElementById("file").value = filePath;
/* Reload the page */
$("testframe").setAttribute("onload", "afterReload()");
@ -62,8 +61,7 @@ function afterReload() {
"password field value forgotten");
is(iframeDoc.getElementById("hidden").value, "gecko",
"hidden field value preserved");
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
is(iframeDoc.getElementById("file").value, filePath,
is(SpecialPowers.wrap(iframeDoc).getElementById("file").value, filePath,
"file field value preserved");
SimpleTest.finish();

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

@ -31,9 +31,10 @@ function eventHandler(evt) {
function test(trusted, type, removeAddedListener, removeSetListener, allowUntrusted) {
if (trusted) {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var x1 = SpecialPowers.wrap(new XMLHttpRequest());
} else {
x1 = new XMLHttpRequest();
}
var x1 = new XMLHttpRequest();
var handlerCount = 0;
if (trusted || allowUntrusted || allowUntrusted == undefined) {

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

@ -22,14 +22,13 @@
request.send(null);
// Try reading headers in privileged context
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
is(request.getResponseHeader("Set-Cookie"), "test", "Reading Set-Cookie response header in privileged context");
is(request.getResponseHeader("Set-Cookie2"), "test2", "Reading Set-Cookie2 response header in privileged context");
is(request.getResponseHeader("X-Dummy"), "test", "Reading X-Dummy response header in privileged context");
is(SpecialPowers.wrap(request).getResponseHeader("Set-Cookie"), "test", "Reading Set-Cookie response header in privileged context");
is(SpecialPowers.wrap(request).getResponseHeader("Set-Cookie2"), "test2", "Reading Set-Cookie2 response header in privileged context");
is(SpecialPowers.wrap(request).getResponseHeader("X-Dummy"), "test", "Reading X-Dummy response header in privileged context");
ok(/\bSet-Cookie:/i.test(request.getAllResponseHeaders()), "Looking for Set-Cookie in all response headers in privileged context");
ok(/\bSet-Cookie2:/i.test(request.getAllResponseHeaders()), "Looking for Set-Cookie2 in all response headers in privileged context");
ok(/\bX-Dummy:/i.test(request.getAllResponseHeaders()), "Looking for X-Dummy in all response headers in privileged context");
ok(/\bSet-Cookie:/i.test(SpecialPowers.wrap(request).getAllResponseHeaders()), "Looking for Set-Cookie in all response headers in privileged context");
ok(/\bSet-Cookie2:/i.test(SpecialPowers.wrap(request).getAllResponseHeaders()), "Looking for Set-Cookie2 in all response headers in privileged context");
ok(/\bX-Dummy:/i.test(SpecialPowers.wrap(request).getAllResponseHeaders()), "Looking for X-Dummy in all response headers in privileged context");
// Try reading headers in unprivileged context
setTimeout(function() {

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

@ -19,10 +19,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=422537
<script class="testbody" type="text/javascript">
/** Test for Bug 422537 **/
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var isupports_string = Components.classes["@mozilla.org/supports-string;1"]
.createInstance(Components.interfaces.nsISupportsString);
var isupports_string = SpecialPowers.wrap(Components)
.classes["@mozilla.org/supports-string;1"]
.createInstance(Components.interfaces.nsISupportsString);
isupports_string.data = "foo";
const url = "http://mochi.test:8888";
@ -35,12 +34,15 @@ var body = [
for each (var i in body) {
var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
xhr.send(i);
var chan = SpecialPowers.unwrap(SpecialPowers.wrap(xhr).channel);
if (!(chan instanceof Components.interfaces.nsIUploadChannel))
if (i == isupports_string)
SpecialPowers.wrap(xhr).send(i);
else
xhr.send(i);
var chan = SpecialPowers.wrap(xhr).channel;
if (!SpecialPowers.call_Instanceof(chan, Components.interfaces.nsIUploadChannel))
throw "Must be an upload channel";
var stream = chan.uploadStream;
if (!stream || !(stream instanceof Components.interfaces.nsISeekableStream))
if (!stream || !SpecialPowers.call_Instanceof(stream, Components.interfaces.nsISeekableStream))
throw "Stream must be seekable";
// the following is a no-op, but should not throw an exception
stream.seek(Components.interfaces.nsISeekableStream.NS_SEEK_CUR, 0);

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

@ -0,0 +1,10 @@
<!doctype HTML>
<html>
<body>
<canvas id="c" width="10000" height="10000"></canvas>
<script>
var ctx = document.getElementById("c").getContext("2d");
ctx.fillText("Hello world!", 50, 50);
</script>
</body>
</html>

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

@ -12,3 +12,4 @@ load 746813-1.html
#load 745818-large-source.html
load 743499-negative-size.html
load 767337-1.html
load 780392-1.html

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

@ -6,13 +6,14 @@
<script>
SimpleTest.waitForExplicitFinish();
const Cc = SpecialPowers.wrap(Components).classes;
const Cr = SpecialPowers.wrap(Components).results;
function IsD2DEnabled() {
var enabled = false;
try {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
enabled = Components.classes["@mozilla.org/gfx/info;1"].getService(Components.interfaces.nsIGfxInfo).D2DEnabled;
enabled = Cc["@mozilla.org/gfx/info;1"].getService(Components.interfaces.nsIGfxInfo).D2DEnabled;
} catch(e) {}
return enabled;
@ -26,10 +27,9 @@ function IsMacOSX10_5orOlder() {
var is105orOlder = false;
if (navigator.platform.indexOf("Mac") == 0) {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var version = Components.classes["@mozilla.org/system-info;1"]
.getService(Components.interfaces.nsIPropertyBag2)
.getProperty("version");
var version = Cc["@mozilla.org/system-info;1"]
.getService(Components.interfaces.nsIPropertyBag2)
.getProperty("version");
// the next line is correct: Mac OS 10.6 corresponds to Darwin version 10 !
// Mac OS 10.5 would be Darwin version 9. the |version| string we've got here
// is the Darwin version.
@ -43,8 +43,7 @@ function IsAzureEnabled() {
var enabled = false;
try {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var backend = Components.classes["@mozilla.org/gfx/info;1"].getService(Components.interfaces.nsIGfxInfo).getInfo().AzureCanvasBackend;
var backend = Cc["@mozilla.org/gfx/info;1"].getService(Components.interfaces.nsIGfxInfo).getInfo().AzureCanvasBackend;
enabled = (backend != "none");
} catch (e) { }
@ -55,8 +54,7 @@ function IsAzureSkia() {
var enabled = false;
try {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var backend = Components.classes["@mozilla.org/gfx/info;1"].getService(Components.interfaces.nsIGfxInfo).getInfo().AzureCanvasBackend;
var backend = Cc["@mozilla.org/gfx/info;1"].getService(Components.interfaces.nsIGfxInfo).getInfo().AzureCanvasBackend;
enabled = (backend == "skia");
} catch (e) { }
@ -67,8 +65,7 @@ function IsAzureCairo() {
var enabled = false;
try {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var backend = Components.classes["@mozilla.org/gfx/info;1"].getService(Components.interfaces.nsIGfxInfo).getInfo().AzureCanvasBackend;
var backend = Cc["@mozilla.org/gfx/info;1"].getService(Components.interfaces.nsIGfxInfo).getInfo().AzureCanvasBackend;
enabled = (backend == "cairo");
} catch (e) { }
@ -126,7 +123,8 @@ ok(ctx.canvas === canvas, "ctx.canvas === canvas");
function isPixel(ctx, x,y, r,g,b,a, d) {
var pos = x + "," + y;
var colour = r + "," + g + "," + b + "," + a;
var pixel = ctx.getImageData(x, y, 1, 1);
var pixel = SpecialPowers.unwrap(SpecialPowers.wrap(ctx)
.getImageData(x, y, 1, 1));
var pr = pixel.data[0],
pg = pixel.data[1],
pb = pixel.data[2],
@ -19804,9 +19802,8 @@ function test_bug397524() {
<script>
function test_bug405982() {
var canvas = document.getElementById('c614');
var canvas = SpecialPowers.wrap(document.getElementById('c614'));
var ctx = canvas.getContext('2d');
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var _threw = false;
try {
@ -21123,7 +21120,6 @@ img.onload = wrapFunction(function ()
ctx667.drawImage(img, 0, 25);
// (The alpha values do not really survive float->int conversion, so just
// do approximate comparisons)
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
isPixel(ctx667, 12,40, 1,3,254,255, 0);
isPixel(ctx667, 37,40, 8,252,248,191, 2);
isPixel(ctx667, 62,40, 6,10,250,127, 4);
@ -21250,7 +21246,6 @@ deferTest();
img.onload = wrapFunction(function ()
{
ctx672.drawImage(img, 0, 0);
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
isPixel(ctx672, 12,20, 255,255,0,255, 0);
isPixel(ctx672, 50,20, 0,255,255,255, 0);
isPixel(ctx672, 87,20, 0,0,255,255, 0);

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

@ -24,10 +24,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=143220
var leafName;
var fullPath;
function initVals() {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var dirSvc = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties);
var dirSvc = SpecialPowers.wrap(Components)
.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties);
var file = dirSvc.get("XpcomLib", Components.interfaces.nsILocalFile);
isnot(file, null, "Must have file here");
@ -36,15 +37,13 @@ function initVals() {
}
function initControl1() {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
$("i1").value = fullPath;
is($("i1").value, fullPath, "Should have set full path 1");
SpecialPowers.wrap($("i1")).value = fullPath;
is(SpecialPowers.wrap($("i1")).value, fullPath, "Should have set full path 1");
}
function initControl2() {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
$("i2").value = fullPath;
is($("i2").value, fullPath, "Should have set full path 2");
SpecialPowers.wrap($("i2")).value = fullPath;
is(SpecialPowers.wrap($("i2")).value, fullPath, "Should have set full path 2");
}
initVals();

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

@ -32,26 +32,25 @@ var input2Files =
SimpleTest.waitForExplicitFinish();
function setFileInputs () {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
f = createFileWithData(input1File.name, input1File.body);
singleFileInput.mozSetFileNameArray([f.path], 1);
SpecialPowers.wrap(singleFileInput).mozSetFileNameArray([f.path], 1);
var input2FileNames = [];
for each (file in input2Files) {
f = createFileWithData(file.name, file.body);
input2FileNames.push(f.path);
}
multiFileInput.mozSetFileNameArray(input2FileNames, input2FileNames.length);
SpecialPowers.wrap(multiFileInput).mozSetFileNameArray(input2FileNames, input2FileNames.length);
}
function createFileWithData(fileName, fileData) {
var dirSvc = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties);
var dirSvc = SpecialPowers.wrap(Components).classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties);
var testFile = dirSvc.get("ProfD", Components.interfaces.nsIFile);
testFile.append(fileName);
var outStream = Components.
classes["@mozilla.org/network/file-output-stream;1"].
createInstance(Components.interfaces.nsIFileOutputStream);
var outStream = SpecialPowers.wrap(Components).
classes["@mozilla.org/network/file-output-stream;1"].
createInstance(Components.interfaces.nsIFileOutputStream);
outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
0666, 0);
outStream.write(fileData, fileData.length);

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

@ -92,7 +92,9 @@ public:
// imgIDecoderObserver (override nsStubImageDecoderObserver)
NS_IMETHOD OnStartContainer(imgIRequest* aRequest, imgIContainer* aImage);
NS_IMETHOD OnStopContainer(imgIRequest* aRequest, imgIContainer* aImage);
NS_IMETHOD OnStopDecode(imgIRequest *aRequest, nsresult aStatus, const PRUnichar *aStatusArg);
NS_IMETHOD OnDiscard(imgIRequest *aRequest);
// nsIDOMEventListener
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
@ -519,6 +521,20 @@ ImageDocument::OnStartContainer(imgIRequest* aRequest, imgIContainer* aImage)
return NS_OK;
}
NS_IMETHODIMP
ImageDocument::OnStopContainer(imgIRequest* aRequest, imgIContainer* aImage)
{
if (mImageContent) {
// Update the background-color of the image only after the
// image has been decoded to prevent flashes of just the
// background-color.
mImageContent->SetAttr(kNameSpaceID_None, nsGkAtoms::_class,
NS_LITERAL_STRING("decoded"), true);
}
return NS_OK;
}
NS_IMETHODIMP
ImageDocument::OnStopDecode(imgIRequest *aRequest,
nsresult aStatus,
@ -526,12 +542,6 @@ ImageDocument::OnStopDecode(imgIRequest *aRequest,
{
UpdateTitleAndCharset();
nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mImageContent);
if (imageLoader) {
mObservingImageLoader = false;
imageLoader->RemoveObserver(this);
}
// mImageContent can be null if the document is already destroyed
if (NS_FAILED(aStatus) && mStringBundle && mImageContent) {
nsCAutoString src;
@ -549,6 +559,18 @@ ImageDocument::OnStopDecode(imgIRequest *aRequest,
return NS_OK;
}
NS_IMETHODIMP
ImageDocument::OnDiscard(imgIRequest *aRequest)
{
// mImageContent can be null if the document is already destroyed
if (mImageContent) {
// Remove any decoded-related styling when the image is unloaded.
mImageContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::_class,
true);
}
return NS_OK;
}
NS_IMETHODIMP
ImageDocument::HandleEvent(nsIDOMEvent* aEvent)
{

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

@ -55,9 +55,7 @@ function checkURI(uri, name, type) {
function checkFrame(num) {
// Just snarf our data
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var outer = window.frames[num]
var outer = SpecialPowers.wrap(window.frames[num]);
name = outer.name;
is(outer.document.baseURI,

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

@ -24,21 +24,19 @@ var frame = document.getElementById("i");
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var viewer =
frame.contentWindow
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIDocShell)
.contentViewer
.QueryInterface(Components.interfaces.nsIMarkupDocumentViewer);
SpecialPowers.wrap(frame.contentWindow
.QueryInterface(Components.interfaces.nsIInterfaceRequestor))
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIDocShell)
.contentViewer
.QueryInterface(Components.interfaces.nsIMarkupDocumentViewer);
viewer.fullZoom = 1.5;
setTimeout(function() {
synthesizeMouse(frame, 30, 30, {});
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
is(viewer.fullZoom, 1.5, "Zoom in the image frame should not have been reset");
SimpleTest.finish();

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

@ -159,10 +159,9 @@ function fileUriToSrc(path, mustExist) {
if (navigator.appVersion.indexOf("Android") != -1)
return path;
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
const Ci = Components.interfaces;
const Cc = Components.classes;
const Cr = Components.results;
const Cc = SpecialPowers.wrap(Components).classes;
const Cr = SpecialPowers.wrap(Components).results;
var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
getService(Ci.nsIProperties);
var f = dirSvc.get("CurWorkD", Ci.nsILocalFile);
@ -444,8 +443,7 @@ function MediaTestManager() {
// Force a GC after every completed testcase. This ensures that any decoders
// with live threads waiting for the GC are killed promptly, to free up the
// thread stacks' address space.
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
Components.utils.forceGC();
SpecialPowers.forceGC();
while (this.testNum < this.tests.length && this.tokens.length < PARALLEL_TESTS) {
var test = this.tests[this.testNum];
@ -497,15 +495,14 @@ function mediaTestCleanup() {
A[i].parentNode.removeChild(A[i]);
A[i] = null;
}
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
Components.utils.forceGC();
SpecialPowers.forceGC();
}
(function() {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
// Ensure that preload preferences are comsistent
var prefService = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefService);
var prefService = SpecialPowers.wrap(Components)
.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefService);
var branch = prefService.getBranch("media.");
var oldDefault = 2;
var oldAuto = 3;
@ -522,7 +519,6 @@ function mediaTestCleanup() {
branch.setBoolPref("opus.enabled", true);
window.addEventListener("unload", function() {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
branch.setIntPref("preload.default", oldDefault);
branch.setIntPref("preload.auto", oldAuto);
if (oldOpus !== undefined)

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

@ -6055,17 +6055,19 @@ nsDocShell::OnStateChange(nsIWebProgress * aProgress, nsIRequest * aRequest,
channel->GetURI(getter_AddRefs(uri));
nsCAutoString aURI;
uri->GetAsciiSpec(aURI);
if (this == aProgress){
nsCOMPtr<nsIWyciwygChannel> wcwgChannel(do_QueryInterface(aRequest));
nsCOMPtr<nsIWebProgress> webProgress =
do_QueryInterface(GetAsSupports(this));
// We don't update navigation timing for wyciwyg channels
if (this == aProgress && !wcwgChannel){
rv = MaybeInitTiming();
if (mTiming) {
mTiming->NotifyFetchStart(uri, ConvertLoadTypeToNavigationType(mLoadType));
}
}
nsCOMPtr<nsIWyciwygChannel> wcwgChannel(do_QueryInterface(aRequest));
nsCOMPtr<nsIWebProgress> webProgress =
do_QueryInterface(GetAsSupports(this));
// Was the wyciwyg document loaded on this docshell?
if (wcwgChannel && !mLSHE && (mItemType == typeContent) && aProgress == webProgress.get()) {
bool equalUri = true;

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

@ -95,6 +95,8 @@ MOCHITEST_FILES = \
test_bug691547.html \
bug691547_frame.html \
test_bug694612.html \
test_bug703855.html \
file_bug703855.html \
test_bug713825.html \
test_bug728939.html \
file_bug728939.html \

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

@ -0,0 +1,2 @@
<!DOCTYPE html>
<!-- Just need an empty file here, as long as it's served over HTTP -->

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

@ -98,17 +98,18 @@ function isInaccessible(wnd, message) {
///////////////////////////////////////////////////////////////////////////
function xpcEnumerateContentWindows(callback) {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var Ci = Components.interfaces;
var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
.getService(Ci.nsIWindowWatcher);
var ww = SpecialPowers.wrap(Components)
.classes["@mozilla.org/embedcomp/window-watcher;1"]
.getService(Ci.nsIWindowWatcher);
var enumerator = ww.getWindowEnumerator();
var contentWindows = [];
while (enumerator.hasMoreElements()) {
var win = enumerator.getNext();
if (typeof ChromeWindow != "undefined" && win instanceof ChromeWindow) {
if (typeof ChromeWindow != "undefined" && SpecialPowers.call_Instanceof(win, ChromeWindow)) {
var docshellTreeNode = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeNode);

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

@ -4,7 +4,6 @@
function testDone() {
document.body.removeChild(document.body.firstChild);
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var isOK = false;
try {
isOK = history.previous != location;

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

@ -60,7 +60,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=386782
}
function beginTest() {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
gTest.window.document.body.focus();
// WARNING: If the following test fails, give the setTimeout() in the onload()
@ -74,7 +73,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=386782
}
function goBack() {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
gTest.window.history.back();
setTimeout(function() {
SimpleTest.waitForFocus(checkStillEditable, gTest.window);
@ -82,7 +80,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=386782
}
function checkStillEditable() {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
// Check that the contents are correct.
is(gTest.window.document.body.innerHTML, gTest.expectedBodyAfterEdit, "Edited contents still correct?");

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

@ -186,9 +186,9 @@ var gNextTest = 0;
function runNextTest()
{
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefBranch);
var prefs = SpecialPowers.wrap(Components)
.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
if (gNextTest < gTests.length) {
gCurrentTest = gTests[gNextTest++];
@ -214,9 +214,9 @@ function runNextTest()
function finishTest()
{
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefBranch);
var prefs = SpecialPowers.wrap(Components)
.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
prefs.setBoolPref("network.jar.open-unsafe-types", false);
if (gNumPokes == 0) {
@ -228,9 +228,9 @@ function finishTest()
function startTests()
{
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefBranch);
var prefs = SpecialPowers.wrap(Components)
.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
gPrefValue = prefs.getBoolPref("network.jar.open-unsafe-types");
}

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

@ -41,8 +41,6 @@ function onChildLoad(e) {
}
function runTest() {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var popup = window.open("file_bug509055.html", "popup 0",
"height=200,width=200,location=yes," +
"menubar=yes,status=yes,toolbar=yes,dependent=yes");
@ -72,9 +70,10 @@ function runTest() {
dump('Got second hashchange. Spinning event loop.\n');
yield;
var sh = popup.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.sessionHistory;
var sh = SpecialPowers.wrap(popup)
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.sessionHistory;
// Get the title of the inner popup's current SHEntry
var sheTitle = sh.getEntryAtIndex(sh.index, false).title;

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

@ -43,7 +43,6 @@ function pollForPage(f, w)
function windowLoaded()
{
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
switch (phase)
{
case 0:
@ -57,18 +56,16 @@ function windowLoaded()
pollForPage(function(succeeded) {
ok(succeeded, "Waiting for error page succeeded");
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
/* 3. now, while we are on the error page, try to reload it, actually
click the "Try Again" button */
w.location.reload();
SpecialPowers.wrap(w).location.reload();
pollForPage(function(succeeded) {
ok(succeeded, "Waiting for error page succeeded");
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
/* 4-finish, check we are still on the error page */
is(w.location.href, faultyURL, "Is on an error page");
isnot(w.location.href, workingURL, "Is not on the previous page");
is(SpecialPowers.wrap(w).location.href, faultyURL, "Is on an error page");
isnot(SpecialPowers.wrap(w).location.href, workingURL, "Is not on the previous page");
is(gotWrongPageOnTryAgainClick, false,
"Must not get www.example.com page on reload of an error page");
w.close();

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

@ -42,8 +42,6 @@ function pollForPage(expectErrorPage, f, w)
function windowLoaded()
{
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
/* 2. We have successfully loaded a page, now go to a faulty URL */
// XXX The test fails when we change the location synchronously
window.setTimeout(function() {
@ -52,11 +50,9 @@ function windowLoaded()
pollForPage(true, function(succeeded) {
ok(succeeded, "Waiting for error page succeeded");
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
/* 3. now, while we are on the error page, navigate back */
try {
w.back();
SpecialPowers.wrap(w).back();
}
catch(ex) {
ok(false, "w.back() threw " + ex);
@ -64,11 +60,9 @@ function windowLoaded()
pollForPage(false, function(succeeded) {
ok(succeeded, "Waiting for original page succeeded");
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
/* 4-finish, check we are back at the original page */
isnot(w.location.href, faultyURL, "Is on an error page");
is(w.location.href, workingURL, "Is not on the previous page");
isnot(SpecialPowers.wrap(w).location.href, faultyURL, "Is on an error page");
is(SpecialPowers.wrap(w).location.href, workingURL, "Is not on the previous page");
w.close();
SimpleTest.finish();
}, w);

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

@ -0,0 +1,79 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=703855
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 703855</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=703855">Mozilla Bug 703855</a>
<p id="display"></p>
<div id="content" style="display: none">
<iframe id="f" src="file_bug703855.html"></iframe>
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 703855 **/
SimpleTest.waitForExplicitFinish();
var timingAttributes = [
'connectEnd',
'connectStart',
'domComplete',
'domContentLoadedEventEnd',
'domContentLoadedEventStart',
'domInteractive',
'domLoading',
'domainLookupEnd',
'domainLookupStart',
'fetchStart',
'loadEventEnd',
'loadEventStart',
'navigationStart',
'redirectEnd',
'redirectStart',
'requestStart',
'responseEnd',
'responseStart',
'unloadEventEnd',
'unloadEventStart'
];
var originalTiming = {};
function runTest() {
var timing = $("f").contentWindow.performance.timing;
for (i in timingAttributes) {
originalTiming[timingAttributes[i]] = timing[timingAttributes[i]];
}
var doc = $("f").contentDocument;
doc.open();
doc.write("<!DOCTYPE html>");
doc.close();
SimpleTest.executeSoon(function() {
var newTiming = $("f").contentWindow.performance.timing;
for (var i in timingAttributes) {
is(timing[timingAttributes[i]], originalTiming[timingAttributes[i]],
"document.open should not affect value of " + timingAttributes[i]);
}
SimpleTest.finish();
});
}
addLoadEvent(function() {
SimpleTest.executeSoon(runTest);
});
</script>
</pre>
</body>
</html>

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

@ -221,6 +221,7 @@ let DOMApplicationRegistry = {
this.getSelf(msg);
break;
case "Webapps:Uninstall":
Services.obs.notifyObservers(this, "webapps-uninstall", JSON.stringify(msg));
this.uninstall(msg);
break;
case "Webapps:Launch":
@ -698,7 +699,25 @@ let DOMApplicationRegistry = {
for (let id in this.webapps) {
let app = this.webapps[id];
if (app.manifestURL == aManifestURL) {
return this._cloneAppObject(app);
let res = this._cloneAppObject(app);
res.hasPermission = function(permission) {
let localId = DOMApplicationRegistry.getAppLocalIdByManifestURL(
this.manifestURL);
let uri = Services.io.newURI(this.manifestURL, null, null);
let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager);
// XXX for the purposes of permissions checking, this helper
// should always be called on !isBrowser frames, so we
// assume false here.
let principal = secMan.getAppCodebasePrincipal(uri, localId,
/*mozbrowser*/false);
let perm = Services.perms.testExactPermissionFromPrincipal(principal,
permission);
return (perm === Ci.nsIPermissionManager.ALLOW_ACTION);
};
res.QueryInterface = XPCOMUtils.generateQI([Ci.mozIDOMApplication,
Ci.mozIApplication]);
return res;
}
}
@ -957,6 +976,10 @@ DOMApplicationManifest.prototype = {
return this._localeProp("appcache_path");
},
get orientation() {
return this._localeProp("orientation");
},
iconURLForSize: function(aSize) {
let icons = this._localeProp("icons");
if (!icons)

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

@ -41,6 +41,14 @@ nsDOMNavigationTiming::Clear()
mDOMContentLoadedEventEnd = 0;
mDOMComplete = 0;
mRedirectCheck = NOT_CHECKED;
mLoadEventStartSet = false;
mLoadEventEndSet = false;
mDOMLoadingSet = false;
mDOMInteractiveSet = false;
mDOMContentLoadedEventStartSet = false;
mDOMContentLoadedEventEndSet = false;
mDOMCompleteSet = false;
}
DOMTimeMilliSec
@ -128,13 +136,19 @@ nsDOMNavigationTiming::NotifyUnloadEventEnd()
void
nsDOMNavigationTiming::NotifyLoadEventStart()
{
mLoadEventStart = DurationFromStart();
if (!mLoadEventStartSet) {
mLoadEventStart = DurationFromStart();
mLoadEventStartSet = true;
}
}
void
nsDOMNavigationTiming::NotifyLoadEventEnd()
{
mLoadEventEnd = DurationFromStart();
if (!mLoadEventEndSet) {
mLoadEventEnd = DurationFromStart();
mLoadEventEndSet = true;
}
}
bool
@ -166,43 +180,61 @@ nsDOMNavigationTiming::ReportRedirects()
void
nsDOMNavigationTiming::SetDOMLoadingTimeStamp(nsIURI* aURI, mozilla::TimeStamp aValue)
{
mLoadedURI = aURI;
mDOMLoading = TimeStampToDOM(aValue);
if (!mDOMLoadingSet) {
mLoadedURI = aURI;
mDOMLoading = TimeStampToDOM(aValue);
mDOMLoadingSet = true;
}
}
void
nsDOMNavigationTiming::NotifyDOMLoading(nsIURI* aURI)
{
mLoadedURI = aURI;
mDOMLoading = DurationFromStart();
if (!mDOMLoadingSet) {
mLoadedURI = aURI;
mDOMLoading = DurationFromStart();
mDOMLoadingSet = true;
}
}
void
nsDOMNavigationTiming::NotifyDOMInteractive(nsIURI* aURI)
{
mLoadedURI = aURI;
mDOMInteractive = DurationFromStart();
if (!mDOMInteractiveSet) {
mLoadedURI = aURI;
mDOMInteractive = DurationFromStart();
mDOMInteractiveSet = true;
}
}
void
nsDOMNavigationTiming::NotifyDOMComplete(nsIURI* aURI)
{
mLoadedURI = aURI;
mDOMComplete = DurationFromStart();
if (!mDOMCompleteSet) {
mLoadedURI = aURI;
mDOMComplete = DurationFromStart();
mDOMCompleteSet = true;
}
}
void
nsDOMNavigationTiming::NotifyDOMContentLoadedStart(nsIURI* aURI)
{
mLoadedURI = aURI;
mDOMContentLoadedEventStart = DurationFromStart();
if (!mDOMContentLoadedEventStartSet) {
mLoadedURI = aURI;
mDOMContentLoadedEventStart = DurationFromStart();
mDOMContentLoadedEventStartSet = true;
}
}
void
nsDOMNavigationTiming::NotifyDOMContentLoadedEnd(nsIURI* aURI)
{
mLoadedURI = aURI;
mDOMContentLoadedEventEnd = DurationFromStart();
if (!mDOMContentLoadedEventEndSet) {
mLoadedURI = aURI;
mDOMContentLoadedEventEnd = DurationFromStart();
mDOMContentLoadedEventEndSet = true;
}
}
PRUint16

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

@ -136,6 +136,17 @@ private:
DOMTimeMilliSec mDOMContentLoadedEventStart;
DOMTimeMilliSec mDOMContentLoadedEventEnd;
DOMTimeMilliSec mDOMComplete;
// Booleans to keep track of what things we've already been notified
// about. We don't update those once we've been notified about them
// once.
bool mLoadEventStartSet : 1;
bool mLoadEventEndSet : 1;
bool mDOMLoadingSet : 1;
bool mDOMInteractiveSet : 1;
bool mDOMContentLoadedEventStartSet : 1;
bool mDOMContentLoadedEventEndSet : 1;
bool mDOMCompleteSet : 1;
};
#endif /* nsDOMNavigationTiming_h___ */

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

@ -1956,6 +1956,17 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
if (newInnerWindow->mNavigator) {
newInnerWindow->mNavigator->SetWindow(newInnerWindow);
}
// Make a copy of the old window's performance object on document.open.
// Note that we have to force eager creation of it here, because we need
// to grab the current document channel and whatnot before that changes.
currentInner->CreatePerformanceObjectIfNeeded();
if (currentInner->mPerformance) {
newInnerWindow->mPerformance =
new nsPerformance(newInnerWindow,
currentInner->mPerformance->GetDOMTiming(),
currentInner->mPerformance->GetChannel());
}
}
// Don't free objects on our current inner window if it's going to be
@ -2931,27 +2942,31 @@ nsGlobalWindow::GetPerformance(nsISupports** aPerformance)
*aPerformance = nullptr;
if (nsGlobalWindow::HasPerformanceSupport()) {
if (!mPerformance) {
if (!mDoc) {
return NS_OK;
}
nsRefPtr<nsDOMNavigationTiming> timing = mDoc->GetNavigationTiming();
nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(mDoc->GetChannel()));
bool timingEnabled = false;
if (!timedChannel ||
!NS_SUCCEEDED(timedChannel->GetTimingEnabled(&timingEnabled)) ||
!timingEnabled) {
timedChannel = nullptr;
}
if (timing) {
mPerformance = new nsPerformance(this, timing, timedChannel);
}
}
CreatePerformanceObjectIfNeeded();
NS_IF_ADDREF(*aPerformance = mPerformance);
}
return NS_OK;
}
void
nsGlobalWindow::CreatePerformanceObjectIfNeeded()
{
if (mPerformance || !mDoc) {
return;
}
nsRefPtr<nsDOMNavigationTiming> timing = mDoc->GetNavigationTiming();
nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(mDoc->GetChannel()));
bool timingEnabled = false;
if (!timedChannel ||
!NS_SUCCEEDED(timedChannel->GetTimingEnabled(&timingEnabled)) ||
!timingEnabled) {
timedChannel = nullptr;
}
if (timing) {
mPerformance = new nsPerformance(this, timing, timedChannel);
}
}
/**
* GetScriptableParent is called when script reads window.parent.
*

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

@ -905,6 +905,9 @@ protected:
// Implements Get{Real,Scriptable}Top.
nsresult GetTopImpl(nsIDOMWindow **aWindow, bool aScriptable);
// Helper for creating performance objects.
void CreatePerformanceObjectIfNeeded();
// When adding new member variables, be careful not to create cycles
// through JavaScript. If there is any chance that a member variable
// could own objects that are implemented in JavaScript, then those
@ -990,6 +993,7 @@ protected:
nsCOMPtr<nsIPrincipal> mArgumentsOrigin;
nsRefPtr<Navigator> mNavigator;
nsRefPtr<nsScreen> mScreen;
// mPerformance is only used on inner windows.
nsRefPtr<nsPerformance> mPerformance;
nsRefPtr<nsDOMWindowList> mFrames;
nsRefPtr<nsBarProp> mMenubar;

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

@ -140,6 +140,11 @@ public:
return mDOMTiming;
}
nsITimedChannel* GetChannel() const
{
return mChannel;
}
nsIDOMWindow* GetParentObject() const
{
return mWindow.get();

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

@ -64,7 +64,7 @@ struct TypedArray : public TypedArray_base<T,UnboxArray> {
static inline JSObject*
Create(JSContext* cx, nsWrapperCache* creator, uint32_t length,
T* data = NULL) {
const T* data = NULL) {
JSObject* creatorWrapper;
JSAutoEnterCompartment ac;
if (creator && (creatorWrapper = creator->GetWrapperPreserveColor())) {

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

@ -9,6 +9,7 @@ const ContentPanning = {
});
addMessageListener("Viewport:Change", this._recvViewportChange.bind(this));
addMessageListener("Gesture:DoubleTap", this._recvDoubleTap.bind(this));
},
handleEvent: function cp_handleEvent(evt) {
@ -43,6 +44,16 @@ const ContentPanning = {
let oldTarget = this.target;
[this.target, this.scrollCallback] = this.getPannable(evt.target);
// If we found a target, that means we have found a scrollable subframe. In
// this case, and if we are using async panning and zooming on the parent
// frame, inform the pan/zoom controller that it should not attempt to
// handle any touch events it gets until the next batch (meaning the next
// time we get a touch end).
if (this.target != null && ContentPanning._asyncPanZoomForViewportFrame) {
var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
os.notifyObservers(docShell, 'cancel-default-pan-zoom', null);
}
// If there is a pan animation running (from a previous pan gesture) and
// the user touch back the screen, stop this animation immediatly and
// prevent the possible click action if the touch happens on the same
@ -190,21 +201,34 @@ const ContentPanning = {
},
_recvViewportChange: function(data) {
let viewport = data.json;
let displayPort = viewport.displayPort;
let metrics = data.json;
let displayPort = metrics.displayPort;
let screenWidth = viewport.screenSize.width;
let screenHeight = viewport.screenSize.height;
let screenWidth = metrics.screenSize.width;
let screenHeight = metrics.screenSize.height;
let x = viewport.x;
let y = viewport.y;
let x = metrics.x;
let y = metrics.y;
this._zoom = metrics.zoom;
this._viewport = new Rect(x, y,
screenWidth / metrics.zoom,
screenHeight / metrics.zoom);
this._cssPageRect = new Rect(metrics.cssPageRect.x,
metrics.cssPageRect.y,
metrics.cssPageRect.width,
metrics.cssPageRect.height);
let cwu = content.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
cwu.setCSSViewport(screenWidth, screenHeight);
if (this._screenWidth != screenWidth || this._screenHeight != screenHeight) {
cwu.setCSSViewport(screenWidth, screenHeight);
this._screenWidth = screenWidth;
this._screenHeight = screenHeight;
}
// Set scroll position
cwu.setScrollPositionClampingScrollPortSize(
screenWidth / viewport.zoom, screenHeight / viewport.zoom);
screenWidth / metrics.zoom, screenHeight / metrics.zoom);
content.scrollTo(x, y);
cwu.setResolution(displayPort.resolution, displayPort.resolution);
@ -216,6 +240,109 @@ const ContentPanning = {
displayPort.height,
element);
}
},
_recvDoubleTap: function(data) {
let data = data.json;
// We haven't received a metrics update yet; don't do anything.
if (this._viewport == null) {
return;
}
let win = content;
let zoom = this._zoom;
let element = ElementTouchHelper.anyElementFromPoint(win, data.x, data.y);
if (!element) {
this._zoomOut();
return;
}
while (element && !this._shouldZoomToElement(element))
element = element.parentNode;
if (!element) {
this._zoomOut();
} else {
const margin = 15;
let rect = ElementTouchHelper.getBoundingContentRect(element);
let cssPageRect = this._cssPageRect;
let viewport = this._viewport;
let bRect = new Rect(Math.max(cssPageRect.left, rect.x - margin),
rect.y,
rect.w + 2 * margin,
rect.h);
// constrict the rect to the screen's right edge
bRect.width = Math.min(bRect.width, cssPageRect.right - bRect.x);
// if the rect is already taking up most of the visible area and is stretching the
// width of the page, then we want to zoom out instead.
if (this._isRectZoomedIn(bRect, viewport)) {
this._zoomOut();
return;
}
rect.x = Math.round(bRect.x);
rect.y = Math.round(bRect.y);
rect.w = Math.round(bRect.width);
rect.h = Math.round(Math.min(bRect.width * viewport.height / viewport.height, bRect.height));
// if the block we're zooming to is really tall, and the user double-tapped
// more than a screenful of height from the top of it, then adjust the y-coordinate
// so that we center the actual point the user double-tapped upon. this prevents
// flying to the top of a page when double-tapping to zoom in (bug 761721).
// the 1.2 multiplier is just a little fuzz to compensate for bRect including horizontal
// margins but not vertical ones.
let cssTapY = viewport.y + data.y;
if ((bRect.height > rect.h) && (cssTapY > rect.y + (rect.h * 1.2))) {
rect.y = cssTapY - (rect.h / 2);
}
var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
os.notifyObservers(docShell, 'browser-zoom-to-rect', JSON.stringify(rect));
}
},
_shouldZoomToElement: function(aElement) {
let win = aElement.ownerDocument.defaultView;
if (win.getComputedStyle(aElement, null).display == "inline")
return false;
if (aElement instanceof Ci.nsIDOMHTMLLIElement)
return false;
if (aElement instanceof Ci.nsIDOMHTMLQuoteElement)
return false;
return true;
},
_zoomOut: function() {
let rect = new Rect(0, 0, 0, 0);
var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
os.notifyObservers(docShell, 'browser-zoom-to-rect', JSON.stringify(rect));
},
_isRectZoomedIn: function(aRect, aViewport) {
// This function checks to see if the area of the rect visible in the
// viewport (i.e. the "overlapArea" variable below) is approximately
// the max area of the rect we can show. It also checks that the rect
// is actually on-screen by testing the left and right edges of the rect.
// In effect, this tells us whether or not zooming in to this rect
// will significantly change what the user is seeing.
const minDifference = -20;
const maxDifference = 20;
let vRect = new Rect(aViewport.x, aViewport.y, aViewport.width, aViewport.height);
let overlap = vRect.intersect(aRect);
let overlapArea = overlap.width * overlap.height;
let availHeight = Math.min(aRect.width * vRect.height / vRect.width, aRect.height);
let showing = overlapArea / (aRect.width * availHeight);
let dw = (aRect.width - vRect.width);
let dx = (aRect.x - vRect.x);
return (showing > 0.9 &&
dx > minDifference && dx < maxDifference &&
dw > minDifference && dw < maxDifference);
}
};
@ -389,3 +516,52 @@ const KineticPanning = {
content.mozRequestAnimationFrame(callback);
}
};
const ElementTouchHelper = {
anyElementFromPoint: function(aWindow, aX, aY) {
let cwu = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
let elem = cwu.elementFromPoint(aX, aY, true, true);
let HTMLIFrameElement = Ci.nsIDOMHTMLIFrameElement;
let HTMLFrameElement = Ci.nsIDOMHTMLFrameElement;
while (elem && (elem instanceof HTMLIFrameElement || elem instanceof HTMLFrameElement)) {
let rect = elem.getBoundingClientRect();
aX -= rect.left;
aY -= rect.top;
cwu = elem.contentDocument.defaultView.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
elem = cwu.elementFromPoint(aX, aY, true, true);
}
return elem;
},
getBoundingContentRect: function(aElement) {
if (!aElement)
return {x: 0, y: 0, w: 0, h: 0};
let document = aElement.ownerDocument;
while (document.defaultView.frameElement)
document = document.defaultView.frameElement.ownerDocument;
let cwu = document.defaultView.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
let scrollX = {}, scrollY = {};
cwu.getScrollXY(false, scrollX, scrollY);
let r = aElement.getBoundingClientRect();
// step out of iframes and frames, offsetting scroll values
for (let frame = aElement.ownerDocument.defaultView; frame.frameElement && frame != content; frame = frame.parent) {
// adjust client coordinates' origin to be top left of iframe viewport
let rect = frame.frameElement.getBoundingClientRect();
let left = frame.getComputedStyle(frame.frameElement, "").borderLeftWidth;
let top = frame.getComputedStyle(frame.frameElement, "").borderTopWidth;
scrollX.value += rect.left + parseInt(left);
scrollY.value += rect.top + parseInt(top);
}
return {x: r.left + scrollX.value,
y: r.top + scrollY.value,
w: r.width,
h: r.height };
}
};

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

@ -15,6 +15,7 @@ XPIDL_MODULE = dom_apps
GRE_MODULE = 1
XPIDLSRCS = \
mozIApplication.idl \
nsIDOMApplicationRegistry.idl \
nsIAppsService.idl \
nsIDOMMozApplicationEvent.idl \

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

@ -0,0 +1,19 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIDOMApplicationRegistry.idl"
/**
* We expose Gecko-internal helpers related to "web apps" through this
* sub-interface.
*/
[scriptable, uuid(8de25e36-b4cb-4e89-9310-a199dce4e5f4)]
interface mozIApplication: mozIDOMApplication
{
/* Return true if this app has |permission|. */
boolean hasPermission(in string permission);
};

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

@ -0,0 +1,54 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "AppProcessPermissions.h"
#include "ContentParent.h"
#include "mozIApplication.h"
#include "nsIDOMApplicationRegistry.h"
#include "TabParent.h"
using namespace mozilla::dom;
using namespace mozilla::services;
namespace mozilla {
bool
AppProcessHasPermission(PBrowserParent* aActor, const char* aPermission)
{
if (!aActor) {
NS_WARNING("Testing permissions for null actor");
return false;
}
TabParent* tab = static_cast<TabParent*>(aActor);
nsCOMPtr<mozIApplication> app = tab->GetApp();
// isBrowser frames inherit their app descriptor to identify their
// data storage, but they don't inherit the permissions associated
// with that descriptor.
if (!app || tab->IsBrowserElement()) {
return false;
}
bool hasPermission = false;
return (NS_SUCCEEDED(app->HasPermission(aPermission, &hasPermission)) &&
hasPermission);
}
bool
AppProcessHasPermission(PContentParent* aActor, const char* aPermission)
{
const InfallibleTArray<PBrowserParent*>& browsers =
aActor->ManagedPBrowserParent();
for (uint32_t i = 0; i < browsers.Length(); ++i) {
if (AppProcessHasPermission(browsers[i], aPermission)) {
return true;
}
}
return false;
}
} // namespace mozilla

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

@ -0,0 +1,43 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_Capabilities_h
#define mozilla_Capabilities_h
namespace mozilla {
namespace dom {
class PBrowserParent;
class PContentParent;
}
/**
* Return true iff the specified browser has the specified capability.
*/
bool
AppProcessHasPermissions(mozilla::dom::PBrowserParent* aActor,
const char* aPermission);
/**
* Return true iff any of the PBrowsers loaded in this content process
* has the specified capability.
*/
bool
AppProcessHasPermission(mozilla::dom::PContentParent* aActor,
const char* aPermission);
// NB: when adding capability checks for other IPDL actors, please add
// them to this file and have them delegate to the two functions above
// as appropriate. For example,
//
// bool AppProcessHasCapability(PNeckoParent* aActor) {
// return AppProcessHasCapability(aActor->Manager());
// }
} // namespace mozilla
#endif // mozilla_Capabilities_h

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

@ -39,6 +39,7 @@
#include "nsIObserverService.h"
#include "nsTObserverArray.h"
#include "nsIObserver.h"
#include "nsIScriptSecurityManager.h"
#include "nsServiceManagerUtils.h"
#include "nsXULAppAPI.h"
#include "nsWeakReference.h"
@ -402,10 +403,11 @@ ContentChild::AllocPCompositor(mozilla::ipc::Transport* aTransport,
PBrowserChild*
ContentChild::AllocPBrowser(const PRUint32& aChromeFlags,
const bool& aIsBrowserElement,
const PRUint32& aAppId)
const bool& aIsBrowserElement, const AppId& aApp)
{
nsRefPtr<TabChild> iframe = new TabChild(aChromeFlags, aIsBrowserElement, aAppId);
PRUint32 appId = aApp.get_uint32_t();
nsRefPtr<TabChild> iframe = new TabChild(aChromeFlags, aIsBrowserElement,
appId);
return NS_SUCCEEDED(iframe->Init()) ? iframe.forget().get() : NULL;
}

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

@ -68,7 +68,7 @@ public:
virtual PBrowserChild* AllocPBrowser(const PRUint32& aChromeFlags,
const bool& aIsBrowserElement,
const PRUint32& aAppId);
const AppId& aAppId);
virtual bool DeallocPBrowser(PBrowserChild*);
virtual PDeviceStorageRequestChild* AllocPDeviceStorageRequest(const DeviceStorageParams&);

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

@ -20,6 +20,7 @@
#include "IDBFactory.h"
#include "IndexedDBParent.h"
#include "IndexedDatabaseManager.h"
#include "mozIApplication.h"
#include "mozilla/Preferences.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
@ -49,8 +50,10 @@
#include "nsFrameMessageManager.h"
#include "nsHashPropertyBag.h"
#include "nsIAlertsService.h"
#include "nsIAppsService.h"
#include "nsIClipboard.h"
#include "nsIConsoleService.h"
#include "nsIDOMApplicationRegistry.h"
#include "nsIDOMGeoGeolocation.h"
#include "nsIDOMWindow.h"
#include "nsIFilePicker.h"
@ -59,6 +62,7 @@
#include "nsIPresShell.h"
#include "nsIRemoteBlob.h"
#include "nsIScriptError.h"
#include "nsIScriptSecurityManager.h"
#include "nsISupportsPrimitives.h"
#include "nsIWindowWatcher.h"
#include "nsMemoryReporterManager.h"
@ -149,7 +153,7 @@ nsTArray<ContentParent*>* ContentParent::gPrivateContent;
// The first content child has ID 1, so the chrome process can have ID 0.
static PRUint64 gContentChildID = 1;
ContentParent*
/*static*/ ContentParent*
ContentParent::GetNewOrUsed()
{
if (!gNonAppContentParents)
@ -165,7 +169,7 @@ ContentParent::GetNewOrUsed()
NS_ASSERTION(p->IsAlive(), "Non-alive contentparent in gNonAppContentParents?");
return p;
}
nsRefPtr<ContentParent> p =
new ContentParent(/* appManifestURL = */ EmptyString());
p->Init();
@ -173,11 +177,20 @@ ContentParent::GetNewOrUsed()
return p;
}
ContentParent*
ContentParent::GetForApp(const nsAString& aAppManifestURL)
/*static*/ TabParent*
ContentParent::CreateBrowser(mozIApplication* aApp, bool aIsBrowserElement)
{
if (aAppManifestURL.IsEmpty()) {
return GetNewOrUsed();
if (!aApp) {
if (ContentParent* cp = GetNewOrUsed()) {
nsRefPtr<TabParent> tp(new TabParent(aApp, aIsBrowserElement));
return static_cast<TabParent*>(
cp->SendPBrowserConstructor(
// DeallocPBrowserParent() releases the ref we take here
tp.forget().get(),
/*chromeFlags*/0,
aIsBrowserElement, nsIScriptSecurityManager::NO_APP_ID));
}
return nullptr;
}
if (!gAppContentParents) {
@ -187,14 +200,39 @@ ContentParent::GetForApp(const nsAString& aAppManifestURL)
}
// Each app gets its own ContentParent instance.
ContentParent* p = gAppContentParents->Get(aAppManifestURL);
if (!p) {
p = new ContentParent(aAppManifestURL);
p->Init();
gAppContentParents->Put(aAppManifestURL, p);
nsAutoString manifestURL;
if (NS_FAILED(aApp->GetManifestURL(manifestURL))) {
NS_ERROR("Failed to get manifest URL");
return nullptr;
}
return p;
nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
if (!appsService) {
NS_ERROR("Failed to get apps service");
return nullptr;
}
// Send the local app ID to the new TabChild so it knows what app
// it is.
PRUint32 appId;
if (NS_FAILED(appsService->GetAppLocalIdByManifestURL(manifestURL, &appId))) {
NS_ERROR("Failed to get local app ID");
return nullptr;
}
ContentParent* p = gAppContentParents->Get(manifestURL);
if (!p) {
p = new ContentParent(manifestURL);
p->Init();
gAppContentParents->Put(manifestURL, p);
}
nsRefPtr<TabParent> tp(new TabParent(aApp, aIsBrowserElement));
return static_cast<TabParent*>(
// DeallocPBrowserParent() releases the ref we take here
p->SendPBrowserConstructor(tp.forget().get(),
/*chromeFlags*/0,
aIsBrowserElement, appId));
}
static PLDHashOperator
@ -455,12 +493,6 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
NS_DispatchToCurrentThread(new DelayedDeleteContentParentTask(this));
}
TabParent*
ContentParent::CreateTab(PRUint32 aChromeFlags, bool aIsBrowserElement, PRUint32 aAppId)
{
return static_cast<TabParent*>(SendPBrowserConstructor(aChromeFlags, aIsBrowserElement, aAppId));
}
void
ContentParent::NotifyTabDestroyed(PBrowserParent* aTab)
{
@ -862,22 +894,40 @@ ContentParent::AllocPCompositor(mozilla::ipc::Transport* aTransport,
PBrowserParent*
ContentParent::AllocPBrowser(const PRUint32& aChromeFlags,
const bool& aIsBrowserElement,
const PRUint32& aAppId)
const bool& aIsBrowserElement, const AppId& aApp)
{
TabParent* parent = new TabParent();
if (parent){
// We only use this Alloc() method when the content processes asks
// us to open a window. In that case, we're expecting to see the
// opening PBrowser as its app descriptor, and we can trust the data
// associated with that PBrowser since it's fully owned by this
// process.
if (AppId::TPBrowserParent != aApp.type()) {
NS_ERROR("Content process attempting to forge app ID");
return nullptr;
}
TabParent* opener = static_cast<TabParent*>(aApp.get_PBrowserParent());
// Popup windows of isBrowser frames are isBrowser if the parent
// isBrowser. Allocating a !isBrowser frame with same app ID
// would allow the content to access data it's not supposed to.
if (opener && opener->IsBrowserElement() && !aIsBrowserElement) {
NS_ERROR("Content process attempting to escalate data access privileges");
return nullptr;
}
TabParent* parent = new TabParent(opener ? opener->GetApp() : nullptr,
aIsBrowserElement);
// We release this ref in DeallocPBrowser()
NS_ADDREF(parent);
}
return parent;
return parent;
}
bool
ContentParent::DeallocPBrowser(PBrowserParent* frame)
{
TabParent* parent = static_cast<TabParent*>(frame);
NS_RELEASE(parent);
return true;
TabParent* parent = static_cast<TabParent*>(frame);
NS_RELEASE(parent);
return true;
}
PDeviceStorageRequestParent*

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

@ -26,6 +26,7 @@
#include "nsInterfaceHashtable.h"
#include "nsHashKeys.h"
class mozIApplication;
class nsFrameMessageManager;
class nsIDOMBlob;
@ -60,13 +61,16 @@ public:
static ContentParent* GetNewOrUsed();
/**
* Get or create a content process for the given app. A given app
* (identified by its manifest URL) gets one process all to itself.
* Get or create a content process for the given app descriptor,
* which may be null. This function will assign processes to app
* or non-app browsers by internal heuristics.
*
* If the given manifest is the empty string, then this method is equivalent
* to GetNewOrUsed().
* Currently apps are given their own process, and browser tabs
* share processes.
*/
static ContentParent* GetForApp(const nsAString& aManifestURL);
static TabParent* CreateBrowser(mozIApplication* aApp,
bool aIsBrowserFrame);
static void GetAll(nsTArray<ContentParent*>& aArray);
NS_DECL_ISUPPORTS
@ -74,14 +78,6 @@ public:
NS_DECL_NSITHREADOBSERVER
NS_DECL_NSIDOMGEOPOSITIONCALLBACK
/**
* Create a new tab.
*
* |aIsBrowserElement| indicates whether this tab is part of an
* <iframe mozbrowser>.
* |aAppId| indicates which app the tab belongs to.
*/
TabParent* CreateTab(PRUint32 aChromeFlags, bool aIsBrowserElement, PRUint32 aAppId);
/** Notify that a tab was destroyed during normal operation. */
void NotifyTabDestroyed(PBrowserParent* aTab);
@ -143,7 +139,9 @@ private:
PCompositorParent* AllocPCompositor(mozilla::ipc::Transport* aTransport,
base::ProcessId aOtherProcess) MOZ_OVERRIDE;
virtual PBrowserParent* AllocPBrowser(const PRUint32& aChromeFlags, const bool& aIsBrowserElement, const PRUint32& aAppId);
virtual PBrowserParent* AllocPBrowser(const PRUint32& aChromeFlags,
const bool& aIsBrowserElement,
const AppId& aApp);
virtual bool DeallocPBrowser(PBrowserParent* frame);
virtual PDeviceStorageRequestParent* AllocPDeviceStorageRequest(const DeviceStorageParams&);

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

@ -23,10 +23,15 @@ endif
EXPORTS = PCOMContentPermissionRequestChild.h
EXPORTS_NAMESPACES = \
mozilla \
mozilla/dom \
mozilla/dom/ipc \
$(NULL)
EXPORTS_mozilla = \
AppProcessPermissions.h \
$(NULL)
EXPORTS_mozilla/dom = \
ContentChild.h \
ContentParent.h \
@ -47,6 +52,7 @@ EXPORTS_mozilla/dom/ipc = \
$(NULL)
CPPSRCS = \
AppProcessPermissions.cpp \
Blob.cpp \
ContentProcess.cpp \
ContentParent.cpp \

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

@ -15,6 +15,7 @@ include protocol POfflineCacheUpdate;
include protocol PIndexedDB;
include "gfxMatrix.h";
include "FrameMetrics.h";
include "IPC/nsGUIEventIPC.h";
include "mozilla/dom/TabMessageUtils.h";
include "mozilla/dom/PermissionMessageUtils.h";
@ -26,8 +27,10 @@ include DOMTypes;
using IPC::URI;
using IPC::Principal;
using gfxMatrix;
using gfxRect;
using gfxSize;
using mozilla::layers::LayersBackend;
using mozilla::layers::FrameMetrics;
using mozilla::layout::ScrollingBehavior;
using mozilla::WindowsHandle;
using nscolor;
@ -247,6 +250,14 @@ parent:
nsString aName, nsString aFeatures)
returns (bool windowOpened);
NotifyDOMTouchListenerAdded();
/**
* Instructs the TabParent to forward a request to zoom to a rect given in
* CSS pixels. This rect is relative to the document.
*/
ZoomToRect(gfxRect aRect);
__delete__();
child:
@ -265,10 +276,14 @@ child:
UpdateDimensions(nsRect rect, nsIntSize size);
UpdateFrame(nsIntRect displayPort,
nsIntPoint scrollOffset,
gfxSize resolution,
nsIntRect screenSize);
UpdateFrame(FrameMetrics frame);
/**
* Requests handling of a double tap. |point| is in CSS pixels, relative to
* the scroll offset. This message is expected to round-trip back to
* ZoomToRect() with a rect indicating where we should zoom to.
*/
HandleDoubleTap(nsIntPoint point);
/**
* Sending an activate message moves focus to the child.

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

@ -122,6 +122,11 @@ union BlobConstructorParams
MysteryBlobConstructorParams;
};
union AppId {
uint32_t;
nullable PBrowser;
};
rpc protocol PContent
{
parent opens PCompositor;
@ -145,9 +150,16 @@ both:
// created from either the child or parent process!
//
// The child creates the PBrowser as part of
// TabChild::BrowserFrameProvideWindow, and the parent creates the PBrowser
// as part of ContentParent::CreateTab.
async PBrowser(PRUint32 chromeFlags, bool isBrowserElement, PRUint32 appId);
// TabChild::BrowserFrameProvideWindow, and the parent creates the
// PBrowser as part of ContentParent::CreateTab.
//
// When the parent constructs a PBrowser, the app ID handed to the
// child side is trusted. In that case, |appId| is uint32_t.
// However, when the child side constructs a PBrowser, for
// window.open(), the parent must validate the app ID used on the
// parent side. To do so, the child process must pass a valid
// PBrowser as its |AppId|.
async PBrowser(PRUint32 chromeFlags, bool isBrowserElement, AppId appId);
async PBlob(BlobConstructorParams params);

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

@ -20,6 +20,7 @@
#include "mozilla/layers/CompositorChild.h"
#include "mozilla/layers/PLayersChild.h"
#include "mozilla/layout/RenderFrameChild.h"
#include "mozilla/unused.h"
#include "nsComponentManagerUtils.h"
#include "nsComponentManagerUtils.h"
#include "nsContentUtils.h"
@ -106,6 +107,40 @@ TabChild::TabChild(PRUint32 aChromeFlags, bool aIsBrowserElement,
printf("creating %d!\n", NS_IsMainThread());
}
nsresult
TabChild::Observe(nsISupports *aSubject,
const char *aTopic,
const PRUnichar *aData)
{
if (!strcmp(aTopic, "dom-touch-listener-added")) {
nsCOMPtr<nsIDOMWindow> subject(do_QueryInterface(aSubject));
nsCOMPtr<nsIDOMWindow> win(do_GetInterface(mWebNav));
nsCOMPtr<nsIDOMWindow> topSubject;
subject->GetTop(getter_AddRefs(topSubject));
if (win == topSubject) {
SendNotifyDOMTouchListenerAdded();
}
} else if (!strcmp(aTopic, "cancel-default-pan-zoom")) {
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aSubject));
nsCOMPtr<nsITabChild> tabChild(GetTabChildFrom(docShell));
if (tabChild == this) {
mRemoteFrame->CancelDefaultPanZoom();
}
} else if (!strcmp(aTopic, "browser-zoom-to-rect")) {
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aSubject));
nsCOMPtr<nsITabChild> tabChild(GetTabChildFrom(docShell));
if (tabChild == this) {
gfxRect rect;
sscanf(NS_ConvertUTF16toUTF8(aData).get(),
"{\"x\":%lf,\"y\":%lf,\"w\":%lf,\"h\":%lf}",
&rect.x, &rect.y, &rect.width, &rect.height);
SendZoomToRect(rect);
}
}
return NS_OK;
}
nsresult
TabChild::Init()
{
@ -121,6 +156,22 @@ TabChild::Init()
nsCOMPtr<nsIDocShellTreeItem> docShellItem(do_QueryInterface(mWebNav));
docShellItem->SetItemType(nsIDocShellTreeItem::typeContentWrapper);
nsCOMPtr<nsIObserverService> observerService =
do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
if (observerService) {
observerService->AddObserver(this,
"dom-touch-listener-added",
false);
observerService->AddObserver(this,
"cancel-default-pan-zoom",
false);
observerService->AddObserver(this,
"browser-zoom-to-rect",
false);
}
return NS_OK;
}
@ -384,10 +435,16 @@ TabChild::BrowserFrameProvideWindow(nsIDOMWindow* aOpener,
{
*aReturn = nullptr;
nsRefPtr<TabChild> newChild =
static_cast<TabChild*>(Manager()->SendPBrowserConstructor(
/* aChromeFlags = */ 0, mIsBrowserElement, mAppId));
PRUint32 chromeFlags = 0;
nsRefPtr<TabChild> newChild = new TabChild(chromeFlags,
mIsBrowserElement, mAppId);
if (!NS_SUCCEEDED(newChild->Init())) {
return NS_ERROR_ABORT;
}
unused << Manager()->SendPBrowserConstructor(
// We release this ref in DeallocPBrowserChild
nsRefPtr<TabChild>(newChild).forget().get(),
chromeFlags, mIsBrowserElement, this);
nsCAutoString spec;
if (aURI) {
aURI->GetSpec(spec);
@ -644,41 +701,17 @@ TabChild::RecvUpdateDimensions(const nsRect& rect, const nsIntSize& size)
return true;
}
bool
TabChild::RecvUpdateFrame(const nsIntRect& aDisplayPort,
const nsIntPoint& aScrollOffset,
const gfxSize& aResolution,
const nsIntRect& aScreenSize)
void
TabChild::DispatchMessageManagerMessage(const nsAString& aMessageName,
const nsACString& aJSONData)
{
if (!mCx || !mTabChildGlobal) {
return true;
}
nsCString data;
data += nsPrintfCString("{ \"x\" : %d", aScrollOffset.x);
data += nsPrintfCString(", \"y\" : %d", aScrollOffset.y);
// We don't treat the x and y scales any differently for this
// semi-platform-specific code.
data += nsPrintfCString(", \"zoom\" : %f", aResolution.width);
data += nsPrintfCString(", \"displayPort\" : ");
data += nsPrintfCString("{ \"left\" : %d", aDisplayPort.X());
data += nsPrintfCString(", \"top\" : %d", aDisplayPort.Y());
data += nsPrintfCString(", \"width\" : %d", aDisplayPort.Width());
data += nsPrintfCString(", \"height\" : %d", aDisplayPort.Height());
data += nsPrintfCString(", \"resolution\" : %f", aResolution.width);
data += nsPrintfCString(" }");
data += nsPrintfCString(", \"screenSize\" : ");
data += nsPrintfCString("{ \"width\" : %d", aScreenSize.width);
data += nsPrintfCString(", \"height\" : %d", aScreenSize.height);
data += nsPrintfCString(" }");
data += nsPrintfCString(" }");
JSAutoRequest ar(mCx);
jsval json = JSVAL_NULL;
StructuredCloneData cloneData;
JSAutoStructuredCloneBuffer buffer;
if (JS_ParseJSON(mCx,
static_cast<const jschar*>(NS_ConvertUTF8toUTF16(data).get()),
data.Length(),
static_cast<const jschar*>(NS_ConvertUTF8toUTF16(aJSONData).get()),
aJSONData.Length(),
&json)) {
WriteStructuredClone(mCx, json, buffer, cloneData.mClosure);
cloneData.mData = buffer.data();
@ -691,8 +724,60 @@ TabChild::RecvUpdateFrame(const nsIntRect& aDisplayPort,
nsRefPtr<nsFrameMessageManager> mm =
static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get());
mm->ReceiveMessage(static_cast<nsIDOMEventTarget*>(mTabChildGlobal),
NS_LITERAL_STRING("Viewport:Change"), false,
&cloneData, nullptr, nullptr);
aMessageName, false, &cloneData, nullptr, nullptr);
}
bool
TabChild::RecvUpdateFrame(const FrameMetrics& aFrameMetrics)
{
if (!mCx || !mTabChildGlobal) {
return true;
}
nsCString data;
data += nsPrintfCString("{ \"x\" : %d", aFrameMetrics.mViewportScrollOffset.x);
data += nsPrintfCString(", \"y\" : %d", aFrameMetrics.mViewportScrollOffset.y);
// We don't treat the x and y scales any differently for this
// semi-platform-specific code.
data += nsPrintfCString(", \"zoom\" : %f", aFrameMetrics.mResolution.width);
data += nsPrintfCString(", \"displayPort\" : ");
data += nsPrintfCString("{ \"left\" : %d", aFrameMetrics.mDisplayPort.X());
data += nsPrintfCString(", \"top\" : %d", aFrameMetrics.mDisplayPort.Y());
data += nsPrintfCString(", \"width\" : %d", aFrameMetrics.mDisplayPort.Width());
data += nsPrintfCString(", \"height\" : %d", aFrameMetrics.mDisplayPort.Height());
data += nsPrintfCString(", \"resolution\" : %f", aFrameMetrics.mResolution.width);
data += nsPrintfCString(" }");
data += nsPrintfCString(", \"screenSize\" : ");
data += nsPrintfCString("{ \"width\" : %d", aFrameMetrics.mViewport.width);
data += nsPrintfCString(", \"height\" : %d", aFrameMetrics.mViewport.height);
data += nsPrintfCString(" }");
data += nsPrintfCString(", \"cssPageRect\" : ");
data += nsPrintfCString("{ \"x\" : %f", aFrameMetrics.mCSSContentRect.x);
data += nsPrintfCString(", \"y\" : %f", aFrameMetrics.mCSSContentRect.y);
data += nsPrintfCString(", \"width\" : %f", aFrameMetrics.mCSSContentRect.width);
data += nsPrintfCString(", \"height\" : %f", aFrameMetrics.mCSSContentRect.height);
data += nsPrintfCString(" }");
data += nsPrintfCString(" }");
DispatchMessageManagerMessage(NS_LITERAL_STRING("Viewport:Change"), data);
return true;
}
bool
TabChild::RecvHandleDoubleTap(const nsIntPoint& aPoint)
{
if (!mCx || !mTabChildGlobal) {
return true;
}
nsCString data;
data += nsPrintfCString("{ \"x\" : %d", aPoint.x);
data += nsPrintfCString(", \"y\" : %d", aPoint.y);
data += nsPrintfCString(" }");
DispatchMessageManagerMessage(NS_LITERAL_STRING("Gesture:DoubleTap"), data);
return true;
}

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

@ -47,6 +47,7 @@
#include "nsWeakReference.h"
#include "nsITabChild.h"
#include "mozilla/Attributes.h"
#include "FrameMetrics.h"
struct gfxMatrix;
@ -140,7 +141,8 @@ class TabChild : public PBrowserChild,
public nsIWindowProvider,
public nsSupportsWeakReference,
public nsIDialogCreator,
public nsITabChild
public nsITabChild,
public nsIObserver
{
typedef mozilla::layout::RenderFrameChild RenderFrameChild;
typedef mozilla::dom::ClonedMessageData ClonedMessageData;
@ -157,6 +159,8 @@ public:
virtual ~TabChild();
nsresult Init();
PRUint32 GetAppId() { return mAppId; }
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBBROWSERCHROME
NS_DECL_NSIWEBBROWSERCHROME2
@ -166,14 +170,13 @@ public:
NS_DECL_NSIWINDOWPROVIDER
NS_DECL_NSIDIALOGCREATOR
NS_DECL_NSITABCHILD
NS_DECL_NSIOBSERVER
virtual bool RecvLoadURL(const nsCString& uri);
virtual bool RecvShow(const nsIntSize& size);
virtual bool RecvUpdateDimensions(const nsRect& rect, const nsIntSize& size);
virtual bool RecvUpdateFrame(const nsIntRect& aDisplayPort,
const nsIntPoint& aScrollOffset,
const gfxSize& aResolution,
const nsIntRect& aScreenSize);
virtual bool RecvUpdateFrame(const mozilla::layers::FrameMetrics& aFrameMetrics);
virtual bool RecvHandleDoubleTap(const nsIntPoint& aPoint);
virtual bool RecvActivate();
virtual bool RecvDeactivate();
virtual bool RecvMouseEvent(const nsString& aType,
@ -287,6 +290,14 @@ private:
// Call RecvShow(nsIntSize(0, 0)) and block future calls to RecvShow().
void DoFakeShow();
// Wraps up a JSON object as a structured clone and sends it to the browser
// chrome script.
//
// XXX/bug 780335: Do the work the browser chrome script does in C++ instead
// so we don't need things like this.
void DispatchMessageManagerMessage(const nsAString& aMessageName,
const nsACString& aJSONData);
nsresult
BrowserFrameProvideWindow(nsIDOMWindow* aOpener,
nsIURI* aURI,

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

@ -11,6 +11,7 @@
#include "Blob.h"
#include "IDBFactory.h"
#include "IndexedDBParent.h"
#include "mozIApplication.h"
#include "mozilla/BrowserElementParent.h"
#include "mozilla/docshell/OfflineCacheUpdateParent.h"
#include "mozilla/dom/ContentParent.h"
@ -27,6 +28,7 @@
#include "nsFocusManager.h"
#include "nsFrameLoader.h"
#include "nsIContent.h"
#include "nsIDOMApplicationRegistry.h"
#include "nsIDOMElement.h"
#include "nsIDOMEvent.h"
#include "nsIDOMEventTarget.h"
@ -36,6 +38,7 @@
#include "nsIPromptFactory.h"
#include "nsIURI.h"
#include "nsIMozBrowserFrame.h"
#include "nsIScriptSecurityManager.h"
#include "nsIViewManager.h"
#include "nsIWidget.h"
#include "nsIWindowWatcher.h"
@ -52,6 +55,7 @@ using namespace mozilla::dom;
using namespace mozilla::ipc;
using namespace mozilla::layers;
using namespace mozilla::layout;
using namespace mozilla::services;
using namespace mozilla::widget;
using namespace mozilla::dom::indexedDB;
@ -66,8 +70,9 @@ TabParent *TabParent::mIMETabParent = nullptr;
NS_IMPL_ISUPPORTS3(TabParent, nsITabParent, nsIAuthPromptProvider, nsISecureBrowserUI)
TabParent::TabParent()
TabParent::TabParent(mozIApplication* aApp, bool aIsBrowserElement)
: mFrameElement(NULL)
, mApp(aApp)
, mIMESelectionAnchor(0)
, mIMESelectionFocus(0)
, mIMEComposing(false)
@ -76,6 +81,7 @@ TabParent::TabParent()
, mIMESeqno(0)
, mDPI(0)
, mActive(false)
, mIsBrowserElement(aIsBrowserElement)
, mShown(false)
{
}
@ -225,10 +231,12 @@ TabParent::UpdateDimensions(const nsRect& rect, const nsIntSize& size)
void
TabParent::UpdateFrame(const FrameMetrics& aFrameMetrics)
{
unused << SendUpdateFrame(aFrameMetrics.mDisplayPort,
aFrameMetrics.mViewportScrollOffset,
aFrameMetrics.mResolution,
aFrameMetrics.mViewport);
unused << SendUpdateFrame(aFrameMetrics);
}
void TabParent::HandleDoubleTap(const nsIntPoint& aPoint)
{
unused << SendHandleDoubleTap(aPoint);
}
void
@ -1090,5 +1098,23 @@ TabParent::RecvBrowserFrameOpenWindow(PBrowserParent* aOpener,
return true;
}
bool
TabParent::RecvNotifyDOMTouchListenerAdded()
{
if (RenderFrameParent* rfp = GetRenderFrame()) {
rfp->NotifyDOMTouchListenerAdded();
}
return true;
}
bool
TabParent::RecvZoomToRect(const gfxRect& aRect)
{
if (RenderFrameParent* rfp = GetRenderFrame()) {
rfp->ZoomToRect(aRect);
}
return true;
}
} // namespace tabs
} // namespace mozilla

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

@ -24,6 +24,7 @@
struct gfxMatrix;
struct JSContext;
struct JSObject;
class mozIApplication;
class nsFrameLoader;
class nsIDOMElement;
class nsIURI;
@ -53,7 +54,7 @@ class TabParent : public PBrowserParent
typedef mozilla::dom::ClonedMessageData ClonedMessageData;
public:
TabParent();
TabParent(mozIApplication* aApp, bool aIsBrowserElement);
virtual ~TabParent();
nsIDOMElement* GetOwnerElement() { return mFrameElement; }
void SetOwnerElement(nsIDOMElement* aElement);
@ -62,6 +63,9 @@ public:
mBrowserDOMWindow = aBrowserDOMWindow;
}
mozIApplication* GetApp() { return mApp; }
bool IsBrowserElement() { return mIsBrowserElement; }
void Destroy();
virtual bool RecvMoveFocus(const bool& aForward);
@ -101,6 +105,8 @@ public:
virtual bool RecvSetBackgroundColor(const nscolor& aValue);
virtual bool RecvGetDPI(float* aValue);
virtual bool RecvGetWidgetNativeData(WindowsHandle* aValue);
virtual bool RecvNotifyDOMTouchListenerAdded();
virtual bool RecvZoomToRect(const gfxRect& aRect);
virtual PContentDialogParent* AllocPContentDialog(const PRUint32& aType,
const nsCString& aName,
const nsCString& aFeatures,
@ -120,6 +126,7 @@ public:
void Show(const nsIntSize& size);
void UpdateDimensions(const nsRect& rect, const nsIntSize& size);
void UpdateFrame(const layers::FrameMetrics& aFrameMetrics);
void HandleDoubleTap(const nsIntPoint& aPoint);
void Activate();
void Deactivate();
@ -224,6 +231,7 @@ protected:
uint64_t* aLayersId) MOZ_OVERRIDE;
virtual bool DeallocPRenderFrame(PRenderFrameParent* aFrame) MOZ_OVERRIDE;
nsCOMPtr<mozIApplication> mApp;
// IME
static TabParent *mIMETabParent;
nsString mIMECacheText;
@ -239,6 +247,7 @@ protected:
float mDPI;
bool mActive;
bool mIsBrowserElement;
bool mShown;
private:

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

@ -24,21 +24,21 @@ NS_IMPL_ISUPPORTS1(AlertServiceObserver, nsIObserver)
/* nsDesktopNotification */
/* ------------------------------------------------------------------------ */
void
nsresult
nsDOMDesktopNotification::PostDesktopNotification()
{
nsCOMPtr<nsIAlertsService> alerts = do_GetService("@mozilla.org/alerts-service;1");
if (!alerts)
return;
return NS_ERROR_NOT_IMPLEMENTED;
if (!mObserver)
mObserver = new AlertServiceObserver(this);
alerts->ShowAlertNotification(mIconURL, mTitle, mDescription,
true,
EmptyString(),
mObserver,
EmptyString());
return alerts->ShowAlertNotification(mIconURL, mTitle, mDescription,
true,
EmptyString(),
mObserver,
EmptyString());
}
DOMCI_DATA(DesktopNotification, nsDOMDesktopNotification)
@ -145,14 +145,16 @@ nsDOMDesktopNotification::DispatchNotificationEvent(const nsString& aName)
}
}
void
nsresult
nsDOMDesktopNotification::SetAllow(bool aAllow)
{
mAllow = aAllow;
// if we have called Show() already, lets go ahead and post a notification
if (mShowHasBeenCalled && aAllow)
PostDesktopNotification();
return PostDesktopNotification();
return NS_OK;
}
void
@ -176,8 +178,7 @@ nsDOMDesktopNotification::Show()
if (!mAllow)
return NS_OK;
PostDesktopNotification();
return NS_OK;
return PostDesktopNotification();
}
NS_IMETHODIMP
@ -277,17 +278,17 @@ nsDesktopNotificationRequest::GetElement(nsIDOMElement * *aElement)
NS_IMETHODIMP
nsDesktopNotificationRequest::Cancel()
{
mDesktopNotification->SetAllow(false);
nsresult rv = mDesktopNotification->SetAllow(false);
mDesktopNotification = nullptr;
return NS_OK;
return rv;
}
NS_IMETHODIMP
nsDesktopNotificationRequest::Allow()
{
mDesktopNotification->SetAllow(true);
nsresult rv = mDesktopNotification->SetAllow(true);
mDesktopNotification = nullptr;
return NS_OK;
return rv;
}
NS_IMETHODIMP

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

@ -87,9 +87,9 @@ public:
* PostDesktopNotification
* Uses alert service to display a notification
*/
void PostDesktopNotification();
nsresult PostDesktopNotification();
void SetAllow(bool aAllow);
nsresult SetAllow(bool aAllow);
/*
* Creates and dispatches a dom event of type aName

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

@ -21,16 +21,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=317448
var x = new XMLHttpRequest();
x.open("GET", document.location.href);
x.send("");
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
is(x instanceof Components.interfaces.nsIInterfaceRequestor,
true, "Must be interface requestor");
var count = {};
var interfaces = x.
var interfaces = SpecialPowers.wrap(x).
QueryInterface(Components.interfaces.nsIClassInfo).
getInterfaces(count).
map(function(id) {
return Components.interfacesByID[id].toString();
id = SpecialPowers.wrap(id);
return SpecialPowers.wrap(Components).interfacesByID[id].toString();
});
isnot(interfaces.indexOf("nsIInterfaceRequestor"), "-1",
"Must have interface requestor classinfo");

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

@ -116,9 +116,8 @@ function test5()
SimpleTest.executeSoon(function() {
// We have to focus back the originating window but we can't do that with
// .focus() or .blur() anymore.
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var fm = Components.classes["@mozilla.org/focus-manager;1"].
getService(Components.interfaces.nsIFocusManager);
var fm = SpecialPowers.wrap(Components).classes["@mozilla.org/focus-manager;1"]
.getService(Components.interfaces.nsIFocusManager);
fm.focusedWindow = window;
});
}, w, true);
@ -126,10 +125,9 @@ function test5()
function finished()
{
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch)
.setBoolPref("dom.disable_window_flip", gOldPrefValue);
SpecialPowers.wrap(Components).classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch)
.setBoolPref("dom.disable_window_flip", gOldPrefValue);
SimpleTest.finish();
}
@ -137,9 +135,8 @@ SimpleTest.waitForExplicitFinish();
// dom.disable_window_flip has to be set to true for this test.
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var prefs = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
var prefs = SpecialPowers.wrap(Components).classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
gOldPrefValue = prefs.getBoolPref("dom.disable_window_flip");
prefs.setBoolPref("dom.disable_window_flip", true);

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

@ -153,8 +153,7 @@ function popstateExpected(msg) {
}
function getColor(elem) {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var utils = document.defaultView.
var utils = SpecialPowers.wrap(document).defaultView.
QueryInterface(Components.interfaces.nsIInterfaceRequestor).
getInterface(Components.interfaces.nsIDOMWindowUtils);
return utils.getVisitedDependentComputedStyle(elem, "", "color");
@ -162,12 +161,10 @@ function getColor(elem) {
function getSHistory(theWindow)
{
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
const Ci = Components.interfaces;
var sh = theWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.sessionHistory;
var sh = SpecialPowers.wrap(theWindow.QueryInterface(Ci.nsIInterfaceRequestor))
.getInterface(Ci.nsIWebNavigation)
.sessionHistory;
if (!sh || sh == null)
throw("Couldn't get shistory for window!");
@ -176,8 +173,6 @@ function getSHistory(theWindow)
function getSHTitle(sh, offset)
{
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
if (!offset)
offset = 0;

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

@ -22,11 +22,10 @@ var iframe = document.getElementById("load-frame");
function enableJS() allowJS(true, iframe);
function disableJS() allowJS(false, iframe);
function allowJS(allow, frame) {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
frame.contentWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIDocShell)
.allowJavascript = allow;
SpecialPowers.wrap(frame.contentWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor))
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIDocShell)
.allowJavascript = allow;
}
function expectJSAllowed(allowed, testCondition, callback) {
window.ICanRunMyJS = false;

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

@ -36,10 +36,10 @@ function editDoc() {
function getSpellCheckSelection() {
var Ci = Components.interfaces;
var win = editDoc().defaultView;
var editingSession = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIEditingSession);
var editingSession = SpecialPowers.wrap(win.QueryInterface(Ci.nsIInterfaceRequestor))
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIEditingSession);
var editor = editingSession.getEditorForWindow(win);
var selcon = editor.selectionController;
return selcon.getSelection(selcon.SELECTION_SPELLCHECK);
@ -51,7 +51,6 @@ function runTest() {
}
function addWords(aLimit) {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
if (aLimit == 0) {
is(isSpellingCheckOk(), true, "All misspellings accounted for.");
SimpleTest.finish();

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

@ -20,8 +20,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=468353
var styleSheets = null;
function checkStylesheets() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
// Evidently RemoveStyleSheet is the only method in nsIEditorStyleSheets
// that would throw. RemoveOverrideStyleSheet returns NS_OK even if the
// sheet is not there
@ -43,8 +41,6 @@ function checkStylesheets() {
}
function runTest() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
const Ci = Components.interfaces;
const Cc = Components.classes;
@ -58,7 +54,7 @@ function runTest() {
editdoc.designMode='on';
// Hold the reference to the editor
editor = editframe.QueryInterface(Ci.nsIInterfaceRequestor)
editor = SpecialPowers.wrap(editframe.QueryInterface(Ci.nsIInterfaceRequestor))
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIEditingSession)
@ -77,7 +73,7 @@ function runTest() {
editdoc.body.contentEditable = true;
// Hold the reference to the editor
editor = editframe.QueryInterface(Ci.nsIInterfaceRequestor)
editor = SpecialPowers.wrap(editframe.QueryInterface(Ci.nsIInterfaceRequestor))
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIEditingSession)
@ -94,7 +90,7 @@ function runTest() {
editdoc.designMode = "off";
// Hold the reference to the editor
editor = editframe.QueryInterface(Ci.nsIInterfaceRequestor)
editor = SpecialPowers.wrap(editframe.QueryInterface(Ci.nsIInterfaceRequestor))
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIEditingSession)

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

@ -8,8 +8,6 @@
<script class="testbody" type="application/javascript">
function runTest() {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
function verifyContent(s) {
var e = document.getElementById('i1');
var doc = e.contentDocument;
@ -27,7 +25,7 @@ function runTest() {
selection.removeAllRanges();
selection.selectAllChildren(e);
selection.collapseToEnd();
doc.execCommand("paste", false, null);
SpecialPowers.wrap(doc).execCommand("paste", false, null);
return e;
}
@ -51,7 +49,7 @@ function runTest() {
range.selectNode(doc.getElementById(target_id));
selection.addRange(range);
}
doc.execCommand("copy", false, null);
SpecialPowers.wrap(doc).execCommand("copy", false, null);
return e;
}

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

@ -8,8 +8,6 @@
<script class="testbody" type="application/javascript">
function runTest() {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
function verifyContent(s) {
var e = document.getElementById('i1');
var doc = e.contentDocument;
@ -30,7 +28,7 @@ function runTest() {
selection.removeAllRanges();
selection.selectAllChildren(e);
selection.collapseToEnd();
doc.execCommand("paste", false, null);
SpecialPowers.wrap(doc).execCommand("paste", false, null);
return e;
}
@ -54,7 +52,7 @@ function runTest() {
range.selectNode(doc.getElementById(target_id));
selection.addRange(range);
}
doc.execCommand("copy", false, null);
SpecialPowers.wrap(doc).execCommand("copy", false, null);
return e;
}

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

@ -550,7 +550,8 @@ function doNextTest() {
function getLoadContext() {
const Ci = Components.interfaces;
return window.QueryInterface(Ci.nsIInterfaceRequestor)
return SpecialPowers.wrap(window)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsILoadContext);
}
@ -563,13 +564,11 @@ function runTest(test) {
} else
elem.focus();
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var trans = Components.classes["@mozilla.org/widget/transferable;1"]
.createInstance(Components.interfaces.nsITransferable);
var trans = SpecialPowers.wrap(Components).classes["@mozilla.org/widget/transferable;1"]
.createInstance(Components.interfaces.nsITransferable);
trans.init(getLoadContext());
var data = Components.classes["@mozilla.org/supports-string;1"]
.createInstance(Components.interfaces.nsISupportsString);
var data = SpecialPowers.wrap(Components).classes["@mozilla.org/supports-string;1"]
.createInstance(Components.interfaces.nsISupportsString);
data.data = test.payload;
trans.addDataFlavor("text/html");
trans.setTransferData("text/html", data, data.data.length * 2);
@ -582,14 +581,14 @@ function runTest(test) {
getSelection().collapse(elem, 0);
win = window;
}
editor = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIEditorDocShell)
.editor;
editor = SpecialPowers.wrap(win).QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIEditorDocShell)
.editor;
editor.pasteTransferable(trans);
} else {
var clipboard = Components.classes["@mozilla.org/widget/clipboard;1"]
.getService(Components.interfaces.nsIClipboard);
var clipboard = SpecialPowers.wrap(Components).classes["@mozilla.org/widget/clipboard;1"]
.getService(Components.interfaces.nsIClipboard);
clipboard.setData(trans, null, Components.interfaces.nsIClipboard.kGlobalClipboard);

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

@ -7,13 +7,14 @@
<script class="testbody" type="application/javascript">
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var utils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindowUtils);
var Cc = Components.classes;
var utils = SpecialPowers.wrap(window)
.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindowUtils);
var Cc = SpecialPowers.wrap(Components).classes;
var Ci = Components.interfaces;
function getLoadContext() {
return window.QueryInterface(Ci.nsIInterfaceRequestor)
return SpecialPowers.wrap(window)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsILoadContext);
}
@ -29,7 +30,6 @@ function runTest() {
}
function pasteInto(trans, html, target_id) {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var e = document.getElementById('i1');
var doc = e.contentDocument;
doc.designMode = "on";
@ -53,7 +53,6 @@ function runTest() {
}
function getTransferableFromClipboard(asHTML) {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var trans = Cc["@mozilla.org/widget/transferable;1"].createInstance(Ci.nsITransferable);
trans.init(getLoadContext());
if (asHTML) {
@ -67,8 +66,6 @@ function runTest() {
}
function makeTransferable(s,asHTML,target_id) {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var e = document.getElementById('i2');
var doc = e.contentDocument;
if (asHTML) {
@ -112,7 +109,6 @@ function runTest() {
}
function copyToClipBoard(s,asHTML,target_id) {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var e = document.getElementById('i2');
var doc = e.contentDocument;
if (asHTML) {
@ -132,7 +128,7 @@ function runTest() {
range.selectNode(doc.getElementById(target_id));
selection.addRange(range);
}
doc.execCommand("copy", false, null);
SpecialPowers.wrap(doc).execCommand("copy", false, null);
return e;
}

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

@ -22,8 +22,6 @@
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(runTest);
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
function runDesignModeTest(aDoc, aFocus, aNewSource)
{
aDoc.designMode = "on";
@ -83,11 +81,9 @@ var gSetFocusToIFrame = false;
function onLoadIFrame()
{
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var frameDoc = gIFrame.contentWindow.document;
var selCon = gIFrame.contentWindow.
var selCon = SpecialPowers.wrap(gIFrame).contentWindow.
QueryInterface(Components.interfaces.nsIInterfaceRequestor).
getInterface(Components.interfaces.nsIWebNavigation).
QueryInterface(Components.interfaces.nsIInterfaceRequestor).

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

@ -355,10 +355,7 @@ DrawTargetCairo::DrawSurface(SourceSurface *aSurface,
cairo_push_group(mContext);
cairo_new_path(mContext);
cairo_rectangle(mContext, 0, 0, aDest.Width(), aDest.Height());
//TODO[nrc] remove comments if test ok
//cairo_clip(mContext);
cairo_set_source(mContext, pat);
//cairo_paint(mContext);
cairo_fill(mContext);
cairo_pop_group_to_source(mContext);
} else {
@ -449,10 +446,7 @@ DrawTargetCairo::DrawSurfaceWithShadow(SourceSurface *aSurface,
cairo_push_group(mContext);
cairo_new_path(mContext);
cairo_rectangle(mContext, 0, 0, width, height);
//TODO[nrc] remove comments if test ok
//cairo_clip(mContext);
cairo_set_source(mContext, pat);
//cairo_paint(mContext);
cairo_fill(mContext);
cairo_pop_group_to_source(mContext);
} else {

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

@ -1803,7 +1803,7 @@ DrawTargetD2D::FillGlyphsManual(ScaledFontDWrite *aFont,
DWRITE_RENDERING_MODE renderMode = DWRITE_RENDERING_MODE_DEFAULT;
if (params) {
hr = aFont->mFontFace->GetRecommendedRenderingMode(
(FLOAT)aFont->mSize,
(FLOAT)aFont->GetSize(),
1.0f,
DWRITE_MEASURING_MODE_NATURAL,
params,
@ -1822,7 +1822,7 @@ DrawTargetD2D::FillGlyphsManual(ScaledFontDWrite *aFont,
case DWRITE_RENDERING_MODE_DEFAULT:
// As per DWRITE_RENDERING_MODE documentation, pick Natural for font
// sizes under 16 ppem
if (aFont->mSize < 16.0f) {
if (aFont->GetSize() < 16.0f) {
renderMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL;
} else {
renderMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;

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

@ -8,6 +8,7 @@
#include "2D.h"
#include "cairo.h"
#include "Logging.h"
namespace mozilla {
namespace gfx {
@ -87,7 +88,10 @@ GfxFormatToCairoFormat(SurfaceFormat format)
return CAIRO_FORMAT_RGB24;
case FORMAT_A8:
return CAIRO_FORMAT_A8;
case FORMAT_R5G6B5:
return CAIRO_FORMAT_RGB16_565;
default:
gfxWarning() << "Unknown image format";
return CAIRO_FORMAT_ARGB32;
}
}
@ -100,10 +104,12 @@ GfxFormatToCairoContent(SurfaceFormat format)
case FORMAT_B8G8R8A8:
return CAIRO_CONTENT_COLOR_ALPHA;
case FORMAT_B8G8R8X8:
case FORMAT_R5G6B5: //fall through
return CAIRO_CONTENT_COLOR;
case FORMAT_A8:
return CAIRO_CONTENT_ALPHA;
default:
gfxWarning() << "Unknown image format";
return CAIRO_CONTENT_COLOR_ALPHA;
}
}
@ -150,6 +156,7 @@ CairoContentToGfxFormat(cairo_content_t content)
case CAIRO_CONTENT_COLOR_ALPHA:
return FORMAT_B8G8R8A8;
case CAIRO_CONTENT_COLOR:
// BEWARE! format may be 565
return FORMAT_B8G8R8X8;
case CAIRO_CONTENT_ALPHA:
return FORMAT_A8;

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

@ -242,7 +242,7 @@ DWriteGlyphRunFromGlyphs(const GlyphBuffer &aGlyphs, ScaledFontDWrite *aFont, Au
run->bidiLevel = 0;
run->fontFace = aFont->mFontFace;
run->fontEmSize = aFont->mSize;
run->fontEmSize = aFont->GetSize();
run->glyphCount = aGlyphs.mNumGlyphs;
run->isSideways = FALSE;
}

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

@ -30,6 +30,8 @@ public:
virtual void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder);
float GetSize() { return mSize; }
#ifdef USE_SKIA
virtual SkTypeface* GetSkTypeface() { return mTypeface; }
#endif

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

@ -6,20 +6,20 @@
#ifndef MOZILLA_GFX_SCALEDFONTDWRITE_H_
#define MOZILLA_GFX_SCALEDFONTDWRITE_H_
#include "2D.h"
#include <dwrite.h>
#include "ScaledFontBase.h"
struct ID2D1GeometrySink;
namespace mozilla {
namespace gfx {
class ScaledFontDWrite : public ScaledFont
class ScaledFontDWrite : public ScaledFontBase
{
public:
ScaledFontDWrite(IDWriteFontFace *aFont, Float aSize)
: mFontFace(aFont)
, mSize(aSize)
, ScaledFontBase(aSize)
{}
virtual FontType GetType() const { return FONT_DWRITE; }
@ -29,8 +29,15 @@ public:
void CopyGlyphsToSink(const GlyphBuffer &aBuffer, ID2D1GeometrySink *aSink);
#ifdef USE_SKIA
virtual SkTypeface* GetSkTypeface()
{
MOZ_ASSERT(false, "Skia and DirectWrite do not mix");
return nullptr;
}
#endif
RefPtr<IDWriteFontFace> mFontFace;
Float mSize;
};
class GlyphRenderingOptionsDWrite : public GlyphRenderingOptions

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

@ -6,19 +6,26 @@
#include "CompositorParent.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/Constants.h"
#include "mozilla/Util.h"
#include "mozilla/XPCOM.h"
#include "mozilla/Monitor.h"
#include "mozilla/StaticPtr.h"
#include "AsyncPanZoomController.h"
#include "GestureEventListener.h"
#include "nsIThreadManager.h"
#include "nsThreadUtils.h"
#include "Layers.h"
#include "AnimationCommon.h"
using namespace mozilla::css;
namespace mozilla {
namespace layers {
const float AsyncPanZoomController::TOUCH_START_TOLERANCE = 1.0f/16.0f;
static const float EPSILON = 0.0001;
/**
@ -44,6 +51,26 @@ static const float MIN_SKATE_SPEED = 0.5f;
*/
static const float AXIS_LOCK_ANGLE = M_PI / 6.0;
/**
* Duration of a zoom to animation.
*/
static const TimeDuration ZOOM_TO_DURATION = TimeDuration::FromSeconds(0.25);
/**
* Computed time function used for sampling frames of a zoom to animation.
*/
StaticAutoPtr<ComputedTimingFunction> gComputedTimingFunction;
/**
* Maximum zoom amount, always used, even if a page asks for higher.
*/
static const double MAX_ZOOM = 8.0;
/**
* Minimum zoom amount, always used, even if a page asks for lower.
*/
static const double MIN_ZOOM = 0.125;
AsyncPanZoomController::AsyncPanZoomController(GeckoContentController* aGeckoContentController,
GestureBehavior aGestures)
: mGeckoContentController(aGeckoContentController),
@ -53,13 +80,22 @@ AsyncPanZoomController::AsyncPanZoomController(GeckoContentController* aGeckoCon
mLastSampleTime(TimeStamp::Now()),
mState(NOTHING),
mDPI(72),
mContentPainterStatus(CONTENT_IDLE)
mContentPainterStatus(CONTENT_IDLE),
mMayHaveTouchListeners(false),
mDisableNextTouchBatch(false)
{
if (aGestures == USE_GESTURE_DETECTOR) {
mGestureEventListener = new GestureEventListener(this);
}
SetDPI(mDPI);
if (!gComputedTimingFunction) {
gComputedTimingFunction = new ComputedTimingFunction();
gComputedTimingFunction->Init(
nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE));
ClearOnShutdown(&gComputedTimingFunction);
}
}
AsyncPanZoomController::~AsyncPanZoomController() {
@ -146,7 +182,7 @@ AsyncPanZoomController::HandleInputEvent(const nsInputEvent& aEvent,
nsEventStatus AsyncPanZoomController::HandleInputEvent(const InputData& aEvent) {
nsEventStatus rv = nsEventStatus_eIgnore;
if (mGestureEventListener) {
if (mGestureEventListener && !mDisableNextTouchBatch) {
nsEventStatus rv = mGestureEventListener->HandleInputEvent(aEvent);
if (rv == nsEventStatus_eConsumeNoDefault)
return rv;
@ -200,13 +236,19 @@ nsEventStatus AsyncPanZoomController::OnTouchStart(const MultiTouchInput& aEvent
PRInt32 xPos = point.x, yPos = point.y;
switch (mState) {
case ANIMATING_ZOOM:
// We just interrupted a double-tap animation, so force a redraw in case
// this touchstart is just a tap that doesn't end up triggering a redraw.
RequestContentRepaint();
ScheduleComposite();
// Fall through.
case FLING:
CancelAnimation();
// Fall through.
case NOTHING:
mX.StartTouch(xPos);
mY.StartTouch(yPos);
mState = TOUCHING;
SetState(TOUCHING);
break;
case TOUCHING:
case PANNING:
@ -222,20 +264,28 @@ nsEventStatus AsyncPanZoomController::OnTouchStart(const MultiTouchInput& aEvent
}
nsEventStatus AsyncPanZoomController::OnTouchMove(const MultiTouchInput& aEvent) {
if (mDisableNextTouchBatch) {
return nsEventStatus_eIgnore;
}
switch (mState) {
case FLING:
case NOTHING:
case ANIMATING_ZOOM:
// May happen if the user double-taps and drags without lifting after the
// second tap. Ignore the move if this happens.
return nsEventStatus_eIgnore;
case TOUCHING: {
float panThreshold = 1.0f/2.0f * mDPI;
float panThreshold = TOUCH_START_TOLERANCE * mDPI;
UpdateWithTouchAtDevicePoint(aEvent);
if (PanDistance() < panThreshold) {
return nsEventStatus_eIgnore;
}
StartPanning(aEvent);
return nsEventStatus_eConsumeNoDefault;
}
@ -253,18 +303,24 @@ nsEventStatus AsyncPanZoomController::OnTouchMove(const MultiTouchInput& aEvent)
}
nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent) {
if (mDisableNextTouchBatch) {
mDisableNextTouchBatch = false;
return nsEventStatus_eIgnore;
}
switch (mState) {
case FLING:
// Should never happen.
NS_WARNING("Received impossible touch end in OnTouchEnd.");
// Fall through.
case ANIMATING_ZOOM:
case NOTHING:
// May happen if the user double-taps and drags without lifting after the
// second tap. Ignore if this happens.
return nsEventStatus_eIgnore;
case TOUCHING:
mState = NOTHING;
SetState(NOTHING);
return nsEventStatus_eIgnore;
case PANNING:
@ -273,10 +329,10 @@ nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent)
ScheduleComposite();
RequestContentRepaint();
}
mState = FLING;
SetState(FLING);
return nsEventStatus_eConsumeNoDefault;
case PINCHING:
mState = NOTHING;
SetState(NOTHING);
// Scale gesture listener should have handled this.
NS_WARNING("Gesture listener should have handled pinching in OnTouchEnd.");
return nsEventStatus_eIgnore;
@ -286,12 +342,12 @@ nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent)
}
nsEventStatus AsyncPanZoomController::OnTouchCancel(const MultiTouchInput& aEvent) {
mState = NOTHING;
SetState(NOTHING);
return nsEventStatus_eConsumeNoDefault;
}
nsEventStatus AsyncPanZoomController::OnScaleBegin(const PinchGestureInput& aEvent) {
mState = PINCHING;
SetState(PINCHING);
mLastZoomFocus = aEvent.mFocusPoint;
return nsEventStatus_eConsumeNoDefault;
@ -329,14 +385,14 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
PRInt32 neededDisplacementX = 0, neededDisplacementY = 0;
// Only do the scaling if we won't go over 8x zoom in or out.
bool doScale = (scale < 8.0f && spanRatio > 1.0f) || (scale > 0.125f && spanRatio < 1.0f);
bool doScale = (scale < MAX_ZOOM && spanRatio > 1.0f) || (scale > MIN_ZOOM && spanRatio < 1.0f);
// If this zoom will take it over 8x zoom in either direction, but it's not
// already there, then normalize it.
if (scale * spanRatio > 8.0f) {
spanRatio = scale / 8.0f;
} else if (scale * spanRatio < 0.125f) {
spanRatio = scale / 0.125f;
if (scale * spanRatio > MAX_ZOOM) {
spanRatio = scale / MAX_ZOOM;
} else if (scale * spanRatio < MIN_ZOOM) {
spanRatio = scale / MIN_ZOOM;
}
if (doScale) {
@ -393,7 +449,7 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
}
nsEventStatus AsyncPanZoomController::OnScaleEnd(const PinchGestureInput& aEvent) {
mState = PANNING;
SetState(PANNING);
mX.StartTouch(aEvent.mFocusPoint.x);
mY.StartTouch(aEvent.mFocusPoint.y);
{
@ -421,7 +477,15 @@ nsEventStatus AsyncPanZoomController::OnSingleTapConfirmed(const TapGestureInput
}
nsEventStatus AsyncPanZoomController::OnDoubleTap(const TapGestureInput& aEvent) {
// XXX: Implement this.
if (mGeckoContentController) {
MonitorAutoLock monitor(mMonitor);
gfx::Point point = WidgetSpaceToCompensatedViewportSpace(
gfx::Point(aEvent.mPoint.x, aEvent.mPoint.y),
mFrameMetrics.mResolution.width);
mGeckoContentController->HandleDoubleTap(nsIntPoint(NS_lround(point.x), NS_lround(point.y)));
return nsEventStatus_eConsumeNoDefault;
}
return nsEventStatus_eIgnore;
}
@ -431,14 +495,12 @@ nsEventStatus AsyncPanZoomController::OnCancelTap(const TapGestureInput& aEvent)
}
float AsyncPanZoomController::PanDistance() {
return NS_hypot(mX.PanDistance(), mY.PanDistance()) * mFrameMetrics.mResolution.width;
MonitorAutoLock monitor(mMonitor);
return NS_hypot(mX.PanDistance(), mY.PanDistance());
}
const nsPoint AsyncPanZoomController::GetVelocityVector() {
return nsPoint(
mX.GetVelocity(),
mY.GetVelocity()
);
const gfx::Point AsyncPanZoomController::GetVelocityVector() {
return gfx::Point(mX.GetVelocity(), mY.GetVelocity());
}
void AsyncPanZoomController::StartPanning(const MultiTouchInput& aEvent) {
@ -452,7 +514,7 @@ void AsyncPanZoomController::StartPanning(const MultiTouchInput& aEvent) {
mX.StartTouch(touch.mScreenPoint.x);
mY.StartTouch(touch.mScreenPoint.y);
mState = PANNING;
SetState(PANNING);
if (angle < AXIS_LOCK_ANGLE || angle > (M_PI - AXIS_LOCK_ANGLE)) {
mY.LockPanning();
@ -559,7 +621,7 @@ void AsyncPanZoomController::SetPageRect(const gfx::Rect& aCSSPageRect) {
float scale = mFrameMetrics.mResolution.width;
// The page rect is the css page rect scaled by the current zoom.
pageSize.ScaleRoundOut(scale);
pageSize.ScaleRoundOut(1 / scale);
// Round the page rect so we don't get any truncation, then get the nsIntRect
// from this.
@ -573,7 +635,8 @@ void AsyncPanZoomController::ScaleWithFocus(float aScale, const nsIntPoint& aFoc
FrameMetrics metrics(mFrameMetrics);
// Don't set the scale to the inputted value, but rather multiply it in.
float scaleFactor = aScale / metrics.mResolution.width;
float scaleFactor = aScale / metrics.mResolution.width,
oldScale = metrics.mResolution.width;
metrics.mResolution.width = metrics.mResolution.height = aScale;
@ -583,21 +646,38 @@ void AsyncPanZoomController::ScaleWithFocus(float aScale, const nsIntPoint& aFoc
nsIntPoint scrollOffset = metrics.mViewportScrollOffset;
scrollOffset.x += aFocus.x * (scaleFactor - 1.0f);
scrollOffset.y += aFocus.y * (scaleFactor - 1.0f);
scrollOffset.x += NS_lround(float(aFocus.x) * (scaleFactor - 1.0f) / oldScale);
scrollOffset.y += NS_lround(float(aFocus.y) * (scaleFactor - 1.0f) / oldScale);
metrics.mViewportScrollOffset = scrollOffset;
mFrameMetrics = metrics;
}
bool AsyncPanZoomController::EnlargeDisplayPortAlongAxis(float aViewport,
float aVelocity,
float* aDisplayPortOffset,
float* aDisplayPortLength)
{
const float MIN_SKATE_SIZE_MULTIPLIER = 2.0f;
const float MAX_SKATE_SIZE_MULTIPLIER = 4.0f;
if (fabsf(aVelocity) > MIN_SKATE_SPEED) {
*aDisplayPortLength = aViewport * clamped(fabsf(aVelocity),
MIN_SKATE_SIZE_MULTIPLIER, MAX_SKATE_SIZE_MULTIPLIER);
*aDisplayPortOffset = aVelocity > 0 ? 0 : aViewport - *aDisplayPortLength;
return true;
}
return false;
}
const nsIntRect AsyncPanZoomController::CalculatePendingDisplayPort() {
float scale = mFrameMetrics.mResolution.width;
nsIntRect viewport = mFrameMetrics.mViewport;
viewport.ScaleRoundIn(1 / scale);
nsIntPoint scrollOffset = mFrameMetrics.mViewportScrollOffset;
nsPoint velocity = GetVelocityVector();
gfx::Point velocity = GetVelocityVector();
// The displayport is relative to the current scroll offset. Here's a little
// diagram to make it easier to see:
@ -624,28 +704,25 @@ const nsIntRect AsyncPanZoomController::CalculatePendingDisplayPort() {
// and far top, it is clear that this distance is 1/4 of the displayport's
// height/width dimension.
const float STATIONARY_SIZE_MULTIPLIER = 2.0f;
const float SKATE_SIZE_MULTIPLIER = 3.0f;
gfx::Rect displayPort(0, 0,
viewport.width * STATIONARY_SIZE_MULTIPLIER,
viewport.height * STATIONARY_SIZE_MULTIPLIER);
// Iff there's motion along only one axis of movement, and it's above a
// threshold, then we want to paint a larger area in the direction of that
// motion so that it's less likely to checkerboard. Also note that the other
// axis doesn't need its displayport enlarged beyond the viewport dimension,
// since it is impossible for it to checkerboard along that axis until motion
// begins on it.
if (fabsf(velocity.x) > MIN_SKATE_SPEED && fabsf(velocity.y) < MIN_SKATE_SPEED) {
displayPort.height = viewport.height;
displayPort.width = viewport.width * SKATE_SIZE_MULTIPLIER;
displayPort.x = velocity.x > 0 ? 0 : viewport.width - displayPort.width;
} else if (fabsf(velocity.x) < MIN_SKATE_SPEED && fabsf(velocity.y) > MIN_SKATE_SPEED) {
displayPort.width = viewport.width;
displayPort.height = viewport.height * SKATE_SIZE_MULTIPLIER;
displayPort.y = velocity.y > 0 ? 0 : viewport.height - displayPort.height;
} else {
// If there's motion along an axis of movement, and it's above a threshold,
// then we want to paint a larger area in the direction of that motion so that
// it's less likely to checkerboard.
bool enlargedX = EnlargeDisplayPortAlongAxis(
viewport.width, velocity.x, &displayPort.x, &displayPort.width);
bool enlargedY = EnlargeDisplayPortAlongAxis(
viewport.height, velocity.y, &displayPort.y, &displayPort.height);
if (!enlargedX && !enlargedY) {
displayPort.x = -displayPort.width / 4;
displayPort.y = -displayPort.height / 4;
} else if (!enlargedX) {
displayPort.width = viewport.width;
} else if (!enlargedY) {
displayPort.height = viewport.height;
}
gfx::Rect shiftedDisplayPort = displayPort;
@ -663,6 +740,10 @@ void AsyncPanZoomController::SetDPI(int aDPI) {
mDPI = aDPI;
}
int AsyncPanZoomController::GetDPI() {
return mDPI;
}
void AsyncPanZoomController::ScheduleComposite() {
if (mCompositorParent) {
mCompositorParent->ScheduleRenderOnCompositorThread();
@ -716,9 +797,43 @@ bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSa
{
MonitorAutoLock mon(mMonitor);
// If a fling is currently happening, apply it now. We can pull the updated
// metrics afterwards.
requestAnimationFrame = requestAnimationFrame || DoFling(aSampleTime - mLastSampleTime);
switch (mState)
{
case FLING:
// If a fling is currently happening, apply it now. We can pull the updated
// metrics afterwards.
requestAnimationFrame |= DoFling(aSampleTime - mLastSampleTime);
break;
case ANIMATING_ZOOM: {
double animPosition = (aSampleTime - mAnimationStartTime) / ZOOM_TO_DURATION;
if (animPosition > 1.0) {
animPosition = 1.0;
}
double sampledPosition = gComputedTimingFunction->GetValue(animPosition);
mFrameMetrics.mResolution.width = mFrameMetrics.mResolution.height =
mEndZoomToMetrics.mResolution.width * sampledPosition +
mStartZoomToMetrics.mResolution.width * (1 - sampledPosition);
mFrameMetrics.mViewportScrollOffset = nsIntPoint(
mEndZoomToMetrics.mViewportScrollOffset.x * sampledPosition +
mStartZoomToMetrics.mViewportScrollOffset.x * (1 - sampledPosition),
mEndZoomToMetrics.mViewportScrollOffset.y * sampledPosition +
mStartZoomToMetrics.mViewportScrollOffset.y * (1 - sampledPosition)
);
requestAnimationFrame = true;
if (aSampleTime - mAnimationStartTime >= ZOOM_TO_DURATION) {
mState = NOTHING;
RequestContentRepaint();
}
break;
}
default:
break;
}
// Current local transform; this is not what's painted but rather what PZC has
// transformed due to touches like panning or pinching. Eventually, the root
@ -784,7 +899,11 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aViewportFr
// we get a larger displayport. This is very bad because we're wasting a
// paint and not initializating the displayport correctly.
RequestContentRepaint();
} else if (!mFrameMetrics.mContentRect.IsEqualEdges(aViewportFrame.mContentRect)) {
// Assuming a first paint means a new page has been loaded, clear the flag
// indicating that we may have touch listeners.
mMayHaveTouchListeners = false;
} else if (!mFrameMetrics.mCSSContentRect.IsEqualEdges(aViewportFrame.mCSSContentRect)) {
mFrameMetrics.mCSSContentRect = aViewportFrame.mCSSContentRect;
SetPageRect(mFrameMetrics.mCSSContentRect);
}
@ -802,5 +921,95 @@ void AsyncPanZoomController::UpdateViewportSize(int aWidth, int aHeight) {
mFrameMetrics = metrics;
}
void AsyncPanZoomController::NotifyDOMTouchListenerAdded() {
mMayHaveTouchListeners = true;
}
void AsyncPanZoomController::CancelDefaultPanZoom() {
mDisableNextTouchBatch = true;
if (mGestureEventListener) {
mGestureEventListener->CancelGesture();
}
}
void AsyncPanZoomController::ZoomToRect(const gfxRect& aRect) {
gfx::Rect zoomToRect(gfx::Rect(aRect.x, aRect.y, aRect.width, aRect.height));
gfx::Rect cssPageRect = mFrameMetrics.mCSSContentRect;
SetState(ANIMATING_ZOOM);
{
MonitorAutoLock mon(mMonitor);
nsIntRect viewport = mFrameMetrics.mViewport;
// If the rect is empty, treat it as a request to zoom out to the full page
// size.
if (zoomToRect.IsEmpty()) {
nsIntRect cssViewport = viewport;
cssViewport.ScaleRoundIn(1 / mFrameMetrics.mResolution.width);
cssViewport.MoveBy(mFrameMetrics.mViewportScrollOffset);
float y = mFrameMetrics.mViewportScrollOffset.y;
float newHeight = cssViewport.height * cssPageRect.width / cssViewport.width;
float dh = cssViewport.height - newHeight;
zoomToRect = gfx::Rect(0.0f,
y + dh/2,
cssPageRect.width,
y + dh/2 + newHeight);
} else {
float targetRatio = float(viewport.width) / float(viewport.height);
float rectRatio = zoomToRect.width / zoomToRect.height;
if (fabsf(targetRatio - rectRatio) < EPSILON) {
// All good, do nothing.
} else if (targetRatio < rectRatio) {
// Need to increase zoomToRect height.
float newHeight = zoomToRect.height / targetRatio;
zoomToRect.y -= (newHeight - zoomToRect.height) / 2;
zoomToRect.height = newHeight;
} else { // (targetRatio > rectRatio) {
// Need to increase zoomToRect width.
float newWidth = targetRatio * zoomToRect.width;
zoomToRect.x -= (newWidth - zoomToRect.width) / 2;
zoomToRect.width = newWidth;
}
zoomToRect = zoomToRect.Intersect(cssPageRect);
}
mEndZoomToMetrics.mResolution.width = mEndZoomToMetrics.mResolution.height =
NS_MIN(viewport.width / zoomToRect.width, viewport.height / zoomToRect.height);
mEndZoomToMetrics.mResolution.width = mEndZoomToMetrics.mResolution.height =
clamped(mEndZoomToMetrics.mResolution.width, MIN_ZOOM, MAX_ZOOM);
// Recalculate the zoom to rect using the new dimensions.
zoomToRect.width = viewport.width / mEndZoomToMetrics.mResolution.width;
zoomToRect.height = viewport.height / mEndZoomToMetrics.mResolution.height;
// Clamp the zoom to rect to the CSS rect to make sure it fits.
zoomToRect = zoomToRect.Intersect(cssPageRect);
// Do one final recalculation to get the resolution.
mEndZoomToMetrics.mResolution.width = mEndZoomToMetrics.mResolution.height =
NS_MAX(viewport.width / zoomToRect.width, viewport.height / zoomToRect.height);
mStartZoomToMetrics = mFrameMetrics;
mEndZoomToMetrics.mViewportScrollOffset =
nsIntPoint(NS_lround(zoomToRect.x), NS_lround(zoomToRect.y));
mAnimationStartTime = TimeStamp::Now();
ScheduleComposite();
}
}
void AsyncPanZoomController::SetState(PanZoomState aState) {
MonitorAutoLock monitor(mMonitor);
mState = aState;
}
}
}

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

@ -57,6 +57,14 @@ public:
USE_GESTURE_DETECTOR
};
/**
* Constant describing the tolerance in distance we use, multiplied by the
* device DPI, before we start panning the screen. This is to prevent us from
* accidentally processing taps as touch moves, and from very short/accidental
* touches moving the screen.
*/
static const float TOUCH_START_TOLERANCE;
AsyncPanZoomController(GeckoContentController* aController,
GestureBehavior aGestures = DEFAULT_GESTURES);
~AsyncPanZoomController();
@ -99,6 +107,33 @@ public:
*/
void UpdateViewportSize(int aWidth, int aHeight);
/**
* A DOM touch listener has been added. When called, we enable the machinery
* that allows touch listeners to preventDefault any touch inputs. This should
* not be called unless there are actually touch listeners as it introduces
* potentially unbounded lag because it causes a round-trip through content.
* Usually, if content is responding in a timely fashion, this only introduces
* a nearly constant few hundred ms of lag.
*/
void NotifyDOMTouchListenerAdded();
/**
* We have found a scrollable subframe, so disable our machinery until we hit
* a touch end or a new touch start. This prevents us from accidentally
* panning both the subframe and the parent frame.
*
* XXX/bug 775452: We should eventually be supporting async scrollable
* subframes.
*/
void CancelDefaultPanZoom();
/**
* Kicks an animation to zoom to a rect. This may be either a zoom out or zoom
* in. The actual animation is done on the compositor thread after being set
* up. |aRect| must be given in CSS pixels, relative to the document.
*/
void ZoomToRect(const gfxRect& aRect);
// --------------------------------------------------------------------------
// These methods must only be called on the compositor thread.
//
@ -152,6 +187,12 @@ public:
*/
void SetDPI(int aDPI);
/**
* Gets the DPI of the device for use outside the panning and zooming logic.
* It defaults to 72 if not set using SetDPI() at any point.
*/
int GetDPI();
protected:
/**
* Helper method for touches beginning. Sets everything up for panning and any
@ -255,6 +296,8 @@ protected:
* Cancels any currently running animation. Note that all this does is set the
* state of the AsyncPanZoomController back to NOTHING, but it is the
* animation's responsibility to check this before advancing.
*
* *** The monitor must be held while calling this.
*/
void CancelAnimation();
@ -269,7 +312,7 @@ protected:
/**
* Gets a vector of the velocities of each axis.
*/
const nsPoint GetVelocityVector();
const gfx::Point GetVelocityVector();
/**
* Gets a reference to the first SingleTouchData from a MultiTouchInput. This
@ -304,6 +347,17 @@ protected:
*/
const nsIntRect CalculatePendingDisplayPort();
/**
* Attempts to enlarge the displayport along a single axis. Returns whether or
* not the displayport was enlarged. This will fail in circumstances where the
* velocity along that axis is not high enough to need any changes. The
* displayport metrics are expected to be passed into |aDisplayPortOffset| and
* |aDisplayPortLength|. If enlarged, these will be updated with the new
* metrics.
*/
bool EnlargeDisplayPortAlongAxis(float aViewport, float aVelocity,
float* aDisplayPortOffset, float* aDisplayPortLength);
/**
* Utility function to send updated FrameMetrics to Gecko so that it can paint
* the displayport area. Calls into GeckoContentController to do the actual
@ -335,6 +389,7 @@ private:
TOUCHING, /* one touch-start event received */
PANNING, /* panning without axis lock */
PINCHING, /* nth touch-start, where n > 1. this mode allows pan and zoom */
ANIMATING_ZOOM /* animated zoom to a new rect */
};
enum ContentPainterStatus {
@ -356,6 +411,13 @@ private:
CONTENT_PAINTING_AND_PAINT_PENDING
};
/**
* Helper to set the current state. Holds the monitor before actually setting
* it. If the monitor is already held by the current thread, it is safe to
* instead use: |mState = NEWSTATE;|
*/
void SetState(PanZoomState aState);
nsRefPtr<CompositorParent> mCompositorParent;
nsRefPtr<GeckoContentController> mGeckoContentController;
nsRefPtr<GestureEventListener> mGestureEventListener;
@ -371,9 +433,23 @@ private:
// If we don't do this check, we don't get a ShadowLayersUpdated back.
FrameMetrics mLastPaintRequestMetrics;
// Old metrics from before we started a zoom animation. This is only valid
// when we are in the "ANIMATED_ZOOM" state. This is used so that we can
// interpolate between the start and end frames. We only use the
// |mViewportScrollOffset| and |mResolution| fields on this.
FrameMetrics mStartZoomToMetrics;
// Target metrics for a zoom to animation. This is only valid when we are in
// the "ANIMATED_ZOOM" state. We only use the |mViewportScrollOffset| and
// |mResolution| fields on this.
FrameMetrics mEndZoomToMetrics;
AxisX mX;
AxisY mY;
// Protects |mFrameMetrics|, |mLastContentPaintMetrics| and |mState|. Before
// manipulating |mFrameMetrics| or |mLastContentPaintMetrics|, the monitor
// should be held. When setting |mState|, either the SetState() function can
// be used, or the monitor can be held and then |mState| updated.
Monitor mMonitor;
// The last time the compositor has sampled the content transform for this
@ -382,10 +458,18 @@ private:
// The last time a touch event came through on the UI thread.
PRInt32 mLastEventTime;
// Start time of an animation. This is used for a zoom to animation to mark
// the beginning.
TimeStamp mAnimationStartTime;
// Stores the previous focus point if there is a pinch gesture happening. Used
// to allow panning by moving multiple fingers (thus moving the focus point).
nsIntPoint mLastZoomFocus;
// Stores the state of panning and zooming this frame. This is protected by
// |mMonitor|; that is, it should be held whenever this is updated.
PanZoomState mState;
int mDPI;
// Stores the current paint status of the frame that we're managing. Repaints
@ -394,6 +478,14 @@ private:
// requests a repaint.
ContentPainterStatus mContentPainterStatus;
// Whether or not we might have touch listeners. This is a conservative
// approximation and may not be accurate.
bool mMayHaveTouchListeners;
// Flag used to determine whether or not we should disable handling of the
// next batch of touch events. This is used for sync scrolling of subframes.
bool mDisableNextTouchBatch;
friend class Axis;
};

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

@ -23,6 +23,14 @@ public:
*/
virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) = 0;
/**
* Requests handling of a double tap. |aPoint| is in CSS pixels, relative to
* the current scroll offset. This should eventually round-trip back to
* AsyncPanZoomController::ZoomToRect with the dimensions that we want to zoom
* to.
*/
virtual void HandleDoubleTap(const nsIntPoint& aPoint) = 0;
GeckoContentController() {}
virtual ~GeckoContentController() {}
};

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

@ -63,6 +63,7 @@ nsEventStatus GestureEventListener::HandleInputEvent(const InputData& aEvent)
size_t length = mTouches.Length();
if (length == 1) {
mTapStartTime = event.mTime;
mTouchStartPosition = event.mTouches[0].mScreenPoint;
if (mState == GESTURE_NONE) {
mState = GESTURE_WAITING_SINGLE_TAP;
}
@ -74,9 +75,14 @@ nsEventStatus GestureEventListener::HandleInputEvent(const InputData& aEvent)
break;
}
case MultiTouchInput::MULTITOUCH_MOVE: {
// If we move at all, just bail out of the tap. We need to change this so
// that there's some tolerance in the future.
HandleTapCancel(event);
// If we move too much, bail out of the tap.
nsIntPoint touch = (nsIntPoint&)event.mTouches[0].mScreenPoint;
if (mTouches.Length() == 1 &&
NS_hypot(mTouchStartPosition.x - touch.x, mTouchStartPosition.y - touch.y) >
mAsyncPanZoomController->GetDPI() * AsyncPanZoomController::TOUCH_START_TOLERANCE)
{
HandleTapCancel(event);
}
bool foundAlreadyExistingTouch = false;
for (size_t i = 0; i < mTouches.Length(); i++) {
@ -260,5 +266,10 @@ AsyncPanZoomController* GestureEventListener::GetAsyncPanZoomController() {
return mAsyncPanZoomController;
}
void GestureEventListener::CancelGesture() {
mTouches.Clear();
mState = GESTURE_NONE;
}
}
}

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

@ -1,7 +1,4 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=4 ts=8 et tw=80 : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set sw=4 ts=8 et tw=80 : */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_layers_GestureEventListener_h
@ -47,6 +44,13 @@ public:
*/
nsEventStatus HandleInputEvent(const InputData& aEvent);
/**
* Cancels any currently active gesture. May not properly handle situations
* that require extra work at the gesture's end, like a pinch which only
* requests a repaint once it has ended.
*/
void CancelGesture();
/**
* Returns the AsyncPanZoomController stored on this class and used for
* callbacks.
@ -163,6 +167,13 @@ protected:
* we can cancel it if a double tap actually comes in.
*/
CancelableTask *mDoubleTapTimeoutTask;
/**
* Position of the last touch starting. This is only valid during an attempt
* to determine if a touch is a tap. This means that it is used in both the
* "GESTURE_WAITING_SINGLE_TAP" and "GESTURE_WAITING_DOUBLE_TAP" states.
*/
nsIntPoint mTouchStartPosition;
};
}

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

@ -9,7 +9,6 @@
#define IPC_ShadowLayerUtils_h
#include "IPC/IPCMessageUtils.h"
#include "FrameMetrics.h"
#include "GLContext.h"
#include "mozilla/WidgetUtils.h"
@ -39,34 +38,6 @@ struct MagicGrallocBufferHandle {
namespace IPC {
template <>
struct ParamTraits<mozilla::layers::FrameMetrics>
{
typedef mozilla::layers::FrameMetrics paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, aParam.mCSSContentRect);
WriteParam(aMsg, aParam.mViewport);
WriteParam(aMsg, aParam.mContentRect);
WriteParam(aMsg, aParam.mViewportScrollOffset);
WriteParam(aMsg, aParam.mDisplayPort);
WriteParam(aMsg, aParam.mScrollId);
WriteParam(aMsg, aParam.mResolution);
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
return (ReadParam(aMsg, aIter, &aResult->mCSSContentRect) &&
ReadParam(aMsg, aIter, &aResult->mViewport) &&
ReadParam(aMsg, aIter, &aResult->mContentRect) &&
ReadParam(aMsg, aIter, &aResult->mViewportScrollOffset) &&
ReadParam(aMsg, aIter, &aResult->mDisplayPort) &&
ReadParam(aMsg, aIter, &aResult->mScrollId) &&
ReadParam(aMsg, aIter, &aResult->mResolution));
}
};
#if !defined(MOZ_HAVE_SURFACEDESCRIPTORX11)
template <>
struct ParamTraits<mozilla::layers::SurfaceDescriptorX11> {

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

@ -20,16 +20,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=627498
// Make sure that acceleration is enabled/disabled the way we expect it to be
// based on platform.
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var importObj = {};
Components.utils.import("resource://gre/modules/Services.jsm");
var Cc = Components.classes;
var Cc = SpecialPowers.wrap(Components).classes;
var Ci = Components.interfaces;
var sysInfo = Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2);
var windows = Services.ww.getWindowEnumerator();
var windows = SpecialPowers.Services.ww.getWindowEnumerator();
var windowutils;
var acceleratedWindows = 0;
while (windows.hasMoreElements()) {

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

@ -779,10 +779,15 @@ gfxWindowsPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
NativeFont nativeFont;
nativeFont.mType = NATIVE_FONT_DWRITE_FONT_FACE;
nativeFont.mFont = font->GetFontFace();
RefPtr<ScaledFont> scaledFont =
mozilla::gfx::Factory::CreateScaledFontForNativeFont(nativeFont, font->GetAdjustedSize());
return scaledFont;
if (aTarget->GetType() == BACKEND_CAIRO) {
return Factory::CreateScaledFontWithCairo(nativeFont,
font->GetAdjustedSize(),
font->GetCairoScaledFont());
}
return Factory::CreateScaledFontForNativeFont(nativeFont,
font->GetAdjustedSize());
}
NS_ASSERTION(aFont->GetType() == gfxFont::FONT_TYPE_GDI,

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

@ -23,11 +23,13 @@
#include "gfxMatrix.h"
#include "gfxPattern.h"
#include "gfxPoint.h"
#include "gfxRect.h"
#include "nsRect.h"
#include "nsRegion.h"
#include "gfxASurface.h"
#include "jsapi.h"
#include "LayersTypes.h"
#include "FrameMetrics.h"
#ifdef _MSC_VER
#pragma warning( disable : 4800 )
@ -517,6 +519,28 @@ struct ParamTraits<gfxSize>
}
};
template<>
struct ParamTraits<gfxRect>
{
typedef gfxRect paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, aParam.x);
WriteParam(aMsg, aParam.y);
WriteParam(aMsg, aParam.width);
WriteParam(aMsg, aParam.height);
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
return ReadParam(aMsg, aIter, &aResult->x) &&
ReadParam(aMsg, aIter, &aResult->y) &&
ReadParam(aMsg, aIter, &aResult->width) &&
ReadParam(aMsg, aIter, &aResult->height);
}
};
template<>
struct ParamTraits<gfx3DMatrix>
{
@ -902,6 +926,34 @@ struct ParamTraits<mozilla::SerializedStructuredCloneBuffer>
}
};
template <>
struct ParamTraits<mozilla::layers::FrameMetrics>
{
typedef mozilla::layers::FrameMetrics paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, aParam.mCSSContentRect);
WriteParam(aMsg, aParam.mViewport);
WriteParam(aMsg, aParam.mContentRect);
WriteParam(aMsg, aParam.mViewportScrollOffset);
WriteParam(aMsg, aParam.mDisplayPort);
WriteParam(aMsg, aParam.mScrollId);
WriteParam(aMsg, aParam.mResolution);
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
return (ReadParam(aMsg, aIter, &aResult->mCSSContentRect) &&
ReadParam(aMsg, aIter, &aResult->mViewport) &&
ReadParam(aMsg, aIter, &aResult->mContentRect) &&
ReadParam(aMsg, aIter, &aResult->mViewportScrollOffset) &&
ReadParam(aMsg, aIter, &aResult->mDisplayPort) &&
ReadParam(aMsg, aIter, &aResult->mScrollId) &&
ReadParam(aMsg, aIter, &aResult->mResolution));
}
};
} /* namespace IPC */
#endif /* __IPC_GLUE_IPCMESSAGEUTILS_H__ */

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

@ -17,7 +17,9 @@ include $(DEPTH)/config/autoconf.mk
MODULE = jsdebug
LIBRARY_NAME = jsd
DIRS = idl
CPPSRCS = jsd_xpc.cpp
CPPSRCS = \
jsd_xpc.cpp \
jshash.cpp
IS_COMPONENT = 1
LIBXUL_LIBRARY = 1

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

@ -61,7 +61,7 @@ static JSHashAllocOps defaultHashAllocOps = {
DefaultAllocEntry, DefaultFreeEntry
};
JS_PUBLIC_API(JSHashTable *)
JSHashTable *
JS_NewHashTable(uint32_t n, JSHashFunction keyHash,
JSHashComparator keyCompare, JSHashComparator valueCompare,
JSHashAllocOps *allocOps, void *allocPriv)
@ -101,7 +101,7 @@ JS_NewHashTable(uint32_t n, JSHashFunction keyHash,
return ht;
}
JS_PUBLIC_API(void)
void
JS_HashTableDestroy(JSHashTable *ht)
{
uint32_t i, n;
@ -133,7 +133,7 @@ JS_HashTableDestroy(JSHashTable *ht)
#define BUCKET_HEAD(ht, keyHash) \
(&(ht)->buckets[((keyHash) * JS_GOLDEN_RATIO) >> (ht)->shift])
JS_PUBLIC_API(JSHashEntry **)
JSHashEntry **
JS_HashTableRawLookup(JSHashTable *ht, JSHashNumber keyHash, const void *key)
{
JSHashEntry *he, **hep, **hep0;
@ -212,7 +212,7 @@ Resize(JSHashTable *ht, uint32_t newshift)
return JS_TRUE;
}
JS_PUBLIC_API(JSHashEntry *)
JSHashEntry *
JS_HashTableRawAdd(JSHashTable *ht, JSHashEntry **&hep,
JSHashNumber keyHash, const void *key, void *value)
{
@ -243,7 +243,7 @@ JS_HashTableRawAdd(JSHashTable *ht, JSHashEntry **&hep,
return he;
}
JS_PUBLIC_API(JSHashEntry *)
JSHashEntry *
JS_HashTableAdd(JSHashTable *ht, const void *key, void *value)
{
JSHashNumber keyHash;
@ -265,7 +265,7 @@ JS_HashTableAdd(JSHashTable *ht, const void *key, void *value)
return JS_HashTableRawAdd(ht, hep, keyHash, key, value);
}
JS_PUBLIC_API(void)
void
JS_HashTableRawRemove(JSHashTable *ht, JSHashEntry **hep, JSHashEntry *he)
{
uint32_t n;
@ -283,7 +283,7 @@ JS_HashTableRawRemove(JSHashTable *ht, JSHashEntry **hep, JSHashEntry *he)
}
}
JS_PUBLIC_API(JSBool)
JSBool
JS_HashTableRemove(JSHashTable *ht, const void *key)
{
JSHashNumber keyHash;
@ -299,7 +299,7 @@ JS_HashTableRemove(JSHashTable *ht, const void *key)
return JS_TRUE;
}
JS_PUBLIC_API(void *)
void *
JS_HashTableLookup(JSHashTable *ht, const void *key)
{
JSHashNumber keyHash;
@ -318,7 +318,7 @@ JS_HashTableLookup(JSHashTable *ht, const void *key)
** entry found. Stop if "f" says to (return value & JS_ENUMERATE_STOP).
** Return a count of the number of elements scanned.
*/
JS_PUBLIC_API(int)
int
JS_HashTableEnumerateEntries(JSHashTable *ht, JSHashEnumerator f, void *arg)
{
JSHashEntry *he, **hep, **bucket;
@ -367,7 +367,7 @@ out:
#ifdef JS_HASHMETER
#include <stdio.h>
JS_PUBLIC_API(void)
void
JS_HashTableDumpMeter(JSHashTable *ht, JSHashEnumerator dump, FILE *fp)
{
double sqsum, mean, sigma;
@ -413,7 +413,7 @@ JS_HashTableDumpMeter(JSHashTable *ht, JSHashEnumerator dump, FILE *fp)
}
#endif /* JS_HASHMETER */
JS_PUBLIC_API(int)
int
JS_HashTableDump(JSHashTable *ht, JSHashEnumerator dump, FILE *fp)
{
int count;
@ -425,7 +425,7 @@ JS_HashTableDump(JSHashTable *ht, JSHashEnumerator dump, FILE *fp)
return count;
}
JS_PUBLIC_API(JSHashNumber)
JSHashNumber
JS_HashString(const void *key)
{
JSHashNumber h;
@ -437,7 +437,7 @@ JS_HashString(const void *key)
return h;
}
JS_PUBLIC_API(int)
int
JS_CompareValues(const void *v1, const void *v2)
{
return v1 == v2;

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

@ -70,49 +70,49 @@ struct JSHashTable {
* Create a new hash table.
* If allocOps is null, use default allocator ops built on top of malloc().
*/
extern JS_PUBLIC_API(JSHashTable *)
extern JSHashTable *
JS_NewHashTable(uint32_t n, JSHashFunction keyHash,
JSHashComparator keyCompare, JSHashComparator valueCompare,
JSHashAllocOps *allocOps, void *allocPriv);
extern JS_PUBLIC_API(void)
extern void
JS_HashTableDestroy(JSHashTable *ht);
/* Low level access methods */
extern JS_PUBLIC_API(JSHashEntry **)
extern JSHashEntry **
JS_HashTableRawLookup(JSHashTable *ht, JSHashNumber keyHash, const void *key);
#ifdef __cplusplus
extern JS_PUBLIC_API(JSHashEntry *)
extern JSHashEntry *
JS_HashTableRawAdd(JSHashTable *ht, JSHashEntry **&hep, JSHashNumber keyHash,
const void *key, void *value);
#endif
extern JS_PUBLIC_API(void)
extern void
JS_HashTableRawRemove(JSHashTable *ht, JSHashEntry **hep, JSHashEntry *he);
/* Higher level access methods */
extern JS_PUBLIC_API(JSHashEntry *)
extern JSHashEntry *
JS_HashTableAdd(JSHashTable *ht, const void *key, void *value);
extern JS_PUBLIC_API(JSBool)
extern JSBool
JS_HashTableRemove(JSHashTable *ht, const void *key);
extern JS_PUBLIC_API(int)
extern int
JS_HashTableEnumerateEntries(JSHashTable *ht, JSHashEnumerator f, void *arg);
extern JS_PUBLIC_API(void *)
extern void *
JS_HashTableLookup(JSHashTable *ht, const void *key);
extern JS_PUBLIC_API(int)
extern int
JS_HashTableDump(JSHashTable *ht, JSHashEnumerator dump, FILE *fp);
/* General-purpose C string hash function. */
extern JS_PUBLIC_API(JSHashNumber)
extern JSHashNumber
JS_HashString(const void *key);
/* Stub function just returns v1 == v2 */
extern JS_PUBLIC_API(int)
extern int
JS_CompareValues(const void *v1, const void *v2);
JS_END_EXTERN_C

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

@ -82,7 +82,6 @@ CPPSRCS = \
jsfun.cpp \
jsgc.cpp \
jscrashreport.cpp \
jshash.cpp \
jsinfer.cpp \
jsinterp.cpp \
jsiter.cpp \
@ -162,7 +161,6 @@ INSTALLED_HEADERS = \
jsdhash.h \
jsfriendapi.h \
jsgc.h \
jshash.h \
jslock.h \
json.h \
jsproxy.h \

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

@ -278,8 +278,8 @@ frontend::Emit3(JSContext *cx, BytecodeEmitter *bce, JSOp op, jsbytecode op1,
jsbytecode op2)
{
/* These should filter through EmitVarOp. */
JS_ASSERT(JOF_OPTYPE(op) != JOF_QARG);
JS_ASSERT(JOF_OPTYPE(op) != JOF_LOCAL);
JS_ASSERT(!IsArgOp(op));
JS_ASSERT(!IsLocalOp(op));
ptrdiff_t offset = EmitCheck(cx, bce, 3);
@ -815,12 +815,6 @@ EmitAtomIncDec(JSContext *cx, JSAtom *atom, JSOp op, BytecodeEmitter *bce)
return true;
}
static bool
EmitFunctionOp(JSContext *cx, JSOp op, uint32_t index, BytecodeEmitter *bce)
{
return EmitIndex32(cx, op, index, bce);
}
static bool
EmitObjectOp(JSContext *cx, ObjectBox *objbox, JSOp op, BytecodeEmitter *bce)
{
@ -917,11 +911,11 @@ EmitAliasedVarOp(JSContext *cx, JSOp op, ParseNode *pn, BytecodeEmitter *bce)
}
ScopeCoordinate sc;
if (JOF_OPTYPE(pn->getOp()) == JOF_QARG) {
if (IsArgOp(pn->getOp())) {
sc.hops = skippedScopes + ClonedBlockDepth(bceOfDef);
sc.slot = bceOfDef->sc->bindings.formalIndexToSlot(pn->pn_cookie.slot());
} else {
JS_ASSERT(JOF_OPTYPE(pn->getOp()) == JOF_LOCAL || pn->isKind(PNK_FUNCTION));
JS_ASSERT(IsLocalOp(pn->getOp()) || pn->isKind(PNK_FUNCTION));
unsigned local = pn->pn_cookie.slot();
if (local < bceOfDef->sc->bindings.numVars()) {
sc.hops = skippedScopes + ClonedBlockDepth(bceOfDef);
@ -946,7 +940,7 @@ static bool
EmitVarOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce)
{
JS_ASSERT(pn->isKind(PNK_FUNCTION) || pn->isKind(PNK_NAME));
JS_ASSERT_IF(pn->isKind(PNK_NAME), JOF_OPTYPE(op) == JOF_QARG || JOF_OPTYPE(op) == JOF_LOCAL);
JS_ASSERT_IF(pn->isKind(PNK_NAME), IsArgOp(op) || IsLocalOp(op));
JS_ASSERT(!pn->pn_cookie.isFree());
if (!bce->isAliasedName(pn)) {
@ -970,7 +964,7 @@ static bool
EmitVarIncDec(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce)
{
JS_ASSERT(pn->isKind(PNK_NAME));
JS_ASSERT(JOF_OPTYPE(op) == JOF_QARG || JOF_OPTYPE(op) == JOF_LOCAL);
JS_ASSERT(IsArgOp(op) || IsLocalOp(op));
JS_ASSERT(js_CodeSpec[op].format & (JOF_INC | JOF_DEC));
JS_ASSERT(!pn->pn_cookie.isFree());
@ -1034,8 +1028,7 @@ BytecodeEmitter::noteClosedVar(ParseNode *pn)
#ifdef DEBUG
JS_ASSERT(shouldNoteClosedName(pn));
Definition *dn = (Definition *)pn;
JS_ASSERT(dn->kind() == Definition::VAR || dn->kind() == Definition::CONST ||
dn->kind() == Definition::FUNCTION);
JS_ASSERT(dn->kind() == Definition::VAR || dn->kind() == Definition::CONST);
JS_ASSERT(pn->pn_cookie.slot() < sc->bindings.numVars());
for (size_t i = 0; i < closedVars.length(); ++i)
JS_ASSERT(closedVars[i] != pn->pn_cookie.slot());
@ -1211,12 +1204,14 @@ BindNameToSlot(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
{
JS_ASSERT(pn->isKind(PNK_NAME) || pn->isKind(PNK_INTRINSICNAME));
/* Don't attempt if 'pn' is already bound or deoptimized or a nop. */
JSOp op = pn->getOp();
if (pn->isBound() || pn->isDeoptimized() || op == JSOP_NOP)
JS_ASSERT_IF(pn->isKind(PNK_FUNCTION), pn->isBound());
/* Don't attempt if 'pn' is already bound or deoptimized or a function. */
if (pn->isBound() || pn->isDeoptimized())
return true;
/* JSOP_CALLEE is pre-bound by definition. */
JSOp op = pn->getOp();
JS_ASSERT(op != JSOP_CALLEE);
JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
@ -1236,8 +1231,6 @@ BindNameToSlot(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
return true;
}
JS_ASSERT_IF(dn->kind() == Definition::CONST, pn->pn_dflags & PND_CONST);
/*
* Turn attempts to mutate const-declared bindings into get ops (for
* pre-increment and pre-decrement ops, our caller will have to emit
@ -1331,9 +1324,6 @@ BindNameToSlot(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
* rewrite pn_op and update pn accordingly.
*/
switch (dn->kind()) {
case Definition::UNKNOWN:
return true;
case Definition::ARG:
switch (op) {
case JSOP_NAME: op = JSOP_GETARG; break;
@ -1348,55 +1338,6 @@ BindNameToSlot(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
break;
case Definition::VAR:
if (dn->isOp(JSOP_CALLEE)) {
JS_ASSERT(op != JSOP_CALLEE);
/*
* Currently, the ALIASEDVAR ops do not support accessing the
* callee of a DeclEnvObject, so use NAME.
*/
if (dn->pn_cookie.level() != bce->script->staticLevel)
return true;
JS_ASSERT(bce->sc->fun()->flags & JSFUN_LAMBDA);
JS_ASSERT(pn->pn_atom == bce->sc->fun()->atom);
/*
* Leave pn->isOp(JSOP_NAME) if bce->fun is heavyweight to
* address two cases: a new binding introduced by eval, and
* assignment to the name in strict mode.
*
* var fun = (function f(s) { eval(s); return f; });
* assertEq(fun("var f = 42"), 42);
*
* ECMAScript specifies that a function expression's name is bound
* in a lexical environment distinct from that used to bind its
* named parameters, the arguments object, and its variables. The
* new binding for "var f = 42" shadows the binding for the
* function itself, so the name of the function will not refer to
* the function.
*
* (function f() { "use strict"; f = 12; })();
*
* Outside strict mode, assignment to a function expression's name
* has no effect. But in strict mode, this attempt to mutate an
* immutable binding must throw a TypeError. We implement this by
* not optimizing such assignments and by marking such functions as
* heavyweight, ensuring that the function name is represented in
* the scope chain so that assignment will throw a TypeError.
*/
if (!bce->sc->funIsHeavyweight()) {
op = JSOP_CALLEE;
pn->pn_dflags |= PND_CONST;
}
pn->setOp(op);
pn->pn_dflags |= PND_BOUND;
return true;
}
/* FALL THROUGH */
case Definition::FUNCTION:
case Definition::CONST:
case Definition::LET:
switch (op) {
@ -1411,8 +1352,55 @@ BindNameToSlot(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
}
break;
default:
JS_NOT_REACHED("unexpected dn->kind()");
case Definition::NAMED_LAMBDA:
JS_ASSERT(dn->isOp(JSOP_CALLEE));
JS_ASSERT(op != JSOP_CALLEE);
/*
* Currently, the ALIASEDVAR ops do not support accessing the
* callee of a DeclEnvObject, so use NAME.
*/
if (dn->pn_cookie.level() != bce->script->staticLevel)
return true;
JS_ASSERT(bce->sc->fun()->flags & JSFUN_LAMBDA);
JS_ASSERT(pn->pn_atom == bce->sc->fun()->atom);
/*
* Leave pn->isOp(JSOP_NAME) if bce->fun is heavyweight to
* address two cases: a new binding introduced by eval, and
* assignment to the name in strict mode.
*
* var fun = (function f(s) { eval(s); return f; });
* assertEq(fun("var f = 42"), 42);
*
* ECMAScript specifies that a function expression's name is bound
* in a lexical environment distinct from that used to bind its
* named parameters, the arguments object, and its variables. The
* new binding for "var f = 42" shadows the binding for the
* function itself, so the name of the function will not refer to
* the function.
*
* (function f() { "use strict"; f = 12; })();
*
* Outside strict mode, assignment to a function expression's name
* has no effect. But in strict mode, this attempt to mutate an
* immutable binding must throw a TypeError. We implement this by
* not optimizing such assignments and by marking such functions as
* heavyweight, ensuring that the function name is represented in
* the scope chain so that assignment will throw a TypeError.
*/
if (!bce->sc->funIsHeavyweight()) {
op = JSOP_CALLEE;
pn->pn_dflags |= PND_CONST;
}
pn->setOp(op);
pn->pn_dflags |= PND_BOUND;
return true;
case Definition::PLACEHOLDER:
return true;
}
/*
@ -2697,7 +2685,7 @@ MaybeEmitVarDecl(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *
}
if (bce->sc->inFunction() &&
JOF_OPTYPE(pn->getOp()) == JOF_LOCAL &&
IsLocalOp(pn->getOp()) &&
!pn->isLet() &&
bce->shouldNoteClosedName(pn))
{
@ -4850,7 +4838,7 @@ EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
* for the already-emitted function definition prolog opcode. See
* comments in EmitStatementList.
*/
JS_ASSERT(pn->isOp(JSOP_NOP));
JS_ASSERT(pn->functionIsHoisted());
JS_ASSERT(bce->sc->inFunction());
return EmitFunctionDefNop(cx, bce, pn->pn_index);
}
@ -4893,12 +4881,12 @@ EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
/* Make the function object a literal in the outer script's pool. */
unsigned index = bce->objectList.add(pn->pn_funbox);
/* Emit a bytecode pointing to the closure object in its immediate. */
if (pn->getOp() != JSOP_NOP) {
/* Non-hoisted functions simply emit their respective op. */
if (!pn->functionIsHoisted()) {
if (pn->pn_funbox->inGenexpLambda && NewSrcNote(cx, bce, SRC_GENEXP) < 0)
return false;
return EmitFunctionOp(cx, pn->getOp(), index, bce);
return EmitIndex32(cx, pn->getOp(), index, bce);
}
/*
@ -4911,16 +4899,15 @@ EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
* definitions can be scheduled before generating the rest of code.
*/
if (!bce->sc->inFunction()) {
JS_ASSERT(!bce->topStmt);
JS_ASSERT(pn->pn_cookie.isFree());
if (pn->pn_cookie.isFree()) {
bce->switchToProlog();
if (!EmitFunctionOp(cx, JSOP_DEFFUN, index, bce))
return false;
if (!UpdateLineNumberNotes(cx, bce, pn->pn_pos.begin.lineno))
return false;
bce->switchToMain();
}
JS_ASSERT(pn->getOp() == JSOP_NOP);
JS_ASSERT(!bce->topStmt);
bce->switchToProlog();
if (!EmitIndex32(cx, JSOP_DEFFUN, index, bce))
return false;
if (!UpdateLineNumberNotes(cx, bce, pn->pn_pos.begin.lineno))
return false;
bce->switchToMain();
/* Emit NOP for the decompiler. */
if (!EmitFunctionDefNop(cx, bce, index))
@ -4928,18 +4915,29 @@ EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
} else {
#ifdef DEBUG
BindingIter bi(cx, bce->sc->bindings.lookup(cx, fun->atom->asPropertyName()));
JS_ASSERT(bi->kind == VARIABLE || bi->kind == CONSTANT);
JS_ASSERT(bi->kind == VARIABLE || bi->kind == CONSTANT || bi->kind == ARGUMENT);
JS_ASSERT(bi.frameIndex() < JS_BIT(20));
#endif
pn->pn_index = index;
if (bce->shouldNoteClosedName(pn) && !bce->noteClosedVar(pn))
return false;
if (bce->shouldNoteClosedName(pn)) {
Definition::Kind kind = ((Definition *)pn)->kind();
if (kind == Definition::ARG) {
if (!bce->noteClosedArg(pn))
return false;
} else {
JS_ASSERT(kind == Definition::VAR);
if (!bce->noteClosedVar(pn))
return false;
}
}
if (NewSrcNote(cx, bce, SRC_CONTINUE) < 0)
return false;
if (!EmitIndexOp(cx, JSOP_LAMBDA, index, bce))
return false;
if (!EmitVarOp(cx, pn, JSOP_SETLOCAL, bce))
JS_ASSERT(pn->getOp() == JSOP_GETLOCAL || pn->getOp() == JSOP_GETARG);
JSOp setOp = pn->getOp() == JSOP_GETLOCAL ? JSOP_SETLOCAL : JSOP_SETARG;
if (!EmitVarOp(cx, pn, setOp, bce))
return false;
if (Emit1(cx, bce, JSOP_POP) < 0)
return false;
@ -6069,17 +6067,9 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
// Currently this is used only for functions, as compile-as-we go
// mode for scripts does not allow separate emitter passes.
for (ParseNode *pn2 = pnchild; pn2; pn2 = pn2->pn_next) {
if (pn2->isKind(PNK_FUNCTION)) {
if (pn2->isOp(JSOP_NOP)) {
if (!EmitTree(cx, bce, pn2))
return false;
} else {
// JSOP_DEFFUN in a top-level block with function
// definitions appears, for example, when "if (true)"
// is optimized away from "if (true) function x() {}".
// See bug 428424.
JS_ASSERT(pn2->isOp(JSOP_DEFFUN));
}
if (pn2->isKind(PNK_FUNCTION) && pn2->functionIsHoisted()) {
if (!EmitTree(cx, bce, pn2))
return false;
}
}
}
@ -6130,7 +6120,7 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
continue;
if (!BindNameToSlot(cx, bce, pn2))
return false;
if (JOF_OPTYPE(pn2->getOp()) == JOF_QARG && bce->shouldNoteClosedName(pn2)) {
if (IsArgOp(pn2->getOp()) && bce->shouldNoteClosedName(pn2)) {
if (!bce->noteClosedArg(pn2))
return false;
}
@ -6517,13 +6507,6 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
break;
case PNK_NAME:
/*
* Cope with a left-over function definition that was replaced by a use
* of a later function definition of the same name. See FunctionDef and
* MakeDefIntoUse in Parser.cpp.
*/
if (pn->isOp(JSOP_NOP))
break;
if (!EmitNameOp(cx, bce, pn, false))
return false;
break;
@ -6646,6 +6629,10 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
break;
#endif /* JS_HAS_XML_SUPPORT */
case PNK_NOP:
JS_ASSERT(pn->getArity() == PN_NULLARY);
break;
default:
JS_ASSERT(0);
}

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

@ -69,6 +69,7 @@ class UpvarCookie
* The long comment after this enum block describes the kinds in detail.
*/
enum ParseNodeKind {
PNK_NOP,
PNK_SEMI,
PNK_COMMA,
PNK_CONDITIONAL,
@ -476,6 +477,7 @@ enum ParseNodeKind {
* if-guarded PNK_ARRAYPUSH
* PNK_ARRAYPUSH unary pn_op: JSOP_ARRAYCOMP
* pn_kid: array comprehension expression
* PNK_NOP nullary
*/
enum ParseNodeArity {
PN_NULLARY, /* 0 kids, only pn_atom/pn_dval/etc. */
@ -776,6 +778,16 @@ struct ParseNode {
return pn_cookie.slot();
}
bool functionIsHoisted() const {
JS_ASSERT(pn_arity == PN_FUNC);
JS_ASSERT(isOp(JSOP_LAMBDA) || // lambda, genexpr
isOp(JSOP_DEFFUN) || // non-body-level function statement
isOp(JSOP_NOP) || // body-level function stmt in global code
isOp(JSOP_GETLOCAL) || // body-level function stmt in function code
isOp(JSOP_GETARG)); // body-level function redeclaring formal
return !(isOp(JSOP_LAMBDA) || isOp(JSOP_DEFFUN));
}
inline bool test(unsigned flag) const;
bool isLet() const { return test(PND_LET); }
@ -1357,18 +1369,23 @@ struct Definition : public ParseNode
return pn_cookie.isFree();
}
enum Kind { VAR, CONST, LET, FUNCTION, ARG, UNKNOWN };
enum Kind { VAR, CONST, LET, ARG, NAMED_LAMBDA, PLACEHOLDER };
bool canHaveInitializer() { return int(kind()) <= int(LET) || kind() == ARG; }
bool canHaveInitializer() { return int(kind()) <= int(ARG); }
static const char *kindString(Kind kind);
Kind kind() {
if (getKind() == PNK_FUNCTION)
return FUNCTION;
if (getKind() == PNK_FUNCTION) {
if (isOp(JSOP_GETARG))
return ARG;
return VAR;
}
JS_ASSERT(getKind() == PNK_NAME);
if (isOp(JSOP_NOP))
return UNKNOWN;
if (isOp(JSOP_CALLEE))
return NAMED_LAMBDA;
if (isPlaceholder())
return PLACEHOLDER;
if (isOp(JSOP_GETARG))
return ARG;
if (isConst())
@ -1408,27 +1425,13 @@ ParseNode::test(unsigned flag) const
return !!(pn_dflags & flag);
}
/*
* We store definition pointers in PN_NAMESET AtomDefnMapPtrs in the AST,
* but due to redefinition these nodes may become uses of other
* definitions. This is unusual, so we simply chase the pn_lexdef link to
* find the final definition node. See functions called from
* js::frontend::AnalyzeFunctions.
*
* FIXME: MakeAssignment mutates for want of a parent link...
*/
inline Definition *
ParseNode::resolve()
{
ParseNode *pn = this;
while (!pn->isDefn()) {
if (pn->isAssignment()) {
pn = pn->pn_left;
continue;
}
pn = pn->lexdef();
}
return (Definition *) pn;
if (isDefn())
return (Definition *)this;
JS_ASSERT(lexdef()->isDefn());
return (Definition *)lexdef();
}
inline void

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

@ -497,66 +497,6 @@ ReportBadParameter(JSContext *cx, Parser *parser, JSAtom *name, unsigned errorNu
parser->reportStrictModeError(dn, errorNumber, bytes.ptr());
}
/*
* In strict mode code, all parameter names must be distinct, must not be
* strict mode reserved keywords, and must not be 'eval' or 'arguments'. We
* must perform these checks here, and not eagerly during parsing, because a
* function's body may turn on strict mode for the function head.
*/
static bool
CheckStrictParameters(JSContext *cx, Parser *parser)
{
SharedContext *sc = parser->tc->sc;
JS_ASSERT(sc->inFunction());
if (!sc->needStrictChecks() || sc->bindings.numArgs() == 0)
return true;
JSAtom *argumentsAtom = cx->runtime->atomState.argumentsAtom;
JSAtom *evalAtom = cx->runtime->atomState.evalAtom;
/* name => whether we've warned about the name already */
HashMap<JSAtom *, bool> parameters(cx);
if (!parameters.init(sc->bindings.numArgs()))
return false;
// Start with lastVariable(), not the last argument, for destructuring.
for (BindingIter bi(cx, sc->bindings); bi; bi++) {
PropertyName *name = bi->maybeName;
if (!name)
continue;
if (name == argumentsAtom || name == evalAtom) {
if (!ReportBadParameter(cx, parser, name, JSMSG_BAD_BINDING))
return false;
}
if (FindKeyword(name->charsZ(), name->length())) {
/*
* JSOPTION_STRICT is supposed to warn about future keywords, too,
* but we took care of that in the scanner.
*/
if (!ReportBadParameter(cx, parser, name, JSMSG_RESERVED_ID))
return false;
}
/*
* Check for a duplicate parameter: warn or report an error exactly
* once for each duplicated parameter.
*/
if (HashMap<JSAtom *, bool>::AddPtr p = parameters.lookupForAdd(name)) {
if (!p->value && !ReportBadParameter(cx, parser, name, JSMSG_DUPLICATE_FORMAL))
return false;
p->value = true;
} else {
if (!parameters.add(p, name, false))
return false;
}
}
return true;
}
static bool
BindLocalVariable(JSContext *cx, TreeContext *tc, ParseNode *pn, BindingKind kind)
{
@ -626,13 +566,6 @@ Parser::functionBody(FunctionBodyType type)
}
}
/*
* Check CheckStrictParameters before arguments logic below adds
* 'arguments' to bindings.
*/
if (!CheckStrictParameters(context, this))
return NULL;
Rooted<PropertyName*> arguments(context, context->runtime->atomState.argumentsAtom);
/*
@ -850,38 +783,31 @@ MakeAssignment(ParseNode *pn, ParseNode *rhs, Parser *parser)
return lhs;
}
static ParseNode *
/* See comment for use in Parser::functionDef. */
static bool
MakeDefIntoUse(Definition *dn, ParseNode *pn, JSAtom *atom, Parser *parser)
{
/*
* If dn is arg, or in [var, const, let] and has an initializer, then we
* must rewrite it to be an assignment node, whose freshly allocated
* left-hand side becomes a use of pn.
*/
if (dn->canHaveInitializer()) {
ParseNode *rhs = dn->expr();
if (rhs) {
ParseNode *lhs = MakeAssignment(dn, rhs, parser);
if (!lhs)
return NULL;
//pn->dn_uses = lhs;
dn = (Definition *) lhs;
}
TreeContext *tc = parser->tc;
dn->setOp((js_CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETNAME : JSOP_NAME);
} else if (dn->kind() == Definition::FUNCTION) {
JS_ASSERT(dn->isOp(JSOP_NOP));
parser->prepareNodeForMutation(dn);
dn->setKind(PNK_NAME);
dn->setArity(PN_NAME);
dn->pn_atom = atom;
/*
* In a function, dn must have been bound to an argument or local to be in
* tc->decls. pn is going to take dn's place in tc->decls, so copy over the
* cookie and op so that pn gets the same binding.
*/
if (tc->sc->inFunction()) {
JS_ASSERT(!dn->pn_cookie.isFree());
JS_ASSERT(dn->isBound());
pn->pn_cookie = dn->pn_cookie;
JS_ASSERT(JOF_OPTYPE(dn->getOp()) == JOF_QARG || JOF_OPTYPE(dn->getOp()) == JOF_LOCAL);
pn->setOp(JOF_OPTYPE(dn->getOp()) == JOF_QARG ? JSOP_GETARG : JSOP_GETLOCAL);
pn->pn_dflags |= PND_BOUND;
}
/* Now make dn no longer a definition, rather a use of pn. */
JS_ASSERT(dn->isKind(PNK_NAME));
JS_ASSERT(dn->isArity(PN_NAME));
JS_ASSERT(dn->pn_atom == atom);
/* Turn pn into a definition. */
parser->tc->decls.updateFirst(atom, (Definition *) pn);
pn->setDefn(true);
/* Change all uses of dn to be uses of pn. */
for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
JS_ASSERT(pnu->isUsed());
JS_ASSERT(!pnu->isDefn());
@ -891,38 +817,56 @@ MakeDefIntoUse(Definition *dn, ParseNode *pn, JSAtom *atom, Parser *parser)
pn->pn_dflags |= dn->pn_dflags & PND_USE2DEF_FLAGS;
pn->dn_uses = dn;
/*
* A PNK_FUNCTION node must be a definition, so convert shadowed function
* statements into nops. This is valid since all body-level function
* statement initialization happens at the beginning of the function
* (thus, only the last statement's effect is visible). E.g., in
*
* function outer() {
* function g() { return 1 }
* assertEq(g(), 2);
* function g() { return 2 }
* assertEq(g(), 2);
* }
*
* both asserts are valid.
*/
if (dn->getKind() == PNK_FUNCTION) {
JS_ASSERT(dn->functionIsHoisted());
pn->dn_uses = dn->pn_link;
parser->prepareNodeForMutation(dn);
dn->setKind(PNK_NOP);
dn->setArity(PN_NULLARY);
return true;
}
/*
* If dn is arg, or in [var, const, let] and has an initializer, then we
* must rewrite it to be an assignment node, whose freshly allocated
* left-hand side becomes a use of pn.
*/
if (dn->canHaveInitializer()) {
if (ParseNode *rhs = dn->expr()) {
ParseNode *lhs = MakeAssignment(dn, rhs, parser);
if (!lhs)
return false;
pn->dn_uses = lhs;
dn->pn_link = NULL;
dn = (Definition *) lhs;
}
}
/* Turn dn into a use of pn. */
JS_ASSERT(dn->isKind(PNK_NAME));
JS_ASSERT(dn->isArity(PN_NAME));
JS_ASSERT(dn->pn_atom == atom);
dn->setOp((js_CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETNAME : JSOP_NAME);
dn->setDefn(false);
dn->setUsed(true);
dn->pn_lexdef = (Definition *) pn;
dn->pn_cookie.makeFree();
dn->pn_dflags &= ~PND_BOUND;
return dn;
}
bool
frontend::DefineArg(ParseNode *pn, JSAtom *atom, unsigned i, Parser *parser)
{
/*
* Make an argument definition node, distinguished by being in
* parser->tc->decls but having PNK_NAME kind and JSOP_NOP op. Insert it in
* a PNK_ARGSBODY list node returned via pn->pn_body.
*/
ParseNode *argpn = NameNode::create(PNK_NAME, atom, parser, parser->tc);
if (!argpn)
return false;
JS_ASSERT(argpn->isKind(PNK_NAME) && argpn->isOp(JSOP_NOP));
/* Arguments are initialized by definition. */
if (!Define(argpn, atom, parser->tc))
return false;
ParseNode *argsbody = pn->pn_body;
argsbody->append(argpn);
argpn->setOp(JSOP_GETARG);
if (!argpn->pn_cookie.set(parser->context, parser->tc->staticLevel, i))
return false;
argpn->pn_dflags |= PND_BOUND;
return true;
}
@ -972,51 +916,6 @@ struct frontend::BindData {
}
};
#if JS_HAS_DESTRUCTURING
static bool
BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom, Parser *parser)
{
TreeContext *tc = parser->tc;
JS_ASSERT(tc->sc->inFunction());
/*
* NB: Check tc->decls rather than tc->sc->bindings, because destructuring
* bindings aren't added to tc->sc->bindings until after all arguments have
* been parsed.
*/
if (tc->decls.lookupFirst(atom)) {
parser->reportError(NULL, JSMSG_DESTRUCT_DUP_ARG);
return false;
}
ParseNode *pn = data->pn;
/*
* Distinguish destructured-to binding nodes as vars, not args, by setting
* pn_op to JSOP_SETLOCAL. Parser::functionDef checks for this pn_op value
* when processing the destructuring-assignment AST prelude induced by such
* destructuring args in Parser::functionArguments.
*
* We must set the PND_BOUND flag too to prevent pn_op from being reset to
* JSOP_SETNAME by BindDestructuringVar. The only field not initialized is
* pn_cookie; it gets set in functionDef in the first "if (prelude)" block.
* We have to wait to set the cookie until we can call JSFunction::addLocal
* with kind = JSLOCAL_VAR, after all JSLOCAL_ARG locals have been added.
*
* Thus a destructuring formal parameter binds an ARG (as in arguments[i]
* element) with a null atom name for the object or array passed in to be
* destructured, and zero or more VARs (as in named local variables) for
* the destructured-to identifiers in the property value positions within
* the object or array destructuring pattern, and all ARGs for the formal
* parameter list bound as locals before any VAR for a destructured name.
*/
pn->setOp(JSOP_SETLOCAL);
pn->pn_dflags |= PND_BOUND;
return Define(pn, atom, tc);
}
#endif /* JS_HAS_DESTRUCTURING */
JSFunction *
Parser::newFunction(TreeContext *tc, JSAtom *atom, FunctionSyntaxKind kind)
{
@ -1124,6 +1023,7 @@ LeaveFunction(ParseNode *fn, Parser *parser, PropertyName *funName = NULL,
return false;
dn->pn_dflags |= PND_BOUND;
foundCallee = 1;
JS_ASSERT(dn->kind() == Definition::NAMED_LAMBDA);
continue;
}
@ -1234,6 +1134,96 @@ LeaveFunction(ParseNode *fn, Parser *parser, PropertyName *funName = NULL,
return true;
}
/*
* DefineArg is called for both the formals of a regular function definition
* and the formals specified by the Function constructor.
*/
bool
frontend::DefineArg(ParseNode *pn, PropertyName *name, unsigned i, Parser *parser)
{
JSContext *cx = parser->context;
TreeContext *tc = parser->tc;
SharedContext *sc = tc->sc;
/*
* Make an argument definition node, distinguished by being in
* parser->tc->decls but having PNK_NAME kind and JSOP_NOP op. Insert it in
* a PNK_ARGSBODY list node returned via pn->pn_body.
*/
ParseNode *argpn = NameNode::create(PNK_NAME, name, parser, tc);
if (!argpn)
return false;
JS_ASSERT(argpn->isKind(PNK_NAME) && argpn->isOp(JSOP_NOP));
if (sc->needStrictChecks() && tc->decls.lookupFirst(name)) {
if (!ReportBadParameter(cx, parser, name, JSMSG_DUPLICATE_FORMAL))
return false;
}
if (!CheckStrictBinding(cx, parser, name, argpn))
return false;
/* Arguments are initialized by definition. */
if (!Define(argpn, name, tc))
return false;
ParseNode *argsbody = pn->pn_body;
argsbody->append(argpn);
argpn->setOp(JSOP_GETARG);
if (!argpn->pn_cookie.set(cx, tc->staticLevel, i))
return false;
argpn->pn_dflags |= PND_BOUND;
return true;
}
#if JS_HAS_DESTRUCTURING
static bool
BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom, Parser *parser)
{
TreeContext *tc = parser->tc;
JS_ASSERT(tc->sc->inFunction());
/*
* NB: Check tc->decls rather than tc->sc->bindings, because destructuring
* bindings aren't added to tc->sc->bindings until after all arguments have
* been parsed.
*/
if (tc->decls.lookupFirst(atom)) {
parser->reportError(NULL, JSMSG_DESTRUCT_DUP_ARG);
return false;
}
ParseNode *pn = data->pn;
if (!CheckStrictBinding(cx, parser, atom->asPropertyName(), pn))
return false;
/*
* Distinguish destructured-to binding nodes as vars, not args, by setting
* pn_op to JSOP_SETLOCAL. Parser::functionDef checks for this pn_op value
* when processing the destructuring-assignment AST prelude induced by such
* destructuring args in Parser::functionArguments.
*
* We must set the PND_BOUND flag too to prevent pn_op from being reset to
* JSOP_SETNAME by BindDestructuringVar. The only field not initialized is
* pn_cookie; it gets set in functionDef in the first "if (prelude)" block.
* We have to wait to set the cookie until we can call JSFunction::addLocal
* with kind = JSLOCAL_VAR, after all JSLOCAL_ARG locals have been added.
*
* Thus a destructuring formal parameter binds an ARG (as in arguments[i]
* element) with a null atom name for the object or array passed in to be
* destructured, and zero or more VARs (as in named local variables) for
* the destructured-to identifiers in the property value positions within
* the object or array destructuring pattern, and all ARGs for the formal
* parameter list bound as locals before any VAR for a destructured name.
*/
pn->setOp(JSOP_SETLOCAL);
pn->pn_dflags |= PND_BOUND;
return Define(pn, atom, tc);
}
#endif /* JS_HAS_DESTRUCTURING */
bool
Parser::functionArguments(ParseNode **listp, bool &hasRest)
{
@ -1438,56 +1428,51 @@ Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSynta
pn->pn_cookie.makeFree();
pn->pn_dflags = 0;
/*
* Record names for function statements in tc->decls so we know when to
* avoid optimizing variable references that might name a function.
*/
/* Function statements add a binding to the enclosing scope. */
bool bodyLevel = tc->atBodyLevel();
if (kind == Statement) {
/*
* Handle redeclaration and optimize cases where we can statically bind the
* function (thereby avoiding JSOP_DEFFUN and dynamic name lookup).
*/
if (Definition *dn = tc->decls.lookupFirst(funName)) {
Definition::Kind dn_kind = dn->kind();
JS_ASSERT(!dn->isUsed());
JS_ASSERT(dn->isDefn());
if (context->hasStrictOption() || dn_kind == Definition::CONST) {
if (context->hasStrictOption() || dn->kind() == Definition::CONST) {
JSAutoByteString name;
Reporter reporter = (dn_kind != Definition::CONST)
Reporter reporter = (dn->kind() != Definition::CONST)
? &Parser::reportStrictWarning
: &Parser::reportError;
if (!js_AtomToPrintableString(context, funName, &name) ||
!(this->*reporter)(NULL, JSMSG_REDECLARED_VAR, Definition::kindString(dn_kind),
!(this->*reporter)(NULL, JSMSG_REDECLARED_VAR, Definition::kindString(dn->kind()),
name.ptr()))
{
return NULL;
}
}
if (bodyLevel) {
tc->decls.updateFirst(funName, (Definition *) pn);
pn->setDefn(true);
pn->dn_uses = dn; /* dn->dn_uses is now pn_link */
if (!MakeDefIntoUse(dn, pn, funName, this))
return NULL;
}
/*
* Body-level function statements are effectively variable
* declarations where the initialization is hoisted to the
* beginning of the block. This means that any other variable
* declaration with the same name is really just an assignment to
* the function's binding (which is mutable), so turn any existing
* declaration into a use.
*/
if (bodyLevel && !MakeDefIntoUse(dn, pn, funName, this))
return NULL;
} else if (bodyLevel) {
/*
* If this function was used before it was defined, claim the
* pre-created definition node for this function that primaryExpr
* put in tc->lexdeps on first forward reference, and recycle pn.
*/
if (Definition *fn = tc->lexdeps.lookupDefn(funName)) {
JS_ASSERT(fn->isDefn());
fn->setKind(PNK_FUNCTION);
fn->setArity(PN_FUNC);
fn->pn_pos.begin = pn->pn_pos.begin;
/*
* Set fn->pn_pos.end too, in case of error before we parse the
* closing brace. See bug 640075.
*/
fn->pn_pos.end = pn->pn_pos.end;
fn->pn_body = NULL;
@ -1500,41 +1485,64 @@ Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSynta
if (!Define(pn, funName, tc))
return NULL;
/*
* A function directly inside another's body needs only a local
* variable to bind its name to its value, and not an activation object
* property (it might also need the activation property, if the outer
* function contains with statements, e.g., but the stack slot wins
* when BytecodeEmitter.cpp's BindNameToSlot can optimize a JSOP_NAME
* into a JSOP_GETLOCAL bytecode).
*/
if (tc->sc->inFunction()) {
unsigned varIndex = tc->sc->bindings.numVars();
if (!tc->sc->bindings.addVariable(context, funName))
return NULL;
if (!pn->pn_cookie.set(context, tc->staticLevel, varIndex))
return NULL;
pn->setOp(JSOP_GETLOCAL);
}
}
/*
* A function directly inside another's body needs only a local
* variable to bind its name to its value, and not an activation object
* property (it might also need the activation property, if the outer
* function contains with statements, e.g., but the stack slot wins
* when BytecodeEmitter.cpp's BindNameToSlot can optimize a JSOP_NAME
* into a JSOP_GETLOCAL bytecode).
* As a SpiderMonkey-specific extension, non-body-level function
* statements (e.g., functions in an "if" or "while" block) are
* dynamically bound when control flow reaches the statement. The
* emitter normally emits functions in two passes (see PNK_ARGSBODY).
* To distinguish
*/
if (bodyLevel && tc->sc->inFunction()) {
/*
* Define a local in the outer function so that BindNameToSlot
* can properly optimize accesses. Note that we need a local
* variable, not an argument, for the function statement. Thus
* we add a variable even if a parameter with the given name
* already exists.
*/
BindingIter bi(context, tc->sc->bindings.lookup(context, funName));
if (!bi || bi->kind != CONSTANT) {
unsigned varIndex;
if (!bi || bi->kind == ARGUMENT) {
varIndex = tc->sc->bindings.numVars();
if (!tc->sc->bindings.addVariable(context, funName))
return NULL;
} else {
JS_ASSERT(bi->kind == VARIABLE);
varIndex = bi.frameIndex();
}
if (bodyLevel) {
JS_ASSERT(pn->functionIsHoisted());
JS_ASSERT_IF(tc->sc->inFunction(), !pn->pn_cookie.isFree());
JS_ASSERT_IF(!tc->sc->inFunction(), pn->pn_cookie.isFree());
} else {
JS_ASSERT(tc->sc->strictModeState != StrictMode::STRICT);
JS_ASSERT(pn->pn_cookie.isFree());
tc->sc->setFunMightAliasLocals();
tc->sc->setFunHasExtensibleScope();
tc->sc->setFunIsHeavyweight();
pn->setOp(JSOP_DEFFUN);
if (!pn->pn_cookie.set(context, tc->staticLevel, varIndex))
/*
* Instead of setting bindingsAccessedDynamically, which would be
* overly conservative, remember the names of all function
* statements and mark any bindings with the same as aliased at the
* end of functionBody.
*/
if (!tc->funcStmts) {
tc->funcStmts = context->new_<FuncStmtSet>(context);
if (!tc->funcStmts || !tc->funcStmts->init())
return NULL;
pn->pn_dflags |= PND_BOUND;
}
if (!tc->funcStmts->put(funName))
return NULL;
}
/* No further binding (in BindNameToSlot) is needed for functions. */
pn->pn_dflags |= PND_BOUND;
} else {
/* A function expression does not introduce any binding. */
pn->setOp(JSOP_LAMBDA);
}
TreeContext *outertc = tc;
@ -1695,47 +1703,10 @@ Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSynta
outertc->sc->setFunIsHeavyweight();
}
JSOp op = JSOP_NOP;
if (kind == Expression) {
op = JSOP_LAMBDA;
} else {
if (!bodyLevel) {
/*
* Extension: in non-strict mode code, a function statement not at
* the top level of a function body or whole program, e.g., in a
* compound statement such as the "then" part of an "if" statement,
* binds a closure only if control reaches that sub-statement.
*/
JS_ASSERT(outertc->sc->strictModeState != StrictMode::STRICT);
op = JSOP_DEFFUN;
outertc->sc->setFunMightAliasLocals();
outertc->sc->setFunHasExtensibleScope();
outertc->sc->setFunIsHeavyweight();
/*
* Instead of setting bindingsAccessedDynamically, which would be
* overly conservative, remember the names of all function
* statements and mark any bindings with the same as aliased at the
* end of functionBody.
*/
if (!outertc->funcStmts) {
outertc->funcStmts = context->new_<FuncStmtSet>(context);
if (!outertc->funcStmts || !outertc->funcStmts->init())
return NULL;
}
if (!outertc->funcStmts->put(funName))
return NULL;
}
}
pn->pn_funbox = funbox;
pn->setOp(op);
pn->pn_body->append(body);
pn->pn_body->pn_pos = body->pn_pos;
JS_ASSERT_IF(!outertc->sc->inFunction() && bodyLevel && kind == Statement,
pn->pn_cookie.isFree());
pn->pn_blockid = outertc->blockid();
if (!LeaveFunction(pn, this, funName, kind))
@ -6925,7 +6896,7 @@ Parser::primaryExpr(TokenKind tt, bool afterDoubleDot)
if (!js_AtomToPrintableString(context, atom, &name))
return NULL;
Reporter reporter =
Reporter reporter =
(oldAssignType == VALUE && assignType == VALUE && !tc->sc->needStrictChecks())
? &Parser::reportWarning
: (tc->sc->needStrictChecks() ? &Parser::reportStrictModeError : &Parser::reportError);

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

@ -327,7 +327,7 @@ Parser::reportStrictModeError(ParseNode *pn, unsigned errorNumber, ...)
}
bool
DefineArg(ParseNode *pn, JSAtom *atom, unsigned i, Parser *parser);
DefineArg(ParseNode *pn, PropertyName *name, unsigned i, Parser *parser);
} /* namespace frontend */
} /* namespace js */

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

@ -0,0 +1,20 @@
function f(x) {
function x() {}
arguments[0] = 42;
return x;
}
assertEq(f(0), 42);
function g(x) {
function x() {}
assertEq(arguments[0], x);
}
g(0);
var caught = false;
try {
(function h(x) { function x() {} }).blah.baz;
} catch (e) {
caught = true;
}
assertEq(caught, true);

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

@ -0,0 +1,44 @@
function f1() {
assertEq(g(), 3);
function g() { return 1 }
assertEq(g(), 3);
function g() { return 2 }
assertEq(g(), 3);
function g() { return 3 }
assertEq(g(), 3);
}
f1();
function f2() {
assertEq(g(), 2);
var g = 3;
assertEq(g, 3);
function g() { return 1 }
function g() { return 2 }
}
f2();
function f3() {
assertEq(g(), 2);
var g = 3;
assertEq(g, 3);
function g() { return 1 }
var g = 4;
assertEq(g, 4);
function g() { return 2 }
}
f3();
function f4() {
assertEq(g(), 4);
function g() { return 1 }
assertEq(g(), 4);
function g() { return 2 }
var g = 9;
assertEq(g, 9);
function g() { return 3 }
assertEq(g, 9);
function g() { return 4 }
assertEq(g, 9);
}
f4();

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

@ -1,15 +1,23 @@
// |jit-test| error: ExitCleanly
// proxies can return primitives
assertEq(new (Proxy.createFunction({}, function(){}, function(){})), undefined);
x = Proxy.createFunction((function () {}), Uint16Array, wrap)
new(wrap(x))
assertEq((new (Proxy.createFunction({},
function(){ this.x = 1 },
function(){ this.x = 2 }))).x, 2);
try {
x = Proxy.createFunction((function () {}), Uint16Array, wrap)
new(wrap(x))
throw "Should not be reached"
}
catch (e) {
assertEq(String(e.message).indexOf('is not a constructor') === -1, false);
}
// proxies can return the callee
var x = Proxy.createFunction({}, function (q) { return q; });
assertEq(new x(x), x);
try {
var x = (Proxy.createFunction({}, "".indexOf));
new x;
throw "Should not be reached"
}
catch (e) {
assertEq(String(e.message).indexOf('is not a constructor') === -1, false);

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

@ -15,7 +15,6 @@
#include "jstypes.h"
#include "jsutil.h"
#include "jshash.h"
#include "jsprf.h"
#include "jsapi.h"
#include "jsatom.h"
@ -43,12 +42,6 @@ using namespace js::gc;
const size_t JSAtomState::commonAtomsOffset = offsetof(JSAtomState, emptyAtom);
/*
* ATOM_HASH assumes that JSHashNumber is 32-bit even on 64-bit systems.
*/
JS_STATIC_ASSERT(sizeof(JSHashNumber) == 4);
JS_STATIC_ASSERT(sizeof(JSAtom *) == JS_BYTES_PER_WORD);
const char *
js_AtomToPrintableString(JSContext *cx, JSAtom *atom, JSAutoByteString *bytes)
{

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

@ -12,12 +12,12 @@
#include "jsalloc.h"
#include "jsapi.h"
#include "jsprvtd.h"
#include "jshash.h"
#include "jspubtd.h"
#include "jslock.h"
#include "gc/Barrier.h"
#include "js/HashTable.h"
#include "mozilla/HashFunctions.h"
struct JSIdArray {
int length;
@ -83,23 +83,15 @@ JSID_TO_ATOM(jsid id)
return (JSAtom *)JSID_TO_STRING(id);
}
JS_STATIC_ASSERT(sizeof(JSHashNumber) == 4);
JS_STATIC_ASSERT(sizeof(js::HashNumber) == 4);
JS_STATIC_ASSERT(sizeof(jsid) == JS_BYTES_PER_WORD);
namespace js {
static JS_ALWAYS_INLINE JSHashNumber
static JS_ALWAYS_INLINE js::HashNumber
HashId(jsid id)
{
JSHashNumber n =
#if JS_BYTES_PER_WORD == 4
JSHashNumber(JSID_BITS(id));
#elif JS_BYTES_PER_WORD == 8
JSHashNumber(JSID_BITS(id)) ^ JSHashNumber(JSID_BITS(id) >> 32);
#else
# error "Unsupported configuration"
#endif
return n * JS_GOLDEN_RATIO;
return HashGeneric(JSID_BITS(id));
}
static JS_ALWAYS_INLINE Value
@ -135,15 +127,6 @@ struct DefaultHasher<jsid>
}
#if JS_BYTES_PER_WORD == 4
# define ATOM_HASH(atom) ((JSHashNumber)(atom) >> 2)
#elif JS_BYTES_PER_WORD == 8
# define ATOM_HASH(atom) (((JSHashNumber)(uintptr_t)(atom) >> 3) ^ \
(JSHashNumber)((uintptr_t)(atom) >> 32))
#else
# error "Unsupported configuration"
#endif
/*
* Return a printable, lossless char[] representation of a string-type atom.
* The lifetime of the result matches the lifetime of bytes.

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

@ -44,7 +44,6 @@
#include "jstypes.h"
#include "jsutil.h"
#include "jshash.h"
#include "jsclist.h"
#include "jsprf.h"
#include "jsapi.h"

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

@ -15,7 +15,6 @@
#include "jstypes.h"
#include "jsutil.h"
#include "jshash.h"
#include "jsprf.h"
#include "jsapi.h"
#include "jsarray.h"

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

@ -21,7 +21,6 @@
#include "jsclass.h"
#include "jsfriendapi.h"
#include "jsinfer.h"
#include "jshash.h"
#include "jspubtd.h"
#include "jsprvtd.h"
#include "jslock.h"

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

@ -376,7 +376,7 @@ js_DumpPC(JSContext *cx)
return ok;
}
JSBool
JS_FRIEND_API(JSBool)
js_DumpScript(JSContext *cx, JSScript *script_)
{
Sprinter sprinter(cx);
@ -4819,7 +4819,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, int nb)
* syntactically appear.
*/
jsbytecode *nextpc = pc + JSOP_LAMBDA_LENGTH;
LOCAL_ASSERT(*nextpc == JSOP_SETLOCAL || *nextpc == JSOP_SETALIASEDVAR);
LOCAL_ASSERT(*nextpc == JSOP_SETLOCAL || *nextpc == JSOP_SETALIASEDVAR || *nextpc == JSOP_SETARG);
nextpc += js_CodeSpec[*nextpc].length;
LOCAL_ASSERT(*nextpc == JSOP_POP);
nextpc += JSOP_POP_LENGTH;

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше