Merge m-c to b2ginbound, a=merge

This commit is contained in:
Wes Kocher 2015-07-24 13:47:56 -07:00
Родитель 91f6865f7b c835884065
Коммит c090d50b89
165 изменённых файлов: 4313 добавлений и 1938 удалений

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

@ -88,3 +88,7 @@ GPATH
# XCode project cruft
^embedding/ios/GeckoEmbed/GeckoEmbed.xcodeproj/project.xcworkspace/xcuserdata
^embedding/ios/GeckoEmbed/GeckoEmbed.xcodeproj/xcuserdata
# Ignore mozharness execution files
^testing/mozharness/logs/
^testing/mozharness/build/

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

@ -204,7 +204,89 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime)
}
// Process rendered text change notifications.
mTextHash.EnumerateEntries(TextEnumerator, mDocument);
for (auto iter = mTextHash.Iter(); !iter.Done(); iter.Next()) {
nsCOMPtrHashKey<nsIContent>* entry = iter.Get();
nsIContent* textNode = entry->GetKey();
Accessible* textAcc = mDocument->GetAccessible(textNode);
// If the text node is not in tree or doesn't have frame then this case should
// have been handled already by content removal notifications.
nsINode* containerNode = textNode->GetParentNode();
if (!containerNode) {
NS_ASSERTION(!textAcc,
"Text node was removed but accessible is kept alive!");
continue;
}
nsIFrame* textFrame = textNode->GetPrimaryFrame();
if (!textFrame) {
NS_ASSERTION(!textAcc,
"Text node isn't rendered but accessible is kept alive!");
continue;
}
nsIContent* containerElm = containerNode->IsElement() ?
containerNode->AsElement() : nullptr;
nsAutoString text;
textFrame->GetRenderedText(&text);
// Remove text accessible if rendered text is empty.
if (textAcc) {
if (text.IsEmpty()) {
#ifdef A11Y_LOG
if (logging::IsEnabled(logging::eTree | logging::eText)) {
logging::MsgBegin("TREE", "text node lost its content");
logging::Node("container", containerElm);
logging::Node("content", textNode);
logging::MsgEnd();
}
#endif
mDocument->ContentRemoved(containerElm, textNode);
continue;
}
// Update text of the accessible and fire text change events.
#ifdef A11Y_LOG
if (logging::IsEnabled(logging::eText)) {
logging::MsgBegin("TEXT", "text may be changed");
logging::Node("container", containerElm);
logging::Node("content", textNode);
logging::MsgEntry("old text '%s'",
NS_ConvertUTF16toUTF8(textAcc->AsTextLeaf()->Text()).get());
logging::MsgEntry("new text: '%s'",
NS_ConvertUTF16toUTF8(text).get());
logging::MsgEnd();
}
#endif
TextUpdater::Run(mDocument, textAcc->AsTextLeaf(), text);
continue;
}
// Append an accessible if rendered text is not empty.
if (!text.IsEmpty()) {
#ifdef A11Y_LOG
if (logging::IsEnabled(logging::eTree | logging::eText)) {
logging::MsgBegin("TREE", "text node gains new content");
logging::Node("container", containerElm);
logging::Node("content", textNode);
logging::MsgEnd();
}
#endif
// Make sure the text node is in accessible document still.
Accessible* container = mDocument->GetAccessibleOrContainer(containerNode);
NS_ASSERTION(container,
"Text node having rendered text hasn't accessible document!");
if (container) {
nsTArray<nsCOMPtr<nsIContent> > insertedContents;
insertedContents.AppendElement(textNode);
mDocument->ProcessContentInserted(container, &insertedContents);
}
}
}
mTextHash.Clear();
// Bind hanging child documents.
@ -314,99 +396,6 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime)
}
}
////////////////////////////////////////////////////////////////////////////////
// Notification controller: text leaf accessible text update
PLDHashOperator
NotificationController::TextEnumerator(nsCOMPtrHashKey<nsIContent>* aEntry,
void* aUserArg)
{
DocAccessible* document = static_cast<DocAccessible*>(aUserArg);
nsIContent* textNode = aEntry->GetKey();
Accessible* textAcc = document->GetAccessible(textNode);
// If the text node is not in tree or doesn't have frame then this case should
// have been handled already by content removal notifications.
nsINode* containerNode = textNode->GetParentNode();
if (!containerNode) {
NS_ASSERTION(!textAcc,
"Text node was removed but accessible is kept alive!");
return PL_DHASH_NEXT;
}
nsIFrame* textFrame = textNode->GetPrimaryFrame();
if (!textFrame) {
NS_ASSERTION(!textAcc,
"Text node isn't rendered but accessible is kept alive!");
return PL_DHASH_NEXT;
}
nsIContent* containerElm = containerNode->IsElement() ?
containerNode->AsElement() : nullptr;
nsAutoString text;
textFrame->GetRenderedText(&text);
// Remove text accessible if rendered text is empty.
if (textAcc) {
if (text.IsEmpty()) {
#ifdef A11Y_LOG
if (logging::IsEnabled(logging::eTree | logging::eText)) {
logging::MsgBegin("TREE", "text node lost its content");
logging::Node("container", containerElm);
logging::Node("content", textNode);
logging::MsgEnd();
}
#endif
document->ContentRemoved(containerElm, textNode);
return PL_DHASH_NEXT;
}
// Update text of the accessible and fire text change events.
#ifdef A11Y_LOG
if (logging::IsEnabled(logging::eText)) {
logging::MsgBegin("TEXT", "text may be changed");
logging::Node("container", containerElm);
logging::Node("content", textNode);
logging::MsgEntry("old text '%s'",
NS_ConvertUTF16toUTF8(textAcc->AsTextLeaf()->Text()).get());
logging::MsgEntry("new text: '%s'",
NS_ConvertUTF16toUTF8(text).get());
logging::MsgEnd();
}
#endif
TextUpdater::Run(document, textAcc->AsTextLeaf(), text);
return PL_DHASH_NEXT;
}
// Append an accessible if rendered text is not empty.
if (!text.IsEmpty()) {
#ifdef A11Y_LOG
if (logging::IsEnabled(logging::eTree | logging::eText)) {
logging::MsgBegin("TREE", "text node gains new content");
logging::Node("container", containerElm);
logging::Node("content", textNode);
logging::MsgEnd();
}
#endif
// Make sure the text node is in accessible document still.
Accessible* container = document->GetAccessibleOrContainer(containerNode);
NS_ASSERTION(container,
"Text node having rendered text hasn't accessible document!");
if (container) {
nsTArray<nsCOMPtr<nsIContent> > insertedContents;
insertedContents.AppendElement(textNode);
document->ProcessContentInserted(container, &insertedContents);
}
}
return PL_DHASH_NEXT;
}
////////////////////////////////////////////////////////////////////////////////
// NotificationController: content inserted notification

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

@ -297,12 +297,6 @@ private:
*/
nsTHashtable<nsCOMPtrHashKey<nsIContent> > mTextHash;
/**
* Update the accessible tree for pending rendered text change notifications.
*/
static PLDHashOperator TextEnumerator(nsCOMPtrHashKey<nsIContent>* aEntry,
void* aUserArg);
/**
* Other notifications like DOM events. Don't make this an nsAutoTArray; we
* use SwapElements() on it.

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

@ -221,13 +221,6 @@ DocAccessibleParent::AddChildDoc(DocAccessibleParent* aChildDoc,
return true;
}
PLDHashOperator
DocAccessibleParent::ShutdownAccessibles(ProxyEntry* entry, void*)
{
ProxyDestroyed(entry->mProxy);
return PL_DHASH_REMOVE;
}
bool
DocAccessibleParent::RecvShutdown()
{
@ -252,7 +245,10 @@ DocAccessibleParent::Destroy()
for (uint32_t i = childDocCount - 1; i < childDocCount; i--)
mChildDocs[i]->Destroy();
mAccessibles.EnumerateEntries(ShutdownAccessibles, nullptr);
for (auto iter = mAccessibles.Iter(); !iter.Done(); iter.Next()) {
ProxyDestroyed(iter.Get()->mProxy);
iter.Remove();
}
ProxyDestroyed(this);
if (mParentDoc)
mParentDoc->RemoveChildDoc(this);

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

@ -152,8 +152,6 @@ private:
uint32_t aIdxInParent);
void CheckDocTree() const;
static PLDHashOperator ShutdownAccessibles(ProxyEntry* entry, void* unused);
nsTArray<DocAccessibleParent*> mChildDocs;
DocAccessibleParent* mParentDoc;

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

@ -8,6 +8,11 @@ let TrackingProtection = {
PREF_ENABLED_IN_PRIVATE_WINDOWS: "privacy.trackingprotection.pbmode.enabled",
enabledGlobally: false,
enabledInPrivateWindows: false,
container: null,
content: null,
icon: null,
activeTooltipText: null,
disabledTooltipText: null,
init() {
let $ = selector => document.querySelector(selector);
@ -19,6 +24,11 @@ let TrackingProtection = {
Services.prefs.addObserver(this.PREF_ENABLED_GLOBALLY, this, false);
Services.prefs.addObserver(this.PREF_ENABLED_IN_PRIVATE_WINDOWS, this, false);
this.activeTooltipText =
gNavigatorBundle.getString("trackingProtection.icon.activeTooltip");
this.disabledTooltipText =
gNavigatorBundle.getString("trackingProtection.icon.disabledTooltip");
this.enabledHistogram.add(this.enabledGlobally);
},
@ -66,21 +76,14 @@ let TrackingProtection = {
this.icon.setAttribute("animate", "true");
}
let {
STATE_BLOCKED_TRACKING_CONTENT, STATE_LOADED_TRACKING_CONTENT
} = Ci.nsIWebProgressListener;
let isBlocking = state & Ci.nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT;
let isAllowing = state & Ci.nsIWebProgressListener.STATE_LOADED_TRACKING_CONTENT;
for (let element of [this.icon, this.content]) {
if (state & STATE_BLOCKED_TRACKING_CONTENT) {
element.setAttribute("state", "blocked-tracking-content");
} else if (state & STATE_LOADED_TRACKING_CONTENT) {
element.setAttribute("state", "loaded-tracking-content");
} else {
element.removeAttribute("state");
}
}
if (isBlocking) {
this.icon.setAttribute("tooltiptext", this.activeTooltipText);
this.icon.setAttribute("state", "blocked-tracking-content");
this.content.setAttribute("state", "blocked-tracking-content");
if (state & STATE_BLOCKED_TRACKING_CONTENT) {
// Open the tracking protection introduction panel, if applicable.
let introCount = gPrefService.getIntPref("privacy.trackingprotection.introCount");
if (introCount < TrackingProtection.MAX_INTROS) {
@ -88,6 +91,14 @@ let TrackingProtection = {
gPrefService.savePrefFile(null);
this.showIntroPanel();
}
} else if (isAllowing) {
this.icon.setAttribute("tooltiptext", this.disabledTooltipText);
this.icon.setAttribute("state", "loaded-tracking-content");
this.content.setAttribute("state", "loaded-tracking-content");
} else {
this.icon.removeAttribute("tooltiptext");
this.icon.removeAttribute("state");
this.content.removeAttribute("state");
}
// Telemetry for state change.

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

@ -278,6 +278,8 @@ skip-if = os == "mac" || e10s # bug 967013; e10s: bug 1094761 - test hits the ne
[browser_ctrlTab.js]
[browser_datareporting_notification.js]
skip-if = !datareporting
[browser_datachoices_notification.js]
skip-if = !datareporting
[browser_devedition.js]
[browser_devices_get_user_media.js]
skip-if = buildapp == 'mulet' || (os == "linux" && debug) || e10s # linux: bug 976544; e10s: bug 1071623

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

@ -0,0 +1,213 @@
/* 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";
// Pass an empty scope object to the import to prevent "leaked window property"
// errors in tests.
let Preferences = Cu.import("resource://gre/modules/Preferences.jsm", {}).Preferences;
let TelemetryReportingPolicy =
Cu.import("resource://gre/modules/TelemetryReportingPolicy.jsm", {}).TelemetryReportingPolicy;
XPCOMUtils.defineLazyGetter(this, "gDatareportingService",
() => Cc["@mozilla.org/datareporting/service;1"]
.getService(Ci.nsISupports)
.wrappedJSObject);
const PREF_BRANCH = "datareporting.policy.";
const PREF_DRS_ENABLED = "datareporting.healthreport.service.enabled";
const PREF_BYPASS_NOTIFICATION = PREF_BRANCH + "dataSubmissionPolicyBypassNotification";
const PREF_CURRENT_POLICY_VERSION = PREF_BRANCH + "currentPolicyVersion";
const PREF_ACCEPTED_POLICY_VERSION = PREF_BRANCH + "dataSubmissionPolicyAcceptedVersion";
const PREF_ACCEPTED_POLICY_DATE = PREF_BRANCH + "dataSubmissionPolicyNotifiedTime";
const TEST_POLICY_VERSION = 37;
/**
* Wait for a tick.
*/
function promiseNextTick() {
return new Promise(resolve => executeSoon(resolve));
}
/**
* Wait for a notification to be shown in a notification box.
* @param {Object} aNotificationBox The notification box.
* @return {Promise} Resolved when the notification is displayed.
*/
function promiseWaitForAlertActive(aNotificationBox) {
let deferred = PromiseUtils.defer();
aNotificationBox.addEventListener("AlertActive", function onActive() {
aNotificationBox.removeEventListener("AlertActive", onActive, true);
deferred.resolve();
});
return deferred.promise;
}
/**
* Wait for a notification to be closed.
* @param {Object} aNotification The notification.
* @return {Promise} Resolved when the notification is closed.
*/
function promiseWaitForNotificationClose(aNotification) {
let deferred = PromiseUtils.defer();
waitForNotificationClose(aNotification, deferred.resolve);
return deferred.promise;
}
let checkInfobarButton = Task.async(function* (aNotification) {
// Check that the button on the data choices infobar does the right thing.
let buttons = aNotification.getElementsByTagName("button");
Assert.equal(buttons.length, 1, "There is 1 button in the data reporting notification.");
let button = buttons[0];
// Add an observer to ensure the "advanced" pane opened (but don't bother
// closing it - we close the entire window when done.)
let paneLoadedPromise = promiseTopicObserved("advanced-pane-loaded");
// Click on the button.
button.click();
// Wait for the preferences panel to open.
let preferenceWindow = yield paneLoadedPromise;
yield promiseNextTick();
// If the prefs are being displayed in a dialog we need to close it.
// If in a tab (ie, in-content prefs) it closes with the window.
if (!Services.prefs.getBoolPref("browser.preferences.inContent")) {
prefWin.close();
}
});
add_task(function* setup(){
const drsEnabled = Preferences.get(PREF_DRS_ENABLED, true);
const bypassNotification = Preferences.get(PREF_BYPASS_NOTIFICATION, true);
const currentPolicyVersion = Preferences.get(PREF_CURRENT_POLICY_VERSION, 1);
// Register a cleanup function to reset our preferences.
registerCleanupFunction(() => {
Preferences.set(PREF_DRS_ENABLED, drsEnabled);
Preferences.set(PREF_BYPASS_NOTIFICATION, bypassNotification);
Preferences.set(PREF_CURRENT_POLICY_VERSION, currentPolicyVersion);
// Start polling again.
gDatareportingService.policy.startPolling();
return closeAllNotifications();
});
// Disable Healthreport/Data reporting service.
Preferences.set(PREF_DRS_ENABLED, false);
// Don't skip the infobar visualisation.
Preferences.set(PREF_BYPASS_NOTIFICATION, false);
// Set the current policy version.
Preferences.set(PREF_CURRENT_POLICY_VERSION, TEST_POLICY_VERSION);
// Stop the polling to make sure no policy gets displayed by FHR.
gDatareportingService.policy.stopPolling();
});
function clearAcceptedPolicy() {
// Reset the accepted policy.
Preferences.reset(PREF_ACCEPTED_POLICY_VERSION);
Preferences.reset(PREF_ACCEPTED_POLICY_DATE);
}
add_task(function* test_single_window(){
clearAcceptedPolicy();
// Close all the notifications, then try to trigger the data choices infobar.
yield closeAllNotifications();
let notificationBox = document.getElementById("global-notificationbox");
// Make sure that we have a coherent initial state.
Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_VERSION, 0), 0,
"No version should be set on init.");
Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_DATE, 0), 0,
"No date should be set on init.");
Assert.ok(!TelemetryReportingPolicy.testIsUserNotified(),
"User not notified about datareporting policy.");
let alertShownPromise = promiseWaitForAlertActive(notificationBox);
// This should be false and trigger the Infobar.
Assert.ok(!TelemetryReportingPolicy.canUpload(),
"User should not be allowed to upload and the infobar should be triggered.");
// Wait for the infobar to be displayed.
yield alertShownPromise;
Assert.equal(notificationBox.allNotifications.length, 1, "Notification Displayed.");
Assert.ok(TelemetryReportingPolicy.canUpload(), "User should be allowed to upload now.");
yield promiseNextTick();
let promiseClosed = promiseWaitForNotificationClose(notificationBox.currentNotification);
yield checkInfobarButton(notificationBox.currentNotification);
yield promiseClosed;
Assert.equal(notificationBox.allNotifications.length, 0, "No notifications remain.");
// Check that we are still clear to upload and that the policy data is saved.
Assert.ok(TelemetryReportingPolicy.canUpload());
Assert.equal(TelemetryReportingPolicy.testIsUserNotified(), true,
"User notified about datareporting policy.");
Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_VERSION, 0), TEST_POLICY_VERSION,
"Version pref set.");
Assert.greater(parseInt(Preferences.get(PREF_ACCEPTED_POLICY_DATE, null), 10), -1,
"Date pref set.");
});
add_task(function* test_multiple_windows(){
clearAcceptedPolicy();
// Close all the notifications, then try to trigger the data choices infobar.
yield closeAllNotifications();
// Ensure we see the notification on all windows and that action on one window
// results in dismiss on every window.
let otherWindow = yield BrowserTestUtils.openNewBrowserWindow();
// Get the notification box for both windows.
let notificationBoxes = [
document.getElementById("global-notificationbox"),
otherWindow.document.getElementById("global-notificationbox")
];
Assert.ok(notificationBoxes[1], "2nd window has a global notification box.");
// Make sure that we have a coherent initial state.
Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_VERSION, 0), 0, "No version should be set on init.");
Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_DATE, 0), 0, "No date should be set on init.");
Assert.ok(!TelemetryReportingPolicy.testIsUserNotified(), "User not notified about datareporting policy.");
let showAlertPromises = [
promiseWaitForAlertActive(notificationBoxes[0]),
promiseWaitForAlertActive(notificationBoxes[1])
];
// This should be false and trigger the Infobar.
Assert.ok(!TelemetryReportingPolicy.canUpload(),
"User should not be allowed to upload and the infobar should be triggered.");
yield Promise.all(showAlertPromises);
// Both notification were displayed. Close one and check that both gets closed.
let closeAlertPromises = [
promiseWaitForNotificationClose(notificationBoxes[0].currentNotification),
promiseWaitForNotificationClose(notificationBoxes[1].currentNotification)
];
notificationBoxes[0].currentNotification.close();
yield Promise.all(closeAlertPromises);
// Close the second window we opened.
yield BrowserTestUtils.closeWindow(otherWindow);
// Check that we are clear to upload and that the policy data us saved.
Assert.ok(TelemetryReportingPolicy.canUpload(),"User should be allowed to upload now.");
Assert.equal(TelemetryReportingPolicy.testIsUserNotified(), true,
"User notified about datareporting policy.");
Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_VERSION, 0), TEST_POLICY_VERSION,
"Version pref set.");
Assert.greater(parseInt(Preferences.get(PREF_ACCEPTED_POLICY_DATE, null), 10), -1,
"Date pref set.");
});

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

