--- a/b2g/chrome/content/devtools/debugger.js
+++ b/b2g/chrome/content/devtools/debugger.js
@@ -16,16 +16,22 @@ XPCOMUtils.defineLazyGetter(this, "devto
Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
return devtools;
});
XPCOMUtils.defineLazyGetter(this, "discovery", function() {
return devtools.require("devtools/toolkit/discovery/discovery");
});
+XPCOMUtils.defineLazyGetter(this, "B2GTabList", function() {
+ const { B2GTabList } =
+ devtools.require("resource://gre/modules/DebuggerActors.js");
+ return B2GTabList;
+});
+
let RemoteDebugger = {
_promptDone: false,
_promptAnswer: false,
_listening: false,
prompt: function() {
this._listen();
@@ -86,25 +92,17 @@ let RemoteDebugger = {
*
* * @param connection DebuggerServerConnection
* The conection to the client.
*/
DebuggerServer.createRootActor = function createRootActor(connection)
{
let { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
let parameters = {
- // We do not expose browser tab actors yet,
- // but we still have to define tabList.getList(),
- // otherwise, client won't be able to fetch global actors
- // from listTabs request!
- tabList: {
- getList: function() {
- return promise.resolve([]);
- }
- },
+ tabList: new B2GTabList(connection),
// Use an explicit global actor list to prevent exposing
// unexpected actors
globalActorFactories: restrictPrivileges ? {
webappsActor: DebuggerServer.globalActorFactories.webappsActor,
deviceActor: DebuggerServer.globalActorFactories.deviceActor,
} : DebuggerServer.globalActorFactories
};
let { RootActor } = devtools.require("devtools/server/actors/root");
--- a/b2g/chrome/content/devtools/hud.js
+++ b/b2g/chrome/content/devtools/hud.js
@@ -24,17 +24,17 @@ XPCOMUtils.defineLazyGetter(this, 'WebCo
XPCOMUtils.defineLazyGetter(this, 'EventLoopLagFront', function() {
return devtools.require('devtools/server/actors/eventlooplag').EventLoopLagFront;
});
XPCOMUtils.defineLazyGetter(this, 'MemoryFront', function() {
return devtools.require('devtools/server/actors/memory').MemoryFront;
});
-Cu.import('resource://gre/modules/AppFrames.jsm');
+Cu.import('resource://gre/modules/Frames.jsm');
/**
* The Developer HUD is an on-device developer tool that displays widgets,
* showing visual debug information about apps. Each widget corresponds to a
* metric as tracked by a metric watcher (e.g. consoleWatcher).
*/
let developerHUD = {
@@ -75,19 +75,20 @@ let developerHUD = {
this._client = new DebuggerClient(transport);
for (let w of this._watchers) {
if (w.init) {
w.init(this._client);
}
}
- AppFrames.addObserver(this);
+ Frames.addObserver(this);
- for (let frame of AppFrames.list()) {
+ let appFrames = Frames.list().filter(frame => frame.getAttribute('mozapp'));
+ for (let frame of appFrames) {
this.trackFrame(frame);
}
SettingsListener.observe('hud.logging', this._logging, enabled => {
this._logging = enabled;
});
},
@@ -95,17 +96,17 @@ let developerHUD = {
if (!this._client) {
return;
}
for (let frame of this._targets.keys()) {
this.untrackFrame(frame);
}
- AppFrames.removeObserver(this);
+ Frames.removeObserver(this);
this._client.close();
delete this._client;
},
/**
* This method will ask all registered watchers to track and update metrics
* on an app frame.
@@ -132,21 +133,29 @@ let developerHUD = {
w.untrackTarget(target);
}
target.destroy();
this._targets.delete(frame);
}
},
- onAppFrameCreated: function (frame, isFirstAppFrame) {
+ onFrameCreated: function (frame, isFirstAppFrame) {
+ let mozapp = frame.getAttribute('mozapp');
+ if (!mozapp) {
+ return;
+ }
this.trackFrame(frame);
},
- onAppFrameDestroyed: function (frame, isLastAppFrame) {
+ onFrameDestroyed: function (frame, isLastAppFrame) {
+ let mozapp = frame.getAttribute('mozapp');
+ if (!mozapp) {
+ return;
+ }
this.untrackFrame(frame);
},
log: function dwp_log(message) {
if (this._logging) {
dump(DEVELOPER_HUD_LOG_PREFIX + ': ' + message + '\n');
}
}
new file mode 100644
--- /dev/null
+++ b/b2g/components/DebuggerActors.js
@@ -0,0 +1,83 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- /
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+/* 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/. */
+
+"use strict";
+
+const { Cu } = require("chrome");
+const DevToolsUtils = require("devtools/toolkit/DevToolsUtils.js");
+const promise = require("promise");
+const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
+const { BrowserTabList } = require("devtools/server/actors/webbrowser");
+
+XPCOMUtils.defineLazyGetter(this, "Frames", function() {
+ const { Frames } =
+ Cu.import("resource://gre/modules/Frames.jsm", {});
+ return Frames;
+});
+
+/**
+ * Unlike the original BrowserTabList which iterates over XUL windows, we
+ * override many portions to refer to Frames for the info needed here.
+ */
+function B2GTabList(connection) {
+ BrowserTabList.call(this, connection);
+ this._listening = false;
+}
+
+B2GTabList.prototype = Object.create(BrowserTabList.prototype);
+
+B2GTabList.prototype._getBrowsers = function() {
+ return Frames.list().filter(frame => {
+ // Ignore app frames
+ return !frame.getAttribute("mozapp");
+ });
+};
+
+B2GTabList.prototype._getSelectedBrowser = function() {
+ return this._getBrowsers().find(frame => {
+ // Find the one visible browser (if any)
+ return !frame.classList.contains("hidden");
+ });
+};
+
+B2GTabList.prototype._checkListening = function() {
+ // The conditions from BrowserTabList are merged here, since we must listen to
+ // all events with our observer design.
+ this._listenForEventsIf(this._onListChanged && this._mustNotify ||
+ this._actorByBrowser.size > 0);
+};
+
+B2GTabList.prototype._listenForEventsIf = function(shouldListen) {
+ if (this._listening != shouldListen) {
+ let op = shouldListen ? "addObserver" : "removeObserver";
+ Frames[op](this);
+ this._listening = shouldListen;
+ }
+};
+
+B2GTabList.prototype.onFrameCreated = function(frame) {
+ let mozapp = frame.getAttribute("mozapp");
+ if (mozapp) {
+ // Ignore app frames
+ return;
+ }
+ this._notifyListChanged();
+ this._checkListening();
+};
+
+B2GTabList.prototype.onFrameDestroyed = function(frame) {
+ let mozapp = frame.getAttribute("mozapp");
+ if (mozapp) {
+ // Ignore app frames
+ return;
+ }
+ let actor = this._actorByBrowser.get(frame);
+ if (actor) {
+ this._handleActorClose(actor, frame);
+ }
+};
+
+exports.B2GTabList = B2GTabList;
rename from b2g/components/AppFrames.jsm
rename to b2g/components/Frames.jsm
--- a/b2g/components/AppFrames.jsm
+++ b/b2g/components/Frames.jsm
@@ -1,15 +1,15 @@
/* 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/. */
'use strict';
-this.EXPORTED_SYMBOLS = ['AppFrames'];
+this.EXPORTED_SYMBOLS = ['Frames'];
const Cu = Components.utils;
const Ci = Components.interfaces;
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/SystemAppProxy.jsm');
const listeners = [];
@@ -22,21 +22,23 @@ const Observer = {
// Also save current number of iframes opened by app
_apps: new Map(),
start: function () {
Services.obs.addObserver(this, 'remote-browser-shown', false);
Services.obs.addObserver(this, 'inprocess-browser-shown', false);
Services.obs.addObserver(this, 'message-manager-disconnect', false);
- SystemAppProxy.getAppFrames().forEach((frame) => {
+ SystemAppProxy.getFrames().forEach(frame => {
let mm = frame.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader.messageManager;
this._frames.set(mm, frame);
let mozapp = frame.getAttribute('mozapp');
- this._apps.set(mozapp, (this._apps.get(mozapp) || 0) + 1);
+ if (mozapp) {
+ this._apps.set(mozapp, (this._apps.get(mozapp) || 0) + 1);
+ }
});
},
stop: function () {
Services.obs.removeObserver(this, 'remote-browser-shown');
Services.obs.removeObserver(this, 'inprocess-browser-shown');
Services.obs.removeObserver(this, 'message-manager-disconnect');
this._frames.clear();
@@ -63,58 +65,66 @@ const Observer = {
this.onMessageManagerDestroyed(subject);
break;
}
},
onMessageManagerCreated: function (mm, frame) {
this._frames.set(mm, frame);
+ let isFirstAppFrame = null;
let mozapp = frame.getAttribute('mozapp');
- let count = (this._apps.get(mozapp) || 0) + 1;
- this._apps.set(mozapp, count);
+ if (mozapp) {
+ let count = (this._apps.get(mozapp) || 0) + 1;
+ this._apps.set(mozapp, count);
+ isFirstAppFrame = (count === 1);
+ }
- let isFirstAppFrame = (count === 1);
listeners.forEach(function (listener) {
try {
- listener.onAppFrameCreated(frame, isFirstAppFrame);
+ listener.onFrameCreated(frame, isFirstAppFrame);
} catch(e) {
- dump('Exception while calling Frames.jsm listener:' + e + '\n' + e.stack + '\n');
+ dump('Exception while calling Frames.jsm listener:' + e + '\n' +
+ e.stack + '\n');
}
});
},
onMessageManagerDestroyed: function (mm) {
let frame = this._frames.get(mm);
if (!frame) {
- // We receive an event for a non mozapp message manager
+ // We received an event for an unknown message manager
return;
}
this._frames.delete(mm);
+ let isLastAppFrame = null;
let mozapp = frame.getAttribute('mozapp');
- let count = (this._apps.get(mozapp) || 0) - 1;
- this._apps.set(mozapp, count);
+ if (mozapp) {
+ let count = (this._apps.get(mozapp) || 0) - 1;
+ this._apps.set(mozapp, count);
+ isLastAppFrame = (count === 0);
+ }
- let isLastAppFrame = (count === 0);
listeners.forEach(function (listener) {
try {
- listener.onAppFrameDestroyed(frame, isLastAppFrame);
+ listener.onFrameDestroyed(frame, isLastAppFrame);
} catch(e) {
- dump('Exception while calling Frames.jsm listener:' + e + '\n' + e.stack + '\n');
+ dump('Exception while calling Frames.jsm listener:' + e + '\n' +
+ e.stack + '\n');
}
});
}
};
-let AppFrames = this.AppFrames = {
+let Frames = this.Frames = {
- list: () => SystemAppProxy.getAppFrames(),
+ list: () => SystemAppProxy.getFrames(),
addObserver: function (listener) {
if (listeners.indexOf(listener) !== -1) {
return;
}
listeners.push(listener);
if (listeners.length == 1) {
--- a/b2g/components/SystemAppProxy.jsm
+++ b/b2g/components/SystemAppProxy.jsm
@@ -112,30 +112,23 @@ let SystemAppProxy = {
} else {
this._pendingListeners = this._pendingListeners.filter(
args => {
return args[0] != name || args[1] != listener;
});
}
},
- getAppFrames: function systemApp_getAppFrames() {
+ getFrames: function systemApp_getFrames() {
let systemAppFrame = this._frame;
if (!systemAppFrame) {
return [];
}
-
let list = [systemAppFrame];
-
- // List all app frames hosted in the system app: the homescreen,
- // all regular apps, activities, rocket bar, attention screen and the keyboard.
- // Bookmark apps and other system app internal frames like captive portal
- // are also hosted in system app, but they are not using mozapp attribute.
- let frames = systemAppFrame.contentDocument.querySelectorAll("iframe[mozapp]");
+ let frames = systemAppFrame.contentDocument.querySelectorAll('iframe');
for (let i = 0; i < frames.length; i++) {
list.push(frames[i]);
}
-
return list;
}
};
this.SystemAppProxy = SystemAppProxy;
--- a/b2g/components/moz.build
+++ b/b2g/components/moz.build
@@ -43,19 +43,20 @@ EXTRA_PP_COMPONENTS += [
if CONFIG['MOZ_UPDATER']:
EXTRA_PP_COMPONENTS += [
'UpdatePrompt.js',
]
EXTRA_JS_MODULES += [
'AlertsHelper.jsm',
- 'AppFrames.jsm',
'ContentRequestHelper.jsm',
+ 'DebuggerActors.js',
'ErrorPage.jsm',
+ 'Frames.jsm',
'FxAccountsMgmtService.jsm',
'LogCapture.jsm',
'LogParser.jsm',
'LogShake.jsm',
'SignInToWebsite.jsm',
'SystemAppProxy.jsm',
'TelURIParser.jsm',
'WebappsUpdater.jsm',
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,25 +10,25 @@
<!--original fetch url was git://codeaurora.org/-->
<remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<!-- B2G specific things. -->
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
- <project name="gaia" path="gaia" remote="mozillaorg" revision="de254419f3553f48187d003ee8e38034b429f069"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="5f1f0960ae9d22acf2a324ad37a48174d6df87f6"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
- <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
+ <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
<project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
<project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
<project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
<project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="83760d213fb3bec7b4117d266fcfbf6fe2ba14ab"/>
<project name="device/common" path="device/common" revision="6a2995683de147791e516aae2ccb31fdfbe2ad30"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,23 +14,23 @@
<!--original fetch url was git://github.com/apitrace/-->
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
- <project name="gaia.git" path="gaia" remote="mozillaorg" revision="de254419f3553f48187d003ee8e38034b429f069"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="5f1f0960ae9d22acf2a324ad37a48174d6df87f6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
- <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
+ <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
<project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
<project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
<project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
<project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
<project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,20 +12,20 @@
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<!-- B2G specific things. -->
<project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
- <project name="gaia" path="gaia" remote="mozillaorg" revision="de254419f3553f48187d003ee8e38034b429f069"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="5f1f0960ae9d22acf2a324ad37a48174d6df87f6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
- <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
+ <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
<project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,25 +10,25 @@
<!--original fetch url was git://codeaurora.org/-->
<remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<!-- B2G specific things. -->
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
- <project name="gaia" path="gaia" remote="mozillaorg" revision="de254419f3553f48187d003ee8e38034b429f069"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="5f1f0960ae9d22acf2a324ad37a48174d6df87f6"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
- <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
+ <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
<project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="1950e4760fa14688b83cdbb5acaa1af9f82ef434"/>
<project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="ac6eb97a37035c09fb5ede0852f0881e9aadf9ad"/>
<project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="737f591c5f95477148d26602c7be56cbea0cdeb9"/>
<project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="51da9b1981be481b92a59a826d4d78dc73d0989a"/>
<project name="device/common" path="device/common" revision="798a3664597e6041985feab9aef42e98d458bc3d"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,23 +14,23 @@
<!--original fetch url was git://github.com/apitrace/-->
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
- <project name="gaia.git" path="gaia" remote="mozillaorg" revision="de254419f3553f48187d003ee8e38034b429f069"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="5f1f0960ae9d22acf2a324ad37a48174d6df87f6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
- <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
+ <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
<project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
<project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
<project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
<project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
<project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,25 +10,25 @@
<!--original fetch url was git://codeaurora.org/-->
<remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<!-- B2G specific things. -->
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
- <project name="gaia" path="gaia" remote="mozillaorg" revision="de254419f3553f48187d003ee8e38034b429f069"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="5f1f0960ae9d22acf2a324ad37a48174d6df87f6"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
- <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
+ <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
<project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
<project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
<project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
<project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="a32003194f707f66a2d8cdb913ed1869f1926c5d"/>
<project name="device/common" path="device/common" revision="96d4d2006c4fcb2f19a3fa47ab10cb409faa017b"/>
@@ -128,17 +128,17 @@
<remove-project name="platform/external/bluetooth/bluedroid"/>
<!--original fetch url was git://github.com/t2m-foxfone/-->
<remote fetch="https://git.mozilla.org/external/t2m-foxfone" name="t2m"/>
<default remote="caf" revision="LNX.LA.3.5.2.1.1" sync-j="4"/>
<!-- Flame specific things -->
<project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="1bb28abbc215f45220620af5cd60a8ac1be93722"/>
<project name="device/qcom/common" path="device/qcom/common" revision="54c32c2ddef066fbdf611d29e4b7c47e0363599e"/>
<project name="device-flame" path="device/t2m/flame" remote="b2g" revision="52c909e821d107d414f851e267dedcd7aae2cebf"/>
- <project name="codeaurora_kernel_msm" path="kernel" remote="b2g" revision="1072f7d31dc0bf3a2adc64177b1104da9f4ce4b6"/>
+ <project name="codeaurora_kernel_msm" path="kernel" remote="b2g" revision="7731d63c809dbca4da408e1de0c1a044f0765e52"/>
<project name="kernel_lk" path="bootable/bootloader/lk" remote="b2g" revision="fda40423ffa573dc6cafd3780515010cb2a086be"/>
<project name="platform/external/bluetooth/bluedroid" path="external/bluetooth/bluedroid" revision="30b96dfca99cb384bf520a16b81f3aba56f09907"/>
<project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="5b71e40213f650459e95d35b6f14af7e88d8ab62"/>
<project name="platform_external_libnfc-nci" path="external/libnfc-nci" remote="t2m" revision="4186bdecb4dae911b39a8202252cc2310d91b0be"/>
<project name="platform/frameworks/av" path="frameworks/av" revision="ea2f399b3ca0a23524d2828f85f69902caefc22e"/>
<project name="platform/frameworks/base" path="frameworks/base" revision="6b58ab45e3e56c1fc20708cc39fa2264c52558df"/>
<project name="platform/frameworks/native" path="frameworks/native" revision="a46a9f1ac0ed5662d614c277cbb14eb3f332f365"/>
<project name="platform/hardware/libhardware" path="hardware/libhardware" revision="7196881a0e9dd7bfbbcf0af64c8064e70f0fa094"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,20 +12,20 @@
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<!-- B2G specific things. -->
<project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
- <project name="gaia" path="gaia" remote="mozillaorg" revision="de254419f3553f48187d003ee8e38034b429f069"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="5f1f0960ae9d22acf2a324ad37a48174d6df87f6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
- <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
+ <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
<project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
{
"git": {
"git_revision": "",
"remote": "",
"branch": ""
},
- "revision": "3e3eb020773e765f4cb7775356ae9c22896db875",
+ "revision": "b4f77d39d6d8eb153ede94f8a0d70247ccad74e8",
"repo_path": "/integration/gaia-central"
}
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,22 +12,22 @@
<!--original fetch url was git://github.com/apitrace/-->
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
- <project name="gaia.git" path="gaia" remote="mozillaorg" revision="de254419f3553f48187d003ee8e38034b429f069"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="5f1f0960ae9d22acf2a324ad37a48174d6df87f6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
- <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
+ <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
<project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
<project name="platform/bootable/recovery" path="bootable/recovery" revision="746bc48f34f5060f90801925dcdd964030c1ab6d"/>
<project name="platform/development" path="development" revision="2460485184bc8535440bb63876d4e63ec1b4770c"/>
<project name="device/common" path="device/common" revision="0dcc1e03659db33b77392529466f9eb685cdd3c7"/>
<project name="device/sample" path="device/sample" revision="68b1cb978a20806176123b959cb05d4fa8adaea4"/>
<project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
- <project name="gaia.git" path="gaia" remote="mozillaorg" revision="de254419f3553f48187d003ee8e38034b429f069"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="5f1f0960ae9d22acf2a324ad37a48174d6df87f6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
<project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,20 +12,20 @@
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<!-- B2G specific things. -->
<project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
- <project name="gaia" path="gaia" remote="mozillaorg" revision="de254419f3553f48187d003ee8e38034b429f069"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="5f1f0960ae9d22acf2a324ad37a48174d6df87f6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
- <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
+ <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
<project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,22 +12,22 @@
<!--original fetch url was git://github.com/apitrace/-->
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
- <project name="gaia.git" path="gaia" remote="mozillaorg" revision="de254419f3553f48187d003ee8e38034b429f069"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="5f1f0960ae9d22acf2a324ad37a48174d6df87f6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
- <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
+ <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
<project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
<project name="platform/bootable/recovery" path="bootable/recovery" revision="e0a9ac010df3afaa47ba107192c05ac8b5516435"/>
<project name="platform/development" path="development" revision="a384622f5fcb1d2bebb9102591ff7ae91fe8ed2d"/>
<project name="device/common" path="device/common" revision="7c65ea240157763b8ded6154a17d3c033167afb7"/>
<project name="device/sample" path="device/sample" revision="c328f3d4409db801628861baa8d279fb8855892f"/>
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1287,16 +1287,17 @@ pref("services.sync.prefs.sync.security.
pref("services.sync.prefs.sync.security.tls.version.max", true);
pref("services.sync.prefs.sync.signon.rememberSignons", true);
pref("services.sync.prefs.sync.spellchecker.dictionary", true);
pref("services.sync.prefs.sync.xpinstall.whitelist.required", true);
#endif
// Developer edition preferences
pref("browser.devedition.theme.enabled", false);
+pref("browser.devedition.theme.showCustomizeButton", false);
// Disable the error console
pref("devtools.errorconsole.enabled", false);
// Developer toolbar and GCLI preferences
pref("devtools.toolbar.enabled", true);
pref("devtools.toolbar.visible", false);
pref("devtools.commands.dir", "");
--- a/browser/components/customizableui/CustomizableUI.jsm
+++ b/browser/components/customizableui/CustomizableUI.jsm
@@ -32,16 +32,17 @@ XPCOMUtils.defineLazyServiceGetter(this,
const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const kSpecialWidgetPfx = "customizableui-special-";
const kPrefCustomizationState = "browser.uiCustomization.state";
const kPrefCustomizationAutoAdd = "browser.uiCustomization.autoAdd";
const kPrefCustomizationDebug = "browser.uiCustomization.debug";
const kPrefDrawInTitlebar = "browser.tabs.drawInTitlebar";
+const kPrefDeveditionTheme = "browser.devedition.theme.enabled";
/**
* The keys are the handlers that are fired when the event type (the value)
* is fired on the subview. A widget that provides a subview has the option
* of providing onViewShowing and onViewHiding event handlers.
*/
const kSubviewEvents = [
"ViewShowing",
@@ -134,16 +135,17 @@ let gBuildWindows = new Map();
let gNewElementCount = 0;
let gGroupWrapperCache = new Map();
let gSingleWrapperCache = new WeakMap();
let gListeners = new Set();
let gUIStateBeforeReset = {
uiCustomizationState: null,
drawInTitlebar: null,
+ gUIStateBeforeReset: null,
};
let gModuleName = "[CustomizableUI]";
#include logging.js
let CustomizableUIInternal = {
initialize: function() {
LOG("Initializing");
@@ -2294,23 +2296,25 @@ let CustomizableUIInternal = {
this._rebuildRegisteredAreas();
gResetting = false;
},
_resetUIState: function() {
try {
gUIStateBeforeReset.drawInTitlebar = Services.prefs.getBoolPref(kPrefDrawInTitlebar);
+ gUIStateBeforeReset.deveditionTheme = Services.prefs.getBoolPref(kPrefDeveditionTheme);
gUIStateBeforeReset.uiCustomizationState = Services.prefs.getCharPref(kPrefCustomizationState);
} catch(e) { }
this._resetExtraToolbars();
Services.prefs.clearUserPref(kPrefCustomizationState);
Services.prefs.clearUserPref(kPrefDrawInTitlebar);
+ Services.prefs.clearUserPref(kPrefDeveditionTheme);
LOG("State reset");
// Reset placements to make restoring default placements possible.
gPlacements = new Map();
gDirtyAreaCache = new Set();
gSeenWidgets = new Set();
// Clear the saved state to ensure that defaults will be used.
gSavedState = null;
@@ -2362,30 +2366,33 @@ let CustomizableUIInternal = {
}
},
/**
* Undoes a previous reset, restoring the state of the UI to the state prior to the reset.
*/
undoReset: function() {
if (gUIStateBeforeReset.uiCustomizationState == null ||
- gUIStateBeforeReset.drawInTitlebar == null) {
+ gUIStateBeforeReset.drawInTitlebar == null ||
+ gUIStateBeforeReset.deveditionTheme == null) {
return;
}
gUndoResetting = true;
let uiCustomizationState = gUIStateBeforeReset.uiCustomizationState;
let drawInTitlebar = gUIStateBeforeReset.drawInTitlebar;
+ let deveditionTheme = gUIStateBeforeReset.deveditionTheme;
// Need to clear the previous state before setting the prefs
// because pref observers may check if there is a previous UI state.
this._clearPreviousUIState();
Services.prefs.setCharPref(kPrefCustomizationState, uiCustomizationState);
Services.prefs.setBoolPref(kPrefDrawInTitlebar, drawInTitlebar);
+ Services.prefs.setBoolPref(kPrefDeveditionTheme, deveditionTheme);
this.loadSavedState();
// If the user just customizes toolbar/titlebar visibility, gSavedState will be null
// and we don't need to do anything else here:
if (gSavedState) {
for (let areaId of Object.keys(gSavedState.placements)) {
let placements = gSavedState.placements[areaId];
gPlacements.set(areaId, placements);
}
@@ -2553,16 +2560,20 @@ let CustomizableUIInternal = {
}
}
}
if (Services.prefs.prefHasUserValue(kPrefDrawInTitlebar)) {
LOG(kPrefDrawInTitlebar + " pref is non-default");
return false;
}
+ if (Services.prefs.prefHasUserValue(kPrefDeveditionTheme)) {
+ LOG(kPrefDeveditionTheme + " pref is non-default");
+ return false;
+ }
return true;
},
setToolbarVisibility: function(aToolbarId, aIsVisible) {
// We only persist the attribute the first time.
let isFirstChangedToolbar = true;
for (let window of CustomizableUI.windows) {
@@ -3253,17 +3264,18 @@ this.CustomizableUI = {
/**
* Can the last Restore Defaults operation be undone.
*
* @return A boolean stating whether an undo of the
* Restore Defaults can be performed.
*/
get canUndoReset() {
return gUIStateBeforeReset.uiCustomizationState != null ||
- gUIStateBeforeReset.drawInTitlebar != null;
+ gUIStateBeforeReset.drawInTitlebar != null ||
+ gUIStateBeforeReset.deveditionTheme != null;
},
/**
* Get the placement of a widget. This is by far the best way to obtain
* information about what the state of your widget is. The internals of
* this call are cheap (no DOM necessary) and you will know where the user
* has put your widget.
*
--- a/browser/components/customizableui/CustomizeMode.jsm
+++ b/browser/components/customizableui/CustomizeMode.jsm
@@ -12,16 +12,18 @@ const kPrefCustomizationDebug = "browser
const kPrefCustomizationAnimation = "browser.uiCustomization.disableAnimation";
const kPaletteId = "customization-palette";
const kAboutURI = "about:customizing";
const kDragDataTypePrefix = "text/toolbarwrapper-id/";
const kPlaceholderClass = "panel-customization-placeholder";
const kSkipSourceNodePref = "browser.uiCustomization.skipSourceNodeCheck";
const kToolbarVisibilityBtn = "customization-toolbar-visibility-button";
const kDrawInTitlebarPref = "browser.tabs.drawInTitlebar";
+const kDeveditionThemePref = "browser.devedition.theme.enabled";
+const kDeveditionButtonPref = "browser.devedition.theme.showCustomizeButton";
const kMaxTransitionDurationMs = 2000;
const kPanelItemContextMenu = "customizationPanelItemContextMenu";
const kPaletteItemContextMenu = "customizationPaletteItemContextMenu";
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource:///modules/CustomizableUI.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
@@ -64,18 +66,21 @@ function CustomizeMode(aWindow) {
this.tipPanel = this.document.getElementById("customization-tipPanel");
let lwthemeButton = this.document.getElementById("customization-lwtheme-button");
if (Services.prefs.getCharPref("general.skins.selectedSkin") != "classic/1.0") {
lwthemeButton.setAttribute("hidden", "true");
}
#ifdef CAN_DRAW_IN_TITLEBAR
this._updateTitlebarButton();
Services.prefs.addObserver(kDrawInTitlebarPref, this, false);
+#endif
+ this._updateDevEditionThemeButton();
+ Services.prefs.addObserver(kDeveditionButtonPref, this, false);
+ Services.prefs.addObserver(kDeveditionThemePref, this, false);
this.window.addEventListener("unload", this);
-#endif
};
CustomizeMode.prototype = {
_changed: false,
_transitioning: false,
window: null,
document: null,
// areas is used to cache the customizable areas when in customization mode.
@@ -100,16 +105,18 @@ CustomizeMode.prototype = {
get _handler() {
return this.window.CustomizationHandler;
},
uninit: function() {
#ifdef CAN_DRAW_IN_TITLEBAR
Services.prefs.removeObserver(kDrawInTitlebarPref, this);
#endif
+ Services.prefs.removeObserver(kDeveditionButtonPref, this);
+ Services.prefs.removeObserver(kDeveditionThemePref, this);
},
toggle: function() {
if (this._handler.isEnteringCustomizeMode || this._handler.isExitingCustomizeMode) {
this._wantToBeInCustomizeMode = !this._wantToBeInCustomizeMode;
return;
}
if (this._customizing) {
@@ -1442,32 +1449,31 @@ CustomizeMode.prototype = {
case "mouseup":
this._onMouseUp(aEvent);
break;
case "keypress":
if (aEvent.keyCode == aEvent.DOM_VK_ESCAPE) {
this.exit();
}
break;
-#ifdef CAN_DRAW_IN_TITLEBAR
case "unload":
this.uninit();
break;
-#endif
}
},
observe: function(aSubject, aTopic, aData) {
switch (aTopic) {
case "nsPref:changed":
this._updateResetButton();
this._updateUndoResetButton();
#ifdef CAN_DRAW_IN_TITLEBAR
this._updateTitlebarButton();
#endif
+ this._updateDevEditionThemeButton();
break;
case "lightweight-theme-window-updated":
if (aSubject == this.window) {
aData = JSON.parse(aData);
if (!aData) {
this.removeLWTStyling();
} else {
this.updateLWTStyling(aData);
@@ -1493,16 +1499,39 @@ CustomizeMode.prototype = {
},
toggleTitlebar: function(aShouldShowTitlebar) {
// Drawing in the titlebar means not showing the titlebar, hence the negation:
Services.prefs.setBoolPref(kDrawInTitlebarPref, !aShouldShowTitlebar);
},
#endif
+ _updateDevEditionThemeButton: function() {
+ let button = this.document.getElementById("customization-devedition-theme-button");
+
+ let themeEnabled = Services.prefs.getBoolPref(kDeveditionThemePref);
+ if (themeEnabled) {
+ button.setAttribute("checked", "true");
+ } else {
+ button.removeAttribute("checked");
+ }
+
+ let buttonVisible = Services.prefs.getBoolPref(kDeveditionButtonPref);
+ if (buttonVisible) {
+ button.removeAttribute("hidden");
+ } else {
+ button.setAttribute("hidden", "true");
+ }
+ },
+ toggleDevEditionTheme: function() {
+ let button = this.document.getElementById("customization-devedition-theme-button");
+ let preferenceValue = button.hasAttribute("checked");
+ Services.prefs.setBoolPref(kDeveditionThemePref, preferenceValue);
+ },
+
_onDragStart: function(aEvent) {
__dumpDragData(aEvent);
let item = aEvent.target;
while (item && item.localName != "toolbarpaletteitem") {
if (item.localName == "toolbar") {
return;
}
item = item.parentNode;
--- a/browser/components/customizableui/content/customizeMode.inc.xul
+++ b/browser/components/customizableui/content/customizeMode.inc.xul
@@ -47,16 +47,24 @@
<toolbarbutton class="customization-lwtheme-menu-footeritem"
label="&customizeMode.lwthemes.menuGetMore;"
accesskey="&customizeMode.lwthemes.menuGetMore.accessKey;"
tabindex="0"
oncommand="gCustomizeMode.getMoreThemes(event);"/>
</hbox>
</panel>
</button>
+
+ <button id="customization-devedition-theme-button"
+ class="customizationmode-button"
+ hidden="true"
+ label="&customizeMode.deveditionTheme.label;"
+ oncommand="gCustomizeMode.toggleDevEditionTheme()"
+ type="checkbox" />
+
<spacer id="customization-footer-spacer"/>
<button id="customization-undo-reset-button"
class="customizationmode-button"
hidden="true"
oncommand="gCustomizeMode.undoReset();"
label="&undoCmd.label;"/>
<button id="customization-reset-button"
oncommand="gCustomizeMode.reset();"
--- a/browser/components/customizableui/test/browser_970511_undo_restore_default.js
+++ b/browser/components/customizableui/test/browser_970511_undo_restore_default.js
@@ -96,12 +96,50 @@ add_task(function() {
is(Services.prefs.getBoolPref(prefName), !defaultValue, "Undo-reset goes back to previous pref value");
is(undoResetButton.hidden, true, "Undo reset button should be hidden after undo-reset clicked");
Services.prefs.clearUserPref(prefName);
ok(CustomizableUI.inDefaultState, "In default state after pref cleared");
is(undoResetButton.hidden, true, "Undo reset button should be hidden at end of test");
});
+// Bug 1082108 - Restore Defaults should clear user pref for devedition theme
+add_task(function() {
+ let prefName = "browser.devedition.theme.enabled";
+ Services.prefs.setBoolPref("browser.devedition.theme.showCustomizeButton", true);
+ let defaultValue = Services.prefs.getBoolPref(prefName);
+ let restoreDefaultsButton = document.getElementById("customization-reset-button");
+ let deveditionThemeButton = document.getElementById("customization-devedition-theme-button");
+ let undoResetButton = document.getElementById("customization-undo-reset-button");
+ ok(CustomizableUI.inDefaultState, "Should be in default state at start of test");
+ ok(restoreDefaultsButton.disabled, "Restore defaults button should be disabled when in default state");
+ is(deveditionThemeButton.hasAttribute("checked"), defaultValue, "Devedition theme button should reflect pref value");
+ is(undoResetButton.hidden, true, "Undo reset button should be hidden at start of test");
+ Services.prefs.setBoolPref(prefName, !defaultValue);
+ ok(!restoreDefaultsButton.disabled, "Restore defaults button should be enabled when pref changed");
+ is(deveditionThemeButton.hasAttribute("checked"), !defaultValue, "Devedition theme button should reflect changed pref value");
+ ok(!CustomizableUI.inDefaultState, "With devedition theme flipped, no longer default");
+ is(undoResetButton.hidden, true, "Undo reset button should be hidden after pref change");
+
+ yield gCustomizeMode.reset();
+ ok(restoreDefaultsButton.disabled, "Restore defaults button should be disabled after reset");
+ is(deveditionThemeButton.hasAttribute("checked"), defaultValue, "devedition theme button should reflect default value after reset");
+ is(Services.prefs.getBoolPref(prefName), defaultValue, "Reset should reset devedition.theme.enabled");
+ ok(CustomizableUI.inDefaultState, "In default state after devedition theme reset");
+ is(undoResetButton.hidden, false, "Undo reset button should be visible after reset");
+ ok(!undoResetButton.disabled, "Undo reset button should be enabled after reset");
+
+ yield gCustomizeMode.undoReset();
+ ok(!restoreDefaultsButton.disabled, "Restore defaults button should be enabled after undo-reset");
+ is(deveditionThemeButton.hasAttribute("checked"), !defaultValue, "devedition theme button should reflect undo-reset value");
+ ok(!CustomizableUI.inDefaultState, "No longer in default state after undo");
+ is(Services.prefs.getBoolPref(prefName), !defaultValue, "Undo-reset goes back to previous pref value");
+ is(undoResetButton.hidden, true, "Undo reset button should be hidden after undo-reset clicked");
+
+ Services.prefs.clearUserPref(prefName);
+ ok(CustomizableUI.inDefaultState, "In default state after pref cleared");
+ is(undoResetButton.hidden, true, "Undo reset button should be hidden at end of test");
+});
+
add_task(function asyncCleanup() {
yield gCustomizeMode.reset();
yield endCustomizing();
});
--- a/browser/components/loop/MozLoopAPI.jsm
+++ b/browser/components/loop/MozLoopAPI.jsm
@@ -35,17 +35,27 @@ this.EXPORTED_SYMBOLS = ["injectLoopAPI"
* object.
*
* @param {Error} error Error object to copy
* @param {nsIDOMWindow} targetWindow The content window to attach the API
*/
const cloneErrorObject = function(error, targetWindow) {
let obj = new targetWindow.Error();
for (let prop of Object.getOwnPropertyNames(error)) {
- obj[prop] = String(error[prop]);
+ let value = error[prop];
+ if (typeof value != "string" && typeof value != "number") {
+ value = String(value);
+ }
+
+ Object.defineProperty(Cu.waiveXrays(obj), prop, {
+ configurable: false,
+ enumerable: true,
+ value: value,
+ writable: false
+ });
}
return obj;
};
/**
* Makes an object or value available to an unprivileged target window.
*
* Primitives are returned as they are, while objects are cloned into the
--- a/browser/components/places/PlacesUIUtils.jsm
+++ b/browser/components/places/PlacesUIUtils.jsm
@@ -39,16 +39,53 @@ let CloudSync = null;
#ifdef MOZ_SERVICES_SYNC
XPCOMUtils.defineLazyModuleGetter(this, "Weave",
"resource://services-sync/main.js");
#endif
// copied from utilityOverlay.js
const TAB_DROP_TYPE = "application/x-moz-tabbrowser-tab";
+// This function isn't public both because it's synchronous and because it is
+// going to be removed in bug 1072833.
+function IsLivemark(aItemId) {
+ // Since this check may be done on each dragover event, it's worth maintaining
+ // a cache.
+ let self = IsLivemark;
+ if (!("ids" in self)) {
+ const LIVEMARK_ANNO = PlacesUtils.LMANNO_FEEDURI;
+
+ let idsVec = PlacesUtils.annotations.getItemsWithAnnotation(LIVEMARK_ANNO);
+ self.ids = new Set(idsVec);
+
+ let obs = Object.freeze({
+ QueryInterface: XPCOMUtils.generateQI(Ci.nsIAnnotationObserver),
+
+ onItemAnnotationSet(itemId, annoName) {
+ if (annoName == LIVEMARK_ANNO)
+ self.ids.add(itemId);
+ },
+
+ onItemAnnotationRemoved(itemId, annoName) {
+ // If annoName is set to an empty string, the item is gone.
+ if (annoName == LIVEMARK_ANNO || annoName == "")
+ self.ids.delete(itemId);
+ },
+
+ onPageAnnotationSet() { },
+ onPageAnnotationRemoved() { },
+ });
+ PlacesUtils.annotations.addObserver(obs);
+ PlacesUtils.registerShutdownFunction(() => {
+ PlacesUtils.annotations.removeObserver(obs);
+ });
+ }
+ return self.ids.has(aItemId);
+}
+
this.PlacesUIUtils = {
ORGANIZER_LEFTPANE_VERSION: 7,
ORGANIZER_FOLDER_ANNO: "PlacesOrganizer/OrganizerFolder",
ORGANIZER_QUERY_ANNO: "PlacesOrganizer/OrganizerQuery",
LOAD_IN_SIDEBAR_ANNO: "bookmarkProperties/loadInSidebar",
DESCRIPTION_ANNO: "bookmarkProperties/description",
@@ -556,16 +593,99 @@ this.PlacesUIUtils = {
*/
getItemDescription: function PUIU_getItemDescription(aItemId) {
if (PlacesUtils.annotations.itemHasAnnotation(aItemId, this.DESCRIPTION_ANNO))
return PlacesUtils.annotations.getItemAnnotation(aItemId, this.DESCRIPTION_ANNO);
return "";
},
/**
+ * Check whether or not the given node represents a removable entry (either in
+ * history or in bookmarks).
+ *
+ * @param aNode
+ * a node, except the root node of a query.
+ * @return true if the aNode represents a removable entry, false otherwise.
+ */
+ canUserRemove: function (aNode) {
+ let parentNode = aNode.parent;
+ if (!parentNode)
+ throw new Error("canUserRemove doesn't accept root nodes");
+
+ // If it's not a bookmark, we can remove it unless it's a child of a
+ // livemark.
+ if (aNode.itemId == -1) {
+ // Rather than executing a db query, checking the existence of the feedURI
+ // annotation, detect livemark children by the fact that they are the only
+ // direct non-bookmark children of bookmark folders.
+ return !PlacesUtils.nodeIsFolder(parentNode);
+ }
+
+ // Otherwise it has to be a child of an editable folder.
+ return !this.isContentsReadOnly(parentNode);
+ },
+
+ /**
+ * DO NOT USE THIS API IN ADDONS. IT IS VERY LIKELY TO CHANGE WHEN THE SWITCH
+ * TO GUIDS IS COMPLETE (BUG 1071511).
+ *
+ * Check whether or not the given node or item-id points to a folder which
+ * should not be modified by the user (i.e. its children should be unremovable
+ * and unmovable, new children should be disallowed, etc).
+ * These semantics are not inherited, meaning that read-only folder may
+ * contain editable items (for instance, the places root is read-only, but all
+ * of its direct children aren't).
+ *
+ * You should only pass folder item ids or folder nodes for aNodeOrItemId.
+ * While this is only enforced for the node case (if an item id of a separator
+ * or a bookmark is passed, false is returned), it's considered the caller's
+ * job to ensure that it checks a folder.
+ * Also note that folder-shortcuts should only be passed as result nodes.
+ * Otherwise they are just treated as bookmarks (i.e. false is returned).
+ *
+ * @param aNodeOrItemId
+ * any item id or result node.
+ * @throws if aNodeOrItemId is neither an item id nor a folder result node.
+ * @note livemark "folders" are considered read-only (but see bug 1072833).
+ * @return true if aItemId points to a read-only folder, false otherwise.
+ */
+ isContentsReadOnly: function (aNodeOrItemId) {
+ let itemId;
+ if (typeof(aNodeOrItemId) == "number") {
+ itemId = aNodeOrItemId;
+ }
+ else if (PlacesUtils.nodeIsFolder(aNodeOrItemId)) {
+ itemId = PlacesUtils.getConcreteItemId(aNodeOrItemId);
+ }
+ else {
+ throw new Error("invalid value for aNodeOrItemId");
+ }
+
+ if (itemId == PlacesUtils.placesRootId || IsLivemark(itemId))
+ return true;
+
+ // leftPaneFolderId, and as a result, allBookmarksFolderId, is a lazy getter
+ // performing at least a synchronous DB query (and on its very first call
+ // in a fresh profile, it also creates the entire structure).
+ // Therefore we don't want to this function, which is called very often by
+ // isCommandEnabled, to ever be the one that invokes it first, especially
+ // because isCommandEnabled may be called way before the left pane folder is
+ // even created (for example, if the user only uses the bookmarks menu or
+ // toolbar for managing bookmarks). To do so, we avoid comparing to those
+ // special folder if the lazy getter is still in place. This is safe merely
+ // because the only way to access the left pane contents goes through
+ // "resolving" the leftPaneFolderId getter.
+ if ("get" in Object.getOwnPropertyDescriptor(this, "leftPaneFolderId"))
+ return false;
+
+ return itemId == this.leftPaneFolderId ||
+ itemId == this.allBookmarksFolderId;
+ },
+
+ /**
* Gives the user a chance to cancel loading lots of tabs at once
*/
_confirmOpenInTabs:
function PUIU__confirmOpenInTabs(numTabsToOpen, aWindow) {
const WARN_ON_OPEN_PREF = "browser.tabs.warnOnOpen";
var reallyOpen = true;
if (Services.prefs.getBoolPref(WARN_ON_OPEN_PREF)) {
@@ -957,18 +1077,16 @@ this.PlacesUIUtils = {
create_folder: function CB_create_folder(aFolderName, aParentId, aIsRoot) {
// Left Pane Root Folder.
let folderId = bs.createFolder(aParentId,
queries[aFolderName].title,
bs.DEFAULT_INDEX);
// We should never backup this, since it changes between profiles.
as.setItemAnnotation(folderId, PlacesUtils.EXCLUDE_FROM_BACKUP_ANNO, 1,
0, as.EXPIRE_NEVER);
- // Disallow manipulating this folder within the organizer UI.
- bs.setFolderReadonly(folderId, true);
if (aIsRoot) {
// Mark as special left pane root.
as.setItemAnnotation(folderId, PlacesUIUtils.ORGANIZER_FOLDER_ANNO,
PlacesUIUtils.ORGANIZER_LEFTPANE_VERSION,
0, as.EXPIRE_NEVER);
}
else {
--- a/browser/components/places/content/browserPlacesViews.js
+++ b/browser/components/places/content/browserPlacesViews.js
@@ -1371,18 +1371,18 @@ PlacesToolbar.prototype = {
return null;
let dropPoint = { ip: null, beforeIndex: null, folderElt: null };
let elt = aEvent.target;
if (elt._placesNode && elt != this._rootElt &&
elt.localName != "menupopup") {
let eltRect = elt.getBoundingClientRect();
let eltIndex = Array.indexOf(this._rootElt.childNodes, elt);
- if (PlacesUtils.nodeIsFolder(elt._placesNode) &&
- !PlacesUtils.nodeIsReadOnly(elt._placesNode)) {
+ if (PlacesUIUtils.nodeIsFolder(elt._placesNode) &&
+ !PlacesUIUtils.isContentsReadOnly(elt._placesNode)) {
// This is a folder.
// If we are in the middle of it, drop inside it.
// Otherwise, drop before it, with regards to RTL mode.
let threshold = eltRect.width * 0.25;
if (this.isRTL ? (aEvent.clientX > eltRect.right - threshold)
: (aEvent.clientX < eltRect.left + threshold)) {
// Drop before this folder.
dropPoint.ip =
--- a/browser/components/places/content/controller.js
+++ b/browser/components/places/content/controller.js
@@ -195,17 +195,17 @@ PlacesController.prototype = {
case "placesCmd_reload":
// Livemark containers
var selectedNode = this._view.selectedNode;
return selectedNode && this.hasCachedLivemarkInfo(selectedNode);
case "placesCmd_sortBy:name":
var selectedNode = this._view.selectedNode;
return selectedNode &&
PlacesUtils.nodeIsFolder(selectedNode) &&
- !PlacesUtils.nodeIsReadOnly(selectedNode) &&
+ !PlacesUIUtils.isContentsReadOnly(selectedNode) &&
this._view.result.sortingMode ==
Ci.nsINavHistoryQueryOptions.SORT_BY_NONE;
case "placesCmd_createBookmark":
var node = this._view.selectedNode;
return node && PlacesUtils.nodeIsURI(node) && node.itemId == -1;
default:
return false;
}
@@ -325,31 +325,17 @@ PlacesController.prototype = {
for (var j = 0; j < ranges.length; j++) {
var nodes = ranges[j];
for (var i = 0; i < nodes.length; ++i) {
// Disallow removing the view's root node
if (nodes[i] == root)
return false;
- if (PlacesUtils.nodeIsFolder(nodes[i]) &&
- !PlacesControllerDragHelper.canMoveNode(nodes[i]))
- return false;
-
- // We don't call nodeIsReadOnly here, because nodeIsReadOnly means that
- // a node has children that cannot be edited, reordered or removed. Here,
- // we don't care if a node's children can't be reordered or edited, just
- // that they're removable. All history results have removable children
- // (based on the principle that any URL in the history table should be
- // removable), but some special bookmark folders may have non-removable
- // children, e.g. live bookmark folder children. It doesn't make sense
- // to delete a child of a live bookmark folder, since when the folder
- // refreshes, the child will return.
- var parent = nodes[i].parent || root;
- if (PlacesUtils.isReadonlyFolder(parent))
+ if (!PlacesUIUtils.canUserRemove(nodes[i]))
return false;
}
}
return true;
},
/**
@@ -1555,83 +1541,41 @@ let PlacesControllerDragHelper = {
*
* @param aUnwrappedNode
* A node unwrapped by PlacesUtils.unwrapNodes().
* @return True if the node can be moved, false otherwise.
*/
canMoveUnwrappedNode: function (aUnwrappedNode) {
return aUnwrappedNode.id > 0 &&
!PlacesUtils.isRootItem(aUnwrappedNode.id) &&
- aUnwrappedNode.parent != PlacesUtils.placesRootId &&
+ !PlacesUIUtils.isContentsReadOnly(aUnwrappedNode.parent) ||
aUnwrappedNode.parent != PlacesUtils.tagsFolderId &&
- aUnwrappedNode.grandParentId != PlacesUtils.tagsFolderId &&
- !aUnwrappedNode.parentReadOnly;
+ aUnwrappedNode.grandParentId != PlacesUtils.tagsFolderId;
},
/**
* Determines if a node can be moved.
*
* @param aNode
* A nsINavHistoryResultNode node.
* @return True if the node can be moved, false otherwise.
*/
canMoveNode:
function PCDH_canMoveNode(aNode) {
- // Can't move query root.
- if (!aNode.parent)
- return false;
-
- let parentId = PlacesUtils.getConcreteItemId(aNode.parent);
- let concreteId = PlacesUtils.getConcreteItemId(aNode);
-
- // Can't move children of tag containers.
- if (PlacesUtils.nodeIsTagQuery(aNode.parent))
- return false;
-
- // Can't move children of read-only containers.
- if (PlacesUtils.nodeIsReadOnly(aNode.parent))
- return false;
-
- // Check for special folders, etc.
- if (PlacesUtils.nodeIsContainer(aNode) &&
- !this.canMoveContainer(aNode.itemId, parentId))
+ // Only bookmark items are movable.
+ if (aNode.itemId == -1)
return false;
- return true;
- },
-
- /**
- * Determines if a container node can be moved.
- *
- * @param aId
- * A bookmark folder id.
- * @param [optional] aParentId
- * The parent id of the folder.
- * @return True if the container can be moved to the target.
- */
- canMoveContainer:
- function PCDH_canMoveContainer(aId, aParentId) {
- if (aId == -1)
- return false;
-
- // Disallow moving of roots and special folders.
- const ROOTS = [PlacesUtils.placesRootId, PlacesUtils.bookmarksMenuFolderId,
- PlacesUtils.tagsFolderId, PlacesUtils.unfiledBookmarksFolderId,
- PlacesUtils.toolbarFolderId];
- if (ROOTS.indexOf(aId) != -1)
- return false;
-
- // Get parent id if necessary.
- if (aParentId == null || aParentId == -1)
- aParentId = PlacesUtils.bookmarks.getFolderIdForItem(aId);
-
- if (PlacesUtils.bookmarks.getFolderReadonly(aParentId))
- return false;
-
- return true;
+ // Once tags and bookmarked are divorced, the tag-query check should be
+ // removed.
+ let parentNode = aNode.parent;
+ return parentNode != null &&
+ !(PlacesUtils.nodeIsFolder(parentNode) &&
+ PlacesUIUtils.isContentsReadOnly(parentNode)) &&
+ !PlacesUtils.nodeIsTagQuery(parentNode);
},
/**
* Handles the drop of one or more items onto a view.
* @param insertionPoint
* The insertion point where the items should be dropped
*/
onDrop: Task.async(function* (insertionPoint, dt) {
@@ -1721,22 +1665,20 @@ let PlacesControllerDragHelper = {
/**
* Checks if we can insert into a container.
* @param aContainer
* The container were we are want to drop
*/
disallowInsertion: function(aContainer) {
NS_ASSERT(aContainer, "empty container");
- // Allow dropping into Tag containers.
- if (PlacesUtils.nodeIsTagQuery(aContainer))
- return false;
- // Disallow insertion of items under readonly folders.
- return (!PlacesUtils.nodeIsFolder(aContainer) ||
- PlacesUtils.nodeIsReadOnly(aContainer));
+ // Allow dropping into Tag containers and editable folders.
+ return !PlacesUtils.nodeIsTagQuery(aContainer) &&
+ (!PlacesUtils.nodeIsFolder(aContainer) ||
+ PlacesUIUtils.isContentsReadOnly(aContainer));
}
};
XPCOMUtils.defineLazyServiceGetter(PlacesControllerDragHelper, "dragService",
"@mozilla.org/widget/dragservice;1",
"nsIDragService");
--- a/browser/components/places/content/menu.xml
+++ b/browser/components/places/content/menu.xml
@@ -101,19 +101,19 @@
if (isMenu && elt.lastChild &&
elt.lastChild.hasAttribute("placespopup"))
dropPoint.folderElt = elt;
return dropPoint;
}
let tagName = PlacesUtils.nodeIsTagQuery(elt._placesNode) ?
elt._placesNode.title : null;
- if ((PlacesUtils.nodeIsFolder(elt._placesNode) ||
- PlacesUtils.nodeIsTagQuery(elt._placesNode)) &&
- !PlacesUtils.nodeIsReadOnly(elt._placesNode)) {
+ if ((PlacesUtils.nodeIsFolder(elt._placesNode) &&
+ !PlacesUIUtils.isContentsReadOnly(elt._placesNode)) ||
+ PlacesUtils.nodeIsTagQuery(elt._placesNode)) {
// This is a folder or a tag container.
if (eventY - eltY < eltHeight * 0.20) {
// If mouse is in the top part of the element, drop above folder.
dropPoint.ip = new InsertionPoint(
PlacesUtils.getConcreteItemId(resultNode),
-1,
Ci.nsITreeView.DROP_BEFORE,
tagName,
--- a/browser/components/places/content/treeView.js
+++ b/browser/components/places/content/treeView.js
@@ -1644,33 +1644,49 @@ PlacesTreeView.prototype = {
this._result.sortingMode = newSort;
},
isEditable: function PTV_isEditable(aRow, aColumn) {
// At this point we only support editing the title field.
if (aColumn.index != 0)
return false;
- // Only bookmark-nodes are editable, and those are never built lazily
let node = this._rows[aRow];
- if (!node || node.itemId == -1)
+ if (!node) {
+ Cu.reportError("isEditable called for an unbuilt row.");
+ return false;
+ }
+ let itemId = node.itemId;
+
+ // Only bookmark-nodes are editable. Fortunately, this checks also takes
+ // care of livemark children.
+ if (itemId == -1)
return false;
- // The following items are never editable:
- // * Read-only items.
+ // The following items are also not editable, even though they are bookmark
+ // items.
// * places-roots
+ // * the left pane special folders and queries (those are place: uri
+ // bookmarks)
// * separators
- if (PlacesUtils.nodeIsReadOnly(node) ||
- PlacesUtils.nodeIsSeparator(node))
+ //
+ // Note that concrete itemIds aren't used intentionally. For example, we
+ // have no reason to disallow renaming a shortcut to the Bookmarks Toolbar,
+ // except for the one under All Bookmarks.
+ if (PlacesUtils.nodeIsSeparator(node) || PlacesUtils.isRootItem(itemId))
return false;
- if (PlacesUtils.nodeIsFolder(node)) {
- let itemId = PlacesUtils.getConcreteItemId(node);
- if (PlacesUtils.isRootItem(itemId))
- return false;
+ let parentId = PlacesUtils.getConcreteItemId(node.parent);
+ if (parentId == PlacesUIUtils.leftPaneFolderId ||
+ parentId == PlacesUIUtils.allBookmarksFolderId) {
+ // Note that the for the time being this is the check that actually
+ // blocks renaming places "roots", and not the isRootItem check above.
+ // That's because places root are only exposed through folder shortcuts
+ // descendants of the left pane folder.
+ return false;
}
return true;
},
setCellText: function PTV_setCellText(aRow, aColumn, aText) {
// We may only get here if the cell is editable.
let node = this._rows[aRow];
--- a/browser/components/places/tests/browser/browser_423515.js
+++ b/browser/components/places/tests/browser/browser_423515.js
@@ -22,18 +22,16 @@ function test() {
tests.push({
populate: function() {
this.id =
PlacesUtils.bookmarks.createFolder(rootId, "", IDX);
},
validate: function() {
is(rootNode.childCount, 1,
"populate added data to the test root");
- is(PlacesControllerDragHelper.canMoveContainer(this.id),
- true, "can move regular folder id");
is(PlacesControllerDragHelper.canMoveNode(rootNode.getChild(0)),
true, "can move regular folder node");
}
});
// add a regular folder shortcut, should be moveable
tests.push({
populate: function() {
@@ -52,19 +50,16 @@ function test() {
var shortcutNode = rootNode.getChild(1);
is(shortcutNode.type, 9, "node is folder shortcut");
is(this.shortcutId, shortcutNode.itemId, "shortcut id and shortcut node item id match");
var concreteId = PlacesUtils.getConcreteItemId(shortcutNode);
is(concreteId, folderNode.itemId, "shortcut node id and concrete id match");
- is(PlacesControllerDragHelper.canMoveContainer(this.shortcutId),
- true, "can move folder shortcut id");
-
is(PlacesControllerDragHelper.canMoveNode(shortcutNode),
true, "can move folder shortcut node");
}
});
// add a regular query, should be moveable
tests.push({
populate: function() {
@@ -78,19 +73,16 @@ function test() {
"populated data to the test root");
var bmNode = rootNode.getChild(0);
is(bmNode.itemId, this.bookmarkId, "bookmark id and bookmark node item id match");
var queryNode = rootNode.getChild(1);
is(queryNode.itemId, this.queryId, "query id and query node item id match");
- is(PlacesControllerDragHelper.canMoveContainer(this.queryId),
- true, "can move query id");
-
is(PlacesControllerDragHelper.canMoveNode(queryNode),
true, "can move query node");
}
});
// test that special folders cannot be moved
// test that special folders shortcuts can be moved
tests.push({
@@ -122,33 +114,26 @@ function test() {
node.containerOpen = false;
ok(false, "Unable to find child node");
return null;
}
for (var i = 0; i < this.folders.length; i++) {
var id = this.folders[i];
- is(PlacesControllerDragHelper.canMoveContainer(id),
- false, "shouldn't be able to move special folder id");
-
var node = getRootChildNode(id);
isnot(node, null, "Node found");
is(PlacesControllerDragHelper.canMoveNode(node),
false, "shouldn't be able to move special folder node");
var shortcutId = this.shortcuts[id];
var shortcutNode = rootNode.getChild(i);
is(shortcutNode.itemId, shortcutId, "shortcut id and shortcut node item id match");
- dump("can move shortcut id?\n");
- is(PlacesControllerDragHelper.canMoveContainer(shortcutId),
- true, "should be able to move special folder shortcut id");
-
dump("can move shortcut node?\n");
is(PlacesControllerDragHelper.canMoveNode(shortcutNode),
true, "should be able to move special folder shortcut node");
}
}
});
// test that a tag container cannot be moved
@@ -164,56 +149,23 @@ function test() {
var options = PlacesUtils.history.getNewQueryOptions();
options.resultType = Ci.nsINavHistoryQueryOptions.RESULTS_AS_TAG_QUERY;
var tagsNode = PlacesUtils.history.executeQuery(query, options).root;
tagsNode.containerOpen = true;
is(tagsNode.childCount, 1, "has new tag");
var tagNode = tagsNode.getChild(0);
-
+
is(PlacesControllerDragHelper.canMoveNode(tagNode),
false, "should not be able to move tag container node");
-
tagsNode.containerOpen = false;
}
});
- // test that any child of a read-only node cannot be moved
- tests.push({
- populate: function() {
- this.id =
- PlacesUtils.bookmarks.createFolder(rootId, "foo", IDX);
- PlacesUtils.bookmarks.createFolder(this.id, "bar", IDX);
- PlacesUtils.bookmarks.setFolderReadonly(this.id, true);
- },
- validate: function() {
- is(rootNode.childCount, 1,
- "populate added data to the test root");
- var readOnlyFolder = rootNode.getChild(0);
-
- // test that we can move the read-only folder
- is(PlacesControllerDragHelper.canMoveContainer(this.id),
- true, "can move read-only folder id");
- is(PlacesControllerDragHelper.canMoveNode(readOnlyFolder),
- true, "can move read-only folder node");
-
- // test that we cannot move the child of a read-only folder
- readOnlyFolder.QueryInterface(Ci.nsINavHistoryContainerResultNode);
- readOnlyFolder.containerOpen = true;
- var childFolder = readOnlyFolder.getChild(0);
-
- is(PlacesControllerDragHelper.canMoveContainer(childFolder.itemId),
- false, "cannot move a child of a read-only folder");
- is(PlacesControllerDragHelper.canMoveNode(childFolder),
- false, "cannot move a child node of a read-only folder node");
- readOnlyFolder.containerOpen = false;
- }
- });
-
tests.forEach(function(aTest) {
PlacesUtils.bookmarks.removeFolderChildren(rootId);
aTest.populate();
aTest.validate();
});
rootNode.containerOpen = false;
PlacesUtils.bookmarks.removeItem(rootId);
--- a/browser/themes/shared/customizableui/customizeMode.inc.css
+++ b/browser/themes/shared/customizableui/customizeMode.inc.css
@@ -125,16 +125,25 @@
padding: 2px 12px;
background-color: rgb(251,251,251);
color: rgb(71,71,71);
box-shadow: 0 1px rgba(255, 255, 255, 0.5),
inset 0 1px rgba(255, 255, 255, 0.5);
-moz-appearance: none;
}
+#customization-titlebar-visibility-button[checked],
+#customization-devedition-theme-button[checked] {
+ background-color: rgb(218, 218, 218);
+ border-color: rgb(168, 168, 168);
+ text-shadow: 0 1px rgb(236, 236, 236);
+ box-shadow: 0 1px rgba(255, 255, 255, 0.5),
+ inset 0 1px rgb(196, 196, 196);
+}
+
.customizationmode-button[disabled="true"] {
opacity: .5;
}
.customizationmode-button > .box-inherit > .box-inherit > .button-icon,
.customizationmode-button > .button-box > .button-icon {
height: 24px;
}
@@ -151,21 +160,16 @@
}
#customization-titlebar-visibility-button > .button-box > .button-icon {
vertical-align: middle;
}
#customization-titlebar-visibility-button[checked] {
-moz-image-region: rect(0, 48px, 24px, 24px);
- background-color: rgb(218, 218, 218);
- border-color: rgb(168, 168, 168);
- text-shadow: 0 1px rgb(236, 236, 236);
- box-shadow: 0 1px rgba(255, 255, 255, 0.5),
- inset 0 1px rgb(196, 196, 196);
}
#main-window[customize-entered] #customization-panel-container {
background-image: url("chrome://browser/skin/customizableui/customizeMode-separatorHorizontal.png"),
url("chrome://browser/skin/customizableui/customizeMode-separatorVertical.png"),
url("chrome://browser/skin/customizableui/customizeMode-gridTexture.png"),
url("chrome://browser/skin/customizableui/background-noise-toolbar.png"),
linear-gradient(to bottom, #3e86ce, #3878ba);
--- a/content/html/content/src/HTMLInputElement.cpp
+++ b/content/html/content/src/HTMLInputElement.cpp
@@ -2403,20 +2403,28 @@ HTMLInputElement::SetUserInput(const nsA
Sequence<nsString> list;
list.AppendElement(aValue);
MozSetFileNameArray(list);
return NS_OK;
} else {
SetValueInternal(aValue, true, true);
}
- return nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
- static_cast<nsIDOMHTMLInputElement*>(this),
- NS_LITERAL_STRING("input"), true,
- true);
+ nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
+ static_cast<nsIDOMHTMLInputElement*>(this),
+ NS_LITERAL_STRING("input"), true,
+ true);
+
+ // If this element is not currently focused, it won't receive a change event for this
+ // update through the normal channels. So fire a change event immediately, instead.
+ if (!ShouldBlur(this)) {
+ FireChangeEventIfNeeded();
+ }
+
+ return NS_OK;
}
nsIEditor*
HTMLInputElement::GetEditor()
{
nsTextEditorState* state = GetEditorState();
if (state) {
return state->GetEditor();
--- a/content/html/content/test/test_bug388558.html
+++ b/content/html/content/test/test_bug388558.html
@@ -37,17 +37,17 @@ function testUserInput() {
is(inputChange, 1,
"Change event dispatched when setting the value of the input element");
input.value = "";
is(inputChange, 1,
"Change event dispatched when setting the value of the input element (2).");
SpecialPowers.wrap(input).setUserInput("foo");
- is(inputChange, 1,
+ is(inputChange, 2,
"Change event dispatched when input element doesn't have focus.");
textarea.focus();
textarea.setUserInput("foo");
textarea.blur();
is(textareaChange, 1, "Textarea element should have got one change event.");
textarea.focus();
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -2853,24 +2853,31 @@ nsDocShell::PopProfileTimelineMarkers(JS
// {name,start,end} JS object.
// Paint markers are different because paint is handled at root docShell level
// in the information that a paint was done is then stored at each sub
// docShell level but we can only be sure that a paint did happen in a
// docShell if an Layer marker type was recorded too.
nsTArray<mozilla::dom::ProfileTimelineMarker> profileTimelineMarkers;
+ // If we see an unpaired START, we keep it around for the next call
+ // to PopProfileTimelineMarkers. We store the kept START objects in
+ // this array.
+ decltype(mProfileTimelineMarkers) keptMarkers;
+
for (uint32_t i = 0; i < mProfileTimelineMarkers.Length(); ++i) {
ProfilerMarkerTracing* startPayload = static_cast<ProfilerMarkerTracing*>(
mProfileTimelineMarkers[i]->mPayload);
const char* startMarkerName = mProfileTimelineMarkers[i]->mName;
bool hasSeenPaintedLayer = false;
if (startPayload->GetMetaData() == TRACING_INTERVAL_START) {
+ bool hasSeenEnd = false;
+
// The assumption is that the devtools timeline flushes markers frequently
// enough for the amount of markers to always be small enough that the
// nested for loop isn't going to be a performance problem.
for (uint32_t j = i + 1; j < mProfileTimelineMarkers.Length(); ++j) {
ProfilerMarkerTracing* endPayload = static_cast<ProfilerMarkerTracing*>(
mProfileTimelineMarkers[j]->mPayload);
const char* endMarkerName = mProfileTimelineMarkers[j]->mName;
@@ -2888,25 +2895,36 @@ nsDocShell::PopProfileTimelineMarkers(JS
if (!isPaint || (isPaint && hasSeenPaintedLayer)) {
mozilla::dom::ProfileTimelineMarker marker;
marker.mName = NS_ConvertUTF8toUTF16(startMarkerName);
marker.mStart = mProfileTimelineMarkers[i]->mTime;
marker.mEnd = mProfileTimelineMarkers[j]->mTime;
profileTimelineMarkers.AppendElement(marker);
}
+ // We want the start to be dropped either way.
+ hasSeenEnd = true;
+
break;
}
}
+
+ // If we did not see the corresponding END, keep the START.
+ if (!hasSeenEnd) {
+ keptMarkers.AppendElement(mProfileTimelineMarkers[i]);
+ mProfileTimelineMarkers.RemoveElementAt(i);
+ --i;
+ }
}
}
ToJSValue(aCx, profileTimelineMarkers, aProfileTimelineMarkers);
ClearProfileTimelineMarkers();
+ mProfileTimelineMarkers.SwapElements(keptMarkers);
return NS_OK;
#else
return NS_ERROR_FAILURE;
#endif
}
float
@@ -2947,18 +2965,17 @@ nsDocShell::AddProfileTimelineMarker(con
#endif
}
void
nsDocShell::ClearProfileTimelineMarkers()
{
#ifdef MOZ_ENABLE_PROFILER_SPS
for (uint32_t i = 0; i < mProfileTimelineMarkers.Length(); ++i) {
- delete mProfileTimelineMarkers[i]->mPayload;
- mProfileTimelineMarkers[i]->mPayload = nullptr;
+ delete mProfileTimelineMarkers[i];
}
mProfileTimelineMarkers.Clear();
#endif
}
nsIDOMStorageManager*
nsDocShell::TopSessionStorageManager()
{
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -16,16 +16,17 @@
#include "nsIScrollable.h"
#include "nsITextScroll.h"
#include "nsIContentViewerContainer.h"
#include "nsIDOMStorageManager.h"
#include "nsDocLoader.h"
#include "mozilla/WeakPtr.h"
#include "mozilla/TimeStamp.h"
#include "GeckoProfiler.h"
+#include "ProfilerMarkers.h"
// Helper Classes
#include "nsCOMPtr.h"
#include "nsPoint.h" // mCurrent/mDefaultScrollbarPreferences
#include "nsString.h"
#include "nsAutoPtr.h"
#include "nsThreadUtils.h"
@@ -954,21 +955,27 @@ private:
{
InternalProfileTimelineMarker(const char* aName,
ProfilerMarkerTracing* aPayload,
float aTime)
: mName(aName)
, mPayload(aPayload)
, mTime(aTime)
{}
+
+ ~InternalProfileTimelineMarker()
+ {
+ delete mPayload;
+ }
+
const char* mName;
ProfilerMarkerTracing* mPayload;
float mTime;
};
- nsTArray<nsAutoPtr<InternalProfileTimelineMarker>> mProfileTimelineMarkers;
+ nsTArray<InternalProfileTimelineMarker*> mProfileTimelineMarkers;
// Get the elapsed time (in millis) since the profile timeline recording
// started
float GetProfileTimelineDelta();
// Get rid of all the timeline markers accumulated so far
void ClearProfileTimelineMarkers();
--- a/dom/nfc/NfcContentHelper.js
+++ b/dom/nfc/NfcContentHelper.js
@@ -31,23 +31,26 @@ XPCOMUtils.defineLazyGetter(this, "NFC",
Cu.import("resource://gre/modules/systemlibs.js");
const NFC_ENABLED = libcutils.property_get("ro.moz.nfc.enabled", "false") === "true";
// set to true to in nfc_consts.js to see debug messages
let DEBUG = NFC.DEBUG_CONTENT_HELPER;
let debug;
-if (DEBUG) {
- debug = function (s) {
- dump("-*- NfcContentHelper: " + s + "\n");
- };
-} else {
- debug = function (s) {};
-}
+function updateDebug() {
+ if (DEBUG) {
+ debug = function (s) {
+ dump("-*- NfcContentHelper: " + s + "\n");
+ };
+ } else {
+ debug = function (s) {};
+ }
+};
+updateDebug();
const NFCCONTENTHELPER_CID =
Components.ID("{4d72c120-da5f-11e1-9b23-0800200c9a66}");
const NFC_IPC_MSG_NAMES = [
"NFC:ReadNDEFResponse",
"NFC:WriteNDEFResponse",
"NFC:MakeReadOnlyNDEFResponse",
@@ -60,16 +63,18 @@ const NFC_IPC_MSG_NAMES = [
];
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
"nsISyncMessageSender");
function NfcContentHelper() {
this.initDOMRequestHelper(/* aWindow */ null, NFC_IPC_MSG_NAMES);
+
+ Services.obs.addObserver(this, NFC.TOPIC_MOZSETTINGS_CHANGED, false);
Services.obs.addObserver(this, "xpcom-shutdown", false);
this._requestMap = [];
}
NfcContentHelper.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
@@ -81,16 +86,27 @@ NfcContentHelper.prototype = {
classID: NFCCONTENTHELPER_CID,
classDescription: "NfcContentHelper",
interfaces: [Ci.nsINfcContentHelper]
}),
_requestMap: null,
eventTarget: null,
+ init: function init(aWindow) {
+ if (aWindow && aWindow.navigator.mozSettings) {
+ let lock = aWindow.navigator.mozSettings.createLock();
+ var nfcDebug = lock.get(NFC.SETTING_NFC_DEBUG);
+ nfcDebug.onsuccess = function _nfcDebug() {
+ DEBUG = nfcDebug.result[NFC.SETTING_NFC_DEBUG];
+ updateDebug();
+ };
+ }
+ },
+
encodeNDEFRecords: function encodeNDEFRecords(records) {
let encodedRecords = [];
for (let i = 0; i < records.length; i++) {
let record = records[i];
encodedRecords.push({
tnf: record.tnf,
type: record.type || undefined,
id: record.id || undefined,
@@ -323,18 +339,26 @@ NfcContentHelper.prototype = {
{requestId: requestId});
return request;
},
// nsIObserver
observe: function observe(subject, topic, data) {
if (topic == "xpcom-shutdown") {
this.destroyDOMRequestHelper();
+ Services.obs.removeObserver(this, NFC.TOPIC_MOZSETTINGS_CHANGED);
Services.obs.removeObserver(this, "xpcom-shutdown");
cpmm = null;
+ } else if (topic == NFC.TOPIC_MOZSETTINGS_CHANGED) {
+ if ("wrappedJSObject" in subject) {
+ subject = subject.wrappedJSObject;
+ }
+ if (subject) {
+ this.handle(subject.key, subject.value);
+ }
}
},
// nsIMessageListener
fireRequestSuccess: function fireRequestSuccess(requestId, result) {
let request = this.takeRequest(requestId);
if (!request) {
@@ -390,16 +414,25 @@ NfcContentHelper.prototype = {
case NFC.NFC_PEER_EVENT_LOST:
this.eventTarget.notifyPeerLost(result.sessionToken);
break;
}
break;
}
},
+ handle: function handle(name, result) {
+ switch (name) {
+ case NFC.SETTING_NFC_DEBUG:
+ DEBUG = result;
+ updateDebug();
+ break;
+ }
+ },
+
handleReadNDEFResponse: function handleReadNDEFResponse(result) {
let requester = this._requestMap[result.requestId];
if (!requester) {
debug("Response Invalid requestId=" + result.requestId);
return;
}
delete this._requestMap[result.requestId];
--- a/dom/nfc/gonk/Nfc.js
+++ b/dom/nfc/gonk/Nfc.js
@@ -17,36 +17,43 @@
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
+XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService",
+ "@mozilla.org/settingsService;1",
+ "nsISettingsService");
+
XPCOMUtils.defineLazyGetter(this, "NFC", function () {
let obj = {};
Cu.import("resource://gre/modules/nfc_consts.js", obj);
return obj;
});
Cu.import("resource://gre/modules/systemlibs.js");
const NFC_ENABLED = libcutils.property_get("ro.moz.nfc.enabled", "false") === "true";
// set to true in nfc_consts.js to see debug messages
let DEBUG = NFC.DEBUG_NFC;
let debug;
-if (DEBUG) {
- debug = function (s) {
- dump("-*- Nfc: " + s + "\n");
- };
-} else {
- debug = function (s) {};
-}
+function updateDebug() {
+ if (DEBUG) {
+ debug = function (s) {
+ dump("-*- Nfc: " + s + "\n");
+ };
+ } else {
+ debug = function (s) {};
+ }
+};
+updateDebug();
const NFC_CONTRACTID = "@mozilla.org/nfc;1";
const NFC_CID =
Components.ID("{2ff24790-5e74-11e1-b86c-0800200c9a66}");
const NFC_IPC_ADD_EVENT_TARGET_MSG_NAMES = [
"NFC:AddEventTarget"
];
@@ -98,24 +105,29 @@ XPCOMUtils.defineLazyGetter(this, "gMess
peerTargets: {},
currentPeer: null,
eventTargets: [],
init: function init(nfc) {
this.nfc = nfc;
+ let lock = gSettingsService.createLock();
+ lock.get(NFC.SETTING_NFC_DEBUG, this.nfc);
+
+ Services.obs.addObserver(this, NFC.TOPIC_MOZSETTINGS_CHANGED, false);
Services.obs.addObserver(this, NFC.TOPIC_XPCOM_SHUTDOWN, false);
this._registerMessageListeners();
},
_shutdown: function _shutdown() {
this.nfc.shutdown();
this.nfc = null;
+ Services.obs.removeObserver(this, NFC.TOPIC_MOZSETTINGS_CHANGED);
Services.obs.removeObserver(this, NFC.TOPIC_XPCOM_SHUTDOWN);
this._unregisterMessageListeners();
},
_registerMessageListeners: function _registerMessageListeners() {
ppmm.addMessageListener("child-process-shutdown", this);
for (let message of NFC_IPC_ADD_EVENT_TARGET_MSG_NAMES) {
@@ -330,16 +342,24 @@ XPCOMUtils.defineLazyGetter(this, "gMess
},
/**
* nsIObserver interface methods.
*/
observe: function observe(subject, topic, data) {
switch (topic) {
+ case NFC.TOPIC_MOZSETTINGS_CHANGED:
+ if ("wrappedJSObject" in subject) {
+ subject = subject.wrappedJSObject;
+ }
+ if (subject) {
+ this.nfc.handle(subject.key, subject.value);
+ }
+ break;
case NFC.TOPIC_XPCOM_SHUTDOWN:
this._shutdown();
break;
}
},
};
});
@@ -645,16 +665,28 @@ Nfc.prototype = {
Object.keys(this.targetsByRequestId).forEach((requestId) => {
if (this.targetsByRequestId[requestId] === target) {
delete this.targetsByRequestId[requestId];
}
});
},
/**
+ * nsISettingsServiceCallback
+ */
+ handle: function handle(name, result) {
+ switch (name) {
+ case NFC.SETTING_NFC_DEBUG:
+ DEBUG = result;
+ updateDebug();
+ break;
+ }
+ },
+
+ /**
* nsIObserver interface methods.
*/
observe: function(subject, topic, data) {
if (topic != "profile-after-change") {
debug("Should receive 'profile-after-change' only, received " + topic);
}
},
--- a/dom/nfc/gonk/nfc_consts.js
+++ b/dom/nfc/gonk/nfc_consts.js
@@ -100,15 +100,18 @@ this.NFC_ERROR_MSG[this.NFC_GECKO_ERROR_
this.NFC_ERROR_MSG[this.NFC_GECKO_ERROR_SEND_FILE_FAILED] = "NfcSendFileFailed";
// NFC powerlevels must match config PDUs.
this.NFC_POWER_LEVEL_UNKNOWN = -1;
this.NFC_POWER_LEVEL_DISABLED = 0;
this.NFC_POWER_LEVEL_LOW = 1;
this.NFC_POWER_LEVEL_ENABLED = 2;
+this.TOPIC_MOZSETTINGS_CHANGED = "mozsettings-changed";
this.TOPIC_XPCOM_SHUTDOWN = "xpcom-shutdown";
+this.SETTING_NFC_DEBUG = "nfc.debugging.enabled";
+
this.NFC_PEER_EVENT_READY = 0x01;
this.NFC_PEER_EVENT_LOST = 0x02;
// Allow this file to be imported via Components.utils.import().
this.EXPORTED_SYMBOLS = Object.keys(this);
--- a/dom/nfc/nsINfcContentHelper.idl
+++ b/dom/nfc/nsINfcContentHelper.idl
@@ -22,22 +22,24 @@ interface nsINfcDOMEventTarget : nsISupp
* Callback function used to notify peerlost.
*
* @param sessionToken
* SessionToken received from Chrome process
*/
void notifyPeerLost(in DOMString sessionToken);
};
-[scriptable, uuid(d3f1bdc1-048f-44a8-abe2-bc386edce40b)]
+[scriptable, uuid(cb9c934d-a7fa-422b-bcc1-4ac39741e6ec)]
interface nsINfcContentHelper : nsISupports
{
const long NFC_EVENT_PEER_READY = 0x01;
const long NFC_EVENT_PEER_LOST = 0x02;
+ void init(in nsIDOMWindow window);
+
boolean checkSessionToken(in DOMString sessionToken);
nsIDOMDOMRequest readNDEF(in nsIDOMWindow window, in DOMString sessionToken);
nsIDOMDOMRequest writeNDEF(in nsIDOMWindow window, in nsIVariant records, in DOMString sessionToken);
nsIDOMDOMRequest makeReadOnlyNDEF(in nsIDOMWindow window, in DOMString sessionToken);
nsIDOMDOMRequest connect(in nsIDOMWindow window, in unsigned long techType, in DOMString sessionToken);
nsIDOMDOMRequest close(in nsIDOMWindow window, in DOMString sessionToken);
--- a/dom/nfc/nsNfc.js
+++ b/dom/nfc/nsNfc.js
@@ -143,16 +143,19 @@ function mozNfc() {
mozNfc.prototype = {
_nfcContentHelper: null,
_window: null,
nfcObject: null,
init: function init(aWindow) {
debug("mozNfc init called");
this._window = aWindow;
+ if (this._nfcContentHelper) {
+ this._nfcContentHelper.init(aWindow);
+ }
},
// Only apps which have nfc-manager permission can call the following interfaces
// 'checkP2PRegistration' , 'notifyUserAcceptedP2P' , 'notifySendFileStatus',
// 'startPoll', 'stopPoll', and 'powerOff'.
checkP2PRegistration: function checkP2PRegistration(manifestUrl) {
// Get the AppID and pass it to ContentHelper
let appID = appsService.getAppLocalIdByManifestURL(manifestUrl);
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -83,30 +83,27 @@
#include "TiledLayerBuffer.h" // For TILEDLAYERBUFFER_TILE_SIZE
#include "ClientLayerManager.h"
#include "nsRefreshDriver.h"
#include "nsIContentViewer.h"
#include "LayersLogging.h"
#include "mozilla/Preferences.h"
#include "nsFrameSelection.h"
#include "FrameLayerBuilder.h"
+#include "mozilla/layers/AsyncPanZoomController.h"
#ifdef MOZ_XUL
#include "nsXULPopupManager.h"
#endif
#include "GeckoProfiler.h"
#include "nsAnimationManager.h"
#include "nsTransitionManager.h"
#include "RestyleManager.h"
-// Additional includes used on B2G by code in GetOrMaybeCreateDisplayPort().
-#ifdef MOZ_WIDGET_GONK
-#include "mozilla/layers/AsyncPanZoomController.h"
-#endif
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::image;
using namespace mozilla::layers;
using namespace mozilla::layout;
using namespace mozilla::gfx;
@@ -2729,19 +2726,16 @@ nsLayoutUtils::GetFramesForArea(nsIFrame
#endif
nsDisplayItem::HitTestState hitTestState;
list.HitTest(&builder, aRect, &hitTestState, &aOutFrames);
list.DeleteAll();
return NS_OK;
}
-// This function is only used on B2G, and some compilers complain about
-// unused static functions, so we need to #ifdef it.
-#ifdef MOZ_WIDGET_GONK
// aScrollFrame and aScrollFrameAsScrollable must be non-nullptr
static FrameMetrics
CalculateFrameMetricsForDisplayPort(nsIFrame* aScrollFrame,
nsIScrollableFrame* aScrollFrameAsScrollable) {
// Calculate the metrics necessary for calculating the displayport.
// This code has a lot in common with the code in ComputeFrameMetrics();
// we may want to refactor this at some point.
FrameMetrics metrics;
@@ -2779,17 +2773,16 @@ CalculateFrameMetricsForDisplayPort(nsIF
metrics.SetScrollOffset(CSSPoint::FromAppUnits(
aScrollFrameAsScrollable->GetScrollPosition()));
metrics.mScrollableRect = CSSRect::FromAppUnits(
nsLayoutUtils::CalculateScrollableRectForFrame(aScrollFrameAsScrollable, nullptr));
return metrics;
}
-#endif
bool
nsLayoutUtils::GetOrMaybeCreateDisplayPort(nsDisplayListBuilder& aBuilder,
nsIFrame* aScrollFrame,
nsRect aDisplayPortBase,
nsRect* aOutDisplayport) {
nsIContent* content = aScrollFrame->GetContent();
nsIScrollableFrame* scrollableFrame = do_QueryFrame(aScrollFrame);
@@ -2799,18 +2792,17 @@ nsLayoutUtils::GetOrMaybeCreateDisplayPo
// Set the base rect. Note that this will not influence 'haveDisplayPort',
// which is based on either the whole rect or margins being set, but it
// will affect what is returned in 'aOutDisplayPort' if margins are set.
SetDisplayPortBase(content, aDisplayPortBase);
bool haveDisplayPort = GetDisplayPort(content, aOutDisplayport);
-#ifdef MOZ_WIDGET_GONK
- // On B2G, we perform an optimization where we ensure that at least one
+ // We perform an optimization where we ensure that at least one
// async-scrollable frame (i.e. one that WantsAsyncScroll()) has a displayport.
// If that's not the case yet, and we are async-scrollable, we will get a
// displayport.
// Note: we only do this in processes where we do subframe scrolling to
// begin with (i.e., not in the parent process on B2G).
if (aBuilder.IsPaintingToWindow() && WantSubAPZC() &&
!aBuilder.HaveScrollableDisplayPort() &&
scrollableFrame->WantAsyncScroll()) {
@@ -2829,17 +2821,16 @@ nsLayoutUtils::GetOrMaybeCreateDisplayPo
alignment.height, 0, nsLayoutUtils::RepaintMode::DoNotRepaint);
haveDisplayPort = GetDisplayPort(content, aOutDisplayport);
NS_ASSERTION(haveDisplayPort, "should have a displayport after having just set it");
}
// Record that the we now have a scrollable display port.
aBuilder.SetHaveScrollableDisplayPort();
}
-#endif
return haveDisplayPort;
}
nsresult
nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFrame,
const nsRegion& aDirtyRegion, nscolor aBackstop,
uint32_t aFlags)
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -292,70 +292,20 @@ pref("browser.mirroring.enabled.roku", t
// Enable sparse localization by setting a few package locale overrides
pref("chrome.override_package.global", "browser");
pref("chrome.override_package.mozapps", "browser");
pref("chrome.override_package.passwordmgr", "browser");
// enable xul error pages
pref("browser.xul.error_pages.enabled", true);
-// Specify emptyRestriction = 0 so that bookmarks appear in the list by default
-pref("browser.urlbar.default.behavior", 0);
-pref("browser.urlbar.default.behavior.emptyRestriction", 0);
-
-// Let the faviconservice know that we display favicons as 32x32px so that it
-// uses the right size when optimizing favicons
-pref("places.favicons.optimizeToDimension", 32);
-
-// various and sundry awesomebar prefs (should remove/re-evaluate
-// these once bug 447900 is fixed)
-pref("browser.urlbar.clickSelectsAll", true);
-pref("browser.urlbar.doubleClickSelectsAll", true);
-pref("browser.urlbar.autoFill", false);
-pref("browser.urlbar.matchOnlyTyped", false);
-pref("browser.urlbar.matchBehavior", 1);
-pref("browser.urlbar.filter.javascript", true);
-pref("browser.urlbar.maxRichResults", 24); // increased so we see more results when portrait
-pref("browser.urlbar.search.chunkSize", 1000);
-pref("browser.urlbar.search.timeout", 100);
-pref("browser.urlbar.restrict.history", "^");
-pref("browser.urlbar.restrict.bookmark", "*");
-pref("browser.urlbar.restrict.tag", "+");
-pref("browser.urlbar.match.title", "#");
-pref("browser.urlbar.match.url", "@");
-pref("browser.urlbar.autocomplete.search_threshold", 5);
pref("browser.history.grouping", "day");
pref("browser.history.showSessions", false);
pref("browser.sessionhistory.max_entries", 50);
pref("browser.history_expire_sites", 40000);
-pref("browser.places.migratePostDataAnnotations", true);
-pref("browser.places.updateRecentTagsUri", true);
-pref("places.frecency.numVisits", 10);
-pref("places.frecency.numCalcOnIdle", 50);
-pref("places.frecency.numCalcOnMigrate", 50);
-pref("places.frecency.updateIdleTime", 60000);
-pref("places.frecency.firstBucketCutoff", 4);
-pref("places.frecency.secondBucketCutoff", 14);
-pref("places.frecency.thirdBucketCutoff", 31);
-pref("places.frecency.fourthBucketCutoff", 90);
-pref("places.frecency.firstBucketWeight", 100);
-pref("places.frecency.secondBucketWeight", 70);
-pref("places.frecency.thirdBucketWeight", 50);
-pref("places.frecency.fourthBucketWeight", 30);
-pref("places.frecency.defaultBucketWeight", 10);
-pref("places.frecency.embedVisitBonus", 0);
-pref("places.frecency.linkVisitBonus", 100);
-pref("places.frecency.typedVisitBonus", 2000);
-pref("places.frecency.bookmarkVisitBonus", 150);
-pref("places.frecency.downloadVisitBonus", 0);
-pref("places.frecency.permRedirectVisitBonus", 0);
-pref("places.frecency.tempRedirectVisitBonus", 0);
-pref("places.frecency.defaultVisitBonus", 0);
-pref("places.frecency.unvisitedBookmarkBonus", 140);
-pref("places.frecency.unvisitedTypedBonus", 200);
// disable color management
pref("gfx.color_management.mode", 0);
// 0=fixed margin, 1=velocity bias, 2=dynamic resolution, 3=no margins, 4=prediction bias
pref("gfx.displayport.strategy", 1);
// all of the following displayport strategy prefs will be divided by 1000
--- a/mobile/android/base/BrowserLocaleManager.java
+++ b/mobile/android/base/BrowserLocaleManager.java
@@ -244,16 +244,47 @@ public class BrowserLocaleManager implem
final Locale changed = configuration.locale;
if (changed.equals(currentActivityLocale)) {
return null;
}
return changed;
}
+ /**
+ * Gecko needs to know the OS locale to compute a useful Accept-Language
+ * header. If it changed since last time, send a message to Gecko and
+ * persist the new value. If unchanged, returns immediately.
+ *
+ * @param prefs the SharedPreferences instance to use. Cannot be null.
+ * @param osLocale the new locale instance. Safe if null.
+ */
+ public static void storeAndNotifyOSLocale(final SharedPreferences prefs,
+ final Locale osLocale) {
+ if (osLocale == null) {
+ return;
+ }
+
+ final String lastOSLocale = prefs.getString("osLocale", null);
+ final String osLocaleString = osLocale.toString();
+
+ if (osLocaleString.equals(lastOSLocale)) {
+ return;
+ }
+
+ // Store the Java-native form.
+ prefs.edit().putString("osLocale", osLocaleString).apply();
+
+ // The value we send to Gecko should be a language tag, not
+ // a Java locale string.
+ final String osLanguageTag = BrowserLocaleManager.getLanguageTag(osLocale);
+ final GeckoEvent localeOSEvent = GeckoEvent.createBroadcastEvent("Locale:OS", osLanguageTag);
+ GeckoAppShell.sendEventToGecko(localeOSEvent);
+ }
+
@Override
public String getAndApplyPersistedLocale(Context context) {
initialize(context);
final long t1 = android.os.SystemClock.uptimeMillis();
final String localeCode = getPersistedLocale(context);
if (localeCode == null) {
return null;
@@ -325,16 +356,19 @@ public class BrowserLocaleManager implem
config.locale = locale;
res.updateConfiguration(config, null);
}
private SharedPreferences getSharedPreferences(Context context) {
return GeckoSharedPrefs.forApp(context);
}
+ /**
+ * @return the persisted locale in Java format: "en_US".
+ */
private String getPersistedLocale(Context context) {
final SharedPreferences settings = getSharedPreferences(context);
final String locale = settings.getString(PREF_LOCALE, "");
if ("".equals(locale)) {
return null;
}
return locale;
@@ -359,29 +393,35 @@ public class BrowserLocaleManager implem
}
/**
* Updates the Java locale and the Android configuration.
*
* Returns the persisted locale if it differed.
*
* Does not notify Gecko.
+ *
+ * @param localeCode a locale string in Java format: "en_US".
+ * @return if it differed, a locale string in Java format: "en_US".
*/
private String updateLocale(Context context, String localeCode) {
// Fast path.
final Locale defaultLocale = Locale.getDefault();
if (defaultLocale.toString().equals(localeCode)) {
return null;
}
final Locale locale = parseLocaleCode(localeCode);
return updateLocale(context, locale);
}
+ /**
+ * @return the Java locale string: e.g., "en_US".
+ */
private String updateLocale(Context context, final Locale locale) {
// Fast path.
if (Locale.getDefault().equals(locale)) {
return null;
}
Locale.setDefault(locale);
currentLocale = locale;
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -1208,16 +1208,19 @@ public abstract class GeckoApp
Log.e(LOGTAG, "Exception starting favicon cache. Corrupt resources?", e);
}
// Did the OS locale change while we were backgrounded? If so,
// we need to die so that Gecko will re-init add-ons that touch
// the UI.
// This is using a sledgehammer to crack a nut, but it'll do for
// now.
+ // Our OS locale pref will be detected as invalid after the
+ // restart, and will be propagated to Gecko accordingly, so there's
+ // no need to touch that here.
if (BrowserLocaleManager.getInstance().systemLocaleDidChange()) {
Log.i(LOGTAG, "System locale changed. Restarting.");
doRestart();
GeckoAppShell.systemExit();
return;
}
if (GeckoThread.isCreated()) {
@@ -1319,38 +1322,46 @@ public abstract class GeckoApp
editor.apply();
// The lifecycle of mHealthRecorder is "shortly after onCreate"
// through "onDestroy" -- essentially the same as the lifecycle
// of the activity itself.
final String profilePath = getProfile().getDir().getAbsolutePath();
final EventDispatcher dispatcher = EventDispatcher.getInstance();
- final String osLocale = Locale.getDefault().toString();
- String appLocale = localeManager.getAndApplyPersistedLocale(GeckoApp.this);
- Log.d(LOGTAG, "OS locale is " + osLocale + ", app locale is " + appLocale);
-
- if (appLocale == null) {
- appLocale = osLocale;
+ // This is the locale prior to fixing it up.
+ final Locale osLocale = Locale.getDefault();
+
+ // Both of these are Java-format locale strings: "en_US", not "en-US".
+ final String osLocaleString = osLocale.toString();
+ String appLocaleString = localeManager.getAndApplyPersistedLocale(GeckoApp.this);
+ Log.d(LOGTAG, "OS locale is " + osLocaleString + ", app locale is " + appLocaleString);
+
+ if (appLocaleString == null) {
+ appLocaleString = osLocaleString;
}
mHealthRecorder = GeckoApp.this.createHealthRecorder(GeckoApp.this,
profilePath,
dispatcher,
- osLocale,
- appLocale,
+ osLocaleString,
+ appLocaleString,
previousSession);
- final String uiLocale = appLocale;
+ final String uiLocale = appLocaleString;
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
GeckoApp.this.onLocaleReady(uiLocale);
}
});
+
+ // We use per-profile prefs here, because we're tracking against
+ // a Gecko pref. The same applies to the locale switcher!
+ BrowserLocaleManager.storeAndNotifyOSLocale(GeckoSharedPrefs.forProfile(GeckoApp.this), osLocale);
}
});
GeckoAppShell.setNotificationClient(makeNotificationClient());
IntentHelper.init(this);
}
/**
@@ -1848,38 +1859,27 @@ public abstract class GeckoApp
// Check if launched from data reporting notification.
Intent settingsIntent = new Intent(GeckoApp.this, GeckoPreferences.class);
// Copy extras.
settingsIntent.putExtras(intent);
startActivity(settingsIntent);
}
}
- /*
+ /**
* Handles getting a URI from an intent in a way that is backwards-
* compatible with our previous implementations.
*/
protected String getURIFromIntent(Intent intent) {
final String action = intent.getAction();
if (ACTION_ALERT_CALLBACK.equals(action) || NotificationHelper.HELPER_BROADCAST_ACTION.equals(action)) {
return null;
}
- String uri = intent.getDataString();
- if (uri != null) {
- return uri;
- }
-
- if ((action != null && action.startsWith(ACTION_WEBAPP_PREFIX)) || ACTION_HOMESCREEN_SHORTCUT.equals(action)) {
- uri = StringUtils.getStringExtra(intent, "args");
- if (uri != null && uri.startsWith("--url=")) {
- uri.replace("--url=", "");
- }
- }
- return uri;
+ return intent.getDataString();
}
protected int getOrientation() {
return GeckoScreenOrientation.getInstance().getAndroidOrientation();
}
@Override
public void onResume()
--- a/mobile/android/base/gfx/GLController.java
+++ b/mobile/android/base/gfx/GLController.java
@@ -196,20 +196,16 @@ public class GLController {
// is blocked on the gecko sync event in updateCompositor() above
mCompositorCreated = true;
}
public boolean isServerSurfaceValid() {
return mServerSurfaceValid;
}
- public boolean isCompositorCreated() {
- return mCompositorCreated;
- }
-
private void initEGL() {
if (mEGL != null) {
return;
}
// This join() should not be necessary, but makes this code a bit easier to think about.
// The EGLPreloadingThread should long be done by now, and even if it's not,
// it shouldn't be a problem to be initalizing EGL from two different threads.
--- a/mobile/android/base/gfx/LayerView.java
+++ b/mobile/android/base/gfx/LayerView.java
@@ -471,23 +471,18 @@ public class LayerView extends FrameLayo
* Gecko is also sent the new window size, and this will likely cause an
* extra draw a few frames later, after it's re-rendered and caught up.
*
* In the case that there is no valid GL surface (for example, when
* resuming, or when coming back from the awesomescreen), or we're using a
* TextureView instead of a SurfaceView, the first phase is skipped.
*/
private void onSizeChanged(int width, int height) {
- if (!mGLController.isCompositorCreated()) {
- return;
- }
-
- surfaceChanged(width, height);
-
- if (mSurfaceView == null) {
+ if (!mGLController.isServerSurfaceValid() || mSurfaceView == null) {
+ surfaceChanged(width, height);
return;
}
if (mListener != null) {
mListener.sizeChanged(width, height);
}
if (mOverscroll != null) {
--- a/mobile/android/base/tests/BaseTest.java
+++ b/mobile/android/base/tests/BaseTest.java
@@ -77,16 +77,26 @@ abstract class BaseTest extends BaseRobo
protected String mRawBaseUrl;
protected String mProfile;
public Device mDevice;
protected DatabaseHelper mDatabaseHelper;
protected int mScreenMidWidth;
protected int mScreenMidHeight;
private final HashSet<Integer> mKnownTabIDs = new HashSet<Integer>();
+ protected void blockForDelayedStartup() {
+ try {
+ Actions.EventExpecter delayedStartupExpector = mActions.expectGeckoEvent("Gecko:DelayedStartup");
+ delayedStartupExpector.blockForEvent(GECKO_READY_WAIT_MS, true);
+ delayedStartupExpector.unregisterListener();
+ } catch (Exception e) {
+ mAsserter.dumpLog("Exception in blockForDelayedStartup", e);
+ }
+ }
+
protected void blockForGeckoReady() {
try {
Actions.EventExpecter geckoReadyExpector = mActions.expectGeckoEvent("Gecko:Ready");
if (!GeckoThread.checkLaunchState(LaunchState.GeckoRunning)) {
geckoReadyExpector.blockForEvent(GECKO_READY_WAIT_MS, true);
}
geckoReadyExpector.unregisterListener();
} catch (Exception e) {
@@ -122,24 +132,27 @@ abstract class BaseTest extends BaseRobo
mDevice = new Device();
mDatabaseHelper = new DatabaseHelper(mActivity, mAsserter);
// Ensure Robocop tests have access to network, and are run with Display powered on.
throwIfHttpGetFails();
throwIfScreenNotOn();
}
- protected void initializeProfile() {
- final GeckoProfile profile;
+ protected GeckoProfile getTestProfile() {
if (mProfile.startsWith("/")) {
- profile = GeckoProfile.get(getActivity(), "default", mProfile);
- } else {
- profile = GeckoProfile.get(getActivity(), mProfile);
+ return GeckoProfile.get(getActivity(), "default", mProfile);
}
+ return GeckoProfile.get(getActivity(), mProfile);
+ }
+
+ protected void initializeProfile() {
+ final GeckoProfile profile = getTestProfile();
+
// In Robocop tests, we typically don't get initialized correctly, because
// GeckoProfile doesn't create the profile directory.
profile.enqueueInitialization(profile.getDir());
}
@Override
protected void runTest() throws Throwable {
try {
--- a/mobile/android/base/tests/JavascriptTest.java
+++ b/mobile/android/base/tests/JavascriptTest.java
@@ -16,21 +16,24 @@ public class JavascriptTest extends Base
public JavascriptTest(String javascriptUrl) {
super();
this.javascriptUrl = javascriptUrl;
}
public void testJavascript() throws Exception {
blockForGeckoReady();
+ doTestJavascript();
+ }
+
+ protected void doTestJavascript() throws Exception {
// We want to be waiting for Robocop messages before the page is loaded
// because the test harness runs each test in the suite (and possibly
// completes testing) before the page load event is fired.
- final Actions.EventExpecter expecter =
- mActions.expectGeckoEvent(EVENT_TYPE);
+ final Actions.EventExpecter expecter = mActions.expectGeckoEvent(EVENT_TYPE);
mAsserter.dumpLog("Registered listener for " + EVENT_TYPE);
final String url = getAbsoluteUrl(StringHelper.getHarnessUrlForJavascript(javascriptUrl));
mAsserter.dumpLog("Loading JavaScript test from " + url);
loadUrl(url);
final JavascriptMessageParser testMessageParser =
new JavascriptMessageParser(mAsserter, false);
--- a/mobile/android/base/tests/robocop.ini
+++ b/mobile/android/base/tests/robocop.ini
@@ -99,16 +99,17 @@ skip-if = android_version == "10"
[testAccounts]
[testAndroidLog]
[testBrowserDiscovery]
[testDebuggerServer]
[testDeviceSearchEngine]
[testJNI]
# [testMozPay] # see bug 945675
[testOrderedBroadcast]
+[testOSLocale]
[testResourceSubstitutions]
[testRestrictedProfiles]
[testSharedPreferences]
[testSimpleDiscovery]
[testUITelemetry]
[testVideoDiscovery]
# Used for Talos, please don't use in mochitest
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/tests/testOSLocale.java
@@ -0,0 +1,134 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.tests;
+
+import java.util.Locale;
+
+import org.mozilla.gecko.BrowserLocaleManager;
+import org.mozilla.gecko.GeckoSharedPrefs;
+import org.mozilla.gecko.PrefsHelper;
+
+import android.content.SharedPreferences;
+
+
+public class testOSLocale extends BaseTest {
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ // Clear per-profile SharedPreferences as a workaround for Bug 1069687.
+ // We're trying to exercise logic that only applies on first onCreate!
+ // We can't rely on this occurring prior to the first broadcast, though,
+ // so see the main test method for more logic.
+ final String profileName = getTestProfile().getName();
+ mAsserter.info("Setup", "Clearing pref in " + profileName + ".");
+ GeckoSharedPrefs.forProfileName(getActivity(), profileName)
+ .edit()
+ .remove("osLocale")
+ .apply();
+ }
+
+ public static class PrefState extends PrefsHelper.PrefHandlerBase {
+ private static final String PREF_LOCALE_OS = "intl.locale.os";
+ private static final String PREF_ACCEPT_LANG = "intl.accept_languages";
+
+ private static final String[] TO_FETCH = {PREF_LOCALE_OS, PREF_ACCEPT_LANG};
+
+ public volatile String osLocale;
+ public volatile String acceptLanguages;
+
+ private final Object waiter = new Object();
+
+ public void fetch() throws InterruptedException {
+ synchronized (waiter) {
+ PrefsHelper.getPrefs(TO_FETCH, this);
+ waiter.wait(MAX_WAIT_MS);
+ }
+ }
+
+ @Override
+ public void prefValue(String pref, String value) {
+ switch (pref) {
+ case PREF_LOCALE_OS:
+ osLocale = value;
+ return;
+ case PREF_ACCEPT_LANG:
+ acceptLanguages = value;
+ return;
+ }
+ }
+
+ @Override
+ public void finish() {
+ synchronized (waiter) {
+ waiter.notify();
+ }
+ }
+ }
+
+ public void testOSLocale() throws Exception {
+ blockForDelayedStartup();
+
+ final SharedPreferences prefs = GeckoSharedPrefs.forProfile(getActivity());
+ final PrefState state = new PrefState();
+
+ state.fetch();
+
+ // We don't know at this point whether we were run against a dirty profile or not.
+ //
+ // If we cleared the pref above prior to BrowserApp's delayed init, or our Gecko
+ // profile has been used before, then we're already going to be set up for en-US.
+ //
+ // If we cleared the pref after the initial broadcast, and our Android-side profile
+ // has been used before but the Gecko profile is clean, then the Gecko prefs won't
+ // have been set.
+ //
+ // Instead, we always send a new locale code, and see what we get.
+ final Locale fr = BrowserLocaleManager.parseLocaleCode("fr");
+ BrowserLocaleManager.storeAndNotifyOSLocale(prefs, fr);
+
+ state.fetch();
+
+ mAsserter.is(state.osLocale, "fr", "We're in fr.");
+
+ // Now we can see what the expected Accept-Languages header should be.
+ // The OS locale is 'fr', so we have our app locale (en-US),
+ // the OS locale (fr), then any remaining fallbacks from intl.properties.
+ mAsserter.is(state.acceptLanguages, "en-us,fr,en", "We have the default en-US+fr Accept-Languages.");
+
+ // Now set the app locale to be es-ES.
+ BrowserLocaleManager.getInstance().setSelectedLocale(getActivity(), "es-ES");
+
+ state.fetch();
+
+ mAsserter.is(state.osLocale, "fr", "We're still in fr.");
+
+ // The correct set here depends on whether the
+ // browser was built with multiple locales or not.
+ // This is exasperating, but hey.
+ final boolean isMultiLocaleBuild = false;
+
+ // This never changes.
+ final String SELECTED_LOCALES = "es-es,fr,";
+
+
+ // Expected, from es-ES's intl.properties:
+ final String EXPECTED = SELECTED_LOCALES +
+ (isMultiLocaleBuild ? "es,en-us,en" : // Expected, from es-ES's intl.properties.
+ "en-us,en"); // Expected, from en-US (the default).
+
+ mAsserter.is(state.acceptLanguages, EXPECTED, "We have the right es-ES+fr Accept-Languages for this build.");
+
+ // And back to en-US.
+ final Locale en_US = BrowserLocaleManager.parseLocaleCode("en-US");
+ BrowserLocaleManager.storeAndNotifyOSLocale(prefs, en_US);
+ BrowserLocaleManager.getInstance().resetToSystemLocale(getActivity());
+
+ state.fetch();
+
+ mAsserter.is(state.osLocale, "en-US", "We're in en-US.");
+ mAsserter.is(state.acceptLanguages, "en-us,en", "We have the default processed en-US Accept-Languages.");
+ }
+}
\ No newline at end of file
--- a/mobile/android/chrome/content/aboutFeedback.js
+++ b/mobile/android/chrome/content/aboutFeedback.js
@@ -62,17 +62,19 @@ function init() {
document.getElementById("open-play-store").addEventListener("click", openPlayStore, false);
document.forms[0].addEventListener("submit", sendFeedback, false);
for (let anchor of document.querySelectorAll(".no-thanks")) {
anchor.addEventListener("click", evt => window.close(), false);
}
let sumoLink = Services.urlFormatter.formatURLPref("app.support.baseURL");
- document.getElementById("sumo-link").href = sumoLink;
+ document.getElementById("help-section").addEventListener("click", function() {
+ window.open(sumoLink, "_blank");
+ }, false);
window.addEventListener("popstate", function (aEvent) {
updateActiveSection(aEvent.state ? aEvent.state.section : "intro")
}, false);
// Fill "Last visited site" input with most recent history entry URL.
Services.obs.addObserver(function observer(aSubject, aTopic, aData) {
document.getElementById("last-url").value = aData;
--- a/mobile/android/chrome/content/aboutFeedback.xhtml
+++ b/mobile/android/chrome/content/aboutFeedback.xhtml
@@ -77,14 +77,14 @@
<div class="message">&sad.thanksMessageTop;</div>
<div class="message">&sad.thanksMessageBottom;</div>
</div>
</section>
<footer>
<div id="help-section">
<img id="sumo-icon" />
- <span>&support.pre3;<a id="sumo-link">&support.link2;</a>&support.post3;</span>
+ <span>&support.pre3;<span class="link">&support.link2;</span>&support.post3;</span>
</div>
</footer>
<script type="application/javascript;version=1.8" src="chrome://browser/content/aboutFeedback.js"></script>
</body>
</html>
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -337,16 +337,17 @@ var BrowserApp = {
} catch(ex) { console.log(ex); }
}, false);
BrowserEventHandler.init();
ViewportHandler.init();
Services.androidBridge.browserApp = this;
+ Services.obs.addObserver(this, "Locale:OS", false);
Services.obs.addObserver(this, "Locale:Changed", false);
Services.obs.addObserver(this, "Tab:Load", false);
Services.obs.addObserver(this, "Tab:Selected", false);
Services.obs.addObserver(this, "Tab:Closed", false);
Services.obs.addObserver(this, "Session:Back", false);
Services.obs.addObserver(this, "Session:ShowHistory", false);
Services.obs.addObserver(this, "Session:Forward", false);
Services.obs.addObserver(this, "Session:Reload", false);
@@ -1753,16 +1754,44 @@ var BrowserApp = {
case "Webapps:Load":
this._loadWebapp(JSON.parse(aData));
break;
case "Webapps:AutoUninstall":
WebappManager.autoUninstall(JSON.parse(aData));
break;
+ case "Locale:OS":
+ // We know the system locale. We use this for generating Accept-Language headers.
+ console.log("Locale:OS: " + aData);
+ let currentOSLocale;
+ try {
+ currentOSLocale = Services.prefs.getCharPref("intl.locale.os");
+ } catch (e) {
+ }
+ if (currentOSLocale == aData) {
+ break;
+ }
+
+ console.log("New OS locale.");
+
+ // Ensure that this choice is immediately persisted, because
+ // Gecko won't be told again if it forgets.
+ Services.prefs.setCharPref("intl.locale.os", aData);
+ Services.prefs.savePrefFile(null);
+
+ let appLocale;
+ try {
+ appLocale = Services.prefs.getCharPref("general.useragent.locale");
+ } catch (e) {
+ }
+
+ this.computeAcceptLanguages(aData, appLocale);
+ break;
+
case "Locale:Changed":
if (aData) {
// The value provided to Locale:Changed should be a BCP47 language tag
// understood by Gecko -- for example, "es-ES" or "de".
console.log("Locale:Changed: " + aData);
Services.prefs.setCharPref("general.useragent.locale", aData);
} else {
// Resetting.
@@ -1774,25 +1803,92 @@ var BrowserApp = {
// Ensure that this choice is immediately persisted, because
// Gecko won't be told again if it forgets.
Services.prefs.savePrefFile(null);
// Blow away the string cache so that future lookups get the
// correct locale.
Services.strings.flushBundles();
+
+ // Make sure we use the right Accept-Language header.
+ let osLocale;
+ try {
+ // This should never not be set at this point, but better safe than sorry.
+ osLocale = Services.prefs.getCharPref("intl.locale.os");
+ } catch (e) {
+ }
+
+ this.computeAcceptLanguages(osLocale, aData);
break;
default:
dump('BrowserApp.observe: unexpected topic "' + aTopic + '"\n');
break;
}
},
+ /**
+ * Set intl.accept_languages accordingly.
+ *
+ * After Bug 881510 this will also accept a real Accept-Language choice as
+ * input; all Accept-Language logic lives here.
+ *
+ * osLocale should never be null, but this method is safe regardless.
+ * appLocale may explicitly be null.
+ */
+ computeAcceptLanguages(osLocale, appLocale) {
+ let defaultBranch = Services.prefs.getDefaultBranch(null);
+ let defaultAccept = defaultBranch.getComplexValue("intl.accept_languages", Ci.nsIPrefLocalizedString).data;
+ console.log("Default intl.accept_languages = " + defaultAccept);
+
+ // A guard for potential breakage. Bug 438031.
+ // This should not be necessary, because we're reading from the default branch,
+ // but better safe than sorry.
+ if (defaultAccept && defaultAccept.startsWith("chrome://")) {
+ defaultAccept = null;
+ } else {
+ // Ensure lowercase everywhere so we can compare.
+ defaultAccept = defaultAccept.toLowerCase();
+ }
+
+ if (appLocale) {
+ appLocale = appLocale.toLowerCase();
+ }
+
+ if (osLocale) {
+ osLocale = osLocale.toLowerCase();
+ }
+
+ // Eliminate values if they're present in the default.
+ let chosen;
+ if (defaultAccept) {
+ // intl.accept_languages is a comma-separated list, with no q-value params. Those
+ // are added when the header is generated.
+ chosen = defaultAccept.split(",")
+ .map(String.trim)
+ .filter((x) => (x != appLocale && x != osLocale));
+ } else {
+ chosen = [];
+ }
+
+ if (osLocale) {
+ chosen.unshift(osLocale);
+ }
+
+ if (appLocale && appLocale != osLocale) {
+ chosen.unshift(appLocale);
+ }
+
+ let result = chosen.join(",");
+ console.log("Setting intl.accept_languages to " + result);
+ Services.prefs.setCharPref("intl.accept_languages", result);
+ },
+
get defaultBrowserWidth() {
delete this.defaultBrowserWidth;
let width = Services.prefs.getIntPref("browser.viewport.desktopWidth");
return this.defaultBrowserWidth = width;
},
get layersTileWidth() {
delete this.layersTileWidth;
--- a/mobile/android/themes/core/aboutFeedback.css
+++ b/mobile/android/themes/core/aboutFeedback.css
@@ -185,18 +185,19 @@ footer {
font-size: 16px;
width: 100%;
background-color: #0092DB;
border-radius: 4px;
border-width: 0;
color: #fff;
}
-#sumo-link {
+.link {
color: #222;
+ text-decoration: underline;
}
@media screen and (max-height: 400px) {
body {
padding-top: 40px;
}
.bottom-links {
--- a/toolkit/components/passwordmgr/test/test_input_events.html
+++ b/toolkit/components/passwordmgr/test/test_input_events.html
@@ -12,62 +12,82 @@ Login Manager test: input events should
<script>
commonInit();
SimpleTest.waitForExplicitFinish();
/** Test for Login Manager: form fill, should get input events. **/
var usernameInputFired = false;
var passwordInputFired = false;
+var usernameChangeFired = false;
+var passwordChangeFired = false;
var onloadFired = false;
function onNewEvent(e) {
info("Got " + e.type + " event.");
if (e.type == "load") {
onloadFired = true;
- } else if (e.target.name == "uname") {
- ise(e.target.value, "testuser", "Should get 'testuser' as username");
- ok(!usernameInputFired, "Should not have gotten an input event for the username field yet.");
- usernameInputFired = true;
- } else if (e.target.name == "pword") {
- ise(e.target.value, "testpass", "Should get 'testpass' as password");
- ok(!passwordInputFired, "Should not have gotten an input event for the password field yet.");
- passwordInputFired = true;
+ } else if (e.type == "input") {
+ if (e.target.name == "uname") {
+ ise(e.target.value, "testuser", "Should get 'testuser' as username");
+ ok(!usernameInputFired, "Should not have gotten an input event for the username field yet.");
+ usernameInputFired = true;
+ } else if (e.target.name == "pword") {
+ ise(e.target.value, "testpass", "Should get 'testpass' as password");
+ ok(!passwordInputFired, "Should not have gotten an input event for the password field yet.");
+ passwordInputFired = true;
+ }
+ } else if (e.type == "change") {
+ if (e.target.name == "uname") {
+ ise(e.target.value, "testuser", "Should get 'testuser' as username");
+ ok(usernameInputFired, "Should get input event before change event for username field.");
+ ok(!usernameChangeFired, "Should not have gotten a change event for the username field yet.");
+ usernameChangeFired = true;
+ } else if (e.target.name == "pword") {
+ ise(e.target.value, "testpass", "Should get 'testpass' as password");
+ ok(passwordInputFired, "Should get input event before change event for password field.");
+ ok(!passwordChangeFired, "Should not have gotten a change event for the password field yet.");
+ passwordChangeFired = true;
+ }
}
- if (onloadFired && usernameInputFired && passwordInputFired) {
+ if (onloadFired && usernameInputFired && passwordInputFired && usernameChangeFired && passwordChangeFired) {
ok(true, "All events fired as expected, we're done.");
SimpleTest.finish();
}
}
SimpleTest.registerCleanupFunction(function cleanup() {
clearTimeout(timeout);
$_(1, "uname").removeAttribute("oninput");
$_(1, "pword").removeAttribute("oninput");
+ $_(1, "uname").removeAttribute("onchange");
+ $_(1, "pword").removeAttribute("onchange");
document.body.removeAttribute("onload");
});
var timeout = setTimeout(function() {
ok(usernameInputFired, "Username input event should have fired by now.");
ok(passwordInputFired, "Password input event should have fired by now.");
+ ok(usernameChangeFired, "Username change event should have fired by now.");
+ ok(passwordChangeFired, "Password change event should have fired by now.");
ok(onloadFired, "Window load event should have fired by now.");
ok(false, "Not all events fired yet.");
SimpleTest.finish();
}, 10000);
</script>
<p id="display"></p>
<div id="content" style="display: none">
<form id="form1" action="formtest.js">
<p>This is form 1.</p>
- <input type="text" name="uname" oninput="onNewEvent(event)">
- <input type="password" name="pword" oninput="onNewEvent(event)">
+ <input type="text" name="uname" oninput="onNewEvent(event)" onchange="onNewEvent(event)">
+ <input type="password" name="pword" oninput="onNewEvent(event)" onchange="onNewEvent(event)">
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
</div>
<pre id="test"></pre>
</body>
--- a/toolkit/components/places/PlacesUtils.jsm
+++ b/toolkit/components/places/PlacesUtils.jsm
@@ -203,45 +203,18 @@ this.PlacesUtils = {
nodeAncestors: function PU_nodeAncestors(aNode) {
let node = aNode.parent;
while (node) {
yield node;
node = node.parent;
}
},
- /**
- * Cache array of read-only item IDs.
- *
- * The first time this property is called:
- * - the cache is filled with all ids with the RO annotation
- * - an annotation observer is added
- * - a shutdown observer is added
- *
- * When the annotation observer detects annotations added or
- * removed that are the RO annotation name, it adds/removes
- * the ids from the cache.
- *
- * At shutdown, the annotation and shutdown observers are removed.
- */
- get _readOnly() {
- // Add annotations observer.
- this.annotations.addObserver(this, false);
- this.registerShutdownFunction(function () {
- this.annotations.removeObserver(this);
- });
-
- var readOnly = this.annotations.getItemsWithAnnotation(this.READ_ONLY_ANNO);
- this.__defineGetter__("_readOnly", function() readOnly);
- return this._readOnly;
- },
-
QueryInterface: XPCOMUtils.generateQI([
- Ci.nsIAnnotationObserver
- , Ci.nsIObserver
+ Ci.nsIObserver
, Ci.nsITransactionListener
]),
_shutdownFunctions: [],
registerShutdownFunction: function PU_registerShutdownFunction(aFunc)
{
// If this is the first registered function, add the shutdown observer.
if (this._shutdownFunctions.length == 0) {
@@ -270,34 +243,16 @@ this.PlacesUtils = {
while (this._bookmarksServiceObserversQueue.length > 0) {
let observerInfo = this._bookmarksServiceObserversQueue.shift();
this.bookmarks.addObserver(observerInfo.observer, observerInfo.weak);
}
break;
}
},
- //////////////////////////////////////////////////////////////////////////////
- //// nsIAnnotationObserver
-
- onItemAnnotationSet: function PU_onItemAnnotationSet(aItemId, aAnnotationName)
- {
- if (aAnnotationName == this.READ_ONLY_ANNO &&
- this._readOnly.indexOf(aItemId) == -1)
- this._readOnly.push(aItemId);
- },
-
- onItemAnnotationRemoved:
- function PU_onItemAnnotationRemoved(aItemId, aAnnotationName)
- {
- var index = this._readOnly.indexOf(aItemId);
- if (aAnnotationName == this.READ_ONLY_ANNO && index > -1)
- delete this._readOnly[index];
- },
-
onPageAnnotationSet: function() {},
onPageAnnotationRemoved: function() {},
//////////////////////////////////////////////////////////////////////////////
//// nsITransactionListener
didDo: function PU_didDo(aManager, aTransaction, aDoResult)
@@ -337,37 +292,16 @@ this.PlacesUtils = {
willUndo: function PU_willUndo() {},
willRedo: function PU_willRedo() {},
willBeginBatch: function PU_willBeginBatch() {},
willEndBatch: function PU_willEndBatch() {},
didEndBatch: function PU_didEndBatch() {},
willMerge: function PU_willMerge() {},
didMerge: function PU_didMerge() {},
-
- /**
- * Determines if a node is read only (children cannot be inserted, sometimes
- * they cannot be removed depending on the circumstance)
- * @param aNode
- * A result node
- * @returns true if the node is readonly, false otherwise
- */
- nodeIsReadOnly: function PU_nodeIsReadOnly(aNode) {
- let itemId = aNode.itemId;
- if (itemId != -1) {
- return this._readOnly.indexOf(itemId) != -1;
- }
-
- if (this.nodeIsQuery(aNode) &&
- asQuery(aNode).queryOptions.resultType !=
- Ci.nsINavHistoryQueryOptions.RESULTS_AS_TAG_CONTENTS)
- return aNode.childrenReadOnly;
- return false;
- },
-
/**
* Determines whether or not a ResultNode is a host container.
* @param aNode
* A result node
* @returns true if the node is a host container, false otherwise
*/
nodeIsHost: function PU_nodeIsHost(aNode) {
return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY &&
@@ -429,27 +363,16 @@ this.PlacesUtils = {
Ci.nsINavHistoryQueryOptions.RESULTS_AS_DATE_SITE_QUERY ||
resultType == Ci.nsINavHistoryQueryOptions.RESULTS_AS_DATE_QUERY ||
resultType == Ci.nsINavHistoryQueryOptions.RESULTS_AS_SITE_QUERY ||
this.nodeIsDay(aNode) ||
this.nodeIsHost(aNode));
},
/**
- * Determines whether or not a node is a readonly folder.
- * @param aNode
- * The node to test.
- * @returns true if the node is a readonly folder.
- */
- isReadonlyFolder: function(aNode) {
- return this.nodeIsFolder(aNode) &&
- this._readOnly.indexOf(asQuery(aNode).folderItemId) != -1;
- },
-
- /**
* Gets the concrete item-id for the given node. Generally, this is just
* node.itemId, but for folder-shortcuts that's node.folderItemId.
*/
getConcreteItemId: function PU_getConcreteItemId(aNode) {
if (aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER_SHORTCUT)
return asQuery(aNode).folderItemId;
else if (PlacesUtils.nodeIsTagQuery(aNode)) {
// RESULTS_AS_TAG_CONTENTS queries are similar to folder shortcuts
@@ -1108,20 +1031,19 @@ this.PlacesUtils = {
_serializeNodeAsJSONToOutputStream: function (aNode, aStream) {
function addGenericProperties(aPlacesNode, aJSNode) {
aJSNode.title = aPlacesNode.title;
aJSNode.id = aPlacesNode.itemId;
let guid = aPlacesNode.bookmarkGuid;
if (guid) {
aJSNode.itemGuid = guid;
var parent = aPlacesNode.parent;
- if (parent) {
+ if (parent)
aJSNode.parent = parent.itemId;
- aJSNode.parentReadOnly = PlacesUtils.nodeIsReadOnly(parent);
- }
+
var dateAdded = aPlacesNode.dateAdded;
if (dateAdded)
aJSNode.dateAdded = dateAdded;
var lastModified = aPlacesNode.lastModified;
if (lastModified)
aJSNode.lastModified = lastModified;
// XXX need a hasAnnos api
--- a/toolkit/components/places/nsINavBookmarksService.idl
+++ b/toolkit/components/places/nsINavBookmarksService.idl
@@ -218,17 +218,17 @@ interface nsINavBookmarkObserver : nsISu
};
/**
* The BookmarksService interface provides methods for managing bookmarked
* history items. Bookmarks consist of a set of user-customizable
* folders. A URI in history can be contained in one or more such folders.
*/
-[scriptable, uuid(A78EA368-E28E-462E-897A-26606D4DDCE6)]
+[scriptable, uuid(4C309044-B6DA-4511-AF57-E8940DB00045)]
interface nsINavBookmarksService : nsISupports
{
/**
* The item ID of the Places root.
*/
readonly attribute long long placesRoot;
/**
@@ -462,40 +462,16 @@ interface nsINavBookmarksService : nsISu
/**
* Get an item's type (bookmark, separator, folder).
* The type is one of the TYPE_* constants defined above.
*/
unsigned short getItemType(in long long aItemId);
/**
- * Checks whether a folder is marked as read-only.
- * If this is set to true, UI will not allow the user to add, remove,
- * or reorder children in this folder. The default for all folders is false.
- * Note: This does not restrict API calls, only UI actions.
- *
- * @param aItemId
- * the item-id of the folder.
- */
- boolean getFolderReadonly(in long long aItemId);
-
- /**
- * Sets or unsets the readonly flag from a folder.
- * If this is set to true, UI will not allow the user to add, remove,
- * or reorder children in this folder. The default for all folders is false.
- * Note: This does not restrict API calls, only UI actions.
- *
- * @param aFolder
- * the item-id of the folder.
- * @param aReadOnly
- * the read-only state (boolean).
- */
- void setFolderReadonly(in long long aFolder, in boolean aReadOnly);
-
- /**
* Returns true if the given URI is in any bookmark folder. If you want the
* results to be redirect-aware, use getBookmarkedURIFor()
*/
boolean isBookmarked(in nsIURI aURI);
/**
* Used to see if the given URI is bookmarked, or any page that redirected to
* it is bookmarked. For example, if I bookmark "mozilla.org" by manually
--- a/toolkit/components/places/nsINavHistoryService.idl
+++ b/toolkit/components/places/nsINavHistoryService.idl
@@ -170,17 +170,17 @@ interface nsINavHistoryResultNode : nsIS
};
/**
* Base class for container results. This includes all types of groupings.
* Bookmark folders and places queries will be QueryResultNodes which extends
* these items.
*/
-[scriptable, uuid(5bac9734-c0ff-44eb-8d19-da88462ff6da)]
+[scriptable, uuid(3E9CC95F-0D93-45F1-894F-908EEB9866D7)]
interface nsINavHistoryContainerResultNode : nsINavHistoryResultNode
{
/**
* Set this to allow descent into the container. When closed, attempting
* to call getChildren or childCount will result in an error. You should
* set this to false when you are done reading.
*
@@ -251,36 +251,27 @@ interface nsINavHistoryContainerResultNo
* @throws NS_ERROR_NOT_AVAILABLE if this container is closed.
* @return a result node that matches the given details if any, null
* otherwise.
*/
nsINavHistoryResultNode findNodeByDetails(in AUTF8String aURIString,
in PRTime aTime,
in long long aItemId,
in boolean aRecursive);
-
- /**
- * Returns false if this node's list of children can be modified
- * (adding or removing children, or reordering children), or true if
- * the UI should not allow the list of children to be modified.
- * This is false for bookmark folder nodes unless setFolderReadOnly() has
- * been called to override it, and true for non-folder nodes.
- */
- readonly attribute boolean childrenReadOnly;
};
/**
* Used for places queries and as a base for bookmark folders.
*
* Note that if you request places to *not* be expanded in the options that
* generated this node, this item will report it has no children and never try
* to populate itself.
*/
-[scriptable, uuid(a4144c3e-8125-46d5-a719-831bec8095f4)]
+[scriptable, uuid(91AC5E59-3F5C-4ACD-AB3B-325FC425A5A1)]
interface nsINavHistoryQueryResultNode : nsINavHistoryContainerResultNode
{
/**
* Get the queries which build this node's children.
* Only valid for RESULT_TYPE_QUERY nodes.
*/
void getQueries([optional] out unsigned long queryCount,
[retval,array,size_is(queryCount)] out nsINavHistoryQuery queries);
@@ -1113,22 +1104,19 @@ interface nsINavHistoryQueryOptions : ns
/**
* Set to true to exclude queries ("place:" URIs) from the query results.
* Simple folder queries (bookmark folder symlinks) will still be included.
* Defaults to false.
*/
attribute boolean excludeQueries;
/**
- * Set to true to exclude read-only folders from the query results. This is
- * designed for cases where you want to give the user the option of filing
- * something into a list of folders. It only affects cases where the actual
- * folder result node would appear in its parent folder and filters it out.
- * It doesn't affect the query at all, and doesn't affect more complex
- * queries (such as "folders with annotation X").
+ * DO NOT USE THIS API. IT'LL BE REMOVED IN BUG 1072833.
+ *
+ * Set to true to exclude live bookmarks from the query results.
*/
attribute boolean excludeReadOnlyFolders;
/**
* When set, allows items with "place:" URIs to appear as containers,
* with the container's contents filled in from the stored query.
* If not set, these will appear as normal items. Doesn't do anything if
* excludeQueries is set. Defaults to false.
--- a/toolkit/components/places/nsLivemarkService.js
+++ b/toolkit/components/places/nsLivemarkService.js
@@ -542,17 +542,16 @@ function Livemark(aLivemarkInfo)
this.lastModified = aLivemarkInfo.lastModified;
}
else {
// Create a new livemark.
this.id = PlacesUtils.bookmarks.createFolder(aLivemarkInfo.parentId,
aLivemarkInfo.title,
aLivemarkInfo.index,
aLivemarkInfo.guid);
- PlacesUtils.bookmarks.setFolderReadonly(this.id, true);
this.writeFeedURI(aLivemarkInfo.feedURI);
if (aLivemarkInfo.siteURI) {
this.writeSiteURI(aLivemarkInfo.siteURI);
}
// Last modified time must be the last change.
if (aLivemarkInfo.lastModified) {
this.lastModified = aLivemarkInfo.lastModified;
PlacesUtils.bookmarks.setItemLastModified(this.id, this.lastModified);
--- a/toolkit/components/places/nsNavBookmarks.cpp
+++ b/toolkit/components/places/nsNavBookmarks.cpp
@@ -55,17 +55,17 @@ const int32_t nsNavBookmarks::kGetChildr
const int32_t nsNavBookmarks::kGetChildrenIndex_PlaceID = 18;
using namespace mozilla::places;
PLACES_FACTORY_SINGLETON_IMPLEMENTATION(nsNavBookmarks, gBookmarksService)
#define BOOKMARKS_ANNO_PREFIX "bookmarks/"
#define BOOKMARKS_TOOLBAR_FOLDER_ANNO NS_LITERAL_CSTRING(BOOKMARKS_ANNO_PREFIX "toolbarFolder")
-#define READ_ONLY_ANNO NS_LITERAL_CSTRING("placesInternal/READ_ONLY")
+#define FEED_URI_ANNO NS_LITERAL_CSTRING("livemark/feedURI")
namespace {
struct keywordSearchData
{
int64_t itemId;
nsString keyword;
@@ -785,56 +785,28 @@ nsNavBookmarks::CreateFolder(int64_t aPa
// will cause notifications to be sent to bookmark observers.
int32_t localIndex = aIndex;
nsresult rv = CreateContainerWithID(-1, aParent, aName, true, &localIndex,
aGUID, aNewFolder);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
-NS_IMETHODIMP
-nsNavBookmarks::GetFolderReadonly(int64_t aFolder, bool* aResult)
+bool nsNavBookmarks::IsLivemark(int64_t aFolderId)
{
- NS_ENSURE_ARG_MIN(aFolder, 1);
- NS_ENSURE_ARG_POINTER(aResult);
-
- nsAnnotationService* annosvc = nsAnnotationService::GetAnnotationService();
- NS_ENSURE_TRUE(annosvc, NS_ERROR_OUT_OF_MEMORY);
- nsresult rv = annosvc->ItemHasAnnotation(aFolder, READ_ONLY_ANNO, aResult);
- NS_ENSURE_SUCCESS(rv, rv);
- return NS_OK;
-}
-
-
-NS_IMETHODIMP
-nsNavBookmarks::SetFolderReadonly(int64_t aFolder, bool aReadOnly)
-{
- NS_ENSURE_ARG_MIN(aFolder, 1);
-
nsAnnotationService* annosvc = nsAnnotationService::GetAnnotationService();
- NS_ENSURE_TRUE(annosvc, NS_ERROR_OUT_OF_MEMORY);
- nsresult rv;
- if (aReadOnly) {
- rv = annosvc->SetItemAnnotationInt32(aFolder, READ_ONLY_ANNO, 1, 0,
- nsAnnotationService::EXPIRE_NEVER);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- else {
- bool hasAnno;
- rv = annosvc->ItemHasAnnotation(aFolder, READ_ONLY_ANNO, &hasAnno);
- NS_ENSURE_SUCCESS(rv, rv);
- if (hasAnno) {
- rv = annosvc->RemoveItemAnnotation(aFolder, READ_ONLY_ANNO);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- }
- return NS_OK;
+ NS_ENSURE_TRUE(annosvc, false);
+ bool isLivemark;
+ nsresult rv = annosvc->ItemHasAnnotation(aFolderId,
+ FEED_URI_ANNO,
+ &isLivemark);
+ NS_ENSURE_SUCCESS(rv, false);
+ return isLivemark;
}
-
nsresult
nsNavBookmarks::CreateContainerWithID(int64_t aItemId,
int64_t aParent,
const nsACString& aTitle,
bool aIsBookmarkFolder,
int32_t* aIndex,
const nsACString& aGUID,
int64_t* aNewFolder)
@@ -1861,21 +1833,20 @@ nsNavBookmarks::ProcessFolderNodeRow(
aOptions->ExcludeQueries()) ||
(nodeType != nsINavHistoryResultNode::RESULT_TYPE_QUERY &&
nodeType != nsINavHistoryResultNode::RESULT_TYPE_FOLDER_SHORTCUT &&
aOptions->ExcludeItems())) {
return NS_OK;
}
}
else if (itemType == TYPE_FOLDER) {
+ // ExcludeReadOnlyFolders currently means "ExcludeLivemarks" (to be fixed in
+ // bug 1072833)
if (aOptions->ExcludeReadOnlyFolders()) {
- // If the folder is read-only, skip it.
- bool readOnly = false;
- GetFolderReadonly(id, &readOnly);
- if (readOnly)
+ if (IsLivemark(id))
return NS_OK;
}
nsAutoCString title;
rv = aRow->GetUTF8String(nsNavHistory::kGetInfoIndex_Title, title);
NS_ENSURE_SUCCESS(rv, rv);
node = new nsNavHistoryFolderResultNode(title, aOptions, id);
--- a/toolkit/components/places/nsNavBookmarks.h
+++ b/toolkit/components/places/nsNavBookmarks.h
@@ -230,16 +230,25 @@ public:
nsTArray<int64_t>& aDescendantFoldersArray);
private:
static nsNavBookmarks* gBookmarksService;
~nsNavBookmarks();
/**
+ * Checks whether or not aFolderId points to a live bookmark.
+ *
+ * @param aFolderId
+ * the item-id of the folder to check.
+ * @return true if aFolderId points to live bookmarks, false otherwise.
+ */
+ bool IsLivemark(int64_t aFolderId);
+
+ /**
* Locates the root items in the bookmarks folder hierarchy assigning folder
* ids to the root properties that are exposed through the service interface.
*/
nsresult ReadRoots();
nsresult AdjustIndices(int64_t aFolder,
int32_t aStartIndex,
int32_t aEndIndex,
--- a/toolkit/components/places/nsNavHistoryResult.cpp
+++ b/toolkit/components/places/nsNavHistoryResult.cpp
@@ -317,38 +317,36 @@ NS_IMPL_RELEASE_INHERITED(nsNavHistoryCo
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsNavHistoryContainerResultNode)
NS_INTERFACE_MAP_STATIC_AMBIGUOUS(nsNavHistoryContainerResultNode)
NS_INTERFACE_MAP_ENTRY(nsINavHistoryContainerResultNode)
NS_INTERFACE_MAP_END_INHERITING(nsNavHistoryResultNode)
nsNavHistoryContainerResultNode::nsNavHistoryContainerResultNode(
const nsACString& aURI, const nsACString& aTitle,
- const nsACString& aIconURI, uint32_t aContainerType, bool aReadOnly,
+ const nsACString& aIconURI, uint32_t aContainerType,
nsNavHistoryQueryOptions* aOptions) :
nsNavHistoryResultNode(aURI, aTitle, 0, 0, aIconURI),
mResult(nullptr),
mContainerType(aContainerType),
mExpanded(false),
- mChildrenReadOnly(aReadOnly),
mOptions(aOptions),
mAsyncCanceledState(NOT_CANCELED)
{
}
nsNavHistoryContainerResultNode::nsNavHistoryContainerResultNode(
const nsACString& aURI, const nsACString& aTitle,
PRTime aTime,
- const nsACString& aIconURI, uint32_t aContainerType, bool aReadOnly,
+ const nsACString& aIconURI, uint32_t aContainerType,
nsNavHistoryQueryOptions* aOptions) :
nsNavHistoryResultNode(aURI, aTitle, 0, aTime, aIconURI),
mResult(nullptr),
mContainerType(aContainerType),
mExpanded(false),
- mChildrenReadOnly(aReadOnly),
mOptions(aOptions),
mAsyncCanceledState(NOT_CANCELED)
{
}
nsNavHistoryContainerResultNode::~nsNavHistoryContainerResultNode()
{
@@ -1712,26 +1710,16 @@ nsNavHistoryContainerResultNode::FindNod
}
}
}
NS_IF_ADDREF(*_retval);
return NS_OK;
}
/**
- * @note Overridden for folders to query the bookmarks service directly.
- */
-NS_IMETHODIMP
-nsNavHistoryContainerResultNode::GetChildrenReadOnly(bool *aChildrenReadOnly)
-{
- *aChildrenReadOnly = mChildrenReadOnly;
- return NS_OK;
-}
-
-/**
* HOW QUERY UPDATING WORKS
*
* Queries are different than bookmark folders in that we can not always do
* dynamic updates (easily) and updates are more expensive. Therefore, we do
* NOT query if we are not open and want to see if we have any children (for
* drawing a twisty) and always assume we will.
*
* When the container is opened, we execute the query and register the
@@ -1748,31 +1736,31 @@ NS_IMPL_ISUPPORTS_INHERITED(nsNavHistory
nsNavHistoryContainerResultNode,
nsINavHistoryQueryResultNode)
nsNavHistoryQueryResultNode::nsNavHistoryQueryResultNode(
const nsACString& aTitle, const nsACString& aIconURI,
const nsACString& aQueryURI) :
nsNavHistoryContainerResultNode(aQueryURI, aTitle, aIconURI,
nsNavHistoryResultNode::RESULT_TYPE_QUERY,
- true, nullptr),
+ nullptr),
mLiveUpdate(QUERYUPDATE_COMPLEX_WITH_BOOKMARKS),
mHasSearchTerms(false),
mContentsValid(false),
mBatchChanges(0)
{
}
nsNavHistoryQueryResultNode::nsNavHistoryQueryResultNode(
const nsACString& aTitle, const nsACString& aIconURI,
const nsCOMArray<nsNavHistoryQuery>& aQueries,
nsNavHistoryQueryOptions* aOptions) :
nsNavHistoryContainerResultNode(EmptyCString(), aTitle, aIconURI,
nsNavHistoryResultNode::RESULT_TYPE_QUERY,
- true, aOptions),
+ aOptions),
mQueries(aQueries),
mContentsValid(false),
mBatchChanges(0),
mTransitions(mQueries[0]->Transitions())
{
NS_ASSERTION(aQueries.Count() > 0, "Must have at least one query");
nsNavHistory* history = nsNavHistory::GetHistoryService();
@@ -1795,17 +1783,17 @@ nsNavHistoryQueryResultNode::nsNavHistor
nsNavHistoryQueryResultNode::nsNavHistoryQueryResultNode(
const nsACString& aTitle, const nsACString& aIconURI,
PRTime aTime,
const nsCOMArray<nsNavHistoryQuery>& aQueries,
nsNavHistoryQueryOptions* aOptions) :
nsNavHistoryContainerResultNode(EmptyCString(), aTitle, aTime, aIconURI,
nsNavHistoryResultNode::RESULT_TYPE_QUERY,
- true, aOptions),
+ aOptions),
mQueries(aQueries),
mContentsValid(false),
mBatchChanges(0),
mTransitions(mQueries[0]->Transitions())
{
NS_ASSERTION(aQueries.Count() > 0, "Must have at least one query");
nsNavHistory* history = nsNavHistory::GetHistoryService();
@@ -2983,17 +2971,17 @@ NS_IMPL_ISUPPORTS_INHERITED(nsNavHistory
nsNavHistoryContainerResultNode,
nsINavHistoryQueryResultNode)
nsNavHistoryFolderResultNode::nsNavHistoryFolderResultNode(
const nsACString& aTitle, nsNavHistoryQueryOptions* aOptions,
int64_t aFolderId) :
nsNavHistoryContainerResultNode(EmptyCString(), aTitle, EmptyCString(),
nsNavHistoryResultNode::RESULT_TYPE_FOLDER,
- false, aOptions),
+ aOptions),
mContentsValid(false),
mQueryItemId(-1),
mIsRegisteredFolderObserver(false)
{
mItemId = aFolderId;
}
nsNavHistoryFolderResultNode::~nsNavHistoryFolderResultNode()
@@ -3085,35 +3073,16 @@ nsNavHistoryFolderResultNode::GetHasChil
*/
NS_IMETHODIMP
nsNavHistoryFolderResultNode::GetItemId(int64_t* aItemId)
{
*aItemId = mQueryItemId == -1 ? mItemId : mQueryItemId;
return NS_OK;
}
-/**
- * Here, we override the getter and ignore the value stored in our object.
- * The bookmarks service can tell us whether this folder should be read-only
- * or not.
- *
- * It would be nice to put this code in the folder constructor, but the
- * database was complaining. I believe it is because most folders are created
- * while enumerating the bookmarks table and having a statement open, and doing
- * another statement might make it unhappy in some cases.
- */
-NS_IMETHODIMP
-nsNavHistoryFolderResultNode::GetChildrenReadOnly(bool *aChildrenReadOnly)
-{
- nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService();
- NS_ENSURE_TRUE(bookmarks, NS_ERROR_UNEXPECTED);
- return bookmarks->GetFolderReadonly(mItemId, aChildrenReadOnly);
-}
-
-
NS_IMETHODIMP
nsNavHistoryFolderResultNode::GetFolderItemId(int64_t* aItemId)
{
*aItemId = mItemId;
return NS_OK;
}
/**
--- a/toolkit/components/places/nsNavHistoryResult.h
+++ b/toolkit/components/places/nsNavHistoryResult.h
@@ -396,17 +396,17 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHisto
//
// This is the base class for all nodes that can have children. It is
// overridden for nodes that are dynamically populated such as queries and
// folders. It is used directly for simple containers such as host groups
// in history views.
// derived classes each provide their own implementation of has children and
// forward the rest to us using this macro
-#define NS_FORWARD_CONTAINERNODE_EXCEPT_HASCHILDREN_AND_READONLY \
+#define NS_FORWARD_CONTAINERNODE_EXCEPT_HASCHILDREN \
NS_IMETHOD GetState(uint16_t* _state) \
{ return nsNavHistoryContainerResultNode::GetState(_state); } \
NS_IMETHOD GetContainerOpen(bool *aContainerOpen) \
{ return nsNavHistoryContainerResultNode::GetContainerOpen(aContainerOpen); } \
NS_IMETHOD SetContainerOpen(bool aContainerOpen) \
{ return nsNavHistoryContainerResultNode::SetContainerOpen(aContainerOpen); } \
NS_IMETHOD GetChildCount(uint32_t *aChildCount) \
{ return nsNavHistoryContainerResultNode::GetChildCount(aChildCount); } \
@@ -425,22 +425,22 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHisto
class nsNavHistoryContainerResultNode : public nsNavHistoryResultNode,
public nsINavHistoryContainerResultNode
{
public:
nsNavHistoryContainerResultNode(
const nsACString& aURI, const nsACString& aTitle,
const nsACString& aIconURI, uint32_t aContainerType,
- bool aReadOnly, nsNavHistoryQueryOptions* aOptions);
+ nsNavHistoryQueryOptions* aOptions);
nsNavHistoryContainerResultNode(
const nsACString& aURI, const nsACString& aTitle,
PRTime aTime,
const nsACString& aIconURI, uint32_t aContainerType,
- bool aReadOnly, nsNavHistoryQueryOptions* aOptions);
+ nsNavHistoryQueryOptions* aOptions);
virtual nsresult Refresh();
NS_DECLARE_STATIC_IID_ACCESSOR(NS_NAVHISTORYCONTAINERRESULTNODE_IID)
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsNavHistoryContainerResultNode, nsNavHistoryResultNode)
NS_FORWARD_COMMON_RESULTNODE_TO_BASE
@@ -474,18 +474,16 @@ public:
// When there are children, this stores the open state in the tree
// this is set to the default in the constructor.
bool mExpanded;
// Filled in by the result type generator in nsNavHistory.
nsCOMArray<nsNavHistoryResultNode> mChildren;
- bool mChildrenReadOnly;
-
nsCOMPtr<nsNavHistoryQueryOptions> mOptions;
void FillStats();
nsresult ReverseUpdateStats(int32_t aAccessCountChange);
// Sorting methods.
typedef nsCOMArray<nsNavHistoryResultNode>::nsCOMArrayComparatorFunc SortComparator;
virtual uint16_t GetSortType();
@@ -639,20 +637,18 @@ public:
const nsCOMArray<nsNavHistoryQuery>& aQueries,
nsNavHistoryQueryOptions* aOptions);
NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_COMMON_RESULTNODE_TO_BASE
NS_IMETHOD GetType(uint32_t* type)
{ *type = nsNavHistoryResultNode::RESULT_TYPE_QUERY; return NS_OK; }
NS_IMETHOD GetUri(nsACString& aURI); // does special lazy creation
- NS_FORWARD_CONTAINERNODE_EXCEPT_HASCHILDREN_AND_READONLY
+ NS_FORWARD_CONTAINERNODE_EXCEPT_HASCHILDREN
NS_IMETHOD GetHasChildren(bool* aHasChildren);
- NS_IMETHOD GetChildrenReadOnly(bool *aChildrenReadOnly)
- { return nsNavHistoryContainerResultNode::GetChildrenReadOnly(aChildrenReadOnly); }
NS_DECL_NSINAVHISTORYQUERYRESULTNODE
bool CanExpand();
bool IsContainersQuery();
virtual nsresult OpenContainer();
NS_DECL_BOOKMARK_HISTORY_OBSERVER_INTERNAL
@@ -720,19 +716,18 @@ public:
if (mQueryItemId != -1) {
*type = nsNavHistoryResultNode::RESULT_TYPE_FOLDER_SHORTCUT;
} else {
*type = nsNavHistoryResultNode::RESULT_TYPE_FOLDER;
}
return NS_OK;
}
NS_IMETHOD GetUri(nsACString& aURI);
- NS_FORWARD_CONTAINERNODE_EXCEPT_HASCHILDREN_AND_READONLY
+ NS_FORWARD_CONTAINERNODE_EXCEPT_HASCHILDREN
NS_IMETHOD GetHasChildren(bool* aHasChildren);
- NS_IMETHOD GetChildrenReadOnly(bool *aChildrenReadOnly);
NS_IMETHOD GetItemId(int64_t *aItemId);
NS_DECL_NSINAVHISTORYQUERYRESULTNODE
virtual nsresult OpenContainer();
virtual nsresult OpenContainerAsync();
NS_DECL_ASYNCSTATEMENTCALLBACK
--- a/toolkit/components/places/tests/queries/head_queries.js
+++ b/toolkit/components/places/tests/queries/head_queries.js
@@ -147,18 +147,16 @@ function task_populateDB(aArray)
qdata.annoExpiration);
}
}
if (qdata.isFolder) {
let folderId = PlacesUtils.bookmarks.createFolder(qdata.parentFolder,
qdata.title,
qdata.index);
- if (qdata.readOnly)
- PlacesUtils.bookmarks.setFolderReadonly(folderId, true);
}
if (qdata.isLivemark) {
PlacesUtils.livemarks.addLivemark({ title: qdata.title
, parentId: qdata.parentFolder
, index: qdata.index
, feedURI: uri(qdata.feedURI)
, siteURI: uri(qdata.uri)
@@ -241,17 +239,16 @@ function queryData(obj) {
this.feedURI = obj.feedURI ? obj.feedURI : "";
this.index = obj.index ? obj.index : PlacesUtils.bookmarks.DEFAULT_INDEX;
this.isFolder = obj.isFolder ? obj.isFolder : false;
this.contractId = obj.contractId ? obj.contractId : "";
this.lastModified = obj.lastModified ? obj.lastModified : today;
this.dateAdded = obj.dateAdded ? obj.dateAdded : today;
this.keyword = obj.keyword ? obj.keyword : "";
this.visitCount = obj.visitCount ? obj.visitCount : 0;
- this.readOnly = obj.readOnly ? obj.readOnly : false;
this.isSeparator = obj.hasOwnProperty("isSeparator") && obj.isSeparator;
// And now, the attribute for whether or not this object should appear in the
// resulting query
this.isInQuery = obj.isInQuery ? obj.isInQuery : false;
}
// All attributes are set in the constructor above
--- a/toolkit/components/places/tests/queries/test_async.js
+++ b/toolkit/components/places/tests/queries/test_async.js
@@ -308,17 +308,16 @@ let DataHelper = {
isSeparator: true,
parentFolder: dat.parent,
index: PlacesUtils.bookmarks.DEFAULT_INDEX,
isInQuery: true
};
case "folder":
return {
isFolder: true,
- readOnly: false,
parentFolder: dat.parent,
index: PlacesUtils.bookmarks.DEFAULT_INDEX,
title: dat.title,
isInQuery: true
};
default:
do_throw("Unknown data type when populating DB: " + type);
}
deleted file mode 100644
--- a/toolkit/components/places/tests/queries/test_excludeReadOnlyFolders.js
+++ /dev/null
@@ -1,48 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-// The test data for our database, note that the ordering of the results that
-// will be returned by the query (the isInQuery: true objects) is IMPORTANT.
-// see compareArrayToResult in head_queries.js for more info.
-var testData = [
- // Normal folder
- { isInQuery: true, isFolder: true, title: "Folder 1",
- parentFolder: PlacesUtils.toolbarFolderId },
-
- // Read only folder
- { isInQuery: false, isFolder: true, title: "Folder 2 RO",
- parentFolder: PlacesUtils.toolbarFolderId, readOnly: true }
-];
-
-function run_test()
-{
- run_next_test();
-}
-
-add_task(function test_excludeReadOnlyFolders()
-{
- yield task_populateDB(testData);
-
- var query = PlacesUtils.history.getNewQuery();
- query.setFolders([PlacesUtils.toolbarFolderId], 1);
-
- // Options
- var options = PlacesUtils.history.getNewQueryOptions();
- options.excludeQueries = true;
- options.excludeReadOnlyFolders = true;
-
- // Results
- var result = PlacesUtils.history.executeQuery(query, options);
- var root = result.root;
- root.containerOpen = true;
-
- displayResultSet(root);
- // The readonly folder should not be in our result set.
- do_check_eq(1, root.childCount);
- do_check_eq("Folder 1", root.getChild(0).title);
-
- root.containerOpen = false;
-});
--- a/toolkit/components/places/tests/queries/test_querySerialization.js
+++ b/toolkit/components/places/tests/queries/test_querySerialization.js
@@ -409,27 +409,16 @@ const queryOptionSwitches = [
desc: "nsINavHistoryQueryOptions.excludeQueries",
matches: simplePropertyMatches,
runs: [
function (aQuery, aQueryOptions) {
aQueryOptions.excludeQueries = true;
}
]
},
- // excludeReadOnlyFolders
- {
- property: "excludeReadOnlyFolders",
- desc: "nsINavHistoryQueryOptions.excludeReadOnlyFolders",
- matches: simplePropertyMatches,
- runs: [
- function (aQuery, aQueryOptions) {
- aQueryOptions.excludeReadOnlyFolders = true;
- }
- ]
- },
// expandQueries
{
property: "expandQueries",
desc: "nsINavHistoryQueryOptions.expandQueries",
matches: simplePropertyMatches,
runs: [
function (aQuery, aQueryOptions) {
aQueryOptions.expandQueries = true;
--- a/toolkit/components/places/tests/queries/xpcshell.ini
+++ b/toolkit/components/places/tests/queries/xpcshell.ini
@@ -3,17 +3,16 @@ head = head_queries.js
tail =
skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_415716.js]
[test_abstime-annotation-domain.js]
[test_abstime-annotation-uri.js]
[test_async.js]
[test_containersQueries_sorting.js]
-[test_excludeReadOnlyFolders.js]
[test_history_queries_tags_liveUpdate.js]
[test_history_queries_titles_liveUpdate.js]
[test_onlyBookmarked.js]
[test_querySerialization.js]
[test_redirects.js]
# Bug 676989: test hangs consistently on Android
skip-if = os == "android"
[test_results-as-tag-contents-query.js]
--- a/toolkit/devtools/apps/tests/debugger-protocol-helper.js
+++ b/toolkit/devtools/apps/tests/debugger-protocol-helper.js
@@ -146,17 +146,17 @@ addMessageListener("addFrame", function
});
addMessageListener("cleanup", function () {
webappActorRequest({type: "unwatchApps"}, function () {
gClient.close();
});
});
-let AppFramesMock = {
+let FramesMock = {
list: function () {
return Frames;
},
addObserver: function () {},
removeObserver: function () {}
};
-require("devtools/server/actors/webapps").setAppFramesMock(AppFramesMock);
+require("devtools/server/actors/webapps").setFramesMock(FramesMock);
--- a/toolkit/devtools/server/actors/childtab.js
+++ b/toolkit/devtools/server/actors/childtab.js
@@ -22,49 +22,68 @@ let { TabActor } = require("devtools/ser
* @param chromeGlobal
* The content script global holding |content| and |docShell| properties for a tab.
*/
function ContentActor(connection, chromeGlobal)
{
this._chromeGlobal = chromeGlobal;
TabActor.call(this, connection, chromeGlobal);
this.traits.reconfigure = false;
+ this._sendForm = this._sendForm.bind(this);
+ this._chromeGlobal.addMessageListener("debug:form", this._sendForm);
}
ContentActor.prototype = Object.create(TabActor.prototype);
ContentActor.prototype.constructor = ContentActor;
Object.defineProperty(ContentActor.prototype, "docShell", {
get: function() {
return this._chromeGlobal.docShell;
},
enumerable: true,
configurable: true
});
+Object.defineProperty(ContentActor.prototype, "title", {
+ get: function() {
+ return this.window.document.title;
+ },
+ enumerable: true,
+ configurable: true
+});
+
ContentActor.prototype.exit = function() {
+ this._chromeGlobal.removeMessageListener("debug:form", this._sendForm);
+ this._sendForm = null;
TabActor.prototype.exit.call(this);
};
-// Override grip just to rename this._tabActorPool to this._tabActorPool2
+// Override form just to rename this._tabActorPool to this._tabActorPool2
// in order to prevent it to be cleaned on detach.
// We have to keep tab actors alive as we keep the ContentActor
// alive after detach and reuse it for multiple debug sessions.
-ContentActor.prototype.grip = function () {
+ContentActor.prototype.form = function () {
let response = {
- 'actor': this.actorID,
- 'title': this.title,
- 'url': this.url
+ "actor": this.actorID,
+ "title": this.title,
+ "url": this.url
};
// Walk over tab actors added by extensions and add them to a new ActorPool.
let actorPool = new ActorPool(this.conn);
this._createExtraActors(DebuggerServer.tabActorFactories, actorPool);
if (!actorPool.isEmpty()) {
this._tabActorPool2 = actorPool;
this.conn.addActorPool(this._tabActorPool2);
}
this._appendExtraActors(response);
return response;
};
+/**
+ * On navigation events, our URL and/or title may change, so we update our
+ * counterpart in the parent process that participates in the tab list.
+ */
+ContentActor.prototype._sendForm = function() {
+ this._chromeGlobal.sendAsyncMessage("debug:form", this.form());
+};
--- a/toolkit/devtools/server/actors/webapps.js
+++ b/toolkit/devtools/server/actors/webapps.js
@@ -13,29 +13,29 @@ Cu.import("resource://gre/modules/FileUt
let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
let DevToolsUtils = require("devtools/toolkit/DevToolsUtils");
let { ActorPool } = require("devtools/server/actors/common");
let { DebuggerServer } = require("devtools/server/main");
let Services = require("Services");
-let AppFramesMock = null;
+let FramesMock = null;
-exports.setAppFramesMock = function (mock) {
- AppFramesMock = mock;
-}
+exports.setFramesMock = function (mock) {
+ FramesMock = mock;
+};
-DevToolsUtils.defineLazyGetter(this, "AppFrames", () => {
+DevToolsUtils.defineLazyGetter(this, "Frames", () => {
// Offer a way for unit test to provide a mock
- if (AppFramesMock) {
- return AppFramesMock;
+ if (FramesMock) {
+ return FramesMock;
}
try {
- return Cu.import("resource://gre/modules/AppFrames.jsm", {}).AppFrames;
+ return Cu.import("resource://gre/modules/Frames.jsm", {}).Frames;
} catch(e) {}
return null;
});
function debug(aMsg) {
/*
Cc["@mozilla.org/consoleservice;1"]
.getService(Ci.nsIConsoleService)
@@ -855,18 +855,20 @@ WebappsActor.prototype = {
reg.close(app);
return {};
},
_appFrames: function () {
// Try to filter on b2g and mulet
- if (AppFrames) {
- return AppFrames.list();
+ if (Frames) {
+ return Frames.list().filter(frame => {
+ return frame.getAttribute('mozapp');
+ });
} else {
return [];
}
},
listRunningApps: function (aRequest) {
debug("listRunningApps\n");
@@ -950,37 +952,38 @@ WebappsActor.prototype = {
}
return { actor: actor };
});
},
watchApps: function () {
// For now, app open/close events are only implement on b2g
- if (AppFrames) {
- AppFrames.addObserver(this);
+ if (Frames) {
+ Frames.addObserver(this);
}
Services.obs.addObserver(this, "webapps-installed", false);
Services.obs.addObserver(this, "webapps-uninstall", false);
return {};
},
unwatchApps: function () {
- if (AppFrames) {
- AppFrames.removeObserver(this);
+ if (Frames) {
+ Frames.removeObserver(this);
}
Services.obs.removeObserver(this, "webapps-installed", false);
Services.obs.removeObserver(this, "webapps-uninstall", false);
return {};
},
- onAppFrameCreated: function (frame, isFirstAppFrame) {
- if (!isFirstAppFrame) {
+ onFrameCreated: function (frame, isFirstAppFrame) {
+ let mozapp = frame.getAttribute('mozapp');
+ if (!mozapp || !isFirstAppFrame) {
return;
}
let manifestURL = frame.appManifestURL;
// Only track app frames
if (!manifestURL) {
return;
}
@@ -990,18 +993,19 @@ WebappsActor.prototype = {
this.conn.send({ from: this.actorID,
type: "appOpen",
manifestURL: manifestURL
});
}
});
},
- onAppFrameDestroyed: function (frame, isLastAppFrame) {
- if (!isLastAppFrame) {
+ onFrameDestroyed: function (frame, isLastAppFrame) {
+ let mozapp = frame.getAttribute('mozapp');
+ if (!mozapp || !isLastAppFrame) {
return;
}
let manifestURL = frame.appManifestURL;
// Only track app frames
if (!manifestURL) {
return;
}
--- a/toolkit/devtools/server/actors/webbrowser.js
+++ b/toolkit/devtools/server/actors/webbrowser.js
@@ -262,69 +262,79 @@ BrowserTabList.prototype.constructor = B
* The currently selected xul:browser element, if any. Note that the
* browser window might not be loaded yet - the function will return
* |null| in such cases.
*/
BrowserTabList.prototype._getSelectedBrowser = function(aWindow) {
return aWindow.gBrowser ? aWindow.gBrowser.selectedBrowser : null;
};
+/**
+ * Produces an iterable (in this case a generator) to enumerate all available
+ * browser tabs.
+ */
+BrowserTabList.prototype._getBrowsers = function*() {
+ // Iterate over all navigator:browser XUL windows.
+ for (let win of allAppShellDOMWindows(DebuggerServer.chromeWindowType)) {
+ // For each tab in this XUL window, ensure that we have an actor for
+ // it, reusing existing actors where possible. We actually iterate
+ // over 'browser' XUL elements, and BrowserTabActor uses
+ // browser.contentWindow as the debuggee global.
+ for (let browser of this._getChildren(win)) {
+ yield browser;
+ }
+ }
+};
+
BrowserTabList.prototype._getChildren = function(aWindow) {
return aWindow.gBrowser.browsers;
};
+BrowserTabList.prototype._isRemoteBrowser = function(browser) {
+ return browser.getAttribute("remote");
+};
+
BrowserTabList.prototype.getList = function() {
let topXULWindow = Services.wm.getMostRecentWindow(DebuggerServer.chromeWindowType);
+ let selectedBrowser = null;
+ if (topXULWindow) {
+ selectedBrowser = this._getSelectedBrowser(topXULWindow);
+ }
// As a sanity check, make sure all the actors presently in our map get
// picked up when we iterate over all windows' tabs.
let initialMapSize = this._actorByBrowser.size;
let foundCount = 0;
// To avoid mysterious behavior if tabs are closed or opened mid-iteration,
// we update the map first, and then make a second pass over it to yield
// the actors. Thus, the sequence yielded is always a snapshot of the
// actors that were live when we began the iteration.
let actorPromises = [];
- // Iterate over all navigator:browser XUL windows.
- for (let win of allAppShellDOMWindows(DebuggerServer.chromeWindowType)) {
- let selectedBrowser = this._getSelectedBrowser(win);
- if (!selectedBrowser) {
- continue;
+ for (let browser of this._getBrowsers()) {
+ // Do we have an existing actor for this browser? If not, create one.
+ let actor = this._actorByBrowser.get(browser);
+ if (actor) {
+ actorPromises.push(actor.update());
+ foundCount++;
+ } else if (this._isRemoteBrowser(browser)) {
+ actor = new RemoteBrowserTabActor(this._connection, browser);
+ this._actorByBrowser.set(browser, actor);
+ actorPromises.push(actor.connect());
+ } else {
+ actor = new BrowserTabActor(this._connection, browser,
+ browser.getTabBrowser());
+ this._actorByBrowser.set(browser, actor);
+ actorPromises.push(promise.resolve(actor));
}
- // For each tab in this XUL window, ensure that we have an actor for
- // it, reusing existing actors where possible. We actually iterate
- // over 'browser' XUL elements, and BrowserTabActor uses
- // browser.contentWindow as the debuggee global.
- for (let browser of this._getChildren(win)) {
- // Do we have an existing actor for this browser? If not, create one.
- let actor = this._actorByBrowser.get(browser);
- if (actor) {
- actorPromises.push(promise.resolve(actor));
- foundCount++;
- } else if (browser.isRemoteBrowser) {
- actor = new RemoteBrowserTabActor(this._connection, browser);
- this._actorByBrowser.set(browser, actor);
- let promise = actor.connect().then((form) => {
- actor._form = form;
- return actor;
- });
- actorPromises.push(promise);
- } else {
- actor = new BrowserTabActor(this._connection, browser, win.gBrowser);
- this._actorByBrowser.set(browser, actor);
- actorPromises.push(promise.resolve(actor));
- }
-
- // Set the 'selected' properties on all actors correctly.
- actor.selected = (win === topXULWindow && browser === selectedBrowser);
- }
+ // Set the 'selected' properties on all actors correctly.
+ actor.selected = browser === selectedBrowser;
}
if (this._testing && initialMapSize !== foundCount)
throw Error("_actorByBrowser map contained actors for dead tabs");
this._mustNotify = true;
this._checkListening();
@@ -733,19 +743,28 @@ TabActor.prototype = {
if (this.webNavigation.currentURI) {
return this.webNavigation.currentURI.spec;
}
// Abrupt closing of the browser window may leave callbacks without a
// currentURI.
return null;
},
+ /**
+ * This is called by BrowserTabList.getList for existing tab actors prior to
+ * calling |form| below. It can be used to do any async work that may be
+ * needed to assemble the form.
+ */
+ update: function() {
+ return promise.resolve(this);
+ },
+
form: function BTA_form() {
dbg_assert(!this.exited,
- "grip() shouldn't be called on exited browser actor.");
+ "form() shouldn't be called on exited browser actor.");
dbg_assert(this.actorID,
"tab should have an actorID.");
let windowUtils = this.window
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
let response = {
@@ -956,17 +975,17 @@ TabActor.prototype = {
parentID = window.parent
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.outerWindowID;
}
return {
id: id,
url: window.location.href,
- title: window.title,
+ title: window.document.title,
parentID: parentID
};
});
},
_notifyDocShellsUpdate: function (docshells) {
let windows = this._docShellsToWindows(docshells);
this.conn.send({ from: this.actorID,
@@ -1612,28 +1631,51 @@ function RemoteBrowserTabActor(aConnecti
{
this._conn = aConnection;
this._browser = aBrowser;
this._form = null;
}
RemoteBrowserTabActor.prototype = {
connect: function() {
- return DebuggerServer.connectToChild(this._conn, this._browser);
+ let connect = DebuggerServer.connectToChild(this._conn, this._browser);
+ return connect.then(form => {
+ this._form = form;
+ return this;
+ });
+ },
+
+ get _mm() {
+ return this._browser.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader
+ .messageManager;
+ },
+
+ update: function() {
+ let deferred = promise.defer();
+ let onFormUpdate = msg => {
+ this._mm.removeMessageListener("debug:form", onFormUpdate);
+ this._form = msg.json;
+ deferred.resolve(this);
+ };
+ this._mm.addMessageListener("debug:form", onFormUpdate);
+ this._mm.sendAsyncMessage("debug:form");
+ return deferred.promise;
},
form: function() {
return this._form;
},
exit: function() {
this._browser = null;
},
};
+exports.RemoteBrowserTabActor = RemoteBrowserTabActor;
+
function BrowserAddonList(aConnection)
{
this._connection = aConnection;
this._actorByAddonId = new Map();
this._onListChanged = null;
}
BrowserAddonList.prototype.getList = function() {
--- a/toolkit/devtools/server/child.js
+++ b/toolkit/devtools/server/child.js
@@ -41,17 +41,17 @@ let chromeGlobal = this;
let conn = DebuggerServer.connectToParent(prefix, mm);
connections.set(id, conn);
let actor = new DebuggerServer.ContentActor(conn, chromeGlobal);
let actorPool = new ActorPool(conn);
actorPool.addActor(actor);
conn.addActorPool(actorPool);
- sendAsyncMessage("debug:actor", {actor: actor.grip(), childID: id});
+ sendAsyncMessage("debug:actor", {actor: actor.form(), childID: id});
});
addMessageListener("debug:connect", onConnect);
let onDisconnect = DevToolsUtils.makeInfallible(function (msg) {
removeMessageListener("debug:disconnect", onDisconnect);
// Call DebuggerServerConnection.close to destroy all child actors