Merge m-c to b2g-inbound

This commit is contained in:
Wes Kocher 2013-11-07 18:43:55 -08:00
commit 27a86159e9
155 changed files with 1748 additions and 921 deletions

View File

@ -1078,7 +1078,7 @@ pref("devtools.commands.dir", "");
// Enable the app manager
pref("devtools.appmanager.enabled", true);
pref("devtools.appmanager.firstrun", true);
pref("devtools.appmanager.lastTab", "help");
pref("devtools.appmanager.manifestEditor.enabled", false);
// Toolbox preferences

View File

@ -986,16 +986,15 @@ nsContextMenu.prototype = {
},
saveVideoFrameAsImage: function () {
urlSecurityCheck(this.mediaURL,
this._unremotePrincipal(this.browser.contentPrincipal),
Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
let name = "";
try {
let uri = makeURI(this.mediaURL);
let url = uri.QueryInterface(Ci.nsIURL);
if (url.fileBaseName)
name = decodeURI(url.fileBaseName) + ".jpg";
} catch (e) { }
if (this.mediaURL) {
try {
let uri = makeURI(this.mediaURL);
let url = uri.QueryInterface(Ci.nsIURL);
if (url.fileBaseName)
name = decodeURI(url.fileBaseName) + ".jpg";
} catch (e) { }
}
if (!name)
name = "snapshot.jpg";
var video = this.target;

View File

@ -162,16 +162,13 @@ let UI = {
if (!this.connected) {
return;
}
let app = this.store.object.apps.all.filter(a => a.manifestURL == manifest)[0];
getTargetForApp(this.connection.client,
this.listTabsResponse.webappsActor,
manifest).then((target) => {
gDevTools.showToolbox(target,
null,
devtools.Toolbox.HostType.WINDOW).then(toolbox => {
this.connection.once(Connection.Events.DISCONNECTED, () => {
toolbox.destroy();
});
});
top.UI.openAndShowToolboxForTarget(target, app.name, app.iconURL);
}, console.error);
},

View File

@ -7,76 +7,176 @@ Cu.import("resource:///modules/devtools/gDevTools.jsm");
const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const {require} = devtools;
const {ConnectionManager, Connection} = require("devtools/client/connection-manager");
const promise = require("sdk/core/promise");
const prefs = require('sdk/preferences/service');
let connection;
window.addEventListener("message", function(event) {
try {
let json = JSON.parse(event.data);
switch (json.name) {
case "connection":
let cid = +json.cid;
for (let c of ConnectionManager.connections) {
if (c.uid == cid) {
connection = c;
onNewConnection();
break;
}
}
break;
case "closeHelp":
selectTab("projects");
break;
default:
Cu.reportError("Unknown message: " + json.name);
let UI = {
_toolboxTabCursor: 0,
_handledTargets: new Map(),
connection: null,
init: function() {
this.onLoad = this.onLoad.bind(this);
this.onUnload = this.onUnload.bind(this);
this.onMessage = this.onMessage.bind(this);
this.onConnected = this.onConnected.bind(this);
this.onDisconnected = this.onDisconnected.bind(this);
window.addEventListener("load", this.onLoad);
window.addEventListener("unload", this.onUnload);
window.addEventListener("message", this.onMessage);
},
onLoad: function() {
window.removeEventListener("load", this.onLoad);
let defaultPanel = prefs.get("devtools.appmanager.lastTab");
let panelExists = !!document.querySelector("." + defaultPanel + "-panel");
this.selectTab(panelExists ? defaultPanel : "projects");
},
onUnload: function() {
window.removeEventListener("unload", this.onUnload);
window.removeEventListener("message", this.onMessage);
if (this.connection) {
this.connection.off(Connection.Status.CONNECTED, this.onConnected);
this.connection.off(Connection.Status.DISCONNECTED, this.onDisconnected);
}
} catch(e) { Cu.reportError(e); }
},
// Forward message
let panels = document.querySelectorAll(".panel");
for (let frame of panels) {
frame.contentWindow.postMessage(event.data, "*");
}
}, false);
onMessage: function(event) {
try {
let json = JSON.parse(event.data);
switch (json.name) {
case "connection":
let cid = +json.cid;
for (let c of ConnectionManager.connections) {
if (c.uid == cid) {
this.onNewConnection(c);
break;
}
}
break;
case "closeHelp":
this.selectTab("projects");
break;
case "toolbox-raise":
this.selectTab(json.uid);
break;
case "toolbox-close":
this.closeToolboxTab(json.uid);
break;
default:
Cu.reportError("Unknown message: " + json.name);
}
} catch(e) { Cu.reportError(e); }
window.addEventListener("unload", function onUnload() {
window.removeEventListener("unload", onUnload);
if (connection) {
connection.off(Connection.Status.CONNECTED, onConnected);
connection.off(Connection.Status.DISCONNECTED, onDisconnected);
}
});
// Forward message
let panels = document.querySelectorAll(".panel");
for (let frame of panels) {
frame.contentWindow.postMessage(event.data, "*");
}
},
function onNewConnection() {
connection.on(Connection.Status.CONNECTED, onConnected);
connection.on(Connection.Status.DISCONNECTED, onDisconnected);
}
selectTabFromButton: function(button) {
if (!button.hasAttribute("panel"))
return;
this.selectTab(button.getAttribute("panel"));
},
function onConnected() {
document.querySelector("#content").classList.add("connected");
}
selectTab: function(panel) {
let isToolboxTab = false;
for (let type of ["button", "panel"]) {
let oldSelection = document.querySelector("." + type + "[selected]");
let newSelection = document.querySelector("." + panel + "-" + type);
if (oldSelection) oldSelection.removeAttribute("selected");
if (newSelection) {
newSelection.scrollIntoView(false);
newSelection.setAttribute("selected", "true");
if (newSelection.classList.contains("toolbox")) {
isToolboxTab = true;
}
}
}
if (!isToolboxTab) {
prefs.set("devtools.appmanager.lastTab", panel);
}
},
function onDisconnected() {
document.querySelector("#content").classList.remove("connected");
}
onNewConnection: function(connection) {
this.connection = connection;
this.connection.on(Connection.Status.CONNECTED, this.onConnected);
this.connection.on(Connection.Status.DISCONNECTED, this.onDisconnected);
},
function selectTab(id) {
for (let type of ["button", "panel"]) {
let oldSelection = document.querySelector("." + type + "[selected]");
let newSelection = document.querySelector("." + id + "-" + type);
if (oldSelection) oldSelection.removeAttribute("selected");
if (newSelection) newSelection.setAttribute("selected", "true");
}
if (id != "help") {
// Might be the first time the user is accessing the actual app manager
prefs.set("devtools.appmanager.firstrun", false);
onConnected: function() {
document.querySelector("#content").classList.add("connected");
},
onDisconnected: function() {
for (let [,toolbox] of this._handledTargets) {
if (toolbox) {
toolbox.destroy();
}
}
this._handledTargets.clear();
document.querySelector("#content").classList.remove("connected");
},
createToolboxTab: function(name, iconURL, uid) {
let button = document.createElement("button");
button.className = "button toolbox " + uid + "-button";
button.setAttribute("panel", uid);
button.textContent = name;
button.setAttribute("style", "background-image: url(" + iconURL + ")");
let toolboxTabs = document.querySelector("#toolbox-tabs");
toolboxTabs.appendChild(button);
let iframe = document.createElement("iframe");
iframe.setAttribute("flex", "1");
iframe.className = "panel toolbox " + uid + "-panel";
let panels = document.querySelector("#tab-panels");
panels.appendChild(iframe);
this.selectTab(uid);
return iframe;
},
closeToolboxTab: function(uid) {
let buttonToDestroy = document.querySelector("." + uid + "-button");
let panelToDestroy = document.querySelector("." + uid + "-panel");
if (buttonToDestroy.hasAttribute("selected")) {
let lastTab = prefs.get("devtools.appmanager.lastTab");
this.selectTab(lastTab);
}
buttonToDestroy.remove();
panelToDestroy.remove();
},
openAndShowToolboxForTarget: function(target, name, icon) {
let host = devtools.Toolbox.HostType.CUSTOM;
if (!this._handledTargets.has(target)) {
let uid = "uid" + this._toolboxTabCursor++;
let iframe = this.createToolboxTab(name, icon, uid);
let options = { customIframe: iframe , uid: uid };
this._handledTargets.set(target, null);
return gDevTools.showToolbox(target, null, host, options).then(toolbox => {
this._handledTargets.set(target, toolbox);
toolbox.once("destroyed", () => {
this._handledTargets.delete(target)
});
});
} else {
let toolbox = this._handledTargets.get(target);
if (!toolbox) {
// Target is handled, but toolbox is still being
// created.
return promise.resolve(null);
}
return gDevTools.showToolbox(target, null, host);
}
}
}
let firstRun = prefs.get("devtools.appmanager.firstrun");
if (firstRun) {
selectTab("help");
} else {
selectTab("projects");
}
UI.init();

View File

@ -22,11 +22,11 @@
<vbox id="root" flex="1">
<hbox id="content" flex="1">
<vbox id="tabs">
<button class="button projects-button" onclick="selectTab('projects')">&index.projects2;</button>
<button class="button device-button" onclick="selectTab('device')">&index.device2;</button>
<spacer flex="1"/>
<button class="button help-button" onclick="selectTab('help')">&index.help;</button>
<vbox id="tabs" onclick="UI.selectTabFromButton(event.target)">
<button class="button projects-button" panel="projects">&index.projects2;</button>
<button class="button device-button" panel="device">&index.device2;</button>
<vbox id="toolbox-tabs" flex="1"/>
<button class="button help-button" panel="help">&index.help;</button>
</vbox>
<hbox id="tab-panels" flex="1">
<iframe flex="1" class="panel projects-panel" src="chrome://browser/content/devtools/app-manager/projects.xhtml"/>

View File

@ -356,25 +356,15 @@ let UI = {
loop(0);
return deferred.promise;
};
let onTargetReady = (target) => {
// Finally, when it's finally opened, display the toolbox
let deferred = promise.defer();
gDevTools.showToolbox(target,
null,
devtools.Toolbox.HostType.WINDOW).then(toolbox => {
this.connection.once(Connection.Events.DISCONNECTED, () => {
toolbox.destroy();
});
deferred.resolve(toolbox);
});
return deferred.promise;
};
// First try to open the app
this.start(project)
.then(null, onFailedToStart)
.then(onStarted)
.then(onTargetReady)
.then((target) =>
top.UI.openAndShowToolboxForTarget(target,
project.manifest.name,
project.icon))
.then(() => {
// And only when the toolbox is opened, release the button
button.disabled = false;

View File

@ -33,7 +33,7 @@ function test() {
});
}
function testNavigate() {
function testNavigate([aGrip, aResponse]) {
let outstanding = [promise.defer(), promise.defer()];
gClient.addListener("tabNavigated", function onTabNavigated(aEvent, aPacket) {
@ -51,14 +51,16 @@ function testNavigate() {
});
gBrowser.selectedTab.linkedBrowser.loadURI(TAB2_URL);
return promise.all(outstanding.map(e => e.promise));
return promise.all(outstanding.map(e => e.promise))
.then(() => aGrip.actor);
}
function testDetach() {
function testDetach(aActor) {
let deferred = promise.defer();
gClient.addOneTimeListener("tabDetached", () => {
gClient.addOneTimeListener("tabDetached", (aType, aPacket) => {
ok(true, "Got a tab detach notification.");
is(aPacket.from, aActor, "tab detach message comes from the expected actor");
gClient.close(deferred.resolve);
});

View File

@ -206,11 +206,13 @@ DevTools.prototype = {
* The id of the tool to show
* @param {Toolbox.HostType} hostType
* The type of host (bottom, window, side)
* @param {object} hostOptions
* Options for host specifically
*
* @return {Toolbox} toolbox
* The toolbox that was opened
*/
showToolbox: function(target, toolId, hostType) {
showToolbox: function(target, toolId, hostType, hostOptions) {
let deferred = promise.defer();
let toolbox = this._toolboxes.get(target);
@ -233,7 +235,7 @@ DevTools.prototype = {
}
else {
// No toolbox for target, create one
toolbox = new devtools.Toolbox(target, toolId, hostType);
toolbox = new devtools.Toolbox(target, toolId, hostType, hostOptions);
this._toolboxes.set(target, toolbox);

View File

@ -350,7 +350,13 @@ TabTarget.prototype = {
* Setup listeners for remote debugging, updating existing ones as necessary.
*/
_setupRemoteListeners: function TabTarget__setupRemoteListeners() {
this.client.addListener("tabDetached", this.destroy);
this._onTabDetached = (aType, aPacket) => {
// We have to filter message to ensure that this detach is for this tab
if (aPacket.from == this._form.actor) {
this.destroy();
}
};
this.client.addListener("tabDetached", this._onTabDetached);
this._onTabNavigated = function onRemoteTabNavigated(aType, aPacket) {
let event = Object.create(null);
@ -377,7 +383,7 @@ TabTarget.prototype = {
*/
_teardownRemoteListeners: function TabTarget__teardownRemoteListeners() {
this.client.removeListener("tabNavigated", this._onTabNavigated);
this.client.removeListener("tabDetached", this.destroy);
this.client.removeListener("tabDetached", this._onTabDetached);
},
/**

View File

@ -22,3 +22,4 @@ support-files = head.js
[browser_toolbox_window_shortcuts.js]
[browser_toolbox_window_title_changes.js]
[browser_toolbox_zoom.js]
[browser_toolbox_custom_host.js]

View File

@ -0,0 +1,60 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
Cu.import("resource://gre/modules/Services.jsm");
let temp = {}
Cu.import("resource:///modules/devtools/gDevTools.jsm", temp);
let DevTools = temp.DevTools;
Cu.import("resource://gre/modules/devtools/LayoutHelpers.jsm", temp);
let LayoutHelpers = temp.LayoutHelpers;
Cu.import("resource://gre/modules/devtools/Loader.jsm", temp);
let devtools = temp.devtools;
let Toolbox = devtools.Toolbox;
let toolbox, iframe, target, tab;
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
target = TargetFactory.forTab(gBrowser.selectedTab);
window.addEventListener("message", onMessage);
iframe = document.createElement("iframe");
document.documentElement.appendChild(iframe);
gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
let options = {customIframe: iframe};
gDevTools.showToolbox(target, null, Toolbox.HostType.CUSTOM, options)
.then(testCustomHost, console.error)
.then(null, console.error);
}, true);
content.location = "data:text/html,test custom host";
function onMessage(event) {
info("onMessage: " + event.data);
let json = JSON.parse(event.data);
if (json.name == "toolbox-close") {
ok("Got the `toolbox-close` message");
cleanup();
}
}
function testCustomHost(toolbox) {
is(toolbox.doc.defaultView.top, window, "Toolbox is included in browser.xul");
is(toolbox.doc, iframe.contentDocument, "Toolbox is in the custom iframe");
executeSoon(() => gBrowser.removeCurrentTab());
}
function cleanup() {
window.removeEventListener("message", onMessage);
iframe.remove();
finish();
}
}

View File

@ -10,6 +10,7 @@ let promise = require("sdk/core/promise");
let EventEmitter = require("devtools/shared/event-emitter");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource:///modules/devtools/DOMHelpers.jsm");
/**
* A toolbox host represents an object that contains a toolbox (e.g. the
@ -23,7 +24,8 @@ Cu.import("resource://gre/modules/Services.jsm");
exports.Hosts = {
"bottom": BottomHost,
"side": SidebarHost,
"window": WindowHost
"window": WindowHost,
"custom": CustomHost
}
/**
@ -61,18 +63,18 @@ BottomHost.prototype = {
this._nbox.appendChild(this.frame);
let frameLoad = function() {
this.frame.removeEventListener("DOMContentLoaded", frameLoad, true);
this.emit("ready", this.frame);
deferred.resolve(this.frame);
}.bind(this);
this.frame.tooltip = "aHTMLTooltip";
this.frame.addEventListener("DOMContentLoaded", frameLoad, true);
// we have to load something so we can switch documents if we have to
this.frame.setAttribute("src", "about:blank");
let domHelper = new DOMHelpers(this.frame.contentWindow);
domHelper.onceDOMReady(frameLoad);
focusTab(this.hostTab);
return deferred.promise;
@ -272,6 +274,59 @@ WindowHost.prototype = {
}
}
/**
* Host object for the toolbox in its own tab
*/
function CustomHost(hostTab, options) {
this.frame = options.customIframe;
this.uid = options.uid;
EventEmitter.decorate(this);
}
CustomHost.prototype = {
type: "custom",
_sendMessageToTopWindow: function CH__sendMessageToTopWindow(msg) {
// It's up to the custom frame owner (parent window) to honor
// "close" or "raise" instructions.
let topWindow = this.frame.ownerDocument.defaultView;
let json = {name:"toolbox-" + msg, uid: this.uid}
topWindow.postMessage(JSON.stringify(json), "*");
},
/**
* Create a new xul window to contain the toolbox.
*/
create: function CH_create() {
return promise.resolve(this.frame);
},
/**
* Raise the host.
*/
raise: function CH_raise() {
this._sendMessageToTopWindow("raise");
},
/**
* Set the toolbox title.
*/
setTitle: function CH_setTitle(title) {
// Not supported
},
/**
* Destroy the window.
*/
destroy: function WH_destroy() {
if (!this._destroyed) {
this._destroyed = true;
this._sendMessageToTopWindow("close");
}
return promise.resolve(null);
}
}
/**
* Switch to the given tab in a browser and focus the browser window
*/

View File

@ -19,6 +19,7 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource:///modules/devtools/gDevTools.jsm");
Cu.import("resource:///modules/devtools/scratchpad-manager.jsm");
Cu.import("resource:///modules/devtools/DOMHelpers.jsm");
loader.lazyGetter(this, "Hosts", () => require("devtools/framework/toolbox-hosts").Hosts);
@ -55,8 +56,10 @@ loader.lazyGetter(this, "Requisition", () => {
* Tool to select initially
* @param {Toolbox.HostType} hostType
* Type of host that will host the toolbox (e.g. sidebar, window)
* @param {object} hostOptions
* Options for host specifically
*/
function Toolbox(target, selectedTool, hostType) {
function Toolbox(target, selectedTool, hostType, hostOptions) {
this._target = target;
this._toolPanels = new Map();
this._telemetry = new Telemetry();
@ -79,7 +82,7 @@ function Toolbox(target, selectedTool, hostType) {
}
this._defaultToolId = selectedTool;
this._host = this._createHost(hostType);
this._host = this._createHost(hostType, hostOptions);
EventEmitter.decorate(this);
@ -99,7 +102,8 @@ exports.Toolbox = Toolbox;
Toolbox.HostType = {
BOTTOM: "bottom",
SIDE: "side",
WINDOW: "window"
WINDOW: "window",
CUSTOM: "custom"
};
Toolbox.prototype = {
@ -187,8 +191,6 @@ Toolbox.prototype = {
let deferred = promise.defer();
let domReady = () => {
iframe.removeEventListener("DOMContentLoaded", domReady, true);
this.isReady = true;
let closeButton = this.doc.getElementById("toolbox-close");
@ -211,9 +213,11 @@ Toolbox.prototype = {
});
};
iframe.addEventListener("DOMContentLoaded", domReady, true);
iframe.setAttribute("src", this._URL);
let domHelper = new DOMHelpers(iframe.contentWindow);
domHelper.onceDOMReady(domReady);
return deferred.promise;
});
},
@ -387,6 +391,7 @@ Toolbox.prototype = {
for (let type in Toolbox.HostType) {
let position = Toolbox.HostType[type];
if (position == this.hostType ||
position == Toolbox.HostType.CUSTOM ||
(!sideEnabled && position == Toolbox.HostType.SIDE)) {
continue;
}
@ -555,8 +560,6 @@ Toolbox.prototype = {
vbox.appendChild(iframe);
let onLoad = () => {
iframe.removeEventListener("DOMContentLoaded", onLoad, true);
let built = definition.build(iframe.contentWindow, this);
promise.resolve(built).then((panel) => {
this._toolPanels.set(id, panel);
@ -566,8 +569,25 @@ Toolbox.prototype = {
});
};
iframe.addEventListener("DOMContentLoaded", onLoad, true);
iframe.setAttribute("src", definition.url);
// Depending on the host, iframe.contentWindow is not always
// defined at this moment. If it is not defined, we use an
// event listener on the iframe DOM node. If it's defined,
// we use the chromeEventHandler. We can't use a listener
// on the DOM node every time because this won't work
// if the (xul chrome) iframe is loaded in a content docshell.
if (iframe.contentWindow) {
let domHelper = new DOMHelpers(iframe.contentWindow);
domHelper.onceDOMReady(onLoad);
} else {
let callback = () => {
iframe.removeEventListener("DOMContentLoaded", callback);
onLoad();
}
iframe.addEventListener("DOMContentLoaded", callback);
}
return deferred.promise;
},
@ -732,13 +752,13 @@ Toolbox.prototype = {
* @return {Host} host
* The created host object
*/
_createHost: function(hostType) {
_createHost: function(hostType, options) {
if (!Hosts[hostType]) {
throw new Error("Unknown hostType: " + hostType);
}
// clean up the toolbox if its window is closed
let newHost = new Hosts[hostType](this.target.tab);
let newHost = new Hosts[hostType](this.target.tab, options);
newHost.on("window-closed", this.destroy);
return newHost;
},
@ -766,7 +786,9 @@ Toolbox.prototype = {
this._host = newHost;
Services.prefs.setCharPref(this._prefs.LAST_HOST, this._host.type);
if (this.hostType != Toolbox.HostType.CUSTOM) {
Services.prefs.setCharPref(this._prefs.LAST_HOST, this._host.type);
}
this._buildDockButtons();
this._addKeysToWindow();

View File

@ -181,6 +181,13 @@ function ResponsiveUI(aWindow, aTab)
this.buildUI();
this.checkMenus();
this.docShell = this.browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
this._deviceSizeWasPageSize = this.docShell.deviceSizeIsPageSize;
this.docShell.deviceSizeIsPageSize = true;
try {
if (Services.prefs.getBoolPref("devtools.responsiveUI.rotate")) {
this.rotate();
@ -249,6 +256,8 @@ ResponsiveUI.prototype = {
return;
this.closing = true;
this.docShell.deviceSizeIsPageSize = this._deviceSizeWasPageSize;
this.browser.removeEventListener("load", this.bound_onPageLoad, true);
this.browser.removeEventListener("unload", this.bound_onPageUnload, true);
@ -288,6 +297,7 @@ ResponsiveUI.prototype = {
this.container.removeAttribute("responsivemode");
this.stack.removeAttribute("responsivemode");
delete this.docShell;
delete this.tab.__responsiveUI;
if (this.touchEventHandler)
this.touchEventHandler.stop();

View File

@ -9,3 +9,4 @@ support-files =
[browser_responsiveui.js]
[browser_responsiveui_touch.js]
[browser_responsiveuiaddcustompreset.js]
[browser_responsive_devicewidth.js]

View File

@ -0,0 +1,64 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
let instance;
let mgr = ResponsiveUI.ResponsiveUIManager;
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onload() {
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
waitForFocus(startTest, content);
}, true);
content.location = "data:text/html,mop";
function startTest() {
mgr.once("on", function() {executeSoon(onUIOpen)});
document.getElementById("Tools:ResponsiveUI").doCommand();
}
function onUIOpen() {
instance = gBrowser.selectedTab.__responsiveUI;
instance.stack.setAttribute("notransition", "true");
ok(instance, "instance of the module is attached to the tab.");
instance.setSize(110, 500);
ok(content.innerWidth, 110, "initial width is valid");
let mql = content.matchMedia("(max-device-width:100px)")
ok(!mql.matches, "media query doesn't match.");
mql.addListener(onMediaChange);
instance.setSize(90, 500);
}
function onMediaChange(mql) {
mql.removeListener(onMediaChange);
ok(mql.matches, "media query matches.");
ok(window.screen.width != content.screen.width, "screen.width is not the size of the screen.");
is(content.screen.width, 90, "screen.width is the width of the page.");
is(content.screen.height, 500, "screen.height is the height of the page.");
let docShell = content.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
mql.addListener(onMediaChange2);
docShell.deviceSizeIsPageSize = false;
}
function onMediaChange2(mql) {
mql.removeListener(onMediaChange);
ok(!mql.matches, "media query has been re-evaluated.");
ok(window.screen.width == content.screen.width, "screen.width is not the size of the screen.");
instance.stack.removeAttribute("notransition");
document.getElementById("Tools:ResponsiveUI").doCommand();
gBrowser.removeCurrentTab();
finish();
}
}

View File

@ -2,6 +2,10 @@
* 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/. */
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
this.EXPORTED_SYMBOLS = ["DOMHelpers"];
/**
@ -13,6 +17,9 @@ this.EXPORTED_SYMBOLS = ["DOMHelpers"];
* The content window, owning the document to traverse.
*/
this.DOMHelpers = function DOMHelpers(aWindow) {
if (!aWindow) {
throw new Error("window can't be null or undefined");
}
this.window = aWindow;
};
@ -120,5 +127,30 @@ DOMHelpers.prototype = {
{
delete this.window;
delete this.treeWalker;
},
/**
* A simple way to be notified (once) when a window becomes
* interactive (DOMContentLoaded).
*
* It is based on the chromeEventHandler. This is useful when
* chrome iframes are loaded in content docshells (in Firefox
* tabs for example).
*/
onceDOMReady: function Helpers_onLocationChange(callback) {
let window = this.window;
let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
let onReady = function(event) {
if (event.target == window.document) {
docShell.chromeEventHandler.removeEventListener("DOMContentLoaded", onReady, false);
// If in `callback` the URL of the window is changed and a listener to DOMContentLoaded
// is attached, the event we just received will be also be caught by the new listener.
// We want to avoid that so we execute the callback in the next queue.
Services.tm.mainThread.dispatch(callback, 0);
}
}
docShell.chromeEventHandler.addEventListener("DOMContentLoaded", onReady, false);
}
};

View File

@ -12,6 +12,7 @@
#banners-and-logs {
display: flex;
flex-grow: 1;
}
#logs {

View File

@ -14,6 +14,10 @@
background: #252C33;
}
#toolbox-tabs {
overflow-y: auto;
}
.button {
width: 80px;
height: 85px;
@ -54,6 +58,12 @@
display: none;
}
.button.toolbox {
background-repeat: no-repeat;
background-position: center 15px;
background-size: 40px 40px;
}
.projects-button {
background: url('chrome://browser/skin/devtools/app-manager/index-icons.svg') no-repeat;
background-position: left -5px;

View File

@ -1,9 +1,8 @@
#filter substitution
/* 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/. */
package @ANDROID_PACKAGE_NAME@;
package org.mozilla.gecko;
import java.util.List;
import java.util.ArrayList;

View File

@ -8,7 +8,7 @@
<uses-sdk android:minSdkVersion="8" />
<instrumentation
android:name="@ANDROID_PACKAGE_NAME@.FennecInstrumentationTestRunner"
android:name="org.mozilla.gecko.FennecInstrumentationTestRunner"
android:targetPackage="@ANDROID_PACKAGE_NAME@" />
<application

View File

@ -1,9 +1,8 @@
#filter substitution
/* 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/. */
package @ANDROID_PACKAGE_NAME@;
package org.mozilla.gecko;
public interface Assert {
void dumpLog(String message);

View File

@ -1,9 +1,8 @@
#filter substitution
/* 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/. */
package @ANDROID_PACKAGE_NAME@;
package org.mozilla.gecko;
import java.util.List;
import android.app.Activity;

View File

@ -1,9 +1,8 @@
#filter substitution
/* 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/. */
package @ANDROID_PACKAGE_NAME@;
package org.mozilla.gecko;
/**
* Element provides access to a specific UI view (android.view.View).

View File

@ -1,9 +1,8 @@
#filter substitution
/* 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/. */
package @ANDROID_PACKAGE_NAME@;
package org.mozilla.gecko;
import android.os.Bundle;
import android.test.InstrumentationTestRunner;

View File

@ -1,9 +1,8 @@
#filter substitution
/* 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/. */
package @ANDROID_PACKAGE_NAME@;
package org.mozilla.gecko;
import java.util.LinkedList;
import android.os.SystemClock;

View File

@ -1,9 +1,8 @@
#filter substitution
/* 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/. */
package @ANDROID_PACKAGE_NAME@;
package org.mozilla.gecko;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@ -28,7 +27,7 @@ import android.view.ViewConfiguration;
import com.jayway.android.robotium.solo.Solo;
import static @ANDROID_PACKAGE_NAME@.FennecNativeDriver.LogLevel;
import static org.mozilla.gecko.FennecNativeDriver.LogLevel;
public class FennecNativeActions implements Actions {
private Solo mSolo;

View File

@ -1,9 +1,8 @@
#filter substitution
/* 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/. */
package @ANDROID_PACKAGE_NAME@;
package org.mozilla.gecko;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;

View File

@ -1,9 +1,8 @@
#filter substitution
/* 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/. */
package @ANDROID_PACKAGE_NAME@;
package org.mozilla.gecko;
import android.app.Activity;
import android.view.View;

View File

@ -1,9 +1,8 @@
#filter substitution
/* 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/. */
package @ANDROID_PACKAGE_NAME@;
package org.mozilla.gecko;
public class FennecTalosAssert implements Assert {

View File

@ -30,18 +30,14 @@ _JAVA_HARNESS := \
PaintedSurface.java \
$(NULL)
# pre-process harness sources
PP_TARGETS += java-harness
java-harness := $(addprefix $(srcdir)/,$(addsuffix .in,$(_JAVA_HARNESS)))
java-harness-dep := $(addprefix $(CURDIR)/,$(_JAVA_HARNESS))
java-harness_PATH := $(CURDIR)
java-harness := $(addprefix $(srcdir)/,$(_JAVA_HARNESS))
java-tests := $(wildcard $(TESTPATH)/*.java)
# pre-process test sources
PP_TARGETS += java-tests
java-tests-src := $(wildcard $(TESTPATH)/*.java.in)
java-tests-dep := $(patsubst $(TESTPATH)/%.java.in,$(dir-tests)/%.java,$(java-tests-src))
java-tests := $(java-tests-src)
java-tests_PATH := $(dir-tests)
# pre-process TestConstants.java.in
PP_TARGETS += testconstants
testconstants-dep := $(dir-tests)/TestConstants.java
testconstants := $(TESTPATH)/TestConstants.java.in
testconstants_PATH := $(dir-tests)
PP_TARGETS += manifest
manifest := $(srcdir)/AndroidManifest.xml.in
@ -68,15 +64,15 @@ MOCHITEST_ROBOCOP_FILES := \
GARBAGE += \
AndroidManifest.xml \
$(java-tests-dep) \
$(java-harness-dep) \
$(robocop-deps) \
$(testconstants-dep) \
$(NULL)
JAVAFILES += \
$(java-harness) \
$(java-tests) \
$(robocop-deps) \
$(java-harness-dep) \
$(java-tests-dep) \
$(testconstants-dep) \
$(NULL)
DEFINES += \
@ -88,8 +84,3 @@ include $(topsrcdir)/config/rules.mk
tools:: $(ANDROID_APK_NAME).apk
GENERATED_DIRS += $(dir-tests)
# PP_java-tests not fully usable here
# Intermediate step toward a library rule.
$(dir-tests)/%.java: $(TESTPATH)/%.java.in $(call mkdir_deps,$(dir-tests))
$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $< > $@

View File

@ -1,9 +1,8 @@
#filter substitution
/* 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/. */
package @ANDROID_PACKAGE_NAME@;
package org.mozilla.gecko;
import android.graphics.Bitmap;
import android.util.Base64;

View File

@ -1,9 +1,8 @@
#filter substitution
/* 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/. */
package @ANDROID_PACKAGE_NAME@;
package org.mozilla.gecko;
public class RoboCopException extends RuntimeException {

View File

@ -1,10 +1,8 @@
#filter substitution
/* 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/. */
package @ANDROID_PACKAGE_NAME@;
package org.mozilla.gecko;
import android.app.Activity;

View File

@ -95,6 +95,10 @@ public:
virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> scope)
MOZ_OVERRIDE = 0;
void SetCapacity(uint32_t aCapacity)
{
mElements.SetCapacity(aCapacity);
}
protected:
/**
* To be called from non-destructor locations (e.g. unlink) that want to

View File

@ -2337,8 +2337,8 @@ AddScopeElements(TreeMatchContext& aMatchContext,
// Actually find elements matching aSelectorList (which must not be
// null) and which are descendants of aRoot and put them in aList. If
// onlyFirstMatch, then stop once the first one is found.
template<bool onlyFirstMatch, class T>
inline static nsresult
template<bool onlyFirstMatch, class Collector, class T>
MOZ_ALWAYS_INLINE static nsresult
FindMatchingElements(nsINode* aRoot, const nsAString& aSelector, T &aList)
{
@ -2424,6 +2424,7 @@ FindMatchingElements(nsINode* aRoot, const nsAString& aSelector, T &aList)
return NS_OK;
}
Collector results;
for (nsIContent* cur = aRoot->GetFirstChild();
cur;
cur = cur->GetNextNode(aRoot)) {
@ -2431,10 +2432,19 @@ FindMatchingElements(nsINode* aRoot, const nsAString& aSelector, T &aList)
nsCSSRuleProcessor::SelectorListMatches(cur->AsElement(),
matchingContext,
selectorList)) {
aList.AppendElement(cur->AsElement());
if (onlyFirstMatch) {
aList.AppendElement(cur->AsElement());
return NS_OK;
}
results.AppendElement(cur->AsElement());
}
}
const uint32_t len = results.Length();
if (len) {
aList.SetCapacity(len);
for (uint32_t i = 0; i < len; ++i) {
aList.AppendElement(results.ElementAt(i));
}
}
@ -2447,6 +2457,10 @@ struct ElementHolder {
NS_ABORT_IF_FALSE(!mElement, "Should only get one element");
mElement = aElement;
}
void SetCapacity(uint32_t aCapacity) { MOZ_CRASH("Don't call me!"); }
uint32_t Length() { return 0; }
Element* ElementAt(uint32_t aIndex) { return nullptr; }
Element* mElement;
};
@ -2454,7 +2468,7 @@ Element*
nsINode::QuerySelector(const nsAString& aSelector, ErrorResult& aResult)
{
ElementHolder holder;
aResult = FindMatchingElements<true>(this, aSelector, holder);
aResult = FindMatchingElements<true, ElementHolder>(this, aSelector, holder);
return holder.mElement;
}
@ -2464,7 +2478,10 @@ nsINode::QuerySelectorAll(const nsAString& aSelector, ErrorResult& aResult)
{
nsRefPtr<nsSimpleContentList> contentList = new nsSimpleContentList(this);
aResult = FindMatchingElements<false>(this, aSelector, *contentList);
aResult =
FindMatchingElements<false, nsAutoTArray<Element*, 128>>(this,
aSelector,
*contentList);
return contentList.forget();
}

View File

@ -755,6 +755,7 @@ nsDocShell::nsDocShell():
mIsAppTab(false),
mUseGlobalHistory(false),
mInPrivateBrowsing(false),
mDeviceSizeIsPageSize(false),
mFiredUnloadEvent(false),
mEODForCurrentDocument(false),
mURIResultedInDocument(false),
@ -3920,6 +3921,27 @@ nsDocShell::GetCurrentSHEntry(nsISHEntry** aEntry, bool* aOSHE)
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::SetDeviceSizeIsPageSize(bool aValue)
{
if (mDeviceSizeIsPageSize != aValue) {
mDeviceSizeIsPageSize = aValue;
nsRefPtr<nsPresContext> presContext;
GetPresContext(getter_AddRefs(presContext));
if (presContext) {
presContext->MediaFeatureValuesChanged(presContext->eAlwaysRebuildStyle);
}
}
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::GetDeviceSizeIsPageSize(bool* aValue)
{
*aValue = mDeviceSizeIsPageSize;
return NS_OK;
}
void
nsDocShell::ClearFrameHistory(nsISHEntry* aEntry)
{
@ -4929,6 +4951,10 @@ nsDocShell::Create()
gAddedPreferencesVarCache = true;
}
mDeviceSizeIsPageSize =
Preferences::GetBool("docshell.device_size_is_page_size",
mDeviceSizeIsPageSize);
nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
if (serv) {
const char* msg = mItemType == typeContent ?

View File

@ -815,6 +815,7 @@ protected:
bool mIsAppTab;
bool mUseGlobalHistory;
bool mInPrivateBrowsing;
bool mDeviceSizeIsPageSize;
// This boolean is set to true right before we fire pagehide and generally
// unset when we embed a new content viewer. While it's true no navigation

View File

@ -43,7 +43,7 @@ interface nsIReflowObserver;
typedef unsigned long nsLoadFlags;
[scriptable, builtinclass, uuid(1470A132-99B2-44C3-B37D-D8093B2E29BF)]
[scriptable, builtinclass, uuid(77aca3ee-7417-4cd2-994e-9bd95ca1d98a)]
interface nsIDocShell : nsIDocShellTreeItem
{
/**
@ -907,4 +907,16 @@ interface nsIDocShell : nsIDocShellTreeItem
*/
[noscript, notxpcom] bool IsInvisible();
[noscript, notxpcom] void SetInvisible(in bool aIsInvisibleDochsell);
/**
* If deviceSizeIsPageSize is set to true, device-width/height media queries
* will be calculated from the page size, not the device size.
*
* Used by the Responsive Design View and B2G Simulator.
*
* Default is False.
* Default value can be overriden with
* docshell.device_size_is_page_size pref.
*/
[infallible] attribute boolean deviceSizeIsPageSize;
};

View File

@ -390,6 +390,19 @@ nsScreen::SlowMozUnlockOrientation()
return NS_OK;
}
bool
nsScreen::IsDeviceSizePageSize()
{
nsPIDOMWindow* owner = GetOwner();
if (owner) {
nsIDocShell* docShell = owner->GetDocShell();
if (docShell) {
return docShell->GetDeviceSizeIsPageSize();
}
}
return false;
}
/* virtual */
JSObject*
nsScreen::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)

View File

@ -51,6 +51,15 @@ public:
int32_t GetWidth(ErrorResult& aRv)
{
nsRect rect;
if (IsDeviceSizePageSize()) {
nsCOMPtr<nsPIDOMWindow> owner = GetOwner();
if (owner) {
int32_t innerWidth = 0;
aRv = owner->GetInnerWidth(&innerWidth);
return innerWidth;
}
}
aRv = GetRect(rect);
return rect.width;
}
@ -58,6 +67,15 @@ public:
int32_t GetHeight(ErrorResult& aRv)
{
nsRect rect;
if (IsDeviceSizePageSize()) {
nsCOMPtr<nsPIDOMWindow> owner = GetOwner();
if (owner) {
int32_t innerHeight = 0;
aRv = owner->GetInnerHeight(&innerHeight);
return innerHeight;
}
}
aRv = GetRect(rect);
return rect.height;
}
@ -137,6 +155,8 @@ private:
LockPermission GetLockOrientationPermission() const;
bool IsDeviceSizePageSize();
nsRefPtr<FullScreenEventListener> mEventListener;
};

View File

@ -410,7 +410,7 @@ CreateStrokeStyleForOptions(const StrokeOptions &aStrokeOptions)
capStyle, joinStyle,
aStrokeOptions.mMiterLimit,
D2D1_DASH_STYLE_CUSTOM,
aStrokeOptions.mDashOffset),
aStrokeOptions.mDashOffset / lineWidth),
&dash[0], // data() is not C++98, although it's in recent gcc
// and VC10's STL
dash.size(),

View File

@ -16,6 +16,7 @@
#include "mozilla/MouseEvents.h"
#include "mozilla/mozalloc.h" // for operator new
#include "mozilla/TouchEvents.h"
#include "nsDebug.h" // for NS_WARNING
#include "nsPoint.h" // for nsIntPoint
#include "nsTArray.h" // for nsTArray, nsTArray_Impl, etc
#include "nsThreadUtils.h" // for NS_IsMainThread
@ -29,7 +30,8 @@ namespace layers {
float APZCTreeManager::sDPI = 72.0;
APZCTreeManager::APZCTreeManager()
: mTreeLock("APZCTreeLock")
: mTreeLock("APZCTreeLock"),
mTouchCount(0)
{
MOZ_ASSERT(NS_IsMainThread());
AsyncPanZoomController::InitializeGlobalState();
@ -238,6 +240,7 @@ APZCTreeManager::ReceiveInputEvent(const InputData& aEvent)
case MULTITOUCH_INPUT: {
const MultiTouchInput& multiTouchInput = aEvent.AsMultiTouchInput();
if (multiTouchInput.mType == MultiTouchInput::MULTITOUCH_START) {
mTouchCount++;
mApzcForInputBlock = GetTargetAPZC(ScreenPoint(multiTouchInput.mTouches[0].mScreenPoint));
for (size_t i = 1; i < multiTouchInput.mTouches.Length(); i++) {
nsRefPtr<AsyncPanZoomController> apzc2 = GetTargetAPZC(ScreenPoint(multiTouchInput.mTouches[i].mScreenPoint));
@ -267,10 +270,18 @@ APZCTreeManager::ReceiveInputEvent(const InputData& aEvent)
ApplyTransform(&(inputForApzc.mTouches[i].mScreenPoint), transformToApzc);
}
result = mApzcForInputBlock->ReceiveInputEvent(inputForApzc);
}
if (multiTouchInput.mType == MultiTouchInput::MULTITOUCH_CANCEL ||
multiTouchInput.mType == MultiTouchInput::MULTITOUCH_END) {
if (mTouchCount >= multiTouchInput.mTouches.Length()) {
mTouchCount -= multiTouchInput.mTouches.Length();
} else {
NS_WARNING("Got an unexpected touchend/touchcancel");
mTouchCount = 0;
}
// If we have an mApzcForInputBlock and it's the end of the touch sequence
// then null it out so we don't keep a dangling reference and leak things.
if (multiTouchInput.mType == MultiTouchInput::MULTITOUCH_CANCEL ||
(multiTouchInput.mType == MultiTouchInput::MULTITOUCH_END && multiTouchInput.mTouches.Length() == 1)) {
if (mTouchCount == 0) {
mApzcForInputBlock = nullptr;
}
}
@ -333,31 +344,50 @@ nsEventStatus
APZCTreeManager::ProcessTouchEvent(const WidgetTouchEvent& aEvent,
WidgetTouchEvent* aOutEvent)
{
// For computing the input for the APZC, used the cached transform.
// This ensures that the sequence of touch points an APZC sees in an
// input block are all in the same coordinate space.
gfx3DMatrix transformToApzc = mCachedTransformToApzcForInputBlock;
MultiTouchInput inputForApzc(aEvent);
for (size_t i = 0; i < inputForApzc.mTouches.Length(); i++) {
ApplyTransform(&(inputForApzc.mTouches[i].mScreenPoint), transformToApzc);
nsEventStatus ret = nsEventStatus_eIgnore;
if (!aEvent.touches.Length()) {
return ret;
}
nsEventStatus ret = mApzcForInputBlock->ReceiveInputEvent(inputForApzc);
// For computing the event to pass back to Gecko, use the up-to-date transforms.
// This ensures that transformToApzc and transformToGecko are in sync
// (note that transformToGecko isn't cached).
gfx3DMatrix transformToGecko;
GetInputTransforms(mApzcForInputBlock, transformToApzc, transformToGecko);
gfx3DMatrix outTransform = transformToApzc * transformToGecko;
for (size_t i = 0; i < aOutEvent->touches.Length(); i++) {
ApplyTransform(&(aOutEvent->touches[i]->mRefPoint), outTransform);
if (aEvent.message == NS_TOUCH_START) {
mTouchCount++;
ScreenPoint point = ScreenPoint(aEvent.touches[0]->mRefPoint.x, aEvent.touches[0]->mRefPoint.y);
mApzcForInputBlock = GetTouchInputBlockAPZC(aEvent, point);
}
if (mApzcForInputBlock) {
// For computing the input for the APZC, used the cached transform.
// This ensures that the sequence of touch points an APZC sees in an
// input block are all in the same coordinate space.
gfx3DMatrix transformToApzc = mCachedTransformToApzcForInputBlock;
MultiTouchInput inputForApzc(aEvent);
for (size_t i = 0; i < inputForApzc.mTouches.Length(); i++) {
ApplyTransform(&(inputForApzc.mTouches[i].mScreenPoint), transformToApzc);
}
ret = mApzcForInputBlock->ReceiveInputEvent(inputForApzc);
// For computing the event to pass back to Gecko, use the up-to-date transforms.
// This ensures that transformToApzc and transformToGecko are in sync
// (note that transformToGecko isn't cached).
gfx3DMatrix transformToGecko;
GetInputTransforms(mApzcForInputBlock, transformToApzc, transformToGecko);
gfx3DMatrix outTransform = transformToApzc * transformToGecko;
for (size_t i = 0; i < aOutEvent->touches.Length(); i++) {
ApplyTransform(&(aOutEvent->touches[i]->mRefPoint), outTransform);
}
}
// If we have an mApzcForInputBlock and it's the end of the touch sequence
// then null it out so we don't keep a dangling reference and leak things.
if (aEvent.message == NS_TOUCH_CANCEL ||
(aEvent.message == NS_TOUCH_END && aEvent.touches.Length() == 1)) {
mApzcForInputBlock = nullptr;
aEvent.message == NS_TOUCH_END) {
if (mTouchCount >= aEvent.touches.Length()) {
mTouchCount -= aEvent.touches.Length();
} else {
NS_WARNING("Got an unexpected touchend/touchcancel");
mTouchCount = 0;
}
if (mTouchCount == 0) {
mApzcForInputBlock = nullptr;
}
}
return ret;
}
@ -406,16 +436,6 @@ APZCTreeManager::ReceiveInputEvent(const WidgetInputEvent& aEvent,
switch (aEvent.eventStructType) {
case NS_TOUCH_EVENT: {
const WidgetTouchEvent& touchEvent = *aEvent.AsTouchEvent();
if (!touchEvent.touches.Length()) {
return nsEventStatus_eIgnore;
}
if (touchEvent.message == NS_TOUCH_START) {
ScreenPoint point = ScreenPoint(touchEvent.touches[0]->mRefPoint.x, touchEvent.touches[0]->mRefPoint.y);
mApzcForInputBlock = GetTouchInputBlockAPZC(touchEvent, point);
}
if (!mApzcForInputBlock) {
return nsEventStatus_eIgnore;
}
return ProcessTouchEvent(touchEvent, aOutEvent->AsTouchEvent());
}
case NS_MOUSE_EVENT: {
@ -438,16 +458,6 @@ APZCTreeManager::ReceiveInputEvent(WidgetInputEvent& aEvent)
switch (aEvent.eventStructType) {
case NS_TOUCH_EVENT: {
WidgetTouchEvent& touchEvent = *aEvent.AsTouchEvent();
if (!touchEvent.touches.Length()) {
return nsEventStatus_eIgnore;
}
if (touchEvent.message == NS_TOUCH_START) {
ScreenPoint point = ScreenPoint(touchEvent.touches[0]->mRefPoint.x, touchEvent.touches[0]->mRefPoint.y);
mApzcForInputBlock = GetTouchInputBlockAPZC(touchEvent, point);
}
if (!mApzcForInputBlock) {
return nsEventStatus_eIgnore;
}
return ProcessTouchEvent(touchEvent, &touchEvent);
}
default: {

View File

@ -321,6 +321,8 @@ private:
* input delivery thread, and so does not require locking.
*/
nsRefPtr<AsyncPanZoomController> mApzcForInputBlock;
/* The number of touch points we are tracking that are currently on the screen. */
uint32_t mTouchCount;
/* The transform from root screen coordinates into mApzcForInputBlock's
* screen coordinates, as returned through the 'aTransformToApzcOut' parameter
* of GetInputTransform(), at the start of the input block. This is cached

View File

@ -1,5 +1,5 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=4 ts=8 et tw=80 : */
/* vim: set sw=2 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/. */
@ -73,11 +73,7 @@ nsEventStatus GestureEventListener::HandleInputEvent(const InputData& aEvent)
}
}
NS_WARN_IF_FALSE(!foundAlreadyExistingTouch, "Tried to add a touch that already exists");
// If we didn't find a touch in our list that matches this, then add it.
// If it already existed, we don't want to add it twice because that
// messes with our touch move/end code.
if (!foundAlreadyExistingTouch) {
mTouches.AppendElement(event.mTouches[i]);
}
@ -137,18 +133,17 @@ nsEventStatus GestureEventListener::HandleInputEvent(const InputData& aEvent)
}
case MultiTouchInput::MULTITOUCH_END:
case MultiTouchInput::MULTITOUCH_LEAVE: {
bool foundAlreadyExistingTouch = false;
for (size_t i = 0; i < event.mTouches.Length() && !foundAlreadyExistingTouch; i++) {
for (size_t i = 0; i < event.mTouches.Length(); i++) {
bool foundAlreadyExistingTouch = false;
for (size_t j = 0; j < mTouches.Length() && !foundAlreadyExistingTouch; j++) {
if (event.mTouches[i].mIdentifier == mTouches[j].mIdentifier) {
foundAlreadyExistingTouch = true;
mTouches.RemoveElementAt(j);
}
}
NS_WARN_IF_FALSE(foundAlreadyExistingTouch, "Touch ended, but not in list");
}
NS_WARN_IF_FALSE(foundAlreadyExistingTouch, "Touch ended, but not in list");
if (mState == GESTURE_WAITING_DOUBLE_TAP) {
CancelDoubleTapTimeoutTask();
if (mTapStartTime - mLastTapEndTime > MAX_TAP_TIME ||

View File

@ -1,5 +1,5 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=4 ts=8 et tw=80 : */
/* vim: set sw=2 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/. */

View File

@ -250,63 +250,141 @@ static inline void js_free(void* p)
}\
\
template <class T, class P1>\
QUALIFIERS T *NEWNAME(P1 p1) {\
JS_NEW_BODY(ALLOCATOR, T, (p1))\
QUALIFIERS T *NEWNAME(P1 &&p1) {\
JS_NEW_BODY(ALLOCATOR, T,\
(mozilla::Forward<P1>(p1)))\
}\
\
template <class T, class P1, class P2>\
QUALIFIERS T *NEWNAME(P1 p1, P2 p2) {\
JS_NEW_BODY(ALLOCATOR, T, (p1, p2))\
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2) {\
JS_NEW_BODY(ALLOCATOR, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2)))\
}\
\
template <class T, class P1, class P2, class P3>\
QUALIFIERS T *NEWNAME(P1 p1, P2 p2, P3 p3) {\
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3))\
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3) {\
JS_NEW_BODY(ALLOCATOR, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3)))\
}\
\
template <class T, class P1, class P2, class P3, class P4>\
QUALIFIERS T *NEWNAME(P1 p1, P2 p2, P3 p3, P4 p4) {\
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4))\
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4) {\
JS_NEW_BODY(ALLOCATOR, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3),\
mozilla::Forward<P4>(p4)))\
}\
\
template <class T, class P1, class P2, class P3, class P4, class P5>\
QUALIFIERS T *NEWNAME(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {\
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5))\
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5) {\
JS_NEW_BODY(ALLOCATOR, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3),\
mozilla::Forward<P4>(p4),\
mozilla::Forward<P5>(p5)))\
}\
\
template <class T, class P1, class P2, class P3, class P4, class P5, class P6>\
QUALIFIERS T *NEWNAME(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) {\
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6))\
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6) {\
JS_NEW_BODY(ALLOCATOR, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3),\
mozilla::Forward<P4>(p4),\
mozilla::Forward<P5>(p5),\
mozilla::Forward<P6>(p6)))\
}\
\
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7>\
QUALIFIERS T *NEWNAME(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) {\
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7))\
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7) {\
JS_NEW_BODY(ALLOCATOR, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3),\
mozilla::Forward<P4>(p4),\
mozilla::Forward<P5>(p5),\
mozilla::Forward<P6>(p6),\
mozilla::Forward<P7>(p7)))\
}\
\
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>\
QUALIFIERS T *NEWNAME(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) {\
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7, p8))\
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8) {\
JS_NEW_BODY(ALLOCATOR, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3),\
mozilla::Forward<P4>(p4),\
mozilla::Forward<P5>(p5),\
mozilla::Forward<P6>(p6),\
mozilla::Forward<P7>(p7),\
mozilla::Forward<P8>(p8)))\
}\
\
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9>\
QUALIFIERS T *NEWNAME(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9) {\
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7, p8, p9))\
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9) {\
JS_NEW_BODY(ALLOCATOR, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3),\
mozilla::Forward<P4>(p4),\
mozilla::Forward<P5>(p5),\
mozilla::Forward<P6>(p6),\
mozilla::Forward<P7>(p7),\
mozilla::Forward<P8>(p8),\
mozilla::Forward<P9>(p9)))\
}\
\
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10>\
QUALIFIERS T *NEWNAME(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10) {\
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10))\
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9, P10 &&p10) {\
JS_NEW_BODY(ALLOCATOR, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3),\
mozilla::Forward<P4>(p4),\
mozilla::Forward<P5>(p5),\
mozilla::Forward<P6>(p6),\
mozilla::Forward<P7>(p7),\
mozilla::Forward<P8>(p8),\
mozilla::Forward<P9>(p9),\
mozilla::Forward<P10>(p10)))\
}\
\
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10, class P11>\
QUALIFIERS T *NEWNAME(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11) {\
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11))\
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9, P10 &&p10, P11 &&p11) {\
JS_NEW_BODY(ALLOCATOR, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3),\
mozilla::Forward<P4>(p4),\
mozilla::Forward<P5>(p5),\
mozilla::Forward<P6>(p6),\
mozilla::Forward<P7>(p7),\
mozilla::Forward<P8>(p8),\
mozilla::Forward<P9>(p9),\
mozilla::Forward<P10>(p10),\
mozilla::Forward<P11>(p11)))\
}\
\
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10, class P11, class P12>\
QUALIFIERS T *NEWNAME(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11, P12 p12) {\
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12))\
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9, P10 &&p10, P11 &&p11, P12 &&p12) {\
JS_NEW_BODY(ALLOCATOR, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3),\
mozilla::Forward<P4>(p4),\
mozilla::Forward<P5>(p5),\
mozilla::Forward<P6>(p6),\
mozilla::Forward<P7>(p7),\
mozilla::Forward<P8>(p8),\
mozilla::Forward<P9>(p9),\
mozilla::Forward<P10>(p10),\
mozilla::Forward<P11>(p11),\
mozilla::Forward<P12>(p12)))\
}\
JS_DECLARE_NEW_METHODS(js_new, js_malloc, static JS_ALWAYS_INLINE)