@ -47,30 +47,6 @@ function sendNotifyRequest(name) {
return [policy, deferred.promise];
}
/**
* Wait for a <notification> to be closed then call the specified callback.
*/
function waitForNotificationClose(notification, cb) {
let parent = notification.parentNode;
let observer = new MutationObserver(function onMutatations(mutations) {
for (let mutation of mutations) {
for (let i = 0; i < mutation.removedNodes.length; i++) {
let node = mutation.removedNodes.item(i);
if (node != notification) {
continue;
}
observer.disconnect();
cb();
}
}
});
observer.observe(parent, {childList: true});
}
let dumpAppender, rootLogger;
function test() {

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

@ -46,6 +46,7 @@ function testBenignPage() {
ok(!TrackingProtection.container.hidden, "The container is visible");
ok(!TrackingProtection.content.hasAttribute("state"), "content: no state");
ok(!TrackingProtection.icon.hasAttribute("state"), "icon: no state");
ok(!TrackingProtection.icon.hasAttribute("tooltiptext"), "icon: no tooltip");
ok(hidden("#tracking-protection-icon"), "icon is hidden");
ok(hidden("#tracking-action-block"), "blockButton is hidden");
@ -64,6 +65,8 @@ function testTrackingPage(window) {
'content: state="blocked-tracking-content"');
is(TrackingProtection.icon.getAttribute("state"), "blocked-tracking-content",
'icon: state="blocked-tracking-content"');
is(TrackingProtection.icon.getAttribute("tooltiptext"),
gNavigatorBundle.getString("trackingProtection.icon.activeTooltip"), "correct tooltip");
ok(!hidden("#tracking-protection-icon"), "icon is visible");
ok(hidden("#tracking-action-block"), "blockButton is hidden");
@ -90,6 +93,8 @@ function testTrackingPageUnblocked() {
'content: state="loaded-tracking-content"');
is(TrackingProtection.icon.getAttribute("state"), "loaded-tracking-content",
'icon: state="loaded-tracking-content"');
is(TrackingProtection.icon.getAttribute("tooltiptext"),
gNavigatorBundle.getString("trackingProtection.icon.disabledTooltip"), "correct tooltip");
ok(!hidden("#tracking-protection-icon"), "icon is visible");
ok(!hidden("#tracking-action-block"), "blockButton is visible");

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

@ -9,6 +9,27 @@ XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils",
"resource://testing-common/PlacesTestUtils.jsm");
/**
* Wait for a <notification> to be closed then call the specified callback.
*/
function waitForNotificationClose(notification, cb) {
let parent = notification.parentNode;
let observer = new MutationObserver(function onMutatations(mutations) {
for (let mutation of mutations) {
for (let i = 0; i < mutation.removedNodes.length; i++) {
let node = mutation.removedNodes.item(i);
if (node != notification) {
continue;
}
observer.disconnect();
cb();
}
}
});
observer.observe(parent, {childList: true});
}
function closeAllNotifications () {
let notificationBox = document.getElementById("global-notificationbox");

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 1.5 KiB

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

После

Ширина:  |  Высота:  |  Размер: 10 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.3 KiB

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

@ -14,7 +14,6 @@ browser.jar:
content/branding/icon16.png (../default16.png)
content/branding/icon32.png (../default32.png)
content/branding/icon128.png (../mozicon128.png)
content/branding/identity-icons-brand.png (identity-icons-brand.png)
content/branding/identity-icons-brand@2x.png (identity-icons-brand@2x.png)
content/branding/identity-icons-brand.svg (identity-icons-brand.svg)
content/branding/silhouette-40.svg (silhouette-40.svg)
content/branding/aboutDialog.css (aboutDialog.css)

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 1.6 KiB

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

После

Ширина:  |  Высота:  |  Размер: 38 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 4.2 KiB

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

@ -14,7 +14,6 @@ browser.jar:
content/branding/icon16.png (../default16.png)
content/branding/icon32.png (../default32.png)
content/branding/icon128.png (../mozicon128.png)
content/branding/identity-icons-brand.png (identity-icons-brand.png)
content/branding/identity-icons-brand@2x.png (identity-icons-brand@2x.png)
content/branding/identity-icons-brand.svg (identity-icons-brand.svg)
content/branding/silhouette-40.svg (silhouette-40.svg)
content/branding/aboutDialog.css (aboutDialog.css)

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 1.3 KiB

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

После

Ширина:  |  Высота:  |  Размер: 10 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.1 KiB

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

@ -13,7 +13,6 @@ browser.jar:
content/branding/icon16.png (../default16.png)
content/branding/icon32.png (../default32.png)
content/branding/icon128.png (../mozicon128.png)
content/branding/identity-icons-brand.png (identity-icons-brand.png)
content/branding/identity-icons-brand@2x.png (identity-icons-brand@2x.png)
content/branding/identity-icons-brand.svg (identity-icons-brand.svg)
content/branding/silhouette-40.svg (silhouette-40.svg)
content/branding/aboutDialog.css (aboutDialog.css)

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 1.6 KiB

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

После

Ширина:  |  Высота:  |  Размер: 38 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 4.2 KiB

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

@ -14,7 +14,6 @@ browser.jar:
content/branding/icon16.png (../default16.png)
content/branding/icon32.png (../default32.png)
content/branding/icon128.png (../mozicon128.png)
content/branding/identity-icons-brand.png (identity-icons-brand.png)
content/branding/identity-icons-brand@2x.png (identity-icons-brand@2x.png)
content/branding/identity-icons-brand.svg (identity-icons-brand.svg)
content/branding/silhouette-40.svg (silhouette-40.svg)
content/branding/aboutDialog.css (aboutDialog.css)

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

@ -638,6 +638,7 @@ loop.roomViews = (function(mozL10n) {
return true;
case ROOM_STATES.READY:
case ROOM_STATES.GATHER:
case ROOM_STATES.INIT:
case ROOM_STATES.JOINING:
case ROOM_STATES.SESSION_CONNECTED:

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

@ -638,6 +638,7 @@ loop.roomViews = (function(mozL10n) {
return true;
case ROOM_STATES.READY:
case ROOM_STATES.GATHER:
case ROOM_STATES.INIT:
case ROOM_STATES.JOINING:
case ROOM_STATES.SESSION_CONNECTED:

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

@ -372,6 +372,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
return true;
case ROOM_STATES.READY:
case ROOM_STATES.GATHER:
case ROOM_STATES.INIT:
case ROOM_STATES.JOINING:
case ROOM_STATES.SESSION_CONNECTED:

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

@ -372,6 +372,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
return true;
case ROOM_STATES.READY:
case ROOM_STATES.GATHER:
case ROOM_STATES.INIT:
case ROOM_STATES.JOINING:
case ROOM_STATES.SESSION_CONNECTED:

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

@ -251,18 +251,18 @@ ThreadNode.prototype = {
* Uninverts the call tree after its having been built.
*/
_uninvert: function uninvert() {
function mergeOrAddFrameNode(calls, node) {
function mergeOrAddFrameNode(calls, node, samples) {
// Unlike the inverted call tree, we don't use a root table for the top
// level, as in general, there are many fewer entry points than
// leaves. Instead, linear search is used regardless of level.
for (let i = 0; i < calls.length; i++) {
if (calls[i].key === node.key) {
let foundNode = calls[i];
foundNode._merge(node);
foundNode._merge(node, samples);
return foundNode.calls;
}
}
let copy = node._clone();
let copy = node._clone(samples);
calls.push(copy);
return copy.calls;
}
@ -280,19 +280,42 @@ ThreadNode.prototype = {
let node = entry.node;
let calls = node.calls;
let callSamples = 0;
if (calls.length === 0) {
// We've bottomed out. Reverse the spine and add them to the
// uninverted call tree.
// Continue the depth-first walk.
for (let i = 0; i < calls.length; i++) {
workstack.push({ node: calls[i], level: entry.level + 1 });
callSamples += calls[i].samples;
}
// The sample delta is used to distinguish stacks.
//
// Suppose we have the following stack samples:
//
// A -> B
// A -> C
// A
//
// The inverted tree is:
//
// A
// / \
// B C
//
// with A.samples = 3, B.samples = 1, C.samples = 1.
//
// A is distinguished as being its own stack because
// A.samples - (B.samples + C.samples) > 0.
//
// Note that bottoming out is a degenerate where callSamples = 0.
let samplesDelta = node.samples - callSamples;
if (samplesDelta > 0) {
// Reverse the spine and add them to the uninverted call tree.
let uninvertedCalls = rootCalls;
for (let level = entry.level; level > 0; level--) {
let callee = spine[level];
uninvertedCalls = mergeOrAddFrameNode(uninvertedCalls, callee.node);
}
} else {
// We still have children. Continue the depth-first walk.
for (let i = 0; i < calls.length; i++) {
workstack.push({ node: calls[i], level: entry.level + 1 });
uninvertedCalls = mergeOrAddFrameNode(uninvertedCalls, callee.node, samplesDelta);
}
}
}
@ -410,19 +433,21 @@ FrameNode.prototype = {
}
},
_clone: function () {
_clone: function (samples) {
let newNode = new FrameNode(this.key, this, this.isMetaCategory);
newNode._merge(this);
newNode._merge(this, samples);
return newNode;
},
_merge: function (otherNode) {
_merge: function (otherNode, samples) {
if (this === otherNode) {
return;
}
this.samples += otherNode.samples;
this.youngestFrameSamples += otherNode.youngestFrameSamples;
this.samples += samples;
if (otherNode.youngestFrameSamples > 0) {
this.youngestFrameSamples += samples;
}
if (otherNode._optimizations) {
let opts = this._optimizations;

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

@ -0,0 +1,93 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test that uninverting the call tree works correctly when there are stacks
// in the profile that prefixes of other stacks.
function run_test() {
run_next_test();
}
add_task(function () {
let { ThreadNode } = devtools.require("devtools/performance/tree-model");
let thread = new ThreadNode(gThread, { startTime: 0, endTime: 50 });
let root = getFrameNodePath(thread, "(root)");
/**
* Samples
*
* A->B
* C->B
* B
* A
* Z->Y->X
* W->Y->X
* Y->X
*/
equal(getFrameNodePath(root, "A > B").youngestFrameSamples, 1,
"A > B has the correct self count");
equal(getFrameNodePath(root, "C > B").youngestFrameSamples, 1,
"C > B has the correct self count");
equal(getFrameNodePath(root, "B").youngestFrameSamples, 1,
"B has the correct self count");
equal(getFrameNodePath(root, "A").youngestFrameSamples, 1,
"A has the correct self count");
equal(getFrameNodePath(root, "Z > Y > X").youngestFrameSamples, 1,
"Z > Y > X has the correct self count");
equal(getFrameNodePath(root, "W > Y > X").youngestFrameSamples, 1,
"W > Y > X has the correct self count");
equal(getFrameNodePath(root, "Y > X").youngestFrameSamples, 1,
"Y > X has the correct self count");
});
let gThread = synthesizeProfileForTest([{
time: 5,
frames: [
{ location: "(root)" },
{ location: "A" },
{ location: "B" },
]
}, {
time: 10,
frames: [
{ location: "(root)" },
{ location: "C" },
{ location: "B" },
]
}, {
time: 15,
frames: [
{ location: "(root)" },
{ location: "B" },
]
},{
time: 20,
frames: [
{ location: "(root)" },
{ location: "A" },
]
}, {
time: 21,
frames: [
{ location: "(root)" },
{ location: "Z" },
{ location: "Y" },
{ location: "X" },
]
}, {
time: 22,
frames: [
{ location: "(root)" },
{ location: "W" },
{ location: "Y" },
{ location: "X" },
]
}, {
time: 23,
frames: [
{ location: "(root)" },
{ location: "Y" },
{ location: "X" },
]
}]);

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

@ -0,0 +1,85 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Like test_tree-model-12, but inverted.
function run_test() {
run_next_test();
}
add_task(function () {
let { ThreadNode } = devtools.require("devtools/performance/tree-model");
let root = new ThreadNode(gThread, { invertTree: true, startTime: 0, endTime: 50 });
/**
* Samples
*
* A->B
* C->B
* B
* A
* Z->Y->X
* W->Y->X
* Y->X
*/
equal(getFrameNodePath(root, "B").youngestFrameSamples, 3,
"B has the correct self count");
equal(getFrameNodePath(root, "A").youngestFrameSamples, 1,
"A has the correct self count");
equal(getFrameNodePath(root, "X").youngestFrameSamples, 3,
"X has the correct self count");
equal(getFrameNodePath(root, "X > Y").samples, 3,
"X > Y has the correct total count");
});
let gThread = synthesizeProfileForTest([{
time: 5,
frames: [
{ location: "(root)" },
{ location: "A" },
{ location: "B" },
]
}, {
time: 10,
frames: [
{ location: "(root)" },
{ location: "C" },
{ location: "B" },
]
}, {
time: 15,
frames: [
{ location: "(root)" },
{ location: "B" },
]
},{
time: 20,
frames: [
{ location: "(root)" },
{ location: "A" },
]
}, {
time: 21,
frames: [
{ location: "(root)" },
{ location: "Z" },
{ location: "Y" },
{ location: "X" },
]
}, {
time: 22,
frames: [
{ location: "(root)" },
{ location: "W" },
{ location: "Y" },
{ location: "X" },
]
}, {
time: 23,
frames: [
{ location: "(root)" },
{ location: "Y" },
{ location: "X" },
]
}]);

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

@ -24,6 +24,8 @@ skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_tree-model-09.js]
[test_tree-model-10.js]
[test_tree-model-11.js]
[test_tree-model-12.js]
[test_tree-model-13.js]
[test_waterfall-utils-collapse-01.js]
[test_waterfall-utils-collapse-02.js]
[test_waterfall-utils-collapse-03.js]

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

@ -343,6 +343,9 @@ trackingProtection.intro.description=When the shield is visible, that means Fire
trackingProtection.intro.step1of3=1 of 3
trackingProtection.intro.nextButton.label=Next
trackingProtection.icon.activeTooltip=Tracking attempts blocked
trackingProtection.icon.disabledTooltip=Tracking content detected
# Edit Bookmark UI
editBookmarkPanel.pageBookmarkedTitle=Page Bookmarked
editBookmarkPanel.pageBookmarkedDescription=%S will always remember this page for you.

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

@ -34,7 +34,7 @@
--toolbarbutton-combined-boxshadow: 0 0 0 1px hsla(0,0%,100%,.2);
--toolbarbutton-combined-backgroundimage: linear-gradient(hsla(210,54%,20%,.2) 0, hsla(210,54%,20%,.2) 18px);
--verified-identity-box-backgroundcolor: #fff;
--identity-box-verified-background-color: #fff;
}
#menubar-items {
@ -986,7 +986,7 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
}
#identity-box.verifiedIdentity:not(:-moz-lwtheme):not(:hover):not([open=true]) {
background-color: var(--verified-identity-box-backgroundcolor);
background-color: var(--identity-box-verified-background-color);
}
#identity-box:-moz-focusring {

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

@ -174,16 +174,6 @@ panelmultiview[nosubviews=true] > .panel-viewcontainer > .panel-viewstack > .pan
flex-direction: column;
}
#app-extension-point-end > #PanelUI-menu-button {
padding: 2px 5px;
}
#app-extension-point-end > #PanelUI-menu-button .toolbarbutton-text {
display: none;
}
#app-extension-point-end > #PanelUI-menu-button .toolbarbutton-icon {
margin: 0;
}
#PanelUI-popup > arrowscrollbox > autorepeatbutton {
display: none;
}

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

@ -63,7 +63,7 @@
:root[devtoolstheme="dark"] #identity-box {
--identity-box-border-color: #5F6670;
--identity-box-chrome-color: #46afe3;
--verified-identity-box-background-color: transparent;
--identity-box-verified-background-color: transparent;
--identity-box-selected-background-color: rgba(231,230,230,.2);
}

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

@ -18,7 +18,7 @@
%endif
%endif
border-inline-end: 1px solid;
border-inline-end: 1px solid var(--identity-box-border-color);
border-image: linear-gradient(transparent 15%,
var(--identity-box-border-color) 15%,
var(--identity-box-border-color) 85%,
@ -33,6 +33,7 @@
#identity-box:hover,
#identity-box[open=true] {
background-color: var(--identity-box-selected-background-color);
border-image-source: none;
}
#urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity {
@ -119,8 +120,7 @@
}
.chromeUI > #page-proxy-favicon[pageproxystate="valid"] {
list-style-image: url(chrome://branding/content/identity-icons-brand.png);
-moz-image-region: rect(0, 16px, 16px, 0);
list-style-image: url(chrome://branding/content/identity-icons-brand.svg);
}
.verifiedDomain > #page-proxy-favicon[pageproxystate="valid"],
@ -146,13 +146,6 @@
opacity: 0.3;
}
@media (min-resolution: 1.1dppx) {
.chromeUI > #page-proxy-favicon[pageproxystate="valid"] {
list-style-image: url(chrome://branding/content/identity-icons-brand@2x.png);
-moz-image-region: rect(0, 32px, 32px, 0);
}
}
#urlbar[actiontype="searchengine"] > #identity-box > #page-proxy-favicon {
-moz-image-region: inherit;
list-style-image: url(chrome://global/skin/icons/autocomplete-search.svg#search-icon);

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

@ -38,7 +38,7 @@
--toolbarbutton-combined-boxshadow: none;
--toolbarbutton-combined-backgroundimage: linear-gradient(hsla(210,54%,20%,.2) 0, hsla(210,54%,20%,.2) 16px);
--verified-identity-box-backgroundcolor: #FFF;
--identity-box-verified-background-color: #fff;
--urlbar-dropmarker-url: url("chrome://browser/skin/urlbar-history-dropmarker.png");
--urlbar-dropmarker-region: rect(0px, 11px, 14px, 0px);
@ -1261,6 +1261,8 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
.searchbar-textbox {
font-size: 1.15em;
min-height: 28px;
transition-property: border-color, box-shadow;
transition-duration: .1s;
}
:root {
@ -1435,7 +1437,7 @@ html|*.urlbar-input:-moz-lwtheme::-moz-placeholder,
}
#identity-box.verifiedIdentity:not(:-moz-lwtheme):not(:hover):not([open=true]) {
background-color: var(--verified-identity-box-backgroundcolor);
background-color: var(--identity-box-verified-background-color);
}
#identity-box:-moz-focusring {

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

@ -5389,11 +5389,15 @@ if test -n "$MOZ_FMP4"; then
MOZ_EME=1
fi;
if test "$MOZ_WIDGET_TOOLKIT" = "gonk" -a -n "$MOZ_FMP4" -a "$ANDROID_VERSION" -ge "18"; then
MOZ_GONK_MEDIACODEC=1
AC_SUBST(MOZ_GONK_MEDIACODEC)
if test x"$MOZ_WIDGET_TOOLKIT" = x"gonk" -a -n "$MOZ_FMP4" -a -n "$ANDROID_VERSION"; then
# we now know for sure that $ANDROID_VERSION is not an empty string!
if test "$ANDROID_VERSION" -ge "18"; then
MOZ_GONK_MEDIACODEC=1
AC_SUBST(MOZ_GONK_MEDIACODEC)
fi
fi
dnl ========================================================
dnl = EME support
dnl ========================================================

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

@ -207,6 +207,8 @@ public:
virtual
~ConsoleRunnable()
{
// Shutdown the StructuredCloneHelperInternal class.
Shutdown();
}
bool

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

@ -490,15 +490,15 @@ private:
return map;
}
static PLDHashOperator SetNodeDirection(nsPtrHashKey<Element>* aEntry, void* aDir)
static nsCheapSetOperator SetNodeDirection(nsPtrHashKey<Element>* aEntry, void* aDir)
{
MOZ_ASSERT(aEntry->GetKey()->IsElement(), "Must be an Element");
aEntry->GetKey()->SetDirectionality(*reinterpret_cast<Directionality*>(aDir),
true);
return PL_DHASH_NEXT;
return OpNext;
}
static PLDHashOperator ResetNodeDirection(nsPtrHashKey<Element>* aEntry, void* aData)
static nsCheapSetOperator ResetNodeDirection(nsPtrHashKey<Element>* aEntry, void* aData)
{
MOZ_ASSERT(aEntry->GetKey()->IsElement(), "Must be an Element");
// run the downward propagation algorithm
@ -516,15 +516,15 @@ private:
rootNode->ClearHasDirAutoSet();
rootNode->UnsetProperty(nsGkAtoms::dirAutoSetBy);
}
return PL_DHASH_REMOVE;
return OpRemove;
}
static PLDHashOperator ClearEntry(nsPtrHashKey<Element>* aEntry, void* aData)
static nsCheapSetOperator ClearEntry(nsPtrHashKey<Element>* aEntry, void* aData)
{
Element* rootNode = aEntry->GetKey();
rootNode->ClearHasDirAutoSet();
rootNode->UnsetProperty(nsGkAtoms::dirAutoSetBy);
return PL_DHASH_REMOVE;
return OpRemove;
}
public:

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

