mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge mozilla-central to b2g-inbound
This commit is contained in:
commit
1fe5e00320
2
CLOBBER
2
CLOBBER
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
96
browser/base/content/browser-trackingprotection.js
Normal file
96
browser/base/content/browser-trackingprotection.js
Normal 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();
|
||||
},
|
||||
};
|
@ -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);
|
||||
|
@ -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();
|
||||
});
|
||||
|
@ -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();
|
||||
});
|
||||
|
@ -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>
|
||||
|
@ -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">
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -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 () {}
|
||||
};
|
||||
|
@ -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">
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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 |
22
browser/themes/shared/controlcenter/tracking-protection.svg
Normal file
22
browser/themes/shared/controlcenter/tracking-protection.svg
Normal 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 |
@ -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)
|
||||
|
1
config/external/nss/nss.def
vendored
1
config/external/nss/nss.def
vendored
@ -678,6 +678,7 @@ VFY_Begin
|
||||
VFY_CreateContext
|
||||
VFY_DestroyContext
|
||||
VFY_End
|
||||
VFY_EndWithSignature
|
||||
VFY_Update
|
||||
VFY_VerifyData
|
||||
VFY_VerifyDataWithAlgorithmID
|
||||
|
@ -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 ========================================================
|
||||
|
@ -201,7 +201,7 @@ ArchiveRequest::GetFilenamesResult(JSContext* aCx,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*aValue = OBJECT_TO_JSVAL(array);
|
||||
aValue->setObject(*array);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 |
|
||||
|
@ -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);
|
||||
|
@ -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]:
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -212,7 +212,7 @@ public:
|
||||
imageInfo.mImageDataStatus = newStatus;
|
||||
}
|
||||
|
||||
void EnsureNoUninitializedImageData(TexImageTarget imageTarget, GLint level);
|
||||
bool EnsureInitializedImageData(TexImageTarget imageTarget, GLint level);
|
||||
|
||||
protected:
|
||||
TexMinFilter mMinFilter;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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 = ¤tVal.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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -184,7 +184,7 @@ private:
|
||||
|
||||
SourceBufferAppendMode mAppendMode;
|
||||
bool mUpdating;
|
||||
bool mGenerateTimestamp;
|
||||
bool mGenerateTimestamps;
|
||||
bool mIsUsingFormatReader;
|
||||
|
||||
mozilla::Atomic<bool> mActive;
|
||||
|
@ -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) { }
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
PRLogModuleInfo* GetSourceBufferResourceLog()
|
||||
{
|
||||
static PRLogModuleInfo* sLogModule;
|
||||
static PRLogModuleInfo* sLogModule = nullptr;
|
||||
if (!sLogModule) {
|
||||
sLogModule = PR_NewLogModule("SourceBufferResource");
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -2457,7 +2457,7 @@ XMLHttpRequest::GetResponse(JSContext* /* unused */,
|
||||
return;
|
||||
}
|
||||
|
||||
mStateData.mResponse = STRING_TO_JSVAL(str);
|
||||
mStateData.mResponse.setString(str);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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(),
|
||||
|
@ -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();
|
||||
};
|
||||
};
|
@ -0,0 +1,4 @@
|
||||
var worker = new Worker("myworker");
|
||||
worker.onmessage = function(e) {
|
||||
postMessage(e.data);
|
||||
};
|
@ -0,0 +1,5 @@
|
||||
onconnect = function(e) {
|
||||
e.ports[0].start();
|
||||
e.ports[0].postMessage("ack");
|
||||
self.close();
|
||||
};
|
1
dom/workers/test/serviceworkers/fetch/context/worker.js
Normal file
1
dom/workers/test/serviceworkers/fetch/context/worker.js
Normal file
@ -0,0 +1 @@
|
||||
postMessage("ack");
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
|
@ -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
69
image/LookupResult.h
Normal 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
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user