View File

@ -0,0 +1,13 @@
// |jit-test| error: InternalError
function f(){
var j;
f(0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9);
}
f()

View File

@ -489,7 +489,14 @@ BaselineCompiler::emitStackCheck(bool earlyCheck)
pushArg(Imm32(tolerance));
masm.loadBaselineFramePtr(BaselineFrameReg, R1.scratchReg());
pushArg(R1.scratchReg());
if (!callVM(CheckOverRecursedWithExtraInfo, /*preInitialize=*/earlyCheck))
CallVMPhase phase = POST_INITIALIZE;
if (earlyCheck)
phase = PRE_INITIALIZE;
else if (needsEarlyStackCheck())
phase = CHECK_OVER_RECURSED;
if (!callVM(CheckOverRecursedWithExtraInfo, phase))
return false;
masm.bind(&skipCall);
@ -536,6 +543,10 @@ static const VMFunction HeavyweightFunPrologueInfo =
bool
BaselineCompiler::initScopeChain()
{
CallVMPhase phase = POST_INITIALIZE;
if (needsEarlyStackCheck())
phase = CHECK_OVER_RECURSED;
RootedFunction fun(cx, function());
if (fun) {
// Use callee->environment as scope chain. Note that we do
@ -554,7 +565,7 @@ BaselineCompiler::initScopeChain()
masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
pushArg(R0.scratchReg());
if (!callVM(HeavyweightFunPrologueInfo))
if (!callVM(HeavyweightFunPrologueInfo, phase))
return false;
}
} else {
@ -568,7 +579,7 @@ BaselineCompiler::initScopeChain()
masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
pushArg(R0.scratchReg());
if (!callVM(StrictEvalPrologueInfo))
if (!callVM(StrictEvalPrologueInfo, phase))
return false;
}
}

View File

@ -1976,7 +1976,7 @@ AnalyzePoppedThis(JSContext *cx, types::TypeObject *type,
RootedId id(cx, NameToId(setprop->name()));
RootedValue value(cx, UndefinedValue());
if (!DefineNativeProperty(cx, baseobj, id, value, nullptr, nullptr,
JSPROP_ENUMERATE, 0, 0, DNP_SKIP_TYPE))
JSPROP_ENUMERATE, 0, 0))
{
return false;
}

View File

@ -6310,14 +6310,9 @@ IonBuilder::setStaticName(JSObject *staticObject, PropertyName *name)
// If the property has a known type, we may be able to optimize typed stores by not
// storing the type tag.
MIRType slotType = MIRType_None;
{
Shape *shape = staticObject->nativeLookup(cx, id);
if (!shape || !shape->hasSlot() || !staticObject->getSlot(shape->slot()).isUndefined()) {
JSValueType knownType = property.knownTypeTag(constraints());
if (knownType != JSVAL_TYPE_UNKNOWN)
slotType = MIRTypeFromValueType(knownType);
}
}
JSValueType knownType = property.knownTypeTag(constraints());
if (knownType != JSVAL_TYPE_UNKNOWN)
slotType = MIRTypeFromValueType(knownType);
bool needsBarrier = property.needsBarrier(constraints());
return storeSlot(obj, property.maybeTypes()->definiteSlot(), NumFixedSlots(staticObject),

View File

@ -462,7 +462,7 @@ SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValu
// required for initializing 'const' closure variables.
Shape *shape = obj->nativeLookup(cx, name);
JS_ASSERT(shape && shape->hasSlot());
JSObject::nativeSetSlotWithType(cx, obj, shape, value);
obj->nativeSetSlotWithType(cx, shape, value);
return true;
}

View File

@ -31,7 +31,7 @@ BaselineCompilerShared::BaselineCompilerShared(JSContext *cx, HandleScript scrip
{ }
bool
BaselineCompilerShared::callVM(const VMFunction &fun, bool preInitialize)
BaselineCompilerShared::callVM(const VMFunction &fun, CallVMPhase phase)
{
IonCode *code = cx->runtime()->jitRuntime()->getVMWrapper(fun);
if (!code)
@ -50,14 +50,43 @@ BaselineCompilerShared::callVM(const VMFunction &fun, bool preInitialize)
// Assert all arguments were pushed.
JS_ASSERT(masm.framePushed() - pushedBeforeCall_ == argSize);
uint32_t frameVals = preInitialize ? 0 : frame.nlocals() + frame.stackDepth();
uint32_t frameSize = BaselineFrame::FramePointerOffset + BaselineFrame::Size() +
(frameVals * sizeof(Value));
Address frameSizeAddress(BaselineFrameReg, BaselineFrame::reverseOffsetOfFrameSize());
uint32_t frameVals = frame.nlocals() + frame.stackDepth();
uint32_t frameBaseSize = BaselineFrame::FramePointerOffset + BaselineFrame::Size();
uint32_t frameFullSize = frameBaseSize + (frameVals * sizeof(Value));
if (phase == POST_INITIALIZE) {
masm.store32(Imm32(frameFullSize), frameSizeAddress);
uint32_t descriptor = MakeFrameDescriptor(frameFullSize + argSize, IonFrame_BaselineJS);
masm.push(Imm32(descriptor));
masm.store32(Imm32(frameSize), Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFrameSize()));
} else if (phase == PRE_INITIALIZE) {
masm.store32(Imm32(frameBaseSize), frameSizeAddress);
uint32_t descriptor = MakeFrameDescriptor(frameBaseSize + argSize, IonFrame_BaselineJS);
masm.push(Imm32(descriptor));
uint32_t descriptor = MakeFrameDescriptor(frameSize + argSize, IonFrame_BaselineJS);
masm.push(Imm32(descriptor));
} else {
JS_ASSERT(phase == CHECK_OVER_RECURSED);
Label afterWrite;
Label writePostInitialize;
// If OVER_RECURSED is set, then frame locals haven't been pushed yet.
masm.branchTest32(Assembler::Zero,
frame.addressOfFlags(),
Imm32(BaselineFrame::OVER_RECURSED),
&writePostInitialize);
masm.move32(Imm32(frameBaseSize), BaselineTailCallReg);
masm.jump(&afterWrite);
masm.bind(&writePostInitialize);
masm.move32(Imm32(frameFullSize), BaselineTailCallReg);
masm.bind(&afterWrite);
masm.store32(BaselineTailCallReg, frameSizeAddress);
masm.add32(Imm32(argSize), BaselineTailCallReg);
masm.makeFrameDescriptor(BaselineTailCallReg, IonFrame_BaselineJS);
masm.push(BaselineTailCallReg);
}
// Perform the call.
masm.call(code);

View File

@ -127,7 +127,12 @@ class BaselineCompilerShared
masm.Push(BaselineFrameReg);
}
bool callVM(const VMFunction &fun, bool preInitialize=false);
enum CallVMPhase {
POST_INITIALIZE,
PRE_INITIALIZE,
CHECK_OVER_RECURSED
};
bool callVM(const VMFunction &fun, CallVMPhase phase=POST_INITIALIZE);
public:
BytecodeAnalysis &analysis() {

View File

@ -520,7 +520,8 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
/* Restore all saved variables. :FIXME: maybe do this precisely. */
for (unsigned i = 0; i < savedCount; i++) {
LifetimeVariable &var = *saved[i];
var.lifetime = alloc.new_<Lifetime>(offset, var.savedEnd, var.saved);
uint32_t savedEnd = var.savedEnd;
var.lifetime = alloc.new_<Lifetime>(offset, savedEnd, var.saved);
if (!var.lifetime) {
js_free(saved);
setOOM(cx);
@ -612,7 +613,8 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
* Jumping to a place where this variable is live. Make a new
* lifetime segment for the variable.
*/
var.lifetime = alloc.new_<Lifetime>(offset, var.savedEnd, var.saved);
uint32_t savedEnd = var.savedEnd;
var.lifetime = alloc.new_<Lifetime>(offset, savedEnd, var.saved);
if (!var.lifetime) {
js_free(saved);
setOOM(cx);
@ -676,7 +678,8 @@ ScriptAnalysis::addVariable(JSContext *cx, LifetimeVariable &var, unsigned offse
}
}
}
var.lifetime = cx->typeLifoAlloc().new_<Lifetime>(offset, var.savedEnd, var.saved);
uint32_t savedEnd = var.savedEnd;
var.lifetime = cx->typeLifoAlloc().new_<Lifetime>(offset, savedEnd, var.saved);
if (!var.lifetime) {
setOOM(cx);
return;
@ -691,7 +694,8 @@ ScriptAnalysis::killVariable(JSContext *cx, LifetimeVariable &var, unsigned offs
{
if (!var.lifetime) {
/* Make a point lifetime indicating the write. */
Lifetime *lifetime = cx->typeLifoAlloc().new_<Lifetime>(offset, var.savedEnd, var.saved);
uint32_t savedEnd = var.savedEnd;
Lifetime *lifetime = cx->typeLifoAlloc().new_<Lifetime>(offset, savedEnd, var.saved);
if (!lifetime) {
setOOM(cx);
return;

View File

@ -286,7 +286,7 @@ SetArrayElement(JSContext *cx, HandleObject obj, double index, HandleValue v)
break;
if (idx >= arr->length())
arr->setLengthInt32(idx + 1);
JSObject::setDenseElementWithType(cx, arr, idx, v);
arr->setDenseElementWithType(cx, idx, v);
return true;
} while (false);
@ -677,14 +677,12 @@ js::ArraySetLength(typename ExecutionModeTraits<mode>::ContextType cxArg,
RootedValue v(cxArg, NumberValue(newLen));
if (mode == ParallelExecution) {
// Adding the property type or overflowing int32 requires changing TI
// state.
if (!HasTypePropertyId(arr, id, v) || newLen > INT32_MAX)
// Overflowing int32 requires changing TI state.
if (newLen > INT32_MAX)
return false;
arr->setLengthInt32(newLen);
} else {
JSContext *cx = cxArg->asJSContext();
AddTypePropertyId(cx, arr, id, v);
ArrayObject::setLength(cx, arr, newLen);
}
@ -2022,7 +2020,7 @@ NewbornArrayPushImpl(JSContext *cx, HandleObject obj, const Value &v)
arr->setDenseInitializedLength(length + 1);
arr->setLengthInt32(length + 1);
JSObject::initDenseElementWithType(cx, arr, length, v);
arr->initDenseElementWithType(cx, length, v);
return true;
}
@ -2066,7 +2064,7 @@ js::array_push(JSContext *cx, unsigned argc, Value *vp)
if (result == JSObject::ED_OK) {
for (uint32_t i = 0, index = length; i < argCount; index++, i++)
JSObject::setDenseElementWithType(cx, obj, index, args[i]);
obj->setDenseElementWithType(cx, index, args[i]);
uint32_t newlength = length + argCount;
args.rval().setNumber(newlength);
if (obj->is<ArrayObject>()) {

View File

@ -1000,7 +1000,7 @@ class ConstraintDataFreeze
const char *kind() { return "freeze"; }
bool invalidateOnNewType(Type type) { return true; }
bool invalidateOnNewPropertyState(TypeSet *property) { return false; }
bool invalidateOnNewPropertyState(TypeSet *property) { return true; }
bool invalidateOnNewObjectState(TypeObject *object) { return false; }
bool constraintHolds(JSContext *cx,
@ -1103,7 +1103,7 @@ HeapTypeSetKey::knownTypeTag(CompilerConstraintList *constraints)
bool
HeapTypeSetKey::isOwnProperty(CompilerConstraintList *constraints)
{
if (maybeTypes() && !maybeTypes()->empty())
if (maybeTypes() && (!maybeTypes()->empty() || maybeTypes()->configuredProperty()))
return true;
if (JSObject *obj = object()->singleton()) {
if (CanHaveEmptyPropertyTypesForOwnProperty(obj))
@ -1138,9 +1138,9 @@ TemporaryTypeSet::getSingleton()
JSObject *
HeapTypeSetKey::singleton(CompilerConstraintList *constraints)
{
TypeSet *types = maybeTypes();
HeapTypeSet *types = maybeTypes();
if (!types || types->baseFlags() != 0 || types->getObjectCount() != 1)
if (!types || types->configuredProperty() || types->baseFlags() != 0 || types->getObjectCount() != 1)
return nullptr;
JSObject *obj = types->getSingleObject(0);

View File

@ -536,7 +536,7 @@ MarkTypeObjectUnknownProperties(JSContext *cx, TypeObject *obj,
* have a getter/setter.
*/
inline void
MarkTypePropertyConfigured(ExclusiveContext *cx, HandleObject obj, jsid id)
MarkTypePropertyConfigured(ExclusiveContext *cx, JSObject *obj, jsid id)
{
if (cx->typeInferenceEnabled()) {
id = IdToTypeId(id);

View File

@ -1442,9 +1442,9 @@ js::NewObjectWithClassProtoCommon(ExclusiveContext *cxArg,
* Create a plain object with the specified type. This bypasses getNewType to
* avoid losing creation site information for objects made by scripted 'new'.
*/
static JSObject *
NewObjectWithType(JSContext *cx, HandleTypeObject type, JSObject *parent, gc::AllocKind allocKind,
NewObjectKind newKind = GenericObject)
JSObject *
js::NewObjectWithType(JSContext *cx, HandleTypeObject type, JSObject *parent, gc::AllocKind allocKind,
NewObjectKind newKind)
{
JS_ASSERT(type->proto->hasNewType(&JSObject::class_, type));
JS_ASSERT(parent);
@ -1500,46 +1500,6 @@ js::NewObjectScriptedCall(JSContext *cx, MutableHandleObject pobj)
return true;
}
JSObject *
js::NewReshapedObject(JSContext *cx, HandleTypeObject type, JSObject *parent,
gc::AllocKind allocKind, HandleShape shape, NewObjectKind newKind)
{
RootedObject res(cx, NewObjectWithType(cx, type, parent, allocKind, newKind));
if (!res)
return nullptr;
if (shape->isEmptyShape())
return res;
/* Get all the ids in the object, in order. */
js::AutoIdVector ids(cx);
{
for (unsigned i = 0; i <= shape->slot(); i++) {
if (!ids.append(JSID_VOID))
return nullptr;
}
Shape *nshape = shape;
while (!nshape->isEmptyShape()) {
ids[nshape->slot()] = nshape->propid();
nshape = nshape->previous();
}
}
/* Construct the new shape. */
RootedId id(cx);
RootedValue undefinedValue(cx, UndefinedValue());
for (unsigned i = 0; i < ids.length(); i++) {
id = ids[i];
if (!DefineNativeProperty(cx, res, id, undefinedValue, nullptr, nullptr,
JSPROP_ENUMERATE, 0, 0, DNP_SKIP_TYPE)) {
return nullptr;
}
}
JS_ASSERT(!res->inDictionaryMode());
return res;
}
JSObject*
js::CreateThis(JSContext *cx, const Class *newclasp, HandleObject callee)
{
@ -2224,7 +2184,6 @@ DefineStandardSlot(JSContext *cx, HandleObject obj, JSProtoKey key, JSAtom *atom
uint32_t slot = GlobalObject::constructorPropertySlot(key);
if (!JSObject::addProperty(cx, obj, id, JS_PropertyStub, JS_StrictPropertyStub, slot, attrs, 0, 0))
return false;
AddTypePropertyId(cx, obj, id, v);
named = true;
return true;
@ -3431,7 +3390,7 @@ CallAddPropertyHook(typename ExecutionModeTraits<mode>::ExclusiveContextType cxA
}
if (value.get() != nominal) {
if (shape->hasSlot())
JSObject::nativeSetSlotWithType(cx, obj, shape, value);
obj->nativeSetSlotWithType(cx, shape, value);
}
}
return true;
@ -3473,16 +3432,43 @@ CallAddPropertyHookDense(typename ExecutionModeTraits<mode>::ExclusiveContextTyp
Rooted<jsid> id(cx, INT_TO_JSID(index));
if (!CallJSPropertyOp(cx->asJSContext(), clasp->addProperty, obj, id, &value)) {
JSObject::setDenseElementHole(cx, obj, index);
obj->setDenseElementHole(cx, index);
return false;
}
if (value.get() != nominal)
JSObject::setDenseElementWithType(cx, obj, index, value);
obj->setDenseElementWithType(cx, index, value);
}
return true;
}
template <ExecutionMode mode>
static bool
UpdateShapeTypeAndValue(typename ExecutionModeTraits<mode>::ExclusiveContextType cx,
JSObject *obj, Shape *shape, const Value &value)
{
jsid id = shape->propid();
if (shape->hasSlot()) {
if (mode == ParallelExecution) {
if (!obj->nativeSetSlotIfHasType(shape, value))
return false;
} else {
obj->nativeSetSlotWithType(cx->asExclusiveContext(), shape, value);
}
}
if (!shape->hasSlot() || !shape->writable() ||
!shape->hasDefaultGetter() || !shape->hasDefaultSetter())
{
if (mode == ParallelExecution) {
if (!IsTypePropertyIdMarkedConfigured(obj, id))
return false;
} else {
MarkTypePropertyConfigured(cx->asExclusiveContext(), obj, id);
}
}
return true;
}
template <ExecutionMode mode>
static inline bool
DefinePropertyOrElement(typename ExecutionModeTraits<mode>::ExclusiveContextType cx,
@ -3517,7 +3503,12 @@ DefinePropertyOrElement(typename ExecutionModeTraits<mode>::ExclusiveContextType
if (result == JSObject::ED_FAILED)
return false;
if (result == JSObject::ED_OK) {
obj->setDenseElementMaybeConvertDouble(index, value);
if (mode == ParallelExecution) {
if (!obj->setDenseElementIfHasType(index, value))
return false;
} else {
obj->setDenseElementWithType(cx->asExclusiveContext(), index, value);
}
return CallAddPropertyHookDense<mode>(cx, obj->getClass(), obj, index, value);
}
}
@ -3549,8 +3540,8 @@ DefinePropertyOrElement(typename ExecutionModeTraits<mode>::ExclusiveContextType
if (!shape)
return false;
if (shape->hasSlot())
obj->nativeSetSlot(shape->slot(), value);
if (!UpdateShapeTypeAndValue<mode>(cx, obj, shape, value))
return false;
/*
* Clear any existing dense index after adding a sparse indexed property,
@ -3594,7 +3585,7 @@ js::DefineNativeProperty(ExclusiveContext *cx, HandleObject obj, HandleId id, Ha
PropertyOp getter, StrictPropertyOp setter, unsigned attrs,
unsigned flags, int shortid, unsigned defineHow /* = 0 */)
{
JS_ASSERT((defineHow & ~(DNP_DONT_PURGE | DNP_SKIP_TYPE)) == 0);
JS_ASSERT((defineHow & ~DNP_DONT_PURGE) == 0);
JS_ASSERT(!(attrs & JSPROP_NATIVE_ACCESSORS));
AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
@ -3606,10 +3597,6 @@ js::DefineNativeProperty(ExclusiveContext *cx, HandleObject obj, HandleId id, Ha
*/
RootedShape shape(cx);
if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
/* Type information for getter/setter properties is unknown. */
AddTypePropertyId(cx, obj, id, types::Type::UnknownType());
MarkTypePropertyConfigured(cx, obj, id);
/*
* If we are defining a getter whose setter was already defined, or
* vice versa, finish the job via obj->changeProperty.
@ -3656,24 +3643,13 @@ js::DefineNativeProperty(ExclusiveContext *cx, HandleObject obj, HandleId id, Ha
if (!setter && !(attrs & JSPROP_SETTER))
setter = clasp->setProperty;
if ((getter == JS_PropertyStub) && !(defineHow & DNP_SKIP_TYPE)) {
/*
* Type information for normal native properties should reflect the
* initial value of the property.
*/
AddTypePropertyId(cx, obj, id, value);
if (attrs & JSPROP_READONLY)
MarkTypePropertyConfigured(cx, obj, id);
}
if (!shape) {
return DefinePropertyOrElement<SequentialExecution>(cx, obj, id, getter, setter,
attrs, flags, shortid, value,
false, false);
}
if (shape->hasSlot())
obj->nativeSetSlot(shape->slot(), value);
JS_ALWAYS_TRUE(UpdateShapeTypeAndValue<SequentialExecution>(cx, obj, shape, value));
return CallAddPropertyHook<SequentialExecution>(cx, clasp, obj, shape, value);
}
@ -4162,7 +4138,7 @@ js::NativeSet(typename ExecutionModeTraits<mode>::ContextType cxArg,
if (!obj->nativeSetSlotIfHasType(shape, vp))
return false;
} else {
obj->nativeSetSlotWithType(cxArg->asExclusiveContext(), obj, shape, vp);
obj->nativeSetSlotWithType(cxArg->asExclusiveContext(), shape, vp);
}
return true;
@ -4197,8 +4173,7 @@ js::NativeSet(typename ExecutionModeTraits<mode>::ContextType cxArg,
if (shape->hasSlot() &&
(JS_LIKELY(cx->runtime()->propertyRemovals == sample) ||
obj->nativeContains(cx, shape)))
{
AddTypePropertyId(cx, obj, shape->propid(), ovp);
{
obj->setSlot(shape->slot(), vp);
}
@ -4242,10 +4217,6 @@ GetPropertyHelperInline(JSContext *cx,
return false;
}
/* Record non-undefined values produced by the class getter hook. */
if (!vp.isUndefined())
AddTypePropertyId(cx, obj, id, vp);
/*
* Give a strict warning if foo.bar is evaluated by a script for an
* object foo with no property named 'bar'.
@ -4830,7 +4801,7 @@ baseops::SetPropertyHelper(typename ExecutionModeTraits<mode>::ContextType cxArg
if (mode == ParallelExecution)
obj->setDenseElementIfHasType(index, vp);
else
JSObject::setDenseElementWithType(cxArg->asJSContext(), obj, index, vp);
obj->setDenseElementWithType(cxArg->asJSContext(), index, vp);
return true;
}
@ -4871,9 +4842,6 @@ baseops::SetPropertyHelper(typename ExecutionModeTraits<mode>::ContextType cxArg
/* Purge the property cache of now-shadowed id in obj's scope chain. */
if (!PurgeScopeChain(cx, obj, id))
return false;
if (getter == JS_PropertyStub)
AddTypePropertyId(cx, obj, id, vp);
}
return DefinePropertyOrElement<mode>(cxArg, obj, id, getter, setter,
@ -4937,9 +4905,15 @@ baseops::SetAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *a
return false;
shape = obj->nativeLookup(cx, id);
}
return nobj->isNative()
? JSObject::changePropertyAttributes(cx, nobj, shape, *attrsp)
: JSObject::setGenericAttributes(cx, nobj, id, attrsp);
if (nobj->isNative()) {
if (!JSObject::changePropertyAttributes(cx, nobj, shape, *attrsp))
return false;
if (*attrsp & JSPROP_READONLY)
MarkTypePropertyConfigured(cx, obj, id);
return true;
} else {
return JSObject::setGenericAttributes(cx, nobj, id, attrsp);
}
}
bool
@ -4965,7 +4939,7 @@ baseops::DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, bool *succe
if (!succeeded)
return true;
JSObject::setDenseElementHole(cx, obj, JSID_TO_INT(id));
obj->setDenseElementHole(cx, JSID_TO_INT(id));
return js_SuppressDeletedProperty(cx, obj, id);
}

View File

@ -409,10 +409,8 @@ class JSObject : public js::ObjectImpl
}
inline bool nativeSetSlotIfHasType(js::Shape *shape, const js::Value &value);
static inline void nativeSetSlotWithType(js::ExclusiveContext *cx,
js::HandleObject, js::Shape *shape,
const js::Value &value);
inline void nativeSetSlotWithType(js::ExclusiveContext *cx, js::Shape *shape,
const js::Value &value);
inline const js::Value &getReservedSlot(uint32_t index) const {
JS_ASSERT(index < JSSLOT_FREE(getClass()));
@ -642,12 +640,11 @@ class JSObject : public js::ObjectImpl
}
inline bool setDenseElementIfHasType(uint32_t index, const js::Value &val);
static inline void setDenseElementWithType(js::ExclusiveContext *cx, js::HandleObject obj,
uint32_t index, const js::Value &val);
static inline void initDenseElementWithType(js::ExclusiveContext *cx, js::HandleObject obj,
uint32_t index, const js::Value &val);
static inline void setDenseElementHole(js::ExclusiveContext *cx,
js::HandleObject obj, uint32_t index);
inline void setDenseElementWithType(js::ExclusiveContext *cx, uint32_t index,
const js::Value &val);
inline void initDenseElementWithType(js::ExclusiveContext *cx, uint32_t index,
const js::Value &val);
inline void setDenseElementHole(js::ExclusiveContext *cx, uint32_t index);
static inline void removeDenseElementForSparseIndex(js::ExclusiveContext *cx,
js::HandleObject obj, uint32_t index);
@ -1394,7 +1391,6 @@ const unsigned DNP_DONT_PURGE = 1; /* suppress js_PurgeScopeChain */
const unsigned DNP_UNQUALIFIED = 2; /* Unqualified property set. Only used in
the defineHow argument of
js_SetPropertyHelper. */
const unsigned DNP_SKIP_TYPE = 4; /* Don't update type information */
/*
* Return successfully added or changed shape or nullptr on error.

View File

@ -43,7 +43,6 @@ JSObject::deleteProperty(JSContext *cx, js::HandleObject obj, js::HandleProperty
bool *succeeded)
{
JS::RootedId id(cx, js::NameToId(name));
js::types::AddTypePropertyId(cx, obj, id, js::types::Type::UndefinedType());
js::types::MarkTypePropertyConfigured(cx, obj, id);
js::DeletePropertyOp op = obj->getOps()->deleteProperty;
return (op ? op : js::baseops::DeleteProperty)(cx, obj, name, succeeded);
@ -55,7 +54,6 @@ JSObject::deleteElement(JSContext *cx, js::HandleObject obj, uint32_t index, boo
JS::RootedId id(cx);
if (!js::IndexToId(cx, index, &id))
return false;
js::types::AddTypePropertyId(cx, obj, id, js::types::Type::UndefinedType());
js::types::MarkTypePropertyConfigured(cx, obj, id);
js::DeleteElementOp op = obj->getOps()->deleteElement;
return (op ? op : js::baseops::DeleteElement)(cx, obj, index, succeeded);
@ -66,7 +64,6 @@ JSObject::deleteSpecial(JSContext *cx, js::HandleObject obj, js::HandleSpecialId
bool *succeeded)
{
JS::RootedId id(cx, SPECIALID_TO_JSID(sid));
js::types::AddTypePropertyId(cx, obj, id, js::types::Type::UndefinedType());
js::types::MarkTypePropertyConfigured(cx, obj, id);
js::DeleteSpecialOp op = obj->getOps()->deleteSpecial;
return (op ? op : js::baseops::DeleteSpecial)(cx, obj, sid, succeeded);
@ -145,32 +142,32 @@ JSObject::setDenseElementIfHasType(uint32_t index, const js::Value &val)
return true;
}
/* static */ inline void
JSObject::setDenseElementWithType(js::ExclusiveContext *cx, js::HandleObject obj, uint32_t index,
inline void
JSObject::setDenseElementWithType(js::ExclusiveContext *cx, uint32_t index,
const js::Value &val)
{
// Avoid a slow AddTypePropertyId call if the type is the same as the type
// of the previous element.
js::types::Type thisType = js::types::GetValueType(val);
if (index == 0 || js::types::GetValueType(obj->elements[index - 1]) != thisType)
js::types::AddTypePropertyId(cx, obj, JSID_VOID, thisType);
obj->setDenseElementMaybeConvertDouble(index, val);
if (index == 0 || js::types::GetValueType(elements[index - 1]) != thisType)
js::types::AddTypePropertyId(cx, this, JSID_VOID, thisType);
setDenseElementMaybeConvertDouble(index, val);
}
/* static */ inline void
JSObject::initDenseElementWithType(js::ExclusiveContext *cx, js::HandleObject obj, uint32_t index,
inline void
JSObject::initDenseElementWithType(js::ExclusiveContext *cx, uint32_t index,
const js::Value &val)
{
JS_ASSERT(!obj->shouldConvertDoubleElements());
js::types::AddTypePropertyId(cx, obj, JSID_VOID, val);
obj->initDenseElement(index, val);
JS_ASSERT(!shouldConvertDoubleElements());
js::types::AddTypePropertyId(cx, this, JSID_VOID, val);
initDenseElement(index, val);
}
/* static */ inline void
JSObject::setDenseElementHole(js::ExclusiveContext *cx, js::HandleObject obj, uint32_t index)
inline void
JSObject::setDenseElementHole(js::ExclusiveContext *cx, uint32_t index)
{
js::types::MarkTypeObjectFlags(cx, obj, js::types::OBJECT_FLAG_NON_PACKED);
obj->setDenseElement(index, js::MagicValue(JS_ELEMENTS_HOLE));
js::types::MarkTypeObjectFlags(cx, this, js::types::OBJECT_FLAG_NON_PACKED);
setDenseElement(index, js::MagicValue(JS_ELEMENTS_HOLE));
}
/* static */ inline void
@ -535,12 +532,12 @@ JSObject::nativeSetSlotIfHasType(js::Shape *shape, const js::Value &value)
return true;
}
/* static */ inline void
JSObject::nativeSetSlotWithType(js::ExclusiveContext *cx, js::HandleObject obj, js::Shape *shape,
inline void
JSObject::nativeSetSlotWithType(js::ExclusiveContext *cx, js::Shape *shape,
const js::Value &value)
{
obj->nativeSetSlot(shape->slot(), value);
js::types::AddTypePropertyId(cx, obj, shape->propid(), value);
nativeSetSlot(shape->slot(), value);
js::types::AddTypePropertyId(cx, this, shape->propid(), value);
}
/* static */ inline bool
@ -903,6 +900,10 @@ CopyInitializerObject(JSContext *cx, HandleObject baseobj, NewObjectKind newKind
return obj;
}
JSObject *
NewObjectWithType(JSContext *cx, HandleTypeObject type, JSObject *parent, gc::AllocKind allocKind,
NewObjectKind newKind = GenericObject);
JSObject *
NewReshapedObject(JSContext *cx, HandleTypeObject type, JSObject *parent,
gc::AllocKind allocKind, HandleShape shape,
@ -945,7 +946,6 @@ DefineConstructorAndPrototype(JSContext *cx, Handle<GlobalObject*> global,
global->setPrototype(key, ObjectValue(*proto));
global->setConstructorPropertySlot(key, ObjectValue(*ctor));
types::AddTypePropertyId(cx, global, id, ObjectValue(*ctor));
if (!global->addDataProperty(cx, id, GlobalObject::constructorPropertySlot(key), 0)) {
global->setConstructor(key, UndefinedValue());
global->setPrototype(key, UndefinedValue());
@ -953,6 +953,7 @@ DefineConstructorAndPrototype(JSContext *cx, Handle<GlobalObject*> global,
return false;
}
types::AddTypePropertyId(cx, global, id, ObjectValue(*ctor));
return true;
}

View File

@ -23,8 +23,6 @@ ArrayObject::setLength(ExclusiveContext *cx, Handle<ArrayObject*> arr, uint32_t
if (length > INT32_MAX) {
/* Track objects with overflowing lengths in type information. */
types::MarkTypeObjectFlags(cx, arr, types::OBJECT_FLAG_LENGTH_OVERFLOW);
jsid lengthId = NameToId(cx->names().length);
types::AddTypePropertyId(cx, arr, lengthId, types::Type::DoubleType());
}
arr->getElementsHeader()->length = length;

View File

@ -411,7 +411,7 @@ js::intrinsic_UnsafePutElements(JSContext *cx, unsigned argc, Value *vp)
if (arrobj->isNative()) {
JS_ASSERT(idx < arrobj->getDenseInitializedLength());
JSObject::setDenseElementWithType(cx, arrobj, idx, args[elemi]);
arrobj->setDenseElementWithType(cx, idx, args[elemi]);
} else {
JS_ASSERT(idx < arrobj->as<TypedArrayObject>().length());
RootedValue tmp(cx, args[elemi]);

View File

@ -673,6 +673,61 @@ JSObject::addPropertyInternal<ParallelExecution>(ForkJoinSlice *cx,
unsigned flags, int shortid, Shape **spp,
bool allowDictionary);
JSObject *
js::NewReshapedObject(JSContext *cx, HandleTypeObject type, JSObject *parent,
gc::AllocKind allocKind, HandleShape shape, NewObjectKind newKind)
{
RootedObject res(cx, NewObjectWithType(cx, type, parent, allocKind, newKind));
if (!res)
return nullptr;
if (shape->isEmptyShape())
return res;
/* Get all the ids in the object, in order. */
js::AutoIdVector ids(cx);
{
for (unsigned i = 0; i <= shape->slot(); i++) {
if (!ids.append(JSID_VOID))
return nullptr;
}
Shape *nshape = shape;
while (!nshape->isEmptyShape()) {
ids[nshape->slot()] = nshape->propid();
nshape = nshape->previous();
}
}
/* Construct the new shape, without updating type information. */
RootedId id(cx);
RootedShape newShape(cx, res->lastProperty());
for (unsigned i = 0; i < ids.length(); i++) {
id = ids[i];
JS_ASSERT(!res->nativeContains(cx, id));
uint32_t index;
bool indexed = js_IdIsIndex(id, &index);
Rooted<UnownedBaseShape*> nbase(cx, newShape->base()->toUnowned());
if (indexed) {
StackBaseShape base(nbase);
base.flags |= BaseShape::INDEXED;
nbase = GetOrLookupUnownedBaseShape<SequentialExecution>(cx, base);
if (!nbase)
return nullptr;
}
StackShape child(nbase, id, i, res->numFixedSlots(), JSPROP_ENUMERATE, 0, 0);
newShape = cx->compartment()->propertyTree.getChild(cx, newShape, res->numFixedSlots(), child);
if (!newShape)
return nullptr;
if (!JSObject::setLastProperty(cx, res, newShape))
return nullptr;
}
return res;
}
/*
* Check and adjust the new attributes for the shape to make sure that our
* slot access optimizations are sound. It is responsibility of the callers to
@ -925,16 +980,6 @@ JSObject::changeProperty(typename ExecutionModeTraits<mode>::ExclusiveContextTyp
types::MarkTypePropertyConfigured(cx->asExclusiveContext(), obj, shape->propid());
}
if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
if (mode == ParallelExecution) {
if (!types::HasTypePropertyId(obj, shape->propid(), types::Type::UnknownType()))
return nullptr;
} else {
types::AddTypePropertyId(cx->asExclusiveContext(), obj, shape->propid(),
types::Type::UnknownType());
}
}
if (getter == JS_PropertyStub)
getter = nullptr;
if (setter == JS_StrictPropertyStub)

View File

@ -1260,6 +1260,13 @@ nsLayoutUtils::GetActiveScrolledRootFor(nsIFrame* aFrame,
nsIFrame* parent = GetCrossDocParentFrame(f);
if (!parent)
break;
nsIAtom* parentType = parent->GetType();
#ifdef ANDROID
// Treat the slider thumb as being as an active scrolled root
// on mobile so that it can move without repainting.
if (parentType == nsGkAtoms::sliderFrame)
break;
#endif
// Sticky frames are active if their nearest scrollable frame
// is also active, just keep a record of sticky frames that we
// encounter for now.
@ -1267,8 +1274,8 @@ nsLayoutUtils::GetActiveScrolledRootFor(nsIFrame* aFrame,
!stickyFrame) {
stickyFrame = f;
}
nsIScrollableFrame* sf = do_QueryFrame(parent);
if (sf) {
if (parentType == nsGkAtoms::scrollFrame) {
nsIScrollableFrame* sf = do_QueryFrame(parent);
if (sf->IsScrollingActive() && sf->GetScrolledFrame() == f) {
// If we found a sticky frame inside this active scroll frame,
// then use that. Otherwise use the scroll frame.

View File

@ -2688,6 +2688,17 @@ nsPresContext::AppUnitsToGfxUnits(nscoord aAppUnits) const
return mDeviceContext->AppUnitsToGfxUnits(aAppUnits);
}
bool
nsPresContext::IsDeviceSizePageSize()
{
bool isDeviceSizePageSize = false;
nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mContainer));
if (docShell) {
isDeviceSizePageSize = docShell->GetDeviceSizeIsPageSize();
}
return isDeviceSizePageSize;
}
nsRootPresContext::nsRootPresContext(nsIDocument* aDocument,
nsPresContextType aType)
: nsPresContext(aDocument, aType),

View File

@ -1000,6 +1000,8 @@ public:
mExistThrottledUpdates = aExistThrottledUpdates;
}
bool IsDeviceSizePageSize();
protected:
friend class nsRunnableMethod<nsPresContext>;
NS_HIDDEN_(void) ThemeChangedInternal();

View File

@ -113,14 +113,18 @@ static nsSize
GetDeviceSize(nsPresContext* aPresContext)
{
nsSize size;
if (aPresContext->IsRootPaginatedDocument())
if (aPresContext->IsDeviceSizePageSize()) {
size = GetSize(aPresContext);
} else if (aPresContext->IsRootPaginatedDocument()) {
// We want the page size, including unprintable areas and margins.
// XXX The spec actually says we want the "page sheet size", but
// how is that different?
size = aPresContext->GetPageSize();
else
} else {
GetDeviceContextFor(aPresContext)->
GetDeviceSurfaceDimensions(size.width, size.height);
}
return size;
}

View File

@ -20,16 +20,9 @@ import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ -49,6 +42,10 @@ public class GeckoView extends LayerView
boolean doInit = a.getBoolean(R.styleable.GeckoView_doinit, true);
a.recycle();
// TODO: Fennec currently takes care of its own initialization, so this
// flag is a hack used in Fennec to prevent GeckoView initialization.
// This should go away once Fennec also uses GeckoView for
// initialization.
if (!doInit)
return;
@ -97,12 +94,17 @@ public class GeckoView extends LayerView
ThreadUtils.setUiThread(Thread.currentThread(), new Handler());
initializeView(GeckoAppShell.getEventDispatcher());
GeckoProfile profile = GeckoProfile.get(context).forceCreate();
BrowserDB.initialize(profile.getName());
if (GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.Launching, GeckoThread.LaunchState.Launched)) {
// This is the first launch, so finish initialization and go.
GeckoProfile profile = GeckoProfile.get(context).forceCreate();
BrowserDB.initialize(profile.getName());
GeckoAppShell.setLayerView(this);
GeckoThread.createAndStart();
} else if(GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) {
// If Gecko is already running, that means the Activity was
// destroyed, so we need to re-attach Gecko to this GeckoView.
connectToGecko();
}
}
@ -195,7 +197,7 @@ public class GeckoView extends LayerView
});
}
private void handleReady(final JSONObject message) {
private void connectToGecko() {
GeckoThread.setLaunchState(GeckoThread.LaunchState.GeckoRunning);
Tab selectedTab = Tabs.getInstance().getSelectedTab();
if (selectedTab != null)
@ -203,8 +205,10 @@ public class GeckoView extends LayerView
geckoConnected();
GeckoAppShell.setLayerClient(getLayerClient());
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Viewport:Flush", null));
show();
requestRender();
}
private void handleReady(final JSONObject message) {
connectToGecko();
if (mChromeDelegate != null) {
mChromeDelegate.onReady(this);

View File

@ -1,8 +1,7 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
import com.jayway.android.robotium.solo.Condition;
import @ANDROID_PACKAGE_NAME@.*;
import org.mozilla.gecko.*;
import android.content.ContentResolver;
import android.database.Cursor;

View File

@ -1,9 +1,8 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
import com.jayway.android.robotium.solo.Condition;
import com.jayway.android.robotium.solo.Solo;
import @ANDROID_PACKAGE_NAME@.*;
import org.mozilla.gecko.*;
import android.app.Activity;
import android.app.Instrumentation;
@ -46,7 +45,7 @@ abstract class BaseTest extends ActivityInstrumentationTestCase2<Activity> {
public static final int TEST_TALOS = 1;
private static final String TARGET_PACKAGE_ID = "org.mozilla.gecko";
private static final String LAUNCH_ACTIVITY_FULL_CLASSNAME ="@ANDROID_PACKAGE_NAME@.App";
private static final String LAUNCH_ACTIVITY_FULL_CLASSNAME = TestConstants.ANDROID_PACKAGE_NAME + ".App";
private static final int VERIFY_URL_TIMEOUT = 2000;
private static final int MAX_LIST_ATTEMPTS = 3;
private static final int MAX_WAIT_ENABLED_TEXT_MS = 10000;

View File

@ -1,7 +1,6 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
import @ANDROID_PACKAGE_NAME@.*;
import org.mozilla.gecko.*;
import android.content.ContentResolver;
import android.util.DisplayMetrics;

View File

@ -1,5 +1,4 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
import android.content.ContentProvider;
import android.content.ContentValues;

View File

@ -1,7 +1,6 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
import @ANDROID_PACKAGE_NAME@.*;
import org.mozilla.gecko.*;
import android.app.Activity;
import android.content.ContentResolver;
@ -39,7 +38,7 @@ class DatabaseHelper {
protected Uri buildUri(BrowserDataType dataType) {
Uri uri = null;
if (dataType == BrowserDataType.BOOKMARKS || dataType == BrowserDataType.HISTORY) {
uri = Uri.parse("content://@ANDROID_PACKAGE_NAME@.db.browser/" + dataType.toString().toLowerCase());
uri = Uri.parse("content://" + TestConstants.ANDROID_PACKAGE_NAME + ".db.browser/" + dataType.toString().toLowerCase());
} else {
mAsserter.ok(false, "The wrong data type has been provided = " + dataType.toString(), "Please provide the correct data type");
}

View File

@ -1,7 +1,6 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
import @ANDROID_PACKAGE_NAME@.*;
import org.mozilla.gecko.*;
import android.util.Log;

View File

@ -1,5 +1,4 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
import android.app.Instrumentation;
import android.os.SystemClock;

View File

@ -1,5 +1,4 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
import java.io.BufferedReader;
import java.io.InputStream;

View File

@ -1,7 +1,6 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
import @ANDROID_PACKAGE_NAME@.*;
import org.mozilla.gecko.*;
abstract class PixelTest extends BaseTest {
private static final long PAINT_CLEAR_DELAY = 10000; // milliseconds

View File

@ -1,7 +1,6 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
import @ANDROID_PACKAGE_NAME@.*;
import org.mozilla.gecko.*;
class StringHelper {
// Note: DEFAULT_BOOKMARKS_TITLES.length == DEFAULT_BOOKMARKS_URLS.length

View File

@ -0,0 +1,11 @@
#filter substitution
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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/. */
package org.mozilla.gecko;
public class TestConstants {
public static final String ANDROID_PACKAGE_NAME = "@ANDROID_PACKAGE_NAME@";
}

View File

@ -1,7 +1,6 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
import @ANDROID_PACKAGE_NAME@.*;
import org.mozilla.gecko.*;
/* Tests related to the about: page:
* - check that about: loads from the URL bar

View File

@ -1,7 +1,6 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
import @ANDROID_PACKAGE_NAME@.*;
import org.mozilla.gecko.*;
import android.view.View;
import android.widget.ListAdapter;
import android.widget.ListView;

View File

@ -1,7 +1,6 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
import @ANDROID_PACKAGE_NAME@.*;
import org.mozilla.gecko.*;
import android.util.DisplayMetrics;
import org.json.JSONArray;

View File

@ -1,5 +1,4 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
public class testAwesomebar extends BaseTest {
@Override

View File

@ -1,5 +1,4 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
import com.jayway.android.robotium.solo.Solo;
@ -7,7 +6,7 @@ import android.widget.ListView;
import android.widget.TabWidget;
import android.support.v4.view.ViewPager;
import @ANDROID_PACKAGE_NAME@.*;
import org.mozilla.gecko.*;
/* Tests swiping between tabs on the awesome bar and other basic
awesome bar tab selections.

View File

@ -1,7 +1,6 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
import @ANDROID_PACKAGE_NAME@.*;
import org.mozilla.gecko.*;
/**
* Basic test for axis locking behaviour.

View File

@ -1,7 +1,6 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
import @ANDROID_PACKAGE_NAME@.*;
import org.mozilla.gecko.*;
import android.view.View;
import android.widget.ListView;

View File

@ -1,7 +1,6 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
import @ANDROID_PACKAGE_NAME@.*;
import org.mozilla.gecko.*;
import com.jayway.android.robotium.solo.Condition;

View File

@ -1,7 +1,6 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
import @ANDROID_PACKAGE_NAME@.*;
import org.mozilla.gecko.*;
public class testBookmarkKeyword extends AboutHomeTest {

View File

@ -1,7 +1,6 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
import @ANDROID_PACKAGE_NAME@.*;
import org.mozilla.gecko.*;
import android.database.Cursor;
import android.widget.ListView;

View File

@ -1,7 +1,6 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
import @ANDROID_PACKAGE_NAME@.*;
import org.mozilla.gecko.*;
public class testBookmarksPage extends AboutHomeTest {

View File

@ -1,5 +1,4 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
import android.content.ContentValues;
import android.content.ContentUris;

View File

@ -1,5 +1,4 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
import android.content.ContentResolver;
import android.content.ContentValues;

View File

@ -1,7 +1,6 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
import @ANDROID_PACKAGE_NAME@.*;
import org.mozilla.gecko.*;
import android.app.Activity;
import android.content.Context;
import android.support.v4.app.Fragment;

View File

@ -1,5 +1,4 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
public class testCheck extends PixelTest {
private void pause(int length) {

View File

@ -1,5 +1,4 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
public class testCheck2 extends PixelTest {
@Override

View File

@ -1,7 +1,6 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
import @ANDROID_PACKAGE_NAME@.*;
import org.mozilla.gecko.*;
import java.util.ArrayList;
public class testClearPrivateData extends PixelTest {

View File

@ -1,7 +1,6 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
import @ANDROID_PACKAGE_NAME@.*;
import org.mozilla.gecko.*;
public class testDeviceSearchEngine extends JavascriptTest {

View File

@ -1,7 +1,6 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
import @ANDROID_PACKAGE_NAME@.*;
import org.mozilla.gecko.*;
import android.app.Activity;
import android.content.Context;

View File

@ -1,7 +1,6 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
package org.mozilla.gecko.tests;
import @ANDROID_PACKAGE_NAME@.*;
import org.mozilla.gecko.*;
import android.app.Activity;
import android.content.SharedPreferences;

Some files were not shown because too many files have changed in this diff Show More