@ -23,246 +23,6 @@
namespace mozilla {
namespace dom {
namespace {
struct StructuredCloneInfo
{
PostMessageEvent* event;
nsPIDOMWindow* window;
// This hashtable contains the transferred ports - used to avoid duplicates.
nsTArray<nsRefPtr<MessagePortBase>> transferredPorts;
// This array is populated when the ports are cloned.
nsTArray<nsRefPtr<MessagePortBase>> clonedPorts;
};
} // namespace
const JSStructuredCloneCallbacks PostMessageEvent::sPostMessageCallbacks = {
PostMessageEvent::ReadStructuredClone,
PostMessageEvent::WriteStructuredClone,
nullptr,
PostMessageEvent::ReadTransferStructuredClone,
PostMessageEvent::TransferStructuredClone,
PostMessageEvent::FreeTransferStructuredClone
};
/* static */ JSObject*
PostMessageEvent::ReadStructuredClone(JSContext* cx,
JSStructuredCloneReader* reader,
uint32_t tag,
uint32_t data,
void* closure)
{
StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
NS_ASSERTION(scInfo, "Must have scInfo!");
if (tag == SCTAG_DOM_BLOB) {
NS_ASSERTION(!data, "Data should be empty");
// What we get back from the reader is a BlobImpl.
// From that we create a new File.
BlobImpl* blobImpl;
if (JS_ReadBytes(reader, &blobImpl, sizeof(blobImpl))) {
MOZ_ASSERT(blobImpl);
// nsRefPtr<File> needs to go out of scope before toObjectOrNull() is
// called because the static analysis thinks dereferencing XPCOM objects
// can GC (because in some cases it can!), and a return statement with a
// JSObject* type means that JSObject* is on the stack as a raw pointer
// while destructors are running.
JS::Rooted<JS::Value> val(cx);
{
nsRefPtr<Blob> blob = Blob::Create(scInfo->window, blobImpl);
if (!ToJSValue(cx, blob, &val)) {
return nullptr;
}
}
return &val.toObject();
}
}
if (tag == SCTAG_DOM_FILELIST) {
NS_ASSERTION(!data, "Data should be empty");
// What we get back from the reader is a FileListClonedData.
// From that we create a new FileList.
FileListClonedData* fileListClonedData;
if (JS_ReadBytes(reader, &fileListClonedData, sizeof(fileListClonedData))) {
MOZ_ASSERT(fileListClonedData);
// nsRefPtr<FileList> needs to go out of scope before toObjectOrNull() is
// called because the static analysis thinks dereferencing XPCOM objects
// can GC (because in some cases it can!), and a return statement with a
// JSObject* type means that JSObject* is on the stack as a raw pointer
// while destructors are running.
JS::Rooted<JS::Value> val(cx);
{
nsRefPtr<FileList> fileList =
FileList::Create(scInfo->window, fileListClonedData);
if (!fileList || !ToJSValue(cx, fileList, &val)) {
return nullptr;
}
}
return &val.toObject();
}
}
const JSStructuredCloneCallbacks* runtimeCallbacks =
js::GetContextStructuredCloneCallbacks(cx);
if (runtimeCallbacks) {
return runtimeCallbacks->read(cx, reader, tag, data, nullptr);
}
return nullptr;
}
/* static */ bool
PostMessageEvent::WriteStructuredClone(JSContext* cx,
JSStructuredCloneWriter* writer,
JS::Handle<JSObject*> obj,
void *closure)
{
StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
NS_ASSERTION(scInfo, "Must have scInfo!");
// See if this is a File/Blob object.
{
Blob* blob = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, obj, blob))) {
BlobImpl* blobImpl = blob->Impl();
if (JS_WriteUint32Pair(writer, SCTAG_DOM_BLOB, 0) &&
JS_WriteBytes(writer, &blobImpl, sizeof(blobImpl))) {
scInfo->event->StoreISupports(blobImpl);
return true;
}
}
}
// See if this is a FileList object.
{
FileList* fileList = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, obj, fileList))) {
nsRefPtr<FileListClonedData> fileListClonedData =
fileList->CreateClonedData();
MOZ_ASSERT(fileListClonedData);
FileListClonedData* ptr = fileListClonedData.get();
if (JS_WriteUint32Pair(writer, SCTAG_DOM_FILELIST, 0) &&
JS_WriteBytes(writer, &ptr, sizeof(ptr))) {
scInfo->event->StoreISupports(fileListClonedData);
return true;
}
}
}
const JSStructuredCloneCallbacks* runtimeCallbacks =
js::GetContextStructuredCloneCallbacks(cx);
if (runtimeCallbacks) {
return runtimeCallbacks->write(cx, writer, obj, nullptr);
}
return false;
}
/* static */ bool
PostMessageEvent::ReadTransferStructuredClone(JSContext* aCx,
JSStructuredCloneReader* reader,
uint32_t tag, void* aData,
uint64_t aExtraData,
void* aClosure,
JS::MutableHandle<JSObject*> returnObject)
{
StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure);
NS_ASSERTION(scInfo, "Must have scInfo!");
if (tag == SCTAG_DOM_MAP_MESSAGEPORT) {
MOZ_ASSERT(!aData);
// aExtraData is the index of this port identifier.
ErrorResult rv;
nsRefPtr<MessagePort> port =
MessagePort::Create(scInfo->window,
scInfo->event->GetPortIdentifier(aExtraData),
rv);
if (NS_WARN_IF(rv.Failed())) {
return false;
}
scInfo->clonedPorts.AppendElement(port);
JS::Rooted<JS::Value> value(aCx);
if (!GetOrCreateDOMReflector(aCx, port, &value)) {
JS_ClearPendingException(aCx);
return false;
}
returnObject.set(&value.toObject());
return true;
}
return false;
}
/* static */ bool
PostMessageEvent::TransferStructuredClone(JSContext* aCx,
JS::Handle<JSObject*> aObj,
void* aClosure,
uint32_t* aTag,
JS::TransferableOwnership* aOwnership,
void** aContent,
uint64_t* aExtraData)
{
StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure);
NS_ASSERTION(scInfo, "Must have scInfo!");
MessagePortBase* port = nullptr;
nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port);
if (NS_SUCCEEDED(rv)) {
if (scInfo->transferredPorts.Contains(port)) {
// No duplicates.
return false;
}
// We use aExtraData to store the index of this new port identifier.
MessagePortIdentifier* identifier =
scInfo->event->NewPortIdentifier(aExtraData);
if (!port->CloneAndDisentangle(*identifier)) {
return false;
}
scInfo->transferredPorts.AppendElement(port);
*aTag = SCTAG_DOM_MAP_MESSAGEPORT;
*aOwnership = JS::SCTAG_TMO_CUSTOM;
*aContent = nullptr;
return true;
}
return false;
}
/* static */ void
PostMessageEvent::FreeTransferStructuredClone(uint32_t aTag,
JS::TransferableOwnership aOwnership,
void *aContent,
uint64_t aExtraData,
void* aClosure)
{
if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
MOZ_ASSERT(aClosure);
MOZ_ASSERT(!aContent);
StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure);
MessagePort::ForceClose(scInfo->event->GetPortIdentifier(aExtraData));
}
}
PostMessageEvent::PostMessageEvent(nsGlobalWindow* aSource,
const nsAString& aCallerOrigin,
nsGlobalWindow* aTargetWindow,
@ -282,20 +42,6 @@ PostMessageEvent::~PostMessageEvent()
MOZ_COUNT_DTOR(PostMessageEvent);
}
const MessagePortIdentifier&
PostMessageEvent::GetPortIdentifier(uint64_t aId)
{
MOZ_ASSERT(aId < mPortIdentifiers.Length());
return mPortIdentifiers[aId];
}
MessagePortIdentifier*
PostMessageEvent::NewPortIdentifier(uint64_t* aPosition)
{
*aPosition = mPortIdentifiers.Length();
return mPortIdentifiers.AppendElement();
}
NS_IMETHODIMP
PostMessageEvent::Run()
{
@ -347,13 +93,9 @@ PostMessageEvent::Run()
}
}
// Deserialize the structured clone data
JS::Rooted<JS::Value> messageData(cx);
StructuredCloneInfo scInfo;
scInfo.event = this;
scInfo.window = targetWindow;
if (!mBuffer.read(cx, &messageData, &sPostMessageCallbacks, &scInfo)) {
nsCOMPtr<nsPIDOMWindow> window = targetWindow.get();
if (!Read(window, cx, &messageData)) {
return NS_ERROR_DOM_DATA_CLONE_ERR;
}
@ -368,7 +110,7 @@ PostMessageEvent::Run()
EmptyString(), mSource);
event->SetPorts(new MessagePortList(static_cast<dom::Event*>(event.get()),
scInfo.clonedPorts));
GetTransferredPorts()));
// We can't simply call dispatchEvent on the window because doing so ends
// up flipping the trusted bit on the event, and we don't want that to
@ -392,19 +134,5 @@ PostMessageEvent::Run()
return NS_OK;
}
bool
PostMessageEvent::Write(JSContext* aCx, JS::Handle<JS::Value> aMessage,
JS::Handle<JS::Value> aTransfer, nsPIDOMWindow* aWindow)
{
// We *must* clone the data here, or the JS::Value could be modified
// by script
StructuredCloneInfo scInfo;
scInfo.event = this;
scInfo.window = aWindow;
return mBuffer.write(aCx, aMessage, aTransfer, &sPostMessageCallbacks,
&scInfo);
}
} // namespace dom
} // namespace mozilla

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

