mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-27 12:15:33 +00:00
Merge mozilla-central to mozilla-inbound
This commit is contained in:
commit
0c5d14bebd
@ -6410,7 +6410,7 @@
|
||||
|
||||
if (this._lastNumPinned != numPinned) {
|
||||
this._lastNumPinned = numPinned;
|
||||
this._handleTabSelect(false);
|
||||
this._handleTabSelect(true);
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
@ -6452,7 +6452,7 @@
|
||||
let tabScreenX = draggedTab.boxObject.screenX;
|
||||
let translateX = screenX - draggedTab._dragData.screenX;
|
||||
if (!pinned)
|
||||
translateX += this.mTabstrip.scrollPosition - draggedTab._dragData.scrollX;
|
||||
translateX += this.mTabstrip._scrollbox.scrollLeft - draggedTab._dragData.scrollX;
|
||||
let leftBound = leftTab.boxObject.screenX - tabScreenX;
|
||||
let rightBound = (rightTab.boxObject.screenX + rightTab.boxObject.width) -
|
||||
(tabScreenX + tabWidth);
|
||||
@ -6547,7 +6547,7 @@
|
||||
var width = this.mTabstrip.boxObject.width;
|
||||
if (width != this.mTabstripWidth) {
|
||||
this.adjustTabstrip();
|
||||
this._handleTabSelect(false);
|
||||
this._handleTabSelect(true);
|
||||
this.mTabstripWidth = width;
|
||||
this.updateSessionRestoreVisibility();
|
||||
}
|
||||
@ -6996,7 +6996,7 @@
|
||||
tab._dragData = {
|
||||
offsetX: event.screenX - window.screenX - tabOffsetX,
|
||||
offsetY: event.screenY - window.screenY,
|
||||
scrollX: this.mTabstrip.scrollPosition,
|
||||
scrollX: this.mTabstrip._scrollbox.scrollLeft,
|
||||
screenX: event.screenX
|
||||
};
|
||||
|
||||
|
@ -83,6 +83,10 @@ const clearHistory = options => {
|
||||
return sanitizer.items.history.clear(makeRange(options));
|
||||
};
|
||||
|
||||
const clearLocalStorage = async function(options) {
|
||||
Services.obs.notifyObservers(null, "extension:purge-localStorage");
|
||||
};
|
||||
|
||||
const clearPasswords = async function(options) {
|
||||
let loginManager = Services.logins;
|
||||
let yieldCounter = 0;
|
||||
@ -152,6 +156,9 @@ const doRemoval = (options, dataToRemove, extension) => {
|
||||
case "history":
|
||||
removalPromises.push(clearHistory(options));
|
||||
break;
|
||||
case "localStorage":
|
||||
removalPromises.push(clearLocalStorage(options));
|
||||
break;
|
||||
case "passwords":
|
||||
removalPromises.push(clearPasswords(options));
|
||||
break;
|
||||
@ -225,6 +232,9 @@ this.browsingData = class extends ExtensionAPI {
|
||||
removeHistory(options) {
|
||||
return doRemoval(options, {history: true});
|
||||
},
|
||||
removeLocalStorage(options) {
|
||||
return doRemoval(options, {localStorage: true});
|
||||
},
|
||||
removePasswords(options) {
|
||||
return doRemoval(options, {passwords: true});
|
||||
},
|
||||
|
@ -341,7 +341,6 @@
|
||||
"description": "Clears websites' local storage data.",
|
||||
"type": "function",
|
||||
"async": "callback",
|
||||
"unsupported": true,
|
||||
"parameters": [
|
||||
{
|
||||
"$ref": "RemovalOptions",
|
||||
|
@ -46,6 +46,7 @@ skip-if = (os == 'win' && !debug) # bug 1352668
|
||||
[browser_ext_browserAction_theme_icons.js]
|
||||
[browser_ext_browsingData_formData.js]
|
||||
[browser_ext_browsingData_history.js]
|
||||
[browser_ext_browsingData_localStorage.js]
|
||||
[browser_ext_browsingData_pluginData.js]
|
||||
[browser_ext_browsingData_serviceWorkers.js]
|
||||
[browser_ext_commands_execute_browser_action.js]
|
||||
|
@ -0,0 +1,93 @@
|
||||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
add_task(async function testLocalStorage() {
|
||||
async function background() {
|
||||
function openTabs() {
|
||||
let promise = new Promise(resolve => {
|
||||
let tabURLs = [
|
||||
"http://example.com/",
|
||||
"http://example.net/",
|
||||
];
|
||||
|
||||
let tabs;
|
||||
let waitingCount = tabURLs.length;
|
||||
|
||||
let listener = async msg => {
|
||||
if (msg !== "content-script-ready" || --waitingCount) {
|
||||
return;
|
||||
}
|
||||
browser.runtime.onMessage.removeListener(listener);
|
||||
resolve(Promise.all(tabs));
|
||||
};
|
||||
|
||||
browser.runtime.onMessage.addListener(listener);
|
||||
|
||||
tabs = tabURLs.map(url => {
|
||||
return browser.tabs.create({url: url});
|
||||
});
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
function sendMessageToTabs(tabs, message) {
|
||||
return Promise.all(
|
||||
tabs.map(tab => { return browser.tabs.sendMessage(tab.id, message); }));
|
||||
}
|
||||
|
||||
let tabs = await openTabs();
|
||||
|
||||
await sendMessageToTabs(tabs, "resetLocalStorage");
|
||||
await sendMessageToTabs(tabs, "checkLocalStorageSet");
|
||||
await browser.browsingData.removeLocalStorage({});
|
||||
await sendMessageToTabs(tabs, "checkLocalStorageCleared");
|
||||
|
||||
await sendMessageToTabs(tabs, "resetLocalStorage");
|
||||
await sendMessageToTabs(tabs, "checkLocalStorageSet");
|
||||
await browser.browsingData.remove({}, {localStorage: true});
|
||||
await sendMessageToTabs(tabs, "checkLocalStorageCleared");
|
||||
|
||||
browser.tabs.remove(tabs.map(tab => tab.id));
|
||||
|
||||
browser.test.notifyPass("done");
|
||||
}
|
||||
|
||||
function contentScript() {
|
||||
browser.runtime.onMessage.addListener(msg => {
|
||||
if (msg === "resetLocalStorage") {
|
||||
localStorage.clear();
|
||||
localStorage.setItem("test", "test");
|
||||
} else if (msg === "checkLocalStorageSet") {
|
||||
browser.test.assertEq("test", localStorage.getItem("test"));
|
||||
} else if (msg === "checkLocalStorageCleared") {
|
||||
browser.test.assertEq(null, localStorage.getItem("test"));
|
||||
}
|
||||
});
|
||||
browser.runtime.sendMessage("content-script-ready");
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background,
|
||||
manifest: {
|
||||
"permissions": ["browsingData"],
|
||||
"content_scripts": [{
|
||||
"matches": [
|
||||
"http://example.com/",
|
||||
"http://example.net/",
|
||||
],
|
||||
"js": ["content-script.js"],
|
||||
"run_at": "document_start",
|
||||
}],
|
||||
},
|
||||
files: {
|
||||
"content-script.js": contentScript,
|
||||
},
|
||||
});
|
||||
|
||||
await extension.startup();
|
||||
await extension.awaitFinish("done");
|
||||
await extension.unload();
|
||||
});
|
||||
|
@ -44,7 +44,7 @@ add_task(async function testInvalidArguments() {
|
||||
|
||||
add_task(async function testUnimplementedDataType() {
|
||||
function background() {
|
||||
browser.browsingData.remove({}, {localStorage: true});
|
||||
browser.browsingData.remove({}, {indexedDB: true});
|
||||
browser.test.sendMessage("finished");
|
||||
}
|
||||
|
||||
@ -61,6 +61,6 @@ add_task(async function testUnimplementedDataType() {
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
let warningObserved = messages.find(line => /Firefox does not support dataTypes: localStorage/.test(line));
|
||||
let warningObserved = messages.find(line => /Firefox does not support dataTypes: indexedDB/.test(line));
|
||||
ok(warningObserved, "Warning issued when calling remove with an unimplemented dataType.");
|
||||
});
|
||||
|
12
browser/extensions/formautofill/bootstrap.js
vendored
12
browser/extensions/formautofill/bootstrap.js
vendored
@ -13,6 +13,7 @@ const CACHED_STYLESHEETS = new WeakMap();
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AddonManager", "resource://gre/modules/AddonManager.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FormAutofillParent",
|
||||
"resource://formautofill/FormAutofillParent.jsm");
|
||||
|
||||
@ -40,12 +41,21 @@ function onMaybeOpenPopup(evt) {
|
||||
insertStyleSheet(domWindow, STYLESHEET_URI);
|
||||
}
|
||||
|
||||
function startup() {
|
||||
function startup(data) {
|
||||
if (Services.prefs.getStringPref("extensions.formautofill.available") != "on") {
|
||||
Services.prefs.clearUserPref("dom.forms.autocomplete.formautofill");
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.hasOwnProperty("instanceID") && data.instanceID) {
|
||||
AddonManager.addUpgradeListener(data.instanceID, (upgrade) => {
|
||||
// don't install the upgrade by doing nothing here.
|
||||
// The upgrade will be installed upon next restart.
|
||||
});
|
||||
} else {
|
||||
throw Error("no instanceID passed to bootstrap startup");
|
||||
}
|
||||
|
||||
// This pref is used for web contents to detect the autocomplete feature.
|
||||
// When it's true, "element.autocomplete" will return tokens we currently
|
||||
// support -- otherwise it'll return an empty string.
|
||||
|
@ -13,20 +13,31 @@ browser.onboarding.tour-set = "new" // for new user tour, or "update" for update
|
||||
```
|
||||
And make sure the value of `browser.onboarding.tourset-verion` and `browser.onboarding.seen-tourset-verion` are the same.
|
||||
|
||||
## How to show the onboarding notification
|
||||
|
||||
Besides above settings, notification will wait 5 minutes before showing the first notification on a new profile or the updated user profile (to not put too much information to the user at once).
|
||||
|
||||
To manually remove the mute duration, set pref `browser.onboarding.notification.mute-duration-on-first-session-ms` to `0` and notification will be shown at the next time you open `about:home` or `about:newtab`.
|
||||
|
||||
## How to show the snippets
|
||||
|
||||
Snippets (the remote notification that handled by activity stream) will only be shown after onboarding notifications are all done. You can set preference `browser.onboarding.notification.finished` to `true` to disable onboarding notification and accept snippets right away.
|
||||
|
||||
## Architecture
|
||||
|
||||
Everytime `about:home` or `about:newtab` page is opened, onboarding overlay is injected into that page.
|
||||
|
||||
`OnboardingTourType.jsm` will check the onboarding tour type (currently support `new` and `update`). Then in `onboarding.js`, All tours are defined inside of `onboardingTourset` dictionary. `getTourIDList` function will load tours from proper preferences. (Check `How to change the order of tours` section for more detail).
|
||||
|
||||
When user clicks the action button in each tour, We use [UITour](http://bedrock.readthedocs.io/en/latest/uitour.html) to highlight the correspondent browser UI element.
|
||||
When user clicks the action button in each tour, We use [UITour](http://bedrock.readthedocs.io/en/latest/uitour.html) to highlight the correspondent browser UI element. The UITour client is bundled in onboarding addon via `jar.mn`.
|
||||
|
||||
## Landing rules
|
||||
|
||||
We would apply some rules:
|
||||
|
||||
* All styles and ids should be formatted as `onboarding-*` to avoid conflict with the origin page.
|
||||
* All strings in `locales` should be formatted as `onboarding.*` for consistency.
|
||||
* To avoid conflict with the origin page, all styles and ids should be formatted as `onboarding-*`.
|
||||
* For consistency and easier filtering, all strings in `locales` should be formatted as `onboarding.*`.
|
||||
* For consistency, all related preferences should be formatted as `browser.onboarding.*`.
|
||||
* For accessibility, images that are for presentation only should have `role="presentation"` attribute.
|
||||
|
||||
## How to change the order of tours
|
||||
|
@ -85,7 +85,7 @@ function test_getUnanimatedComputedStyle() {
|
||||
}
|
||||
|
||||
addStyle([cssAnimationStyle,
|
||||
".pseudo::before { animation: cssanimation 1s; }"]);
|
||||
".pseudo::before { animation: cssanimation 1s; content: ''}"]);
|
||||
const pseudoAnimation = target => {
|
||||
target.classList.add("pseudo");
|
||||
return target.getAnimations({ subtree: true })[0];
|
||||
|
@ -3744,9 +3744,11 @@ HTMLMediaElement::LookupMediaElementURITable(nsIURI* aURI)
|
||||
// Ditto for anything else that could cause us to send different headers.
|
||||
if (NS_SUCCEEDED(elem->NodePrincipal()->Equals(NodePrincipal(), &equal)) && equal &&
|
||||
elem->mCORSMode == mCORSMode) {
|
||||
NS_ASSERTION(elem->mDecoder && elem->mDecoder->GetResource(), "Decoder gone");
|
||||
MediaResource* resource = elem->mDecoder->GetResource();
|
||||
if (resource->CanClone()) {
|
||||
// See SetupDecoder() below. We only add a element to the table when
|
||||
// mDecoder is a ChannelMediaDecoder.
|
||||
auto decoder = static_cast<ChannelMediaDecoder*>(elem->mDecoder.get());
|
||||
NS_ASSERTION(decoder, "Decoder gone");
|
||||
if (decoder->CanClone()) {
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
@ -4721,10 +4723,6 @@ HTMLMediaElement::InitializeDecoderAsClone(ChannelMediaDecoder* aOriginal)
|
||||
NS_ASSERTION(mLoadingSrc, "mLoadingSrc must already be set");
|
||||
NS_ASSERTION(mDecoder == nullptr, "Shouldn't have a decoder");
|
||||
|
||||
MediaResource* originalResource = aOriginal->GetResource();
|
||||
if (!originalResource)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
MediaDecoderInit decoderInit(this,
|
||||
mAudioChannel,
|
||||
mMuted ? 0.0 : mVolume,
|
||||
@ -4742,14 +4740,6 @@ HTMLMediaElement::InitializeDecoderAsClone(ChannelMediaDecoder* aOriginal)
|
||||
|
||||
LOG(LogLevel::Debug, ("%p Cloned decoder %p from %p", this, decoder.get(), aOriginal));
|
||||
|
||||
nsresult rv = decoder->Load(originalResource);
|
||||
if (NS_FAILED(rv)) {
|
||||
decoder->Shutdown();
|
||||
LOG(LogLevel::Debug,
|
||||
("%p Failed to load for decoder %p", this, decoder.get()));
|
||||
return rv;
|
||||
}
|
||||
|
||||
return FinishDecoderSetup(decoder);
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
namespace mozilla {
|
||||
|
||||
ChannelMediaDecoder*
|
||||
ADTSDecoder::Clone(MediaDecoderInit& aInit)
|
||||
ADTSDecoder::CloneImpl(MediaDecoderInit& aInit)
|
||||
{
|
||||
if (!IsEnabled())
|
||||
return nullptr;
|
||||
|
@ -21,12 +21,14 @@ public:
|
||||
: ChannelMediaDecoder(aInit)
|
||||
{
|
||||
}
|
||||
ChannelMediaDecoder* Clone(MediaDecoderInit& aInit) override;
|
||||
|
||||
// Returns true if the ADTS backend is pref'ed on, and we're running on a
|
||||
// platform that is likely to have decoders for the format.
|
||||
static bool IsEnabled();
|
||||
static bool IsSupportedType(const MediaContainerType& aContainerType);
|
||||
|
||||
private:
|
||||
ChannelMediaDecoder* CloneImpl(MediaDecoderInit& aInit) override;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -155,6 +155,31 @@ ChannelMediaDecoder::ChannelMediaDecoder(MediaDecoderInit& aInit)
|
||||
mResourceCallback->Connect(this);
|
||||
}
|
||||
|
||||
bool
|
||||
ChannelMediaDecoder::CanClone()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return mResource && mResource->CanClone();
|
||||
}
|
||||
|
||||
already_AddRefed<ChannelMediaDecoder>
|
||||
ChannelMediaDecoder::Clone(MediaDecoderInit& aInit)
|
||||
{
|
||||
if (!mResource) {
|
||||
return nullptr;
|
||||
}
|
||||
RefPtr<ChannelMediaDecoder> decoder = CloneImpl(aInit);
|
||||
if (!decoder) {
|
||||
return nullptr;
|
||||
}
|
||||
nsresult rv = decoder->Load(mResource);
|
||||
if (NS_FAILED(rv)) {
|
||||
decoder->Shutdown();
|
||||
return nullptr;
|
||||
}
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
MediaResource*
|
||||
ChannelMediaDecoder::GetResource() const
|
||||
{
|
||||
@ -200,7 +225,7 @@ ChannelMediaDecoder::Load(nsIChannel* aChannel,
|
||||
MOZ_ASSERT(!mResource);
|
||||
|
||||
mResource =
|
||||
MediaResource::Create(mResourceCallback, aChannel, aIsPrivateBrowsing);
|
||||
BaseMediaResource::Create(mResourceCallback, aChannel, aIsPrivateBrowsing);
|
||||
if (!mResource) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -220,7 +245,7 @@ ChannelMediaDecoder::Load(nsIChannel* aChannel,
|
||||
}
|
||||
|
||||
nsresult
|
||||
ChannelMediaDecoder::Load(MediaResource* aOriginal)
|
||||
ChannelMediaDecoder::Load(BaseMediaResource* aOriginal)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mResource);
|
||||
|
@ -15,6 +15,8 @@ class nsIStreamListener;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class BaseMediaResource;
|
||||
|
||||
class ChannelMediaDecoder : public MediaDecoder
|
||||
{
|
||||
// Used to register with MediaResource to receive notifications which will
|
||||
@ -53,7 +55,7 @@ class ChannelMediaDecoder : public MediaDecoder
|
||||
|
||||
protected:
|
||||
RefPtr<ResourceCallback> mResourceCallback;
|
||||
RefPtr<MediaResource> mResource;
|
||||
RefPtr<BaseMediaResource> mResource;
|
||||
|
||||
public:
|
||||
explicit ChannelMediaDecoder(MediaDecoderInit& aInit);
|
||||
@ -64,17 +66,19 @@ public:
|
||||
|
||||
void Shutdown() override;
|
||||
|
||||
// Create a new decoder of the same type as this one.
|
||||
// Subclasses must implement this.
|
||||
virtual ChannelMediaDecoder* Clone(MediaDecoderInit& aInit) = 0;
|
||||
bool CanClone();
|
||||
|
||||
virtual nsresult Load(nsIChannel* aChannel,
|
||||
bool aIsPrivateBrowsing,
|
||||
nsIStreamListener** aStreamListener);
|
||||
virtual nsresult Load(MediaResource* aOriginal);
|
||||
// Create a new decoder of the same type as this one.
|
||||
already_AddRefed<ChannelMediaDecoder> Clone(MediaDecoderInit& aInit);
|
||||
|
||||
nsresult Load(nsIChannel* aChannel,
|
||||
bool aIsPrivateBrowsing,
|
||||
nsIStreamListener** aStreamListener);
|
||||
|
||||
private:
|
||||
virtual ChannelMediaDecoder* CloneImpl(MediaDecoderInit& aInit) = 0;
|
||||
nsresult OpenResource(nsIStreamListener** aStreamListener);
|
||||
nsresult Load(BaseMediaResource* aOriginal);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -642,7 +642,8 @@ bool ChannelMediaResource::CanClone()
|
||||
return mCacheStream.IsAvailableForSharing();
|
||||
}
|
||||
|
||||
already_AddRefed<MediaResource> ChannelMediaResource::CloneData(MediaResourceCallback* aCallback)
|
||||
already_AddRefed<BaseMediaResource>
|
||||
ChannelMediaResource::CloneData(MediaResourceCallback* aCallback)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
||||
NS_ASSERTION(mCacheStream.IsAvailableForSharing(), "Stream can't be cloned");
|
||||
@ -1413,9 +1414,10 @@ int64_t FileMediaResource::Tell()
|
||||
return offset;
|
||||
}
|
||||
|
||||
already_AddRefed<MediaResource>
|
||||
MediaResource::Create(MediaResourceCallback* aCallback,
|
||||
nsIChannel* aChannel, bool aIsPrivateBrowsing)
|
||||
already_AddRefed<BaseMediaResource>
|
||||
BaseMediaResource::Create(MediaResourceCallback* aCallback,
|
||||
nsIChannel* aChannel,
|
||||
bool aIsPrivateBrowsing)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(),
|
||||
"MediaResource::Open called on non-main thread");
|
||||
@ -1434,7 +1436,7 @@ MediaResource::Create(MediaResourceCallback* aCallback,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<MediaResource> resource;
|
||||
RefPtr<BaseMediaResource> resource;
|
||||
|
||||
// Let's try to create a FileMediaResource in case the channel is a nsIFile
|
||||
nsCOMPtr<nsIFileChannel> fc = do_QueryInterface(aChannel);
|
||||
|
@ -174,20 +174,6 @@ public:
|
||||
virtual void Resume() = 0;
|
||||
// Get the current principal for the channel
|
||||
virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal() = 0;
|
||||
// If this returns false, then we shouldn't try to clone this MediaResource
|
||||
// because its underlying resources are not suitable for reuse (e.g.
|
||||
// because the underlying connection has been lost, or this resource
|
||||
// just can't be safely cloned). If this returns true, CloneData could
|
||||
// still fail. If this returns false, CloneData should not be called.
|
||||
virtual bool CanClone() { return false; }
|
||||
// Create a new stream of the same type that refers to the same URI
|
||||
// with a new channel. Any cached data associated with the original
|
||||
// stream should be accessible in the new stream too.
|
||||
virtual already_AddRefed<MediaResource> CloneData(
|
||||
MediaResourceCallback* aCallback)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// These methods are called off the main thread.
|
||||
// The mode is initially MODE_PLAYBACK.
|
||||
@ -294,14 +280,6 @@ public:
|
||||
// requests are supported by the connection/server.
|
||||
virtual bool IsTransportSeekable() = 0;
|
||||
|
||||
/**
|
||||
* Create a resource, reading data from the channel. Call on main thread only.
|
||||
* The caller must follow up by calling resource->Open().
|
||||
*/
|
||||
static already_AddRefed<MediaResource>
|
||||
Create(MediaResourceCallback* aCallback,
|
||||
nsIChannel* aChannel, bool aIsPrivateBrowsing);
|
||||
|
||||
/**
|
||||
* Open the stream. This creates a stream listener and returns it in
|
||||
* aStreamListener; this listener needs to be notified of incoming data.
|
||||
@ -338,6 +316,31 @@ private:
|
||||
|
||||
class BaseMediaResource : public MediaResource {
|
||||
public:
|
||||
/**
|
||||
* Create a resource, reading data from the channel. Call on main thread only.
|
||||
* The caller must follow up by calling resource->Open().
|
||||
*/
|
||||
static already_AddRefed<BaseMediaResource> Create(
|
||||
MediaResourceCallback* aCallback,
|
||||
nsIChannel* aChannel,
|
||||
bool aIsPrivateBrowsing);
|
||||
|
||||
// If this returns false, then we shouldn't try to clone this MediaResource
|
||||
// because its underlying resources are not suitable for reuse (e.g.
|
||||
// because the underlying connection has been lost, or this resource
|
||||
// just can't be safely cloned). If this returns true, CloneData could
|
||||
// still fail. If this returns false, CloneData should not be called.
|
||||
virtual bool CanClone() { return false; }
|
||||
|
||||
// Create a new stream of the same type that refers to the same URI
|
||||
// with a new channel. Any cached data associated with the original
|
||||
// stream should be accessible in the new stream too.
|
||||
virtual already_AddRefed<BaseMediaResource> CloneData(
|
||||
MediaResourceCallback* aCallback)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SetLoadInBackground(bool aLoadInBackground) override;
|
||||
|
||||
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override
|
||||
@ -497,7 +500,8 @@ public:
|
||||
// Return true if the stream has been closed.
|
||||
bool IsClosed() const { return mCacheStream.IsClosed(); }
|
||||
bool CanClone() override;
|
||||
already_AddRefed<MediaResource> CloneData(MediaResourceCallback* aDecoder) override;
|
||||
already_AddRefed<BaseMediaResource> CloneData(
|
||||
MediaResourceCallback* aDecoder) override;
|
||||
nsresult ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount) override;
|
||||
void EnsureCacheUpToDate() override;
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
namespace mozilla {
|
||||
|
||||
ChannelMediaDecoder*
|
||||
FlacDecoder::Clone(MediaDecoderInit& aInit)
|
||||
FlacDecoder::CloneImpl(MediaDecoderInit& aInit)
|
||||
{
|
||||
if (!IsEnabled()) {
|
||||
return nullptr;
|
||||
|
@ -21,12 +21,14 @@ public:
|
||||
: ChannelMediaDecoder(aInit)
|
||||
{
|
||||
}
|
||||
ChannelMediaDecoder* Clone(MediaDecoderInit& aInit) override;
|
||||
|
||||
// Returns true if the Flac backend is pref'ed on, and we're running on a
|
||||
// platform that is likely to have decoders for the format.
|
||||
static bool IsEnabled();
|
||||
static bool IsSupportedType(const MediaContainerType& aContainerType);
|
||||
|
||||
private:
|
||||
ChannelMediaDecoder* CloneImpl(MediaDecoderInit& aInit) override;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -20,14 +20,6 @@ class MP4Decoder : public ChannelMediaDecoder
|
||||
public:
|
||||
explicit MP4Decoder(MediaDecoderInit& aInit);
|
||||
|
||||
ChannelMediaDecoder* Clone(MediaDecoderInit& aInit) override
|
||||
{
|
||||
if (!IsEnabled()) {
|
||||
return nullptr;
|
||||
}
|
||||
return new MP4Decoder(aInit);
|
||||
}
|
||||
|
||||
// Returns true if aContainerType is an MP4 type that we think we can render
|
||||
// with the a platform decoder backend.
|
||||
// If provided, codecs are checked for support.
|
||||
@ -51,6 +43,15 @@ public:
|
||||
IsVideoAccelerated(layers::KnowsCompositor* aKnowsCompositor, nsIGlobalObject* aParent);
|
||||
|
||||
void GetMozDebugReaderData(nsACString& aString) override;
|
||||
|
||||
private:
|
||||
ChannelMediaDecoder* CloneImpl(MediaDecoderInit& aInit) override
|
||||
{
|
||||
if (!IsEnabled()) {
|
||||
return nullptr;
|
||||
}
|
||||
return new MP4Decoder(aInit);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -14,7 +14,7 @@
|
||||
namespace mozilla {
|
||||
|
||||
ChannelMediaDecoder*
|
||||
MP3Decoder::Clone(MediaDecoderInit& aInit)
|
||||
MP3Decoder::CloneImpl(MediaDecoderInit& aInit)
|
||||
{
|
||||
if (!IsEnabled()) {
|
||||
return nullptr;
|
||||
|
@ -20,12 +20,14 @@ public:
|
||||
: ChannelMediaDecoder(aInit)
|
||||
{
|
||||
}
|
||||
ChannelMediaDecoder* Clone(MediaDecoderInit& aInit) override;
|
||||
|
||||
// Returns true if the MP3 backend is preffed on, and we're running on a
|
||||
// platform that is likely to have decoders for the format.
|
||||
static bool IsEnabled();
|
||||
static bool IsSupportedType(const MediaContainerType& aContainerType);
|
||||
|
||||
private:
|
||||
ChannelMediaDecoder* CloneImpl(MediaDecoderInit& aInit) override;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -19,19 +19,21 @@ public:
|
||||
: ChannelMediaDecoder(aInit)
|
||||
{}
|
||||
|
||||
ChannelMediaDecoder* Clone(MediaDecoderInit& aInit) override
|
||||
{
|
||||
if (!IsOggEnabled()) {
|
||||
return nullptr;
|
||||
}
|
||||
return new OggDecoder(aInit);
|
||||
}
|
||||
MediaDecoderStateMachine* CreateStateMachine() override;
|
||||
|
||||
// Returns true if aContainerType is an Ogg type that we think we can render
|
||||
// with an enabled platform decoder backend.
|
||||
// If provided, codecs are checked for support.
|
||||
static bool IsSupportedType(const MediaContainerType& aContainerType);
|
||||
|
||||
private:
|
||||
ChannelMediaDecoder* CloneImpl(MediaDecoderInit& aInit) override
|
||||
{
|
||||
if (!IsOggEnabled()) {
|
||||
return nullptr;
|
||||
}
|
||||
return new OggDecoder(aInit);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -12,7 +12,7 @@
|
||||
namespace mozilla {
|
||||
|
||||
ChannelMediaDecoder*
|
||||
WaveDecoder::Clone(MediaDecoderInit& aInit)
|
||||
WaveDecoder::CloneImpl(MediaDecoderInit& aInit)
|
||||
{
|
||||
return new WaveDecoder(aInit);
|
||||
}
|
||||
|
@ -20,11 +20,13 @@ public:
|
||||
: ChannelMediaDecoder(aInit)
|
||||
{
|
||||
}
|
||||
ChannelMediaDecoder* Clone(MediaDecoderInit& aInit) override;
|
||||
|
||||
// Returns true if the Wave backend is pref'ed on, and we're running on a
|
||||
// platform that is likely to have decoders for the format.
|
||||
static bool IsSupportedType(const MediaContainerType& aContainerType);
|
||||
|
||||
private:
|
||||
ChannelMediaDecoder* CloneImpl(MediaDecoderInit& aInit) override;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -19,13 +19,6 @@ public:
|
||||
: ChannelMediaDecoder(aInit)
|
||||
{
|
||||
}
|
||||
ChannelMediaDecoder* Clone(MediaDecoderInit& aInit) override
|
||||
{
|
||||
if (!IsWebMEnabled()) {
|
||||
return nullptr;
|
||||
}
|
||||
return new WebMDecoder(aInit);
|
||||
}
|
||||
|
||||
// Returns true if aContainerType is a WebM type that we think we can render
|
||||
// with an enabled platform decoder backend.
|
||||
@ -33,6 +26,15 @@ public:
|
||||
static bool IsSupportedType(const MediaContainerType& aContainerType);
|
||||
|
||||
void GetMozDebugReaderData(nsACString& aString) override;
|
||||
|
||||
private:
|
||||
ChannelMediaDecoder* CloneImpl(MediaDecoderInit& aInit) override
|
||||
{
|
||||
if (!IsWebMEnabled()) {
|
||||
return nullptr;
|
||||
}
|
||||
return new WebMDecoder(aInit);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -386,7 +386,8 @@ LocalStorageManager::Observe(const char* aTopic,
|
||||
}
|
||||
|
||||
// Clear everything, caches + database
|
||||
if (!strcmp(aTopic, "cookie-cleared")) {
|
||||
if (!strcmp(aTopic, "cookie-cleared") ||
|
||||
!strcmp(aTopic, "extension:purge-localStorage-caches")) {
|
||||
ClearCaches(LocalStorageCache::kUnloadComplete, pattern, EmptyCString());
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -66,6 +66,7 @@ StorageObserver::Init()
|
||||
obs->AddObserver(sSelf, "browser:purge-domain-data", true);
|
||||
obs->AddObserver(sSelf, "last-pb-context-exited", true);
|
||||
obs->AddObserver(sSelf, "clear-origin-attributes-data", true);
|
||||
obs->AddObserver(sSelf, "extension:purge-localStorage", true);
|
||||
|
||||
// Shutdown
|
||||
obs->AddObserver(sSelf, "profile-after-change", true);
|
||||
@ -252,6 +253,17 @@ StorageObserver::Observe(nsISupports* aSubject,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!strcmp(aTopic, "extension:purge-localStorage")) {
|
||||
StorageDBBridge* db = LocalStorageCache::StartDatabase();
|
||||
NS_ENSURE_TRUE(db, NS_ERROR_FAILURE);
|
||||
|
||||
db->AsyncClearAll();
|
||||
|
||||
Notify("extension:purge-localStorage-caches");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Clear everything (including so and pb data) from caches and database
|
||||
// for the gived domain and subdomains.
|
||||
if (!strcmp(aTopic, "browser:purge-domain-data")) {
|
||||
|
@ -239,7 +239,11 @@ HTMLEditor::CreateAnonymousElement(nsIAtom* aTag,
|
||||
// Must style the new element, otherwise the PostRecreateFramesFor call
|
||||
// below will do nothing.
|
||||
if (ServoStyleSet* styleSet = ps->StyleSet()->GetAsServo()) {
|
||||
styleSet->StyleNewSubtree(newContent);
|
||||
// Sometimes editor likes to append anonymous content to elements
|
||||
// in display:none subtrees, so avoid styling in those cases.
|
||||
if (styleSet->MayTraverseFrom(newContent)) {
|
||||
styleSet->StyleNewSubtree(newContent);
|
||||
}
|
||||
}
|
||||
|
||||
ElementDeletionObserver* observer =
|
||||
|
@ -828,8 +828,30 @@ nsFrame::GetOffsets(int32_t &aStart, int32_t &aEnd) const
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
static void
|
||||
CompareLayers(const nsStyleImageLayers* aFirstLayers,
|
||||
const nsStyleImageLayers* aSecondLayers,
|
||||
const std::function<void(imgRequestProxy* aReq)>& aCallback)
|
||||
{
|
||||
NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, (*aFirstLayers)) {
|
||||
const nsStyleImage& image = aFirstLayers->mLayers[i].mImage;
|
||||
if (image.GetType() != eStyleImageType_Image || !image.IsResolved()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// aCallback is called when the style image in aFirstLayers is thought to
|
||||
// be different with the corresponded one in aSecondLayers
|
||||
if (!aSecondLayers || i >= aSecondLayers->mImageCount ||
|
||||
(!aSecondLayers->mLayers[i].mImage.IsResolved() ||
|
||||
!image.ImageDataEquals(aSecondLayers->mLayers[i].mImage))) {
|
||||
if (imgRequestProxy* req = image.GetImageData()) {
|
||||
aCallback(req);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
AddAndRemoveImageAssociations(nsFrame* aFrame,
|
||||
const nsStyleImageLayers* aOldLayers,
|
||||
const nsStyleImageLayers* aNewLayers)
|
||||
@ -845,43 +867,17 @@ AddAndRemoveImageAssociations(nsFrame* aFrame,
|
||||
// to clear those notifiers unless we have to. (They'll be reset
|
||||
// when we paint, although we could miss a notification in that
|
||||
// interval.)
|
||||
|
||||
if (aOldLayers) {
|
||||
NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, (*aOldLayers)) {
|
||||
const nsStyleImage& oldImage = aOldLayers->mLayers[i].mImage;
|
||||
if (oldImage.GetType() != eStyleImageType_Image ||
|
||||
!oldImage.IsResolved()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If there is an image in oldBG that's not in newBG, drop it.
|
||||
if (i >= aNewLayers->mImageCount ||
|
||||
!oldImage.ImageDataEquals(aNewLayers->mLayers[i].mImage)) {
|
||||
|
||||
if (aFrame->HasImageRequest()) {
|
||||
if (imgRequestProxy* req = oldImage.GetImageData()) {
|
||||
imageLoader->DisassociateRequestFromFrame(req, aFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CompareLayers(aOldLayers, aNewLayers,
|
||||
[&imageLoader, aFrame](imgRequestProxy* aReq)
|
||||
{ imageLoader->DisassociateRequestFromFrame(aReq, aFrame); }
|
||||
);
|
||||
}
|
||||
|
||||
NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, (*aNewLayers)) {
|
||||
const nsStyleImage& newImage = aNewLayers->mLayers[i].mImage;
|
||||
if (newImage.GetType() != eStyleImageType_Image ||
|
||||
!newImage.IsResolved()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If there is an image in newBG that's not in oldBG, add it.
|
||||
if (!aOldLayers || i >= aOldLayers->mImageCount ||
|
||||
!newImage.ImageDataEquals(aOldLayers->mLayers[i].mImage)) {
|
||||
if (imgRequestProxy* req = newImage.GetImageData()) {
|
||||
imageLoader->AssociateRequestToFrame(req, aFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
CompareLayers(aNewLayers, aOldLayers,
|
||||
[&imageLoader, aFrame](imgRequestProxy* aReq)
|
||||
{ imageLoader->AssociateRequestToFrame(aReq, aFrame); }
|
||||
);
|
||||
}
|
||||
|
||||
// Subclass hook for style post processing
|
||||
|
26
layout/style/crashtests/1387481-1-iframe.html
Normal file
26
layout/style/crashtests/1387481-1-iframe.html
Normal file
@ -0,0 +1,26 @@
|
||||
<html>
|
||||
<head>
|
||||
<script id='x'>
|
||||
try { o1 = document.getElementById('x') } catch(e) { }
|
||||
try { o2 = document.createElement('table') } catch(e) { }
|
||||
try { o3 = document.createElement('td') } catch(e) { }
|
||||
try { o5 = document.createElement('input') } catch(e) { }
|
||||
try { o6 = document.createTextNode('{\r\u2044/=+=\u06F0\u2029\u06F9a \uDC1D0\n-\v') } catch(e) { }
|
||||
try { o7 = new Image(0.167398293512524, 0.2503646329685738) } catch(e) { }
|
||||
try { o1.appendChild(o2) } catch(e) { }
|
||||
try { o2.appendChild(o3) } catch(e) { }
|
||||
try { o3.appendChild(o6) } catch(e) { }
|
||||
try { o8 = document.createRange() } catch(e) { }
|
||||
try { document.documentElement.appendChild(o7) } catch(e) { }
|
||||
try { o7.outerHTML = '<select contenteditable="true"></select>' } catch(e) { }
|
||||
try { document.documentElement.appendChild(o5) } catch(e) { }
|
||||
try { o9 = window.getSelection() } catch(e) { }
|
||||
try { o5.select() } catch(e) { }
|
||||
try { document.replaceChild(document.documentElement, document.documentElement) } catch(e) { }
|
||||
try { document.designMode = 'on' } catch(e) { }
|
||||
try { o8.selectNode(o6) } catch(e) { }
|
||||
try { o9.addRange(o8) } catch(e) { }
|
||||
try { document.execCommand('unlink', false, null) } catch(e) { }
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
13
layout/style/crashtests/1387481-1.html
Normal file
13
layout/style/crashtests/1387481-1.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="reftest-wait">
|
||||
<iframe id="f" src="1387481-1-iframe.html" onload="step()"></iframe>
|
||||
<script>
|
||||
var reloads = 3;
|
||||
function step() {
|
||||
if (--reloads) {
|
||||
f.contentWindow.location.reload();
|
||||
} else {
|
||||
document.documentElement.className = "";
|
||||
}
|
||||
}
|
||||
</script>
|
@ -198,3 +198,4 @@ load 1383981.html
|
||||
load 1383981-2.html
|
||||
load 1384824-1.html
|
||||
load 1384824-2.html
|
||||
load 1387481-1.html
|
||||
|
@ -345,7 +345,6 @@
|
||||
"description": "Clears websites' local storage data.",
|
||||
"type": "function",
|
||||
"async": "callback",
|
||||
"unsupported": true,
|
||||
"parameters": [
|
||||
{
|
||||
"$ref": "RemovalOptions",
|
||||
|
@ -5711,11 +5711,7 @@ pref("dom.webkitBlink.dirPicker.enabled", true);
|
||||
pref("dom.webkitBlink.filesystem.enabled", true);
|
||||
#endif
|
||||
|
||||
#ifdef RELEASE_OR_BETA
|
||||
pref("media.block-autoplay-until-in-foreground", false);
|
||||
#else
|
||||
pref("media.block-autoplay-until-in-foreground", true);
|
||||
#endif
|
||||
|
||||
// Is Stylo CSS support built and enabled?
|
||||
// Only define this pref if Stylo support is actually built in.
|
||||
|
@ -622,6 +622,20 @@ GetWidget(WidgetNodeType aWidgetType)
|
||||
GtkWidget* widget = sWidgetStorage[aWidgetType];
|
||||
if (!widget) {
|
||||
widget = CreateWidget(aWidgetType);
|
||||
// In GTK versions prior to 3.18, automatic invalidation of style contexts
|
||||
// for widgets was delayed until the next resize event. Gecko however,
|
||||
// typically uses the style context before the resize event runs and so an
|
||||
// explicit invalidation may be required. This is necessary if a style
|
||||
// property was retrieved before all changes were made to the style
|
||||
// context. One such situation is where gtk_button_construct_child()
|
||||
// retrieves the style property "image-spacing" during construction of the
|
||||
// GtkButton, before its parent is set to provide inheritance of ancestor
|
||||
// properties. More recent GTK versions do not need this, but do not
|
||||
// re-resolve until required and so invalidation does not trigger
|
||||
// unnecessary resolution in general.
|
||||
GtkStyleContext* style = gtk_widget_get_style_context(widget);
|
||||
gtk_style_context_invalidate(style);
|
||||
|
||||
sWidgetStorage[aWidgetType] = widget;
|
||||
}
|
||||
return widget;
|
||||
|
Loading…
Reference in New Issue
Block a user