Merge mozilla-central to b2g-inbound

This commit is contained in:
Carsten "Tomcat" Book 2015-07-01 15:49:08 +02:00
commit 1fe5e00320
509 changed files with 20405 additions and 20371 deletions

View File

@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Bug 1075758 (updating ICU to 55) requires a clobber.
Bug 1178215 requires clobber for libvpx file moves.

View File

@ -297,7 +297,6 @@ pref("ui.dragThresholdY", 25);
// Layers Acceleration. We can only have nice things on gonk, because
// they're not maintained anywhere else.
pref("layers.offmainthreadcomposition.enabled", true);
pref("layers.offmainthreadcomposition.async-animations", true);
#ifndef MOZ_WIDGET_GONK
pref("dom.ipc.tabs.disabled", true);
#else

View File

@ -1806,7 +1806,11 @@ pref("geo.wifi.uri", "https://location.services.mozilla.com/v1/geolocate?key=%MO
#endif
#ifdef XP_MACOSX
#ifdef RELEASE_BUILD
pref("geo.provider.use_corelocation", false);
#else
pref("geo.provider.use_corelocation", true);
#endif
#endif
#ifdef XP_WIN

View File

@ -0,0 +1,96 @@
# 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/.
let TrackingProtection = {
PREF_ENABLED: "privacy.trackingprotection.enabled",
init() {
let $ = selector => document.querySelector(selector);
this.container = $("#tracking-protection-container");
this.content = $("#tracking-protection-content");
this.updateEnabled();
Services.prefs.addObserver(this.PREF_ENABLED, this, false);
this.enabledHistogram.add(this.enabled);
},
uninit() {
Services.prefs.removeObserver(this.PREF_ENABLED, this);
},
observe() {
this.updateEnabled();
},
updateEnabled() {
this.enabled = Services.prefs.getBoolPref(this.PREF_ENABLED);
this.container.hidden = !this.enabled;
},
get enabledHistogram() {
return Services.telemetry.getHistogramById("TRACKING_PROTECTION_ENABLED");
},
get eventsHistogram() {
return Services.telemetry.getHistogramById("TRACKING_PROTECTION_EVENTS");
},
onSecurityChange(state) {
if (!this.enabled) {
return;
}
let {
STATE_BLOCKED_TRACKING_CONTENT, STATE_LOADED_TRACKING_CONTENT
} = Ci.nsIWebProgressListener;
if (state & STATE_BLOCKED_TRACKING_CONTENT) {
this.content.setAttribute("block-active", true);
this.content.removeAttribute("block-disabled");
} else if (state & STATE_LOADED_TRACKING_CONTENT) {
this.content.setAttribute("block-disabled", true);
this.content.removeAttribute("block-active");
} else {
this.content.removeAttribute("block-disabled");
this.content.removeAttribute("block-active");
}
// Telemetry for state change.
this.eventsHistogram.add(0);
},
disableForCurrentPage() {
// Convert document URI into the format used by
// nsChannelClassifier::ShouldEnableTrackingProtection.
// Any scheme turned into https is correct.
let normalizedUrl = Services.io.newURI(
"https://" + gBrowser.selectedBrowser.currentURI.hostPort,
null, null);
// Add the current host in the 'trackingprotection' consumer of
// the permission manager using a normalized URI. This effectively
// places this host on the tracking protection allowlist.
Services.perms.add(normalizedUrl,
"trackingprotection", Services.perms.ALLOW_ACTION);
// Telemetry for disable protection.
this.eventsHistogram.add(1);
BrowserReload();
},
enableForCurrentPage() {
// Remove the current host from the 'trackingprotection' consumer
// of the permission manager. This effectively removes this host
// from the tracking protection allowlist.
Services.perms.remove(gBrowser.selectedBrowser.currentURI.host,
"trackingprotection");
// Telemetry for enable protection.
this.eventsHistogram.add(2);
BrowserReload();
},
};

View File

@ -280,6 +280,7 @@ let gInitialPages = [
#include browser-social.js
#include browser-tabview.js
#include browser-thumbnails.js
#include browser-trackingprotection.js
#ifdef MOZ_DATA_REPORTING
#include browser-data-submission-info-bar.js
@ -964,6 +965,7 @@ var gBrowserInit = {
BrowserOnClick.init();
DevEdition.init();
AboutPrivateBrowsingListener.init();
TrackingProtection.init();
let mm = window.getGroupMessageManager("browsers");
mm.loadFrameScript("chrome://browser/content/tab-content.js", true);
@ -1446,12 +1448,6 @@ var gBrowserInit = {
}
}, 5000);
// Telemetry for tracking protection.
let tpEnabled = gPrefService
.getBoolPref("privacy.trackingprotection.enabled");
Services.telemetry.getHistogramById("TRACKING_PROTECTION_ENABLED")
.add(tpEnabled);
PanicButtonNotifier.init();
});
this.delayedStartupFinished = true;
@ -1534,6 +1530,8 @@ var gBrowserInit = {
DevEdition.uninit();
TrackingProtection.uninit();
gMenuButtonUpdateBadge.uninit();
ReadingListUI.uninit();
@ -4383,6 +4381,7 @@ var XULBrowserWindow = {
uri = Services.uriFixup.createExposableURI(uri);
} catch (e) {}
gIdentityHandler.checkIdentity(this._state, uri);
TrackingProtection.onSecurityChange(this._state);
},
// simulate all change notifications after switching tabs
@ -6781,7 +6780,7 @@ var gIdentityHandler = {
nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT |
nsIWebProgressListener.STATE_LOADED_TRACKING_CONTENT)) {
this.showBadContentDoorhanger(state);
} else if (gPrefService.getBoolPref("privacy.trackingprotection.enabled")) {
} else if (TrackingProtection.enabled) {
// We didn't show the shield
Services.telemetry.getHistogramById("TRACKING_PROTECTION_SHIELD")
.add(0);

View File

@ -2,118 +2,100 @@
* 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/. */
// Test that the Tracking Protection Doorhanger appears
// and has the correct state when tracking content is blocked (Bug 1043801)
// Test that the Tracking Protection section is visible in the Control Center
// and has the correct state for the cases when:
// * A page with no tracking elements is loaded.
// * A page with tracking elements is loaded and they are blocked.
// * A page with tracking elements is loaded and they are not blocked.
// See also Bugs 1175327 and 1043801.
var PREF = "privacy.trackingprotection.enabled";
var BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/benignPage.html";
var TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/trackingPage.html";
let PREF = "privacy.trackingprotection.enabled";
let BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/benignPage.html";
let TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/trackingPage.html";
let TrackingProtection = null;
function testBenignPage(gTestBrowser)
{
// Make sure the doorhanger does NOT appear
var notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
is(notification, null, "Tracking Content Doorhanger did NOT appear when protection was ON and tracking was NOT present");
registerCleanupFunction(function() {
TrackingProtection = null;
Services.prefs.clearUserPref(PREF);
gBrowser.removeCurrentTab();
});
function hidden(sel) {
let win = gBrowser.ownerGlobal;
let el = win.document.querySelector(sel);
let display = win.getComputedStyle(el).getPropertyValue("display", null);
return display === "none";
}
function* testTrackingPage(gTestBrowser)
{
// Make sure the doorhanger appears
var notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
isnot(notification, null, "Tracking Content Doorhanger did appear when protection was ON and tracking was present");
notification.reshow();
var notificationElement = PopupNotifications.panel.firstChild;
function testBenignPage() {
ok (!TrackingProtection.content.hasAttribute("block-disabled"), "blocking not disabled");
ok (!TrackingProtection.content.hasAttribute("block-active"), "blocking is not active");
// Wait for the method to be attached after showing the popup
yield promiseWaitForCondition(() => {
return notificationElement.disableTrackingContentProtection;
});
// Make sure the state of the doorhanger includes blocking tracking elements
ok(notificationElement.isTrackingContentBlocked,
"Tracking Content is being blocked");
// Make sure the notification has no trackingblockdisabled attribute
ok(!notificationElement.hasAttribute("trackingblockdisabled"),
"Doorhanger must have no trackingblockdisabled attribute");
// Make sure that the no tracking elements message appears
ok (!hidden("#tracking-not-detected"), "labelNoTracking is visible");
ok (hidden("#tracking-loaded"), "labelTrackingLoaded is hidden");
ok (hidden("#tracking-blocked"), "labelTrackingBlocked is hidden");
}
function* testTrackingPageWhitelisted(gTestBrowser)
{
// Make sure the doorhanger appears
var notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
isnot(notification, null, "Tracking Content Doorhanger did appear when protection was ON and tracking was present but white-listed");
notification.reshow();
var notificationElement = PopupNotifications.panel.firstChild;
function testTrackingPage() {
ok (!TrackingProtection.content.hasAttribute("block-disabled"), "blocking not disabled");
ok (TrackingProtection.content.hasAttribute("block-active"), "blocking is active");
// Wait for the method to be attached after showing the popup
yield promiseWaitForCondition(() => {
return notificationElement.disableTrackingContentProtection;
});
var notificationElement = PopupNotifications.panel.firstChild;
// Make sure the state of the doorhanger does NOT include blocking tracking elements
ok(!notificationElement.isTrackingContentBlocked,
"Tracking Content is NOT being blocked");
// Make sure the notification has the trackingblockdisabled attribute set to true
is(notificationElement.getAttribute("trackingblockdisabled"), "true",
"Doorhanger must have [trackingblockdisabled='true'] attribute");
// Make sure that the blocked tracking elements message appears
ok (hidden("#tracking-not-detected"), "labelNoTracking is hidden");
ok (hidden("#tracking-loaded"), "labelTrackingLoaded is hidden");
ok (!hidden("#tracking-blocked"), "labelTrackingBlocked is visible");
}
function testTrackingPageOFF(gTestBrowser)
{
// Make sure the doorhanger does NOT appear
var notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
is(notification, null, "Tracking Content Doorhanger did NOT appear when protection was OFF and tracking was present");
}
function testTrackingPageWhitelisted() {
ok (TrackingProtection.content.hasAttribute("block-disabled"), "blocking is disabled");
ok (!TrackingProtection.content.hasAttribute("block-active"), "blocking is not active");
function testBenignPageOFF(gTestBrowser)
{
// Make sure the doorhanger does NOT appear
var notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
is(notification, null, "Tracking Content Doorhanger did NOT appear when protection was OFF and tracking was NOT present");
// Make sure that the blocked tracking elements message appears
ok (hidden("#tracking-not-detected"), "labelNoTracking is hidden");
ok (!hidden("#tracking-loaded"), "labelTrackingLoaded is visible");
ok (hidden("#tracking-blocked"), "labelTrackingBlocked is hidden");
}
add_task(function* () {
registerCleanupFunction(function() {
Services.prefs.clearUserPref(PREF);
gBrowser.removeCurrentTab();
});
yield updateTrackingProtectionDatabase();
let tab = gBrowser.selectedTab = gBrowser.addTab();
// Enable Tracking Protection
TrackingProtection = gBrowser.ownerGlobal.TrackingProtection;
ok (TrackingProtection, "Functionality is attached to the browser window");
is (TrackingProtection.enabled, Services.prefs.getBoolPref(PREF),
"The initial enabled value is based on the default pref value");
info("Enable Tracking Protection");
Services.prefs.setBoolPref(PREF, true);
ok (TrackingProtection.enabled, "Functionality is enabled after setting the pref");
// Point tab to a test page NOT containing tracking elements
info("Point tab to a test page NOT containing tracking elements");
yield promiseTabLoadEvent(tab, BENIGN_PAGE);
testBenignPage(gBrowser.getBrowserForTab(tab));
testBenignPage();
// Point tab to a test page containing tracking elements
info("Point tab to a test page containing tracking elements");
yield promiseTabLoadEvent(tab, TRACKING_PAGE);
// Tracking content must be blocked
yield testTrackingPage(gBrowser.getBrowserForTab(tab));
info("Tracking content must be blocked");
testTrackingPage();
// Disable Tracking Content Protection for the page (which reloads the page)
PopupNotifications.panel.firstChild.disableTrackingContentProtection();
info("Disable Tracking Content Protection for the page (which reloads the page)");
TrackingProtection.disableForCurrentPage();
// Wait for tab to reload following tracking-protection page white-listing
info("Wait for tab to reload following tracking-protection page white-listing");
yield promiseTabLoadEvent(tab);
// Tracking content must be white-listed (NOT blocked)
yield testTrackingPageWhitelisted(gBrowser.getBrowserForTab(tab));
info("Tracking content must be white-listed (NOT blocked)");
testTrackingPageWhitelisted();
// Re-enable Tracking Content Protection for the page (which reloads the page)
PopupNotifications.panel.firstChild.enableTrackingContentProtection();
info("Re-enable Tracking Content Protection for the page (which reloads the page)");
TrackingProtection.enableForCurrentPage();
// Wait for tab to reload following tracking-protection page white-listing
info("Wait for tab to reload following tracking-protection page white-listing");
yield promiseTabLoadEvent(tab);
// Tracking content must be blocked
yield testTrackingPage(gBrowser.getBrowserForTab(tab));
info("Tracking content must be blocked");
testTrackingPage();
});

View File

@ -2,45 +2,48 @@
* 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/. */
// Test that the Tracking Protection Doorhanger does not ever appear
// when the feature is off (Bug 1043801)
// Test that the Tracking Protection section is never visible in the
// Control Center when the feature is off.
// See also Bugs 1175327 and 1043801.
var PREF = "privacy.trackingprotection.enabled";
var BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/benignPage.html";
var TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/trackingPage.html";
let PREF = "privacy.trackingprotection.enabled";
let BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/benignPage.html";
let TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/trackingPage.html";
let TrackingProtection = null;
function testTrackingPageOFF(gTestBrowser)
{
// Make sure the doorhanger does NOT appear
var notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
is(notification, null, "Tracking Content Doorhanger did NOT appear when protection was OFF and tracking was present");
registerCleanupFunction(function() {
TrackingProtection = null;
Services.prefs.clearUserPref(PREF);
gBrowser.removeCurrentTab();
});
function testTrackingPageOFF() {
ok (TrackingProtection.container.hidden, "The container is hidden");
}
function testBenignPageOFF(gTestBrowser)
{
// Make sure the doorhanger does NOT appear
var notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
is(notification, null, "Tracking Content Doorhanger did NOT appear when protection was OFF and tracking was NOT present");
function testBenignPageOFF() {
ok (TrackingProtection.container.hidden, "The container is hidden");
}
add_task(function* () {
registerCleanupFunction(function() {
Services.prefs.clearUserPref(PREF);
gBrowser.removeCurrentTab();
});
yield updateTrackingProtectionDatabase();
let tab = gBrowser.selectedTab = gBrowser.addTab();
// Disable Tracking Protection
TrackingProtection = gBrowser.ownerGlobal.TrackingProtection;
ok (TrackingProtection, "Functionality is attached to the browser window");
is (TrackingProtection.enabled, Services.prefs.getBoolPref(PREF),
"The initial enabled value is based on the default pref value");
info ("Disable Tracking Protection");
Services.prefs.setBoolPref(PREF, false);
ok (!TrackingProtection.enabled, "Functionality is disabled after setting the pref");
// Point tab to a test page containing tracking elements
info ("Point tab to a test page containing tracking elements");
yield promiseTabLoadEvent(tab, TRACKING_PAGE);
testTrackingPageOFF(gBrowser.getBrowserForTab(tab));
testTrackingPageOFF();
// Point tab to a test page NOT containing tracking elements
info ("Point tab to a test page NOT containing tracking elements");
yield promiseTabLoadEvent(tab, BENIGN_PAGE);
testBenignPageOFF(gBrowser.getBrowserForTab(tab));
testBenignPageOFF();
});

View File

@ -2377,10 +2377,6 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
Services.urlFormatter.formatURLPref("app.support.baseURL")
+ "tracking-protection";
}
if (Services.prefs.getBoolPref("privacy.trackingprotection.enabled")) {
let histogram = Services.telemetry.getHistogramById("TRACKING_PROTECTION_EVENTS");
histogram.add(0);
}
]]></constructor>
<method name="disableMixedContentProtection">
<body><![CDATA[
@ -2415,10 +2411,6 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
// places this host on the tracking protection allowlist.
Services.perms.add(normalizedUrl,
"trackingprotection", Services.perms.ALLOW_ACTION);
// Telemetry for disable protection
let histogram = Services.telemetry.getHistogramById(
"TRACKING_PROTECTION_EVENTS");
histogram.add(1);
BrowserReload();
]]></body>
</method>
@ -2429,10 +2421,6 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
// from the tracking protection allowlist.
Services.perms.remove(gBrowser.selectedBrowser.currentURI.host,
"trackingprotection");
// Telemetry for enable protection
let histogram = Services.telemetry.getHistogramById(
"TRACKING_PROTECTION_EVENTS");
histogram.add(2);
BrowserReload();
]]></body>
</method>

View File

@ -36,6 +36,42 @@
oncommand="gIdentityHandler.showSubView('security', this)"/>
</hbox>
<!-- Tracking Protection Section -->
<hbox id="tracking-protection-container" class="identity-popup-section">
<vbox id="tracking-protection-content" flex="1">
<description class="identity-popup-text identity-popup-headline"
crop="end"
value="&trackingProtection.title;" />
<label id="tracking-blocked"
class="identity-popup-text"
crop="end">&trackingProtection.detectedBlocked;</label>
<label id="tracking-loaded"
class="identity-popup-text"
crop="end">&trackingProtection.detectedNotBlocked;</label>
<label id="tracking-not-detected"
class="identity-popup-text"
crop="end">&trackingProtection.notDetected;</label>
<button id="tracking-actions"
type="menu" label="&trackingContentBlocked.options;"
sizetopopup="none">
<menupopup>
<menuitem
id="tracking-action-unblock"
label="&trackingProtection.unblock.label;"
accesskey="&trackingProtection.unblock.accesskey;"
oncommand="TrackingProtection.disableForCurrentPage();"/>
<menuitem
id="tracking-action-block"
label="&trackingProtection.block.label;"
accesskey="&trackingProtection.block.accesskey;"
oncommand="TrackingProtection.enableForCurrentPage();"/>
</menupopup>
</button>
</vbox>
</hbox>
<!-- Permissions Section -->
<hbox id="identity-popup-permissions" class="identity-popup-section">
<vbox id="identity-popup-permissions-content" flex="1">

View File

@ -21,7 +21,7 @@ function test() {
];
if (AppConstants.NIGHTLY_BUILD)
tests.push(test_locbar_suggestion_retention("searches", true)),
tests.push(test_locbar_suggestion_retention("searches", true));
run_test_subset(tests);
}

View File

@ -21,7 +21,7 @@ function test() {
];
if (AppConstants.NIGHTLY_BUILD)
tests.push(test_locbar_suggestion_retention("searches", true)),
tests.push(test_locbar_suggestion_retention("searches", true));
run_test_subset(tests);
}

View File

@ -4,6 +4,7 @@ no_sccache=1
ac_add_options --with-l10n-base=../../l10n
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
ac_add_options --enable-update-packaging
ac_add_options --with-branding=browser/branding/nightly
. $topsrcdir/build/unix/mozconfig.linux32

View File

@ -4,6 +4,7 @@ no_sccache=1
ac_add_options --with-l10n-base=../../l10n
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
ac_add_options --enable-update-packaging
ac_add_options --with-branding=browser/branding/nightly
. $topsrcdir/build/unix/mozconfig.linux

View File

@ -3,6 +3,7 @@
ac_add_options --with-l10n-base=../../../l10n
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
ac_add_options --enable-update-packaging
ac_add_options --with-branding=browser/branding/nightly
if test "${MOZ_UPDATE_CHANNEL}" = "nightly"; then
ac_add_options --with-macbundlename-prefix=Firefox

View File

@ -3,6 +3,7 @@
ac_add_options --with-l10n-base=../../l10n
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
ac_add_options --enable-update-packaging
ac_add_options --with-branding=browser/branding/nightly
. "$topsrcdir/build/mozconfig.cache"
. "$topsrcdir/build/mozconfig.common.override"

View File

@ -4,6 +4,7 @@ ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
ac_add_options --enable-update-packaging
ac_add_options --with-l10n-base=../../l10n
ac_add_options --with-windows-version=603
ac_add_options --with-branding=browser/branding/nightly
export MOZILLA_OFFICIAL=1

View File

@ -5,6 +5,7 @@ ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
ac_add_options --enable-update-packaging
ac_add_options --with-l10n-base=../../l10n
ac_add_options --with-windows-version=603
ac_add_options --with-branding=browser/branding/nightly
export MOZILLA_OFFICIAL=1

View File

@ -455,6 +455,7 @@ function Workers() {
this._onWorkerListChanged = this._onWorkerListChanged.bind(this);
this._onWorkerFreeze = this._onWorkerFreeze.bind(this);
this._onWorkerThaw = this._onWorkerThaw.bind(this);
this._onWorkerSelect = this._onWorkerSelect.bind(this);
}
Workers.prototype = {
@ -476,6 +477,10 @@ Workers.prototype = {
},
_updateWorkerList: function () {
if (!this._tabClient.listWorkers) {
return;
}
this._tabClient.listWorkers((response) => {
let workerActors = new Set();
for (let worker of response.workers) {
@ -516,6 +521,13 @@ Workers.prototype = {
_onWorkerThaw: function (type, packet) {
let workerClient = this._workerClients.get(packet.from);
DebuggerView.Workers.addWorker(packet.from, workerClient.url);
},
_onWorkerSelect: function (workerActor) {
let workerClient = this._workerClients.get(workerActor);
gDevTools.showToolbox(devtools.TargetFactory.forWorker(workerClient),
"jsdebugger",
devtools.Toolbox.HostType.WINDOW);
}
};

View File

@ -3,7 +3,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
function WorkersView() {}
function WorkersView() {
this._onWorkerSelect = this._onWorkerSelect.bind(this);
}
WorkersView.prototype = Heritage.extend(WidgetMethods, {
initialize: function () {
@ -17,6 +19,7 @@ WorkersView.prototype = Heritage.extend(WidgetMethods, {
showArrows: true,
});
this.emptyText = L10N.getStr("noWorkersText");
this.widget.addEventListener("select", this._onWorkerSelect, false);
},
addWorker: function (actor, name) {
@ -30,6 +33,13 @@ WorkersView.prototype = Heritage.extend(WidgetMethods, {
removeWorker: function (actor) {
this.remove(this.getItemByValue(actor));
},
_onWorkerSelect: function () {
if (this.selectedItem !== null) {
DebuggerController.Workers._onWorkerSelect(this.selectedItem.value);
this.selectedItem = null;
}
}
});

View File

@ -60,6 +60,15 @@ exports.TargetFactory = {
return targetPromise;
},
forWorker: function TF_forWorker(workerClient) {
let target = targets.get(workerClient);
if (target == null) {
target = new WorkerTarget(workerClient);
targets.set(workerClient, target);
}
return target;
},
/**
* Creating a target for a tab that is being closed is a problem because it
* allows a leak as a result of coming after the close event which normally
@ -799,3 +808,64 @@ WindowTarget.prototype = {
return 'WindowTarget:' + this.window;
},
};
function WorkerTarget(workerClient) {
EventEmitter.decorate(this);
this._workerClient = workerClient;
}
/**
* A WorkerTarget represents a worker. Unlike TabTarget, which can represent
* either a local or remote tab, WorkerTarget always represents a remote worker.
* Moreover, unlike TabTarget, which is constructed with a placeholder object
* for remote tabs (from which a TabClient can then be lazily obtained),
* WorkerTarget is constructed with a WorkerClient directly.
*
* The reason for this is that in order to get notifications when a worker
* closes/freezes/thaws, the UI needs to attach to each worker anyway, so by
* the time a WorkerTarget for a given worker is created, a WorkerClient for
* that worker will already be available. Consequently, there is no need to
* obtain a WorkerClient lazily.
*
* WorkerClient is designed to mimic the interface of TabClient as closely as
* possible. This allows us to debug workers as if they were ordinary tabs,
* requiring only minimal changes to the rest of the frontend.
*/
WorkerTarget.prototype = {
get isRemote() {
return true;
},
get isTabActor() {
return true;
},
get form() {
return {
from: this._workerClient.actor,
type: "attached",
isFrozen: this._workerClient.isFrozen,
url: this._workerClient.url
};
},
get activeTab() {
return this._workerClient;
},
get client() {
return this._workerClient.client;
},
destroy: function () {},
hasActor: function (name) {
return false;
},
getTrait: function (name) {
return undefined;
},
makeRemote: function () {}
};

View File

@ -768,6 +768,15 @@ you can use these alternative items. Otherwise, their values should be empty. -
<!ENTITY mixedContentBlocked2.block.accesskey "E">
<!ENTITY mixedContentBlocked2.disabled.message "Protection is disabled">
<!ENTITY trackingProtection.title "Tracking Protection">
<!ENTITY trackingProtection.detectedBlocked "Attempts to track your online behavior have been blocked.">
<!ENTITY trackingProtection.detectedNotBlocked "Tracking elements detected. You have disabled protection on this site.">
<!ENTITY trackingProtection.notDetected "No tracking elements detected on this website.">
<!ENTITY trackingProtection.unblock.label "Disable protection for this site">
<!ENTITY trackingProtection.unblock.accesskey "D">
<!ENTITY trackingProtection.block.label "Enable protection for this site">
<!ENTITY trackingProtection.block.accesskey "E">
<!ENTITY trackingContentBlocked.message "Tracking">
<!ENTITY trackingContentBlocked.moreinfo "Parts of the page that track your online activity have been blocked.">
<!ENTITY trackingContentBlocked.learnMore "Learn More">

View File

@ -10,6 +10,8 @@ let Cu = Components.utils;
this.EXPORTED_SYMBOLS = [ "NewTabURL" ];
Components.utils.import("resource://gre/modules/Services.jsm");
this.NewTabURL = {
_url: "about:newtab",
_overridden: false,
@ -25,10 +27,12 @@ this.NewTabURL = {
override: function(newURL) {
this._url = newURL;
this._overridden = true;
Services.obs.notifyObservers(null, "newtab-url-changed", this._url);
},
reset: function() {
this._url = "about:newtab";
this._overridden = false;
Services.obs.notifyObservers(null, "newtab-url-changed", this._url);
}
};

View File

@ -4,14 +4,30 @@
"use strict";
Components.utils.import("resource:///modules/NewTabURL.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
function run_test() {
add_task(function* () {
Assert.equal(NewTabURL.get(), "about:newtab", "Default newtab URL should be about:newtab");
let url = "http://example.com/";
let notificationPromise = promiseNewtabURLNotification(url);
NewTabURL.override(url);
yield notificationPromise;
Assert.ok(NewTabURL.overridden, "Newtab URL should be overridden");
Assert.equal(NewTabURL.get(), url, "Newtab URL should be the custom URL");
notificationPromise = promiseNewtabURLNotification("about:newtab");
NewTabURL.reset();
yield notificationPromise;
Assert.ok(!NewTabURL.overridden, "Newtab URL should not be overridden");
Assert.equal(NewTabURL.get(), "about:newtab", "Newtab URL should be the about:newtab");
});
function promiseNewtabURLNotification(aNewURL) {
return new Promise(resolve => {
Services.obs.addObserver(function observer(aSubject, aTopic, aData) {
Services.obs.removeObserver(observer, aTopic);
Assert.equal(aData, aNewURL, "Data for newtab-url-changed notification should be new URL.");
resolve();
}, "newtab-url-changed", false);
});
}

View File

@ -150,6 +150,8 @@ browser.jar:
skin/classic/browser/controlcenter/conn-secure-dv.svg (../shared/controlcenter/conn-secure-dv.svg)
skin/classic/browser/controlcenter/conn-secure-ev.svg (../shared/controlcenter/conn-secure-ev.svg)
skin/classic/browser/controlcenter/permissions.svg (../shared/controlcenter/permissions.svg)
skin/classic/browser/controlcenter/tracking-protection.svg (../shared/controlcenter/tracking-protection.svg)
skin/classic/browser/controlcenter/tracking-protection-disabled.svg (../shared/controlcenter/tracking-protection-disabled.svg)
skin/classic/browser/customizableui/background-noise-toolbar.png (customizableui/background-noise-toolbar.png)
skin/classic/browser/customizableui/customize-illustration.png (../shared/customizableui/customize-illustration.png)
skin/classic/browser/customizableui/customize-illustration-rtl.png (../shared/customizableui/customize-illustration-rtl.png)

View File

@ -194,6 +194,8 @@ browser.jar:
skin/classic/browser/controlcenter/conn-secure-dv.svg (../shared/controlcenter/conn-secure-dv.svg)
skin/classic/browser/controlcenter/conn-secure-ev.svg (../shared/controlcenter/conn-secure-ev.svg)
skin/classic/browser/controlcenter/permissions.svg (../shared/controlcenter/permissions.svg)
skin/classic/browser/controlcenter/tracking-protection.svg (../shared/controlcenter/tracking-protection.svg)
skin/classic/browser/controlcenter/tracking-protection-disabled.svg (../shared/controlcenter/tracking-protection-disabled.svg)
skin/classic/browser/customizableui/background-noise-toolbar.png (customizableui/background-noise-toolbar.png)
skin/classic/browser/customizableui/customize-titleBar-toggle.png (customizableui/customize-titleBar-toggle.png)
skin/classic/browser/customizableui/customize-titleBar-toggle@2x.png (customizableui/customize-titleBar-toggle@2x.png)

View File

@ -55,7 +55,8 @@
#identity-popup-securityView,
#identity-popup-security-content,
#identity-popup-permissions-content {
#identity-popup-permissions-content,
#tracking-protection-content {
padding: 0.75em 0 1em;
-moz-padding-start: calc(2em + 24px);
-moz-padding-end: 1em;
@ -66,7 +67,8 @@
#identity-popup-securityView:-moz-locale-dir(rtl),
#identity-popup-security-content:-moz-locale-dir(rtl),
#identity-popup-permissions-content:-moz-locale-dir(rtl) {
#identity-popup-permissions-content:-moz-locale-dir(rtl),
#tracking-protection-content:-moz-locale-dir(rtl) {
background-position: calc(100% - 1em) 1em;
}
@ -199,6 +201,30 @@
margin-top: 1em;
}
/* TRACKING PROTECTION */
#tracking-protection-content {
background-image: url("chrome://browser/skin/controlcenter/tracking-protection.svg");
}
#tracking-protection-content[block-disabled] {
background-image: url("chrome://browser/skin/controlcenter/tracking-protection-disabled.svg");
}
#tracking-actions {
margin: 1em 0 0;
}
#tracking-protection-content[block-active] > #tracking-not-detected,
#tracking-protection-content[block-disabled] > #tracking-not-detected,
#tracking-protection-content:not([block-active]) > #tracking-blocked,
#tracking-protection-content:not([block-active]) #tracking-action-unblock,
#tracking-protection-content:not([block-disabled]) > #tracking-loaded,
#tracking-protection-content:not([block-disabled]) #tracking-action-block,
#tracking-protection-content:not([block-active]):not([block-disabled]) > #tracking-actions {
display: none;
}
/* PERMISSIONS */
#identity-popup-permissions-content {

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="16"
height="16"
viewBox="0 0 16 16">
<defs>
<path id="shape-shield-outer" d="M8,1L2.8,1.9C2.4,1.9,2,2.4,2,2.8C2,4,2,6.1,2.1,7.1c0.3,2.7,0.8,4,1.9,5.6C5.6,14.7,8,15,8,15s2.4-0.3,4-2.4 c1.2-1.5,1.7-2.9,1.9-5.6C14,6.1,14,4,14,2.8c0-0.5-0.4-0.9-0.8-1L8,1L8,1z"/>
<path id="shape-shield-inner" d="M8,2l5,0.8c0,2,0,3.5-0.1,4.1c-0.3,2.7-0.8,3.8-1.7,5.1c-1.1,1.5-2.7,1.9-3.2,2c-0.4-0.1-2.1-0.5-3.2-2 c-1-1.3-1.5-2.4-1.7-5.1C3,6.3,3,4.8,3,2.8L8,2"/>
<path id="shape-shield-detail" d="M8,13c-0.5-0.1-1.6-0.5-2.4-1.5c-0.9-1.2-1.3-2.1-1.5-4.6C4,6.3,4,5.2,4,3.7L8,3 V13z"/>
<mask id="mask-shield-cutout">
<rect width="16" height="16" fill="#000" />
<use xlink:href="#shape-shield-outer" fill="#fff" />
<use xlink:href="#shape-shield-inner" fill="#000" />
<use xlink:href="#shape-shield-detail" fill="#fff" />
<line x1="3" y1="15" x2="15" y2="3" stroke="#000" stroke-width="2" />
</mask>
</defs>
<use xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout)" fill="#808080" />
<line x1="3" y1="14" x2="15" y2="2" stroke="#d92d21" stroke-width="2" />
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="16"
height="16"
viewBox="0 0 16 16">
<defs>
<path id="shape-shield-outer" d="M8,1L2.8,1.9C2.4,1.9,2,2.4,2,2.8C2,4,2,6.1,2.1,7.1c0.3,2.7,0.8,4,1.9,5.6C5.6,14.7,8,15,8,15s2.4-0.3,4-2.4 c1.2-1.5,1.7-2.9,1.9-5.6C14,6.1,14,4,14,2.8c0-0.5-0.4-0.9-0.8-1L8,1L8,1z"/>
<path id="shape-shield-inner" d="M8,2l5,0.8c0,2,0,3.5-0.1,4.1c-0.3,2.7-0.8,3.8-1.7,5.1c-1.1,1.5-2.7,1.9-3.2,2c-0.4-0.1-2.1-0.5-3.2-2 c-1-1.3-1.5-2.4-1.7-5.1C3,6.3,3,4.8,3,2.8L8,2"/>
<path id="shape-shield-detail" d="M8,13c-0.5-0.1-1.6-0.5-2.4-1.5c-0.9-1.2-1.3-2.1-1.5-4.6C4,6.3,4,5.2,4,3.7L8,3 V13z"/>
<mask id="mask-shield-cutout">
<rect width="16" height="16" fill="#000" />
<use xlink:href="#shape-shield-outer" fill="#fff" />
<use xlink:href="#shape-shield-inner" fill="#000" />
<use xlink:href="#shape-shield-detail" fill="#fff" />
</mask>
</defs>
<use xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout)" fill="#808080" />
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -197,6 +197,8 @@ browser.jar:
skin/classic/browser/controlcenter/conn-secure-dv.svg (../shared/controlcenter/conn-secure-dv.svg)
skin/classic/browser/controlcenter/conn-secure-ev.svg (../shared/controlcenter/conn-secure-ev.svg)
skin/classic/browser/controlcenter/permissions.svg (../shared/controlcenter/permissions.svg)
skin/classic/browser/controlcenter/tracking-protection.svg (../shared/controlcenter/tracking-protection.svg)
skin/classic/browser/controlcenter/tracking-protection-disabled.svg (../shared/controlcenter/tracking-protection-disabled.svg)
skin/classic/browser/customizableui/background-noise-toolbar.png (customizableui/background-noise-toolbar.png)
skin/classic/browser/customizableui/customizeFavicon.ico (../shared/customizableui/customizeFavicon.ico)
skin/classic/browser/customizableui/customize-illustration.png (../shared/customizableui/customize-illustration.png)

View File

@ -678,6 +678,7 @@ VFY_Begin
VFY_CreateContext
VFY_DestroyContext
VFY_End
VFY_EndWithSignature
VFY_Update
VFY_VerifyData
VFY_VerifyDataWithAlgorithmID

View File

@ -5591,6 +5591,9 @@ if test -n "$MOZ_VPX" -a -z "$MOZ_NATIVE_LIBVPX"; then
else
AC_MSG_WARN([No assembler or assembly support for libvpx. Using unoptimized C routines.])
fi
dnl native libvpx no longer has vpx_mem_set_functions
AC_DEFINE(MOZ_VPX_NO_MEM_REPORTING)
fi
dnl ========================================================

View File

@ -201,7 +201,7 @@ ArchiveRequest::GetFilenamesResult(JSContext* aCx,
return NS_ERROR_FAILURE;
}
*aValue = OBJECT_TO_JSVAL(array);
aValue->setObject(*array);
return NS_OK;
}

View File

@ -1271,7 +1271,7 @@ EventSource::DispatchAllMessageEvents()
message->mData.Length());
NS_ENSURE_TRUE_VOID(jsString);
jsData = STRING_TO_JSVAL(jsString);
jsData.setString(jsString);
}
// create an event that uses the MessageEvent interface,

View File

@ -1764,7 +1764,7 @@ WebSocket::CreateAndDispatchMessageEvent(JSContext* aCx,
nsresult rv = nsContentUtils::CreateArrayBuffer(aCx, aData,
arrayBuf.address());
NS_ENSURE_SUCCESS(rv, rv);
jsData = OBJECT_TO_JSVAL(arrayBuf);
jsData.setObject(*arrayBuf);
} else {
NS_RUNTIMEABORT("Unknown binary type!");
return NS_ERROR_UNEXPECTED;
@ -1776,7 +1776,7 @@ WebSocket::CreateAndDispatchMessageEvent(JSContext* aCx,
jsString = JS_NewUCStringCopyN(aCx, utf16Data.get(), utf16Data.Length());
NS_ENSURE_TRUE(jsString, NS_ERROR_FAILURE);
jsData = STRING_TO_JSVAL(jsString);
jsData.setString(jsString);
}
// create an event that uses the MessageEvent interface,

View File

@ -1885,7 +1885,7 @@ ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx,
}
}
v = OBJECT_TO_JSVAL(dot_prototype);
v.setObject(*dot_prototype);
JSAutoCompartment ac(cx, class_obj);

View File

@ -389,7 +389,7 @@ nsDOMDataChannel::DoOnMessageAvailable(const nsACString& aData,
JS::Rooted<JSObject*> arrayBuf(cx);
rv = nsContentUtils::CreateArrayBuffer(cx, aData, arrayBuf.address());
NS_ENSURE_SUCCESS(rv, rv);
jsData = OBJECT_TO_JSVAL(arrayBuf);
jsData.setObject(*arrayBuf);
} else {
NS_RUNTIMEABORT("Unknown binary type!");
return NS_ERROR_UNEXPECTED;
@ -399,7 +399,7 @@ nsDOMDataChannel::DoOnMessageAvailable(const nsACString& aData,
JSString* jsString = JS_NewUCStringCopyN(cx, utf16data.get(), utf16data.Length());
NS_ENSURE_TRUE(jsString, NS_ERROR_FAILURE);
jsData = STRING_TO_JSVAL(jsString);
jsData.setString(jsString);
}
nsCOMPtr<nsIDOMEvent> event;

View File

@ -931,7 +931,7 @@ nsJSContext::AddSupportsPrimitiveTojsvals(nsISupports *aArg, JS::Value *aArgv)
JSString *str = ::JS_NewStringCopyN(cx, data.get(), data.Length());
NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
*aArgv = STRING_TO_JSVAL(str);
aArgv->setString(str);
break;
}
@ -949,7 +949,7 @@ nsJSContext::AddSupportsPrimitiveTojsvals(nsISupports *aArg, JS::Value *aArgv)
::JS_NewUCStringCopyN(cx, data.get(), data.Length());
NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
*aArgv = STRING_TO_JSVAL(str);
aArgv->setString(str);
break;
}
case nsISupportsPrimitive::TYPE_PRBOOL : {
@ -960,7 +960,7 @@ nsJSContext::AddSupportsPrimitiveTojsvals(nsISupports *aArg, JS::Value *aArgv)
p->GetData(&data);
*aArgv = BOOLEAN_TO_JSVAL(data);
aArgv->setBoolean(data);
break;
}
@ -972,7 +972,7 @@ nsJSContext::AddSupportsPrimitiveTojsvals(nsISupports *aArg, JS::Value *aArgv)
p->GetData(&data);
*aArgv = INT_TO_JSVAL(data);
aArgv->setInt32(data);
break;
}
@ -984,7 +984,7 @@ nsJSContext::AddSupportsPrimitiveTojsvals(nsISupports *aArg, JS::Value *aArgv)
p->GetData(&data);
*aArgv = INT_TO_JSVAL(data);
aArgv->setInt32(data);
break;
}
@ -996,7 +996,7 @@ nsJSContext::AddSupportsPrimitiveTojsvals(nsISupports *aArg, JS::Value *aArgv)
p->GetData(&data);
*aArgv = INT_TO_JSVAL(data);
aArgv->setInt32(data);
break;
}
@ -1011,7 +1011,7 @@ nsJSContext::AddSupportsPrimitiveTojsvals(nsISupports *aArg, JS::Value *aArgv)
JSString *str = ::JS_NewStringCopyN(cx, &data, 1);
NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
*aArgv = STRING_TO_JSVAL(str);
aArgv->setString(str);
break;
}
@ -1023,7 +1023,7 @@ nsJSContext::AddSupportsPrimitiveTojsvals(nsISupports *aArg, JS::Value *aArgv)
p->GetData(&data);
*aArgv = INT_TO_JSVAL(data);
aArgv->setInt32(data);
break;
}
@ -1035,7 +1035,7 @@ nsJSContext::AddSupportsPrimitiveTojsvals(nsISupports *aArg, JS::Value *aArgv)
p->GetData(&data);
*aArgv = INT_TO_JSVAL(data);
aArgv->setInt32(data);
break;
}

View File

@ -214,7 +214,7 @@ nsScriptLoader::CheckContentPolicy(nsIDocument* aDocument,
const nsAString &aType)
{
int16_t shouldLoad = nsIContentPolicy::ACCEPT;
nsresult rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_SCRIPT,
nsresult rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_INTERNAL_SCRIPT,
aURI,
aDocument->NodePrincipal(),
aContext,
@ -289,7 +289,7 @@ nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType,
aRequest->mURI,
mDocument,
nsILoadInfo::SEC_NORMAL,
nsIContentPolicy::TYPE_SCRIPT,
nsIContentPolicy::TYPE_INTERNAL_SCRIPT,
loadGroup,
prompter,
nsIRequest::LOAD_NORMAL |

View File

@ -3028,7 +3028,7 @@ CreateGlobal(JSContext* aCx, T* aNative, nsWrapperCache* aCache,
JSAutoCompartment ac(aCx, aGlobal);
{
js::SetReservedSlot(aGlobal, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aNative));
js::SetReservedSlot(aGlobal, DOM_OBJECT_SLOT, JS::PrivateValue(aNative));
NS_ADDREF(aNative);
aCache->SetWrapper(aGlobal);

View File

@ -5570,7 +5570,7 @@ def convertConstIDLValueToJSVal(value):
tag = value.type.tag()
if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16,
IDLType.Tags.uint16, IDLType.Tags.int32]:
return "INT_TO_JSVAL(%s)" % (value.value)
return "JS::Int32Value(%s)" % (value.value)
if tag == IDLType.Tags.uint32:
return "UINT_TO_JSVAL(%sU)" % (value.value)
if tag in [IDLType.Tags.int64, IDLType.Tags.uint64]:

View File

@ -133,9 +133,15 @@ class Configuration:
self.unionsPerFilename = defaultdict(list)
for (t, descriptor, _) in getAllTypes(self.descriptors, self.dictionaries, self.callbacks):
if t.isMozMap():
t = t.inner
t = t.unroll()
while True:
if t.isMozMap():
t = t.inner
elif t.isPromise():
t = t.promiseInnerType()
elif t.unroll() != t:
t = t.unroll()
else:
break
if t.isUnion():
filenamesForUnion = self.filenamesPerUnion[t.name]
if t.filename() not in filenamesForUnion:

View File

@ -281,6 +281,18 @@ ToJSValue(JSContext* aCx,
ErrorResult& aArgument,
JS::MutableHandle<JS::Value> aValue);
// Accept owning WebIDL unions.
template <typename T>
MOZ_WARN_UNUSED_RESULT
typename EnableIf<IsBaseOf<AllOwningUnionBase, T>::value, bool>::Type
ToJSValue(JSContext* aCx,
const T& aArgument,
JS::MutableHandle<JS::Value> aValue)
{
JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
return aArgument.ToJSVal(aCx, global, aValue);
}
// Accept pointers to other things we accept
template <typename T>
MOZ_WARN_UNUSED_RESULT

View File

@ -1273,7 +1273,11 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
args = attr.args() if attr.hasArgs() else []
retType = IDLWrapperType(self.location, self)
if self.identifier.name == "Promise":
promiseType = BuiltinTypes[IDLBuiltinType.Types.any]
else:
promiseType = None
retType = IDLWrapperType(self.location, self, promiseType)
if identifier == "Constructor" or identifier == "ChromeConstructor":
name = "constructor"
@ -2633,6 +2637,10 @@ class IDLWrapperType(IDLType):
return isinstance(self.inner, IDLInterface) and \
self.inner.identifier.name == "Promise"
def promiseInnerType(self):
assert self.isPromise()
return self._promiseInnerType
def isSerializable(self):
if self.isInterface():
if self.inner.isExternal():
@ -2709,9 +2717,9 @@ class IDLWrapperType(IDLType):
# Let's say true, though ideally we'd only do this when
# exposureSet contains the primary global's name.
return True
if (iface.identifier.name == "Promise" and
if (self.isPromise() and
# Check the internal type
not self._promiseInnerType.unroll().isExposedInAllOf(exposureSet)):
not self.promiseInnerType().unroll().isExposedInAllOf(exposureSet)):
return False
return iface.exposureSet.issuperset(exposureSet)

View File

@ -155,14 +155,14 @@ SetJsObject(JSContext* aContext,
v.get_nsString().BeginReading(),
v.get_nsString().Length());
NS_ENSURE_TRUE(jsData, false);
val = STRING_TO_JSVAL(jsData);
val.setString(jsData);
break;
}
case BluetoothValue::Tuint32_t:
val = INT_TO_JSVAL(v.get_uint32_t());
val.setInt32(v.get_uint32_t());
break;
case BluetoothValue::Tbool:
val = BOOLEAN_TO_JSVAL(v.get_bool());
val.setBoolean(v.get_bool());
break;
default:
BT_WARNING("SetJsObject: Parameter is not handled");
@ -197,7 +197,7 @@ BroadcastSystemMessage(const nsAString& aType,
JSString* jsData = JS_NewUCStringCopyN(cx,
aData.get_nsString().BeginReading(),
aData.get_nsString().Length());
value = STRING_TO_JSVAL(jsData);
value.setString(jsData);
} else if (aData.type() == BluetoothValue::TArrayOfBluetoothNamedValue) {
JS::Rooted<JSObject*> obj(cx, JS_NewPlainObject(cx));
if (!obj) {

View File

@ -402,7 +402,8 @@ WebGL2Context::TexSubImage3D(GLenum rawTarget, GLint level,
if (coversWholeImage) {
tex->SetImageDataStatus(texImageTarget, level, WebGLImageDataStatus::InitializedImageData);
} else {
tex->EnsureNoUninitializedImageData(texImageTarget, level);
if (!tex->EnsureInitializedImageData(texImageTarget, level))
return;
}
}

View File

@ -459,7 +459,8 @@ WebGLContext::CopyTexSubImage2D_base(TexImageTarget texImageTarget, GLint level,
tex->SetImageInfo(texImageTarget, level, width, height, 1,
effectiveInternalFormat,
WebGLImageDataStatus::UninitializedImageData);
tex->EnsureNoUninitializedImageData(texImageTarget, level);
if (!tex->EnsureInitializedImageData(texImageTarget, level))
return;
}
// if we are completely outside of the framebuffer, we can exit now with our black texture
@ -607,7 +608,8 @@ WebGLContext::CopyTexSubImage2D(GLenum rawTexImgTarget,
if (coversWholeImage) {
tex->SetImageDataStatus(texImageTarget, level, WebGLImageDataStatus::InitializedImageData);
} else {
tex->EnsureNoUninitializedImageData(texImageTarget, level);
if (!tex->EnsureInitializedImageData(texImageTarget, level))
return;
}
}
@ -3062,7 +3064,8 @@ WebGLContext::CompressedTexSubImage2D(GLenum rawTexImgTarget, GLint level, GLint
if (coversWholeImage) {
tex->SetImageDataStatus(texImageTarget, level, WebGLImageDataStatus::InitializedImageData);
} else {
tex->EnsureNoUninitializedImageData(texImageTarget, level);
if (!tex->EnsureInitializedImageData(texImageTarget, level))
return;
}
}
@ -3535,7 +3538,8 @@ WebGLContext::TexSubImage2D_base(GLenum rawImageTarget, GLint level,
if (coversWholeImage) {
tex->SetImageDataStatus(texImageTarget, level, WebGLImageDataStatus::InitializedImageData);
} else {
tex->EnsureNoUninitializedImageData(texImageTarget, level);
if (!tex->EnsureInitializedImageData(texImageTarget, level))
return;
}
}
MakeContextCurrent();

View File

@ -492,7 +492,7 @@ WebGLTexture::ResolvedFakeBlackStatus()
const ImageInfo& imageInfo = ImageInfoAt(imageTarget, level);
if (imageInfo.mImageDataStatus == WebGLImageDataStatus::UninitializedImageData)
{
EnsureNoUninitializedImageData(imageTarget, level);
EnsureInitializedImageData(imageTarget, level);
}
}
}
@ -613,13 +613,13 @@ ClearWithTempFB(WebGLContext* webgl, GLuint tex,
}
void
WebGLTexture::EnsureNoUninitializedImageData(TexImageTarget imageTarget,
GLint level)
bool
WebGLTexture::EnsureInitializedImageData(TexImageTarget imageTarget,
GLint level)
{
const ImageInfo& imageInfo = ImageInfoAt(imageTarget, level);
if (!imageInfo.HasUninitializedImageData())
return;
return true;
mContext->MakeContextCurrent();
@ -631,13 +631,11 @@ WebGLTexture::EnsureNoUninitializedImageData(TexImageTarget imageTarget,
if (cleared) {
SetImageDataStatus(imageTarget, level,
WebGLImageDataStatus::InitializedImageData);
return;
return true;
}
}
// That didn't work. Try uploading zeros then.
gl::ScopedBindTexture autoBindTex(mContext->gl, mGLName, mTarget);
size_t bitspertexel = GetBitsPerTexel(imageInfo.mEffectiveInternalFormat);
MOZ_ASSERT((bitspertexel % 8) == 0); // That would only happen for
// compressed images, which cannot use
@ -653,11 +651,22 @@ WebGLTexture::EnsureNoUninitializedImageData(TexImageTarget imageTarget,
MOZ_ASSERT(checked_byteLength.isValid()); // Should have been checked
// earlier.
// Infallible for now.
UniquePtr<uint8_t> zeros((uint8_t*)moz_xcalloc(1,
checked_byteLength.value()));
size_t byteCount = checked_byteLength.value();
UniquePtr<uint8_t> zeros((uint8_t*)calloc(1, byteCount));
if (zeros == nullptr) {
// Failed to allocate memory. Lose the context. Return OOM error.
mContext->ForceLoseContext(true);
mContext->ErrorOutOfMemory("EnsureInitializedImageData: Failed to alloc %u "
"bytes to clear image target `%s` level `%d`.",
byteCount, mContext->EnumName(imageTarget.get()),
level);
return false;
}
gl::GLContext* gl = mContext->gl;
gl::ScopedBindTexture autoBindTex(gl, mGLName, mTarget);
GLenum driverInternalFormat = LOCAL_GL_NONE;
GLenum driverFormat = LOCAL_GL_NONE;
GLenum driverType = LOCAL_GL_NONE;
@ -691,11 +700,27 @@ WebGLTexture::EnsureNoUninitializedImageData(TexImageTarget imageTarget,
// from this here.
gfxCriticalError() << "GL context GetAndFlushUnderlyingGLErrors " << gfx::hexa(error);
printf_stderr("Error: 0x%4x\n", error);
MOZ_CRASH(); // Errors on texture upload have been related to video
// memory exposure in the past.
if (error != LOCAL_GL_OUT_OF_MEMORY) {
// Errors on texture upload have been related to video
// memory exposure in the past, which is a security issue.
// Force loss of context.
mContext->ForceLoseContext(true);
return false;
}
// Out-of-memory uploading pixels to GL. Lose context and report OOM.
mContext->ForceLoseContext(true);
mContext->ErrorOutOfMemory("EnsureNoUninitializedImageData: Failed to "
"upload texture of width: %u, height: %u, "
"depth: %u to target %s level %d.",
imageInfo.mWidth, imageInfo.mHeight, imageInfo.mDepth,
mContext->EnumName(imageTarget.get()), level);
return false;
}
SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData);
return true;
}
void

View File

@ -212,7 +212,7 @@ public:
imageInfo.mImageDataStatus = newStatus;
}
void EnsureNoUninitializedImageData(TexImageTarget imageTarget, GLint level);
bool EnsureInitializedImageData(TexImageTarget imageTarget, GLint level);
protected:
TexMinFilter mMinFilter;

View File

@ -113,9 +113,15 @@ InternalRequest::MapContentPolicyTypeToRequestContext(nsContentPolicyType aConte
case nsIContentPolicy::TYPE_OTHER:
context = RequestContext::Internal;
break;
case nsIContentPolicy::TYPE_SCRIPT:
case nsIContentPolicy::TYPE_INTERNAL_SCRIPT:
context = RequestContext::Script;
break;
case nsIContentPolicy::TYPE_INTERNAL_WORKER:
context = RequestContext::Worker;
break;
case nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER:
context = RequestContext::Sharedworker;
break;
case nsIContentPolicy::TYPE_IMAGE:
context = RequestContext::Image;
break;

View File

@ -53,13 +53,13 @@ namespace dom {
* ping | TYPE_PING
* plugin | TYPE_OBJECT_SUBREQUEST
* prefetch |
* script | TYPE_SCRIPT
* sharedworker |
* script | TYPE_INTERNAL_SCRIPT
* sharedworker | TYPE_INTERNAL_SHARED_WORKER
* subresource | Not supported by Gecko
* style | TYPE_STYLESHEET
* track | TYPE_INTERNAL_TRACK
* video | TYPE_INTERNAL_VIDEO
* worker |
* worker | TYPE_INTERNAL_WORKER
* xmlhttprequest | TYPE_XMLHTTPREQUEST
* xslt | TYPE_XSLT
*
@ -68,7 +68,6 @@ namespace dom {
* TODO: Split TYPE_XMLHTTPREQUEST and TYPE_DATAREQUEST for EventSource
* TODO: Figure out if TYPE_WEBSOCKET maps to anything useful
* TODO: Differentiate between frame and iframe
* TODO: Add content types for different kinds of workers
* TODO: Add a content type for prefetch
* TODO: Use the content type for manifest when it becomes available
* TODO: Add a content type for location

View File

@ -23070,8 +23070,7 @@ ObjectStoreAddOrPutRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
MOZ_ASSERT(autoIncrementNum > 0);
if (autoIncrementNum > (1LL << 53)) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
}
key.SetFromInteger(autoIncrementNum);

View File

@ -89,8 +89,8 @@ GetJSValFromKeyPathString(JSContext* aCx,
nsString targetObjectPropName;
JS::Rooted<JSObject*> targetObject(aCx, nullptr);
JS::Rooted<JSObject*> obj(aCx,
aValue.isPrimitive() ? nullptr : aValue.toObjectOrNull());
JS::Rooted<JS::Value> currentVal(aCx, aValue);
JS::Rooted<JSObject*> obj(aCx);
while (tokenizer.hasMoreTokens()) {
const nsDependentSubstring& token = tokenizer.nextToken();
@ -103,9 +103,18 @@ GetJSValFromKeyPathString(JSContext* aCx,
bool hasProp;
if (!targetObject) {
// We're still walking the chain of existing objects
if (!obj) {
// http://w3c.github.io/IndexedDB/#dfn-evaluate-a-key-path-on-a-value
// step 4 substep 1: check for .length on a String value.
if (currentVal.isString() && !tokenizer.hasMoreTokens() &&
token.EqualsLiteral("length") && aOptions == DoNotCreateProperties) {
aKeyJSVal->setNumber(double(JS_GetStringLength(currentVal.toString())));
break;
}
if (!currentVal.isObject()) {
return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
}
obj = &currentVal.toObject();
bool ok = JS_HasUCProperty(aCx, obj, keyPathChars, keyPathLen,
&hasProp);
@ -123,10 +132,7 @@ GetJSValFromKeyPathString(JSContext* aCx,
}
if (tokenizer.hasMoreTokens()) {
// ...and walk to it if there are more steps...
if (intermediate.isPrimitive()) {
return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
}
obj = intermediate.toObjectOrNull();
currentVal = intermediate;
}
else {
// ...otherwise use it as key
@ -365,7 +371,7 @@ KeyPath::ExtractKeyAsJSVal(JSContext* aCx, const JS::Value& aValue,
}
}
*aOutVal = OBJECT_TO_JSVAL(arrayObj);
aOutVal->setObject(*arrayObj);
return NS_OK;
}

View File

@ -45,7 +45,7 @@ function testSteps()
const objectStoreDataLengthSort = [
{ key: "5", value: arr},
//{ key: "4", value: str},
{ key: "4", value: str},
];
let request = indexedDB.open(name, 1);

View File

@ -427,6 +427,14 @@ public:
return Intersection(intervals);
}
SelfType& operator-= (const SelfType& aIntervals)
{
for (const auto& interval : aIntervals.mIntervals) {
*this -= interval;
}
return *this;
}
SelfType operator- (const ElemType& aInterval)
{
SelfType intervals(*this);

View File

@ -58,15 +58,20 @@ PRLogModuleInfo* gMediaDecoderLog;
#define DECODER_LOG(x, ...) \
MOZ_LOG(gMediaDecoderLog, LogLevel::Debug, ("Decoder=%p " x, this, ##__VA_ARGS__))
static const char* const gPlayStateStr[] = {
"START",
"LOADING",
"PAUSED",
"PLAYING",
"SEEKING",
"ENDED",
"SHUTDOWN"
};
static const char*
ToPlayStateStr(MediaDecoder::PlayState aState)
{
switch (aState) {
case MediaDecoder::PLAY_STATE_START: return "START";
case MediaDecoder::PLAY_STATE_LOADING: return "LOADING";
case MediaDecoder::PLAY_STATE_PAUSED: return "PAUSED";
case MediaDecoder::PLAY_STATE_PLAYING: return "PLAYING";
case MediaDecoder::PLAY_STATE_ENDED: return "ENDED";
case MediaDecoder::PLAY_STATE_SHUTDOWN: return "SHUTDOWN";
default: MOZ_ASSERT_UNREACHABLE("Invalid playState.");
}
return "UNKNOWN";
}
class MediaMemoryTracker : public nsIMemoryReporter
{
@ -136,7 +141,7 @@ MediaDecoder::InitStatics()
NS_IMPL_ISUPPORTS(MediaMemoryTracker, nsIMemoryReporter)
NS_IMPL_ISUPPORTS(MediaDecoder, nsIObserver)
NS_IMPL_ISUPPORTS0(MediaDecoder)
void MediaDecoder::NotifyOwnerActivityChanged()
{
@ -807,18 +812,6 @@ void MediaDecoder::PlaybackEnded()
}
}
NS_IMETHODIMP MediaDecoder::Observe(nsISupports *aSubjet,
const char *aTopic,
const char16_t *someData)
{
MOZ_ASSERT(NS_IsMainThread());
if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
Shutdown();
}
return NS_OK;
}
MediaDecoder::Statistics
MediaDecoder::GetStatistics()
{
@ -1019,7 +1012,7 @@ void MediaDecoder::ChangeState(PlayState aState)
}
DECODER_LOG("ChangeState %s => %s",
gPlayStateStr[mPlayState], gPlayStateStr[aState]);
ToPlayStateStr(mPlayState), ToPlayStateStr(aState));
mPlayState = aState;
if (mPlayState == PLAY_STATE_PLAYING) {

View File

@ -277,7 +277,6 @@ public:
typedef MediaPromise<SeekResolveValue, bool /* aIgnored */, /* IsExclusive = */ true> SeekPromise;
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIOBSERVER
// Enumeration for the valid play states (see mPlayState)
enum PlayState {

View File

@ -188,6 +188,9 @@ public:
friend TimeUnit operator* (const TimeUnit& aUnit, int aVal) {
return TimeUnit(aUnit.mValue * aVal);
}
friend TimeUnit operator/ (const TimeUnit& aUnit, int aVal) {
return TimeUnit(aUnit.mValue / aVal);
}
bool IsValid() const
{

View File

@ -19,7 +19,7 @@
#endif
#include "SourceBufferResource.h"
extern PRLogModuleInfo* GetMediaSourceLog();
extern PRLogModuleInfo* GetMediaSourceSamplesLog();
/* Polyfill __func__ on MSVC to pass to the log. */
#ifdef _MSC_VER
@ -28,8 +28,8 @@ extern PRLogModuleInfo* GetMediaSourceLog();
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define MSE_DEBUG(name, arg, ...) MOZ_LOG(GetMediaSourceLog(), mozilla::LogLevel::Debug, (TOSTRING(name) "(%p:%s)::%s: " arg, this, mType.get(), __func__, ##__VA_ARGS__))
#define MSE_DEBUGV(name, arg, ...) MOZ_LOG(GetMediaSourceLog(), mozilla::LogLevel::Verbose, (TOSTRING(name) "(%p:%s)::%s: " arg, this, mType.get(), __func__, ##__VA_ARGS__))
#define MSE_DEBUG(name, arg, ...) MOZ_LOG(GetMediaSourceSamplesLog(), mozilla::LogLevel::Debug, (TOSTRING(name) "(%p:%s)::%s: " arg, this, mType.get(), __func__, ##__VA_ARGS__))
#define MSE_DEBUGV(name, arg, ...) MOZ_LOG(GetMediaSourceSamplesLog(), mozilla::LogLevel::Verbose, (TOSTRING(name) "(%p:%s)::%s: " arg, this, mType.get(), __func__, ##__VA_ARGS__))
namespace mozilla {

View File

@ -41,7 +41,7 @@ class JSObject;
PRLogModuleInfo* GetMediaSourceLog()
{
static PRLogModuleInfo* sLogModule;
static PRLogModuleInfo* sLogModule = nullptr;
if (!sLogModule) {
sLogModule = PR_NewLogModule("MediaSource");
}
@ -50,7 +50,7 @@ PRLogModuleInfo* GetMediaSourceLog()
PRLogModuleInfo* GetMediaSourceAPILog()
{
static PRLogModuleInfo* sLogModule;
static PRLogModuleInfo* sLogModule = nullptr;
if (!sLogModule) {
sLogModule = PR_NewLogModule("MediaSource");
}
@ -85,10 +85,6 @@ IsTypeSupported(const nsAString& aType)
if (NS_FAILED(rv)) {
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}
if (Preferences::GetBool("media.mediasource.format-reader", false) &&
!mimeType.EqualsASCII("video/mp4") && !mimeType.EqualsASCII("audio/mp4")) {
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}
bool found = false;
for (uint32_t i = 0; gMediaSourceTypes[i]; ++i) {
if (mimeType.EqualsASCII(gMediaSourceTypes[i])) {
@ -120,6 +116,12 @@ IsTypeSupported(const nsAString& aType)
if (dom::HTMLMediaElement::GetCanPlay(aType) == CANPLAY_NO) {
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}
if (Preferences::GetBool("media.mediasource.format-reader", false) &&
!mimeType.EqualsASCII("video/mp4") && !mimeType.EqualsASCII("audio/mp4")) {
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}
return NS_OK;
}

View File

@ -73,7 +73,7 @@ SourceBuffer::SetMode(SourceBufferAppendMode aMode, ErrorResult& aRv)
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
if (mIsUsingFormatReader && mGenerateTimestamp &&
if (mIsUsingFormatReader && mGenerateTimestamps &&
aMode == SourceBufferAppendMode::Segments) {
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
return;
@ -331,14 +331,14 @@ SourceBuffer::SourceBuffer(MediaSource* aMediaSource, const nsACString& aType)
mContentManager.get());
if (aType.LowerCaseEqualsLiteral("audio/mpeg") ||
aType.LowerCaseEqualsLiteral("audio/aac")) {
mGenerateTimestamp = true;
mGenerateTimestamps = true;
} else {
mGenerateTimestamp = false;
mGenerateTimestamps = false;
}
mIsUsingFormatReader =
Preferences::GetBool("media.mediasource.format-reader", false);
ErrorResult dummy;
if (mGenerateTimestamp) {
if (mGenerateTimestamps) {
SetMode(SourceBufferAppendMode::Sequence, dummy);
} else {
SetMode(SourceBufferAppendMode::Segments, dummy);
@ -427,7 +427,7 @@ SourceBuffer::CheckEndTime()
{
MOZ_ASSERT(NS_IsMainThread());
// Check if we need to update mMediaSource duration
double endTime = GetBufferedEnd();
double endTime = mContentManager->GroupEndTimestamp().ToSeconds();
double duration = mMediaSource->Duration();
if (endTime > duration) {
mMediaSource->SetDuration(endTime, MSRangeRemovalAction::SKIP);

View File

@ -184,7 +184,7 @@ private:
SourceBufferAppendMode mAppendMode;
bool mUpdating;
bool mGenerateTimestamp;
bool mGenerateTimestamps;
bool mIsUsingFormatReader;
mozilla::Atomic<bool> mActive;

View File

@ -100,6 +100,7 @@ public:
virtual void SetGroupStartTimestamp(const TimeUnit& aGroupStartTimestamp) {}
virtual void RestartGroupStartTimestamp() {}
virtual TimeUnit GroupEndTimestamp() = 0;
#if defined(DEBUG)
virtual void Dump(const char* aPath) { }

View File

@ -15,7 +15,7 @@
PRLogModuleInfo* GetSourceBufferResourceLog()
{
static PRLogModuleInfo* sLogModule;
static PRLogModuleInfo* sLogModule = nullptr;
if (!sLogModule) {
sLogModule = PR_NewLogModule("SourceBufferResource");
}

View File

@ -68,6 +68,12 @@ public:
void Detach() override;
TimeUnit GroupEndTimestamp() override
{
return Buffered().GetEnd();
}
// Mark the current decoder's resource as ended, clear mCurrentDecoder and
// reset mLast{Start,End}Timestamp. Main thread only.
void DiscardCurrentDecoder();

View File

@ -20,6 +20,16 @@ extern PRLogModuleInfo* GetMediaSourceLog();
#define MSE_DEBUG(arg, ...) MOZ_LOG(GetMediaSourceLog(), mozilla::LogLevel::Debug, ("TrackBuffersManager(%p:%s)::%s: " arg, this, mType.get(), __func__, ##__VA_ARGS__))
#define MSE_DEBUGV(arg, ...) MOZ_LOG(GetMediaSourceLog(), mozilla::LogLevel::Verbose, ("TrackBuffersManager(%p:%s)::%s: " arg, this, mType.get(), __func__, ##__VA_ARGS__))
PRLogModuleInfo* GetMediaSourceSamplesLog()
{
static PRLogModuleInfo* sLogModule = nullptr;
if (!sLogModule) {
sLogModule = PR_NewLogModule("MediaSourceSamples");
}
return sLogModule;
}
#define SAMPLE_DEBUG(arg, ...) MOZ_LOG(GetMediaSourceSamplesLog(), mozilla::LogLevel::Debug, ("TrackBuffersManager(%p:%s)::%s: " arg, this, mType.get(), __func__, ##__VA_ARGS__))
namespace mozilla {
static const char*
@ -475,6 +485,7 @@ TrackBuffersManager::CodedFrameRemoval(TimeInterval aInterval)
}
TimeUnit duration{TimeUnit::FromSeconds(mMediaSourceDuration.Ref().ref())};
#if DEBUG
MSE_DEBUG("duration:%.2f", duration.ToSeconds());
if (HasVideo()) {
MSE_DEBUG("before video ranges=%s",
@ -484,6 +495,7 @@ TrackBuffersManager::CodedFrameRemoval(TimeInterval aInterval)
MSE_DEBUG("before audio ranges=%s",
DumpTimeRanges(mAudioTracks.mBufferedRanges).get());
}
#endif
// 1. Let start be the starting presentation timestamp for the removal range.
TimeUnit start = aInterval.mStart;
@ -510,96 +522,12 @@ TrackBuffersManager::CodedFrameRemoval(TimeInterval aInterval)
}
}
bool removeCurrentCodedFrameGroup = false;
// 3. Remove all media data, from this track buffer, that contain starting
// timestamps greater than or equal to start and less than the remove end timestamp.
TimeInterval removedInterval;
Maybe<uint32_t> firstRemovedIndex;
TrackBuffer& data = track->mBuffers.LastElement();
for (uint32_t i = 0; i < data.Length();) {
const auto& frame = data[i];
if (frame->mTime >= start.ToMicroseconds() &&
frame->mTime < removeEndTimestamp.ToMicroseconds()) {
if (firstRemovedIndex.isNothing()) {
removedInterval =
TimeInterval(TimeUnit::FromMicroseconds(frame->mTime),
TimeUnit::FromMicroseconds(frame->mTime + frame->mDuration));
firstRemovedIndex = Some(i);
} else {
removedInterval = removedInterval.Span(
TimeInterval(TimeUnit::FromMicroseconds(frame->mTime),
TimeUnit::FromMicroseconds(frame->mTime + frame->mDuration)));
}
track->mSizeBuffer -= sizeof(*frame) + frame->mSize;
data.RemoveElementAt(i);
removeCurrentCodedFrameGroup |=
track->mNextInsertionIndex.isSome() &&
track->mNextInsertionIndex.ref() == i;
if (!removeCurrentCodedFrameGroup &&
track->mNextInsertionIndex.isSome() &&
track->mNextInsertionIndex.ref() > i) {
track->mNextInsertionIndex.ref()--;
}
if (track->mNextGetSampleIndex.isSome()) {
if (track->mNextGetSampleIndex.ref() == i) {
MSE_DEBUG("Next sample to be played got evicted");
track->mNextGetSampleIndex.reset();
} else if (track->mNextGetSampleIndex.ref() > i) {
track->mNextGetSampleIndex.ref()--;
}
}
} else {
i++;
}
}
// 4. Remove decoding dependencies of the coded frames removed in the previous step:
// Remove all coded frames between the coded frames removed in the previous step and the next random access point after those removed frames.
if (firstRemovedIndex.isSome()) {
uint32_t start = firstRemovedIndex.ref();
uint32_t end = start;
for (;end < data.Length(); end++) {
MediaRawData* sample = data[end].get();
if (sample->mKeyframe) {
break;
}
removedInterval = removedInterval.Span(
TimeInterval(TimeUnit::FromMicroseconds(sample->mTime),
TimeUnit::FromMicroseconds(sample->GetEndTime())));
track->mSizeBuffer -= sizeof(*sample) + sample->mSize;
}
data.RemoveElementsAt(start, end - start);
removeCurrentCodedFrameGroup |=
track->mNextInsertionIndex.isSome() &&
track->mNextInsertionIndex.ref() >= start &&
track->mNextInsertionIndex.ref() < end;
if (!removeCurrentCodedFrameGroup &&
track->mNextInsertionIndex.isSome() &&
track->mNextInsertionIndex.ref() >= end) {
track->mNextInsertionIndex.ref() -= end - start;
}
if (track->mNextGetSampleIndex.isSome()) {
if (track->mNextGetSampleIndex.ref() >= start &&
track->mNextGetSampleIndex.ref() < end) {
MSE_DEBUG("Next sample to be played got evicted");
track->mNextGetSampleIndex.reset();
} else if (track->mNextGetSampleIndex.ref() >= end) {
track->mNextGetSampleIndex.ref() -= end - start;
}
}
MSE_DEBUG("Removing undecodable frames from:%u (frames:%d) ([%f, %f))",
start, end - start,
removedInterval.mStart.ToSeconds(), removedInterval.mEnd.ToSeconds());
track->mBufferedRanges -= removedInterval;
dataRemoved = true;
if (removeCurrentCodedFrameGroup) {
track->ResetAppendState();
}
}
TimeIntervals removedInterval{TimeInterval(start, removeEndTimestamp)};
RemoveFrames(removedInterval, *track, 0);
// 5. If this object is in activeSourceBuffers, the current playback position
// is greater than or equal to start and less than the remove end timestamp,
@ -609,20 +537,7 @@ TrackBuffersManager::CodedFrameRemoval(TimeInterval aInterval)
// TODO properly, so it works even if paused.
}
{
MonitorAutoLock mon(mMonitor);
mVideoBufferedRanges = mVideoTracks.mBufferedRanges;
mAudioBufferedRanges = mAudioTracks.mBufferedRanges;
}
if (HasVideo()) {
MSE_DEBUG("after video ranges=%s",
DumpTimeRanges(mVideoTracks.mBufferedRanges).get());
}
if (HasAudio()) {
MSE_DEBUG("after audio ranges=%s",
DumpTimeRanges(mAudioTracks.mBufferedRanges).get());
}
UpdateBufferedRanges();
// Update our reported total size.
mSizeSourceBuffer = mVideoTracks.mSizeBuffer + mAudioTracks.mSizeBuffer;
@ -639,6 +554,28 @@ TrackBuffersManager::CodedFrameRemoval(TimeInterval aInterval)
return dataRemoved;
}
void
TrackBuffersManager::UpdateBufferedRanges()
{
MonitorAutoLock mon(mMonitor);
mVideoBufferedRanges = mVideoTracks.mBufferedRanges;
mAudioBufferedRanges = mAudioTracks.mBufferedRanges;
#if DEBUG
if (HasVideo()) {
MSE_DEBUG("after video ranges=%s",
DumpTimeRanges(mVideoTracks.mBufferedRanges).get());
}
if (HasAudio()) {
MSE_DEBUG("after audio ranges=%s",
DumpTimeRanges(mAudioTracks.mBufferedRanges).get());
}
#endif
mOfficialGroupEndTimestamp = mGroupEndTimestamp;
}
nsRefPtr<TrackBuffersManager::AppendPromise>
TrackBuffersManager::InitSegmentParserLoop()
{
@ -668,6 +605,10 @@ TrackBuffersManager::AppendIncomingBuffers()
mLastTimestampOffset = mTimestampOffset;
}
mIncomingBuffers.Clear();
mAppendWindow =
TimeInterval(TimeUnit::FromSeconds(mParent->AppendWindowStart()),
TimeUnit::FromSeconds(mParent->AppendWindowEnd()));
}
void
@ -1175,15 +1116,10 @@ TrackBuffersManager::CompleteCodedFrameProcessing()
MSE_DEBUG("mAbort:%d", static_cast<bool>(mAbort));
// 1. For each coded frame in the media segment run the following steps:
for (auto& sample : mVideoTracks.mQueuedSamples) {
while (true) {
if (!ProcessFrame(sample, mVideoTracks)) {
break;
}
}
}
// Coded Frame Processing steps 1.1 to 1.21.
ProcessFrames(mVideoTracks.mQueuedSamples, mVideoTracks);
mVideoTracks.mQueuedSamples.Clear();
#if defined(DEBUG)
if (HasVideo()) {
const auto& track = mVideoTracks.mBuffers.LastElement();
@ -1195,14 +1131,9 @@ TrackBuffersManager::CompleteCodedFrameProcessing()
}
#endif
for (auto& sample : mAudioTracks.mQueuedSamples) {
while (true) {
if (!ProcessFrame(sample, mAudioTracks)) {
break;
}
}
}
ProcessFrames(mAudioTracks.mQueuedSamples, mAudioTracks);
mAudioTracks.mQueuedSamples.Clear();
#if defined(DEBUG)
if (HasAudio()) {
const auto& track = mAudioTracks.mBuffers.LastElement();
@ -1214,21 +1145,7 @@ TrackBuffersManager::CompleteCodedFrameProcessing()
}
#endif
{
MonitorAutoLock mon(mMonitor);
// Save our final tracks buffered ranges.
mVideoBufferedRanges = mVideoTracks.mBufferedRanges;
mAudioBufferedRanges = mAudioTracks.mBufferedRanges;
if (HasAudio()) {
MSE_DEBUG("audio new buffered range = %s",
DumpTimeRanges(mAudioBufferedRanges).get());
}
if (HasVideo()) {
MSE_DEBUG("video new buffered range = %s",
DumpTimeRanges(mVideoBufferedRanges).get());
}
}
UpdateBufferedRanges();
// Update our reported total size.
mSizeSourceBuffer = mVideoTracks.mSizeBuffer + mAudioTracks.mSizeBuffer;
@ -1286,22 +1203,9 @@ TrackBuffersManager::ResolveProcessing(bool aResolveValue, const char* aName)
mProcessingPromise.ResolveIfExists(aResolveValue, __func__);
}
bool
TrackBuffersManager::ProcessFrame(MediaRawData* aSample,
TrackData& aTrackData)
void
TrackBuffersManager::CheckSequenceDiscontinuity()
{
TimeUnit presentationTimestamp;
TimeUnit decodeTimestamp;
if (!mParent->mGenerateTimestamp) {
presentationTimestamp = TimeUnit::FromMicroseconds(aSample->mTime);
decodeTimestamp = TimeUnit::FromMicroseconds(aSample->mTimecode);
}
// 2. Let frame duration be a double precision floating point representation of the coded frame's duration in seconds.
TimeUnit frameDuration{TimeUnit::FromMicroseconds(aSample->mDuration)};
// 3. If mode equals "sequence" and group start timestamp is set, then run the following steps:
if (mParent->mAppendMode == SourceBufferAppendMode::Sequence &&
mGroupStartTimestamp.isSome()) {
mTimestampOffset = mGroupStartTimestamp.ref();
@ -1310,93 +1214,253 @@ TrackBuffersManager::ProcessFrame(MediaRawData* aSample,
mAudioTracks.mNeedRandomAccessPoint = true;
mGroupStartTimestamp.reset();
}
}
// 4. If timestampOffset is not 0, then run the following steps:
if (mTimestampOffset != TimeUnit::FromSeconds(0)) {
presentationTimestamp += mTimestampOffset;
decodeTimestamp += mTimestampOffset;
void
TrackBuffersManager::ProcessFrames(TrackBuffer& aSamples, TrackData& aTrackData)
{
if (!aSamples.Length()) {
return;
}
MSE_DEBUGV("Processing %s frame(pts:%lld end:%lld, dts:%lld, duration:%lld, "
"kf:%d)",
aTrackData.mInfo->mMimeType.get(),
presentationTimestamp.ToMicroseconds(),
(presentationTimestamp + frameDuration).ToMicroseconds(),
decodeTimestamp.ToMicroseconds(),
frameDuration.ToMicroseconds(),
aSample->mKeyframe);
// 3. If mode equals "sequence" and group start timestamp is set, then run the following steps:
CheckSequenceDiscontinuity();
// 5. Let track buffer equal the track buffer that the coded frame will be added to.
auto& trackBuffer = aTrackData;
// 6. If last decode timestamp for track buffer is set and decode timestamp is less than last decode timestamp:
// OR
// If last decode timestamp for track buffer is set and the difference between decode timestamp and last decode timestamp is greater than 2 times last frame duration:
// TODO: Maybe we should be using TimeStamp and TimeDuration instead?
// Some MP4 content may exhibit an extremely short frame duration.
// As such, we can't use the last frame duration as a way to detect
// discontinuities as required per step 6 above.
// Instead we use the biggest duration seen so far in this run (init + media
// segment).
if ((trackBuffer.mLastDecodeTimestamp.isSome() &&
decodeTimestamp < trackBuffer.mLastDecodeTimestamp.ref()) ||
(trackBuffer.mLastDecodeTimestamp.isSome() &&
decodeTimestamp - trackBuffer.mLastDecodeTimestamp.ref() > 2*trackBuffer.mLongestFrameDuration.ref())) {
// 1a. If mode equals "segments":
if (mParent->mAppendMode == SourceBufferAppendMode::Segments) {
// Set group end timestamp to presentation timestamp.
mGroupEndTimestamp = presentationTimestamp;
}
// 1b. If mode equals "sequence":
if (mParent->mAppendMode == SourceBufferAppendMode::Sequence) {
// Set group start timestamp equal to the group end timestamp.
mGroupStartTimestamp = Some(mGroupEndTimestamp);
}
for (auto& track : GetTracksList()) {
// 2. Unset the last decode timestamp on all track buffers.
// 3. Unset the last frame duration on all track buffers.
// 4. Unset the highest end timestamp on all track buffers.
// 5. Set the need random access point flag on all track buffers to true.
track->ResetAppendState();
}
MSE_DEBUG("Discontinuity detected. Restarting process");
// 6. Jump to the Loop Top step above to restart processing of the current coded frame.
return true;
}
// 7. Let frame end timestamp equal the sum of presentation timestamp and frame duration.
TimeUnit frameEndTimestamp = presentationTimestamp + frameDuration;
// 8. If presentation timestamp is less than appendWindowStart, then set the need random access point flag to true, drop the coded frame, and jump to the top of the loop to start processing the next coded frame.
// 9. If frame end timestamp is greater than appendWindowEnd, then set the need random access point flag to true, drop the coded frame, and jump to the top of the loop to start processing the next coded frame.
// We apply a fuzz search += mLongestFrameDuration to get around videos where
// We apply a fuzz search +- mLongestFrameDuration to get around videos where
// the start time is negative but close to 0.
TimeInterval targetWindow{
TimeInterval(TimeUnit::FromSeconds(mParent->mAppendWindowStart),
TimeUnit::FromSeconds(mParent->mAppendWindowEnd),
trackBuffer.mLongestFrameDuration.valueOr(frameDuration))};
TimeInterval frameInterval{presentationTimestamp, frameEndTimestamp};
TimeInterval(mAppendWindow.mStart, mAppendWindow.mEnd,
trackBuffer.mLongestFrameDuration.refOr(TimeUnit::FromMicroseconds(aSamples[0]->mDuration)))};
if (!targetWindow.Contains(frameInterval)) {
trackBuffer.mNeedRandomAccessPoint = true;
return false;
}
TimeIntervals samplesRange;
uint32_t sizeNewSamples = 0;
TrackBuffer samples; // array that will contain the frames to be added
// to our track buffer.
// 10. If the need random access point flag on track buffer equals true, then run the following steps:
if (trackBuffer.mNeedRandomAccessPoint) {
// 1. If the coded frame is not a random access point, then drop the coded frame and jump to the top of the loop to start processing the next coded frame.
if (!aSample->mKeyframe) {
return false;
// We assume that no frames are contiguous within a media segment and as such
// don't need to check for discontinuity except for the first frame and should
// a frame be ignored due to the target window.
bool needDiscontinuityCheck = true;
for (auto& sample : aSamples) {
SAMPLE_DEBUG("Processing %s frame(pts:%lld end:%lld, dts:%lld, duration:%lld, "
"kf:%d)",
aTrackData.mInfo->mMimeType.get(),
sample->mTime,
sample->GetEndTime(),
sample->mTimecode,
sample->mDuration,
sample->mKeyframe);
// We perform step 10 right away as we can't do anything should a keyframe
// be needed until we have one.
// 10. If the need random access point flag on track buffer equals true, then run the following steps:
if (trackBuffer.mNeedRandomAccessPoint) {
// 1. If the coded frame is not a random access point, then drop the coded frame and jump to the top of the loop to start processing the next coded frame.
if (!sample->mKeyframe) {
continue;
}
// 2. Set the need random access point flag on track buffer to false.
trackBuffer.mNeedRandomAccessPoint = false;
}
// We perform step 1,2 and 4 at once:
// 1. If generate timestamps flag equals true:
// Let presentation timestamp equal 0.
// Let decode timestamp equal 0.
// Otherwise:
// Let presentation timestamp be a double precision floating point representation of the coded frame's presentation timestamp in seconds.
// Let decode timestamp be a double precision floating point representation of the coded frame's decode timestamp in seconds.
// 2. Let frame duration be a double precision floating point representation of the coded frame's duration in seconds.
// Step 3 is performed earlier or when a discontinuity has been detected.
// 4. If timestampOffset is not 0, then run the following steps:
TimeInterval sampleInterval =
mParent->mGenerateTimestamps
? TimeInterval(mTimestampOffset,
mTimestampOffset + TimeUnit::FromMicroseconds(sample->mDuration))
: TimeInterval(TimeUnit::FromMicroseconds(sample->mTime) + mTimestampOffset,
TimeUnit::FromMicroseconds(sample->GetEndTime()) + mTimestampOffset);
TimeUnit decodeTimestamp =
mParent->mGenerateTimestamps
? mTimestampOffset
: TimeUnit::FromMicroseconds(sample->mTimecode) + mTimestampOffset;
// 6. If last decode timestamp for track buffer is set and decode timestamp is less than last decode timestamp:
// OR
// If last decode timestamp for track buffer is set and the difference between decode timestamp and last decode timestamp is greater than 2 times last frame duration:
if (needDiscontinuityCheck && trackBuffer.mLastDecodeTimestamp.isSome() &&
(decodeTimestamp < trackBuffer.mLastDecodeTimestamp.ref() ||
decodeTimestamp - trackBuffer.mLastDecodeTimestamp.ref() > 2*trackBuffer.mLongestFrameDuration.ref())) {
MSE_DEBUG("Discontinuity detected.");
// 1a. If mode equals "segments":
if (mParent->mAppendMode == SourceBufferAppendMode::Segments) {
// Set group end timestamp to presentation timestamp.
mGroupEndTimestamp = sampleInterval.mStart;
}
// 1b. If mode equals "sequence":
if (mParent->mAppendMode == SourceBufferAppendMode::Sequence) {
// Set group start timestamp equal to the group end timestamp.
mGroupStartTimestamp = Some(mGroupEndTimestamp);
}
for (auto& track : GetTracksList()) {
// 2. Unset the last decode timestamp on all track buffers.
// 3. Unset the last frame duration on all track buffers.
// 4. Unset the highest end timestamp on all track buffers.
// 5. Set the need random access point flag on all track buffers to true.
track->ResetAppendState();
}
// 6. Jump to the Loop Top step above to restart processing of the current coded frame.
// Rather that restarting the process for the frame, we run the first
// steps again instead.
// 3. If mode equals "sequence" and group start timestamp is set, then run the following steps:
CheckSequenceDiscontinuity();
if (!sample->mKeyframe) {
continue;
}
if (mParent->mAppendMode == SourceBufferAppendMode::Sequence) {
// mTimestampOffset was modified during CheckSequenceDiscontinuity.
// We need to update our variables.
sampleInterval =
mParent->mGenerateTimestamps
? TimeInterval(mTimestampOffset,
mTimestampOffset + TimeUnit::FromMicroseconds(sample->mDuration))
: TimeInterval(TimeUnit::FromMicroseconds(sample->mTime) + mTimestampOffset,
TimeUnit::FromMicroseconds(sample->GetEndTime()) + mTimestampOffset);
decodeTimestamp =
mParent->mGenerateTimestamps
? mTimestampOffset
: TimeUnit::FromMicroseconds(sample->mTimecode) + mTimestampOffset;
}
trackBuffer.mNeedRandomAccessPoint = false;
needDiscontinuityCheck = false;
}
// 7. Let frame end timestamp equal the sum of presentation timestamp and frame duration.
// This is sampleInterval.mEnd
// 8. If presentation timestamp is less than appendWindowStart, then set the need random access point flag to true, drop the coded frame, and jump to the top of the loop to start processing the next coded frame.
// 9. If frame end timestamp is greater than appendWindowEnd, then set the need random access point flag to true, drop the coded frame, and jump to the top of the loop to start processing the next coded frame.
if (!targetWindow.Contains(sampleInterval)) {
if (samples.Length()) {
// We are creating a discontinuity in the samples.
// Insert the samples processed so far.
InsertFrames(samples, samplesRange, trackBuffer);
samples.Clear();
samplesRange = TimeIntervals();
trackBuffer.mSizeBuffer += sizeNewSamples;
sizeNewSamples = 0;
}
trackBuffer.mNeedRandomAccessPoint = true;
needDiscontinuityCheck = true;
continue;
}
samplesRange += sampleInterval;
sizeNewSamples += sizeof(*sample) + sample->mSize;
sample->mTime = sampleInterval.mStart.ToMicroseconds();
sample->mTimecode = decodeTimestamp.ToMicroseconds();
sample->mTrackInfo = trackBuffer.mLastInfo;
samples.AppendElement(sample);
// Steps 11,12,13,14, 15 and 16 will be done in one block in InsertFrames.
// 17. Set last decode timestamp for track buffer to decode timestamp.
trackBuffer.mLastDecodeTimestamp =
Some(TimeUnit::FromMicroseconds(sample->mTimecode));
// 18. Set last frame duration for track buffer to frame duration.
trackBuffer.mLastFrameDuration =
Some(TimeUnit::FromMicroseconds(sample->mDuration));
trackBuffer.mLongestFrameDuration =
Some(trackBuffer.mLongestFrameDuration.isNothing()
? trackBuffer.mLastFrameDuration.ref()
: std::max(trackBuffer.mLastFrameDuration.ref(),
trackBuffer.mLongestFrameDuration.ref()));
// 19. If highest end timestamp for track buffer is unset or frame end timestamp is greater than highest end timestamp, then set highest end timestamp for track buffer to frame end timestamp.
if (trackBuffer.mHighestEndTimestamp.isNothing() ||
sampleInterval.mEnd > trackBuffer.mHighestEndTimestamp.ref()) {
trackBuffer.mHighestEndTimestamp = Some(sampleInterval.mEnd);
}
// 20. If frame end timestamp is greater than group end timestamp, then set group end timestamp equal to frame end timestamp.
if (sampleInterval.mEnd > mGroupEndTimestamp) {
mGroupEndTimestamp = sampleInterval.mEnd;
}
// 21. If generate timestamps flag equals true, then set timestampOffset equal to frame end timestamp.
if (mParent->mGenerateTimestamps) {
mTimestampOffset = sampleInterval.mEnd;
}
// 2. Set the need random access point flag on track buffer to false.
trackBuffer.mNeedRandomAccessPoint = false;
}
if (samples.Length()) {
InsertFrames(samples, samplesRange, trackBuffer);
trackBuffer.mSizeBuffer += sizeNewSamples;
}
}
void
TrackBuffersManager::CheckNextInsertionIndex(TrackData& aTrackData,
const TimeUnit& aSampleTime)
{
if (aTrackData.mNextInsertionIndex.isSome()) {
return;
}
TrackBuffer& data = aTrackData.mBuffers.LastElement();
if (data.IsEmpty() || aSampleTime < aTrackData.mBufferedRanges.GetStart()) {
aTrackData.mNextInsertionIndex = Some(size_t(0));
return;
}
// Find which discontinuity we should insert the frame before.
TimeInterval target;
for (const auto& interval : aTrackData.mBufferedRanges) {
if (aSampleTime < interval.mStart) {
target = interval;
break;
}
}
if (target.IsEmpty()) {
// No target found, it will be added at the end of the track buffer.
aTrackData.mNextInsertionIndex = Some(data.Length());
return;
}
for (uint32_t i = 0; i < data.Length(); i++) {
const nsRefPtr<MediaRawData>& sample = data[i];
TimeInterval sampleInterval{
TimeUnit::FromMicroseconds(sample->mTime),
TimeUnit::FromMicroseconds(sample->GetEndTime())};
if (target.Intersects(sampleInterval)) {
aTrackData.mNextInsertionIndex = Some(size_t(i));
return;
}
}
MOZ_CRASH("Insertion Index Not Found");
}
void
TrackBuffersManager::InsertFrames(TrackBuffer& aSamples,
const TimeIntervals& aIntervals,
TrackData& aTrackData)
{
// 5. Let track buffer equal the track buffer that the coded frame will be added to.
auto& trackBuffer = aTrackData;
MSE_DEBUGV("Processing %d %s frames(start:%lld end:%lld)",
aSamples.Length(),
aTrackData.mInfo->mMimeType.get(),
aIntervals.GetStart().ToMicroseconds(),
aIntervals.GetEnd().ToMicroseconds());
// TODO: Handle splicing of audio (and text) frames.
// 11. Let spliced audio frame be an unset variable for holding audio splice information
// 12. Let spliced timed text frame be an unset variable for holding timed text splice information
@ -1414,180 +1478,121 @@ TrackBuffersManager::ProcessFrame(MediaRawData* aSample,
// There is an ambiguity on how to remove frames, which was lodged with:
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=28710, implementing as per
// bug description.
Maybe<uint32_t> firstRemovedIndex;
TimeInterval removedInterval;
TrackBuffer& data = trackBuffer.mBuffers.LastElement();
bool removeCodedFrames =
trackBuffer.mHighestEndTimestamp.isSome()
? trackBuffer.mHighestEndTimestamp.ref() <= presentationTimestamp
: true;
if (removeCodedFrames) {
TimeUnit lowerBound =
trackBuffer.mHighestEndTimestamp.valueOr(presentationTimestamp);
if (trackBuffer.mBufferedRanges.ContainsStrict(lowerBound)) {
for (uint32_t i = 0; i < data.Length();) {
MediaRawData* sample = data[i].get();
if (sample->mTime >= lowerBound.ToMicroseconds() &&
sample->mTime < frameEndTimestamp.ToMicroseconds()) {
if (firstRemovedIndex.isNothing()) {
removedInterval =
TimeInterval(TimeUnit::FromMicroseconds(sample->mTime),
TimeUnit::FromMicroseconds(sample->GetEndTime()));
firstRemovedIndex = Some(i);
} else {
removedInterval = removedInterval.Span(
TimeInterval(TimeUnit::FromMicroseconds(sample->mTime),
TimeUnit::FromMicroseconds(sample->GetEndTime())));
}
trackBuffer.mSizeBuffer -= sizeof(*sample) + sample->mSize;
MSE_DEBUGV("Overlapping frame:%u ([%f, %f))",
i,
TimeUnit::FromMicroseconds(sample->mTime).ToSeconds(),
TimeUnit::FromMicroseconds(sample->GetEndTime()).ToSeconds());
data.RemoveElementAt(i);
if (trackBuffer.mNextGetSampleIndex.isSome()) {
if (trackBuffer.mNextGetSampleIndex.ref() == i) {
MSE_DEBUG("Next sample to be played got evicted");
trackBuffer.mNextGetSampleIndex.reset();
} else if (trackBuffer.mNextGetSampleIndex.ref() > i) {
trackBuffer.mNextGetSampleIndex.ref()--;
}
}
} else {
i++;
}
}
}
// 15. Remove decoding dependencies of the coded frames removed in the previous step:
// Remove all coded frames between the coded frames removed in the previous step and the next random access point after those removed frames.
if (firstRemovedIndex.isSome()) {
uint32_t start = firstRemovedIndex.ref();
uint32_t end = start;
for (;end < data.Length(); end++) {
MediaRawData* sample = data[end].get();
if (sample->mKeyframe) {
break;
}
removedInterval = removedInterval.Span(
TimeInterval(TimeUnit::FromMicroseconds(sample->mTime),
TimeUnit::FromMicroseconds(sample->GetEndTime())));
trackBuffer.mSizeBuffer -= sizeof(*sample) + sample->mSize;
}
data.RemoveElementsAt(start, end - start);
// 15. Remove decoding dependencies of the coded frames removed in the previous step:
// Remove all coded frames between the coded frames removed in the previous step and the next random access point after those removed frames.
MSE_DEBUG("Removing undecodable frames from:%u (frames:%u) ([%f, %f))",
start, end - start,
removedInterval.mStart.ToSeconds(), removedInterval.mEnd.ToSeconds());
TimeIntervals intersection = trackBuffer.mBufferedRanges;
intersection.Intersection(aIntervals);
if (trackBuffer.mNextGetSampleIndex.isSome()) {
if (trackBuffer.mNextGetSampleIndex.ref() >= start &&
trackBuffer.mNextGetSampleIndex.ref() < end) {
MSE_DEBUG("Next sample to be played got evicted");
trackBuffer.mNextGetSampleIndex.reset();
} else if (trackBuffer.mNextGetSampleIndex.ref() >= end) {
trackBuffer.mNextGetSampleIndex.ref() -= end - start;
}
}
// Update our buffered range to exclude the range just removed.
trackBuffer.mBufferedRanges -= removedInterval;
MOZ_ASSERT(trackBuffer.mNextInsertionIndex.isNothing() ||
trackBuffer.mNextInsertionIndex.ref() <= start);
}
if (intersection.Length()) {
RemoveFrames(aIntervals, trackBuffer, trackBuffer.mNextInsertionIndex.refOr(0));
}
// 16. Add the coded frame with the presentation timestamp, decode timestamp, and frame duration to the track buffer.
aSample->mTime = presentationTimestamp.ToMicroseconds();
aSample->mTimecode = decodeTimestamp.ToMicroseconds();
aSample->mTrackInfo = trackBuffer.mLastInfo;
CheckNextInsertionIndex(aTrackData,
TimeUnit::FromMicroseconds(aSamples[0]->mTime));
if (data.IsEmpty()) {
data.AppendElement(aSample);
MOZ_ASSERT(aSample->mKeyframe);
trackBuffer.mNextInsertionIndex = Some(data.Length());
} else if (trackBuffer.mNextInsertionIndex.isSome()) {
data.InsertElementAt(trackBuffer.mNextInsertionIndex.ref(), aSample);
MOZ_ASSERT(trackBuffer.mNextInsertionIndex.ref() == 0 ||
data[trackBuffer.mNextInsertionIndex.ref()]->mTrackInfo->GetID() == data[trackBuffer.mNextInsertionIndex.ref()-1]->mTrackInfo->GetID() ||
data[trackBuffer.mNextInsertionIndex.ref()]->mKeyframe);
trackBuffer.mNextInsertionIndex.ref()++;
} else if (presentationTimestamp < trackBuffer.mBufferedRanges.GetStart()) {
data.InsertElementAt(0, aSample);
MOZ_ASSERT(aSample->mKeyframe);
trackBuffer.mNextInsertionIndex = Some(size_t(1));
} else {
// Find which discontinuity we should insert the frame before.
TimeInterval target;
for (const auto& interval : trackBuffer.mBufferedRanges) {
if (presentationTimestamp < interval.mStart) {
target = interval;
break;
}
}
if (target.IsEmpty()) {
// No existing ranges found after our frame presentation time.
// Insert frame at the end of array.
data.AppendElement(aSample);
MOZ_ASSERT(data.Length() <= 2 ||
data[data.Length()-1]->mTrackInfo->GetID() == data[data.Length()-2]->mTrackInfo->GetID() ||
data[data.Length()-1]->mKeyframe);
trackBuffer.mNextInsertionIndex = Some(data.Length());
}
for (uint32_t i = 0; i < data.Length(); i++) {
const nsRefPtr<MediaRawData>& sample = data[i];
TimeInterval sampleInterval{
TimeUnit::FromMicroseconds(sample->mTime),
TimeUnit::FromMicroseconds(sample->GetEndTime())};
if (target.Intersects(sampleInterval)) {
data.InsertElementAt(i, aSample);
MOZ_ASSERT(i != 0 &&
(data[i]->mTrackInfo->GetID() == data[i-1]->mTrackInfo->GetID() ||
data[i]->mKeyframe));
trackBuffer.mNextInsertionIndex = Some(size_t(i) + 1);
break;
}
}
MOZ_ASSERT(aSample->mKeyframe);
}
trackBuffer.mSizeBuffer += sizeof(*aSample) + aSample->mSize;
// 17. Set last decode timestamp for track buffer to decode timestamp.
trackBuffer.mLastDecodeTimestamp = Some(decodeTimestamp);
// 18. Set last frame duration for track buffer to frame duration.
trackBuffer.mLastFrameDuration =
Some(TimeUnit::FromMicroseconds(aSample->mDuration));
if (trackBuffer.mLongestFrameDuration.isNothing()) {
trackBuffer.mLongestFrameDuration = trackBuffer.mLastFrameDuration;
} else {
trackBuffer.mLongestFrameDuration =
Some(std::max(trackBuffer.mLongestFrameDuration.ref(),
trackBuffer.mLastFrameDuration.ref()));
}
// 19. If highest end timestamp for track buffer is unset or frame end timestamp is greater than highest end timestamp, then set highest end timestamp for track buffer to frame end timestamp.
if (trackBuffer.mHighestEndTimestamp.isNothing() ||
frameEndTimestamp > trackBuffer.mHighestEndTimestamp.ref()) {
trackBuffer.mHighestEndTimestamp = Some(frameEndTimestamp);
}
// 20. If frame end timestamp is greater than group end timestamp, then set group end timestamp equal to frame end timestamp.
if (frameEndTimestamp > mGroupEndTimestamp) {
mGroupEndTimestamp = frameEndTimestamp;
}
// 21. If generate timestamps flag equals true, then set timestampOffset equal to frame end timestamp.
if (mParent->mGenerateTimestamp) {
mTimestampOffset = frameEndTimestamp;
}
TrackBuffer& data = trackBuffer.mBuffers.LastElement();
data.InsertElementsAt(trackBuffer.mNextInsertionIndex.ref(), aSamples);
trackBuffer.mNextInsertionIndex.ref() += aSamples.Length();
// Update our buffered range with new sample interval.
// We allow a fuzz factor in our interval of half a frame length,
// as fuzz is +/- value, giving an effective leeway of a full frame
// length.
trackBuffer.mBufferedRanges +=
TimeInterval(presentationTimestamp, frameEndTimestamp,
TimeUnit::FromMicroseconds(aSample->mDuration / 2));
return false;
TimeIntervals range(aIntervals);
range.SetFuzz(trackBuffer.mLongestFrameDuration.ref() / 2);
trackBuffer.mBufferedRanges += range;
}
void
TrackBuffersManager::RemoveFrames(const TimeIntervals& aIntervals,
TrackData& aTrackData,
uint32_t aStartIndex)
{
TrackBuffer& data = aTrackData.mBuffers.LastElement();
Maybe<uint32_t> firstRemovedIndex;
uint32_t lastRemovedIndex;
// We loop from aStartIndex to avoid removing frames that we inserted earlier
// and part of the current coded frame group. This is allows to handle step
// 14 of the coded frame processing algorithm without having to check the value
// of highest end timestamp:
// "Remove existing coded frames in track buffer:
// If highest end timestamp for track buffer is not set:
// Remove all coded frames from track buffer that have a presentation timestamp greater than or equal to presentation timestamp and less than frame end timestamp.
// If highest end timestamp for track buffer is set and less than or equal to presentation timestamp:
// Remove all coded frames from track buffer that have a presentation timestamp greater than or equal to highest end timestamp and less than frame end timestamp"
for (uint32_t i = aStartIndex; i < data.Length(); i++) {
MediaRawData* sample = data[i].get();
TimeInterval sampleInterval =
TimeInterval(TimeUnit::FromMicroseconds(sample->mTime),
TimeUnit::FromMicroseconds(sample->GetEndTime()));
if (aIntervals.Contains(sampleInterval)) {
if (firstRemovedIndex.isNothing()) {
firstRemovedIndex = Some(i);
}
lastRemovedIndex = i;
}
}
if (firstRemovedIndex.isNothing()) {
return;
}
// Remove decoding dependencies of the coded frames removed in the previous step:
// Remove all coded frames between the coded frames removed in the previous step and the next random access point after those removed frames.
for (uint32_t i = lastRemovedIndex + 1; i < data.Length(); i++) {
MediaRawData* sample = data[i].get();
if (sample->mKeyframe) {
break;
}
lastRemovedIndex = i;
}
TimeIntervals removedIntervals;
for (uint32_t i = firstRemovedIndex.ref(); i <= lastRemovedIndex; i++) {
MediaRawData* sample = data[i].get();
TimeInterval sampleInterval =
TimeInterval(TimeUnit::FromMicroseconds(sample->mTime),
TimeUnit::FromMicroseconds(sample->GetEndTime()));
removedIntervals += sampleInterval;
aTrackData.mSizeBuffer -= sizeof(*sample) + sample->mSize;
}
MSE_DEBUG("Removing frames from:%u (frames:%u) ([%f, %f))",
firstRemovedIndex.ref(),
lastRemovedIndex - firstRemovedIndex.ref() + 1,
removedIntervals.GetStart().ToSeconds(),
removedIntervals.GetEnd().ToSeconds());
if (aTrackData.mNextGetSampleIndex.isSome()) {
if (aTrackData.mNextGetSampleIndex.ref() >= firstRemovedIndex.ref() &&
aTrackData.mNextGetSampleIndex.ref() <= lastRemovedIndex) {
MSE_DEBUG("Next sample to be played got evicted");
aTrackData.mNextGetSampleIndex.reset();
} else if (aTrackData.mNextGetSampleIndex.ref() > lastRemovedIndex) {
aTrackData.mNextGetSampleIndex.ref() -=
lastRemovedIndex - firstRemovedIndex.ref() + 1;
}
}
if (aTrackData.mNextInsertionIndex.isSome()) {
if (aTrackData.mNextInsertionIndex.ref() > firstRemovedIndex.ref() &&
aTrackData.mNextInsertionIndex.ref() <= lastRemovedIndex + 1) {
aTrackData.ResetAppendState();
} else if (aTrackData.mNextInsertionIndex.ref() > lastRemovedIndex + 1) {
aTrackData.mNextInsertionIndex.ref() -=
lastRemovedIndex - firstRemovedIndex.ref() + 1;
}
}
// Update our buffered range to exclude the range just removed.
aTrackData.mBufferedRanges -= removedIntervals;
data.RemoveElementsAt(firstRemovedIndex.ref(),
lastRemovedIndex - firstRemovedIndex.ref() + 1);
}
void
@ -1673,6 +1678,13 @@ TrackBuffersManager::RestartGroupStartTimestamp()
mGroupStartTimestamp = Some(mGroupEndTimestamp);
}
TimeUnit
TrackBuffersManager::GroupEndTimestamp()
{
MonitorAutoLock mon(mMonitor);
return mOfficialGroupEndTimestamp;
}
MediaInfo
TrackBuffersManager::GetMetadata()
{
@ -1873,3 +1885,5 @@ TrackBuffersManager::GetNextRandomAccessPoint(TrackInfo::TrackType aTrack)
}
#undef MSE_DEBUG
#undef MSE_DEBUGV
#undef SAMPLE_DEBUG

View File

@ -71,6 +71,7 @@ public:
void SetGroupStartTimestamp(const TimeUnit& aGroupStartTimestamp) override;
void RestartGroupStartTimestamp() override;
TimeUnit GroupEndTimestamp() override;
// Interface for MediaSourceDemuxer
MediaInfo GetMetadata();
@ -254,7 +255,17 @@ private:
}
};
bool ProcessFrame(MediaRawData* aSample, TrackData& aTrackData);
void CheckSequenceDiscontinuity();
void ProcessFrames(TrackBuffer& aSamples, TrackData& aTrackData);
void CheckNextInsertionIndex(TrackData& aTrackData,
const TimeUnit& aSampleTime);
void InsertFrames(TrackBuffer& aSamples,
const TimeIntervals& aIntervals,
TrackData& aTrackData);
void RemoveFrames(const TimeIntervals& aIntervals,
TrackData& aTrackData,
uint32_t aStartIndex);
void UpdateBufferedRanges();
void RejectProcessing(nsresult aRejectValue, const char* aName);
void ResolveProcessing(bool aResolveValue, const char* aName);
MediaPromiseRequestHolder<CodedFrameProcessingPromise> mProcessingRequest;
@ -291,6 +302,7 @@ private:
}
RefPtr<MediaTaskQueue> mTaskQueue;
TimeInterval mAppendWindow;
TimeUnit mTimestampOffset;
TimeUnit mLastTimestampOffset;
void RestoreCachedVariables();
@ -318,6 +330,7 @@ private:
// Stable audio and video track time ranges.
TimeIntervals mVideoBufferedRanges;
TimeIntervals mAudioBufferedRanges;
TimeUnit mOfficialGroupEndTimestamp;
// MediaInfo of the first init segment read.
MediaInfo mInfo;
};

View File

@ -290,7 +290,7 @@ MobileMessageCallback::NotifyGetSmscAddress(const nsAString& aSmscAddress)
return NotifyError(nsIMobileMessageCallback::INTERNAL_ERROR);
}
JS::Rooted<JS::Value> val(cx, STRING_TO_JSVAL(smsc));
JS::Rooted<JS::Value> val(cx, JS::StringValue(smsc));
return NotifySuccess(val);
}

View File

@ -489,7 +489,7 @@ NPVariantToJSVal(NPP npp, JSContext *cx, const NPVariant *variant)
case NPVariantType_Null :
return JS::NullValue();
case NPVariantType_Bool :
return BOOLEAN_TO_JSVAL(NPVARIANT_TO_BOOLEAN(*variant));
return JS::BooleanValue(NPVARIANT_TO_BOOLEAN(*variant));
case NPVariantType_Int32 :
{
// Don't use INT_TO_JSVAL directly to prevent bugs when dealing
@ -509,7 +509,7 @@ NPVariantToJSVal(NPP npp, JSContext *cx, const NPVariant *variant)
::JS_NewUCStringCopyN(cx, utf16String.get(), utf16String.Length());
if (str) {
return STRING_TO_JSVAL(str);
return JS::StringValue(str);
}
break;
@ -521,7 +521,7 @@ NPVariantToJSVal(NPP npp, JSContext *cx, const NPVariant *variant)
nsNPObjWrapper::GetNewOrUsed(npp, cx, NPVARIANT_TO_OBJECT(*variant));
if (obj) {
return OBJECT_TO_JSVAL(obj);
return JS::ObjectValue(*obj);
}
}

View File

@ -357,7 +357,7 @@ void CleanupOSFileConstants()
* Produces a |ConstantSpec|.
*/
#define INT_CONSTANT(name) \
{ #name, INT_TO_JSVAL(name) }
{ #name, JS::Int32Value(name) }
/**
* Define a simple read-only property holding an unsigned integer.
@ -576,94 +576,94 @@ static const dom::ConstantSpec gLibcProperties[] =
#if defined(XP_UNIX)
// The size of |mode_t|.
{ "OSFILE_SIZEOF_MODE_T", INT_TO_JSVAL(sizeof (mode_t)) },
{ "OSFILE_SIZEOF_MODE_T", JS::Int32Value(sizeof (mode_t)) },
// The size of |gid_t|.
{ "OSFILE_SIZEOF_GID_T", INT_TO_JSVAL(sizeof (gid_t)) },
{ "OSFILE_SIZEOF_GID_T", JS::Int32Value(sizeof (gid_t)) },
// The size of |uid_t|.
{ "OSFILE_SIZEOF_UID_T", INT_TO_JSVAL(sizeof (uid_t)) },
{ "OSFILE_SIZEOF_UID_T", JS::Int32Value(sizeof (uid_t)) },
// The size of |time_t|.
{ "OSFILE_SIZEOF_TIME_T", INT_TO_JSVAL(sizeof (time_t)) },
{ "OSFILE_SIZEOF_TIME_T", JS::Int32Value(sizeof (time_t)) },
// The size of |fsblkcnt_t|.
{ "OSFILE_SIZEOF_FSBLKCNT_T", INT_TO_JSVAL(sizeof (fsblkcnt_t)) },
{ "OSFILE_SIZEOF_FSBLKCNT_T", JS::Int32Value(sizeof (fsblkcnt_t)) },
#if !defined(ANDROID)
// The size of |posix_spawn_file_actions_t|.
{ "OSFILE_SIZEOF_POSIX_SPAWN_FILE_ACTIONS_T", INT_TO_JSVAL(sizeof (posix_spawn_file_actions_t)) },
{ "OSFILE_SIZEOF_POSIX_SPAWN_FILE_ACTIONS_T", JS::Int32Value(sizeof (posix_spawn_file_actions_t)) },
#endif // !defined(ANDROID)
// Defining |dirent|.
// Size
{ "OSFILE_SIZEOF_DIRENT", INT_TO_JSVAL(sizeof (dirent)) },
{ "OSFILE_SIZEOF_DIRENT", JS::Int32Value(sizeof (dirent)) },
// Defining |flock|.
#if defined(XP_UNIX)
{ "OSFILE_SIZEOF_FLOCK", INT_TO_JSVAL(sizeof (struct flock)) },
{ "OSFILE_OFFSETOF_FLOCK_L_START", INT_TO_JSVAL(offsetof (struct flock, l_start)) },
{ "OSFILE_OFFSETOF_FLOCK_L_LEN", INT_TO_JSVAL(offsetof (struct flock, l_len)) },
{ "OSFILE_OFFSETOF_FLOCK_L_PID", INT_TO_JSVAL(offsetof (struct flock, l_pid)) },
{ "OSFILE_OFFSETOF_FLOCK_L_TYPE", INT_TO_JSVAL(offsetof (struct flock, l_type)) },
{ "OSFILE_OFFSETOF_FLOCK_L_WHENCE", INT_TO_JSVAL(offsetof (struct flock, l_whence)) },
{ "OSFILE_SIZEOF_FLOCK", JS::Int32Value(sizeof (struct flock)) },
{ "OSFILE_OFFSETOF_FLOCK_L_START", JS::Int32Value(offsetof (struct flock, l_start)) },
{ "OSFILE_OFFSETOF_FLOCK_L_LEN", JS::Int32Value(offsetof (struct flock, l_len)) },
{ "OSFILE_OFFSETOF_FLOCK_L_PID", JS::Int32Value(offsetof (struct flock, l_pid)) },
{ "OSFILE_OFFSETOF_FLOCK_L_TYPE", JS::Int32Value(offsetof (struct flock, l_type)) },
{ "OSFILE_OFFSETOF_FLOCK_L_WHENCE", JS::Int32Value(offsetof (struct flock, l_whence)) },
#endif // defined(XP_UNIX)
// Offset of field |d_name|.
{ "OSFILE_OFFSETOF_DIRENT_D_NAME", INT_TO_JSVAL(offsetof (struct dirent, d_name)) },
{ "OSFILE_OFFSETOF_DIRENT_D_NAME", JS::Int32Value(offsetof (struct dirent, d_name)) },
// An upper bound to the length of field |d_name| of struct |dirent|.
// (may not be exact, depending on padding).
{ "OSFILE_SIZEOF_DIRENT_D_NAME", INT_TO_JSVAL(sizeof (struct dirent) - offsetof (struct dirent, d_name)) },
{ "OSFILE_SIZEOF_DIRENT_D_NAME", JS::Int32Value(sizeof (struct dirent) - offsetof (struct dirent, d_name)) },
// Defining |timeval|.
{ "OSFILE_SIZEOF_TIMEVAL", INT_TO_JSVAL(sizeof (struct timeval)) },
{ "OSFILE_OFFSETOF_TIMEVAL_TV_SEC", INT_TO_JSVAL(offsetof (struct timeval, tv_sec)) },
{ "OSFILE_OFFSETOF_TIMEVAL_TV_USEC", INT_TO_JSVAL(offsetof (struct timeval, tv_usec)) },
{ "OSFILE_SIZEOF_TIMEVAL", JS::Int32Value(sizeof (struct timeval)) },
{ "OSFILE_OFFSETOF_TIMEVAL_TV_SEC", JS::Int32Value(offsetof (struct timeval, tv_sec)) },
{ "OSFILE_OFFSETOF_TIMEVAL_TV_USEC", JS::Int32Value(offsetof (struct timeval, tv_usec)) },
#if defined(DT_UNKNOWN)
// Position of field |d_type| in |dirent|
// Not strictly posix, but seems defined on all platforms
// except mingw32.
{ "OSFILE_OFFSETOF_DIRENT_D_TYPE", INT_TO_JSVAL(offsetof (struct dirent, d_type)) },
{ "OSFILE_OFFSETOF_DIRENT_D_TYPE", JS::Int32Value(offsetof (struct dirent, d_type)) },
#endif // defined(DT_UNKNOWN)
// Under MacOS X and BSDs, |dirfd| is a macro rather than a
// function, so we need a little help to get it to work
#if defined(dirfd)
{ "OSFILE_SIZEOF_DIR", INT_TO_JSVAL(sizeof (DIR)) },
{ "OSFILE_SIZEOF_DIR", JS::Int32Value(sizeof (DIR)) },
{ "OSFILE_OFFSETOF_DIR_DD_FD", INT_TO_JSVAL(offsetof (DIR, __dd_fd)) },
{ "OSFILE_OFFSETOF_DIR_DD_FD", JS::Int32Value(offsetof (DIR, __dd_fd)) },
#endif
// Defining |stat|
{ "OSFILE_SIZEOF_STAT", INT_TO_JSVAL(sizeof (struct stat)) },
{ "OSFILE_SIZEOF_STAT", JS::Int32Value(sizeof (struct stat)) },
{ "OSFILE_OFFSETOF_STAT_ST_MODE", INT_TO_JSVAL(offsetof (struct stat, st_mode)) },
{ "OSFILE_OFFSETOF_STAT_ST_UID", INT_TO_JSVAL(offsetof (struct stat, st_uid)) },
{ "OSFILE_OFFSETOF_STAT_ST_GID", INT_TO_JSVAL(offsetof (struct stat, st_gid)) },
{ "OSFILE_OFFSETOF_STAT_ST_SIZE", INT_TO_JSVAL(offsetof (struct stat, st_size)) },
{ "OSFILE_OFFSETOF_STAT_ST_MODE", JS::Int32Value(offsetof (struct stat, st_mode)) },
{ "OSFILE_OFFSETOF_STAT_ST_UID", JS::Int32Value(offsetof (struct stat, st_uid)) },
{ "OSFILE_OFFSETOF_STAT_ST_GID", JS::Int32Value(offsetof (struct stat, st_gid)) },
{ "OSFILE_OFFSETOF_STAT_ST_SIZE", JS::Int32Value(offsetof (struct stat, st_size)) },
#if defined(HAVE_ST_ATIMESPEC)
{ "OSFILE_OFFSETOF_STAT_ST_ATIME", INT_TO_JSVAL(offsetof (struct stat, st_atimespec)) },
{ "OSFILE_OFFSETOF_STAT_ST_MTIME", INT_TO_JSVAL(offsetof (struct stat, st_mtimespec)) },
{ "OSFILE_OFFSETOF_STAT_ST_CTIME", INT_TO_JSVAL(offsetof (struct stat, st_ctimespec)) },
{ "OSFILE_OFFSETOF_STAT_ST_ATIME", JS::Int32Value(offsetof (struct stat, st_atimespec)) },
{ "OSFILE_OFFSETOF_STAT_ST_MTIME", JS::Int32Value(offsetof (struct stat, st_mtimespec)) },
{ "OSFILE_OFFSETOF_STAT_ST_CTIME", JS::Int32Value(offsetof (struct stat, st_ctimespec)) },
#else
{ "OSFILE_OFFSETOF_STAT_ST_ATIME", INT_TO_JSVAL(offsetof (struct stat, st_atime)) },
{ "OSFILE_OFFSETOF_STAT_ST_MTIME", INT_TO_JSVAL(offsetof (struct stat, st_mtime)) },
{ "OSFILE_OFFSETOF_STAT_ST_CTIME", INT_TO_JSVAL(offsetof (struct stat, st_ctime)) },
{ "OSFILE_OFFSETOF_STAT_ST_ATIME", JS::Int32Value(offsetof (struct stat, st_atime)) },
{ "OSFILE_OFFSETOF_STAT_ST_MTIME", JS::Int32Value(offsetof (struct stat, st_mtime)) },
{ "OSFILE_OFFSETOF_STAT_ST_CTIME", JS::Int32Value(offsetof (struct stat, st_ctime)) },
#endif // defined(HAVE_ST_ATIME)
// Several OSes have a birthtime field. For the moment, supporting only Darwin.
#if defined(_DARWIN_FEATURE_64_BIT_INODE)
{ "OSFILE_OFFSETOF_STAT_ST_BIRTHTIME", INT_TO_JSVAL(offsetof (struct stat, st_birthtime)) },
{ "OSFILE_OFFSETOF_STAT_ST_BIRTHTIME", JS::Int32Value(offsetof (struct stat, st_birthtime)) },
#endif // defined(_DARWIN_FEATURE_64_BIT_INODE)
// Defining |statvfs|
{ "OSFILE_SIZEOF_STATVFS", INT_TO_JSVAL(sizeof (struct statvfs)) },
{ "OSFILE_SIZEOF_STATVFS", JS::Int32Value(sizeof (struct statvfs)) },
{ "OSFILE_OFFSETOF_STATVFS_F_BSIZE", INT_TO_JSVAL(offsetof (struct statvfs, f_bsize)) },
{ "OSFILE_OFFSETOF_STATVFS_F_BAVAIL", INT_TO_JSVAL(offsetof (struct statvfs, f_bavail)) },
{ "OSFILE_OFFSETOF_STATVFS_F_BSIZE", JS::Int32Value(offsetof (struct statvfs, f_bsize)) },
{ "OSFILE_OFFSETOF_STATVFS_F_BAVAIL", JS::Int32Value(offsetof (struct statvfs, f_bavail)) },
#endif // defined(XP_UNIX)
@ -678,7 +678,7 @@ static const dom::ConstantSpec gLibcProperties[] =
// whenever macro _DARWIN_FEATURE_64_BIT_INODE is set. We export
// this value to be able to do so from JavaScript.
#if defined(_DARWIN_FEATURE_64_BIT_INODE)
{ "_DARWIN_FEATURE_64_BIT_INODE", INT_TO_JSVAL(1) },
{ "_DARWIN_FEATURE_64_BIT_INODE", JS::Int32Value(1) },
#endif // defined(_DARWIN_FEATURE_64_BIT_INODE)
// Similar feature for Linux
@ -738,7 +738,7 @@ static const dom::ConstantSpec gWinProperties[] =
INT_CONSTANT(FILE_FLAG_BACKUP_SEMANTICS),
// CreateFile error constant
{ "INVALID_HANDLE_VALUE", INT_TO_JSVAL(INT_PTR(INVALID_HANDLE_VALUE)) },
{ "INVALID_HANDLE_VALUE", JS::Int32Value(INT_PTR(INVALID_HANDLE_VALUE)) },
// CreateFile flags
@ -824,7 +824,7 @@ bool SetStringProperty(JSContext *cx, JS::Handle<JSObject*> aObject, const char
}
JSString* strValue = JS_NewUCStringCopyZ(cx, aValue.get());
NS_ENSURE_TRUE(strValue, false);
JS::Rooted<JS::Value> valValue(cx, STRING_TO_JSVAL(strValue));
JS::Rooted<JS::Value> valValue(cx, JS::StringValue(strValue));
return JS_SetProperty(cx, aObject, aProperty, valValue);
}
@ -891,7 +891,7 @@ bool DefineOSFileConstants(JSContext *cx, JS::Handle<JSObject*> global)
if (!strVersion){
return false;
}
JS::Rooted<JS::Value> valVersion(cx, STRING_TO_JSVAL(strVersion));
JS::Rooted<JS::Value> valVersion(cx, JS::StringValue(strVersion));
if (!JS_SetProperty(cx, objSys, "Name", valVersion)) {
return false;
}
@ -907,7 +907,7 @@ bool DefineOSFileConstants(JSContext *cx, JS::Handle<JSObject*> global)
return false;
}
JS::Rooted<JS::Value> valVersion(cx, STRING_TO_JSVAL(strVersion));
JS::Rooted<JS::Value> valVersion(cx, JS::StringValue(strVersion));
if (!JS_SetProperty(cx, objSys, "Name", valVersion)) {
return false;
}
@ -922,9 +922,9 @@ bool DefineOSFileConstants(JSContext *cx, JS::Handle<JSObject*> global)
#endif
#if defined(HAVE_64BIT_BUILD)
JS::Rooted<JS::Value> valBits(cx, INT_TO_JSVAL(64));
JS::Rooted<JS::Value> valBits(cx, JS::Int32Value(64));
#else
JS::Rooted<JS::Value> valBits(cx, INT_TO_JSVAL(32));
JS::Rooted<JS::Value> valBits(cx, JS::Int32Value(32));
#endif //defined (HAVE_64BIT_BUILD)
if (!JS_SetProperty(cx, objSys, "bits", valBits)) {
return false;

View File

@ -2384,7 +2384,7 @@ RuntimeService::CreateSharedWorkerInternal(const GlobalObject& aGlobal,
nsresult rv = WorkerPrivate::GetLoadInfo(cx, window, nullptr, aScriptURL,
false,
WorkerPrivate::OverrideLoadGroup,
&loadInfo);
aType, &loadInfo);
NS_ENSURE_SUCCESS(rv, rv);
return CreateSharedWorkerFromLoadInfo(cx, &loadInfo, aScriptURL, aName, aType,

View File

@ -96,6 +96,7 @@ ChannelFromScriptURL(nsIPrincipal* principal,
const nsAString& aScriptURL,
bool aIsMainScript,
WorkerScriptType aWorkerScriptType,
nsContentPolicyType aContentPolicyType,
nsIChannel** aChannel)
{
AssertIsOnMainThread();
@ -112,7 +113,7 @@ ChannelFromScriptURL(nsIPrincipal* principal,
// If we're part of a document then check the content load policy.
if (parentDoc) {
int16_t shouldLoad = nsIContentPolicy::ACCEPT;
rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_SCRIPT, uri,
rv = NS_CheckContentLoadPolicy(aContentPolicyType, uri,
principal, parentDoc,
NS_LITERAL_CSTRING("text/javascript"),
nullptr, &shouldLoad,
@ -167,7 +168,7 @@ ChannelFromScriptURL(nsIPrincipal* principal,
uri,
parentDoc,
nsILoadInfo::SEC_NORMAL,
nsIContentPolicy::TYPE_SCRIPT,
aContentPolicyType,
loadGroup,
nullptr, // aCallbacks
flags,
@ -182,7 +183,7 @@ ChannelFromScriptURL(nsIPrincipal* principal,
uri,
principal,
nsILoadInfo::SEC_NORMAL,
nsIContentPolicy::TYPE_SCRIPT,
aContentPolicyType,
loadGroup,
nullptr, // aCallbacks
flags,
@ -840,7 +841,9 @@ private:
if (!channel) {
rv = ChannelFromScriptURL(principal, baseURI, parentDoc, loadGroup, ios,
secMan, loadInfo.mURL, IsMainWorkerScript(),
mWorkerScriptType, getter_AddRefs(channel));
mWorkerScriptType,
mWorkerPrivate->ContentPolicyType(),
getter_AddRefs(channel));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -1578,6 +1581,8 @@ public:
scriptloader::ChannelFromScriptURLMainThread(principal, baseURI,
parentDoc, loadGroup,
mScriptURL,
// Nested workers are always dedicated.
nsIContentPolicy::TYPE_INTERNAL_WORKER,
getter_AddRefs(channel));
if (NS_SUCCEEDED(mResult)) {
channel.forget(mChannel);
@ -1789,6 +1794,7 @@ ChannelFromScriptURLMainThread(nsIPrincipal* aPrincipal,
nsIDocument* aParentDoc,
nsILoadGroup* aLoadGroup,
const nsAString& aScriptURL,
nsContentPolicyType aContentPolicyType,
nsIChannel** aChannel)
{
AssertIsOnMainThread();
@ -1799,7 +1805,8 @@ ChannelFromScriptURLMainThread(nsIPrincipal* aPrincipal,
NS_ASSERTION(secMan, "This should never be null!");
return ChannelFromScriptURL(aPrincipal, aBaseURI, aParentDoc, aLoadGroup,
ios, secMan, aScriptURL, true, WorkerScript, aChannel);
ios, secMan, aScriptURL, true, WorkerScript,
aContentPolicyType, aChannel);
}
nsresult

View File

@ -8,6 +8,7 @@
#define mozilla_dom_workers_scriptloader_h__
#include "Workers.h"
#include "nsIContentPolicyBase.h"
class nsIPrincipal;
class nsIURI;
@ -37,6 +38,7 @@ ChannelFromScriptURLMainThread(nsIPrincipal* aPrincipal,
nsIDocument* aParentDoc,
nsILoadGroup* aLoadGroup,
const nsAString& aScriptURL,
nsContentPolicyType aContentPolicyType,
nsIChannel** aChannel);
nsresult

View File

@ -2701,6 +2701,7 @@ ServiceWorkerManager::CreateServiceWorkerForWindow(nsPIDOMWindow* aWindow,
NS_ConvertUTF8toUTF16(aInfo->ScriptSpec()),
false,
WorkerPrivate::OverrideLoadGroup,
WorkerTypeService,
&loadInfo);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;

View File

@ -107,10 +107,13 @@ public:
return rv;
}
// Note that because there is no "serviceworker" RequestContext type, we can
// use the external TYPE_SCRIPT content policy types when loading a service
// worker.
rv = NS_NewChannel(getter_AddRefs(mChannel),
uri, aPrincipal,
nsILoadInfo::SEC_NORMAL,
nsIContentPolicy::TYPE_SCRIPT, // FIXME(nsm): TYPE_SERVICEWORKER
nsIContentPolicy::TYPE_SCRIPT,
loadGroup);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;

View File

@ -4854,7 +4854,7 @@ WorkerPrivate::Constructor(JSContext* aCx,
nsresult rv = GetLoadInfo(aCx, nullptr, parent, aScriptURL,
aIsChromeWorker, InheritLoadGroup,
stackLoadInfo.ptr());
aWorkerType, stackLoadInfo.ptr());
if (NS_FAILED(rv)) {
scriptloader::ReportLoadError(aCx, aScriptURL, rv, !parent);
aRv.Throw(rv);
@ -4912,6 +4912,7 @@ WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow,
WorkerPrivate* aParent, const nsAString& aScriptURL,
bool aIsChromeWorker,
LoadGroupBehavior aLoadGroupBehavior,
WorkerType aWorkerType,
WorkerLoadInfo* aLoadInfo)
{
using namespace mozilla::dom::workers::scriptloader;
@ -5165,6 +5166,7 @@ WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow,
rv = ChannelFromScriptURLMainThread(loadInfo.mPrincipal, loadInfo.mBaseURI,
document, loadInfo.mLoadGroup,
aScriptURL,
ContentPolicyType(aWorkerType),
getter_AddRefs(loadInfo.mChannel));
NS_ENSURE_SUCCESS(rv, rv);

View File

@ -9,6 +9,7 @@
#include "Workers.h"
#include "nsIContentPolicy.h"
#include "nsIContentSecurityPolicy.h"
#include "nsILoadGroup.h"
#include "nsIWorkerDebugger.h"
@ -734,6 +735,28 @@ public:
return mWorkerType == WorkerTypeService;
}
nsContentPolicyType
ContentPolicyType() const
{
return ContentPolicyType(mWorkerType);
}
static nsContentPolicyType
ContentPolicyType(WorkerType aWorkerType)
{
switch (aWorkerType) {
case WorkerTypeDedicated:
return nsIContentPolicy::TYPE_INTERNAL_WORKER;
case WorkerTypeShared:
return nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER;
case WorkerTypeService:
return nsIContentPolicy::TYPE_SCRIPT;
default:
MOZ_ASSERT_UNREACHABLE("Invalid worker type");
return nsIContentPolicy::TYPE_INVALID;
}
}
const nsCString&
SharedWorkerName() const
{
@ -982,7 +1005,8 @@ public:
static nsresult
GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow, WorkerPrivate* aParent,
const nsAString& aScriptURL, bool aIsChromeWorker,
LoadGroupBehavior aLoadGroupBehavior, WorkerLoadInfo* aLoadInfo);
LoadGroupBehavior aLoadGroupBehavior, WorkerType aWorkerType,
WorkerLoadInfo* aLoadInfo);
static void
OverrideLoadInfoLoadGroup(WorkerLoadInfo& aLoadInfo);

View File

@ -742,7 +742,7 @@ workerdebuggersandbox_convert(JSContext *cx, JS::Handle<JSObject *> obj,
JSType type, JS::MutableHandle<JS::Value> vp)
{
if (type == JSTYPE_OBJECT) {
vp.set(OBJECT_TO_JSVAL(obj));
vp.setObject(*obj);
return true;
}

View File

@ -2457,7 +2457,7 @@ XMLHttpRequest::GetResponse(JSContext* /* unused */,
return;
}
mStateData.mResponse = STRING_TO_JSVAL(str);
mStateData.mResponse.setString(str);
}
}

View File

@ -70,6 +70,22 @@ self.addEventListener("fetch", function(event) {
}
} else if (event.request.url.indexOf("xslt") >= 0) {
respondToServiceWorker(event, "xslt");
} else if (event.request.url.indexOf("myworker") >= 0) {
if (event.request.context == "worker") {
event.respondWith(fetch("worker.js"));
}
} else if (event.request.url.indexOf("myparentworker") >= 0) {
if (event.request.context == "worker") {
event.respondWith(fetch("parentworker.js"));
}
} else if (event.request.url.indexOf("mysharedworker") >= 0) {
if (event.request.context == "sharedworker") {
event.respondWith(fetch("sharedworker.js"));
}
} else if (event.request.url.indexOf("myparentsharedworker") >= 0) {
if (event.request.context == "sharedworker") {
event.respondWith(fetch("parentsharedworker.js"));
}
} else if (event.request.url.indexOf("cache") >= 0) {
var cache;
var origContext = event.request.context;

View File

@ -341,6 +341,58 @@
});
}
function testWorker() {
return new Promise(function(resolve, reject) {
var worker = new Worker("myworker");
worker.onmessage = function(e) {
if (e.data == "ack") {
worker.terminate();
resolve();
}
};
worker.onerror = reject;
});
}
function testNestedWorker() {
return new Promise(function(resolve, reject) {
var worker = new Worker("myparentworker");
worker.onmessage = function(e) {
if (e.data == "ack") {
worker.terminate();
resolve();
}
};
worker.onerror = reject;
});
}
function testSharedWorker() {
return new Promise(function(resolve, reject) {
var worker = new SharedWorker("mysharedworker");
worker.port.start();
worker.port.onmessage = function(e) {
if (e.data == "ack") {
resolve();
}
};
worker.onerror = reject;
});
}
function testNestedWorkerInSharedWorker() {
return new Promise(function(resolve, reject) {
var worker = new SharedWorker("myparentsharedworker");
worker.port.start();
worker.port.onmessage = function(e) {
if (e.data == "ack") {
resolve();
}
};
worker.onerror = reject;
});
}
function testCache() {
return new Promise(function(resolve, reject) {
// Issue an XHR that will be intercepted by the SW in order to start off
@ -383,6 +435,10 @@
testTrack(),
testXHR(),
testXSLT(),
testWorker(),
testNestedWorker(),
testSharedWorker(),
testNestedWorkerInSharedWorker(),
// Also, test to see if the type of the request can be persisted in the database.
testCache(),

View File

@ -0,0 +1,8 @@
onconnect = function(e) {
e.ports[0].start();
var worker = new Worker("myworker?shared");
worker.onmessage = function(e2) {
e.ports[0].postMessage(e2.data);
self.close();
};
};

View File

@ -0,0 +1,4 @@
var worker = new Worker("myworker");
worker.onmessage = function(e) {
postMessage(e.data);
};

View File

@ -0,0 +1,5 @@
onconnect = function(e) {
e.ports[0].start();
e.ports[0].postMessage("ack");
self.close();
};

View File

@ -0,0 +1 @@
postMessage("ack");

View File

@ -38,6 +38,10 @@ support-files =
fetch/context/beacon.sjs
fetch/context/csp-violate.sjs
fetch/context/ping.html
fetch/context/worker.js
fetch/context/parentworker.js
fetch/context/sharedworker.js
fetch/context/parentsharedworker.js
fetch/context/xml.xml
fetch/https/index.html
fetch/https/register.html

View File

@ -1029,7 +1029,7 @@ nsXBLBinding::DoInitJSClass(JSContext *cx,
nsXBLDocumentInfo* docInfo = aProtoBinding->XBLDocumentInfo();
::JS_SetPrivate(proto, docInfo);
NS_ADDREF(docInfo);
JS_SetReservedSlot(proto, 0, PRIVATE_TO_JSVAL(aProtoBinding));
JS_SetReservedSlot(proto, 0, JS::PrivateValue(aProtoBinding));
// Next, enter the compartment of the property holder, wrap the proto, and
// stick it on.

View File

@ -8,6 +8,7 @@
#include "mozilla/MemoryReporting.h"
#include "mozilla/Move.h"
#include "imgIContainer.h"
#include "LookupResult.h"
#include "MainThreadUtils.h"
#include "RasterImage.h"
@ -265,25 +266,27 @@ FrameAnimator::GetFirstFrameRefreshArea() const
return mFirstFrameRefreshArea;
}
DrawableFrameRef
LookupResult
FrameAnimator::GetCompositedFrame(uint32_t aFrameNum)
{
MOZ_ASSERT(aFrameNum != 0, "First frame is never composited");
// If we have a composited version of this frame, return that.
if (mLastCompositedFrameIndex == int32_t(aFrameNum)) {
return mCompositingFrame->DrawableRef();
return LookupResult(mCompositingFrame->DrawableRef(),
/* aIsExactMatch = */ true);
}
// Otherwise return the raw frame. DoBlend is required to ensure that we only
// hit this case if the frame is not paletted and doesn't require compositing.
DrawableFrameRef ref =
LookupResult result =
SurfaceCache::Lookup(ImageKey(mImage),
RasterSurfaceKey(mSize,
0, // Default decode flags.
aFrameNum));
MOZ_ASSERT(!ref || !ref->GetIsPaletted(), "About to return a paletted frame");
return ref;
MOZ_ASSERT(!result || !result.DrawableRef()->GetIsPaletted(),
"About to return a paletted frame");
return result;
}
int32_t
@ -367,13 +370,13 @@ FrameAnimator::CollectSizeOfCompositingSurfaces(
RawAccessFrameRef
FrameAnimator::GetRawFrame(uint32_t aFrameNum) const
{
DrawableFrameRef ref =
LookupResult result =
SurfaceCache::Lookup(ImageKey(mImage),
RasterSurfaceKey(mSize,
0, // Default decode flags.
aFrameNum));
return ref ? ref->RawAccessRef()
: RawAccessFrameRef();
return result ? result.DrawableRef()->RawAccessRef()
: RawAccessFrameRef();
}
//******************************************************************************

View File

@ -128,10 +128,10 @@ public:
/**
* If we have a composited frame for @aFrameNum, returns it. Otherwise,
* returns an empty DrawableFrameRef. It is an error to call this method with
* returns an empty LookupResult. It is an error to call this method with
* aFrameNum == 0, because the first frame is never composited.
*/
DrawableFrameRef GetCompositedFrame(uint32_t aFrameNum);
LookupResult GetCompositedFrame(uint32_t aFrameNum);
/*
* Returns the frame's adjusted timeout. If the animation loops and the

69
image/LookupResult.h Normal file
View File

@ -0,0 +1,69 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
/**
* LookupResult is the return type of SurfaceCache's Lookup*() functions. It
* combines a surface with relevant metadata tracked by SurfaceCache.
*/
#ifndef mozilla_image_LookupResult_h
#define mozilla_image_LookupResult_h
#include "mozilla/Attributes.h"
#include "mozilla/Move.h"
#include "imgFrame.h"
namespace mozilla {
namespace image {
/**
* LookupResult is the return type of SurfaceCache's Lookup*() functions. It
* combines a surface with relevant metadata tracked by SurfaceCache.
*/
class MOZ_STACK_CLASS LookupResult
{
public:
LookupResult()
: mIsExactMatch(false)
{ }
LookupResult(LookupResult&& aOther)
: mDrawableRef(Move(aOther.mDrawableRef))
, mIsExactMatch(aOther.mIsExactMatch)
{ }
LookupResult(DrawableFrameRef&& aDrawableRef, bool aIsExactMatch)
: mDrawableRef(Move(aDrawableRef))
, mIsExactMatch(aIsExactMatch)
{ }
LookupResult& operator=(LookupResult&& aOther)
{
MOZ_ASSERT(&aOther != this, "Self-move-assignment is not supported");
mDrawableRef = Move(aOther.mDrawableRef);
mIsExactMatch = aOther.mIsExactMatch;
return *this;
}
DrawableFrameRef& DrawableRef() { return mDrawableRef; }
const DrawableFrameRef& DrawableRef() const { return mDrawableRef; }
/// @return true if this LookupResult contains a surface.
explicit operator bool() const { return bool(mDrawableRef); }
/// @return true if the surface is an exact match for the Lookup*() arguments.
bool IsExactMatch() const { return mIsExactMatch; }
private:
LookupResult(const LookupResult&) = delete;
DrawableFrameRef mDrawableRef;
bool mIsExactMatch;
};
} // namespace image
} // namespace mozilla
#endif // mozilla_image_LookupResult_h

View File

@ -20,6 +20,7 @@
#include "ImageContainer.h"
#include "ImageRegion.h"
#include "Layers.h"
#include "LookupResult.h"
#include "nsPresContext.h"
#include "SourceBuffer.h"
#include "SurfaceCache.h"
@ -469,7 +470,7 @@ RasterImage::GetType(uint16_t* aType)
return NS_OK;
}
DrawableFrameRef
LookupResult
RasterImage::LookupFrameInternal(uint32_t aFrameNum,
const IntSize& aSize,
uint32_t aFlags)
@ -522,14 +523,14 @@ RasterImage::LookupFrame(uint32_t aFrameNum,
IntSize requestedSize = CanDownscaleDuringDecode(aSize, aFlags)
? aSize : mSize;
DrawableFrameRef ref = LookupFrameInternal(aFrameNum, requestedSize, aFlags);
LookupResult result = LookupFrameInternal(aFrameNum, requestedSize, aFlags);
if (!ref && !mHasSize) {
if (!result && !mHasSize) {
// We can't request a decode without knowing our intrinsic size. Give up.
return DrawableFrameRef();
}
if (!ref || ref->GetImageSize() != requestedSize) {
if (!result || !result.IsExactMatch()) {
// The OS threw this frame away. We need to redecode if we can.
MOZ_ASSERT(!mAnim, "Animated frames should be locked");
@ -537,29 +538,30 @@ RasterImage::LookupFrame(uint32_t aFrameNum,
// If we can sync decode, we should already have the frame.
if (aFlags & FLAG_SYNC_DECODE) {
ref = LookupFrameInternal(aFrameNum, requestedSize, aFlags);
result = LookupFrameInternal(aFrameNum, requestedSize, aFlags);
}
}
if (!ref) {
if (!result) {
// We still weren't able to get a frame. Give up.
return DrawableFrameRef();
}
if (ref->GetCompositingFailed()) {
if (result.DrawableRef()->GetCompositingFailed()) {
return DrawableFrameRef();
}
MOZ_ASSERT(!ref || !ref->GetIsPaletted(), "Should not have paletted frame");
MOZ_ASSERT(!result.DrawableRef()->GetIsPaletted(),
"Should not have a paletted frame");
// Sync decoding guarantees that we got the frame, but if it's owned by an
// async decoder that's currently running, the contents of the frame may not
// be available yet. Make sure we get everything.
if (ref && mHasSourceData && (aFlags & FLAG_SYNC_DECODE)) {
ref->WaitUntilComplete();
if (mHasSourceData && (aFlags & FLAG_SYNC_DECODE)) {
result.DrawableRef()->WaitUntilComplete();
}
return ref;
return Move(result.DrawableRef());
}
uint32_t
@ -1835,19 +1837,19 @@ RasterImage::DrawWithPreDownscaleIfNeeded(DrawableFrameRef&& aFrameRef,
DrawableFrameRef frameRef;
if (CanScale(aFilter, aSize, aFlags)) {
frameRef =
LookupResult result =
SurfaceCache::Lookup(ImageKey(this),
RasterSurfaceKey(aSize,
DecodeFlags(aFlags),
0));
if (!frameRef) {
if (!result) {
// We either didn't have a matching scaled frame or the OS threw it away.
// Request a new one so we'll be ready next time. For now, we'll fall back
// to aFrameRef below.
RequestScale(aFrameRef.get(), aFlags, aSize);
}
if (frameRef && !frameRef->IsImageComplete()) {
frameRef.reset(); // We're still scaling, so we can't use this yet.
if (result && result.DrawableRef()->IsImageComplete()) {
frameRef = Move(result.DrawableRef()); // The scaled version is ready.
}
}
@ -2247,21 +2249,21 @@ RasterImage::OptimalImageSizeForDest(const gfxSize& aDest, uint32_t aWhichFrame,
CanDownscaleDuringDecode(destSize, aFlags)) {
return destSize;
} else if (CanScale(aFilter, destSize, aFlags)) {
DrawableFrameRef frameRef =
LookupResult result =
SurfaceCache::Lookup(ImageKey(this),
RasterSurfaceKey(destSize,
DecodeFlags(aFlags),
0));
if (frameRef && frameRef->IsImageComplete()) {
return destSize; // We have an existing HQ scale for this size.
if (result && result.DrawableRef()->IsImageComplete()) {
return destSize; // We have an existing HQ scale for this size.
}
if (!frameRef) {
if (!result) {
// We could HQ scale to this size, but we haven't. Request a scale now.
frameRef = LookupFrame(GetRequestedFrameIndex(aWhichFrame),
mSize, aFlags);
if (frameRef) {
RequestScale(frameRef.get(), aFlags, destSize);
DrawableFrameRef ref = LookupFrame(GetRequestedFrameIndex(aWhichFrame),
mSize, aFlags);
if (ref) {
RequestScale(ref.get(), aFlags, destSize);
}
}
}

View File

@ -23,6 +23,7 @@
#include "nsIProperties.h"
#include "nsTArray.h"
#include "imgFrame.h"
#include "LookupResult.h"
#include "nsThreadUtils.h"
#include "DecodePool.h"
#include "Orientation.h"
@ -301,9 +302,9 @@ private:
Pair<DrawResult, RefPtr<gfx::SourceSurface>>
GetFrameInternal(uint32_t aWhichFrame, uint32_t aFlags);
DrawableFrameRef LookupFrameInternal(uint32_t aFrameNum,
const gfx::IntSize& aSize,
uint32_t aFlags);
LookupResult LookupFrameInternal(uint32_t aFrameNum,
const gfx::IntSize& aSize,
uint32_t aFlags);
DrawableFrameRef LookupFrame(uint32_t aFrameNum,
const nsIntSize& aSize,
uint32_t aFlags);

View File

@ -25,6 +25,7 @@
#include "gfxPrefs.h"
#include "imgFrame.h"
#include "Image.h"
#include "LookupResult.h"
#include "nsAutoPtr.h"
#include "nsExpirationTracker.h"
#include "nsHashKeys.h"
@ -543,17 +544,17 @@ public:
"More available cost than we started with");
}
DrawableFrameRef Lookup(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey)
LookupResult Lookup(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey)
{
nsRefPtr<ImageSurfaceCache> cache = GetImageCache(aImageKey);
if (!cache) {
return DrawableFrameRef(); // No cached surfaces for this image.
return LookupResult(); // No cached surfaces for this image.
}
nsRefPtr<CachedSurface> surface = cache->Lookup(aSurfaceKey);
if (!surface) {
return DrawableFrameRef(); // Lookup in the per-image cache missed.
return LookupResult(); // Lookup in the per-image cache missed.
}
DrawableFrameRef ref = surface->DrawableRef();
@ -561,7 +562,7 @@ public:
// The surface was released by the operating system. Remove the cache
// entry as well.
Remove(surface);
return DrawableFrameRef();
return LookupResult();
}
if (cache->IsLocked()) {
@ -570,16 +571,16 @@ public:
mExpirationTracker.MarkUsed(surface);
}
return ref;
return LookupResult(Move(ref), /* aIsExactMatch = */ true);
}
DrawableFrameRef LookupBestMatch(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey,
const Maybe<uint32_t>& aAlternateFlags)
LookupResult LookupBestMatch(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey,
const Maybe<uint32_t>& aAlternateFlags)
{
nsRefPtr<ImageSurfaceCache> cache = GetImageCache(aImageKey);
if (!cache) {
return DrawableFrameRef(); // No cached surfaces for this image.
return LookupResult(); // No cached surfaces for this image.
}
// Repeatedly look up the best match, trying again if the resulting surface
@ -593,7 +594,7 @@ public:
while (true) {
surface = cache->LookupBestMatch(aSurfaceKey, aAlternateFlags);
if (!surface) {
return DrawableFrameRef(); // Lookup in the per-image cache missed.
return LookupResult(); // Lookup in the per-image cache missed.
}
ref = surface->DrawableRef();
@ -612,7 +613,15 @@ public:
mExpirationTracker.MarkUsed(surface);
}
return ref;
SurfaceKey key = surface->GetSurfaceKey();
const bool isExactMatch = key.Size() == aSurfaceKey.Size();
MOZ_ASSERT(isExactMatch ==
(key == aSurfaceKey ||
(aAlternateFlags && key == aSurfaceKey.WithNewFlags(*aAlternateFlags))),
"Result differs in a way other than size or alternate flags");
return LookupResult(Move(ref), isExactMatch);
}
void RemoveSurface(const ImageKey aImageKey,
@ -970,34 +979,34 @@ SurfaceCache::Shutdown()
sInstance = nullptr;
}
/* static */ DrawableFrameRef
/* static */ LookupResult
SurfaceCache::Lookup(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey,
const Maybe<uint32_t>& aAlternateFlags /* = Nothing() */)
{
if (!sInstance) {
return DrawableFrameRef();
return LookupResult();
}
MutexAutoLock lock(sInstance->GetMutex());
DrawableFrameRef ref = sInstance->Lookup(aImageKey, aSurfaceKey);
if (!ref && aAlternateFlags) {
ref = sInstance->Lookup(aImageKey,
aSurfaceKey.WithNewFlags(*aAlternateFlags));
LookupResult result = sInstance->Lookup(aImageKey, aSurfaceKey);
if (!result && aAlternateFlags) {
result = sInstance->Lookup(aImageKey,
aSurfaceKey.WithNewFlags(*aAlternateFlags));
}
return ref;
return result;
}
/* static */ DrawableFrameRef
/* static */ LookupResult
SurfaceCache::LookupBestMatch(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey,
const Maybe<uint32_t>& aAlternateFlags
/* = Nothing() */)
{
if (!sInstance) {
return DrawableFrameRef();
return LookupResult();
}
MutexAutoLock lock(sInstance->GetMutex());

View File

@ -24,9 +24,9 @@
namespace mozilla {
namespace image {
class DrawableFrameRef;
class Image;
class imgFrame;
class LookupResult;
struct SurfaceMemoryCounter;
/*
@ -174,7 +174,7 @@ struct SurfaceCache
*
* If the imgFrame was found in the cache, but had stored its surface in a
* volatile buffer which was discarded by the OS, then it is automatically
* removed from the cache and an empty DrawableFrameRef is returned. Note that
* removed from the cache and an empty LookupResult is returned. Note that
* this will never happen to persistent surfaces associated with a locked
* image; the cache keeps a strong reference to such surfaces internally.
*
@ -190,14 +190,13 @@ struct SurfaceCache
* than calling Lookup() twice, which requires taking a
* lock each time.
*
* @return a DrawableFrameRef to the imgFrame wrapping the
* requested surface, or an empty DrawableFrameRef if
* not found.
* @return a LookupResult, which will either contain a
* DrawableFrameRef to the requested surface, or an
* empty DrawableFrameRef if the surface was not found.
*/
static DrawableFrameRef Lookup(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey,
const Maybe<uint32_t>& aAlternateFlags
= Nothing());
static LookupResult Lookup(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey,
const Maybe<uint32_t>& aAlternateFlags = Nothing());
/**
* Looks up the best matching surface in the cache and returns a drawable
@ -216,13 +215,17 @@ struct SurfaceCache
* acceptable to the caller. This is much more
* efficient than calling LookupBestMatch() twice.
*
* @return a DrawableFrameRef to the imgFrame wrapping a surface similar to
* the requested surface, or an empty DrawableFrameRef if not found.
* @return a LookupResult, which will either contain a
* DrawableFrameRef to a surface similar to the
* requested surface, or an empty DrawableFrameRef if
* the surface was not found. Callers can use
* LookupResult::IsExactMatch() to check whether the
* returned surface exactly matches @aSurfaceKey.
*/
static DrawableFrameRef LookupBestMatch(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey,
const Maybe<uint32_t>& aAlternateFlags
= Nothing());
static LookupResult LookupBestMatch(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey,
const Maybe<uint32_t>& aAlternateFlags
= Nothing());
/**
* Insert a surface into the cache. If a surface with the same ImageKey and

View File

@ -27,6 +27,7 @@
#include "nsSVGEffects.h" // for nsSVGRenderingObserver
#include "nsWindowMemoryReporter.h"
#include "ImageRegion.h"
#include "LookupResult.h"
#include "Orientation.h"
#include "SVGDocumentWrapper.h"
#include "nsIDOMEventListener.h"
@ -829,18 +830,18 @@ VectorImage::Draw(gfxContext* aContext,
return DrawResult::SUCCESS;
}
DrawableFrameRef frameRef =
LookupResult result =
SurfaceCache::Lookup(ImageKey(this),
VectorSurfaceKey(params.size,
params.svgContext,
params.animationTime));
// Draw.
if (frameRef) {
RefPtr<SourceSurface> surface = frameRef->GetSurface();
if (result) {
RefPtr<SourceSurface> surface = result.DrawableRef()->GetSurface();
if (surface) {
nsRefPtr<gfxDrawable> svgDrawable =
new gfxSurfaceDrawable(surface, frameRef->GetSize());
new gfxSurfaceDrawable(surface, result.DrawableRef()->GetSize());
Show(svgDrawable, params);
return DrawResult::SUCCESS;
}

View File

@ -444,6 +444,8 @@ public:
}
private:
DrawableFrameRef(const DrawableFrameRef& aOther) = delete;
nsRefPtr<imgFrame> mFrame;
VolatileBufferPtr<uint8_t> mRef;
};
@ -526,6 +528,8 @@ public:
}
private:
RawAccessFrameRef(const RawAccessFrameRef& aOther) = delete;
nsRefPtr<imgFrame> mFrame;
};

View File

@ -362,7 +362,7 @@ JavaScriptShared::fromVariant(JSContext* cx, const JSVariant& from, MutableHandl
return true;
case JSVariant::Tbool:
to.set(BOOLEAN_TO_JSVAL(from.get_bool()));
to.setBoolean(from.get_bool());
return true;
case JSVariant::TnsString:

View File

@ -1392,12 +1392,10 @@ UndefinedValue()
#endif
}
static inline Value
static inline JS_VALUE_CONSTEXPR Value
Int32Value(int32_t i32)
{
Value v;
v.setInt32(i32);
return v;
return IMPL_TO_JSVAL(INT32_TO_JSVAL_IMPL(i32));
}
static inline Value
@ -1934,12 +1932,6 @@ static_assert(sizeof(jsval_layout) == sizeof(JS::Value),
/************************************************************************/
static inline JS_VALUE_CONSTEXPR jsval
INT_TO_JSVAL(int32_t i)
{
return IMPL_TO_JSVAL(INT32_TO_JSVAL_IMPL(i));
}
static inline JS_VALUE_CONSTEXPR jsval
DOUBLE_TO_JSVAL(double d)
{
@ -1967,38 +1959,10 @@ static inline JS_VALUE_CONSTEXPR jsval
UINT_TO_JSVAL(uint32_t i)
{
return i <= JSVAL_INT_MAX
? INT_TO_JSVAL((int32_t)i)
? JS::Int32Value(int32_t(i))
: DOUBLE_TO_JSVAL((double)i);
}
static inline jsval
STRING_TO_JSVAL(JSString* str)
{
return IMPL_TO_JSVAL(STRING_TO_JSVAL_IMPL(str));
}
static inline jsval
OBJECT_TO_JSVAL(JSObject* obj)
{
if (obj)
return IMPL_TO_JSVAL(OBJECT_TO_JSVAL_IMPL(obj));
return IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_NULL, 0));
}
static inline jsval
BOOLEAN_TO_JSVAL(bool b)
{
return IMPL_TO_JSVAL(BOOLEAN_TO_JSVAL_IMPL(b));
}
/* To be GC-safe, privates are tagged as doubles. */
static inline jsval
PRIVATE_TO_JSVAL(void* ptr)
{
return IMPL_TO_JSVAL(PRIVATE_PTR_TO_JSVAL_IMPL(ptr));
}
namespace JS {
extern JS_PUBLIC_DATA(const HandleValue) NullHandleValue;

View File

@ -425,6 +425,7 @@ ValidateAtomicsBuiltinFunction(JSContext* cx, AsmJSModule::Global& global, Handl
case AsmJSAtomicsBuiltin_and: native = atomics_and; break;
case AsmJSAtomicsBuiltin_or: native = atomics_or; break;
case AsmJSAtomicsBuiltin_xor: native = atomics_xor; break;
case AsmJSAtomicsBuiltin_isLockFree: native = atomics_isLockFree; break;
}
if (!IsNativeFunction(v, native))

View File

@ -77,7 +77,8 @@ enum AsmJSAtomicsBuiltinFunction
AsmJSAtomicsBuiltin_sub,
AsmJSAtomicsBuiltin_and,
AsmJSAtomicsBuiltin_or,
AsmJSAtomicsBuiltin_xor
AsmJSAtomicsBuiltin_xor,
AsmJSAtomicsBuiltin_isLockFree
};
// Set of known global object SIMD's attributes, i.e. types

View File

@ -35,6 +35,7 @@
#include "asmjs/AsmJSSignalHandlers.h"
#include "builtin/SIMD.h"
#include "frontend/Parser.h"
#include "jit/AtomicOperations.h"
#include "jit/CodeGenerator.h"
#include "jit/CompileWrappers.h"
#include "jit/MIR.h"
@ -49,6 +50,7 @@
#include "frontend/ParseNode-inl.h"
#include "frontend/Parser-inl.h"
#include "jit/AtomicOperations-inl.h"
#include "jit/MacroAssembler-inl.h"
using namespace js;
@ -1540,7 +1542,8 @@ class MOZ_STACK_CLASS ModuleCompiler
!addStandardLibraryAtomicsName("sub", AsmJSAtomicsBuiltin_sub) ||
!addStandardLibraryAtomicsName("and", AsmJSAtomicsBuiltin_and) ||
!addStandardLibraryAtomicsName("or", AsmJSAtomicsBuiltin_or) ||
!addStandardLibraryAtomicsName("xor", AsmJSAtomicsBuiltin_xor))
!addStandardLibraryAtomicsName("xor", AsmJSAtomicsBuiltin_xor) ||
!addStandardLibraryAtomicsName("isLockFree", AsmJSAtomicsBuiltin_isLockFree))
{
return false;
}
@ -4967,7 +4970,7 @@ CheckAtomicsLoad(FunctionCompiler& f, ParseNode* call, MDefinition** def, Type*
PrepareArrayIndex(f, &pointerDef, needsBoundsCheck, mask);
*def = f.atomicLoadHeap(viewType, pointerDef, needsBoundsCheck);
*type = Type::Signed;
*type = Type::Intish;
return true;
}
@ -5001,7 +5004,7 @@ CheckAtomicsStore(FunctionCompiler& f, ParseNode* call, MDefinition** def, Type*
f.atomicStoreHeap(viewType, pointerDef, rhsDef, needsBoundsCheck);
*def = rhsDef;
*type = Type::Signed;
*type = rhsType;
return true;
}
@ -5033,7 +5036,24 @@ CheckAtomicsBinop(FunctionCompiler& f, ParseNode* call, MDefinition** def, Type*
PrepareArrayIndex(f, &pointerDef, needsBoundsCheck, mask);
*def = f.atomicBinopHeap(op, viewType, pointerDef, valueArgDef, needsBoundsCheck);
*type = Type::Signed;
*type = Type::Intish;
return true;
}
static bool
CheckAtomicsIsLockFree(FunctionCompiler& f, ParseNode* call, MDefinition** def, Type* type)
{
if (CallArgListLength(call) != 1)
return f.fail(call, "Atomics.isLockFree must be passed 1 argument");
ParseNode* sizeArg = CallArgList(call);
uint32_t size;
if (!IsLiteralInt(f.m(), sizeArg, &size))
return f.fail(sizeArg, "Atomics.isLockFree requires an integer literal argument");
*def = f.constant(Int32Value(AtomicOperations::isLockfree(size)), Type::Int);
*type = Type::Int;
return true;
}
@ -5075,7 +5095,7 @@ CheckAtomicsCompareExchange(FunctionCompiler& f, ParseNode* call, MDefinition**
*def = f.atomicCompareExchangeHeap(viewType, pointerDef, oldValueArgDef, newValueArgDef,
needsBoundsCheck);
*type = Type::Signed;
*type = Type::Intish;
return true;
}
@ -5102,6 +5122,8 @@ CheckAtomicsBuiltinCall(FunctionCompiler& f, ParseNode* callNode, AsmJSAtomicsBu
return CheckAtomicsBinop(f, callNode, resultDef, resultType, AtomicFetchOrOp);
case AsmJSAtomicsBuiltin_xor:
return CheckAtomicsBinop(f, callNode, resultDef, resultType, AtomicFetchXorOp);
case AsmJSAtomicsBuiltin_isLockFree:
return CheckAtomicsIsLockFree(f, callNode, resultDef, resultType);
default:
MOZ_CRASH("unexpected atomicsBuiltin function");
}

Some files were not shown because too many files have changed in this diff Show More