зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to graphics
MozReview-Commit-ID: GvQyuOvxr8o
This commit is contained in:
Коммит
cbf426c332
|
@ -55,7 +55,6 @@ b2g/locales/en-US/b2g-l10n.js
|
|||
# browser/ exclusions
|
||||
browser/app/**
|
||||
browser/branding/**/firefox-branding.js
|
||||
browser/base/content/nsContextMenu.js
|
||||
browser/base/content/sanitizeDialog.js
|
||||
browser/base/content/test/general/file_csp_block_all_mixedcontent.html
|
||||
browser/base/content/test/urlbar/file_blank_but_not_blank.html
|
||||
|
|
|
@ -66,9 +66,8 @@ require('../../system/unload').when( _ =>
|
|||
);
|
||||
|
||||
function getNode(id, window) {
|
||||
return !views.has(id) || ignoreWindow(window)
|
||||
? null
|
||||
: CustomizableUI.getWidget(id).forWindow(window).node
|
||||
let view = views.get(id);
|
||||
return view && view.nodes.get(window);
|
||||
};
|
||||
|
||||
function isInToolbar(id) {
|
||||
|
@ -133,9 +132,6 @@ function create(options) {
|
|||
|
||||
let image = getImage(icon, true, window.devicePixelRatio);
|
||||
|
||||
if (ignoreWindow(window))
|
||||
node.style.display = 'none';
|
||||
|
||||
node.setAttribute('id', this.id);
|
||||
node.setAttribute('class', 'toolbarbutton-1 chromeclass-toolbar-additional badged-button');
|
||||
node.setAttribute('type', type);
|
||||
|
@ -144,12 +140,24 @@ function create(options) {
|
|||
node.setAttribute('image', image);
|
||||
node.setAttribute('constrain-size', 'true');
|
||||
|
||||
views.set(id, {
|
||||
if (!views.get(id)) {
|
||||
views.set(id, {
|
||||
nodes: new WeakMap(),
|
||||
});
|
||||
}
|
||||
|
||||
let view = views.get(id);
|
||||
Object.assign(view, {
|
||||
area: this.currentArea,
|
||||
icon: icon,
|
||||
label: label
|
||||
});
|
||||
|
||||
if (ignoreWindow(window))
|
||||
node.style.display = 'none';
|
||||
else
|
||||
view.nodes.set(window, node);
|
||||
|
||||
node.addEventListener('command', function(event) {
|
||||
if (views.has(id)) {
|
||||
emit(viewEvents, 'data', {
|
||||
|
@ -219,7 +227,7 @@ function setBadge(id, window, badge, color) {
|
|||
if (node) {
|
||||
// `Array.from` is needed to handle unicode symbol properly:
|
||||
// '𝐀𝐁'.length is 4 where Array.from('𝐀𝐁').length is 2
|
||||
let text = isNil(badge)
|
||||
let text = badge == null
|
||||
? ''
|
||||
: Array.from(String(badge)).slice(0, 4).join('');
|
||||
|
||||
|
@ -229,7 +237,7 @@ function setBadge(id, window, badge, color) {
|
|||
'class', 'toolbarbutton-badge');
|
||||
|
||||
if (badgeNode)
|
||||
badgeNode.style.backgroundColor = isNil(color) ? '' : color;
|
||||
badgeNode.style.backgroundColor = color == null ? '' : color;
|
||||
}
|
||||
}
|
||||
exports.setBadge = setBadge;
|
||||
|
|
|
@ -97,7 +97,9 @@ tools repackage:: $(DIST)/bin/$(MOZ_APP_NAME)
|
|||
cp -RL $(DIST)/branding/firefox.icns $(dist_dest)/Contents/Resources/firefox.icns
|
||||
cp -RL $(DIST)/branding/document.icns $(dist_dest)/Contents/Resources/document.icns
|
||||
$(MKDIR) -p $(dist_dest)/Contents/Library/LaunchServices
|
||||
ifdef MOZ_UPDATER
|
||||
mv -f $(dist_dest)/Contents/MacOS/updater.app/Contents/MacOS/org.mozilla.updater $(dist_dest)/Contents/Library/LaunchServices
|
||||
ln -s ../../../../Library/LaunchServices/org.mozilla.updater $(dist_dest)/Contents/MacOS/updater.app/Contents/MacOS/org.mozilla.updater
|
||||
endif
|
||||
printf APPLMOZB > $(dist_dest)/Contents/PkgInfo
|
||||
endif
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -7106,8 +7106,7 @@
|
|||
class="tab-content" align="center">
|
||||
<xul:image xbl:inherits="fadein,pinned,busy,progress,selected=visuallyselected"
|
||||
class="tab-throbber"
|
||||
role="presentation"
|
||||
layer="true" />
|
||||
role="presentation"/>
|
||||
<xul:image xbl:inherits="src=image,loadingprincipal=iconLoadingPrincipal,fadein,pinned,selected=visuallyselected,busy,crashed,sharing"
|
||||
anonid="tab-icon-image"
|
||||
class="tab-icon-image"
|
||||
|
|
|
@ -3,7 +3,7 @@ support-files =
|
|||
head.js
|
||||
|
||||
[browser_all_files_referenced.js]
|
||||
skip-if = debug # no point in running on both opt and debug, and will likely intermittently timeout on debug
|
||||
skip-if = debug || (os == 'linux' && bits == 32) # no point in running on both opt and debug, and will likely intermittently timeout on debug; oom crashes on linux32 (bug 1349307)
|
||||
[browser_misused_characters_in_strings.js]
|
||||
support-files =
|
||||
bug1262648_string_with_newlines.dtd
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Slow on asan builds.
|
||||
requestLongerTimeout(5);
|
||||
|
||||
var isDevtools = SimpleTest.harnessParameters.subsuite == "devtools";
|
||||
|
||||
var gExceptionPaths = ["chrome://browser/content/defaultthemes/",
|
||||
|
@ -149,8 +152,6 @@ var whitelist = new Set([
|
|||
{file: "chrome://marionette/content/test_anonymous_content.xul"},
|
||||
{file: "chrome://marionette/content/test_dialog.properties"},
|
||||
{file: "chrome://marionette/content/test_dialog.xul"},
|
||||
// Bug 1348532
|
||||
{file: "chrome://mozapps/content/extensions/list.xul"},
|
||||
// Bug 1348533
|
||||
{file: "chrome://mozapps/skin/downloads/buttons.png", platforms: ["macosx"]},
|
||||
{file: "chrome://mozapps/skin/downloads/downloadButtons.png", platforms: ["linux", "win"]},
|
||||
|
|
|
@ -157,7 +157,7 @@ browser.jar:
|
|||
content/browser/webext-panels.js (content/webext-panels.js)
|
||||
* content/browser/webext-panels.xul (content/webext-panels.xul)
|
||||
* content/browser/baseMenuOverlay.xul (content/baseMenuOverlay.xul)
|
||||
* content/browser/nsContextMenu.js (content/nsContextMenu.js)
|
||||
content/browser/nsContextMenu.js (content/nsContextMenu.js)
|
||||
# XXX: We should exclude this one as well (bug 71895)
|
||||
* content/browser/hiddenWindow.xul (content/hiddenWindow.xul)
|
||||
#ifdef XP_MACOSX
|
||||
|
|
|
@ -42,7 +42,6 @@ DEFINES['MOZ_APP_VERSION_DISPLAY'] = CONFIG['MOZ_APP_VERSION_DISPLAY']
|
|||
DEFINES['APP_LICENSE_BLOCK'] = '%s/content/overrides/app-license.html' % SRCDIR
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3', 'cocoa'):
|
||||
DEFINES['HAVE_SHELL_SERVICE'] = 1
|
||||
DEFINES['CONTEXT_COPY_IMAGE_CONTENTS'] = 1
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'cocoa'):
|
||||
|
|
|
@ -179,7 +179,7 @@ var MessageListener = {
|
|||
|
||||
onLoadStarted() {
|
||||
// Notify the parent that the tab is no longer pending.
|
||||
sendSyncMessage("SessionStore:restoreTabContentStarted", {epoch});
|
||||
sendAsyncMessage("SessionStore:restoreTabContentStarted", {epoch});
|
||||
},
|
||||
|
||||
onLoadFinished() {
|
||||
|
@ -189,13 +189,21 @@ var MessageListener = {
|
|||
}
|
||||
});
|
||||
|
||||
// When restoreHistory finishes, we send a synchronous message to
|
||||
// SessionStore.jsm so that it can run SSTabRestoring. Users of
|
||||
// SSTabRestoring seem to get confused if chrome and content are out of
|
||||
// sync about the state of the restore (particularly regarding
|
||||
// docShell.currentURI). Using a synchronous message is the easiest way
|
||||
// to temporarily synchronize them.
|
||||
sendSyncMessage("SessionStore:restoreHistoryComplete", {epoch, isRemotenessUpdate});
|
||||
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_DEFAULT) {
|
||||
// For non-remote tabs, when restoreHistory finishes, we send a synchronous
|
||||
// message to SessionStore.jsm so that it can run SSTabRestoring. Users of
|
||||
// SSTabRestoring seem to get confused if chrome and content are out of
|
||||
// sync about the state of the restore (particularly regarding
|
||||
// docShell.currentURI). Using a synchronous message is the easiest way
|
||||
// to temporarily synchronize them.
|
||||
//
|
||||
// For remote tabs, because all nsIWebProgress notifications are sent
|
||||
// asynchronously using messages, we get the same-order guarantees of the
|
||||
// message manager, and can use an async message.
|
||||
sendSyncMessage("SessionStore:restoreHistoryComplete", {epoch, isRemotenessUpdate});
|
||||
} else {
|
||||
sendAsyncMessage("SessionStore:restoreHistoryComplete", {epoch, isRemotenessUpdate});
|
||||
}
|
||||
},
|
||||
|
||||
restoreTabContent({loadArguments, isRemotenessUpdate, reason}) {
|
||||
|
@ -326,20 +334,24 @@ var SessionHistoryListener = {
|
|||
},
|
||||
|
||||
OnHistoryNewEntry(newURI, oldIndex) {
|
||||
// We ought to collect the previously current entry as well, see bug 1350567.
|
||||
this.collectFrom(oldIndex);
|
||||
},
|
||||
|
||||
OnHistoryGoBack(backURI) {
|
||||
// We ought to collect the previously current entry as well, see bug 1350567.
|
||||
this.collectFrom(kLastIndex);
|
||||
return true;
|
||||
},
|
||||
|
||||
OnHistoryGoForward(forwardURI) {
|
||||
// We ought to collect the previously current entry as well, see bug 1350567.
|
||||
this.collectFrom(kLastIndex);
|
||||
return true;
|
||||
},
|
||||
|
||||
OnHistoryGotoIndex(index, gotoURI) {
|
||||
// We ought to collect the previously current entry as well, see bug 1350567.
|
||||
this.collectFrom(kLastIndex);
|
||||
return true;
|
||||
},
|
||||
|
|
|
@ -31,6 +31,7 @@ support-files =
|
|||
browser_pageStyle_sample_nested.html
|
||||
browser_sessionHistory_slow.sjs
|
||||
browser_scrollPositions_sample.html
|
||||
browser_scrollPositions_sample2.html
|
||||
browser_scrollPositions_sample_frameset.html
|
||||
browser_scrollPositions_readerModeArticle.html
|
||||
browser_sessionStorage.html
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
const BASE = "http://example.com/browser/browser/components/sessionstore/test/"
|
||||
const URL = BASE + "browser_scrollPositions_sample.html";
|
||||
const URL2 = BASE + "browser_scrollPositions_sample2.html";
|
||||
const URL_FRAMESET = BASE + "browser_scrollPositions_sample_frameset.html";
|
||||
|
||||
// Randomized set of scroll positions we will use in this test.
|
||||
|
@ -108,6 +109,8 @@ add_task(function* test_scroll_nested() {
|
|||
/**
|
||||
* Test that scroll positions persist after restoring background tabs in
|
||||
* a restored window (bug 1228518).
|
||||
* Also test that scroll positions for previous session history entries
|
||||
* are preserved as well (bug 1265818).
|
||||
*/
|
||||
add_task(function* test_scroll_background_tabs() {
|
||||
pushPrefs(["browser.sessionstore.restore_on_demand", true]);
|
||||
|
@ -119,7 +122,15 @@ add_task(function* test_scroll_background_tabs() {
|
|||
|
||||
// Scroll down a little.
|
||||
yield sendMessage(browser, "ss-test:setScrollPosition", {x: SCROLL_X, y: SCROLL_Y});
|
||||
yield checkScroll(tab, {scroll: SCROLL_STR}, "scroll is fine");
|
||||
yield checkScroll(tab, {scroll: SCROLL_STR}, "scroll on first page is fine");
|
||||
|
||||
// Navigate to a different page and scroll there as well.
|
||||
browser.loadURI(URL2);
|
||||
yield BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
// Scroll down a little.
|
||||
yield sendMessage(browser, "ss-test:setScrollPosition", {x: SCROLL2_X, y: SCROLL2_Y});
|
||||
yield checkScroll(tab, {scroll: SCROLL2_STR}, "scroll on second page is fine");
|
||||
|
||||
// Close the window
|
||||
yield BrowserTestUtils.closeWindow(newWin);
|
||||
|
@ -149,7 +160,17 @@ add_task(function* test_scroll_background_tabs() {
|
|||
newWin.gBrowser.selectedTab = tab;
|
||||
yield promiseTabRestored(tab);
|
||||
|
||||
yield checkScroll(tab, {scroll: SCROLL_STR}, "scroll is still fine");
|
||||
yield checkScroll(tab, {scroll: SCROLL2_STR}, "scroll is still fine");
|
||||
|
||||
// Now go back in history and check that the scroll position
|
||||
// is restored there as well.
|
||||
is(browser.canGoBack, true, "can go back");
|
||||
browser.goBack();
|
||||
|
||||
yield BrowserTestUtils.browserLoaded(browser);
|
||||
yield TabStateFlusher.flush(browser);
|
||||
|
||||
yield checkScroll(tab, {scroll: SCROLL_STR}, "scroll is still fine after navigating back");
|
||||
|
||||
yield BrowserTestUtils.closeWindow(newWin);
|
||||
});
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>browser_scrollPositions_sample.html</title>
|
||||
</head>
|
||||
<body style='width: 100000px; height: 100000px;'>top</body>
|
||||
</html>
|
|
@ -35,7 +35,9 @@
|
|||
#ifdef XP_MACOSX
|
||||
; Mac bundle stuff
|
||||
@APPNAME@/Contents/Info.plist
|
||||
#ifdef MOZ_UPDATER
|
||||
@APPNAME@/Contents/Library/LaunchServices
|
||||
#endif
|
||||
@APPNAME@/Contents/PkgInfo
|
||||
@RESPATH@/firefox.icns
|
||||
@RESPATH@/document.icns
|
||||
|
|
|
@ -441,7 +441,14 @@ Function .onInit
|
|||
StrCpy $CheckboxShortcuts "1"
|
||||
StrCpy $CheckboxSendPing "1"
|
||||
!ifdef MOZ_MAINTENANCE_SERVICE
|
||||
StrCpy $CheckboxInstallMaintSvc "1"
|
||||
; We can only install the maintenance service if the user is an admin.
|
||||
Call IsUserAdmin
|
||||
Pop $0
|
||||
${If} "$0" == "true"
|
||||
StrCpy $CheckboxInstallMaintSvc "1"
|
||||
${Else}
|
||||
StrCpy $CheckboxInstallMaintSvc "0"
|
||||
${EndIf}
|
||||
!else
|
||||
StrCpy $CheckboxInstallMaintSvc "0"
|
||||
!endif
|
||||
|
|
|
@ -517,7 +517,6 @@ webNotifications.allow.accesskey=A
|
|||
webNotifications.notNow=Not Now
|
||||
webNotifications.notNow.accesskey=n
|
||||
webNotifications.never=Never Allow
|
||||
webNotifications.neverForSession=Never For This Session
|
||||
webNotifications.never.accesskey=v
|
||||
webNotifications.receiveFromSite2=Will you allow %S to send notifications?
|
||||
# LOCALIZATION NOTE (webNotifications.upgradeTitle): When using native notifications on OS X, the title may be truncated around 32 characters.
|
||||
|
|
|
@ -12,7 +12,6 @@ this.EXPORTED_SYMBOLS = [ "ContentLinkHandler" ];
|
|||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Feeds",
|
||||
"resource:///modules/Feeds.jsm");
|
||||
|
|
|
@ -568,7 +568,7 @@ DesktopNotificationPermissionPrompt.prototype = {
|
|||
},
|
||||
|
||||
get promptActions() {
|
||||
return [
|
||||
let actions = [
|
||||
{
|
||||
label: gBrowserBundle.GetStringFromName("webNotifications.allow"),
|
||||
accessKey:
|
||||
|
@ -582,16 +582,17 @@ DesktopNotificationPermissionPrompt.prototype = {
|
|||
gBrowserBundle.GetStringFromName("webNotifications.notNow.accesskey"),
|
||||
action: SitePermissions.BLOCK,
|
||||
},
|
||||
{
|
||||
label: PrivateBrowsingUtils.isBrowserPrivate(this.browser) ?
|
||||
gBrowserBundle.GetStringFromName("webNotifications.neverForSession") :
|
||||
gBrowserBundle.GetStringFromName("webNotifications.never"),
|
||||
];
|
||||
if (!PrivateBrowsingUtils.isBrowserPrivate(this.browser)) {
|
||||
actions.push({
|
||||
label: gBrowserBundle.GetStringFromName("webNotifications.never"),
|
||||
accessKey:
|
||||
gBrowserBundle.GetStringFromName("webNotifications.never.accesskey"),
|
||||
action: SitePermissions.BLOCK,
|
||||
scope: SitePermissions.SCOPE_PERSISTENT,
|
||||
},
|
||||
];
|
||||
});
|
||||
}
|
||||
return actions;
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -5,11 +5,6 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
/* Global Styles */
|
||||
.checkbox-check {
|
||||
-moz-appearance: checkbox;
|
||||
}
|
||||
|
||||
/* General Pane */
|
||||
#useFirefoxSync,
|
||||
#getStarted {
|
||||
|
|
|
@ -98,9 +98,9 @@
|
|||
skin/classic/browser/search-indicator-magnifying-glass.svg (../shared/search/search-indicator-magnifying-glass.svg)
|
||||
skin/classic/browser/search-arrow-go.svg (../shared/search/search-arrow-go.svg)
|
||||
skin/classic/browser/gear.svg (../shared/search/gear.svg)
|
||||
skin/classic/browser/tabbrowser/connecting.png (../shared/tabbrowser/connecting.png)
|
||||
skin/classic/browser/tabbrowser/connecting@2x.png (../shared/tabbrowser/connecting@2x.png)
|
||||
skin/classic/browser/tabbrowser/connecting.svg (../shared/tabbrowser/connecting.svg)
|
||||
skin/classic/browser/tabbrowser/crashed.svg (../shared/tabbrowser/crashed.svg)
|
||||
skin/classic/browser/tabbrowser/loading.svg (../shared/tabbrowser/loading.svg)
|
||||
skin/classic/browser/tabbrowser/pendingpaint.png (../shared/tabbrowser/pendingpaint.png)
|
||||
skin/classic/browser/tabbrowser/tab-audio.svg (../shared/tabbrowser/tab-audio.svg)
|
||||
skin/classic/browser/tabbrowser/tab-audio-small.svg (../shared/tabbrowser/tab-audio-small.svg)
|
||||
|
|
Двоичные данные
browser/themes/shared/tabbrowser/connecting.png
Двоичные данные
browser/themes/shared/tabbrowser/connecting.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 8.3 KiB |
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<path d="M8,0A8,8,0,0,0,0,8a8,8,0,0,0,8,8,8,8,0,0,0,8-8A8,8,0,0,0,8,0ZM8,13A5,5,0,0,1,3,8,5,5,0,0,1,8,3a5,5,0,0,1,5,5A5,5,0,0,1,8,13Z" fill="context-fill" fill-opacity=".2"/>
|
||||
<circle cx="14.5" cy="8" r="1.5" fill="context-fill" fill-opacity=".8"/>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 495 B |
Двоичные данные
browser/themes/shared/tabbrowser/connecting@2x.png
Двоичные данные
browser/themes/shared/tabbrowser/connecting@2x.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 29 KiB |
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
|
||||
<defs>
|
||||
<radialGradient id="radialGradient" cx=".85" cy=".65" r=".75">
|
||||
<stop stop-color="#000" offset=".2"/>
|
||||
<stop stop-color="#fff" offset="1"/>
|
||||
</radialGradient>
|
||||
|
||||
<mask id="myMask">
|
||||
<rect width="16" height="16" fill="#fff"/>
|
||||
<path d="M11.8,9.3A4,4,0,1,1,5.2,5.2L1.6,1.6a9,9,0,1,0,14.9,9.2Z" fill="url(#radialGradient)"/>
|
||||
</mask>
|
||||
</defs>
|
||||
|
||||
<path fill="#0077ff" fill-opacity=".15" d="M8,0A8,8,0,0,0,0,8a8,8,0,0,0,8,8,8,8,0,0,0,8-8A8,8,0,0,0,8,0ZM8,13A5,5,0,0,1,3,8,5,5,0,0,1,8,3a5,5,0,0,1,5,5A5,5,0,0,1,8,13Z"/>
|
||||
<path mask="url(#myMask)" fill="#0090ff" d="M8,3a5,5,0,0,1,5,5h0a1.5,1.5,0,0,0,3,0h0a8,8,0,1,0-.8,3.5l-2.7-1.3A5,5,0,1,1,8,3Z"/>
|
||||
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 932 B |
|
@ -178,12 +178,34 @@
|
|||
list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-white-blocked");
|
||||
}
|
||||
|
||||
@keyframes tab-throbber-loading {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes tab-throbber-connecting {
|
||||
from {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.tab-throbber[busy] {
|
||||
list-style-image: url("chrome://browser/skin/tabbrowser/connecting.png");
|
||||
list-style-image: url("chrome://browser/skin/tabbrowser/connecting.svg");
|
||||
animation-duration: 960ms;
|
||||
animation-iteration-count: infinite;
|
||||
animation-name: tab-throbber-connecting;
|
||||
animation-timing-function: linear;
|
||||
/* uncomment after bug 1350010:
|
||||
context-properties: fill;
|
||||
*/
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
.tab-throbber[progress] {
|
||||
list-style-image: url("chrome://global/skin/icons/loading.png");
|
||||
list-style-image: url("chrome://browser/skin/tabbrowser/loading.svg");
|
||||
animation-duration: 800ms;
|
||||
animation-name: tab-throbber-loading;
|
||||
}
|
||||
|
||||
.tab-label {
|
||||
|
@ -562,17 +584,9 @@
|
|||
var(--lwt-header-image);
|
||||
}
|
||||
|
||||
.tab-throbber[busy] {
|
||||
list-style-image: url("chrome://browser/skin/tabbrowser/connecting@2x.png");
|
||||
}
|
||||
|
||||
.tab-icon-image {
|
||||
list-style-image: url("chrome://mozapps/skin/places/defaultFavicon@2x.png");
|
||||
}
|
||||
|
||||
.tab-throbber[progress] {
|
||||
list-style-image: url("chrome://global/skin/icons/loading@2x.png");
|
||||
}
|
||||
}
|
||||
|
||||
/* All tabs menupopup */
|
||||
|
|
|
@ -101,6 +101,22 @@ if test "$OS_TARGET" = "Android"; then
|
|||
AC_MSG_ERROR([Couldn't find path to llvm-libc++ in the android ndk])
|
||||
fi
|
||||
|
||||
if ! test -e "$cxx_include"; then
|
||||
# NDK r13 removes the inner "libcxx" directory.
|
||||
cxx_include="$cxx_base/include"
|
||||
if ! test -e "$cxx_include"; then
|
||||
AC_MSG_ERROR([Couldn't find path to libc++ includes in the android ndk])
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! test -e "$cxxabi_include"; then
|
||||
# NDK r13 removes the inner "libcxxabi" directory.
|
||||
cxxabi_include="$cxxabi_base/include"
|
||||
if ! test -e "$cxxabi_include"; then
|
||||
AC_MSG_ERROR([Couldn't find path to libc++abi includes in the android ndk])
|
||||
fi
|
||||
fi
|
||||
|
||||
STLPORT_LIBS="-L$cxx_libs -lc++_static"
|
||||
# NDK r12 split the libc++ runtime libraries into pieces.
|
||||
for lib in c++abi unwind android_support; do
|
||||
|
@ -111,7 +127,7 @@ if test "$OS_TARGET" = "Android"; then
|
|||
# Add android/support/include/ for prototyping long double math
|
||||
# functions, locale-specific C library functions, multibyte support,
|
||||
# etc.
|
||||
STLPORT_CPPFLAGS="-I$android_ndk/sources/android/support/include -I$cxx_include -I$cxxabi_include"
|
||||
STLPORT_CPPFLAGS="-I$cxx_include -I$android_ndk/sources/android/support/include -I$cxxabi_include"
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([Bad value for --enable-android-cxx-stl])
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {Cu} = require("chrome");
|
||||
const Services = require("Services");
|
||||
const promise = require("promise");
|
||||
const defer = require("devtools/shared/defer");
|
||||
|
|
|
@ -1,47 +1,43 @@
|
|||
<!-- 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/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 16 16" height="16" width="16">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16">
|
||||
<defs>
|
||||
<linearGradient id="b">
|
||||
<stop offset="0" stop-color="#747254"/>
|
||||
<stop offset="1" stop-color="#8b8965"/>
|
||||
<stop stop-color="#747254" offset="0"/>
|
||||
<stop stop-color="#8b8965" offset="1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="a">
|
||||
<stop offset="0" stop-color="#e1e1d7"/>
|
||||
<stop offset="1" stop-color="#f2f2ee"/>
|
||||
<stop stop-color="#e1e1d7" offset="0"/>
|
||||
<stop stop-color="#f2f2ee" offset="1"/>
|
||||
</linearGradient>
|
||||
<linearGradient gradientTransform="translate(-2.38 -2.38) scale(1.17241)" gradientUnits="userSpaceOnUse" y2="4.847" x2="2.94" y1="12.978" x1="13.037" id="g" xlink:href="#a"/>
|
||||
<linearGradient gradientTransform="translate(-2.38 -2.38) scale(1.17241)" gradientUnits="userSpaceOnUse" y2="2.729" x2="4.832" y1="11.063" x1="14.997" id="h" xlink:href="#b"/>
|
||||
<linearGradient gradientTransform="matrix(.64 0 0 .6988 .88 .987)" gradientUnits="userSpaceOnUse" xlink:href="#c" id="i" y2=".583" x2="6.34" y1="4.311" x1="8.637"/>
|
||||
<linearGradient xlink:href="#a" id="g" x1="13" y1="13" x2="2.9" y2="4.8" gradientUnits="userSpaceOnUse" gradientTransform="translate(-2.28 -2.28) scale(1.1724)"/>
|
||||
<linearGradient xlink:href="#b" id="h" x1="15" y1="11.1" x2="4.8" y2="2.7" gradientUnits="userSpaceOnUse" gradientTransform="translate(-2.28 -2.28) scale(1.1724)"/>
|
||||
<linearGradient x1="8.6" y1="4.3" x2="6.3" y2=".6" id="i" xlink:href="#c" gradientUnits="userSpaceOnUse" gradientTransform="matrix(.62854 0 0 .6863 5.97 6.076)"/>
|
||||
<linearGradient id="c">
|
||||
<stop offset="0" stop-color="#c8c8c8"/>
|
||||
<stop offset="1" stop-color="#dcdcdc"/>
|
||||
<stop stop-color="#c8c8c8" offset="0"/>
|
||||
<stop stop-color="#dcdcdc" offset="1"/>
|
||||
</linearGradient>
|
||||
<linearGradient gradientTransform="matrix(.64 0 0 .6988 .88 .987)" gradientUnits="userSpaceOnUse" xlink:href="#d" id="j" y2="1.392" x2="4.956" y1="5.078" x1="7.188"/>
|
||||
<linearGradient x1="7.2" y1="5.1" x2="5" y2="1.4" id="j" xlink:href="#d" gradientUnits="userSpaceOnUse" gradientTransform="matrix(.62854 0 0 .6863 5.97 6.076)"/>
|
||||
<linearGradient id="d">
|
||||
<stop offset="0" stop-color="#a0a0a0"/>
|
||||
<stop offset="1" stop-color="#c8c8c8"/>
|
||||
<stop stop-color="#787878" offset="0"/>
|
||||
<stop stop-color="#8c8c8c" offset="1"/>
|
||||
</linearGradient>
|
||||
<linearGradient gradientTransform="matrix(.62152 0 0 .5895 1.028 -609.403)" gradientUnits="userSpaceOnUse" xlink:href="#c" id="k" y2="1040.666" x2="4.559" y1="1052.085" x1="11.377"/>
|
||||
<linearGradient gradientTransform="matrix(.62152 0 0 .5895 1.028 -609.403)" gradientUnits="userSpaceOnUse" xlink:href="#d" id="l" y2="1041.923" x2="1.917" y1="1053.385" x1="8.842"/>
|
||||
<linearGradient gradientTransform="matrix(.71429 0 0 .71492 .286 .276)" gradientUnits="userSpaceOnUse" xlink:href="#e" id="m" y2="7.825" x2="6.608" y1="12.498" x1="8.54"/>
|
||||
<linearGradient x1="11.4" y1="1052.1" x2="4.6" y2="1040.7" id="k" xlink:href="#c" gradientUnits="userSpaceOnUse" gradientTransform="matrix(.6104 0 0 .57897 6.117 -593.406)"/>
|
||||
<linearGradient x1="8.8" y1="1053.4" x2="1.9" y2="1041.9" id="l" xlink:href="#d" gradientUnits="userSpaceOnUse" gradientTransform="matrix(.6104 0 0 .57897 6.117 -593.406)"/>
|
||||
<linearGradient x1="8.5" y1="12.5" x2="6.6" y2="7.8" id="m" xlink:href="#e" gradientUnits="userSpaceOnUse" gradientTransform="matrix(.7015 0 0 .70214 5.388 5.378)"/>
|
||||
<linearGradient id="e">
|
||||
<stop offset="0" stop-color="#505050"/>
|
||||
<stop offset="1" stop-color="#787878"/>
|
||||
<stop stop-color="#505050" offset="0"/>
|
||||
<stop stop-color="#787878" offset="1"/>
|
||||
</linearGradient>
|
||||
<linearGradient gradientTransform="matrix(.71429 0 0 .71492 .286 .276)" gradientUnits="userSpaceOnUse" xlink:href="#f" id="n" y2="7.414" x2="7.402" y1="12.116" x1="9.392"/>
|
||||
<linearGradient x1="9.4" y1="12.1" x2="7.4" y2="7.4" id="n" xlink:href="#f" gradientUnits="userSpaceOnUse" gradientTransform="matrix(.7015 0 0 .70214 5.388 5.378)"/>
|
||||
<linearGradient id="f">
|
||||
<stop offset="0" stop-color="#787878"/>
|
||||
<stop offset="1" stop-color="#b4b4b4"/>
|
||||
<stop stop-color="#787878" offset="0"/>
|
||||
<stop stop-color="#b4b4b4" offset="1"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g stroke-linejoin="round">
|
||||
<path d="M9.351.2l1.603 1.575.833.819h.84c.65 0 1.173.52 1.173 1.167v8.872c0 .646-.523 1.167-1.172 1.167H1.372C.722 13.8.2 13.28.2 12.633V3.76c0-.647.523-1.167 1.172-1.167h5.543l.834-.819L9.35.2z" fill="url(#g)" stroke="url(#h)" stroke-width=".4"/>
|
||||
<g transform="matrix(.9821 0 0 .98213 5.107 5.107)">
|
||||
<path d="M6 1.215a2.982 2.982 0 0 0-2.991 2.904c.114-.019.238-.045.357-.045h.938C4.386 3.194 5.1 2.421 6 2.421c.899 0 1.614.773 1.696 1.653h.938c.119 0 .243.026.357.045A2.982 2.982 0 0 0 6 1.215z" fill="url(#i)" stroke="url(#j)" stroke-width=".611"/>
|
||||
<rect y="4.065" x="1.214" ry=".787" rx=".787" height="6.72" width="9.571" fill="url(#k)" stroke="url(#l)" stroke-width=".611"/>
|
||||
<path d="M6 5.504A1.2 1.2 0 0 0 4.795 6.71c0 .562.375 1.023.893 1.162v1.475h.625V7.872c.517-.139.892-.6.892-1.162A1.2 1.2 0 0 0 6 5.504z" fill="url(#m)" stroke="url(#n)" stroke-width=".407"/>
|
||||
</g>
|
||||
</g>
|
||||
<path d="M9.5.3L11 2l1 .7h.7c.7 0 1.2.5 1.2 1.2v8.7c0 .7-.6 1.2-1.3 1.2H1.5c-.7 0-1.2-.6-1.2-1.3V4c0-.8.5-1.3 1.2-1.3H7l.8-.8L9.4.2z" fill="url(#g)" stroke="url(#h)" stroke-width=".6" stroke-linejoin="round"/>
|
||||
<path d="M11 6.3a3 3 0 0 0-3 3l.4-.2h1c0-.8.7-1.5 1.6-1.5 1 0 1.6.7 1.7 1.6h1l.2.2a3 3 0 0 0-3-3z" fill="url(#i)" stroke="url(#j)" stroke-width=".6" stroke-linejoin="round"/>
|
||||
<rect width="9.4" height="6.6" rx=".8" ry=".8" x="6.3" y="9.1" fill="url(#k)" stroke="url(#l)" stroke-width=".6" stroke-linejoin="round"/>
|
||||
<path d="M11 10.5a1.2 1.2 0 0 0-1.2 1.2c0 .5.4 1 1 1v1.6h.5v-1.5c.5 0 1-.6 1-1a1.2 1.2 0 0 0-1.3-1.3z" fill="url(#m)" stroke="url(#n)" stroke-width=".4" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
|
До Ширина: | Высота: | Размер: 3.5 KiB После Ширина: | Высота: | Размер: 3.2 KiB |
|
@ -50,6 +50,17 @@ function consoleOpened(hud) {
|
|||
// Use another js script to not depend on the test file line numbers.
|
||||
Services.scriptloader.loadSubScript(TEST_FILE, hud.iframeWindow);
|
||||
|
||||
// Bug 1348885: test that error from nuked globals do not throw
|
||||
let sandbox = new Cu.Sandbox(null, {
|
||||
wantComponents: false,
|
||||
wantGlobalProperties: ["URL", "URLSearchParams"],
|
||||
});
|
||||
let error = Cu.evalInSandbox(`
|
||||
new Error("1348885");
|
||||
`, sandbox);
|
||||
Cu.reportError(error);
|
||||
Cu.nukeSandbox(sandbox);
|
||||
|
||||
// Add a message from a content window.
|
||||
content.console.log("bug587757b");
|
||||
|
||||
|
@ -99,6 +110,12 @@ function consoleOpened(hud) {
|
|||
// and consoleOpened call
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Error from nuked global works",
|
||||
text: "1348885",
|
||||
category: CATEGORY_JS,
|
||||
severity: SEVERITY_ERROR,
|
||||
},
|
||||
{
|
||||
name: "content window console.log() is displayed",
|
||||
text: "bug587757b",
|
||||
|
|
|
@ -1512,7 +1512,9 @@ WebConsoleActor.prototype =
|
|||
{
|
||||
let stack = null;
|
||||
// Convert stack objects to the JSON attributes expected by client code
|
||||
if (aPageError.stack) {
|
||||
// Bug 1348885: If the global from which this error came from has been
|
||||
// nuked, stack is going to be a dead wrapper.
|
||||
if (aPageError.stack && !Cu.isDeadWrapper(aPageError.stack)) {
|
||||
stack = [];
|
||||
let s = aPageError.stack;
|
||||
while (s !== null) {
|
||||
|
|
|
@ -155,8 +155,7 @@ exports.Memory = Class({
|
|||
boundaries = { debugger: this.dbg };
|
||||
}
|
||||
}
|
||||
const path = ThreadSafeChromeUtils.saveHeapSnapshot(boundaries);
|
||||
return HeapSnapshotFileUtils.getSnapshotIdFromPath(path);
|
||||
return ThreadSafeChromeUtils.saveHeapSnapshotGetId(boundaries);
|
||||
}, "saveHeapSnapshot"),
|
||||
|
||||
/**
|
||||
|
|
|
@ -1444,13 +1444,19 @@ msSinceProcessCreation(const TimeStamp& now)
|
|||
/* static */ already_AddRefed<nsIFile>
|
||||
HeapSnapshot::CreateUniqueCoreDumpFile(ErrorResult& rv,
|
||||
const TimeStamp& now,
|
||||
nsAString& outFilePath)
|
||||
nsAString& outFilePath,
|
||||
nsAString& outSnapshotId)
|
||||
{
|
||||
nsCOMPtr<nsIFile> file;
|
||||
rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(file));
|
||||
if (NS_WARN_IF(rv.Failed()))
|
||||
return nullptr;
|
||||
|
||||
nsAutoString tempPath;
|
||||
rv = file->GetPath(tempPath);
|
||||
if (NS_WARN_IF(rv.Failed()))
|
||||
return nullptr;
|
||||
|
||||
auto ms = msSinceProcessCreation(now);
|
||||
rv = file->AppendNative(nsPrintfCString("%lu.fxsnapshot", ms));
|
||||
if (NS_WARN_IF(rv.Failed()))
|
||||
|
@ -1462,7 +1468,12 @@ HeapSnapshot::CreateUniqueCoreDumpFile(ErrorResult& rv,
|
|||
|
||||
rv = file->GetPath(outFilePath);
|
||||
if (NS_WARN_IF(rv.Failed()))
|
||||
return nullptr;
|
||||
return nullptr;
|
||||
|
||||
// The snapshot ID must be computed in the process that created the
|
||||
// temp file, because TmpD may not be the same in all processes.
|
||||
outSnapshotId.Assign(Substring(outFilePath, tempPath.Length() + 1,
|
||||
outFilePath.Length() - tempPath.Length() - sizeof(".fxsnapshot")));
|
||||
|
||||
return file.forget();
|
||||
}
|
||||
|
@ -1489,14 +1500,18 @@ using UniqueHeapSnapshotTempFileHelperChild = UniquePtr<PHeapSnapshotTempFileHel
|
|||
// the filesystem. Use IPDL to request a file descriptor from the parent
|
||||
// process.
|
||||
static already_AddRefed<nsIOutputStream>
|
||||
getCoreDumpOutputStream(ErrorResult& rv, TimeStamp& start, nsAString& outFilePath)
|
||||
getCoreDumpOutputStream(ErrorResult& rv,
|
||||
TimeStamp& start,
|
||||
nsAString& outFilePath,
|
||||
nsAString& outSnapshotId)
|
||||
{
|
||||
if (XRE_IsParentProcess()) {
|
||||
// Create the file and open the output stream directly.
|
||||
|
||||
nsCOMPtr<nsIFile> file = HeapSnapshot::CreateUniqueCoreDumpFile(rv,
|
||||
start,
|
||||
outFilePath);
|
||||
outFilePath,
|
||||
outSnapshotId);
|
||||
if (NS_WARN_IF(rv.Failed()))
|
||||
return nullptr;
|
||||
|
||||
|
@ -1535,6 +1550,7 @@ getCoreDumpOutputStream(ErrorResult& rv, TimeStamp& start, nsAString& outFilePat
|
|||
|
||||
auto opened = response.get_OpenedFile();
|
||||
outFilePath = opened.path();
|
||||
outSnapshotId = opened.snapshotId();
|
||||
nsCOMPtr<nsIOutputStream> outputStream =
|
||||
FileDescriptorOutputStream::Create(opened.descriptor());
|
||||
if (NS_WARN_IF(!outputStream)) {
|
||||
|
@ -1553,10 +1569,11 @@ using namespace JS;
|
|||
using namespace devtools;
|
||||
|
||||
/* static */ void
|
||||
ThreadSafeChromeUtils::SaveHeapSnapshot(GlobalObject& global,
|
||||
const HeapSnapshotBoundaries& boundaries,
|
||||
nsAString& outFilePath,
|
||||
ErrorResult& rv)
|
||||
ThreadSafeChromeUtils::SaveHeapSnapshotShared(GlobalObject& global,
|
||||
const HeapSnapshotBoundaries& boundaries,
|
||||
nsAString& outFilePath,
|
||||
nsAString& outSnapshotId,
|
||||
ErrorResult& rv)
|
||||
{
|
||||
auto start = TimeStamp::Now();
|
||||
|
||||
|
@ -1565,7 +1582,9 @@ ThreadSafeChromeUtils::SaveHeapSnapshot(GlobalObject& global,
|
|||
uint32_t nodeCount = 0;
|
||||
uint32_t edgeCount = 0;
|
||||
|
||||
nsCOMPtr<nsIOutputStream> outputStream = getCoreDumpOutputStream(rv, start, outFilePath);
|
||||
nsCOMPtr<nsIOutputStream> outputStream = getCoreDumpOutputStream(rv, start,
|
||||
outFilePath,
|
||||
outSnapshotId);
|
||||
if (NS_WARN_IF(rv.Failed()))
|
||||
return;
|
||||
|
||||
|
@ -1618,6 +1637,26 @@ ThreadSafeChromeUtils::SaveHeapSnapshot(GlobalObject& global,
|
|||
edgeCount);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
ThreadSafeChromeUtils::SaveHeapSnapshot(GlobalObject& global,
|
||||
const HeapSnapshotBoundaries& boundaries,
|
||||
nsAString& outFilePath,
|
||||
ErrorResult& rv)
|
||||
{
|
||||
nsAutoString snapshotId;
|
||||
SaveHeapSnapshotShared(global, boundaries, outFilePath, snapshotId, rv);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
ThreadSafeChromeUtils::SaveHeapSnapshotGetId(GlobalObject& global,
|
||||
const HeapSnapshotBoundaries& boundaries,
|
||||
nsAString& outSnapshotId,
|
||||
ErrorResult& rv)
|
||||
{
|
||||
nsAutoString filePath;
|
||||
SaveHeapSnapshotShared(global, boundaries, filePath, outSnapshotId, rv);
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<HeapSnapshot>
|
||||
ThreadSafeChromeUtils::ReadHeapSnapshot(GlobalObject& global,
|
||||
const nsAString& filePath,
|
||||
|
|
|
@ -126,7 +126,8 @@ public:
|
|||
// snapshots are serialized into.
|
||||
static already_AddRefed<nsIFile> CreateUniqueCoreDumpFile(ErrorResult& rv,
|
||||
const TimeStamp& now,
|
||||
nsAString& outFilePath);
|
||||
nsAString& outFilePath,
|
||||
nsAString& outSnapshotId);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(HeapSnapshot)
|
||||
|
|
|
@ -81,15 +81,3 @@ exports.haveHeapSnapshotTempFile = function (snapshotId) {
|
|||
return OS.File.stat(path).then(() => true,
|
||||
() => false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Given a heap snapshot's file path, extricate the snapshot id.
|
||||
*
|
||||
* @param {String} path
|
||||
*
|
||||
* @returns String
|
||||
*/
|
||||
exports.getSnapshotIdFromPath = function (path) {
|
||||
return path.slice(OS.Constants.Path.tmpDir.length + 1,
|
||||
path.length - ".fxsnapshot".length);
|
||||
};
|
||||
|
|
|
@ -31,9 +31,11 @@ HeapSnapshotTempFileHelperParent::RecvOpenHeapSnapshotTempFile(
|
|||
auto start = TimeStamp::Now();
|
||||
ErrorResult rv;
|
||||
nsAutoString filePath;
|
||||
nsAutoString snapshotId;
|
||||
nsCOMPtr<nsIFile> file = HeapSnapshot::CreateUniqueCoreDumpFile(rv,
|
||||
start,
|
||||
filePath);
|
||||
filePath,
|
||||
snapshotId);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
if (!openFileFailure(rv, outResponse)) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
|
@ -53,7 +55,7 @@ HeapSnapshotTempFileHelperParent::RecvOpenHeapSnapshotTempFile(
|
|||
FileDescriptor::PlatformHandleType handle =
|
||||
FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(prfd));
|
||||
FileDescriptor fd(handle);
|
||||
*outResponse = OpenedFile(filePath, fd);
|
||||
*outResponse = OpenedFile(filePath, snapshotId, fd);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace devtools {
|
|||
struct OpenedFile
|
||||
{
|
||||
nsString path;
|
||||
nsString snapshotId;
|
||||
FileDescriptor descriptor;
|
||||
};
|
||||
|
||||
|
|
|
@ -139,6 +139,12 @@ interface nsISHEntry : nsISupports
|
|||
/** LayoutHistoryState for scroll position and form values */
|
||||
attribute nsILayoutHistoryState layoutHistoryState;
|
||||
|
||||
/**
|
||||
* Initialises the LayoutHistoryState if it doesn't already exist
|
||||
* and returns a reference to it.
|
||||
*/
|
||||
nsILayoutHistoryState initLayoutHistoryState();
|
||||
|
||||
/** parent of this entry */
|
||||
attribute nsISHEntry parent;
|
||||
|
||||
|
|
|
@ -292,6 +292,19 @@ nsSHEntry::SetLayoutHistoryState(nsILayoutHistoryState* aState)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSHEntry::InitLayoutHistoryState(nsILayoutHistoryState** aState)
|
||||
{
|
||||
if (!mShared->mLayoutHistoryState) {
|
||||
nsCOMPtr<nsILayoutHistoryState> historyState;
|
||||
historyState = NS_NewLayoutHistoryState();
|
||||
nsresult rv = SetLayoutHistoryState(historyState);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return GetLayoutHistoryState(aState);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSHEntry::GetLoadType(uint32_t* aResult)
|
||||
{
|
||||
|
|
|
@ -74,7 +74,7 @@ var data = [
|
|||
},
|
||||
{
|
||||
wrong: 'user:@example.com:8080/this/is/a/test.html',
|
||||
fixed: 'http://user:@example.com:8080/this/is/a/test.html',
|
||||
fixed: 'http://user@example.com:8080/this/is/a/test.html',
|
||||
},
|
||||
{
|
||||
wrong: '//user:pass@example.com:8080/this/is/a/test.html',
|
||||
|
|
|
@ -40,12 +40,20 @@ struct OwningAnimationTarget
|
|||
|
||||
struct NonOwningAnimationTarget
|
||||
{
|
||||
NonOwningAnimationTarget() = default;
|
||||
|
||||
NonOwningAnimationTarget(dom::Element* aElement, CSSPseudoElementType aType)
|
||||
: mElement(aElement), mPseudoType(aType) { }
|
||||
|
||||
explicit NonOwningAnimationTarget(const OwningAnimationTarget& aOther)
|
||||
: mElement(aOther.mElement), mPseudoType(aOther.mPseudoType) { }
|
||||
|
||||
bool operator==(const NonOwningAnimationTarget& aOther) const
|
||||
{
|
||||
return mElement == aOther.mElement &&
|
||||
mPseudoType == aOther.mPseudoType;
|
||||
}
|
||||
|
||||
// mElement represents the parent element of a pseudo-element, not the
|
||||
// generated content element.
|
||||
dom::Element* MOZ_NON_OWNING_REF mElement = nullptr;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "mozilla/RestyleManagerInlines.h"
|
||||
#include "mozilla/ServoStyleSet.h"
|
||||
#include "mozilla/StyleAnimationValue.h"
|
||||
#include "mozilla/TypeTraits.h" // For Forward<>
|
||||
#include "nsComputedDOMStyle.h" // nsComputedDOMStyle::GetPresShellForContent
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCSSPseudoElements.h"
|
||||
|
@ -360,9 +361,10 @@ EffectCompositor::PostRestyleForThrottledAnimations()
|
|||
}
|
||||
}
|
||||
|
||||
template<typename StyleType>
|
||||
void
|
||||
EffectCompositor::UpdateEffectProperties(nsStyleContext* aStyleContext,
|
||||
dom::Element* aElement,
|
||||
EffectCompositor::UpdateEffectProperties(StyleType&& aStyleType,
|
||||
Element* aElement,
|
||||
CSSPseudoElementType aPseudoType)
|
||||
{
|
||||
EffectSet* effectSet = EffectSet::GetEffectSet(aElement, aPseudoType);
|
||||
|
@ -370,12 +372,13 @@ EffectCompositor::UpdateEffectProperties(nsStyleContext* aStyleContext,
|
|||
return;
|
||||
}
|
||||
|
||||
// Style context change might cause CSS cascade level,
|
||||
// e.g removing !important, so we should update the cascading result.
|
||||
// Style context (Gecko) or computed values (Stylo) change might cause CSS
|
||||
// cascade level, e.g removing !important, so we should update the cascading
|
||||
// result.
|
||||
effectSet->MarkCascadeNeedsUpdate();
|
||||
|
||||
for (KeyframeEffectReadOnly* effect : *effectSet) {
|
||||
effect->UpdateProperties(aStyleContext);
|
||||
effect->UpdateProperties(Forward<StyleType>(aStyleType));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1156,4 +1159,18 @@ EffectCompositor::AnimationStyleRuleProcessor::SizeOfIncludingThis(
|
|||
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
|
||||
}
|
||||
|
||||
template
|
||||
void
|
||||
EffectCompositor::UpdateEffectProperties<RefPtr<nsStyleContext>&>(
|
||||
RefPtr<nsStyleContext>& aStyleContext,
|
||||
Element* aElement,
|
||||
CSSPseudoElementType aPseudoType);
|
||||
|
||||
template
|
||||
void
|
||||
EffectCompositor::UpdateEffectProperties<const ServoComputedValuesWithParent&>(
|
||||
const ServoComputedValuesWithParent& aServoValues,
|
||||
Element* aElement,
|
||||
CSSPseudoElementType aPseudoType);
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -116,11 +116,12 @@ public:
|
|||
// posted because updates on the main thread are throttled.
|
||||
void PostRestyleForThrottledAnimations();
|
||||
|
||||
// Called when the style context on the specified (pseudo-) element might
|
||||
// Called when computed style on the specified (pseudo-) element might
|
||||
// have changed so that any context-sensitive values stored within
|
||||
// animation effects (e.g. em-based endpoints used in keyframe effects)
|
||||
// can be re-resolved to computed values.
|
||||
void UpdateEffectProperties(nsStyleContext* aStyleContext,
|
||||
template<typename StyleType>
|
||||
void UpdateEffectProperties(StyleType&& aStyleType,
|
||||
dom::Element* aElement,
|
||||
CSSPseudoElementType aPseudoType);
|
||||
|
||||
|
|
|
@ -867,6 +867,127 @@ waitForAllPaints(function() {
|
|||
yield ensureElementRemoval(div);
|
||||
});
|
||||
|
||||
add_task(function *no_throttling_animations_in_view_svg() {
|
||||
/*
|
||||
On Android throttled animations are left behind on the main thread in some
|
||||
frames, We will fix this in bug 1247800.
|
||||
*/
|
||||
if (isAndroid) {
|
||||
return;
|
||||
}
|
||||
|
||||
var div = addDiv(null, { style: 'overflow: scroll;' +
|
||||
'height: 100px; width: 100px;' });
|
||||
var svg = addSVGElement(div, 'svg', { viewBox: '-10 -10 0.1 0.1',
|
||||
width: '50px',
|
||||
height: '50px' });
|
||||
var rect = addSVGElement(svg, 'rect', { x: '-10',
|
||||
y: '-10',
|
||||
width: '10',
|
||||
height: '10',
|
||||
fill: 'red' });
|
||||
var animation = rect.animate({ fill: ['blue', 'lime'] }, 100 * MS_PER_SEC);
|
||||
yield animation.ready;
|
||||
|
||||
var markers = yield observeStyling(5);
|
||||
is(markers.length, 5,
|
||||
'CSS animations on an in-view svg element with post-transform should ' +
|
||||
'not be throttled.');
|
||||
|
||||
yield ensureElementRemoval(div);
|
||||
});
|
||||
|
||||
add_task(function *throttling_animations_out_of_view_svg() {
|
||||
if (!SpecialPowers.getBoolPref('dom.animations.offscreen-throttling')) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
On Android throttled animations are left behind on the main thread in some
|
||||
frames, We will fix this in bug 1247800.
|
||||
*/
|
||||
if (isAndroid) {
|
||||
return;
|
||||
}
|
||||
|
||||
var div = addDiv(null, { style: 'overflow: scroll;' +
|
||||
'height: 100px; width: 100px;' });
|
||||
var svg = addSVGElement(div, 'svg', { viewBox: '-10 -10 0.1 0.1',
|
||||
width: '50px',
|
||||
height: '50px' });
|
||||
var rect = addSVGElement(svg, 'rect', { width: '10',
|
||||
height: '10',
|
||||
fill: 'red' });
|
||||
|
||||
var animation = rect.animate({ fill: ['blue', 'lime'] }, 100 * MS_PER_SEC);
|
||||
yield animation.ready;
|
||||
|
||||
var markers = yield observeStyling(5);
|
||||
is(markers.length, 0,
|
||||
'CSS animations on an out-of-view svg element with post-transform ' +
|
||||
'should be throttled.');
|
||||
|
||||
yield ensureElementRemoval(div);
|
||||
});
|
||||
|
||||
add_task(function *no_throttling_animations_in_view_css_transform() {
|
||||
/*
|
||||
On Android throttled animations are left behind on the main thread in some
|
||||
frames, We will fix this in bug 1247800.
|
||||
*/
|
||||
if (isAndroid) {
|
||||
return;
|
||||
}
|
||||
|
||||
var scrollDiv = addDiv(null, { style: 'overflow: scroll; ' +
|
||||
'height: 100px; width: 100px;' });
|
||||
var targetDiv = addDiv(null,
|
||||
{ style: 'animation: background-color 100s;' +
|
||||
'transform: translate(-50px, -50px);' });
|
||||
scrollDiv.appendChild(targetDiv);
|
||||
|
||||
var animation = targetDiv.getAnimations()[0];
|
||||
yield animation.ready;
|
||||
|
||||
var markers = yield observeStyling(5);
|
||||
is(markers.length, 5,
|
||||
'CSS animation on an in-view element with pre-transform should not ' +
|
||||
'be throttled.');
|
||||
|
||||
yield ensureElementRemoval(scrollDiv);
|
||||
});
|
||||
|
||||
add_task(function *throttling_animations_out_of_view_css_transform() {
|
||||
if (!SpecialPowers.getBoolPref('dom.animations.offscreen-throttling')) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
On Android throttled animations are left behind on the main thread in some
|
||||
frames, We will fix this in bug 1247800.
|
||||
*/
|
||||
if (isAndroid) {
|
||||
return;
|
||||
}
|
||||
|
||||
var scrollDiv = addDiv(null, { style: 'overflow: scroll;' +
|
||||
'height: 100px; width: 100px;' });
|
||||
var targetDiv = addDiv(null,
|
||||
{ style: 'animation: background-color 100s;' +
|
||||
'transform: translate(100px, 100px);' });
|
||||
scrollDiv.appendChild(targetDiv);
|
||||
|
||||
var animation = targetDiv.getAnimations()[0];
|
||||
yield animation.ready;
|
||||
|
||||
var markers = yield observeStyling(5);
|
||||
is(markers.length, 0,
|
||||
'CSS animation on an out-of-view element with pre-transform should be ' +
|
||||
'throttled.');
|
||||
|
||||
yield ensureElementRemoval(scrollDiv);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
|
|
|
@ -332,3 +332,25 @@ function isOMTAEnabled() {
|
|||
return SpecialPowers.DOMWindowUtils.layerManagerRemote &&
|
||||
SpecialPowers.getBoolPref(OMTAPrefKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append an SVG element to the target element.
|
||||
*
|
||||
* @param target The element which want to append.
|
||||
* @param attrs A array object with attribute name and values to set on
|
||||
* the SVG element.
|
||||
* @return An SVG outer element.
|
||||
*/
|
||||
function addSVGElement(target, tag, attrs) {
|
||||
if (!target) {
|
||||
return null;
|
||||
}
|
||||
var element = document.createElementNS('http://www.w3.org/2000/svg', tag);
|
||||
if (attrs) {
|
||||
for (var attrName in attrs) {
|
||||
element.setAttributeNS(null, attrName, attrs[attrName]);
|
||||
}
|
||||
}
|
||||
target.appendChild(element);
|
||||
return element;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,14 @@ class Promise;
|
|||
|
||||
class ThreadSafeChromeUtils
|
||||
{
|
||||
private:
|
||||
// Implemented in devtools/shared/heapsnapshot/HeapSnapshot.cpp
|
||||
static void SaveHeapSnapshotShared(GlobalObject& global,
|
||||
const HeapSnapshotBoundaries& boundaries,
|
||||
nsAString& filePath,
|
||||
nsAString& snapshotId,
|
||||
ErrorResult& rv);
|
||||
|
||||
public:
|
||||
// Implemented in devtools/shared/heapsnapshot/HeapSnapshot.cpp
|
||||
static void SaveHeapSnapshot(GlobalObject& global,
|
||||
|
@ -33,6 +41,12 @@ public:
|
|||
nsAString& filePath,
|
||||
ErrorResult& rv);
|
||||
|
||||
// Implemented in devtools/shared/heapsnapshot/HeapSnapshot.cpp
|
||||
static void SaveHeapSnapshotGetId(GlobalObject& global,
|
||||
const HeapSnapshotBoundaries& boundaries,
|
||||
nsAString& snapshotId,
|
||||
ErrorResult& rv);
|
||||
|
||||
// Implemented in devtools/shared/heapsnapshot/HeapSnapshot.cpp
|
||||
static already_AddRefed<devtools::HeapSnapshot> ReadHeapSnapshot(GlobalObject& global,
|
||||
const nsAString& filePath,
|
||||
|
|
|
@ -8052,7 +8052,11 @@ GetSurfaceDataImpl(mozilla::gfx::DataSourceSurface* aSurface,
|
|||
mozilla::gfx::IntSize size = aSurface->GetSize();
|
||||
mozilla::CheckedInt32 requiredBytes =
|
||||
mozilla::CheckedInt32(map.mStride) * mozilla::CheckedInt32(size.height);
|
||||
size_t maxBufLen = requiredBytes.isValid() ? requiredBytes.value() : 0;
|
||||
if (!requiredBytes.isValid()) {
|
||||
return GetSurfaceDataContext::NullValue();
|
||||
}
|
||||
|
||||
size_t maxBufLen = requiredBytes.value();
|
||||
mozilla::gfx::SurfaceFormat format = aSurface->GetFormat();
|
||||
|
||||
// Surface data handling is totally nuts. This is the magic one needs to
|
||||
|
|
|
@ -1327,6 +1327,9 @@ nsIDocument::nsIDocument()
|
|||
mFontFaceSetDirty(true),
|
||||
mGetUserFontSetCalled(false),
|
||||
mPostedFlushUserFontSet(false),
|
||||
mDidFireDOMContentLoaded(true),
|
||||
mHasScrollLinkedEffect(false),
|
||||
mFrameRequestCallbacksScheduled(false),
|
||||
mCompatMode(eCompatibility_FullStandards),
|
||||
mReadyState(ReadyState::READYSTATE_UNINITIALIZED),
|
||||
mStyleBackendType(StyleBackendType::None),
|
||||
|
@ -1355,8 +1358,6 @@ nsIDocument::nsIDocument()
|
|||
mBFCacheEntry(nullptr),
|
||||
mInSyncOperationCount(0),
|
||||
mBlockDOMContentLoaded(0),
|
||||
mDidFireDOMContentLoaded(true),
|
||||
mHasScrollLinkedEffect(false),
|
||||
mUseCounters(0),
|
||||
mChildDocumentUseCounters(0),
|
||||
mNotifiedPageForUseCounter(0),
|
||||
|
@ -1922,6 +1923,9 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
|
|||
tmp->mSubDocuments = nullptr;
|
||||
|
||||
tmp->mFrameRequestCallbacks.Clear();
|
||||
MOZ_RELEASE_ASSERT(!tmp->mFrameRequestCallbacksScheduled,
|
||||
"How did we get here without our presshell going away "
|
||||
"first?");
|
||||
|
||||
tmp->mRadioGroups.Clear();
|
||||
|
||||
|
@ -3797,7 +3801,7 @@ nsDocument::CreateShell(nsPresContext* aContext, nsViewManager* aViewManager,
|
|||
|
||||
mExternalResourceMap.ShowViewers();
|
||||
|
||||
MaybeRescheduleAnimationFrameNotifications();
|
||||
UpdateFrameRequestCallbackSchedulingState();
|
||||
|
||||
// Now that we have a shell, we might have @font-face rules.
|
||||
RebuildUserFontSet();
|
||||
|
@ -3806,17 +3810,29 @@ nsDocument::CreateShell(nsPresContext* aContext, nsViewManager* aViewManager,
|
|||
}
|
||||
|
||||
void
|
||||
nsDocument::MaybeRescheduleAnimationFrameNotifications()
|
||||
nsIDocument::UpdateFrameRequestCallbackSchedulingState(nsIPresShell* aOldShell)
|
||||
{
|
||||
if (!mPresShell || !IsEventHandlingEnabled()) {
|
||||
// bail out for now, until one of those conditions changes
|
||||
// If the condition for shouldBeScheduled changes to depend on some other
|
||||
// variable, add UpdateFrameRequestCallbackSchedulingState() calls to the
|
||||
// places where that variable can change.
|
||||
bool shouldBeScheduled =
|
||||
mPresShell && IsEventHandlingEnabled() && !mFrameRequestCallbacks.IsEmpty();
|
||||
if (shouldBeScheduled == mFrameRequestCallbacksScheduled) {
|
||||
// nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefreshDriver* rd = mPresShell->GetPresContext()->RefreshDriver();
|
||||
if (!mFrameRequestCallbacks.IsEmpty()) {
|
||||
nsIPresShell* presShell = aOldShell ? aOldShell : mPresShell;
|
||||
MOZ_RELEASE_ASSERT(presShell);
|
||||
|
||||
nsRefreshDriver* rd = presShell->GetPresContext()->RefreshDriver();
|
||||
if (shouldBeScheduled) {
|
||||
rd->ScheduleFrameRequestCallbacks(this);
|
||||
} else {
|
||||
rd->RevokeFrameRequestCallbacks(this);
|
||||
}
|
||||
|
||||
mFrameRequestCallbacksScheduled = shouldBeScheduled;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -3824,6 +3840,9 @@ nsIDocument::TakeFrameRequestCallbacks(FrameRequestCallbackList& aCallbacks)
|
|||
{
|
||||
aCallbacks.AppendElements(mFrameRequestCallbacks);
|
||||
mFrameRequestCallbacks.Clear();
|
||||
// No need to manually remove ourselves from the refresh driver; it will
|
||||
// handle that part. But we do have to update our state.
|
||||
mFrameRequestCallbacksScheduled = false;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -3871,9 +3890,6 @@ void
|
|||
nsDocument::DeleteShell()
|
||||
{
|
||||
mExternalResourceMap.HideViewers();
|
||||
if (IsEventHandlingEnabled()) {
|
||||
RevokeAnimationFrameNotifications();
|
||||
}
|
||||
if (nsPresContext* presContext = mPresShell->GetPresContext()) {
|
||||
presContext->RefreshDriver()->CancelPendingEvents(this);
|
||||
}
|
||||
|
@ -3887,19 +3903,12 @@ nsDocument::DeleteShell()
|
|||
// objects for @font-face rules that came from the style set.
|
||||
RebuildUserFontSet();
|
||||
|
||||
nsIPresShell* oldShell = mPresShell;
|
||||
mPresShell = nullptr;
|
||||
UpdateFrameRequestCallbackSchedulingState(oldShell);
|
||||
mStyleSetFilled = false;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::RevokeAnimationFrameNotifications()
|
||||
{
|
||||
if (!mFrameRequestCallbacks.IsEmpty()) {
|
||||
mPresShell->GetPresContext()->RefreshDriver()->
|
||||
RevokeFrameRequestCallbacks(this);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
SubDocClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
|
||||
{
|
||||
|
@ -4654,10 +4663,6 @@ nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
|
|||
// our layout history state now.
|
||||
mLayoutHistoryState = GetLayoutHistoryState();
|
||||
|
||||
if (mPresShell && !EventHandlingSuppressed()) {
|
||||
RevokeAnimationFrameNotifications();
|
||||
}
|
||||
|
||||
// Also make sure to remove our onload blocker now if we haven't done it yet
|
||||
if (mOnloadBlockCount != 0) {
|
||||
nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
|
||||
|
@ -4719,6 +4724,8 @@ nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
|
|||
EnsureOnloadBlocker();
|
||||
}
|
||||
|
||||
UpdateFrameRequestCallbackSchedulingState();
|
||||
|
||||
if (aScriptGlobalObject) {
|
||||
// Go back to using the docshell for the layout history state
|
||||
mLayoutHistoryState = nullptr;
|
||||
|
@ -4752,8 +4759,6 @@ nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
|
|||
}
|
||||
}
|
||||
|
||||
MaybeRescheduleAnimationFrameNotifications();
|
||||
|
||||
// If we are set in a window that is already focused we should remember this
|
||||
// as the time the document gained focus.
|
||||
bool focused = false;
|
||||
|
@ -9396,12 +9401,8 @@ SuppressEventHandlingInDocument(nsIDocument* aDocument, void* aData)
|
|||
void
|
||||
nsDocument::SuppressEventHandling(uint32_t aIncrease)
|
||||
{
|
||||
if (mEventsSuppressed == 0 && aIncrease != 0 && mPresShell &&
|
||||
mScriptGlobalObject) {
|
||||
RevokeAnimationFrameNotifications();
|
||||
}
|
||||
|
||||
mEventsSuppressed += aIncrease;
|
||||
UpdateFrameRequestCallbackSchedulingState();
|
||||
for (uint32_t i = 0; i < aIncrease; ++i) {
|
||||
ScriptLoader()->AddExecuteBlocker();
|
||||
}
|
||||
|
@ -10069,14 +10070,10 @@ nsIDocument::ScheduleFrameRequestCallback(FrameRequestCallback& aCallback,
|
|||
}
|
||||
int32_t newHandle = ++mFrameRequestCallbackCounter;
|
||||
|
||||
bool alreadyRegistered = !mFrameRequestCallbacks.IsEmpty();
|
||||
DebugOnly<FrameRequest*> request =
|
||||
mFrameRequestCallbacks.AppendElement(FrameRequest(aCallback, newHandle));
|
||||
NS_ASSERTION(request, "This is supposed to be infallible!");
|
||||
if (!alreadyRegistered && mPresShell && IsEventHandlingEnabled()) {
|
||||
mPresShell->GetPresContext()->RefreshDriver()->
|
||||
ScheduleFrameRequestCallbacks(this);
|
||||
}
|
||||
UpdateFrameRequestCallbackSchedulingState();
|
||||
|
||||
*aHandle = newHandle;
|
||||
return NS_OK;
|
||||
|
@ -10086,11 +10083,8 @@ void
|
|||
nsIDocument::CancelFrameRequestCallback(int32_t aHandle)
|
||||
{
|
||||
// mFrameRequestCallbacks is stored sorted by handle
|
||||
if (mFrameRequestCallbacks.RemoveElementSorted(aHandle) &&
|
||||
mFrameRequestCallbacks.IsEmpty() &&
|
||||
mPresShell && IsEventHandlingEnabled()) {
|
||||
mPresShell->GetPresContext()->RefreshDriver()->
|
||||
RevokeFrameRequestCallbacks(this);
|
||||
if (mFrameRequestCallbacks.RemoveElementSorted(aHandle)) {
|
||||
UpdateFrameRequestCallbackSchedulingState();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -920,7 +920,7 @@ public:
|
|||
void DecreaseEventSuppression() {
|
||||
MOZ_ASSERT(mEventsSuppressed);
|
||||
--mEventsSuppressed;
|
||||
MaybeRescheduleAnimationFrameNotifications();
|
||||
UpdateFrameRequestCallbackSchedulingState();
|
||||
}
|
||||
|
||||
virtual nsIDocument* GetTemplateContentsOwner() override;
|
||||
|
@ -1535,12 +1535,6 @@ private:
|
|||
void EnableStyleSheetsForSetInternal(const nsAString& aSheetSet,
|
||||
bool aUpdateCSSLoader);
|
||||
|
||||
// Revoke any pending notifications due to requestAnimationFrame calls
|
||||
void RevokeAnimationFrameNotifications();
|
||||
// Reschedule any notifications we need to handle
|
||||
// requestAnimationFrame, if it's OK to do so.
|
||||
void MaybeRescheduleAnimationFrameNotifications();
|
||||
|
||||
void ClearAllBoxObjects();
|
||||
|
||||
// Returns true if the scheme for the url for this document is "about"
|
||||
|
|
|
@ -2967,6 +2967,13 @@ protected:
|
|||
return mId;
|
||||
}
|
||||
|
||||
// Update our frame request callback scheduling state, if needed. This will
|
||||
// schedule or unschedule them, if necessary, and update
|
||||
// mFrameRequestCallbacksScheduled. aOldShell should only be passed when
|
||||
// mPresShell is becoming null; in that case it will be used to get hold of
|
||||
// the relevant refresh driver.
|
||||
void UpdateFrameRequestCallbackSchedulingState(nsIPresShell* aOldShell = nullptr);
|
||||
|
||||
nsCString mReferrer;
|
||||
nsString mLastModified;
|
||||
|
||||
|
@ -3183,6 +3190,18 @@ protected:
|
|||
// Do we currently have an event posted to call FlushUserFontSet?
|
||||
bool mPostedFlushUserFontSet : 1;
|
||||
|
||||
// True if we have fired the DOMContentLoaded event, or don't plan to fire one
|
||||
// (e.g. we're not being parsed at all).
|
||||
bool mDidFireDOMContentLoaded : 1;
|
||||
|
||||
// True if ReportHasScrollLinkedEffect() has been called.
|
||||
bool mHasScrollLinkedEffect : 1;
|
||||
|
||||
// True if we have frame request callbacks scheduled with the refresh driver.
|
||||
// This should generally be updated only via
|
||||
// UpdateFrameRequestCallbackSchedulingState.
|
||||
bool mFrameRequestCallbacksScheduled : 1;
|
||||
|
||||
// Compatibility mode
|
||||
nsCompatibility mCompatMode;
|
||||
|
||||
|
@ -3333,9 +3352,6 @@ protected:
|
|||
nsTArray<RefPtr<mozilla::dom::AnonymousContent>> mAnonymousContents;
|
||||
|
||||
uint32_t mBlockDOMContentLoaded;
|
||||
bool mDidFireDOMContentLoaded:1;
|
||||
|
||||
bool mHasScrollLinkedEffect:1;
|
||||
|
||||
// Our live MediaQueryLists
|
||||
PRCList mDOMMediaQueryLists;
|
||||
|
|
|
@ -1495,30 +1495,37 @@ DataTransfer::FillInExternalCustomTypes(nsIVariant* aData, uint32_t aIndex,
|
|||
return;
|
||||
}
|
||||
|
||||
stream->SetInputStream(stringStream);
|
||||
rv = stream->SetInputStream(stringStream);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
uint32_t type;
|
||||
do {
|
||||
stream->Read32(&type);
|
||||
rv = stream->Read32(&type);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
if (type == eCustomClipboardTypeId_String) {
|
||||
uint32_t formatLength;
|
||||
stream->Read32(&formatLength);
|
||||
rv = stream->Read32(&formatLength);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
char* formatBytes;
|
||||
stream->ReadBytes(formatLength, &formatBytes);
|
||||
rv = stream->ReadBytes(formatLength, &formatBytes);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
nsAutoString format;
|
||||
format.Adopt(reinterpret_cast<char16_t*>(formatBytes),
|
||||
formatLength / sizeof(char16_t));
|
||||
|
||||
uint32_t dataLength;
|
||||
stream->Read32(&dataLength);
|
||||
rv = stream->Read32(&dataLength);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
char* dataBytes;
|
||||
stream->ReadBytes(dataLength, &dataBytes);
|
||||
rv = stream->ReadBytes(dataLength, &dataBytes);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
nsAutoString data;
|
||||
data.Adopt(reinterpret_cast<char16_t*>(dataBytes),
|
||||
dataLength / sizeof(char16_t));
|
||||
|
||||
RefPtr<nsVariantCC> variant = new nsVariantCC();
|
||||
variant->SetAsAString(data);
|
||||
rv = variant->SetAsAString(data);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
SetDataWithPrincipal(format, variant, aIndex, aPrincipal);
|
||||
}
|
||||
|
|
|
@ -463,10 +463,18 @@ DataTransferItem::GetAsString(FunctionStringCallback* aCallback,
|
|||
nsString mStringData;
|
||||
};
|
||||
|
||||
nsCOMPtr<nsINode> parentNode =
|
||||
do_QueryInterface(mDataTransfer->GetParentObject());
|
||||
MOZ_ASSERT(parentNode);
|
||||
RefPtr<GASRunnable> runnable = new GASRunnable(aCallback, stringData);
|
||||
rv = NS_DispatchToMainThread(runnable);
|
||||
if (nsIDocument* doc = parentNode->OwnerDoc()) {
|
||||
rv = doc->Dispatch("GASRunnable", TaskCategory::Other,
|
||||
runnable.forget());
|
||||
} else {
|
||||
rv = NS_DispatchToMainThread(runnable);
|
||||
}
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("NS_DispatchToMainThread Failed in "
|
||||
NS_WARNING("Dispatch to main thread Failed in "
|
||||
"DataTransferItem::GetAsString!");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -366,8 +366,17 @@ EventListenerService::NotifyAboutMainThreadListenerChangeInternal(dom::EventTarg
|
|||
|
||||
if (!mPendingListenerChanges) {
|
||||
mPendingListenerChanges = nsArrayBase::Create();
|
||||
NS_DispatchToCurrentThread(NewRunnableMethod(this,
|
||||
&EventListenerService::NotifyPendingChanges));
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NewRunnableMethod("EventListenerService::NotifyPendingChanges",
|
||||
this, &EventListenerService::NotifyPendingChanges);
|
||||
if (nsCOMPtr<nsIGlobalObject> global = aTarget->GetOwnerGlobal()) {
|
||||
global->Dispatch(nullptr, TaskCategory::Other, runnable.forget());
|
||||
} else if (nsCOMPtr<nsINode> node = do_QueryInterface(aTarget)) {
|
||||
node->OwnerDoc()->Dispatch(nullptr, TaskCategory::Other,
|
||||
runnable.forget());
|
||||
} else {
|
||||
NS_DispatchToCurrentThread(runnable);
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<EventListenerChange> changes = mPendingListenerChangesSet.Get(aTarget);
|
||||
|
|
|
@ -339,8 +339,13 @@ EventStateManager::UpdateUserActivityTimer()
|
|||
if (!gUserInteractionTimerCallback)
|
||||
return NS_OK;
|
||||
|
||||
if (!gUserInteractionTimer)
|
||||
if (!gUserInteractionTimer) {
|
||||
CallCreateInstance("@mozilla.org/timer;1", &gUserInteractionTimer);
|
||||
if (gUserInteractionTimer) {
|
||||
gUserInteractionTimer->SetTarget(
|
||||
SystemGroup::EventTargetFor(TaskCategory::Other));
|
||||
}
|
||||
}
|
||||
|
||||
if (gUserInteractionTimer) {
|
||||
gUserInteractionTimer->InitWithCallback(gUserInteractionTimerCallback,
|
||||
|
@ -1419,6 +1424,7 @@ EventStateManager::CreateClickHoldTimer(nsPresContext* inPresContext,
|
|||
if (mClickHoldTimer) {
|
||||
int32_t clickHoldDelay =
|
||||
Preferences::GetInt("ui.click_hold_context_menus.delay", 500);
|
||||
mClickHoldTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::Other));
|
||||
mClickHoldTimer->InitWithFuncCallback(sClickHoldCallback, this,
|
||||
clickHoldDelay,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
|
|
|
@ -1414,8 +1414,16 @@ IMEContentObserver::FlushMergeableNotifications()
|
|||
// it may kick runnable event immediately after DOM tree is changed but
|
||||
// the selection range isn't modified yet.
|
||||
mQueuedSender = new IMENotificationSender(this);
|
||||
NS_DispatchToCurrentThread(mQueuedSender);
|
||||
|
||||
nsIScriptGlobalObject* globalObject = mDocShell ?
|
||||
mDocShell->GetScriptGlobalObject() :
|
||||
nullptr;
|
||||
if (globalObject) {
|
||||
RefPtr<IMENotificationSender> queuedSender = mQueuedSender;
|
||||
globalObject->Dispatch("IMENotificationSender",
|
||||
TaskCategory::Other, queuedSender.forget());
|
||||
} else {
|
||||
NS_DispatchToCurrentThread(mQueuedSender);
|
||||
}
|
||||
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
||||
("0x%p IMEContentObserver::FlushMergeableNotifications(), "
|
||||
"finished", this));
|
||||
|
@ -1540,7 +1548,17 @@ IMEContentObserver::IMENotificationSender::Run()
|
|||
"posting IMENotificationSender to current thread", this));
|
||||
mIMEContentObserver->mQueuedSender =
|
||||
new IMENotificationSender(mIMEContentObserver);
|
||||
NS_DispatchToCurrentThread(mIMEContentObserver->mQueuedSender);
|
||||
nsIScriptGlobalObject* globalObject =
|
||||
mIMEContentObserver->mDocShell ?
|
||||
mIMEContentObserver->mDocShell->GetScriptGlobalObject() : nullptr;
|
||||
if (globalObject) {
|
||||
RefPtr<IMENotificationSender> queuedSender =
|
||||
mIMEContentObserver->mQueuedSender;
|
||||
globalObject->Dispatch("IMENotificationSender",
|
||||
TaskCategory::Other, queuedSender.forget());
|
||||
} else {
|
||||
NS_DispatchToCurrentThread(mIMEContentObserver->mQueuedSender);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
// This is the first notification to IME. So, we don't need to notify
|
||||
|
@ -1604,7 +1622,17 @@ IMEContentObserver::IMENotificationSender::Run()
|
|||
"posting IMENotificationSender to current thread", this));
|
||||
mIMEContentObserver->mQueuedSender =
|
||||
new IMENotificationSender(mIMEContentObserver);
|
||||
NS_DispatchToCurrentThread(mIMEContentObserver->mQueuedSender);
|
||||
nsIScriptGlobalObject* globalObject =
|
||||
mIMEContentObserver->mDocShell ?
|
||||
mIMEContentObserver->mDocShell->GetScriptGlobalObject() : nullptr;
|
||||
if (globalObject) {
|
||||
RefPtr<IMENotificationSender> queuedSender =
|
||||
mIMEContentObserver->mQueuedSender;
|
||||
globalObject->Dispatch("IMENotificationSender",
|
||||
TaskCategory::Other, queuedSender.forget());
|
||||
} else {
|
||||
NS_DispatchToCurrentThread(mIMEContentObserver->mQueuedSender);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
|
|
|
@ -89,6 +89,10 @@ FileSystemSecurity::ContentProcessHasAccessTo(ContentParentId aId,
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
AssertIsInMainProcess();
|
||||
|
||||
if (FindInReadable(NS_LITERAL_STRING(".."), aPath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsTArray<nsString>* paths;
|
||||
if (!mPaths.Get(aId, &paths)) {
|
||||
return false;
|
||||
|
|
|
@ -2734,7 +2734,11 @@ TabChild::InitAPZState()
|
|||
// The ContentProcessController will hold a reference to the tab, and will be destroyed by the compositor or ipdl
|
||||
// during destruction.
|
||||
RefPtr<GeckoContentController> contentController = new ContentProcessController(this);
|
||||
cbc->SendPAPZConstructor(new APZChild(contentController), mLayersId);
|
||||
APZChild* apzChild = new APZChild(contentController);
|
||||
cbc->SetEventTargetForActor(
|
||||
apzChild, TabGroup()->EventTargetFor(TaskCategory::Other));
|
||||
MOZ_ASSERT(apzChild->GetActorEventTarget());
|
||||
cbc->SendPAPZConstructor(apzChild, mLayersId);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -2700,7 +2700,8 @@ MediaDecoderStateMachine::CreateAudioSink()
|
|||
auto audioSinkCreator = [self] () {
|
||||
MOZ_ASSERT(self->OnTaskQueue());
|
||||
AudioSink* audioSink = new AudioSink(
|
||||
self->mTaskQueue, self->mAudioQueue, self->GetMediaTime(),
|
||||
self->mTaskQueue, self->mAudioQueue,
|
||||
TimeUnit::FromMicroseconds(self->GetMediaTime()),
|
||||
self->Info().mAudio, self->mAudioChannel);
|
||||
|
||||
self->mAudibleListener = audioSink->AudibleEvent().Connect(
|
||||
|
@ -3492,7 +3493,7 @@ MediaDecoderStateMachine::UpdatePlaybackPositionPeriodically()
|
|||
// Cap the current time to the larger of the audio and video end time.
|
||||
// This ensures that if we're running off the system clock, we don't
|
||||
// advance the clock to after the media end time.
|
||||
if (VideoEndTime() != -1 || AudioEndTime() != -1) {
|
||||
if (VideoEndTime() > 0 || AudioEndTime() > 0) {
|
||||
|
||||
const int64_t clockTime = GetClock();
|
||||
// Skip frames up to the frame at the playback position, and figure out
|
||||
|
@ -3651,7 +3652,7 @@ MediaDecoderStateMachine::AudioEndTime() const
|
|||
if (mMediaSink->IsStarted()) {
|
||||
return mMediaSink->GetEndTime(TrackInfo::kAudioTrack);
|
||||
}
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t
|
||||
|
@ -3661,7 +3662,7 @@ MediaDecoderStateMachine::VideoEndTime() const
|
|||
if (mMediaSink->IsStarted()) {
|
||||
return mMediaSink->GetEndTime(TrackInfo::kVideoTrack);
|
||||
}
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -170,7 +170,11 @@ private:
|
|||
DECL_MEDIA_PREF("media.rust.test_mode", RustTestMode, bool, false);
|
||||
#endif
|
||||
|
||||
#if defined(OS_LINUX) && defined(DEBUG)
|
||||
DECL_MEDIA_PREF("media.rust.mp4parser", EnableRustMP4Parser, bool, true);
|
||||
#else
|
||||
DECL_MEDIA_PREF("media.rust.mp4parser", EnableRustMP4Parser, bool, false);
|
||||
#endif
|
||||
|
||||
public:
|
||||
// Manage the singleton:
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "nsDeque.h"
|
||||
#include "MediaEventSource.h"
|
||||
#include "TimeUnits.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -131,6 +132,11 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void GetElementsAfter(const media::TimeUnit& aTime,
|
||||
nsTArray<RefPtr<T>>* aResult) {
|
||||
GetElementsAfter(aTime.ToMicroseconds(), aResult);
|
||||
}
|
||||
|
||||
void GetFirstElements(uint32_t aMaxElements, nsTArray<RefPtr<T>>* aResult) {
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
for (size_t i = 0; i < aMaxElements && i < GetSize(); ++i) {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "mozilla/FloatingPoint.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/dom/TimeRanges.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace media {
|
||||
|
@ -105,7 +106,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
static TimeUnit FromMicroseconds(int64_t aValue) {
|
||||
static constexpr TimeUnit FromMicroseconds(int64_t aValue) {
|
||||
return TimeUnit(aValue);
|
||||
}
|
||||
|
||||
|
@ -113,14 +114,22 @@ public:
|
|||
return TimeUnit(aValue.mValue);
|
||||
}
|
||||
|
||||
static TimeUnit FromNanoseconds(int64_t aValue) {
|
||||
static constexpr TimeUnit FromNanoseconds(int64_t aValue) {
|
||||
return TimeUnit(aValue / 1000);
|
||||
}
|
||||
|
||||
static TimeUnit FromInfinity() {
|
||||
static constexpr TimeUnit FromInfinity() {
|
||||
return TimeUnit(INT64_MAX);
|
||||
}
|
||||
|
||||
static TimeUnit FromTimeDuration(const TimeDuration& aDuration) {
|
||||
return FromSeconds(aDuration.ToSeconds());
|
||||
}
|
||||
|
||||
static constexpr TimeUnit Zero() {
|
||||
return TimeUnit(0);
|
||||
}
|
||||
|
||||
static TimeUnit Invalid() {
|
||||
TimeUnit ret;
|
||||
ret.mValue = CheckedInt64(INT64_MAX);
|
||||
|
@ -144,6 +153,10 @@ public:
|
|||
return double(mValue.value()) / USECS_PER_S;
|
||||
}
|
||||
|
||||
TimeDuration ToTimeDuration() const {
|
||||
return TimeDuration::FromMicroseconds(mValue.value());
|
||||
}
|
||||
|
||||
bool IsInfinite() const {
|
||||
return mValue.value() == INT64_MAX;
|
||||
}
|
||||
|
@ -207,7 +220,7 @@ public:
|
|||
return mValue.isValid();
|
||||
}
|
||||
|
||||
TimeUnit()
|
||||
constexpr TimeUnit()
|
||||
: mValue(CheckedInt64(0))
|
||||
{}
|
||||
|
||||
|
@ -225,7 +238,7 @@ public:
|
|||
TimeUnit& operator = (const TimeUnit&) = default;
|
||||
|
||||
private:
|
||||
explicit TimeUnit(CheckedInt64 aMicroseconds)
|
||||
explicit constexpr TimeUnit(CheckedInt64 aMicroseconds)
|
||||
: mValue(aMicroseconds)
|
||||
{}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "mozilla/Unused.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "base/time.h"
|
||||
#include "GMPUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
@ -154,15 +155,11 @@ ToString(const cdm::KeyInformation* aKeysInfo, uint32_t aKeysInfoCount)
|
|||
{
|
||||
nsCString str;
|
||||
for (uint32_t i = 0; i < aKeysInfoCount; i++) {
|
||||
nsCString keyId;
|
||||
const cdm::KeyInformation& key = aKeysInfo[i];
|
||||
for (size_t k = 0; k < key.key_id_size; k++) {
|
||||
keyId.Append(nsPrintfCString("%hhX", key.key_id[k]));
|
||||
}
|
||||
if (!str.IsEmpty()) {
|
||||
str.AppendLiteral(",");
|
||||
}
|
||||
str.Append(keyId);
|
||||
const cdm::KeyInformation& key = aKeysInfo[i];
|
||||
str.Append(ToHexString(key.key_id, key.key_id_size));
|
||||
str.AppendLiteral("=");
|
||||
str.AppendInt(key.status);
|
||||
}
|
||||
|
@ -509,7 +506,8 @@ mozilla::ipc::IPCResult
|
|||
ChromiumCDMChild::RecvDecryptAndDecodeFrame(const CDMInputBuffer& aBuffer)
|
||||
{
|
||||
MOZ_ASSERT(IsOnMessageLoopThread());
|
||||
GMP_LOG("ChromiumCDMChild::RecvDecryptAndDecodeFrame()");
|
||||
GMP_LOG("ChromiumCDMChild::RecvDecryptAndDecodeFrame() t=%" PRId64 ")",
|
||||
aBuffer.mTimestamp());
|
||||
MOZ_ASSERT(mDecoderInitialized);
|
||||
|
||||
// The output frame may not have the same timestamp as the frame we put in.
|
||||
|
@ -525,8 +523,9 @@ ChromiumCDMChild::RecvDecryptAndDecodeFrame(const CDMInputBuffer& aBuffer)
|
|||
|
||||
WidevineVideoFrame frame;
|
||||
cdm::Status rv = mCDM->DecryptAndDecodeFrame(input, &frame);
|
||||
GMP_LOG("WidevineVideoDecoder::Decode(timestamp=%" PRId64 ") rv=%d",
|
||||
input.timestamp,
|
||||
GMP_LOG("ChromiumCDMChild::RecvDecryptAndDecodeFrame() t=%" PRId64
|
||||
" CDM decoder rv=%d",
|
||||
aBuffer.mTimestamp(),
|
||||
rv);
|
||||
|
||||
switch (rv) {
|
||||
|
|
|
@ -33,11 +33,10 @@ static const int32_t LOW_AUDIO_USECS = 300000;
|
|||
|
||||
AudioSink::AudioSink(AbstractThread* aThread,
|
||||
MediaQueue<AudioData>& aAudioQueue,
|
||||
int64_t aStartTime,
|
||||
TimeUnit aStartTime,
|
||||
const AudioInfo& aInfo,
|
||||
dom::AudioChannel aChannel)
|
||||
: mStartTime(aStartTime)
|
||||
, mLastGoodPosition(0)
|
||||
, mInfo(aInfo)
|
||||
, mChannel(aChannel)
|
||||
, mPlaying(true)
|
||||
|
@ -48,7 +47,6 @@ AudioSink::AudioSink(AbstractThread* aThread,
|
|||
, mOwnerThread(aThread)
|
||||
, mProcessedQueueLength(0)
|
||||
, mFramesParsed(0)
|
||||
, mLastEndTime(0)
|
||||
, mIsAudioDataAudible(false)
|
||||
, mAudioQueue(aAudioQueue)
|
||||
{
|
||||
|
@ -103,12 +101,13 @@ AudioSink::Init(const PlaybackParams& aParams)
|
|||
return p;
|
||||
}
|
||||
|
||||
int64_t
|
||||
TimeUnit
|
||||
AudioSink::GetPosition()
|
||||
{
|
||||
int64_t pos;
|
||||
int64_t tmp;
|
||||
if (mAudioStream &&
|
||||
(pos = mAudioStream->GetPosition()) >= 0) {
|
||||
(tmp = mAudioStream->GetPosition()) >= 0) {
|
||||
TimeUnit pos = TimeUnit::FromMicroseconds(tmp);
|
||||
NS_ASSERTION(pos >= mLastGoodPosition,
|
||||
"AudioStream position shouldn't go backward");
|
||||
// Update the last good position when we got a good one.
|
||||
|
@ -221,7 +220,7 @@ AudioSink::InitializeAudioStream(const PlaybackParams& aParams)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
int64_t
|
||||
TimeUnit
|
||||
AudioSink::GetEndTime() const
|
||||
{
|
||||
int64_t written;
|
||||
|
@ -229,14 +228,14 @@ AudioSink::GetEndTime() const
|
|||
MonitorAutoLock mon(mMonitor);
|
||||
written = mWritten;
|
||||
}
|
||||
CheckedInt64 playedUsecs = FramesToUsecs(written, mOutputRate) + mStartTime;
|
||||
if (!playedUsecs.isValid()) {
|
||||
TimeUnit played = FramesToTimeUnit(written, mOutputRate) + mStartTime;
|
||||
if (!played.IsValid()) {
|
||||
NS_WARNING("Int overflow calculating audio end time");
|
||||
return -1;
|
||||
return TimeUnit::Zero();
|
||||
}
|
||||
// As we may be resampling, rounding errors may occur. Ensure we never get
|
||||
// past the original end time.
|
||||
return std::min<int64_t>(mLastEndTime, playedUsecs.value());
|
||||
return std::min(mLastEndTime, played);
|
||||
}
|
||||
|
||||
UniquePtr<AudioStream::Chunk>
|
||||
|
@ -407,8 +406,8 @@ AudioSink::NotifyAudioNeeded()
|
|||
// audio hardware, so we can play across the gap.
|
||||
// Calculate the timestamp of the next chunk of audio in numbers of
|
||||
// samples.
|
||||
CheckedInt64 sampleTime = UsecsToFrames(data->mTime - mStartTime,
|
||||
data->mRate);
|
||||
CheckedInt64 sampleTime = TimeUnitToFrames(
|
||||
TimeUnit::FromMicroseconds(data->mTime) - mStartTime, data->mRate);
|
||||
// Calculate the number of frames that have been pushed onto the audio hardware.
|
||||
CheckedInt64 missingFrames = sampleTime - mFramesParsed;
|
||||
|
||||
|
@ -450,7 +449,7 @@ AudioSink::NotifyAudioNeeded()
|
|||
}
|
||||
}
|
||||
|
||||
mLastEndTime = data->GetEndTime();
|
||||
mLastEndTime = TimeUnit::FromMicroseconds(data->GetEndTime());
|
||||
mFramesParsed += data->mFrames;
|
||||
|
||||
if (mConverter->InputConfig() != mConverter->OutputConfig()) {
|
||||
|
|
|
@ -32,7 +32,7 @@ class AudioSink : private AudioStream::DataSource {
|
|||
public:
|
||||
AudioSink(AbstractThread* aThread,
|
||||
MediaQueue<AudioData>& aAudioQueue,
|
||||
int64_t aStartTime,
|
||||
TimeUnit aStartTime,
|
||||
const AudioInfo& aInfo,
|
||||
dom::AudioChannel aChannel);
|
||||
|
||||
|
@ -46,8 +46,8 @@ public:
|
|||
* All public functions are not thread-safe.
|
||||
* Called on the task queue of MDSM only.
|
||||
*/
|
||||
int64_t GetPosition();
|
||||
int64_t GetEndTime() const;
|
||||
TimeUnit GetPosition();
|
||||
TimeUnit GetEndTime() const;
|
||||
|
||||
// Check whether we've pushed more frames to the audio hardware than it has
|
||||
// played.
|
||||
|
@ -80,15 +80,15 @@ private:
|
|||
// The audio stream resource. Used on the task queue of MDSM only.
|
||||
RefPtr<AudioStream> mAudioStream;
|
||||
|
||||
// The presentation time of the first audio frame that was played in
|
||||
// microseconds. We can add this to the audio stream position to determine
|
||||
// The presentation time of the first audio frame that was played.
|
||||
// We can add this to the audio stream position to determine
|
||||
// the current audio time.
|
||||
const int64_t mStartTime;
|
||||
const TimeUnit mStartTime;
|
||||
|
||||
// Keep the last good position returned from the audio stream. Used to ensure
|
||||
// position returned by GetPosition() is mono-increasing in spite of audio
|
||||
// stream error. Used on the task queue of MDSM only.
|
||||
int64_t mLastGoodPosition;
|
||||
TimeUnit mLastGoodPosition;
|
||||
|
||||
const AudioInfo mInfo;
|
||||
|
||||
|
@ -149,7 +149,7 @@ private:
|
|||
// at the current input framerate.
|
||||
int64_t mFramesParsed;
|
||||
Maybe<RefPtr<AudioData>> mLastProcessedPacket;
|
||||
int64_t mLastEndTime;
|
||||
TimeUnit mLastEndTime;
|
||||
// Never modifed after construction.
|
||||
uint32_t mOutputRate;
|
||||
uint32_t mOutputChannels;
|
||||
|
|
|
@ -58,9 +58,9 @@ AudioSinkWrapper::GetEndTime(TrackType aType) const
|
|||
AssertOwnerThread();
|
||||
MOZ_ASSERT(mIsStarted, "Must be called after playback starts.");
|
||||
if (aType == TrackInfo::kAudioTrack && mAudioSink) {
|
||||
return mAudioSink->GetEndTime();
|
||||
return mAudioSink->GetEndTime().ToMicroseconds();
|
||||
}
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t
|
||||
|
@ -85,7 +85,7 @@ AudioSinkWrapper::GetPosition(TimeStamp* aTimeStamp) const
|
|||
|
||||
if (!mAudioEnded) {
|
||||
// Rely on the audio sink to report playback position when it is not ended.
|
||||
pos = mAudioSink->GetPosition();
|
||||
pos = mAudioSink->GetPosition().ToMicroseconds();
|
||||
} else if (!mPlayStartTime.IsNull()) {
|
||||
// Calculate playback position using system clock if we are still playing.
|
||||
pos = GetVideoPosition(t);
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace mozilla {
|
|||
* way to DecodedStreamGraphListener from DecodedStream.
|
||||
*/
|
||||
struct PlaybackInfoInit {
|
||||
int64_t mStartTime;
|
||||
media::TimeUnit mStartTime;
|
||||
MediaInfo mInfo;
|
||||
};
|
||||
|
||||
|
@ -144,8 +144,8 @@ public:
|
|||
// mNextVideoTime is the end timestamp for the last packet sent to the stream.
|
||||
// Therefore video packets starting at or after this time need to be copied
|
||||
// to the output stream.
|
||||
int64_t mNextVideoTime; // microseconds
|
||||
int64_t mNextAudioTime; // microseconds
|
||||
media::TimeUnit mNextVideoTime;
|
||||
media::TimeUnit mNextAudioTime;
|
||||
// The last video image sent to the stream. Useful if we need to replicate
|
||||
// the image.
|
||||
RefPtr<layers::Image> mLastVideoImage;
|
||||
|
@ -234,8 +234,9 @@ DecodedStreamData::GetDebugInfo()
|
|||
"DecodedStreamData=%p mPlaying=%d mAudioFramesWritten=%" PRId64
|
||||
" mNextAudioTime=%" PRId64 " mNextVideoTime=%" PRId64 " mHaveSentFinish=%d "
|
||||
"mHaveSentFinishAudio=%d mHaveSentFinishVideo=%d",
|
||||
this, mPlaying, mAudioFramesWritten, mNextAudioTime, mNextVideoTime,
|
||||
mHaveSentFinish, mHaveSentFinishAudio, mHaveSentFinishVideo);
|
||||
this, mPlaying, mAudioFramesWritten, mNextAudioTime.ToMicroseconds(),
|
||||
mNextVideoTime.ToMicroseconds(), mHaveSentFinish, mHaveSentFinishAudio,
|
||||
mHaveSentFinishVideo);
|
||||
}
|
||||
|
||||
DecodedStream::DecodedStream(AbstractThread* aOwnerThread,
|
||||
|
@ -298,8 +299,8 @@ DecodedStream::Start(int64_t aStartTime, const MediaInfo& aInfo)
|
|||
AssertOwnerThread();
|
||||
MOZ_ASSERT(mStartTime.isNothing(), "playback already started.");
|
||||
|
||||
mStartTime.emplace(aStartTime);
|
||||
mLastOutputTime = 0;
|
||||
mStartTime.emplace(FromMicroseconds(aStartTime));
|
||||
mLastOutputTime = media::TimeUnit::Zero();
|
||||
mInfo = aInfo;
|
||||
mPlaying = true;
|
||||
ConnectListener();
|
||||
|
@ -345,7 +346,7 @@ DecodedStream::Start(int64_t aStartTime, const MediaInfo& aInfo)
|
|||
MozPromiseHolder<GenericPromise> promise;
|
||||
mFinishPromise = promise.Ensure(__func__);
|
||||
PlaybackInfoInit init {
|
||||
aStartTime, aInfo
|
||||
FromMicroseconds(aStartTime), aInfo
|
||||
};
|
||||
nsCOMPtr<nsIRunnable> r =
|
||||
new R(Move(init), Move(promise), mOutputStreamManager, mAbstractMainThread);
|
||||
|
@ -447,7 +448,7 @@ DecodedStream::SetPreservesPitch(bool aPreservesPitch)
|
|||
}
|
||||
|
||||
static void
|
||||
SendStreamAudio(DecodedStreamData* aStream, int64_t aStartTime,
|
||||
SendStreamAudio(DecodedStreamData* aStream, const media::TimeUnit& aStartTime,
|
||||
AudioData* aData, AudioSegment* aOutput, uint32_t aRate,
|
||||
const PrincipalHandle& aPrincipalHandle)
|
||||
{
|
||||
|
@ -458,14 +459,14 @@ SendStreamAudio(DecodedStreamData* aStream, int64_t aStartTime,
|
|||
AudioData* audio = aData;
|
||||
// This logic has to mimic AudioSink closely to make sure we write
|
||||
// the exact same silences
|
||||
CheckedInt64 audioWrittenOffset = aStream->mAudioFramesWritten +
|
||||
UsecsToFrames(aStartTime, aRate);
|
||||
CheckedInt64 audioWrittenOffset = aStream->mAudioFramesWritten
|
||||
+ TimeUnitToFrames(aStartTime, aRate);
|
||||
CheckedInt64 frameOffset = UsecsToFrames(audio->mTime, aRate);
|
||||
|
||||
if (!audioWrittenOffset.isValid() ||
|
||||
!frameOffset.isValid() ||
|
||||
// ignore packet that we've already processed
|
||||
audio->GetEndTime() <= aStream->mNextAudioTime) {
|
||||
audio->GetEndTime() <= aStream->mNextAudioTime.ToMicroseconds()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -491,7 +492,7 @@ SendStreamAudio(DecodedStreamData* aStream, int64_t aStartTime,
|
|||
aOutput->AppendFrames(buffer.forget(), channels, audio->mFrames, aPrincipalHandle);
|
||||
aStream->mAudioFramesWritten += audio->mFrames;
|
||||
|
||||
aStream->mNextAudioTime = audio->GetEndTime();
|
||||
aStream->mNextAudioTime = media::TimeUnit::FromMicroseconds(audio->GetEndTime());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -540,17 +541,17 @@ DecodedStream::SendAudio(double aVolume, bool aIsSameOrigin,
|
|||
static void
|
||||
WriteVideoToMediaStream(MediaStream* aStream,
|
||||
layers::Image* aImage,
|
||||
int64_t aEndMicroseconds,
|
||||
int64_t aStartMicroseconds,
|
||||
const media::TimeUnit& aEnd,
|
||||
const media::TimeUnit& aStart,
|
||||
const mozilla::gfx::IntSize& aIntrinsicSize,
|
||||
const TimeStamp& aTimeStamp,
|
||||
VideoSegment* aOutput,
|
||||
const PrincipalHandle& aPrincipalHandle)
|
||||
{
|
||||
RefPtr<layers::Image> image = aImage;
|
||||
StreamTime duration =
|
||||
aStream->MicrosecondsToStreamTimeRoundDown(aEndMicroseconds) -
|
||||
aStream->MicrosecondsToStreamTimeRoundDown(aStartMicroseconds);
|
||||
auto end = aStream->MicrosecondsToStreamTimeRoundDown(aEnd.ToMicroseconds());
|
||||
auto start = aStream->MicrosecondsToStreamTimeRoundDown(aStart.ToMicroseconds());
|
||||
StreamTime duration = end - start;
|
||||
aOutput->AppendFrame(image.forget(), duration, aIntrinsicSize,
|
||||
aPrincipalHandle, false, aTimeStamp);
|
||||
}
|
||||
|
@ -594,7 +595,7 @@ DecodedStream::SendVideo(bool aIsSameOrigin, const PrincipalHandle& aPrincipalHa
|
|||
for (uint32_t i = 0; i < video.Length(); ++i) {
|
||||
VideoData* v = video[i];
|
||||
|
||||
if (mData->mNextVideoTime < v->mTime) {
|
||||
if (mData->mNextVideoTime.ToMicroseconds() < v->mTime) {
|
||||
// Write last video frame to catch up. mLastVideoImage can be null here
|
||||
// which is fine, it just means there's no video.
|
||||
|
||||
|
@ -604,19 +605,21 @@ DecodedStream::SendVideo(bool aIsSameOrigin, const PrincipalHandle& aPrincipalHa
|
|||
// video frame). E.g. if we have a video frame that is 30 sec long
|
||||
// and capture happens at 15 sec, we'll have to append a black frame
|
||||
// that is 15 sec long.
|
||||
WriteVideoToMediaStream(sourceStream, mData->mLastVideoImage, v->mTime,
|
||||
mData->mNextVideoTime, mData->mLastVideoImageDisplaySize,
|
||||
tracksStartTimeStamp + TimeDuration::FromMicroseconds(v->mTime),
|
||||
&output, aPrincipalHandle);
|
||||
mData->mNextVideoTime = v->mTime;
|
||||
WriteVideoToMediaStream(sourceStream, mData->mLastVideoImage,
|
||||
FromMicroseconds(v->mTime),
|
||||
mData->mNextVideoTime, mData->mLastVideoImageDisplaySize,
|
||||
tracksStartTimeStamp + TimeDuration::FromMicroseconds(v->mTime),
|
||||
&output, aPrincipalHandle);
|
||||
mData->mNextVideoTime = FromMicroseconds(v->mTime);
|
||||
}
|
||||
|
||||
if (mData->mNextVideoTime < v->GetEndTime()) {
|
||||
WriteVideoToMediaStream(sourceStream, v->mImage, v->GetEndTime(),
|
||||
mData->mNextVideoTime, v->mDisplay,
|
||||
tracksStartTimeStamp + TimeDuration::FromMicroseconds(v->GetEndTime()),
|
||||
&output, aPrincipalHandle);
|
||||
mData->mNextVideoTime = v->GetEndTime();
|
||||
if (mData->mNextVideoTime.ToMicroseconds() < v->GetEndTime()) {
|
||||
WriteVideoToMediaStream(sourceStream, v->mImage,
|
||||
FromMicroseconds(v->GetEndTime()),
|
||||
mData->mNextVideoTime, v->mDisplay,
|
||||
tracksStartTimeStamp + TimeDuration::FromMicroseconds(v->GetEndTime()),
|
||||
&output, aPrincipalHandle);
|
||||
mData->mNextVideoTime = FromMicroseconds(v->GetEndTime());
|
||||
mData->mLastVideoImage = v->mImage;
|
||||
mData->mLastVideoImageDisplaySize = v->mDisplay;
|
||||
}
|
||||
|
@ -639,13 +642,13 @@ DecodedStream::SendVideo(bool aIsSameOrigin, const PrincipalHandle& aPrincipalHa
|
|||
if (mData->mEOSVideoCompensation) {
|
||||
VideoSegment endSegment;
|
||||
// Calculate the deviation clock time from DecodedStream.
|
||||
int64_t deviation_usec = sourceStream->StreamTimeToMicroseconds(1);
|
||||
auto deviation = FromMicroseconds(sourceStream->StreamTimeToMicroseconds(1));
|
||||
WriteVideoToMediaStream(sourceStream, mData->mLastVideoImage,
|
||||
mData->mNextVideoTime + deviation_usec, mData->mNextVideoTime,
|
||||
mData->mLastVideoImageDisplaySize,
|
||||
tracksStartTimeStamp + TimeDuration::FromMicroseconds(mData->mNextVideoTime + deviation_usec),
|
||||
&endSegment, aPrincipalHandle);
|
||||
mData->mNextVideoTime += deviation_usec;
|
||||
mData->mNextVideoTime + deviation, mData->mNextVideoTime,
|
||||
mData->mLastVideoImageDisplaySize,
|
||||
tracksStartTimeStamp + (mData->mNextVideoTime + deviation).ToTimeDuration(),
|
||||
&endSegment, aPrincipalHandle);
|
||||
mData->mNextVideoTime += deviation;
|
||||
MOZ_ASSERT(endSegment.GetDuration() > 0);
|
||||
if (!aIsSameOrigin) {
|
||||
endSegment.ReplaceWithDisabled();
|
||||
|
@ -672,7 +675,7 @@ DecodedStream::AdvanceTracks()
|
|||
|
||||
if (mInfo.HasVideo()) {
|
||||
StreamTime videoEnd = mData->mStream->MicrosecondsToStreamTimeRoundDown(
|
||||
mData->mNextVideoTime - mStartTime.ref());
|
||||
(mData->mNextVideoTime - mStartTime.ref()).ToMicroseconds());
|
||||
endPosition = std::max(endPosition, videoEnd);
|
||||
}
|
||||
|
||||
|
@ -715,15 +718,15 @@ DecodedStream::GetEndTime(TrackType aType) const
|
|||
{
|
||||
AssertOwnerThread();
|
||||
if (aType == TrackInfo::kAudioTrack && mInfo.HasAudio() && mData) {
|
||||
CheckedInt64 t = mStartTime.ref() +
|
||||
FramesToUsecs(mData->mAudioFramesWritten, mInfo.mAudio.mRate);
|
||||
if (t.isValid()) {
|
||||
return t.value();
|
||||
auto t = mStartTime.ref() + FramesToTimeUnit(
|
||||
mData->mAudioFramesWritten, mInfo.mAudio.mRate);
|
||||
if (t.IsValid()) {
|
||||
return t.ToMicroseconds();
|
||||
}
|
||||
} else if (aType == TrackInfo::kVideoTrack && mData) {
|
||||
return mData->mNextVideoTime;
|
||||
return mData->mNextVideoTime.ToMicroseconds();
|
||||
}
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t
|
||||
|
@ -736,14 +739,14 @@ DecodedStream::GetPosition(TimeStamp* aTimeStamp) const
|
|||
if (aTimeStamp) {
|
||||
*aTimeStamp = TimeStamp::Now();
|
||||
}
|
||||
return mStartTime.ref() + mLastOutputTime;
|
||||
return (mStartTime.ref() + mLastOutputTime).ToMicroseconds();
|
||||
}
|
||||
|
||||
void
|
||||
DecodedStream::NotifyOutput(int64_t aTime)
|
||||
{
|
||||
AssertOwnerThread();
|
||||
mLastOutputTime = aTime;
|
||||
mLastOutputTime = FromMicroseconds(aTime);
|
||||
int64_t currentTime = GetPosition();
|
||||
|
||||
// Remove audio samples that have been played by MSG from the queue.
|
||||
|
@ -784,9 +787,10 @@ nsCString
|
|||
DecodedStream::GetDebugInfo()
|
||||
{
|
||||
AssertOwnerThread();
|
||||
int64_t startTime = mStartTime.isSome() ? mStartTime->ToMicroseconds() : -1;
|
||||
return nsPrintfCString(
|
||||
"DecodedStream=%p mStartTime=%" PRId64 " mLastOutputTime=%" PRId64 " mPlaying=%d mData=%p",
|
||||
this, mStartTime.valueOr(-1), mLastOutputTime, mPlaying, mData.get())
|
||||
this, startTime, mLastOutputTime.ToMicroseconds(), mPlaying, mData.get())
|
||||
+ (mData ? nsCString("\n") + mData->GetDebugInfo() : nsCString());
|
||||
}
|
||||
|
||||
|
|
|
@ -71,6 +71,10 @@ protected:
|
|||
virtual ~DecodedStream();
|
||||
|
||||
private:
|
||||
media::TimeUnit FromMicroseconds(int64_t aTime)
|
||||
{
|
||||
return media::TimeUnit::FromMicroseconds(aTime);
|
||||
}
|
||||
void DestroyData(UniquePtr<DecodedStreamData> aData);
|
||||
void AdvanceTracks();
|
||||
void SendAudio(double aVolume, bool aIsSameOrigin, const PrincipalHandle& aPrincipalHandle);
|
||||
|
@ -107,8 +111,8 @@ private:
|
|||
|
||||
PlaybackParams mParams;
|
||||
|
||||
Maybe<int64_t> mStartTime;
|
||||
int64_t mLastOutputTime = 0; // microseconds
|
||||
media::NullableTimeUnit mStartTime;
|
||||
media::TimeUnit mLastOutputTime;
|
||||
MediaInfo mInfo;
|
||||
|
||||
MediaQueue<AudioData>& mAudioQueue;
|
||||
|
|
|
@ -60,7 +60,7 @@ public:
|
|||
virtual RefPtr<GenericPromise> OnEnded(TrackType aType) = 0;
|
||||
|
||||
// Return the end time of the audio/video data that has been consumed
|
||||
// or -1 if no such track.
|
||||
// or 0 if no such track.
|
||||
// Must be called after playback starts.
|
||||
virtual int64_t GetEndTime(TrackType aType) const = 0;
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ VideoSink::VideoSink(AbstractThread* aThread,
|
|||
, mContainer(aContainer)
|
||||
, mProducerID(ImageContainer::AllocateProducerID())
|
||||
, mFrameStats(aFrameStats)
|
||||
, mVideoFrameEndTime(-1)
|
||||
, mVideoFrameEndTime(0)
|
||||
, mHasVideo(false)
|
||||
, mUpdateScheduler(aThread)
|
||||
, mVideoQueueSendToCompositorSize(aVQueueSentToCompositerSize)
|
||||
|
@ -95,7 +95,7 @@ VideoSink::GetEndTime(TrackType aType) const
|
|||
} else if (aType == TrackInfo::kAudioTrack) {
|
||||
return mAudioSink->GetEndTime(aType);
|
||||
}
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t
|
||||
|
@ -225,7 +225,7 @@ VideoSink::Stop()
|
|||
mEndPromiseHolder.ResolveIfExists(true, __func__);
|
||||
mEndPromise = nullptr;
|
||||
}
|
||||
mVideoFrameEndTime = -1;
|
||||
mVideoFrameEndTime = 0;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -1073,6 +1073,10 @@ WebMTrackDemuxer::Seek(const media::TimeUnit& aTime)
|
|||
mParent->SeekInternal(mType, aTime);
|
||||
nsresult rv = mParent->GetNextPacket(mType, &mSamples);
|
||||
if (NS_FAILED(rv)) {
|
||||
if (rv == NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
|
||||
// Ignore the error for now, the next GetSample will be rejected with EOS.
|
||||
return SeekPromise::CreateAndResolve(media::TimeUnit(), __func__);
|
||||
}
|
||||
return SeekPromise::CreateAndReject(rv, __func__);
|
||||
}
|
||||
mNeedKeyframe = true;
|
||||
|
|
|
@ -112,7 +112,9 @@ class AudioRunnable : public mozilla::Runnable
|
|||
public:
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
AudioRunnable(ANPAudioTrack* aAudioTrack) {
|
||||
AudioRunnable(ANPAudioTrack* aAudioTrack) :
|
||||
Runnable("AudioRunnable")
|
||||
{
|
||||
mTrack = aAudioTrack;
|
||||
}
|
||||
|
||||
|
|
|
@ -557,7 +557,10 @@ NPPExceptionAutoHolder::~NPPExceptionAutoHolder()
|
|||
nsPluginThreadRunnable::nsPluginThreadRunnable(NPP instance,
|
||||
PluginThreadCallback func,
|
||||
void *userData)
|
||||
: mInstance(instance), mFunc(func), mUserData(userData)
|
||||
: Runnable("nsPluginThreadRunnable"),
|
||||
mInstance(instance),
|
||||
mFunc(func),
|
||||
mUserData(userData)
|
||||
{
|
||||
if (!sPluginThreadAsyncCallLock) {
|
||||
// Failed to create lock, not much we can do here then...
|
||||
|
|
|
@ -68,7 +68,12 @@ class PluginEventRunnable : public Runnable
|
|||
{
|
||||
public:
|
||||
PluginEventRunnable(nsNPAPIPluginInstance* instance, ANPEvent* event)
|
||||
: mInstance(instance), mEvent(*event), mCanceled(false) {}
|
||||
: Runnable("PluginEventRunnable"),
|
||||
mInstance(instance),
|
||||
mEvent(*event),
|
||||
mCanceled(false)
|
||||
{
|
||||
}
|
||||
|
||||
virtual nsresult Run() {
|
||||
if (mCanceled)
|
||||
|
|
|
@ -1301,7 +1301,10 @@ nsPluginHost::GetPluginForContentProcess(uint32_t aPluginId, nsNPAPIPlugin** aPl
|
|||
class nsPluginUnloadRunnable : public Runnable
|
||||
{
|
||||
public:
|
||||
explicit nsPluginUnloadRunnable(uint32_t aPluginId) : mPluginId(aPluginId) {}
|
||||
explicit nsPluginUnloadRunnable(uint32_t aPluginId) :
|
||||
Runnable("nsPluginUnloadRunnable"),
|
||||
mPluginId(aPluginId)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
|
@ -3964,7 +3967,8 @@ class nsPluginDestroyRunnable : public Runnable,
|
|||
{
|
||||
public:
|
||||
explicit nsPluginDestroyRunnable(nsNPAPIPluginInstance *aInstance)
|
||||
: mInstance(aInstance)
|
||||
: Runnable("nsPluginDestroyRunnable"),
|
||||
mInstance(aInstance)
|
||||
{
|
||||
PR_INIT_CLIST(this);
|
||||
PR_APPEND_LINK(this, &sRunnableListHead);
|
||||
|
|
|
@ -134,7 +134,9 @@ class AsyncPaintWaitEvent : public Runnable
|
|||
{
|
||||
public:
|
||||
AsyncPaintWaitEvent(nsIContent* aContent, bool aFinished) :
|
||||
mContent(aContent), mFinished(aFinished)
|
||||
Runnable("AsyncPaintWaitEvent"),
|
||||
mContent(aContent),
|
||||
mFinished(aFinished)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -67,7 +67,8 @@ protected:
|
|||
LPARAM mLParam;
|
||||
};
|
||||
|
||||
PluginWindowEvent::PluginWindowEvent()
|
||||
PluginWindowEvent::PluginWindowEvent() :
|
||||
Runnable("PluginWindowEvent")
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
@ -160,7 +161,8 @@ class nsDelayedPopupsEnabledEvent : public Runnable
|
|||
{
|
||||
public:
|
||||
explicit nsDelayedPopupsEnabledEvent(nsNPAPIPluginInstance *inst)
|
||||
: mInst(inst)
|
||||
: Runnable("nsDelayedPopupsEnabledEvent"),
|
||||
mInst(inst)
|
||||
{}
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
|
|
@ -38,7 +38,8 @@ class nsPluginHangUITelemetry : public mozilla::Runnable
|
|||
public:
|
||||
nsPluginHangUITelemetry(int aResponseCode, int aDontAskCode,
|
||||
uint32_t aResponseTimeMs, uint32_t aTimeoutMs)
|
||||
: mResponseCode(aResponseCode),
|
||||
: Runnable("nsPluginHangUITelemetry"),
|
||||
mResponseCode(aResponseCode),
|
||||
mDontAskCode(aDontAskCode),
|
||||
mResponseTimeMs(aResponseTimeMs),
|
||||
mTimeoutMs(aTimeoutMs)
|
||||
|
|
|
@ -23,7 +23,8 @@ class DeferNPObjectReleaseRunnable : public mozilla::Runnable
|
|||
{
|
||||
public:
|
||||
DeferNPObjectReleaseRunnable(const NPNetscapeFuncs* f, NPObject* o)
|
||||
: mFuncs(f)
|
||||
: Runnable("DeferNPObjectReleaseRunnable")
|
||||
, mFuncs(f)
|
||||
, mObject(o)
|
||||
{
|
||||
NS_ASSERTION(o, "no release null objects");
|
||||
|
|
|
@ -2070,7 +2070,10 @@ class GetKeyStateTask : public Runnable
|
|||
|
||||
public:
|
||||
explicit GetKeyStateTask(int aVirtKey, HANDLE aSemaphore, SHORT* aKeyState) :
|
||||
mVirtKey(aVirtKey), mSemaphore(aSemaphore), mKeyState(aKeyState)
|
||||
Runnable("GetKeyStateTask"),
|
||||
mVirtKey(aVirtKey),
|
||||
mSemaphore(aSemaphore),
|
||||
mKeyState(aKeyState)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
|
@ -2141,8 +2144,9 @@ class GetFileNameTask : public Runnable
|
|||
public:
|
||||
explicit GetFileNameTask(GetFileNameFunc func, void* aLpOpenFileName,
|
||||
HANDLE aSemaphore, BOOL* aReturnValue) :
|
||||
mLpOpenFileName(aLpOpenFileName), mSemaphore(aSemaphore),
|
||||
mReturnValue(aReturnValue), mFunc(func)
|
||||
Runnable("GetFileNameTask"), mLpOpenFileName(aLpOpenFileName),
|
||||
mSemaphore(aSemaphore), mReturnValue(aReturnValue),
|
||||
mFunc(func)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
|
|
|
@ -154,7 +154,8 @@ class mozilla::plugins::FinishInjectorInitTask : public mozilla::CancelableRunna
|
|||
{
|
||||
public:
|
||||
FinishInjectorInitTask()
|
||||
: mMutex("FlashInjectorInitTask::mMutex")
|
||||
: CancelableRunnable("FinishInjectorInitTask")
|
||||
, mMutex("FlashInjectorInitTask::mMutex")
|
||||
, mParent(nullptr)
|
||||
, mMainThreadMsgLoop(MessageLoop::current())
|
||||
{
|
||||
|
|
|
@ -22,7 +22,8 @@ class AudioDeviceChangedRunnable : public Runnable
|
|||
public:
|
||||
explicit AudioDeviceChangedRunnable(const PluginModuleSet* aAudioNotificationSet,
|
||||
NPAudioDeviceChangeDetailsIPC aChangeDetails) :
|
||||
mChangeDetails(aChangeDetails)
|
||||
Runnable("AudioDeviceChangedRunnable")
|
||||
, mChangeDetails(aChangeDetails)
|
||||
, mAudioNotificationSet(aAudioNotificationSet)
|
||||
{}
|
||||
|
||||
|
|
|
@ -16,14 +16,17 @@
|
|||
#include "dirent.h"
|
||||
#include "poll.h"
|
||||
#include "sys/stat.h"
|
||||
#if defined(ANDROID)
|
||||
#if defined(XP_LINUX)
|
||||
#include <sys/vfs.h>
|
||||
#define statvfs statfs
|
||||
#define f_frsize f_bsize
|
||||
#else
|
||||
#include "sys/statvfs.h"
|
||||
#endif // defined(XP_LINUX)
|
||||
#if !defined(ANDROID)
|
||||
#include "sys/wait.h"
|
||||
#include <spawn.h>
|
||||
#endif // defined(ANDROID)
|
||||
#endif // !defined(ANDROID)
|
||||
#endif // defined(XP_UNIX)
|
||||
|
||||
#if defined(XP_LINUX)
|
||||
|
@ -699,7 +702,7 @@ static const dom::ConstantSpec gLibcProperties[] =
|
|||
|
||||
{ "OSFILE_SIZEOF_STATVFS", JS::Int32Value(sizeof (struct statvfs)) },
|
||||
|
||||
{ "OSFILE_OFFSETOF_STATVFS_F_BSIZE", JS::Int32Value(offsetof (struct statvfs, f_bsize)) },
|
||||
{ "OSFILE_OFFSETOF_STATVFS_F_FRSIZE", JS::Int32Value(offsetof (struct statvfs, f_frsize)) },
|
||||
{ "OSFILE_OFFSETOF_STATVFS_F_BAVAIL", JS::Int32Value(offsetof (struct statvfs, f_bavail)) },
|
||||
|
||||
#endif // defined(XP_UNIX)
|
||||
|
|
|
@ -6,9 +6,15 @@ var success = 0;
|
|||
|
||||
try {
|
||||
parent[name].success = 1;
|
||||
parent.postMessage(success ? "success" : "failure", "http://mochi.test:8888");
|
||||
parent.postMessage({
|
||||
from: name,
|
||||
result: success ? "success" : "failure"
|
||||
}, "http://mochi.test:8888");
|
||||
} catch (e) {
|
||||
parent.postMessage(e.toString(), "http://mochi.test:8888");
|
||||
parent.postMessage({
|
||||
from: name,
|
||||
result: e.toString()
|
||||
}, "http://mochi.test:8888");
|
||||
}
|
||||
|
||||
</script>
|
||||
|
|
|
@ -15,22 +15,22 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=440572
|
|||
|
||||
/** Test for Bug 440572 **/
|
||||
|
||||
var messages = [];
|
||||
var messages = new Map();
|
||||
|
||||
function receiveMessage(e)
|
||||
{
|
||||
is(e.origin, "http://example.org", "wrong sender!");
|
||||
messages.push(e.data);
|
||||
messages.set(e.data.from, e.data.result);
|
||||
}
|
||||
|
||||
window.addEventListener("message", receiveMessage);
|
||||
|
||||
function runtests()
|
||||
{
|
||||
is(messages.length, 3, "received the right number of messages.");
|
||||
is(messages[0], "success", "test in frame failed.");
|
||||
isnot(messages[1], "success", "parent[\"content\"] should be the WebIDL property of Window.");
|
||||
isnot(messages[2], "success", "parent[\"dump\"] should be the WebIDL property of Window.");
|
||||
is(messages.size, 3, "received the right number of messages.");
|
||||
is(messages.get("test"), "success", "test in frame failed.");
|
||||
isnot(messages.get("content"), "success", "parent[\"content\"] should be the WebIDL property of Window.");
|
||||
isnot(messages.get("dump"), "success", "parent[\"dump\"] should be the WebIDL property of Window.");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
|
|
@ -548,7 +548,7 @@ var interfaceNamesInGlobalScope =
|
|||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"HTMLVideoElement",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "IdleDeadline", nightly: true},
|
||||
{name: "IdleDeadline"},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"IDBCursor",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
|
|
@ -6,5 +6,6 @@ support-files =
|
|||
WebVRHelpers.js
|
||||
|
||||
[test_vrDisplay_getFrameData.html]
|
||||
[test_vrDisplay_exitPresent.html]
|
||||
[test_vrDisplay_requestPresent.html]
|
||||
skip-if = true
|
|
@ -0,0 +1,45 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>VRDisplay ExitPresent</title>
|
||||
<meta name="timeout" content="long"/>
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="runVRTest.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
function testExitPresentOnOtherIframe(content) {
|
||||
return content.navigator.getVRDisplays().then((displays) => {
|
||||
content.vrDisplay = displays[0];
|
||||
return content.vrDisplay.exitPresent();
|
||||
});
|
||||
}
|
||||
var initVRPresentation = function(content) {
|
||||
return content.navigator.getVRDisplays().then((displays) => {
|
||||
console.log("GetVRDisplay!!");
|
||||
content.vrDisplay = displays[0];
|
||||
content.canvas = content.document.createElement("canvas");
|
||||
content.canvas.id = "vrCanvas";
|
||||
return content.vrDisplay.requestPresent([{source:content.canvas}]);
|
||||
});
|
||||
}
|
||||
function startTest() {
|
||||
var ifr1 = document.getElementById("iframe1");
|
||||
var ifr2 = document.getElementById("iframe2");
|
||||
var frame1 = ifr1.contentWindow;
|
||||
var frame2 = ifr2.contentWindow;
|
||||
initVRPresentation(frame1).then(() => {
|
||||
promise_test((test) => {
|
||||
return promise_rejects(test, null, testExitPresentOnOtherIframe(frame2));
|
||||
}, "We cannot exist VR presentation established by another content, this promise is expected to be rejected.")
|
||||
});
|
||||
}
|
||||
runVRTest(startTest);
|
||||
</script>
|
||||
|
||||
<iframe id="iframe1"></iframe>
|
||||
<iframe id="iframe2"></iframe>
|
||||
</body>
|
||||
</html>
|
|
@ -24,6 +24,16 @@ interface ThreadSafeChromeUtils {
|
|||
[Throws]
|
||||
static DOMString saveHeapSnapshot(optional HeapSnapshotBoundaries boundaries);
|
||||
|
||||
/**
|
||||
* This is the same as saveHeapSnapshot, but with a different return value.
|
||||
*
|
||||
* @returns The snapshot ID of the file. This is the file name
|
||||
* without the temp directory or the trailing
|
||||
* `.fxsnapshot`.
|
||||
*/
|
||||
[Throws]
|
||||
static DOMString saveHeapSnapshotGetId(optional HeapSnapshotBoundaries boundaries);
|
||||
|
||||
/**
|
||||
* Deserialize a core dump into a HeapSnapshot.
|
||||
*
|
||||
|
|
|
@ -675,7 +675,6 @@ nsBindingManager::WalkRules(nsIStyleRuleProcessor::EnumFunc aFunc,
|
|||
do {
|
||||
nsXBLBinding *binding = content->GetXBLBinding();
|
||||
if (binding) {
|
||||
aData->mTreeMatchContext.mScopedRoot = content;
|
||||
binding->WalkRules(aFunc, aData);
|
||||
// If we're not looking at our original content, allow the binding to cut
|
||||
// off style inheritance
|
||||
|
@ -698,9 +697,6 @@ nsBindingManager::WalkRules(nsIStyleRuleProcessor::EnumFunc aFunc,
|
|||
// in the loop.
|
||||
*aCutOffInheritance = (content != nullptr);
|
||||
|
||||
// Null out the scoped root that we set repeatedly
|
||||
aData->mTreeMatchContext.mScopedRoot = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include "gfxPrefs.h"
|
||||
#include "LayersLogging.h"
|
||||
#include "mozilla/BasicEvents.h"
|
||||
#include "mozilla/dom/TabChild.h"
|
||||
#include "mozilla/dom/TabGroup.h"
|
||||
#include "mozilla/IntegerPrintfMacros.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
@ -205,6 +207,12 @@ APZEventState::ProcessSingleTap(const CSSPoint& aPoint,
|
|||
|
||||
APZES_LOG("Active element uses style, scheduling timer for click event\n");
|
||||
nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
|
||||
TabChild* tabChild = widget->GetOwningTabChild();
|
||||
|
||||
if (tabChild && XRE_IsContentProcess()) {
|
||||
timer->SetTarget(
|
||||
tabChild->TabGroup()->EventTargetFor(TaskCategory::Other));
|
||||
}
|
||||
RefPtr<DelayedFireSingleTapEvent> callback =
|
||||
new DelayedFireSingleTapEvent(mWidget, ldPoint, aModifiers, aClickCount,
|
||||
timer, touchRollup);
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
#include "mozilla/layers/AnimationMetricsTracker.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <inttypes.h>
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
||||
#define AMT_LOG(...)
|
||||
// #define AMT_LOG(...) printf_stderr("AMT: " __VA_ARGS__)
|
||||
|
@ -16,6 +16,7 @@ namespace mozilla {
|
|||
namespace layers {
|
||||
|
||||
AnimationMetricsTracker::AnimationMetricsTracker()
|
||||
: mMaxLayerAreaAnimated(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -24,15 +25,17 @@ AnimationMetricsTracker::~AnimationMetricsTracker()
|
|||
}
|
||||
|
||||
void
|
||||
AnimationMetricsTracker::UpdateAnimationInProgress(bool aInProgress,
|
||||
uint64_t aLayerArea)
|
||||
AnimationMetricsTracker::UpdateAnimationInProgress(AnimationProcessTypes aActive,
|
||||
uint64_t aLayerArea,
|
||||
TimeDuration aVsyncInterval)
|
||||
{
|
||||
MOZ_ASSERT(aInProgress || aLayerArea == 0);
|
||||
if (mCurrentAnimationStart && !aInProgress) {
|
||||
bool inProgress = (aActive != AnimationProcessTypes::eNone);
|
||||
MOZ_ASSERT(inProgress || aLayerArea == 0);
|
||||
if (mCurrentAnimationStart && !inProgress) {
|
||||
AnimationEnded();
|
||||
mCurrentAnimationStart = TimeStamp();
|
||||
mMaxLayerAreaAnimated = 0;
|
||||
} else if (aInProgress) {
|
||||
} else if (inProgress) {
|
||||
if (!mCurrentAnimationStart) {
|
||||
mCurrentAnimationStart = TimeStamp::Now();
|
||||
mMaxLayerAreaAnimated = aLayerArea;
|
||||
|
@ -41,6 +44,31 @@ AnimationMetricsTracker::UpdateAnimationInProgress(bool aInProgress,
|
|||
mMaxLayerAreaAnimated = std::max(mMaxLayerAreaAnimated, aLayerArea);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateAnimationThroughput("chrome",
|
||||
(aActive & AnimationProcessTypes::eChrome) != AnimationProcessTypes::eNone,
|
||||
mChromeAnimation,
|
||||
aVsyncInterval,
|
||||
Telemetry::COMPOSITOR_ANIMATION_THROUGHPUT_CHROME,
|
||||
Telemetry::COMPOSITOR_ANIMATION_MAX_CONTIGUOUS_DROPS_CHROME);
|
||||
UpdateAnimationThroughput("content",
|
||||
(aActive & AnimationProcessTypes::eContent) != AnimationProcessTypes::eNone,
|
||||
mContentAnimation,
|
||||
aVsyncInterval,
|
||||
Telemetry::COMPOSITOR_ANIMATION_THROUGHPUT_CONTENT,
|
||||
Telemetry::COMPOSITOR_ANIMATION_MAX_CONTIGUOUS_DROPS_CONTENT);
|
||||
}
|
||||
|
||||
void
|
||||
AnimationMetricsTracker::UpdateApzAnimationInProgress(bool aInProgress,
|
||||
TimeDuration aVsyncInterval)
|
||||
{
|
||||
UpdateAnimationThroughput("apz",
|
||||
aInProgress,
|
||||
mApzAnimation,
|
||||
aVsyncInterval,
|
||||
Telemetry::COMPOSITOR_ANIMATION_THROUGHPUT_APZ,
|
||||
Telemetry::COMPOSITOR_ANIMATION_MAX_CONTIGUOUS_DROPS_APZ);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -52,6 +80,7 @@ void
|
|||
AnimationMetricsTracker::AnimationEnded()
|
||||
{
|
||||
MOZ_ASSERT(mCurrentAnimationStart);
|
||||
|
||||
Telemetry::AccumulateTimeDelta(Telemetry::COMPOSITOR_ANIMATION_DURATION, mCurrentAnimationStart);
|
||||
Telemetry::Accumulate(Telemetry::COMPOSITOR_ANIMATION_MAX_LAYER_AREA, mMaxLayerAreaAnimated);
|
||||
AMT_LOG("Ended animation; duration: %f ms, area: %" PRIu64 "\n",
|
||||
|
@ -59,5 +88,78 @@ AnimationMetricsTracker::AnimationEnded()
|
|||
mMaxLayerAreaAnimated);
|
||||
}
|
||||
|
||||
void
|
||||
AnimationMetricsTracker::UpdateAnimationThroughput(const char* aLabel,
|
||||
bool aInProgress,
|
||||
AnimationData& aAnimation,
|
||||
TimeDuration aVsyncInterval,
|
||||
Telemetry::HistogramID aThroughputHistogram,
|
||||
Telemetry::HistogramID aMaxDropsHistogram)
|
||||
{
|
||||
if (aInProgress && !aAnimation.mStart) {
|
||||
// the animation just started
|
||||
aAnimation.mStart = TimeStamp::Now();
|
||||
aAnimation.mLastFrameTime = aAnimation.mStart;
|
||||
aAnimation.mLongestFrame = TimeDuration();
|
||||
aAnimation.mFrameCount = 1;
|
||||
AMT_LOG("Compositor animation of type %s just started\n", aLabel);
|
||||
} else if (aInProgress && aAnimation.mStart) {
|
||||
// the animation continues
|
||||
aAnimation.mFrameCount++;
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
aAnimation.mLongestFrame = std::max(aAnimation.mLongestFrame, now - aAnimation.mLastFrameTime);
|
||||
aAnimation.mLastFrameTime = now;
|
||||
} else if (!aInProgress && aAnimation.mStart) {
|
||||
// the animation just ended
|
||||
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
// Get the length and clear aAnimation.mStart before the early-returns below
|
||||
TimeDuration animationLength = now - aAnimation.mStart;
|
||||
aAnimation.mStart = TimeStamp();
|
||||
|
||||
if (aVsyncInterval == TimeDuration::Forever()) {
|
||||
AMT_LOG("Invalid vsync interval: forever\n");
|
||||
return;
|
||||
}
|
||||
double vsyncIntervalMs = aVsyncInterval.ToMilliseconds();
|
||||
if (vsyncIntervalMs < 1.0f) {
|
||||
// Guard to avoid division by zero or other crazy results below
|
||||
AMT_LOG("Invalid vsync interval: %fms\n", vsyncIntervalMs);
|
||||
return;
|
||||
}
|
||||
|
||||
// We round the expectedFrameCount because it's a count and should be an
|
||||
// integer. The animationLength might not be an exact vsync multiple because
|
||||
// it's taken during the composition process and the amount of work done
|
||||
// between the vsync signal and the Timestamp::Now() call may vary slightly
|
||||
// from one composite to another.
|
||||
uint32_t expectedFrameCount = std::lround(animationLength.ToMilliseconds() / vsyncIntervalMs);
|
||||
AMT_LOG("Type %s ran for %fms (interval: %fms), %u frames (expected: %u)\n",
|
||||
aLabel, animationLength.ToMilliseconds(), vsyncIntervalMs,
|
||||
aAnimation.mFrameCount, expectedFrameCount);
|
||||
if (expectedFrameCount <= 0) {
|
||||
// Graceful handling of probably impossible thing, unless the clock
|
||||
// changes while running?
|
||||
// Note that we also skip the frames-dropped probe if this happens,
|
||||
// because we cannot be sure that the frame length measurements are valid.
|
||||
return;
|
||||
}
|
||||
|
||||
// Scale up by 1000 because telemetry takes ints, truncate intentionally
|
||||
// to avoid artificial inflation of the result.
|
||||
uint32_t frameHitRatio = (uint32_t)(1000.0f * aAnimation.mFrameCount / expectedFrameCount);
|
||||
Telemetry::Accumulate(aThroughputHistogram, frameHitRatio);
|
||||
AMT_LOG("Reported frameHitRatio %u\n", frameHitRatio);
|
||||
|
||||
// Get the longest frame time (make sure to check the final frame as well)
|
||||
TimeDuration longestFrame = std::max(aAnimation.mLongestFrame, now - aAnimation.mLastFrameTime);
|
||||
// As above, we round to get the frame count. Additionally we subtract one
|
||||
// from the frame count to get the number of dropped frames.
|
||||
uint32_t framesDropped = std::lround(longestFrame.ToMilliseconds() / vsyncIntervalMs) - 1;
|
||||
AMT_LOG("Longest frame was %fms (%d drops)\n", longestFrame.ToMilliseconds(), framesDropped);
|
||||
Telemetry::Accumulate(aMaxDropsHistogram, framesDropped);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -6,11 +6,21 @@
|
|||
#ifndef mozilla_layers_AnimationMetricsTracker_h
|
||||
#define mozilla_layers_AnimationMetricsTracker_h
|
||||
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/TypedEnumBits.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
enum class AnimationProcessTypes {
|
||||
eNone = 0x0,
|
||||
eContent = 0x1,
|
||||
eChrome = 0x2
|
||||
};
|
||||
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(AnimationProcessTypes)
|
||||
|
||||
/**
|
||||
* Tracks the start and end of compositor animations.
|
||||
*/
|
||||
|
@ -21,17 +31,58 @@ public:
|
|||
|
||||
/**
|
||||
* This function should be called per composite, to inform the metrics
|
||||
* tracker if any animation is in progress, and if so, what area is
|
||||
* being animated. The aLayerArea is in Layer pixels squared.
|
||||
* tracker which processes have active animations. If there is are animations
|
||||
* in progress, the sum of their areas should also be provided, along with
|
||||
* the vsync interval.
|
||||
*/
|
||||
void UpdateAnimationInProgress(bool aInProgress, uint64_t aLayerArea);
|
||||
void UpdateAnimationInProgress(AnimationProcessTypes aActive, uint64_t aLayerArea,
|
||||
TimeDuration aVsyncInterval);
|
||||
|
||||
/**
|
||||
* Similar to UpdateAnimationInProgress, but this is for APZ animations. Again,
|
||||
* this should be called per composite.
|
||||
*/
|
||||
void UpdateApzAnimationInProgress(bool aInProgress, TimeDuration aVsyncInterval);
|
||||
|
||||
private:
|
||||
// A struct to group data that we need for each type of compositor animation.
|
||||
struct AnimationData {
|
||||
// The start time of the current animation.
|
||||
TimeStamp mStart;
|
||||
// The timestamp of the most recent animation frame.
|
||||
TimeStamp mLastFrameTime;
|
||||
// The longest animation frame length encountered so far.
|
||||
TimeDuration mLongestFrame;
|
||||
// The number of frames composited for the current animation.
|
||||
uint32_t mFrameCount;
|
||||
|
||||
AnimationData()
|
||||
: mFrameCount(0)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void AnimationStarted();
|
||||
void AnimationEnded();
|
||||
void UpdateAnimationThroughput(const char* aLabel,
|
||||
bool aInProgress,
|
||||
AnimationData& aAnimationData,
|
||||
TimeDuration aVsyncInterval,
|
||||
Telemetry::HistogramID aThroughputHistogram,
|
||||
Telemetry::HistogramID aMaxDropsHistogram);
|
||||
|
||||
// The start time of the current compositor animation. This just tracks
|
||||
// whether the compositor is running an animation, without regard to which
|
||||
// process the animation is coming from.
|
||||
TimeStamp mCurrentAnimationStart;
|
||||
// The max area (in layer pixels) that the current compositor animation
|
||||
// has touched on any given animation frame.
|
||||
uint64_t mMaxLayerAreaAnimated;
|
||||
|
||||
// We keep an instance of the struct for each type of compositor animation.
|
||||
AnimationData mChromeAnimation;
|
||||
AnimationData mContentAnimation;
|
||||
AnimationData mApzAnimation;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
|
|
@ -645,26 +645,41 @@ ApplyAnimatedValue(Layer* aLayer,
|
|||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
static AnimationProcessTypes
|
||||
SampleAnimations(Layer* aLayer,
|
||||
CompositorAnimationStorage* aStorage,
|
||||
TimeStamp aPoint,
|
||||
uint64_t* aLayerAreaAnimated)
|
||||
{
|
||||
bool activeAnimations = false;
|
||||
// This tracks the first-encountered RefLayer in the layer tree. Since we are
|
||||
// doing a depth-first traversal, it is set to a non-null value if and only if
|
||||
// the currently-being-traversed node has a RefLayer ancestor. In the case of
|
||||
// nested RefLayers it points to the rootmost RefLayer.
|
||||
RefLayer* ancestorRefLayer = nullptr;
|
||||
|
||||
// This bitfield-enum tracks which processes have active animations. Anything
|
||||
// "above" the |ancestorRefLayer| in the layer tree is assumed to be the
|
||||
// chrome process, and anything "below" is assumed to be the content process.
|
||||
AnimationProcessTypes animProcess = AnimationProcessTypes::eNone;
|
||||
|
||||
ForEachNode<ForwardIterator>(
|
||||
aLayer,
|
||||
[aStorage, &activeAnimations, &aPoint, &aLayerAreaAnimated] (Layer* layer)
|
||||
[&] (Layer* layer)
|
||||
{
|
||||
if (!ancestorRefLayer) {
|
||||
ancestorRefLayer = layer->AsRefLayer();
|
||||
}
|
||||
|
||||
bool hasInEffectAnimations = false;
|
||||
StyleAnimationValue animationValue = layer->GetBaseAnimationStyle();
|
||||
activeAnimations |=
|
||||
AnimationHelper::SampleAnimationForEachNode(aPoint,
|
||||
layer->GetAnimations(),
|
||||
layer->GetAnimationData(),
|
||||
animationValue,
|
||||
hasInEffectAnimations);
|
||||
if (AnimationHelper::SampleAnimationForEachNode(aPoint,
|
||||
layer->GetAnimations(),
|
||||
layer->GetAnimationData(),
|
||||
animationValue,
|
||||
hasInEffectAnimations)) {
|
||||
animProcess |= (ancestorRefLayer ? AnimationProcessTypes::eContent
|
||||
: AnimationProcessTypes::eChrome);
|
||||
}
|
||||
if (hasInEffectAnimations) {
|
||||
Animation& animation = layer->GetAnimations().LastElement();
|
||||
ApplyAnimatedValue(layer,
|
||||
|
@ -676,9 +691,16 @@ SampleAnimations(Layer* aLayer,
|
|||
*aLayerAreaAnimated += (layer->GetVisibleRegion().Area());
|
||||
}
|
||||
}
|
||||
},
|
||||
[&ancestorRefLayer] (Layer* aLayer)
|
||||
{
|
||||
// If we're unwinding up past the rootmost RefLayer, clear our pointer
|
||||
if (ancestorRefLayer && aLayer->AsRefLayer() == ancestorRefLayer) {
|
||||
ancestorRefLayer = nullptr;
|
||||
}
|
||||
});
|
||||
|
||||
return activeAnimations;
|
||||
return animProcess;
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -1336,15 +1358,16 @@ AsyncCompositionManager::TransformShadowTree(TimeStamp aCurrentFrame,
|
|||
// On the initial frame we use aVsyncTimestamp here so the timestamp on the
|
||||
// second frame are the same as the initial frame, but it does not matter.
|
||||
uint64_t layerAreaAnimated = 0;
|
||||
bool wantNextFrame =
|
||||
AnimationProcessTypes animationProcess =
|
||||
SampleAnimations(root,
|
||||
storage,
|
||||
!mPreviousFrameTimeStamp.IsNull() ?
|
||||
mPreviousFrameTimeStamp : aCurrentFrame,
|
||||
&layerAreaAnimated);
|
||||
bool wantNextFrame = (animationProcess != AnimationProcessTypes::eNone);
|
||||
|
||||
mAnimationMetricsTracker.UpdateAnimationInProgress(
|
||||
wantNextFrame, layerAreaAnimated);
|
||||
animationProcess, layerAreaAnimated, aVsyncRate);
|
||||
|
||||
if (!wantNextFrame) {
|
||||
// Clean up the CompositorAnimationStorage because
|
||||
|
@ -1388,7 +1411,9 @@ AsyncCompositionManager::TransformShadowTree(TimeStamp aCurrentFrame,
|
|||
nextFrame += aVsyncRate;
|
||||
}
|
||||
|
||||
wantNextFrame |= SampleAPZAnimations(LayerMetricsWrapper(root), nextFrame);
|
||||
bool apzAnimating = SampleAPZAnimations(LayerMetricsWrapper(root), nextFrame);
|
||||
mAnimationMetricsTracker.UpdateApzAnimationInProgress(apzAnimating, aVsyncRate);
|
||||
wantNextFrame |= apzAnimating;
|
||||
}
|
||||
|
||||
HostLayer* rootComposite = root->AsHostLayer();
|
||||
|
|
|
@ -737,20 +737,21 @@ DXGITextureHostD3D11::GetDevice()
|
|||
if (mFlags & TextureFlags::INVALID_COMPOSITOR) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return mProvider->GetD3D11Device();
|
||||
return mDevice;
|
||||
}
|
||||
|
||||
void
|
||||
DXGITextureHostD3D11::SetTextureSourceProvider(TextureSourceProvider* aProvider)
|
||||
{
|
||||
if (!aProvider || !aProvider->GetD3D11Device()) {
|
||||
mDevice = nullptr;
|
||||
mProvider = nullptr;
|
||||
mTextureSource = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
mProvider = aProvider;
|
||||
mDevice = aProvider->GetD3D11Device();
|
||||
|
||||
if (mTextureSource) {
|
||||
mTextureSource->SetTextureSourceProvider(aProvider);
|
||||
|
@ -776,6 +777,9 @@ DXGITextureHostD3D11::LockWithoutCompositor()
|
|||
// Unlike the normal Lock() function, this function may be called when
|
||||
// mCompositor is nullptr such as during WebVR frame submission. So, there is
|
||||
// no 'mCompositor' checking here.
|
||||
if (!mDevice) {
|
||||
mDevice = DeviceManagerDx::Get()->GetCompositorDevice();
|
||||
}
|
||||
return LockInternal();
|
||||
}
|
||||
|
||||
|
@ -805,7 +809,11 @@ DXGITextureHostD3D11::LockInternal()
|
|||
return false;
|
||||
}
|
||||
|
||||
mTextureSource = new DataTextureSourceD3D11(mFormat, mProvider, mTexture);
|
||||
if (mProvider) {
|
||||
mTextureSource = new DataTextureSourceD3D11(mFormat, mProvider, mTexture);
|
||||
} else {
|
||||
mTextureSource = new DataTextureSourceD3D11(mDevice, mFormat, mTexture);
|
||||
}
|
||||
}
|
||||
|
||||
mIsLocked = LockD3DTexture(mTextureSource->GetD3D11Texture());
|
||||
|
@ -895,12 +903,15 @@ void
|
|||
DXGIYCbCrTextureHostD3D11::SetTextureSourceProvider(TextureSourceProvider* aProvider)
|
||||
{
|
||||
if (!aProvider || !aProvider->GetD3D11Device()) {
|
||||
mProvider = nullptr;
|
||||
mTextureSources[0] = nullptr;
|
||||
mTextureSources[1] = nullptr;
|
||||
mTextureSources[2] = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
mProvider = aProvider;
|
||||
|
||||
if (mTextureSources[0]) {
|
||||
mTextureSources[0]->SetTextureSourceProvider(aProvider);
|
||||
}
|
||||
|
|
|
@ -333,6 +333,7 @@ protected:
|
|||
|
||||
bool OpenSharedHandle();
|
||||
|
||||
RefPtr<ID3D11Device> mDevice;
|
||||
RefPtr<ID3D11Texture2D> mTexture;
|
||||
RefPtr<DataTextureSourceD3D11> mTextureSource;
|
||||
gfx::IntSize mSize;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "base/message_loop.h" // for MessageLoop
|
||||
#include "base/task.h" // for NewRunnableMethod, etc
|
||||
#include "gfxPrefs.h"
|
||||
#include "mozilla/dom/TabGroup.h"
|
||||
#include "mozilla/layers/ImageBridgeChild.h"
|
||||
#include "mozilla/layers/APZChild.h"
|
||||
#include "mozilla/layers/IAPZCTreeManager.h"
|
||||
|
@ -1083,6 +1084,15 @@ CompositorBridgeChild::AllocPAPZCTreeManagerChild(const uint64_t& aLayersId)
|
|||
{
|
||||
APZCTreeManagerChild* child = new APZCTreeManagerChild();
|
||||
child->AddRef();
|
||||
if (aLayersId != 0) {
|
||||
TabChild* tabChild = TabChild::GetFrom(aLayersId);
|
||||
if (tabChild) {
|
||||
SetEventTargetForActor(
|
||||
child, tabChild->TabGroup()->EventTargetFor(TaskCategory::Other));
|
||||
MOZ_ASSERT(child->GetActorEventTarget());
|
||||
}
|
||||
}
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
|
|
|
@ -148,3 +148,9 @@ CompositorThreadHolder::IsInCompositorThread()
|
|||
|
||||
} // namespace mozilla
|
||||
} // namespace layers
|
||||
|
||||
bool
|
||||
NS_IsInCompositorThread()
|
||||
{
|
||||
return mozilla::layers::CompositorThreadHolder::IsInCompositorThread();
|
||||
}
|
||||
|
|
|
@ -48,6 +48,11 @@ bool is_glcontext_egl(void* glcontext_ptr)
|
|||
return glcontext->GetContextType() == mozilla::gl::GLContextType::EGL;
|
||||
}
|
||||
|
||||
void gfx_critical_note(const char* msg)
|
||||
{
|
||||
gfxCriticalNote << msg;
|
||||
}
|
||||
|
||||
void* get_proc_address_from_glcontext(void* glcontext_ptr, const char* procname)
|
||||
{
|
||||
MOZ_ASSERT(glcontext_ptr);
|
||||
|
|
|
@ -2296,10 +2296,13 @@ gfxPlatform::InitWebRenderConfig()
|
|||
"WebRender is an opt-in feature",
|
||||
NS_LITERAL_CSTRING("FEATURE_FAILURE_DEFAULT_OFF"));
|
||||
|
||||
if (Preferences::GetBool("gfx.webrender.enabled", false)) {
|
||||
bool prefEnabled = Preferences::GetBool("gfx.webrender.enabled", false);
|
||||
if (prefEnabled) {
|
||||
featureWebRender.UserEnable("Enabled by pref");
|
||||
}
|
||||
|
||||
ScopedGfxFeatureReporter reporter("WR", prefEnabled);
|
||||
|
||||
// WebRender relies on the GPU process when on Windows
|
||||
#ifdef XP_WIN
|
||||
if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
|
||||
|
@ -2325,7 +2328,10 @@ gfxPlatform::InitWebRenderConfig()
|
|||
#endif
|
||||
|
||||
// gfxFeature is not usable in the GPU process, so we use gfxVars to transmit this feature
|
||||
gfxVars::SetUseWebRender(gfxConfig::IsEnabled(Feature::WEBRENDER));
|
||||
if (gfxConfig::IsEnabled(Feature::WEBRENDER)) {
|
||||
gfxVars::SetUseWebRender(true);
|
||||
reporter.SetSuccessful();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "VRDisplayPresentation.h"
|
||||
|
||||
#include "mozilla/dom/DocGroup.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "VRDisplayClient.h"
|
||||
#include "VRLayerChild.h"
|
||||
|
@ -70,7 +71,16 @@ VRDisplayPresentation::CreateLayers()
|
|||
continue;
|
||||
}
|
||||
|
||||
RefPtr<VRLayerChild> vrLayer = static_cast<VRLayerChild*>(manager->CreateVRLayer(mDisplayClient->GetDisplayInfo().GetDisplayID(), leftBounds, rightBounds));
|
||||
nsCOMPtr<nsIEventTarget> target;
|
||||
nsIDocument* doc;
|
||||
doc = canvasElement->OwnerDoc();
|
||||
if (doc) {
|
||||
target = doc->EventTargetFor(TaskCategory::Other);
|
||||
}
|
||||
|
||||
RefPtr<VRLayerChild> vrLayer =
|
||||
static_cast<VRLayerChild*>(manager->CreateVRLayer(mDisplayClient->GetDisplayInfo().GetDisplayID(),
|
||||
leftBounds, rightBounds, target));
|
||||
if (!vrLayer) {
|
||||
NS_WARNING("CreateVRLayer returned null!");
|
||||
continue;
|
||||
|
|
|
@ -401,11 +401,26 @@ VRManagerChild::DeallocShmem(ipc::Shmem& aShmem)
|
|||
}
|
||||
|
||||
PVRLayerChild*
|
||||
VRManagerChild::CreateVRLayer(uint32_t aDisplayID, const Rect& aLeftEyeRect, const Rect& aRightEyeRect)
|
||||
VRManagerChild::CreateVRLayer(uint32_t aDisplayID,
|
||||
const Rect& aLeftEyeRect,
|
||||
const Rect& aRightEyeRect,
|
||||
nsIEventTarget* aTarget)
|
||||
{
|
||||
return SendPVRLayerConstructor(aDisplayID,
|
||||
aLeftEyeRect.x, aLeftEyeRect.y, aLeftEyeRect.width, aLeftEyeRect.height,
|
||||
aRightEyeRect.x, aRightEyeRect.y, aRightEyeRect.width, aRightEyeRect.height);
|
||||
PVRLayerChild* vrLayerChild = AllocPVRLayerChild(aDisplayID, aLeftEyeRect.x,
|
||||
aLeftEyeRect.y, aLeftEyeRect.width,
|
||||
aLeftEyeRect.height, aRightEyeRect.x,
|
||||
aRightEyeRect.y, aRightEyeRect.width,
|
||||
aRightEyeRect.height);
|
||||
// Do the DOM labeling.
|
||||
if (aTarget) {
|
||||
SetEventTargetForActor(vrLayerChild, aTarget);
|
||||
MOZ_ASSERT(vrLayerChild->GetActorEventTarget());
|
||||
}
|
||||
return SendPVRLayerConstructor(vrLayerChild, aDisplayID, aLeftEyeRect.x,
|
||||
aLeftEyeRect.y, aLeftEyeRect.width,
|
||||
aLeftEyeRect.height, aRightEyeRect.x,
|
||||
aRightEyeRect.y, aRightEyeRect.width,
|
||||
aRightEyeRect.height);
|
||||
}
|
||||
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче