зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to inbound
This commit is contained in:
Коммит
aa27f88eb0
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"revision": "ab0d6e1927a4fbce5d171555044557c1b7ba25c3",
|
||||
"revision": "0af41c1c297f1b784fb103e6150910f334036f20",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
},
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -9,3 +9,4 @@ support-files =
|
|||
[browser_responsiveui.js]
|
||||
[browser_responsiveui_touch.js]
|
||||
[browser_responsiveuiaddcustompreset.js]
|
||||
[browser_responsive_devicewidth.js]
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#banners-and-logs {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
#logs {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -755,6 +755,7 @@ nsDocShell::nsDocShell():
|
|||
mIsAppTab(false),
|
||||
mUseGlobalHistory(false),
|
||||
mInPrivateBrowsing(false),
|
||||
mDeviceSizeIsPageSize(false),
|
||||
mFiredUnloadEvent(false),
|
||||
mEODForCurrentDocument(false),
|
||||
mURIResultedInDocument(false),
|
||||
|
@ -3926,6 +3927,27 @@ nsDocShell::GetScriptGlobalObject()
|
|||
return mScriptGlobal;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -4935,6 +4957,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 ?
|
||||
|
|
|
@ -810,6 +810,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
|
||||
|
|
|
@ -44,7 +44,7 @@ interface nsIReflowObserver;
|
|||
|
||||
typedef unsigned long nsLoadFlags;
|
||||
|
||||
[scriptable, builtinclass, uuid(5c9adf31-8e4a-4d8d-8daf-9999e6002697)]
|
||||
[scriptable, builtinclass, uuid(55ca6545-7ce4-49ad-8117-8286ca9c61bb)]
|
||||
interface nsIDocShell : nsIDocShellTreeItem
|
||||
{
|
||||
/**
|
||||
|
@ -913,4 +913,16 @@ interface nsIDocShell : nsIDocShellTreeItem
|
|||
* Get the script global for the document in this docshell.
|
||||
*/
|
||||
[noscript,notxpcom,nostdcall] nsIScriptGlobalObject GetScriptGlobalObject();
|
||||
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ||
|
||||
|
|
|
@ -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/. */
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -1000,6 +1000,8 @@ public:
|
|||
mExistThrottledUpdates = aExistThrottledUpdates;
|
||||
}
|
||||
|
||||
bool IsDeviceSizePageSize();
|
||||
|
||||
protected:
|
||||
friend class nsRunnableMethod<nsPresContext>;
|
||||
NS_HIDDEN_(void) ThemeChangedInternal();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -3,13 +3,8 @@
|
|||
android:versionCode="1"
|
||||
android:versionName="1.0" >
|
||||
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="8"
|
||||
android:targetSdkVersion="17" />
|
||||
|
|
|
@ -9,11 +9,32 @@ GECKOVIEW_LIBRARY_FILES := \
|
|||
.project \
|
||||
AndroidManifest.xml \
|
||||
project.properties \
|
||||
build.xml \
|
||||
$(NULL)
|
||||
|
||||
|
||||
PP_TARGETS = properties
|
||||
|
||||
properties = local.properties.in
|
||||
properties_PATH = .
|
||||
properties_deps := $(patsubst %.in,%,$(properties))
|
||||
|
||||
GARBAGE = $(GECKOVIEW_LIBRARY_FILES) $(properties_deps)
|
||||
|
||||
GARBAGE_DIRS = \
|
||||
bin \
|
||||
libs \
|
||||
src \
|
||||
.deps \
|
||||
gen \
|
||||
res \
|
||||
$(NULL)
|
||||
|
||||
DEFINES += -DANDROID_SDK=$(ANDROID_SDK)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
package:
|
||||
package: $(properties_deps)
|
||||
# Make directory for the zips
|
||||
$(MKDIR) -p $(DIST)/geckoview_library
|
||||
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="GeckoView" default="help">
|
||||
|
||||
<!-- The local.properties file is created and updated by the 'android' tool.
|
||||
It contains the path to the SDK. It should *NOT* be checked into
|
||||
Version Control Systems. -->
|
||||
<property file="local.properties" />
|
||||
|
||||
<!-- The ant.properties file can be created by you. It is only edited by the
|
||||
'android' tool to add properties to it.
|
||||
This is the place to change some Ant specific build properties.
|
||||
Here are some properties you may want to change/update:
|
||||
|
||||
source.dir
|
||||
The name of the source directory. Default is 'src'.
|
||||
out.dir
|
||||
The name of the output directory. Default is 'bin'.
|
||||
|
||||
For other overridable properties, look at the beginning of the rules
|
||||
files in the SDK, at tools/ant/build.xml
|
||||
|
||||
Properties related to the SDK location or the project target should
|
||||
be updated using the 'android' tool with the 'update' action.
|
||||
|
||||
This file is an integral part of the build system for your
|
||||
application and should be checked into Version Control Systems.
|
||||
|
||||
-->
|
||||
<!--<property file="ant.properties" />-->
|
||||
|
||||
<!-- if sdk.dir was not set from one of the property file, then
|
||||
get it from the ANDROID_HOME env var.
|
||||
This must be done before we load project.properties since
|
||||
the proguard config can use sdk.dir -->
|
||||
<property environment="env" />
|
||||
<condition property="sdk.dir" value="${env.ANDROID_HOME}">
|
||||
<isset property="env.ANDROID_HOME" />
|
||||
</condition>
|
||||
|
||||
<!-- The project.properties file is created and updated by the 'android'
|
||||
tool, as well as ADT.
|
||||
|
||||
This contains project specific properties such as project target, and library
|
||||
dependencies. Lower level build properties are stored in ant.properties
|
||||
(or in .classpath for Eclipse projects).
|
||||
|
||||
This file is an integral part of the build system for your
|
||||
application and should be checked into Version Control Systems. -->
|
||||
<loadproperties srcFile="project.properties" />
|
||||
|
||||
<!-- quick check on sdk.dir -->
|
||||
<fail
|
||||
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
|
||||
unless="sdk.dir"
|
||||
/>
|
||||
|
||||
<!--
|
||||
Import per project custom build rules if present at the root of the project.
|
||||
This is the place to put custom intermediary targets such as:
|
||||
-pre-build
|
||||
-pre-compile
|
||||
-post-compile (This is typically used for code obfuscation.
|
||||
Compiled code location: ${out.classes.absolute.dir}
|
||||
If this is not done in place, override ${out.dex.input.absolute.dir})
|
||||
-post-package
|
||||
-post-build
|
||||
-pre-clean
|
||||
-->
|
||||
<import file="custom_rules.xml" optional="true" />
|
||||
|
||||
<!-- Import the actual build file.
|
||||
|
||||
To customize existing targets, there are two options:
|
||||
- Customize only one target:
|
||||
- copy/paste the target into this file, *before* the
|
||||
<import> task.
|
||||
- customize it to your needs.
|
||||
- Customize the whole content of build.xml
|
||||
- copy/paste the content of the rules files (minus the top node)
|
||||
into this file, replacing the <import> task.
|
||||
- customize to your needs.
|
||||
|
||||
***********************
|
||||
****** IMPORTANT ******
|
||||
***********************
|
||||
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
|
||||
in order to avoid having your file be overridden by tools such as "android update project"
|
||||
-->
|
||||
<!-- version-tag: 1 -->
|
||||
<import file="${sdk.dir}/tools/ant/build.xml" />
|
||||
|
||||
</project>
|
|
@ -0,0 +1,11 @@
|
|||
#filter substitution
|
||||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
# This file must *NOT* be checked into Version Control Systems,
|
||||
# as it contains information specific to your local configuration.
|
||||
|
||||
# location of the SDK. This is only used by Ant
|
||||
# For customization when using a Version Control System, please read the
|
||||
# header note.
|
||||
sdk.dir=@ANDROID_SDK@/../../
|
|
@ -66,7 +66,7 @@ body {
|
|||
|
||||
.header > h1 {
|
||||
font-size: 2.625em;
|
||||
font-weight: 300;
|
||||
font-weight: 700;
|
||||
line-height: 1.1em;
|
||||
width: 100%;
|
||||
margin: 0px;
|
||||
|
@ -75,10 +75,6 @@ body {
|
|||
padding: 0px;
|
||||
}
|
||||
|
||||
.serif > .header > h1 {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.header > .credits {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
|
|
|
@ -281,12 +281,8 @@ nsJARInputStream::ContinueInflate(char* aBuffer, uint32_t aCount,
|
|||
inflateEnd(&mZs);
|
||||
|
||||
// stop returning valid data as soon as we know we have a bad CRC
|
||||
if (mOutCrc != mInCrc) {
|
||||
// asserting because while this rarely happens, you definitely
|
||||
// want to catch it in debug builds!
|
||||
NS_NOTREACHED(0);
|
||||
if (mOutCrc != mInCrc)
|
||||
return NS_ERROR_FILE_CORRUPTED;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
|
|
@ -440,31 +440,8 @@
|
|||
"content/events/test/test_bug322588.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/events/test/test_bug493251.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/events/test/test_bug545268.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/events/test/test_bug650493.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/events/test/test_bug656379-1.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/events/test/test_bug656379-2.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/events/test/test_bug656954.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/events/test/test_bug659350.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/events/test/test_bug662678.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/events/test/test_bug667612.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/events/test/test_bug698929.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/events/test/test_bug741666.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/events/test/test_bug742376.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/events/test/test_bug812744.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/events/test/test_bug847597.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/events/test/test_bug855741.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/events/test/test_bug864040.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/events/test/test_clickevent_on_input.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/events/test/test_dblclick_explicit_original_target.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/events/test/test_dom_keyboard_event.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/events/test/test_dom_mouse_event.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/events/test/test_draggableprop.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/events/test/test_eventctors.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/events/test/test_focus_disabled.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/events/test/test_moz_mouse_pixel_scroll_event.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/html/content/test/forms/test_button_attributes_reflection.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/html/content/test/forms/test_change_event.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/html/content/test/forms/test_form_attribute-1.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/html/content/test/forms/test_input_event.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/html/content/test/forms/test_input_range_key_events.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"content/html/content/test/forms/test_input_range_rounding.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
|
@ -705,26 +682,14 @@
|
|||
"dom/tests/mochitest/general/test__content.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"dom/tests/mochitest/general/test_bug628069_1.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"dom/tests/mochitest/general/test_bug631440.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"dom/tests/mochitest/general/test_frameElementWrapping.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"dom/tests/mochitest/general/test_framedhistoryframes.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"dom/tests/mochitest/general/test_interfaces.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"dom/tests/mochitest/general/test_offsets.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"dom/tests/mochitest/general/test_outerHTML.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"dom/tests/mochitest/general/test_outerHTML.xhtml": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"dom/tests/mochitest/general/test_stylesheetPI.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"dom/tests/mochitest/general/test_vibrator.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"dom/tests/mochitest/general/test_windowProperties.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"dom/tests/mochitest/general/test_windowedhistoryframes.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"dom/tests/mochitest/sessionstorage/test_sessionStorageClone.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"dom/tests/mochitest/sessionstorage/test_sessionStorageReplace.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"dom/tests/mochitest/whatwg/test_postMessage_closed.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"layout/base/tests/test_bug607529.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"layout/base/tests/test_bug749186.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"layout/base/tests/test_bug770106.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"layout/base/tests/test_bug842853.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"layout/base/tests/test_bug842853-2.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"layout/base/tests/test_bug858459.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"layout/base/tests/test_reftests_with_caret.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"layout/base/tests/test_remote_frame.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"layout/generic/test/test_bug735641.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"layout/generic/test/test_bug784410.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
|
@ -732,10 +697,6 @@
|
|||
"layout/generic/test/test_plugin_clipping2.xhtml": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"layout/generic/test/test_plugin_clipping_table.xhtml": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"layout/generic/test/test_plugin_clipping_transformed.xhtml": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"layout/style/test/test_property_syntax_errors.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"layout/style/test/test_redundant_font_download.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"layout/style/test/test_rem_unit.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"layout/style/test/test_rule_serialization.html": "Bug 931116, b2g desktop specific, initial triage",
|
||||
"toolkit/devtools/apps/tests/test_webapps_actor.html": "Bug 931116, b2g desktop specific, initial triage"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1191,8 +1191,8 @@ Engine.prototype = {
|
|||
_updateURL: null,
|
||||
// The url to check for a new icon
|
||||
_iconUpdateURL: null,
|
||||
// A reference to the timer used for lazily serializing the engine to file
|
||||
_serializeTimer: null,
|
||||
/* Deferred serialization task. */
|
||||
_lazySerializeTask: null,
|
||||
|
||||
/**
|
||||
* Retrieves the data from the engine's file. If the engine's dataType is
|
||||
|
@ -2363,28 +2363,15 @@ Engine.prototype = {
|
|||
return doc;
|
||||
},
|
||||
|
||||
_lazySerializeToFile: function SRCH_ENG_serializeToFile() {
|
||||
if (this._serializeTimer) {
|
||||
// Reset the timer
|
||||
this._serializeTimer.delay = LAZY_SERIALIZE_DELAY;
|
||||
} else {
|
||||
this._serializeTimer = Cc["@mozilla.org/timer;1"].
|
||||
createInstance(Ci.nsITimer);
|
||||
var timerCallback = {
|
||||
self: this,
|
||||
notify: function SRCH_ENG_notify(aTimer) {
|
||||
try {
|
||||
this.self._serializeToFile();
|
||||
} catch (ex) {
|
||||
LOG("Serialization from timer callback failed:\n" + ex);
|
||||
}
|
||||
this.self._serializeTimer = null;
|
||||
}
|
||||
};
|
||||
this._serializeTimer.initWithCallback(timerCallback,
|
||||
LAZY_SERIALIZE_DELAY,
|
||||
Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
get lazySerializeTask() {
|
||||
if (!this._lazySerializeTask) {
|
||||
let task = function taskCallback() {
|
||||
this._serializeToFile();
|
||||
}.bind(this);
|
||||
this._lazySerializeTask = new DeferredTask(task, LAZY_SERIALIZE_DELAY);
|
||||
}
|
||||
|
||||
return this._lazySerializeTask;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -2415,6 +2402,9 @@ Engine.prototype = {
|
|||
}
|
||||
|
||||
closeSafeOutputStream(fos);
|
||||
|
||||
Services.obs.notifyObservers(file.clone(), SEARCH_SERVICE_TOPIC,
|
||||
"write-engine-to-disk-complete");
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -2660,7 +2650,7 @@ Engine.prototype = {
|
|||
url.addParam(aName, aValue);
|
||||
|
||||
// Serialize the changes to file lazily
|
||||
this._lazySerializeToFile();
|
||||
this.lazySerializeTask.start();
|
||||
},
|
||||
|
||||
#ifdef ANDROID
|
||||
|
@ -3236,25 +3226,16 @@ SearchService.prototype = {
|
|||
});
|
||||
},
|
||||
|
||||
_batchTimer: null,
|
||||
_batchCacheInvalidation: function SRCH_SVC__batchCacheInvalidation() {
|
||||
let callback = {
|
||||
self: this,
|
||||
notify: function SRCH_SVC_batchTimerNotify(aTimer) {
|
||||
LOG("_batchCacheInvalidation: Invalidating engine cache");
|
||||
this.self._buildCache();
|
||||
this.self._batchTimer = null;
|
||||
}
|
||||
};
|
||||
|
||||
if (!this._batchTimer) {
|
||||
this._batchTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
this._batchTimer.initWithCallback(callback, CACHE_INVALIDATION_DELAY,
|
||||
Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
} else {
|
||||
this._batchTimer.delay = CACHE_INVALIDATION_DELAY;
|
||||
LOG("_batchCacheInvalidation: Batch timer reset");
|
||||
_batchTask: null,
|
||||
get batchTask() {
|
||||
if (!this._batchTask) {
|
||||
let task = function taskCallback() {
|
||||
LOG("batchTask: Invalidating engine cache");
|
||||
this._buildCache();
|
||||
}.bind(this);
|
||||
this._batchTask = new DeferredTask(task, CACHE_INVALIDATION_DELAY);
|
||||
}
|
||||
return this._batchTask;
|
||||
},
|
||||
|
||||
_addEngineToStore: function SRCH_SVC_addEngineToStore(aEngine) {
|
||||
|
@ -3885,7 +3866,7 @@ SearchService.prototype = {
|
|||
engine._initFromMetadata(aName, aIconURL, aAlias, aDescription,
|
||||
aMethod, aTemplate);
|
||||
this._addEngineToStore(engine);
|
||||
this._batchCacheInvalidation();
|
||||
this.batchTask.start();
|
||||
},
|
||||
|
||||
addEngine: function SRCH_SVC_addEngine(aEngineURL, aDataType, aIconURL,
|
||||
|
@ -3948,10 +3929,10 @@ SearchService.prototype = {
|
|||
engineToRemove.hidden = true;
|
||||
engineToRemove.alias = null;
|
||||
} else {
|
||||
// Cancel the lazy serialization timer if it's running
|
||||
if (engineToRemove._serializeTimer) {
|
||||
engineToRemove._serializeTimer.cancel();
|
||||
engineToRemove._serializeTimer = null;
|
||||
// Cancel the serialized task if it's running
|
||||
if (engineToRemove._lazySerializeTask) {
|
||||
engineToRemove._lazySerializeTask.cancel();
|
||||
engineToRemove._lazySerializeTask = null;
|
||||
}
|
||||
|
||||
// Remove the engine file from disk (this might throw)
|
||||
|
@ -4149,21 +4130,20 @@ SearchService.prototype = {
|
|||
LOG("nsSearchService::observe: setting current");
|
||||
this.currentEngine = aEngine;
|
||||
}
|
||||
this._batchCacheInvalidation();
|
||||
this.batchTask.start();
|
||||
break;
|
||||
case SEARCH_ENGINE_CHANGED:
|
||||
case SEARCH_ENGINE_REMOVED:
|
||||
this._batchCacheInvalidation();
|
||||
this.batchTask.start();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case QUIT_APPLICATION_TOPIC:
|
||||
this._removeObservers();
|
||||
if (this._batchTimer) {
|
||||
if (this._batchTask) {
|
||||
// Flush to disk immediately
|
||||
this._batchTimer.cancel();
|
||||
this._buildCache();
|
||||
this._batchTask.flush();
|
||||
}
|
||||
engineMetadataService.flush();
|
||||
break;
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/*
|
||||
* test_serialize_file: Add test engines
|
||||
*
|
||||
* Ensure that :
|
||||
* - File is created.
|
||||
* - File size is bigger than 0.
|
||||
* - lazySerializeTask updates the file.
|
||||
*/
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://testing-common/httpd.js");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
add_test(function test_batchTask() {
|
||||
let observer = function(aSubject, aTopic, aData) {
|
||||
if (aTopic == "browser-search-engine-modified" && aData == "engine-loaded") {
|
||||
let engine1 = Services.search.getEngineByName("Test search engine");
|
||||
let engine2 = Services.search.getEngineByName("Sherlock test search engine");
|
||||
if (engine1 && engine2) {
|
||||
Services.obs.removeObserver(observer, aTopic);
|
||||
// Test that files are written correctly.
|
||||
let engineFile1 = engine1.wrappedJSObject._file;
|
||||
let engineFile2 = engine2.wrappedJSObject._file;
|
||||
do_check_true(engineFile1.exists());
|
||||
do_check_true(engineFile2.exists());
|
||||
do_check_neq(engineFile1.fileSize, 0);
|
||||
do_check_neq(engineFile2.fileSize, 0);
|
||||
run_next_test();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Services.obs.addObserver(observer, "browser-search-engine-modified", false);
|
||||
Services.search.addEngine("http://localhost:4444/data/engine.xml",
|
||||
Ci.nsISearchEngine.DATA_XML, null, false);
|
||||
Services.search.addEngine("http://localhost:4444/data/engine.src",
|
||||
Ci.nsISearchEngine.DATA_TEXT,
|
||||
"http://localhost:4444/data/ico-size-16x16-png.ico",
|
||||
false);
|
||||
});
|
||||
|
||||
add_test(function test_addParam() {
|
||||
let engine = Services.search.getEngineByName("Test search engine");
|
||||
engine.addParam("param-name", "param-value", null);
|
||||
|
||||
function readAsyncFile(aFile, aCallback) {
|
||||
NetUtil.asyncFetch(aFile, function(inputStream, status) {
|
||||
do_check_true(Components.isSuccessCode(status));
|
||||
|
||||
let data = NetUtil.readInputStreamToString(inputStream, inputStream.available());
|
||||
aCallback(data);
|
||||
});
|
||||
}
|
||||
|
||||
let observer = function(aSubject, aTopic, aData) {
|
||||
// The sherlock engine file may still be updated because the icon takes
|
||||
// time be loaded, therefore, the engine name is checked here.
|
||||
aSubject.QueryInterface(Ci.nsIFile);
|
||||
if (aTopic == "browser-search-service" &&
|
||||
aData == "write-engine-to-disk-complete" &&
|
||||
aSubject.leafName == "test-search-engine.xml") {
|
||||
Services.obs.removeObserver(observer, aTopic);
|
||||
|
||||
let engineFile = engine.wrappedJSObject._file;
|
||||
|
||||
readAsyncFile(engineFile, function(engineData) {
|
||||
do_check_true(engineData.indexOf("param-name") > 0);
|
||||
run_next_test();
|
||||
});
|
||||
}
|
||||
}
|
||||
Services.obs.addObserver(observer, "browser-search-service", false);
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
updateAppInfo();
|
||||
|
||||
let httpServer = new HttpServer();
|
||||
httpServer.start(4444);
|
||||
httpServer.registerDirectory("/", do_get_cwd());
|
||||
|
||||
do_register_cleanup(function cleanup() {
|
||||
httpServer.stop(function() {});
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
}
|
|
@ -29,6 +29,7 @@ support-files =
|
|||
[test_notifications.js]
|
||||
[test_addEngine_callback.js]
|
||||
[test_multipleIcons.js]
|
||||
[test_serialize_file.js]
|
||||
[test_async.js]
|
||||
[test_sync.js]
|
||||
[test_sync_fallback.js]
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -178,7 +178,12 @@ namespace {
|
|||
{
|
||||
nsTArray<nsRefPtr<Touch> > *touches =
|
||||
static_cast<nsTArray<nsRefPtr<Touch> > *>(aTouchList);
|
||||
touches->AppendElement(aData);
|
||||
nsRefPtr<Touch> copy = new Touch(aData->mIdentifier,
|
||||
aData->mRefPoint,
|
||||
aData->mRadius,
|
||||
aData->mRotationAngle,
|
||||
aData->mForce);
|
||||
touches->AppendElement(copy);
|
||||
aData->mChanged = false;
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
@ -441,10 +446,6 @@ MetroInput::InitTouchEventTouchList(WidgetTouchEvent* aEvent)
|
|||
bool
|
||||
MetroInput::ShouldDeliverInputToRecognizer()
|
||||
{
|
||||
// If the event is destined for chrome deliver all events to the recognizer.
|
||||
if (mChromeHitTestCacheForTouch) {
|
||||
return true;
|
||||
}
|
||||
return mRecognizerWantsEvents;
|
||||
}
|
||||
|
||||
|
@ -1150,6 +1151,7 @@ MetroInput::DeliverNextQueuedTouchEvent()
|
|||
// the touch block for content.
|
||||
if (mContentConsumingTouch) {
|
||||
mWidget->ApzContentConsumingTouch();
|
||||
DispatchTouchCancel(event);
|
||||
} else {
|
||||
mWidget->ApzContentIgnoringTouch();
|
||||
}
|
||||
|
@ -1194,8 +1196,7 @@ MetroInput::DispatchTouchCancel(WidgetTouchEvent* aEvent)
|
|||
MOZ_ASSERT(aEvent);
|
||||
// Send a touchcancel for each pointer id we have a corresponding start
|
||||
// for. Note we can't rely on mTouches here since touchends remove points
|
||||
// from it. The only time we end up in here is if the apz is consuming
|
||||
// events, so this array shouldn't be very large.
|
||||
// from it.
|
||||
WidgetTouchEvent touchEvent(true, NS_TOUCH_CANCEL, mWidget.Get());
|
||||
nsTArray< nsRefPtr<dom::Touch> >& touches = aEvent->touches;
|
||||
for (uint32_t i = 0; i < touches.Length(); ++i) {
|
||||
|
@ -1213,9 +1214,13 @@ MetroInput::DispatchTouchCancel(WidgetTouchEvent* aEvent)
|
|||
if (!touchEvent.touches.Length()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DUMP_TOUCH_IDS("DOM(4)", &touchEvent);
|
||||
mWidget->DispatchEvent(&touchEvent, sThrowawayStatus);
|
||||
if (mContentConsumingTouch) {
|
||||
DUMP_TOUCH_IDS("APZC(3)", &touchEvent);
|
||||
mWidget->ApzReceiveInputEvent(&touchEvent);
|
||||
} else {
|
||||
DUMP_TOUCH_IDS("DOM(5)", &touchEvent);
|
||||
mWidget->DispatchEvent(&touchEvent, sThrowawayStatus);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
Загрузка…
Ссылка в новой задаче