зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to autoland
This commit is contained in:
Коммит
ac954c6a3f
|
@ -83,11 +83,9 @@ devtools/client/debugger/**
|
||||||
devtools/client/framework/**
|
devtools/client/framework/**
|
||||||
!devtools/client/framework/selection.js
|
!devtools/client/framework/selection.js
|
||||||
!devtools/client/framework/toolbox.js
|
!devtools/client/framework/toolbox.js
|
||||||
devtools/client/jsonview/lib/**
|
|
||||||
devtools/client/netmonitor/test/**
|
devtools/client/netmonitor/test/**
|
||||||
devtools/client/netmonitor/har/test/**
|
devtools/client/netmonitor/har/test/**
|
||||||
devtools/client/projecteditor/**
|
devtools/client/projecteditor/**
|
||||||
devtools/client/promisedebugger/**
|
|
||||||
devtools/client/responsivedesign/**
|
devtools/client/responsivedesign/**
|
||||||
devtools/client/scratchpad/**
|
devtools/client/scratchpad/**
|
||||||
devtools/client/shadereditor/**
|
devtools/client/shadereditor/**
|
||||||
|
@ -104,17 +102,9 @@ devtools/client/webconsole/webconsole-connection-proxy.js
|
||||||
devtools/client/webconsole/webconsole.js
|
devtools/client/webconsole/webconsole.js
|
||||||
devtools/client/webide/**
|
devtools/client/webide/**
|
||||||
!devtools/client/webide/components/webideCli.js
|
!devtools/client/webide/components/webideCli.js
|
||||||
devtools/server/*.js
|
devtools/server/actors/*.js
|
||||||
devtools/server/*.jsm
|
|
||||||
!devtools/server/child.js
|
|
||||||
!devtools/server/css-logic.js
|
|
||||||
!devtools/server/main.js
|
|
||||||
!devtools/server/websocket-server.js
|
|
||||||
devtools/server/actors/**
|
|
||||||
!devtools/server/actors/csscoverage.js
|
!devtools/server/actors/csscoverage.js
|
||||||
!devtools/server/actors/inspector.js
|
!devtools/server/actors/inspector.js
|
||||||
!devtools/server/actors/highlighters/css-grid.js
|
|
||||||
!devtools/server/actors/highlighters/eye-dropper.js
|
|
||||||
!devtools/server/actors/layout.js
|
!devtools/server/actors/layout.js
|
||||||
!devtools/server/actors/string.js
|
!devtools/server/actors/string.js
|
||||||
!devtools/server/actors/styles.js
|
!devtools/server/actors/styles.js
|
||||||
|
@ -122,7 +112,6 @@ devtools/server/actors/**
|
||||||
!devtools/server/actors/webbrowser.js
|
!devtools/server/actors/webbrowser.js
|
||||||
!devtools/server/actors/webextension.js
|
!devtools/server/actors/webextension.js
|
||||||
!devtools/server/actors/webextension-inspected-window.js
|
!devtools/server/actors/webextension-inspected-window.js
|
||||||
devtools/server/performance/**
|
|
||||||
devtools/server/tests/browser/**
|
devtools/server/tests/browser/**
|
||||||
!devtools/server/tests/browser/browser_webextension_inspected_window.js
|
!devtools/server/tests/browser/browser_webextension_inspected_window.js
|
||||||
devtools/server/tests/mochitest/**
|
devtools/server/tests/mochitest/**
|
||||||
|
@ -134,7 +123,6 @@ devtools/shared/gcli/**
|
||||||
!devtools/shared/gcli/templater.js
|
!devtools/shared/gcli/templater.js
|
||||||
devtools/shared/heapsnapshot/**
|
devtools/shared/heapsnapshot/**
|
||||||
devtools/shared/layout/**
|
devtools/shared/layout/**
|
||||||
devtools/shared/locales/**
|
|
||||||
devtools/shared/performance/**
|
devtools/shared/performance/**
|
||||||
!devtools/shared/platform/**
|
!devtools/shared/platform/**
|
||||||
devtools/shared/qrcode/**
|
devtools/shared/qrcode/**
|
||||||
|
|
2
CLOBBER
2
CLOBBER
|
@ -22,4 +22,4 @@
|
||||||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||||
# don't change CLOBBER for WebIDL changes any more.
|
# don't change CLOBBER for WebIDL changes any more.
|
||||||
|
|
||||||
Bug 1142403 needs a clobber to force jemalloc to rerun configure.
|
Bug 1322938 needs a clobber for test_lowDiskSpace.html on Android
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "mozilla/dom/BindingDeclarations.h"
|
#include "mozilla/dom/BindingDeclarations.h"
|
||||||
#include "mozilla/dom/DOMStringList.h"
|
#include "mozilla/dom/DOMStringList.h"
|
||||||
#include "nsIPersistentProperties2.h"
|
#include "nsIPersistentProperties2.h"
|
||||||
|
#include "nsISimpleEnumerator.h"
|
||||||
|
|
||||||
#include "Accessible-inl.h"
|
#include "Accessible-inl.h"
|
||||||
#include "nsAccessibilityService.h"
|
#include "nsAccessibilityService.h"
|
||||||
|
@ -77,6 +78,31 @@ AccessibleNode::GetStates(nsTArray<nsString>& aStates)
|
||||||
aStates.AppendElement(NS_LITERAL_STRING("defunct"));
|
aStates.AppendElement(NS_LITERAL_STRING("defunct"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AccessibleNode::GetAttributes(nsTArray<nsString>& aAttributes)
|
||||||
|
{
|
||||||
|
if (!mIntl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIPersistentProperties> attrs = mIntl->Attributes();
|
||||||
|
|
||||||
|
nsCOMPtr<nsISimpleEnumerator> props;
|
||||||
|
attrs->Enumerate(getter_AddRefs(props));
|
||||||
|
|
||||||
|
bool hasMore = false;
|
||||||
|
while (NS_SUCCEEDED(props->HasMoreElements(&hasMore)) && hasMore) {
|
||||||
|
nsCOMPtr<nsISupports> supp;
|
||||||
|
props->GetNext(getter_AddRefs(supp));
|
||||||
|
|
||||||
|
nsCOMPtr<nsIPropertyElement> prop(do_QueryInterface(supp));
|
||||||
|
|
||||||
|
nsAutoCString attr;
|
||||||
|
prop->GetKey(attr);
|
||||||
|
aAttributes.AppendElement(NS_ConvertUTF8toUTF16(attr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
AccessibleNode::Is(const Sequence<nsString>& aFlavors)
|
AccessibleNode::Is(const Sequence<nsString>& aFlavors)
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,6 +38,7 @@ public:
|
||||||
|
|
||||||
void GetRole(nsAString& aRole);
|
void GetRole(nsAString& aRole);
|
||||||
void GetStates(nsTArray<nsString>& aStates);
|
void GetStates(nsTArray<nsString>& aStates);
|
||||||
|
void GetAttributes(nsTArray<nsString>& aAttributes);
|
||||||
nsINode* GetDOMNode();
|
nsINode* GetDOMNode();
|
||||||
|
|
||||||
bool Is(const Sequence<nsString>& aFlavors);
|
bool Is(const Sequence<nsString>& aFlavors);
|
||||||
|
|
|
@ -86,6 +86,21 @@
|
||||||
ok(anode.has('explicit-name'),
|
ok(anode.has('explicit-name'),
|
||||||
'object attributes are present');
|
'object attributes are present');
|
||||||
|
|
||||||
|
var attrs = [ 'explicit-name' ];
|
||||||
|
if (anode.attributes.length > 1) {
|
||||||
|
attrs = [
|
||||||
|
'margin-left', 'text-align', 'text-indent', 'margin-right',
|
||||||
|
'tag', 'margin-top', 'margin-bottom', 'display',
|
||||||
|
'explicit-name'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
is(anode.attributes.length, attrs.length, 'correct number of attributes');
|
||||||
|
for (var i = 0; i < attrs.length; i++) {
|
||||||
|
is(anode.attributes[i], attrs[i],
|
||||||
|
`${attrs[i]} attribute is expected at ${i}th index`);
|
||||||
|
}
|
||||||
|
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1215,12 +1215,7 @@ pref("social.shareDirectory", "https://activations.cdn.mozilla.net/sharePanel.ht
|
||||||
pref("security.mixed_content.block_active_content", true);
|
pref("security.mixed_content.block_active_content", true);
|
||||||
|
|
||||||
// Show degraded UI for http pages with password fields.
|
// Show degraded UI for http pages with password fields.
|
||||||
// Only for Nightly, Dev Edition and early beta, not for late beta or release.
|
|
||||||
#ifdef EARLY_BETA_OR_EARLIER
|
|
||||||
pref("security.insecure_password.ui.enabled", true);
|
pref("security.insecure_password.ui.enabled", true);
|
||||||
#else
|
|
||||||
pref("security.insecure_password.ui.enabled", false);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pref("security.insecure_field_warning.contextual.enabled", false);
|
pref("security.insecure_field_warning.contextual.enabled", false);
|
||||||
|
|
||||||
|
|
|
@ -2240,6 +2240,15 @@
|
||||||
|
|
||||||
this.tabContainer.updateVisibility();
|
this.tabContainer.updateVisibility();
|
||||||
|
|
||||||
|
// If URI is about:blank and we don't have a preferred remote type,
|
||||||
|
// then we need to use the referrer, if we have one, to get the
|
||||||
|
// correct remote type for the new tab.
|
||||||
|
if (uriIsAboutBlank && !aPreferredRemoteType && aReferrerURI) {
|
||||||
|
aPreferredRemoteType =
|
||||||
|
E10SUtils.getRemoteTypeForURI(aReferrerURI.spec,
|
||||||
|
gMultiProcessBrowser);
|
||||||
|
}
|
||||||
|
|
||||||
// Currently in this incarnation of bug 906076, we are forcing the
|
// Currently in this incarnation of bug 906076, we are forcing the
|
||||||
// browser to immediately be linked. In future incarnations of this
|
// browser to immediately be linked. In future incarnations of this
|
||||||
// bug this will be removed so we can leave the tab in its "lazy"
|
// bug this will be removed so we can leave the tab in its "lazy"
|
||||||
|
@ -6456,44 +6465,58 @@
|
||||||
// to get a full-resolution drag image for use on HiDPI displays.
|
// to get a full-resolution drag image for use on HiDPI displays.
|
||||||
let windowUtils = window.getInterface(Ci.nsIDOMWindowUtils);
|
let windowUtils = window.getInterface(Ci.nsIDOMWindowUtils);
|
||||||
let scale = windowUtils.screenPixelsPerCSSPixel / windowUtils.fullZoom;
|
let scale = windowUtils.screenPixelsPerCSSPixel / windowUtils.fullZoom;
|
||||||
let canvas = this._dndCanvas ? this._dndCanvas
|
let canvas = this._dndCanvas;
|
||||||
: document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
|
if (!canvas) {
|
||||||
canvas.mozOpaque = true;
|
this._dndCanvas = canvas =
|
||||||
|
document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
|
||||||
|
canvas.style.width = "100%";
|
||||||
|
canvas.style.height = "100%";
|
||||||
|
canvas.mozOpaque = true;
|
||||||
|
}
|
||||||
|
|
||||||
canvas.width = 160 * scale;
|
canvas.width = 160 * scale;
|
||||||
canvas.height = 90 * scale;
|
canvas.height = 90 * scale;
|
||||||
let toDrag;
|
let toDrag = canvas;
|
||||||
let dragImageOffset = -16;
|
let dragImageOffset = -16;
|
||||||
if (gMultiProcessBrowser) {
|
if (gMultiProcessBrowser) {
|
||||||
var context = canvas.getContext('2d');
|
var context = canvas.getContext('2d');
|
||||||
context.fillStyle = "white";
|
context.fillStyle = "white";
|
||||||
context.fillRect(0, 0, canvas.width, canvas.height);
|
context.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
// Create a panel to use it in setDragImage
|
|
||||||
// which will tell xul to render a panel that follows
|
let captureListener;
|
||||||
// the pointer while a dnd session is on.
|
let platform = this.tabbrowser.AppConstants.platform;
|
||||||
if (!this._dndPanel) {
|
// On Windows and Mac we can update the drag image during a drag
|
||||||
this._dndCanvas = canvas;
|
// using updateDragImage. On Linux, we can use a panel.
|
||||||
this._dndPanel = document.createElement("panel");
|
if (platform == "win" || platform == "macosx") {
|
||||||
this._dndPanel.className = "dragfeedback-tab";
|
captureListener = function() {
|
||||||
this._dndPanel.setAttribute("type", "drag");
|
dt.updateDragImage(canvas, dragImageOffset, dragImageOffset);
|
||||||
let wrapper = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
|
}
|
||||||
wrapper.style.width = "160px";
|
}
|
||||||
wrapper.style.height = "90px";
|
else {
|
||||||
wrapper.appendChild(canvas);
|
// Create a panel to use it in setDragImage
|
||||||
canvas.style.width = "100%";
|
// which will tell xul to render a panel that follows
|
||||||
canvas.style.height = "100%";
|
// the pointer while a dnd session is on.
|
||||||
this._dndPanel.appendChild(wrapper);
|
if (!this._dndPanel) {
|
||||||
document.documentElement.appendChild(this._dndPanel);
|
this._dndCanvas = canvas;
|
||||||
|
this._dndPanel = document.createElement("panel");
|
||||||
|
this._dndPanel.className = "dragfeedback-tab";
|
||||||
|
this._dndPanel.setAttribute("type", "drag");
|
||||||
|
let wrapper = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
|
||||||
|
wrapper.style.width = "160px";
|
||||||
|
wrapper.style.height = "90px";
|
||||||
|
wrapper.appendChild(canvas);
|
||||||
|
this._dndPanel.appendChild(wrapper);
|
||||||
|
document.documentElement.appendChild(this._dndPanel);
|
||||||
|
}
|
||||||
|
toDrag = this._dndPanel;
|
||||||
}
|
}
|
||||||
// PageThumb is async with e10s but that's fine
|
// PageThumb is async with e10s but that's fine
|
||||||
// since we can update the panel during the dnd.
|
// since we can update the image during the dnd.
|
||||||
PageThumbs.captureToCanvas(browser, canvas);
|
PageThumbs.captureToCanvas(browser, canvas, captureListener);
|
||||||
toDrag = this._dndPanel;
|
|
||||||
} else {
|
} else {
|
||||||
// For the non e10s case we can just use PageThumbs
|
// For the non e10s case we can just use PageThumbs
|
||||||
// sync. No need for xul magic, the native dnd will
|
// sync, so let's use the canvas for setDragImage.
|
||||||
// be fine, so let's use the canvas for setDragImage.
|
|
||||||
PageThumbs.captureToCanvas(browser, canvas);
|
PageThumbs.captureToCanvas(browser, canvas);
|
||||||
toDrag = canvas;
|
|
||||||
dragImageOffset = dragImageOffset * scale;
|
dragImageOffset = dragImageOffset * scale;
|
||||||
}
|
}
|
||||||
dt.setDragImage(toDrag, dragImageOffset, dragImageOffset);
|
dt.setDragImage(toDrag, dragImageOffset, dragImageOffset);
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
|
[DEFAULT]
|
||||||
|
support-files =
|
||||||
|
dummy_page.html
|
||||||
|
|
||||||
[browser_tabSpinnerProbe.js]
|
[browser_tabSpinnerProbe.js]
|
||||||
skip-if = !e10s # Tab spinner is e10s only.
|
skip-if = !e10s # Tab spinner is e10s only.
|
||||||
[browser_tabSwitchPrintPreview.js]
|
[browser_tabSwitchPrintPreview.js]
|
||||||
skip-if = os == 'mac'
|
skip-if = os == 'mac'
|
||||||
[browser_navigatePinnedTab.js]
|
[browser_navigatePinnedTab.js]
|
||||||
|
[browser_opened_file_tab_navigated_to_web.js]
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||||
|
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||||
|
|
||||||
|
const TEST_FILE = "dummy_page.html";
|
||||||
|
|
||||||
|
// Test for bug 1321020.
|
||||||
|
add_task(function* () {
|
||||||
|
let dir = getChromeDir(getResolvedURI(gTestPath));
|
||||||
|
dir.append(TEST_FILE);
|
||||||
|
const uriString = Services.io.newFileURI(dir).spec;
|
||||||
|
const openedUriString = uriString + "?opened";
|
||||||
|
|
||||||
|
// Open first file:// page.
|
||||||
|
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, uriString);
|
||||||
|
registerCleanupFunction(function* () {
|
||||||
|
yield BrowserTestUtils.removeTab(tab);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Open new file:// tab from JavaScript in first file:// page.
|
||||||
|
let promiseTabOpened = BrowserTestUtils.waitForNewTab(gBrowser, openedUriString);
|
||||||
|
yield ContentTask.spawn(tab.linkedBrowser, openedUriString, uri => {
|
||||||
|
content.open(uri, "_blank");
|
||||||
|
});
|
||||||
|
|
||||||
|
let openedTab = yield promiseTabOpened;
|
||||||
|
registerCleanupFunction(function* () {
|
||||||
|
yield BrowserTestUtils.removeTab(openedTab);
|
||||||
|
});
|
||||||
|
|
||||||
|
let openedBrowser = openedTab.linkedBrowser;
|
||||||
|
yield BrowserTestUtils.browserLoaded(openedBrowser);
|
||||||
|
|
||||||
|
// Ensure that new file:// tab can be navigated to web content.
|
||||||
|
openedBrowser.loadURI("http://example.org/");
|
||||||
|
let href = yield BrowserTestUtils.browserLoaded(openedBrowser);
|
||||||
|
is(href, "http://example.org/",
|
||||||
|
"Check that new file:// page has navigated successfully to web content");
|
||||||
|
});
|
|
@ -0,0 +1,9 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Dummy test page</title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"></meta>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>Dummy test page</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -7,8 +7,7 @@ MOZ_AUTOMATION_L10N_CHECK=0
|
||||||
|
|
||||||
ac_add_options --enable-optimize
|
ac_add_options --enable-optimize
|
||||||
|
|
||||||
#Work to make the clang-plugin work on Windows is ongoing in bug 1316545.
|
ac_add_options --enable-clang-plugin
|
||||||
#ac_add_options --enable-clang-plugin
|
|
||||||
|
|
||||||
. $topsrcdir/build/win32/mozconfig.vs-latest
|
. $topsrcdir/build/win32/mozconfig.vs-latest
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,7 @@ MOZ_AUTOMATION_L10N_CHECK=0
|
||||||
ac_add_options --enable-optimize
|
ac_add_options --enable-optimize
|
||||||
ac_add_options --enable-debug
|
ac_add_options --enable-debug
|
||||||
|
|
||||||
#Work to make the clang-plugin work on Windows is ongoing in bug 1316545.
|
ac_add_options --enable-clang-plugin
|
||||||
#ac_add_options --enable-clang-plugin
|
|
||||||
|
|
||||||
. $topsrcdir/build/win32/mozconfig.vs-latest
|
. $topsrcdir/build/win32/mozconfig.vs-latest
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,7 @@ ac_add_options --host=x86_64-pc-mingw32
|
||||||
|
|
||||||
ac_add_options --enable-optimize
|
ac_add_options --enable-optimize
|
||||||
|
|
||||||
#Work to make the clang-plugin work on Windows is ongoing in bug 1316545.
|
ac_add_options --enable-clang-plugin
|
||||||
#ac_add_options --enable-clang-plugin
|
|
||||||
|
|
||||||
. $topsrcdir/build/win64/mozconfig.vs-latest
|
. $topsrcdir/build/win64/mozconfig.vs-latest
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,7 @@ ac_add_options --host=x86_64-pc-mingw32
|
||||||
ac_add_options --enable-optimize
|
ac_add_options --enable-optimize
|
||||||
ac_add_options --enable-debug
|
ac_add_options --enable-debug
|
||||||
|
|
||||||
#Work to make the clang-plugin work on Windows is ongoing in bug 1316545.
|
ac_add_options --enable-clang-plugin
|
||||||
#ac_add_options --enable-clang-plugin
|
|
||||||
|
|
||||||
. $topsrcdir/build/win64/mozconfig.vs-latest
|
. $topsrcdir/build/win64/mozconfig.vs-latest
|
||||||
|
|
||||||
|
|
|
@ -526,7 +526,30 @@ protected:
|
||||||
// This doesn't check that it's really ::std::pair and not
|
// This doesn't check that it's really ::std::pair and not
|
||||||
// ::std::something_else::pair, but should be good enough.
|
// ::std::something_else::pair, but should be good enough.
|
||||||
StringRef Name = getNameChecked(D);
|
StringRef Name = getNameChecked(D);
|
||||||
if (Name == "pair" || Name == "atomic" || Name == "__atomic_base") {
|
if (Name == "pair" ||
|
||||||
|
Name == "atomic" ||
|
||||||
|
// libstdc++ specific names
|
||||||
|
Name == "__atomic_base" ||
|
||||||
|
Name == "atomic_bool" ||
|
||||||
|
// MSVCRT specific names
|
||||||
|
Name == "_Atomic_impl" ||
|
||||||
|
Name == "_Atomic_base" ||
|
||||||
|
Name == "_Atomic_bool" ||
|
||||||
|
Name == "_Atomic_char" ||
|
||||||
|
Name == "_Atomic_schar" ||
|
||||||
|
Name == "_Atomic_uchar" ||
|
||||||
|
Name == "_Atomic_char16_t" ||
|
||||||
|
Name == "_Atomic_char32_t" ||
|
||||||
|
Name == "_Atomic_wchar_t" ||
|
||||||
|
Name == "_Atomic_short" ||
|
||||||
|
Name == "_Atomic_ushort" ||
|
||||||
|
Name == "_Atomic_int" ||
|
||||||
|
Name == "_Atomic_uint" ||
|
||||||
|
Name == "_Atomic_long" ||
|
||||||
|
Name == "_Atomic_ulong" ||
|
||||||
|
Name == "_Atomic_llong" ||
|
||||||
|
Name == "_Atomic_ullong" ||
|
||||||
|
Name == "_Atomic_address") {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
// expected-no-diagnostics
|
||||||
|
|
||||||
|
#define MOZ_NEEDS_MEMMOVABLE_TYPE __attribute__((annotate("moz_needs_memmovable_type")))
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
class MOZ_NEEDS_MEMMOVABLE_TYPE Mover { T mForceInst; };
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <cstdint>
|
||||||
|
struct CustomType{};
|
||||||
|
static struct {
|
||||||
|
Mover<std::atomic<CustomType>> m1;
|
||||||
|
Mover<std::atomic<bool>> m2;
|
||||||
|
Mover<std::atomic<char>> m3;
|
||||||
|
Mover<std::atomic<signed char>> m4;
|
||||||
|
Mover<std::atomic<unsigned char>> m5;
|
||||||
|
Mover<std::atomic<char16_t>> m6;
|
||||||
|
Mover<std::atomic<char32_t>> m7;
|
||||||
|
Mover<std::atomic<wchar_t>> m8;
|
||||||
|
Mover<std::atomic<short>> m9;
|
||||||
|
Mover<std::atomic<unsigned short>> m10;
|
||||||
|
Mover<std::atomic<int>> m11;
|
||||||
|
Mover<std::atomic<unsigned int>> m12;
|
||||||
|
Mover<std::atomic<long>> m13;
|
||||||
|
Mover<std::atomic<unsigned long>> m14;
|
||||||
|
Mover<std::atomic<long long>> m15;
|
||||||
|
Mover<std::atomic<unsigned long long>> m16;
|
||||||
|
Mover<std::atomic<void*>> m17;
|
||||||
|
Mover<std::atomic<CustomType*>> m18;
|
||||||
|
} good;
|
|
@ -30,6 +30,7 @@ SOURCES += [
|
||||||
'TestNonHeapClass.cpp',
|
'TestNonHeapClass.cpp',
|
||||||
'TestNonMemMovable.cpp',
|
'TestNonMemMovable.cpp',
|
||||||
'TestNonMemMovableStd.cpp',
|
'TestNonMemMovableStd.cpp',
|
||||||
|
'TestNonMemMovableStdAtomic.cpp',
|
||||||
'TestNonParameterChecker.cpp',
|
'TestNonParameterChecker.cpp',
|
||||||
'TestNonTemporaryClass.cpp',
|
'TestNonTemporaryClass.cpp',
|
||||||
'TestNoRefcountedInsideLambdas.cpp',
|
'TestNoRefcountedInsideLambdas.cpp',
|
||||||
|
|
|
@ -702,9 +702,9 @@ def compiler(language, host_or_target, c_compiler=None, other_compiler=None,
|
||||||
# Check the compiler version here instead of in `compiler_version` so
|
# Check the compiler version here instead of in `compiler_version` so
|
||||||
# that the `checking` message doesn't pretend the compiler can be used
|
# that the `checking` message doesn't pretend the compiler can be used
|
||||||
# to then bail out one line later.
|
# to then bail out one line later.
|
||||||
if info.type == 'gcc' and info.version < '4.8.0':
|
if info.type == 'gcc' and info.version < '4.9.0':
|
||||||
raise FatalCheckError(
|
raise FatalCheckError(
|
||||||
'Only GCC 4.8 or newer is supported (found version %s).'
|
'Only GCC 4.9 or newer is supported (found version %s).'
|
||||||
% info.version)
|
% info.version)
|
||||||
|
|
||||||
# If you want to bump the version check here search for
|
# If you want to bump the version check here search for
|
||||||
|
|
|
@ -9,6 +9,7 @@ import subprocess
|
||||||
import sys
|
import sys
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
SOURCESTAMP_FILENAME = 'sourcestamp.txt'
|
||||||
|
|
||||||
def buildid_header(output):
|
def buildid_header(output):
|
||||||
buildid = os.environ.get('MOZ_BUILD_DATE')
|
buildid = os.environ.get('MOZ_BUILD_DATE')
|
||||||
|
@ -44,6 +45,26 @@ def get_hg_info(workdir):
|
||||||
def get_hg_changeset(path):
|
def get_hg_changeset(path):
|
||||||
return get_program_output('hg', '-R', path, 'parent', '--template={node}')
|
return get_program_output('hg', '-R', path, 'parent', '--template={node}')
|
||||||
|
|
||||||
|
def get_info_from_sourcestamp(sourcestamp_path):
|
||||||
|
"""Read the repository and changelog information from the sourcestamp
|
||||||
|
file. This assumes that the file exists and returns the results as a list
|
||||||
|
(either strings or None in case of error).
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Load the content of the file.
|
||||||
|
lines = None
|
||||||
|
with open(sourcestamp_path) as f:
|
||||||
|
lines = f.read().splitlines()
|
||||||
|
|
||||||
|
# Parse the repo and the changeset. The sourcestamp file is supposed to
|
||||||
|
# contain two lines: the first is the build id and the second is the source
|
||||||
|
# URL.
|
||||||
|
if len(lines) != 2 or not lines[1].startswith('http'):
|
||||||
|
# Just return if the file doesn't contain what we expect.
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
# Return the repo and the changeset.
|
||||||
|
return lines[1].split('/rev/')
|
||||||
|
|
||||||
def source_repo_header(output):
|
def source_repo_header(output):
|
||||||
# We allow the source repo and changeset to be specified via the
|
# We allow the source repo and changeset to be specified via the
|
||||||
|
@ -54,8 +75,11 @@ def source_repo_header(output):
|
||||||
source = ''
|
source = ''
|
||||||
|
|
||||||
if not repo:
|
if not repo:
|
||||||
|
sourcestamp_path = os.path.join(buildconfig.topsrcdir, SOURCESTAMP_FILENAME)
|
||||||
if os.path.exists(os.path.join(buildconfig.topsrcdir, '.hg')):
|
if os.path.exists(os.path.join(buildconfig.topsrcdir, '.hg')):
|
||||||
repo, changeset = get_hg_info(buildconfig.topsrcdir)
|
repo, changeset = get_hg_info(buildconfig.topsrcdir)
|
||||||
|
elif os.path.exists(sourcestamp_path):
|
||||||
|
repo, changeset = get_info_from_sourcestamp(sourcestamp_path)
|
||||||
elif not changeset:
|
elif not changeset:
|
||||||
changeset = get_hg_changeset(buildconfig.topsrcdir)
|
changeset = get_hg_changeset(buildconfig.topsrcdir)
|
||||||
if not changeset:
|
if not changeset:
|
||||||
|
|
|
@ -150,12 +150,10 @@ RulersHighlighter.prototype = {
|
||||||
} else {
|
} else {
|
||||||
dGraduations += `M${i} 0 L${i} ${graduationLength} `;
|
dGraduations += `M${i} 0 L${i} ${graduationLength} `;
|
||||||
}
|
}
|
||||||
|
} else if (i % 50 === 0) {
|
||||||
|
dMarkers += `M0 ${i} L${graduationLength} ${i}`;
|
||||||
} else {
|
} else {
|
||||||
if (i % 50 === 0) {
|
dGraduations += `M0 ${i} L${graduationLength} ${i}`;
|
||||||
dMarkers += `M0 ${i} L${graduationLength} ${i}`;
|
|
||||||
} else {
|
|
||||||
dGraduations += `M0 ${i} L${graduationLength} ${i}`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -245,7 +245,7 @@ function CanvasFrameAnonymousContentHelper(highlighterEnv, nodeBuilder) {
|
||||||
this._insert();
|
this._insert();
|
||||||
}
|
}
|
||||||
|
|
||||||
this._onWindowReady= this._onWindowReady.bind(this);
|
this._onWindowReady = this._onWindowReady.bind(this);
|
||||||
this.highlighterEnv.on("window-ready", this._onWindowReady);
|
this.highlighterEnv.on("window-ready", this._onWindowReady);
|
||||||
|
|
||||||
this.listeners = new Map();
|
this.listeners = new Map();
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { Ci, Cu } = require("chrome");
|
|
||||||
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
||||||
const { assert, fetch } = DevToolsUtils;
|
const { assert, fetch } = DevToolsUtils;
|
||||||
const EventEmitter = require("devtools/shared/event-emitter");
|
const EventEmitter = require("devtools/shared/event-emitter");
|
||||||
|
@ -137,18 +136,16 @@ TabSources.prototype = {
|
||||||
// is the HTML url.
|
// is the HTML url.
|
||||||
originalUrl = source.url;
|
originalUrl = source.url;
|
||||||
source = null;
|
source = null;
|
||||||
}
|
} else if (this._sourceActors.has(source)) {
|
||||||
else if (this._sourceActors.has(source)) {
|
|
||||||
return this._sourceActors.get(source);
|
return this._sourceActors.get(source);
|
||||||
}
|
}
|
||||||
}
|
} else if (originalUrl) {
|
||||||
else if (originalUrl) {
|
|
||||||
// Not all "original" scripts are distinctly separate from the
|
// Not all "original" scripts are distinctly separate from the
|
||||||
// generated script. Pretty-printed sources have a sourcemap for
|
// generated script. Pretty-printed sources have a sourcemap for
|
||||||
// themselves, so we need to make sure there a real source
|
// themselves, so we need to make sure there a real source
|
||||||
// doesn't already exist with this URL.
|
// doesn't already exist with this URL.
|
||||||
for (let [source, actor] of this._sourceActors) {
|
for (let [sourceData, actor] of this._sourceActors) {
|
||||||
if (source.url === originalUrl) {
|
if (sourceData.url === originalUrl) {
|
||||||
return actor;
|
return actor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,7 +165,7 @@ TabSources.prototype = {
|
||||||
});
|
});
|
||||||
|
|
||||||
let sourceActorStore = this._thread.sourceActorStore;
|
let sourceActorStore = this._thread.sourceActorStore;
|
||||||
var id = sourceActorStore.getReusableActorId(source, originalUrl);
|
let id = sourceActorStore.getReusableActorId(source, originalUrl);
|
||||||
if (id) {
|
if (id) {
|
||||||
actor.actorID = id;
|
actor.actorID = id;
|
||||||
}
|
}
|
||||||
|
@ -179,15 +176,13 @@ TabSources.prototype = {
|
||||||
if (this._autoBlackBox &&
|
if (this._autoBlackBox &&
|
||||||
!this.neverAutoBlackBoxSources.has(actor.url) &&
|
!this.neverAutoBlackBoxSources.has(actor.url) &&
|
||||||
this._isMinifiedURL(actor.url)) {
|
this._isMinifiedURL(actor.url)) {
|
||||||
|
|
||||||
this.blackBox(actor.url);
|
this.blackBox(actor.url);
|
||||||
this.neverAutoBlackBoxSources.add(actor.url);
|
this.neverAutoBlackBoxSources.add(actor.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source) {
|
if (source) {
|
||||||
this._sourceActors.set(source, actor);
|
this._sourceActors.set(source, actor);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
this._sourceMappedSourceActors[originalUrl] = actor;
|
this._sourceMappedSourceActors[originalUrl] = actor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,8 +196,7 @@ TabSources.prototype = {
|
||||||
// it's something that has been sourcemapped, or it represents
|
// it's something that has been sourcemapped, or it represents
|
||||||
// the HTML file that contains inline sources.
|
// the HTML file that contains inline sources.
|
||||||
this.emit("newSource", actor);
|
this.emit("newSource", actor);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// If sourcemapping is enabled and a source has sourcemaps, we
|
// If sourcemapping is enabled and a source has sourcemaps, we
|
||||||
// create `SourceActor` instances for both the original and
|
// create `SourceActor` instances for both the original and
|
||||||
// generated sources. The source actors for the generated
|
// generated sources. The source actors for the generated
|
||||||
|
@ -246,30 +240,29 @@ TabSources.prototype = {
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error("getSourceActorByURL: could not find source for " + url);
|
throw new Error("getSourceActorByURL: could not find source for " + url);
|
||||||
return null;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the URL likely points to a minified resource, false
|
* Returns true if the URL likely points to a minified resource, false
|
||||||
* otherwise.
|
* otherwise.
|
||||||
*
|
*
|
||||||
* @param String aURL
|
* @param String uri
|
||||||
* The URL to test.
|
* The url to test.
|
||||||
* @returns Boolean
|
* @returns Boolean
|
||||||
*/
|
*/
|
||||||
_isMinifiedURL: function (aURL) {
|
_isMinifiedURL: function (uri) {
|
||||||
if (!aURL) {
|
if (!uri) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let url = new URL(aURL);
|
let url = new URL(uri);
|
||||||
let pathname = url.pathname;
|
let pathname = url.pathname;
|
||||||
return MINIFIED_SOURCE_REGEXP.test(pathname.slice(pathname.lastIndexOf("/") + 1));
|
return MINIFIED_SOURCE_REGEXP.test(pathname.slice(pathname.lastIndexOf("/") + 1));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Not a valid URL so don't try to parse out the filename, just test the
|
// Not a valid URL so don't try to parse out the filename, just test the
|
||||||
// whole thing with the minified source regexp.
|
// whole thing with the minified source regexp.
|
||||||
return MINIFIED_SOURCE_REGEXP.test(aURL);
|
return MINIFIED_SOURCE_REGEXP.test(uri);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -278,19 +271,19 @@ TabSources.prototype = {
|
||||||
* source mapping and always returns an actor representing this real
|
* source mapping and always returns an actor representing this real
|
||||||
* source. Use `createSourceActors` if you want to respect source maps.
|
* source. Use `createSourceActors` if you want to respect source maps.
|
||||||
*
|
*
|
||||||
* @param Debugger.Source aSource
|
* @param Debugger.Source source
|
||||||
* The source instance to create an actor for.
|
* The source instance to create an actor for.
|
||||||
* @returns SourceActor
|
* @returns SourceActor
|
||||||
*/
|
*/
|
||||||
createNonSourceMappedActor: function (aSource) {
|
createNonSourceMappedActor: function (source) {
|
||||||
// Don't use getSourceURL because we don't want to consider the
|
// Don't use getSourceURL because we don't want to consider the
|
||||||
// displayURL property if it's an eval source. We only want to
|
// displayURL property if it's an eval source. We only want to
|
||||||
// consider real URLs, otherwise if there is a URL but it's
|
// consider real URLs, otherwise if there is a URL but it's
|
||||||
// invalid the code below will not set the content type, and we
|
// invalid the code below will not set the content type, and we
|
||||||
// will later try to fetch the contents of the URL to figure out
|
// will later try to fetch the contents of the URL to figure out
|
||||||
// the content type, but it's a made up URL for eval sources.
|
// the content type, but it's a made up URL for eval sources.
|
||||||
let url = isEvalSource(aSource) ? null : aSource.url;
|
let url = isEvalSource(source) ? null : source.url;
|
||||||
let spec = { source: aSource };
|
let spec = { source };
|
||||||
|
|
||||||
// XXX bug 915433: We can't rely on Debugger.Source.prototype.text
|
// XXX bug 915433: We can't rely on Debugger.Source.prototype.text
|
||||||
// if the source is an HTML-embedded <script> tag. Since we don't
|
// if the source is an HTML-embedded <script> tag. Since we don't
|
||||||
|
@ -301,51 +294,47 @@ TabSources.prototype = {
|
||||||
|
|
||||||
// Assume the source is inline if the element that introduced it is not a
|
// Assume the source is inline if the element that introduced it is not a
|
||||||
// script element, or does not have a src attribute.
|
// script element, or does not have a src attribute.
|
||||||
let element = aSource.element ? aSource.element.unsafeDereference() : null;
|
let element = source.element ? source.element.unsafeDereference() : null;
|
||||||
if (element && (element.tagName !== "SCRIPT" || !element.hasAttribute("src"))) {
|
if (element && (element.tagName !== "SCRIPT" || !element.hasAttribute("src"))) {
|
||||||
spec.isInlineSource = true;
|
spec.isInlineSource = true;
|
||||||
} else if (aSource.introductionType === "wasm") {
|
} else if (source.introductionType === "wasm") {
|
||||||
// Wasm sources are not JavaScript. Give them their own content-type.
|
// Wasm sources are not JavaScript. Give them their own content-type.
|
||||||
spec.contentType = "text/wasm";
|
spec.contentType = "text/wasm";
|
||||||
} else {
|
} else if (url) {
|
||||||
if (url) {
|
// There are a few special URLs that we know are JavaScript:
|
||||||
// There are a few special URLs that we know are JavaScript:
|
// inline `javascript:` and code coming from the console
|
||||||
// inline `javascript:` and code coming from the console
|
if (url.indexOf("Scratchpad/") === 0 ||
|
||||||
if (url.indexOf("Scratchpad/") === 0 ||
|
url.indexOf("javascript:") === 0 ||
|
||||||
url.indexOf("javascript:") === 0 ||
|
url === "debugger eval code") {
|
||||||
url === "debugger eval code") {
|
spec.contentType = "text/javascript";
|
||||||
spec.contentType = "text/javascript";
|
} else {
|
||||||
} else {
|
try {
|
||||||
try {
|
let pathname = new URL(url).pathname;
|
||||||
let pathname = new URL(url).pathname;
|
let filename = pathname.slice(pathname.lastIndexOf("/") + 1);
|
||||||
let filename = pathname.slice(pathname.lastIndexOf("/") + 1);
|
let index = filename.lastIndexOf(".");
|
||||||
let index = filename.lastIndexOf(".");
|
let extension = index >= 0 ? filename.slice(index + 1) : "";
|
||||||
let extension = index >= 0 ? filename.slice(index + 1) : "";
|
if (extension === "xml") {
|
||||||
if (extension === "xml") {
|
// XUL inline scripts may not correctly have the
|
||||||
// XUL inline scripts may not correctly have the
|
// `source.element` property, so do a blunt check here if
|
||||||
// `source.element` property, so do a blunt check here if
|
// it's an xml page.
|
||||||
// it's an xml page.
|
spec.isInlineSource = true;
|
||||||
spec.isInlineSource = true;
|
} else if (extension === "js") {
|
||||||
}
|
spec.contentType = "text/javascript";
|
||||||
else if (extension === "js") {
|
}
|
||||||
spec.contentType = "text/javascript";
|
} catch (e) {
|
||||||
}
|
// This only needs to be here because URL is not yet exposed to
|
||||||
} catch (e) {
|
// workers. (BUG 1258892)
|
||||||
// This only needs to be here because URL is not yet exposed to
|
const filename = url;
|
||||||
// workers. (BUG 1258892)
|
const index = filename.lastIndexOf(".");
|
||||||
const filename = url;
|
const extension = index >= 0 ? filename.slice(index + 1) : "";
|
||||||
const index = filename.lastIndexOf(".");
|
if (extension === "js") {
|
||||||
const extension = index >= 0 ? filename.slice(index + 1) : "";
|
spec.contentType = "text/javascript";
|
||||||
if (extension === "js") {
|
|
||||||
spec.contentType = "text/javascript";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
} else {
|
||||||
// Assume the content is javascript if there's no URL
|
// Assume the content is javascript if there's no URL
|
||||||
spec.contentType = "text/javascript";
|
spec.contentType = "text/javascript";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.source(spec);
|
return this.source(spec);
|
||||||
|
@ -354,24 +343,24 @@ TabSources.prototype = {
|
||||||
/**
|
/**
|
||||||
* This is an internal function that returns a promise of an array
|
* This is an internal function that returns a promise of an array
|
||||||
* of source actors representing all the source mapped sources of
|
* of source actors representing all the source mapped sources of
|
||||||
* `aSource`, or `null` if the source is not sourcemapped or
|
* `source`, or `null` if the source is not sourcemapped or
|
||||||
* sourcemapping is disabled. Users should call `createSourceActors`
|
* sourcemapping is disabled. Users should call `createSourceActors`
|
||||||
* instead of this.
|
* instead of this.
|
||||||
*
|
*
|
||||||
* @param Debugger.Source aSource
|
* @param Debugger.Source source
|
||||||
* The source instance to create actors for.
|
* The source instance to create actors for.
|
||||||
* @return Promise of an array of source actors
|
* @return Promise of an array of source actors
|
||||||
*/
|
*/
|
||||||
_createSourceMappedActors: function (aSource) {
|
_createSourceMappedActors: function (source) {
|
||||||
if (!this._useSourceMaps || !aSource.sourceMapURL) {
|
if (!this._useSourceMaps || !source.sourceMapURL) {
|
||||||
return resolve(null);
|
return resolve(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.fetchSourceMap(aSource)
|
return this.fetchSourceMap(source)
|
||||||
.then(map => {
|
.then(map => {
|
||||||
if (map) {
|
if (map) {
|
||||||
return map.sources.map(s => {
|
return map.sources.map(s => {
|
||||||
return this.source({ originalUrl: s, generatedSource: aSource });
|
return this.source({ originalUrl: s, generatedSource: source });
|
||||||
}).filter(isNotNull);
|
}).filter(isNotNull);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -380,97 +369,94 @@ TabSources.prototype = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the source actors representing the appropriate sources
|
* Creates the source actors representing the appropriate sources
|
||||||
* of `aSource`. If sourcemapped, returns actors for all of the original
|
* of `source`. If sourcemapped, returns actors for all of the original
|
||||||
* sources, otherwise returns a 1-element array with the actor for
|
* sources, otherwise returns a 1-element array with the actor for
|
||||||
* `aSource`.
|
* `source`.
|
||||||
*
|
*
|
||||||
* @param Debugger.Source aSource
|
* @param Debugger.Source source
|
||||||
* The source instance to create actors for.
|
* The source instance to create actors for.
|
||||||
* @param Promise of an array of source actors
|
* @param Promise of an array of source actors
|
||||||
*/
|
*/
|
||||||
createSourceActors: function (aSource) {
|
createSourceActors: function (source) {
|
||||||
return this._createSourceMappedActors(aSource).then(actors => {
|
return this._createSourceMappedActors(source).then(actors => {
|
||||||
let actor = this.createNonSourceMappedActor(aSource);
|
let actor = this.createNonSourceMappedActor(source);
|
||||||
return (actors || [actor]).filter(isNotNull);
|
return (actors || [actor]).filter(isNotNull);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a promise of a SourceMapConsumer for the source map for
|
* Return a promise of a SourceMapConsumer for the source map for
|
||||||
* `aSource`; if we already have such a promise extant, return that.
|
* `source`; if we already have such a promise extant, return that.
|
||||||
* This will fetch the source map if we don't have a cached object
|
* This will fetch the source map if we don't have a cached object
|
||||||
* and source maps are enabled (see `_fetchSourceMap`).
|
* and source maps are enabled (see `_fetchSourceMap`).
|
||||||
*
|
*
|
||||||
* @param Debugger.Source aSource
|
* @param Debugger.Source source
|
||||||
* The source instance to get sourcemaps for.
|
* The source instance to get sourcemaps for.
|
||||||
* @return Promise of a SourceMapConsumer
|
* @return Promise of a SourceMapConsumer
|
||||||
*/
|
*/
|
||||||
fetchSourceMap: function (aSource) {
|
fetchSourceMap: function (source) {
|
||||||
if (!this._useSourceMaps) {
|
if (!this._useSourceMaps) {
|
||||||
return resolve(null);
|
return resolve(null);
|
||||||
}
|
} else if (this._sourceMaps.has(source)) {
|
||||||
else if (this._sourceMaps.has(aSource)) {
|
return this._sourceMaps.get(source);
|
||||||
return this._sourceMaps.get(aSource);
|
} else if (!source || !source.sourceMapURL) {
|
||||||
}
|
|
||||||
else if (!aSource || !aSource.sourceMapURL) {
|
|
||||||
return resolve(null);
|
return resolve(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
let sourceMapURL = aSource.sourceMapURL;
|
let sourceMapURL = source.sourceMapURL;
|
||||||
if (aSource.url) {
|
if (source.url) {
|
||||||
sourceMapURL = joinURI(aSource.url, sourceMapURL);
|
sourceMapURL = joinURI(source.url, sourceMapURL);
|
||||||
}
|
}
|
||||||
let result = this._fetchSourceMap(sourceMapURL, aSource.url);
|
let result = this._fetchSourceMap(sourceMapURL, source.url);
|
||||||
|
|
||||||
// The promises in `_sourceMaps` must be the exact same instances
|
// The promises in `_sourceMaps` must be the exact same instances
|
||||||
// as returned by `_fetchSourceMap` for `clearSourceMapCache` to
|
// as returned by `_fetchSourceMap` for `clearSourceMapCache` to
|
||||||
// work.
|
// work.
|
||||||
this._sourceMaps.set(aSource, result);
|
this._sourceMaps.set(source, result);
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a promise of a SourceMapConsumer for the source map for
|
* Return a promise of a SourceMapConsumer for the source map for
|
||||||
* `aSource`. The resolved result may be null if the source does not
|
* `source`. The resolved result may be null if the source does not
|
||||||
* have a source map or source maps are disabled.
|
* have a source map or source maps are disabled.
|
||||||
*/
|
*/
|
||||||
getSourceMap: function (aSource) {
|
getSourceMap: function (source) {
|
||||||
return resolve(this._sourceMaps.get(aSource));
|
return resolve(this._sourceMaps.get(source));
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a SourceMapConsumer for the source map for
|
* Set a SourceMapConsumer for the source map for |source|.
|
||||||
* |aSource|.
|
|
||||||
*/
|
*/
|
||||||
setSourceMap: function (aSource, aMap) {
|
setSourceMap: function (source, map) {
|
||||||
this._sourceMaps.set(aSource, resolve(aMap));
|
this._sourceMaps.set(source, resolve(map));
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a promise of a SourceMapConsumer for the source map located at
|
* Return a promise of a SourceMapConsumer for the source map located at
|
||||||
* |aAbsSourceMapURL|, which must be absolute. If there is already such a
|
* |absSourceMapURL|, which must be absolute. If there is already such a
|
||||||
* promise extant, return it. This will not fetch if source maps are
|
* promise extant, return it. This will not fetch if source maps are
|
||||||
* disabled.
|
* disabled.
|
||||||
*
|
*
|
||||||
* @param string aAbsSourceMapURL
|
* @param string absSourceMapURL
|
||||||
* The source map URL, in absolute form, not relative.
|
* The source map URL, in absolute form, not relative.
|
||||||
* @param string aScriptURL
|
* @param string sourceURL
|
||||||
* When the source map URL is a data URI, there is no sourceRoot on the
|
* When the source map URL is a data URI, there is no sourceRoot on the
|
||||||
* source map, and the source map's sources are relative, we resolve
|
* source map, and the source map's sources are relative, we resolve
|
||||||
* them from aScriptURL.
|
* them from sourceURL.
|
||||||
*/
|
*/
|
||||||
_fetchSourceMap: function (aAbsSourceMapURL, aSourceURL) {
|
_fetchSourceMap: function (absSourceMapURL, sourceURL) {
|
||||||
assert(this._useSourceMaps,
|
assert(this._useSourceMaps,
|
||||||
"Cannot fetch sourcemaps if they are disabled");
|
"Cannot fetch sourcemaps if they are disabled");
|
||||||
|
|
||||||
if (this._sourceMapCache[aAbsSourceMapURL]) {
|
if (this._sourceMapCache[absSourceMapURL]) {
|
||||||
return this._sourceMapCache[aAbsSourceMapURL];
|
return this._sourceMapCache[absSourceMapURL];
|
||||||
}
|
}
|
||||||
|
|
||||||
let fetching = fetch(aAbsSourceMapURL, { loadFromCache: false })
|
let fetching = fetch(absSourceMapURL, { loadFromCache: false })
|
||||||
.then(({ content }) => {
|
.then(({ content }) => {
|
||||||
let map = new SourceMapConsumer(content);
|
let map = new SourceMapConsumer(content);
|
||||||
this._setSourceMapRoot(map, aAbsSourceMapURL, aSourceURL);
|
this._setSourceMapRoot(map, absSourceMapURL, sourceURL);
|
||||||
return map;
|
return map;
|
||||||
})
|
})
|
||||||
.then(null, error => {
|
.then(null, error => {
|
||||||
|
@ -479,31 +465,31 @@ TabSources.prototype = {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
this._sourceMapCache[aAbsSourceMapURL] = fetching;
|
this._sourceMapCache[absSourceMapURL] = fetching;
|
||||||
return fetching;
|
return fetching;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the source map's sourceRoot to be relative to the source map url.
|
* Sets the source map's sourceRoot to be relative to the source map url.
|
||||||
*/
|
*/
|
||||||
_setSourceMapRoot: function (aSourceMap, aAbsSourceMapURL, aScriptURL) {
|
_setSourceMapRoot: function (sourceMap, absSourceMapURL, scriptURL) {
|
||||||
// No need to do this fiddling if we won't be fetching any sources over the
|
// No need to do this fiddling if we won't be fetching any sources over the
|
||||||
// wire.
|
// wire.
|
||||||
if (aSourceMap.hasContentsOfAllSources()) {
|
if (sourceMap.hasContentsOfAllSources()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const base = this._dirname(
|
const base = this._dirname(
|
||||||
aAbsSourceMapURL.indexOf("data:") === 0
|
absSourceMapURL.indexOf("data:") === 0
|
||||||
? aScriptURL
|
? scriptURL
|
||||||
: aAbsSourceMapURL);
|
: absSourceMapURL);
|
||||||
aSourceMap.sourceRoot = aSourceMap.sourceRoot
|
sourceMap.sourceRoot = sourceMap.sourceRoot
|
||||||
? joinURI(base, aSourceMap.sourceRoot)
|
? joinURI(base, sourceMap.sourceRoot)
|
||||||
: base;
|
: base;
|
||||||
},
|
},
|
||||||
|
|
||||||
_dirname: function (aPath) {
|
_dirname: function (path) {
|
||||||
let url = new URL(aPath);
|
let url = new URL(path);
|
||||||
let href = url.href;
|
let href = url.href;
|
||||||
return href.slice(0, href.lastIndexOf("/"));
|
return href.slice(0, href.lastIndexOf("/"));
|
||||||
},
|
},
|
||||||
|
@ -516,18 +502,18 @@ TabSources.prototype = {
|
||||||
* this just removes the Debugger.Source cache, but you can remove
|
* this just removes the Debugger.Source cache, but you can remove
|
||||||
* the lower-level URL cache with the `hard` option.
|
* the lower-level URL cache with the `hard` option.
|
||||||
*
|
*
|
||||||
* @param aSourceMapURL string
|
* @param sourceMapURL string
|
||||||
* The source map URL to uncache
|
* The source map URL to uncache
|
||||||
* @param opts object
|
* @param opts object
|
||||||
* An object with the following properties:
|
* An object with the following properties:
|
||||||
* - hard: Also remove the lower-level URL cache, which will
|
* - hard: Also remove the lower-level URL cache, which will
|
||||||
* make us completely forget about the source map.
|
* make us completely forget about the source map.
|
||||||
*/
|
*/
|
||||||
clearSourceMapCache: function (aSourceMapURL, opts = { hard: false }) {
|
clearSourceMapCache: function (sourceMapURL, opts = { hard: false }) {
|
||||||
let oldSm = this._sourceMapCache[aSourceMapURL];
|
let oldSm = this._sourceMapCache[sourceMapURL];
|
||||||
|
|
||||||
if (opts.hard) {
|
if (opts.hard) {
|
||||||
delete this._sourceMapCache[aSourceMapURL];
|
delete this._sourceMapCache[sourceMapURL];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldSm) {
|
if (oldSm) {
|
||||||
|
@ -547,15 +533,14 @@ TabSources.prototype = {
|
||||||
* (pretty-printing is the use case). Generate a random url if one
|
* (pretty-printing is the use case). Generate a random url if one
|
||||||
* isn't specified, allowing you to set "anonymous" source maps.
|
* isn't specified, allowing you to set "anonymous" source maps.
|
||||||
*
|
*
|
||||||
* @param aSource Debugger.Source
|
* @param source Debugger.Source
|
||||||
* The source to change the sourceMapURL property
|
* The source to change the sourceMapURL property
|
||||||
* @param aUrl string
|
* @param url string
|
||||||
* The source map URL (optional)
|
* The source map URL (optional)
|
||||||
* @param aMap SourceMapConsumer
|
* @param map SourceMapConsumer
|
||||||
* The source map instance
|
* The source map instance
|
||||||
*/
|
*/
|
||||||
setSourceMapHard: function (aSource, aUrl, aMap) {
|
setSourceMapHard: function (source, url, map) {
|
||||||
let url = aUrl;
|
|
||||||
if (!url) {
|
if (!url) {
|
||||||
// This is a littly hacky, but we want to forcefully set a
|
// This is a littly hacky, but we want to forcefully set a
|
||||||
// sourcemap regardless of sourcemap settings. We want to
|
// sourcemap regardless of sourcemap settings. We want to
|
||||||
|
@ -566,31 +551,31 @@ TabSources.prototype = {
|
||||||
// just make a fake URL and stick the sourcemap there.
|
// just make a fake URL and stick the sourcemap there.
|
||||||
url = "internal://sourcemap" + (this._anonSourceMapId++) + "/";
|
url = "internal://sourcemap" + (this._anonSourceMapId++) + "/";
|
||||||
}
|
}
|
||||||
aSource.sourceMapURL = url;
|
source.sourceMapURL = url;
|
||||||
|
|
||||||
// Forcefully set the sourcemap cache. This will be used even if
|
// Forcefully set the sourcemap cache. This will be used even if
|
||||||
// sourcemaps are disabled.
|
// sourcemaps are disabled.
|
||||||
this._sourceMapCache[url] = resolve(aMap);
|
this._sourceMapCache[url] = resolve(map);
|
||||||
this.emit("updatedSource", this.getSourceActor(aSource));
|
this.emit("updatedSource", this.getSourceActor(source));
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the non-source-mapped location of the given Debugger.Frame. If the
|
* Return the non-source-mapped location of the given Debugger.Frame. If the
|
||||||
* frame does not have a script, the location's properties are all null.
|
* frame does not have a script, the location's properties are all null.
|
||||||
*
|
*
|
||||||
* @param Debugger.Frame aFrame
|
* @param Debugger.Frame frame
|
||||||
* The frame whose location we are getting.
|
* The frame whose location we are getting.
|
||||||
* @returns Object
|
* @returns Object
|
||||||
* Returns an object of the form { source, line, column }
|
* Returns an object of the form { source, line, column }
|
||||||
*/
|
*/
|
||||||
getFrameLocation: function (aFrame) {
|
getFrameLocation: function (frame) {
|
||||||
if (!aFrame || !aFrame.script) {
|
if (!frame || !frame.script) {
|
||||||
return new GeneratedLocation();
|
return new GeneratedLocation();
|
||||||
}
|
}
|
||||||
let {lineNumber, columnNumber} =
|
let {lineNumber, columnNumber} =
|
||||||
aFrame.script.getOffsetLocation(aFrame.offset);
|
frame.script.getOffsetLocation(frame.offset);
|
||||||
return new GeneratedLocation(
|
return new GeneratedLocation(
|
||||||
this.createNonSourceMappedActor(aFrame.script.source),
|
this.createNonSourceMappedActor(frame.script.source),
|
||||||
lineNumber,
|
lineNumber,
|
||||||
columnNumber
|
columnNumber
|
||||||
);
|
);
|
||||||
|
@ -610,7 +595,6 @@ TabSources.prototype = {
|
||||||
generatedColumn
|
generatedColumn
|
||||||
} = generatedLocation;
|
} = generatedLocation;
|
||||||
let source = generatedSourceActor.source;
|
let source = generatedSourceActor.source;
|
||||||
let url = source ? source.url : generatedSourceActor._originalUrl;
|
|
||||||
|
|
||||||
// In certain scenarios the source map may have not been fetched
|
// In certain scenarios the source map may have not been fetched
|
||||||
// yet (or at least tied to this Debugger.Source instance), so use
|
// yet (or at least tied to this Debugger.Source instance), so use
|
||||||
|
@ -684,7 +668,6 @@ TabSources.prototype = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a promise of the location in the generated source corresponding to
|
* Returns a promise of the location in the generated source corresponding to
|
||||||
* the original source and line given.
|
* the original source and line given.
|
||||||
|
@ -735,69 +718,69 @@ TabSources.prototype = {
|
||||||
/**
|
/**
|
||||||
* Returns true if URL for the given source is black boxed.
|
* Returns true if URL for the given source is black boxed.
|
||||||
*
|
*
|
||||||
* @param aURL String
|
* @param url String
|
||||||
* The URL of the source which we are checking whether it is black
|
* The URL of the source which we are checking whether it is black
|
||||||
* boxed or not.
|
* boxed or not.
|
||||||
*/
|
*/
|
||||||
isBlackBoxed: function (aURL) {
|
isBlackBoxed: function (url) {
|
||||||
return this.blackBoxedSources.has(aURL);
|
return this.blackBoxedSources.has(url);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the given source URL to the set of sources that are black boxed.
|
* Add the given source URL to the set of sources that are black boxed.
|
||||||
*
|
*
|
||||||
* @param aURL String
|
* @param url String
|
||||||
* The URL of the source which we are black boxing.
|
* The URL of the source which we are black boxing.
|
||||||
*/
|
*/
|
||||||
blackBox: function (aURL) {
|
blackBox: function (url) {
|
||||||
this.blackBoxedSources.add(aURL);
|
this.blackBoxedSources.add(url);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the given source URL to the set of sources that are black boxed.
|
* Remove the given source URL to the set of sources that are black boxed.
|
||||||
*
|
*
|
||||||
* @param aURL String
|
* @param url String
|
||||||
* The URL of the source which we are no longer black boxing.
|
* The URL of the source which we are no longer black boxing.
|
||||||
*/
|
*/
|
||||||
unblackBox: function (aURL) {
|
unblackBox: function (url) {
|
||||||
this.blackBoxedSources.delete(aURL);
|
this.blackBoxedSources.delete(url);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the given URL is pretty printed.
|
* Returns true if the given URL is pretty printed.
|
||||||
*
|
*
|
||||||
* @param aURL String
|
* @param url String
|
||||||
* The URL of the source that might be pretty printed.
|
* The URL of the source that might be pretty printed.
|
||||||
*/
|
*/
|
||||||
isPrettyPrinted: function (aURL) {
|
isPrettyPrinted: function (url) {
|
||||||
return this.prettyPrintedSources.has(aURL);
|
return this.prettyPrintedSources.has(url);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the given URL to the set of sources that are pretty printed.
|
* Add the given URL to the set of sources that are pretty printed.
|
||||||
*
|
*
|
||||||
* @param aURL String
|
* @param url String
|
||||||
* The URL of the source to be pretty printed.
|
* The URL of the source to be pretty printed.
|
||||||
*/
|
*/
|
||||||
prettyPrint: function (aURL, aIndent) {
|
prettyPrint: function (url, indent) {
|
||||||
this.prettyPrintedSources.set(aURL, aIndent);
|
this.prettyPrintedSources.set(url, indent);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the indent the given URL was pretty printed by.
|
* Return the indent the given URL was pretty printed by.
|
||||||
*/
|
*/
|
||||||
prettyPrintIndent: function (aURL) {
|
prettyPrintIndent: function (url) {
|
||||||
return this.prettyPrintedSources.get(aURL);
|
return this.prettyPrintedSources.get(url);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the given URL from the set of sources that are pretty printed.
|
* Remove the given URL from the set of sources that are pretty printed.
|
||||||
*
|
*
|
||||||
* @param aURL String
|
* @param url String
|
||||||
* The URL of the source that is no longer pretty printed.
|
* The URL of the source that is no longer pretty printed.
|
||||||
*/
|
*/
|
||||||
disablePrettyPrint: function (aURL) {
|
disablePrettyPrint: function (url) {
|
||||||
this.prettyPrintedSources.delete(aURL);
|
this.prettyPrintedSources.delete(url);
|
||||||
},
|
},
|
||||||
|
|
||||||
iter: function () {
|
iter: function () {
|
||||||
|
@ -817,16 +800,16 @@ TabSources.prototype = {
|
||||||
* Checks if a source should never be displayed to the user because
|
* Checks if a source should never be displayed to the user because
|
||||||
* it's either internal or we don't support in the UI yet.
|
* it's either internal or we don't support in the UI yet.
|
||||||
*/
|
*/
|
||||||
function isHiddenSource(aSource) {
|
function isHiddenSource(source) {
|
||||||
// Ignore the internal Function.prototype script
|
// Ignore the internal Function.prototype script
|
||||||
return aSource.text === "() {\n}";
|
return source.text === "() {\n}";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if its argument is not null.
|
* Returns true if its argument is not null.
|
||||||
*/
|
*/
|
||||||
function isNotNull(aThing) {
|
function isNotNull(thing) {
|
||||||
return aThing !== null;
|
return thing !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.TabSources = TabSources;
|
exports.TabSources = TabSources;
|
||||||
|
|
|
@ -6,10 +6,9 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var { Cu, CC, Ci, Cc } = require("chrome");
|
const { Cu, CC } = require("chrome");
|
||||||
|
|
||||||
const { DebuggerServer } = require("devtools/server/main");
|
const { DebuggerServer } = require("devtools/server/main");
|
||||||
const promise = require("promise");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Support for actor registration. Main used by ActorRegistryActor
|
* Support for actor registration. Main used by ActorRegistryActor
|
||||||
|
|
|
@ -24,7 +24,10 @@ const GRAPHENE_ID = "{d1bfe7d9-c01e-4237-998b-7b5f960a4314}";
|
||||||
*/
|
*/
|
||||||
if (!Services.appinfo
|
if (!Services.appinfo
|
||||||
|| Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT
|
|| Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT
|
||||||
|| Services.appinfo.ID === undefined /* XPCShell */
|
|
||||||
|
/* XPCShell */
|
||||||
|
|| Services.appinfo.ID === undefined
|
||||||
|
|
||||||
|| Services.appinfo.ID == B2G_ID
|
|| Services.appinfo.ID == B2G_ID
|
||||||
|| Services.appinfo.ID == GRAPHENE_ID
|
|| Services.appinfo.ID == GRAPHENE_ID
|
||||||
|| !AddonPathService) {
|
|| !AddonPathService) {
|
||||||
|
@ -35,8 +38,7 @@ if (!Services.appinfo
|
||||||
module.exports = function mapURIToAddonId(uri) {
|
module.exports = function mapURIToAddonId(uri) {
|
||||||
try {
|
try {
|
||||||
return AddonPathService.mapURIToAddonId(uri);
|
return AddonPathService.mapURIToAddonId(uri);
|
||||||
}
|
} catch (e) {
|
||||||
catch (e) {
|
|
||||||
DevToolsUtils.reportException("mapURIToAddonId", e);
|
DevToolsUtils.reportException("mapURIToAddonId", e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,6 @@
|
||||||
* matched.
|
* matched.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const {Ci, Cu} = require("chrome");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The WalkerIndex class indexes the document (and all subdocs) from
|
* The WalkerIndex class indexes the document (and all subdocs) from
|
||||||
* a given walker.
|
* a given walker.
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
const {Cc, Ci, Cu, components} = require("chrome");
|
"use strict";
|
||||||
|
|
||||||
|
const {Cc, Ci, components} = require("chrome");
|
||||||
const {isWindowIncluded} = require("devtools/shared/layout/utils");
|
const {isWindowIncluded} = require("devtools/shared/layout/utils");
|
||||||
const Services = require("Services");
|
const Services = require("Services");
|
||||||
const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
|
const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
|
@ -31,8 +36,7 @@ function ConsoleServiceListener(window, listener) {
|
||||||
}
|
}
|
||||||
exports.ConsoleServiceListener = ConsoleServiceListener;
|
exports.ConsoleServiceListener = ConsoleServiceListener;
|
||||||
|
|
||||||
ConsoleServiceListener.prototype =
|
ConsoleServiceListener.prototype = {
|
||||||
{
|
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIConsoleListener]),
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIConsoleListener]),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -196,8 +200,7 @@ function ConsoleAPIListener(window, owner, {addonId} = {}) {
|
||||||
}
|
}
|
||||||
exports.ConsoleAPIListener = ConsoleAPIListener;
|
exports.ConsoleAPIListener = ConsoleAPIListener;
|
||||||
|
|
||||||
ConsoleAPIListener.prototype =
|
ConsoleAPIListener.prototype = {
|
||||||
{
|
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -384,8 +387,7 @@ function ConsoleReflowListener(window, listener) {
|
||||||
|
|
||||||
exports.ConsoleReflowListener = ConsoleReflowListener;
|
exports.ConsoleReflowListener = ConsoleReflowListener;
|
||||||
|
|
||||||
ConsoleReflowListener.prototype =
|
ConsoleReflowListener.prototype = {
|
||||||
{
|
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver,
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver,
|
||||||
Ci.nsISupportsWeakReference]),
|
Ci.nsISupportsWeakReference]),
|
||||||
docshell: null,
|
docshell: null,
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const {Cc, Ci, Cu, components} = require("chrome");
|
const {Ci, Cu} = require("chrome");
|
||||||
|
|
||||||
// Note that this is only used in WebConsoleCommands, see $0 and pprint().
|
// Note that this is only used in WebConsoleCommands, see $0 and pprint().
|
||||||
if (!isWorker) {
|
if (!isWorker) {
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
/* global setConsoleEventHandler, retrieveConsoleEvents */
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// This file is loaded on the server side for worker debugging.
|
// This file is loaded on the server side for worker debugging.
|
||||||
|
@ -18,18 +20,17 @@ function ConsoleAPIListener(window, owner, consoleID) {
|
||||||
this.observe = this.observe.bind(this);
|
this.observe = this.observe.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConsoleAPIListener.prototype =
|
ConsoleAPIListener.prototype = {
|
||||||
{
|
|
||||||
init: function () {
|
init: function () {
|
||||||
setConsoleEventHandler(this.observe);
|
setConsoleEventHandler(this.observe);
|
||||||
},
|
},
|
||||||
destroy: function () {
|
destroy: function () {
|
||||||
setConsoleEventHandler(null);
|
setConsoleEventHandler(null);
|
||||||
},
|
},
|
||||||
observe: function(message) {
|
observe: function (message) {
|
||||||
this.owner.onConsoleAPICall(message.wrappedJSObject);
|
this.owner.onConsoleAPICall(message.wrappedJSObject);
|
||||||
},
|
},
|
||||||
getCachedMessages: function() {
|
getCachedMessages: function () {
|
||||||
return retrieveConsoleEvents();
|
return retrieveConsoleEvents();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -34,8 +34,9 @@ exports.removeContentGlobal = function (options) {
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
function getGlobalCache(aInnerWindowID) {
|
function getGlobalCache(innerWindowID) {
|
||||||
return globalsCache[aInnerWindowID] = globalsCache[aInnerWindowID] || [];
|
globalsCache[innerWindowID] = globalsCache[innerWindowID] || [];
|
||||||
|
return globalsCache[innerWindowID];
|
||||||
}
|
}
|
||||||
|
|
||||||
// when the window is destroyed, eliminate the associated globals cache
|
// when the window is destroyed, eliminate the associated globals cache
|
||||||
|
|
|
@ -4,10 +4,9 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const Ci = Components.interfaces;
|
const { utils: Cu, interfaces: Ci } = Components;
|
||||||
const Cc = Components.classes;
|
|
||||||
const Cu = Components.utils;
|
|
||||||
|
|
||||||
|
/* exported init */
|
||||||
this.EXPORTED_SYMBOLS = ["init"];
|
this.EXPORTED_SYMBOLS = ["init"];
|
||||||
|
|
||||||
let gLoader;
|
let gLoader;
|
||||||
|
|
|
@ -149,8 +149,9 @@ var parsers = [
|
||||||
const MAX_NESTED_HANDLER_COUNT = 2;
|
const MAX_NESTED_HANDLER_COUNT = 2;
|
||||||
for (let i = 0; i < MAX_NESTED_HANDLER_COUNT; i++) {
|
for (let i = 0; i < MAX_NESTED_HANDLER_COUNT; i++) {
|
||||||
let funcDO = getFirstFunctionVariable(handlerDO);
|
let funcDO = getFirstFunctionVariable(handlerDO);
|
||||||
if (!funcDO)
|
if (!funcDO) {
|
||||||
return handlerDO;
|
return handlerDO;
|
||||||
|
}
|
||||||
|
|
||||||
handlerDO = funcDO;
|
handlerDO = funcDO;
|
||||||
if (isFunctionInProxy(handlerDO)) {
|
if (isFunctionInProxy(handlerDO)) {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { on, once, off, emit } = require("sdk/event/core");
|
const { on, off } = require("sdk/event/core");
|
||||||
const { Class } = require("sdk/core/heritage");
|
const { Class } = require("sdk/core/heritage");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -11,7 +11,7 @@ const { Class } = require("sdk/core/heritage");
|
||||||
* and monitors framerate over time. The actor wrapper around this
|
* and monitors framerate over time. The actor wrapper around this
|
||||||
* can be found at devtools/server/actors/framerate.js
|
* can be found at devtools/server/actors/framerate.js
|
||||||
*/
|
*/
|
||||||
var Framerate = exports.Framerate = Class({
|
exports.Framerate = Class({
|
||||||
initialize: function (tabActor) {
|
initialize: function (tabActor) {
|
||||||
this.tabActor = tabActor;
|
this.tabActor = tabActor;
|
||||||
this._contentWin = tabActor.window;
|
this._contentWin = tabActor.window;
|
||||||
|
|
|
@ -32,7 +32,7 @@ loader.lazyRequireGetter(this, "ChildProcessActor",
|
||||||
* send information over RDP, and TimelineActor for using more light-weight
|
* send information over RDP, and TimelineActor for using more light-weight
|
||||||
* utilities like GC events and measuring memory consumption.
|
* utilities like GC events and measuring memory consumption.
|
||||||
*/
|
*/
|
||||||
var Memory = exports.Memory = Class({
|
exports.Memory = Class({
|
||||||
extends: EventTarget,
|
extends: EventTarget,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -148,9 +148,12 @@ var Memory = exports.Memory = Class({
|
||||||
// If we are observing the whole process, then scope the snapshot
|
// If we are observing the whole process, then scope the snapshot
|
||||||
// accordingly. Otherwise, use the debugger's debuggees.
|
// accordingly. Otherwise, use the debugger's debuggees.
|
||||||
if (!boundaries) {
|
if (!boundaries) {
|
||||||
boundaries = this.parent instanceof ChromeActor || this.parent instanceof ChildProcessActor
|
if (this.parent instanceof ChromeActor ||
|
||||||
? { runtime: true }
|
this.parent instanceof ChildProcessActor) {
|
||||||
: { debugger: this.dbg };
|
boundaries = { runtime: true };
|
||||||
|
} else {
|
||||||
|
boundaries = { debugger: this.dbg };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const path = ThreadSafeChromeUtils.saveHeapSnapshot(boundaries);
|
const path = ThreadSafeChromeUtils.saveHeapSnapshot(boundaries);
|
||||||
return HeapSnapshotFileUtils.getSnapshotIdFromPath(path);
|
return HeapSnapshotFileUtils.getSnapshotIdFromPath(path);
|
||||||
|
@ -168,16 +171,16 @@ var Memory = exports.Memory = Class({
|
||||||
* Start recording allocation sites.
|
* Start recording allocation sites.
|
||||||
*
|
*
|
||||||
* @param {number} options.probability
|
* @param {number} options.probability
|
||||||
* The probability we sample any given allocation when recording allocations.
|
* The probability we sample any given allocation when recording
|
||||||
* Must be between 0 and 1 -- defaults to 1.
|
* allocations. Must be between 0 and 1 -- defaults to 1.
|
||||||
* @param {number} options.maxLogLength
|
* @param {number} options.maxLogLength
|
||||||
* The maximum number of allocation events to keep in the
|
* The maximum number of allocation events to keep in the
|
||||||
* log. If new allocs occur while at capacity, oldest
|
* log. If new allocs occur while at capacity, oldest
|
||||||
* allocations are lost. Must fit in a 32 bit signed integer.
|
* allocations are lost. Must fit in a 32 bit signed integer.
|
||||||
* @param {number} options.drainAllocationsTimeout
|
* @param {number} options.drainAllocationsTimeout
|
||||||
* A number in milliseconds of how often, at least, an `allocation` event
|
* A number in milliseconds of how often, at least, an `allocation`
|
||||||
* gets emitted (and drained), and also emits and drains on every GC event,
|
* event gets emitted (and drained), and also emits and drains on every
|
||||||
* resetting the timer.
|
* GC event, resetting the timer.
|
||||||
*/
|
*/
|
||||||
startRecordingAllocations: expectState("attached", function (options = {}) {
|
startRecordingAllocations: expectState("attached", function (options = {}) {
|
||||||
if (this.isRecordingAllocations()) {
|
if (this.isRecordingAllocations()) {
|
||||||
|
@ -190,13 +193,14 @@ var Memory = exports.Memory = Class({
|
||||||
? options.probability
|
? options.probability
|
||||||
: 1.0;
|
: 1.0;
|
||||||
|
|
||||||
this.drainAllocationsTimeoutTimer = typeof options.drainAllocationsTimeout === "number" ? options.drainAllocationsTimeout : null;
|
this.drainAllocationsTimeoutTimer = options.drainAllocationsTimeout;
|
||||||
|
|
||||||
if (this.drainAllocationsTimeoutTimer != null) {
|
if (this.drainAllocationsTimeoutTimer != null) {
|
||||||
if (this._poller) {
|
if (this._poller) {
|
||||||
this._poller.disarm();
|
this._poller.disarm();
|
||||||
}
|
}
|
||||||
this._poller = new DeferredTask(this._emitAllocations, this.drainAllocationsTimeoutTimer);
|
this._poller = new DeferredTask(this._emitAllocations,
|
||||||
|
this.drainAllocationsTimeoutTimer);
|
||||||
this._poller.arm();
|
this._poller.arm();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,7 +266,8 @@ var Memory = exports.Memory = Class({
|
||||||
* line: <line number for this frame>,
|
* line: <line number for this frame>,
|
||||||
* column: <column number for this frame>,
|
* column: <column number for this frame>,
|
||||||
* source: <filename string for this frame>,
|
* source: <filename string for this frame>,
|
||||||
* functionDisplayName: <this frame's inferred function name function or null>,
|
* functionDisplayName:
|
||||||
|
* <this frame's inferred function name function or null>,
|
||||||
* parent: <index into "frames">
|
* parent: <index into "frames">
|
||||||
* },
|
* },
|
||||||
* ...
|
* ...
|
||||||
|
@ -369,7 +374,8 @@ var Memory = exports.Memory = Class({
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this._mgr.sizeOfTab(this.parent.window, jsObjectsSize, jsStringsSize, jsOtherSize,
|
this._mgr.sizeOfTab(this.parent.window, jsObjectsSize, jsStringsSize, jsOtherSize,
|
||||||
domSize, styleSize, otherSize, totalSize, jsMilliseconds, nonJSMilliseconds);
|
domSize, styleSize, otherSize, totalSize, jsMilliseconds,
|
||||||
|
nonJSMilliseconds);
|
||||||
result.total = totalSize.value;
|
result.total = totalSize.value;
|
||||||
result.domSize = domSize.value;
|
result.domSize = domSize.value;
|
||||||
result.styleSize = styleSize.value;
|
result.styleSize = styleSize.value;
|
||||||
|
@ -404,10 +410,10 @@ var Memory = exports.Memory = Class({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called on `drainAllocationsTimeoutTimer` interval if and only if set during `startRecordingAllocations`,
|
* Called on `drainAllocationsTimeoutTimer` interval if and only if set
|
||||||
* or on a garbage collection event if drainAllocationsTimeout was set.
|
* during `startRecordingAllocations`, or on a garbage collection event if
|
||||||
|
* drainAllocationsTimeout was set.
|
||||||
* Drains allocation log and emits as an event and restarts the timer.
|
* Drains allocation log and emits as an event and restarts the timer.
|
||||||
*/
|
*/
|
||||||
_emitAllocations: function () {
|
_emitAllocations: function () {
|
||||||
|
@ -419,7 +425,8 @@ var Memory = exports.Memory = Class({
|
||||||
* Accesses the docshell to return the current process time.
|
* Accesses the docshell to return the current process time.
|
||||||
*/
|
*/
|
||||||
_getCurrentTime: function () {
|
_getCurrentTime: function () {
|
||||||
return (this.parent.isRootActor ? this.parent.docShell : this.parent.originalDocShell).now();
|
return (this.parent.isRootActor ? this.parent.docShell :
|
||||||
|
this.parent.originalDocShell).now();
|
||||||
},
|
},
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -19,8 +19,8 @@ const PROFILER_SYSTEM_EVENTS = [
|
||||||
"profiler-stopped"
|
"profiler-stopped"
|
||||||
];
|
];
|
||||||
|
|
||||||
// How often the "profiler-status" is emitted by default
|
// How often the "profiler-status" is emitted by default (in ms)
|
||||||
const BUFFER_STATUS_INTERVAL_DEFAULT = 5000; // ms
|
const BUFFER_STATUS_INTERVAL_DEFAULT = 5000;
|
||||||
|
|
||||||
loader.lazyGetter(this, "nsIProfilerModule", () => {
|
loader.lazyGetter(this, "nsIProfilerModule", () => {
|
||||||
return Cc["@mozilla.org/tools/profiler;1"].getService(Ci.nsIProfiler);
|
return Cc["@mozilla.org/tools/profiler;1"].getService(Ci.nsIProfiler);
|
||||||
|
@ -174,12 +174,12 @@ const ProfilerManager = (function () {
|
||||||
*
|
*
|
||||||
* @param number startTime
|
* @param number startTime
|
||||||
* Since the circular buffer will only grow as long as the profiler lives,
|
* Since the circular buffer will only grow as long as the profiler lives,
|
||||||
* the buffer can contain unwanted samples. Pass in a `startTime` to only retrieve
|
* the buffer can contain unwanted samples. Pass in a `startTime` to only
|
||||||
* samples that took place after the `startTime`, with 0 being when the profiler
|
* retrieve samples that took place after the `startTime`, with 0 being
|
||||||
* just started.
|
* when the profiler just started.
|
||||||
* @param boolean stringify
|
* @param boolean stringify
|
||||||
* Whether or not the returned profile object should be a string or not to save
|
* Whether or not the returned profile object should be a string or not to
|
||||||
* JSON parse/stringify cycle if emitting over RDP.
|
* save JSON parse/stringify cycle if emitting over RDP.
|
||||||
*/
|
*/
|
||||||
getProfile: function (options) {
|
getProfile: function (options) {
|
||||||
let startTime = options.startTime || 0;
|
let startTime = options.startTime || 0;
|
||||||
|
@ -238,7 +238,13 @@ const ProfilerManager = (function () {
|
||||||
let isActive = nsIProfilerModule.IsActive();
|
let isActive = nsIProfilerModule.IsActive();
|
||||||
let elapsedTime = isActive ? nsIProfilerModule.getElapsedTime() : undefined;
|
let elapsedTime = isActive ? nsIProfilerModule.getElapsedTime() : undefined;
|
||||||
let { position, totalSize, generation } = this.getBufferInfo();
|
let { position, totalSize, generation } = this.getBufferInfo();
|
||||||
return { isActive: isActive, currentTime: elapsedTime, position, totalSize, generation };
|
return {
|
||||||
|
isActive,
|
||||||
|
currentTime: elapsedTime,
|
||||||
|
position,
|
||||||
|
totalSize,
|
||||||
|
generation
|
||||||
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -247,7 +253,9 @@ const ProfilerManager = (function () {
|
||||||
* profiler is stopped.
|
* profiler is stopped.
|
||||||
*/
|
*/
|
||||||
getSharedLibraryInformation: function () {
|
getSharedLibraryInformation: function () {
|
||||||
return { sharedLibraryInformation: nsIProfilerModule.getSharedLibraryInformation() };
|
return {
|
||||||
|
sharedLibraryInformation: nsIProfilerModule.getSharedLibraryInformation()
|
||||||
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -276,7 +284,8 @@ const ProfilerManager = (function () {
|
||||||
// If the event was generated from `console.profile` or `console.profileEnd`
|
// If the event was generated from `console.profile` or `console.profileEnd`
|
||||||
// we need to start the profiler right away and then just notify the client.
|
// we need to start the profiler right away and then just notify the client.
|
||||||
// Otherwise, we'll lose precious samples.
|
// Otherwise, we'll lose precious samples.
|
||||||
if (topic === "console-api-profiler" && (action === "profile" || action === "profileEnd")) {
|
if (topic === "console-api-profiler" &&
|
||||||
|
(action === "profile" || action === "profileEnd")) {
|
||||||
let { isActive, currentTime } = this.isActive();
|
let { isActive, currentTime } = this.isActive();
|
||||||
|
|
||||||
// Start the profiler only if it wasn't already active. Otherwise, any
|
// Start the profiler only if it wasn't already active. Otherwise, any
|
||||||
|
@ -284,10 +293,9 @@ const ProfilerManager = (function () {
|
||||||
if (!isActive && action === "profile") {
|
if (!isActive && action === "profile") {
|
||||||
this.start();
|
this.start();
|
||||||
details = { profileLabel, currentTime: 0 };
|
details = { profileLabel, currentTime: 0 };
|
||||||
}
|
} else if (!isActive) {
|
||||||
// Otherwise, if inactive and a call to profile end, do nothing
|
// Otherwise, if inactive and a call to profile end, do nothing
|
||||||
// and don't emit event.
|
// and don't emit event.
|
||||||
else if (!isActive) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,7 +348,9 @@ const ProfilerManager = (function () {
|
||||||
* @param {object} data
|
* @param {object} data
|
||||||
*/
|
*/
|
||||||
emitEvent: function (eventName, data) {
|
emitEvent: function (eventName, data) {
|
||||||
let subscribers = Array.from(consumers).filter(c => c.subscribedEvents.has(eventName));
|
let subscribers = Array.from(consumers).filter(c => {
|
||||||
|
return c.subscribedEvents.has(eventName);
|
||||||
|
});
|
||||||
|
|
||||||
for (let subscriber of subscribers) {
|
for (let subscriber of subscribers) {
|
||||||
events.emit(subscriber, eventName, data);
|
events.emit(subscriber, eventName, data);
|
||||||
|
@ -377,12 +387,12 @@ const ProfilerManager = (function () {
|
||||||
_updateProfilerStatusPolling: function () {
|
_updateProfilerStatusPolling: function () {
|
||||||
if (this._profilerStatusSubscribers > 0 && nsIProfilerModule.IsActive()) {
|
if (this._profilerStatusSubscribers > 0 && nsIProfilerModule.IsActive()) {
|
||||||
if (!this._poller) {
|
if (!this._poller) {
|
||||||
this._poller = new DeferredTask(this._emitProfilerStatus.bind(this), this._profilerStatusInterval);
|
this._poller = new DeferredTask(this._emitProfilerStatus.bind(this),
|
||||||
|
this._profilerStatusInterval);
|
||||||
}
|
}
|
||||||
this._poller.arm();
|
this._poller.arm();
|
||||||
}
|
} else if (this._poller) {
|
||||||
// No subscribers; turn off if it exists.
|
// No subscribers; turn off if it exists.
|
||||||
else if (this._poller) {
|
|
||||||
this._poller.disarm();
|
this._poller.disarm();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -414,47 +424,65 @@ var Profiler = exports.Profiler = Class({
|
||||||
/**
|
/**
|
||||||
* @see ProfilerManager.start
|
* @see ProfilerManager.start
|
||||||
*/
|
*/
|
||||||
start: function (options) { return ProfilerManager.start(options); },
|
start: function (options) {
|
||||||
|
return ProfilerManager.start(options);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see ProfilerManager.stop
|
* @see ProfilerManager.stop
|
||||||
*/
|
*/
|
||||||
stop: function () { return ProfilerManager.stop(); },
|
stop: function () {
|
||||||
|
return ProfilerManager.stop();
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see ProfilerManager.getProfile
|
* @see ProfilerManager.getProfile
|
||||||
*/
|
*/
|
||||||
getProfile: function (request = {}) { return ProfilerManager.getProfile(request); },
|
getProfile: function (request = {}) {
|
||||||
|
return ProfilerManager.getProfile(request);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see ProfilerManager.getFeatures
|
* @see ProfilerManager.getFeatures
|
||||||
*/
|
*/
|
||||||
getFeatures: function () { return ProfilerManager.getFeatures(); },
|
getFeatures: function () {
|
||||||
|
return ProfilerManager.getFeatures();
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see ProfilerManager.getBufferInfo
|
* @see ProfilerManager.getBufferInfo
|
||||||
*/
|
*/
|
||||||
getBufferInfo: function () { return ProfilerManager.getBufferInfo(); },
|
getBufferInfo: function () {
|
||||||
|
return ProfilerManager.getBufferInfo();
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see ProfilerManager.getStartOptions
|
* @see ProfilerManager.getStartOptions
|
||||||
*/
|
*/
|
||||||
getStartOptions: function () { return ProfilerManager.getStartOptions(); },
|
getStartOptions: function () {
|
||||||
|
return ProfilerManager.getStartOptions();
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see ProfilerManager.isActive
|
* @see ProfilerManager.isActive
|
||||||
*/
|
*/
|
||||||
isActive: function () { return ProfilerManager.isActive(); },
|
isActive: function () {
|
||||||
|
return ProfilerManager.isActive();
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see ProfilerManager.isActive
|
* @see ProfilerManager.isActive
|
||||||
*/
|
*/
|
||||||
getSharedLibraryInformation: function () { return ProfilerManager.getSharedLibraryInformation(); },
|
getSharedLibraryInformation: function () {
|
||||||
|
return ProfilerManager.getSharedLibraryInformation();
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see ProfilerManager.setProfilerStatusInterval
|
* @see ProfilerManager.setProfilerStatusInterval
|
||||||
*/
|
*/
|
||||||
setProfilerStatusInterval: function (interval) { return ProfilerManager.setProfilerStatusInterval(interval); },
|
setProfilerStatusInterval: function (interval) {
|
||||||
|
return ProfilerManager.setProfilerStatusInterval(interval);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subscribes this instance to one of several events defined in
|
* Subscribes this instance to one of several events defined in
|
||||||
|
@ -535,7 +563,8 @@ function cycleBreaker(key, value) {
|
||||||
*/
|
*/
|
||||||
function sanitizeHandler(handler, identifier) {
|
function sanitizeHandler(handler, identifier) {
|
||||||
return DevToolsUtils.makeInfallible(function (subject, topic, data) {
|
return DevToolsUtils.makeInfallible(function (subject, topic, data) {
|
||||||
subject = (subject && !Cu.isXrayWrapper(subject) && subject.wrappedJSObject) || subject;
|
subject = (subject && !Cu.isXrayWrapper(subject) && subject.wrappedJSObject)
|
||||||
|
|| subject;
|
||||||
subject = JSON.parse(JSON.stringify(subject, cycleBreaker));
|
subject = JSON.parse(JSON.stringify(subject, cycleBreaker));
|
||||||
data = (data && !Cu.isXrayWrapper(data) && data.wrappedJSObject) || data;
|
data = (data && !Cu.isXrayWrapper(data) && data.wrappedJSObject) || data;
|
||||||
data = JSON.parse(JSON.stringify(data, cycleBreaker));
|
data = JSON.parse(JSON.stringify(data, cycleBreaker));
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { Cc, Ci, Cu, Cr } = require("chrome");
|
const { Cu } = require("chrome");
|
||||||
const { Task } = require("devtools/shared/task");
|
const { Task } = require("devtools/shared/task");
|
||||||
|
|
||||||
loader.lazyRequireGetter(this, "Services");
|
loader.lazyRequireGetter(this, "Services");
|
||||||
|
@ -52,7 +52,7 @@ const DRAIN_ALLOCATIONS_TIMEOUT = 2000;
|
||||||
* @param Target target
|
* @param Target target
|
||||||
* The target owning this connection.
|
* The target owning this connection.
|
||||||
*/
|
*/
|
||||||
const PerformanceRecorder = exports.PerformanceRecorder = Class({
|
exports.PerformanceRecorder = Class({
|
||||||
extends: EventTarget,
|
extends: EventTarget,
|
||||||
|
|
||||||
initialize: function (conn, tabActor) {
|
initialize: function (conn, tabActor) {
|
||||||
|
@ -171,7 +171,7 @@ const PerformanceRecorder = exports.PerformanceRecorder = Class({
|
||||||
* The time (in milliseconds) when the call was made, relative to when
|
* The time (in milliseconds) when the call was made, relative to when
|
||||||
* the nsIProfiler module was started.
|
* the nsIProfiler module was started.
|
||||||
*/
|
*/
|
||||||
_onConsoleProfileStart: Task.async(function* ({ profileLabel, currentTime: startTime }) {
|
_onConsoleProfileStart: Task.async(function* ({ profileLabel, currentTime }) {
|
||||||
let recordings = this._recordings;
|
let recordings = this._recordings;
|
||||||
|
|
||||||
// Abort if a profile with this label already exists.
|
// Abort if a profile with this label already exists.
|
||||||
|
@ -183,7 +183,7 @@ const PerformanceRecorder = exports.PerformanceRecorder = Class({
|
||||||
// expecting a recording very soon.
|
// expecting a recording very soon.
|
||||||
events.emit(this, "console-profile-start");
|
events.emit(this, "console-profile-start");
|
||||||
|
|
||||||
let model = yield this.startRecording(extend({}, getPerformanceRecordingPrefs(), {
|
yield this.startRecording(extend({}, getPerformanceRecordingPrefs(), {
|
||||||
console: true,
|
console: true,
|
||||||
label: profileLabel
|
label: profileLabel
|
||||||
}));
|
}));
|
||||||
|
@ -204,7 +204,7 @@ const PerformanceRecorder = exports.PerformanceRecorder = Class({
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let { profileLabel, currentTime: endTime } = data;
|
let { profileLabel } = data;
|
||||||
|
|
||||||
let pending = this._recordings.filter(r => r.isConsole() && r.isRecording());
|
let pending = this._recordings.filter(r => r.isConsole() && r.isRecording());
|
||||||
if (pending.length === 0) {
|
if (pending.length === 0) {
|
||||||
|
@ -216,16 +216,16 @@ const PerformanceRecorder = exports.PerformanceRecorder = Class({
|
||||||
// a label was used in profileEnd(). If no matches, abort.
|
// a label was used in profileEnd(). If no matches, abort.
|
||||||
if (profileLabel) {
|
if (profileLabel) {
|
||||||
model = pending.find(e => e.getLabel() === profileLabel);
|
model = pending.find(e => e.getLabel() === profileLabel);
|
||||||
}
|
} else {
|
||||||
// If no label supplied, pop off the most recent pending console recording
|
// If no label supplied, pop off the most recent pending console recording
|
||||||
else {
|
|
||||||
model = pending[pending.length - 1];
|
model = pending[pending.length - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
// If `profileEnd()` was called with a label, and there are no matching
|
// If `profileEnd()` was called with a label, and there are no matching
|
||||||
// sessions, abort.
|
// sessions, abort.
|
||||||
if (!model) {
|
if (!model) {
|
||||||
Cu.reportError("console.profileEnd() called with label that does not match a recording.");
|
Cu.reportError(
|
||||||
|
"console.profileEnd() called with label that does not match a recording.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,7 +291,7 @@ const PerformanceRecorder = exports.PerformanceRecorder = Class({
|
||||||
let reasons = [];
|
let reasons = [];
|
||||||
|
|
||||||
if (!Profiler.canProfile()) {
|
if (!Profiler.canProfile()) {
|
||||||
success = false,
|
success = false;
|
||||||
reasons.push("profiler-unavailable");
|
reasons.push("profiler-unavailable");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,7 +326,9 @@ const PerformanceRecorder = exports.PerformanceRecorder = Class({
|
||||||
if (data.isActive) {
|
if (data.isActive) {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
let startData = yield this._profiler.start(mapRecordingOptions("profiler", options));
|
let startData = yield this._profiler.start(
|
||||||
|
mapRecordingOptions("profiler", options)
|
||||||
|
);
|
||||||
|
|
||||||
// If no current time is exposed from starting, set it to 0 -- this is an
|
// If no current time is exposed from starting, set it to 0 -- this is an
|
||||||
// older Gecko that does not return its starting time, and uses an epoch based
|
// older Gecko that does not return its starting time, and uses an epoch based
|
||||||
|
@ -347,9 +349,10 @@ const PerformanceRecorder = exports.PerformanceRecorder = Class({
|
||||||
if (this._memory.getState() === "detached") {
|
if (this._memory.getState() === "detached") {
|
||||||
this._memory.attach();
|
this._memory.attach();
|
||||||
}
|
}
|
||||||
memoryStart = this._memory.startRecordingAllocations(extend(mapRecordingOptions("memory", options), {
|
let recordingOptions = extend(mapRecordingOptions("memory", options), {
|
||||||
drainAllocationsTimeout: DRAIN_ALLOCATIONS_TIMEOUT
|
drainAllocationsTimeout: DRAIN_ALLOCATIONS_TIMEOUT
|
||||||
}));
|
});
|
||||||
|
memoryStart = this._memory.startRecordingAllocations(recordingOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
let [profilerStartData, timelineStartData, memoryStartData] = yield promise.all([
|
let [profilerStartData, timelineStartData, memoryStartData] = yield promise.all([
|
||||||
|
@ -359,7 +362,11 @@ const PerformanceRecorder = exports.PerformanceRecorder = Class({
|
||||||
let data = Object.create(null);
|
let data = Object.create(null);
|
||||||
// Filter out start times that are not actually used (0 or undefined), and
|
// Filter out start times that are not actually used (0 or undefined), and
|
||||||
// find the earliest time since all sources use same epoch.
|
// find the earliest time since all sources use same epoch.
|
||||||
let startTimes = [profilerStartData.currentTime, memoryStartData, timelineStartData].filter(Boolean);
|
let startTimes = [
|
||||||
|
profilerStartData.currentTime,
|
||||||
|
memoryStartData,
|
||||||
|
timelineStartData
|
||||||
|
].filter(Boolean);
|
||||||
data.startTime = Math.min(...startTimes);
|
data.startTime = Math.min(...startTimes);
|
||||||
data.position = profilerStartData.position;
|
data.position = profilerStartData.position;
|
||||||
data.generation = profilerStartData.generation;
|
data.generation = profilerStartData.generation;
|
||||||
|
@ -379,7 +386,8 @@ const PerformanceRecorder = exports.PerformanceRecorder = Class({
|
||||||
* Manually ends the recording session for the corresponding PerformanceRecording.
|
* Manually ends the recording session for the corresponding PerformanceRecording.
|
||||||
*
|
*
|
||||||
* @param PerformanceRecording model
|
* @param PerformanceRecording model
|
||||||
* The corresponding PerformanceRecording that belongs to the recording session wished to stop.
|
* The corresponding PerformanceRecording that belongs to the recording
|
||||||
|
* session wished to stop.
|
||||||
* @return PerformanceRecording
|
* @return PerformanceRecording
|
||||||
* Returns the same model, populated with the profiling data.
|
* Returns the same model, populated with the profiling data.
|
||||||
*/
|
*/
|
||||||
|
@ -394,7 +402,6 @@ const PerformanceRecorder = exports.PerformanceRecorder = Class({
|
||||||
// Flag the recording as no longer recording, so that `model.isRecording()`
|
// Flag the recording as no longer recording, so that `model.isRecording()`
|
||||||
// is false. Do this before we fetch all the data, and then subsequently
|
// is false. Do this before we fetch all the data, and then subsequently
|
||||||
// the recording can be considered "completed".
|
// the recording can be considered "completed".
|
||||||
let endTime = Date.now();
|
|
||||||
events.emit(this, "recording-stopping", model);
|
events.emit(this, "recording-stopping", model);
|
||||||
|
|
||||||
// Currently there are two ways profiles stop recording. Either manually in the
|
// Currently there are two ways profiles stop recording. Either manually in the
|
||||||
|
@ -480,15 +487,19 @@ const PerformanceRecorder = exports.PerformanceRecorder = Class({
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an object of configurations based off of preferences for a PerformanceRecording.
|
* Creates an object of configurations based off of
|
||||||
|
* preferences for a PerformanceRecording.
|
||||||
*/
|
*/
|
||||||
function getPerformanceRecordingPrefs() {
|
function getPerformanceRecordingPrefs() {
|
||||||
return {
|
return {
|
||||||
withMarkers: true,
|
withMarkers: true,
|
||||||
withMemory: Services.prefs.getBoolPref("devtools.performance.ui.enable-memory"),
|
withMemory: Services.prefs.getBoolPref("devtools.performance.ui.enable-memory"),
|
||||||
withTicks: Services.prefs.getBoolPref("devtools.performance.ui.enable-framerate"),
|
withTicks: Services.prefs.getBoolPref("devtools.performance.ui.enable-framerate"),
|
||||||
withAllocations: Services.prefs.getBoolPref("devtools.performance.ui.enable-allocations"),
|
withAllocations:
|
||||||
allocationsSampleProbability: +Services.prefs.getCharPref("devtools.performance.memory.sample-probability"),
|
Services.prefs.getBoolPref("devtools.performance.ui.enable-allocations"),
|
||||||
allocationsMaxLogLength: Services.prefs.getIntPref("devtools.performance.memory.max-log-length")
|
allocationsSampleProbability:
|
||||||
|
+Services.prefs.getCharPref("devtools.performance.memory.sample-probability"),
|
||||||
|
allocationsMaxLogLength:
|
||||||
|
Services.prefs.getIntPref("devtools.performance.memory.max-log-length")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,13 +33,13 @@ loader.lazyRequireGetter(this, "EventTarget", "sdk/event/target", true);
|
||||||
|
|
||||||
// How often do we pull markers from the docShells, and therefore, how often do
|
// How often do we pull markers from the docShells, and therefore, how often do
|
||||||
// we send events to the front (knowing that when there are no markers in the
|
// we send events to the front (knowing that when there are no markers in the
|
||||||
// docShell, no event is sent).
|
// docShell, no event is sent). In milliseconds.
|
||||||
const DEFAULT_TIMELINE_DATA_PULL_TIMEOUT = 200; // ms
|
const DEFAULT_TIMELINE_DATA_PULL_TIMEOUT = 200;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The timeline actor pops and forwards timeline markers registered in docshells.
|
* The timeline actor pops and forwards timeline markers registered in docshells.
|
||||||
*/
|
*/
|
||||||
var Timeline = exports.Timeline = Class({
|
exports.Timeline = Class({
|
||||||
extends: EventTarget,
|
extends: EventTarget,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -135,7 +135,9 @@ var Timeline = exports.Timeline = Class({
|
||||||
marker.stack = this._stackFrames.addFrame(Cu.waiveXrays(marker.stack));
|
marker.stack = this._stackFrames.addFrame(Cu.waiveXrays(marker.stack));
|
||||||
}
|
}
|
||||||
if (marker.endStack) {
|
if (marker.endStack) {
|
||||||
marker.endStack = this._stackFrames.addFrame(Cu.waiveXrays(marker.endStack));
|
marker.endStack = this._stackFrames.addFrame(
|
||||||
|
Cu.waiveXrays(marker.endStack)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,11 +332,13 @@ var Timeline = exports.Timeline = Class({
|
||||||
* take the data and make it look like the rest of our markers.
|
* take the data and make it look like the rest of our markers.
|
||||||
*
|
*
|
||||||
* A GC "marker" here represents a full GC cycle, which may contain several incremental
|
* A GC "marker" here represents a full GC cycle, which may contain several incremental
|
||||||
* events within its `collection` array. The marker contains a `reason` field, indicating
|
* events within its `collection` array. The marker contains a `reason` field,
|
||||||
* why there was a GC, and may contain a `nonincrementalReason` when SpiderMonkey could
|
* indicating why there was a GC, and may contain a `nonincrementalReason` when
|
||||||
* not incrementally collect garbage.
|
* SpiderMonkey could not incrementally collect garbage.
|
||||||
*/
|
*/
|
||||||
_onGarbageCollection: function ({ collections, gcCycleNumber, reason, nonincrementalReason }) {
|
_onGarbageCollection: function ({
|
||||||
|
collections, gcCycleNumber, reason, nonincrementalReason
|
||||||
|
}) {
|
||||||
let docShells = this.docShells;
|
let docShells = this.docShells;
|
||||||
if (!this._isRecording || !docShells.length) {
|
if (!this._isRecording || !docShells.length) {
|
||||||
return;
|
return;
|
||||||
|
@ -342,7 +346,9 @@ var Timeline = exports.Timeline = Class({
|
||||||
|
|
||||||
let endTime = docShells[0].now();
|
let endTime = docShells[0].now();
|
||||||
|
|
||||||
events.emit(this, "markers", collections.map(({ startTimestamp: start, endTimestamp: end }) => {
|
events.emit(this, "markers", collections.map(({
|
||||||
|
startTimestamp: start, endTimestamp: end
|
||||||
|
}) => {
|
||||||
return {
|
return {
|
||||||
name: "GarbageCollection",
|
name: "GarbageCollection",
|
||||||
causeName: reason,
|
causeName: reason,
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { on, once, off, emit } = require("sdk/event/core");
|
|
||||||
const { Class } = require("sdk/core/heritage");
|
const { Class } = require("sdk/core/heritage");
|
||||||
|
|
||||||
const WebGLPrimitivesType = {
|
const WebGLPrimitivesType = {
|
||||||
|
@ -23,7 +22,7 @@ const WebGLPrimitivesType = {
|
||||||
const WebGLDrawArrays = "drawArrays";
|
const WebGLDrawArrays = "drawArrays";
|
||||||
const WebGLDrawElements = "drawElements";
|
const WebGLDrawElements = "drawElements";
|
||||||
|
|
||||||
var WebGLPrimitiveCounter = exports.WebGLPrimitiveCounter = Class({
|
exports.WebGLPrimitiveCounter = Class({
|
||||||
initialize: function (tabActor) {
|
initialize: function (tabActor) {
|
||||||
this.tabActor = tabActor;
|
this.tabActor = tabActor;
|
||||||
},
|
},
|
||||||
|
@ -45,7 +44,7 @@ var WebGLPrimitiveCounter = exports.WebGLPrimitiveCounter = Class({
|
||||||
* Stops monitoring primitive draws, returning the recorded values.
|
* Stops monitoring primitive draws, returning the recorded values.
|
||||||
*/
|
*/
|
||||||
getCounts: function () {
|
getCounts: function () {
|
||||||
var result = {
|
let result = {
|
||||||
tris: this._tris,
|
tris: this._tris,
|
||||||
vertices: this._vertices,
|
vertices: this._vertices,
|
||||||
points: this._points,
|
points: this._points,
|
||||||
|
@ -155,6 +154,7 @@ var WebGLPrimitiveCounter = exports.WebGLPrimitiveCounter = Class({
|
||||||
case WebGLPrimitivesType.TRIANGLE_FAN:
|
case WebGLPrimitivesType.TRIANGLE_FAN:
|
||||||
this._tris += (count - 2);
|
this._tris += (count - 2);
|
||||||
this._vertices += count;
|
this._vertices += count;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
console.error("_processDrawElements doesn't define this type.");
|
console.error("_processDrawElements doesn't define this type.");
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -2,11 +2,13 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
/* global addMessageListener */
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
let { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
let { classes: Cc, interfaces: Ci } = Components;
|
||||||
let swm = Cc["@mozilla.org/serviceworkers/manager;1"].
|
let swm = Cc["@mozilla.org/serviceworkers/manager;1"]
|
||||||
getService(Ci.nsIServiceWorkerManager);
|
.getService(Ci.nsIServiceWorkerManager);
|
||||||
|
|
||||||
addMessageListener("serviceWorkerRegistration:start", message => {
|
addMessageListener("serviceWorkerRegistration:start", message => {
|
||||||
let { data } = message;
|
let { data } = message;
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
/* eslint-env worker */
|
||||||
|
/* global worker, loadSubScript, global */
|
||||||
|
|
||||||
// This function is used to do remote procedure calls from the worker to the
|
// This function is used to do remote procedure calls from the worker to the
|
||||||
// main thread. It is exposed as a built-in global to every module by the
|
// main thread. It is exposed as a built-in global to every module by the
|
||||||
// worker loader. To make sure the worker loader can access it, it needs to be
|
// worker loader. To make sure the worker loader can access it, it needs to be
|
||||||
|
@ -42,14 +49,14 @@ this.addEventListener("message", function (event) {
|
||||||
let packet = JSON.parse(event.data);
|
let packet = JSON.parse(event.data);
|
||||||
switch (packet.type) {
|
switch (packet.type) {
|
||||||
case "connect":
|
case "connect":
|
||||||
// Step 3: Create a connection to the parent.
|
// Step 3: Create a connection to the parent.
|
||||||
let connection = DebuggerServer.connectToParent(packet.id, this);
|
let connection = DebuggerServer.connectToParent(packet.id, this);
|
||||||
connections[packet.id] = {
|
connections[packet.id] = {
|
||||||
connection : connection,
|
connection,
|
||||||
rpcs: []
|
rpcs: []
|
||||||
};
|
};
|
||||||
|
|
||||||
// Step 4: Create a thread actor for the connection to the parent.
|
// Step 4: Create a thread actor for the connection to the parent.
|
||||||
let pool = new ActorPool(connection);
|
let pool = new ActorPool(connection);
|
||||||
connection.addActorPool(pool);
|
connection.addActorPool(pool);
|
||||||
|
|
||||||
|
@ -87,8 +94,8 @@ this.addEventListener("message", function (event) {
|
||||||
let consoleActor = new WebConsoleActor(connection, parent);
|
let consoleActor = new WebConsoleActor(connection, parent);
|
||||||
pool.addActor(consoleActor);
|
pool.addActor(consoleActor);
|
||||||
|
|
||||||
// Step 5: Send a response packet to the parent to notify
|
// Step 5: Send a response packet to the parent to notify
|
||||||
// it that a connection has been established.
|
// it that a connection has been established.
|
||||||
postMessage(JSON.stringify({
|
postMessage(JSON.stringify({
|
||||||
type: "connected",
|
type: "connected",
|
||||||
id: packet.id,
|
id: packet.id,
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "mozilla/dom/Dispatcher.h"
|
#include "mozilla/dom/Dispatcher.h"
|
||||||
#include "mozilla/Move.h"
|
#include "mozilla/Move.h"
|
||||||
#include "nsINamed.h"
|
#include "nsINamed.h"
|
||||||
|
#include "nsQueryObject.h"
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
|
|
||||||
|
@ -28,21 +29,27 @@ DispatcherTrait::Dispatch(const char* aName,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<nsIEventTarget>
|
nsIEventTarget*
|
||||||
DispatcherTrait::EventTargetFor(TaskCategory aCategory) const
|
DispatcherTrait::EventTargetFor(TaskCategory aCategory) const
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIEventTarget> main = do_GetMainThread();
|
nsCOMPtr<nsIEventTarget> main = do_GetMainThread();
|
||||||
return main.forget();
|
return main;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
#define NS_DISPATCHEREVENTTARGET_IID \
|
||||||
|
{ 0xbf4e36c8, 0x7d04, 0x4ef4, \
|
||||||
|
{ 0xbb, 0xd8, 0x11, 0x09, 0x0a, 0xdb, 0x4d, 0xf7 } }
|
||||||
|
|
||||||
class DispatcherEventTarget final : public nsIEventTarget
|
class DispatcherEventTarget final : public nsIEventTarget
|
||||||
{
|
{
|
||||||
RefPtr<dom::Dispatcher> mDispatcher;
|
RefPtr<dom::Dispatcher> mDispatcher;
|
||||||
TaskCategory mCategory;
|
TaskCategory mCategory;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
NS_DECLARE_STATIC_IID_ACCESSOR(NS_DISPATCHEREVENTTARGET_IID)
|
||||||
|
|
||||||
DispatcherEventTarget(dom::Dispatcher* aDispatcher, TaskCategory aCategory)
|
DispatcherEventTarget(dom::Dispatcher* aDispatcher, TaskCategory aCategory)
|
||||||
: mDispatcher(aDispatcher)
|
: mDispatcher(aDispatcher)
|
||||||
, mCategory(aCategory)
|
, mCategory(aCategory)
|
||||||
|
@ -57,9 +64,11 @@ private:
|
||||||
virtual ~DispatcherEventTarget() {}
|
virtual ~DispatcherEventTarget() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
NS_DEFINE_STATIC_IID_ACCESSOR(DispatcherEventTarget, NS_DISPATCHEREVENTTARGET_IID)
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS(DispatcherEventTarget, nsIEventTarget)
|
NS_IMPL_ISUPPORTS(DispatcherEventTarget, DispatcherEventTarget, nsIEventTarget)
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
DispatcherEventTarget::DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags)
|
DispatcherEventTarget::DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags)
|
||||||
|
@ -96,3 +105,13 @@ Dispatcher::CreateEventTargetFor(TaskCategory aCategory)
|
||||||
new DispatcherEventTarget(this, aCategory);
|
new DispatcherEventTarget(this, aCategory);
|
||||||
return target.forget();
|
return target.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* static */ Dispatcher*
|
||||||
|
Dispatcher::FromEventTarget(nsIEventTarget* aEventTarget)
|
||||||
|
{
|
||||||
|
RefPtr<DispatcherEventTarget> target = do_QueryObject(aEventTarget);
|
||||||
|
if (!target) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return target->Dispatcher();
|
||||||
|
}
|
||||||
|
|
|
@ -16,6 +16,9 @@ class nsIRunnable;
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
|
class TabGroup;
|
||||||
|
class DocGroup;
|
||||||
|
|
||||||
enum class TaskCategory {
|
enum class TaskCategory {
|
||||||
// User input (clicks, keypresses, etc.)
|
// User input (clicks, keypresses, etc.)
|
||||||
UI,
|
UI,
|
||||||
|
@ -26,6 +29,9 @@ enum class TaskCategory {
|
||||||
// setTimeout, setInterval
|
// setTimeout, setInterval
|
||||||
Timer,
|
Timer,
|
||||||
|
|
||||||
|
// Runnables posted from a worker to the main thread
|
||||||
|
Worker,
|
||||||
|
|
||||||
// requestIdleCallback
|
// requestIdleCallback
|
||||||
IdleCallback,
|
IdleCallback,
|
||||||
|
|
||||||
|
@ -53,8 +59,7 @@ public:
|
||||||
// This method may or may not be safe off of the main thread. For nsIDocument
|
// This method may or may not be safe off of the main thread. For nsIDocument
|
||||||
// it is safe. For nsIGlobalWindow it is not safe. The nsIEventTarget can
|
// it is safe. For nsIGlobalWindow it is not safe. The nsIEventTarget can
|
||||||
// always be used off the main thread.
|
// always be used off the main thread.
|
||||||
virtual already_AddRefed<nsIEventTarget>
|
virtual nsIEventTarget* EventTargetFor(TaskCategory aCategory) const;
|
||||||
EventTargetFor(TaskCategory aCategory) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Base class for DocGroup and TabGroup.
|
// Base class for DocGroup and TabGroup.
|
||||||
|
@ -67,12 +72,17 @@ public:
|
||||||
|
|
||||||
// This method is always safe to call off the main thread. The nsIEventTarget
|
// This method is always safe to call off the main thread. The nsIEventTarget
|
||||||
// can always be used off the main thread.
|
// can always be used off the main thread.
|
||||||
virtual already_AddRefed<nsIEventTarget>
|
virtual nsIEventTarget* EventTargetFor(TaskCategory aCategory) const = 0;
|
||||||
EventTargetFor(TaskCategory aCategory) const = 0;
|
|
||||||
|
// These methods perform a safe cast. They return null if |this| is not of the
|
||||||
|
// requested type.
|
||||||
|
virtual TabGroup* AsTabGroup() { return nullptr; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual already_AddRefed<nsIEventTarget>
|
virtual already_AddRefed<nsIEventTarget>
|
||||||
CreateEventTargetFor(TaskCategory aCategory);
|
CreateEventTargetFor(TaskCategory aCategory);
|
||||||
|
|
||||||
|
static Dispatcher* FromEventTarget(nsIEventTarget* aEventTarget);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
|
|
|
@ -63,7 +63,7 @@ DocGroup::Dispatch(const char* aName,
|
||||||
return mTabGroup->Dispatch(aName, aCategory, Move(aRunnable));
|
return mTabGroup->Dispatch(aName, aCategory, Move(aRunnable));
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<nsIEventTarget>
|
nsIEventTarget*
|
||||||
DocGroup::EventTargetFor(TaskCategory aCategory) const
|
DocGroup::EventTargetFor(TaskCategory aCategory) const
|
||||||
{
|
{
|
||||||
return mTabGroup->EventTargetFor(aCategory);
|
return mTabGroup->EventTargetFor(aCategory);
|
||||||
|
|
|
@ -69,8 +69,7 @@ public:
|
||||||
TaskCategory aCategory,
|
TaskCategory aCategory,
|
||||||
already_AddRefed<nsIRunnable>&& aRunnable) override;
|
already_AddRefed<nsIRunnable>&& aRunnable) override;
|
||||||
|
|
||||||
virtual already_AddRefed<nsIEventTarget>
|
virtual nsIEventTarget* EventTargetFor(TaskCategory aCategory) const override;
|
||||||
EventTargetFor(TaskCategory aCategory) const override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DocGroup(TabGroup* aTabGroup, const nsACString& aKey);
|
DocGroup(TabGroup* aTabGroup, const nsACString& aKey);
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
|
|
||||||
#include "mozilla/dom/TabGroup.h"
|
#include "mozilla/dom/TabGroup.h"
|
||||||
|
|
||||||
|
#include "mozilla/dom/ContentChild.h"
|
||||||
|
#include "mozilla/dom/TabChild.h"
|
||||||
#include "mozilla/dom/DocGroup.h"
|
#include "mozilla/dom/DocGroup.h"
|
||||||
#include "mozilla/ClearOnShutdown.h"
|
#include "mozilla/ClearOnShutdown.h"
|
||||||
#include "mozilla/StaticPtr.h"
|
#include "mozilla/StaticPtr.h"
|
||||||
|
@ -22,6 +24,7 @@ static StaticRefPtr<TabGroup> sChromeTabGroup;
|
||||||
|
|
||||||
TabGroup::TabGroup(bool aIsChrome)
|
TabGroup::TabGroup(bool aIsChrome)
|
||||||
: mLastWindowLeft(false)
|
: mLastWindowLeft(false)
|
||||||
|
, mThrottledQueuesInitialized(false)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < size_t(TaskCategory::Count); i++) {
|
for (size_t i = 0; i < size_t(TaskCategory::Count); i++) {
|
||||||
TaskCategory category = static_cast<TaskCategory>(i);
|
TaskCategory category = static_cast<TaskCategory>(i);
|
||||||
|
@ -36,13 +39,12 @@ TabGroup::TabGroup(bool aIsChrome)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIThread> mainThread;
|
// This constructor can be called from the IPC I/O thread. In that case, we
|
||||||
NS_GetMainThread(getter_AddRefs(mainThread));
|
// won't actually use the TabGroup on the main thread until GetFromWindowActor
|
||||||
MOZ_DIAGNOSTIC_ASSERT(mainThread);
|
// is called, so we initialize the throttled queues there.
|
||||||
|
if (NS_IsMainThread()) {
|
||||||
// This may return nullptr during xpcom shutdown. This is ok as we
|
EnsureThrottledEventQueues();
|
||||||
// do not guarantee a ThrottledEventQueue will be present.
|
}
|
||||||
mThrottledEventQueue = ThrottledEventQueue::Create(mainThread);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TabGroup::~TabGroup()
|
TabGroup::~TabGroup()
|
||||||
|
@ -51,6 +53,28 @@ TabGroup::~TabGroup()
|
||||||
MOZ_ASSERT(mWindows.IsEmpty());
|
MOZ_ASSERT(mWindows.IsEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TabGroup::EnsureThrottledEventQueues()
|
||||||
|
{
|
||||||
|
if (mThrottledQueuesInitialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mThrottledQueuesInitialized = true;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < size_t(TaskCategory::Count); i++) {
|
||||||
|
TaskCategory category = static_cast<TaskCategory>(i);
|
||||||
|
if (category == TaskCategory::Worker || category == TaskCategory::Timer) {
|
||||||
|
nsCOMPtr<nsIEventTarget> target = ThrottledEventQueue::Create(mEventTargets[i]);
|
||||||
|
if (target) {
|
||||||
|
// This may return nullptr during xpcom shutdown. This is ok as we
|
||||||
|
// do not guarantee a ThrottledEventQueue will be present.
|
||||||
|
mEventTargets[i] = target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TabGroup*
|
TabGroup*
|
||||||
TabGroup::GetChromeTabGroup()
|
TabGroup::GetChromeTabGroup()
|
||||||
{
|
{
|
||||||
|
@ -61,6 +85,36 @@ TabGroup::GetChromeTabGroup()
|
||||||
return sChromeTabGroup;
|
return sChromeTabGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* static */ TabGroup*
|
||||||
|
TabGroup::GetFromWindowActor(mozIDOMWindowProxy* aWindow)
|
||||||
|
{
|
||||||
|
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
TabChild* tabChild = TabChild::GetFrom(aWindow);
|
||||||
|
if (!tabChild) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentChild* cc = ContentChild::GetSingleton();
|
||||||
|
nsCOMPtr<nsIEventTarget> target = cc->GetActorEventTarget(tabChild);
|
||||||
|
if (!target) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have an event target. We assume the IPC code created it via
|
||||||
|
// TabGroup::CreateEventTarget.
|
||||||
|
RefPtr<Dispatcher> dispatcher = Dispatcher::FromEventTarget(target);
|
||||||
|
MOZ_RELEASE_ASSERT(dispatcher);
|
||||||
|
auto tabGroup = dispatcher->AsTabGroup();
|
||||||
|
MOZ_RELEASE_ASSERT(tabGroup);
|
||||||
|
|
||||||
|
// We delay creating the event targets until now since the TabGroup
|
||||||
|
// constructor ran off the main thread.
|
||||||
|
tabGroup->EnsureThrottledEventQueues();
|
||||||
|
|
||||||
|
return tabGroup;
|
||||||
|
}
|
||||||
|
|
||||||
already_AddRefed<DocGroup>
|
already_AddRefed<DocGroup>
|
||||||
TabGroup::GetDocGroup(const nsACString& aKey)
|
TabGroup::GetDocGroup(const nsACString& aKey)
|
||||||
{
|
{
|
||||||
|
@ -173,12 +227,6 @@ TabGroup::GetTopLevelWindows()
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
ThrottledEventQueue*
|
|
||||||
TabGroup::GetThrottledEventQueue() const
|
|
||||||
{
|
|
||||||
return mThrottledEventQueue;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS(TabGroup, nsISupports)
|
NS_IMPL_ISUPPORTS(TabGroup, nsISupports)
|
||||||
|
|
||||||
TabGroup::HashEntry::HashEntry(const nsACString* aKey)
|
TabGroup::HashEntry::HashEntry(const nsACString* aKey)
|
||||||
|
@ -203,12 +251,15 @@ TabGroup::Dispatch(const char* aName,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<nsIEventTarget>
|
nsIEventTarget*
|
||||||
TabGroup::EventTargetFor(TaskCategory aCategory) const
|
TabGroup::EventTargetFor(TaskCategory aCategory) const
|
||||||
{
|
{
|
||||||
|
if (aCategory == TaskCategory::Worker || aCategory == TaskCategory::Timer) {
|
||||||
|
MOZ_RELEASE_ASSERT(mThrottledQueuesInitialized || this == sChromeTabGroup);
|
||||||
|
}
|
||||||
|
|
||||||
MOZ_RELEASE_ASSERT(!mLastWindowLeft);
|
MOZ_RELEASE_ASSERT(!mLastWindowLeft);
|
||||||
nsCOMPtr<nsIEventTarget> target = mEventTargets[size_t(aCategory)];
|
return mEventTargets[size_t(aCategory)];
|
||||||
return target.forget();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "nsTHashtable.h"
|
#include "nsTHashtable.h"
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
|
|
||||||
|
#include "mozilla/Atomics.h"
|
||||||
#include "mozilla/dom/Dispatcher.h"
|
#include "mozilla/dom/Dispatcher.h"
|
||||||
#include "mozilla/RefPtr.h"
|
#include "mozilla/RefPtr.h"
|
||||||
|
|
||||||
|
@ -60,6 +61,14 @@ public:
|
||||||
static TabGroup*
|
static TabGroup*
|
||||||
GetChromeTabGroup();
|
GetChromeTabGroup();
|
||||||
|
|
||||||
|
// Checks if the PBrowserChild associated with aWindow already has a TabGroup
|
||||||
|
// assigned to it in IPDL. Returns this TabGroup if it does. This could happen
|
||||||
|
// if the parent process created the PBrowser and we needed to assign a
|
||||||
|
// TabGroup immediately upon receiving the IPDL message. This method is main
|
||||||
|
// thread only.
|
||||||
|
static TabGroup*
|
||||||
|
GetFromWindowActor(mozIDOMWindowProxy* aWindow);
|
||||||
|
|
||||||
explicit TabGroup(bool aIsChrome = false);
|
explicit TabGroup(bool aIsChrome = false);
|
||||||
|
|
||||||
// Get the docgroup for the corresponding doc group key.
|
// Get the docgroup for the corresponding doc group key.
|
||||||
|
@ -101,24 +110,25 @@ public:
|
||||||
|
|
||||||
nsTArray<nsPIDOMWindowOuter*> GetTopLevelWindows();
|
nsTArray<nsPIDOMWindowOuter*> GetTopLevelWindows();
|
||||||
|
|
||||||
// Get the event queue that associated windows can use to issue runnables to
|
// This method is always safe to call off the main thread.
|
||||||
// the main thread. This may return nullptr during browser shutdown.
|
|
||||||
ThrottledEventQueue*
|
|
||||||
GetThrottledEventQueue() const;
|
|
||||||
|
|
||||||
virtual nsresult Dispatch(const char* aName,
|
virtual nsresult Dispatch(const char* aName,
|
||||||
TaskCategory aCategory,
|
TaskCategory aCategory,
|
||||||
already_AddRefed<nsIRunnable>&& aRunnable) override;
|
already_AddRefed<nsIRunnable>&& aRunnable) override;
|
||||||
|
|
||||||
virtual already_AddRefed<nsIEventTarget>
|
// This method is always safe to call off the main thread. The nsIEventTarget
|
||||||
EventTargetFor(TaskCategory aCategory) const override;
|
// can always be used off the main thread.
|
||||||
|
virtual nsIEventTarget* EventTargetFor(TaskCategory aCategory) const override;
|
||||||
|
|
||||||
|
TabGroup* AsTabGroup() override { return this; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void EnsureThrottledEventQueues();
|
||||||
|
|
||||||
~TabGroup();
|
~TabGroup();
|
||||||
DocGroupMap mDocGroups;
|
DocGroupMap mDocGroups;
|
||||||
bool mLastWindowLeft;
|
Atomic<bool> mLastWindowLeft;
|
||||||
nsTArray<nsPIDOMWindowOuter*> mWindows;
|
nsTArray<nsPIDOMWindowOuter*> mWindows;
|
||||||
RefPtr<ThrottledEventQueue> mThrottledEventQueue;
|
Atomic<bool> mThrottledQueuesInitialized;
|
||||||
nsCOMPtr<nsIEventTarget> mEventTargets[size_t(TaskCategory::Count)];
|
nsCOMPtr<nsIEventTarget> mEventTargets[size_t(TaskCategory::Count)];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -204,7 +204,8 @@ TimeoutManager::SetTimeout(nsITimeoutHandler* aHandler,
|
||||||
|
|
||||||
RefPtr<Timeout> copy = timeout;
|
RefPtr<Timeout> copy = timeout;
|
||||||
|
|
||||||
rv = timeout->InitTimer(mWindow.GetThrottledEventQueue(), realInterval);
|
rv = timeout->InitTimer(mWindow.EventTargetFor(TaskCategory::Timer),
|
||||||
|
realInterval);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -585,7 +586,8 @@ TimeoutManager::MaybeApplyBackPressure()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<ThrottledEventQueue> queue = mWindow.TabGroup()->GetThrottledEventQueue();
|
RefPtr<ThrottledEventQueue> queue =
|
||||||
|
do_QueryObject(mWindow.TabGroup()->EventTargetFor(TaskCategory::Timer));
|
||||||
if (!queue) {
|
if (!queue) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -621,7 +623,8 @@ TimeoutManager::CancelOrUpdateBackPressure(nsGlobalWindow* aWindow)
|
||||||
MOZ_ASSERT(mBackPressureDelayMS > 0);
|
MOZ_ASSERT(mBackPressureDelayMS > 0);
|
||||||
|
|
||||||
// First, re-calculate the back pressure delay.
|
// First, re-calculate the back pressure delay.
|
||||||
RefPtr<ThrottledEventQueue> queue = mWindow.TabGroup()->GetThrottledEventQueue();
|
RefPtr<ThrottledEventQueue> queue =
|
||||||
|
do_QueryObject(mWindow.TabGroup()->EventTargetFor(TaskCategory::Timer));
|
||||||
int32_t newBackPressureDelayMS =
|
int32_t newBackPressureDelayMS =
|
||||||
CalculateNewBackPressureDelayMS(queue ? queue->Length() : 0);
|
CalculateNewBackPressureDelayMS(queue ? queue->Length() : 0);
|
||||||
|
|
||||||
|
@ -725,7 +728,7 @@ TimeoutManager::RescheduleTimeout(Timeout* aTimeout, const TimeStamp& now,
|
||||||
|
|
||||||
// Reschedule the OS timer. Don't bother returning any error codes if
|
// Reschedule the OS timer. Don't bother returning any error codes if
|
||||||
// this fails since the callers of this method don't care about them.
|
// this fails since the callers of this method don't care about them.
|
||||||
nsresult rv = aTimeout->InitTimer(mWindow.GetThrottledEventQueue(),
|
nsresult rv = aTimeout->InitTimer(mWindow.EventTargetFor(TaskCategory::Timer),
|
||||||
delay.ToMilliseconds());
|
delay.ToMilliseconds());
|
||||||
|
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
|
@ -769,15 +772,16 @@ TimeoutManager::ResetTimersForThrottleReduction(int32_t aPreviousThrottleDelayMS
|
||||||
Timeouts::SortBy sortBy = mWindow.IsFrozen() ? Timeouts::SortBy::TimeRemaining
|
Timeouts::SortBy sortBy = mWindow.IsFrozen() ? Timeouts::SortBy::TimeRemaining
|
||||||
: Timeouts::SortBy::TimeWhen;
|
: Timeouts::SortBy::TimeWhen;
|
||||||
|
|
||||||
|
nsCOMPtr<nsIEventTarget> queue = mWindow.EventTargetFor(TaskCategory::Timer);
|
||||||
nsresult rv = mNormalTimeouts.ResetTimersForThrottleReduction(aPreviousThrottleDelayMS,
|
nsresult rv = mNormalTimeouts.ResetTimersForThrottleReduction(aPreviousThrottleDelayMS,
|
||||||
minTimeout,
|
minTimeout,
|
||||||
sortBy,
|
sortBy,
|
||||||
mWindow.GetThrottledEventQueue());
|
queue);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
rv = mTrackingTimeouts.ResetTimersForThrottleReduction(aPreviousThrottleDelayMS,
|
rv = mTrackingTimeouts.ResetTimersForThrottleReduction(aPreviousThrottleDelayMS,
|
||||||
minTimeout,
|
minTimeout,
|
||||||
sortBy,
|
sortBy,
|
||||||
mWindow.GetThrottledEventQueue());
|
queue);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -787,7 +791,7 @@ nsresult
|
||||||
TimeoutManager::Timeouts::ResetTimersForThrottleReduction(int32_t aPreviousThrottleDelayMS,
|
TimeoutManager::Timeouts::ResetTimersForThrottleReduction(int32_t aPreviousThrottleDelayMS,
|
||||||
int32_t aMinTimeoutValueMS,
|
int32_t aMinTimeoutValueMS,
|
||||||
SortBy aSortBy,
|
SortBy aSortBy,
|
||||||
ThrottledEventQueue* aQueue)
|
nsIEventTarget* aQueue)
|
||||||
{
|
{
|
||||||
TimeStamp now = TimeStamp::Now();
|
TimeStamp now = TimeStamp::Now();
|
||||||
|
|
||||||
|
@ -1033,7 +1037,8 @@ TimeoutManager::Resume()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult rv = aTimeout->InitTimer(mWindow.GetThrottledEventQueue(), delay);
|
nsresult rv = aTimeout->InitTimer(mWindow.EventTargetFor(TaskCategory::Timer),
|
||||||
|
delay);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
aTimeout->mTimer = nullptr;
|
aTimeout->mTimer = nullptr;
|
||||||
aTimeout->remove();
|
aTimeout->remove();
|
||||||
|
|
|
@ -9,13 +9,11 @@
|
||||||
|
|
||||||
#include "mozilla/dom/Timeout.h"
|
#include "mozilla/dom/Timeout.h"
|
||||||
|
|
||||||
|
class nsIEventTarget;
|
||||||
class nsITimeoutHandler;
|
class nsITimeoutHandler;
|
||||||
class nsGlobalWindow;
|
class nsGlobalWindow;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
class ThrottledEventQueue;
|
|
||||||
|
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
class OrderedTimeoutIterator;
|
class OrderedTimeoutIterator;
|
||||||
|
@ -133,7 +131,7 @@ private:
|
||||||
nsresult ResetTimersForThrottleReduction(int32_t aPreviousThrottleDelayMS,
|
nsresult ResetTimersForThrottleReduction(int32_t aPreviousThrottleDelayMS,
|
||||||
int32_t aMinTimeoutValueMS,
|
int32_t aMinTimeoutValueMS,
|
||||||
SortBy aSortBy,
|
SortBy aSortBy,
|
||||||
mozilla::ThrottledEventQueue* aQueue);
|
nsIEventTarget* aQueue);
|
||||||
|
|
||||||
const Timeout* GetFirst() const { return mTimeoutList.getFirst(); }
|
const Timeout* GetFirst() const { return mTimeoutList.getFirst(); }
|
||||||
Timeout* GetFirst() { return mTimeoutList.getFirst(); }
|
Timeout* GetFirst() { return mTimeoutList.getFirst(); }
|
||||||
|
|
|
@ -2891,7 +2891,7 @@ nsIDocument::Dispatch(const char* aName,
|
||||||
return DispatcherTrait::Dispatch(aName, aCategory, Move(aRunnable));
|
return DispatcherTrait::Dispatch(aName, aCategory, Move(aRunnable));
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<nsIEventTarget>
|
nsIEventTarget*
|
||||||
nsIDocument::EventTargetFor(TaskCategory aCategory) const
|
nsIDocument::EventTargetFor(TaskCategory aCategory) const
|
||||||
{
|
{
|
||||||
if (mDocGroup) {
|
if (mDocGroup) {
|
||||||
|
|
|
@ -9565,18 +9565,6 @@ nsGlobalWindow::UpdateCommands(const nsAString& anAction, nsISelection* aSel, in
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
ThrottledEventQueue*
|
|
||||||
nsGlobalWindow::GetThrottledEventQueue()
|
|
||||||
{
|
|
||||||
// We must have an outer to access the TabGroup.
|
|
||||||
nsGlobalWindow* outer = GetOuterWindowInternal();
|
|
||||||
if (!outer) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TabGroup()->GetThrottledEventQueue();
|
|
||||||
}
|
|
||||||
|
|
||||||
Selection*
|
Selection*
|
||||||
nsGlobalWindow::GetSelectionOuter()
|
nsGlobalWindow::GetSelectionOuter()
|
||||||
{
|
{
|
||||||
|
@ -14161,7 +14149,18 @@ nsGlobalWindow::TabGroupOuter()
|
||||||
toJoin = opener->TabGroup();
|
toJoin = opener->TabGroup();
|
||||||
} else if (parent) {
|
} else if (parent) {
|
||||||
toJoin = parent->TabGroup();
|
toJoin = parent->TabGroup();
|
||||||
|
} else {
|
||||||
|
// If the tab was created by the parent process, the IPC code may have
|
||||||
|
// already created a TabGroup for us. Fetch it in that case.
|
||||||
|
toJoin = TabGroup::GetFromWindowActor(AsOuter());
|
||||||
}
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
// Make sure that, if we have a tab group from the actor, it matches the one
|
||||||
|
// we're planning to join.
|
||||||
|
mozilla::dom::TabGroup* actorTabGroup = TabGroup::GetFromWindowActor(AsOuter());
|
||||||
|
MOZ_ASSERT_IF(actorTabGroup, actorTabGroup == toJoin);
|
||||||
|
#endif
|
||||||
|
|
||||||
mTabGroup = mozilla::dom::TabGroup::Join(AsOuter(), toJoin);
|
mTabGroup = mozilla::dom::TabGroup::Join(AsOuter(), toJoin);
|
||||||
}
|
}
|
||||||
MOZ_ASSERT(mTabGroup);
|
MOZ_ASSERT(mTabGroup);
|
||||||
|
@ -14255,7 +14254,7 @@ nsGlobalWindow::Dispatch(const char* aName,
|
||||||
return DispatcherTrait::Dispatch(aName, aCategory, Move(aRunnable));
|
return DispatcherTrait::Dispatch(aName, aCategory, Move(aRunnable));
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<nsIEventTarget>
|
nsIEventTarget*
|
||||||
nsGlobalWindow::EventTargetFor(TaskCategory aCategory) const
|
nsGlobalWindow::EventTargetFor(TaskCategory aCategory) const
|
||||||
{
|
{
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||||
|
|
|
@ -1184,8 +1184,6 @@ public:
|
||||||
nsPIDOMWindowOuter** _retval) override;
|
nsPIDOMWindowOuter** _retval) override;
|
||||||
nsresult UpdateCommands(const nsAString& anAction, nsISelection* aSel, int16_t aReason) override;
|
nsresult UpdateCommands(const nsAString& anAction, nsISelection* aSel, int16_t aReason) override;
|
||||||
|
|
||||||
mozilla::ThrottledEventQueue* GetThrottledEventQueue() override;
|
|
||||||
|
|
||||||
already_AddRefed<nsPIDOMWindowOuter>
|
already_AddRefed<nsPIDOMWindowOuter>
|
||||||
GetContentInternal(mozilla::ErrorResult& aError,
|
GetContentInternal(mozilla::ErrorResult& aError,
|
||||||
mozilla::dom::CallerType aCallerType);
|
mozilla::dom::CallerType aCallerType);
|
||||||
|
@ -1770,7 +1768,7 @@ public:
|
||||||
mozilla::dom::TaskCategory aCategory,
|
mozilla::dom::TaskCategory aCategory,
|
||||||
already_AddRefed<nsIRunnable>&& aRunnable) override;
|
already_AddRefed<nsIRunnable>&& aRunnable) override;
|
||||||
|
|
||||||
virtual already_AddRefed<nsIEventTarget>
|
virtual nsIEventTarget*
|
||||||
EventTargetFor(mozilla::dom::TaskCategory aCategory) const override;
|
EventTargetFor(mozilla::dom::TaskCategory aCategory) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -2872,7 +2872,7 @@ public:
|
||||||
mozilla::dom::TaskCategory aCategory,
|
mozilla::dom::TaskCategory aCategory,
|
||||||
already_AddRefed<nsIRunnable>&& aRunnable) override;
|
already_AddRefed<nsIRunnable>&& aRunnable) override;
|
||||||
|
|
||||||
virtual already_AddRefed<nsIEventTarget>
|
virtual nsIEventTarget*
|
||||||
EventTargetFor(mozilla::dom::TaskCategory aCategory) const override;
|
EventTargetFor(mozilla::dom::TaskCategory aCategory) const override;
|
||||||
|
|
||||||
// The URLs passed to these functions should match what
|
// The URLs passed to these functions should match what
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "nsTArray.h"
|
#include "nsTArray.h"
|
||||||
|
#include "mozilla/dom/Dispatcher.h"
|
||||||
#include "mozilla/dom/EventTarget.h"
|
#include "mozilla/dom/EventTarget.h"
|
||||||
#include "js/TypeDecls.h"
|
#include "js/TypeDecls.h"
|
||||||
#include "nsRefPtrHashtable.h"
|
#include "nsRefPtrHashtable.h"
|
||||||
|
@ -579,7 +580,8 @@ public:
|
||||||
|
|
||||||
mozilla::dom::DocGroup* GetDocGroup() const;
|
mozilla::dom::DocGroup* GetDocGroup() const;
|
||||||
|
|
||||||
virtual mozilla::ThrottledEventQueue* GetThrottledEventQueue() = 0;
|
virtual nsIEventTarget*
|
||||||
|
EventTargetFor(mozilla::dom::TaskCategory aCategory) const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// The nsPIDOMWindow constructor. The aOuterWindow argument should
|
// The nsPIDOMWindow constructor. The aOuterWindow argument should
|
||||||
|
|
|
@ -35,13 +35,13 @@
|
||||||
#include "nsITimedChannel.h"
|
#include "nsITimedChannel.h"
|
||||||
#include "nsIScriptElement.h"
|
#include "nsIScriptElement.h"
|
||||||
#include "nsIDOMHTMLScriptElement.h"
|
#include "nsIDOMHTMLScriptElement.h"
|
||||||
|
#include "nsIDocShell.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "nsUnicharUtils.h"
|
#include "nsUnicharUtils.h"
|
||||||
#include "nsAutoPtr.h"
|
#include "nsAutoPtr.h"
|
||||||
#include "nsIXPConnect.h"
|
#include "nsIXPConnect.h"
|
||||||
#include "nsError.h"
|
#include "nsError.h"
|
||||||
#include "nsThreadUtils.h"
|
#include "nsThreadUtils.h"
|
||||||
#include "nsDocShell.h"
|
|
||||||
#include "nsDocShellCID.h"
|
#include "nsDocShellCID.h"
|
||||||
#include "nsIContentSecurityPolicy.h"
|
#include "nsIContentSecurityPolicy.h"
|
||||||
#include "mozilla/Logging.h"
|
#include "mozilla/Logging.h"
|
||||||
|
@ -1301,8 +1301,6 @@ nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType,
|
||||||
|
|
||||||
RefPtr<nsScriptLoadHandler> handler =
|
RefPtr<nsScriptLoadHandler> handler =
|
||||||
new nsScriptLoadHandler(this, aRequest, sriDataVerifier.forget());
|
new nsScriptLoadHandler(this, aRequest, sriDataVerifier.forget());
|
||||||
rv = handler->Init();
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
nsCOMPtr<nsIIncrementalStreamLoader> loader;
|
nsCOMPtr<nsIIncrementalStreamLoader> loader;
|
||||||
rv = NS_NewIncrementalStreamLoader(getter_AddRefs(loader), handler);
|
rv = NS_NewIncrementalStreamLoader(getter_AddRefs(loader), handler);
|
||||||
|
@ -2456,7 +2454,7 @@ nsScriptLoader::ConvertToUTF16(nsIChannel* aChannel, const uint8_t* aData,
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsScriptLoader::OnStreamComplete(nsIChannel* aChannel,
|
nsScriptLoader::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
|
||||||
nsISupports* aContext,
|
nsISupports* aContext,
|
||||||
nsresult aChannelStatus,
|
nsresult aChannelStatus,
|
||||||
nsresult aSRIStatus,
|
nsresult aSRIStatus,
|
||||||
|
@ -2467,6 +2465,11 @@ nsScriptLoader::OnStreamComplete(nsIChannel* aChannel,
|
||||||
NS_ASSERTION(request, "null request in stream complete handler");
|
NS_ASSERTION(request, "null request in stream complete handler");
|
||||||
NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
|
NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
|
||||||
|
|
||||||
|
nsCOMPtr<nsIRequest> channelRequest;
|
||||||
|
aLoader->GetRequest(getter_AddRefs(channelRequest));
|
||||||
|
nsCOMPtr<nsIChannel> channel;
|
||||||
|
channel = do_QueryInterface(channelRequest);
|
||||||
|
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
if (!request->mIntegrity.IsEmpty() &&
|
if (!request->mIntegrity.IsEmpty() &&
|
||||||
NS_SUCCEEDED((rv = aSRIStatus))) {
|
NS_SUCCEEDED((rv = aSRIStatus))) {
|
||||||
|
@ -2477,14 +2480,14 @@ nsScriptLoader::OnStreamComplete(nsIChannel* aChannel,
|
||||||
if (mDocument && mDocument->GetDocumentURI()) {
|
if (mDocument && mDocument->GetDocumentURI()) {
|
||||||
mDocument->GetDocumentURI()->GetAsciiSpec(sourceUri);
|
mDocument->GetDocumentURI()->GetAsciiSpec(sourceUri);
|
||||||
}
|
}
|
||||||
rv = aSRIDataVerifier->Verify(request->mIntegrity, aChannel, sourceUri,
|
rv = aSRIDataVerifier->Verify(request->mIntegrity, channel, sourceUri,
|
||||||
mReporter);
|
mReporter);
|
||||||
mReporter->FlushConsoleReports(mDocument);
|
mReporter->FlushConsoleReports(mDocument);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
rv = NS_ERROR_SRI_CORRUPT;
|
rv = NS_ERROR_SRI_CORRUPT;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
|
nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
|
||||||
|
|
||||||
if (loadInfo->GetEnforceSRI()) {
|
if (loadInfo->GetEnforceSRI()) {
|
||||||
MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug,
|
MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug,
|
||||||
|
@ -2503,7 +2506,7 @@ nsScriptLoader::OnStreamComplete(nsIChannel* aChannel,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
rv = PrepareLoadedRequest(request, aChannel, aChannelStatus, aString);
|
rv = PrepareLoadedRequest(request, aLoader, aChannelStatus, aString);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
|
@ -2616,7 +2619,7 @@ nsScriptLoader::MaybeMoveToLoadedList(nsScriptLoadRequest* aRequest)
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsScriptLoader::PrepareLoadedRequest(nsScriptLoadRequest* aRequest,
|
nsScriptLoader::PrepareLoadedRequest(nsScriptLoadRequest* aRequest,
|
||||||
nsIChannel* aChannel,
|
nsIIncrementalStreamLoader* aLoader,
|
||||||
nsresult aStatus,
|
nsresult aStatus,
|
||||||
mozilla::Vector<char16_t> &aString)
|
mozilla::Vector<char16_t> &aString)
|
||||||
{
|
{
|
||||||
|
@ -2634,8 +2637,13 @@ nsScriptLoader::PrepareLoadedRequest(nsScriptLoadRequest* aRequest,
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult rv;
|
// If the load returned an error page, then we need to abort
|
||||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
|
nsCOMPtr<nsIRequest> req;
|
||||||
|
nsresult rv = aLoader->GetRequest(getter_AddRefs(req));
|
||||||
|
NS_ASSERTION(req, "StreamLoader's request went away prematurely");
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(req);
|
||||||
if (httpChannel) {
|
if (httpChannel) {
|
||||||
bool requestSucceeded;
|
bool requestSucceeded;
|
||||||
rv = httpChannel->GetRequestSucceeded(&requestSucceeded);
|
rv = httpChannel->GetRequestSucceeded(&requestSucceeded);
|
||||||
|
@ -2649,14 +2657,19 @@ nsScriptLoader::PrepareLoadedRequest(nsScriptLoadRequest* aRequest,
|
||||||
aRequest->mHasSourceMapURL = true;
|
aRequest->mHasSourceMapURL = true;
|
||||||
aRequest->mSourceMapURL = NS_ConvertUTF8toUTF16(sourceMapURL);
|
aRequest->mSourceMapURL = NS_ConvertUTF8toUTF16(sourceMapURL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (httpChannel->GetIsTrackingResource()) {
|
||||||
|
aRequest->SetIsTracking();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIChannel> channel = do_QueryInterface(req);
|
||||||
// If this load was subject to a CORS check; don't flag it with a
|
// If this load was subject to a CORS check; don't flag it with a
|
||||||
// separate origin principal, so that it will treat our document's
|
// separate origin principal, so that it will treat our document's
|
||||||
// principal as the origin principal
|
// principal as the origin principal
|
||||||
if (aRequest->mCORSMode == CORS_NONE) {
|
if (aRequest->mCORSMode == CORS_NONE) {
|
||||||
rv = nsContentUtils::GetSecurityManager()->
|
rv = nsContentUtils::GetSecurityManager()->
|
||||||
GetChannelResultPrincipal(aChannel, getter_AddRefs(aRequest->mOriginPrincipal));
|
GetChannelResultPrincipal(channel, getter_AddRefs(aRequest->mOriginPrincipal));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2686,13 +2699,13 @@ nsScriptLoader::PrepareLoadedRequest(nsScriptLoadRequest* aRequest,
|
||||||
// When loading a module, only responses with a JavaScript MIME type are
|
// When loading a module, only responses with a JavaScript MIME type are
|
||||||
// acceptable.
|
// acceptable.
|
||||||
nsAutoCString mimeType;
|
nsAutoCString mimeType;
|
||||||
aChannel->GetContentType(mimeType);
|
channel->GetContentType(mimeType);
|
||||||
NS_ConvertUTF8toUTF16 typeString(mimeType);
|
NS_ConvertUTF8toUTF16 typeString(mimeType);
|
||||||
if (!nsContentUtils::IsJavascriptMIMEType(typeString)) {
|
if (!nsContentUtils::IsJavascriptMIMEType(typeString)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
aChannel->GetURI(getter_AddRefs(request->mBaseURL));
|
channel->GetURI(getter_AddRefs(request->mBaseURL));
|
||||||
|
|
||||||
// Attempt to compile off main thread.
|
// Attempt to compile off main thread.
|
||||||
rv = AttemptAsyncScriptCompile(request);
|
rv = AttemptAsyncScriptCompile(request);
|
||||||
|
@ -2839,53 +2852,15 @@ nsScriptLoadHandler::nsScriptLoadHandler(nsScriptLoader *aScriptLoader,
|
||||||
: mScriptLoader(aScriptLoader),
|
: mScriptLoader(aScriptLoader),
|
||||||
mRequest(aRequest),
|
mRequest(aRequest),
|
||||||
mSRIDataVerifier(aSRIDataVerifier),
|
mSRIDataVerifier(aSRIDataVerifier),
|
||||||
mChannelStatus(NS_OK),
|
|
||||||
mSRIStatus(NS_OK),
|
mSRIStatus(NS_OK),
|
||||||
mClassificationStatus(NS_ERROR_NOT_INITIALIZED),
|
|
||||||
mDecoder(),
|
mDecoder(),
|
||||||
mBuffer()
|
mBuffer()
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
nsScriptLoadHandler::Init()
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIURIClassifier> uriClassifier =
|
|
||||||
do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID);
|
|
||||||
if (!uriClassifier) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
PrincipalOriginAttributes attrs;
|
|
||||||
nsIDocShell* docShell = nullptr;
|
|
||||||
if (auto doc = mScriptLoader->GetDocument()) {
|
|
||||||
docShell = doc->GetDocShell();
|
|
||||||
}
|
|
||||||
if (!docShell) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
attrs.InheritFromDocShellToDoc(nsDocShell::Cast(docShell)->GetOriginAttributes(), nullptr);
|
|
||||||
nsCOMPtr<nsIPrincipal> prin =
|
|
||||||
BasePrincipal::CreateCodebasePrincipal(mRequest->mURI, attrs);
|
|
||||||
NS_ENSURE_TRUE(prin, NS_ERROR_FAILURE);
|
|
||||||
|
|
||||||
bool expectCallback = false;
|
|
||||||
uriClassifier->Classify(prin, /* aTrackingProtectionEnabled = */ true,
|
|
||||||
this, &expectCallback);
|
|
||||||
if (!expectCallback) {
|
|
||||||
// If we don't expect to receive a callback, set the classification status
|
|
||||||
// eagerly.
|
|
||||||
mClassificationStatus = NS_OK;
|
|
||||||
}
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsScriptLoadHandler::~nsScriptLoadHandler()
|
nsScriptLoadHandler::~nsScriptLoadHandler()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS(nsScriptLoadHandler,
|
NS_IMPL_ISUPPORTS(nsScriptLoadHandler, nsIIncrementalStreamLoaderObserver)
|
||||||
nsIIncrementalStreamLoaderObserver,
|
|
||||||
nsIURIClassifierCallback)
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsScriptLoadHandler::OnIncrementalData(nsIIncrementalStreamLoader* aLoader,
|
nsScriptLoadHandler::OnIncrementalData(nsIIncrementalStreamLoader* aLoader,
|
||||||
|
@ -3061,33 +3036,7 @@ nsScriptLoadHandler::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIRequest> request;
|
// we have to mediate and use mRequest.
|
||||||
aLoader->GetRequest(getter_AddRefs(request));
|
return mScriptLoader->OnStreamComplete(aLoader, mRequest, aStatus, mSRIStatus,
|
||||||
MOZ_ASSERT(request, "How can we not have a request here?!");
|
mBuffer, mSRIDataVerifier);
|
||||||
mChannel = do_QueryInterface(request);
|
|
||||||
mChannelStatus = aStatus;
|
|
||||||
return MaybeInvokeOnStreamComplete();
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsScriptLoadHandler::OnClassifyComplete(nsresult aResult)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mClassificationStatus == NS_ERROR_NOT_INITIALIZED);
|
|
||||||
MOZ_ASSERT(!mRequest->mIsTracking);
|
|
||||||
mClassificationStatus = aResult;
|
|
||||||
mRequest->mIsTracking = mClassificationStatus == NS_ERROR_TRACKING_URI;
|
|
||||||
return MaybeInvokeOnStreamComplete();
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
nsScriptLoadHandler::MaybeInvokeOnStreamComplete()
|
|
||||||
{
|
|
||||||
// Run the script loader's callback if both the load and classification have
|
|
||||||
// been finished.
|
|
||||||
if (mChannel && mClassificationStatus != NS_ERROR_NOT_INITIALIZED) {
|
|
||||||
// we have to mediate and use mRequest.
|
|
||||||
return mScriptLoader->OnStreamComplete(mChannel, mRequest, mChannelStatus,
|
|
||||||
mSRIStatus, mBuffer, mSRIDataVerifier);
|
|
||||||
}
|
|
||||||
return NS_OK;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
#include "nsAutoPtr.h"
|
#include "nsAutoPtr.h"
|
||||||
#include "nsIDocument.h"
|
#include "nsIDocument.h"
|
||||||
#include "nsIIncrementalStreamLoader.h"
|
#include "nsIIncrementalStreamLoader.h"
|
||||||
#include "nsIURIClassifier.h"
|
|
||||||
#include "nsURIHashKey.h"
|
#include "nsURIHashKey.h"
|
||||||
#include "mozilla/CORSMode.h"
|
#include "mozilla/CORSMode.h"
|
||||||
#include "mozilla/dom/SRIMetadata.h"
|
#include "mozilla/dom/SRIMetadata.h"
|
||||||
|
@ -138,6 +137,11 @@ public:
|
||||||
{
|
{
|
||||||
return mIsTracking;
|
return mIsTracking;
|
||||||
}
|
}
|
||||||
|
void SetIsTracking()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(!mIsTracking);
|
||||||
|
mIsTracking = true;
|
||||||
|
}
|
||||||
|
|
||||||
enum class Progress {
|
enum class Progress {
|
||||||
Loading,
|
Loading,
|
||||||
|
@ -277,14 +281,6 @@ public:
|
||||||
mDocument = nullptr;
|
mDocument = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the document reference.
|
|
||||||
*/
|
|
||||||
nsIDocument* GetDocument() const
|
|
||||||
{
|
|
||||||
return mDocument;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an observer for all scripts loaded through this loader.
|
* Add an observer for all scripts loaded through this loader.
|
||||||
*
|
*
|
||||||
|
@ -414,7 +410,7 @@ public:
|
||||||
* nsScriptLoadHandler object which observes the IncrementalStreamLoader
|
* nsScriptLoadHandler object which observes the IncrementalStreamLoader
|
||||||
* loading the script.
|
* loading the script.
|
||||||
*/
|
*/
|
||||||
nsresult OnStreamComplete(nsIChannel* aChannel,
|
nsresult OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
|
||||||
nsISupports* aContext,
|
nsISupports* aContext,
|
||||||
nsresult aChannelStatus,
|
nsresult aChannelStatus,
|
||||||
nsresult aSRIStatus,
|
nsresult aSRIStatus,
|
||||||
|
@ -577,7 +573,7 @@ private:
|
||||||
|
|
||||||
uint32_t NumberOfProcessors();
|
uint32_t NumberOfProcessors();
|
||||||
nsresult PrepareLoadedRequest(nsScriptLoadRequest* aRequest,
|
nsresult PrepareLoadedRequest(nsScriptLoadRequest* aRequest,
|
||||||
nsIChannel* aChannel,
|
nsIIncrementalStreamLoader* aLoader,
|
||||||
nsresult aStatus,
|
nsresult aStatus,
|
||||||
mozilla::Vector<char16_t> &aString);
|
mozilla::Vector<char16_t> &aString);
|
||||||
|
|
||||||
|
@ -663,22 +659,17 @@ private:
|
||||||
nsCOMPtr<nsIConsoleReportCollector> mReporter;
|
nsCOMPtr<nsIConsoleReportCollector> mReporter;
|
||||||
};
|
};
|
||||||
|
|
||||||
class nsScriptLoadHandler final : public nsIIncrementalStreamLoaderObserver,
|
class nsScriptLoadHandler final : public nsIIncrementalStreamLoaderObserver
|
||||||
private nsIURIClassifierCallback
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit nsScriptLoadHandler(nsScriptLoader* aScriptLoader,
|
explicit nsScriptLoadHandler(nsScriptLoader* aScriptLoader,
|
||||||
nsScriptLoadRequest *aRequest,
|
nsScriptLoadRequest *aRequest,
|
||||||
mozilla::dom::SRICheckDataVerifier *aSRIDataVerifier);
|
mozilla::dom::SRICheckDataVerifier *aSRIDataVerifier);
|
||||||
|
|
||||||
nsresult Init();
|
|
||||||
|
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_ISUPPORTS
|
||||||
NS_DECL_NSIINCREMENTALSTREAMLOADEROBSERVER
|
NS_DECL_NSIINCREMENTALSTREAMLOADEROBSERVER
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NS_DECL_NSIURICLASSIFIERCALLBACK
|
|
||||||
|
|
||||||
virtual ~nsScriptLoadHandler();
|
virtual ~nsScriptLoadHandler();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -696,12 +687,6 @@ private:
|
||||||
const uint8_t* aData, uint32_t aDataLength,
|
const uint8_t* aData, uint32_t aDataLength,
|
||||||
bool aEndOfStream);
|
bool aEndOfStream);
|
||||||
|
|
||||||
/*
|
|
||||||
* Call the script loader OnClassifyComplete if both the load and the
|
|
||||||
* classification have finished.
|
|
||||||
*/
|
|
||||||
nsresult MaybeInvokeOnStreamComplete();
|
|
||||||
|
|
||||||
// ScriptLoader which will handle the parsed script.
|
// ScriptLoader which will handle the parsed script.
|
||||||
RefPtr<nsScriptLoader> mScriptLoader;
|
RefPtr<nsScriptLoader> mScriptLoader;
|
||||||
|
|
||||||
|
@ -711,23 +696,14 @@ private:
|
||||||
// SRI data verifier.
|
// SRI data verifier.
|
||||||
nsAutoPtr<mozilla::dom::SRICheckDataVerifier> mSRIDataVerifier;
|
nsAutoPtr<mozilla::dom::SRICheckDataVerifier> mSRIDataVerifier;
|
||||||
|
|
||||||
// Status of the channel load.
|
|
||||||
nsresult mChannelStatus;
|
|
||||||
|
|
||||||
// Status of SRI data operations.
|
// Status of SRI data operations.
|
||||||
nsresult mSRIStatus;
|
nsresult mSRIStatus;
|
||||||
|
|
||||||
// status of the classification of the script URI.
|
|
||||||
nsresult mClassificationStatus;
|
|
||||||
|
|
||||||
// Unicode decoder for charset.
|
// Unicode decoder for charset.
|
||||||
nsCOMPtr<nsIUnicodeDecoder> mDecoder;
|
nsCOMPtr<nsIUnicodeDecoder> mDecoder;
|
||||||
|
|
||||||
// Accumulated decoded char buffer.
|
// Accumulated decoded char buffer.
|
||||||
mozilla::Vector<char16_t> mBuffer;
|
mozilla::Vector<char16_t> mBuffer;
|
||||||
|
|
||||||
// The channel we loaded the script from.
|
|
||||||
nsCOMPtr<nsIChannel> mChannel;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class nsAutoScriptLoaderDisabler
|
class nsAutoScriptLoaderDisabler
|
||||||
|
|
|
@ -66,6 +66,18 @@ nsresult
|
||||||
AsyncEventDispatcher::PostDOMEvent()
|
AsyncEventDispatcher::PostDOMEvent()
|
||||||
{
|
{
|
||||||
RefPtr<AsyncEventDispatcher> ensureDeletionWhenFailing = this;
|
RefPtr<AsyncEventDispatcher> ensureDeletionWhenFailing = this;
|
||||||
|
if (NS_IsMainThread()) {
|
||||||
|
if (nsCOMPtr<nsIGlobalObject> global = mTarget->GetOwnerGlobal()) {
|
||||||
|
return global->Dispatch("AsyncEvent", TaskCategory::Other, ensureDeletionWhenFailing.forget());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sometimes GetOwnerGlobal returns null because it uses
|
||||||
|
// GetScriptHandlingObject rather than GetScopeObject.
|
||||||
|
if (nsCOMPtr<nsINode> node = do_QueryInterface(mTarget)) {
|
||||||
|
nsCOMPtr<nsIDocument> doc = node->OwnerDoc();
|
||||||
|
return doc->Dispatch("AsyncEvent", TaskCategory::Other, ensureDeletionWhenFailing.forget());
|
||||||
|
}
|
||||||
|
}
|
||||||
return NS_DispatchToCurrentThread(this);
|
return NS_DispatchToCurrentThread(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -758,28 +758,36 @@ DataTransfer::MozClearDataAtHelper(const nsAString& aFormat, uint32_t aIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
DataTransfer::SetDragImage(Element& aImage, int32_t aX, int32_t aY,
|
DataTransfer::SetDragImage(Element& aImage, int32_t aX, int32_t aY)
|
||||||
ErrorResult& aRv)
|
|
||||||
{
|
{
|
||||||
if (mReadOnly) {
|
if (!mReadOnly) {
|
||||||
aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
|
mDragImage = &aImage;
|
||||||
return;
|
mDragImageX = aX;
|
||||||
|
mDragImageY = aY;
|
||||||
}
|
}
|
||||||
|
|
||||||
mDragImage = &aImage;
|
|
||||||
mDragImageX = aX;
|
|
||||||
mDragImageY = aY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
DataTransfer::SetDragImage(nsIDOMElement* aImage, int32_t aX, int32_t aY)
|
DataTransfer::SetDragImage(nsIDOMElement* aImage, int32_t aX, int32_t aY)
|
||||||
{
|
{
|
||||||
ErrorResult rv;
|
|
||||||
nsCOMPtr<Element> image = do_QueryInterface(aImage);
|
nsCOMPtr<Element> image = do_QueryInterface(aImage);
|
||||||
if (image) {
|
if (image) {
|
||||||
SetDragImage(*image, aX, aY, rv);
|
SetDragImage(*image, aX, aY);
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DataTransfer::UpdateDragImage(Element& aImage, int32_t aX, int32_t aY)
|
||||||
|
{
|
||||||
|
if (mEventMessage < eDragDropEventFirst || mEventMessage > eDragDropEventLast) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
|
||||||
|
if (dragSession) {
|
||||||
|
dragSession->UpdateDragImage(aImage.AsDOMNode(), aX, aY);
|
||||||
}
|
}
|
||||||
return rv.StealNSResult();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<Promise>
|
already_AddRefed<Promise>
|
||||||
|
|
|
@ -133,8 +133,8 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetDragImage(Element& aElement, int32_t aX, int32_t aY,
|
void SetDragImage(Element& aElement, int32_t aX, int32_t aY);
|
||||||
ErrorResult& aRv);
|
void UpdateDragImage(Element& aElement, int32_t aX, int32_t aY);
|
||||||
|
|
||||||
void GetTypes(nsTArray<nsString>& aTypes, CallerType aCallerType) const;
|
void GetTypes(nsTArray<nsString>& aTypes, CallerType aCallerType) const;
|
||||||
|
|
||||||
|
|
|
@ -45,8 +45,6 @@ function afterDragTests()
|
||||||
"NoModificationAllowedError", "setDataAt when read only");
|
"NoModificationAllowedError", "setDataAt when read only");
|
||||||
expectError(() => gDataTransfer.mozClearDataAt("text/plain", 0),
|
expectError(() => gDataTransfer.mozClearDataAt("text/plain", 0),
|
||||||
"NoModificationAllowedError", "clearDataAt when read only");
|
"NoModificationAllowedError", "clearDataAt when read only");
|
||||||
expectError(() => gDataTransfer.setDragImage(draggable, 10, 10),
|
|
||||||
"NoModificationAllowedError", "setDragImage when read only");
|
|
||||||
expectError(() => gDataTransfer.addElement(draggable),
|
expectError(() => gDataTransfer.addElement(draggable),
|
||||||
"NoModificationAllowedError", "addElement when read only");
|
"NoModificationAllowedError", "addElement when read only");
|
||||||
|
|
||||||
|
|
|
@ -152,15 +152,12 @@ ContentBridgeChild::RecvPBrowserConstructor(PBrowserChild* aActor,
|
||||||
const ContentParentId& aCpID,
|
const ContentParentId& aCpID,
|
||||||
const bool& aIsForBrowser)
|
const bool& aIsForBrowser)
|
||||||
{
|
{
|
||||||
if (!ContentChild::GetSingleton()->RecvPBrowserConstructor(aActor,
|
return nsIContentChild::RecvPBrowserConstructor(aActor,
|
||||||
aTabId,
|
aTabId,
|
||||||
aContext,
|
aContext,
|
||||||
aChromeFlags,
|
aChromeFlags,
|
||||||
aCpID,
|
aCpID,
|
||||||
aIsForBrowser)) {
|
aIsForBrowser);
|
||||||
return IPC_FAIL_NO_REASON(this);
|
|
||||||
}
|
|
||||||
return IPC_OK();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PBlobChild*
|
PBlobChild*
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "mozilla/dom/VideoDecoderManagerChild.h"
|
#include "mozilla/dom/VideoDecoderManagerChild.h"
|
||||||
#include "mozilla/dom/ContentParent.h"
|
#include "mozilla/dom/ContentParent.h"
|
||||||
#include "mozilla/dom/DataTransfer.h"
|
#include "mozilla/dom/DataTransfer.h"
|
||||||
|
#include "mozilla/dom/DocGroup.h"
|
||||||
#include "mozilla/dom/DOMStorageIPC.h"
|
#include "mozilla/dom/DOMStorageIPC.h"
|
||||||
#include "mozilla/dom/ExternalHelperAppChild.h"
|
#include "mozilla/dom/ExternalHelperAppChild.h"
|
||||||
#include "mozilla/dom/FlyWebPublishedServerIPC.h"
|
#include "mozilla/dom/FlyWebPublishedServerIPC.h"
|
||||||
|
@ -34,6 +35,7 @@
|
||||||
#include "mozilla/dom/PCrashReporterChild.h"
|
#include "mozilla/dom/PCrashReporterChild.h"
|
||||||
#include "mozilla/dom/ProcessGlobal.h"
|
#include "mozilla/dom/ProcessGlobal.h"
|
||||||
#include "mozilla/dom/PushNotifier.h"
|
#include "mozilla/dom/PushNotifier.h"
|
||||||
|
#include "mozilla/dom/TabGroup.h"
|
||||||
#include "mozilla/dom/workers/ServiceWorkerManager.h"
|
#include "mozilla/dom/workers/ServiceWorkerManager.h"
|
||||||
#include "mozilla/dom/nsIContentChild.h"
|
#include "mozilla/dom/nsIContentChild.h"
|
||||||
#include "mozilla/dom/URLClassifierChild.h"
|
#include "mozilla/dom/URLClassifierChild.h"
|
||||||
|
@ -786,6 +788,19 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
|
||||||
ipcContext->get_PopupIPCTabContext().opener() = aTabOpener;
|
ipcContext->get_PopupIPCTabContext().opener() = aTabOpener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We need to assign a TabGroup to the PBrowser actor before we send it to the
|
||||||
|
// parent. Otherwise, the parent could send messages to us before we have a
|
||||||
|
// proper TabGroup for that actor.
|
||||||
|
RefPtr<TabGroup> tabGroup;
|
||||||
|
if (aTabOpener && !aForceNoOpener) {
|
||||||
|
// The new actor will use the same tab group as the opener.
|
||||||
|
tabGroup = aTabOpener->TabGroup();
|
||||||
|
} else {
|
||||||
|
tabGroup = new TabGroup();
|
||||||
|
}
|
||||||
|
nsCOMPtr<nsIEventTarget> target = tabGroup->EventTargetFor(TaskCategory::Other);
|
||||||
|
SetEventTargetForActor(newChild, target);
|
||||||
|
|
||||||
Unused << SendPBrowserConstructor(
|
Unused << SendPBrowserConstructor(
|
||||||
// We release this ref in DeallocPBrowserChild
|
// We release this ref in DeallocPBrowserChild
|
||||||
RefPtr<TabChild>(newChild).forget().take(),
|
RefPtr<TabChild>(newChild).forget().take(),
|
||||||
|
@ -1570,17 +1585,8 @@ ContentChild::RecvPBrowserConstructor(PBrowserChild* aActor,
|
||||||
const ContentParentId& aCpID,
|
const ContentParentId& aCpID,
|
||||||
const bool& aIsForBrowser)
|
const bool& aIsForBrowser)
|
||||||
{
|
{
|
||||||
// This runs after AllocPBrowserChild() returns and the IPC machinery for this
|
return nsIContentChild::RecvPBrowserConstructor(aActor, aTabId, aContext,
|
||||||
// PBrowserChild has been set up.
|
aChromeFlags, aCpID, aIsForBrowser);
|
||||||
|
|
||||||
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
|
||||||
if (os) {
|
|
||||||
nsITabChild* tc =
|
|
||||||
static_cast<nsITabChild*>(static_cast<TabChild*>(aActor));
|
|
||||||
os->NotifyObservers(tc, "tab-child-created", nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
return IPC_OK();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -3234,5 +3240,22 @@ ContentChild::DeallocPURLClassifierChild(PURLClassifierChild* aActor)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The IPC code will call this method asking us to assign an event target to new
|
||||||
|
// actors created by the ContentParent.
|
||||||
|
already_AddRefed<nsIEventTarget>
|
||||||
|
ContentChild::GetConstructedEventTarget(const Message& aMsg)
|
||||||
|
{
|
||||||
|
// Currently we only set targets for PBrowser.
|
||||||
|
if (aMsg.type() != PContent::Msg_PBrowserConstructor__ID) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the request for a new TabChild is coming from the parent process, then
|
||||||
|
// there is no opener. Therefore, we create a fresh TabGroup.
|
||||||
|
RefPtr<TabGroup> tabGroup = new TabGroup();
|
||||||
|
nsCOMPtr<nsIEventTarget> target = tabGroup->EventTargetFor(TaskCategory::Other);
|
||||||
|
return target.forget();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
@ -647,6 +647,9 @@ private:
|
||||||
|
|
||||||
virtual void ProcessingError(Result aCode, const char* aReason) override;
|
virtual void ProcessingError(Result aCode, const char* aReason) override;
|
||||||
|
|
||||||
|
virtual already_AddRefed<nsIEventTarget>
|
||||||
|
GetConstructedEventTarget(const Message& aMsg) override;
|
||||||
|
|
||||||
InfallibleTArray<nsAutoPtr<AlertObserver> > mAlertObservers;
|
InfallibleTArray<nsAutoPtr<AlertObserver> > mAlertObservers;
|
||||||
RefPtr<ConsoleListener> mConsoleListener;
|
RefPtr<ConsoleListener> mConsoleListener;
|
||||||
|
|
||||||
|
|
|
@ -354,7 +354,7 @@ TabChild::Create(nsIContentChild* aManager,
|
||||||
{
|
{
|
||||||
RefPtr<TabChild> iframe = new TabChild(aManager, aTabId,
|
RefPtr<TabChild> iframe = new TabChild(aManager, aTabId,
|
||||||
aContext, aChromeFlags);
|
aContext, aChromeFlags);
|
||||||
return NS_SUCCEEDED(iframe->Init()) ? iframe.forget() : nullptr;
|
return iframe.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
TabChild::TabChild(nsIContentChild* aManager,
|
TabChild::TabChild(nsIContentChild* aManager,
|
||||||
|
@ -3117,6 +3117,14 @@ TabChildSHistoryListener::SHistoryDidUpdate(bool aTruncate /* = false */)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mozilla::dom::TabGroup*
|
||||||
|
TabChild::TabGroup()
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
|
||||||
|
MOZ_ASSERT(window);
|
||||||
|
return window->TabGroup();
|
||||||
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* nsISHistoryListener
|
* nsISHistoryListener
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
|
@ -68,6 +68,7 @@ class PluginWidgetChild;
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
class TabChild;
|
class TabChild;
|
||||||
|
class TabGroup;
|
||||||
class ClonedMessageData;
|
class ClonedMessageData;
|
||||||
class TabChildBase;
|
class TabChildBase;
|
||||||
|
|
||||||
|
@ -665,6 +666,8 @@ public:
|
||||||
|
|
||||||
already_AddRefed<nsISHistory> GetRelatedSHistory();
|
already_AddRefed<nsISHistory> GetRelatedSHistory();
|
||||||
|
|
||||||
|
mozilla::dom::TabGroup* TabGroup();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~TabChild();
|
virtual ~TabChild();
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,31 @@ nsIContentChild::DeallocPBrowserChild(PBrowserChild* aIframe)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mozilla::ipc::IPCResult
|
||||||
|
nsIContentChild::RecvPBrowserConstructor(PBrowserChild* aActor,
|
||||||
|
const TabId& aTabId,
|
||||||
|
const IPCTabContext& aContext,
|
||||||
|
const uint32_t& aChromeFlags,
|
||||||
|
const ContentParentId& aCpID,
|
||||||
|
const bool& aIsForBrowser)
|
||||||
|
{
|
||||||
|
// This runs after AllocPBrowserChild() returns and the IPC machinery for this
|
||||||
|
// PBrowserChild has been set up.
|
||||||
|
|
||||||
|
auto tabChild = static_cast<TabChild*>(static_cast<TabChild*>(aActor));
|
||||||
|
|
||||||
|
if (NS_WARN_IF(NS_FAILED(tabChild->Init()))) {
|
||||||
|
return IPC_FAIL(tabChild, "TabChild::Init failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
||||||
|
if (os) {
|
||||||
|
os->NotifyObservers(static_cast<nsITabChild*>(tabChild), "tab-child-created", nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return IPC_OK();
|
||||||
|
}
|
||||||
|
|
||||||
PBlobChild*
|
PBlobChild*
|
||||||
nsIContentChild::AllocPBlobChild(const BlobConstructorParams& aParams)
|
nsIContentChild::AllocPBlobChild(const BlobConstructorParams& aParams)
|
||||||
{
|
{
|
||||||
|
|
|
@ -88,6 +88,13 @@ protected:
|
||||||
const bool& aIsForBrowser);
|
const bool& aIsForBrowser);
|
||||||
virtual bool DeallocPBrowserChild(PBrowserChild*);
|
virtual bool DeallocPBrowserChild(PBrowserChild*);
|
||||||
|
|
||||||
|
virtual mozilla::ipc::IPCResult RecvPBrowserConstructor(PBrowserChild* aActor,
|
||||||
|
const TabId& aTabId,
|
||||||
|
const IPCTabContext& aContext,
|
||||||
|
const uint32_t& aChromeFlags,
|
||||||
|
const ContentParentId& aCpID,
|
||||||
|
const bool& aIsForBrowse);
|
||||||
|
|
||||||
virtual PBlobChild* AllocPBlobChild(const BlobConstructorParams& aParams);
|
virtual PBlobChild* AllocPBlobChild(const BlobConstructorParams& aParams);
|
||||||
|
|
||||||
virtual bool DeallocPBlobChild(PBlobChild* aActor);
|
virtual bool DeallocPBlobChild(PBlobChild* aActor);
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <winsdkver.h>
|
#include <winsdkver.h>
|
||||||
|
#include <psapi.h>
|
||||||
#include "WMFVideoMFTManager.h"
|
#include "WMFVideoMFTManager.h"
|
||||||
#include "MediaDecoderReader.h"
|
#include "MediaDecoderReader.h"
|
||||||
#include "gfxPrefs.h"
|
#include "gfxPrefs.h"
|
||||||
|
@ -196,6 +197,17 @@ FindDXVABlacklistedDLL(StaticAutoPtr<D3DDLLBlacklistingCache>& aDLLBlacklistingC
|
||||||
// Adopt new pref now, so we don't work on it again.
|
// Adopt new pref now, so we don't work on it again.
|
||||||
aDLLBlacklistingCache->mBlacklistPref = aBlacklist;
|
aDLLBlacklistingCache->mBlacklistPref = aBlacklist;
|
||||||
|
|
||||||
|
HANDLE hProcess = GetCurrentProcess();
|
||||||
|
mozilla::UniquePtr<HMODULE[]> hMods;
|
||||||
|
unsigned int modulesNum = 0;
|
||||||
|
if (hProcess != NULL) {
|
||||||
|
DWORD modulesSize;
|
||||||
|
EnumProcessModules(hProcess, nullptr, 0, &modulesSize);
|
||||||
|
modulesNum = modulesSize / sizeof(HMODULE);
|
||||||
|
hMods = mozilla::MakeUnique<HMODULE[]>(modulesNum);
|
||||||
|
EnumProcessModules(hProcess, hMods.get(), modulesNum * sizeof(HMODULE), &modulesSize);
|
||||||
|
}
|
||||||
|
|
||||||
// media.wmf.disable-d3d*-for-dlls format: (whitespace is trimmed)
|
// media.wmf.disable-d3d*-for-dlls format: (whitespace is trimmed)
|
||||||
// "dll1.dll: 1.2.3.4[, more versions...][; more dlls...]"
|
// "dll1.dll: 1.2.3.4[, more versions...][; more dlls...]"
|
||||||
nsTArray<nsCString> dlls;
|
nsTArray<nsCString> dlls;
|
||||||
|
@ -211,68 +223,92 @@ FindDXVABlacklistedDLL(StaticAutoPtr<D3DDLLBlacklistingCache>& aDLLBlacklistingC
|
||||||
|
|
||||||
nameAndVersions[0].CompressWhitespace();
|
nameAndVersions[0].CompressWhitespace();
|
||||||
NS_ConvertUTF8toUTF16 name(nameAndVersions[0]);
|
NS_ConvertUTF8toUTF16 name(nameAndVersions[0]);
|
||||||
WCHAR systemPath[MAX_PATH + 1];
|
|
||||||
if (!ConstructSystem32Path(name.get(), systemPath, MAX_PATH + 1)) {
|
|
||||||
// Cannot build path -> Assume it's not the blacklisted DLL.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD zero;
|
for (unsigned int i = 0; i <= modulesNum; i++) {
|
||||||
DWORD infoSize = GetFileVersionInfoSizeW(systemPath, &zero);
|
WCHAR dllPath[MAX_PATH + 1];
|
||||||
if (infoSize == 0) {
|
|
||||||
// Can't get file info -> Assume we don't have the blacklisted DLL.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// vInfo is a pointer into infoData, that's why we keep it outside of the loop.
|
|
||||||
auto infoData = MakeUnique<unsigned char[]>(infoSize);
|
|
||||||
VS_FIXEDFILEINFO *vInfo;
|
|
||||||
UINT vInfoLen;
|
|
||||||
if (!GetFileVersionInfoW(systemPath, 0, infoSize, infoData.get())
|
|
||||||
|| !VerQueryValueW(infoData.get(), L"\\", (LPVOID*)&vInfo, &vInfoLen)
|
|
||||||
|| !vInfo) {
|
|
||||||
// Can't find version -> Assume it's not blacklisted.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsTArray<nsCString> versions;
|
if (i < modulesNum) {
|
||||||
SplitAt(",", nameAndVersions[1], versions);
|
if (!GetModuleFileNameEx(hProcess, hMods[i], dllPath, sizeof(dllPath) / sizeof(WCHAR))) {
|
||||||
for (const auto& version : versions) {
|
continue;
|
||||||
nsTArray<nsCString> numberStrings;
|
}
|
||||||
SplitAt(".", version, numberStrings);
|
|
||||||
if (numberStrings.Length() != 4) {
|
nsCOMPtr<nsIFile> file;
|
||||||
NS_WARNING(nsPrintfCString("Skipping incorrect '%s' a.b.c.d version format",
|
if (NS_WARN_IF(NS_FAILED(NS_NewLocalFile(nsDependentString(dllPath), false, getter_AddRefs(file))))) {
|
||||||
aDLLBlacklistPrefName).get());
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsAutoString leafName;
|
||||||
|
if (NS_WARN_IF(NS_FAILED(file->GetLeafName(leafName)))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_wcsicmp(leafName.get(), name.get())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!ConstructSystem32Path(name.get(), dllPath, MAX_PATH + 1)) {
|
||||||
|
// Cannot build path -> Assume it's not the blacklisted DLL.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD zero;
|
||||||
|
DWORD infoSize = GetFileVersionInfoSizeW(dllPath, &zero);
|
||||||
|
if (infoSize == 0) {
|
||||||
|
// Can't get file info -> Assume we don't have the blacklisted DLL.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
DWORD numbers[4];
|
// vInfo is a pointer into infoData, that's why we keep it outside of the loop.
|
||||||
nsresult errorCode = NS_OK;
|
auto infoData = MakeUnique<unsigned char[]>(infoSize);
|
||||||
for (int i = 0; i < 4; ++i) {
|
VS_FIXEDFILEINFO *vInfo;
|
||||||
numberStrings[i].CompressWhitespace();
|
UINT vInfoLen;
|
||||||
numbers[i] = DWORD(numberStrings[i].ToInteger(&errorCode));
|
if (!GetFileVersionInfoW(dllPath, 0, infoSize, infoData.get())
|
||||||
|
|| !VerQueryValueW(infoData.get(), L"\\", (LPVOID*)&vInfo, &vInfoLen)
|
||||||
|
|| !vInfo) {
|
||||||
|
// Can't find version -> Assume it's not blacklisted.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsTArray<nsCString> versions;
|
||||||
|
SplitAt(",", nameAndVersions[1], versions);
|
||||||
|
for (const auto& version : versions) {
|
||||||
|
nsTArray<nsCString> numberStrings;
|
||||||
|
SplitAt(".", version, numberStrings);
|
||||||
|
if (numberStrings.Length() != 4) {
|
||||||
|
NS_WARNING(nsPrintfCString("Skipping incorrect '%s' a.b.c.d version format",
|
||||||
|
aDLLBlacklistPrefName).get());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DWORD numbers[4];
|
||||||
|
nsresult errorCode = NS_OK;
|
||||||
|
for (int i = 0; i < 4; ++i) {
|
||||||
|
numberStrings[i].CompressWhitespace();
|
||||||
|
numbers[i] = DWORD(numberStrings[i].ToInteger(&errorCode));
|
||||||
|
if (NS_FAILED(errorCode)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (numbers[i] > UINT16_MAX) {
|
||||||
|
errorCode = NS_ERROR_FAILURE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (NS_FAILED(errorCode)) {
|
if (NS_FAILED(errorCode)) {
|
||||||
break;
|
NS_WARNING(nsPrintfCString("Skipping incorrect '%s' a.b.c.d version format",
|
||||||
|
aDLLBlacklistPrefName).get());
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if (numbers[i] > UINT16_MAX) {
|
|
||||||
errorCode = NS_ERROR_FAILURE;
|
if (vInfo->dwFileVersionMS == ((numbers[0] << 16) | numbers[1])
|
||||||
break;
|
&& vInfo->dwFileVersionLS == ((numbers[2] << 16) | numbers[3])) {
|
||||||
|
// Blacklisted! Record bad DLL.
|
||||||
|
aDLLBlacklistingCache->mBlacklistedDLL.SetLength(0);
|
||||||
|
aDLLBlacklistingCache->mBlacklistedDLL.AppendPrintf(
|
||||||
|
"%s (%lu.%lu.%lu.%lu)",
|
||||||
|
nameAndVersions[0].get(), numbers[0], numbers[1], numbers[2], numbers[3]);
|
||||||
|
return aDLLBlacklistingCache->mBlacklistedDLL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NS_FAILED(errorCode)) {
|
|
||||||
NS_WARNING(nsPrintfCString("Skipping incorrect '%s' a.b.c.d version format",
|
|
||||||
aDLLBlacklistPrefName).get());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vInfo->dwFileVersionMS == ((numbers[0] << 16) | numbers[1])
|
|
||||||
&& vInfo->dwFileVersionLS == ((numbers[2] << 16) | numbers[3])) {
|
|
||||||
// Blacklisted! Record bad DLL.
|
|
||||||
aDLLBlacklistingCache->mBlacklistedDLL.SetLength(0);
|
|
||||||
aDLLBlacklistingCache->mBlacklistedDLL.AppendPrintf(
|
|
||||||
"%s (%lu.%lu.%lu.%lu)",
|
|
||||||
nameAndVersions[0].get(), numbers[0], numbers[1], numbers[2], numbers[3]);
|
|
||||||
return aDLLBlacklistingCache->mBlacklistedDLL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,17 +27,33 @@ using mozilla::plugins::LaunchCompleteTask;
|
||||||
using mozilla::plugins::PluginProcessParent;
|
using mozilla::plugins::PluginProcessParent;
|
||||||
using base::ProcessArchitecture;
|
using base::ProcessArchitecture;
|
||||||
|
|
||||||
|
#ifdef XP_WIN
|
||||||
|
PluginProcessParent::PidSet* PluginProcessParent::sPidSet = nullptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
PluginProcessParent::PluginProcessParent(const std::string& aPluginFilePath) :
|
PluginProcessParent::PluginProcessParent(const std::string& aPluginFilePath) :
|
||||||
GeckoChildProcessHost(GeckoProcessType_Plugin),
|
GeckoChildProcessHost(GeckoProcessType_Plugin)
|
||||||
mPluginFilePath(aPluginFilePath),
|
, mPluginFilePath(aPluginFilePath)
|
||||||
mTaskFactory(this),
|
, mTaskFactory(this)
|
||||||
mMainMsgLoop(MessageLoop::current()),
|
, mMainMsgLoop(MessageLoop::current())
|
||||||
mRunCompleteTaskImmediately(false)
|
, mRunCompleteTaskImmediately(false)
|
||||||
|
#ifdef XP_WIN
|
||||||
|
, mChildPid(0)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginProcessParent::~PluginProcessParent()
|
PluginProcessParent::~PluginProcessParent()
|
||||||
{
|
{
|
||||||
|
#ifdef XP_WIN
|
||||||
|
if (sPidSet && mChildPid) {
|
||||||
|
sPidSet->RemoveEntry(mChildPid);
|
||||||
|
if (sPidSet->IsEmpty()) {
|
||||||
|
delete sPidSet;
|
||||||
|
sPidSet = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
|
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
|
||||||
|
@ -230,6 +246,14 @@ PluginProcessParent::WaitUntilConnected(int32_t aTimeoutMs)
|
||||||
void
|
void
|
||||||
PluginProcessParent::OnChannelConnected(int32_t peer_pid)
|
PluginProcessParent::OnChannelConnected(int32_t peer_pid)
|
||||||
{
|
{
|
||||||
|
#ifdef XP_WIN
|
||||||
|
mChildPid = static_cast<uint32_t>(peer_pid);
|
||||||
|
if (!sPidSet) {
|
||||||
|
sPidSet = new PluginProcessParent::PidSet();
|
||||||
|
}
|
||||||
|
sPidSet->PutEntry(mChildPid);
|
||||||
|
#endif
|
||||||
|
|
||||||
GeckoChildProcessHost::OnChannelConnected(peer_pid);
|
GeckoChildProcessHost::OnChannelConnected(peer_pid);
|
||||||
if (mLaunchCompleteTask && !mRunCompleteTaskImmediately) {
|
if (mLaunchCompleteTask && !mRunCompleteTaskImmediately) {
|
||||||
mLaunchCompleteTask->SetLaunchSucceeded();
|
mLaunchCompleteTask->SetLaunchSucceeded();
|
||||||
|
@ -255,3 +279,13 @@ PluginProcessParent::IsConnected()
|
||||||
return mProcessState == PROCESS_CONNECTED;
|
return mProcessState == PROCESS_CONNECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
PluginProcessParent::IsPluginProcessId(base::ProcessId procId) {
|
||||||
|
#ifdef XP_WIN
|
||||||
|
MOZ_ASSERT(XRE_IsParentProcess());
|
||||||
|
return sPidSet && sPidSet->Contains(static_cast<uint32_t>(procId));
|
||||||
|
#else
|
||||||
|
NS_ERROR("IsPluginProcessId not available on this platform.");
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
|
@ -75,6 +75,8 @@ public:
|
||||||
|
|
||||||
bool IsConnected();
|
bool IsConnected();
|
||||||
|
|
||||||
|
static bool IsPluginProcessId(base::ProcessId procId);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void RunLaunchCompleteTask();
|
void RunLaunchCompleteTask();
|
||||||
|
|
||||||
|
@ -83,6 +85,12 @@ private:
|
||||||
UniquePtr<LaunchCompleteTask> mLaunchCompleteTask;
|
UniquePtr<LaunchCompleteTask> mLaunchCompleteTask;
|
||||||
MessageLoop* mMainMsgLoop;
|
MessageLoop* mMainMsgLoop;
|
||||||
bool mRunCompleteTaskImmediately;
|
bool mRunCompleteTaskImmediately;
|
||||||
|
#ifdef XP_WIN
|
||||||
|
typedef nsTHashtable<nsUint32HashKey> PidSet;
|
||||||
|
// Set of PIDs for all plugin child processes or NULL if empty.
|
||||||
|
static PidSet* sPidSet;
|
||||||
|
uint32_t mChildPid;
|
||||||
|
#endif
|
||||||
|
|
||||||
DISALLOW_EVIL_CONSTRUCTORS(PluginProcessParent);
|
DISALLOW_EVIL_CONSTRUCTORS(PluginProcessParent);
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "nsIFrame.h"
|
#include "nsIFrame.h"
|
||||||
#include "nsIScriptError.h"
|
#include "nsIScriptError.h"
|
||||||
#include "nsLayoutUtils.h"
|
#include "nsLayoutUtils.h"
|
||||||
|
#include "nsMathUtils.h"
|
||||||
#include "SVGAnimationElement.h"
|
#include "SVGAnimationElement.h"
|
||||||
#include "SVGAnimatedPreserveAspectRatio.h"
|
#include "SVGAnimatedPreserveAspectRatio.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
|
@ -509,7 +510,7 @@ SVGContentUtils::RectilinearGetStrokeBounds(const Rect& aRect,
|
||||||
double
|
double
|
||||||
SVGContentUtils::ComputeNormalizedHypotenuse(double aWidth, double aHeight)
|
SVGContentUtils::ComputeNormalizedHypotenuse(double aWidth, double aHeight)
|
||||||
{
|
{
|
||||||
return sqrt((aWidth*aWidth + aHeight*aHeight)/2);
|
return NS_hypot(aWidth, aHeight) / M_SQRT2;
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
|
|
|
@ -9,6 +9,8 @@ interface AccessibleNode {
|
||||||
readonly attribute DOMString role;
|
readonly attribute DOMString role;
|
||||||
[Frozen, Cached, Pure]
|
[Frozen, Cached, Pure]
|
||||||
readonly attribute sequence<DOMString> states;
|
readonly attribute sequence<DOMString> states;
|
||||||
|
[Frozen, Cached, Pure]
|
||||||
|
readonly attribute sequence<DOMString> attributes;
|
||||||
readonly attribute Node? DOMNode;
|
readonly attribute Node? DOMNode;
|
||||||
|
|
||||||
boolean is(DOMString... states);
|
boolean is(DOMString... states);
|
||||||
|
|
|
@ -14,7 +14,6 @@ interface DataTransfer {
|
||||||
|
|
||||||
readonly attribute DataTransferItemList items;
|
readonly attribute DataTransferItemList items;
|
||||||
|
|
||||||
[Throws]
|
|
||||||
void setDragImage(Element image, long x, long y);
|
void setDragImage(Element image, long x, long y);
|
||||||
|
|
||||||
// ReturnValueNeedsContainsHack on .types because lots of extension
|
// ReturnValueNeedsContainsHack on .types because lots of extension
|
||||||
|
@ -132,6 +131,13 @@ partial interface DataTransfer {
|
||||||
[Throws, NeedsSubjectPrincipal]
|
[Throws, NeedsSubjectPrincipal]
|
||||||
any mozGetDataAt(DOMString format, unsigned long index);
|
any mozGetDataAt(DOMString format, unsigned long index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the drag image. Arguments are the same as setDragImage. This is only
|
||||||
|
* valid within the parent chrome process.
|
||||||
|
*/
|
||||||
|
[ChromeOnly]
|
||||||
|
void updateDragImage(Element image, long x, long y);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will be true when the user has cancelled the drag (typically by pressing
|
* Will be true when the user has cancelled the drag (typically by pressing
|
||||||
* Escape) and when the drag has been cancelled unexpectedly. This will be
|
* Escape) and when the drag has been cancelled unexpectedly. This will be
|
||||||
|
|
|
@ -4049,7 +4049,7 @@ WorkerPrivate::WorkerPrivate(WorkerPrivate* aParent,
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
target = GetWindow() ? GetWindow()->GetThrottledEventQueue() : nullptr;
|
target = GetWindow() ? GetWindow()->EventTargetFor(TaskCategory::Worker) : nullptr;
|
||||||
|
|
||||||
if (!target) {
|
if (!target) {
|
||||||
nsCOMPtr<nsIThread> mainThread;
|
nsCOMPtr<nsIThread> mainThread;
|
||||||
|
|
|
@ -65,7 +65,7 @@ public:
|
||||||
{
|
{
|
||||||
MutexAutoLock lock(mMutex);
|
MutexAutoLock lock(mMutex);
|
||||||
MOZ_ASSERT(aLength <= mData.Length());
|
MOZ_ASSERT(aLength <= mData.Length());
|
||||||
return aString.Assign(mData.BeginReading(), aLength, mozilla::fallible);
|
return aString.Assign(mData, aLength, mozilla::fallible);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -6,9 +6,6 @@
|
||||||
#include "mozilla/layers/APZThreadUtils.h"
|
#include "mozilla/layers/APZThreadUtils.h"
|
||||||
|
|
||||||
#include "mozilla/layers/Compositor.h"
|
#include "mozilla/layers/Compositor.h"
|
||||||
#ifdef MOZ_WIDGET_ANDROID
|
|
||||||
#include "AndroidBridge.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace layers {
|
namespace layers {
|
||||||
|
@ -57,15 +54,6 @@ APZThreadUtils::RunOnControllerThread(already_AddRefed<Runnable> aTask)
|
||||||
{
|
{
|
||||||
RefPtr<Runnable> task = aTask;
|
RefPtr<Runnable> task = aTask;
|
||||||
|
|
||||||
#ifdef MOZ_WIDGET_ANDROID
|
|
||||||
// This is needed while nsWindow::ConfigureAPZControllerThread is not propper
|
|
||||||
// implemented.
|
|
||||||
if (AndroidBridge::IsJavaUiThread()) {
|
|
||||||
task->Run();
|
|
||||||
} else {
|
|
||||||
AndroidBridge::Bridge()->PostTaskToUiThread(task.forget(), 0);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (!sControllerThread) {
|
if (!sControllerThread) {
|
||||||
// Could happen on startup
|
// Could happen on startup
|
||||||
NS_WARNING("Dropping task posted to controller thread");
|
NS_WARNING("Dropping task posted to controller thread");
|
||||||
|
@ -77,17 +65,12 @@ APZThreadUtils::RunOnControllerThread(already_AddRefed<Runnable> aTask)
|
||||||
} else {
|
} else {
|
||||||
sControllerThread->PostTask(task.forget());
|
sControllerThread->PostTask(task.forget());
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*static*/ bool
|
/*static*/ bool
|
||||||
APZThreadUtils::IsControllerThread()
|
APZThreadUtils::IsControllerThread()
|
||||||
{
|
{
|
||||||
#ifdef MOZ_WIDGET_ANDROID
|
|
||||||
return AndroidBridge::IsJavaUiThread();
|
|
||||||
#else
|
|
||||||
return sControllerThread == MessageLoop::current();
|
return sControllerThread == MessageLoop::current();
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS(GenericTimerCallbackBase, nsITimerCallback)
|
NS_IMPL_ISUPPORTS(GenericTimerCallbackBase, nsITimerCallback)
|
||||||
|
|
|
@ -18,9 +18,6 @@
|
||||||
#include "mozilla/gfx/GPUProcessManager.h"
|
#include "mozilla/gfx/GPUProcessManager.h"
|
||||||
#include "mozilla/Unused.h"
|
#include "mozilla/Unused.h"
|
||||||
#include "Units.h"
|
#include "Units.h"
|
||||||
#ifdef MOZ_WIDGET_ANDROID
|
|
||||||
#include "AndroidBridge.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace layers {
|
namespace layers {
|
||||||
|
@ -139,12 +136,8 @@ RemoteContentController::NotifyPinchGesture(PinchGestureInput::PinchGestureType
|
||||||
void
|
void
|
||||||
RemoteContentController::PostDelayedTask(already_AddRefed<Runnable> aTask, int aDelayMs)
|
RemoteContentController::PostDelayedTask(already_AddRefed<Runnable> aTask, int aDelayMs)
|
||||||
{
|
{
|
||||||
#ifdef MOZ_WIDGET_ANDROID
|
|
||||||
AndroidBridge::Bridge()->PostTaskToUiThread(Move(aTask), aDelayMs);
|
|
||||||
#else
|
|
||||||
(MessageLoop::current() ? MessageLoop::current() : mCompositorThread)->
|
(MessageLoop::current() ? MessageLoop::current() : mCompositorThread)->
|
||||||
PostDelayedTask(Move(aTask), aDelayMs);
|
PostDelayedTask(Move(aTask), aDelayMs);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -251,6 +251,12 @@ DynamicImage::StartDecoding(uint32_t aFlags)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
DynamicImage::StartDecodingWithResult(uint32_t aFlags)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
DynamicImage::RequestDecodeForSize(const nsIntSize& aSize, uint32_t aFlags)
|
DynamicImage::RequestDecodeForSize(const nsIntSize& aSize, uint32_t aFlags)
|
||||||
{
|
{
|
||||||
|
|
|
@ -221,6 +221,12 @@ ImageWrapper::StartDecoding(uint32_t aFlags)
|
||||||
return mInnerImage->StartDecoding(aFlags);
|
return mInnerImage->StartDecoding(aFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ImageWrapper::StartDecodingWithResult(uint32_t aFlags)
|
||||||
|
{
|
||||||
|
return mInnerImage->StartDecodingWithResult(aFlags);
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
ImageWrapper::RequestDecodeForSize(const nsIntSize& aSize, uint32_t aFlags)
|
ImageWrapper::RequestDecodeForSize(const nsIntSize& aSize, uint32_t aFlags)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1049,6 +1049,23 @@ RasterImage::StartDecoding(uint32_t aFlags)
|
||||||
return RequestDecodeForSize(mSize, flags);
|
return RequestDecodeForSize(mSize, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
RasterImage::StartDecodingWithResult(uint32_t aFlags)
|
||||||
|
{
|
||||||
|
if (mError) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mHasSize) {
|
||||||
|
mWantFullDecode = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t flags = (aFlags & FLAG_ASYNC_NOTIFY) | FLAG_SYNC_DECODE_IF_FAST;
|
||||||
|
DrawableSurface surface = RequestDecodeForSizeInternal(mSize, flags);
|
||||||
|
return surface && surface->IsFinished();
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
RasterImage::RequestDecodeForSize(const IntSize& aSize, uint32_t aFlags)
|
RasterImage::RequestDecodeForSize(const IntSize& aSize, uint32_t aFlags)
|
||||||
{
|
{
|
||||||
|
@ -1058,9 +1075,23 @@ RasterImage::RequestDecodeForSize(const IntSize& aSize, uint32_t aFlags)
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RequestDecodeForSizeInternal(aSize, aFlags);
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawableSurface
|
||||||
|
RasterImage::RequestDecodeForSizeInternal(const IntSize& aSize, uint32_t aFlags)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
if (mError) {
|
||||||
|
return DrawableSurface();
|
||||||
|
}
|
||||||
|
|
||||||
if (!mHasSize) {
|
if (!mHasSize) {
|
||||||
mWantFullDecode = true;
|
mWantFullDecode = true;
|
||||||
return NS_OK;
|
return DrawableSurface();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decide whether to sync decode images we can decode quickly. Here we are
|
// Decide whether to sync decode images we can decode quickly. Here we are
|
||||||
|
@ -1074,10 +1105,8 @@ RasterImage::RequestDecodeForSize(const IntSize& aSize, uint32_t aFlags)
|
||||||
: aFlags & ~FLAG_SYNC_DECODE_IF_FAST;
|
: aFlags & ~FLAG_SYNC_DECODE_IF_FAST;
|
||||||
|
|
||||||
// Perform a frame lookup, which will implicitly start decoding if needed.
|
// Perform a frame lookup, which will implicitly start decoding if needed.
|
||||||
LookupFrame(aSize, flags, mAnimationState ? PlaybackType::eAnimated
|
return LookupFrame(aSize, flags, mAnimationState ? PlaybackType::eAnimated
|
||||||
: PlaybackType::eStatic);
|
: PlaybackType::eStatic);
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
|
|
@ -480,6 +480,8 @@ private: // data
|
||||||
|
|
||||||
bool IsOpaque();
|
bool IsOpaque();
|
||||||
|
|
||||||
|
DrawableSurface RequestDecodeForSizeInternal(const gfx::IntSize& aSize, uint32_t aFlags);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit RasterImage(ImageURL* aURI = nullptr);
|
explicit RasterImage(ImageURL* aURI = nullptr);
|
||||||
|
|
||||||
|
|
|
@ -1032,6 +1032,13 @@ VectorImage::StartDecoding(uint32_t aFlags)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
VectorImage::StartDecodingWithResult(uint32_t aFlags)
|
||||||
|
{
|
||||||
|
// SVG images are ready to draw when they are loaded
|
||||||
|
return mIsFullyLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
VectorImage::RequestDecodeForSize(const nsIntSize& aSize, uint32_t aFlags)
|
VectorImage::RequestDecodeForSize(const nsIntSize& aSize, uint32_t aFlags)
|
||||||
{
|
{
|
||||||
|
|
|
@ -420,6 +420,15 @@ interface imgIContainer : nsISupports
|
||||||
*/
|
*/
|
||||||
[noscript] void startDecoding(in uint32_t aFlags);
|
[noscript] void startDecoding(in uint32_t aFlags);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Exactly like startDecoding above except returns whether the current frame
|
||||||
|
* of the image is complete or not.
|
||||||
|
*
|
||||||
|
* @param aFlags Flags of the FLAG_* variety. Only FLAG_ASYNC_NOTIFY
|
||||||
|
* is accepted; all others are ignored.
|
||||||
|
*/
|
||||||
|
[noscript, notxpcom] boolean startDecodingWithResult(in uint32_t aFlags);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This method triggers decoding for an image, but unlike startDecoding() it
|
* This method triggers decoding for an image, but unlike startDecoding() it
|
||||||
* enables the caller to provide more detailed information about the decode
|
* enables the caller to provide more detailed information about the decode
|
||||||
|
|
|
@ -155,6 +155,12 @@ interface imgIRequest : nsIRequest
|
||||||
*/
|
*/
|
||||||
void startDecoding(in uint32_t aFlags);
|
void startDecoding(in uint32_t aFlags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exactly like startDecoding above except returns whether the current frame
|
||||||
|
* of the image is complete or not.
|
||||||
|
*/
|
||||||
|
[noscript, notxpcom] boolean startDecodingWithResult(in uint32_t aFlags);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Locks an image. If the image does not exist yet, locks it once it becomes
|
* Locks an image. If the image does not exist yet, locks it once it becomes
|
||||||
* available. The lock persists for the lifetime of the imgIRequest (until
|
* available. The lock persists for the lifetime of the imgIRequest (until
|
||||||
|
|
|
@ -375,6 +375,24 @@ imgRequestProxy::StartDecoding(uint32_t aFlags)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
imgRequestProxy::StartDecodingWithResult(uint32_t aFlags)
|
||||||
|
{
|
||||||
|
// Flag this, so we know to transfer the request if our owner changes
|
||||||
|
mDecodeRequested = true;
|
||||||
|
|
||||||
|
RefPtr<Image> image = GetImage();
|
||||||
|
if (image) {
|
||||||
|
return image->StartDecodingWithResult(aFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetOwner()) {
|
||||||
|
GetOwner()->StartDecoding();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
imgRequestProxy::LockImage()
|
imgRequestProxy::LockImage()
|
||||||
{
|
{
|
||||||
|
|
|
@ -130,6 +130,12 @@ MessageLoop::MessageLoop(Type type, nsIThread* aThread)
|
||||||
pump_ = new mozilla::ipc::MessagePumpForNonMainUIThreads(aThread);
|
pump_ = new mozilla::ipc::MessagePumpForNonMainUIThreads(aThread);
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(MOZ_WIDGET_ANDROID)
|
||||||
|
case TYPE_MOZILLA_ANDROID_UI:
|
||||||
|
MOZ_RELEASE_ASSERT(aThread);
|
||||||
|
pump_ = new mozilla::ipc::MessagePumpForAndroidUI(aThread);
|
||||||
|
return;
|
||||||
|
#endif // defined(MOZ_WIDGET_ANDROID)
|
||||||
default:
|
default:
|
||||||
// Create one of Chromium's standard MessageLoop types below.
|
// Create one of Chromium's standard MessageLoop types below.
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -180,7 +180,8 @@ public:
|
||||||
TYPE_MOZILLA_CHILD,
|
TYPE_MOZILLA_CHILD,
|
||||||
TYPE_MOZILLA_PARENT,
|
TYPE_MOZILLA_PARENT,
|
||||||
TYPE_MOZILLA_NONMAINTHREAD,
|
TYPE_MOZILLA_NONMAINTHREAD,
|
||||||
TYPE_MOZILLA_NONMAINUITHREAD
|
TYPE_MOZILLA_NONMAINUITHREAD,
|
||||||
|
TYPE_MOZILLA_ANDROID_UI
|
||||||
};
|
};
|
||||||
|
|
||||||
// Normally, it is not necessary to instantiate a MessageLoop. Instead, it
|
// Normally, it is not necessary to instantiate a MessageLoop. Instead, it
|
||||||
|
|
|
@ -463,3 +463,29 @@ MessagePumpForNonMainUIThreads::AfterProcessNextEvent(nsIThreadInternal *thread,
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // XP_WIN
|
#endif // XP_WIN
|
||||||
|
|
||||||
|
#if defined(MOZ_WIDGET_ANDROID)
|
||||||
|
void
|
||||||
|
MessagePumpForAndroidUI::Run(Delegate* delegate)
|
||||||
|
{
|
||||||
|
MOZ_CRASH("MessagePumpForAndroidUI should never be Run.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MessagePumpForAndroidUI::Quit()
|
||||||
|
{
|
||||||
|
MOZ_CRASH("MessagePumpForAndroidUI should never be Quit.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MessagePumpForAndroidUI::ScheduleWork()
|
||||||
|
{
|
||||||
|
MOZ_CRASH("MessagePumpForAndroidUI should never ScheduleWork");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MessagePumpForAndroidUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time)
|
||||||
|
{
|
||||||
|
MOZ_CRASH("MessagePumpForAndroidUI should never ScheduleDelayedWork");
|
||||||
|
}
|
||||||
|
#endif // defined(MOZ_WIDGET_ANDROID)
|
||||||
|
|
|
@ -164,6 +164,43 @@ private:
|
||||||
};
|
};
|
||||||
#endif // defined(XP_WIN)
|
#endif // defined(XP_WIN)
|
||||||
|
|
||||||
|
#if defined(MOZ_WIDGET_ANDROID)
|
||||||
|
/*`
|
||||||
|
* The MessagePumpForAndroidUI exists to enable IPDL in the Android UI thread. The Android
|
||||||
|
* UI thread event loop is controlled by Android. This prevents running an existing
|
||||||
|
* MessagePump implementation in the Android UI thread. In order to enable IPDL on the
|
||||||
|
* Android UI thread it is necessary to have a non-looping MessagePump. This class enables
|
||||||
|
* forwarding of nsIRunnables from MessageLoop::PostTask_Helper to the registered
|
||||||
|
* nsIEventTarget with out the need to control the event loop. The only member function
|
||||||
|
* that should be invoked is GetXPCOMThread. All other member functions will invoke MOZ_CRASH
|
||||||
|
*/
|
||||||
|
class MessagePumpForAndroidUI : public base::MessagePump {
|
||||||
|
|
||||||
|
public:
|
||||||
|
MessagePumpForAndroidUI(nsIEventTarget* aEventTarget)
|
||||||
|
: mEventTarget(aEventTarget)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
virtual void Run(Delegate* delegate);
|
||||||
|
virtual void Quit();
|
||||||
|
virtual void ScheduleWork();
|
||||||
|
virtual void ScheduleDelayedWork(const base::TimeTicks& delayed_work_time);
|
||||||
|
virtual nsIEventTarget* GetXPCOMThread()
|
||||||
|
{
|
||||||
|
return mEventTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
~MessagePumpForAndroidUI()
|
||||||
|
{ }
|
||||||
|
MessagePumpForAndroidUI()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
nsIEventTarget* mEventTarget;
|
||||||
|
};
|
||||||
|
#endif // defined(MOZ_WIDGET_ANDROID)
|
||||||
|
|
||||||
|
|
||||||
} /* namespace ipc */
|
} /* namespace ipc */
|
||||||
} /* namespace mozilla */
|
} /* namespace mozilla */
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ private:
|
||||||
class MOZ_RAII DeneuteredWindowRegion
|
class MOZ_RAII DeneuteredWindowRegion
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DeneuteredWindowRegion(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
|
explicit DeneuteredWindowRegion(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
|
||||||
~DeneuteredWindowRegion();
|
~DeneuteredWindowRegion();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -60,7 +60,7 @@ private:
|
||||||
class MOZ_RAII SuppressedNeuteringRegion
|
class MOZ_RAII SuppressedNeuteringRegion
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SuppressedNeuteringRegion(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
|
explicit SuppressedNeuteringRegion(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
|
||||||
~SuppressedNeuteringRegion();
|
~SuppressedNeuteringRegion();
|
||||||
|
|
||||||
static inline bool IsNeuteringSuppressed() { return sSuppressNeutering; }
|
static inline bool IsNeuteringSuppressed() { return sSuppressNeutering; }
|
||||||
|
|
|
@ -799,6 +799,16 @@ IToplevelProtocol::GetMessageEventTarget(const Message& aMsg)
|
||||||
return target.forget();
|
return target.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
already_AddRefed<nsIEventTarget>
|
||||||
|
IToplevelProtocol::GetActorEventTarget(IProtocol* aActor)
|
||||||
|
{
|
||||||
|
MOZ_RELEASE_ASSERT(aActor->Id() != kNullActorId && aActor->Id() != kFreedActorId);
|
||||||
|
|
||||||
|
MutexAutoLock lock(mEventTargetMutex);
|
||||||
|
nsCOMPtr<nsIEventTarget> target = mEventTargetMap.Lookup(aActor->Id());
|
||||||
|
return target.forget();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
IToplevelProtocol::SetEventTargetForActorInternal(IProtocol* aActor,
|
IToplevelProtocol::SetEventTargetForActorInternal(IProtocol* aActor,
|
||||||
nsIEventTarget* aEventTarget)
|
nsIEventTarget* aEventTarget)
|
||||||
|
|
|
@ -362,6 +362,9 @@ public:
|
||||||
virtual already_AddRefed<nsIEventTarget>
|
virtual already_AddRefed<nsIEventTarget>
|
||||||
GetMessageEventTarget(const Message& aMsg);
|
GetMessageEventTarget(const Message& aMsg);
|
||||||
|
|
||||||
|
already_AddRefed<nsIEventTarget>
|
||||||
|
GetActorEventTarget(IProtocol* aActor);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual already_AddRefed<nsIEventTarget>
|
virtual already_AddRefed<nsIEventTarget>
|
||||||
GetConstructedEventTarget(const Message& aMsg) { return nullptr; }
|
GetConstructedEventTarget(const Message& aMsg) { return nullptr; }
|
||||||
|
|
|
@ -7,20 +7,84 @@
|
||||||
#ifndef js_RefCounted_h
|
#ifndef js_RefCounted_h
|
||||||
#define js_RefCounted_h
|
#define js_RefCounted_h
|
||||||
|
|
||||||
#include "mozilla/RefCounted.h"
|
#include "mozilla/Atomics.h"
|
||||||
|
#include "mozilla/RefCountType.h"
|
||||||
|
|
||||||
#include "js/Utility.h"
|
#include "js/Utility.h"
|
||||||
|
|
||||||
|
// These types implement the same interface as mozilla::(Atomic)RefCounted and
|
||||||
|
// must be used instead of mozilla::(Atomic)RefCounted for everything in
|
||||||
|
// SpiderMonkey. There are two reasons:
|
||||||
|
// - Release() needs to call js_delete, not delete
|
||||||
|
// - SpiderMonkey does not have MOZILLA_INTERNAL_API defined which can lead
|
||||||
|
// to ODR violations that show up as spurious leak reports when ref-counted
|
||||||
|
// types are allocated by SpiderMonkey and released by Gecko (or vice versa).
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
// Replacement for mozilla::RefCounted and mozilla::external::AtomicRefCounted
|
template <typename T>
|
||||||
// that default to JS::DeletePolicy.
|
class RefCounted
|
||||||
|
{
|
||||||
|
static const MozRefCountType DEAD = 0xffffdead;
|
||||||
|
|
||||||
template <typename T, typename D = JS::DeletePolicy<T>>
|
protected:
|
||||||
using RefCounted = mozilla::RefCounted<T, D>;
|
RefCounted() : mRefCnt(0) {}
|
||||||
|
~RefCounted() { MOZ_ASSERT(mRefCnt == DEAD); }
|
||||||
|
|
||||||
template <typename T, typename D = JS::DeletePolicy<T>>
|
public:
|
||||||
using AtomicRefCounted = mozilla::external::AtomicRefCounted<T, D>;
|
void AddRef() const
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(int32_t(mRefCnt) >= 0);
|
||||||
|
++mRefCnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Release() const
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(int32_t(mRefCnt) > 0);
|
||||||
|
MozRefCountType cnt = --mRefCnt;
|
||||||
|
if (0 == cnt) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
mRefCnt = DEAD;
|
||||||
|
#endif
|
||||||
|
js_delete(const_cast<T*>(static_cast<const T*>(this)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
mutable MozRefCountType mRefCnt;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class AtomicRefCounted
|
||||||
|
{
|
||||||
|
static const MozRefCountType DEAD = 0xffffdead;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
AtomicRefCounted() : mRefCnt(0) {}
|
||||||
|
~AtomicRefCounted() { MOZ_ASSERT(mRefCnt == DEAD); }
|
||||||
|
|
||||||
|
public:
|
||||||
|
void AddRef() const
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(int32_t(mRefCnt) >= 0);
|
||||||
|
++mRefCnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Release() const
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(int32_t(mRefCnt) > 0);
|
||||||
|
MozRefCountType cnt = --mRefCnt;
|
||||||
|
if (0 == cnt) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
mRefCnt = DEAD;
|
||||||
|
#endif
|
||||||
|
js_delete(const_cast<T*>(static_cast<const T*>(this)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
mutable mozilla::Atomic<MozRefCountType> mRefCnt;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace js
|
} // namespace js
|
||||||
|
|
||||||
|
|
|
@ -84,8 +84,7 @@ static bool
|
||||||
ReportOutOfRange(JSContext* cx)
|
ReportOutOfRange(JSContext* cx)
|
||||||
{
|
{
|
||||||
// Use JSMSG_BAD_INDEX here even if it is generic, since that is
|
// Use JSMSG_BAD_INDEX here even if it is generic, since that is
|
||||||
// the message used by ToIntegerIndex for its initial range
|
// the message used by NonStandardToIndex for its initial range checking.
|
||||||
// checking.
|
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
|
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -115,7 +114,7 @@ static bool
|
||||||
GetTypedArrayIndex(JSContext* cx, HandleValue v, Handle<TypedArrayObject*> view, uint32_t* offset)
|
GetTypedArrayIndex(JSContext* cx, HandleValue v, Handle<TypedArrayObject*> view, uint32_t* offset)
|
||||||
{
|
{
|
||||||
uint64_t index;
|
uint64_t index;
|
||||||
if (!js::ToIntegerIndex(cx, v, &index))
|
if (!NonStandardToIndex(cx, v, &index))
|
||||||
return false;
|
return false;
|
||||||
if (index >= view->length())
|
if (index >= view->length())
|
||||||
return ReportOutOfRange(cx);
|
return ReportOutOfRange(cx);
|
||||||
|
|
|
@ -1339,7 +1339,7 @@ static bool
|
||||||
ArgumentToLaneIndex(JSContext* cx, JS::HandleValue v, unsigned limit, unsigned* lane)
|
ArgumentToLaneIndex(JSContext* cx, JS::HandleValue v, unsigned limit, unsigned* lane)
|
||||||
{
|
{
|
||||||
uint64_t arg;
|
uint64_t arg;
|
||||||
if (!ToIntegerIndex(cx, v, &arg))
|
if (!NonStandardToIndex(cx, v, &arg))
|
||||||
return false;
|
return false;
|
||||||
if (arg >= limit)
|
if (arg >= limit)
|
||||||
return ErrorBadIndex(cx);
|
return ErrorBadIndex(cx);
|
||||||
|
@ -1366,7 +1366,7 @@ TypedArrayFromArgs(JSContext* cx, const CallArgs& args, uint32_t accessBytes,
|
||||||
typedArray.set(&argobj);
|
typedArray.set(&argobj);
|
||||||
|
|
||||||
uint64_t index;
|
uint64_t index;
|
||||||
if (!ToIntegerIndex(cx, args[1], &index))
|
if (!NonStandardToIndex(cx, args[1], &index))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Do the range check in 64 bits even when size_t is 32 bits.
|
// Do the range check in 64 bits even when size_t is 32 bits.
|
||||||
|
|
|
@ -228,6 +228,10 @@ var ignoreFunctions = {
|
||||||
"calloc" : true,
|
"calloc" : true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function extraGCFunctions() {
|
||||||
|
return ["ffi_call"];
|
||||||
|
}
|
||||||
|
|
||||||
function isProtobuf(name)
|
function isProtobuf(name)
|
||||||
{
|
{
|
||||||
return name.match(/\bgoogle::protobuf\b/) ||
|
return name.match(/\bgoogle::protobuf\b/) ||
|
||||||
|
|
|
@ -126,6 +126,11 @@ function loadCallgraph(file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add in any extra functions at the end. (If we did this early, it would
|
||||||
|
// mess up the id <-> name correspondence.)
|
||||||
|
for (var func of extraGCFunctions())
|
||||||
|
addGCFunction(func, "annotation");
|
||||||
|
|
||||||
// Initialize suppressedFunctions to the set of all functions, and the
|
// Initialize suppressedFunctions to the set of all functions, and the
|
||||||
// worklist to all toplevel callers.
|
// worklist to all toplevel callers.
|
||||||
var worklist = [];
|
var worklist = [];
|
||||||
|
|
|
@ -51,16 +51,17 @@ HeapSlot::preconditionForSet(NativeObject* owner, Kind kind, uint32_t slot) cons
|
||||||
: &owner->getDenseElement(slot) == (const Value*)this;
|
: &owner->getDenseElement(slot) == (const Value*)this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
HeapSlot::preconditionForWriteBarrierPost(NativeObject* obj, Kind kind, uint32_t slot,
|
HeapSlot::assertPreconditionForWriteBarrierPost(NativeObject* obj, Kind kind, uint32_t slot,
|
||||||
const Value& target) const
|
const Value& target) const
|
||||||
{
|
{
|
||||||
bool isCorrectSlot = kind == Slot
|
if (kind == Slot)
|
||||||
? obj->getSlotAddressUnchecked(slot)->get() == target
|
MOZ_ASSERT(obj->getSlotAddressUnchecked(slot)->get() == target);
|
||||||
: static_cast<HeapSlot*>(obj->getDenseElements() + slot)->get() == target;
|
else
|
||||||
bool isBlackToGray = target.isMarkable() &&
|
MOZ_ASSERT(static_cast<HeapSlot*>(obj->getDenseElements() + slot)->get() == target);
|
||||||
IsMarkedBlack(obj) && JS::GCThingIsMarkedGray(JS::GCCellPtr(target));
|
|
||||||
return isCorrectSlot && !isBlackToGray;
|
MOZ_ASSERT_IF(target.isMarkable() && IsMarkedBlack(obj),
|
||||||
|
!JS::GCThingIsMarkedGray(JS::GCCellPtr(target)));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -676,8 +676,8 @@ class HeapSlot : public WriteBarrieredBase<Value>
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
bool preconditionForSet(NativeObject* owner, Kind kind, uint32_t slot) const;
|
bool preconditionForSet(NativeObject* owner, Kind kind, uint32_t slot) const;
|
||||||
bool preconditionForWriteBarrierPost(NativeObject* obj, Kind kind, uint32_t slot,
|
void assertPreconditionForWriteBarrierPost(NativeObject* obj, Kind kind, uint32_t slot,
|
||||||
const Value& target) const;
|
const Value& target) const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void set(NativeObject* owner, Kind kind, uint32_t slot, const Value& v) {
|
void set(NativeObject* owner, Kind kind, uint32_t slot, const Value& v) {
|
||||||
|
@ -694,7 +694,9 @@ class HeapSlot : public WriteBarrieredBase<Value>
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void post(NativeObject* owner, Kind kind, uint32_t slot, const Value& target) {
|
void post(NativeObject* owner, Kind kind, uint32_t slot, const Value& target) {
|
||||||
MOZ_ASSERT(preconditionForWriteBarrierPost(owner, kind, slot, target));
|
#ifdef DEBUG
|
||||||
|
assertPreconditionForWriteBarrierPost(owner, kind, slot, target);
|
||||||
|
#endif
|
||||||
if (this->value.isObject()) {
|
if (this->value.isObject()) {
|
||||||
gc::Cell* cell = reinterpret_cast<gc::Cell*>(&this->value.toObject());
|
gc::Cell* cell = reinterpret_cast<gc::Cell*>(&this->value.toObject());
|
||||||
if (cell->storeBuffer())
|
if (cell->storeBuffer())
|
||||||
|
|
|
@ -254,8 +254,10 @@ Zone::discardJitCode(FreeOp* fop, bool discardBaselineCode)
|
||||||
*
|
*
|
||||||
* Defer freeing any allocated blocks until after the next minor GC.
|
* Defer freeing any allocated blocks until after the next minor GC.
|
||||||
*/
|
*/
|
||||||
if (discardBaselineCode)
|
if (discardBaselineCode) {
|
||||||
jitZone()->optimizedStubSpace()->freeAllAfterMinorGC(fop->runtime());
|
jitZone()->optimizedStubSpace()->freeAllAfterMinorGC(fop->runtime());
|
||||||
|
jitZone()->purgeIonCacheIRStubInfo();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free all control flow graphs that are cached on BaselineScripts.
|
* Free all control flow graphs that are cached on BaselineScripts.
|
||||||
|
|
|
@ -7,6 +7,7 @@ with(7) {
|
||||||
}
|
}
|
||||||
const x = 42;
|
const x = 42;
|
||||||
function g() {
|
function g() {
|
||||||
|
eval("");
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
return g;
|
return g;
|
||||||
|
|
|
@ -15,7 +15,7 @@ assertEq(names.length, 1);
|
||||||
assertEq(names[0], 'a');
|
assertEq(names[0], 'a');
|
||||||
var desc = Object.getOwnPropertyDescriptor(o, 'a');
|
var desc = Object.getOwnPropertyDescriptor(o, 'a');
|
||||||
assertEq(typeof desc.value, "function");
|
assertEq(typeof desc.value, "function");
|
||||||
assertEq(desc.value.name, "wasm-function[0]");
|
assertEq(desc.value.name, "0");
|
||||||
assertEq(desc.value.length, 0);
|
assertEq(desc.value.length, 0);
|
||||||
assertEq(desc.value(), undefined);
|
assertEq(desc.value(), undefined);
|
||||||
assertEq(desc.writable, false);
|
assertEq(desc.writable, false);
|
||||||
|
@ -33,14 +33,14 @@ wasmFailValidateText('(module (func) (func) (export "a" 2))', /exported function
|
||||||
|
|
||||||
var o = wasmEvalText('(module (func) (export "a" 0) (export "b" 0))').exports;
|
var o = wasmEvalText('(module (func) (export "a" 0) (export "b" 0))').exports;
|
||||||
assertEq(Object.getOwnPropertyNames(o).sort().toString(), "a,b");
|
assertEq(Object.getOwnPropertyNames(o).sort().toString(), "a,b");
|
||||||
assertEq(o.a.name, "wasm-function[0]");
|
assertEq(o.a.name, "0");
|
||||||
assertEq(o.b.name, "wasm-function[0]");
|
assertEq(o.b.name, "0");
|
||||||
assertEq(o.a === o.b, true);
|
assertEq(o.a === o.b, true);
|
||||||
|
|
||||||
var o = wasmEvalText('(module (func) (func) (export "a" 0) (export "b" 1))').exports;
|
var o = wasmEvalText('(module (func) (func) (export "a" 0) (export "b" 1))').exports;
|
||||||
assertEq(Object.getOwnPropertyNames(o).sort().toString(), "a,b");
|
assertEq(Object.getOwnPropertyNames(o).sort().toString(), "a,b");
|
||||||
assertEq(o.a.name, "wasm-function[0]");
|
assertEq(o.a.name, "0");
|
||||||
assertEq(o.b.name, "wasm-function[1]");
|
assertEq(o.b.name, "1");
|
||||||
assertEq(o.a === o.b, false);
|
assertEq(o.a === o.b, false);
|
||||||
|
|
||||||
var o = wasmEvalText('(module (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) (export "a" 0) (export "b" 1))').exports;
|
var o = wasmEvalText('(module (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) (export "a" 0) (export "b" 1))').exports;
|
||||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче