diff options
Diffstat (limited to 'dom/base')
-rw-r--r-- | dom/base/DOMIntersectionObserver.cpp | 37 | ||||
-rw-r--r-- | dom/base/DOMIntersectionObserver.h | 4 | ||||
-rw-r--r-- | dom/base/Element.cpp | 81 | ||||
-rw-r--r-- | dom/base/Element.h | 4 | ||||
-rwxr-xr-x | dom/base/File.cpp | 2 | ||||
-rw-r--r-- | dom/base/FragmentOrElement.cpp | 8 | ||||
-rw-r--r-- | dom/base/FragmentOrElement.h | 8 | ||||
-rw-r--r-- | dom/base/Location.cpp | 20 | ||||
-rw-r--r-- | dom/base/StructuredCloneHolder.cpp | 34 | ||||
-rw-r--r-- | dom/base/WebSocket.cpp | 8 | ||||
-rw-r--r-- | dom/base/nsContentPolicyUtils.h | 1 | ||||
-rw-r--r-- | dom/base/nsDocument.cpp | 3 | ||||
-rw-r--r-- | dom/base/nsFrameMessageManager.cpp | 5 | ||||
-rw-r--r-- | dom/base/nsGkAtomList.h | 2 | ||||
-rw-r--r-- | dom/base/nsGlobalWindow.cpp | 4 | ||||
-rw-r--r-- | dom/base/nsIContentPolicy.idl | 2 | ||||
-rw-r--r-- | dom/base/nsIContentPolicyBase.idl | 16 | ||||
-rw-r--r-- | dom/base/nsINode.cpp | 20 | ||||
-rw-r--r-- | dom/base/nsISimpleContentPolicy.idl | 2 | ||||
-rw-r--r-- | dom/base/nsImageLoadingContent.cpp | 36 | ||||
-rw-r--r-- | dom/base/nsImageLoadingContent.h | 10 | ||||
-rw-r--r-- | dom/base/nsNodeUtils.cpp | 9 | ||||
-rw-r--r-- | dom/base/nsStructuredCloneContainer.cpp | 2 | ||||
-rw-r--r-- | dom/base/test/test_intersectionobservers.html | 59 |
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 () { |