Merge fx-team to m-c.

This commit is contained in:
Ryan VanderMeulen 2013-11-01 14:51:36 -04:00
commit 43eeed0ee4
82 changed files with 1537 additions and 548 deletions

View File

@ -981,7 +981,7 @@ var WebappsHelper = {
});
break;
case "webapps-close":
shell.sendEvent(shell.getContentWindow(), "webapps-close",
shell.sendEvent(getContentWindow(), "webapps-close",
{
__exposedProps__: { "manifestURL": "r" },
"manifestURL": json.manifestURL

View File

@ -4206,6 +4206,10 @@ var TabsProgressListener = {
if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT)
return;
// Filter out location changes in sub documents.
if (!aWebProgress.isTopLevel)
return;
// Only need to call locationChange if the PopupNotifications object
// for this window has already been initialized (i.e. its getter no
// longer exists)
@ -4214,10 +4218,7 @@ var TabsProgressListener = {
gBrowser.getNotificationBox(aBrowser).removeTransientNotifications();
// Filter out location changes in sub documents.
if (aWebProgress.isTopLevel) {
FullZoom.onLocationChange(aLocationURI, false, aBrowser);
}
FullZoom.onLocationChange(aLocationURI, false, aBrowser);
},
onRefreshAttempted: function (aBrowser, aWebProgress, aURI, aDelay, aSameURI) {

View File

@ -31,6 +31,15 @@ let gPage = {
this._updateAttributes(enabled);
},
/**
* True if the page is allowed to capture thumbnails using the background
* thumbnail service.
*/
get allowBackgroundCaptures() {
return document.documentElement.getAttribute("allow-background-captures") ==
"true";
},
/**
* Listens for notifications specific to this page.
*/
@ -74,6 +83,20 @@ let gPage = {
this._initialized = true;
this._mutationObserver = new MutationObserver(() => {
if (this.allowBackgroundCaptures) {
for (let site of gGrid.sites) {
if (site) {
site.captureIfMissing();
}
}
}
});
this._mutationObserver.observe(document.documentElement, {
attributes: true,
attributeFilter: ["allow-background-captures"],
});
gLinks.populateCache(function () {
// Initialize and render the grid.
gGrid.init();
@ -123,6 +146,7 @@ let gPage = {
handleEvent: function Page_handleEvent(aEvent) {
switch (aEvent.type) {
case "unload":
this._mutationObserver.disconnect();
gAllPages.unregister(this);
break;
case "click":

View File

@ -0,0 +1,31 @@
/* 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/. */
(function () { // bug 673569 workaround :(
const ALLOW_BG_CAPTURES_MSG = "BrowserNewTabPreloader:allowBackgroundCaptures";
addMessageListener(ALLOW_BG_CAPTURES_MSG, function onMsg(msg) {
removeMessageListener(ALLOW_BG_CAPTURES_MSG, onMsg);
if (content.document.readyState == "complete") {
setAllowBackgroundCaptures();
return;
}
// This is the case when preloading is disabled.
addEventListener("load", function onLoad(event) {
if (event.target == content.document) {
removeEventListener("load", onLoad, true);
setAllowBackgroundCaptures();
}
}, true);
});
function setAllowBackgroundCaptures() {
content.document.documentElement.setAttribute("allow-background-captures",
"true");
}
})();

View File

@ -133,11 +133,20 @@ Site.prototype = {
this._updateAttributes(true);
// Capture the page if the thumbnail is missing, which will cause page.js
// to be notified and call our refreshThumbnail() method.
BackgroundPageThumbs.captureIfMissing(this.url);
this.captureIfMissing();
// but still display whatever thumbnail might be available now.
this.refreshThumbnail();
},
/**
* Captures the site's thumbnail in the background, but only if there's no
* existing thumbnail and the page allows background captures.
*/
captureIfMissing: function Site_captureIfMissing() {
if (gPage.allowBackgroundCaptures)
BackgroundPageThumbs.captureIfMissing(this.url);
},
/**
* Refreshes the thumbnail for the site.
*/

View File

@ -829,23 +829,41 @@ var tests = [
});
}
},
{ // Test #28 - location change in embedded frame removes notification
{ // Test #28 - location change in an embedded frame should not remove a notification
run: function () {
loadURI("data:text/html,<iframe id='iframe' src='http://example.com/'>", function () {
let notifyObj = new basicNotification();
notifyObj.options.eventCallback = function (eventName) {
loadURI("data:text/html;charset=utf8,<iframe id='iframe' src='http://example.com/'>", function () {
this.notifyObj = new basicNotification();
this.notifyObj.options.eventCallback = function (eventName) {
if (eventName == "removed") {
ok(true, "Notification removed in background tab after reloading");
executeSoon(goNext);
ok(false, "Test 28: Notification removed from browser when subframe navigated");
}
};
showNotification(notifyObj);
executeSoon(function () {
content.document.getElementById("iframe")
.setAttribute("src", "http://example.org/");
});
});
}
showNotification(this.notifyObj);
}.bind(this));
},
onShown: function (popup) {
let self = this;
let progressListener = {
onLocationChange: function onLocationChange(aBrowser) {
if (aBrowser != gBrowser.selectedBrowser) {
return;
}
let notification = PopupNotifications.getNotification(self.notifyObj.id,
self.notifyObj.browser);
ok(notification != null, "Test 28: Notification remained when subframe navigated");
self.notifyObj.options.eventCallback = undefined;
notification.remove();
gBrowser.removeTabsProgressListener(progressListener);
},
};
info("Test 28: Adding progress listener and performing navigation");
gBrowser.addTabsProgressListener(progressListener);
content.document.getElementById("iframe")
.setAttribute("src", "http://example.org/");
},
onHidden: function () {}
},
{ // Test #29 - Popup Notifications should catch exceptions from callbacks
run: function () {

View File

@ -1,6 +1,7 @@
[DEFAULT]
support-files = head.js
[browser_newtab_background_captures.js]
[browser_newtab_block.js]
[browser_newtab_bug721442.js]
[browser_newtab_bug722273.js]

View File

@ -0,0 +1,100 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Verifies that hidden, pre-loaded newtabs don't allow background captures, and
* when unhidden, do allow background captures.
*/
const CAPTURE_PREF = "browser.pagethumbnails.capturing_disabled";
function runTests() {
let imports = {};
Cu.import("resource://gre/modules/PageThumbs.jsm", imports);
Cu.import("resource:///modules/BrowserNewTabPreloader.jsm", imports);
// Disable captures.
let originalDisabledState = Services.prefs.getBoolPref(CAPTURE_PREF);
Services.prefs.setBoolPref(CAPTURE_PREF, true);
// Make sure the thumbnail doesn't exist yet.
let siteName = "newtab_background_captures";
let url = "http://example.com/#" + siteName;
let path = imports.PageThumbsStorage.getFilePathForURL(url);
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
file.initWithPath(path);
try {
file.remove(false);
}
catch (err) {}
// Add a top site.
yield setLinks(siteName);
// We need a handle to a hidden, pre-loaded newtab so we can verify that it
// doesn't allow background captures. Add a newtab, which triggers creation
// of a hidden newtab, and then keep calling BrowserNewTabPreloader.newTab
// until it returns true, meaning that it swapped the passed-in tab's docshell
// for the hidden newtab docshell.
let tab = gWindow.gBrowser.addTab("about:blank");
yield addNewTabPageTab();
let swapWaitCount = 0;
let swapped = imports.BrowserNewTabPreloader.newTab(tab);
while (!swapped) {
if (++swapWaitCount == 10) {
ok(false, "Timed out waiting for newtab docshell swap.");
return;
}
// Give the hidden newtab some time to finish loading.
yield wait(2000);
info("Checking newtab swap " + swapWaitCount);
swapped = imports.BrowserNewTabPreloader.newTab(tab);
}
// The tab's docshell is now the previously hidden newtab docshell.
let doc = tab.linkedBrowser.contentDocument;
isnot(doc.documentElement.getAttribute("allow-background-captures"), "true",
"Pre-loaded docshell just synchronously swapped, so background " +
"captures should not be allowed yet");
// Enable captures.
Services.prefs.setBoolPref(CAPTURE_PREF, false);
// Now that the newtab is visible, its allow-background-captures attribute
// should be set eventually.
let allowBackgroundCaptures = false;
let mutationObserver = new MutationObserver(() => {
mutationObserver.disconnect();
allowBackgroundCaptures = true;
is(doc.documentElement.getAttribute("allow-background-captures"), "true",
"allow-background-captures should now be true");
info("Waiting for thumbnail to be created after observing " +
"allow-background-captures change");
});
mutationObserver.observe(doc.documentElement, {
attributes: true,
attributeFilter: ["allow-background-captures"],
});
// And the allow-background-captures change should trigger the thumbnail
// capture.
Services.obs.addObserver(function onCreate(subj, topic, data) {
if (data != url)
return;
ok(allowBackgroundCaptures,
"page-thumbnail:create should be observed after " +
"allow-background-captures was set");
Services.obs.removeObserver(onCreate, "page-thumbnail:create");
// Test finished!
Services.prefs.setBoolPref(CAPTURE_PREF, originalDisabledState);
file.remove(false);
TestRunner.next();
}, "page-thumbnail:create", false);
info("Waiting for allow-background-captures change");
yield true;
}
function wait(ms) {
setTimeout(TestRunner.next, ms);
}

View File

@ -64,6 +64,7 @@ browser.jar:
content/browser/newtab/newTab.xul (content/newtab/newTab.xul)
* content/browser/newtab/newTab.js (content/newtab/newTab.js)
content/browser/newtab/newTab.css (content/newtab/newTab.css)
content/browser/newtab/preloaderContent.js (content/newtab/preloaderContent.js)
* content/browser/pageinfo/pageInfo.xul (content/pageinfo/pageInfo.xul)
content/browser/pageinfo/pageInfo.js (content/pageinfo/pageInfo.js)
content/browser/pageinfo/pageInfo.css (content/pageinfo/pageInfo.css)

View File

@ -205,7 +205,7 @@ var bookmarksObserver = {
}
},
onItemRemoved: function PSB_onItemRemoved(aItemId, aFolder, aIndex,
onItemRemoved: function PSB_onItemRemoved(aItemId, aFolderId, aIndex,
aItemType) {
var views = getViewsForFolder(aFolderId);
ok(views.length > 0, "Found affected views (" + views.length + "): " + views);

View File

@ -19,11 +19,11 @@ module.exports = ConnectionStore = function(connection) {
ObservableObject.call(this, {status:null,host:null,port:null});
this._destroy = this._destroy.bind(this);
this.destroy = this.destroy.bind(this);
this._feedStore = this._feedStore.bind(this);
this._connection = connection;
this._connection.once(Connection.Events.DESTROYED, this._destroy);
this._connection.once(Connection.Events.DESTROYED, this.destroy);
this._connection.on(Connection.Events.STATUS_CHANGED, this._feedStore);
this._connection.on(Connection.Events.PORT_CHANGED, this._feedStore);
this._connection.on(Connection.Events.HOST_CHANGED, this._feedStore);
@ -32,12 +32,18 @@ module.exports = ConnectionStore = function(connection) {
}
ConnectionStore.prototype = {
_destroy: function() {
this._connection.off(Connection.Events.STATUS_CHANGED, this._feedStore);
this._connection.off(Connection.Events.PORT_CHANGED, this._feedStore);
this._connection.off(Connection.Events.HOST_CHANGED, this._feedStore);
_knownConnectionStores.delete(this._connection);
this._connection = null;
destroy: function() {
if (this._connection) {
// While this.destroy is bound using .once() above, that event may not
// have occurred when the ConnectionStore client calls destroy, so we
// manually remove it here.
this._connection.off(Connection.Events.DESTROYED, this.destroy);
this._connection.off(Connection.Events.STATUS_CHANGED, this._feedStore);
this._connection.off(Connection.Events.PORT_CHANGED, this._feedStore);
this._connection.off(Connection.Events.HOST_CHANGED, this._feedStore);
_knownConnectionStores.delete(this._connection);
this._connection = null;
}
},
_feedStore: function() {

View File

@ -18,6 +18,11 @@ const DeviceStore = require("devtools/app-manager/device-store");
const simulatorsStore = require("devtools/app-manager/simulators-store");
const adbStore = require("devtools/app-manager/builtin-adb-store");
window.addEventListener("unload", function onUnload() {
window.removeEventListener("unload", onUnload);
UI.destroy();
});
let UI = {
init: function() {
this.useFloatingScrollbarsIfNeeded();
@ -54,10 +59,7 @@ let UI = {
let pre = document.querySelector("#logs > pre");
pre.textContent = this.connection.logs;
pre.scrollTop = pre.scrollTopMax;
this.connection.on(Connection.Events.NEW_LOG, (event, str) => {
pre.textContent += "\n" + str;
pre.scrollTop = pre.scrollTopMax;
});
this.connection.on(Connection.Events.NEW_LOG, this._onNewLog);
this.template = new Template(document.body, this.store, Utils.l10n);
this.template.start();
@ -66,6 +68,18 @@ let UI = {
this._onSimulatorDisconnected = this._onSimulatorDisconnected.bind(this);
},
destroy: function() {
this.store.destroy();
this.connection.off(Connection.Events.NEW_LOG, this._onNewLog);
this.template.destroy();
},
_onNewLog: function(event, str) {
let pre = document.querySelector("#logs > pre");
pre.textContent += "\n" + str;
pre.scrollTop = pre.scrollTopMax;
},
useFloatingScrollbarsIfNeeded: function() {
if (Services.appinfo.OS == "Darwin") {
return;

View File

@ -32,12 +32,16 @@ window.addEventListener("message", function(event) {
} catch(e) {
Cu.reportError(e);
}
}, false);
});
window.addEventListener("unload", function onUnload() {
window.removeEventListener("unload", onUnload);
UI.destroy();
});
let UI = {
init: function() {
this.showFooterIfNeeded();
this._onConnectionStatusChange = this._onConnectionStatusChange.bind(this);
this.setTab("apps");
if (this.connection) {
this.onNewConnection();
@ -46,6 +50,18 @@ let UI = {
}
},
destroy: function() {
if (this.connection) {
this.connection.off(Connection.Events.STATUS_CHANGED, this._onConnectionStatusChange);
}
if (this.store) {
this.store.destroy();
}
if (this.template) {
this.template.destroy();
}
},
showFooterIfNeeded: function() {
let footer = document.querySelector("#connection-footer");
if (window.parent == window) {
@ -73,6 +89,9 @@ let UI = {
"apps": new WebappsStore(this.connection),
});
if (this.template) {
this.template.destroy();
}
this.template = new Template(document.body, this.store, Utils.l10n);
this.template.start();
@ -189,3 +208,7 @@ let UI = {
return deferred.promise;
},
}
// This must be bound immediately, as it might be used via the message listener
// before UI.init() has been called.
UI._onConnectionStatusChange = UI._onConnectionStatusChange.bind(UI);

View File

@ -40,13 +40,25 @@ window.addEventListener("message", function(event) {
}
}, false);
window.addEventListener("unload", function onUnload() {
window.removeEventListener("unload", onUnload);
if (connection) {
connection.off(Connection.Status.CONNECTED, onConnected);
connection.off(Connection.Status.DISCONNECTED, onDisconnected);
}
});
function onNewConnection() {
connection.on(Connection.Status.CONNECTED, () => {
document.querySelector("#content").classList.add("connected");
});
connection.on(Connection.Status.DISCONNECTED, () => {
document.querySelector("#content").classList.remove("connected");
});
connection.on(Connection.Status.CONNECTED, onConnected);
connection.on(Connection.Status.DISCONNECTED, onDisconnected);
}
function onConnected() {
document.querySelector("#content").classList.add("connected");
}
function onDisconnected() {
document.querySelector("#content").classList.remove("connected");
}
function selectTab(id) {

View File

@ -35,7 +35,12 @@ window.addEventListener("message", function(event) {
}
}
} catch(e) {}
}, false);
});
window.addEventListener("unload", function onUnload() {
window.removeEventListener("unload", onUnload);
UI.destroy();
});
let UI = {
isReady: false,
@ -55,8 +60,15 @@ let UI = {
});
},
destroy: function() {
if (this.connection) {
this.connection.off(Connection.Events.STATUS_CHANGED, this._onConnectionStatusChange);
}
this.template.destroy();
},
onNewConnection: function() {
this.connection.on(Connection.Events.STATUS_CHANGED, () => this._onConnectionStatusChange());
this.connection.on(Connection.Events.STATUS_CHANGED, this._onConnectionStatusChange);
this._onConnectionStatusChange();
},
@ -427,4 +439,8 @@ let UI = {
}
};
// This must be bound immediately, as it might be used via the message listener
// before UI.onload() has been called.
UI._onConnectionStatusChange = UI._onConnectionStatusChange.bind(UI);
EventEmitter.decorate(UI);

View File

@ -69,7 +69,8 @@ function Template(root, store, l10nResolver) {
this._root = root;
this._doc = this._root.ownerDocument;
this._store.on("set", (event,path,value) => this._storeChanged(path,value));
this._storeChanged = this._storeChanged.bind(this);
this._store.on("set", this._storeChanged);
}
Template.prototype = {
@ -77,6 +78,12 @@ Template.prototype = {
this._processTree(this._root);
},
destroy: function() {
this._store.off("set", this._storeChanged);
this._root = null;
this._doc = null;
},
_resolvePath: function(path, defaultValue=null) {
// From the store, get the value of an object located
@ -110,7 +117,7 @@ Template.prototype = {
return obj;
},
_storeChanged: function(path, value) {
_storeChanged: function(event, path, value) {
// The store has changed (a "set" event has been emitted).
// We need to invalidate and rebuild the affected elements.

View File

@ -19,19 +19,36 @@ let Utils = (function() {
const EventEmitter = require("devtools/shared/event-emitter");
function _forwardSetEvent(key, store, finalStore) {
store.on("set", function(event, path, value) {
function _createSetEventForwarder(key, finalStore) {
return function(event, path, value) {
finalStore.emit("set", [key].concat(path), value);
});
};
}
function mergeStores(stores) {
let finalStore = {object:{}};
EventEmitter.decorate(finalStore);
let setEventForwarders = {};
for (let key in stores) {
finalStore.object[key] = stores[key].object,
_forwardSetEvent(key, stores[key], finalStore);
let store = stores[key];
finalStore.object[key] = store.object;
setEventForwarders[key] = _createSetEventForwarder(key, finalStore);
store.on("set", setEventForwarders[key]);
}
finalStore.destroy = () => {
for (let key in stores) {
let store = stores[key];
store.off("set", setEventForwarders[key]);
if (store.destroy) {
store.destroy();
}
}
};
return finalStore;
}

View File

@ -25,21 +25,27 @@ module.exports = DeviceStore = function(connection) {
this._resetStore();
this._destroy = this._destroy.bind(this);
this.destroy = this.destroy.bind(this);
this._onStatusChanged = this._onStatusChanged.bind(this);
this._connection = connection;
this._connection.once(Connection.Events.DESTROYED, this._destroy);
this._connection.once(Connection.Events.DESTROYED, this.destroy);
this._connection.on(Connection.Events.STATUS_CHANGED, this._onStatusChanged);
this._onStatusChanged();
return this;
}
DeviceStore.prototype = {
_destroy: function() {
this._connection.off(Connection.Events.STATUS_CHANGED, this._onStatusChanged);
_knownDeviceStores.delete(this._connection);
this._connection = null;
destroy: function() {
if (this._connection) {
// While this.destroy is bound using .once() above, that event may not
// have occurred when the DeviceStore client calls destroy, so we
// manually remove it here.
this._connection.off(Connection.Events.DESTROYED, this.destroy);
this._connection.off(Connection.Events.STATUS_CHANGED, this._onStatusChanged);
_knownDeviceStores.delete(this._connection);
this._connection = null;
}
},
_resetStore: function() {

View File

@ -101,7 +101,9 @@ function waitForProjectsPanel(deferred = promise.defer()) {
let projectsWindow = getProjectsWindow();
let projectsUI = projectsWindow.UI;
if (!projectsUI) {
info("projectsUI false");
projectsWindow.addEventListener("load", function onLoad() {
info("got load event");
projectsWindow.removeEventListener("load", onLoad);
waitForProjectsPanel(deferred);
});
@ -109,10 +111,12 @@ function waitForProjectsPanel(deferred = promise.defer()) {
}
if (projectsUI.isReady) {
info("projectsUI ready");
deferred.resolve();
return deferred.promise;
}
info("projectsUI not ready");
projectsUI.once("ready", deferred.resolve);
return deferred.promise;
}

View File

@ -25,21 +25,27 @@ module.exports = WebappsStore = function(connection) {
this._resetStore();
this._destroy = this._destroy.bind(this);
this.destroy = this.destroy.bind(this);
this._onStatusChanged = this._onStatusChanged.bind(this);
this._connection = connection;
this._connection.once(Connection.Events.DESTROYED, this._destroy);
this._connection.once(Connection.Events.DESTROYED, this.destroy);
this._connection.on(Connection.Events.STATUS_CHANGED, this._onStatusChanged);
this._onStatusChanged();
return this;
}
WebappsStore.prototype = {
_destroy: function() {
this._connection.off(Connection.Events.STATUS_CHANGED, this._onStatusChanged);
_knownWebappsStores.delete(this._connection);
this._connection = null;
destroy: function() {
if (this._connection) {
// While this.destroy is bound using .once() above, that event may not
// have occurred when the WebappsStore client calls destroy, so we
// manually remove it here.
this._connection.off(Connection.Events.DESTROYED, this.destroy);
this._connection.off(Connection.Events.STATUS_CHANGED, this._onStatusChanged);
_knownWebappsStores.delete(this._connection);
this._connection = null;
}
},
_resetStore: function() {

View File

@ -49,7 +49,7 @@
<button id="requests-menu-status-button"
class="requests-menu-header-button requests-menu-status"
onclick="NetMonitorView.RequestsMenu.sortBy('status')"
label="&netmonitorUI.toolbar.status;">
label="&netmonitorUI.toolbar.status2;">
</button>
<button id="requests-menu-method-button"
class="requests-menu-header-button requests-menu-method"

View File

@ -19,8 +19,13 @@ const Editor = require("devtools/sourceeditor/editor");
// The panel's window global is an EventEmitter firing the following events:
const EVENTS = {
// When new programs are received from the server.
NEW_PROGRAM: "ShaderEditor:NewProgram",
PROGRAMS_ADDED: "ShaderEditor:ProgramsAdded",
// When the vertex and fragment sources were shown in the editor.
SOURCES_SHOWN: "ShaderEditor:SourcesShown",
// When a shader's source was edited and compiled via the editor.
SHADER_COMPILED: "ShaderEditor:ShaderCompiled"
};
@ -72,10 +77,12 @@ let EventsHandler = {
*/
initialize: function() {
this._onHostChanged = this._onHostChanged.bind(this);
this._onWillNavigate = this._onWillNavigate.bind(this);
this._onTabNavigated = this._onTabNavigated.bind(this);
this._onProgramLinked = this._onProgramLinked.bind(this);
this._onProgramsAdded = this._onProgramsAdded.bind(this);
gToolbox.on("host-changed", this._onHostChanged);
gTarget.on("will-navigate", this._onWillNavigate);
gTarget.on("will-navigate", this._onTabNavigated);
gTarget.on("navigate", this._onTabNavigated);
gFront.on("program-linked", this._onProgramLinked);
},
@ -85,7 +92,8 @@ let EventsHandler = {
*/
destroy: function() {
gToolbox.off("host-changed", this._onHostChanged);
gTarget.off("will-navigate", this._onWillNavigate);
gTarget.off("will-navigate", this._onTabNavigated);
gTarget.off("navigate", this._onTabNavigated);
gFront.off("program-linked", this._onProgramLinked);
},
@ -101,20 +109,51 @@ let EventsHandler = {
/**
* Called for each location change in the debugged tab.
*/
_onWillNavigate: function() {
gFront.setup();
_onTabNavigated: function(event) {
switch (event) {
case "will-navigate": {
// Make sure the backend is prepared to handle WebGL contexts.
gFront.setup({ reload: false });
ShadersListView.empty();
ShadersEditorsView.setText({ vs: "", fs: "" });
$("#reload-notice").hidden = true;
$("#waiting-notice").hidden = false;
$("#content").hidden = true;
// Reset UI.
ShadersListView.empty();
ShadersEditorsView.setText({ vs: "", fs: "" });
$("#reload-notice").hidden = true;
$("#waiting-notice").hidden = false;
$("#content").hidden = true;
break;
}
case "navigate": {
// Manually retrieve the list of program actors known to the server,
// because the backend won't emit "program-linked" notifications
// in the case of a bfcache navigation (since no new programs are
// actually linked).
gFront.getPrograms().then(this._onProgramsAdded);
break;
}
}
},
/**
* Called every time a program was linked in the debugged tab.
*/
_onProgramLinked: function(programActor) {
this._addProgram(programActor);
window.emit(EVENTS.NEW_PROGRAM);
},
/**
* Callback for the front's getPrograms() method.
*/
_onProgramsAdded: function(programActors) {
programActors.forEach(this._addProgram);
window.emit(EVENTS.PROGRAMS_ADDED);
},
/**
* Adds a program to the shaders list and unhides any modal notices.
*/
_addProgram: function(programActor) {
$("#waiting-notice").hidden = true;
$("#reload-notice").hidden = true;
$("#content").hidden = false;
@ -163,6 +202,10 @@ let ShadersListView = Heritage.extend(WidgetMethods, {
* The program actor coming from the active thread.
*/
addProgram: function(programActor) {
if (this.hasProgram(programActor)) {
return;
}
// Currently, there's no good way of differentiating between programs
// in a way that helps humans. It will be a good idea to implement a
// standard of allowing debuggees to add some identifiable metadata to their
@ -192,6 +235,18 @@ let ShadersListView = Heritage.extend(WidgetMethods, {
}
},
/**
* Returns whether a program was already added to this programs container.
*
* @param object programActor
* The program actor coming from the active thread.
* @param boolean
* True if the program was added, false otherwise.
*/
hasProgram: function(programActor) {
return !!this.attachments.filter(e => e.programActor == programActor).length;
},
/**
* The select listener for the sources container.
*/

View File

@ -24,7 +24,7 @@
<button id="requests-menu-reload-notice-button"
class="devtools-toolbarbutton"
label="&shaderEditorUI.reloadNotice1;"
oncommand="gFront.setup();"/>
oncommand="gFront.setup({ reload: true });"/>
<label id="requests-menu-reload-notice-label"
class="plain"
value="&shaderEditorUI.reloadNotice2;"/>

View File

@ -6,6 +6,7 @@ support-files =
head.js
[browser_se_aaa_run_first_leaktest.js]
[browser_se_bfcache.js]
[browser_se_editors-contents.js]
[browser_se_editors-lazy-init.js]
[browser_se_first-run.js]
@ -31,3 +32,5 @@ support-files =
[browser_webgl-actor-test-12.js]
[browser_webgl-actor-test-13.js]
[browser_webgl-actor-test-14.js]
[browser_webgl-actor-test-15.js]
[browser_webgl-actor-test-16.js]

View File

@ -0,0 +1,64 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if the shader editor works with bfcache.
*/
function ifWebGLSupported() {
let [target, debuggee, panel] = yield initShaderEditor(SIMPLE_CANVAS_URL);
let { gFront, $, EVENTS, ShadersListView, ShadersEditorsView } = panel.panelWin;
let reloaded = reload(target);
let firstProgram = yield once(gFront, "program-linked");
yield reloaded;
let navigated = navigate(target, MULTIPLE_CONTEXTS_URL);
let secondProgram = yield once(gFront, "program-linked");
let thirdProgram = yield once(gFront, "program-linked");
yield navigated;
let vsEditor = yield ShadersEditorsView._getEditor("vs");
let fsEditor = yield ShadersEditorsView._getEditor("fs");
yield navigateInHistory(target, "back", "will-navigate");
yield once(panel.panelWin, EVENTS.PROGRAMS_ADDED);
yield once(panel.panelWin, EVENTS.SOURCES_SHOWN);
is($("#content").hidden, false,
"The tool's content should not be hidden.");
is(ShadersListView.itemCount, 1,
"The shaders list contains one entry after navigating back.");
is(ShadersListView.selectedIndex, 0,
"The shaders list has a correct selection after navigating back.");
is(vsEditor.getText().indexOf("gl_Position"), 170,
"The vertex shader editor contains the correct text.");
is(fsEditor.getText().indexOf("gl_FragColor"), 97,
"The fragment shader editor contains the correct text.");
yield navigateInHistory(target, "forward", "will-navigate");
yield once(panel.panelWin, EVENTS.PROGRAMS_ADDED);
yield once(panel.panelWin, EVENTS.SOURCES_SHOWN);
is($("#content").hidden, false,
"The tool's content should not be hidden.");
is(ShadersListView.itemCount, 2,
"The shaders list contains two entries after navigating forward.");
is(ShadersListView.selectedIndex, 0,
"The shaders list has a correct selection after navigating forward.");
is(vsEditor.getText().indexOf("gl_Position"), 100,
"The vertex shader editor contains the correct text.");
is(fsEditor.getText().indexOf("gl_FragColor"), 89,
"The fragment shader editor contains the correct text.");
yield teardown(panel);
finish();
}
function once(aTarget, aEvent) {
let deferred = promise.defer();
aTarget.once(aEvent, deferred.resolve);
return deferred.promise;
}

View File

@ -12,7 +12,7 @@ function ifWebGLSupported() {
let navigated = once(target, "navigate");
let linked = once(front, "program-linked");
yield front.setup();
yield front.setup({ reload: true });
ok(true, "The front was setup up successfully.");
yield navigated;

View File

@ -8,7 +8,7 @@
function ifWebGLSupported() {
let [target, debuggee, front] = yield initBackend(SIMPLE_CANVAS_URL);
front.setup();
front.setup({ reload: true });
let programActor = yield once(front, "program-linked");
ok(programActor,

View File

@ -8,7 +8,7 @@
function ifWebGLSupported() {
let [target, debuggee, front] = yield initBackend(SIMPLE_CANVAS_URL);
front.setup();
front.setup({ reload: true });
let programActor = yield once(front, "program-linked");
let vertexShader = yield programActor.getVertexShader();

View File

@ -8,7 +8,7 @@
function ifWebGLSupported() {
let [target, debuggee, front] = yield initBackend(SIMPLE_CANVAS_URL);
front.setup();
front.setup({ reload: true });
let programActor = yield once(front, "program-linked");
let vertexShader = yield programActor.getVertexShader();

View File

@ -7,7 +7,7 @@
function ifWebGLSupported() {
let [target, debuggee, front] = yield initBackend(SIMPLE_CANVAS_URL);
front.setup();
front.setup({ reload: true });
let programActor = yield once(front, "program-linked");
let vertexShader = yield programActor.getVertexShader();

View File

@ -8,7 +8,7 @@
function ifWebGLSupported() {
let [target, debuggee, front] = yield initBackend(SIMPLE_CANVAS_URL);
front.setup();
front.setup({ reload: true });
let programActor = yield once(front, "program-linked");
let vertexShader = yield programActor.getVertexShader();

View File

@ -8,7 +8,7 @@
function ifWebGLSupported() {
let [target, debuggee, front] = yield initBackend(SIMPLE_CANVAS_URL);
front.setup();
front.setup({ reload: true });
let programActor = yield once(front, "program-linked");
let vertexShader = yield programActor.getVertexShader();

View File

@ -9,36 +9,33 @@
function ifWebGLSupported() {
let [target, debuggee, front] = yield initBackend(SIMPLE_CANVAS_URL);
let linked = once(front, "program-linked");
yield front.setup();
yield linked;
front.setup({ reload: true });
yield testHighlighting((yield once(front, "program-linked")));
ok(true, "Canvas was correctly instrumented on the first navigation.");
let linked = once(front, "program-linked");
yield reload(target);
yield linked;
reload(target);
yield testHighlighting((yield once(front, "program-linked")));
ok(true, "Canvas was correctly instrumented on the second navigation.");
let linked = once(front, "program-linked");
yield reload(target);
yield linked;
reload(target);
yield testHighlighting((yield once(front, "program-linked")));
ok(true, "Canvas was correctly instrumented on the third navigation.");
let programActor = yield linked;
let vertexShader = yield programActor.getVertexShader();
let fragmentShader = yield programActor.getFragmentShader();
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
ok(true, "The top left pixel color was correct before highlighting.");
yield programActor.highlight([0, 0, 1, 1]);
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 255, a: 255 }, true);
ok(true, "The top left pixel color is correct after highlighting.");
yield programActor.unhighlight();
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
ok(true, "The top left pixel color is correct after unhighlighting.");
yield removeTab(target.tab);
finish();
function testHighlighting(programActor) {
return Task.spawn(function() {
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
ok(true, "The top left pixel color was correct before highlighting.");
yield programActor.highlight([0, 0, 1, 1]);
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 255, a: 255 }, true);
ok(true, "The top left pixel color is correct after highlighting.");
yield programActor.unhighlight();
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
ok(true, "The top left pixel color is correct after unhighlighting.");
});
}
}

View File

@ -10,7 +10,7 @@ function ifWebGLSupported() {
let [target, debuggee, front] = yield initBackend(SIMPLE_CANVAS_URL);
let linked = once(front, "program-linked");
yield front.setup();
front.setup({ reload: true });
yield linked;
ok(true, "Canvas was correctly instrumented on the first navigation.");

View File

@ -8,7 +8,7 @@
function ifWebGLSupported() {
let [target, debuggee, front] = yield initBackend(SHADER_ORDER_URL);
front.setup();
front.setup({ reload: true });
let programActor = yield once(front, "program-linked");
let vertexShader = yield programActor.getVertexShader();

View File

@ -7,7 +7,7 @@
function ifWebGLSupported() {
let [target, debuggee, front] = yield initBackend(MULTIPLE_CONTEXTS_URL);
front.setup();
front.setup({ reload: true });
let firstProgramActor = yield once(front, "program-linked");
let secondProgramActor = yield once(front, "program-linked");

View File

@ -8,7 +8,7 @@
function ifWebGLSupported() {
let [target, debuggee, front] = yield initBackend(MULTIPLE_CONTEXTS_URL);
front.setup();
front.setup({ reload: true });
let firstProgramActor = yield once(front, "program-linked");
let secondProgramActor = yield once(front, "program-linked");

View File

@ -0,0 +1,127 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if program actors are cached when navigating in the bfcache.
*/
function ifWebGLSupported() {
let [target, debuggee, front] = yield initBackend(SIMPLE_CANVAS_URL);
front.setup({ reload: false });
reload(target);
let firstProgram = yield once(front, "program-linked");
yield checkFirstCachedPrograms(firstProgram);
yield checkHighlightingInTheFirstPage(firstProgram);
ok(true, "The cached programs behave correctly before the navigation.");
navigate(target, MULTIPLE_CONTEXTS_URL);
let secondProgram = yield once(front, "program-linked");
let thirdProgram = yield once(front, "program-linked");
yield checkSecondCachedPrograms(firstProgram, [secondProgram, thirdProgram]);
yield checkHighlightingInTheSecondPage(secondProgram, thirdProgram);
ok(true, "The cached programs behave correctly after the navigation.");
once(front, "program-linked").then(() => {
ok(false, "Shouldn't have received any more program-linked notifications.");
});
yield navigateInHistory(target, "back");
yield checkFirstCachedPrograms(firstProgram);
yield checkHighlightingInTheFirstPage(firstProgram);
ok(true, "The cached programs behave correctly after navigating back.");
yield navigateInHistory(target, "forward");
yield checkSecondCachedPrograms(firstProgram, [secondProgram, thirdProgram]);
yield checkHighlightingInTheSecondPage(secondProgram, thirdProgram);
ok(true, "The cached programs behave correctly after navigating forward.");
yield navigateInHistory(target, "back");
yield checkFirstCachedPrograms(firstProgram);
yield checkHighlightingInTheFirstPage(firstProgram);
ok(true, "The cached programs behave correctly after navigating back again.");
yield navigateInHistory(target, "forward");
yield checkSecondCachedPrograms(firstProgram, [secondProgram, thirdProgram]);
yield checkHighlightingInTheSecondPage(secondProgram, thirdProgram);
ok(true, "The cached programs behave correctly after navigating forward again.");
yield removeTab(target.tab);
finish();
function checkFirstCachedPrograms(programActor) {
return Task.spawn(function() {
let programs = yield front.getPrograms();
is(programs.length, 1,
"There should be 1 cached program actor.");
is(programs[0], programActor,
"The cached program actor was the expected one.");
})
}
function checkSecondCachedPrograms(oldProgramActor, newProgramActors) {
return Task.spawn(function() {
let programs = yield front.getPrograms();
is(programs.length, 2,
"There should be 2 cached program actors after the navigation.");
is(programs[0], newProgramActors[0],
"The first cached program actor was the expected one after the navigation.");
is(programs[1], newProgramActors[1],
"The second cached program actor was the expected one after the navigation.");
isnot(newProgramActors[0], oldProgramActor,
"The old program actor is not equal to the new first program actor.");
isnot(newProgramActors[1], oldProgramActor,
"The old program actor is not equal to the new second program actor.");
});
}
function checkHighlightingInTheFirstPage(programActor) {
return Task.spawn(function() {
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
ok(true, "The top left pixel color was correct before highlighting.");
yield programActor.highlight([0, 0, 1, 1]);
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 255, a: 255 }, true);
ok(true, "The top left pixel color is correct after highlighting.");
yield programActor.unhighlight();
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
ok(true, "The top left pixel color is correct after unhighlighting.");
});
}
function checkHighlightingInTheSecondPage(firstProgramActor, secondProgramActor) {
return Task.spawn(function() {
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
ok(true, "The two canvases are correctly drawn before highlighting.");
yield firstProgramActor.highlight([1, 0, 0, 1]);
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
ok(true, "The first canvas was correctly filled after highlighting.");
yield secondProgramActor.highlight([0, 1, 0, 1]);
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 255, b: 0, a: 255 }, true, "#canvas2");
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 255, b: 0, a: 255 }, true, "#canvas2");
ok(true, "The second canvas was correctly filled after highlighting.");
yield firstProgramActor.unhighlight();
yield secondProgramActor.unhighlight();
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
ok(true, "The two canvases were correctly filled after unhighlighting.");
});
}
}

View File

@ -0,0 +1,105 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if program actors are invalidated from the cache when a window is
* removed from the bfcache.
*/
function ifWebGLSupported() {
let [target, debuggee, front] = yield initBackend(SIMPLE_CANVAS_URL);
front.setup({ reload: false });
reload(target);
let firstProgram = yield once(front, "program-linked");
navigate(target, MULTIPLE_CONTEXTS_URL);
let secondProgram = yield once(front, "program-linked");
let thirdProgram = yield once(front, "program-linked");
yield navigateInHistory(target, "back");
let globalDestroyed = observe("inner-window-destroyed");
let globalCreated = observe("content-document-global-created");
reload(target);
yield globalDestroyed;
let programs = yield front.getPrograms();
is(programs.length, 0,
"There should be no cached program actors yet.");
yield globalCreated;
let programs = yield front.getPrograms();
is(programs.length, 1,
"There should be 1 cached program actor now.");
yield checkHighlightingInTheFirstPage(programs[0]);
ok(true, "The cached programs behave correctly after navigating back and reloading.");
yield navigateInHistory(target, "forward");
let globalDestroyed = observe("inner-window-destroyed");
let globalCreated = observe("content-document-global-created");
reload(target);
yield globalDestroyed;
let programs = yield front.getPrograms();
is(programs.length, 0,
"There should be no cached program actors yet.");
yield globalCreated;
let programs = yield front.getPrograms();
is(programs.length, 2,
"There should be 2 cached program actors now.");
yield checkHighlightingInTheSecondPage(programs[0], programs[1]);
ok(true, "The cached programs behave correctly after navigating forward and reloading.");
yield removeTab(target.tab);
finish();
function checkHighlightingInTheFirstPage(programActor) {
return Task.spawn(function() {
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
ok(true, "The top left pixel color was correct before highlighting.");
yield programActor.highlight([0, 0, 1, 1]);
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 255, a: 255 }, true);
ok(true, "The top left pixel color is correct after highlighting.");
yield programActor.unhighlight();
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
ok(true, "The top left pixel color is correct after unhighlighting.");
});
}
function checkHighlightingInTheSecondPage(firstProgramActor, secondProgramActor) {
return Task.spawn(function() {
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
ok(true, "The two canvases are correctly drawn before highlighting.");
yield firstProgramActor.highlight([1, 0, 0, 1]);
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
ok(true, "The first canvas was correctly filled after highlighting.");
yield secondProgramActor.highlight([0, 1, 0, 1]);
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 255, b: 0, a: 255 }, true, "#canvas2");
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 255, b: 0, a: 255 }, true, "#canvas2");
ok(true, "The second canvas was correctly filled after highlighting.");
yield firstProgramActor.unhighlight();
yield secondProgramActor.unhighlight();
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
ok(true, "The two canvases were correctly filled after unhighlighting.");
});
}
}

View File

@ -133,6 +133,19 @@ function once(aTarget, aEventName, aUseCapture = false) {
return deferred.promise;
}
function observe(aNotificationName, aOwnsWeak = false) {
info("Waiting for observer notification: '" + aNotificationName + ".");
let deferred = promise.defer();
Services.obs.addObserver(function onNotification(...aArgs) {
Services.obs.removeObserver(onNotification, aNotificationName);
deferred.resolve.apply(deferred, aArgs);
}, aNotificationName, aOwnsWeak);
return deferred.promise;
}
function waitForFrame(aDebuggee) {
let deferred = promise.defer();
aDebuggee.requestAnimationFrame(deferred.resolve);
@ -193,16 +206,19 @@ function ensurePixelIs(aDebuggee, aPosition, aColor, aWaitFlag = false, aSelecto
return promise.reject(null);
}
function navigate(aTarget, aUrl) {
let navigated = once(aTarget, "navigate");
aTarget.client.activeTab.navigateTo(aUrl);
return navigated;
function navigateInHistory(aTarget, aDirection, aWaitForTargetEvent = "navigate") {
executeSoon(() => content.history[aDirection]());
return once(aTarget, aWaitForTargetEvent);
}
function reload(aTarget) {
let navigated = once(aTarget, "navigate");
function navigate(aTarget, aUrl, aWaitForTargetEvent = "navigate") {
executeSoon(() => aTarget.client.activeTab.navigateTo(aUrl));
return once(aTarget, aWaitForTargetEvent);
}
function reload(aTarget, aWaitForTargetEvent = "navigate") {
executeSoon(() => aTarget.client.activeTab.reload());
return navigated;
return once(aTarget, aWaitForTargetEvent);
}
function initBackend(aUrl) {

View File

@ -181,6 +181,10 @@ Tooltip.prototype = {
this.stopTogglingOnHover();
}
// If no targetNodeCb callback is provided, then we need to hide the tooltip
// on mouseleave since baseNode is the target node itself
this._hideOnMouseLeave = !targetNodeCb;
this._basedNode = baseNode;
this._showDelay = showDelay;
this._targetNodeCb = targetNodeCb || (() => true);
@ -221,7 +225,7 @@ Tooltip.prototype = {
},
_showOnHover: function(target) {
if (this._targetNodeCb && this._targetNodeCb(target, this)) {
if (this._targetNodeCb(target, this)) {
this.show(target);
this._lastHovered = target;
}
@ -230,6 +234,9 @@ Tooltip.prototype = {
_onBaseNodeMouseLeave: function() {
clearNamedTimeout(this.uid);
this._lastHovered = null;
if (this._hideOnMouseLeave) {
this.hide();
}
},
/**

View File

@ -49,8 +49,6 @@ let Svc = {};
XPCOMUtils.defineLazyServiceGetter(Svc, 'mime',
'@mozilla.org/mime;1', 'nsIMIMEService');
let profiler = Cc["@mozilla.org/tools/profiler;1"].getService(Ci.nsIProfiler);
function getBoolPref(pref, def) {
try {
return Services.prefs.getBoolPref(pref);
@ -222,7 +220,10 @@ ChromeActions.prototype = {
});
},
addProfilerMarker: function (marker) {
profiler.AddMarker(marker);
if ('nsIProfiler' in Ci) {
let profiler = Cc["@mozilla.org/tools/profiler;1"].getService(Ci.nsIProfiler);
profiler.AddMarker(marker);
}
},
getPluginParams: function getPluginParams() {
return JSON.stringify({

View File

@ -1 +1 @@
0.7.501
0.7.502

View File

@ -15,9 +15,9 @@
- in the network table when empty. -->
<!ENTITY netmonitorUI.emptyNotice2 "Perform a request or reload the page to see detailed information about network activity.">
<!-- LOCALIZATION NOTE (netmonitorUI.toolbar.status): This is the label displayed
<!-- LOCALIZATION NOTE (netmonitorUI.toolbar.status2): This is the label displayed
- in the network table toolbar, above the "status" column. -->
<!ENTITY netmonitorUI.toolbar.status "√">
<!ENTITY netmonitorUI.toolbar.status2 "✓">
<!-- LOCALIZATION NOTE (netmonitorUI.toolbar.method): This is the label displayed
- in the network table toolbar, above the "method" column. -->

View File

@ -9,8 +9,7 @@ let Cu = Components.utils;
let Cr = Components.results;
/**
* Handler for APZC display port and pan begin/end notifications.
* These notifications are only sent by widget/windows/winrt code when
* Misc. front end utilities for apzc management.
* the pref: layers.async-pan-zoom.enabled is true.
*/
@ -29,7 +28,6 @@ var APZCObserver = {
}
let os = Services.obs;
os.addObserver(this, "apzc-request-content-repaint", false);
os.addObserver(this, "apzc-handle-pan-begin", false);
os.addObserver(this, "apzc-handle-pan-end", false);
@ -42,6 +40,10 @@ var APZCObserver = {
switch (aEvent.type) {
case 'pageshow':
case 'TabSelect':
// ROOT_ID doesn't really identify the view we want. When we call
// this on a content document (tab), findElementWithViewId will
// always return the root content document associated with the
// scrollable frame.
const ROOT_ID = 1;
let windowUtils = Browser.selectedBrowser.contentWindow.
QueryInterface(Ci.nsIInterfaceRequestor).
@ -73,6 +75,7 @@ var APZCObserver = {
}
}
},
shutdown: function shutdown() {
if (!this._enabled) {
return;
@ -82,45 +85,12 @@ var APZCObserver = {
Elements.tabList.removeEventListener("TabClose", this, true);
let os = Services.obs;
os.removeObserver(this, "apzc-request-content-repaint");
os.removeObserver(this, "apzc-handle-pan-begin");
os.removeObserver(this, "apzc-handle-pan-end");
},
observe: function ao_observe(aSubject, aTopic, aData) {
if (aTopic == "apzc-request-content-repaint") {
let frameMetrics = JSON.parse(aData);
let scrollId = frameMetrics.scrollId;
let scrollTo = frameMetrics.scrollTo;
let displayPort = frameMetrics.displayPort;
let resolution = frameMetrics.resolution;
let compositedRect = frameMetrics.compositedRect;
let windowUtils = Browser.selectedBrowser.contentWindow.
QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIDOMWindowUtils);
windowUtils.setScrollPositionClampingScrollPortSize(compositedRect.width,
compositedRect.height);
Browser.selectedBrowser.messageManager.sendAsyncMessage("Content:SetDisplayPort", {
scrollX: scrollTo.x,
scrollY: scrollTo.y,
x: displayPort.x + scrollTo.x,
y: displayPort.y + scrollTo.y,
w: displayPort.width,
h: displayPort.height,
scale: resolution,
id: scrollId
});
if (this._debugEvents) {
Util.dumpLn("APZC scrollId: " + scrollId);
Util.dumpLn("APZC scrollTo.x: " + scrollTo.x + ", scrollTo.y: " + scrollTo.y);
Util.dumpLn("APZC setResolution: " + resolution);
Util.dumpLn("APZC setDisplayPortForElement: displayPort.x: " +
displayPort.x + ", displayPort.y: " + displayPort.y +
", displayPort.width: " + displayPort.width +
", displayort.height: " + displayPort.height);
}
} else if (aTopic == "apzc-handle-pan-begin") {
if (aTopic == "apzc-handle-pan-begin") {
// When we're panning, hide the main scrollbars by setting imprecise
// input (which sets a property on the browser which hides the scrollbar
// via CSS). This reduces jittering from left to right. We may be able
@ -141,7 +111,7 @@ var APZCObserver = {
// its scroll offset data.
case "Browser:ContentScroll": {
let data = json.viewId + " " + json.presShellId + " (" + json.scrollOffset.x + ", " + json.scrollOffset.y + ")";
Services.obs.notifyObservers(null, "scroll-offset-changed", data);
Services.obs.notifyObservers(null, "apzc-scroll-offset-changed", data);
break;
}
}

View File

@ -552,7 +552,6 @@ let ContentScroll = {
_scrollOffset: { x: 0, y: 0 },
init: function() {
addMessageListener("Content:SetDisplayPort", this);
addMessageListener("Content:SetWindowSize", this);
if (Services.prefs.getBoolPref("layers.async-pan-zoom.enabled")) {
@ -575,77 +574,9 @@ let ContentScroll = {
return { x: aElement.scrollLeft, y: aElement.scrollTop };
},
setScrollOffsetForElement: function(aElement, aLeft, aTop) {
if (aElement.parentNode == aElement.ownerDocument) {
aElement.ownerDocument.defaultView.scrollTo(aLeft, aTop);
} else {
aElement.scrollLeft = aLeft;
aElement.scrollTop = aTop;
}
},
receiveMessage: function(aMessage) {
let json = aMessage.json;
switch (aMessage.name) {
// Sent to us from chrome when the the apz has requested that the
// display port be updated and that content should repaint.
case "Content:SetDisplayPort": {
// Set resolution for root view
let rootCwu = content.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
if (json.id == 1) {
rootCwu.setResolution(json.scale, json.scale);
if (!WebProgressListener._firstPaint)
break;
}
let displayport = new Rect(json.x, json.y, json.w, json.h);
if (displayport.isEmpty())
break;
// Map ID to element
let element = null;
try {
element = rootCwu.findElementWithViewId(json.id);
} catch(e) {
// This could give NS_ERROR_NOT_AVAILABLE. In that case, the
// presshell is not available because the page is reloading.
}
if (!element)
break;
let binding = element.ownerDocument.getBindingParent(element);
if (binding instanceof Ci.nsIDOMHTMLInputElement && binding.mozIsTextField(false))
break;
// Set the scroll offset for this element if specified
if (json.scrollX >= 0 || json.scrollY >= 0) {
this.setScrollOffsetForElement(element, json.scrollX, json.scrollY);
if (element == content.document.documentElement) {
// scrollTo can make some small adjustments to the offset before
// actually scrolling the document. To ensure that _scrollOffset
// actually matches the offset stored in the window, re-query it.
this._scrollOffset = this.getScrollOffset(content);
}
}
// Set displayport. We want to set this after setting the scroll offset, because
// it is calculated based on the scroll offset.
let scrollOffset = this.getScrollOffsetForElement(element);
let x = displayport.x - scrollOffset.x;
let y = displayport.y - scrollOffset.y;
if (json.id == 1) {
x = Math.round(x * json.scale) / json.scale;
y = Math.round(y * json.scale) / json.scale;
}
let win = element.ownerDocument.defaultView;
let winCwu = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
winCwu.setDisplayPortForElement(x, y, displayport.width, displayport.height, element);
break;
}
case "Content:SetWindowSize": {
let cwu = content.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
cwu.setCSSViewport(json.width, json.height);
@ -704,8 +635,7 @@ let ContentScroll = {
if (target == content.document) {
if (this._scrollOffset.x == scrollOffset.x && this._scrollOffset.y == scrollOffset.y) {
// Don't send a scroll message back to APZC if it's the same as the
// last one set by APZC. We use this to avoid sending APZC back an
// event that it originally triggered.
// last one.
return;
}
this._scrollOffset = scrollOffset;

View File

@ -35,6 +35,8 @@ const TOPIC_TIMER_CALLBACK = "timer-callback";
const TOPIC_DELAYED_STARTUP = "browser-delayed-startup-finished";
const TOPIC_XUL_WINDOW_CLOSED = "xul-window-destroyed";
const FRAME_SCRIPT_URL = "chrome://browser/content/newtab/preloaderContent.js";
function createTimer(obj, delay) {
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
timer.init(obj, delay, Ci.nsITimer.TYPE_ONE_SHOT);
@ -61,6 +63,7 @@ this.BrowserNewTabPreloader = {
},
newTab: function Preloader_newTab(aTab) {
let swapped = false;
let win = aTab.ownerDocument.defaultView;
if (win.gBrowser) {
let utils = win.QueryInterface(Ci.nsIInterfaceRequestor)
@ -69,11 +72,17 @@ this.BrowserNewTabPreloader = {
let {width, height} = utils.getBoundsWithoutFlushing(win.gBrowser);
let hiddenBrowser = HiddenBrowsers.get(width, height)
if (hiddenBrowser) {
return hiddenBrowser.swapWithNewTab(aTab);
swapped = hiddenBrowser.swapWithNewTab(aTab);
}
// aTab's browser is now visible and is therefore allowed to make
// background captures.
let msgMan = aTab.linkedBrowser.messageManager;
msgMan.loadFrameScript(FRAME_SCRIPT_URL, false);
msgMan.sendAsyncMessage("BrowserNewTabPreloader:allowBackgroundCaptures");
}
return false;
return swapped;
}
};

View File

@ -50,6 +50,7 @@ html|*.highlighter-nodeinfobar-pseudo-classes {
.highlighter-nodeinfobar-button {
-moz-appearance: none;
border-width: 0;
padding: 0;
width: 26px;
min-height: 26px;

View File

@ -2380,11 +2380,6 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
width: 16px;
}
#identity-popup-help-icon:-moz-focusring {
outline: 1px dotted;
outline-offset: 1px;
}
#identity-popup-more-info-button {
margin-top: 6px;
margin-bottom: 0;

View File

@ -68,14 +68,14 @@ function submitForm(idNum) {
function submitFormMouse(idNum) {
$("test"+idNum).setAttribute("onload", "frameLoaded(this)");
// Use 4.999 instead of 5 to guard against the possibility that the
// Use 4.99 instead of 5 to guard against the possibility that the
// image's 'top' is exactly N + 0.5 pixels from the root. In that case
// we'd round up the widget mouse coordinate to N + 6, which relative
// to the image would be 5.5, which would get rounded up to 6 when
// submitting the form. Instead we round the widget mouse coordinate to
// N + 5, which relative to the image would be 4.5 which gets rounded up
// to 5.
synthesizeMouse($("test" + idNum + "image"), 4.999, 4.999, {});
synthesizeMouse($("test" + idNum + "image"), 4.99, 4.99, {});
}
addLoadEvent(function() {

View File

@ -651,6 +651,9 @@ static const dom::ConstantSpec gWinProperties[] =
INT_CONSTANT(MOVEFILE_COPY_ALLOWED),
INT_CONSTANT(MOVEFILE_REPLACE_EXISTING),
// GetFileAttributes error constant
INT_CONSTANT(INVALID_FILE_ATTRIBUTES),
// Errors
INT_CONSTANT(ERROR_ACCESS_DENIED),
INT_CONSTANT(ERROR_DIR_NOT_EMPTY),

View File

@ -1077,6 +1077,14 @@ nsIPresShell::SetAuthorStyleDisabled(bool aStyleDisabled)
if (aStyleDisabled != mStyleSet->GetAuthorStyleDisabled()) {
mStyleSet->SetAuthorStyleDisabled(aStyleDisabled);
ReconstructStyleData();
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (observerService) {
observerService->NotifyObservers(mDocument,
"author-style-disabled-changed",
nullptr);
}
}
}

View File

@ -99,8 +99,8 @@ function updateList() {
request.onsuccess = function() {
for (let i = 0; i < request.result.length; i++)
addApplication(request.result[i]);
if (!request.result.length)
document.getElementById("noapps").className = "";
if (request.result.length)
document.getElementById("main-container").classList.remove("hidden");
}
}

View File

@ -39,7 +39,7 @@
<div id="header-button" role="button" aria-label="&aboutApps.browseMarketplace;" pref="app.marketplaceURL" onclick="openLink(this);"/>
</div>
<div id="main-container" class="list hidden">
<div id="main-container" class="hidden">
<div>
<div class="spacer" id="spacer1"> </div>
<div id="appgrid"/>

View File

@ -134,7 +134,8 @@ Object.defineProperty(OSError.prototype, "becauseExists", {
*/
Object.defineProperty(OSError.prototype, "becauseNoSuchFile", {
get: function becauseNoSuchFile() {
return this.winLastError == Const.ERROR_FILE_NOT_FOUND;
return this.winLastError == Const.ERROR_FILE_NOT_FOUND ||
this.winLastError == Const.ERROR_PATH_NOT_FOUND;
}
});
/**

View File

@ -345,6 +345,17 @@
"FlushFileBuffers", ctypes.winapi_abi,
/*return*/ Type.zero_or_nothing,
/*file*/ Type.HANDLE);
declareLazyFFI(SysFile, "GetFileAttributes", libc,
"GetFileAttributesW", ctypes.winapi_abi,
/*return*/ Type.DWORD,
/*fileName*/ Type.path);
declareLazyFFI(SysFile, "SetFileAttributes", libc,
"SetFileAttributesW", ctypes.winapi_abi,
/*return*/ Type.zero_or_nothing,
/*fileName*/ Type.path,
/*fileAttributes*/ Type.DWORD);
};
exports.OS.Win = {

View File

@ -382,14 +382,27 @@
* @throws {OS.File.Error} In case of I/O error.
*/
File.remove = function remove(path, options = {}) {
let result = WinFile.DeleteFile(path);
if (!result) {
if ((!("ignoreAbsent" in options) || options.ignoreAbsent) &&
ctypes.winLastError == Const.ERROR_FILE_NOT_FOUND) {
if (WinFile.DeleteFile(path)) {
return;
}
if (ctypes.winLastError == Const.ERROR_FILE_NOT_FOUND) {
if ((!("ignoreAbsent" in options) || options.ignoreAbsent)) {
return;
}
throw new File.Error("remove");
} else if (ctypes.winLastError == Const.ERROR_ACCESS_DENIED) {
let attributes = WinFile.GetFileAttributes(path);
if (attributes != Const.INVALID_FILE_ATTRIBUTES &&
attributes & Const.FILE_ATTRIBUTE_READONLY) {
let newAttributes = attributes & ~Const.FILE_ATTRIBUTE_READONLY;
if (WinFile.SetFileAttributes(path, newAttributes) &&
WinFile.DeleteFile(path)) {
return;
}
}
}
throw new File.Error("remove");
};
/**

View File

@ -151,7 +151,6 @@ let test = maketest("Main", function main(test) {
SimpleTest.waitForExplicitFinish();
yield test_constants();
yield test_path();
yield test_open();
yield test_stat();
yield test_debug();
yield test_info_features_detect();
@ -199,50 +198,6 @@ let test_path = maketest("path", function path(test) {
});
});
/**
* Test OS.File.open for reading:
* - with an existing file (should succeed);
* - with a non-existing file (should fail);
* - with inconsistent arguments (should fail).
*/
let test_open = maketest("open", function open(test) {
return Task.spawn(function() {
// Attempt to open a file that does not exist, ensure that it yields the
// appropriate error.
try {
let fd = yield OS.File.open(OS.Path.join(".", "This file does not exist"));
test.ok(false, "File opening 1 succeeded (it should fail)" + fd);
} catch (err) {
test.ok(true, "File opening 1 failed " + err);
test.ok(err instanceof OS.File.Error, "File opening 1 returned a file error");
test.ok(err.becauseNoSuchFile, "File opening 1 informed that the file does not exist");
}
// Attempt to open a file with the wrong args, so that it fails before
// serialization, ensure that it yields the appropriate error.
test.info("Attempting to open a file with wrong arguments");
try {
let fd = yield OS.File.open(1, 2, 3);
test.ok(false, "File opening 2 succeeded (it should fail)" + fd);
} catch (err) {
test.ok(true, "File opening 2 failed " + err);
test.ok(!(err instanceof OS.File.Error), "File opening 2 returned something that is not a file error");
test.ok(err.constructor.name == "TypeError", "File opening 2 returned a TypeError");
}
// Attempt to open a file correctly
test.info("Attempting to open a file correctly");
let openedFile = yield OS.File.open(EXISTING_FILE);
test.ok(true, "File opened correctly");
test.info("Attempting to close a file correctly");
yield openedFile.close();
test.info("Attempting to close a file again");
yield openedFile.close();
});
});
/**
* Test OS.File.stat and OS.File.prototype.stat
*/

View File

@ -844,4 +844,16 @@ function test_remove_file()
OS.File.remove(absent_file_name);
});
ok(!exn, "test_remove_file: ignoreAbsent works");
if (OS.Win) {
let file_name = "test_osfile_front_file_to_remove.tmp";
let file = OS.File.open(file_name, {write: true});
file.close();
ok(OS.File.exists(file_name), "test_remove_file: test file exists");
OS.Win.File.SetFileAttributes(file_name,
OS.Constants.Win.FILE_ATTRIBUTE_READONLY);
OS.File.remove(file_name);
ok(!OS.File.exists(file_name),
"test_remove_file: test file has been removed");
}
}

View File

@ -0,0 +1,75 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
Components.utils.import("resource://gre/modules/osfile.jsm");
function run_test() {
do_test_pending();
run_next_test();
}
/**
* Test OS.File.open for reading:
* - with an existing file (should succeed);
* - with a non-existing file (should fail);
* - with inconsistent arguments (should fail).
*/
add_task(function() {
// Attempt to open a file that does not exist, ensure that it yields the
// appropriate error.
try {
let fd = yield OS.File.open(OS.Path.join(".", "This file does not exist"));
do_check_true(false, "File opening 1 succeeded (it should fail)");
} catch (err if err instanceof OS.File.Error && err.becauseNoSuchFile) {
do_print("File opening 1 failed " + err);
}
// Attempt to open a file with the wrong args, so that it fails before
// serialization, ensure that it yields the appropriate error.
do_print("Attempting to open a file with wrong arguments");
try {
let fd = yield OS.File.open(1, 2, 3);
do_check_true(false, "File opening 2 succeeded (it should fail)" + fd);
} catch (err) {
do_print("File opening 2 failed " + err);
do_check_false(err instanceof OS.File.Error,
"File opening 2 returned something that is not a file error");
do_check_true(err.constructor.name == "TypeError",
"File opening 2 returned a TypeError");
}
// Attempt to open a file correctly
do_print("Attempting to open a file correctly");
let openedFile = yield OS.File.open(OS.Path.join(do_get_cwd().path, "test_open.js"));
do_print("File opened correctly");
do_print("Attempting to close a file correctly");
yield openedFile.close();
do_print("Attempting to close a file again");
yield openedFile.close();
});
/**
* Test the error thrown by OS.File.open when attempting to open a directory
* that does not exist.
*/
add_task(function test_error_attributes () {
let dir = OS.Path.join(do_get_profile().path, "test_osfileErrorAttrs");
let fpath = OS.Path.join(dir, "test_error_attributes.txt");
try {
yield OS.File.open(fpath, {truncate: true}, {});
do_check_true(false, "Opening path suceeded (it should fail) " + fpath);
} catch (err) {
do_check_true(err instanceof OS.File.Error);
do_check_true(err.becauseNoSuchFile);
}
});
add_task(function() {
do_test_finished();
});

View File

@ -19,3 +19,4 @@ tail =
[test_reset.js]
[test_shutdown.js]
[test_unique.js]
[test_open.js]

View File

@ -1,9 +1,27 @@
/*
* Initialization: for each test, remove any prior notifications.
*/
function cleanUpPopupNotifications() {
var container = getPopupNotifications(window.top);
var notes = container._currentNotifications;
info(true, "Removing " + notes.length + " popup notifications.");
for (var i = notes.length-1; i >= 0; i--) {
notes[i].remove();
}
}
cleanUpPopupNotifications();
/*
* getPopupNotifications
*
* Fetches the popup notification for the specified window.
*/
function getPopupNotifications(aWindow) {
var Ci = SpecialPowers.Ci;
var Cc = SpecialPowers.Cc;
ok(Ci != null, "Access Ci");
ok(Cc != null, "Access Cc");
var chromeWin = SpecialPowers.wrap(aWindow)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)

View File

@ -27,6 +27,8 @@ loader:
5. Prepend `module.exports = ` to the package.json file contents, so that the
JSON data is exported, and we can load package.json as a module.
Bug 933482: Note, this is a workaround for Bug 910594, which will allow the SDK loader to require JSON files. To remove ambiguity, comment out the `require('./package.json').version` line in `escodegen.js` so that when Bug 910594 is uplifted into central, it does not attempt to look for `package.json`, rather than `package.json.js`. This is a temporary workaround, and once Bug 933500 is solved, either `package.json` or `package.json.js` will work.
6. Copy the estraverse.js that escodegen depends on into our tree:
$ cp node_modules/estraverse/estraverse.js /path/to/mozilla-central/devtools/escodegen/estraverse.js

View File

@ -2055,7 +2055,7 @@
FORMAT_DEFAULTS = getDefaultOptions().format;
exports.version = require('./package.json').version;
// exports.version = require('./package.json').version;
exports.generate = generate;
exports.attachComments = estraverse.attachComments;
exports.browser = false;

View File

@ -767,7 +767,7 @@ BrowserTabActor.prototype = {
* Prepare to enter a nested event loop by disabling debuggee events.
*/
preNest: function BTA_preNest() {
if (!this.browser) {
if (!this.window) {
// The tab is already closed.
return;
}
@ -782,7 +782,7 @@ BrowserTabActor.prototype = {
* Prepare to exit a nested event loop by enabling debuggee events.
*/
postNest: function BTA_postNest(aNestData) {
if (!this.browser) {
if (!this.window) {
// The tab is already closed.
return;
}

View File

@ -184,7 +184,9 @@ let WebGLActor = exports.WebGLActor = protocol.ActorClass({
protocol.Actor.prototype.initialize.call(this, conn);
this.tabActor = tabActor;
this._onGlobalCreated = this._onGlobalCreated.bind(this);
this._onGlobalDestroyed = this._onGlobalDestroyed.bind(this);
this._onProgramLinked = this._onProgramLinked.bind(this);
this._programActorsCache = [];
},
destroy: function(conn) {
protocol.Actor.prototype.destroy.call(this, conn);
@ -198,7 +200,7 @@ let WebGLActor = exports.WebGLActor = protocol.ActorClass({
*
* See ContentObserver and WebGLInstrumenter for more details.
*/
setup: method(function() {
setup: method(function({ reload }) {
if (this._initialized) {
return;
}
@ -206,10 +208,14 @@ let WebGLActor = exports.WebGLActor = protocol.ActorClass({
this._contentObserver = new ContentObserver(this.tabActor);
this._webglObserver = new WebGLObserver();
on(this._contentObserver, "global-created", this._onGlobalCreated);
on(this._contentObserver, "global-destroyed", this._onGlobalDestroyed);
on(this._webglObserver, "program-linked", this._onProgramLinked);
this.tabActor.window.location.reload();
if (reload) {
this.tabActor.window.location.reload();
}
}, {
request: { reload: Option(0, "boolean") },
oneway: true
}),
@ -225,11 +231,23 @@ let WebGLActor = exports.WebGLActor = protocol.ActorClass({
this._initialized = false;
this._contentObserver.stopListening();
off(this._contentObserver, "global-created", this._onGlobalCreated);
off(this._contentObserver, "global-destroyed", this._onGlobalDestroyed);
off(this._webglObserver, "program-linked", this._onProgramLinked);
}, {
oneway: true
}),
/**
* Gets an array of cached program actors for the current tab actor's window.
* This is useful for dealing with bfcache, when no new programs are linked.
*/
getPrograms: method(function() {
let id = getInnerWindowID(this.tabActor.window);
return this._programActorsCache.filter(e => e.owner == id).map(e => e.actor);
}, {
response: { programs: RetVal("array:gl-program") }
}),
/**
* Events emitted by this actor. The "program-linked" event is fired
* every time a WebGL program was linked with its respective two shaders.
@ -248,6 +266,14 @@ let WebGLActor = exports.WebGLActor = protocol.ActorClass({
WebGLInstrumenter.handle(window, this._webglObserver);
},
/**
* Invoked whenever the current tab actor's inner window is destroyed.
*/
_onGlobalDestroyed: function(id) {
this._programActorsCache =
this._programActorsCache.filter(e => e.owner != id);
},
/**
* Invoked whenever the current WebGL context links a program.
*/
@ -275,6 +301,11 @@ let WebGLActor = exports.WebGLActor = protocol.ActorClass({
programActor.program = program;
programActor.shadersData = shadersData;
this._programActorsCache.push({
owner: getInnerWindowID(this.tabActor.window),
actor: programActor
});
events.emit(this, "program-linked", programActor);
}
});
@ -297,8 +328,9 @@ let WebGLFront = exports.WebGLFront = protocol.FrontClass(WebGLActor, {
* instrument the HTMLCanvasElement with the appropriate inspection methods.
*/
function ContentObserver(tabActor) {
this._contentWindow = tabActor.browser.contentWindow;
this._contentWindow = tabActor.window;
this._onContentGlobalCreated = this._onContentGlobalCreated.bind(this);
this._onInnerWindowDestroyed = this._onInnerWindowDestroyed.bind(this);
this.startListening();
}
@ -309,6 +341,8 @@ ContentObserver.prototype = {
startListening: function() {
Services.obs.addObserver(
this._onContentGlobalCreated, "content-document-global-created", false);
Services.obs.addObserver(
this._onInnerWindowDestroyed, "inner-window-destroyed", false);
},
/**
@ -317,6 +351,8 @@ ContentObserver.prototype = {
stopListening: function() {
Services.obs.removeObserver(
this._onContentGlobalCreated, "content-document-global-created", false);
Services.obs.removeObserver(
this._onInnerWindowDestroyed, "inner-window-destroyed", false);
},
/**
@ -326,6 +362,14 @@ ContentObserver.prototype = {
if (subject == this._contentWindow) {
emit(this, "global-created", subject);
}
},
/**
* Fired when an inner window is removed from the backward/forward cache.
*/
_onInnerWindowDestroyed: function(subject, topic, data) {
let id = subject.QueryInterface(Ci.nsISupportsPRUint64).data;
emit(this, "global-destroyed", id);
}
};
@ -849,3 +893,10 @@ WebGLProxy.prototype = {
return result;
}
};
function getInnerWindowID(window) {
return window
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.currentInnerWindowID;
}

View File

@ -177,16 +177,64 @@ let PendingErrors = {
lineNumber: null
};
try { // Defend against non-enumerable values
if (typeof error == "object" && error) {
if (error && error instanceof Ci.nsIException) {
// nsIException does things a little differently.
try {
// For starters |.toString()| does not only contain the message, but
// also the top stack frame, and we don't really want that.
value.message = error.message;
} catch (ex) {
// Ignore field
}
try {
// All lowercase filename. ;)
value.fileName = error.filename;
} catch (ex) {
// Ignore field
}
try {
value.lineNumber = error.lineNumber;
} catch (ex) {
// Ignore field
}
} else if (typeof error == "object" && error) {
for (let k of ["fileName", "stack", "lineNumber"]) {
try { // Defend against fallible getters and string conversions
let v = error[k];
value[k] = v ? ("" + v):null;
value[k] = v ? ("" + v) : null;
} catch (ex) {
// Ignore field
}
}
}
if (!value.stack) {
// |error| is not an Error (or Error-alike). Try to figure out the stack.
let stack = null;
if (error && error.location &&
error.location instanceof Ci.nsIStackFrame) {
// nsIException has full stack frames in the |.location| member.
stack = error.location;
} else {
// Components.stack to the rescue!
stack = Components.stack;
// Remove those top frames that refer to Promise.jsm.
while (stack) {
if (!stack.filename.endsWith("/Promise.jsm")) {
break;
}
stack = stack.caller;
}
}
if (stack) {
let frames = [];
while (stack) {
frames.push(stack);
stack = stack.caller;
}
value.stack = frames.join("\n");
}
}
} catch (ex) {
// Ignore value
}

View File

@ -757,14 +757,20 @@ function wait_for_uncaught(aMustAppear, aTimeout = undefined) {
let make_string_rejection = function make_string_rejection() {
let salt = (Math.random() * ( Math.pow(2, 24) - 1 ));
let string = "This is an uncaught rejection " + salt;
return {mustFind: [string], error: string};
// Our error is not Error-like nor an nsIException, so the stack will
// include the closure doing the actual rejection.
return {mustFind: ["test_rejection_closure", string], error: string};
};
let make_num_rejection = function make_num_rejection() {
let salt = (Math.random() * ( Math.pow(2, 24) - 1 ));
return {mustFind: [salt], error: salt};
// Our error is not Error-like nor an nsIException, so the stack will
// include the closure doing the actual rejection.
return {mustFind: ["test_rejection_closure", salt], error: salt};
};
let make_undefined_rejection = function make_undefined_rejection() {
return {mustFind: [], error: undefined};
// Our error is not Error-like nor an nsIException, so the stack will
// include the closure doing the actual rejection.
return {mustFind: ["test_rejection_closure"], error: undefined};
};
let make_error_rejection = function make_error_rejection() {
let salt = (Math.random() * ( Math.pow(2, 24) - 1 ));
@ -774,16 +780,26 @@ function wait_for_uncaught(aMustAppear, aTimeout = undefined) {
error: error
};
};
let make_exception_rejection = function make_exception_rejection() {
let salt = (Math.random() * ( Math.pow(2, 24) - 1 ));
let exn = new Components.Exception("This is an uncaught exception " + salt,
Components.results.NS_ERROR_NOT_AVAILABLE);
return {
mustFind: [exn.message, exn.filename, exn.lineNumber, exn.location.toString()],
error: exn
};
};
for (let make_rejection of [make_string_rejection,
make_num_rejection,
make_undefined_rejection,
make_error_rejection]) {
make_error_rejection,
make_exception_rejection]) {
let {mustFind, error} = make_rejection();
let name = make_rejection.name;
tests.push(make_promise_test(function test_uncaught_is_reported() {
do_print("Testing with rejection " + name);
let promise = wait_for_uncaught(mustFind);
(function() {
(function test_rejection_closure() {
// For the moment, we cannot be absolutely certain that a value is
// garbage-collected, even if it is not referenced anymore, due to
// the conservative stack-scanning algorithm.

View File

@ -11,6 +11,11 @@
#include "nsIDOMMouseEvent.h"
#include "mozilla/Preferences.h"
#ifdef MOZ_LOGGING
#define FORCE_PR_LOG /* Allow logging in the release build */
#endif // MOZ_LOGGING
#include "prlog.h"
#include "nsString.h"
#include "nsDirectoryServiceUtils.h"
#include "imgIContainer.h"
@ -35,6 +40,10 @@
#include "nsTextStore.h"
#endif // #ifdef NS_ENABLE_TSF
#ifdef PR_LOGGING
PRLogModuleInfo* gWindowsLog = nullptr;
#endif
namespace mozilla {
namespace widget {
@ -75,6 +84,11 @@ WinUtils::DwmGetCompositionTimingInfoProc WinUtils::dwmGetCompositionTimingInfoP
void
WinUtils::Initialize()
{
#ifdef PR_LOGGING
if (!gWindowsLog) {
gWindowsLog = PR_NewLogModule("Widget");
}
#endif
if (!sDwmDll && WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION) {
sDwmDll = ::LoadLibraryW(kDwmLibraryName);
@ -128,6 +142,81 @@ WinUtils::GetWindowsServicePackVersion(UINT& aOutMajor, UINT& aOutMinor)
return true;
}
// static
void
WinUtils::LogW(const wchar_t *fmt, ...)
{
va_list args = NULL;
if(!lstrlenW(fmt)) {
return;
}
va_start(args, fmt);
int buflen = _vscwprintf(fmt, args);
wchar_t* buffer = new wchar_t[buflen+1];
if (!buffer) {
va_end(args);
return;
}
vswprintf(buffer, buflen, fmt, args);
va_end(args);
// MSVC, including remote debug sessions
OutputDebugStringW(buffer);
OutputDebugStringW(L"\n");
int len = wcslen(buffer);
if (len) {
char* utf8 = new char[len+1];
memset(utf8, 0, sizeof(utf8));
if (WideCharToMultiByte(CP_ACP, 0, buffer,
-1, utf8, len+1, NULL,
NULL) > 0) {
// desktop console
printf("%s\n", utf8);
#ifdef PR_LOGGING
NS_ASSERTION(gWindowsLog, "Called WinUtils Log() but Widget "
"log module doesn't exist!");
PR_LOG(gWindowsLog, PR_LOG_ALWAYS, (utf8));
#endif
}
delete[] utf8;
}
delete[] buffer;
}
// static
void
WinUtils::Log(const char *fmt, ...)
{
va_list args = NULL;
if(!strlen(fmt)) {
return;
}
va_start(args, fmt);
int buflen = _vscprintf(fmt, args);
char* buffer = new char[buflen+1];
if (!buffer) {
va_end(args);
return;
}
vsprintf(buffer, fmt, args);
va_end(args);
// MSVC, including remote debug sessions
OutputDebugStringA(buffer);
OutputDebugStringW(L"\n");
// desktop console
printf("%s\n", buffer);
#ifdef PR_LOGGING
NS_ASSERTION(gWindowsLog, "Called WinUtils Log() but Widget "
"log module doesn't exist!");
PR_LOG(gWindowsLog, PR_LOG_ALWAYS, (buffer));
#endif
delete[] buffer;
}
/* static */
bool
WinUtils::PeekMessage(LPMSG aMsg, HWND aWnd, UINT aFirstMessage,

View File

@ -53,6 +53,13 @@ namespace widget {
QS_ALLPOSTMESSAGE | QS_RAWINPUT | \
QS_TOUCH | QS_POINTER)
// Logging macros
#define LogFunction() mozilla::widget::WinUtils::Log(__FUNCTION__)
#define LogThread() mozilla::widget::WinUtils::Log("%s: IsMainThread:%d ThreadId:%X", __FUNCTION__, NS_IsMainThread(), GetCurrentThreadId())
#define LogThis() mozilla::widget::WinUtils::Log("[%X] %s", this, __FUNCTION__)
#define LogException(e) mozilla::widget::WinUtils::Log("%s Exception:%s", __FUNCTION__, e->ToString()->Data())
#define LogHRESULT(hr) mozilla::widget::WinUtils::Log("%s hr=%X", __FUNCTION__, hr)
class myDownloadObserver MOZ_FINAL : public nsIDownloadObserver
{
public:
@ -76,6 +83,13 @@ public:
// Returns true on success, false on failure.
static bool GetWindowsServicePackVersion(UINT& aOutMajor, UINT& aOutMinor);
/**
* Logging helpers that dump output to prlog module 'Widget', console, and
* OutputDebugString. Note these output in both debug and release builds.
*/
static void Log(const char *fmt, ...);
static void LogW(const wchar_t *fmt, ...);
/**
* PeekMessage() and GetMessage() are wrapper methods for PeekMessageW(),
* GetMessageW(), ITfMessageMgr::PeekMessageW() and

View File

@ -253,7 +253,7 @@ uint32_t nsWindow::sOOPPPluginFocusEvent =
static const char *sScreenManagerContractID = "@mozilla.org/gfx/screenmanager;1";
#ifdef PR_LOGGING
PRLogModuleInfo* gWindowsLog = nullptr;
extern PRLogModuleInfo* gWindowsLog;
#endif
// Global used in Show window enumerations.
@ -311,12 +311,6 @@ static const int32_t kResizableBorderMinSize = 3;
nsWindow::nsWindow() : nsWindowBase()
{
#ifdef PR_LOGGING
if (!gWindowsLog) {
gWindowsLog = PR_NewLogModule("nsWindow");
}
#endif
mIconSmall = nullptr;
mIconBig = nullptr;
mWnd = nullptr;

View File

@ -8,57 +8,201 @@
#include "nsThreadUtils.h"
#include "MetroUtils.h"
#include "nsPrintfCString.h"
#include "nsIWidgetListener.h"
#include "APZCCallbackHelper.h"
#include "nsIDocument.h"
#include "nsPresContext.h"
#include "nsIDOMElement.h"
#include "mozilla/dom/Element.h"
#include "nsIDOMWindowUtils.h"
#include "nsIInterfaceRequestorUtils.h"
//#define DEBUG_CONTROLLER 1
#ifdef DEBUG_CONTROLLER
#include "WinUtils.h"
using namespace mozilla::widget;
#endif
namespace mozilla {
namespace widget {
namespace winrt {
nsRefPtr<mozilla::layers::APZCTreeManager> APZController::sAPZC;
/*
* Metro layout specific - test to see if a sub document is a
* tab.
*/
static bool
IsTab(nsCOMPtr<nsIDocument>& aSubDocument)
{
nsRefPtr<nsIDocument> parent = aSubDocument->GetParentDocument();
if (!parent) {
NS_WARNING("huh? IsTab should always get a sub document for a parameter");
return false;
}
return parent->IsRootDisplayDocument();
}
/*
* Returns the sub document associated with the scroll id.
*/
static bool
GetDOMTargets(nsIPresShell* aPresShell, uint64_t aScrollId,
nsCOMPtr<nsIDocument>& aSubDocument,
nsCOMPtr<nsIDOMElement>& aTargetElement)
{
MOZ_ASSERT(aPresShell);
nsRefPtr<nsIDocument> rootDocument = aPresShell->GetDocument();
if (!rootDocument) {
return false;
}
nsCOMPtr<nsIDOMWindowUtils> rootUtils;
nsCOMPtr<nsIDOMWindow> rootWindow = rootDocument->GetDefaultView();
if (!rootWindow) {
return false;
}
rootUtils = do_GetInterface(rootWindow);
if (!rootUtils) {
return false;
}
// For tabs and subframes this will return the HTML sub document
rootUtils->FindElementWithViewId(aScrollId, getter_AddRefs(aTargetElement));
if (!aTargetElement) {
return false;
}
nsCOMPtr<mozilla::dom::Element> domElement = do_QueryInterface(aTargetElement);
if (!domElement) {
return false;
}
aSubDocument = domElement->OwnerDoc();
if (!aSubDocument) {
return false;
}
// If the root element equals domElement, FindElementWithViewId found
// a document, vs. an element within a document.
if (aSubDocument->GetRootElement() == domElement && IsTab(aSubDocument)) {
aTargetElement = nullptr;
}
return true;
}
class RequestContentRepaintEvent : public nsRunnable
{
typedef mozilla::layers::FrameMetrics FrameMetrics;
typedef mozilla::layers::FrameMetrics FrameMetrics;
public:
RequestContentRepaintEvent(const FrameMetrics& aFrameMetrics) : mFrameMetrics(aFrameMetrics)
{
RequestContentRepaintEvent(const FrameMetrics& aFrameMetrics,
nsIWidgetListener* aListener,
CSSIntPoint* aLastOffsetOut) :
mFrameMetrics(aFrameMetrics),
mWidgetListener(aListener),
mLastOffsetOut(aLastOffsetOut)
{
}
NS_IMETHOD Run() {
// This event shuts down the worker thread and so must be main thread.
MOZ_ASSERT(NS_IsMainThread());
#ifdef DEBUG_CONTROLLER
WinUtils::Log("APZController: mScrollOffset: %f %f", mFrameMetrics.mScrollOffset.x,
mFrameMetrics.mScrollOffset.y);
#endif
nsIPresShell* presShell = mWidgetListener->GetPresShell();
if (!presShell) {
return NS_OK;
}
NS_IMETHOD Run() {
// This event shuts down the worker thread and so must be main thread.
MOZ_ASSERT(NS_IsMainThread());
CSSToScreenScale resolution = mFrameMetrics.mZoom;
CSSRect compositedRect = mFrameMetrics.CalculateCompositedRectInCssPixels();
NS_ConvertASCIItoUTF16 data(nsPrintfCString("{ " \
" \"resolution\": %.2f, " \
" \"scrollId\": %d, " \
" \"compositedRect\": { \"width\": %d, \"height\": %d }, " \
" \"displayPort\": { \"x\": %d, \"y\": %d, \"width\": %d, \"height\": %d }, " \
" \"scrollTo\": { \"x\": %d, \"y\": %d }" \
"}",
(float)(resolution.scale / mFrameMetrics.mDevPixelsPerCSSPixel.scale),
(int)mFrameMetrics.mScrollId,
(int)compositedRect.width,
(int)compositedRect.height,
(int)mFrameMetrics.mDisplayPort.x,
(int)mFrameMetrics.mDisplayPort.y,
(int)mFrameMetrics.mDisplayPort.width,
(int)mFrameMetrics.mDisplayPort.height,
(int)mFrameMetrics.mScrollOffset.x,
(int)mFrameMetrics.mScrollOffset.y));
MetroUtils::FireObserver("apzc-request-content-repaint", data.get());
return NS_OK;
nsCOMPtr<nsIDocument> subDocument;
nsCOMPtr<nsIDOMElement> targetElement;
if (!GetDOMTargets(presShell, mFrameMetrics.mScrollId,
subDocument, targetElement)) {
return NS_OK;
}
// If we're dealing with a sub frame or content editable element,
// call UpdateSubFrame.
if (targetElement) {
#ifdef DEBUG_CONTROLLER
WinUtils::Log("APZController: detected subframe or content editable");
#endif
nsCOMPtr<nsIContent> content = do_QueryInterface(targetElement);
if (content) {
APZCCallbackHelper::UpdateSubFrame(content, mFrameMetrics);
}
return NS_OK;
}
#ifdef DEBUG_CONTROLLER
WinUtils::Log("APZController: detected tab");
#endif
// We're dealing with a tab, call UpdateRootFrame.
nsCOMPtr<nsIDOMWindowUtils> utils;
nsCOMPtr<nsIDOMWindow> window = subDocument->GetDefaultView();
if (window) {
utils = do_GetInterface(window);
if (utils) {
APZCCallbackHelper::UpdateRootFrame(utils, mFrameMetrics);
// Return the actual scroll value so we can use it to filter
// out scroll messages triggered by setting the display port.
CSSIntPoint actualScrollOffset;
utils->GetScrollXY(false, &actualScrollOffset.x, &actualScrollOffset.y);
if (mLastOffsetOut) {
*mLastOffsetOut = actualScrollOffset;
}
#ifdef DEBUG_CONTROLLER
WinUtils::Log("APZController: %I64d mDisplayPort: %0.2f %0.2f %0.2f %0.2f",
mFrameMetrics.mScrollId,
mFrameMetrics.mDisplayPort.x,
mFrameMetrics.mDisplayPort.y,
mFrameMetrics.mDisplayPort.width,
mFrameMetrics.mDisplayPort.height);
#endif
}
}
return NS_OK;
}
protected:
const FrameMetrics mFrameMetrics;
FrameMetrics mFrameMetrics;
nsIWidgetListener* mWidgetListener;
CSSIntPoint* mLastOffsetOut;
};
void
APZController::SetWidgetListener(nsIWidgetListener* aWidgetListener)
{
mWidgetListener = aWidgetListener;
}
// APZC sends us this request when we need to update the display port on
// the scrollable frame the apzc is managing.
void
APZController::RequestContentRepaint(const FrameMetrics& aFrameMetrics)
{
// Send the result back to the main thread so that it can shutdown
nsCOMPtr<nsIRunnable> r1 = new RequestContentRepaintEvent(aFrameMetrics);
if (!mWidgetListener) {
NS_WARNING("Can't update display port, !mWidgetListener");
return;
}
#ifdef DEBUG_CONTROLLER
WinUtils::Log("APZController::RequestContentRepaint scroll id = %I64d",
aFrameMetrics.mScrollId);
#endif
nsCOMPtr<nsIRunnable> r1 = new RequestContentRepaintEvent(aFrameMetrics,
mWidgetListener,
&mLastScrollOffset);
if (!NS_IsMainThread()) {
NS_DispatchToMainThread(r1);
} else {
@ -66,6 +210,27 @@ APZController::RequestContentRepaint(const FrameMetrics& aFrameMetrics)
}
}
// Content send us this when it detect content has scrolled via
// a dom scroll event. Note we get these in response to dom scroll
// events and as a result of apzc scrolling which we filter out.
void
APZController::UpdateScrollOffset(const mozilla::layers::ScrollableLayerGuid& aScrollLayerId,
CSSIntPoint& aScrollOffset)
{
#ifdef DEBUG_CONTROLLER
WinUtils::Log("APZController::UpdateScrollOffset: %d %d == %d %d",
aScrollOffset.x, aScrollOffset.y,
mLastScrollOffset.x, mLastScrollOffset.y);
#endif
if (!sAPZC || mLastScrollOffset == aScrollOffset) {
return;
}
sAPZC->UpdateScrollOffset(aScrollLayerId, aScrollOffset);
}
// Gesture event handlers from the APZC. Currently not in use.
void
APZController::HandleDoubleTap(const CSSIntPoint& aPoint)
{
@ -81,8 +246,11 @@ APZController::HandleLongTap(const CSSIntPoint& aPoint)
{
}
// requests that we send a mozbrowserasyncscroll domevent. not in use.
void
APZController::SendAsyncScrollDOMEvent(FrameMetrics::ViewID aScrollId, const CSSRect &aContentRect, const CSSSize &aScrollableSize)
APZController::SendAsyncScrollDOMEvent(FrameMetrics::ViewID aScrollId,
const CSSRect &aContentRect,
const CSSSize &aScrollableSize)
{
}
@ -92,6 +260,8 @@ APZController::PostDelayedTask(Task* aTask, int aDelayMs)
MessageLoop::current()->PostDelayedTask(FROM_HERE, aTask, aDelayMs);
}
// async scroll notifications
void
APZController::HandlePanBegin()
{

View File

@ -7,18 +7,23 @@
#include "mozwrlbase.h"
#include "mozilla/layers/GeckoContentController.h"
#include "mozilla/layers/APZCTreeManager.h"
#include "FrameMetrics.h"
#include "Units.h"
class nsIWidgetListener;
namespace mozilla {
namespace widget {
namespace winrt {
class APZController : public mozilla::layers::GeckoContentController
class APZController :
public mozilla::layers::GeckoContentController
{
typedef mozilla::layers::FrameMetrics FrameMetrics;
public:
// GeckoContentController interface
virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics);
virtual void HandleDoubleTap(const mozilla::CSSIntPoint& aPoint);
virtual void HandleSingleTap(const mozilla::CSSIntPoint& aPoint);
@ -27,6 +32,16 @@ public:
virtual void PostDelayedTask(Task* aTask, int aDelayMs);
virtual void HandlePanBegin();
virtual void HandlePanEnd();
void SetWidgetListener(nsIWidgetListener* aWidgetListener);
void UpdateScrollOffset(const mozilla::layers::ScrollableLayerGuid& aScrollLayerId, CSSIntPoint& aScrollOffset);
public:
static nsRefPtr<mozilla::layers::APZCTreeManager> sAPZC;
private:
nsIWidgetListener* mWidgetListener;
CSSIntPoint mLastScrollOffset;
};
} } }

View File

@ -98,7 +98,7 @@ FrameworkView::Run()
mMetroApp->Run();
// Gecko is completely shut down at this point.
Log("Exiting FrameworkView::Run()");
WinUtils::Log("Exiting FrameworkView::Run()");
return S_OK;
}
@ -463,10 +463,9 @@ FrameworkView::OnAutomationProviderRequested(ICoreWindow* aSender,
LogFunction();
if (!EnsureAutomationProviderCreated())
return E_FAIL;
Log("OnAutomationProviderRequested %X", mAutomationProvider.Get());
HRESULT hr = aArgs->put_AutomationProvider(mAutomationProvider.Get());
if (FAILED(hr)) {
Log("put failed? %X", hr);
WinUtils::Log("put failed? %X", hr);
}
return S_OK;
}

View File

@ -22,6 +22,7 @@ using namespace ABI::Windows::System;
using namespace ABI::Windows::Foundation;
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace mozilla::widget;
// Metro specific XRE methods we call from here on an
// appropriate thread.
@ -83,11 +84,11 @@ MetroApp::Run()
this, &MetroApp::OnResuming).Get(), &mResumeEvent);
AssertHRESULT(hr);
Log("XPCOM startup initialization began");
WinUtils::Log("XPCOM startup initialization began");
nsresult rv = XRE_metroStartup(true);
Log("XPCOM startup initialization complete");
WinUtils::Log("XPCOM startup initialization complete");
if (NS_FAILED(rv)) {
Log("XPCOM startup initialization failed, bailing. rv=%X", rv);
WinUtils::Log("XPCOM startup initialization failed, bailing. rv=%X", rv);
CoreExit();
}
}
@ -153,7 +154,7 @@ HRESULT
MetroApp::OnAsyncTileCreated(ABI::Windows::Foundation::IAsyncOperation<bool>* aOperation,
AsyncStatus aStatus)
{
Log("Async operation status: %d", aStatus);
WinUtils::Log("Async operation status: %d", aStatus);
return S_OK;
}
@ -217,12 +218,6 @@ XRE_MetroCoreApplicationRun()
using namespace mozilla::widget::winrt;
#ifdef PR_LOGGING
if (!gWindowsLog) {
gWindowsLog = PR_NewLogModule("nsWindow");
}
#endif
sMetroApp = Make<MetroApp>();
HStringReference className(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication);
@ -256,7 +251,7 @@ XRE_MetroCoreApplicationRun()
hr = sCoreApp->Run(sMetroApp.Get());
sFrameworkView = nullptr;
Log("Exiting CoreApplication::Run");
WinUtils::Log("Exiting CoreApplication::Run");
sCoreApp = nullptr;
sMetroApp = nullptr;

View File

@ -281,7 +281,7 @@ MetroAppShell::ProcessOneNativeEventIfPresent()
// Calling into ProcessNativeEvents is harmless, but won't actually process any
// native events. So we log here so we can spot this and get a handle on the
// corner cases where this can happen.
Log("WARNING: Reentrant call into process events detected, returning early.");
WinUtils::Log("WARNING: Reentrant call into process events detected, returning early.");
return false;
}
@ -395,7 +395,7 @@ MetroAppShell::Observe(nsISupports *subject, const char *topic,
NS_ENSURE_ARG_POINTER(topic);
if (!strcmp(topic, "dl-start")) {
if (mPowerRequestCount++ == 0) {
Log("Download started - Disallowing suspend");
WinUtils::Log("Download started - Disallowing suspend");
REASON_CONTEXT context;
context.Version = POWER_REQUEST_CONTEXT_VERSION;
context.Flags = POWER_REQUEST_CONTEXT_SIMPLE_STRING;
@ -408,7 +408,7 @@ MetroAppShell::Observe(nsISupports *subject, const char *topic,
!strcmp(topic, "dl-cancel") ||
!strcmp(topic, "dl-failed")) {
if (--mPowerRequestCount == 0 && mPowerRequest) {
Log("All downloads ended - Allowing suspend");
WinUtils::Log("All downloads ended - Allowing suspend");
PowerClearRequestDyn(mPowerRequest, PowerRequestExecutionRequired);
mPowerRequest.reset();
}

View File

@ -59,7 +59,7 @@ FrameworkView::SearchActivated(ComPtr<ISearchActivatedEventArgs>& aArgs, bool aS
return;
unsigned int length;
LogW(L"SearchActivated text=%s", data.GetRawBuffer(&length));
WinUtils::LogW(L"SearchActivated text=%s", data.GetRawBuffer(&length));
if (aStartup) {
mActivationURI = data.GetRawBuffer(&length);
} else {
@ -136,7 +136,7 @@ FrameworkView::ProcessLaunchArguments()
NS_ConvertUTF16toUTF8 arg(argv[i]);
argvUTF8[i] = new char[arg.Length() + 1];
strcpy(argvUTF8[i], const_cast<char *>(arg.BeginReading()));
LogW(L"Launch arg[%d]: '%s'", i, argv[i]);
WinUtils::LogW(L"Launch arg[%d]: '%s'", i, argv[i]);
}
nsresult rv = cmdLine->Init(argc,
@ -163,7 +163,7 @@ FrameworkView::ProcessActivationArgs(IActivatedEventArgs* aArgs, bool aStartup)
return;
ComPtr<IActivatedEventArgs> args(aArgs);
if (kind == ActivationKind::ActivationKind_Protocol) {
Log("Activation argument kind: Protocol");
WinUtils::Log("Activation argument kind: Protocol");
ComPtr<IProtocolActivatedEventArgs> protoArgs;
AssertHRESULT(args.As(&protoArgs));
ComPtr<IUriRuntimeClass> uri;
@ -183,17 +183,17 @@ FrameworkView::ProcessActivationArgs(IActivatedEventArgs* aArgs, bool aStartup)
PerformURILoad(data);
}
} else if (kind == ActivationKind::ActivationKind_Search) {
Log("Activation argument kind: Search");
WinUtils::Log("Activation argument kind: Search");
ComPtr<ISearchActivatedEventArgs> searchArgs;
args.As(&searchArgs);
SearchActivated(searchArgs, aStartup);
} else if (kind == ActivationKind::ActivationKind_File) {
Log("Activation argument kind: File");
WinUtils::Log("Activation argument kind: File");
ComPtr<IFileActivatedEventArgs> fileArgs;
args.As(&fileArgs);
FileActivated(fileArgs, aStartup);
} else if (kind == ActivationKind::ActivationKind_Launch) {
Log("Activation argument kind: Launch");
WinUtils::Log("Activation argument kind: Launch");
ComPtr<ILaunchActivatedEventArgs> launchArgs;
args.As(&launchArgs);
LaunchActivated(launchArgs, aStartup);
@ -263,7 +263,7 @@ FrameworkView::PerformURILoad(HString& aURI)
LogFunction();
unsigned int length;
LogW(L"PerformURILoad uri=%s", aURI.GetRawBuffer(&length));
WinUtils::LogW(L"PerformURILoad uri=%s", aURI.GetRawBuffer(&length));
nsCOMPtr<nsICommandLineRunner> cmdLine =
(do_CreateInstance("@mozilla.org/toolkit/command-line;1"));
@ -323,7 +323,7 @@ FrameworkView::PerformURILoadOrSearch(HString& aString)
LogFunction();
if (WindowsIsStringEmpty(aString.Get())) {
Log("Emptry string passed to PerformURILoadOrSearch");
WinUtils::Log("Emptry string passed to PerformURILoadOrSearch");
return;
}

View File

@ -3,11 +3,6 @@
* 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/. */
#ifdef MOZ_LOGGING
// so we can get logging even in release builds
#define FORCE_PR_LOG 1
#endif
#include "MetroUtils.h"
#include <windows.h>
#include "nsICommandLineRunner.h"
@ -39,10 +34,6 @@ using namespace ABI::Windows::Graphics::Display;
// File-scoped statics (unnamed namespace)
namespace {
#ifdef PR_LOGGING
PRLogModuleInfo* metroWidgetLog = PR_NewLogModule("MetroWidget");
#endif
FLOAT LogToPhysFactor() {
ComPtr<IDisplayPropertiesStatics> dispProps;
if (SUCCEEDED(GetActivationFactory(HStringReference(RuntimeClass_Windows_Graphics_Display_DisplayProperties).Get(),
@ -68,75 +59,6 @@ namespace {
}
};
void LogW(const wchar_t *fmt, ...)
{
va_list args = nullptr;
if(!lstrlenW(fmt))
return;
va_start(args, fmt);
int buflen = _vscwprintf(fmt, args);
wchar_t* buffer = new wchar_t[buflen+1];
if (!buffer) {
va_end(args);
return;
}
vswprintf(buffer, buflen, fmt, args);
va_end(args);
// MSVC, including remote debug sessions
OutputDebugStringW(buffer);
OutputDebugStringW(L"\n");
int len = wcslen(buffer);
if (len) {
char* utf8 = new char[len+1];
memset(utf8, 0, sizeof(utf8));
if (WideCharToMultiByte(CP_ACP, 0, buffer,
-1, utf8, len+1, nullptr,
nullptr) > 0) {
// desktop console
printf("%s\n", utf8);
#ifdef PR_LOGGING
NS_ASSERTION(metroWidgetLog, "Called MetroUtils Log() but MetroWidget "
"log module doesn't exist!");
PR_LOG(metroWidgetLog, PR_LOG_ALWAYS, (utf8));
#endif
}
delete[] utf8;
}
delete[] buffer;
}
void Log(const char *fmt, ...)
{
va_list args = nullptr;
if(!strlen(fmt))
return;
va_start(args, fmt);
int buflen = _vscprintf(fmt, args);
char* buffer = new char[buflen+1];
if (!buffer) {
va_end(args);
return;
}
vsprintf(buffer, fmt, args);
va_end(args);
// MSVC, including remote debug sessions
OutputDebugStringA(buffer);
OutputDebugStringW(L"\n");
// desktop console
printf("%s\n", buffer);
#ifdef PR_LOGGING
NS_ASSERTION(metroWidgetLog, "Called MetroUtils Log() but MetroWidget "
"log module doesn't exist!");
PR_LOG(metroWidgetLog, PR_LOG_ALWAYS, (buffer));
#endif
delete[] buffer;
}
// Conversion between logical and physical coordinates
int32_t
MetroUtils::LogToPhys(FLOAT aValue)

View File

@ -9,6 +9,7 @@
#include "nsThreadUtils.h"
#include "nsString.h"
#include "nsPoint.h"
#include "WinUtils.h"
#include "mozwrlbase.h"
@ -16,15 +17,6 @@
#include <windows.foundation.h>
#include <windows.ui.viewmanagement.h>
void Log(const char *fmt, ...);
void LogW(const wchar_t *fmt, ...);
#define LogFunction() Log(__FUNCTION__)
#define LogThread() Log("%s: IsMainThread:%d ThreadId:%X", __FUNCTION__, NS_IsMainThread(), GetCurrentThreadId())
#define LogThis() Log("[%X] %s", this, __FUNCTION__)
#define LogException(e) Log("%s Exception:%s", __FUNCTION__, e->ToString()->Data())
#define LogHRESULT(hr) Log("%s hr=%X", __FUNCTION__, hr)
// HRESULT checkers, these warn on failure in debug builds
#ifdef DEBUG
#define DebugLogHR(hr) LogHRESULT(hr)

View File

@ -120,20 +120,20 @@ namespace {
for (uint32_t i = 0; i < aExtraInputsLen; i++) {
inputs[keySequence.Length()+i] = aExtraInputs[i];
}
Log(" Sending inputs");
WinUtils::Log(" Sending inputs");
for (uint32_t i = 0; i < len; i++) {
if (inputs[i].type == INPUT_KEYBOARD) {
Log(" Key press: 0x%x %s",
WinUtils::Log(" Key press: 0x%x %s",
inputs[i].ki.wVk,
inputs[i].ki.dwFlags & KEYEVENTF_KEYUP
? "UP"
: "DOWN");
} else if(inputs[i].type == INPUT_MOUSE) {
Log(" Mouse input: 0x%x 0x%x",
WinUtils::Log(" Mouse input: 0x%x 0x%x",
inputs[i].mi.dwFlags,
inputs[i].mi.mouseData);
} else {
Log(" Unknown input type!");
WinUtils::Log(" Unknown input type!");
}
}
::SendInput(len, inputs, sizeof(INPUT));
@ -143,7 +143,7 @@ namespace {
// waiting to be processed by our event loop. Now we manually pump
// those messages so that, upon our return, all the inputs have been
// processed.
Log(" Inputs sent. Waiting for input messages to clear");
WinUtils::Log(" Inputs sent. Waiting for input messages to clear");
MSG msg;
while (WinUtils::PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
if (nsTextStore::ProcessRawKeyMessage(msg)) {
@ -151,17 +151,14 @@ namespace {
}
::TranslateMessage(&msg);
::DispatchMessage(&msg);
Log(" Dispatched 0x%x 0x%x 0x%x", msg.message, msg.wParam, msg.lParam);
WinUtils::Log(" Dispatched 0x%x 0x%x 0x%x", msg.message, msg.wParam, msg.lParam);
}
Log(" No more input messages");
WinUtils::Log(" No more input messages");
}
}
NS_IMPL_ISUPPORTS_INHERITED0(MetroWidget, nsBaseWidget)
nsRefPtr<mozilla::layers::APZCTreeManager> MetroWidget::sAPZC;
MetroWidget::MetroWidget() :
mTransparencyMode(eTransparencyOpaque),
mWnd(nullptr),
@ -188,7 +185,7 @@ MetroWidget::~MetroWidget()
// Global shutdown
if (!gInstanceCount) {
MetroWidget::sAPZC = nullptr;
APZController::sAPZC = nullptr;
nsTextStore::Terminate();
} // !gInstanceCount
}
@ -217,20 +214,20 @@ MetroWidget::Create(nsIWidget *aParent,
if (mWindowType != eWindowType_toplevel) {
switch(mWindowType) {
case eWindowType_dialog:
Log("eWindowType_dialog window requested, returning failure.");
WinUtils::Log("eWindowType_dialog window requested, returning failure.");
break;
case eWindowType_child:
Log("eWindowType_child window requested, returning failure.");
WinUtils::Log("eWindowType_child window requested, returning failure.");
break;
case eWindowType_popup:
Log("eWindowType_popup window requested, returning failure.");
WinUtils::Log("eWindowType_popup window requested, returning failure.");
break;
case eWindowType_plugin:
Log("eWindowType_plugin window requested, returning failure.");
WinUtils::Log("eWindowType_plugin window requested, returning failure.");
break;
// we should support toolkit's eWindowType_invisible at some point.
case eWindowType_invisible:
Log("eWindowType_invisible window requested, this doesn't actually exist!");
WinUtils::Log("eWindowType_invisible window requested, this doesn't actually exist!");
return NS_OK;
}
NS_WARNING("Invalid window type requested.");
@ -271,7 +268,7 @@ MetroWidget::Destroy()
{
if (mOnDestroyCalled)
return NS_OK;
Log("[%X] %s mWnd=%X type=%d", this, __FUNCTION__, mWnd, mWindowType);
WinUtils::Log("[%X] %s mWnd=%X type=%d", this, __FUNCTION__, mWnd, mWindowType);
mOnDestroyCalled = true;
nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
@ -280,7 +277,7 @@ MetroWidget::Destroy()
nsresult rv;
nsCOMPtr<nsIObserverService> observerService = do_GetService("@mozilla.org/observer-service;1", &rv);
if (NS_SUCCEEDED(rv)) {
observerService->RemoveObserver(this, "scroll-offset-changed");
observerService->RemoveObserver(this, "apzc-scroll-offset-changed");
}
}
@ -520,7 +517,7 @@ MetroWidget::SynthesizeNativeMouseEvent(nsIntPoint aPoint,
uint32_t aNativeMessage,
uint32_t aModifierFlags)
{
Log("ENTERED SynthesizeNativeMouseEvent");
WinUtils::Log("ENTERED SynthesizeNativeMouseEvent");
INPUT inputs[2];
memset(inputs, 0, 2*sizeof(INPUT));
@ -535,7 +532,7 @@ MetroWidget::SynthesizeNativeMouseEvent(nsIntPoint aPoint,
inputs[1].mi.dwFlags = aNativeMessage;
SendInputs(aModifierFlags, inputs, 2);
Log("Exiting SynthesizeNativeMouseEvent");
WinUtils::Log("Exiting SynthesizeNativeMouseEvent");
return NS_OK;
}
@ -814,7 +811,7 @@ MetroWidget::WindowProcedure(HWND aWnd, UINT aMsg, WPARAM aWParam, LPARAM aLPara
return res;
}
NS_ASSERTION(res, "UiaReturnRawElementProvider failed!");
Log("UiaReturnRawElementProvider failed! GetLastError=%X", GetLastError());
WinUtils::Log("UiaReturnRawElementProvider failed! GetLastError=%X", GetLastError());
}
}
break;
@ -941,22 +938,34 @@ MetroWidget::ShouldUseAPZC()
Preferences::GetBool(kPrefName, false);
}
void
MetroWidget::SetWidgetListener(nsIWidgetListener* aWidgetListener)
{
mWidgetListener = aWidgetListener;
if (mController) {
mController->SetWidgetListener(aWidgetListener);
}
}
CompositorParent* MetroWidget::NewCompositorParent(int aSurfaceWidth, int aSurfaceHeight)
{
CompositorParent *compositor = nsBaseWidget::NewCompositorParent(aSurfaceWidth, aSurfaceHeight);
if (ShouldUseAPZC()) {
mRootLayerTreeId = compositor->RootLayerTreeId();
mController = new APZController();
mController->SetWidgetListener(mWidgetListener);
CompositorParent::SetControllerForLayerTree(mRootLayerTreeId, mController);
MetroWidget::sAPZC = CompositorParent::GetAPZCTreeManager(compositor->RootLayerTreeId());
MetroWidget::sAPZC->SetDPI(GetDPI());
APZController::sAPZC = CompositorParent::GetAPZCTreeManager(compositor->RootLayerTreeId());
APZController::sAPZC->SetDPI(GetDPI());
nsresult rv;
nsCOMPtr<nsIObserverService> observerService = do_GetService("@mozilla.org/observer-service;1", &rv);
if (NS_SUCCEEDED(rv)) {
observerService->AddObserver(this, "scroll-offset-changed", false);
observerService->AddObserver(this, "apzc-scroll-offset-changed", false);
}
}
@ -967,29 +976,29 @@ void
MetroWidget::ApzContentConsumingTouch()
{
LogFunction();
if (!MetroWidget::sAPZC) {
if (!APZController::sAPZC) {
return;
}
MetroWidget::sAPZC->ContentReceivedTouch(mRootLayerTreeId, true);
APZController::sAPZC->ContentReceivedTouch(mRootLayerTreeId, true);
}
void
MetroWidget::ApzContentIgnoringTouch()
{
LogFunction();
if (!MetroWidget::sAPZC) {
if (!APZController::sAPZC) {
return;
}
MetroWidget::sAPZC->ContentReceivedTouch(mRootLayerTreeId, false);
APZController::sAPZC->ContentReceivedTouch(mRootLayerTreeId, false);
}
bool
MetroWidget::HitTestAPZC(ScreenPoint& pt)
{
if (!MetroWidget::sAPZC) {
if (!APZController::sAPZC) {
return false;
}
return MetroWidget::sAPZC->HitTestAPZC(pt);
return APZController::sAPZC->HitTestAPZC(pt);
}
nsEventStatus
@ -997,10 +1006,10 @@ MetroWidget::ApzReceiveInputEvent(WidgetInputEvent* aEvent)
{
MOZ_ASSERT(aEvent);
if (!MetroWidget::sAPZC) {
if (!APZController::sAPZC) {
return nsEventStatus_eIgnore;
}
return MetroWidget::sAPZC->ReceiveInputEvent(*aEvent->AsInputEvent());
return APZController::sAPZC->ReceiveInputEvent(*aEvent->AsInputEvent());
}
nsEventStatus
@ -1010,11 +1019,11 @@ MetroWidget::ApzReceiveInputEvent(WidgetInputEvent* aInEvent,
MOZ_ASSERT(aInEvent);
MOZ_ASSERT(aOutEvent);
if (!MetroWidget::sAPZC) {
if (!APZController::sAPZC) {
return nsEventStatus_eIgnore;
}
return MetroWidget::sAPZC->ReceiveInputEvent(*aInEvent->AsInputEvent(),
aOutEvent);
return APZController::sAPZC->ReceiveInputEvent(*aInEvent->AsInputEvent(),
aOutEvent);
}
LayerManager*
@ -1517,7 +1526,7 @@ NS_IMETHODIMP
MetroWidget::Observe(nsISupports *subject, const char *topic, const PRUnichar *data)
{
NS_ENSURE_ARG_POINTER(topic);
if (!strcmp(topic, "scroll-offset-changed")) {
if (!strcmp(topic, "apzc-scroll-offset-changed")) {
uint64_t scrollId;
int32_t presShellId;
CSSIntPoint scrollOffset;
@ -1531,11 +1540,11 @@ MetroWidget::Observe(nsISupports *subject, const char *topic, const PRUnichar *d
NS_WARNING("Malformed scroll-offset-changed message");
return NS_ERROR_UNEXPECTED;
}
if (MetroWidget::sAPZC) {
MetroWidget::sAPZC->UpdateScrollOffset(
ScrollableLayerGuid(mRootLayerTreeId, presShellId, scrollId),
scrollOffset);
if (!mController) {
return NS_ERROR_UNEXPECTED;
}
mController->UpdateScrollOffset(ScrollableLayerGuid(mRootLayerTreeId, presShellId, scrollId),
scrollOffset);
}
return NS_OK;
}

View File

@ -22,7 +22,6 @@
#endif
#include "mozilla/EventForwards.h"
#include "mozilla/layers/CompositorParent.h"
#include "mozilla/layers/APZCTreeManager.h"
#include "mozilla/layers/LayerManagerComposite.h"
#include "nsDeque.h"
#include "APZController.h"
@ -85,6 +84,7 @@ public:
// nsBaseWidget
virtual CompositorParent* NewCompositorParent(int aSurfaceWidth, int aSurfaceHeight);
virtual void SetWidgetListener(nsIWidgetListener* aWidgetListener);
// nsIWidget interface
NS_IMETHOD Create(nsIWidget *aParent,
@ -235,10 +235,6 @@ protected:
void DispatchAsyncScrollEvent(DispatchMsg* aEvent);
void DeliverNextScrollEvent();
void DeliverNextKeyboardEvent();
DispatchMsg* CreateDispatchMsg(UINT aMsg, WPARAM aWParam, LPARAM aLParam);
public:
static nsRefPtr<mozilla::layers::APZCTreeManager> sAPZC;
protected:
OleInitializeWrapper mOleInitializeWrapper;

View File

@ -7,6 +7,7 @@
#include "MetroUtils.h"
#include "UIABridgePrivate.h"
#include "MetroWidget.h"
#include "WinUtils.h"
#include <wrl.h>
#include <OAIdl.h>
@ -15,6 +16,7 @@
#ifdef ACCESSIBILITY
using namespace mozilla::a11y;
#endif
using namespace mozilla::widget;
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::UI;
@ -26,10 +28,11 @@ using namespace ABI::Windows::System;
#if !defined(DEBUG_BRIDGE)
#undef LogThread
#undef LogFunction
#undef Log
#define LogThread()
#define LogFunction()
#define Log(...)
#define BridgeLog(...)
#else
#define BridgeLog(...) WinUtils::Log(__VA_ARGS__)
#endif
#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
@ -49,7 +52,6 @@ static ComPtr<IUIAElement> gElement = nullptr;
HRESULT
UIABridge_CreateInstance(IInspectable **retVal)
{
LogFunction();
HRESULT hr = E_OUTOFMEMORY;
*retVal = nullptr;
ComPtr<UIABridge> spProvider = Make<UIABridge>();
@ -129,12 +131,14 @@ UIABridge::Connected()
HRESULT
UIABridge::SetFocusInternal(LONG_PTR aAccessible)
{
LogFunction();
return S_OK;
}
HRESULT
UIABridge::ClearFocus()
{
LogFunction();
return S_OK;
}
@ -147,9 +151,9 @@ DumpChildInfo(nsCOMPtr<nsIAccessible>& aChild)
}
nsString str;
aChild->GetName(str);
Log("name: %ls", str.BeginReading());
BridgeLog("name: %ls", str.BeginReading());
aChild->GetDescription(str);
Log("description: %ls", str.BeginReading());
BridgeLog("description: %ls", str.BeginReading());
#endif
}
@ -157,7 +161,7 @@ static bool
ChildHasFocus(nsCOMPtr<nsIAccessible>& aChild)
{
Accessible* access = (Accessible*)aChild.get();
Log("Focus element flags: editable:%d focusable:%d readonly:%d",
BridgeLog("Focus element flags: editable:%d focusable:%d readonly:%d",
((access->NativeState() & mozilla::a11y::states::EDITABLE) > 0),
((access->NativeState() & mozilla::a11y::states::FOCUSABLE) > 0),
((access->NativeState() & mozilla::a11y::states::READONLY) > 0));
@ -207,7 +211,7 @@ UIABridge::ElementProviderFromPoint(double x, double y, IRawElementProviderFragm
}
// Windows calls this looking for the current focus element. Windows
// will call here before accessible sends up any observer events through
// will call here before accessible sends us any observer events through
// the accessibility bridge, so update child focus information.
HRESULT
UIABridge::GetFocus(IRawElementProviderFragment ** retVal)
@ -220,7 +224,7 @@ UIABridge::GetFocus(IRawElementProviderFragment ** retVal)
nsCOMPtr<nsIAccessible> child;
nsresult rv = mAccessible->GetFocusedChild(getter_AddRefs(child));
if (!child) {
Log("mAccessible->GetFocusedChild failed.");
BridgeLog("mAccessible->GetFocusedChild failed.");
return S_OK;
}
@ -229,7 +233,7 @@ UIABridge::GetFocus(IRawElementProviderFragment ** retVal)
ComPtr<IUIAElement> element;
gElement.As(&element);
if (!element) {
Log("gElement as IUIAElement failed.");
BridgeLog("gElement as IUIAElement failed.");
return S_OK;
}
@ -256,20 +260,20 @@ UIABridge::Navigate(NavigateDirection direction, IRawElementProviderFragment **
switch(direction) {
case NavigateDirection_Parent:
Log("UIABridge::Navigate NavigateDirection_Parent");
BridgeLog("UIABridge::Navigate NavigateDirection_Parent");
break;
case NavigateDirection_NextSibling:
Log("UIABridge::Navigate NavigateDirection_NextSibling");
BridgeLog("UIABridge::Navigate NavigateDirection_NextSibling");
break;
case NavigateDirection_PreviousSibling:
Log("UIABridge::Navigate NavigateDirection_PreviousSibling");
BridgeLog("UIABridge::Navigate NavigateDirection_PreviousSibling");
break;
case NavigateDirection_FirstChild:
Log("UIABridge::Navigate NavigateDirection_FirstChild");
BridgeLog("UIABridge::Navigate NavigateDirection_FirstChild");
gElement.Get()->QueryInterface(IID_PPV_ARGS(retVal));
break;
case NavigateDirection_LastChild:
Log("UIABridge::Navigate NavigateDirection_LastChild");
BridgeLog("UIABridge::Navigate NavigateDirection_LastChild");
gElement.Get()->QueryInterface(IID_PPV_ARGS(retVal));
break;
}
@ -366,7 +370,7 @@ HRESULT
UIABridge::GetPatternProvider(PATTERNID patternId, IUnknown **ppRetVal)
{
LogFunction();
Log("UIABridge::GetPatternProvider=%d", patternId);
BridgeLog("UIABridge::GetPatternProvider=%d", patternId);
// The root window doesn't support any specific pattern
*ppRetVal = nullptr;
@ -381,37 +385,37 @@ UIABridge::GetPropertyValue(PROPERTYID idProp, VARIANT * pRetVal)
switch (idProp) {
case UIA_AutomationIdPropertyId:
Log("UIABridge::GetPropertyValue: idProp=UIA_AutomationIdPropertyId");
BridgeLog("UIABridge::GetPropertyValue: idProp=UIA_AutomationIdPropertyId");
break;
case UIA_ControlTypePropertyId:
Log("UIABridge::GetPropertyValue: idProp=UIA_ControlTypePropertyId");
BridgeLog("UIABridge::GetPropertyValue: idProp=UIA_ControlTypePropertyId");
break;
case UIA_IsKeyboardFocusablePropertyId:
Log("UIABridge::GetPropertyValue: idProp=UIA_IsKeyboardFocusablePropertyId");
BridgeLog("UIABridge::GetPropertyValue: idProp=UIA_IsKeyboardFocusablePropertyId");
break;
case UIA_IsContentElementPropertyId:
Log("UIABridge::GetPropertyValue: idProp=UIA_IsContentElementPropertyId");
BridgeLog("UIABridge::GetPropertyValue: idProp=UIA_IsContentElementPropertyId");
break;
case UIA_IsControlElementPropertyId:
Log("UIABridge::GetPropertyValue: idProp=UIA_IsControlElementPropertyId");
BridgeLog("UIABridge::GetPropertyValue: idProp=UIA_IsControlElementPropertyId");
break;
case UIA_IsEnabledPropertyId:
Log("UIABridge::GetPropertyValue: idProp=UIA_IsEnabledPropertyId");
BridgeLog("UIABridge::GetPropertyValue: idProp=UIA_IsEnabledPropertyId");
break;
case UIA_HasKeyboardFocusPropertyId:
Log("UIABridge::GetPropertyValue: idProp=UIA_HasKeyboardFocusPropertyId");
BridgeLog("UIABridge::GetPropertyValue: idProp=UIA_HasKeyboardFocusPropertyId");
break;
case UIA_NamePropertyId:
Log("UIABridge::GetPropertyValue: idProp=UIA_NamePropertyId");
BridgeLog("UIABridge::GetPropertyValue: idProp=UIA_NamePropertyId");
break;
case UIA_IsPasswordPropertyId:
Log("UIABridge::GetPropertyValue: idProp=UIA_IsPasswordPropertyId");
BridgeLog("UIABridge::GetPropertyValue: idProp=UIA_IsPasswordPropertyId");
break;
case UIA_NativeWindowHandlePropertyId:
Log("UIABridge::GetPropertyValue: idProp=UIA_NativeWindowHandlePropertyId");
BridgeLog("UIABridge::GetPropertyValue: idProp=UIA_NativeWindowHandlePropertyId");
break;
default:
Log("UIABridge::GetPropertyValue: idProp=%d", idProp);
BridgeLog("UIABridge::GetPropertyValue: idProp=%d", idProp);
break;
}
@ -459,7 +463,7 @@ UIABridge::GetPropertyValue(PROPERTYID idProp, VARIANT * pRetVal)
break;
default:
Log("UIABridge: Unhandled property");
BridgeLog("UIABridge: Unhandled property");
break;
}
return S_OK;
@ -564,7 +568,7 @@ UIATextElement::get_BoundingRectangle(UiaRect * retVal)
retVal->width = (float)docWidth;
retVal->height = (float)docHeight;
Log("get_BoundingRectangle: left=%d top=%d right=%d bottom=%d", docX, docY, docX + docWidth, docY + docHeight);
BridgeLog("get_BoundingRectangle: left=%d top=%d right=%d bottom=%d", docX, docY, docX + docWidth, docY + docHeight);
return S_OK;
}
@ -603,7 +607,7 @@ HRESULT
UIATextElement::GetPatternProvider(PATTERNID patternId, IUnknown **ppRetVal)
{
LogFunction();
Log("UIATextElement::GetPatternProvider=%d", patternId);
BridgeLog("UIATextElement::GetPatternProvider=%d", patternId);
// UIA_ValuePatternId - 10002
// UIA_TextPatternId - 10014
@ -611,12 +615,12 @@ UIATextElement::GetPatternProvider(PATTERNID patternId, IUnknown **ppRetVal)
*ppRetVal = nullptr;
if (patternId == UIA_TextPatternId) {
Log("** TextPattern requested from element.");
BridgeLog("** TextPattern requested from element.");
*ppRetVal = static_cast<ITextProvider*>(this);
AddRef();
return S_OK;
} else if (patternId == UIA_ValuePatternId) {
Log("** ValuePattern requested from element.");
BridgeLog("** ValuePattern requested from element.");
*ppRetVal = static_cast<IValueProvider*>(this);
AddRef();
return S_OK;
@ -637,34 +641,34 @@ UIATextElement::GetPropertyValue(PROPERTYID idProp, VARIANT * pRetVal)
switch (idProp) {
case UIA_AutomationIdPropertyId:
Log("UIATextElement::GetPropertyValue: idProp=UIA_AutomationIdPropertyId");
BridgeLog("UIATextElement::GetPropertyValue: idProp=UIA_AutomationIdPropertyId");
break;
case UIA_ControlTypePropertyId:
Log("UIATextElement::GetPropertyValue: idProp=UIA_ControlTypePropertyId");
BridgeLog("UIATextElement::GetPropertyValue: idProp=UIA_ControlTypePropertyId");
break;
case UIA_IsKeyboardFocusablePropertyId:
Log("UIATextElement::GetPropertyValue: idProp=UIA_IsKeyboardFocusablePropertyId");
BridgeLog("UIATextElement::GetPropertyValue: idProp=UIA_IsKeyboardFocusablePropertyId");
break;
case UIA_IsContentElementPropertyId:
Log("UIATextElement::GetPropertyValue: idProp=UIA_IsContentElementPropertyId");
BridgeLog("UIATextElement::GetPropertyValue: idProp=UIA_IsContentElementPropertyId");
break;
case UIA_IsControlElementPropertyId:
Log("UIATextElement::GetPropertyValue: idProp=UIA_IsControlElementPropertyId");
BridgeLog("UIATextElement::GetPropertyValue: idProp=UIA_IsControlElementPropertyId");
break;
case UIA_IsEnabledPropertyId:
Log("UIATextElement::GetPropertyValue: idProp=UIA_IsEnabledPropertyId");
BridgeLog("UIATextElement::GetPropertyValue: idProp=UIA_IsEnabledPropertyId");
break;
case UIA_HasKeyboardFocusPropertyId:
Log("UIATextElement::GetPropertyValue: idProp=UIA_HasKeyboardFocusPropertyId");
BridgeLog("UIATextElement::GetPropertyValue: idProp=UIA_HasKeyboardFocusPropertyId");
break;
case UIA_NamePropertyId:
Log("UIATextElement::GetPropertyValue: idProp=UIA_NamePropertyId");
BridgeLog("UIATextElement::GetPropertyValue: idProp=UIA_NamePropertyId");
break;
case UIA_IsPasswordPropertyId:
Log("UIATextElement::GetPropertyValue: idProp=UIA_IsPasswordPropertyId");
BridgeLog("UIATextElement::GetPropertyValue: idProp=UIA_IsPasswordPropertyId");
break;
default:
Log("UIATextElement::GetPropertyValue: idProp=%d", idProp);
BridgeLog("UIATextElement::GetPropertyValue: idProp=%d", idProp);
break;
}
@ -719,7 +723,7 @@ UIATextElement::GetPropertyValue(PROPERTYID idProp, VARIANT * pRetVal)
break;
default:
Log("UIATextElement: Unhandled property");
BridgeLog("UIATextElement: Unhandled property");
break;
}
return S_OK;