@ -7,7 +7,7 @@
#ifndef mozilla_dom_PostMessageEvent_h
#define mozilla_dom_PostMessageEvent_h
#include "js/StructuredClone.h"
#include "mozilla/dom/StructuredCloneHelper.h"
#include "nsCOMPtr.h"
#include "nsRefPtr.h"
#include "nsTArray.h"
@ -28,6 +28,7 @@ class MessagePortIdentifier;
* which asynchronously creates and dispatches events.
*/
class PostMessageEvent final : public nsRunnable
, public StructuredCloneHelper
{
public:
NS_DECL_NSIRUNNABLE
@ -38,69 +39,14 @@ public:
nsIPrincipal* aProvidedPrincipal,
bool aTrustedCaller);
bool Write(JSContext* aCx, JS::Handle<JS::Value> aMessage,
JS::Handle<JS::Value> aTransfer, nsPIDOMWindow* aWindow);
private:
~PostMessageEvent();
const MessagePortIdentifier& GetPortIdentifier(uint64_t aId);
MessagePortIdentifier* NewPortIdentifier(uint64_t* aPosition);
bool StoreISupports(nsISupports* aSupports)
{
mSupportsArray.AppendElement(aSupports);
return true;
}
static JSObject*
ReadStructuredClone(JSContext* cx,
JSStructuredCloneReader* reader,
uint32_t tag,
uint32_t data,
void* closure);
static bool
WriteStructuredClone(JSContext* cx,
JSStructuredCloneWriter* writer,
JS::Handle<JSObject*> obj,
void *closure);
static bool
ReadTransferStructuredClone(JSContext* aCx,
JSStructuredCloneReader* reader,
uint32_t tag, void* aData,
uint64_t aExtraData,
void* aClosure,
JS::MutableHandle<JSObject*> returnObject);
static bool
TransferStructuredClone(JSContext* aCx,
JS::Handle<JSObject*> aObj,
void* aClosure,
uint32_t* aTag,
JS::TransferableOwnership* aOwnership,
void** aContent,
uint64_t* aExtraData);
static void
FreeTransferStructuredClone(uint32_t aTag,
JS::TransferableOwnership aOwnership,
void *aContent,
uint64_t aExtraData,
void* aClosure);
static const JSStructuredCloneCallbacks sPostMessageCallbacks;
JSAutoStructuredCloneBuffer mBuffer;
nsRefPtr<nsGlobalWindow> mSource;
nsString mCallerOrigin;
nsRefPtr<nsGlobalWindow> mTargetWindow;
nsCOMPtr<nsIPrincipal> mProvidedPrincipal;
bool mTrustedCaller;
nsTArray<nsCOMPtr<nsISupports>> mSupportsArray;
nsTArray<MessagePortIdentifier> mPortIdentifiers;
};
} // namespace dom

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

@ -6,6 +6,10 @@
#include "StructuredCloneHelper.h"
#include "mozilla/dom/BlobBinding.h"
#include "mozilla/dom/FileListBinding.h"
#include "mozilla/dom/StructuredCloneTags.h"
namespace mozilla {
namespace dom {
@ -85,7 +89,7 @@ void
StructuredCloneCallbacksError(JSContext* aCx,
uint32_t aErrorId)
{
NS_WARNING("Failed to clone data for the Console API in workers.");
NS_WARNING("Failed to clone data.");
}
const JSStructuredCloneCallbacks gCallbacks = {
@ -99,21 +103,61 @@ const JSStructuredCloneCallbacks gCallbacks = {
} // anonymous namespace
// StructuredCloneHelperInternal class
StructuredCloneHelperInternal::StructuredCloneHelperInternal()
#ifdef DEBUG
: mShutdownCalled(false)
#endif
{}
StructuredCloneHelperInternal::~StructuredCloneHelperInternal()
{
#ifdef DEBUG
MOZ_ASSERT(mShutdownCalled);
#endif
}
void
StructuredCloneHelperInternal::Shutdown()
{
#ifdef DEBUG
MOZ_ASSERT(!mShutdownCalled, "Shutdown already called!");
mShutdownCalled = true;
#endif
mBuffer = nullptr;
}
bool
StructuredCloneHelperInternal::Write(JSContext* aCx,
JS::Handle<JS::Value> aValue)
{
MOZ_ASSERT(!mBuffer, "Double Write is not allowed");
MOZ_ASSERT(!mShutdownCalled, "This method cannot be called after Shutdown.");
mBuffer = new JSAutoStructuredCloneBuffer(&gCallbacks, this);
return mBuffer->write(aCx, aValue, &gCallbacks, this);
}
bool
StructuredCloneHelperInternal::Write(JSContext* aCx,
JS::Handle<JS::Value> aValue,
JS::Handle<JS::Value> aTransfer)
{
MOZ_ASSERT(!mBuffer, "Double Write is not allowed");
MOZ_ASSERT(!mShutdownCalled, "This method cannot be called after Shutdown.");
mBuffer = new JSAutoStructuredCloneBuffer(&gCallbacks, this);
return mBuffer->write(aCx, aValue, aTransfer, &gCallbacks, this);
}
bool
StructuredCloneHelperInternal::Read(JSContext* aCx,
JS::MutableHandle<JS::Value> aValue)
{
MOZ_ASSERT(mBuffer, "Read() without Write() is not allowed.");
MOZ_ASSERT(!mShutdownCalled, "This method cannot be called after Shutdown.");
bool ok = mBuffer->read(aCx, aValue, &gCallbacks, this);
mBuffer = nullptr;
@ -132,7 +176,6 @@ StructuredCloneHelperInternal::ReadTransferCallback(JSContext* aCx,
return false;
}
bool
StructuredCloneHelperInternal::WriteTransferCallback(JSContext* aCx,
JS::Handle<JSObject*> aObj,
@ -154,5 +197,222 @@ StructuredCloneHelperInternal::FreeTransferCallback(uint32_t aTag,
MOZ_CRASH("Nothing to free.");
}
// StructuredCloneHelper class
StructuredCloneHelper::StructuredCloneHelper(uint32_t aFlags)
: mFlags(aFlags)
, mParent(nullptr)
{}
StructuredCloneHelper::~StructuredCloneHelper()
{
Shutdown();
}
bool
StructuredCloneHelper::Write(JSContext* aCx,
JS::Handle<JS::Value> aValue,
JS::Handle<JS::Value> aTransfer)
{
bool ok = StructuredCloneHelperInternal::Write(aCx, aValue, aTransfer);
mTransferringPort.Clear();
return ok;
}
bool
StructuredCloneHelper::Read(nsISupports* aParent,
JSContext* aCx,
JS::MutableHandle<JS::Value> aValue)
{
mozilla::AutoRestore<nsISupports*> guard(mParent);
mParent = aParent;
return StructuredCloneHelperInternal::Read(aCx, aValue);
}
JSObject*
StructuredCloneHelper::ReadCallback(JSContext* aCx,
JSStructuredCloneReader* aReader,
uint32_t aTag,
uint32_t aIndex)
{
if (aTag == SCTAG_DOM_BLOB) {
MOZ_ASSERT(!(mFlags & eBlobNotSupported));
BlobImpl* blobImpl;
if (JS_ReadBytes(aReader, &blobImpl, sizeof(blobImpl))) {
MOZ_ASSERT(blobImpl);
// nsRefPtr<File> needs to go out of scope before toObjectOrNull() is
// called because the static analysis thinks dereferencing XPCOM objects
// can GC (because in some cases it can!), and a return statement with a
// JSObject* type means that JSObject* is on the stack as a raw pointer
// while destructors are running.
JS::Rooted<JS::Value> val(aCx);
{
nsRefPtr<Blob> blob = Blob::Create(mParent, blobImpl);
if (!ToJSValue(aCx, blob, &val)) {
return nullptr;
}
}
return &val.toObject();
}
}
if (aTag == SCTAG_DOM_FILELIST) {
MOZ_ASSERT(!(mFlags & eFileListNotSupported));
FileListClonedData* fileListClonedData;
if (JS_ReadBytes(aReader, &fileListClonedData,
sizeof(fileListClonedData))) {
MOZ_ASSERT(fileListClonedData);
// nsRefPtr<FileList> needs to go out of scope before toObjectOrNull() is
// called because the static analysis thinks dereferencing XPCOM objects
// can GC (because in some cases it can!), and a return statement with a
// JSObject* type means that JSObject* is on the stack as a raw pointer
// while destructors are running.
JS::Rooted<JS::Value> val(aCx);
{
nsRefPtr<FileList> fileList =
FileList::Create(mParent, fileListClonedData);
if (!fileList || !ToJSValue(aCx, fileList, &val)) {
return nullptr;
}
}
return &val.toObject();
}
}
return NS_DOMReadStructuredClone(aCx, aReader, aTag, aIndex, nullptr);
}
bool
StructuredCloneHelper::WriteCallback(JSContext* aCx,
JSStructuredCloneWriter* aWriter,
JS::Handle<JSObject*> aObj)
{
// See if this is a File/Blob object.
if (!(mFlags & eBlobNotSupported)) {
Blob* blob = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) {
BlobImpl* blobImpl = blob->Impl();
return JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB, 0) &&
JS_WriteBytes(aWriter, &blobImpl, sizeof(blobImpl)) &&
StoreISupports(blobImpl);
}
}
if (!(mFlags & eFileListNotSupported)) {
FileList* fileList = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, aObj, fileList))) {
nsRefPtr<FileListClonedData> fileListClonedData =
fileList->CreateClonedData();
MOZ_ASSERT(fileListClonedData);
FileListClonedData* ptr = fileListClonedData.get();
return JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILELIST, 0) &&
JS_WriteBytes(aWriter, &ptr, sizeof(ptr)) &&
StoreISupports(fileListClonedData);
}
}
return NS_DOMWriteStructuredClone(aCx, aWriter, aObj, nullptr);
}
bool
StructuredCloneHelper::ReadTransferCallback(JSContext* aCx,
JSStructuredCloneReader* aReader,
uint32_t aTag,
void* aContent,
uint64_t aExtraData,
JS::MutableHandleObject aReturnObject)
{
if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
MOZ_ASSERT(!(mFlags & eMessagePortNotSupported));
// This can be null.
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mParent);
MOZ_ASSERT(aExtraData < mPortIdentifiers.Length());
const MessagePortIdentifier& portIdentifier = mPortIdentifiers[aExtraData];
// aExtraData is the index of this port identifier.
ErrorResult rv;
nsRefPtr<MessagePort> port =
MessagePort::Create(window, portIdentifier, rv);
if (NS_WARN_IF(rv.Failed())) {
return false;
}
mTransferredPorts.AppendElement(port);
JS::Rooted<JS::Value> value(aCx);
if (!GetOrCreateDOMReflector(aCx, port, &value)) {
JS_ClearPendingException(aCx);
return false;
}
aReturnObject.set(&value.toObject());
return true;
}
return false;
}
bool
StructuredCloneHelper::WriteTransferCallback(JSContext* aCx,
JS::Handle<JSObject*> aObj,
uint32_t* aTag,
JS::TransferableOwnership* aOwnership,
void** aContent,
uint64_t* aExtraData)
{
if (!(mFlags & eMessagePortNotSupported)) {
MessagePortBase* port = nullptr;
nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port);
if (NS_SUCCEEDED(rv)) {
if (mTransferringPort.Contains(port)) {
// No duplicates.
return false;
}
// We use aExtraData to store the index of this new port identifier.
*aExtraData = mPortIdentifiers.Length();
MessagePortIdentifier* identifier = mPortIdentifiers.AppendElement();
if (!port->CloneAndDisentangle(*identifier)) {
return false;
}
mTransferringPort.AppendElement(port);
*aTag = SCTAG_DOM_MAP_MESSAGEPORT;
*aOwnership = JS::SCTAG_TMO_CUSTOM;
*aContent = nullptr;
return true;
}
}
return false;
}
void
StructuredCloneHelper::FreeTransferCallback(uint32_t aTag,
JS::TransferableOwnership aOwnership,
void* aContent,
uint64_t aExtraData)
{
if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
MOZ_ASSERT(!(mFlags & eMessagePortNotSupported));
MOZ_ASSERT(!aContent);
MOZ_ASSERT(aExtraData < mPortIdentifiers.Length());
MessagePort::ForceClose(mPortIdentifiers[aExtraData]);
}
}
} // dom namespace
} // mozilla namespace

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

@ -8,6 +8,8 @@
#include "js/StructuredClone.h"
#include "nsAutoPtr.h"
#include "nsISupports.h"
#include "nsTArray.h"
namespace mozilla {
namespace dom {
@ -15,6 +17,9 @@ namespace dom {
class StructuredCloneHelperInternal
{
public:
StructuredCloneHelperInternal();
virtual ~StructuredCloneHelperInternal();
// These methods should be implemented in order to clone data.
// Read more documentation in js/public/StructuredClone.h.
@ -27,6 +32,12 @@ public:
JSStructuredCloneWriter* aWriter,
JS::Handle<JSObject*> aObj) = 0;
// This method has to be called when this object is not needed anymore.
// It will free memory and the buffer. This has to be called because
// otherwise the buffer will be freed in the DTOR of this class and at that
// point we cannot use the overridden methods.
void Shutdown();
// If these 3 methods are not implement, transfering objects will not be
// allowed.
@ -67,6 +78,113 @@ public:
protected:
nsAutoPtr<JSAutoStructuredCloneBuffer> mBuffer;
#ifdef DEBUG
bool mShutdownCalled;
#endif
};
class MessagePortBase;
class MessagePortIdentifier;
class StructuredCloneHelper : public StructuredCloneHelperInternal
{
public:
enum StructuredCloneHelperFlags {
eAll = 0,
// Disable the cloning of blobs. If a blob is part of the cloning value,
// an exception will be thrown.
eBlobNotSupported = 1 << 0,
// Disable the cloning of FileLists. If a FileList is part of the cloning
// value, an exception will be thrown.
eFileListNotSupported = 1 << 1,
// MessagePort can just be transfered. Using this flag we do not support
// the transfering.
eMessagePortNotSupported = 1 << 2,
};
// aFlags is a bitmap of StructuredCloneHelperFlags.
explicit StructuredCloneHelper(uint32_t aFlags = eAll);
virtual ~StructuredCloneHelper();
bool Write(JSContext* aCx,
JS::Handle<JS::Value> aValue,
JS::Handle<JS::Value> aTransfer);
bool Read(nsISupports* aParent,
JSContext* aCx,
JS::MutableHandle<JS::Value> aValue);
nsTArray<nsRefPtr<MessagePortBase>>& GetTransferredPorts()
{
MOZ_ASSERT(!(mFlags & eMessagePortNotSupported));
return mTransferredPorts;
}
// Custom Callbacks
virtual JSObject* ReadCallback(JSContext* aCx,
JSStructuredCloneReader* aReader,
uint32_t aTag,
uint32_t aIndex) override;
virtual bool WriteCallback(JSContext* aCx,
JSStructuredCloneWriter* aWriter,
JS::Handle<JSObject*> aObj) override;
virtual bool ReadTransferCallback(JSContext* aCx,
JSStructuredCloneReader* aReader,
uint32_t aTag,
void* aContent,
uint64_t aExtraData,
JS::MutableHandleObject aReturnObject) override;
virtual bool WriteTransferCallback(JSContext* aCx,
JS::Handle<JSObject*> aObj,
uint32_t* aTag,
JS::TransferableOwnership* aOwnership,
void** aContent,
uint64_t* aExtraData) override;
virtual void FreeTransferCallback(uint32_t aTag,
JS::TransferableOwnership aOwnership,
void* aContent,
uint64_t aExtraData) override;
private:
bool StoreISupports(nsISupports* aSupports)
{
MOZ_ASSERT(aSupports);
mSupportsArray.AppendElement(aSupports);
return true;
}
// This is our bitmap.
uint32_t mFlags;
// Useful for the structured clone algorithm:
nsTArray<nsCOMPtr<nsISupports>> mSupportsArray;
// This raw pointer is set and unset into the ::Read(). It's always null
// outside that method. For this reason it's a raw pointer.
nsISupports* MOZ_NON_OWNING_REF mParent;
// This hashtable contains the ports while doing write (transferring and
// mapping transferred objects to the objects in the clone). It's an empty
// array outside the 'Write()' method.
nsTArray<nsRefPtr<MessagePortBase>> mTransferringPort;
// This array contains the ports once we've finished the reading. It's
// generated from the mPortIdentifiers array.
nsTArray<nsRefPtr<MessagePortBase>> mTransferredPorts;
// This array contains the identifiers of the MessagePorts. Based on these we
// are able to reconnect the new transferred ports with the other
// MessageChannel ports.
nsTArray<MessagePortIdentifier> mPortIdentifiers;
};
} // dom namespace

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

@ -8582,7 +8582,7 @@ nsGlobalWindow::PostMessageMozOuter(JSContext* aCx, JS::Handle<JS::Value> aMessa
JS::Rooted<JS::Value> message(aCx, aMessage);
JS::Rooted<JS::Value> transfer(aCx, aTransfer);
if (!event->Write(aCx, message, transfer, this)) {
if (!event->Write(aCx, message, transfer)) {
aError.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
return;
}

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

@ -802,5 +802,6 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g'
[test_file_negative_date.html]
[test_nonascii_blob_url.html]
[test_window_element_enumeration.html]
[test_referrer_redirect.html]
[test_cloning_fileList.html]
support-files = script_cloning_fileList.js iframe_cloning_fileList.html

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

@ -1,33 +1,51 @@
/*
* Test server for iframe, anchor, and area referrer attributes.
* https://bugzilla.mozilla.org/show_bug.cgi?id=1175736
* Also server for further referrer tests such as redirecting tests
* bug 1174913, bug 1175736, bug 1184781
*/
Components.utils.importGlobalProperties(["URLSearchParams"]);
const BASE_URL = 'example.com/tests/dom/base/test/referrer_testserver.sjs';
const SHARED_KEY = 'referrer_testserver.sjs';
const SJS = "referrer_testserver.sjs?";
const BASE_URL = "example.com/tests/dom/base/test/" + SJS;
const SHARED_KEY = SJS;
const SAME_ORIGIN = "mochi.test:8888/tests/dom/base/test/" + SJS;
const CROSS_ORIGIN = "test1.example.com/tests/dom/base/test/" + SJS;
const IMG_BYTES = atob(
"iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" +
"P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==");
function createTestUrl(aPolicy, aAction, aName, aType) {
return 'http://' + BASE_URL + '?' +
'ACTION=' + aAction + '&' +
'policy=' + aPolicy + '&' +
'name=' + aName + '&' +
'type=' + aType;
return "http://" + BASE_URL +
"ACTION=" + aAction + "&" +
"policy=" + aPolicy + "&" +
"NAME=" + aName + "&" +
"type=" + aType;
}
// test page using iframe referrer attribute
function createIframeTestPageUsingRefferer(aMetaPolicy, aAttributePolicy, aNewAttributePolicy, aName, aChangingMethod) {
// if aParams are set this creates a test where the iframe url is a redirect
function createIframeTestPageUsingRefferer(aMetaPolicy, aAttributePolicy, aNewAttributePolicy, aName, aParams, aChangingMethod) {
var metaString = "";
if (aMetaPolicy) {
metaString = '<meta name="referrer" content="' + aMetaPolicy + '">';
metaString = `<meta name="referrer" content="${aMetaPolicy}">`;
}
var changeString = '';
if (aChangingMethod === 'setAttribute') {
var changeString = "";
if (aChangingMethod === "setAttribute") {
changeString = `document.getElementById("myframe").setAttribute("referrer", "${aNewAttributePolicy}")`;
} else if (aChangingMethod === 'property') {
} else if (aChangingMethod === "property") {
changeString = `document.getElementById("myframe").referrer = "${aNewAttributePolicy}"`;
}
var iFrameString = `<iframe src="" id="myframe" ${aAttributePolicy ? ` referrer='${aAttributePolicy}'` : ""}>iframe</iframe>`;
var iFrameString = `<iframe src="" id="myframe" ${aAttributePolicy ? ` referrer="${aAttributePolicy}"` : ""}>iframe</iframe>`;
var iframeUrl = "";
if (aParams) {
aParams.delete("ACTION");
aParams.append("ACTION", "redirectIframe");
iframeUrl = "http://" + CROSS_ORIGIN + aParams.toString();
} else {
iframeUrl = createTestUrl(aAttributePolicy, "test", aName, "iframe");
}
return `<!DOCTYPE HTML>
<html>
@ -42,7 +60,7 @@ function createIframeTestPageUsingRefferer(aMetaPolicy, aAttributePolicy, aNewAt
document.getElementById("myframe").onload = function(){
parent.postMessage("childLoadComplete", "http://mochi.test:8888");
};
document.getElementById("myframe").src = "${createTestUrl(aAttributePolicy, 'test', aName, 'iframe')}";
document.getElementById("myframe").src = "${iframeUrl}";
}.bind(window), false);
</script>
</body>
@ -71,17 +89,17 @@ function buildAreaString(aMetaPolicy, aReferrerPolicy, aName, aRelString){
// test page using anchor or area referrer attribute
function createAETestPageUsingRefferer(aMetaPolicy, aAttributePolicy, aNewAttributePolicy, aName, aRel, aStringBuilder, aChangingMethod) {
var metaString = '';
var metaString = "";
if (aMetaPolicy) {
metaString = '<head><meta name="referrer" content="' + aMetaPolicy + '"></head>';
metaString = `<head><meta name="referrer" content="${aMetaPolicy}"></head>`;
}
var changeString = '';
if (aChangingMethod === 'setAttribute') {
var changeString = "";
if (aChangingMethod === "setAttribute") {
changeString = `document.getElementById("link").setAttribute("referrer", "${aNewAttributePolicy}")`;
} else if (aChangingMethod === 'property') {
} else if (aChangingMethod === "property") {
changeString = `document.getElementById("link").referrer = "${aNewAttributePolicy}"`;
}
var relString = '';
var relString = "";
if (aRel) {
relString = `rel="noreferrer"`;
}
@ -102,41 +120,84 @@ function createAETestPageUsingRefferer(aMetaPolicy, aAttributePolicy, aNewAttrib
</html>`;
}
// creates test page with img that is a redirect
function createRedirectImgTestCase(aParams, aAttributePolicy) {
var metaString = "";
if (aParams.has("META_POLICY")) {
metaString = `<meta name="referrer" content="${aParams.get('META_POLICY')}">`;
}
aParams.delete("ACTION");
aParams.append("ACTION", "redirectImg");
var imgUrl = "http://" + CROSS_ORIGIN + aParams.toString();
return `<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
${metaString}
<title>Test referrer policies on redirect (img)</title>
</head>
<body>
<img id="testImg" src="${imgUrl}" ${aAttributePolicy ? ` referrer="${aAttributePolicy}"` : ""}>
<script>
window.addEventListener("load", function() {
parent.postMessage("childLoadComplete", "http://mochi.test:8888");
}.bind(window), false);
</script>
</body>
</html>`;
}
function handleRequest(request, response) {
var params = new URLSearchParams(request.queryString);
var action = params.get('ACTION');
var action = params.get("ACTION");
response.setHeader('Cache-Control', 'no-cache', false);
response.setHeader('Content-Type', 'text/html; charset=utf-8', false);
if (action === 'resetState') {
if (action === "resetState") {
setSharedState(SHARED_KEY, "{}");
response.write("");
return;
}
if (action === 'get-test-results') {
if (action === "get-test-results") {
// ?action=get-result
response.setHeader('Cache-Control', 'no-cache', false);
response.setHeader('Content-Type', 'text/plain', false);
response.setHeader("Cache-Control", "no-cache", false);
response.setHeader("Content-Type", "text/plain", false);
response.write(getSharedState(SHARED_KEY));
return;
}
if (action === 'redirect') {
if (action === "redirect") {
response.write('<script>parent.postMessage("childLoadComplete", "http://mochi.test:8888");</script>');
return;
}
if (action === 'test') {
if (action === "redirectImg"){
params.delete("ACTION");
params.append("ACTION", "test");
params.append("type", "img");
// 302 found, 301 Moved Permanently, 303 See Other, 307 Temporary Redirect
response.setStatusLine("1.1", 302, "found");
response.setHeader("Location", "http://" + CROSS_ORIGIN + params.toString(), false);
return;
}
if (action === "redirectIframe"){
params.delete("ACTION");
params.append("ACTION", "test");
params.append("type", "iframe");
// 302 found, 301 Moved Permanently, 303 See Other, 307 Temporary Redirect
response.setStatusLine("1.1", 302, "found");
response.setHeader("Location", "http://" + CROSS_ORIGIN + params.toString(), false);
return;
}
if (action === "test") {
// ?action=test&policy=origin&name=name
var policy = params.get('policy');
var name = params.get('name');
var type = params.get('type');
var policy = params.get("policy");
var name = params.get("NAME");
var type = params.get("type");
var result = getSharedState(SHARED_KEY);
result = result ? JSON.parse(result) : {};
var referrerLevel = "none";
var test = {}
if (request.hasHeader('Referer')) {
if (request.hasHeader("Referer")) {
var referrer = request.getHeader("Referer");
if (referrer.indexOf("referrer_testserver") > 0) {
referrerLevel = "full";
@ -148,7 +209,7 @@ function handleRequest(request, response) {
}
test.referrer = referrer;
} else {
test.referrer = '';
test.referrer = "";
}
test.policy = referrerLevel;
test.expected = policy;
@ -157,23 +218,34 @@ function handleRequest(request, response) {
setSharedState(SHARED_KEY, JSON.stringify(result));
if (type === "img") {
// return image
response.setHeader("Content-Type", "image/png");
response.write(IMG_BYTES);
return;
}
if (type === "iframe") {
// return iframe page
response.write("<html><body>I am the iframe</body></html>");
} else if (type === "link") {
return;
}
if (type === "link") {
// forward link click to redirect URL to finish test
var loc = "http://" + BASE_URL + "?ACTION=redirect";
response.setStatusLine('1.1', 302, 'Found');
response.setHeader('Location', loc, false);
var loc = "http://" + BASE_URL + "ACTION=redirect";
response.setStatusLine("1.1", 302, "Found");
response.setHeader("Location", loc, false);
}
return;
}
response.setHeader("Cache-Control", "no-cache", false);
response.setHeader("Content-Type", "text/html; charset=utf-8", false);
// parse test arguments and start test
var attributePolicy = params.get("ATTRIBUTE_POLICY") || '';
var newAttributePolicy = params.get("NEW_ATTRIBUTE_POLICY") || '';
var metaPolicy = params.get("META_POLICY") || '';
var rel = params.get("REL") || '';
var attributePolicy = params.get("ATTRIBUTE_POLICY") || "";
var newAttributePolicy = params.get("NEW_ATTRIBUTE_POLICY") || "";
var metaPolicy = params.get("META_POLICY") || "";
var rel = params.get("REL") || "";
var name = params.get("NAME");
// anchor & area
@ -182,45 +254,55 @@ function handleRequest(request, response) {
var _getAreaPage = _getPage.bind(null, buildAreaString);
// aMetaPolicy, aAttributePolicy, aNewAttributePolicy, aName, aChangingMethod, aStringBuilder
if (action === 'generate-anchor-policy-test') {
if (action === "generate-anchor-policy-test") {
response.write(_getAnchorPage());
return;
}
if (action === 'generate-anchor-changing-policy-test-set-attribute') {
response.write(_getAnchorPage('setAttribute'));
if (action === "generate-anchor-changing-policy-test-set-attribute") {
response.write(_getAnchorPage("setAttribute"));
return;
}
if (action === 'generate-anchor-changing-policy-test-property') {
response.write(_getAnchorPage('property'));
if (action === "generate-anchor-changing-policy-test-property") {
response.write(_getAnchorPage("property"));
return;
}
if (action === 'generate-area-policy-test') {
if (action === "generate-area-policy-test") {
response.write(_getAreaPage());
return;
}
if (action === 'generate-area-changing-policy-test-set-attribute') {
response.write(_getAreaPage('setAttribute'));
if (action === "generate-area-changing-policy-test-set-attribute") {
response.write(_getAreaPage("setAttribute"));
return;
}
if (action === 'generate-area-changing-policy-test-property') {
response.write(_getAreaPage('property'));
if (action === "generate-area-changing-policy-test-property") {
response.write(_getAreaPage("property"));
return;
}
// iframe
_getPage = createIframeTestPageUsingRefferer.bind(null, metaPolicy, attributePolicy, newAttributePolicy, name);
_getPage = createIframeTestPageUsingRefferer.bind(null, metaPolicy, attributePolicy, newAttributePolicy, name, "");
// aMetaPolicy, aAttributePolicy, aNewAttributePolicy, aName, aChangingMethod
if (action === 'generate-iframe-policy-test') {
if (action === "generate-iframe-policy-test") {
response.write(_getPage());
return;
}
if (action === 'generate-iframe-changing-policy-test-set-attribute') {
response.write(_getPage('setAttribute'));
if (action === "generate-iframe-changing-policy-test-set-attribute") {
response.write(_getPage("setAttribute"));
return;
}
if (action === 'generate-iframe-changing-policy-test-property') {
response.write(_getPage('property'));
if (action === "generate-iframe-changing-policy-test-property") {
response.write(_getPage("property"));
return;
}
// redirect tests with img and iframe
if (action === "generate-img-redirect-policy-test") {
response.write(createRedirectImgTestCase(params, attributePolicy));
return;
}
if (action === "generate-iframe-redirect-policy-test") {
response.write(createIframeTestPageUsingRefferer(metaPolicy, attributePolicy, newAttributePolicy, name, params));
return;
}

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

@ -0,0 +1,72 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test anchor and area policy attribute for Bug 1184781</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<!--
Testing referrer headers after redirects.
https://bugzilla.mozilla.org/show_bug.cgi?id=1184781
-->
<script type="application/javascript;version=1.8">
const SJS = "/tests/dom/base/test/referrer_testserver.sjs?";
const PARAMS = ["ATTRIBUTE_POLICY", "NEW_ATTRIBUTE_POLICY", "META_POLICY"];
const testCases = [
{ACTION: ["generate-img-redirect-policy-test", "generate-iframe-redirect-policy-test"],
TESTS: [
{
ATTRIBUTE_POLICY: "no-referrer",
NAME: "no-referrer-with-no-meta",
DESC: "no-referrer (img/iframe) with no meta",
RESULT: "none"
},
{
ATTRIBUTE_POLICY: "origin",
NAME: "origin-with-no-meta",
DESC: "origin (img/iframe) with no meta",
RESULT: "origin"
},
{
ATTRIBUTE_POLICY: "unsafe-url",
NAME: "unsafe-url-with-no-meta",
DESC: "unsafe-url (img/iframe) with no meta",
RESULT: "full"
},
{
META_POLICY: "unsafe-url",
NAME: "unsafe-url-in-meta",
DESC: "unsafe-url in meta",
RESULT: "full"
},
{
META_POLICY: "origin",
NAME: "origin-in-meta",
DESC: "origin in meta",
RESULT: "origin"
},
{
META_POLICY: "no-referrer",
NAME: "no-referrer-in-meta",
DESC: "no-referrer in meta",
RESULT: "none"
},
{
META_POLICY: "origin-when-cross-origin",
NAME: "origin-when-cross-origin-in-meta",
DESC: "origin-when-cross-origin in meta",
RESULT: "origin"
}]}
];
</script>
<script type="application/javascript;version=1.7" src="/tests/dom/base/test/referrer_helper.js"></script>
</head>
<body onload="tests.next();">
<iframe id="testframe"></iframe>
</body>
</html>

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

@ -570,15 +570,8 @@ CreateHeadlessANGLE(bool forceEnabled, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
nsRefPtr<GLContext> gl;
#ifdef XP_WIN
if (!forceEnabled &&
IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_ANGLE))
{
webgl->GenerateWarning("Refused to create ANGLE OpenGL context"
" because of blacklisting.");
return nullptr;
}
gl = gl::GLContextProviderEGL::CreateHeadless(requireCompatProfile);
gl = gl::GLContextProviderEGL::CreateHeadless(requireCompatProfile,
forceEnabled);
if (!gl) {
webgl->GenerateWarning("Error during ANGLE OpenGL init.");
return nullptr;

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

@ -23,12 +23,11 @@ extern PRLogModuleInfo* gMediaDecoderLog;
static const int64_t AUDIO_FUZZ_FRAMES = 1;
AudioSink::AudioSink(MediaQueue<AudioData>& aAudioQueue,
ReentrantMonitor& aMonitor,
int64_t aStartTime,
const AudioInfo& aInfo,
dom::AudioChannel aChannel)
: mAudioQueue(aAudioQueue)
, mDecoderMonitor(aMonitor)
, mMonitor("AudioSink::mMonitor")
, mStartTime(aStartTime)
, mWritten(0)
, mLastGoodPosition(0)
@ -71,7 +70,7 @@ AudioSink::Init()
int64_t
AudioSink::GetPosition()
{
AssertCurrentThreadInMonitor();
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
int64_t pos;
if (mAudioStream &&
@ -86,7 +85,7 @@ AudioSink::GetPosition()
bool
AudioSink::HasUnplayedFrames()
{
AssertCurrentThreadInMonitor();
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
// Experimentation suggests that GetPositionInFrames() is zero-indexed,
// so we need to add 1 here before comparing it to mWritten.
return mAudioStream && mAudioStream->GetPositionInFrames() + 1 < mWritten;
@ -95,13 +94,14 @@ AudioSink::HasUnplayedFrames()
void
AudioSink::Shutdown()
{
AssertCurrentThreadInMonitor();
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
mStopAudioThread = true;
if (mAudioStream) {
mAudioStream->Cancel();
}
GetReentrantMonitor().NotifyAll();
// Exit the monitor so audio loop can enter the monitor and finish its job.
ReentrantMonitorAutoExit exit(GetReentrantMonitor());
mThread->Shutdown();
mThread = nullptr;
@ -114,7 +114,7 @@ AudioSink::Shutdown()
void
AudioSink::SetVolume(double aVolume)
{
AssertCurrentThreadInMonitor();
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
mVolume = aVolume;
mSetVolume = true;
}
@ -122,7 +122,7 @@ AudioSink::SetVolume(double aVolume)
void
AudioSink::SetPlaybackRate(double aPlaybackRate)
{
AssertCurrentThreadInMonitor();
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
NS_ASSERTION(mPlaybackRate != 0, "Don't set the playbackRate to 0 on AudioStream");
mPlaybackRate = aPlaybackRate;
mSetPlaybackRate = true;
@ -131,7 +131,7 @@ AudioSink::SetPlaybackRate(double aPlaybackRate)
void
AudioSink::SetPreservesPitch(bool aPreservesPitch)
{
AssertCurrentThreadInMonitor();
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
mPreservesPitch = aPreservesPitch;
mSetPreservesPitch = true;
}
@ -139,11 +139,18 @@ AudioSink::SetPreservesPitch(bool aPreservesPitch)
void
AudioSink::SetPlaying(bool aPlaying)
{
AssertCurrentThreadInMonitor();
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
mPlaying = aPlaying;
GetReentrantMonitor().NotifyAll();
}
void
AudioSink::NotifyData()
{
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
GetReentrantMonitor().NotifyAll();
}
void
AudioSink::AudioLoop()
{

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

@ -26,7 +26,6 @@ public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AudioSink)
AudioSink(MediaQueue<AudioData>& aAudioQueue,
ReentrantMonitor& aMonitor,
int64_t aStartTime,
const AudioInfo& aInfo,
dom::AudioChannel aChannel);
@ -35,9 +34,10 @@ public:
// or rejected if any error.
nsRefPtr<GenericPromise> Init();
/*
* All public functions below are thread-safe.
*/
int64_t GetPosition();
// Thread-safe. Can be called on any thread.
int64_t GetEndTime() const;
// Check whether we've pushed more frames to the audio hardware than it has
@ -45,15 +45,17 @@ public:
bool HasUnplayedFrames();
// Shut down the AudioSink's resources.
// Must be called with the decoder monitor held.
void Shutdown();
void SetVolume(double aVolume);
void SetPlaybackRate(double aPlaybackRate);
void SetPreservesPitch(bool aPreservesPitch);
void SetPlaying(bool aPlaying);
// Wake up the audio loop if it is waiting for data to play or the audio
// queue is finished.
void NotifyData();
private:
~AudioSink() {}
@ -104,7 +106,7 @@ private:
}
ReentrantMonitor& GetReentrantMonitor() const {
return mDecoderMonitor;
return mMonitor;
}
void AssertCurrentThreadInMonitor() const {
@ -114,7 +116,7 @@ private:
void AssertOnAudioThread();
MediaQueue<AudioData>& mAudioQueue;
ReentrantMonitor& mDecoderMonitor;
mutable ReentrantMonitor mMonitor;
// Thread for pushing audio onto the audio hardware.
// The "audio push thread".

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

@ -238,7 +238,9 @@ media::TimeIntervals
MediaDecoderReader::GetBuffered()
{
MOZ_ASSERT(OnTaskQueue());
NS_ENSURE_TRUE(HaveStartTime(), media::TimeIntervals());
if (!HaveStartTime()) {
return media::TimeIntervals();
}
AutoPinned<MediaResource> stream(mDecoder->GetResource());
if (!mDuration.Ref().isSome()) {

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

@ -642,8 +642,9 @@ MediaDecoderStateMachine::Push(AudioData* aSample)
UpdateNextFrameStatus();
DispatchDecodeTasksIfNeeded();
// XXXbholley - Still necessary?
mDecoder->GetReentrantMonitor().NotifyAll();
if (mAudioSink) {
mAudioSink->NotifyData();
}
}
void
@ -789,6 +790,10 @@ MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
case DECODER_STATE_DECODING: {
CheckIfDecodeComplete();
mDecoder->GetReentrantMonitor().NotifyAll();
// Tell AudioSink to wake up for audio queue is finished.
if (mAudioSink) {
mAudioSink->NotifyData();
}
// Schedule the state machine to notify track ended as soon as possible.
if (mAudioCaptured) {
ScheduleStateMachine();
@ -1053,9 +1058,6 @@ void MediaDecoderStateMachine::StopPlayback()
mPlayDuration = GetClock();
SetPlayStartTime(TimeStamp());
}
// Notify the audio sink, so that it notices that we've stopped playing,
// so it can pause audio playback.
mDecoder->GetReentrantMonitor().NotifyAll();
NS_ASSERTION(!IsPlaying(), "Should report not playing at end of StopPlayback()");
DispatchDecodeTasksIfNeeded();
@ -1794,7 +1796,7 @@ MediaDecoderStateMachine::StartAudioThread()
if (HasAudio() && !mAudioSink) {
mAudioCompleted = false;
mAudioSink = new AudioSink(mAudioQueue, mDecoder->GetReentrantMonitor(),
mAudioSink = new AudioSink(mAudioQueue,
GetMediaTime(), mInfo.mAudio,
mDecoder->GetAudioChannel());

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

@ -1449,10 +1449,14 @@ MediaFormatReader::GetBuffered()
return intervals;
}
int64_t startTime;
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
NS_ENSURE_TRUE(HaveStartTime(), media::TimeIntervals());
if (!ForceZeroStartTime()) {
if (!HaveStartTime()) {
return intervals;
}
startTime = StartTime();
} else {
// MSE, start time is assumed to be 0 we can proceeed with what we have.
startTime = 0;
}
// Ensure we have up to date buffered time range.
if (HasVideo()) {

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

@ -3473,6 +3473,13 @@ MediaStreamGraphImpl::ApplyAudioContextOperationImpl(AudioNodeStream* aStream,
mMixer.RemoveCallback(CurrentDriver()->AsAudioCallbackDriver());
CurrentDriver()->SwitchAtNextIteration(driver);
}
// We are closing or suspending an AudioContext, but we just got resumed.
// Queue the operation on the next driver so that the ordering is
// preserved.
} else if (!audioTrackPresent && CurrentDriver()->Switching()) {
MOZ_ASSERT(CurrentDriver()->NextDriver()->AsAudioCallbackDriver());
CurrentDriver()->NextDriver()->AsAudioCallbackDriver()->
EnqueueStreamAndPromiseForOperation(aStream, aPromise, aOperation);
} else {
// We are closing or suspending an AudioContext, but something else is
// using the audio stream, we can resolve the promise now.

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

@ -184,6 +184,18 @@ CDMCaps::AutoLock::AreCapsKnown()
return mData.mCaps != 0;
}
bool
CDMCaps::AutoLock::CanRenderAudio()
{
return mData.HasCap(GMP_EME_CAP_RENDER_AUDIO);
}
bool
CDMCaps::AutoLock::CanRenderVideo()
{
return mData.HasCap(GMP_EME_CAP_RENDER_VIDEO);
}
bool
CDMCaps::AutoLock::CanDecryptAndDecodeAudio()
{

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

@ -75,6 +75,9 @@ public:
// GMP_EME_CAP_* flags from gmp-decryption.h.
void SetCaps(uint64_t aCaps);
bool CanRenderAudio();
bool CanRenderVideo();
bool CanDecryptAndDecodeAudio();
bool CanDecryptAndDecodeVideo();

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

@ -432,13 +432,13 @@ GeckoMediaPluginServiceParent::AsyncShutdownPluginStates::Update(const nsCString
note += pluginIt.Key();
note += ":{";
bool firstInstance = true;
for (auto instanceIt = pluginIt.Data()->ConstIter(); !instanceIt.Done(); instanceIt.Next()) {
for (auto instanceIt = pluginIt.UserData()->ConstIter(); !instanceIt.Done(); instanceIt.Next()) {
if (!firstInstance) { note += ','; } else { firstInstance = false; }
note += instanceIt.Key();
note += ":\"";
note += instanceIt.Data()->mStateSequence;
note += instanceIt.UserData()->mStateSequence;
note += '=';
note += instanceIt.Data()->mLastStateDescription;
note += instanceIt.UserData()->mLastStateDescription;
note += '"';
}
note += '}';

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

@ -125,6 +125,10 @@ typedef int64_t GMPTimestamp;
#define GMP_EME_CAP_DECRYPT_AND_DECODE_AUDIO (uint64_t(1) << 2)
#define GMP_EME_CAP_DECRYPT_AND_DECODE_VIDEO (uint64_t(1) << 3)
// Capability; CDM can decrypt and then decode and render encrypted buffers
#define GMP_EME_CAP_RENDER_AUDIO (uint64_t(1) << 4)
#define GMP_EME_CAP_RENDER_VIDEO (uint64_t(1) << 5)
// Callbacks to be called from the CDM. Threadsafe.
class GMPDecryptorCallback {
public:

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

@ -1840,7 +1840,9 @@ nsresult OggReader::SeekBisection(int64_t aTarget,
media::TimeIntervals OggReader::GetBuffered()
{
MOZ_ASSERT(OnTaskQueue());
NS_ENSURE_TRUE(HaveStartTime(), media::TimeIntervals());
if (!HaveStartTime()) {
return media::TimeIntervals();
}
{
mozilla::ReentrantMonitorAutoEnter mon(mMonitor);
if (mIsChained) {

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

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html class="reftest-wait">
<head>
<script>
function boom()
{
var ac = new window.AudioContext();
var oscillator = ac.createOscillator();
oscillator.start(0);
oscillator.stop(0.1);
setTimeout(function() {
oscillator.channelCount = 1;
oscillator.channelCountMode = "explicit";
oscillator.channelInterpretation = "speakers";
document.documentElement.removeAttribute("class");
}, 1000);
}
</script>
</head>
<body onload="boom();"></body>
</html>

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

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<script>
function boom()
{
new Audio().mozCaptureStreamUntilEnded();
var ac = new window.AudioContext();
ac.resume();
ac.close();
}
</script>
</head>
<body onload="boom();"></body>
</html>

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

@ -81,6 +81,8 @@ load 1157994.html
load 1122218.html
load 1127188.html
load audiocontext-double-suspend.html
load 1185176.html
load 1185192.html
include ../../mediasource/test/crashtests/crashtests.list
# This needs to run at the end to avoid leaking busted state into other tests.

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

@ -26,8 +26,11 @@ function startTest() {
'Media recorder stream = element stream post recording');
stopCount++;
if (stopCount == 2) {
is(2, dataavailable, 'Should has two dataavailable event');
SimpleTest.finish();
if (dataavailable >= 2) {
SimpleTest.finish();
} else {
ok(false, 'Should have at least two dataavailable events');
}
}
}
recorder.ondataavailable = function (evt) {
@ -41,9 +44,6 @@ function startTest() {
info('blob size = ' + evt.data.size);
is(evt.data.type, expectedMimeType,
'Blob data received should have type = ' + expectedMimeType);
} else {
is(evt.data.type, '',
'Blob data received should have empty type');
}
dataavailable++;
}

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

@ -455,31 +455,31 @@ var commandsPeerConnectionOfferAnswer = [
},
function PC_LOCAL_CHECK_STATS(test) {
return test.pcLocal.getStats(null).then(stats => {
return test.pcLocal.getStats().then(stats => {
test.pcLocal.checkStats(stats, test.steeplechase);
});
},
function PC_REMOTE_CHECK_STATS(test) {
test.pcRemote.getStats(null).then(stats => {
test.pcRemote.getStats().then(stats => {
test.pcRemote.checkStats(stats, test.steeplechase);
});
},
function PC_LOCAL_CHECK_ICE_CONNECTION_TYPE(test) {
test.pcLocal.getStats(null).then(stats => {
test.pcLocal.getStats().then(stats => {
test.pcLocal.checkStatsIceConnectionType(stats);
});
},
function PC_REMOTE_CHECK_ICE_CONNECTION_TYPE(test) {
test.pcRemote.getStats(null).then(stats => {
test.pcRemote.getStats().then(stats => {
test.pcRemote.checkStatsIceConnectionType(stats);
});
},
function PC_LOCAL_CHECK_ICE_CONNECTIONS(test) {
test.pcLocal.getStats(null).then(stats => {
test.pcLocal.getStats().then(stats => {
test.pcLocal.checkStatsIceConnections(stats,
test._offer_constraints,
test._offer_options,
@ -488,7 +488,7 @@ var commandsPeerConnectionOfferAnswer = [
},
function PC_REMOTE_CHECK_ICE_CONNECTIONS(test) {
test.pcRemote.getStats(null).then(stats => {
test.pcRemote.getStats().then(stats => {
test.pcRemote.checkStatsIceConnections(stats,
test._offer_constraints,
test._offer_options,

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

@ -294,9 +294,10 @@ AudioNode::SendThreeDPointParameterToStream(uint32_t aIndex, const ThreeDPoint&
void
AudioNode::SendChannelMixingParametersToStream()
{
MOZ_ASSERT(mStream, "How come we don't have a stream here?");
mStream->SetChannelMixingParameters(mChannelCount, mChannelCountMode,
mChannelInterpretation);
if (mStream) {
mStream->SetChannelMixingParameters(mChannelCount, mChannelCountMode,
mChannelInterpretation);
}
}
void
@ -422,8 +423,9 @@ AudioNode::SetPassThrough(bool aPassThrough)
{
MOZ_ASSERT(NumberOfInputs() <= 1 && NumberOfOutputs() == 1);
mPassThrough = aPassThrough;
MOZ_ASSERT(mStream, "How come we don't have a stream here?");
mStream->SetPassThrough(mPassThrough);
if (mStream) {
mStream->SetPassThrough(mPassThrough);
}
}
} // namespace dom

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

@ -786,7 +786,9 @@ nsresult WebMReader::SeekInternal(int64_t aTarget)
media::TimeIntervals WebMReader::GetBuffered()
{
MOZ_ASSERT(OnTaskQueue());
NS_ENSURE_TRUE(HaveStartTime(), media::TimeIntervals());
if (!HaveStartTime()) {
return media::TimeIntervals();
}
AutoPinned<MediaResource> resource(mDecoder->GetResource());
media::TimeIntervals buffered;

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

@ -144,7 +144,7 @@ interface mozRTCPeerConnection : EventTarget {
attribute EventHandler onremovestream;
attribute EventHandler oniceconnectionstatechange;
Promise<RTCStatsReport> getStats (MediaStreamTrack? selector);
Promise<RTCStatsReport> getStats (optional MediaStreamTrack? selector);
// Data channel.
RTCDataChannel createDataChannel (DOMString label,

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

@ -122,7 +122,7 @@ EGLDisplay __stdcall eglGetPlatformDisplayEXT(EGLenum platform, void *native_dis
#if !defined(ANGLE_ENABLE_WINDOWS_STORE)
// Validate the display device context
if (WindowFromDC(displayId) == NULL)
if (displayId != EGL_DEFAULT_DISPLAY && WindowFromDC(displayId) == NULL)
{
return egl::success(EGL_NO_DISPLAY);
}

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

@ -196,6 +196,14 @@ public:
return false;
}
/**
* Returns true if the context is using WARP. This should only be overridden
* for an ANGLE implementation.
*/
virtual bool IsWARP() const {
return false;
}
/**
* Return true if we are running on a OpenGL core profile context
*/

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

@ -66,6 +66,10 @@ public:
return sEGLLibrary.IsANGLE();
}
virtual bool IsWARP() const override {
return sEGLLibrary.IsWARP();
}
virtual bool BindTexImage() override;
virtual bool ReleaseTexImage() override;

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

@ -287,7 +287,7 @@ CreateOffscreenFBOContext(bool requireCompatProfile)
}
already_AddRefed<GLContext>
GLContextProviderCGL::CreateHeadless(bool requireCompatProfile)
GLContextProviderCGL::CreateHeadless(bool requireCompatProfile, bool forceEnabled)
{
nsRefPtr<GLContextCGL> gl;
gl = CreateOffscreenFBOContext(requireCompatProfile);

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

@ -933,9 +933,9 @@ GLContextEGL::CreateEGLPixmapOffscreenContext(const mozilla::gfx::IntSize& size)
}
already_AddRefed<GLContext>
GLContextProviderEGL::CreateHeadless(bool)
GLContextProviderEGL::CreateHeadless(bool requireCompatProfile, bool forceEnabled)
{
if (!sEGLLibrary.EnsureInitialized()) {
if (!sEGLLibrary.EnsureInitialized(forceEnabled)) {
return nullptr;
}

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

@ -1215,7 +1215,7 @@ DONE_CREATING_PIXMAP:
}
already_AddRefed<GLContext>
GLContextProviderGLX::CreateHeadless(bool)
GLContextProviderGLX::CreateHeadless(bool requireCompatProfile, bool forceEnabled)
{
IntSize dummySize = IntSize(16, 16);
nsRefPtr<GLContext> glContext = CreateOffscreenPixmapContext(dummySize);

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

@ -66,7 +66,7 @@ public:
// Just create a context. We'll add offscreen stuff ourselves.
static already_AddRefed<GLContext>
CreateHeadless(bool requireCompatProfile);
CreateHeadless(bool requireCompatProfile, bool forceEnabled = false);
/**
* Create wrapping Gecko GLContext for external gl context.

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

@ -607,7 +607,7 @@ CreateWindowOffscreenContext()
}
already_AddRefed<GLContext>
GLContextProviderWGL::CreateHeadless(bool)
GLContextProviderWGL::CreateHeadless(bool requireCompatProfile, bool forceEnabled)
{
if (!sWGLLib.EnsureInitialized()) {
return nullptr;

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

@ -54,6 +54,11 @@
#define LOCAL_EGL_PRESERVED_RESOURCES 0x3030
#define LOCAL_EGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_EXT 0x3138
// ANGLE_platform_angle_d3d
#define LOCAL_EGL_PLATFORM_ANGLE_ANGLE 0x3201
#define LOCAL_EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3202
#define LOCAL_EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE 0x3206
#define LOCAL_GL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
#define LOCAL_GL_CONTEXT_LOST 0x9242
#define LOCAL_GL_CONTEXT_FLAGS_ARB 0x2094

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

@ -9,6 +9,7 @@
#include "mozilla/Assertions.h"
#include "nsDirectoryServiceDefs.h"
#include "nsDirectoryServiceUtils.h"
#include "nsIGfxInfo.h"
#include "nsPrintfCString.h"
#ifdef XP_WIN
#include "nsWindowsHelpers.h"
@ -101,8 +102,36 @@ LoadLibraryForEGLOnWindows(const nsAString& filename)
}
return lib;
}
#endif // XP_WIN
static EGLDisplay
GetAndInitWARPDisplay(GLLibraryEGL& egl, void* displayType)
{
EGLint attrib_list[] = { LOCAL_EGL_PLATFORM_ANGLE_TYPE_ANGLE,
LOCAL_EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE,
LOCAL_EGL_NONE };
EGLDisplay display = egl.fGetPlatformDisplayEXT(LOCAL_EGL_PLATFORM_ANGLE_ANGLE,
displayType,
attrib_list);
if (display == EGL_NO_DISPLAY)
return EGL_NO_DISPLAY;
if (!egl.fInitialize(display, nullptr, nullptr))
return EGL_NO_DISPLAY;
return display;
}
static bool
IsAccelAngleSupported(const nsCOMPtr<nsIGfxInfo>& gfxInfo)
{
int32_t angleSupport;
gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_WEBGL_ANGLE, &angleSupport);
return (angleSupport == nsIGfxInfo::FEATURE_STATUS_OK);
}
static EGLDisplay
GetAndInitDisplay(GLLibraryEGL& egl, void* displayType)
{
@ -117,7 +146,7 @@ GetAndInitDisplay(GLLibraryEGL& egl, void* displayType)
}
bool
GLLibraryEGL::EnsureInitialized()
GLLibraryEGL::EnsureInitialized(bool forceAccel)
{
if (mInitialized) {
return true;
@ -277,42 +306,60 @@ GLLibraryEGL::EnsureInitialized()
}
}
#endif
mEGLDisplay = GetAndInitDisplay(*this, EGL_DEFAULT_DISPLAY);
const char* vendor = (char*)fQueryString(mEGLDisplay, LOCAL_EGL_VENDOR);
if (vendor && (strstr(vendor, "TransGaming") != 0 ||
strstr(vendor, "Google Inc.") != 0))
{
mIsANGLE = true;
}
mEGLDisplay = EGL_NO_DISPLAY;
// Check the ANGLE support the system has
nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
mIsANGLE = IsExtensionSupported(ANGLE_platform_angle_d3d);
if (mIsANGLE) {
EGLDisplay newDisplay = EGL_NO_DISPLAY;
bool accelAngleSupport = IsAccelAngleSupported(gfxInfo);
bool warpAngleSupport = gfxPlatform::CanUseDirect3D11ANGLE();
// D3D11 ANGLE only works with OMTC; there's a bug in the non-OMTC layer
// manager, and it's pointless to try to fix it. We also don't try
// D3D11 ANGLE if the layer manager is prefering D3D9 (hrm, do we care?)
if (gfxPrefs::LayersOffMainThreadCompositionEnabled() &&
!gfxPrefs::LayersPreferD3D9())
{
if (gfxPrefs::WebGLANGLEForceD3D11()) {
newDisplay = GetAndInitDisplay(*this,
LOCAL_EGL_D3D11_ONLY_DISPLAY_ANGLE);
} else if (gfxPrefs::WebGLANGLETryD3D11() && gfxPlatform::CanUseDirect3D11ANGLE()) {
newDisplay = GetAndInitDisplay(*this,
LOCAL_EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE);
bool shouldTryAccel = forceAccel || accelAngleSupport;
bool shouldTryWARP = !shouldTryAccel && warpAngleSupport;
if (gfxPrefs::WebGLANGLEForceWARP()) {
shouldTryWARP = true;
shouldTryAccel = false;
}
// Fallback to a WARP display if non-WARP is blacklisted,
// or if WARP is forced
if (shouldTryWARP) {
mEGLDisplay = GetAndInitWARPDisplay(*this,
EGL_DEFAULT_DISPLAY);
if (mEGLDisplay != EGL_NO_DISPLAY) {
mIsWARP = true;
}
}
if (newDisplay != EGL_NO_DISPLAY) {
DebugOnly<EGLBoolean> success = fTerminate(mEGLDisplay);
MOZ_ASSERT(success == LOCAL_EGL_TRUE);
mEGLDisplay = newDisplay;
vendor = (char*)fQueryString(mEGLDisplay, LOCAL_EGL_VENDOR);
// If falling back to WARP did not work and we don't want to try
// using HW accelerated ANGLE, then fail
if (mEGLDisplay == EGL_NO_DISPLAY && !shouldTryAccel) {
NS_ERROR("Fallback WARP ANGLE context failed to initialize.");
return false;
}
// Hardware accelerated ANGLE path
if (mEGLDisplay == EGL_NO_DISPLAY && shouldTryAccel) {
// D3D11 ANGLE only works with OMTC; there's a bug in the non-OMTC layer
// manager, and it's pointless to try to fix it. We also don't try
// D3D11 ANGLE if the layer manager is prefering D3D9 (hrm, do we care?)
if (gfxPrefs::LayersOffMainThreadCompositionEnabled() &&
!gfxPrefs::LayersPreferD3D9())
{
if (gfxPrefs::WebGLANGLEForceD3D11()) {
mEGLDisplay = GetAndInitDisplay(*this,
LOCAL_EGL_D3D11_ONLY_DISPLAY_ANGLE);
} else if (gfxPrefs::WebGLANGLETryD3D11() && gfxPlatform::CanUseDirect3D11ANGLE()) {
mEGLDisplay = GetAndInitDisplay(*this,
LOCAL_EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE);
}
}
}
}
if (mEGLDisplay == EGL_NO_DISPLAY) {
mEGLDisplay = GetAndInitDisplay(*this, EGL_DEFAULT_DISPLAY);
}
InitExtensionsFromDisplay(mEGLDisplay);

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

@ -108,7 +108,8 @@ public:
GLLibraryEGL()
: mInitialized(false),
mEGLLibrary(nullptr),
mIsANGLE(false)
mIsANGLE(false),
mIsWARP(false)
{
}
@ -469,6 +470,10 @@ public:
return mIsANGLE;
}
bool IsWARP() const {
return mIsWARP;
}
bool HasKHRImageBase() {
return IsExtensionSupported(KHR_image) || IsExtensionSupported(KHR_image_base);
}
@ -489,7 +494,7 @@ public:
return IsExtensionSupported(EXT_create_context_robustness);
}
bool EnsureInitialized();
bool EnsureInitialized(bool forceAccel = false);
void DumpEGLConfig(EGLConfig cfg);
void DumpEGLConfigs();
@ -619,6 +624,7 @@ private:
EGLDisplay mEGLDisplay;
bool mIsANGLE;
bool mIsWARP;
};
extern GLLibraryEGL sEGLLibrary;

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

@ -98,7 +98,10 @@ ClientCanvasLayer::Initialize(const Data& aData)
}
case mozilla::layers::LayersBackend::LAYERS_D3D11: {
#ifdef XP_WIN
// Enable surface sharing only if ANGLE and compositing devices
// are both WARP or both not WARP
if (mGLContext->IsANGLE() &&
(mGLContext->IsWARP() == gfxWindowsPlatform::GetPlatform()->IsWARP()) &&
gfxWindowsPlatform::GetPlatform()->DoesD3D11TextureSharingWork())
{
factory = SurfaceFactory_ANGLEShareHandle::Create(mGLContext, caps, forwarder,

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

@ -953,7 +953,7 @@ ClientTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
js::ProfileEntry::Category::GRAPHICS);
mNewValidRegion = aNewValidRegion;
Update(aNewValidRegion, aPaintRegion);
Update(aNewValidRegion, aPaintRegion, aDirtyRegion);
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
if (PR_IntervalNow() - start > 10) {
@ -1049,7 +1049,8 @@ void PadDrawTargetOutFromRegion(RefPtr<DrawTarget> drawTarget, nsIntRegion &regi
}
void
ClientTiledLayerBuffer::PostValidate(const nsIntRegion& aPaintRegion)
ClientTiledLayerBuffer::PostValidate(const nsIntRegion& aPaintRegion,
const nsIntRegion& aDirtyRegion)
{
if (gfxPrefs::TiledDrawTargetEnabled() && mMoz2DTiles.size() > 0) {
gfx::TileSet tileset;
@ -1065,7 +1066,7 @@ ClientTiledLayerBuffer::PostValidate(const nsIntRegion& aPaintRegion)
ctx->SetMatrix(
ctx->CurrentMatrix().Scale(mResolution, mResolution).Translate(ThebesPoint(-mTilingOrigin)));
mCallback(mPaintedLayer, ctx, aPaintRegion, aPaintRegion,
mCallback(mPaintedLayer, ctx, aPaintRegion, aDirtyRegion,
DrawRegionClip::DRAW, nsIntRegion(), mCallbackData);
mMoz2DTiles.clear();
// Reset:
@ -1095,7 +1096,8 @@ ClientTiledLayerBuffer::UnlockTile(TileClient& aTile)
}
void ClientTiledLayerBuffer::Update(const nsIntRegion& newValidRegion,
const nsIntRegion& aPaintRegion)
const nsIntRegion& aPaintRegion,
const nsIntRegion& aDirtyRegion)
{
const IntSize scaledTileSize = GetScaledTileSize();
const gfx::IntRect newBounds = newValidRegion.GetBounds();
@ -1148,7 +1150,7 @@ void ClientTiledLayerBuffer::Update(const nsIntRegion& newValidRegion,
}
}
PostValidate(aPaintRegion);
PostValidate(aPaintRegion, aDirtyRegion);
for (TileClient& tile : mRetainedTiles) {
UnlockTile(tile);

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

@ -419,7 +419,9 @@ public:
LayerManager::DrawPaintedLayerCallback aCallback,
void* aCallbackData);
void Update(const nsIntRegion& aNewValidRegion, const nsIntRegion& aPaintRegion);
void Update(const nsIntRegion& aNewValidRegion,
const nsIntRegion& aPaintRegion,
const nsIntRegion& aDirtyRegion);
void ReadLock();
@ -449,7 +451,7 @@ public:
return;
}
Update(nsIntRegion(), nsIntRegion());
Update(nsIntRegion(), nsIntRegion(), nsIntRegion());
mResolution = aResolution;
}
@ -467,7 +469,8 @@ protected:
const nsIntPoint& aTileRect,
const nsIntRegion& dirtyRect);
void PostValidate(const nsIntRegion& aPaintRegion);
void PostValidate(const nsIntRegion& aPaintRegion,
const nsIntRegion& aDirtyRegion);
void UnlockTile(TileClient& aTile);

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

@ -1264,6 +1264,7 @@ CompositorParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
// race condition.
mLayerManager->UpdateRenderBounds(aTargetConfig.naturalBounds());
mLayerManager->SetRegionToClear(aTargetConfig.clearRegion());
mLayerManager->GetCompositor()->SetScreenRotation(aTargetConfig.rotation());
mCompositionManager->Updated(aIsFirstPaint, aTargetConfig);
Layer* root = aLayerTree->GetRoot();

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

@ -245,11 +245,6 @@ LayerTransactionParent::RecvUpdate(InfallibleTArray<Edit>&& cset,
return true;
}
if (mLayerManager && mLayerManager->GetCompositor() &&
!targetConfig.naturalBounds().IsEmpty()) {
mLayerManager->GetCompositor()->SetScreenRotation(targetConfig.rotation());
}
EditReplyVector replyv;
AutoLayerTransactionParentAsyncMessageSender autoAsyncMessageSender(this);

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

@ -381,6 +381,7 @@ private:
DECL_GFX_PREF(Live, "ui.click_hold_context_menus.delay", UiClickHoldContextMenusDelay, int32_t, 500);
DECL_GFX_PREF(Once, "webgl.angle.force-d3d11", WebGLANGLEForceD3D11, bool, false);
DECL_GFX_PREF(Once, "webgl.angle.try-d3d11", WebGLANGLETryD3D11, bool, false);
DECL_GFX_PREF(Once, "webgl.angle.force-warp", WebGLANGLEForceWARP, bool, false);
DECL_GFX_PREF(Live, "webgl.disable-fail-if-major-performance-caveat",
WebGLDisableFailIfMajorPerformanceCaveat, bool, false);
DECL_GFX_PREF(Once, "webgl.force-layers-readback", WebGLForceLayersReadback, bool, false);

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

@ -2122,6 +2122,12 @@ gfxWindowsPlatform::InitD3D11Devices()
mD3D11Status = FeatureStatus::Failed;
}
// Only test for texture sharing on Windows 8 since it puts the device into
// an unusable state if used on Windows 7
if (mD3D11Device && IsWin8OrLater()) {
mDoesD3D11TextureSharingWork = ::DoesD3D11TextureSharingWork(mD3D11Device);
}
if (!mD3D11Device) {
// We could not get a D3D11 compositor, and there's nothing more we can try.
return;

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

@ -18,7 +18,7 @@ import re
def env(config):
e = dict(os.environ)
e['PATH'] = '%s:%s' % (e['PATH'], config['sixgill_bin'])
e['PATH'] = ':'.join(p for p in (config.get('gcc_bin'), config.get('sixgill_bin'), e['PATH']) if p)
e['XDB'] = '%(sixgill_bin)s/xdb.so' % config
e['SOURCE'] = config['source']
e['ANALYZED_OBJDIR'] = config['objdir']

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

@ -280,27 +280,34 @@ function edgeCanGC(edge)
{
if (edge.Kind != "Call")
return false;
var callee = edge.Exp[0];
while (callee.Kind == "Drf")
callee = callee.Exp[0];
if (callee.Kind == "Var") {
var variable = callee.Variable;
assert(variable.Kind == "Func");
var callee = mangled(variable.Name[0]);
if ((callee in gcFunctions) || ((callee + internalMarker) in gcFunctions))
return "'" + variable.Name[0] + "'";
return null;
if (variable.Kind == "Func") {
var callee = mangled(variable.Name[0]);
if ((callee in gcFunctions) || ((callee + internalMarker) in gcFunctions))
return "'" + variable.Name[0] + "'";
return null;
}
var varName = variable.Name[0];
return indirectCallCannotGC(functionName, varName) ? null : "*" + varName;
}
assert(callee.Kind == "Drf");
if (callee.Exp[0].Kind == "Fld") {
var field = callee.Exp[0].Field;
if (callee.Kind == "Fld") {
var field = callee.Field;
var csuName = field.FieldCSU.Type.Name;
var fullFieldName = csuName + "." + field.Name[0];
if (fieldCallCannotGC(csuName, fullFieldName))
return null;
return (fullFieldName in suppressedFunctions) ? null : fullFieldName;
}
assert(callee.Exp[0].Kind == "Var");
var varName = callee.Exp[0].Variable.Name[0];
return indirectCallCannotGC(functionName, varName) ? null : "*" + varName;
}
// Search recursively through predecessors from a variable use, returning

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

@ -245,21 +245,6 @@ function ignoreGCFunction(mangled)
return false;
}
function isRootedTypeName(name)
{
if (name == "mozilla::ErrorResult" ||
name == "JSErrorResult" ||
name == "WrappableJSErrorResult" ||
name == "js::frontend::TokenStream" ||
name == "js::frontend::TokenStream::Position" ||
name == "ModuleCompiler" ||
name == "JSAddonId")
{
return true;
}
return false;
}
function stripUCSAndNamespace(name)
{
if (name.startsWith('struct '))
@ -282,16 +267,36 @@ function stripUCSAndNamespace(name)
return name;
}
function isRootedPointerTypeName(name)
function isRootedGCTypeName(name)
{
return (name == "JSAddonId");
}
function isRootedGCPointerTypeName(name)
{
name = stripUCSAndNamespace(name);
if (name.startsWith('MaybeRooted<'))
return /\(js::AllowGC\)1u>::RootType/.test(name);
if (name == "ErrorResult" ||
name == "JSErrorResult" ||
name == "WrappableJSErrorResult" ||
name == "frontend::TokenStream" ||
name == "frontend::TokenStream::Position" ||
name == "ModuleCompiler")
{
return true;
}
return name.startsWith('Rooted') || name.startsWith('PersistentRooted');
}
function isRootedTypeName(name)
{
return isRootedGCTypeName(name) || isRootedGCPointerTypeName(name);
}
function isUnsafeStorage(typeName)
{
typeName = stripUCSAndNamespace(typeName);
@ -357,6 +362,10 @@ function listGCPointers() {
'JS::Value',
'jsid',
'js::TypeSet',
'js::TypeSet::ObjectKey',
'js::TypeSet::Type',
// AutoCheckCannotGC should also not be held live across a GC function.
'JS::AutoCheckCannotGC',
];

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

@ -74,44 +74,60 @@ var gcTypes = {}; // map from parent struct => Set of GC typed children
var gcPointers = {}; // map from parent struct => Set of GC typed children
var nonGCTypes = {}; // set of types that would ordinarily be GC types but we are suppressing
var nonGCPointers = {}; // set of types that would ordinarily be GC pointers but we are suppressing
var gcFields = {};
var gcFields = new Map;
// "typeName is a (pointer to a)*'depth' GC type because it contains a field
// named 'child' of type 'why' (or pointer to 'why' if ptrdness == 1), which
function stars(n) { return n ? '*' + stars(n-1) : '' };
// "typeName is a (pointer to a)^'typePtrLevel' GC type because it contains a field
// named 'child' of type 'why' (or pointer to 'why' if fieldPtrLevel == 1), which is
// itself a GCThing or GCPointer."
function markGCType(typeName, child, why, depth, ptrdness)
function markGCType(typeName, child, why, typePtrLevel, fieldPtrLevel, indent)
{
//printErr(`${indent}${typeName}${stars(typePtrLevel)} may be a gctype/ptr because of its child '${child}' of type ${why}${stars(fieldPtrLevel)}`);
// Some types, like UniquePtr, do not mark/trace/relocate their contained
// pointers and so should not hold them live across a GC. UniquePtr in
// particular should be the only thing pointing to a structure containing a
// GCPointer, so nothing else can be tracing it and it'll die when the
// UniquePtr goes out of scope. So we say that a UniquePtr's memory is just
// as unsafe as the stack for storing GC pointers.
if (!ptrdness && isUnsafeStorage(typeName)) {
// GCPointer, so nothing else can possibly trace it and it'll die when the
// UniquePtr goes out of scope. So we say that memory pointed to by a
// UniquePtr is just as unsafe as the stack for storing GC pointers.
if (!fieldPtrLevel && isUnsafeStorage(typeName)) {
// The UniquePtr itself is on the stack but when you dereference the
// contained pointer, you get to the unsafe memory that we are treating
// as if it were the stack (aka depth 0). Note that
// as if it were the stack (aka ptrLevel 0). Note that
// UniquePtr<UniquePtr<JSObject*>> is fine, so we don't want to just
// hardcode the depth.
ptrdness = -1;
// hardcode the ptrLevel.
fieldPtrLevel = -1;
}
depth += ptrdness;
if (depth > 2)
// Example: with:
// struct Pair { JSObject* foo; int bar; };
// struct { Pair** info }***
// make a call to:
// child='info' typePtrLevel=3 fieldPtrLevel=2
// for a final ptrLevel of 5, used to later call:
// child='foo' typePtrLevel=5 fieldPtrLevel=1
//
var ptrLevel = typePtrLevel + fieldPtrLevel;
// ...except when > 2 levels of pointers away from an actual GC thing, stop
// searching the graph. (This would just be > 1, except that a UniquePtr
// field might still have a GC pointer.)
if (ptrLevel > 2)
return;
if (depth == 0 && isRootedTypeName(typeName))
if (ptrLevel == 0 && isRootedGCTypeName(typeName))
return;
if (depth == 1 && isRootedPointerTypeName(typeName))
if (ptrLevel == 1 && isRootedGCPointerTypeName(typeName))
return;
if (depth == 0) {
if (ptrLevel == 0) {
if (typeName in nonGCTypes)
return;
if (!(typeName in gcTypes))
gcTypes[typeName] = new Set();
gcTypes[typeName].add(why);
} else if (depth == 1) {
} else if (ptrLevel == 1) {
if (typeName in nonGCPointers)
return;
if (!(typeName in gcPointers))
@ -119,32 +135,34 @@ function markGCType(typeName, child, why, depth, ptrdness)
gcPointers[typeName].add(why);
}
if (!(typeName in gcFields))
gcFields[typeName] = new Map();
gcFields[typeName].set(why, [ child, ptrdness ]);
if (ptrLevel < 2) {
if (!gcFields.has(typeName))
gcFields.set(typeName, new Map());
gcFields.get(typeName).set(child, [ why, fieldPtrLevel ]);
}
if (typeName in structureParents) {
for (var field of structureParents[typeName]) {
var [ holderType, fieldName ] = field;
markGCType(holderType, typeName, fieldName, depth, 0);
markGCType(holderType, fieldName, typeName, ptrLevel, 0, indent + " ");
}
}
if (typeName in pointerParents) {
for (var field of pointerParents[typeName]) {
var [ holderType, fieldName ] = field;
markGCType(holderType, typeName, fieldName, depth, 1);
markGCType(holderType, fieldName, typeName, ptrLevel, 1, indent + " ");
}
}
}
function addGCType(typeName, child, why, depth, ptrdness)
function addGCType(typeName, child, why, depth, fieldPtrLevel)
{
markGCType(typeName, 'annotation', '<annotation>', 0, 0);
markGCType(typeName, '<annotation>', '(annotation)', 0, 0, "");
}
function addGCPointer(typeName)
{
markGCType(typeName, 'annotation', '<pointer-annotation>', 1, 0);
markGCType(typeName, '<pointer-annotation>', '(annotation)', 1, 0, "");
}
for (var type of listNonGCTypes())
@ -163,17 +181,19 @@ function explain(csu, indent, seen) {
if (!seen)
seen = new Set();
seen.add(csu);
if (!(csu in gcFields))
if (!gcFields.has(csu))
return;
if (gcFields[csu].has('<annotation>')) {
var fields = gcFields.get(csu);
if (fields.has('<annotation>')) {
print(indent + "which is a GCThing because I said so");
return;
}
if (gcFields[csu].has('<pointer-annotation>')) {
if (fields.has('<pointer-annotation>')) {
print(indent + "which is a GCPointer because I said so");
return;
}
for (var [ field, [ child, ptrdness ] ] of gcFields[csu]) {
for (var [ field, [ child, ptrdness ] ] of fields) {
var inherit = "";
if (field == "field:0")
inherit = " (probably via inheritance)";

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -40,7 +40,7 @@ bool
CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,
const AutoNameVector& formals, JS::SourceBufferHolder& srcBuf,
HandleObject enclosingStaticScope);
Handle<ScopeObject*> enclosingStaticScope);
bool
CompileStarGeneratorBody(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,

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

@ -406,12 +406,9 @@ IonBuilder::DontInline(JSScript* targetScript, const char* reason)
bool
IonBuilder::hasCommonInliningPath(const JSScript* scriptToInline)
{
if (this->script() == scriptToInline)
return true;
// Find all previous inlinings of the |scriptToInline| and check for common
// inlining paths with the top of the inlining stack.
for (IonBuilder* it = this; it; it = it->callerBuilder_) {
for (IonBuilder* it = this->callerBuilder_; it; it = it->callerBuilder_) {
if (it->script() != scriptToInline)
continue;

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

@ -4199,7 +4199,7 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
const char* name, unsigned nargs, const char* const* argnames,
SourceBufferHolder& srcBuf,
HandleObject enclosingDynamicScope,
HandleObject enclosingStaticScope,
Handle<ScopeObject*> enclosingStaticScope,
MutableHandleFunction fun)
{
MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));

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

@ -803,7 +803,7 @@ ObjectGroup::newArrayObject(ExclusiveContext* cx,
}
// Get a type which captures all the elements in the array to be created.
TypeSet::Type elementType = TypeSet::UnknownType();
Rooted<TypeSet::Type> elementType(cx, TypeSet::UnknownType());
if (arrayKind != NewArrayKind::UnknownIndex && length != 0) {
elementType = GetValueTypeForTable(vp[0]);
for (unsigned i = 1; i < length; i++) {
@ -860,7 +860,7 @@ ObjectGroup::newArrayObject(ExclusiveContext* cx,
group->setPreliminaryObjects(preliminaryObjects);
}
if (!p.add(cx, *table, key, group))
if (!p.add(cx, *table, ObjectGroupCompartment::ArrayObjectKey(elementType), group))
return nullptr;
}

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

@ -272,7 +272,7 @@ class TypeSet
// Information about a single concrete type. We pack this into one word,
// where small values are particular primitive or other singleton types and
// larger values are either specific JS objects or object groups.
class Type
class Type : public JS::StaticTraceable
{
friend class TypeSet;
@ -350,6 +350,10 @@ class TypeSet
inline ObjectGroup* group() const;
inline ObjectGroup* groupNoBarrier() const;
static void trace(Type* v, JSTracer* trc) {
MarkTypeUnbarriered(trc, v, "TypeSet::Type");
}
bool operator == (Type o) const { return data == o.data; }
bool operator != (Type o) const { return data != o.data; }
};

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