forked from mirrors/gecko-dev
Merge mozilla-central to inbound. a=merge CLOSED TREE
This commit is contained in:
commit
17675612bf
39 changed files with 865 additions and 496 deletions
|
|
@ -126,7 +126,7 @@ if (AppConstants.NIGHTLY_BUILD) {
|
||||||
// lazy service getters
|
// lazy service getters
|
||||||
|
|
||||||
XPCOMUtils.defineLazyServiceGetters(this, {
|
XPCOMUtils.defineLazyServiceGetters(this, {
|
||||||
Favicons: ["@mozilla.org/browser/favicon-service;1", "mozIAsyncFavicons"],
|
Favicons: ["@mozilla.org/browser/favicon-service;1", "nsIFaviconService"],
|
||||||
gAboutNewTabService: ["@mozilla.org/browser/aboutnewtab-service;1", "nsIAboutNewTabService"],
|
gAboutNewTabService: ["@mozilla.org/browser/aboutnewtab-service;1", "nsIAboutNewTabService"],
|
||||||
gDNSService: ["@mozilla.org/network/dns-service;1", "nsIDNSService"],
|
gDNSService: ["@mozilla.org/network/dns-service;1", "nsIDNSService"],
|
||||||
gSerializationHelper: ["@mozilla.org/network/serialization-helper;1", "nsISerializationHelper"],
|
gSerializationHelper: ["@mozilla.org/network/serialization-helper;1", "nsISerializationHelper"],
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ support-files =
|
||||||
[browser_devices_get_user_media.js]
|
[browser_devices_get_user_media.js]
|
||||||
skip-if = (os == "linux" && debug) # linux: bug 976544
|
skip-if = (os == "linux" && debug) # linux: bug 976544
|
||||||
[browser_devices_get_user_media_anim.js]
|
[browser_devices_get_user_media_anim.js]
|
||||||
|
[browser_devices_get_user_media_default_permissions.js]
|
||||||
[browser_devices_get_user_media_in_frame.js]
|
[browser_devices_get_user_media_in_frame.js]
|
||||||
skip-if = debug # bug 1369731
|
skip-if = debug # bug 1369731
|
||||||
[browser_devices_get_user_media_multi_process.js]
|
[browser_devices_get_user_media_multi_process.js]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,164 @@
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
const permissionError = "error: NotAllowedError: The request is not allowed " +
|
||||||
|
"by the user agent or the platform in the current context.";
|
||||||
|
|
||||||
|
const CAMERA_PREF = "permissions.default.camera";
|
||||||
|
const MICROPHONE_PREF = "permissions.default.microphone";
|
||||||
|
|
||||||
|
var gTests = [
|
||||||
|
|
||||||
|
{
|
||||||
|
desc: "getUserMedia audio+video: globally blocking camera",
|
||||||
|
run: async function checkAudioVideo() {
|
||||||
|
Services.prefs.setIntPref(CAMERA_PREF, SitePermissions.BLOCK);
|
||||||
|
|
||||||
|
// Requesting audio+video shouldn't work.
|
||||||
|
let promise = promiseMessage(permissionError);
|
||||||
|
await promiseRequestDevice(true, true);
|
||||||
|
await promise;
|
||||||
|
await expectObserverCalled("recording-window-ended");
|
||||||
|
await checkNotSharing();
|
||||||
|
|
||||||
|
// Requesting only video shouldn't work.
|
||||||
|
promise = promiseMessage(permissionError);
|
||||||
|
await promiseRequestDevice(false, true);
|
||||||
|
await promise;
|
||||||
|
await expectObserverCalled("recording-window-ended");
|
||||||
|
await checkNotSharing();
|
||||||
|
|
||||||
|
// Requesting audio should work.
|
||||||
|
promise = promisePopupNotificationShown("webRTC-shareDevices");
|
||||||
|
await promiseRequestDevice(true);
|
||||||
|
await promise;
|
||||||
|
await expectObserverCalled("getUserMedia:request");
|
||||||
|
|
||||||
|
is(PopupNotifications.getNotification("webRTC-shareDevices").anchorID,
|
||||||
|
"webRTC-shareMicrophone-notification-icon", "anchored to mic icon");
|
||||||
|
checkDeviceSelectors(true);
|
||||||
|
let iconclass =
|
||||||
|
PopupNotifications.panel.firstChild.getAttribute("iconclass");
|
||||||
|
ok(iconclass.includes("microphone-icon"), "panel using microphone icon");
|
||||||
|
|
||||||
|
let indicator = promiseIndicatorWindow();
|
||||||
|
await promiseMessage("ok", () => {
|
||||||
|
PopupNotifications.panel.firstChild.button.click();
|
||||||
|
});
|
||||||
|
await expectObserverCalled("getUserMedia:response:allow");
|
||||||
|
await expectObserverCalled("recording-device-events");
|
||||||
|
Assert.deepEqual((await getMediaCaptureState()), {audio: true},
|
||||||
|
"expected microphone to be shared");
|
||||||
|
|
||||||
|
await indicator;
|
||||||
|
await checkSharingUI({audio: true});
|
||||||
|
await closeStream();
|
||||||
|
Services.prefs.clearUserPref(CAMERA_PREF);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
desc: "getUserMedia video: globally blocking camera + local exception",
|
||||||
|
run: async function checkAudioVideo() {
|
||||||
|
let browser = gBrowser.selectedBrowser;
|
||||||
|
Services.prefs.setIntPref(CAMERA_PREF, SitePermissions.BLOCK);
|
||||||
|
// Overwrite the permission for that URI, requesting video should work again.
|
||||||
|
SitePermissions.set(browser.currentURI, "camera", SitePermissions.ALLOW);
|
||||||
|
|
||||||
|
// Requesting video should work.
|
||||||
|
let indicator = promiseIndicatorWindow();
|
||||||
|
let promise = promiseMessage("ok");
|
||||||
|
await promiseRequestDevice(false, true);
|
||||||
|
await promise;
|
||||||
|
|
||||||
|
await expectObserverCalled("getUserMedia:request");
|
||||||
|
await expectObserverCalled("getUserMedia:response:allow");
|
||||||
|
await expectObserverCalled("recording-device-events");
|
||||||
|
await indicator;
|
||||||
|
await checkSharingUI({video: true});
|
||||||
|
await closeStream();
|
||||||
|
|
||||||
|
SitePermissions.remove(browser.currentURI, "camera");
|
||||||
|
Services.prefs.clearUserPref(CAMERA_PREF);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
desc: "getUserMedia audio+video: globally blocking microphone",
|
||||||
|
run: async function checkAudioVideo() {
|
||||||
|
Services.prefs.setIntPref(MICROPHONE_PREF, SitePermissions.BLOCK);
|
||||||
|
|
||||||
|
// Requesting audio+video shouldn't work.
|
||||||
|
let promise = promiseMessage(permissionError);
|
||||||
|
await promiseRequestDevice(true, true);
|
||||||
|
await promise;
|
||||||
|
await expectObserverCalled("recording-window-ended");
|
||||||
|
await checkNotSharing();
|
||||||
|
|
||||||
|
// Requesting only audio shouldn't work.
|
||||||
|
promise = promiseMessage(permissionError);
|
||||||
|
await promiseRequestDevice(true);
|
||||||
|
await promise;
|
||||||
|
await expectObserverCalled("recording-window-ended");
|
||||||
|
await checkNotSharing();
|
||||||
|
|
||||||
|
// Requesting video should work.
|
||||||
|
promise = promisePopupNotificationShown("webRTC-shareDevices");
|
||||||
|
await promiseRequestDevice(false, true);
|
||||||
|
await promise;
|
||||||
|
await expectObserverCalled("getUserMedia:request");
|
||||||
|
|
||||||
|
is(PopupNotifications.getNotification("webRTC-shareDevices").anchorID,
|
||||||
|
"webRTC-shareDevices-notification-icon", "anchored to device icon");
|
||||||
|
checkDeviceSelectors(false, true);
|
||||||
|
let iconclass =
|
||||||
|
PopupNotifications.panel.firstChild.getAttribute("iconclass");
|
||||||
|
ok(iconclass.includes("camera-icon"), "panel using devices icon");
|
||||||
|
|
||||||
|
let indicator = promiseIndicatorWindow();
|
||||||
|
await promiseMessage("ok", () => {
|
||||||
|
PopupNotifications.panel.firstChild.button.click();
|
||||||
|
});
|
||||||
|
await expectObserverCalled("getUserMedia:response:allow");
|
||||||
|
await expectObserverCalled("recording-device-events");
|
||||||
|
Assert.deepEqual((await getMediaCaptureState()), {video: true},
|
||||||
|
"expected camera to be shared");
|
||||||
|
|
||||||
|
await indicator;
|
||||||
|
await checkSharingUI({video: true});
|
||||||
|
await closeStream();
|
||||||
|
Services.prefs.clearUserPref(MICROPHONE_PREF);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
desc: "getUserMedia audio: globally blocking microphone + local exception",
|
||||||
|
run: async function checkAudioVideo() {
|
||||||
|
let browser = gBrowser.selectedBrowser;
|
||||||
|
Services.prefs.setIntPref(MICROPHONE_PREF, SitePermissions.BLOCK);
|
||||||
|
// Overwrite the permission for that URI, requesting video should work again.
|
||||||
|
SitePermissions.set(browser.currentURI, "microphone", SitePermissions.ALLOW);
|
||||||
|
|
||||||
|
// Requesting audio should work.
|
||||||
|
let indicator = promiseIndicatorWindow();
|
||||||
|
let promise = promiseMessage("ok");
|
||||||
|
await promiseRequestDevice(true);
|
||||||
|
await promise;
|
||||||
|
|
||||||
|
await expectObserverCalled("getUserMedia:request");
|
||||||
|
await expectObserverCalled("getUserMedia:response:allow");
|
||||||
|
await expectObserverCalled("recording-device-events");
|
||||||
|
await indicator;
|
||||||
|
await checkSharingUI({audio: true});
|
||||||
|
await closeStream();
|
||||||
|
|
||||||
|
SitePermissions.remove(browser.currentURI, "microphone");
|
||||||
|
Services.prefs.clearUserPref(MICROPHONE_PREF);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
];
|
||||||
|
add_task(async function test() {
|
||||||
|
await runTests(gTests);
|
||||||
|
});
|
||||||
|
|
@ -114,7 +114,7 @@ async function assertWebRTCIndicatorStatus(expected) {
|
||||||
while (windows.hasMoreElements()) {
|
while (windows.hasMoreElements()) {
|
||||||
let win = windows.getNext();
|
let win = windows.getNext();
|
||||||
let menu = win.document.getElementById("tabSharingMenu");
|
let menu = win.document.getElementById("tabSharingMenu");
|
||||||
is(menu && !menu.hidden, !!expected, "WebRTC menu should be " + expectedState);
|
is(!!menu && !menu.hidden, !!expected, "WebRTC menu should be " + expectedState);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!("nsISystemStatusBar" in Ci)) {
|
if (!("nsISystemStatusBar" in Ci)) {
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@
|
||||||
value="custom"
|
value="custom"
|
||||||
search-l10n-ids="
|
search-l10n-ids="
|
||||||
history-private-browsing-permanent.label,
|
history-private-browsing-permanent.label,
|
||||||
history-remember-option.label,
|
history-remember-browser-option.label,
|
||||||
history-remember-search-option.label,
|
history-remember-search-option.label,
|
||||||
history-clear-on-close-option.label,
|
history-clear-on-close-option.label,
|
||||||
history-clear-on-close-settings.label"/>
|
history-clear-on-close-settings.label"/>
|
||||||
|
|
@ -120,7 +120,7 @@
|
||||||
preference="browser.privatebrowsing.autostart"/>
|
preference="browser.privatebrowsing.autostart"/>
|
||||||
<vbox class="indent">
|
<vbox class="indent">
|
||||||
<checkbox id="rememberHistory"
|
<checkbox id="rememberHistory"
|
||||||
data-l10n-id="history-remember-option"
|
data-l10n-id="history-remember-browser-option"
|
||||||
preference="places.history.enabled"/>
|
preference="places.history.enabled"/>
|
||||||
<checkbox id="rememberForms"
|
<checkbox id="rememberForms"
|
||||||
data-l10n-id="history-remember-search-option"
|
data-l10n-id="history-remember-search-option"
|
||||||
|
|
@ -146,7 +146,7 @@
|
||||||
<button id="clearDataSettings"
|
<button id="clearDataSettings"
|
||||||
class="accessory-button"
|
class="accessory-button"
|
||||||
data-l10n-id="history-clear-on-close-settings"
|
data-l10n-id="history-clear-on-close-settings"
|
||||||
searchkeywords="&clearDataSettings3.label;
|
searchkeywords="&clearDataSettings4.label;
|
||||||
&historySection.label;
|
&historySection.label;
|
||||||
&itemHistoryAndDownloads.label;
|
&itemHistoryAndDownloads.label;
|
||||||
&itemCookies.label;
|
&itemCookies.label;
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@
|
||||||
|
|
||||||
<script type="application/javascript" src="chrome://browser/content/preferences/sanitize.js"/>
|
<script type="application/javascript" src="chrome://browser/content/preferences/sanitize.js"/>
|
||||||
|
|
||||||
<description>&clearDataSettings3.label;</description>
|
<description>&clearDataSettings4.label;</description>
|
||||||
|
|
||||||
<groupbox orient="horizontal">
|
<groupbox orient="horizontal">
|
||||||
<caption><label>&historySection.label;</label></caption>
|
<caption><label>&historySection.label;</label></caption>
|
||||||
|
|
|
||||||
|
|
@ -696,8 +696,8 @@ history-private-browsing-permanent =
|
||||||
.label = Always use private browsing mode
|
.label = Always use private browsing mode
|
||||||
.accesskey = p
|
.accesskey = p
|
||||||
|
|
||||||
history-remember-option =
|
history-remember-browser-option =
|
||||||
.label = Remember my browsing and download history
|
.label = Remember browsing and download history
|
||||||
.accesskey = b
|
.accesskey = b
|
||||||
|
|
||||||
history-remember-search-option =
|
history-remember-search-option =
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
<!-- LOCALIZATION NOTE (sanitizeDialog2.width): width of the Clear Recent History dialog -->
|
<!-- LOCALIZATION NOTE (sanitizeDialog2.width): width of the Clear Recent History dialog -->
|
||||||
<!ENTITY sanitizeDialog2.width "34em">
|
<!ENTITY sanitizeDialog2.width "34em">
|
||||||
|
|
||||||
<!ENTITY clearDataSettings3.label "When I quit &brandShortName;, it should automatically clear all">
|
<!ENTITY clearDataSettings4.label "When closed, &brandShortName; should automatically clear all">
|
||||||
|
|
||||||
<!-- XXX rearrange entities to match physical layout when l10n isn't an issue -->
|
<!-- XXX rearrange entities to match physical layout when l10n isn't an issue -->
|
||||||
<!-- LOCALIZATION NOTE (clearTimeDuration.*): "Time range to clear" dropdown.
|
<!-- LOCALIZATION NOTE (clearTimeDuration.*): "Time range to clear" dropdown.
|
||||||
|
|
|
||||||
|
|
@ -341,12 +341,20 @@ function prompt(aBrowser, aRequest) {
|
||||||
let { audioDevices, videoDevices, sharingScreen, sharingAudio,
|
let { audioDevices, videoDevices, sharingScreen, sharingAudio,
|
||||||
requestTypes } = aRequest;
|
requestTypes } = aRequest;
|
||||||
|
|
||||||
|
let uri;
|
||||||
|
try {
|
||||||
|
// This fails for principals that serialize to "null", e.g. file URIs.
|
||||||
|
uri = Services.io.newURI(aRequest.origin);
|
||||||
|
} catch (e) {
|
||||||
|
uri = Services.io.newURI(aRequest.documentURI);
|
||||||
|
}
|
||||||
|
|
||||||
// If the user has already denied access once in this tab,
|
// If the user has already denied access once in this tab,
|
||||||
// deny again without even showing the notification icon.
|
// deny again without even showing the notification icon.
|
||||||
if ((audioDevices.length && SitePermissions
|
if ((audioDevices.length && SitePermissions
|
||||||
.get(null, "microphone", aBrowser).state == SitePermissions.BLOCK) ||
|
.get(uri, "microphone", aBrowser).state == SitePermissions.BLOCK) ||
|
||||||
(videoDevices.length && SitePermissions
|
(videoDevices.length && SitePermissions
|
||||||
.get(null, sharingScreen ? "screen" : "camera", aBrowser).state == SitePermissions.BLOCK)) {
|
.get(uri, sharingScreen ? "screen" : "camera", aBrowser).state == SitePermissions.BLOCK)) {
|
||||||
denyRequest(aBrowser, aRequest);
|
denyRequest(aBrowser, aRequest);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -356,14 +364,6 @@ function prompt(aBrowser, aRequest) {
|
||||||
aBrowser.dispatchEvent(new aBrowser.ownerGlobal
|
aBrowser.dispatchEvent(new aBrowser.ownerGlobal
|
||||||
.CustomEvent("PermissionStateChange"));
|
.CustomEvent("PermissionStateChange"));
|
||||||
|
|
||||||
let uri;
|
|
||||||
try {
|
|
||||||
// This fails for principals that serialize to "null", e.g. file URIs.
|
|
||||||
uri = Services.io.newURI(aRequest.origin);
|
|
||||||
} catch (e) {
|
|
||||||
uri = Services.io.newURI(aRequest.documentURI);
|
|
||||||
}
|
|
||||||
|
|
||||||
let chromeDoc = aBrowser.ownerDocument;
|
let chromeDoc = aBrowser.ownerDocument;
|
||||||
let stringBundle = chromeDoc.defaultView.gNavigatorBundle;
|
let stringBundle = chromeDoc.defaultView.gNavigatorBundle;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -104,16 +104,19 @@ if test -n "$ENABLE_CLANG_PLUGIN"; then
|
||||||
AC_LANG_SAVE
|
AC_LANG_SAVE
|
||||||
AC_LANG_CPLUSPLUS
|
AC_LANG_CPLUSPLUS
|
||||||
_SAVE_CXXFLAGS="$CXXFLAGS"
|
_SAVE_CXXFLAGS="$CXXFLAGS"
|
||||||
|
_SAVE_CPPFLAGS="$CPPFLAGS"
|
||||||
_SAVE_CXX="$CXX"
|
_SAVE_CXX="$CXX"
|
||||||
_SAVE_MACOSX_DEPLOYMENT_TARGET="$MACOSX_DEPLOYMENT_TARGET"
|
_SAVE_MACOSX_DEPLOYMENT_TARGET="$MACOSX_DEPLOYMENT_TARGET"
|
||||||
unset MACOSX_DEPLOYMENT_TARGET
|
unset MACOSX_DEPLOYMENT_TARGET
|
||||||
CXXFLAGS="${LLVM_CXXFLAGS}"
|
CXXFLAGS="${LLVM_CXXFLAGS}"
|
||||||
|
CPPFLAGS=""
|
||||||
CXX="${HOST_CXX}"
|
CXX="${HOST_CXX}"
|
||||||
AC_TRY_COMPILE([#include "clang/ASTMatchers/ASTMatchers.h"],
|
AC_TRY_COMPILE([#include "clang/ASTMatchers/ASTMatchers.h"],
|
||||||
[clang::ast_matchers::cxxConstructExpr();],
|
[clang::ast_matchers::cxxConstructExpr();],
|
||||||
ac_cv_have_new_ASTMatcher_names="yes",
|
ac_cv_have_new_ASTMatcher_names="yes",
|
||||||
ac_cv_have_new_ASTMatcher_names="no")
|
ac_cv_have_new_ASTMatcher_names="no")
|
||||||
CXX="$_SAVE_CXX"
|
CXX="$_SAVE_CXX"
|
||||||
|
CPPFLAGS="$_SAVE_CPPFLAGS"
|
||||||
CXXFLAGS="$_SAVE_CXXFLAGS"
|
CXXFLAGS="$_SAVE_CXXFLAGS"
|
||||||
export MACOSX_DEPLOYMENT_TARGET="$_SAVE_MACOSX_DEPLOYMENT_TARGET"
|
export MACOSX_DEPLOYMENT_TARGET="$_SAVE_MACOSX_DEPLOYMENT_TARGET"
|
||||||
AC_LANG_RESTORE
|
AC_LANG_RESTORE
|
||||||
|
|
@ -131,10 +134,12 @@ if test -n "$ENABLE_CLANG_PLUGIN"; then
|
||||||
AC_LANG_SAVE
|
AC_LANG_SAVE
|
||||||
AC_LANG_CPLUSPLUS
|
AC_LANG_CPLUSPLUS
|
||||||
_SAVE_CXXFLAGS="$CXXFLAGS"
|
_SAVE_CXXFLAGS="$CXXFLAGS"
|
||||||
|
_SAVE_CPPFLAGS="$CPPFLAGS"
|
||||||
_SAVE_CXX="$CXX"
|
_SAVE_CXX="$CXX"
|
||||||
_SAVE_MACOSX_DEPLOYMENT_TARGET="$MACOSX_DEPLOYMENT_TARGET"
|
_SAVE_MACOSX_DEPLOYMENT_TARGET="$MACOSX_DEPLOYMENT_TARGET"
|
||||||
unset MACOSX_DEPLOYMENT_TARGET
|
unset MACOSX_DEPLOYMENT_TARGET
|
||||||
CXXFLAGS="${LLVM_CXXFLAGS}"
|
CXXFLAGS="${LLVM_CXXFLAGS}"
|
||||||
|
CPPFLAGS=""
|
||||||
CXX="${HOST_CXX}"
|
CXX="${HOST_CXX}"
|
||||||
AC_TRY_COMPILE([#include "clang/ASTMatchers/ASTMatchers.h"],
|
AC_TRY_COMPILE([#include "clang/ASTMatchers/ASTMatchers.h"],
|
||||||
[using namespace clang::ast_matchers;
|
[using namespace clang::ast_matchers;
|
||||||
|
|
@ -143,6 +148,7 @@ if test -n "$ENABLE_CLANG_PLUGIN"; then
|
||||||
ac_cv_has_accepts_ignoringParenImpCasts="yes",
|
ac_cv_has_accepts_ignoringParenImpCasts="yes",
|
||||||
ac_cv_has_accepts_ignoringParenImpCasts="no")
|
ac_cv_has_accepts_ignoringParenImpCasts="no")
|
||||||
CXX="$_SAVE_CXX"
|
CXX="$_SAVE_CXX"
|
||||||
|
CPPFLAGS="$_SAVE_CPPFLAGS"
|
||||||
CXXFLAGS="$_SAVE_CXXFLAGS"
|
CXXFLAGS="$_SAVE_CXXFLAGS"
|
||||||
export MACOSX_DEPLOYMENT_TARGET="$_SAVE_MACOSX_DEPLOYMENT_TARGET"
|
export MACOSX_DEPLOYMENT_TARGET="$_SAVE_MACOSX_DEPLOYMENT_TARGET"
|
||||||
AC_LANG_RESTORE
|
AC_LANG_RESTORE
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ function TabboxPanel({
|
||||||
activeTabId,
|
activeTabId,
|
||||||
cloneSelectedRequest = () => {},
|
cloneSelectedRequest = () => {},
|
||||||
connector,
|
connector,
|
||||||
|
hideToggleButton,
|
||||||
openLink,
|
openLink,
|
||||||
request,
|
request,
|
||||||
selectTab,
|
selectTab,
|
||||||
|
|
@ -56,7 +57,8 @@ function TabboxPanel({
|
||||||
onSelect: selectTab,
|
onSelect: selectTab,
|
||||||
renderOnlySelected: true,
|
renderOnlySelected: true,
|
||||||
showAllTabsMenu: true,
|
showAllTabsMenu: true,
|
||||||
sidebarToggleButton: {
|
sidebarToggleButton: hideToggleButton ? null :
|
||||||
|
{
|
||||||
collapsed: false,
|
collapsed: false,
|
||||||
collapsePaneTitle: COLLAPSE_DETAILS_PANE,
|
collapsePaneTitle: COLLAPSE_DETAILS_PANE,
|
||||||
expandPaneTitle: "",
|
expandPaneTitle: "",
|
||||||
|
|
@ -144,6 +146,7 @@ TabboxPanel.propTypes = {
|
||||||
request: PropTypes.object,
|
request: PropTypes.object,
|
||||||
selectTab: PropTypes.func.isRequired,
|
selectTab: PropTypes.func.isRequired,
|
||||||
sourceMapService: PropTypes.object,
|
sourceMapService: PropTypes.object,
|
||||||
|
hideToggleButton: PropTypes.boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = TabboxPanel;
|
module.exports = TabboxPanel;
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,7 @@ function NetworkEventMessage({
|
||||||
selectTab: (tabId) => {
|
selectTab: (tabId) => {
|
||||||
dispatch(actions.selectNetworkMessageTab(tabId));
|
dispatch(actions.selectNetworkMessageTab(tabId));
|
||||||
},
|
},
|
||||||
|
hideToggleButton: true,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,9 @@ async function openRequestAfterUpdates(target, hud) {
|
||||||
let urlNode = messageNode.querySelector(".url");
|
let urlNode = messageNode.querySelector(".url");
|
||||||
urlNode.click();
|
urlNode.click();
|
||||||
|
|
||||||
|
let toggleButtonNode = messageNode.querySelector(".sidebar-toggle");
|
||||||
|
ok(!toggleButtonNode, "Sidebar toggle button shouldn't be shown");
|
||||||
|
|
||||||
await payload;
|
await payload;
|
||||||
await testNetworkMessage(toolbox, messageNode);
|
await testNetworkMessage(toolbox, messageNode);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -214,7 +214,6 @@
|
||||||
#ifdef MOZ_PLACES
|
#ifdef MOZ_PLACES
|
||||||
#include "nsIFaviconService.h"
|
#include "nsIFaviconService.h"
|
||||||
#include "mozIPlacesPendingOperation.h"
|
#include "mozIPlacesPendingOperation.h"
|
||||||
#include "mozIAsyncFavicons.h"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if NS_PRINT_PREVIEW
|
#if NS_PRINT_PREVIEW
|
||||||
|
|
@ -9121,7 +9120,7 @@ nsDocShell::CopyFavicon(nsIURI* aOldURI,
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MOZ_PLACES
|
#ifdef MOZ_PLACES
|
||||||
nsCOMPtr<mozIAsyncFavicons> favSvc =
|
nsCOMPtr<nsIFaviconService> favSvc =
|
||||||
do_GetService("@mozilla.org/browser/favicon-service;1");
|
do_GetService("@mozilla.org/browser/favicon-service;1");
|
||||||
if (favSvc) {
|
if (favSvc) {
|
||||||
favSvc->CopyFavicons(aOldURI, aNewURI,
|
favSvc->CopyFavicons(aOldURI, aNewURI,
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ SpecialPowers.registerConsoleListener(function ConsoleMsgListener(aMsg) {
|
||||||
if (aMsg.message == "SENTINEL") {
|
if (aMsg.message == "SENTINEL") {
|
||||||
is(consoleCount, 0);
|
is(consoleCount, 0);
|
||||||
SimpleTest.executeSoon(finish);
|
SimpleTest.executeSoon(finish);
|
||||||
} else {
|
} else if (aMsg.message.includes("Content Security Policy")) {
|
||||||
++consoleCount;
|
++consoleCount;
|
||||||
ok(false, "Must never see a console warning here");
|
ok(false, "Must never see a console warning here");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -570,6 +570,12 @@ WebRenderLayerManager::SetTransactionIdAllocator(TransactionIdAllocator* aAlloca
|
||||||
mTransactionIdAllocator = aAllocator;
|
mTransactionIdAllocator = aAllocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TransactionId
|
||||||
|
WebRenderLayerManager::GetLastTransactionId()
|
||||||
|
{
|
||||||
|
return mLatestTransactionId;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
WebRenderLayerManager::AddDidCompositeObserver(DidCompositeObserver* aObserver)
|
WebRenderLayerManager::AddDidCompositeObserver(DidCompositeObserver* aObserver)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,7 @@ public:
|
||||||
virtual TextureFactoryIdentifier GetTextureFactoryIdentifier() override;
|
virtual TextureFactoryIdentifier GetTextureFactoryIdentifier() override;
|
||||||
|
|
||||||
virtual void SetTransactionIdAllocator(TransactionIdAllocator* aAllocator) override;
|
virtual void SetTransactionIdAllocator(TransactionIdAllocator* aAllocator) override;
|
||||||
|
virtual TransactionId GetLastTransactionId() override;
|
||||||
|
|
||||||
virtual void AddDidCompositeObserver(DidCompositeObserver* aObserver) override;
|
virtual void AddDidCompositeObserver(DidCompositeObserver* aObserver) override;
|
||||||
virtual void RemoveDidCompositeObserver(DidCompositeObserver* aObserver) override;
|
virtual void RemoveDidCompositeObserver(DidCompositeObserver* aObserver) override;
|
||||||
|
|
|
||||||
|
|
@ -36,11 +36,14 @@ function StartListener(event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function IterationListener(event) {
|
function IterationListener(event) {
|
||||||
setTimeout(RemoveReftestWait, 0);
|
window.addEventListener("MozAfterPaint", () => {
|
||||||
|
requestAnimationFrame(RemoveReftestWait);
|
||||||
|
}, { once: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
function RemoveReftestWait() {
|
function RemoveReftestWait() {
|
||||||
document.documentElement.classList.remove("reftest-wait");
|
document.documentElement.classList.remove("reftest-wait");
|
||||||
|
document.documentElement.classList.add("reftest-ignore-pending-paints");
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<!DOCTYPE HTML>
|
<!DOCTYPE HTML>
|
||||||
<html class="reftest-wait">
|
<html class="reftest-wait reftest-no-flush">
|
||||||
<title>Testcase, bug 1176969</title>
|
<title>Testcase, bug 1176969</title>
|
||||||
<style>
|
<style>
|
||||||
|
|
||||||
|
|
@ -46,11 +46,14 @@ body { padding: 50px }
|
||||||
document.getElementById("parent").addEventListener("animationiteration", IterationListener);
|
document.getElementById("parent").addEventListener("animationiteration", IterationListener);
|
||||||
|
|
||||||
function IterationListener(event) {
|
function IterationListener(event) {
|
||||||
setTimeout(RemoveReftestWait, 0);
|
window.addEventListener("MozAfterPaint", () => {
|
||||||
|
requestAnimationFrame(RemoveReftestWait);
|
||||||
|
}, { once: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
function RemoveReftestWait() {
|
function RemoveReftestWait() {
|
||||||
document.documentElement.classList.remove("reftest-wait");
|
document.documentElement.classList.remove("reftest-wait");
|
||||||
|
document.documentElement.classList.add("reftest-ignore-pending-paints");
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<!DOCTYPE HTML>
|
<!DOCTYPE HTML>
|
||||||
<html class="reftest-wait">
|
<html class="reftest-wait reftest-no-flush">
|
||||||
<title>Testcase, bug 1176969</title>
|
<title>Testcase, bug 1176969</title>
|
||||||
<style>
|
<style>
|
||||||
|
|
||||||
|
|
@ -48,11 +48,14 @@ function StartListener(event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function IterationListener(event) {
|
function IterationListener(event) {
|
||||||
setTimeout(RemoveReftestWait, 0);
|
window.addEventListener("MozAfterPaint", () => {
|
||||||
|
requestAnimationFrame(RemoveReftestWait);
|
||||||
|
}, { once: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
function RemoveReftestWait() {
|
function RemoveReftestWait() {
|
||||||
document.documentElement.classList.remove("reftest-wait");
|
document.documentElement.classList.remove("reftest-wait");
|
||||||
|
document.documentElement.classList.add("reftest-ignore-pending-paints");
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ fuzzy(3,99) == animate-cube-degrees.html animate-cube-degrees-ref.html # subpixe
|
||||||
!= animate-cube-degrees-ref.html animate-cube-degrees-zoom-ref.html
|
!= animate-cube-degrees-ref.html animate-cube-degrees-zoom-ref.html
|
||||||
fuzzy-if(gtkWidget,128,100) fuzzy-if(Android||OSX==1010||(gtkWidget&&layersGPUAccelerated),143,100) fuzzy-if(winWidget||OSX<1010,141,100) == preserves3d-nested.html preserves3d-nested-ref.html
|
fuzzy-if(gtkWidget,128,100) fuzzy-if(Android||OSX==1010||(gtkWidget&&layersGPUAccelerated),143,100) fuzzy-if(winWidget||OSX<1010,141,100) == preserves3d-nested.html preserves3d-nested-ref.html
|
||||||
fuzzy-if(cocoaWidget,128,9) == animate-preserve3d-parent.html animate-preserve3d-ref.html # intermittently fuzzy on Mac
|
fuzzy-if(cocoaWidget,128,9) == animate-preserve3d-parent.html animate-preserve3d-ref.html # intermittently fuzzy on Mac
|
||||||
fuzzy-if(cocoaWidget,128,9) == animate-preserve3d-child.html animate-preserve3d-ref.html # intermittently fuzzy on Mac
|
fuzzy-if(cocoaWidget,128,9) skip-if(Android) == animate-preserve3d-child.html animate-preserve3d-ref.html # intermittently fuzzy on Mac, bug 1461311 for Android
|
||||||
== animate-backface-hidden.html about:blank
|
== animate-backface-hidden.html about:blank
|
||||||
== 1245450-1.html green-rect.html
|
== 1245450-1.html green-rect.html
|
||||||
fuzzy(1,2000) == opacity-preserve3d-1.html opacity-preserve3d-1-ref.html
|
fuzzy(1,2000) == opacity-preserve3d-1.html opacity-preserve3d-1-ref.html
|
||||||
|
|
|
||||||
|
|
@ -665,3 +665,20 @@ to push a layer-tree update to the compositor before taking the snapshot.
|
||||||
Setting the "reftest-no-sync-layers" attribute on the root element skips this
|
Setting the "reftest-no-sync-layers" attribute on the root element skips this
|
||||||
step, enabling testing that layer-tree updates are being correctly generated.
|
step, enabling testing that layer-tree updates are being correctly generated.
|
||||||
However the test must manually wait for a MozAfterPaint event before ending.
|
However the test must manually wait for a MozAfterPaint event before ending.
|
||||||
|
|
||||||
|
Avoid hanging on long/infinite animation tests: reftest-ignore-pending-paints
|
||||||
|
=============================================================================
|
||||||
|
|
||||||
|
If a test contains a long animation, and the desired behaviour is to take a
|
||||||
|
snapshot partway through the animation, the usual procedure is to have a part
|
||||||
|
of the animation that is visually unchanging, and when the test page reaches that
|
||||||
|
part, it removes the reftest-wait to allow the harness to finish. However, this
|
||||||
|
relies on an optimization inside Gecko that stops repaints if it detects that
|
||||||
|
nothing will visually change (by detecting an empty invalidation area, for
|
||||||
|
example). In some cases, this optimization may not trigger (e.g. with WebRender
|
||||||
|
enabled). For such cases, the reftest-wait class attribute can be replaced by
|
||||||
|
reftest-ignore-pending-paints on the root html element, and this will make the
|
||||||
|
harness ignore any pending repaints (i.e. stop listening for MozAfterPaint) and
|
||||||
|
just go ahead and finish the test.
|
||||||
|
Note that any reftest that attempts to use this feature without animations will
|
||||||
|
fail with an error.
|
||||||
|
|
|
||||||
|
|
@ -422,10 +422,26 @@ function shouldWaitForExplicitPaintWaiters() {
|
||||||
return gExplicitPendingPaintCount > 0;
|
return gExplicitPendingPaintCount > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function shouldWaitForPendingPaints() {
|
function shouldWaitForPendingPaints(contentRootElement) {
|
||||||
// if gHaveCanvasSnapshot is false, we're not taking snapshots so
|
// if gHaveCanvasSnapshot is false, we're not taking snapshots so
|
||||||
// there is no need to wait for pending paints to be flushed.
|
// there is no need to wait for pending paints to be flushed.
|
||||||
return gHaveCanvasSnapshot && windowUtils().isMozAfterPaintPending;
|
return gHaveCanvasSnapshot &&
|
||||||
|
!shouldIgnorePendingMozAfterPaints(contentRootElement) &&
|
||||||
|
windowUtils().isMozAfterPaintPending;
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldIgnorePendingMozAfterPaints(contentRootElement) {
|
||||||
|
// use getAttribute because className works differently in HTML and SVG
|
||||||
|
var ignore = contentRootElement &&
|
||||||
|
contentRootElement.hasAttribute('class') &&
|
||||||
|
contentRootElement.getAttribute('class').split(/\s+/)
|
||||||
|
.includes("reftest-ignore-pending-paints");
|
||||||
|
// getAnimations is nightly-only, so check it exists before calling it
|
||||||
|
if (ignore && contentRootElement.ownerDocument.getAnimations
|
||||||
|
&& contentRootElement.ownerDocument.getAnimations().length == 0) {
|
||||||
|
LogError("reftest-ignore-pending-paints should only be used on documents with animations!");
|
||||||
|
}
|
||||||
|
return ignore;
|
||||||
}
|
}
|
||||||
|
|
||||||
function shouldWaitForReftestWaitRemoval(contentRootElement) {
|
function shouldWaitForReftestWaitRemoval(contentRootElement) {
|
||||||
|
|
@ -611,13 +627,13 @@ function WaitForTestEnd(contentRootElement, inPrintMode, spellCheckedElements) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case STATE_WAITING_TO_FIRE_INVALIDATE_EVENT: {
|
case STATE_WAITING_TO_FIRE_INVALIDATE_EVENT: {
|
||||||
LogInfo("MakeProgress: STATE_WAITING_TO_FIRE_INVALIDATE_EVENT");
|
LogInfo("MakeProgress: STATE_WAITING_TO_FIRE_INVALIDATE_EVENT");
|
||||||
if (shouldWaitForExplicitPaintWaiters() || shouldWaitForPendingPaints()) {
|
if (shouldWaitForExplicitPaintWaiters() || shouldWaitForPendingPaints(contentRootElement)) {
|
||||||
gFailureReason = "timed out waiting for pending paint count to reach zero";
|
gFailureReason = "timed out waiting for pending paint count to reach zero";
|
||||||
if (shouldWaitForExplicitPaintWaiters()) {
|
if (shouldWaitForExplicitPaintWaiters()) {
|
||||||
gFailureReason += " (waiting for MozPaintWaitFinished)";
|
gFailureReason += " (waiting for MozPaintWaitFinished)";
|
||||||
LogInfo("MakeProgress: waiting for MozPaintWaitFinished");
|
LogInfo("MakeProgress: waiting for MozPaintWaitFinished");
|
||||||
}
|
}
|
||||||
if (shouldWaitForPendingPaints()) {
|
if (shouldWaitForPendingPaints(contentRootElement)) {
|
||||||
gFailureReason += " (waiting for MozAfterPaint)";
|
gFailureReason += " (waiting for MozAfterPaint)";
|
||||||
LogInfo("MakeProgress: waiting for MozAfterPaint");
|
LogInfo("MakeProgress: waiting for MozAfterPaint");
|
||||||
}
|
}
|
||||||
|
|
@ -655,7 +671,7 @@ function WaitForTestEnd(contentRootElement, inPrintMode, spellCheckedElements) {
|
||||||
// MozReftestInvalidate handler removed reftest-wait.
|
// MozReftestInvalidate handler removed reftest-wait.
|
||||||
// We expect something to have been invalidated...
|
// We expect something to have been invalidated...
|
||||||
FlushRendering(FlushMode.ALL);
|
FlushRendering(FlushMode.ALL);
|
||||||
if (!shouldWaitForPendingPaints() && !shouldWaitForExplicitPaintWaiters()) {
|
if (!shouldWaitForPendingPaints(contentRootElement) && !shouldWaitForExplicitPaintWaiters()) {
|
||||||
LogWarning("MozInvalidateEvent didn't invalidate");
|
LogWarning("MozInvalidateEvent didn't invalidate");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -720,14 +736,14 @@ function WaitForTestEnd(contentRootElement, inPrintMode, spellCheckedElements) {
|
||||||
|
|
||||||
case STATE_WAITING_TO_FINISH:
|
case STATE_WAITING_TO_FINISH:
|
||||||
LogInfo("MakeProgress: STATE_WAITING_TO_FINISH");
|
LogInfo("MakeProgress: STATE_WAITING_TO_FINISH");
|
||||||
if (shouldWaitForExplicitPaintWaiters() || shouldWaitForPendingPaints()) {
|
if (shouldWaitForExplicitPaintWaiters() || shouldWaitForPendingPaints(contentRootElement)) {
|
||||||
gFailureReason = "timed out waiting for pending paint count to " +
|
gFailureReason = "timed out waiting for pending paint count to " +
|
||||||
"reach zero (after reftest-wait removed and switch to print mode)";
|
"reach zero (after reftest-wait removed and switch to print mode)";
|
||||||
if (shouldWaitForExplicitPaintWaiters()) {
|
if (shouldWaitForExplicitPaintWaiters()) {
|
||||||
gFailureReason += " (waiting for MozPaintWaitFinished)";
|
gFailureReason += " (waiting for MozPaintWaitFinished)";
|
||||||
LogInfo("MakeProgress: waiting for MozPaintWaitFinished");
|
LogInfo("MakeProgress: waiting for MozPaintWaitFinished");
|
||||||
}
|
}
|
||||||
if (shouldWaitForPendingPaints()) {
|
if (shouldWaitForPendingPaints(contentRootElement)) {
|
||||||
gFailureReason += " (waiting for MozAfterPaint)";
|
gFailureReason += " (waiting for MozAfterPaint)";
|
||||||
LogInfo("MakeProgress: waiting for MozAfterPaint");
|
LogInfo("MakeProgress: waiting for MozAfterPaint");
|
||||||
}
|
}
|
||||||
|
|
@ -1080,6 +1096,15 @@ function LoadURI(uri)
|
||||||
webNavigation().loadURI(uri, flags, null, null, null);
|
webNavigation().loadURI(uri, flags, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function LogError(str)
|
||||||
|
{
|
||||||
|
if (gVerbose) {
|
||||||
|
sendSyncMessage("reftest:Log", { type: "error", msg: str });
|
||||||
|
} else {
|
||||||
|
sendAsyncMessage("reftest:Log", { type: "error", msg: str });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function LogWarning(str)
|
function LogWarning(str)
|
||||||
{
|
{
|
||||||
if (gVerbose) {
|
if (gVerbose) {
|
||||||
|
|
|
||||||
|
|
@ -1512,6 +1512,9 @@ function RecvLog(type, msg)
|
||||||
TestBuffer(msg);
|
TestBuffer(msg);
|
||||||
} else if (type == "warning") {
|
} else if (type == "warning") {
|
||||||
logger.warning(msg);
|
logger.warning(msg);
|
||||||
|
} else if (type == "error") {
|
||||||
|
logger.error("REFTEST TEST-UNEXPECTED-FAIL | " + g.currentURL + " | " + msg + "\n");
|
||||||
|
++g.testResults.Exception;
|
||||||
} else {
|
} else {
|
||||||
logger.error("REFTEST TEST-UNEXPECTED-FAIL | " + g.currentURL + " | unknown log type " + type + "\n");
|
logger.error("REFTEST TEST-UNEXPECTED-FAIL | " + g.currentURL + " | unknown log type " + type + "\n");
|
||||||
++g.testResults.Exception;
|
++g.testResults.Exception;
|
||||||
|
|
|
||||||
|
|
@ -106,19 +106,10 @@ pref("browser.cache.compression_level", 0);
|
||||||
pref("browser.download.forbid_open_with", false);
|
pref("browser.download.forbid_open_with", false);
|
||||||
|
|
||||||
// Remove navigator.registerContentHandler
|
// Remove navigator.registerContentHandler
|
||||||
#ifdef EARLY_BETA_OR_EARLIER
|
|
||||||
pref("dom.registerContentHandler.enabled", false);
|
pref("dom.registerContentHandler.enabled", false);
|
||||||
#else
|
|
||||||
pref("dom.registerContentHandler.enabled", true);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Nightly will have insecure registerProtocolHandler disabled by default
|
// Insecure registerProtocolHandler is disabled by default
|
||||||
// Beta and Stable will remain enabled until Firefox 62 providing deprecation stats.
|
|
||||||
#ifdef NIGHTLY_BUILD
|
|
||||||
pref("dom.registerProtocolHandler.insecure.enabled", false);
|
pref("dom.registerProtocolHandler.insecure.enabled", false);
|
||||||
#else
|
|
||||||
pref("dom.registerProtocolHandler.insecure.enabled", true);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Whether or not testing features are enabled.
|
// Whether or not testing features are enabled.
|
||||||
pref("dom.quotaManager.testing", false);
|
pref("dom.quotaManager.testing", false);
|
||||||
|
|
|
||||||
|
|
@ -893,6 +893,9 @@ class BaseMarionetteTestRunner(object):
|
||||||
version_info=self.version_info,
|
version_info=self.version_info,
|
||||||
device_info=device_info)
|
device_info=device_info)
|
||||||
|
|
||||||
|
if self.shuffle:
|
||||||
|
self.logger.info("Using shuffle seed: %d" % self.shuffle_seed)
|
||||||
|
|
||||||
self._log_skipped_tests()
|
self._log_skipped_tests()
|
||||||
|
|
||||||
interrupted = None
|
interrupted = None
|
||||||
|
|
@ -925,8 +928,6 @@ class BaseMarionetteTestRunner(object):
|
||||||
|
|
||||||
for run_tests in self.mixin_run_tests:
|
for run_tests in self.mixin_run_tests:
|
||||||
run_tests(tests)
|
run_tests(tests)
|
||||||
if self.shuffle:
|
|
||||||
self.logger.info("Using shuffle seed: %d" % self.shuffle_seed)
|
|
||||||
|
|
||||||
self.logger.suite_end()
|
self.logger.suite_end()
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@
|
||||||
#include "nsToolkitCompsCID.h"
|
#include "nsToolkitCompsCID.h"
|
||||||
|
|
||||||
#ifdef MOZ_PLACES
|
#ifdef MOZ_PLACES
|
||||||
#include "mozIAsyncFavicons.h"
|
|
||||||
#include "nsIFaviconService.h"
|
#include "nsIFaviconService.h"
|
||||||
#endif // MOZ_PLACES
|
#endif // MOZ_PLACES
|
||||||
|
|
||||||
|
|
@ -104,7 +103,7 @@ ShowWithIconBackend(nsIAlertsService* aBackend, nsIAlertNotification* aAlert,
|
||||||
return NS_ERROR_NOT_IMPLEMENTED;
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<mozIAsyncFavicons> favicons(do_GetService(
|
nsCOMPtr<nsIFaviconService> favicons(do_GetService(
|
||||||
"@mozilla.org/browser/favicon-service;1"));
|
"@mozilla.org/browser/favicon-service;1"));
|
||||||
NS_ENSURE_TRUE(favicons, NS_ERROR_FAILURE);
|
NS_ENSURE_TRUE(favicons, NS_ERROR_FAILURE);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1872,7 +1872,7 @@ XPCOMUtils.defineLazyGetter(PlacesUtils, "history", function() {
|
||||||
|
|
||||||
XPCOMUtils.defineLazyServiceGetter(PlacesUtils, "favicons",
|
XPCOMUtils.defineLazyServiceGetter(PlacesUtils, "favicons",
|
||||||
"@mozilla.org/browser/favicon-service;1",
|
"@mozilla.org/browser/favicon-service;1",
|
||||||
"mozIAsyncFavicons");
|
"nsIFaviconService");
|
||||||
|
|
||||||
XPCOMUtils.defineLazyServiceGetter(this, "bmsvc",
|
XPCOMUtils.defineLazyServiceGetter(this, "bmsvc",
|
||||||
"@mozilla.org/browser/nav-bookmarks-service;1",
|
"@mozilla.org/browser/nav-bookmarks-service;1",
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ XPIDL_MODULE = 'places'
|
||||||
|
|
||||||
if CONFIG['MOZ_PLACES']:
|
if CONFIG['MOZ_PLACES']:
|
||||||
XPIDL_SOURCES += [
|
XPIDL_SOURCES += [
|
||||||
'mozIAsyncFavicons.idl',
|
|
||||||
'mozIAsyncHistory.idl',
|
'mozIAsyncHistory.idl',
|
||||||
'mozIAsyncLivemarks.idl',
|
'mozIAsyncLivemarks.idl',
|
||||||
'mozIColorAnalyzer.idl',
|
'mozIColorAnalyzer.idl',
|
||||||
|
|
|
||||||
|
|
@ -1,211 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#include "nsISupports.idl"
|
|
||||||
|
|
||||||
interface nsIURI;
|
|
||||||
interface nsIFaviconDataCallback;
|
|
||||||
interface nsIPrincipal;
|
|
||||||
interface mozIPlacesPendingOperation;
|
|
||||||
|
|
||||||
[scriptable, uuid(a9c81797-9133-4823-b55f-3646e67cfd41)]
|
|
||||||
interface mozIAsyncFavicons : nsISupports
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Declares that a given page uses a favicon with the given URI and
|
|
||||||
* attempts to fetch and save the icon data by loading the favicon URI
|
|
||||||
* through an async network request.
|
|
||||||
*
|
|
||||||
* If the icon data already exists, we won't try to reload the icon unless
|
|
||||||
* aForceReload is true. Similarly, if the icon is in the failed favicon
|
|
||||||
* cache we won't do anything unless aForceReload is true, in which case
|
|
||||||
* we'll try to reload the favicon.
|
|
||||||
*
|
|
||||||
* This function will only save favicons for pages that are already stored in
|
|
||||||
* the database, like visited pages or bookmarks. For any other URIs, it
|
|
||||||
* will succeed but do nothing. This function will also ignore the error
|
|
||||||
* page favicon URI (see FAVICON_ERRORPAGE_URL below).
|
|
||||||
*
|
|
||||||
* Icons that fail to load will automatically be added to the failed favicon
|
|
||||||
* cache, and this function will not save favicons for non-bookmarked URIs
|
|
||||||
* when history is disabled.
|
|
||||||
*
|
|
||||||
* @note This function is identical to
|
|
||||||
* nsIFaviconService::setAndLoadFaviconForPage.
|
|
||||||
*
|
|
||||||
* @param aPageURI
|
|
||||||
* URI of the page whose favicon is being set.
|
|
||||||
* @param aFaviconURI
|
|
||||||
* URI of the favicon to associate with the page.
|
|
||||||
* @param aForceReload
|
|
||||||
* If aForceReload is false, we try to reload the favicon only if we
|
|
||||||
* don't have it or it has expired from the cache. Setting
|
|
||||||
* aForceReload to true causes us to reload the favicon even if we
|
|
||||||
* have a usable copy.
|
|
||||||
* @param aFaviconLoadType
|
|
||||||
* Set to FAVICON_LOAD_PRIVATE if the favicon is loaded from a private
|
|
||||||
* browsing window. Set to FAVICON_LOAD_NON_PRIVATE otherwise.
|
|
||||||
* @param [optional] aCallback
|
|
||||||
* Once we're done setting and/or fetching the favicon, we invoke this
|
|
||||||
* callback.
|
|
||||||
* @param [optional] aLoadingPrincipal
|
|
||||||
* Principal of the page whose favicon is being set. If this argument
|
|
||||||
* is omitted, the loadingPrincipal defaults to the nullPrincipal.
|
|
||||||
* @param [optional] aRequestContextID
|
|
||||||
* used to inform Necko of how to link the
|
|
||||||
* favicon request with other requests in the same tab.
|
|
||||||
*
|
|
||||||
* @see nsIFaviconDataCallback in nsIFaviconService.idl.
|
|
||||||
*/
|
|
||||||
mozIPlacesPendingOperation setAndFetchFaviconForPage(
|
|
||||||
in nsIURI aPageURI,
|
|
||||||
in nsIURI aFaviconURI,
|
|
||||||
in boolean aForceReload,
|
|
||||||
in unsigned long aFaviconLoadType,
|
|
||||||
[optional] in nsIFaviconDataCallback aCallback,
|
|
||||||
[optional] in nsIPrincipal aLoadingPrincipal,
|
|
||||||
[optional] in unsigned long long aRequestContextID);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the data for a given favicon URI either by replacing existing data in
|
|
||||||
* the database or taking the place of otherwise fetched icon data when
|
|
||||||
* calling setAndFetchFaviconForPage later.
|
|
||||||
*
|
|
||||||
* Favicon data for favicon URIs that are not associated with a page URI via
|
|
||||||
* setAndFetchFaviconForPage will be stored in memory, but may be expired at
|
|
||||||
* any time, so you should make an effort to associate favicon URIs with page
|
|
||||||
* URIs as soon as possible.
|
|
||||||
*
|
|
||||||
* It's better to not use this function for chrome: icon URIs since you can
|
|
||||||
* reference the chrome image yourself. getFaviconLinkForIcon/Page will ignore
|
|
||||||
* any associated data if the favicon URI is "chrome:" and just return the
|
|
||||||
* same chrome URI.
|
|
||||||
*
|
|
||||||
* This function does NOT send out notifications that the data has changed.
|
|
||||||
* Pages using this favicons that are visible in history or bookmarks views
|
|
||||||
* will keep the old icon until they have been refreshed by other means.
|
|
||||||
*
|
|
||||||
* This function tries to optimize the favicon size, if it is bigger
|
|
||||||
* than a defined limit we will try to convert it to a 16x16 png image.
|
|
||||||
* If the conversion fails and favicon is still bigger than our max accepted
|
|
||||||
* size it won't be saved.
|
|
||||||
*
|
|
||||||
* @param aFaviconURI
|
|
||||||
* URI of the favicon whose data is being set.
|
|
||||||
* @param aData
|
|
||||||
* Binary contents of the favicon to save
|
|
||||||
* @param aDataLength
|
|
||||||
* Length of binary data
|
|
||||||
* @param aMimeType
|
|
||||||
* MIME type of the data to store. This is important so that we know
|
|
||||||
* what to report when the favicon is used. You should always set this
|
|
||||||
* param unless you are clearing an icon.
|
|
||||||
* @param [optional] aExpiration
|
|
||||||
* Time in microseconds since the epoch when this favicon expires.
|
|
||||||
* Until this time, we won't try to load it again.
|
|
||||||
* @throws NS_ERROR_FAILURE
|
|
||||||
* Thrown if the favicon is overbloated and won't be saved to the db.
|
|
||||||
*/
|
|
||||||
void replaceFaviconData(in nsIURI aFaviconURI,
|
|
||||||
[const,array,size_is(aDataLen)] in octet aData,
|
|
||||||
in unsigned long aDataLen,
|
|
||||||
in AUTF8String aMimeType,
|
|
||||||
[optional] in PRTime aExpiration);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Same as replaceFaviconData but the data is provided by a string
|
|
||||||
* containing a data URL.
|
|
||||||
*
|
|
||||||
* @see replaceFaviconData
|
|
||||||
*
|
|
||||||
* @param aFaviconURI
|
|
||||||
* URI of the favicon whose data is being set.
|
|
||||||
* @param aDataURL
|
|
||||||
* string containing a data URL that represents the contents of
|
|
||||||
* the favicon to save
|
|
||||||
* @param [optional] aExpiration
|
|
||||||
* Time in microseconds since the epoch when this favicon expires.
|
|
||||||
* Until this time, we won't try to load it again.
|
|
||||||
* @param [optional] aLoadingPrincipal
|
|
||||||
* Principal of the page whose favicon is being set. If this argument
|
|
||||||
* is omitted, the loadingPrincipal defaults to the nullPrincipal.
|
|
||||||
* @throws NS_ERROR_FAILURE
|
|
||||||
* Thrown if the favicon is overbloated and won't be saved to the db.
|
|
||||||
*/
|
|
||||||
void replaceFaviconDataFromDataURL(in nsIURI aFaviconURI,
|
|
||||||
in AString aDataURL,
|
|
||||||
[optional] in PRTime aExpiration,
|
|
||||||
[optional] in nsIPrincipal aLoadingPrincipal);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the favicon URI associated to the given page, if any.
|
|
||||||
*
|
|
||||||
* @param aPageURI
|
|
||||||
* URI of the page whose favicon URI we're looking up.
|
|
||||||
* @param aCallback
|
|
||||||
* This callback is always invoked to notify the result of the lookup.
|
|
||||||
* The aURI parameter will be the favicon URI, or null when no favicon
|
|
||||||
* is associated with the page or an error occurred while fetching it.
|
|
||||||
* aDataLen will be always 0, aData will be an empty array, and
|
|
||||||
* aMimeType will be an empty string, regardless of whether a favicon
|
|
||||||
* was found.
|
|
||||||
* @param [optional] aPreferredWidth
|
|
||||||
* The preferred icon width, 0 for the biggest available.
|
|
||||||
*
|
|
||||||
* @note If a favicon specific to this page cannot be found, this will try to
|
|
||||||
* fallback to the /favicon.ico for the root domain.
|
|
||||||
*
|
|
||||||
* @see nsIFaviconDataCallback in nsIFaviconService.idl.
|
|
||||||
*/
|
|
||||||
void getFaviconURLForPage(in nsIURI aPageURI,
|
|
||||||
in nsIFaviconDataCallback aCallback,
|
|
||||||
[optional] in unsigned short aPreferredWidth);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the favicon URI and data associated to the given page, if any.
|
|
||||||
* If the page icon is not available, it will try to return the root domain
|
|
||||||
* icon data, when it's known.
|
|
||||||
*
|
|
||||||
* @param aPageURI
|
|
||||||
* URI of the page whose favicon URI and data we're looking up.
|
|
||||||
* @param aCallback
|
|
||||||
* This callback is always invoked to notify the result of the lookup. The aURI
|
|
||||||
* parameter will be the favicon URI, or null when no favicon is
|
|
||||||
* associated with the page or an error occurred while fetching it. If
|
|
||||||
* aURI is not null, the other parameters may contain the favicon data.
|
|
||||||
* However, if no favicon data is currently associated with the favicon
|
|
||||||
* URI, aDataLen will be 0, aData will be an empty array, and aMimeType
|
|
||||||
* will be an empty string.
|
|
||||||
* @param [optional] aPreferredWidth
|
|
||||||
* The preferred icon width, 0 for the biggest available.
|
|
||||||
* @note If a favicon specific to this page cannot be found, this will try to
|
|
||||||
* fallback to the /favicon.ico for the root domain.
|
|
||||||
*
|
|
||||||
* @see nsIFaviconDataCallback in nsIFaviconService.idl.
|
|
||||||
*/
|
|
||||||
void getFaviconDataForPage(in nsIURI aPageURI,
|
|
||||||
in nsIFaviconDataCallback aCallback,
|
|
||||||
[optional] in unsigned short aPreferredWidth);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies cached favicons from a page to another one.
|
|
||||||
*
|
|
||||||
* @param aFromPageURI
|
|
||||||
* URI of the originating page.
|
|
||||||
* @param aToPageURI
|
|
||||||
* URI of the destination page.
|
|
||||||
* @param aFaviconLoadType
|
|
||||||
* Set to FAVICON_LOAD_PRIVATE if the copy is started from a private
|
|
||||||
* browsing window. Set to FAVICON_LOAD_NON_PRIVATE otherwise.
|
|
||||||
* @param [optional] aCallback
|
|
||||||
* Once we're done copying the favicon, we invoke this callback.
|
|
||||||
* If a copy has been done, the callback will report one of the
|
|
||||||
* favicons uri as aFaviconURI, otherwise all the params will be null.
|
|
||||||
*/
|
|
||||||
void copyFavicons(in nsIURI aFromPageURI,
|
|
||||||
in nsIURI aToPageURI,
|
|
||||||
in unsigned long aFaviconLoadType,
|
|
||||||
[optional] in nsIFaviconDataCallback aCallback);
|
|
||||||
};
|
|
||||||
|
|
@ -127,7 +127,6 @@ NS_IMPL_CLASSINFO(nsFaviconService, nullptr, 0, NS_FAVICONSERVICE_CID)
|
||||||
NS_IMPL_ISUPPORTS_CI(
|
NS_IMPL_ISUPPORTS_CI(
|
||||||
nsFaviconService
|
nsFaviconService
|
||||||
, nsIFaviconService
|
, nsIFaviconService
|
||||||
, mozIAsyncFavicons
|
|
||||||
, nsITimerCallback
|
, nsITimerCallback
|
||||||
, nsINamed
|
, nsINamed
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@
|
||||||
#define nsFaviconService_h_
|
#define nsFaviconService_h_
|
||||||
|
|
||||||
#include "nsIFaviconService.h"
|
#include "nsIFaviconService.h"
|
||||||
#include "mozIAsyncFavicons.h"
|
|
||||||
|
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
|
|
@ -50,7 +49,6 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
class nsFaviconService final : public nsIFaviconService
|
class nsFaviconService final : public nsIFaviconService
|
||||||
, public mozIAsyncFavicons
|
|
||||||
, public nsITimerCallback
|
, public nsITimerCallback
|
||||||
, public nsINamed
|
, public nsINamed
|
||||||
{
|
{
|
||||||
|
|
@ -124,7 +122,6 @@ public:
|
||||||
|
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_ISUPPORTS
|
||||||
NS_DECL_NSIFAVICONSERVICE
|
NS_DECL_NSIFAVICONSERVICE
|
||||||
NS_DECL_MOZIASYNCFAVICONS
|
|
||||||
NS_DECL_NSITIMERCALLBACK
|
NS_DECL_NSITIMERCALLBACK
|
||||||
NS_DECL_NSINAMED
|
NS_DECL_NSINAMED
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,9 @@
|
||||||
#include "nsISupports.idl"
|
#include "nsISupports.idl"
|
||||||
|
|
||||||
interface nsIURI;
|
interface nsIURI;
|
||||||
|
interface nsIPrincipal;
|
||||||
|
interface mozIPlacesPendingOperation;
|
||||||
|
interface nsIFaviconDataCallback;
|
||||||
|
|
||||||
[scriptable, uuid(e81e0b0c-b9f1-4c2e-8f3c-b809933cf73c)]
|
[scriptable, uuid(e81e0b0c-b9f1-4c2e-8f3c-b809933cf73c)]
|
||||||
interface nsIFaviconService : nsISupports
|
interface nsIFaviconService : nsISupports
|
||||||
|
|
@ -115,6 +118,202 @@ interface nsIFaviconService : nsISupports
|
||||||
* The default favicon mimeType
|
* The default favicon mimeType
|
||||||
*/
|
*/
|
||||||
readonly attribute AUTF8String defaultFaviconMimeType;
|
readonly attribute AUTF8String defaultFaviconMimeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declares that a given page uses a favicon with the given URI and
|
||||||
|
* attempts to fetch and save the icon data by loading the favicon URI
|
||||||
|
* through an async network request.
|
||||||
|
*
|
||||||
|
* If the icon data already exists, we won't try to reload the icon unless
|
||||||
|
* aForceReload is true. Similarly, if the icon is in the failed favicon
|
||||||
|
* cache we won't do anything unless aForceReload is true, in which case
|
||||||
|
* we'll try to reload the favicon.
|
||||||
|
*
|
||||||
|
* This function will only save favicons for pages that are already stored in
|
||||||
|
* the database, like visited pages or bookmarks. For any other URIs, it
|
||||||
|
* will succeed but do nothing. This function will also ignore the error
|
||||||
|
* page favicon URI (see FAVICON_ERRORPAGE_URL below).
|
||||||
|
*
|
||||||
|
* Icons that fail to load will automatically be added to the failed favicon
|
||||||
|
* cache, and this function will not save favicons for non-bookmarked URIs
|
||||||
|
* when history is disabled.
|
||||||
|
*
|
||||||
|
* @note This function is identical to
|
||||||
|
* nsIFaviconService::setAndLoadFaviconForPage.
|
||||||
|
*
|
||||||
|
* @param aPageURI
|
||||||
|
* URI of the page whose favicon is being set.
|
||||||
|
* @param aFaviconURI
|
||||||
|
* URI of the favicon to associate with the page.
|
||||||
|
* @param aForceReload
|
||||||
|
* If aForceReload is false, we try to reload the favicon only if we
|
||||||
|
* don't have it or it has expired from the cache. Setting
|
||||||
|
* aForceReload to true causes us to reload the favicon even if we
|
||||||
|
* have a usable copy.
|
||||||
|
* @param aFaviconLoadType
|
||||||
|
* Set to FAVICON_LOAD_PRIVATE if the favicon is loaded from a private
|
||||||
|
* browsing window. Set to FAVICON_LOAD_NON_PRIVATE otherwise.
|
||||||
|
* @param [optional] aCallback
|
||||||
|
* Once we're done setting and/or fetching the favicon, we invoke this
|
||||||
|
* callback.
|
||||||
|
* @param [optional] aLoadingPrincipal
|
||||||
|
* Principal of the page whose favicon is being set. If this argument
|
||||||
|
* is omitted, the loadingPrincipal defaults to the nullPrincipal.
|
||||||
|
* @param [optional] aRequestContextID
|
||||||
|
* used to inform Necko of how to link the
|
||||||
|
* favicon request with other requests in the same tab.
|
||||||
|
*
|
||||||
|
* @see nsIFaviconDataCallback in nsIFaviconService.idl.
|
||||||
|
*/
|
||||||
|
mozIPlacesPendingOperation setAndFetchFaviconForPage(
|
||||||
|
in nsIURI aPageURI,
|
||||||
|
in nsIURI aFaviconURI,
|
||||||
|
in boolean aForceReload,
|
||||||
|
in unsigned long aFaviconLoadType,
|
||||||
|
[optional] in nsIFaviconDataCallback aCallback,
|
||||||
|
[optional] in nsIPrincipal aLoadingPrincipal,
|
||||||
|
[optional] in unsigned long long aRequestContextID);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the data for a given favicon URI either by replacing existing data in
|
||||||
|
* the database or taking the place of otherwise fetched icon data when
|
||||||
|
* calling setAndFetchFaviconForPage later.
|
||||||
|
*
|
||||||
|
* Favicon data for favicon URIs that are not associated with a page URI via
|
||||||
|
* setAndFetchFaviconForPage will be stored in memory, but may be expired at
|
||||||
|
* any time, so you should make an effort to associate favicon URIs with page
|
||||||
|
* URIs as soon as possible.
|
||||||
|
*
|
||||||
|
* It's better to not use this function for chrome: icon URIs since you can
|
||||||
|
* reference the chrome image yourself. getFaviconLinkForIcon/Page will ignore
|
||||||
|
* any associated data if the favicon URI is "chrome:" and just return the
|
||||||
|
* same chrome URI.
|
||||||
|
*
|
||||||
|
* This function does NOT send out notifications that the data has changed.
|
||||||
|
* Pages using this favicons that are visible in history or bookmarks views
|
||||||
|
* will keep the old icon until they have been refreshed by other means.
|
||||||
|
*
|
||||||
|
* This function tries to optimize the favicon size, if it is bigger
|
||||||
|
* than a defined limit we will try to convert it to a 16x16 png image.
|
||||||
|
* If the conversion fails and favicon is still bigger than our max accepted
|
||||||
|
* size it won't be saved.
|
||||||
|
*
|
||||||
|
* @param aFaviconURI
|
||||||
|
* URI of the favicon whose data is being set.
|
||||||
|
* @param aData
|
||||||
|
* Binary contents of the favicon to save
|
||||||
|
* @param aDataLength
|
||||||
|
* Length of binary data
|
||||||
|
* @param aMimeType
|
||||||
|
* MIME type of the data to store. This is important so that we know
|
||||||
|
* what to report when the favicon is used. You should always set this
|
||||||
|
* param unless you are clearing an icon.
|
||||||
|
* @param [optional] aExpiration
|
||||||
|
* Time in microseconds since the epoch when this favicon expires.
|
||||||
|
* Until this time, we won't try to load it again.
|
||||||
|
* @throws NS_ERROR_FAILURE
|
||||||
|
* Thrown if the favicon is overbloated and won't be saved to the db.
|
||||||
|
*/
|
||||||
|
void replaceFaviconData(in nsIURI aFaviconURI,
|
||||||
|
[const,array,size_is(aDataLen)] in octet aData,
|
||||||
|
in unsigned long aDataLen,
|
||||||
|
in AUTF8String aMimeType,
|
||||||
|
[optional] in PRTime aExpiration);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as replaceFaviconData but the data is provided by a string
|
||||||
|
* containing a data URL.
|
||||||
|
*
|
||||||
|
* @see replaceFaviconData
|
||||||
|
*
|
||||||
|
* @param aFaviconURI
|
||||||
|
* URI of the favicon whose data is being set.
|
||||||
|
* @param aDataURL
|
||||||
|
* string containing a data URL that represents the contents of
|
||||||
|
* the favicon to save
|
||||||
|
* @param [optional] aExpiration
|
||||||
|
* Time in microseconds since the epoch when this favicon expires.
|
||||||
|
* Until this time, we won't try to load it again.
|
||||||
|
* @param [optional] aLoadingPrincipal
|
||||||
|
* Principal of the page whose favicon is being set. If this argument
|
||||||
|
* is omitted, the loadingPrincipal defaults to the nullPrincipal.
|
||||||
|
* @throws NS_ERROR_FAILURE
|
||||||
|
* Thrown if the favicon is overbloated and won't be saved to the db.
|
||||||
|
*/
|
||||||
|
void replaceFaviconDataFromDataURL(in nsIURI aFaviconURI,
|
||||||
|
in AString aDataURL,
|
||||||
|
[optional] in PRTime aExpiration,
|
||||||
|
[optional] in nsIPrincipal aLoadingPrincipal);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the favicon URI associated to the given page, if any.
|
||||||
|
*
|
||||||
|
* @param aPageURI
|
||||||
|
* URI of the page whose favicon URI we're looking up.
|
||||||
|
* @param aCallback
|
||||||
|
* This callback is always invoked to notify the result of the lookup.
|
||||||
|
* The aURI parameter will be the favicon URI, or null when no favicon
|
||||||
|
* is associated with the page or an error occurred while fetching it.
|
||||||
|
* aDataLen will be always 0, aData will be an empty array, and
|
||||||
|
* aMimeType will be an empty string, regardless of whether a favicon
|
||||||
|
* was found.
|
||||||
|
* @param [optional] aPreferredWidth
|
||||||
|
* The preferred icon width, 0 for the biggest available.
|
||||||
|
*
|
||||||
|
* @note If a favicon specific to this page cannot be found, this will try to
|
||||||
|
* fallback to the /favicon.ico for the root domain.
|
||||||
|
*
|
||||||
|
* @see nsIFaviconDataCallback in nsIFaviconService.idl.
|
||||||
|
*/
|
||||||
|
void getFaviconURLForPage(in nsIURI aPageURI,
|
||||||
|
in nsIFaviconDataCallback aCallback,
|
||||||
|
[optional] in unsigned short aPreferredWidth);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the favicon URI and data associated to the given page, if any.
|
||||||
|
* If the page icon is not available, it will try to return the root domain
|
||||||
|
* icon data, when it's known.
|
||||||
|
*
|
||||||
|
* @param aPageURI
|
||||||
|
* URI of the page whose favicon URI and data we're looking up.
|
||||||
|
* @param aCallback
|
||||||
|
* This callback is always invoked to notify the result of the lookup. The aURI
|
||||||
|
* parameter will be the favicon URI, or null when no favicon is
|
||||||
|
* associated with the page or an error occurred while fetching it. If
|
||||||
|
* aURI is not null, the other parameters may contain the favicon data.
|
||||||
|
* However, if no favicon data is currently associated with the favicon
|
||||||
|
* URI, aDataLen will be 0, aData will be an empty array, and aMimeType
|
||||||
|
* will be an empty string.
|
||||||
|
* @param [optional] aPreferredWidth
|
||||||
|
* The preferred icon width, 0 for the biggest available.
|
||||||
|
* @note If a favicon specific to this page cannot be found, this will try to
|
||||||
|
* fallback to the /favicon.ico for the root domain.
|
||||||
|
*
|
||||||
|
* @see nsIFaviconDataCallback in nsIFaviconService.idl.
|
||||||
|
*/
|
||||||
|
void getFaviconDataForPage(in nsIURI aPageURI,
|
||||||
|
in nsIFaviconDataCallback aCallback,
|
||||||
|
[optional] in unsigned short aPreferredWidth);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies cached favicons from a page to another one.
|
||||||
|
*
|
||||||
|
* @param aFromPageURI
|
||||||
|
* URI of the originating page.
|
||||||
|
* @param aToPageURI
|
||||||
|
* URI of the destination page.
|
||||||
|
* @param aFaviconLoadType
|
||||||
|
* Set to FAVICON_LOAD_PRIVATE if the copy is started from a private
|
||||||
|
* browsing window. Set to FAVICON_LOAD_NON_PRIVATE otherwise.
|
||||||
|
* @param [optional] aCallback
|
||||||
|
* Once we're done copying the favicon, we invoke this callback.
|
||||||
|
* If a copy has been done, the callback will report one of the
|
||||||
|
* favicons uri as aFaviconURI, otherwise all the params will be null.
|
||||||
|
*/
|
||||||
|
void copyFavicons(in nsIURI aFromPageURI,
|
||||||
|
in nsIURI aToPageURI,
|
||||||
|
in unsigned long aFaviconLoadType,
|
||||||
|
[optional] in nsIFaviconDataCallback aCallback);
|
||||||
};
|
};
|
||||||
|
|
||||||
[scriptable, function, uuid(c85e5c82-b70f-4621-9528-beb2aa47fb44)]
|
[scriptable, function, uuid(c85e5c82-b70f-4621-9528-beb2aa47fb44)]
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tests for mozIAsyncFavicons::replaceFaviconData()
|
* Tests for replaceFaviconData()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var iconsvc = PlacesUtils.favicons;
|
var iconsvc = PlacesUtils.favicons;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tests for mozIAsyncFavicons::replaceFaviconData()
|
* Tests for replaceFaviconData()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var iconsvc = PlacesUtils.favicons;
|
var iconsvc = PlacesUtils.favicons;
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,14 @@ namespace TelemetryIPCAccumulator = mozilla::TelemetryIPCAccumulator;
|
||||||
// break that cycle, we relax that requirement. Unfortunately this
|
// break that cycle, we relax that requirement. Unfortunately this
|
||||||
// means that this file is not guaranteed race-free.
|
// means that this file is not guaranteed race-free.
|
||||||
|
|
||||||
|
// This is a StaticMutex rather than a plain Mutex (1) so that
|
||||||
|
// it gets initialised in a thread-safe manner the first time
|
||||||
|
// it is used, and (2) because it is never de-initialised, and
|
||||||
|
// a normal Mutex would show up as a leak in BloatView. StaticMutex
|
||||||
|
// also has the "OffTheBooks" property, so it won't show as a leak
|
||||||
|
// in BloatView.
|
||||||
|
static StaticMutex gTelemetryHistogramMutex;
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
|
@ -144,6 +152,17 @@ enum reflectStatus {
|
||||||
REFLECT_FAILURE
|
REFLECT_FAILURE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Struct used to keep information about the histograms for which a
|
||||||
|
// snapshot should be created.
|
||||||
|
struct HistogramSnapshotData {
|
||||||
|
nsTArray<Histogram::Sample> mBucketRanges;
|
||||||
|
nsTArray<Histogram::Count> mBucketCounts;
|
||||||
|
int64_t mSampleSum; // Same type as Histogram::SampleSet::sum_
|
||||||
|
};
|
||||||
|
|
||||||
|
// The following is used to handle snapshot information for keyed histograms.
|
||||||
|
typedef nsDataHashtable<nsCStringHashKey, HistogramSnapshotData> KeyedHistogramSnapshotData;
|
||||||
|
|
||||||
class KeyedHistogram {
|
class KeyedHistogram {
|
||||||
public:
|
public:
|
||||||
KeyedHistogram(HistogramID id, const HistogramInfo& info);
|
KeyedHistogram(HistogramID id, const HistogramInfo& info);
|
||||||
|
|
@ -152,8 +171,11 @@ public:
|
||||||
Histogram* GetHistogram(const nsCString& name);
|
Histogram* GetHistogram(const nsCString& name);
|
||||||
uint32_t GetHistogramType() const { return mHistogramInfo.histogramType; }
|
uint32_t GetHistogramType() const { return mHistogramInfo.histogramType; }
|
||||||
nsresult GetJSKeys(JSContext* cx, JS::CallArgs& args);
|
nsresult GetJSKeys(JSContext* cx, JS::CallArgs& args);
|
||||||
|
// Note: unlike other methods, GetJSSnapshot is thread safe.
|
||||||
nsresult GetJSSnapshot(JSContext* cx, JS::Handle<JSObject*> obj,
|
nsresult GetJSSnapshot(JSContext* cx, JS::Handle<JSObject*> obj,
|
||||||
bool clearSubsession);
|
bool clearSubsession);
|
||||||
|
nsresult GetSnapshot(const StaticMutexAutoLock& aLock,
|
||||||
|
KeyedHistogramSnapshotData& aSnapshot, bool aClearSubsession);
|
||||||
|
|
||||||
nsresult Add(const nsCString& key, uint32_t aSample, ProcessID aProcessType);
|
nsresult Add(const nsCString& key, uint32_t aSample, ProcessID aProcessType);
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
@ -165,10 +187,6 @@ private:
|
||||||
typedef AutoHashtable<KeyedHistogramEntry> KeyedHistogramMapType;
|
typedef AutoHashtable<KeyedHistogramEntry> KeyedHistogramMapType;
|
||||||
KeyedHistogramMapType mHistogramMap;
|
KeyedHistogramMapType mHistogramMap;
|
||||||
|
|
||||||
static bool ReflectKeyedHistogram(KeyedHistogramEntry* entry,
|
|
||||||
JSContext* cx,
|
|
||||||
JS::Handle<JSObject*> obj);
|
|
||||||
|
|
||||||
const HistogramID mId;
|
const HistogramID mId;
|
||||||
const HistogramInfo& mHistogramInfo;
|
const HistogramInfo& mHistogramInfo;
|
||||||
};
|
};
|
||||||
|
|
@ -622,68 +640,98 @@ internal_HistogramAdd(Histogram& histogram,
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
bool
|
/**
|
||||||
internal_FillRanges(JSContext *cx, JS::Handle<JSObject*> array, Histogram *h)
|
* Copy histograms and samples to Mozilla-friendly structures.
|
||||||
|
* Please note that this version does not make use of JS contexts.
|
||||||
|
*
|
||||||
|
* @param {StaticMutexAutoLock} the proof we hold the mutex.
|
||||||
|
* @param {Histogram} the histogram to reflect.
|
||||||
|
* @return {nsresult} NS_ERROR_FAILURE if we fail to allocate memory for the snapshot.
|
||||||
|
*/
|
||||||
|
nsresult
|
||||||
|
internal_GetHistogramAndSamples(const StaticMutexAutoLock& aLock,
|
||||||
|
const Histogram *h,
|
||||||
|
HistogramSnapshotData& aSnapshot)
|
||||||
{
|
{
|
||||||
JS::Rooted<JS::Value> range(cx);
|
MOZ_ASSERT(h);
|
||||||
for (size_t i = 0; i < h->bucket_count(); i++) {
|
|
||||||
range.setInt32(h->ranges(i));
|
|
||||||
if (!JS_DefineElement(cx, array, i, range, JSPROP_ENUMERATE))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum reflectStatus
|
// Convert the ranges of the buckets to a nsTArray.
|
||||||
internal_ReflectHistogramAndSamples(JSContext *cx,
|
const size_t bucketCount = h->bucket_count();
|
||||||
JS::Handle<JSObject*> obj, Histogram *h,
|
for (size_t i = 0; i < bucketCount; i++) {
|
||||||
const Histogram::SampleSet &ss)
|
if (!aSnapshot.mBucketRanges.AppendElement(h->ranges(i))) {
|
||||||
{
|
return NS_ERROR_FAILURE;
|
||||||
if (!(JS_DefineProperty(cx, obj, "min",
|
|
||||||
h->declared_min(), JSPROP_ENUMERATE)
|
|
||||||
&& JS_DefineProperty(cx, obj, "max",
|
|
||||||
h->declared_max(), JSPROP_ENUMERATE)
|
|
||||||
&& JS_DefineProperty(cx, obj, "histogram_type",
|
|
||||||
h->histogram_type(), JSPROP_ENUMERATE)
|
|
||||||
&& JS_DefineProperty(cx, obj, "sum",
|
|
||||||
double(ss.sum()), JSPROP_ENUMERATE))) {
|
|
||||||
return REFLECT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t count = h->bucket_count();
|
|
||||||
JS::Rooted<JSObject*> rarray(cx, JS_NewArrayObject(cx, count));
|
|
||||||
if (!rarray) {
|
|
||||||
return REFLECT_FAILURE;
|
|
||||||
}
|
|
||||||
if (!(internal_FillRanges(cx, rarray, h)
|
|
||||||
&& JS_DefineProperty(cx, obj, "ranges", rarray, JSPROP_ENUMERATE))) {
|
|
||||||
return REFLECT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS::Rooted<JSObject*> counts_array(cx, JS_NewArrayObject(cx, count));
|
|
||||||
if (!counts_array) {
|
|
||||||
return REFLECT_FAILURE;
|
|
||||||
}
|
|
||||||
if (!JS_DefineProperty(cx, obj, "counts", counts_array, JSPROP_ENUMERATE)) {
|
|
||||||
return REFLECT_FAILURE;
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < count; i++) {
|
|
||||||
if (!JS_DefineElement(cx, counts_array, i,
|
|
||||||
ss.counts(i), JSPROP_ENUMERATE)) {
|
|
||||||
return REFLECT_FAILURE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return REFLECT_OK;
|
// Get a snapshot of the samples.
|
||||||
}
|
|
||||||
|
|
||||||
enum reflectStatus
|
|
||||||
internal_ReflectHistogramSnapshot(JSContext *cx,
|
|
||||||
JS::Handle<JSObject*> obj, Histogram *h)
|
|
||||||
{
|
|
||||||
Histogram::SampleSet ss;
|
Histogram::SampleSet ss;
|
||||||
h->SnapshotSample(&ss);
|
h->SnapshotSample(&ss);
|
||||||
return internal_ReflectHistogramAndSamples(cx, obj, h, ss);
|
|
||||||
|
// Get the number of samples in each bucket.
|
||||||
|
for (size_t i = 0; i < bucketCount; i++) {
|
||||||
|
if (!aSnapshot.mBucketCounts.AppendElement(ss.counts(i))) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, save the |sum|. We don't need to reflect declared_min, declared_max and
|
||||||
|
// histogram_type as they are in gHistogramInfo.
|
||||||
|
aSnapshot.mSampleSum = ss.sum();
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
internal_ReflectHistogramAndSamples(JSContext *cx,
|
||||||
|
JS::Handle<JSObject*> obj,
|
||||||
|
const HistogramInfo& aHistogramInfo,
|
||||||
|
const HistogramSnapshotData& aSnapshot)
|
||||||
|
{
|
||||||
|
if (!(JS_DefineProperty(cx, obj, "min",
|
||||||
|
aHistogramInfo.min, JSPROP_ENUMERATE)
|
||||||
|
&& JS_DefineProperty(cx, obj, "max",
|
||||||
|
aHistogramInfo.max, JSPROP_ENUMERATE)
|
||||||
|
&& JS_DefineProperty(cx, obj, "histogram_type",
|
||||||
|
aHistogramInfo.histogramType, JSPROP_ENUMERATE)
|
||||||
|
&& JS_DefineProperty(cx, obj, "sum",
|
||||||
|
double(aSnapshot.mSampleSum), JSPROP_ENUMERATE))) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't rely on the bucket counts from "aHistogramInfo": it may
|
||||||
|
// differ from the length of aSnapshot.mBucketCounts due to expired
|
||||||
|
// histograms.
|
||||||
|
const size_t count = aSnapshot.mBucketCounts.Length();
|
||||||
|
MOZ_ASSERT(count == aSnapshot.mBucketRanges.Length(),
|
||||||
|
"The number of buckets and the number of counts must match.");
|
||||||
|
|
||||||
|
// Create the "ranges" property and add it to the final object.
|
||||||
|
JS::Rooted<JSObject*> rarray(cx, JS_NewArrayObject(cx, count));
|
||||||
|
if (!rarray
|
||||||
|
|| !JS_DefineProperty(cx, obj, "ranges", rarray, JSPROP_ENUMERATE)) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill the "ranges" property.
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
if (!JS_DefineElement(cx, rarray, i, aSnapshot.mBucketRanges[i], JSPROP_ENUMERATE)) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JS::Rooted<JSObject*> counts_array(cx, JS_NewArrayObject(cx, count));
|
||||||
|
if (!counts_array
|
||||||
|
|| !JS_DefineProperty(cx, obj, "counts", counts_array, JSPROP_ENUMERATE)) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill the "counts" property.
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
if (!JS_DefineElement(cx, counts_array, i, aSnapshot.mBucketCounts[i], JSPROP_ENUMERATE)) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
@ -706,10 +754,39 @@ internal_ShouldReflectHistogram(Histogram* h, HistogramID id)
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// PRIVATE: class KeyedHistogram
|
// PRIVATE: class KeyedHistogram and internal_ReflectKeyedHistogram
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
internal_ReflectKeyedHistogram(const KeyedHistogramSnapshotData& aSnapshot,
|
||||||
|
const HistogramInfo& info,
|
||||||
|
JSContext* aCx, JS::Handle<JSObject*> aObj)
|
||||||
|
{
|
||||||
|
for (auto iter = aSnapshot.ConstIter(); !iter.Done(); iter.Next()) {
|
||||||
|
HistogramSnapshotData& keyData = iter.Data();
|
||||||
|
|
||||||
|
JS::RootedObject histogramSnapshot(aCx, JS_NewPlainObject(aCx));
|
||||||
|
if (!histogramSnapshot) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NS_FAILED(internal_ReflectHistogramAndSamples(aCx, histogramSnapshot,
|
||||||
|
info,
|
||||||
|
keyData))) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NS_ConvertUTF8toUTF16 key(iter.Key());
|
||||||
|
if (!JS_DefineUCProperty(aCx, aObj, key.Data(), key.Length(),
|
||||||
|
histogramSnapshot, JSPROP_ENUMERATE)) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
KeyedHistogram::KeyedHistogram(HistogramID id, const HistogramInfo& info)
|
KeyedHistogram::KeyedHistogram(HistogramID id, const HistogramInfo& info)
|
||||||
: mHistogramMap()
|
: mHistogramMap()
|
||||||
, mId(id)
|
, mId(id)
|
||||||
|
|
@ -848,37 +925,47 @@ KeyedHistogram::GetJSKeys(JSContext* cx, JS::CallArgs& args)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
KeyedHistogram::ReflectKeyedHistogram(KeyedHistogramEntry* entry,
|
|
||||||
JSContext* cx, JS::Handle<JSObject*> obj)
|
|
||||||
{
|
|
||||||
JS::RootedObject histogramSnapshot(cx, JS_NewPlainObject(cx));
|
|
||||||
if (!histogramSnapshot) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (internal_ReflectHistogramSnapshot(cx, histogramSnapshot,
|
|
||||||
entry->mData) != REFLECT_OK) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const NS_ConvertUTF8toUTF16 key(entry->GetKey());
|
|
||||||
if (!JS_DefineUCProperty(cx, obj, key.Data(), key.Length(),
|
|
||||||
histogramSnapshot, JSPROP_ENUMERATE)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
KeyedHistogram::GetJSSnapshot(JSContext* cx, JS::Handle<JSObject*> obj, bool clearSubsession)
|
KeyedHistogram::GetJSSnapshot(JSContext* cx, JS::Handle<JSObject*> obj, bool clearSubsession)
|
||||||
{
|
{
|
||||||
if (!mHistogramMap.ReflectIntoJS(&KeyedHistogram::ReflectKeyedHistogram, cx, obj)) {
|
// Get a snapshot of the data.
|
||||||
return NS_ERROR_FAILURE;
|
KeyedHistogramSnapshotData dataSnapshot;
|
||||||
|
{
|
||||||
|
StaticMutexAutoLock locker(gTelemetryHistogramMutex);
|
||||||
|
MOZ_ASSERT(internal_IsHistogramEnumId(mId));
|
||||||
|
|
||||||
|
// Take a snapshot of the data here, protected by the lock, and then,
|
||||||
|
// outside of the lock protection, mirror it to a JS structure.
|
||||||
|
if (NS_FAILED(GetSnapshot(locker, dataSnapshot, clearSubsession))) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clearSubsession) {
|
// Now that we have a copy of the data, mirror it to JS.
|
||||||
|
return internal_ReflectKeyedHistogram(dataSnapshot, gHistogramInfos[mId], cx, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
KeyedHistogram::GetSnapshot(const StaticMutexAutoLock& aLock,
|
||||||
|
KeyedHistogramSnapshotData& aSnapshot, bool aClearSubsession)
|
||||||
|
{
|
||||||
|
// Snapshot every key.
|
||||||
|
for (auto iter = mHistogramMap.ConstIter(); !iter.Done(); iter.Next()) {
|
||||||
|
Histogram* keyData = iter.Get()->mData;
|
||||||
|
if (!keyData) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
HistogramSnapshotData keySnapshot;
|
||||||
|
if (NS_FAILED(internal_GetHistogramAndSamples(aLock, keyData, keySnapshot))) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append to the final snapshot.
|
||||||
|
aSnapshot.Put(iter.Get()->GetKey(), mozilla::Move(keySnapshot));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aClearSubsession) {
|
||||||
Clear();
|
Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -892,14 +979,6 @@ KeyedHistogram::GetJSSnapshot(JSContext* cx, JS::Handle<JSObject*> obj, bool cle
|
||||||
//
|
//
|
||||||
// PRIVATE: thread-unsafe helpers for the external interface
|
// PRIVATE: thread-unsafe helpers for the external interface
|
||||||
|
|
||||||
// This is a StaticMutex rather than a plain Mutex (1) so that
|
|
||||||
// it gets initialised in a thread-safe manner the first time
|
|
||||||
// it is used, and (2) because it is never de-initialised, and
|
|
||||||
// a normal Mutex would show up as a leak in BloatView. StaticMutex
|
|
||||||
// also has the "OffTheBooks" property, so it won't show as a leak
|
|
||||||
// in BloatView.
|
|
||||||
static StaticMutex gTelemetryHistogramMutex;
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
@ -1228,8 +1307,7 @@ internal_JSHistogram_Snapshot(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||||
MOZ_ASSERT(data);
|
MOZ_ASSERT(data);
|
||||||
HistogramID id = data->histogramId;
|
HistogramID id = data->histogramId;
|
||||||
|
|
||||||
Histogram* h = nullptr;
|
HistogramSnapshotData dataSnapshot;
|
||||||
Histogram::SampleSet ss;
|
|
||||||
{
|
{
|
||||||
StaticMutexAutoLock locker(gTelemetryHistogramMutex);
|
StaticMutexAutoLock locker(gTelemetryHistogramMutex);
|
||||||
MOZ_ASSERT(internal_IsHistogramEnumId(id));
|
MOZ_ASSERT(internal_IsHistogramEnumId(id));
|
||||||
|
|
@ -1237,11 +1315,12 @@ internal_JSHistogram_Snapshot(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||||
// This is not good standard behavior given that we have histogram instances
|
// This is not good standard behavior given that we have histogram instances
|
||||||
// covering multiple processes.
|
// covering multiple processes.
|
||||||
// However, changing this requires some broader changes to callers.
|
// However, changing this requires some broader changes to callers.
|
||||||
h = internal_GetHistogramById(id, ProcessID::Parent);
|
Histogram* h = internal_GetHistogramById(id, ProcessID::Parent);
|
||||||
// Take a snapshot of Histogram::SampleSet here, protected by the lock,
|
// Take a snapshot of the data here, protected by the lock, and then,
|
||||||
// and then, outside of the lock protection, mirror it to a JS structure
|
// outside of the lock protection, mirror it to a JS structure
|
||||||
MOZ_ASSERT(h);
|
if (NS_FAILED(internal_GetHistogramAndSamples(locker, h, dataSnapshot))) {
|
||||||
h->SnapshotSample(&ss);
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JS::Rooted<JSObject*> snapshot(cx, JS_NewPlainObject(cx));
|
JS::Rooted<JSObject*> snapshot(cx, JS_NewPlainObject(cx));
|
||||||
|
|
@ -1249,18 +1328,14 @@ internal_JSHistogram_Snapshot(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
reflectStatus status = internal_ReflectHistogramAndSamples(cx, snapshot, h, ss);
|
if (NS_FAILED(internal_ReflectHistogramAndSamples(cx,
|
||||||
|
snapshot,
|
||||||
switch (status) {
|
gHistogramInfos[id],
|
||||||
case REFLECT_FAILURE:
|
dataSnapshot))) {
|
||||||
return false;
|
return false;
|
||||||
case REFLECT_OK:
|
|
||||||
args.rval().setObject(*snapshot);
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
MOZ_ASSERT_UNREACHABLE("Unhandled reflection status.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
args.rval().setObject(*snapshot);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1407,6 +1482,7 @@ internal_KeyedHistogram_SnapshotImpl(JSContext *cx, unsigned argc,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No argument was passed, so snapshot all the keys.
|
||||||
if (args.length() == 0) {
|
if (args.length() == 0) {
|
||||||
JS::RootedObject snapshot(cx, JS_NewPlainObject(cx));
|
JS::RootedObject snapshot(cx, JS_NewPlainObject(cx));
|
||||||
if (!snapshot) {
|
if (!snapshot) {
|
||||||
|
|
@ -1423,17 +1499,30 @@ internal_KeyedHistogram_SnapshotImpl(JSContext *cx, unsigned argc,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// One argument was passed. If it's a string, use it as a key
|
||||||
|
// and just snapshot the data for that key.
|
||||||
nsAutoJSString key;
|
nsAutoJSString key;
|
||||||
if (!args[0].isString() || !key.init(cx, args[0])) {
|
if (!args[0].isString() || !key.init(cx, args[0])) {
|
||||||
JS_ReportErrorASCII(cx, "Not a string");
|
JS_ReportErrorASCII(cx, "Not a string");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Histogram* h = nullptr;
|
HistogramSnapshotData dataSnapshot;
|
||||||
nsresult rv = keyed->GetHistogram(NS_ConvertUTF16toUTF8(key), &h);
|
{
|
||||||
if (NS_FAILED(rv)) {
|
StaticMutexAutoLock locker(gTelemetryHistogramMutex);
|
||||||
JS_ReportErrorASCII(cx, "Failed to get histogram");
|
|
||||||
return false;
|
// Get data for the key we're looking for.
|
||||||
|
Histogram* h = nullptr;
|
||||||
|
nsresult rv = keyed->GetHistogram(NS_ConvertUTF16toUTF8(key), &h);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take a snapshot of the data here, protected by the lock, and then,
|
||||||
|
// outside of the lock protection, mirror it to a JS structure
|
||||||
|
if (NS_FAILED(internal_GetHistogramAndSamples(locker, h, dataSnapshot))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JS::RootedObject snapshot(cx, JS_NewPlainObject(cx));
|
JS::RootedObject snapshot(cx, JS_NewPlainObject(cx));
|
||||||
|
|
@ -1441,17 +1530,15 @@ internal_KeyedHistogram_SnapshotImpl(JSContext *cx, unsigned argc,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (internal_ReflectHistogramSnapshot(cx, snapshot, h)) {
|
if (NS_FAILED(internal_ReflectHistogramAndSamples(cx,
|
||||||
case REFLECT_FAILURE:
|
snapshot,
|
||||||
|
gHistogramInfos[id],
|
||||||
|
dataSnapshot))) {
|
||||||
JS_ReportErrorASCII(cx, "Failed to reflect histogram");
|
JS_ReportErrorASCII(cx, "Failed to reflect histogram");
|
||||||
return false;
|
return false;
|
||||||
case REFLECT_OK:
|
|
||||||
args.rval().setObject(*snapshot);
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
MOZ_CRASH("unhandled reflection status");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
args.rval().setObject(*snapshot);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2140,14 +2227,12 @@ TelemetryHistogram::CreateHistogramSnapshots(JSContext* aCx,
|
||||||
|
|
||||||
// Struct used to keep information about the histograms for which a
|
// Struct used to keep information about the histograms for which a
|
||||||
// snapshot should be created
|
// snapshot should be created
|
||||||
struct MOZ_NON_MEMMOVABLE HistogramProcessInfo {
|
struct HistogramProcessInfo {
|
||||||
Histogram* h;
|
HistogramSnapshotData data;
|
||||||
Histogram::SampleSet ss;
|
HistogramID histogramID;
|
||||||
size_t index;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
mozilla::Vector<mozilla::Vector<HistogramProcessInfo>>
|
mozilla::Vector<mozilla::Vector<HistogramProcessInfo>> processHistArray;
|
||||||
processHistArray;
|
|
||||||
{
|
{
|
||||||
if (!processHistArray.resize(static_cast<uint32_t>(ProcessID::Count))) {
|
if (!processHistArray.resize(static_cast<uint32_t>(ProcessID::Count))) {
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
@ -2182,9 +2267,12 @@ TelemetryHistogram::CreateHistogramSnapshots(JSContext* aCx,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Histogram::SampleSet ss;
|
HistogramSnapshotData snapshotData;
|
||||||
h->SnapshotSample(&ss);
|
if (NS_FAILED(internal_GetHistogramAndSamples(locker, h, snapshotData))) {
|
||||||
if (!hArray.emplaceBack(HistogramProcessInfo{h, ss, i})) {
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hArray.emplaceBack(HistogramProcessInfo{snapshotData, id})) {
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2210,26 +2298,23 @@ TelemetryHistogram::CreateHistogramSnapshots(JSContext* aCx,
|
||||||
const mozilla::Vector<HistogramProcessInfo>& hArray = processHistArray[process];
|
const mozilla::Vector<HistogramProcessInfo>& hArray = processHistArray[process];
|
||||||
for (size_t i = 0; i < hArray.length(); ++i) {
|
for (size_t i = 0; i < hArray.length(); ++i) {
|
||||||
const HistogramProcessInfo& hData = hArray[i];
|
const HistogramProcessInfo& hData = hArray[i];
|
||||||
uint32_t histogramIndex = hData.index;
|
HistogramID id = hData.histogramID;
|
||||||
|
|
||||||
HistogramID id = HistogramID(histogramIndex);
|
|
||||||
|
|
||||||
JS::Rooted<JSObject*> hobj(aCx, JS_NewPlainObject(aCx));
|
JS::Rooted<JSObject*> hobj(aCx, JS_NewPlainObject(aCx));
|
||||||
if (!hobj) {
|
if (!hobj) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Histogram* h = hData.h;
|
if (NS_FAILED(internal_ReflectHistogramAndSamples(aCx,
|
||||||
reflectStatus status = internal_ReflectHistogramAndSamples(aCx, hobj, h,
|
hobj,
|
||||||
hData.ss);
|
gHistogramInfos[id],
|
||||||
switch (status) {
|
hData.data))) {
|
||||||
case REFLECT_FAILURE:
|
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
case REFLECT_OK:
|
}
|
||||||
if (!JS_DefineProperty(aCx, processObject, gHistogramInfos[id].name(),
|
|
||||||
hobj, JSPROP_ENUMERATE)) {
|
if (!JS_DefineProperty(aCx, processObject, gHistogramInfos[id].name(),
|
||||||
|
hobj, JSPROP_ENUMERATE)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2256,7 +2341,63 @@ TelemetryHistogram::GetKeyedHistogramSnapshots(JSContext* aCx,
|
||||||
includeGPUProcess = gpm->AttemptedGPUProcess();
|
includeGPUProcess = gpm->AttemptedGPUProcess();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t process = 0; process < static_cast<uint32_t>(ProcessID::Count); ++process) {
|
struct KeyedHistogramProcessInfo {
|
||||||
|
KeyedHistogramSnapshotData data;
|
||||||
|
HistogramID histogramId;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get a snapshot of all the data while holding the mutex.
|
||||||
|
mozilla::Vector<mozilla::Vector<KeyedHistogramProcessInfo>> dataSnapshot;
|
||||||
|
{
|
||||||
|
if (!dataSnapshot.resize(static_cast<uint32_t>(ProcessID::Count))) {
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
StaticMutexAutoLock locker(gTelemetryHistogramMutex);
|
||||||
|
|
||||||
|
for (uint32_t process = 0; process < static_cast<uint32_t>(ProcessID::Count); ++process) {
|
||||||
|
mozilla::Vector<KeyedHistogramProcessInfo>& hArray = dataSnapshot[process];
|
||||||
|
|
||||||
|
for (size_t i = 0; i < HistogramCount; ++i) {
|
||||||
|
HistogramID id = HistogramID(i);
|
||||||
|
const HistogramInfo& info = gHistogramInfos[id];
|
||||||
|
if (!info.keyed) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CanRecordInProcess(info.record_in_processes, ProcessID(process)) ||
|
||||||
|
((ProcessID(process) == ProcessID::Gpu) && !includeGPUProcess)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsInDataset(info.dataset, aDataset)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyedHistogram* keyed = internal_GetKeyedHistogramById(id,
|
||||||
|
ProcessID(process),
|
||||||
|
/* instantiate = */ false);
|
||||||
|
if (!keyed) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take a snapshot of the keyed histogram data!
|
||||||
|
KeyedHistogramSnapshotData snapshot;
|
||||||
|
if (!NS_SUCCEEDED(keyed->GetSnapshot(locker, snapshot, aClearSubsession))) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hArray.emplaceBack(KeyedHistogramProcessInfo{mozilla::Move(snapshot), id})) {
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mirror the snapshot data to JS, now that we released the mutex.
|
||||||
|
for (uint32_t process = 0; process < dataSnapshot.length(); ++process) {
|
||||||
|
const mozilla::Vector<KeyedHistogramProcessInfo>& hArray = dataSnapshot[process];
|
||||||
|
|
||||||
JS::Rooted<JSObject*> processObject(aCx, JS_NewPlainObject(aCx));
|
JS::Rooted<JSObject*> processObject(aCx, JS_NewPlainObject(aCx));
|
||||||
if (!processObject) {
|
if (!processObject) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
|
@ -2265,38 +2406,20 @@ TelemetryHistogram::GetKeyedHistogramSnapshots(JSContext* aCx,
|
||||||
processObject, JSPROP_ENUMERATE)) {
|
processObject, JSPROP_ENUMERATE)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
for (size_t id = 0; id < HistogramCount; ++id) {
|
for (size_t i = 0; i < hArray.length(); ++i) {
|
||||||
const HistogramInfo& info = gHistogramInfos[id];
|
const KeyedHistogramProcessInfo& hData = hArray[i];
|
||||||
if (!info.keyed) {
|
const HistogramInfo& info = gHistogramInfos[hData.histogramId];
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!CanRecordInProcess(info.record_in_processes, ProcessID(process)) ||
|
|
||||||
((ProcessID(process) == ProcessID::Gpu) && !includeGPUProcess)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!IsInDataset(info.dataset, aDataset)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyedHistogram* keyed = internal_GetKeyedHistogramById(HistogramID(id),
|
|
||||||
ProcessID(process),
|
|
||||||
/* instantiate = */ false);
|
|
||||||
if (!keyed) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS::RootedObject snapshot(aCx, JS_NewPlainObject(aCx));
|
JS::RootedObject snapshot(aCx, JS_NewPlainObject(aCx));
|
||||||
if (!snapshot) {
|
if (!snapshot) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!NS_SUCCEEDED(keyed->GetJSSnapshot(aCx, snapshot, aClearSubsession))) {
|
if (!NS_SUCCEEDED(internal_ReflectKeyedHistogram(hData.data, info, aCx, snapshot))) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!JS_DefineProperty(aCx, processObject, gHistogramInfos[id].name(),
|
if (!JS_DefineProperty(aCx, processObject, info.name(),
|
||||||
snapshot, JSPROP_ENUMERATE)) {
|
snapshot, JSPROP_ENUMERATE)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3890,17 +3890,7 @@ nsWindow::Create(nsIWidget* aParent,
|
||||||
// If the window were to get unredirected, there could be visible
|
// If the window were to get unredirected, there could be visible
|
||||||
// tearing because Gecko does not align its framebuffer updates with
|
// tearing because Gecko does not align its framebuffer updates with
|
||||||
// vblank.
|
// vblank.
|
||||||
if (mIsX11Display) {
|
SetCompositorHint(GTK_WIDGET_COMPOSIDED_ENABLED);
|
||||||
gulong value = 2; // Opt out of unredirection
|
|
||||||
GdkAtom cardinal_atom = gdk_x11_xatom_to_atom(XA_CARDINAL);
|
|
||||||
gdk_property_change(gtk_widget_get_window(mShell),
|
|
||||||
gdk_atom_intern("_NET_WM_BYPASS_COMPOSITOR", FALSE),
|
|
||||||
cardinal_atom,
|
|
||||||
32, // format
|
|
||||||
GDK_PROP_MODE_REPLACE,
|
|
||||||
(guchar*)&value,
|
|
||||||
1);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -4114,60 +4104,70 @@ nsWindow::Create(nsIWidget* aParent,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsWindow::SetWindowClass(const nsAString &xulWinType)
|
nsWindow::RefreshWindowClass(void)
|
||||||
{
|
{
|
||||||
if (!mShell)
|
if (mGtkWindowTypeName.IsEmpty() || mGtkWindowRoleName.IsEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const char *res_class = gdk_get_program_class();
|
GdkWindow* gdkWindow = gtk_widget_get_window(mShell);
|
||||||
if (!res_class)
|
gdk_window_set_role(gdkWindow, mGtkWindowRoleName.get());
|
||||||
return;
|
|
||||||
|
|
||||||
char *res_name = ToNewCString(xulWinType);
|
|
||||||
if (!res_name)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const char *role = nullptr;
|
|
||||||
|
|
||||||
// Parse res_name into a name and role. Characters other than
|
|
||||||
// [A-Za-z0-9_-] are converted to '_'. Anything after the first
|
|
||||||
// colon is assigned to role; if there's no colon, assign the
|
|
||||||
// whole thing to both role and res_name.
|
|
||||||
for (char *c = res_name; *c; c++) {
|
|
||||||
if (':' == *c) {
|
|
||||||
*c = 0;
|
|
||||||
role = c + 1;
|
|
||||||
}
|
|
||||||
else if (!isascii(*c) || (!isalnum(*c) && ('_' != *c) && ('-' != *c)))
|
|
||||||
*c = '_';
|
|
||||||
}
|
|
||||||
res_name[0] = toupper(res_name[0]);
|
|
||||||
if (!role) role = res_name;
|
|
||||||
|
|
||||||
GdkWindow* gdkWindow = gtk_widget_get_window(mShell);
|
|
||||||
gdk_window_set_role(gdkWindow, role);
|
|
||||||
|
|
||||||
#ifdef MOZ_X11
|
#ifdef MOZ_X11
|
||||||
if (mIsX11Display) {
|
if (mIsX11Display) {
|
||||||
XClassHint *class_hint = XAllocClassHint();
|
XClassHint *class_hint = XAllocClassHint();
|
||||||
if (!class_hint) {
|
if (!class_hint) {
|
||||||
free(res_name);
|
return;
|
||||||
return;
|
}
|
||||||
}
|
const char *res_class = gdk_get_program_class();
|
||||||
class_hint->res_name = res_name;
|
if (!res_class)
|
||||||
class_hint->res_class = const_cast<char*>(res_class);
|
return;
|
||||||
|
|
||||||
// Can't use gtk_window_set_wmclass() for this; it prints
|
class_hint->res_name = const_cast<char*>(mGtkWindowTypeName.get());
|
||||||
// a warning & refuses to make the change.
|
class_hint->res_class = const_cast<char*>(res_class);
|
||||||
GdkDisplay *display = gdk_display_get_default();
|
|
||||||
XSetClassHint(GDK_DISPLAY_XDISPLAY(display),
|
// Can't use gtk_window_set_wmclass() for this; it prints
|
||||||
gdk_x11_window_get_xid(gdkWindow),
|
// a warning & refuses to make the change.
|
||||||
class_hint);
|
GdkDisplay *display = gdk_display_get_default();
|
||||||
XFree(class_hint);
|
XSetClassHint(GDK_DISPLAY_XDISPLAY(display),
|
||||||
}
|
gdk_x11_window_get_xid(gdkWindow),
|
||||||
|
class_hint);
|
||||||
|
XFree(class_hint);
|
||||||
|
}
|
||||||
#endif /* MOZ_X11 */
|
#endif /* MOZ_X11 */
|
||||||
|
}
|
||||||
|
|
||||||
free(res_name);
|
void
|
||||||
|
nsWindow::SetWindowClass(const nsAString &xulWinType)
|
||||||
|
{
|
||||||
|
if (!mShell)
|
||||||
|
return;
|
||||||
|
|
||||||
|
char *res_name = ToNewCString(xulWinType);
|
||||||
|
if (!res_name)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const char *role = nullptr;
|
||||||
|
|
||||||
|
// Parse res_name into a name and role. Characters other than
|
||||||
|
// [A-Za-z0-9_-] are converted to '_'. Anything after the first
|
||||||
|
// colon is assigned to role; if there's no colon, assign the
|
||||||
|
// whole thing to both role and res_name.
|
||||||
|
for (char *c = res_name; *c; c++) {
|
||||||
|
if (':' == *c) {
|
||||||
|
*c = 0;
|
||||||
|
role = c + 1;
|
||||||
|
}
|
||||||
|
else if (!isascii(*c) || (!isalnum(*c) && ('_' != *c) && ('-' != *c)))
|
||||||
|
*c = '_';
|
||||||
|
}
|
||||||
|
res_name[0] = toupper(res_name[0]);
|
||||||
|
if (!role) role = res_name;
|
||||||
|
|
||||||
|
mGtkWindowTypeName = res_name;
|
||||||
|
mGtkWindowRoleName = role;
|
||||||
|
free(res_name);
|
||||||
|
|
||||||
|
RefreshWindowClass();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -6731,6 +6731,10 @@ nsWindow::SetDrawsInTitlebar(bool aState)
|
||||||
// can find its way home.
|
// can find its way home.
|
||||||
g_object_set_data(G_OBJECT(gtk_widget_get_window(mShell)),
|
g_object_set_data(G_OBJECT(gtk_widget_get_window(mShell)),
|
||||||
"nsWindow", this);
|
"nsWindow", this);
|
||||||
|
#ifdef MOZ_X11
|
||||||
|
SetCompositorHint(GTK_WIDGET_COMPOSIDED_ENABLED);
|
||||||
|
#endif
|
||||||
|
RefreshWindowClass();
|
||||||
|
|
||||||
// When we use system titlebar setup managed by Gtk+ we also get
|
// When we use system titlebar setup managed by Gtk+ we also get
|
||||||
// _NET_FRAME_EXTENTS property for our toplevel window so we can't
|
// _NET_FRAME_EXTENTS property for our toplevel window so we can't
|
||||||
|
|
@ -7212,3 +7216,21 @@ nsWindow::SetProgress(unsigned long progressPercent)
|
||||||
progressPercent);
|
progressPercent);
|
||||||
#endif // MOZ_X11
|
#endif // MOZ_X11
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef MOZ_X11
|
||||||
|
void
|
||||||
|
nsWindow::SetCompositorHint(WindowComposeRequest aState)
|
||||||
|
{
|
||||||
|
if (mIsX11Display) {
|
||||||
|
gulong value = aState;
|
||||||
|
GdkAtom cardinal_atom = gdk_x11_xatom_to_atom(XA_CARDINAL);
|
||||||
|
gdk_property_change(gtk_widget_get_window(mShell),
|
||||||
|
gdk_atom_intern("_NET_WM_BYPASS_COMPOSITOR", FALSE),
|
||||||
|
cardinal_atom,
|
||||||
|
32, // format
|
||||||
|
GDK_PROP_MODE_REPLACE,
|
||||||
|
(guchar*)&value,
|
||||||
|
1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -481,6 +481,18 @@ private:
|
||||||
|
|
||||||
void UpdateClientOffsetForCSDWindow();
|
void UpdateClientOffsetForCSDWindow();
|
||||||
|
|
||||||
|
#ifdef MOZ_X11
|
||||||
|
typedef enum { GTK_WIDGET_COMPOSIDED_DEFAULT = 0,
|
||||||
|
GTK_WIDGET_COMPOSIDED_DISABLED = 1,
|
||||||
|
GTK_WIDGET_COMPOSIDED_ENABLED = 2
|
||||||
|
} WindowComposeRequest;
|
||||||
|
|
||||||
|
void SetCompositorHint(WindowComposeRequest aState);
|
||||||
|
#endif
|
||||||
|
nsCString mGtkWindowTypeName;
|
||||||
|
nsCString mGtkWindowRoleName;
|
||||||
|
void RefreshWindowClass();
|
||||||
|
|
||||||
GtkWidget *mShell;
|
GtkWidget *mShell;
|
||||||
MozContainer *mContainer;
|
MozContainer *mContainer;
|
||||||
GdkWindow *mGdkWindow;
|
GdkWindow *mGdkWindow;
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
#include "nsNetCID.h"
|
#include "nsNetCID.h"
|
||||||
#include "prtime.h"
|
#include "prtime.h"
|
||||||
#ifdef MOZ_PLACES
|
#ifdef MOZ_PLACES
|
||||||
#include "mozIAsyncFavicons.h"
|
#include "nsIFaviconService.h"
|
||||||
#endif
|
#endif
|
||||||
#include "nsIIconURI.h"
|
#include "nsIIconURI.h"
|
||||||
#include "nsIDownloader.h"
|
#include "nsIDownloader.h"
|
||||||
|
|
@ -1649,7 +1649,7 @@ nsresult
|
||||||
{
|
{
|
||||||
#ifdef MOZ_PLACES
|
#ifdef MOZ_PLACES
|
||||||
// Obtain the favicon service and get the favicon for the specified page
|
// Obtain the favicon service and get the favicon for the specified page
|
||||||
nsCOMPtr<mozIAsyncFavicons> favIconSvc(
|
nsCOMPtr<nsIFaviconService> favIconSvc(
|
||||||
do_GetService("@mozilla.org/browser/favicon-service;1"));
|
do_GetService("@mozilla.org/browser/favicon-service;1"));
|
||||||
NS_ENSURE_TRUE(favIconSvc, NS_ERROR_FAILURE);
|
NS_ENSURE_TRUE(favIconSvc, NS_ERROR_FAILURE);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue