This commit is contained in:
Phil Ringnalda 2016-12-24 16:54:02 -08:00
Родитель 54f2387792 b94a0cbd73
Коммит ac954c6a3f
287 изменённых файлов: 21594 добавлений и 17443 удалений

Просмотреть файл

@ -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/**

Просмотреть файл

@ -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;

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше