summaryrefslogtreecommitdiffstats
path: root/dom
diff options
context:
space:
mode:
Diffstat (limited to 'dom')
-rw-r--r--dom/base/DOMIntersectionObserver.cpp37
-rw-r--r--dom/base/DOMIntersectionObserver.h4
-rw-r--r--dom/base/Element.cpp81
-rw-r--r--dom/base/Element.h4
-rwxr-xr-xdom/base/File.cpp2
-rw-r--r--dom/base/FragmentOrElement.cpp8
-rw-r--r--dom/base/FragmentOrElement.h8
-rw-r--r--dom/base/Location.cpp20
-rw-r--r--dom/base/StructuredCloneHolder.cpp34
-rw-r--r--dom/base/WebSocket.cpp8
-rw-r--r--dom/base/nsContentPolicyUtils.h1
-rw-r--r--dom/base/nsDocument.cpp3
-rw-r--r--dom/base/nsFrameMessageManager.cpp5
-rw-r--r--dom/base/nsGkAtomList.h2
-rw-r--r--dom/base/nsGlobalWindow.cpp4
-rw-r--r--dom/base/nsIContentPolicy.idl2
-rw-r--r--dom/base/nsIContentPolicyBase.idl16
-rw-r--r--dom/base/nsINode.cpp20
-rw-r--r--dom/base/nsISimpleContentPolicy.idl2
-rw-r--r--dom/base/nsImageLoadingContent.cpp36
-rw-r--r--dom/base/nsImageLoadingContent.h10
-rw-r--r--dom/base/nsNodeUtils.cpp9
-rw-r--r--dom/base/nsStructuredCloneContainer.cpp2
-rw-r--r--dom/base/test/test_intersectionobservers.html59
-rw-r--r--dom/bindings/DOMJSProxyHandler.cpp4
-rw-r--r--dom/broadcastchannel/BroadcastChannel.cpp6
-rw-r--r--dom/cache/DBSchema.cpp3
-rw-r--r--dom/canvas/CanvasRenderingContext2D.cpp14
-rw-r--r--dom/canvas/CanvasRenderingContext2D.h5
-rw-r--r--dom/canvas/ImageBitmap.cpp11
-rw-r--r--dom/canvas/WebGLContextDraw.cpp21
-rw-r--r--dom/canvas/WebGLShaderValidator.cpp68
-rw-r--r--dom/canvas/WebGLShaderValidator.h6
-rwxr-xr-xdom/events/Event.cpp16
-rw-r--r--dom/fetch/InternalRequest.cpp3
-rw-r--r--dom/fetch/InternalRequest.h2
-rw-r--r--dom/fetch/Request.cpp18
-rw-r--r--dom/filesystem/tests/test_webkitdirectory.html1
-rw-r--r--dom/html/HTMLInputElement.cpp3
-rw-r--r--dom/html/HTMLMediaElement.cpp49
-rw-r--r--dom/html/HTMLMediaElement.h12
-rw-r--r--dom/indexedDB/ActorsParent.cpp35
-rw-r--r--dom/indexedDB/IDBObjectStore.cpp8
-rw-r--r--dom/indexedDB/IndexedDatabase.h4
-rw-r--r--dom/indexedDB/IndexedDatabaseInlines.h11
-rw-r--r--dom/ipc/ContentParent.cpp8
-rw-r--r--dom/ipc/StructuredCloneData.cpp4
-rw-r--r--dom/ipc/StructuredCloneData.h23
-rw-r--r--dom/media/MediaDecoder.cpp14
-rw-r--r--dom/media/MediaDecoder.h6
-rw-r--r--dom/media/MediaDecoderStateMachine.cpp15
-rw-r--r--dom/media/MediaDecoderStateMachine.h5
-rw-r--r--dom/media/PeerConnection.js17
-rw-r--r--dom/media/mediasink/DecodedStream.cpp11
-rw-r--r--dom/media/mediasink/OutputStreamManager.cpp75
-rw-r--r--dom/media/mediasink/OutputStreamManager.h35
-rw-r--r--dom/notification/Notification.cpp6
-rw-r--r--dom/performance/PerformanceNavigationTiming.cpp17
-rw-r--r--dom/plugins/base/nsPluginStreamListenerPeer.cpp18
-rw-r--r--dom/plugins/test/unit/xpcshell.ini1
-rw-r--r--dom/quota/StorageManager.cpp2
-rw-r--r--dom/security/nsCSPService.cpp5
-rw-r--r--dom/security/nsCSPUtils.cpp3
-rw-r--r--dom/security/nsContentSecurityManager.cpp8
-rw-r--r--dom/security/nsMixedContentBlocker.cpp7
-rw-r--r--dom/security/test/csp/file_nonce_redirector.sjs25
-rw-r--r--dom/security/test/csp/file_nonce_redirects.html23
-rw-r--r--dom/security/test/csp/mochitest.ini3
-rw-r--r--dom/security/test/csp/test_nonce_redirects.html47
-rw-r--r--dom/tests/mochitest/fetch/test_request.js9
-rw-r--r--dom/url/URL.cpp20
-rw-r--r--dom/webidl/Document.webidl3
-rw-r--r--dom/webidl/Element.webidl2
-rw-r--r--dom/webidl/Event.webidl2
-rw-r--r--dom/workers/RuntimeService.cpp2
-rw-r--r--dom/workers/ScriptLoader.cpp14
-rw-r--r--dom/workers/WorkerNavigator.cpp2
-rw-r--r--dom/workers/WorkerPrivate.cpp10
-rw-r--r--dom/workers/WorkerPrivate.h16
-rw-r--r--dom/workers/WorkerRunnable.cpp13
-rw-r--r--dom/workers/WorkerRunnable.h9
-rw-r--r--dom/workers/test/serviceworkers/fetch_event_worker.js23
-rw-r--r--dom/xbl/nsXBLBinding.cpp12
-rw-r--r--dom/xhr/XMLHttpRequestWorker.cpp43
84 files changed, 861 insertions, 374 deletions
diff --git a/dom/base/DOMIntersectionObserver.cpp b/dom/base/DOMIntersectionObserver.cpp
index 169c3fe7a..e39abf1a6 100644
--- a/dom/base/DOMIntersectionObserver.cpp
+++ b/dom/base/DOMIntersectionObserver.cpp
@@ -47,6 +47,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMIntersectionObserver)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallback)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mRoot)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mQueuedEntries)
+ tmp->Disconnect();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMIntersectionObserver)
@@ -184,9 +185,10 @@ DOMIntersectionObserver::Connect()
if (mConnected) {
return;
}
+ mConnected = true;
+
nsIDocument* document = mOwner->GetExtantDoc();
document->AddIntersectionObserver(this);
- mConnected = true;
}
void
@@ -202,7 +204,9 @@ DOMIntersectionObserver::Disconnect()
mObservationTargets.Clear();
if (mOwner) {
nsIDocument* document = mOwner->GetExtantDoc();
- document->RemoveIntersectionObserver(this);
+ if (document) {
+ document->RemoveIntersectionObserver(this);
+ }
}
mConnected = false;
}
@@ -248,6 +252,12 @@ EdgeInclusiveIntersection(const nsRect& aRect, const nsRect& aOtherRect)
return Some(nsRect(left, top, right - left, bottom - top));
}
+enum class BrowsingContextInfo {
+ SimilarOriginBrowsingContext,
+ DifferentOriginBrowsingContext,
+ UnknownBrowsingContext
+};
+
void
DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time)
{
@@ -359,11 +369,22 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time
}
}
- nsRect rootIntersectionRect = rootRect;
- bool isInSimilarOriginBrowsingContext = rootFrame && targetFrame &&
- CheckSimilarOrigin(root, target);
+ nsRect rootIntersectionRect;
+ BrowsingContextInfo isInSimilarOriginBrowsingContext =
+ BrowsingContextInfo::UnknownBrowsingContext;
+
+ if (rootFrame && targetFrame) {
+ rootIntersectionRect = rootRect;
+ }
+
+ if (root && target) {
+ isInSimilarOriginBrowsingContext = CheckSimilarOrigin(root, target) ?
+ BrowsingContextInfo::SimilarOriginBrowsingContext :
+ BrowsingContextInfo::DifferentOriginBrowsingContext;
+ }
- if (isInSimilarOriginBrowsingContext) {
+ if (isInSimilarOriginBrowsingContext ==
+ BrowsingContextInfo::SimilarOriginBrowsingContext) {
rootIntersectionRect.Inflate(rootMargin);
}
@@ -413,7 +434,9 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time
if (target->UpdateIntersectionObservation(this, threshold)) {
QueueIntersectionObserverEntry(
target, time,
- isInSimilarOriginBrowsingContext ? Some(rootIntersectionRect) : Nothing(),
+ isInSimilarOriginBrowsingContext ==
+ BrowsingContextInfo::DifferentOriginBrowsingContext ?
+ Nothing() : Some(rootIntersectionRect),
targetRect, intersectionRect, intersectionRatio
);
}
diff --git a/dom/base/DOMIntersectionObserver.h b/dom/base/DOMIntersectionObserver.h
index 3eb10ad38..8144fc5c5 100644
--- a/dom/base/DOMIntersectionObserver.h
+++ b/dom/base/DOMIntersectionObserver.h
@@ -101,9 +101,7 @@ protected:
class DOMIntersectionObserver final : public nsISupports,
public nsWrapperCache
{
- virtual ~DOMIntersectionObserver() {
- Disconnect();
- }
+ virtual ~DOMIntersectionObserver() { }
public:
DOMIntersectionObserver(already_AddRefed<nsPIDOMWindowInner>&& aOwner,
diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp
index 092755590..79b36a314 100644
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -1230,6 +1230,42 @@ Element::GetAttribute(const nsAString& aName, DOMString& aReturn)
}
}
+bool
+Element::ToggleAttribute(const nsAString& aName,
+ const Optional<bool>& aForce,
+ ErrorResult& aError)
+{
+ aError = nsContentUtils::CheckQName(aName, false);
+ if (aError.Failed()) {
+ return false;
+ }
+
+ nsAutoString nameToUse;
+ const nsAttrName* name = InternalGetAttrNameFromQName(aName, &nameToUse);
+ if (!name) {
+ if (aForce.WasPassed() && !aForce.Value()) {
+ return false;
+ }
+ nsCOMPtr<nsIAtom> nameAtom = NS_Atomize(nameToUse);
+ if (!nameAtom) {
+ aError.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return false;
+ }
+ aError = SetAttr(kNameSpaceID_None, nameAtom, EmptyString(), true);
+ return true;
+ }
+ if (aForce.WasPassed() && aForce.Value()) {
+ return true;
+ }
+ // Hold a strong reference here so that the atom or nodeinfo doesn't go
+ // away during UnsetAttr. If it did UnsetAttr would be left with a
+ // dangling pointer as argument without knowing it.
+ nsAttrName tmp(*name);
+
+ aError = UnsetAttr(name->NamespaceID(), name->LocalName(), true);
+ return false;
+}
+
void
Element::SetAttribute(const nsAString& aName,
const nsAString& aValue,
@@ -3912,44 +3948,55 @@ Element::ClearDataset()
slots->mDataset = nullptr;
}
-nsTArray<Element::nsDOMSlots::IntersectionObserverRegistration>*
+nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>*
Element::RegisteredIntersectionObservers()
{
nsDOMSlots* slots = DOMSlots();
return &slots->mRegisteredIntersectionObservers;
}
+enum nsPreviousIntersectionThreshold {
+ eUninitialized = -2,
+ eNonIntersecting = -1
+};
+
void
Element::RegisterIntersectionObserver(DOMIntersectionObserver* aObserver)
{
- RegisteredIntersectionObservers()->AppendElement(
- nsDOMSlots::IntersectionObserverRegistration { aObserver, -1 });
+ nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>* observers =
+ RegisteredIntersectionObservers();
+ if (observers->Contains(aObserver)) {
+ return;
+ }
+
+ // Value can be:
+ // -2: Makes sure next calculated threshold always differs, leading to a
+ // notification task being scheduled.
+ // -1: Non-intersecting.
+ // >= 0: Intersecting, valid index of aObserver->mThresholds.
+ RegisteredIntersectionObservers()->Put(aObserver, eUninitialized);
}
void
Element::UnregisterIntersectionObserver(DOMIntersectionObserver* aObserver)
{
- nsTArray<nsDOMSlots::IntersectionObserverRegistration>* observers =
+ nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>* observers =
RegisteredIntersectionObservers();
- for (uint32_t i = 0; i < observers->Length(); ++i) {
- nsDOMSlots::IntersectionObserverRegistration reg = observers->ElementAt(i);
- if (reg.observer == aObserver) {
- observers->RemoveElementAt(i);
- break;
- }
- }
+ observers->Remove(aObserver);
}
bool
Element::UpdateIntersectionObservation(DOMIntersectionObserver* aObserver, int32_t aThreshold)
{
- nsTArray<nsDOMSlots::IntersectionObserverRegistration>* observers =
+ nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>* observers =
RegisteredIntersectionObservers();
- for (auto& reg : *observers) {
- if (reg.observer == aObserver && reg.previousThreshold != aThreshold) {
- reg.previousThreshold = aThreshold;
- return true;
- }
+ if (!observers->Contains(aObserver)) {
+ return false;
+ }
+ int32_t previousThreshold = observers->Get(aObserver);
+ if (previousThreshold != aThreshold) {
+ observers->Put(aObserver, aThreshold);
+ return true;
}
return false;
}
diff --git a/dom/base/Element.h b/dom/base/Element.h
index cf1d197e2..c269ab14a 100644
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -686,6 +686,8 @@ public:
void GetAttributeNS(const nsAString& aNamespaceURI,
const nsAString& aLocalName,
nsAString& aReturn);
+ bool ToggleAttribute(const nsAString& aName, const Optional<bool>& aForce,
+ ErrorResult& aError);
void SetAttribute(const nsAString& aName, const nsAString& aValue,
ErrorResult& aError);
void SetAttributeNS(const nsAString& aNamespaceURI,
@@ -1380,7 +1382,7 @@ protected:
nsDOMTokenList* GetTokenList(nsIAtom* aAtom,
const DOMTokenListSupportedTokenArray aSupportedTokens = nullptr);
- nsTArray<nsDOMSlots::IntersectionObserverRegistration>* RegisteredIntersectionObservers();
+ nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>* RegisteredIntersectionObservers();
private:
/**
diff --git a/dom/base/File.cpp b/dom/base/File.cpp
index 8602a3064..7d86dfe8a 100755
--- a/dom/base/File.cpp
+++ b/dom/base/File.cpp
@@ -912,7 +912,7 @@ BlobImplFile::GetType(nsAString& aType)
new GetTypeRunnable(workerPrivate, this);
ErrorResult rv;
- runnable->Dispatch(rv);
+ runnable->Dispatch(Terminating, rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
}
diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp
index b22a0d4ff..fde983e7c 100644
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -608,6 +608,7 @@ FragmentOrElement::nsDOMSlots::Unlink(bool aIsXUL)
mLabelsList = nullptr;
mCustomElementData = nullptr;
mClassList = nullptr;
+ mRegisteredIntersectionObservers.Clear();
}
size_t
@@ -1359,6 +1360,13 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FragmentOrElement)
{
nsDOMSlots *slots = tmp->GetExistingDOMSlots();
if (slots) {
+ if (tmp->IsElement()) {
+ Element* elem = tmp->AsElement();
+ for (auto iter = slots->mRegisteredIntersectionObservers.Iter(); !iter.Done(); iter.Next()) {
+ DOMIntersectionObserver* observer = iter.Key();
+ observer->UnlinkTarget(*elem);
+ }
+ }
slots->Unlink(tmp->IsXULElement());
}
}
diff --git a/dom/base/FragmentOrElement.h b/dom/base/FragmentOrElement.h
index 1cd8033bb..7c74e9cd4 100644
--- a/dom/base/FragmentOrElement.h
+++ b/dom/base/FragmentOrElement.h
@@ -21,6 +21,7 @@
#include "nsIWeakReference.h" // base class
#include "nsNodeUtils.h" // class member nsNodeUtils::CloneNodeImpl
#include "nsIHTMLCollection.h"
+#include "nsDataHashtable.h"
class ContentUnbinder;
class nsContentList;
@@ -353,12 +354,7 @@ public:
/**
* Registered Intersection Observers on the element.
*/
- struct IntersectionObserverRegistration {
- DOMIntersectionObserver* observer;
- int32_t previousThreshold;
- };
-
- nsTArray<IntersectionObserverRegistration> mRegisteredIntersectionObservers;
+ nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t> mRegisteredIntersectionObservers;
};
protected:
diff --git a/dom/base/Location.cpp b/dom/base/Location.cpp
index b6b95aaa6..7b3722f09 100644
--- a/dom/base/Location.cpp
+++ b/dom/base/Location.cpp
@@ -393,6 +393,10 @@ Location::GetHost(nsAString& aHost)
NS_IMETHODIMP
Location::SetHost(const nsAString& aHost)
{
+ if (aHost.IsEmpty()) {
+ return NS_OK; // Ignore empty string
+ }
+
nsCOMPtr<nsIURI> uri;
nsresult rv = GetWritableURI(getter_AddRefs(uri));
if (NS_WARN_IF(NS_FAILED(rv) || !uri)) {
@@ -424,6 +428,10 @@ Location::GetHostname(nsAString& aHostname)
NS_IMETHODIMP
Location::SetHostname(const nsAString& aHostname)
{
+ if (aHostname.IsEmpty()) {
+ return NS_OK; // Ignore empty string
+ }
+
nsCOMPtr<nsIURI> uri;
nsresult rv = GetWritableURI(getter_AddRefs(uri));
if (NS_WARN_IF(NS_FAILED(rv) || !uri)) {
@@ -507,6 +515,10 @@ nsresult
Location::SetHrefWithBase(const nsAString& aHref, nsIURI* aBase,
bool aReplace)
{
+ if (aHref.IsEmpty()) {
+ return NS_OK; // Ignore empty string
+ }
+
nsresult result;
nsCOMPtr<nsIURI> newUri;
@@ -694,6 +706,10 @@ Location::GetProtocol(nsAString& aProtocol)
NS_IMETHODIMP
Location::SetProtocol(const nsAString& aProtocol)
{
+ if (aProtocol.IsEmpty()) {
+ return NS_OK; // Ignore empty string
+ }
+
nsCOMPtr<nsIURI> uri;
nsresult rv = GetWritableURI(getter_AddRefs(uri));
if (NS_WARN_IF(NS_FAILED(rv) || !uri)) {
@@ -747,6 +763,10 @@ Location::GetSearch(nsAString& aSearch)
NS_IMETHODIMP
Location::SetSearch(const nsAString& aSearch)
{
+ if (aSearch.IsEmpty()) {
+ return NS_OK; // Ignore empty string
+ }
+
nsresult rv = SetSearchInternal(aSearch);
if (NS_FAILED(rv)) {
return rv;
diff --git a/dom/base/StructuredCloneHolder.cpp b/dom/base/StructuredCloneHolder.cpp
index 1c27c632e..8e7cee340 100644
--- a/dom/base/StructuredCloneHolder.cpp
+++ b/dom/base/StructuredCloneHolder.cpp
@@ -1075,9 +1075,9 @@ StructuredCloneHolder::CustomReadHandler(JSContext* aCx,
return ReadFormData(aCx, aReader, aIndex, this);
}
- if (aTag == SCTAG_DOM_IMAGEBITMAP) {
- MOZ_ASSERT(mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
- mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread);
+ if (aTag == SCTAG_DOM_IMAGEBITMAP &&
+ (mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
+ mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread)) {
// Get the current global object.
// This can be null.
@@ -1087,7 +1087,9 @@ StructuredCloneHolder::CustomReadHandler(JSContext* aCx,
parent, GetSurfaces(), aIndex);
}
- if (aTag == SCTAG_DOM_WASM) {
+ if (aTag == SCTAG_DOM_WASM &&
+ (mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
+ mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread)) {
return ReadWasmModule(aCx, aIndex, this);
}
@@ -1202,9 +1204,9 @@ StructuredCloneHolder::CustomReadTransferHandler(JSContext* aCx,
return true;
}
- if (aTag == SCTAG_DOM_CANVAS) {
- MOZ_ASSERT(mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
- mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread);
+ if (aTag == SCTAG_DOM_CANVAS &&
+ (mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
+ mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread)) {
MOZ_ASSERT(aContent);
OffscreenCanvasCloneData* data =
static_cast<OffscreenCanvasCloneData*>(aContent);
@@ -1222,9 +1224,9 @@ StructuredCloneHolder::CustomReadTransferHandler(JSContext* aCx,
return true;
}
- if (aTag == SCTAG_DOM_IMAGEBITMAP) {
- MOZ_ASSERT(mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
- mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread);
+ if (aTag == SCTAG_DOM_IMAGEBITMAP &&
+ (mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
+ mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread)) {
MOZ_ASSERT(aContent);
ImageBitmapCloneData* data =
static_cast<ImageBitmapCloneData*>(aContent);
@@ -1328,9 +1330,9 @@ StructuredCloneHolder::CustomFreeTransferHandler(uint32_t aTag,
return;
}
- if (aTag == SCTAG_DOM_CANVAS) {
- MOZ_ASSERT(mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
- mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread);
+ if (aTag == SCTAG_DOM_CANVAS &&
+ (mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
+ mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread)) {
MOZ_ASSERT(aContent);
OffscreenCanvasCloneData* data =
static_cast<OffscreenCanvasCloneData*>(aContent);
@@ -1338,9 +1340,9 @@ StructuredCloneHolder::CustomFreeTransferHandler(uint32_t aTag,
return;
}
- if (aTag == SCTAG_DOM_IMAGEBITMAP) {
- MOZ_ASSERT(mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
- mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread);
+ if (aTag == SCTAG_DOM_IMAGEBITMAP &&
+ (mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
+ mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread)) {
MOZ_ASSERT(aContent);
ImageBitmapCloneData* data =
static_cast<ImageBitmapCloneData*>(aContent);
diff --git a/dom/base/WebSocket.cpp b/dom/base/WebSocket.cpp
index d85bae82b..af4b7858b 100644
--- a/dom/base/WebSocket.cpp
+++ b/dom/base/WebSocket.cpp
@@ -340,7 +340,7 @@ WebSocketImpl::PrintErrorOnConsole(const char *aBundleURI,
new PrintErrorOnConsoleRunnable(this, aBundleURI, aError, aFormatStrings,
aFormatStringsLen);
ErrorResult rv;
- runnable->Dispatch(rv);
+ runnable->Dispatch(Killing, rv);
// XXXbz this seems totally broken. We should be propagating this out, but
// none of our callers really propagate anything usefully. Come to think of
// it, why is this a syncrunnable anyway? Can't this be a fire-and-forget
@@ -629,7 +629,7 @@ WebSocketImpl::Disconnect()
RefPtr<DisconnectInternalRunnable> runnable =
new DisconnectInternalRunnable(this);
ErrorResult rv;
- runnable->Dispatch(rv);
+ runnable->Dispatch(Killing, rv);
// XXXbz this seems totally broken. We should be propagating this out, but
// where to, exactly?
rv.SuppressException();
@@ -1293,7 +1293,7 @@ WebSocket::ConstructorCommon(const GlobalObject& aGlobal,
new InitRunnable(webSocketImpl, !!aTransportProvider, aUrl,
protocolArray, nsDependentCString(file.get()), lineno,
column, aRv, &connectionFailed);
- runnable->Dispatch(aRv);
+ runnable->Dispatch(Terminating, aRv);
}
if (NS_WARN_IF(aRv.Failed())) {
@@ -1377,7 +1377,7 @@ WebSocket::ConstructorCommon(const GlobalObject& aGlobal,
"not yet implemented");
RefPtr<AsyncOpenRunnable> runnable =
new AsyncOpenRunnable(webSocket->mImpl, aRv);
- runnable->Dispatch(aRv);
+ runnable->Dispatch(Terminating, aRv);
}
if (NS_WARN_IF(aRv.Failed())) {
diff --git a/dom/base/nsContentPolicyUtils.h b/dom/base/nsContentPolicyUtils.h
index ed0544226..600b24c56 100644
--- a/dom/base/nsContentPolicyUtils.h
+++ b/dom/base/nsContentPolicyUtils.h
@@ -134,6 +134,7 @@ NS_CP_ContentTypeName(uint32_t contentType)
CASE_RETURN( TYPE_INTERNAL_IMAGE_FAVICON );
CASE_RETURN( TYPE_INTERNAL_STYLESHEET );
CASE_RETURN( TYPE_INTERNAL_STYLESHEET_PRELOAD );
+ CASE_RETURN( TYPE_SAVEAS_DOWNLOAD );
default:
return "<Unknown Type>";
}
diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
index fd3b52948..8acfd901a 100644
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -12507,7 +12507,8 @@ nsDocument::ScheduleIntersectionObserverNotification()
void
nsDocument::NotifyIntersectionObservers()
{
- for (const auto& observer : mIntersectionObservers) {
+ nsTArray<RefPtr<DOMIntersectionObserver>> observers(mIntersectionObservers);
+ for (const auto& observer : observers) {
observer->Notify();
}
}
diff --git a/dom/base/nsFrameMessageManager.cpp b/dom/base/nsFrameMessageManager.cpp
index 049bc0a1a..6fffd376b 100644
--- a/dom/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -271,10 +271,10 @@ BuildClonedMessageData(typename BlobTraits<Flavor>::ConcreteContentManagerType*
ClonedMessageData& aClonedData)
{
SerializedStructuredCloneBuffer& buffer = aClonedData.data();
- auto iter = aData.Data().Iter();
+ auto iter = aData.Data().Start();
size_t size = aData.Data().Size();
bool success;
- buffer.data = aData.Data().Borrow<js::SystemAllocPolicy>(iter, size, &success);
+ buffer.data = aData.Data().Borrow(iter, size, &success);
if (NS_WARN_IF(!success)) {
return false;
}
@@ -1286,6 +1286,7 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
if (aRetVal) {
ErrorResult rv;
StructuredCloneData* data = aRetVal->AppendElement();
+ data->InitScope(JS::StructuredCloneScope::DifferentProcess);
data->Write(cx, rval, rv);
if (NS_WARN_IF(rv.Failed())) {
aRetVal->RemoveElementAt(aRetVal->Length() - 1);
diff --git a/dom/base/nsGkAtomList.h b/dom/base/nsGkAtomList.h
index 50b4449ec..8fefa0e02 100644
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -2240,6 +2240,7 @@ GK_ATOM(windows_accent_color_applies, "windows-accent-color-applies")
GK_ATOM(windows_accent_color_is_dark, "windows-accent-color-is-dark")
GK_ATOM(windows_default_theme, "windows-default-theme")
GK_ATOM(mac_graphite_theme, "mac-graphite-theme")
+GK_ATOM(mac_lion_theme, "mac-lion-theme")
GK_ATOM(mac_yosemite_theme, "mac-yosemite-theme")
GK_ATOM(windows_compositor, "windows-compositor")
GK_ATOM(windows_glass, "windows-glass")
@@ -2271,6 +2272,7 @@ GK_ATOM(_moz_windows_accent_color_applies, "-moz-windows-accent-color-applies")
GK_ATOM(_moz_windows_accent_color_is_dark, "-moz-windows-accent-color-is-dark")
GK_ATOM(_moz_windows_default_theme, "-moz-windows-default-theme")
GK_ATOM(_moz_mac_graphite_theme, "-moz-mac-graphite-theme")
+GK_ATOM(_moz_mac_lion_theme, "-moz-mac-lion-theme")
GK_ATOM(_moz_mac_yosemite_theme, "-moz-mac-yosemite-theme")
GK_ATOM(_moz_windows_compositor, "-moz-windows-compositor")
GK_ATOM(_moz_windows_classic, "-moz-windows-classic")
diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp
index 4e384c4d2..884ad69ca 100644
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -14633,7 +14633,9 @@ nsGlobalWindow::NotifyDefaultButtonLoaded(Element& aDefaultButton,
return;
}
LayoutDeviceIntRect buttonRect =
- LayoutDeviceIntRect::FromUnknownRect(frame->GetScreenRect());
+ LayoutDeviceIntRect::FromAppUnitsToNearest(
+ frame->GetScreenRectInAppUnits(),
+ frame->PresContext()->AppUnitsPerDevPixel());
// Get the widget rect in screen coordinates.
nsIWidget *widget = GetNearestWidget();
diff --git a/dom/base/nsIContentPolicy.idl b/dom/base/nsIContentPolicy.idl
index a73565a9a..200b97fbc 100644
--- a/dom/base/nsIContentPolicy.idl
+++ b/dom/base/nsIContentPolicy.idl
@@ -20,7 +20,7 @@ interface nsIPrincipal;
* by launching a dialog to prompt the user for something).
*/
-[scriptable,uuid(caad4f1f-d047-46ac-ae9d-dc598e4fb91b)]
+[scriptable,uuid(64a5ae16-6836-475c-9938-4b6cc1eee8fb)]
interface nsIContentPolicy : nsIContentPolicyBase
{
/**
diff --git a/dom/base/nsIContentPolicyBase.idl b/dom/base/nsIContentPolicyBase.idl
index 884e3d96d..908e562a8 100644
--- a/dom/base/nsIContentPolicyBase.idl
+++ b/dom/base/nsIContentPolicyBase.idl
@@ -24,7 +24,7 @@ typedef unsigned long nsContentPolicyType;
* by launching a dialog to prompt the user for something).
*/
-[scriptable,uuid(17418187-d86f-48dd-92d1-238838df0a4e)]
+[scriptable,uuid(d6ab1d11-8e24-4db4-8582-c40a78281737)]
interface nsIContentPolicyBase : nsISupports
{
/**
@@ -329,11 +329,17 @@ interface nsIContentPolicyBase : nsISupports
*/
const nsContentPolicyType TYPE_INTERNAL_IMAGE_FAVICON = 41;
+ /**
+ * Indicates an save-as link download from the front-end code.
+ */
+ const nsContentPolicyType TYPE_SAVEAS_DOWNLOAD = 42;
+
/* When adding new content types, please update nsContentBlocker,
- * NS_CP_ContentTypeName, nsCSPContext, all nsIContentPolicy
- * implementations, the static_assert in dom/cache/DBSchema.cpp,
- * and other things that are not listed here that are related to
- * nsIContentPolicy. */
+ * NS_CP_ContentTypeName, nsCSPContext, CSP_ContentTypeToDirective,
+ * DoContentSecurityChecks, all nsIContentPolicy implementations, the
+ * static_assert in dom/cache/DBSchema.cpp, nsPermissionManager.cpp,
+ * and other things that are not listed here that are related
+ * to nsIContentPolicy. */
//////////////////////////////////////////////////////////////////////
diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp
index 715ca93ea..09e848710 100644
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -1777,8 +1777,8 @@ nsINode::Before(const Sequence<OwningNodeOrString>& aNodes,
nsCOMPtr<nsINode> viablePreviousSibling =
FindViablePreviousSibling(*this, aNodes);
- nsCOMPtr<nsINode> node =
- ConvertNodesOrStringsIntoNode(aNodes, OwnerDoc(), aRv);
+ nsCOMPtr<nsIDocument> doc = OwnerDoc();
+ nsCOMPtr<nsINode> node = ConvertNodesOrStringsIntoNode(aNodes, doc, aRv);
if (aRv.Failed()) {
return;
}
@@ -1800,8 +1800,8 @@ nsINode::After(const Sequence<OwningNodeOrString>& aNodes,
nsCOMPtr<nsINode> viableNextSibling = FindViableNextSibling(*this, aNodes);
- nsCOMPtr<nsINode> node =
- ConvertNodesOrStringsIntoNode(aNodes, OwnerDoc(), aRv);
+ nsCOMPtr<nsIDocument> doc = OwnerDoc();
+ nsCOMPtr<nsINode> node = ConvertNodesOrStringsIntoNode(aNodes, doc, aRv);
if (aRv.Failed()) {
return;
}
@@ -1820,8 +1820,8 @@ nsINode::ReplaceWith(const Sequence<OwningNodeOrString>& aNodes,
nsCOMPtr<nsINode> viableNextSibling = FindViableNextSibling(*this, aNodes);
- nsCOMPtr<nsINode> node =
- ConvertNodesOrStringsIntoNode(aNodes, OwnerDoc(), aRv);
+ nsCOMPtr<nsIDocument> doc = OwnerDoc();
+ nsCOMPtr<nsINode> node = ConvertNodesOrStringsIntoNode(aNodes, doc, aRv);
if (aRv.Failed()) {
return;
}
@@ -1880,8 +1880,8 @@ void
nsINode::Prepend(const Sequence<OwningNodeOrString>& aNodes,
ErrorResult& aRv)
{
- nsCOMPtr<nsINode> node =
- ConvertNodesOrStringsIntoNode(aNodes, OwnerDoc(), aRv);
+ nsCOMPtr<nsIDocument> doc = OwnerDoc();
+ nsCOMPtr<nsINode> node = ConvertNodesOrStringsIntoNode(aNodes, doc, aRv);
if (aRv.Failed()) {
return;
}
@@ -1894,8 +1894,8 @@ void
nsINode::Append(const Sequence<OwningNodeOrString>& aNodes,
ErrorResult& aRv)
{
- nsCOMPtr<nsINode> node =
- ConvertNodesOrStringsIntoNode(aNodes, OwnerDoc(), aRv);
+ nsCOMPtr<nsIDocument> doc = OwnerDoc();
+ nsCOMPtr<nsINode> node = ConvertNodesOrStringsIntoNode(aNodes, doc, aRv);
if (aRv.Failed()) {
return;
}
diff --git a/dom/base/nsISimpleContentPolicy.idl b/dom/base/nsISimpleContentPolicy.idl
index 493aee1a5..dc0474736 100644
--- a/dom/base/nsISimpleContentPolicy.idl
+++ b/dom/base/nsISimpleContentPolicy.idl
@@ -28,7 +28,7 @@ interface nsIDOMElement;
* by launching a dialog to prompt the user for something).
*/
-[scriptable,uuid(b9df71e3-a9b3-4706-b2d5-e6c0d3d68ec7)]
+[scriptable,uuid(1553a476-8a14-410b-8ecc-47f48e937392)]
interface nsISimpleContentPolicy : nsIContentPolicyBase
{
/**
diff --git a/dom/base/nsImageLoadingContent.cpp b/dom/base/nsImageLoadingContent.cpp
index d25dd6319..0c6c37b44 100644
--- a/dom/base/nsImageLoadingContent.cpp
+++ b/dom/base/nsImageLoadingContent.cpp
@@ -94,8 +94,7 @@ nsImageLoadingContent::nsImageLoadingContent()
mNewRequestsWillNeedAnimationReset(false),
mStateChangerDepth(0),
mCurrentRequestRegistered(false),
- mPendingRequestRegistered(false),
- mFrameCreateCalled(false)
+ mPendingRequestRegistered(false)
{
if (!nsContentUtils::GetImgLoaderForChannel(nullptr, nullptr)) {
mLoadingEnabled = false;
@@ -489,10 +488,8 @@ nsImageLoadingContent::FrameCreated(nsIFrame* aFrame)
{
NS_ASSERTION(aFrame, "aFrame is null");
- mFrameCreateCalled = true;
-
- TrackImage(mCurrentRequest);
- TrackImage(mPendingRequest);
+ TrackImage(mCurrentRequest, aFrame);
+ TrackImage(mPendingRequest, aFrame);
// We need to make sure that our image request is registered, if it should
// be registered.
@@ -513,8 +510,6 @@ nsImageLoadingContent::FrameDestroyed(nsIFrame* aFrame)
{
NS_ASSERTION(aFrame, "aFrame is null");
- mFrameCreateCalled = false;
-
// We need to make sure that our image request is deregistered.
nsPresContext* presContext = GetFramePresContext();
if (mCurrentRequest) {
@@ -1486,7 +1481,8 @@ nsImageLoadingContent::OnVisibilityChange(Visibility aNewVisibility,
}
void
-nsImageLoadingContent::TrackImage(imgIRequest* aImage)
+nsImageLoadingContent::TrackImage(imgIRequest* aImage,
+ nsIFrame* aFrame /*= nullptr */)
{
if (!aImage)
return;
@@ -1499,13 +1495,21 @@ nsImageLoadingContent::TrackImage(imgIRequest* aImage)
return;
}
- // We only want to track this request if we're visible. Ordinarily we check
- // the visible count, but that requires a frame; in cases where
- // GetOurPrimaryFrame() cannot obtain a frame (e.g. <feImage>), we assume
- // we're visible if FrameCreated() was called.
- nsIFrame* frame = GetOurPrimaryFrame();
- if ((frame && frame->GetVisibility() == Visibility::APPROXIMATELY_NONVISIBLE) ||
- (!frame && !mFrameCreateCalled)) {
+ if (!aFrame) {
+ aFrame = GetOurPrimaryFrame();
+ }
+
+ /* This line is deceptively simple. It hides a lot of subtlety. Before we
+ * create an nsImageFrame we call nsImageFrame::ShouldCreateImageFrameFor
+ * to determine if we should create an nsImageFrame or create a frame based
+ * on the display of the element (ie inline, block, etc). Inline, block, etc
+ * frames don't register for visibility tracking so they will return UNTRACKED
+ * from GetVisibility(). So this line is choosing to mark such images as
+ * visible. Once the image loads we will get an nsImageFrame and the proper
+ * visibility. This is a pitfall of tracking the visibility on the frames
+ * instead of the content node.
+ */
+ if (!aFrame || aFrame->GetVisibility() == Visibility::APPROXIMATELY_NONVISIBLE) {
return;
}
diff --git a/dom/base/nsImageLoadingContent.h b/dom/base/nsImageLoadingContent.h
index 85db2bd2c..5f7daff72 100644
--- a/dom/base/nsImageLoadingContent.h
+++ b/dom/base/nsImageLoadingContent.h
@@ -364,6 +364,11 @@ protected:
*
* No-op if aImage is null.
*
+ * @param aFrame If called from FrameCreated the frame passed to FrameCreated.
+ * This is our frame, but at the time of the FrameCreated call
+ * our primary frame pointer hasn't been set yet, so this is
+ * only way to get our frame.
+ *
* @param aNonvisibleAction A requested action if the frame has become
* nonvisible. If Nothing(), no action is
* requested. If DISCARD_IMAGES is specified, the
@@ -371,7 +376,7 @@ protected:
* associated with to discard their surfaces if
* possible.
*/
- void TrackImage(imgIRequest* aImage);
+ void TrackImage(imgIRequest* aImage, nsIFrame* aFrame = nullptr);
void UntrackImage(imgIRequest* aImage,
const Maybe<OnNonvisible>& aNonvisibleAction = Nothing());
@@ -454,9 +459,6 @@ private:
// registered with the refresh driver.
bool mCurrentRequestRegistered;
bool mPendingRequestRegistered;
-
- // True when FrameCreate has been called but FrameDestroy has not.
- bool mFrameCreateCalled;
};
#endif // nsImageLoadingContent_h__
diff --git a/dom/base/nsNodeUtils.cpp b/dom/base/nsNodeUtils.cpp
index 69a9414fe..ecea95dc1 100644
--- a/dom/base/nsNodeUtils.cpp
+++ b/dom/base/nsNodeUtils.cpp
@@ -297,15 +297,6 @@ nsNodeUtils::LastRelease(nsINode* aNode)
NodeWillBeDestroyed, (aNode));
}
- if (aNode->IsElement()) {
- Element* elem = aNode->AsElement();
- FragmentOrElement::nsDOMSlots* domSlots =
- static_cast<FragmentOrElement::nsDOMSlots*>(slots);
- for (auto& reg : domSlots->mRegisteredIntersectionObservers) {
- reg.observer->UnlinkTarget(*elem);
- }
- }
-
delete slots;
aNode->mSlots = nullptr;
}
diff --git a/dom/base/nsStructuredCloneContainer.cpp b/dom/base/nsStructuredCloneContainer.cpp
index 8c2cdc091..ea2d38bc8 100644
--- a/dom/base/nsStructuredCloneContainer.cpp
+++ b/dom/base/nsStructuredCloneContainer.cpp
@@ -137,7 +137,7 @@ nsStructuredCloneContainer::GetDataAsBase64(nsAString &aOut)
return NS_ERROR_FAILURE;
}
- auto iter = Data().Iter();
+ auto iter = Data().Start();
size_t size = Data().Size();
nsAutoCString binaryData;
binaryData.SetLength(size);
diff --git a/dom/base/test/test_intersectionobservers.html b/dom/base/test/test_intersectionobservers.html
index e7875e3af..10e3d7712 100644
--- a/dom/base/test/test_intersectionobservers.html
+++ b/dom/base/test/test_intersectionobservers.html
@@ -325,7 +325,7 @@ limitations under the License.
});
- it('does not trigger if target does not intersect when observing begins',
+ it('does trigger if target does not intersect when observing begins',
function(done) {
var spy = sinon.spy();
@@ -334,7 +334,7 @@ limitations under the License.
targetEl2.style.top = '-40px';
io.observe(targetEl2);
callDelayed(function() {
- expect(spy.callCount).to.be(0);
+ expect(spy.callCount).to.be(1);
done();
}, ASYNC_TIMEOUT);
});
@@ -528,7 +528,7 @@ limitations under the License.
spy.waitForNotification(function() {
expect(spy.callCount).to.be(1);
var records = sortRecords(spy.lastCall.args[0]);
- expect(records.length).to.be(2);
+ expect(records.length).to.be(3);
expect(records[0].target).to.be(targetEl1);
expect(records[0].intersectionRatio).to.be(0.25);
expect(records[1].target).to.be(targetEl2);
@@ -636,10 +636,10 @@ limitations under the License.
expect(records.length).to.be(3);
expect(records[0].target).to.be(targetEl1);
expect(records[0].intersectionRatio).to.be(0.5);
- expect(records[1].target).to.be(targetEl3);
- expect(records[1].intersectionRatio).to.be(0.5);
- expect(records[2].target).to.be(targetEl4);
+ expect(records[2].target).to.be(targetEl3);
expect(records[2].intersectionRatio).to.be(0.5);
+ expect(records[3].target).to.be(targetEl4);
+ expect(records[3].intersectionRatio).to.be(0.5);
io.disconnect();
done();
}, {root: rootEl, rootMargin: '-10px 10%'});
@@ -652,11 +652,11 @@ limitations under the License.
function(done) {
io = new IntersectionObserver(function(records) {
records = sortRecords(records);
- expect(records.length).to.be(2);
+ expect(records.length).to.be(4);
expect(records[0].target).to.be(targetEl1);
expect(records[0].intersectionRatio).to.be(0.5);
- expect(records[1].target).to.be(targetEl4);
- expect(records[1].intersectionRatio).to.be(0.5);
+ expect(records[3].target).to.be(targetEl4);
+ expect(records[3].intersectionRatio).to.be(0.5);
io.disconnect();
done();
}, {root: rootEl, rootMargin: '-5% -2.5% 0px'});
@@ -669,13 +669,13 @@ limitations under the License.
function(done) {
io = new IntersectionObserver(function(records) {
records = sortRecords(records);
- expect(records.length).to.be(3);
+ expect(records.length).to.be(4);
expect(records[0].target).to.be(targetEl1);
expect(records[0].intersectionRatio).to.be(0.5);
expect(records[1].target).to.be(targetEl2);
expect(records[1].intersectionRatio).to.be(0.5);
- expect(records[2].target).to.be(targetEl4);
- expect(records[2].intersectionRatio).to.be(0.25);
+ expect(records[3].target).to.be(targetEl4);
+ expect(records[3].intersectionRatio).to.be(0.25);
io.disconnect();
done();
}, {root: rootEl, rootMargin: '5% -2.5% -10px -190px'});
@@ -705,9 +705,9 @@ limitations under the License.
spy.waitForNotification(function() {
expect(spy.callCount).to.be(1);
var records = sortRecords(spy.lastCall.args[0]);
- expect(records.length).to.be(1);
- expect(records[0].intersectionRatio).to.be(0);
- expect(records[0].target).to.be(targetEl2);
+ expect(records.length).to.be(2);
+ expect(records[1].intersectionRatio).to.be(0);
+ expect(records[1].target).to.be(targetEl2);
done();
}, ASYNC_TIMEOUT);
},
@@ -797,14 +797,14 @@ limitations under the License.
function(done) {
document.getElementById('fixtures').appendChild(rootEl);
callDelayed(function() {
- expect(spy.callCount).to.be(0);
+ expect(spy.callCount).to.be(1);
done();
}, ASYNC_TIMEOUT);
},
function(done) {
parentEl.insertBefore(targetEl1, targetEl2);
spy.waitForNotification(function() {
- expect(spy.callCount).to.be(1);
+ expect(spy.callCount).to.be(2);
var records = sortRecords(spy.lastCall.args[0]);
expect(records.length).to.be(1);
expect(records[0].intersectionRatio).to.be(1);
@@ -815,7 +815,7 @@ limitations under the License.
function(done) {
grandParentEl.parentNode.removeChild(grandParentEl);
spy.waitForNotification(function() {
- expect(spy.callCount).to.be(2);
+ expect(spy.callCount).to.be(3);
var records = sortRecords(spy.lastCall.args[0]);
expect(records.length).to.be(1);
expect(records[0].intersectionRatio).to.be(0);
@@ -826,7 +826,7 @@ limitations under the License.
function(done) {
rootEl.appendChild(targetEl1);
spy.waitForNotification(function() {
- expect(spy.callCount).to.be(3);
+ expect(spy.callCount).to.be(4);
var records = sortRecords(spy.lastCall.args[0]);
expect(records.length).to.be(1);
expect(records[0].intersectionRatio).to.be(1);
@@ -837,7 +837,7 @@ limitations under the License.
function(done) {
rootEl.parentNode.removeChild(rootEl);
spy.waitForNotification(function() {
- expect(spy.callCount).to.be(4);
+ expect(spy.callCount).to.be(5);
var records = sortRecords(spy.lastCall.args[0]);
expect(records.length).to.be(1);
expect(records[0].intersectionRatio).to.be(0);
@@ -867,8 +867,14 @@ limitations under the License.
targetEl1.style.top = '220px';
targetEl1.style.left = '220px';
+
+ var callCount = 0;
io = new IntersectionObserver(function(records) {
+ callCount++;
+ if (callCount <= 1) {
+ return;
+ }
expect(records.length).to.be(1);
expect(records[0].intersectionRatio).to.be(1);
done();
@@ -891,6 +897,19 @@ limitations under the License.
var win = window.open("intersectionobserver_window.html");
});
+ it('triggers only once if observed multiple times (and does not crash when collected)', function(done) {
+ var spy = sinon.spy();
+ io = new IntersectionObserver(spy, {root: rootEl});
+ io.observe(targetEl1);
+ io.observe(targetEl1);
+ io.observe(targetEl1);
+
+ callDelayed(function () {
+ expect(spy.callCount).to.be(1);
+ done();
+ }, ASYNC_TIMEOUT);
+ });
+
});
describe('observe subframe', function () {
diff --git a/dom/bindings/DOMJSProxyHandler.cpp b/dom/bindings/DOMJSProxyHandler.cpp
index 65e540bc1..23f0abd88 100644
--- a/dom/bindings/DOMJSProxyHandler.cpp
+++ b/dom/bindings/DOMJSProxyHandler.cpp
@@ -166,6 +166,10 @@ DOMProxyHandler::EnsureExpandoObject(JSContext* cx, JS::Handle<JSObject*> obj)
nsISupports* native = UnwrapDOMObject<nsISupports>(obj);
nsWrapperCache* cache;
CallQueryInterface(native, &cache);
+ if (!cache) {
+ return expando;
+ }
+
if (expandoAndGeneration) {
cache->PreserveWrapper(native);
expandoAndGeneration->expando.setObject(*expando);
diff --git a/dom/broadcastchannel/BroadcastChannel.cpp b/dom/broadcastchannel/BroadcastChannel.cpp
index c3c2d448b..d154b6562 100644
--- a/dom/broadcastchannel/BroadcastChannel.cpp
+++ b/dom/broadcastchannel/BroadcastChannel.cpp
@@ -154,8 +154,8 @@ public:
bool success;
SerializedStructuredCloneBuffer& buffer = message.data();
- auto iter = mData->BufferData().Iter();
- buffer.data = mData->BufferData().Borrow<js::SystemAllocPolicy>(iter, mData->BufferData().Size(), &success);
+ auto iter = mData->BufferData().Start();
+ buffer.data = mData->BufferData().Borrow(iter, mData->BufferData().Size(), &success);
if (NS_WARN_IF(!success)) {
return NS_OK;
}
@@ -369,7 +369,7 @@ BroadcastChannel::Constructor(const GlobalObject& aGlobal,
RefPtr<InitializeRunnable> runnable =
new InitializeRunnable(workerPrivate, origin, principalInfo, aRv);
- runnable->Dispatch(aRv);
+ runnable->Dispatch(Closing, aRv);
}
if (aRv.Failed()) {
diff --git a/dom/cache/DBSchema.cpp b/dom/cache/DBSchema.cpp
index d16ba2d6a..176e7b9d1 100644
--- a/dom/cache/DBSchema.cpp
+++ b/dom/cache/DBSchema.cpp
@@ -287,7 +287,8 @@ static_assert(nsIContentPolicy::TYPE_INVALID == 0 &&
nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD == 38 &&
nsIContentPolicy::TYPE_INTERNAL_STYLESHEET == 39 &&
nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD == 40 &&
- nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON == 41,
+ nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON == 41 &&
+ nsIContentPolicy::TYPE_SAVEAS_DOWNLOAD == 42,
"nsContentPolicyType values are as expected");
namespace {
diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp
index f4c4259f6..18af28e9f 100644
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -1862,8 +1862,6 @@ CanvasRenderingContext2D::GetHeight() const
NS_IMETHODIMP
CanvasRenderingContext2D::SetDimensions(int32_t aWidth, int32_t aHeight)
{
- ClearTarget();
-
// Zero sized surfaces can cause problems.
mZero = false;
if (aHeight == 0) {
@@ -1874,14 +1872,14 @@ CanvasRenderingContext2D::SetDimensions(int32_t aWidth, int32_t aHeight)
aWidth = 1;
mZero = true;
}
- mWidth = aWidth;
- mHeight = aHeight;
+
+ ClearTarget(aWidth, aHeight);
return NS_OK;
}
void
-CanvasRenderingContext2D::ClearTarget()
+CanvasRenderingContext2D::ClearTarget(int32_t aWidth, int32_t aHeight)
{
Reset();
@@ -1889,6 +1887,12 @@ CanvasRenderingContext2D::ClearTarget()
SetInitialState();
+ // Update dimensions only if new (strictly positive) values were passed.
+ if (aWidth > 0 && aHeight > 0) {
+ mWidth = aWidth;
+ mHeight = aHeight;
+ }
+
// For vertical writing-mode, unless text-orientation is sideways,
// we'll modify the initial value of textBaseline to 'middle'.
RefPtr<nsStyleContext> canvasStyle;
diff --git a/dom/canvas/CanvasRenderingContext2D.h b/dom/canvas/CanvasRenderingContext2D.h
index d5dff8f3b..848b3ee08 100644
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -669,8 +669,11 @@ protected:
/**
* Disposes an old target and prepares to lazily create a new target.
+ *
+ * Parameters are the new dimensions to be used, or if either is negative,
+ * existing dimensions will be left unchanged.
*/
- void ClearTarget();
+ void ClearTarget(int32_t aWidth = -1, int32_t aHeight = -1);
/*
* Returns the target to the buffer provider. i.e. this will queue a frame for
diff --git a/dom/canvas/ImageBitmap.cpp b/dom/canvas/ImageBitmap.cpp
index 6588e0aa3..e45cdfc6f 100644
--- a/dom/canvas/ImageBitmap.cpp
+++ b/dom/canvas/ImageBitmap.cpp
@@ -950,7 +950,7 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, ImageData& aImageData,
imageSize,
aCropRect,
getter_AddRefs(data));
- task->Dispatch(aRv);
+ task->Dispatch(Terminating, aRv);
}
if (NS_WARN_IF(!data)) {
@@ -1377,10 +1377,10 @@ private:
RefPtr<DecodeBlobInMainThreadSyncTask> task =
new DecodeBlobInMainThreadSyncTask(mWorkerPrivate, *mBlob, mCropRect,
getter_AddRefs(data), sourceSize);
- task->Dispatch(rv); // This is a synchronous call.
+ task->Dispatch(Terminating, rv); // This is a synchronous call.
+ // In case the worker is terminating, this rejection can be handled.
if (NS_WARN_IF(rv.Failed())) {
- // XXXbz does this really make sense if we're shutting down? Ah, well.
mPromise->MaybeReject(rv);
return nullptr;
}
@@ -2104,7 +2104,10 @@ ImageBitmap::Create(nsIGlobalObject* aGlobal,
aFormat,
aLayout,
getter_AddRefs(data));
- task->Dispatch(aRv);
+ task->Dispatch(Terminating, aRv);
+ if (aRv.Failed()) {
+ return promise.forget();
+ }
}
if (NS_WARN_IF(!data)) {
diff --git a/dom/canvas/WebGLContextDraw.cpp b/dom/canvas/WebGLContextDraw.cpp
index 867e47cbd..fd9ee4957 100644
--- a/dom/canvas/WebGLContextDraw.cpp
+++ b/dom/canvas/WebGLContextDraw.cpp
@@ -216,7 +216,21 @@ WebGLContext::BindFakeBlack(uint32_t texUnit, TexTarget target, FakeBlackType fa
UniquePtr<FakeBlackTexture>& fakeBlackTex = *slot;
if (!fakeBlackTex) {
+ gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1);
+ if (IsWebGL2()) {
+ gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_PIXELS, 0);
+ gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_ROWS, 0);
+ gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_IMAGES, 0);
+ }
+
fakeBlackTex = FakeBlackTexture::Create(gl, target, fakeBlack);
+
+ gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, mPixelStore_UnpackAlignment);
+ if (IsWebGL2()) {
+ gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_PIXELS, mPixelStore_UnpackSkipPixels);
+ gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_ROWS, mPixelStore_UnpackSkipRows);
+ gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_IMAGES, mPixelStore_UnpackSkipImages);
+ }
if (!fakeBlackTex) {
return false;
}
@@ -1212,13 +1226,8 @@ WebGLContext::FakeBlackTexture::Create(gl::GLContext* gl, TexTarget target,
gl->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST);
gl->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST);
- // We allocate our zeros on the heap, and we overallocate (16 bytes instead of 4) to
- // minimize the risk of running into a driver bug in texImage2D, as it is a bit
- // unusual maybe to create 1x1 textures, and the stack may not have the alignment that
- // TexImage2D expects.
-
const webgl::DriverUnpackInfo dui = {texFormat, texFormat, LOCAL_GL_UNSIGNED_BYTE};
- UniqueBuffer zeros = moz_xcalloc(1, 16); // Infallible allocation.
+ UniqueBuffer zeros = moz_xcalloc(1, 4); // Infallible allocation.
MOZ_ASSERT(gl->IsCurrent());
diff --git a/dom/canvas/WebGLShaderValidator.cpp b/dom/canvas/WebGLShaderValidator.cpp
index 80ba359a3..fda31e212 100644
--- a/dom/canvas/WebGLShaderValidator.cpp
+++ b/dom/canvas/WebGLShaderValidator.cpp
@@ -28,20 +28,39 @@ IdentifierHashFunc(const char* name, size_t len)
return hash[0];
}
-static ShCompileOptions
+static int
ChooseValidatorCompileOptions(const ShBuiltInResources& resources,
const mozilla::gl::GLContext* gl)
{
- ShCompileOptions options = SH_VARIABLES |
- SH_ENFORCE_PACKING_RESTRICTIONS |
- SH_OBJECT_CODE |
- SH_INIT_GL_POSITION;
-
+ int options = SH_VARIABLES |
+ SH_ENFORCE_PACKING_RESTRICTIONS |
+ SH_INIT_VARYINGS_WITHOUT_STATIC_USE |
+ SH_OBJECT_CODE |
+ SH_INIT_GL_POSITION;
+
+ if (resources.MaxExpressionComplexity > 0) {
+ options |= SH_LIMIT_EXPRESSION_COMPLEXITY;
+ }
// Sampler arrays indexed with non-constant expressions are forbidden in
// GLSL 1.30 and later.
// ESSL 3 requires constant-integral-expressions for this as well.
// Just do it universally.
options |= SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX;
+
+ // Needed for driver bug detection
+ options |= SH_EMULATE_BUILT_IN_FUNCTIONS;
+
+ if (gfxPrefs::WebGLAllANGLEOptions()) {
+ return options |
+ SH_VALIDATE_LOOP_INDEXING |
+ SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX |
+ SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX |
+ SH_CLAMP_INDIRECT_ARRAY_BOUNDS |
+ SH_UNFOLD_SHORT_CIRCUIT |
+ SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS |
+ SH_INIT_OUTPUT_VARIABLES |
+ SH_REGENERATE_STRUCT_NAMES;
+ }
#ifndef XP_MACOSX
// We want to do this everywhere, but to do this on Mac, we need
@@ -55,30 +74,23 @@ ChooseValidatorCompileOptions(const ShBuiltInResources& resources,
// Work around https://bugs.webkit.org/show_bug.cgi?id=124684,
// https://chromium.googlesource.com/angle/angle/+/5e70cf9d0b1bb
options |= SH_UNFOLD_SHORT_CIRCUIT;
+
+ // OS X 10.7/10.8 specific:
+
+ // Work around bug 665578 and bug 769810
+ if (gl->Vendor() == gl::GLVendor::ATI) {
+ options |= SH_EMULATE_BUILT_IN_FUNCTIONS;
+ }
+ // Work around bug 735560
+ if (gl->Vendor() == gl::GLVendor::Intel) {
+ options |= SH_EMULATE_BUILT_IN_FUNCTIONS;
+ }
// Work around that Mac drivers handle struct scopes incorrectly.
options |= SH_REGENERATE_STRUCT_NAMES;
- options |= SH_INIT_OUTPUT_VARIABLES;
}
#endif
- if (gfxPrefs::WebGLAllANGLEOptions()) {
- options = -1;
-
- options ^= SH_INTERMEDIATE_TREE;
- options ^= SH_LINE_DIRECTIVES;
- options ^= SH_SOURCE_PATH;
-
- options ^= SH_LIMIT_EXPRESSION_COMPLEXITY;
- options ^= SH_LIMIT_CALL_STACK_DEPTH;
-
- options ^= SH_EXPAND_SELECT_HLSL_INTEGER_POW_EXPRESSIONS;
- options ^= SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL;
-
- options ^= SH_DONT_REMOVE_INVARIANT_FOR_FRAGMENT_INPUT;
- options ^= SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3;
- }
-
if (resources.MaxExpressionComplexity > 0) {
options |= SH_LIMIT_EXPRESSION_COMPLEXITY;
}
@@ -173,7 +185,7 @@ WebGLContext::CreateShaderValidator(GLenum shaderType) const
#endif
}
- const auto compileOptions = webgl::ChooseValidatorCompileOptions(resources, gl);
+ int compileOptions = webgl::ChooseValidatorCompileOptions(resources, gl);
return webgl::ShaderValidator::Create(shaderType, spec, outputLanguage, resources,
compileOptions);
}
@@ -186,7 +198,7 @@ namespace webgl {
ShaderValidator::Create(GLenum shaderType, ShShaderSpec spec,
ShShaderOutput outputLanguage,
const ShBuiltInResources& resources,
- ShCompileOptions compileOptions)
+ int compileOptions)
{
ShHandle handle = ShConstructCompiler(shaderType, spec, outputLanguage, &resources);
if (!handle)
@@ -283,8 +295,8 @@ ShaderValidator::CanLinkTo(const ShaderValidator* prev, nsCString* const out_log
}
}
{
- const auto vertVars = sh::GetInterfaceBlocks(prev->mHandle);
- const auto fragVars = sh::GetInterfaceBlocks(mHandle);
+ const auto vertVars = ShGetInterfaceBlocks(prev->mHandle);
+ const auto fragVars = ShGetInterfaceBlocks(mHandle);
if (!vertVars || !fragVars) {
nsPrintfCString error("Could not create uniform block list.");
*out_log = error;
diff --git a/dom/canvas/WebGLShaderValidator.h b/dom/canvas/WebGLShaderValidator.h
index deb1c7c7f..ba50def28 100644
--- a/dom/canvas/WebGLShaderValidator.h
+++ b/dom/canvas/WebGLShaderValidator.h
@@ -17,7 +17,7 @@ namespace webgl {
class ShaderValidator final
{
const ShHandle mHandle;
- const ShCompileOptions mCompileOptions;
+ const int mCompileOptions;
const int mMaxVaryingVectors;
bool mHasRun;
@@ -25,10 +25,10 @@ public:
static ShaderValidator* Create(GLenum shaderType, ShShaderSpec spec,
ShShaderOutput outputLanguage,
const ShBuiltInResources& resources,
- ShCompileOptions compileOptions);
+ int compileOptions);
private:
- ShaderValidator(ShHandle handle, ShCompileOptions compileOptions,
+ ShaderValidator(ShHandle handle, int compileOptions,
int maxVaryingVectors)
: mHandle(handle)
, mCompileOptions(compileOptions)
diff --git a/dom/events/Event.cpp b/dom/events/Event.cpp
index 4b9776c0a..f33bfa5a8 100755
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -280,16 +280,10 @@ Event::GetType(nsAString& aType)
return NS_OK;
}
-static EventTarget*
-GetDOMEventTarget(nsIDOMEventTarget* aTarget)
-{
- return aTarget ? aTarget->GetTargetForDOMEvent() : nullptr;
-}
-
EventTarget*
Event::GetTarget() const
{
- return GetDOMEventTarget(mEvent->mTarget);
+ return mEvent->GetDOMEventTarget();
}
NS_IMETHODIMP
@@ -302,7 +296,7 @@ Event::GetTarget(nsIDOMEventTarget** aTarget)
EventTarget*
Event::GetCurrentTarget() const
{
- return GetDOMEventTarget(mEvent->mCurrentTarget);
+ return mEvent->GetCurrentDOMEventTarget();
}
NS_IMETHODIMP
@@ -349,11 +343,7 @@ Event::GetExplicitOriginalTarget(nsIDOMEventTarget** aRealEventTarget)
EventTarget*
Event::GetOriginalTarget() const
{
- if (mEvent->mOriginalTarget) {
- return GetDOMEventTarget(mEvent->mOriginalTarget);
- }
-
- return GetTarget();
+ return mEvent->GetOriginalDOMEventTarget();
}
NS_IMETHODIMP
diff --git a/dom/fetch/InternalRequest.cpp b/dom/fetch/InternalRequest.cpp
index 85feabde3..b2631da6a 100644
--- a/dom/fetch/InternalRequest.cpp
+++ b/dom/fetch/InternalRequest.cpp
@@ -320,6 +320,9 @@ InternalRequest::MapContentPolicyTypeToRequestContext(nsContentPolicyType aConte
case nsIContentPolicy::TYPE_WEB_MANIFEST:
context = RequestContext::Manifest;
break;
+ case nsIContentPolicy::TYPE_SAVEAS_DOWNLOAD:
+ context = RequestContext::Internal;
+ break;
default:
MOZ_ASSERT(false, "Unhandled nsContentPolicyType value");
break;
diff --git a/dom/fetch/InternalRequest.h b/dom/fetch/InternalRequest.h
index 84ee0bf69..966490675 100644
--- a/dom/fetch/InternalRequest.h
+++ b/dom/fetch/InternalRequest.h
@@ -53,7 +53,7 @@ namespace dom {
* image | TYPE_INTERNAL_IMAGE, TYPE_INTERNAL_IMAGE_PRELOAD, TYPE_INTERNAL_IMAGE_FAVICON
* imageset | TYPE_IMAGESET
* import | Not supported by Gecko
- * internal | TYPE_DOCUMENT, TYPE_XBL, TYPE_OTHER
+ * internal | TYPE_DOCUMENT, TYPE_XBL, TYPE_OTHER, TYPE_SAVEAS_DOWNLOAD
* location |
* manifest | TYPE_WEB_MANIFEST
* object | TYPE_INTERNAL_OBJECT
diff --git a/dom/fetch/Request.cpp b/dom/fetch/Request.cpp
index c119a503e..7ca5b43c4 100644
--- a/dom/fetch/Request.cpp
+++ b/dom/fetch/Request.cpp
@@ -338,8 +338,7 @@ Request::Constructor(const GlobalObject& aGlobal,
if (mode == RequestMode::Navigate ||
(aInit.IsAnyMemberPresent() && request->Mode() == RequestMode::Navigate)) {
- aRv.ThrowTypeError<MSG_INVALID_REQUEST_MODE>(NS_LITERAL_STRING("navigate"));
- return nullptr;
+ mode = RequestMode::Same_origin;
}
if (aInit.IsAnyMemberPresent()) {
@@ -374,11 +373,7 @@ Request::Constructor(const GlobalObject& aGlobal,
nsresult rv = principal->CheckMayLoad(uri, /* report */ false,
/* allowIfInheritsPrincipal */ false);
if (NS_FAILED(rv)) {
- nsAutoCString globalOrigin;
- principal->GetOrigin(globalOrigin);
- aRv.ThrowTypeError<MSG_CROSS_ORIGIN_REFERRER_URL>(referrer,
- NS_ConvertUTF8toUTF16(globalOrigin));
- return nullptr;
+ referrerURL.AssignLiteral(kFETCH_CLIENT_REFERRER_STR);
}
}
}
@@ -403,11 +398,10 @@ Request::Constructor(const GlobalObject& aGlobal,
// this work in a single sync loop.
RefPtr<ReferrerSameOriginChecker> checker =
new ReferrerSameOriginChecker(worker, referrerURL, rv);
- checker->Dispatch(aRv);
- if (aRv.Failed() || NS_FAILED(rv)) {
- aRv.ThrowTypeError<MSG_CROSS_ORIGIN_REFERRER_URL>(referrer,
- worker->GetLocationInfo().mOrigin);
- return nullptr;
+ IgnoredErrorResult error;
+ checker->Dispatch(Terminating, error);
+ if (error.Failed() || NS_FAILED(rv)) {
+ referrerURL.AssignLiteral(kFETCH_CLIENT_REFERRER_STR);
}
}
}
diff --git a/dom/filesystem/tests/test_webkitdirectory.html b/dom/filesystem/tests/test_webkitdirectory.html
index 825f5e8fb..591619e45 100644
--- a/dom/filesystem/tests/test_webkitdirectory.html
+++ b/dom/filesystem/tests/test_webkitdirectory.html
@@ -152,6 +152,7 @@ function test_changeDataWhileWorking() {
function test_setup() {
SpecialPowers.pushPrefEnv({"set": [["dom.input.dirpicker", true],
+ ["dom.filesystem.pathcheck.disabled", true],
["dom.webkitBlink.dirPicker.enabled", true]]}, next);
}
diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp
index d09bc3103..e9086933b 100644
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -3546,7 +3546,8 @@ HTMLInputElement::Focus(ErrorResult& aError)
nsNumberControlFrame* numberControlFrame =
do_QueryFrame(GetPrimaryFrame());
if (numberControlFrame) {
- HTMLInputElement* textControl = numberControlFrame->GetAnonTextControl();
+ RefPtr<HTMLInputElement> textControl =
+ numberControlFrame->GetAnonTextControl();
if (textControl) {
textControl->Focus(aError);
return;
diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp
index 1f1a545fa..3954e6208 100644
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -817,6 +817,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTM
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mErrorSink->mError)
for (uint32_t i = 0; i < tmp->mOutputStreams.Length(); ++i) {
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOutputStreams[i].mStream);
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOutputStreams[i].mPreCreatedTracks);
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlayed);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTextTrackManager)
@@ -1020,6 +1021,17 @@ void HTMLMediaElement::ShutdownDecoder()
RemoveMediaElementFromURITable();
NS_ASSERTION(mDecoder, "Must have decoder to shut down");
mWaitingForKeyListener.DisconnectIfExists();
+ for (OutputMediaStream& out : mOutputStreams) {
+ if (!out.mCapturingDecoder) {
+ continue;
+ }
+ if (!out.mStream) {
+ continue;
+ }
+ out.mNextAvailableTrackID = std::max<TrackID>(
+ mDecoder->NextAvailableTrackIDFor(out.mStream->GetInputStream()),
+ out.mNextAvailableTrackID);
+ }
mDecoder->Shutdown();
mDecoder = nullptr;
}
@@ -2730,6 +2742,7 @@ HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded,
if (mDecoder) {
out->mCapturingDecoder = true;
mDecoder->AddOutputStream(out->mStream->GetInputStream()->AsProcessedStream(),
+ out->mNextAvailableTrackID,
aFinishWhenEnded);
} else if (mSrcStream) {
out->mCapturingMediaStream = true;
@@ -2743,23 +2756,26 @@ HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded,
if (mDecoder) {
if (HasAudio()) {
- TrackID audioTrackId = mMediaInfo.mAudio.mTrackId;
+ TrackID audioTrackId = out->mNextAvailableTrackID++;
RefPtr<MediaStreamTrackSource> trackSource =
getter->GetMediaStreamTrackSource(audioTrackId);
RefPtr<MediaStreamTrack> track =
- out->mStream->CreateDOMTrack(audioTrackId, MediaSegment::AUDIO,
+ out->mStream->CreateDOMTrack(audioTrackId,
+ MediaSegment::AUDIO,
trackSource);
+ out->mPreCreatedTracks.AppendElement(track);
out->mStream->AddTrackInternal(track);
LOG(LogLevel::Debug,
("Created audio track %d for captured decoder", audioTrackId));
}
if (IsVideo() && HasVideo() && !out->mCapturingAudioOnly) {
- TrackID videoTrackId = mMediaInfo.mVideo.mTrackId;
+ TrackID videoTrackId = out->mNextAvailableTrackID++;
RefPtr<MediaStreamTrackSource> trackSource =
getter->GetMediaStreamTrackSource(videoTrackId);
RefPtr<MediaStreamTrack> track =
out->mStream->CreateDOMTrack(videoTrackId, MediaSegment::VIDEO,
trackSource);
+ out->mPreCreatedTracks.AppendElement(track);
out->mStream->AddTrackInternal(track);
LOG(LogLevel::Debug,
("Created video track %d for captured decoder", videoTrackId));
@@ -2848,6 +2864,25 @@ NS_IMETHODIMP HTMLMediaElement::GetMozAudioCaptured(bool* aCaptured)
return NS_OK;
}
+void
+HTMLMediaElement::EndPreCreatedCapturedDecoderTracks()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ for (OutputMediaStream& ms : mOutputStreams) {
+ if (!ms.mCapturingDecoder) {
+ continue;
+ }
+ for (RefPtr<MediaStreamTrack>& t : ms.mPreCreatedTracks) {
+ if (t->Ended()) {
+ continue;
+ }
+ NS_DispatchToMainThread(NewRunnableMethod(
+ t, &MediaStreamTrack::OverrideEnded));
+ }
+ ms.mPreCreatedTracks.Clear();
+ }
+}
+
class MediaElementSetForURI : public nsURIHashKey {
public:
explicit MediaElementSetForURI(const nsIURI* aKey) : nsURIHashKey(aKey) {}
@@ -3380,11 +3415,12 @@ HTMLMediaElement::WakeLockRelease()
}
HTMLMediaElement::OutputMediaStream::OutputMediaStream()
- : mFinishWhenEnded(false)
+ : mNextAvailableTrackID(1)
+ , mFinishWhenEnded(false)
, mCapturingAudioOnly(false)
, mCapturingDecoder(false)
, mCapturingMediaStream(false)
- , mNextAvailableTrackID(1) {}
+{}
HTMLMediaElement::OutputMediaStream::~OutputMediaStream()
{
@@ -4008,6 +4044,7 @@ nsresult HTMLMediaElement::FinishDecoderSetup(MediaDecoder* aDecoder,
ms.mCapturingDecoder = true;
aDecoder->AddOutputStream(ms.mStream->GetInputStream()->AsProcessedStream(),
+ ms.mNextAvailableTrackID,
ms.mFinishWhenEnded);
}
@@ -5477,7 +5514,9 @@ void HTMLMediaElement::SuspendOrResumeElement(bool aPauseElement, bool aSuspendE
}
mEventDeliveryPaused = aSuspendEvents;
} else {
+#ifdef MOZ_EME
MOZ_ASSERT(!mMediaKeys);
+#endif
if (mDecoder) {
mDecoder->Resume();
if (!mPaused && !mDecoder->IsEnded()) {
diff --git a/dom/html/HTMLMediaElement.h b/dom/html/HTMLMediaElement.h
index b65049206..af944a318 100644
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -675,6 +675,11 @@ public:
return mAudioCaptured;
}
+ /**
+ * Ensures any MediaStreamTracks captured from a MediaDecoder are ended.
+ */
+ void EndPreCreatedCapturedDecoderTracks();
+
void MozGetMetadata(JSContext* aCx, JS::MutableHandle<JSObject*> aResult,
ErrorResult& aRv);
@@ -815,13 +820,18 @@ protected:
~OutputMediaStream();
RefPtr<DOMMediaStream> mStream;
+ TrackID mNextAvailableTrackID;
bool mFinishWhenEnded;
bool mCapturingAudioOnly;
bool mCapturingDecoder;
bool mCapturingMediaStream;
+ // The following members are keeping state for a captured MediaDecoder.
+ // Tracks that were created on main thread before MediaDecoder fed them
+ // to the MediaStreamGraph.
+ nsTArray<RefPtr<MediaStreamTrack>> mPreCreatedTracks;
+
// The following members are keeping state for a captured MediaStream.
- TrackID mNextAvailableTrackID;
nsTArray<Pair<nsString, RefPtr<MediaInputPort>>> mTrackPorts;
};
diff --git a/dom/indexedDB/ActorsParent.cpp b/dom/indexedDB/ActorsParent.cpp
index 4e1b9f7af..e6fe9e2a8 100644
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -8440,12 +8440,12 @@ class ObjectStoreAddOrPutRequestOp::SCInputStream final
: public nsIInputStream
{
const JSStructuredCloneData& mData;
- JSStructuredCloneData::IterImpl mIter;
+ JSStructuredCloneData::Iterator mIter;
public:
explicit SCInputStream(const JSStructuredCloneData& aData)
: mData(aData)
- , mIter(aData.Iter())
+ , mIter(aData.Start())
{ }
private:
@@ -19687,7 +19687,7 @@ UpgradeFileIdsFunction::OnFunctionCall(mozIStorageValueArray* aArguments,
return NS_ERROR_UNEXPECTED;
}
- StructuredCloneReadInfo cloneInfo;
+ StructuredCloneReadInfo cloneInfo(JS::StructuredCloneScope::DifferentProcess);
DatabaseOperationBase::GetStructuredCloneReadInfoFromValueArray(aArguments,
1,
0,
@@ -19892,7 +19892,7 @@ DatabaseOperationBase::GetStructuredCloneReadInfoFromBlob(
return NS_ERROR_FILE_CORRUPTED;
}
- if (!aInfo->mData.WriteBytes(uncompressedBuffer, uncompressed.Length())) {
+ if (!aInfo->mData.AppendBytes(uncompressedBuffer, uncompressed.Length())) {
return NS_ERROR_OUT_OF_MEMORY;
}
@@ -19978,7 +19978,7 @@ DatabaseOperationBase::GetStructuredCloneReadInfoFromExternalBlob(
break;
}
- if (NS_WARN_IF(!aInfo->mData.WriteBytes(buffer, numRead))) {
+ if (NS_WARN_IF(!aInfo->mData.AppendBytes(buffer, numRead))) {
rv = NS_ERROR_OUT_OF_MEMORY;
break;
}
@@ -25337,7 +25337,7 @@ UpdateIndexDataValuesFunction::OnFunctionCall(mozIStorageValueArray* aValues,
}
#endif
- StructuredCloneReadInfo cloneInfo;
+ StructuredCloneReadInfo cloneInfo(JS::StructuredCloneScope::DifferentProcess);
nsresult rv =
GetStructuredCloneReadInfoFromValueArray(aValues,
/* aDataIndex */ 3,
@@ -26546,18 +26546,9 @@ ObjectStoreAddOrPutRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
char keyPropBuffer[keyPropSize];
LittleEndian::writeUint64(keyPropBuffer, keyPropValue);
- auto iter = cloneData.Iter();
- DebugOnly<bool> result =
- iter.AdvanceAcrossSegments(cloneData, cloneInfo.offsetToKeyProp());
- MOZ_ASSERT(result);
-
- for (uint32_t index = 0; index < keyPropSize; index++) {
- char* keyPropPointer = iter.Data();
- *keyPropPointer = keyPropBuffer[index];
-
- result = iter.AdvanceAcrossSegments(cloneData, 1);
- MOZ_ASSERT(result);
- }
+ auto iter = cloneData.Start();
+ MOZ_ALWAYS_TRUE(cloneData.Advance(iter, cloneInfo.offsetToKeyProp()));
+ MOZ_ALWAYS_TRUE(cloneData.UpdateBytes(iter, keyPropBuffer, keyPropSize));
}
}
@@ -26583,7 +26574,7 @@ ObjectStoreAddOrPutRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
} else {
nsCString flatCloneData;
flatCloneData.SetLength(cloneDataSize);
- auto iter = cloneData.Iter();
+ auto iter = cloneData.Start();
cloneData.ReadBytes(iter, flatCloneData.BeginWriting(), cloneDataSize);
// Compress the bytes before adding into the database.
@@ -26840,7 +26831,7 @@ SCInputStream::ReadSegments(nsWriteSegmentFun aWriter,
*_retval += count;
aCount -= count;
- mIter.Advance(mData, count);
+ mData.Advance(mIter, count);
}
return NS_OK;
@@ -28029,7 +28020,7 @@ CursorOpBase::PopulateResponseFromStatement(
switch (mCursor->mType) {
case OpenCursorParams::TObjectStoreOpenCursorParams: {
- StructuredCloneReadInfo cloneInfo;
+ StructuredCloneReadInfo cloneInfo(JS::StructuredCloneScope::DifferentProcess);
rv = GetStructuredCloneReadInfoFromStatement(aStmt,
2,
1,
@@ -28077,7 +28068,7 @@ CursorOpBase::PopulateResponseFromStatement(
return rv;
}
- StructuredCloneReadInfo cloneInfo;
+ StructuredCloneReadInfo cloneInfo(JS::StructuredCloneScope::DifferentProcess);
rv = GetStructuredCloneReadInfoFromStatement(aStmt,
4,
3,
diff --git a/dom/indexedDB/IDBObjectStore.cpp b/dom/indexedDB/IDBObjectStore.cpp
index a6d6c5f06..8a0b292ad 100644
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -67,7 +67,7 @@ struct IDBObjectStore::StructuredCloneWriteInfo
uint64_t mOffsetToKeyProp;
explicit StructuredCloneWriteInfo(IDBDatabase* aDatabase)
- : mCloneBuffer(JS::StructuredCloneScope::SameProcessSameThread, nullptr,
+ : mCloneBuffer(JS::StructuredCloneScope::DifferentProcessForIndexedDB, nullptr,
nullptr)
, mDatabase(aDatabase)
, mOffsetToKeyProp(0)
@@ -1216,7 +1216,7 @@ IDBObjectStore::DeserializeValue(JSContext* aCx,
// FIXME: Consider to use StructuredCloneHolder here and in other
// deserializing methods.
if (!JS_ReadStructuredClone(aCx, aCloneReadInfo.mData, JS_STRUCTURED_CLONE_VERSION,
- JS::StructuredCloneScope::SameProcessSameThread,
+ JS::StructuredCloneScope::DifferentProcessForIndexedDB,
aValue, &callbacks, &aCloneReadInfo)) {
return false;
}
@@ -1249,7 +1249,7 @@ IDBObjectStore::DeserializeIndexValue(JSContext* aCx,
};
if (!JS_ReadStructuredClone(aCx, aCloneReadInfo.mData, JS_STRUCTURED_CLONE_VERSION,
- JS::StructuredCloneScope::SameProcessSameThread,
+ JS::StructuredCloneScope::DifferentProcessForIndexedDB,
aValue, &callbacks, &aCloneReadInfo)) {
return false;
}
@@ -1285,7 +1285,7 @@ IDBObjectStore::DeserializeUpgradeValue(JSContext* aCx,
};
if (!JS_ReadStructuredClone(aCx, aCloneReadInfo.mData, JS_STRUCTURED_CLONE_VERSION,
- JS::StructuredCloneScope::SameProcessSameThread,
+ JS::StructuredCloneScope::DifferentProcessForIndexedDB,
aValue, &callbacks, &aCloneReadInfo)) {
return false;
}
diff --git a/dom/indexedDB/IndexedDatabase.h b/dom/indexedDB/IndexedDatabase.h
index b0c4cb877..b3c6ab725 100644
--- a/dom/indexedDB/IndexedDatabase.h
+++ b/dom/indexedDB/IndexedDatabase.h
@@ -65,6 +65,10 @@ struct StructuredCloneReadInfo
bool mHasPreprocessInfo;
// In IndexedDatabaseInlines.h
+ inline explicit
+ StructuredCloneReadInfo(JS::StructuredCloneScope aScope);
+
+ // In IndexedDatabaseInlines.h
inline
StructuredCloneReadInfo();
diff --git a/dom/indexedDB/IndexedDatabaseInlines.h b/dom/indexedDB/IndexedDatabaseInlines.h
index 830c2f110..8c34a81dd 100644
--- a/dom/indexedDB/IndexedDatabaseInlines.h
+++ b/dom/indexedDB/IndexedDatabaseInlines.h
@@ -45,14 +45,21 @@ StructuredCloneFile::operator==(const StructuredCloneFile& aOther) const
}
inline
-StructuredCloneReadInfo::StructuredCloneReadInfo()
- : mDatabase(nullptr)
+StructuredCloneReadInfo::StructuredCloneReadInfo(JS::StructuredCloneScope aScope)
+ : mData(aScope)
+ , mDatabase(nullptr)
, mHasPreprocessInfo(false)
{
MOZ_COUNT_CTOR(StructuredCloneReadInfo);
}
inline
+StructuredCloneReadInfo::StructuredCloneReadInfo()
+ : StructuredCloneReadInfo(JS::StructuredCloneScope::DifferentProcessForIndexedDB)
+{
+}
+
+inline
StructuredCloneReadInfo::StructuredCloneReadInfo(
StructuredCloneReadInfo&& aCloneReadInfo)
: mData(Move(aCloneReadInfo.mData))
diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp
index 3488e26bd..0a07147bf 100644
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -4721,6 +4721,14 @@ ContentParent::RecvGetFilesRequest(const nsID& aUUID,
{
MOZ_ASSERT(!mGetFilesPendingRequests.GetWeak(aUUID));
+ if (!mozilla::Preferences::GetBool("dom.filesystem.pathcheck.disabled", false)) {
+ RefPtr<FileSystemSecurity> fss = FileSystemSecurity::Get();
+ if (NS_WARN_IF(!fss ||
+ !fss->ContentProcessHasAccessTo(ChildID(), aDirectoryPath))) {
+ return false;
+ }
+ }
+
ErrorResult rv;
RefPtr<GetFilesHelper> helper =
GetFilesHelperParent::Create(aUUID, aDirectoryPath, aRecursiveFlag, this,
diff --git a/dom/ipc/StructuredCloneData.cpp b/dom/ipc/StructuredCloneData.cpp
index 98f56904f..2c1fff2ac 100644
--- a/dom/ipc/StructuredCloneData.cpp
+++ b/dom/ipc/StructuredCloneData.cpp
@@ -88,7 +88,7 @@ StructuredCloneData::Write(JSContext* aCx,
return;
}
- JSStructuredCloneData data;
+ JSStructuredCloneData data(mBuffer->scope());
mBuffer->abandon();
mBuffer->steal(&data);
mBuffer = nullptr;
@@ -107,7 +107,7 @@ StructuredCloneData::ReadIPCParams(const IPC::Message* aMsg,
PickleIterator* aIter)
{
MOZ_ASSERT(!mInitialized);
- JSStructuredCloneData data;
+ JSStructuredCloneData data(JS::StructuredCloneScope::DifferentProcess);
if (!ReadParam(aMsg, aIter, &data)) {
return false;
}
diff --git a/dom/ipc/StructuredCloneData.h b/dom/ipc/StructuredCloneData.h
index 9e427e938..64cfd1935 100644
--- a/dom/ipc/StructuredCloneData.h
+++ b/dom/ipc/StructuredCloneData.h
@@ -31,8 +31,8 @@ public:
static already_AddRefed<SharedJSAllocatedData>
CreateFromExternalData(const char* aData, size_t aDataLength)
{
- JSStructuredCloneData buf;
- buf.WriteBytes(aData, aDataLength);
+ JSStructuredCloneData buf(JS::StructuredCloneScope::DifferentProcess);
+ buf.AppendBytes(aData, aDataLength);
RefPtr<SharedJSAllocatedData> sharedData =
new SharedJSAllocatedData(Move(buf));
return sharedData.forget();
@@ -41,12 +41,8 @@ public:
static already_AddRefed<SharedJSAllocatedData>
CreateFromExternalData(const JSStructuredCloneData& aData)
{
- JSStructuredCloneData buf;
- auto iter = aData.Iter();
- while (!iter.Done()) {
- buf.WriteBytes(iter.Data(), iter.RemainingInSegment());
- iter.Advance(aData, iter.RemainingInSegment());
- }
+ JSStructuredCloneData buf(aData.scope());
+ buf.Append(aData);
RefPtr<SharedJSAllocatedData> sharedData =
new SharedJSAllocatedData(Move(buf));
return sharedData.forget();
@@ -70,6 +66,7 @@ public:
: StructuredCloneHolder(StructuredCloneHolder::CloningSupported,
StructuredCloneHolder::TransferringSupported,
StructuredCloneHolder::StructuredCloneScope::DifferentProcess)
+ , mExternalData(StructuredCloneHolder::StructuredCloneScope::DifferentProcess)
, mInitialized(false)
{}
@@ -113,10 +110,9 @@ public:
bool UseExternalData(const JSStructuredCloneData& aData)
{
- auto iter = aData.Iter();
+ auto iter = aData.Start();
bool success = false;
- mExternalData =
- aData.Borrow<js::SystemAllocPolicy>(iter, aData.Size(), &success);
+ mExternalData = aData.Borrow(iter, aData.Size(), &success);
mInitialized = true;
return success;
}
@@ -133,6 +129,11 @@ public:
return mSharedData ? mSharedData->Data() : mExternalData;
}
+ void InitScope(JS::StructuredCloneScope aScope)
+ {
+ Data().initScope(aScope);
+ }
+
size_t DataLength() const
{
return mSharedData ? mSharedData->DataLength() : mExternalData.Size();
diff --git a/dom/media/MediaDecoder.cpp b/dom/media/MediaDecoder.cpp
index ab39886ba..9334d1bcb 100644
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -327,11 +327,13 @@ MediaDecoder::SetVolume(double aVolume)
void
MediaDecoder::AddOutputStream(ProcessedMediaStream* aStream,
+ TrackID aNextAvailableTrackID,
bool aFinishWhenEnded)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mDecoderStateMachine, "Must be called after Load().");
- mDecoderStateMachine->AddOutputStream(aStream, aFinishWhenEnded);
+ mDecoderStateMachine->AddOutputStream(
+ aStream, aNextAvailableTrackID, aFinishWhenEnded);
}
void
@@ -342,6 +344,14 @@ MediaDecoder::RemoveOutputStream(MediaStream* aStream)
mDecoderStateMachine->RemoveOutputStream(aStream);
}
+TrackID
+MediaDecoder::NextAvailableTrackIDFor(MediaStream* aOutputStream) const
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(mDecoderStateMachine, "Must be called after Load().");
+ return mDecoderStateMachine->NextAvailableTrackIDFor(aOutputStream);
+}
+
double
MediaDecoder::GetDuration()
{
@@ -1736,6 +1746,8 @@ MediaDecoder::RemoveMediaTracks()
videoList->RemoveTracks();
}
+ element->EndPreCreatedCapturedDecoderTracks();
+
mMediaTracksConstructed = false;
}
diff --git a/dom/media/MediaDecoder.h b/dom/media/MediaDecoder.h
index 825bbbd2c..a4edcbe72 100644
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -210,9 +210,13 @@ public:
// Add an output stream. All decoder output will be sent to the stream.
// The stream is initially blocked. The decoder is responsible for unblocking
// it while it is playing back.
- virtual void AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
+ virtual void AddOutputStream(ProcessedMediaStream* aStream,
+ TrackID aNextAvailableTrackID,
+ bool aFinishWhenEnded);
// Remove an output stream added with AddOutputStream.
virtual void RemoveOutputStream(MediaStream* aStream);
+ // The next TrackID that can be used without risk of a collision.
+ virtual TrackID NextAvailableTrackIDFor(MediaStream* aOutputStream) const;
// Return the duration of the video in seconds.
virtual double GetDuration();
diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp
index f13e59b6c..c586139ad 100644
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -2835,6 +2835,10 @@ MediaDecoderStateMachine::FinishDecodeFirstFrame()
RefPtr<ShutdownPromise>
MediaDecoderStateMachine::BeginShutdown()
{
+ MOZ_ASSERT(NS_IsMainThread());
+ if (mOutputStreamManager) {
+ mOutputStreamManager->Clear();
+ }
return InvokeAsync(OwnerThread(), this, __func__,
&MediaDecoderStateMachine::Shutdown);
}
@@ -3250,11 +3254,12 @@ MediaDecoderStateMachine::DumpDebugInfo()
}
void MediaDecoderStateMachine::AddOutputStream(ProcessedMediaStream* aStream,
+ TrackID aNextAvailableTrackID,
bool aFinishWhenEnded)
{
MOZ_ASSERT(NS_IsMainThread());
DECODER_LOG("AddOutputStream aStream=%p!", aStream);
- mOutputStreamManager->Add(aStream, aFinishWhenEnded);
+ mOutputStreamManager->Add(aStream, aNextAvailableTrackID, aFinishWhenEnded);
nsCOMPtr<nsIRunnable> r = NewRunnableMethod<bool>(
this, &MediaDecoderStateMachine::SetAudioCaptured, true);
OwnerThread()->Dispatch(r.forget());
@@ -3269,9 +3274,17 @@ void MediaDecoderStateMachine::RemoveOutputStream(MediaStream* aStream)
nsCOMPtr<nsIRunnable> r = NewRunnableMethod<bool>(
this, &MediaDecoderStateMachine::SetAudioCaptured, false);
OwnerThread()->Dispatch(r.forget());
+
}
}
+TrackID
+MediaDecoderStateMachine::NextAvailableTrackIDFor(MediaStream* aOutputStream) const
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ return mOutputStreamManager->NextAvailableTrackIDFor(aOutputStream);
+}
+
size_t
MediaDecoderStateMachine::SizeOfVideoQueue() const
{
diff --git a/dom/media/MediaDecoderStateMachine.h b/dom/media/MediaDecoderStateMachine.h
index a61fe13d2..ff3258ff1 100644
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -168,9 +168,12 @@ public:
void DumpDebugInfo();
- void AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
+ void AddOutputStream(ProcessedMediaStream* aStream,
+ TrackID aNextAvailableTrackID,
+ bool aFinishWhenEnded);
// Remove an output stream added with AddOutputStream.
void RemoveOutputStream(MediaStream* aStream);
+ TrackID NextAvailableTrackIDFor(MediaStream* aOutputStream) const;
// Seeks to the decoder to aTarget asynchronously.
RefPtr<MediaDecoder::SeekPromise> InvokeSeek(SeekTarget aTarget);
diff --git a/dom/media/PeerConnection.js b/dom/media/PeerConnection.js
index 0c3021799..0569b15ae 100644
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -516,6 +516,18 @@ RTCPeerConnection.prototype = {
};
},
+ // This implements the fairly common "Queue a task" logic
+ async _queueTaskWithClosedCheck(func) {
+ return new Promise(resolve => {
+ Services.tm.mainThread.dispatch({ run() {
+ if (!this._closed) {
+ func();
+ resolve();
+ }
+ }}, Ci.nsIThread.DISPATCH_NORMAL);
+ });
+ },
+
/**
* An RTCConfiguration may look like this:
*
@@ -1445,7 +1457,10 @@ PeerConnectionObserver.prototype = {
break;
case "IceConnectionState":
- this.handleIceConnectionStateChange(this._dompc._pc.iceConnectionState);
+ let connState = this._dompc._pc.iceConnectionState;
+ this._dompc._queueTaskWithClosedCheck(() => {
+ this.handleIceConnectionStateChange(connState);
+ });
break;
case "IceGatheringState":
diff --git a/dom/media/mediasink/DecodedStream.cpp b/dom/media/mediasink/DecodedStream.cpp
index 9501a6cde..00bc5ea49 100644
--- a/dom/media/mediasink/DecodedStream.cpp
+++ b/dom/media/mediasink/DecodedStream.cpp
@@ -181,17 +181,22 @@ DecodedStreamData::DecodedStreamData(OutputStreamManager* aOutputStreamManager,
, mOutputStreamManager(aOutputStreamManager)
{
mStream->AddListener(mListener);
- mOutputStreamManager->Connect(mStream);
+ TrackID audioTrack = TRACK_NONE;
+ TrackID videoTrack = TRACK_NONE;
// Initialize tracks.
if (aInit.mInfo.HasAudio()) {
- mStream->AddAudioTrack(aInit.mInfo.mAudio.mTrackId,
+ audioTrack = aInit.mInfo.mAudio.mTrackId;
+ mStream->AddAudioTrack(audioTrack,
aInit.mInfo.mAudio.mRate,
0, new AudioSegment());
}
if (aInit.mInfo.HasVideo()) {
- mStream->AddTrack(aInit.mInfo.mVideo.mTrackId, 0, new VideoSegment());
+ videoTrack = aInit.mInfo.mVideo.mTrackId;
+ mStream->AddTrack(videoTrack, 0, new VideoSegment());
}
+
+ mOutputStreamManager->Connect(mStream, audioTrack, videoTrack);
}
DecodedStreamData::~DecodedStreamData()
diff --git a/dom/media/mediasink/OutputStreamManager.cpp b/dom/media/mediasink/OutputStreamManager.cpp
index d5685837a..7ecc203ed 100644
--- a/dom/media/mediasink/OutputStreamManager.cpp
+++ b/dom/media/mediasink/OutputStreamManager.cpp
@@ -13,29 +13,41 @@ OutputStreamData::~OutputStreamData()
{
MOZ_ASSERT(NS_IsMainThread());
// Break the connection to the input stream if necessary.
- if (mPort) {
- mPort->Destroy();
+ for (RefPtr<MediaInputPort>& port : mPorts) {
+ port->Destroy();
}
}
void
-OutputStreamData::Init(OutputStreamManager* aOwner, ProcessedMediaStream* aStream)
+OutputStreamData::Init(OutputStreamManager* aOwner,
+ ProcessedMediaStream* aStream,
+ TrackID aNextAvailableTrackID)
{
mOwner = aOwner;
mStream = aStream;
+ mNextAvailableTrackID = aNextAvailableTrackID;
}
bool
-OutputStreamData::Connect(MediaStream* aStream)
+OutputStreamData::Connect(MediaStream* aStream,
+ TrackID aInputAudioTrackID,
+ TrackID aInputVideoTrackID)
{
MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(!mPort, "Already connected?");
+ MOZ_ASSERT(mPorts.IsEmpty(), "Already connected?");
if (mStream->IsDestroyed()) {
return false;
}
- mPort = mStream->AllocateInputPort(aStream);
+ for (TrackID tid : {aInputAudioTrackID, aInputVideoTrackID}) {
+ if (tid == TRACK_NONE) {
+ continue;
+ }
+ MOZ_ASSERT(IsTrackIDExplicit(tid));
+ mPorts.AppendElement(mStream->AllocateInputPort(
+ aStream, tid, mNextAvailableTrackID++));
+ }
return true;
}
@@ -51,11 +63,11 @@ OutputStreamData::Disconnect()
return false;
}
- // Disconnect the existing port if necessary.
- if (mPort) {
- mPort->Destroy();
- mPort = nullptr;
+ // Disconnect any existing port.
+ for (RefPtr<MediaInputPort>& port : mPorts) {
+ port->Destroy();
}
+ mPorts.Clear();
return true;
}
@@ -71,8 +83,16 @@ OutputStreamData::Graph() const
return mStream->Graph();
}
+TrackID
+OutputStreamData::NextAvailableTrackID() const
+{
+ return mNextAvailableTrackID;
+}
+
void
-OutputStreamManager::Add(ProcessedMediaStream* aStream, bool aFinishWhenEnded)
+OutputStreamManager::Add(ProcessedMediaStream* aStream,
+ TrackID aNextAvailableTrackID,
+ bool aFinishWhenEnded)
{
MOZ_ASSERT(NS_IsMainThread());
// All streams must belong to the same graph.
@@ -84,12 +104,12 @@ OutputStreamManager::Add(ProcessedMediaStream* aStream, bool aFinishWhenEnded)
}
OutputStreamData* p = mStreams.AppendElement();
- p->Init(this, aStream);
+ p->Init(this, aStream, aNextAvailableTrackID);
// Connect to the input stream if we have one. Otherwise the output stream
// will be connected in Connect().
if (mInputStream) {
- p->Connect(mInputStream);
+ p->Connect(mInputStream, mInputAudioTrackID, mInputVideoTrackID);
}
}
@@ -106,12 +126,35 @@ OutputStreamManager::Remove(MediaStream* aStream)
}
void
-OutputStreamManager::Connect(MediaStream* aStream)
+OutputStreamManager::Clear()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ mStreams.Clear();
+}
+
+TrackID
+OutputStreamManager::NextAvailableTrackIDFor(MediaStream* aOutputStream) const
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ for (const OutputStreamData& out : mStreams) {
+ if (out.Equals(aOutputStream)) {
+ return out.NextAvailableTrackID();
+ }
+ }
+ return TRACK_INVALID;
+}
+
+void
+OutputStreamManager::Connect(MediaStream* aStream,
+ TrackID aAudioTrackID,
+ TrackID aVideoTrackID)
{
MOZ_ASSERT(NS_IsMainThread());
mInputStream = aStream;
+ mInputAudioTrackID = aAudioTrackID;
+ mInputVideoTrackID = aVideoTrackID;
for (int32_t i = mStreams.Length() - 1; i >= 0; --i) {
- if (!mStreams[i].Connect(aStream)) {
+ if (!mStreams[i].Connect(aStream, mInputAudioTrackID, mInputVideoTrackID)) {
// Probably the DOMMediaStream was GCed. Clean up.
mStreams.RemoveElementAt(i);
}
@@ -123,6 +166,8 @@ OutputStreamManager::Disconnect()
{
MOZ_ASSERT(NS_IsMainThread());
mInputStream = nullptr;
+ mInputAudioTrackID = TRACK_INVALID;
+ mInputVideoTrackID = TRACK_INVALID;
for (int32_t i = mStreams.Length() - 1; i >= 0; --i) {
if (!mStreams[i].Disconnect()) {
// Probably the DOMMediaStream was GCed. Clean up.
diff --git a/dom/media/mediasink/OutputStreamManager.h b/dom/media/mediasink/OutputStreamManager.h
index 7f91a60c1..941a86cf0 100644
--- a/dom/media/mediasink/OutputStreamManager.h
+++ b/dom/media/mediasink/OutputStreamManager.h
@@ -9,6 +9,7 @@
#include "mozilla/RefPtr.h"
#include "nsTArray.h"
+#include "MediaSegment.h"
namespace mozilla {
@@ -21,11 +22,13 @@ class ProcessedMediaStream;
class OutputStreamData {
public:
~OutputStreamData();
- void Init(OutputStreamManager* aOwner, ProcessedMediaStream* aStream);
+ void Init(OutputStreamManager* aOwner,
+ ProcessedMediaStream* aStream,
+ TrackID aNextAvailableTrackID);
- // Connect mStream to the input stream.
+ // Connect the given input stream's audio and video tracks to mStream.
// Return false is mStream is already destroyed, otherwise true.
- bool Connect(MediaStream* aStream);
+ bool Connect(MediaStream* aStream, TrackID aAudioTrackID, TrackID aVideoTrackID);
// Disconnect mStream from its input stream.
// Return false is mStream is already destroyed, otherwise true.
bool Disconnect();
@@ -34,12 +37,16 @@ public:
bool Equals(MediaStream* aStream) const;
// Return the graph mStream belongs to.
MediaStreamGraph* Graph() const;
+ // The next TrackID that will not cause a collision in mStream.
+ TrackID NextAvailableTrackID() const;
private:
OutputStreamManager* mOwner;
RefPtr<ProcessedMediaStream> mStream;
- // mPort connects our mStream to an input stream.
- RefPtr<MediaInputPort> mPort;
+ // mPort connects an input stream to our mStream.
+ nsTArray<RefPtr<MediaInputPort>> mPorts;
+ // For guaranteeing TrackID uniqueness in our mStream.
+ TrackID mNextAvailableTrackID = TRACK_INVALID;
};
class OutputStreamManager {
@@ -47,18 +54,26 @@ class OutputStreamManager {
public:
// Add the output stream to the collection.
- void Add(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
+ void Add(ProcessedMediaStream* aStream,
+ TrackID aNextAvailableTrackID,
+ bool aFinishWhenEnded);
// Remove the output stream from the collection.
void Remove(MediaStream* aStream);
+ // Clear all output streams from the collection.
+ void Clear();
+ // The next TrackID that will not cause a collision in aOutputStream.
+ TrackID NextAvailableTrackIDFor(MediaStream* aOutputStream) const;
// Return true if the collection empty.
bool IsEmpty() const
{
MOZ_ASSERT(NS_IsMainThread());
return mStreams.IsEmpty();
}
- // Connect all output streams in the collection to the input stream.
- void Connect(MediaStream* aStream);
- // Disconnect all output streams from the input stream.
+ // Connect the given input stream's tracks to all output streams.
+ void Connect(MediaStream* aStream,
+ TrackID aAudioTrackID,
+ TrackID aVideoTrackID);
+ // Disconnect the input stream to all output streams.
void Disconnect();
// Return the graph these streams belong to or null if empty.
MediaStreamGraph* Graph() const
@@ -72,6 +87,8 @@ private:
// Keep the input stream so we can connect the output streams that
// are added after Connect().
RefPtr<MediaStream> mInputStream;
+ TrackID mInputAudioTrackID = TRACK_INVALID;
+ TrackID mInputVideoTrackID = TRACK_INVALID;
nsTArray<OutputStreamData> mStreams;
};
diff --git a/dom/notification/Notification.cpp b/dom/notification/Notification.cpp
index 9c0ce2f18..1dd5724e4 100644
--- a/dom/notification/Notification.cpp
+++ b/dom/notification/Notification.cpp
@@ -1881,7 +1881,7 @@ Notification::GetPermission(nsIGlobalObject* aGlobal, ErrorResult& aRv)
MOZ_ASSERT(worker);
RefPtr<GetPermissionRunnable> r =
new GetPermissionRunnable(worker);
- r->Dispatch(aRv);
+ r->Dispatch(Terminating, aRv);
if (aRv.Failed()) {
return NotificationPermission::Denied;
}
@@ -2484,7 +2484,7 @@ NotificationWorkerHolder::Notify(Status aStatus)
RefPtr<CloseNotificationRunnable> r =
new CloseNotificationRunnable(kungFuDeathGrip);
ErrorResult rv;
- r->Dispatch(rv);
+ r->Dispatch(Killing, rv);
// XXXbz I'm told throwing and returning false from here is pointless (and
// also that doing sync stuff from here is really weird), so I guess we just
// suppress the exception on rv, if any.
@@ -2627,7 +2627,7 @@ Notification::ShowPersistentNotification(JSContext* aCx,
worker->AssertIsOnWorkerThread();
RefPtr<CheckLoadRunnable> loadChecker =
new CheckLoadRunnable(worker, NS_ConvertUTF16toUTF8(aScope));
- loadChecker->Dispatch(aRv);
+ loadChecker->Dispatch(Terminating, aRv);
if (aRv.Failed()) {
return nullptr;
}
diff --git a/dom/performance/PerformanceNavigationTiming.cpp b/dom/performance/PerformanceNavigationTiming.cpp
index 4e00b2bb2..d7e16725a 100644
--- a/dom/performance/PerformanceNavigationTiming.cpp
+++ b/dom/performance/PerformanceNavigationTiming.cpp
@@ -6,6 +6,7 @@
#include "mozilla/dom/PerformanceNavigationTiming.h"
#include "mozilla/dom/PerformanceNavigationTimingBinding.h"
+#include "mozilla/TimerClamping.h"
using namespace mozilla::dom;
@@ -24,49 +25,49 @@ PerformanceNavigationTiming::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aG
DOMHighResTimeStamp
PerformanceNavigationTiming::UnloadEventStart() const
{
- return mTiming->GetDOMTiming()->GetUnloadEventStartHighRes();
+ return TimerClamping::ReduceMsTimeValue(mTiming->GetDOMTiming()->GetUnloadEventStartHighRes());
}
DOMHighResTimeStamp
PerformanceNavigationTiming::UnloadEventEnd() const
{
- return mTiming->GetDOMTiming()->GetUnloadEventEndHighRes();
+ return TimerClamping::ReduceMsTimeValue(mTiming->GetDOMTiming()->GetUnloadEventEndHighRes());
}
DOMHighResTimeStamp
PerformanceNavigationTiming::DomInteractive() const
{
- return mTiming->GetDOMTiming()->GetDomInteractiveHighRes();
+ return TimerClamping::ReduceMsTimeValue(mTiming->GetDOMTiming()->GetDomInteractiveHighRes());
}
DOMHighResTimeStamp
PerformanceNavigationTiming::DomContentLoadedEventStart() const
{
- return mTiming->GetDOMTiming()->GetDomContentLoadedEventStartHighRes();
+ return TimerClamping::ReduceMsTimeValue(mTiming->GetDOMTiming()->GetDomContentLoadedEventStartHighRes());
}
DOMHighResTimeStamp
PerformanceNavigationTiming::DomContentLoadedEventEnd() const
{
- return mTiming->GetDOMTiming()->GetDomContentLoadedEventEndHighRes();
+ return TimerClamping::ReduceMsTimeValue(mTiming->GetDOMTiming()->GetDomContentLoadedEventEndHighRes());
}
DOMHighResTimeStamp
PerformanceNavigationTiming::DomComplete() const
{
- return mTiming->GetDOMTiming()->GetDomCompleteHighRes();
+ return TimerClamping::ReduceMsTimeValue(mTiming->GetDOMTiming()->GetDomCompleteHighRes());
}
DOMHighResTimeStamp
PerformanceNavigationTiming::LoadEventStart() const
{
- return mTiming->GetDOMTiming()->GetLoadEventStartHighRes();
+ return TimerClamping::ReduceMsTimeValue(mTiming->GetDOMTiming()->GetLoadEventStartHighRes());
}
DOMHighResTimeStamp
PerformanceNavigationTiming::LoadEventEnd() const
{
- return mTiming->GetDOMTiming()->GetLoadEventEndHighRes();
+ return TimerClamping::ReduceMsTimeValue(mTiming->GetDOMTiming()->GetLoadEventEndHighRes());
}
NavigationType
diff --git a/dom/plugins/base/nsPluginStreamListenerPeer.cpp b/dom/plugins/base/nsPluginStreamListenerPeer.cpp
index 26e0318e3..665e11ec1 100644
--- a/dom/plugins/base/nsPluginStreamListenerPeer.cpp
+++ b/dom/plugins/base/nsPluginStreamListenerPeer.cpp
@@ -1381,15 +1381,6 @@ nsPluginStreamListenerPeer::AsyncOnChannelRedirect(nsIChannel *oldChannel, nsICh
return NS_ERROR_FAILURE;
}
- nsCOMPtr<nsIAsyncVerifyRedirectCallback> proxyCallback =
- new ChannelRedirectProxyCallback(this, callback, oldChannel, newChannel);
-
- // Give NPAPI a chance to control redirects.
- bool notificationHandled = mPStreamListener->HandleRedirectNotification(oldChannel, newChannel, proxyCallback);
- if (notificationHandled) {
- return NS_OK;
- }
-
// Don't allow cross-origin 307 POST redirects.
nsCOMPtr<nsIHttpChannel> oldHttpChannel(do_QueryInterface(oldChannel));
if (oldHttpChannel) {
@@ -1413,6 +1404,15 @@ nsPluginStreamListenerPeer::AsyncOnChannelRedirect(nsIChannel *oldChannel, nsICh
}
}
+ nsCOMPtr<nsIAsyncVerifyRedirectCallback> proxyCallback =
+ new ChannelRedirectProxyCallback(this, callback, oldChannel, newChannel);
+
+ // Give NPAPI a chance to control redirects.
+ bool notificationHandled = mPStreamListener->HandleRedirectNotification(oldChannel, newChannel, proxyCallback);
+ if (notificationHandled) {
+ return NS_OK;
+ }
+
// Fall back to channel event sink for window.
nsCOMPtr<nsIChannelEventSink> channelEventSink;
nsresult rv = GetInterfaceGlobal(NS_GET_IID(nsIChannelEventSink), getter_AddRefs(channelEventSink));
diff --git a/dom/plugins/test/unit/xpcshell.ini b/dom/plugins/test/unit/xpcshell.ini
index 69b6731b2..2665c82b5 100644
--- a/dom/plugins/test/unit/xpcshell.ini
+++ b/dom/plugins/test/unit/xpcshell.ini
@@ -5,7 +5,6 @@ tail =
tags = addons
firefox-appdir = browser
support-files =
- !/toolkit/mozapps/webextensions/test/xpcshell/head_addons.js
[test_allowed_types.js]
skip-if = appname == "thunderbird"
diff --git a/dom/quota/StorageManager.cpp b/dom/quota/StorageManager.cpp
index c8455f0fe..4e9f0cf8c 100644
--- a/dom/quota/StorageManager.cpp
+++ b/dom/quota/StorageManager.cpp
@@ -335,7 +335,7 @@ StorageManager::Estimate(ErrorResult& aRv)
new EstimateWorkerMainThreadRunnable(promiseProxy->GetWorkerPrivate(),
promiseProxy);
- runnnable->Dispatch(aRv);
+ runnnable->Dispatch(Terminating, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
diff --git a/dom/security/nsCSPService.cpp b/dom/security/nsCSPService.cpp
index 7344e19fa..4807c9aa4 100644
--- a/dom/security/nsCSPService.cpp
+++ b/dom/security/nsCSPService.cpp
@@ -288,6 +288,7 @@ CSPService::AsyncOnChannelRedirect(nsIChannel *oldChannel,
nsContentUtils::InternalContentPolicyTypeToExternalOrWorker(policyType);
int16_t aDecision = nsIContentPolicy::ACCEPT;
+ nsCOMPtr<nsISupports> requestContext = loadInfo->GetLoadingContext();
// 1) Apply speculative CSP for preloads
if (isPreload) {
nsCOMPtr<nsIContentSecurityPolicy> preloadCsp;
@@ -298,7 +299,7 @@ CSPService::AsyncOnChannelRedirect(nsIChannel *oldChannel,
preloadCsp->ShouldLoad(policyType, // load type per nsIContentPolicy (uint32_t)
newUri, // nsIURI
nullptr, // nsIURI
- nullptr, // nsISupports
+ requestContext, // nsISupports
EmptyCString(), // ACString - MIME guess
originalUri, // aExtra
&aDecision);
@@ -321,7 +322,7 @@ CSPService::AsyncOnChannelRedirect(nsIChannel *oldChannel,
csp->ShouldLoad(policyType, // load type per nsIContentPolicy (uint32_t)
newUri, // nsIURI
nullptr, // nsIURI
- nullptr, // nsISupports
+ requestContext, // nsISupports
EmptyCString(), // ACString - MIME guess
originalUri, // aExtra
&aDecision);
diff --git a/dom/security/nsCSPUtils.cpp b/dom/security/nsCSPUtils.cpp
index 49832f8f4..71c8e3433 100644
--- a/dom/security/nsCSPUtils.cpp
+++ b/dom/security/nsCSPUtils.cpp
@@ -258,6 +258,9 @@ CSP_ContentTypeToDirective(nsContentPolicyType aType)
case nsIContentPolicy::TYPE_CSP_REPORT:
return nsIContentSecurityPolicy::NO_DIRECTIVE;
+ case nsIContentPolicy::TYPE_SAVEAS_DOWNLOAD:
+ return nsIContentSecurityPolicy::NO_DIRECTIVE;
+
// Fall through to error for all other directives
default:
MOZ_ASSERT(false, "Can not map nsContentPolicyType to CSPDirective");
diff --git a/dom/security/nsContentSecurityManager.cpp b/dom/security/nsContentSecurityManager.cpp
index f329aa723..570730312 100644
--- a/dom/security/nsContentSecurityManager.cpp
+++ b/dom/security/nsContentSecurityManager.cpp
@@ -303,7 +303,7 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo)
case nsIContentPolicy::TYPE_DOCUMENT: {
mimeTypeGuess = EmptyCString();
- requestingContext = aLoadInfo->LoadingNode();
+ requestingContext = aLoadInfo->ContextForTopLevelLoad();
break;
}
@@ -471,6 +471,12 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo)
break;
}
+ case nsIContentPolicy::TYPE_SAVEAS_DOWNLOAD: {
+ mimeTypeGuess = EmptyCString();
+ requestingContext = aLoadInfo->LoadingNode();
+ break;
+ }
+
default:
// nsIContentPolicy::TYPE_INVALID
MOZ_ASSERT(false, "can not perform security check without a valid contentType");
diff --git a/dom/security/nsMixedContentBlocker.cpp b/dom/security/nsMixedContentBlocker.cpp
index 7d50a43a3..c03628da0 100644
--- a/dom/security/nsMixedContentBlocker.cpp
+++ b/dom/security/nsMixedContentBlocker.cpp
@@ -468,6 +468,13 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
*aDecision = ACCEPT;
return NS_OK;
+ // Creating insecure connections for a save-as link download is acceptable.
+ // This download is completely disconnected from the docShell, but still
+ // using the same loading principal.
+ case TYPE_SAVEAS_DOWNLOAD:
+ *aDecision = ACCEPT;
+ return NS_OK;
+
// Static display content is considered moderate risk for mixed content so
// these will be blocked according to the mixed display preference
case TYPE_IMAGE:
diff --git a/dom/security/test/csp/file_nonce_redirector.sjs b/dom/security/test/csp/file_nonce_redirector.sjs
new file mode 100644
index 000000000..21a8f4e9c
--- /dev/null
+++ b/dom/security/test/csp/file_nonce_redirector.sjs
@@ -0,0 +1,25 @@
+// custom *.sjs file for
+// Bug 1469150:Scripts with valid nonce get blocked if URL redirects.
+
+const URL_PATH = "example.com/tests/dom/security/test/csp/";
+
+function handleRequest(request, response) {
+ response.setHeader("Cache-Control", "no-cache", false);
+ let queryStr = request.queryString;
+
+ if (queryStr === "redirect") {
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location",
+ "https://" + URL_PATH + "file_nonce_redirector.sjs?load", false);
+ return;
+ }
+
+ if (queryStr === "load") {
+ response.setHeader("Content-Type", "application/javascript", false);
+ response.write("console.log('script loaded');");
+ return;
+ }
+
+ // we should never get here - return something unexpected
+ response.write("d'oh");
+}
diff --git a/dom/security/test/csp/file_nonce_redirects.html b/dom/security/test/csp/file_nonce_redirects.html
new file mode 100644
index 000000000..e29116490
--- /dev/null
+++ b/dom/security/test/csp/file_nonce_redirects.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta charset='utf-8'>
+ <meta http-equiv="Content-Security-Policy" content="script-src 'nonce-abcd1234'">
+ <title>Bug 1469150:Scripts with valid nonce get blocked if URL redirects</title>
+ </head>
+<body>
+
+<script nonce='abcd1234' id='redirectScript'></script>
+
+<script nonce='abcd1234' type='application/javascript'>
+ var redirectScript = document.getElementById('redirectScript');
+ redirectScript.onload = function(e) {
+ window.parent.postMessage({result: 'script-loaded'}, '*');
+ };
+ redirectScript.onerror = function(e) {
+ window.parent.postMessage({result: 'script-blocked'}, '*');
+ }
+ redirectScript.src = 'file_nonce_redirector.sjs?redirect';
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/mochitest.ini b/dom/security/test/csp/mochitest.ini
index 33b112020..86b7fd0cd 100644
--- a/dom/security/test/csp/mochitest.ini
+++ b/dom/security/test/csp/mochitest.ini
@@ -88,6 +88,8 @@ support-files =
file_shouldprocess.html
file_nonce_source.html
file_nonce_source.html^headers^
+ file_nonce_redirects.html
+ file_nonce_redirector.sjs
file_bug941404.html
file_bug941404_xhr.html
file_bug941404_xhr.html^headers^
@@ -245,6 +247,7 @@ skip-if = toolkit == 'android' # Times out, not sure why (bug 1008445)
[test_frame_ancestors_ro.html]
[test_policyuri_regression_from_multipolicy.html]
[test_nonce_source.html]
+[test_nonce_redirects.html]
[test_bug941404.html]
[test_form-action.html]
[test_hash_source.html]
diff --git a/dom/security/test/csp/test_nonce_redirects.html b/dom/security/test/csp/test_nonce_redirects.html
new file mode 100644
index 000000000..f84fdcc7b
--- /dev/null
+++ b/dom/security/test/csp/test_nonce_redirects.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1469150:Scripts with valid nonce get blocked if URL redirects</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/* Description of the test:
+ * We load a script with a matching nonce, which redirects
+ * and we make sure that script is allowed.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+function finishTest() {
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+function checkResults(aResult) {
+
+ if (aResult === "script-loaded") {
+ ok(true, "expected result: script loaded");
+ }
+ else {
+ ok(false, "unexpected result: script blocked");
+ }
+ finishTest();
+}
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ checkResults(event.data.result);
+}
+
+document.getElementById("testframe").src = "file_nonce_redirects.html";
+
+</script>
+</body>
+</html>
diff --git a/dom/tests/mochitest/fetch/test_request.js b/dom/tests/mochitest/fetch/test_request.js
index 5be361a46..405767b50 100644
--- a/dom/tests/mochitest/fetch/test_request.js
+++ b/dom/tests/mochitest/fetch/test_request.js
@@ -152,12 +152,9 @@ function testHeaderGuard() {
}
function testMode() {
- try {
- var req = new Request("http://example.com", {mode: "navigate"});
- ok(false, "Creating a Request with navigate RequestMode should throw a TypeError");
- } catch(e) {
- is(e.name, "TypeError", "Creating a Request with navigate RequestMode should throw a TypeError");
- }
+ var req = new Request("http://example.com", {mode: "navigate"});
+ ok(true, "Creating a Request with navigate RequestMode should not throw.");
+ is(req.mode, "same-origin", "Request mode becomes same-origin");
}
function testMethod() {
diff --git a/dom/url/URL.cpp b/dom/url/URL.cpp
index c8724c359..04f5ec137 100644
--- a/dom/url/URL.cpp
+++ b/dom/url/URL.cpp
@@ -1113,6 +1113,12 @@ public:
return true;
}
+ void
+ Dispatch(ErrorResult& aRv)
+ {
+ WorkerMainThreadRunnable::Dispatch(Terminating, aRv);
+ }
+
private:
nsAString& mValue;
GetterType mType;
@@ -1213,6 +1219,12 @@ public:
return mFailed;
}
+ void
+ Dispatch(ErrorResult& aRv)
+ {
+ WorkerMainThreadRunnable::Dispatch(Terminating, aRv);
+ }
+
private:
const nsString mValue;
SetterType mType;
@@ -1224,7 +1236,7 @@ already_AddRefed<URLWorker>
FinishConstructor(JSContext* aCx, WorkerPrivate* aPrivate,
ConstructorRunnable* aRunnable, ErrorResult& aRv)
{
- aRunnable->Dispatch(aRv);
+ aRunnable->Dispatch(Terminating, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
@@ -1302,7 +1314,7 @@ URLWorker::CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob,
RefPtr<CreateURLRunnable> runnable =
new CreateURLRunnable(workerPrivate, blobImpl, aOptions, aResult);
- runnable->Dispatch(aRv);
+ runnable->Dispatch(Terminating, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
@@ -1325,7 +1337,7 @@ URLWorker::RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aUrl,
RefPtr<RevokeURLRunnable> runnable =
new RevokeURLRunnable(workerPrivate, aUrl);
- runnable->Dispatch(aRv);
+ runnable->Dispatch(Terminating, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
@@ -1348,7 +1360,7 @@ URLWorker::IsValidURL(const GlobalObject& aGlobal, const nsAString& aUrl,
RefPtr<IsValidURLRunnable> runnable =
new IsValidURLRunnable(workerPrivate, aUrl);
- runnable->Dispatch(aRv);
+ runnable->Dispatch(Terminating, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return false;
}
diff --git a/dom/webidl/Document.webidl b/dom/webidl/Document.webidl
index 0b8c278fe..904b1fb77 100644
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -277,8 +277,11 @@ partial interface Document {
// https://w3c.github.io/page-visibility/#extensions-to-the-document-interface
partial interface Document {
+ [Pref="dom.visibilityAPI.enabled"]
readonly attribute boolean hidden;
+ [Pref="dom.visibilityAPI.enabled"]
readonly attribute VisibilityState visibilityState;
+ [Pref="dom.visibilityAPI.enabled"]
attribute EventHandler onvisibilitychange;
};
diff --git a/dom/webidl/Element.webidl b/dom/webidl/Element.webidl
index ca5f1b35c..97eb4ffe0 100644
--- a/dom/webidl/Element.webidl
+++ b/dom/webidl/Element.webidl
@@ -41,6 +41,8 @@ interface Element : Node {
[Pure]
DOMString? getAttributeNS(DOMString? namespace, DOMString localName);
[Throws]
+ boolean toggleAttribute(DOMString name, optional boolean force);
+ [Throws]
void setAttribute(DOMString name, DOMString value);
[Throws]
void setAttributeNS(DOMString? namespace, DOMString name, DOMString value);
diff --git a/dom/webidl/Event.webidl b/dom/webidl/Event.webidl
index f87dc195c..70a0ef513 100644
--- a/dom/webidl/Event.webidl
+++ b/dom/webidl/Event.webidl
@@ -17,6 +17,8 @@ interface Event {
readonly attribute DOMString type;
[Pure]
readonly attribute EventTarget? target;
+ [Pure, BinaryName="target"]
+ readonly attribute EventTarget? srcElement;
[Pure]
readonly attribute EventTarget? currentTarget;
diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp
index ad95d4896..e1910536f 100644
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -587,7 +587,7 @@ ContentSecurityPolicyAllows(JSContext* aCx)
new LogViolationDetailsRunnable(worker, fileName, lineNum);
ErrorResult rv;
- runnable->Dispatch(rv);
+ runnable->Dispatch(Killing, rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
}
diff --git a/dom/workers/ScriptLoader.cpp b/dom/workers/ScriptLoader.cpp
index 46545e737..56b18441e 100644
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -2118,12 +2118,16 @@ LoadAllScripts(WorkerPrivate* aWorkerPrivate,
aWorkerPrivate->AssertIsOnWorkerThread();
NS_ASSERTION(!aLoadInfos.IsEmpty(), "Bad arguments!");
- AutoSyncLoopHolder syncLoop(aWorkerPrivate);
+ AutoSyncLoopHolder syncLoop(aWorkerPrivate, Terminating);
+ nsCOMPtr<nsIEventTarget> syncLoopTarget = syncLoop.GetEventTarget();
+ if (!syncLoopTarget) {
+ aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+ return;
+ }
RefPtr<ScriptLoaderRunnable> loader =
- new ScriptLoaderRunnable(aWorkerPrivate, syncLoop.EventTarget(),
- aLoadInfos, aIsMainScript, aWorkerScriptType,
- aRv);
+ new ScriptLoaderRunnable(aWorkerPrivate, syncLoopTarget, aLoadInfos,
+ aIsMainScript, aWorkerScriptType, aRv);
NS_ASSERTION(aLoadInfos.IsEmpty(), "Should have swapped!");
@@ -2184,7 +2188,7 @@ ChannelFromScriptURLWorkerThread(JSContext* aCx,
new ChannelGetterRunnable(aParent, aScriptURL, aChannel);
ErrorResult rv;
- getter->Dispatch(rv);
+ getter->Dispatch(Terminating, rv);
if (rv.Failed()) {
NS_ERROR("Failed to dispatch!");
return rv.StealNSResult();
diff --git a/dom/workers/WorkerNavigator.cpp b/dom/workers/WorkerNavigator.cpp
index 682c7a22c..f79896881 100644
--- a/dom/workers/WorkerNavigator.cpp
+++ b/dom/workers/WorkerNavigator.cpp
@@ -152,7 +152,7 @@ WorkerNavigator::GetUserAgent(nsString& aUserAgent, ErrorResult& aRv) const
RefPtr<GetUserAgentRunnable> runnable =
new GetUserAgentRunnable(workerPrivate, aUserAgent);
- runnable->Dispatch(aRv);
+ runnable->Dispatch(Terminating, aRv);
}
uint64_t
diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp
index 8848e881a..612090027 100644
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -5446,10 +5446,18 @@ WorkerPrivate::CancelAllTimeouts()
}
already_AddRefed<nsIEventTarget>
-WorkerPrivate::CreateNewSyncLoop()
+WorkerPrivate::CreateNewSyncLoop(Status aFailStatus)
{
AssertIsOnWorkerThread();
+ {
+ MutexAutoLock lock(mMutex);
+
+ if (mStatus >= aFailStatus) {
+ return nullptr;
+ }
+ }
+
nsCOMPtr<nsIThreadInternal> thread = do_QueryInterface(NS_GetCurrentThread());
MOZ_ASSERT(thread);
diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h
index 28283bed7..20a530205 100644
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -1442,8 +1442,11 @@ private:
memcpy(aPreferences, mPreferences, WORKERPREF_COUNT * sizeof(bool));
}
+ // If the worker shutdown status is equal or greater then aFailStatus, this
+ // operation will fail and nullptr will be returned. See WorkerHolder.h for
+ // more information about the correct value to use.
already_AddRefed<nsIEventTarget>
- CreateNewSyncLoop();
+ CreateNewSyncLoop(Status aFailStatus);
bool
RunCurrentSyncLoop();
@@ -1518,9 +1521,11 @@ class AutoSyncLoopHolder
uint32_t mIndex;
public:
- explicit AutoSyncLoopHolder(WorkerPrivate* aWorkerPrivate)
+ // See CreateNewSyncLoop() for more information about the correct value to use
+ // for aFailStatus.
+ AutoSyncLoopHolder(WorkerPrivate* aWorkerPrivate, Status aFailStatus)
: mWorkerPrivate(aWorkerPrivate)
- , mTarget(aWorkerPrivate->CreateNewSyncLoop())
+ , mTarget(aWorkerPrivate->CreateNewSyncLoop(aFailStatus))
, mIndex(aWorkerPrivate->mSyncLoopStack.Length() - 1)
{
aWorkerPrivate->AssertIsOnWorkerThread();
@@ -1528,7 +1533,7 @@ public:
~AutoSyncLoopHolder()
{
- if (mWorkerPrivate) {
+ if (mWorkerPrivate && mTarget) {
mWorkerPrivate->AssertIsOnWorkerThread();
mWorkerPrivate->StopSyncLoop(mTarget, false);
mWorkerPrivate->DestroySyncLoop(mIndex);
@@ -1547,8 +1552,9 @@ public:
}
nsIEventTarget*
- EventTarget() const
+ GetEventTarget() const
{
+ // This can be null if CreateNewSyncLoop() fails.
return mTarget;
}
};
diff --git a/dom/workers/WorkerRunnable.cpp b/dom/workers/WorkerRunnable.cpp
index 1e16d7254..6bbe40f66 100644
--- a/dom/workers/WorkerRunnable.cpp
+++ b/dom/workers/WorkerRunnable.cpp
@@ -568,15 +568,20 @@ WorkerMainThreadRunnable::WorkerMainThreadRunnable(WorkerPrivate* aWorkerPrivate
}
void
-WorkerMainThreadRunnable::Dispatch(ErrorResult& aRv)
+WorkerMainThreadRunnable::Dispatch(Status aFailStatus, ErrorResult& aRv)
{
mWorkerPrivate->AssertIsOnWorkerThread();
TimeStamp startTime = TimeStamp::NowLoRes();
- AutoSyncLoopHolder syncLoop(mWorkerPrivate);
+ AutoSyncLoopHolder syncLoop(mWorkerPrivate, aFailStatus);
- mSyncLoopTarget = syncLoop.EventTarget();
+ mSyncLoopTarget = syncLoop.GetEventTarget();
+ if (!mSyncLoopTarget) {
+ // SyncLoop creation can fail if the worker is shutting down.
+ aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+ return;
+ }
DebugOnly<nsresult> rv = mWorkerPrivate->DispatchToMainThread(this);
MOZ_ASSERT(NS_SUCCEEDED(rv),
@@ -621,7 +626,7 @@ bool
WorkerCheckAPIExposureOnMainThreadRunnable::Dispatch()
{
ErrorResult rv;
- WorkerMainThreadRunnable::Dispatch(rv);
+ WorkerMainThreadRunnable::Dispatch(Terminating, rv);
bool ok = !rv.Failed();
rv.SuppressException();
return ok;
diff --git a/dom/workers/WorkerRunnable.h b/dom/workers/WorkerRunnable.h
index c65060f44..8249a8053 100644
--- a/dom/workers/WorkerRunnable.h
+++ b/dom/workers/WorkerRunnable.h
@@ -401,9 +401,12 @@ protected:
public:
// Dispatch the runnable to the main thread. If dispatch to main thread
- // fails, or if the worker is shut down while dispatching, an error will be
- // reported on aRv. In that case the error MUST be propagated out to script.
- void Dispatch(ErrorResult& aRv);
+ // fails, or if the worker is in a state equal or greater of aFailStatus, an
+ // error will be reported on aRv. Normally you want to use 'Terminating' for
+ // aFailStatus, except if you want an infallible runnable. In this case, use
+ // 'Killing'.
+ // In that case the error MUST be propagated out to script.
+ void Dispatch(Status aFailStatus, ErrorResult& aRv);
private:
NS_IMETHOD Run() override;
diff --git a/dom/workers/test/serviceworkers/fetch_event_worker.js b/dom/workers/test/serviceworkers/fetch_event_worker.js
index 1caef71e8..895128e2c 100644
--- a/dom/workers/test/serviceworkers/fetch_event_worker.js
+++ b/dom/workers/test/serviceworkers/fetch_event_worker.js
@@ -148,28 +148,21 @@ onfetch = function(ev) {
}
else if (ev.request.url.includes("navigate.html")) {
- var navigateModeCorrectlyChecked = false;
var requests = [ // should not throw
new Request(ev.request),
new Request(ev.request, undefined),
new Request(ev.request, null),
new Request(ev.request, {}),
new Request(ev.request, {someUnrelatedProperty: 42}),
+ new Request(ev.request, {method: "GET"}),
];
- try {
- var request3 = new Request(ev.request, {method: "GET"}); // should throw
- } catch(e) {
- navigateModeCorrectlyChecked = requests[0].mode == "navigate";
- }
- if (navigateModeCorrectlyChecked) {
- ev.respondWith(Promise.resolve(
- new Response("<script>window.frameElement.test_result = true;</script>", {
- headers : {
- "Content-Type": "text/html"
- }
- })
- ));
- }
+ ev.respondWith(Promise.resolve(
+ new Response("<script>window.frameElement.test_result = true;</script>", {
+ headers : {
+ "Content-Type": "text/html"
+ }
+ })
+ ));
}
else if (ev.request.url.includes("nonexistent_worker_script.js")) {
diff --git a/dom/xbl/nsXBLBinding.cpp b/dom/xbl/nsXBLBinding.cpp
index 6ae17c4c0..d9a2aacc5 100644
--- a/dom/xbl/nsXBLBinding.cpp
+++ b/dom/xbl/nsXBLBinding.cpp
@@ -1014,7 +1014,17 @@ nsXBLBinding::DoInitJSClass(JSContext *cx,
NS_ENSURE_TRUE(xblScope, NS_ERROR_UNEXPECTED);
JS::Rooted<JSObject*> parent_proto(cx);
- if (!JS_GetPrototype(cx, obj, &parent_proto)) {
+ {
+ JS::RootedObject wrapped(cx, obj);
+ JSAutoCompartment ac(cx, xblScope);
+ if (!JS_WrapObject(cx, &wrapped)) {
+ return NS_ERROR_FAILURE;
+ }
+ if (!JS_GetPrototype(cx, wrapped, &parent_proto)) {
+ return NS_ERROR_FAILURE;
+ }
+ }
+ if (!JS_WrapObject(cx, &parent_proto)) {
return NS_ERROR_FAILURE;
}
diff --git a/dom/xhr/XMLHttpRequestWorker.cpp b/dom/xhr/XMLHttpRequestWorker.cpp
index e7193a279..c9e892f26 100644
--- a/dom/xhr/XMLHttpRequestWorker.cpp
+++ b/dom/xhr/XMLHttpRequestWorker.cpp
@@ -208,9 +208,9 @@ public:
}
void
- Dispatch(ErrorResult& aRv)
+ Dispatch(Status aFailStatus, ErrorResult& aRv)
{
- WorkerMainThreadRunnable::Dispatch(aRv);
+ WorkerMainThreadRunnable::Dispatch(aFailStatus, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
@@ -1633,11 +1633,10 @@ XMLHttpRequestWorker::ReleaseProxy(ReleaseType aType)
new SyncTeardownRunnable(mWorkerPrivate, mProxy);
mProxy = nullptr;
- ErrorResult forAssertionsOnly;
- runnable->Dispatch(forAssertionsOnly);
- if (forAssertionsOnly.Failed()) {
- NS_ERROR("Failed to dispatch teardown runnable!");
- }
+ IgnoredErrorResult forAssertionsOnly;
+ // This runnable _must_ be executed.
+ runnable->Dispatch(Dead, forAssertionsOnly);
+ MOZ_DIAGNOSTIC_ASSERT(!forAssertionsOnly.Failed());
}
}
}
@@ -1804,8 +1803,12 @@ XMLHttpRequestWorker::SendInternal(SendRunnable* aRunnable,
nsCOMPtr<nsIEventTarget> syncLoopTarget;
bool isSyncXHR = mProxy->mIsSyncXHR;
if (isSyncXHR) {
- autoSyncLoop.emplace(mWorkerPrivate);
- syncLoopTarget = autoSyncLoop->EventTarget();
+ autoSyncLoop.emplace(mWorkerPrivate, Terminating);
+ syncLoopTarget = autoSyncLoop->GetEventTarget();
+ if (!syncLoopTarget) {
+ aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+ return;
+ }
}
mProxy->mOuterChannelId++;
@@ -1815,7 +1818,7 @@ XMLHttpRequestWorker::SendInternal(SendRunnable* aRunnable,
mStateData.mFlagSend = true;
- aRunnable->Dispatch(aRv);
+ aRunnable->Dispatch(Terminating, aRv);
if (aRv.Failed()) {
// Dispatch() may have spun the event loop and we may have already unrooted.
// If so we don't want autoUnpin to try again.
@@ -1889,7 +1892,7 @@ XMLHttpRequestWorker::Open(const nsACString& aMethod,
mTimeout, mResponseType);
++mProxy->mOpenCount;
- runnable->Dispatch(aRv);
+ runnable->Dispatch(Terminating, aRv);
if (aRv.Failed()) {
if (mProxy && !--mProxy->mOpenCount) {
ReleaseProxy();
@@ -1926,7 +1929,7 @@ XMLHttpRequestWorker::SetRequestHeader(const nsACString& aHeader,
RefPtr<SetRequestHeaderRunnable> runnable =
new SetRequestHeaderRunnable(mWorkerPrivate, mProxy, aHeader, aValue);
- runnable->Dispatch(aRv);
+ runnable->Dispatch(Terminating, aRv);
}
void
@@ -1949,7 +1952,7 @@ XMLHttpRequestWorker::SetTimeout(uint32_t aTimeout, ErrorResult& aRv)
RefPtr<SetTimeoutRunnable> runnable =
new SetTimeoutRunnable(mWorkerPrivate, mProxy, aTimeout);
- runnable->Dispatch(aRv);
+ runnable->Dispatch(Terminating, aRv);
}
void
@@ -1972,7 +1975,7 @@ XMLHttpRequestWorker::SetWithCredentials(bool aWithCredentials, ErrorResult& aRv
RefPtr<SetWithCredentialsRunnable> runnable =
new SetWithCredentialsRunnable(mWorkerPrivate, mProxy, aWithCredentials);
- runnable->Dispatch(aRv);
+ runnable->Dispatch(Terminating, aRv);
}
void
@@ -1997,7 +2000,7 @@ XMLHttpRequestWorker::SetMozBackgroundRequest(bool aBackgroundRequest,
RefPtr<SetBackgroundRequestRunnable> runnable =
new SetBackgroundRequestRunnable(mWorkerPrivate, mProxy,
aBackgroundRequest);
- runnable->Dispatch(aRv);
+ runnable->Dispatch(Terminating, aRv);
}
XMLHttpRequestUpload*
@@ -2265,7 +2268,7 @@ XMLHttpRequestWorker::Abort(ErrorResult& aRv)
mProxy->mOuterEventStreamId++;
RefPtr<AbortRunnable> runnable = new AbortRunnable(mWorkerPrivate, mProxy);
- runnable->Dispatch(aRv);
+ runnable->Dispatch(Terminating, aRv);
}
void
@@ -2288,7 +2291,7 @@ XMLHttpRequestWorker::GetResponseHeader(const nsACString& aHeader,
RefPtr<GetResponseHeaderRunnable> runnable =
new GetResponseHeaderRunnable(mWorkerPrivate, mProxy, aHeader,
responseHeader);
- runnable->Dispatch(aRv);
+ runnable->Dispatch(Terminating, aRv);
if (aRv.Failed()) {
return;
}
@@ -2314,7 +2317,7 @@ XMLHttpRequestWorker::GetAllResponseHeaders(nsACString& aResponseHeaders,
nsCString responseHeaders;
RefPtr<GetAllResponseHeadersRunnable> runnable =
new GetAllResponseHeadersRunnable(mWorkerPrivate, mProxy, responseHeaders);
- runnable->Dispatch(aRv);
+ runnable->Dispatch(Terminating, aRv);
if (aRv.Failed()) {
return;
}
@@ -2346,7 +2349,7 @@ XMLHttpRequestWorker::OverrideMimeType(const nsAString& aMimeType, ErrorResult&
RefPtr<OverrideMimeTypeRunnable> runnable =
new OverrideMimeTypeRunnable(mWorkerPrivate, mProxy, aMimeType);
- runnable->Dispatch(aRv);
+ runnable->Dispatch(Terminating, aRv);
}
void
@@ -2382,7 +2385,7 @@ XMLHttpRequestWorker::SetResponseType(XMLHttpRequestResponseType aResponseType,
RefPtr<SetResponseTypeRunnable> runnable =
new SetResponseTypeRunnable(mWorkerPrivate, mProxy, aResponseType);
- runnable->Dispatch(aRv);
+ runnable->Dispatch(Terminating, aRv);
if (aRv.Failed()) {
return;
}