summaryrefslogtreecommitdiffstats
path: root/dom/base
diff options
context:
space:
mode:
Diffstat (limited to 'dom/base')
-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
24 files changed, 251 insertions, 126 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 () {