зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to inbound. a=merge CLOSED TREE
This commit is contained in:
Коммит
17675612bf
|
@ -126,7 +126,7 @@ if (AppConstants.NIGHTLY_BUILD) {
|
|||
// lazy service getters
|
||||
|
||||
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"],
|
||||
gDNSService: ["@mozilla.org/network/dns-service;1", "nsIDNSService"],
|
||||
gSerializationHelper: ["@mozilla.org/network/serialization-helper;1", "nsISerializationHelper"],
|
||||
|
|
|
@ -8,6 +8,7 @@ support-files =
|
|||
[browser_devices_get_user_media.js]
|
||||
skip-if = (os == "linux" && debug) # linux: bug 976544
|
||||
[browser_devices_get_user_media_anim.js]
|
||||
[browser_devices_get_user_media_default_permissions.js]
|
||||
[browser_devices_get_user_media_in_frame.js]
|
||||
skip-if = debug # bug 1369731
|
||||
[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()) {
|
||||
let win = windows.getNext();
|
||||
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)) {
|
||||
|
|
|
@ -85,7 +85,7 @@
|
|||
value="custom"
|
||||
search-l10n-ids="
|
||||
history-private-browsing-permanent.label,
|
||||
history-remember-option.label,
|
||||
history-remember-browser-option.label,
|
||||
history-remember-search-option.label,
|
||||
history-clear-on-close-option.label,
|
||||
history-clear-on-close-settings.label"/>
|
||||
|
@ -120,7 +120,7 @@
|
|||
preference="browser.privatebrowsing.autostart"/>
|
||||
<vbox class="indent">
|
||||
<checkbox id="rememberHistory"
|
||||
data-l10n-id="history-remember-option"
|
||||
data-l10n-id="history-remember-browser-option"
|
||||
preference="places.history.enabled"/>
|
||||
<checkbox id="rememberForms"
|
||||
data-l10n-id="history-remember-search-option"
|
||||
|
@ -146,7 +146,7 @@
|
|||
<button id="clearDataSettings"
|
||||
class="accessory-button"
|
||||
data-l10n-id="history-clear-on-close-settings"
|
||||
searchkeywords="&clearDataSettings3.label;
|
||||
searchkeywords="&clearDataSettings4.label;
|
||||
&historySection.label;
|
||||
&itemHistoryAndDownloads.label;
|
||||
&itemCookies.label;
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
|
||||
<script type="application/javascript" src="chrome://browser/content/preferences/sanitize.js"/>
|
||||
|
||||
<description>&clearDataSettings3.label;</description>
|
||||
<description>&clearDataSettings4.label;</description>
|
||||
|
||||
<groupbox orient="horizontal">
|
||||
<caption><label>&historySection.label;</label></caption>
|
||||
|
|
|
@ -696,8 +696,8 @@ history-private-browsing-permanent =
|
|||
.label = Always use private browsing mode
|
||||
.accesskey = p
|
||||
|
||||
history-remember-option =
|
||||
.label = Remember my browsing and download history
|
||||
history-remember-browser-option =
|
||||
.label = Remember browsing and download history
|
||||
.accesskey = b
|
||||
|
||||
history-remember-search-option =
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<!-- LOCALIZATION NOTE (sanitizeDialog2.width): width of the Clear Recent History dialog -->
|
||||
<!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 -->
|
||||
<!-- LOCALIZATION NOTE (clearTimeDuration.*): "Time range to clear" dropdown.
|
||||
|
|
|
@ -341,12 +341,20 @@ function prompt(aBrowser, aRequest) {
|
|||
let { audioDevices, videoDevices, sharingScreen, sharingAudio,
|
||||
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,
|
||||
// deny again without even showing the notification icon.
|
||||
if ((audioDevices.length && SitePermissions
|
||||
.get(null, "microphone", aBrowser).state == SitePermissions.BLOCK) ||
|
||||
.get(uri, "microphone", aBrowser).state == SitePermissions.BLOCK) ||
|
||||
(videoDevices.length && SitePermissions
|
||||
.get(null, sharingScreen ? "screen" : "camera", aBrowser).state == SitePermissions.BLOCK)) {
|
||||
.get(uri, sharingScreen ? "screen" : "camera", aBrowser).state == SitePermissions.BLOCK)) {
|
||||
denyRequest(aBrowser, aRequest);
|
||||
return;
|
||||
}
|
||||
|
@ -356,14 +364,6 @@ function prompt(aBrowser, aRequest) {
|
|||
aBrowser.dispatchEvent(new aBrowser.ownerGlobal
|
||||
.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 stringBundle = chromeDoc.defaultView.gNavigatorBundle;
|
||||
|
||||
|
|
|
@ -104,16 +104,19 @@ if test -n "$ENABLE_CLANG_PLUGIN"; then
|
|||
AC_LANG_SAVE
|
||||
AC_LANG_CPLUSPLUS
|
||||
_SAVE_CXXFLAGS="$CXXFLAGS"
|
||||
_SAVE_CPPFLAGS="$CPPFLAGS"
|
||||
_SAVE_CXX="$CXX"
|
||||
_SAVE_MACOSX_DEPLOYMENT_TARGET="$MACOSX_DEPLOYMENT_TARGET"
|
||||
unset MACOSX_DEPLOYMENT_TARGET
|
||||
CXXFLAGS="${LLVM_CXXFLAGS}"
|
||||
CPPFLAGS=""
|
||||
CXX="${HOST_CXX}"
|
||||
AC_TRY_COMPILE([#include "clang/ASTMatchers/ASTMatchers.h"],
|
||||
[clang::ast_matchers::cxxConstructExpr();],
|
||||
ac_cv_have_new_ASTMatcher_names="yes",
|
||||
ac_cv_have_new_ASTMatcher_names="no")
|
||||
CXX="$_SAVE_CXX"
|
||||
CPPFLAGS="$_SAVE_CPPFLAGS"
|
||||
CXXFLAGS="$_SAVE_CXXFLAGS"
|
||||
export MACOSX_DEPLOYMENT_TARGET="$_SAVE_MACOSX_DEPLOYMENT_TARGET"
|
||||
AC_LANG_RESTORE
|
||||
|
@ -131,10 +134,12 @@ if test -n "$ENABLE_CLANG_PLUGIN"; then
|
|||
AC_LANG_SAVE
|
||||
AC_LANG_CPLUSPLUS
|
||||
_SAVE_CXXFLAGS="$CXXFLAGS"
|
||||
_SAVE_CPPFLAGS="$CPPFLAGS"
|
||||
_SAVE_CXX="$CXX"
|
||||
_SAVE_MACOSX_DEPLOYMENT_TARGET="$MACOSX_DEPLOYMENT_TARGET"
|
||||
unset MACOSX_DEPLOYMENT_TARGET
|
||||
CXXFLAGS="${LLVM_CXXFLAGS}"
|
||||
CPPFLAGS=""
|
||||
CXX="${HOST_CXX}"
|
||||
AC_TRY_COMPILE([#include "clang/ASTMatchers/ASTMatchers.h"],
|
||||
[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="no")
|
||||
CXX="$_SAVE_CXX"
|
||||
CPPFLAGS="$_SAVE_CPPFLAGS"
|
||||
CXXFLAGS="$_SAVE_CXXFLAGS"
|
||||
export MACOSX_DEPLOYMENT_TARGET="$_SAVE_MACOSX_DEPLOYMENT_TARGET"
|
||||
AC_LANG_RESTORE
|
||||
|
|
|
@ -39,6 +39,7 @@ function TabboxPanel({
|
|||
activeTabId,
|
||||
cloneSelectedRequest = () => {},
|
||||
connector,
|
||||
hideToggleButton,
|
||||
openLink,
|
||||
request,
|
||||
selectTab,
|
||||
|
@ -56,7 +57,8 @@ function TabboxPanel({
|
|||
onSelect: selectTab,
|
||||
renderOnlySelected: true,
|
||||
showAllTabsMenu: true,
|
||||
sidebarToggleButton: {
|
||||
sidebarToggleButton: hideToggleButton ? null :
|
||||
{
|
||||
collapsed: false,
|
||||
collapsePaneTitle: COLLAPSE_DETAILS_PANE,
|
||||
expandPaneTitle: "",
|
||||
|
@ -144,6 +146,7 @@ TabboxPanel.propTypes = {
|
|||
request: PropTypes.object,
|
||||
selectTab: PropTypes.func.isRequired,
|
||||
sourceMapService: PropTypes.object,
|
||||
hideToggleButton: PropTypes.boolean,
|
||||
};
|
||||
|
||||
module.exports = TabboxPanel;
|
||||
|
|
|
@ -148,6 +148,7 @@ function NetworkEventMessage({
|
|||
selectTab: (tabId) => {
|
||||
dispatch(actions.selectNetworkMessageTab(tabId));
|
||||
},
|
||||
hideToggleButton: true,
|
||||
})
|
||||
);
|
||||
|
||||
|
|
|
@ -94,6 +94,9 @@ async function openRequestAfterUpdates(target, hud) {
|
|||
let urlNode = messageNode.querySelector(".url");
|
||||
urlNode.click();
|
||||
|
||||
let toggleButtonNode = messageNode.querySelector(".sidebar-toggle");
|
||||
ok(!toggleButtonNode, "Sidebar toggle button shouldn't be shown");
|
||||
|
||||
await payload;
|
||||
await testNetworkMessage(toolbox, messageNode);
|
||||
}
|
||||
|
|
|
@ -214,7 +214,6 @@
|
|||
#ifdef MOZ_PLACES
|
||||
#include "nsIFaviconService.h"
|
||||
#include "mozIPlacesPendingOperation.h"
|
||||
#include "mozIAsyncFavicons.h"
|
||||
#endif
|
||||
|
||||
#if NS_PRINT_PREVIEW
|
||||
|
@ -9121,7 +9120,7 @@ nsDocShell::CopyFavicon(nsIURI* aOldURI,
|
|||
}
|
||||
|
||||
#ifdef MOZ_PLACES
|
||||
nsCOMPtr<mozIAsyncFavicons> favSvc =
|
||||
nsCOMPtr<nsIFaviconService> favSvc =
|
||||
do_GetService("@mozilla.org/browser/favicon-service;1");
|
||||
if (favSvc) {
|
||||
favSvc->CopyFavicons(aOldURI, aNewURI,
|
||||
|
|
|
@ -32,7 +32,7 @@ SpecialPowers.registerConsoleListener(function ConsoleMsgListener(aMsg) {
|
|||
if (aMsg.message == "SENTINEL") {
|
||||
is(consoleCount, 0);
|
||||
SimpleTest.executeSoon(finish);
|
||||
} else {
|
||||
} else if (aMsg.message.includes("Content Security Policy")) {
|
||||
++consoleCount;
|
||||
ok(false, "Must never see a console warning here");
|
||||
}
|
||||
|
|
|
@ -570,6 +570,12 @@ WebRenderLayerManager::SetTransactionIdAllocator(TransactionIdAllocator* aAlloca
|
|||
mTransactionIdAllocator = aAllocator;
|
||||
}
|
||||
|
||||
TransactionId
|
||||
WebRenderLayerManager::GetLastTransactionId()
|
||||
{
|
||||
return mLatestTransactionId;
|
||||
}
|
||||
|
||||
void
|
||||
WebRenderLayerManager::AddDidCompositeObserver(DidCompositeObserver* aObserver)
|
||||
{
|
||||
|
|
|
@ -102,6 +102,7 @@ public:
|
|||
virtual TextureFactoryIdentifier GetTextureFactoryIdentifier() override;
|
||||
|
||||
virtual void SetTransactionIdAllocator(TransactionIdAllocator* aAllocator) override;
|
||||
virtual TransactionId GetLastTransactionId() override;
|
||||
|
||||
virtual void AddDidCompositeObserver(DidCompositeObserver* aObserver) override;
|
||||
virtual void RemoveDidCompositeObserver(DidCompositeObserver* aObserver) override;
|
||||
|
|
|
@ -36,11 +36,14 @@ function StartListener(event) {
|
|||
}
|
||||
|
||||
function IterationListener(event) {
|
||||
setTimeout(RemoveReftestWait, 0);
|
||||
window.addEventListener("MozAfterPaint", () => {
|
||||
requestAnimationFrame(RemoveReftestWait);
|
||||
}, { once: true });
|
||||
}
|
||||
|
||||
function RemoveReftestWait() {
|
||||
document.documentElement.classList.remove("reftest-wait");
|
||||
document.documentElement.classList.add("reftest-ignore-pending-paints");
|
||||
}
|
||||
|
||||
</script>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<html class="reftest-wait reftest-no-flush">
|
||||
<title>Testcase, bug 1176969</title>
|
||||
<style>
|
||||
|
||||
|
@ -46,11 +46,14 @@ body { padding: 50px }
|
|||
document.getElementById("parent").addEventListener("animationiteration", IterationListener);
|
||||
|
||||
function IterationListener(event) {
|
||||
setTimeout(RemoveReftestWait, 0);
|
||||
window.addEventListener("MozAfterPaint", () => {
|
||||
requestAnimationFrame(RemoveReftestWait);
|
||||
}, { once: true });
|
||||
}
|
||||
|
||||
function RemoveReftestWait() {
|
||||
document.documentElement.classList.remove("reftest-wait");
|
||||
document.documentElement.classList.add("reftest-ignore-pending-paints");
|
||||
}
|
||||
|
||||
</script>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<html class="reftest-wait reftest-no-flush">
|
||||
<title>Testcase, bug 1176969</title>
|
||||
<style>
|
||||
|
||||
|
@ -48,11 +48,14 @@ function StartListener(event) {
|
|||
}
|
||||
|
||||
function IterationListener(event) {
|
||||
setTimeout(RemoveReftestWait, 0);
|
||||
window.addEventListener("MozAfterPaint", () => {
|
||||
requestAnimationFrame(RemoveReftestWait);
|
||||
}, { once: true });
|
||||
}
|
||||
|
||||
function RemoveReftestWait() {
|
||||
document.documentElement.classList.remove("reftest-wait");
|
||||
document.documentElement.classList.add("reftest-ignore-pending-paints");
|
||||
}
|
||||
|
||||
</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
|
||||
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-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
|
||||
== 1245450-1.html green-rect.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
|
||||
step, enabling testing that layer-tree updates are being correctly generated.
|
||||
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;
|
||||
}
|
||||
|
||||
function shouldWaitForPendingPaints() {
|
||||
function shouldWaitForPendingPaints(contentRootElement) {
|
||||
// if gHaveCanvasSnapshot is false, we're not taking snapshots so
|
||||
// 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) {
|
||||
|
@ -611,13 +627,13 @@ function WaitForTestEnd(contentRootElement, inPrintMode, spellCheckedElements) {
|
|||
switch (state) {
|
||||
case 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";
|
||||
if (shouldWaitForExplicitPaintWaiters()) {
|
||||
gFailureReason += " (waiting for MozPaintWaitFinished)";
|
||||
LogInfo("MakeProgress: waiting for MozPaintWaitFinished");
|
||||
}
|
||||
if (shouldWaitForPendingPaints()) {
|
||||
if (shouldWaitForPendingPaints(contentRootElement)) {
|
||||
gFailureReason += " (waiting for MozAfterPaint)";
|
||||
LogInfo("MakeProgress: waiting for MozAfterPaint");
|
||||
}
|
||||
|
@ -655,7 +671,7 @@ function WaitForTestEnd(contentRootElement, inPrintMode, spellCheckedElements) {
|
|||
// MozReftestInvalidate handler removed reftest-wait.
|
||||
// We expect something to have been invalidated...
|
||||
FlushRendering(FlushMode.ALL);
|
||||
if (!shouldWaitForPendingPaints() && !shouldWaitForExplicitPaintWaiters()) {
|
||||
if (!shouldWaitForPendingPaints(contentRootElement) && !shouldWaitForExplicitPaintWaiters()) {
|
||||
LogWarning("MozInvalidateEvent didn't invalidate");
|
||||
}
|
||||
}
|
||||
|
@ -720,14 +736,14 @@ function WaitForTestEnd(contentRootElement, inPrintMode, spellCheckedElements) {
|
|||
|
||||
case 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 " +
|
||||
"reach zero (after reftest-wait removed and switch to print mode)";
|
||||
if (shouldWaitForExplicitPaintWaiters()) {
|
||||
gFailureReason += " (waiting for MozPaintWaitFinished)";
|
||||
LogInfo("MakeProgress: waiting for MozPaintWaitFinished");
|
||||
}
|
||||
if (shouldWaitForPendingPaints()) {
|
||||
if (shouldWaitForPendingPaints(contentRootElement)) {
|
||||
gFailureReason += " (waiting for MozAfterPaint)";
|
||||
LogInfo("MakeProgress: waiting for MozAfterPaint");
|
||||
}
|
||||
|
@ -1080,6 +1096,15 @@ function LoadURI(uri)
|
|||
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)
|
||||
{
|
||||
if (gVerbose) {
|
||||
|
|
|
@ -1512,6 +1512,9 @@ function RecvLog(type, msg)
|
|||
TestBuffer(msg);
|
||||
} else if (type == "warning") {
|
||||
logger.warning(msg);
|
||||
} else if (type == "error") {
|
||||
logger.error("REFTEST TEST-UNEXPECTED-FAIL | " + g.currentURL + " | " + msg + "\n");
|
||||
++g.testResults.Exception;
|
||||
} else {
|
||||
logger.error("REFTEST TEST-UNEXPECTED-FAIL | " + g.currentURL + " | unknown log type " + type + "\n");
|
||||
++g.testResults.Exception;
|
||||
|
|
|
@ -106,19 +106,10 @@ pref("browser.cache.compression_level", 0);
|
|||
pref("browser.download.forbid_open_with", false);
|
||||
|
||||
// Remove navigator.registerContentHandler
|
||||
#ifdef EARLY_BETA_OR_EARLIER
|
||||
pref("dom.registerContentHandler.enabled", false);
|
||||
#else
|
||||
pref("dom.registerContentHandler.enabled", true);
|
||||
#endif
|
||||
|
||||
// Nightly will have insecure registerProtocolHandler disabled by default
|
||||
// Beta and Stable will remain enabled until Firefox 62 providing deprecation stats.
|
||||
#ifdef NIGHTLY_BUILD
|
||||
// Insecure registerProtocolHandler is disabled by default
|
||||
pref("dom.registerProtocolHandler.insecure.enabled", false);
|
||||
#else
|
||||
pref("dom.registerProtocolHandler.insecure.enabled", true);
|
||||
#endif
|
||||
|
||||
// Whether or not testing features are enabled.
|
||||
pref("dom.quotaManager.testing", false);
|
||||
|
|
|
@ -893,6 +893,9 @@ class BaseMarionetteTestRunner(object):
|
|||
version_info=self.version_info,
|
||||
device_info=device_info)
|
||||
|
||||
if self.shuffle:
|
||||
self.logger.info("Using shuffle seed: %d" % self.shuffle_seed)
|
||||
|
||||
self._log_skipped_tests()
|
||||
|
||||
interrupted = None
|
||||
|
@ -925,8 +928,6 @@ class BaseMarionetteTestRunner(object):
|
|||
|
||||
for run_tests in self.mixin_run_tests:
|
||||
run_tests(tests)
|
||||
if self.shuffle:
|
||||
self.logger.info("Using shuffle seed: %d" % self.shuffle_seed)
|
||||
|
||||
self.logger.suite_end()
|
||||
except Exception:
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include "nsToolkitCompsCID.h"
|
||||
|
||||
#ifdef MOZ_PLACES
|
||||
#include "mozIAsyncFavicons.h"
|
||||
#include "nsIFaviconService.h"
|
||||
#endif // MOZ_PLACES
|
||||
|
||||
|
@ -104,7 +103,7 @@ ShowWithIconBackend(nsIAlertsService* aBackend, nsIAlertNotification* aAlert,
|
|||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsCOMPtr<mozIAsyncFavicons> favicons(do_GetService(
|
||||
nsCOMPtr<nsIFaviconService> favicons(do_GetService(
|
||||
"@mozilla.org/browser/favicon-service;1"));
|
||||
NS_ENSURE_TRUE(favicons, NS_ERROR_FAILURE);
|
||||
|
||||
|
|
|
@ -1872,7 +1872,7 @@ XPCOMUtils.defineLazyGetter(PlacesUtils, "history", function() {
|
|||
|
||||
XPCOMUtils.defineLazyServiceGetter(PlacesUtils, "favicons",
|
||||
"@mozilla.org/browser/favicon-service;1",
|
||||
"mozIAsyncFavicons");
|
||||
"nsIFaviconService");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "bmsvc",
|
||||
"@mozilla.org/browser/nav-bookmarks-service;1",
|
||||
|
|
|
@ -15,7 +15,6 @@ XPIDL_MODULE = 'places'
|
|||
|
||||
if CONFIG['MOZ_PLACES']:
|
||||
XPIDL_SOURCES += [
|
||||
'mozIAsyncFavicons.idl',
|
||||
'mozIAsyncHistory.idl',
|
||||
'mozIAsyncLivemarks.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(
|
||||
nsFaviconService
|
||||
, nsIFaviconService
|
||||
, mozIAsyncFavicons
|
||||
, nsITimerCallback
|
||||
, nsINamed
|
||||
)
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#define nsFaviconService_h_
|
||||
|
||||
#include "nsIFaviconService.h"
|
||||
#include "mozIAsyncFavicons.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
|
@ -50,7 +49,6 @@ public:
|
|||
};
|
||||
|
||||
class nsFaviconService final : public nsIFaviconService
|
||||
, public mozIAsyncFavicons
|
||||
, public nsITimerCallback
|
||||
, public nsINamed
|
||||
{
|
||||
|
@ -124,7 +122,6 @@ public:
|
|||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIFAVICONSERVICE
|
||||
NS_DECL_MOZIASYNCFAVICONS
|
||||
NS_DECL_NSITIMERCALLBACK
|
||||
NS_DECL_NSINAMED
|
||||
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIURI;
|
||||
interface nsIPrincipal;
|
||||
interface mozIPlacesPendingOperation;
|
||||
interface nsIFaviconDataCallback;
|
||||
|
||||
[scriptable, uuid(e81e0b0c-b9f1-4c2e-8f3c-b809933cf73c)]
|
||||
interface nsIFaviconService : nsISupports
|
||||
|
@ -115,6 +118,202 @@ interface nsIFaviconService : nsISupports
|
|||
* The default favicon mimeType
|
||||
*/
|
||||
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)]
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/*
|
||||
* Tests for mozIAsyncFavicons::replaceFaviconData()
|
||||
* Tests for replaceFaviconData()
|
||||
*/
|
||||
|
||||
var iconsvc = PlacesUtils.favicons;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/*
|
||||
* Tests for mozIAsyncFavicons::replaceFaviconData()
|
||||
* Tests for replaceFaviconData()
|
||||
*/
|
||||
|
||||
var iconsvc = PlacesUtils.favicons;
|
||||
|
|
|
@ -106,6 +106,14 @@ namespace TelemetryIPCAccumulator = mozilla::TelemetryIPCAccumulator;
|
|||
// break that cycle, we relax that requirement. Unfortunately this
|
||||
// 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
|
||||
};
|
||||
|
||||
// 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 {
|
||||
public:
|
||||
KeyedHistogram(HistogramID id, const HistogramInfo& info);
|
||||
|
@ -152,8 +171,11 @@ public:
|
|||
Histogram* GetHistogram(const nsCString& name);
|
||||
uint32_t GetHistogramType() const { return mHistogramInfo.histogramType; }
|
||||
nsresult GetJSKeys(JSContext* cx, JS::CallArgs& args);
|
||||
// Note: unlike other methods, GetJSSnapshot is thread safe.
|
||||
nsresult GetJSSnapshot(JSContext* cx, JS::Handle<JSObject*> obj,
|
||||
bool clearSubsession);
|
||||
nsresult GetSnapshot(const StaticMutexAutoLock& aLock,
|
||||
KeyedHistogramSnapshotData& aSnapshot, bool aClearSubsession);
|
||||
|
||||
nsresult Add(const nsCString& key, uint32_t aSample, ProcessID aProcessType);
|
||||
void Clear();
|
||||
|
@ -165,10 +187,6 @@ private:
|
|||
typedef AutoHashtable<KeyedHistogramEntry> KeyedHistogramMapType;
|
||||
KeyedHistogramMapType mHistogramMap;
|
||||
|
||||
static bool ReflectKeyedHistogram(KeyedHistogramEntry* entry,
|
||||
JSContext* cx,
|
||||
JS::Handle<JSObject*> obj);
|
||||
|
||||
const HistogramID mId;
|
||||
const HistogramInfo& mHistogramInfo;
|
||||
};
|
||||
|
@ -622,68 +640,98 @@ internal_HistogramAdd(Histogram& histogram,
|
|||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
MOZ_ASSERT(h);
|
||||
|
||||
enum reflectStatus
|
||||
internal_ReflectHistogramAndSamples(JSContext *cx,
|
||||
JS::Handle<JSObject*> obj, Histogram *h,
|
||||
const Histogram::SampleSet &ss)
|
||||
{
|
||||
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;
|
||||
// Convert the ranges of the buckets to a nsTArray.
|
||||
const size_t bucketCount = h->bucket_count();
|
||||
for (size_t i = 0; i < bucketCount; i++) {
|
||||
if (!aSnapshot.mBucketRanges.AppendElement(h->ranges(i))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return REFLECT_OK;
|
||||
}
|
||||
|
||||
enum reflectStatus
|
||||
internal_ReflectHistogramSnapshot(JSContext *cx,
|
||||
JS::Handle<JSObject*> obj, Histogram *h)
|
||||
{
|
||||
// Get a snapshot of the samples.
|
||||
Histogram::SampleSet 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
|
||||
|
@ -706,10 +754,39 @@ internal_ShouldReflectHistogram(Histogram* h, HistogramID id)
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PRIVATE: class KeyedHistogram
|
||||
// PRIVATE: class KeyedHistogram and internal_ReflectKeyedHistogram
|
||||
|
||||
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)
|
||||
: mHistogramMap()
|
||||
, mId(id)
|
||||
|
@ -848,37 +925,47 @@ KeyedHistogram::GetJSKeys(JSContext* cx, JS::CallArgs& args)
|
|||
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
|
||||
KeyedHistogram::GetJSSnapshot(JSContext* cx, JS::Handle<JSObject*> obj, bool clearSubsession)
|
||||
{
|
||||
if (!mHistogramMap.ReflectIntoJS(&KeyedHistogram::ReflectKeyedHistogram, cx, obj)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
// Get a snapshot of the data.
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -892,14 +979,6 @@ KeyedHistogram::GetJSSnapshot(JSContext* cx, JS::Handle<JSObject*> obj, bool cle
|
|||
//
|
||||
// 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 {
|
||||
|
||||
bool
|
||||
|
@ -1228,8 +1307,7 @@ internal_JSHistogram_Snapshot(JSContext *cx, unsigned argc, JS::Value *vp)
|
|||
MOZ_ASSERT(data);
|
||||
HistogramID id = data->histogramId;
|
||||
|
||||
Histogram* h = nullptr;
|
||||
Histogram::SampleSet ss;
|
||||
HistogramSnapshotData dataSnapshot;
|
||||
{
|
||||
StaticMutexAutoLock locker(gTelemetryHistogramMutex);
|
||||
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
|
||||
// covering multiple processes.
|
||||
// However, changing this requires some broader changes to callers.
|
||||
h = internal_GetHistogramById(id, ProcessID::Parent);
|
||||
// Take a snapshot of Histogram::SampleSet here, protected by the lock,
|
||||
// and then, outside of the lock protection, mirror it to a JS structure
|
||||
MOZ_ASSERT(h);
|
||||
h->SnapshotSample(&ss);
|
||||
Histogram* h = internal_GetHistogramById(id, ProcessID::Parent);
|
||||
// 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::Rooted<JSObject*> snapshot(cx, JS_NewPlainObject(cx));
|
||||
|
@ -1249,18 +1328,14 @@ internal_JSHistogram_Snapshot(JSContext *cx, unsigned argc, JS::Value *vp)
|
|||
return false;
|
||||
}
|
||||
|
||||
reflectStatus status = internal_ReflectHistogramAndSamples(cx, snapshot, h, ss);
|
||||
|
||||
switch (status) {
|
||||
case REFLECT_FAILURE:
|
||||
if (NS_FAILED(internal_ReflectHistogramAndSamples(cx,
|
||||
snapshot,
|
||||
gHistogramInfos[id],
|
||||
dataSnapshot))) {
|
||||
return false;
|
||||
case REFLECT_OK:
|
||||
args.rval().setObject(*snapshot);
|
||||
return true;
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("Unhandled reflection status.");
|
||||
}
|
||||
|
||||
args.rval().setObject(*snapshot);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1407,6 +1482,7 @@ internal_KeyedHistogram_SnapshotImpl(JSContext *cx, unsigned argc,
|
|||
return false;
|
||||
}
|
||||
|
||||
// No argument was passed, so snapshot all the keys.
|
||||
if (args.length() == 0) {
|
||||
JS::RootedObject snapshot(cx, JS_NewPlainObject(cx));
|
||||
if (!snapshot) {
|
||||
|
@ -1423,17 +1499,30 @@ internal_KeyedHistogram_SnapshotImpl(JSContext *cx, unsigned argc,
|
|||
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;
|
||||
if (!args[0].isString() || !key.init(cx, args[0])) {
|
||||
JS_ReportErrorASCII(cx, "Not a string");
|
||||
return false;
|
||||
}
|
||||
|
||||
Histogram* h = nullptr;
|
||||
nsresult rv = keyed->GetHistogram(NS_ConvertUTF16toUTF8(key), &h);
|
||||
if (NS_FAILED(rv)) {
|
||||
JS_ReportErrorASCII(cx, "Failed to get histogram");
|
||||
return false;
|
||||
HistogramSnapshotData dataSnapshot;
|
||||
{
|
||||
StaticMutexAutoLock locker(gTelemetryHistogramMutex);
|
||||
|
||||
// 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));
|
||||
|
@ -1441,17 +1530,15 @@ internal_KeyedHistogram_SnapshotImpl(JSContext *cx, unsigned argc,
|
|||
return false;
|
||||
}
|
||||
|
||||
switch (internal_ReflectHistogramSnapshot(cx, snapshot, h)) {
|
||||
case REFLECT_FAILURE:
|
||||
if (NS_FAILED(internal_ReflectHistogramAndSamples(cx,
|
||||
snapshot,
|
||||
gHistogramInfos[id],
|
||||
dataSnapshot))) {
|
||||
JS_ReportErrorASCII(cx, "Failed to reflect histogram");
|
||||
return false;
|
||||
case REFLECT_OK:
|
||||
args.rval().setObject(*snapshot);
|
||||
return true;
|
||||
default:
|
||||
MOZ_CRASH("unhandled reflection status");
|
||||
}
|
||||
|
||||
args.rval().setObject(*snapshot);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2140,14 +2227,12 @@ TelemetryHistogram::CreateHistogramSnapshots(JSContext* aCx,
|
|||
|
||||
// Struct used to keep information about the histograms for which a
|
||||
// snapshot should be created
|
||||
struct MOZ_NON_MEMMOVABLE HistogramProcessInfo {
|
||||
Histogram* h;
|
||||
Histogram::SampleSet ss;
|
||||
size_t index;
|
||||
struct HistogramProcessInfo {
|
||||
HistogramSnapshotData data;
|
||||
HistogramID histogramID;
|
||||
};
|
||||
|
||||
mozilla::Vector<mozilla::Vector<HistogramProcessInfo>>
|
||||
processHistArray;
|
||||
mozilla::Vector<mozilla::Vector<HistogramProcessInfo>> processHistArray;
|
||||
{
|
||||
if (!processHistArray.resize(static_cast<uint32_t>(ProcessID::Count))) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
@ -2182,9 +2267,12 @@ TelemetryHistogram::CreateHistogramSnapshots(JSContext* aCx,
|
|||
continue;
|
||||
}
|
||||
|
||||
Histogram::SampleSet ss;
|
||||
h->SnapshotSample(&ss);
|
||||
if (!hArray.emplaceBack(HistogramProcessInfo{h, ss, i})) {
|
||||
HistogramSnapshotData snapshotData;
|
||||
if (NS_FAILED(internal_GetHistogramAndSamples(locker, h, snapshotData))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!hArray.emplaceBack(HistogramProcessInfo{snapshotData, id})) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
|
@ -2210,26 +2298,23 @@ TelemetryHistogram::CreateHistogramSnapshots(JSContext* aCx,
|
|||
const mozilla::Vector<HistogramProcessInfo>& hArray = processHistArray[process];
|
||||
for (size_t i = 0; i < hArray.length(); ++i) {
|
||||
const HistogramProcessInfo& hData = hArray[i];
|
||||
uint32_t histogramIndex = hData.index;
|
||||
|
||||
HistogramID id = HistogramID(histogramIndex);
|
||||
HistogramID id = hData.histogramID;
|
||||
|
||||
JS::Rooted<JSObject*> hobj(aCx, JS_NewPlainObject(aCx));
|
||||
if (!hobj) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
Histogram* h = hData.h;
|
||||
reflectStatus status = internal_ReflectHistogramAndSamples(aCx, hobj, h,
|
||||
hData.ss);
|
||||
switch (status) {
|
||||
case REFLECT_FAILURE:
|
||||
if (NS_FAILED(internal_ReflectHistogramAndSamples(aCx,
|
||||
hobj,
|
||||
gHistogramInfos[id],
|
||||
hData.data))) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2256,7 +2341,63 @@ TelemetryHistogram::GetKeyedHistogramSnapshots(JSContext* aCx,
|
|||
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));
|
||||
if (!processObject) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -2265,38 +2406,20 @@ TelemetryHistogram::GetKeyedHistogramSnapshots(JSContext* aCx,
|
|||
processObject, JSPROP_ENUMERATE)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
for (size_t id = 0; id < HistogramCount; ++id) {
|
||||
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(HistogramID(id),
|
||||
ProcessID(process),
|
||||
/* instantiate = */ false);
|
||||
if (!keyed) {
|
||||
continue;
|
||||
}
|
||||
for (size_t i = 0; i < hArray.length(); ++i) {
|
||||
const KeyedHistogramProcessInfo& hData = hArray[i];
|
||||
const HistogramInfo& info = gHistogramInfos[hData.histogramId];
|
||||
|
||||
JS::RootedObject snapshot(aCx, JS_NewPlainObject(aCx));
|
||||
if (!snapshot) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (!JS_DefineProperty(aCx, processObject, gHistogramInfos[id].name(),
|
||||
if (!JS_DefineProperty(aCx, processObject, info.name(),
|
||||
snapshot, JSPROP_ENUMERATE)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
|
|
@ -3890,17 +3890,7 @@ nsWindow::Create(nsIWidget* aParent,
|
|||
// If the window were to get unredirected, there could be visible
|
||||
// tearing because Gecko does not align its framebuffer updates with
|
||||
// vblank.
|
||||
if (mIsX11Display) {
|
||||
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);
|
||||
}
|
||||
SetCompositorHint(GTK_WIDGET_COMPOSIDED_ENABLED);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
@ -4114,60 +4104,70 @@ nsWindow::Create(nsIWidget* aParent,
|
|||
}
|
||||
|
||||
void
|
||||
nsWindow::SetWindowClass(const nsAString &xulWinType)
|
||||
nsWindow::RefreshWindowClass(void)
|
||||
{
|
||||
if (!mShell)
|
||||
return;
|
||||
if (mGtkWindowTypeName.IsEmpty() || mGtkWindowRoleName.IsEmpty())
|
||||
return;
|
||||
|
||||
const char *res_class = gdk_get_program_class();
|
||||
if (!res_class)
|
||||
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);
|
||||
GdkWindow* gdkWindow = gtk_widget_get_window(mShell);
|
||||
gdk_window_set_role(gdkWindow, mGtkWindowRoleName.get());
|
||||
|
||||
#ifdef MOZ_X11
|
||||
if (mIsX11Display) {
|
||||
XClassHint *class_hint = XAllocClassHint();
|
||||
if (!class_hint) {
|
||||
free(res_name);
|
||||
return;
|
||||
}
|
||||
class_hint->res_name = res_name;
|
||||
class_hint->res_class = const_cast<char*>(res_class);
|
||||
if (mIsX11Display) {
|
||||
XClassHint *class_hint = XAllocClassHint();
|
||||
if (!class_hint) {
|
||||
return;
|
||||
}
|
||||
const char *res_class = gdk_get_program_class();
|
||||
if (!res_class)
|
||||
return;
|
||||
|
||||
// Can't use gtk_window_set_wmclass() for this; it prints
|
||||
// a warning & refuses to make the change.
|
||||
GdkDisplay *display = gdk_display_get_default();
|
||||
XSetClassHint(GDK_DISPLAY_XDISPLAY(display),
|
||||
gdk_x11_window_get_xid(gdkWindow),
|
||||
class_hint);
|
||||
XFree(class_hint);
|
||||
}
|
||||
class_hint->res_name = const_cast<char*>(mGtkWindowTypeName.get());
|
||||
class_hint->res_class = const_cast<char*>(res_class);
|
||||
|
||||
// Can't use gtk_window_set_wmclass() for this; it prints
|
||||
// a warning & refuses to make the change.
|
||||
GdkDisplay *display = gdk_display_get_default();
|
||||
XSetClassHint(GDK_DISPLAY_XDISPLAY(display),
|
||||
gdk_x11_window_get_xid(gdkWindow),
|
||||
class_hint);
|
||||
XFree(class_hint);
|
||||
}
|
||||
#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
|
||||
|
@ -6731,6 +6731,10 @@ nsWindow::SetDrawsInTitlebar(bool aState)
|
|||
// can find its way home.
|
||||
g_object_set_data(G_OBJECT(gtk_widget_get_window(mShell)),
|
||||
"nsWindow", this);
|
||||
#ifdef MOZ_X11
|
||||
SetCompositorHint(GTK_WIDGET_COMPOSIDED_ENABLED);
|
||||
#endif
|
||||
RefreshWindowClass();
|
||||
|
||||
// When we use system titlebar setup managed by Gtk+ we also get
|
||||
// _NET_FRAME_EXTENTS property for our toplevel window so we can't
|
||||
|
@ -7212,3 +7216,21 @@ nsWindow::SetProgress(unsigned long progressPercent)
|
|||
progressPercent);
|
||||
#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();
|
||||
|
||||
#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;
|
||||
MozContainer *mContainer;
|
||||
GdkWindow *mGdkWindow;
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
#include "nsNetCID.h"
|
||||
#include "prtime.h"
|
||||
#ifdef MOZ_PLACES
|
||||
#include "mozIAsyncFavicons.h"
|
||||
#include "nsIFaviconService.h"
|
||||
#endif
|
||||
#include "nsIIconURI.h"
|
||||
#include "nsIDownloader.h"
|
||||
|
@ -1649,7 +1649,7 @@ nsresult
|
|||
{
|
||||
#ifdef MOZ_PLACES
|
||||
// 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"));
|
||||
NS_ENSURE_TRUE(favIconSvc, NS_ERROR_FAILURE);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче