new file mode 100644
--- /dev/null
+++ b/dom/base/ImageTracker.cpp
@@ -0,0 +1,161 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* table of images used in a document, for batch locking/unlocking and
+ * animating */
+
+#include "ImageTracker.h"
+
+namespace mozilla {
+namespace dom {
+
+ImageTracker::ImageTracker()
+ : mLockingImages(false)
+ , mAnimatingImages(true)
+{
+}
+
+ImageTracker::~ImageTracker()
+{
+ SetImageLockingState(false);
+}
+
+nsresult
+ImageTracker::AddImage(imgIRequest* aImage)
+{
+ MOZ_ASSERT(aImage);
+
+ // See if the image is already in the hashtable. If it is, get the old count.
+ uint32_t oldCount = 0;
+ mImageTracker.Get(aImage, &oldCount);
+
+ // Put the image in the hashtable, with the proper count.
+ mImageTracker.Put(aImage, oldCount + 1);
+
+ nsresult rv = NS_OK;
+
+ // If this is the first insertion and we're locking images, lock this image
+ // too.
+ if (oldCount == 0 && mLockingImages) {
+ rv = aImage->LockImage();
+ }
+
+ // If this is the first insertion and we're animating images, request
+ // that this image be animated too.
+ if (oldCount == 0 && mAnimatingImages) {
+ nsresult rv2 = aImage->IncrementAnimationConsumers();
+ rv = NS_SUCCEEDED(rv) ? rv2 : rv;
+ }
+
+ return rv;
+}
+
+nsresult
+ImageTracker::RemoveImage(imgIRequest* aImage, uint32_t aFlags)
+{
+ NS_ENSURE_ARG_POINTER(aImage);
+
+ // Get the old count. It should exist and be > 0.
+ uint32_t count = 0;
+ DebugOnly<bool> found = mImageTracker.Get(aImage, &count);
+ MOZ_ASSERT(found, "Removing image that wasn't in the tracker!");
+ MOZ_ASSERT(count > 0, "Entry in the cache tracker with count 0!");
+
+ // We're removing, so decrement the count.
+ count--;
+
+ // If the count is now zero, remove from the tracker.
+ // Otherwise, set the new value.
+ if (count != 0) {
+ mImageTracker.Put(aImage, count);
+ return NS_OK;
+ }
+
+ mImageTracker.Remove(aImage);
+
+ nsresult rv = NS_OK;
+
+ // Now that we're no longer tracking this image, unlock it if we'd
+ // previously locked it.
+ if (mLockingImages) {
+ rv = aImage->UnlockImage();
+ }
+
+ // If we're animating images, remove our request to animate this one.
+ if (mAnimatingImages) {
+ nsresult rv2 = aImage->DecrementAnimationConsumers();
+ rv = NS_SUCCEEDED(rv) ? rv2 : rv;
+ }
+
+ if (aFlags & REQUEST_DISCARD) {
+ // Request that the image be discarded if nobody else holds a lock on it.
+ // Do this even if !mLockingImages, because even if we didn't just unlock
+ // this image, it might still be a candidate for discarding.
+ aImage->RequestDiscard();
+ }
+
+ return rv;
+}
+
+nsresult
+ImageTracker::SetImageLockingState(bool aLocked)
+{
+ if (XRE_IsContentProcess() &&
+ !Preferences::GetBool("image.mem.allow_locking_in_content_processes", true)) {
+ return NS_OK;
+ }
+
+ // If there's no change, there's nothing to do.
+ if (mLockingImages == aLocked)
+ return NS_OK;
+
+ // Otherwise, iterate over our images and perform the appropriate action.
+ for (auto iter = mImageTracker.Iter(); !iter.Done(); iter.Next()) {
+ imgIRequest* image = iter.Key();
+ if (aLocked) {
+ image->LockImage();
+ } else {
+ image->UnlockImage();
+ }
+ }
+
+ // Update state.
+ mLockingImages = aLocked;
+
+ return NS_OK;
+}
+
+void
+ImageTracker::SetImagesNeedAnimating(bool aAnimating)
+{
+ // If there's no change, there's nothing to do.
+ if (mAnimatingImages == aAnimating)
+ return;
+
+ // Otherwise, iterate over our images and perform the appropriate action.
+ for (auto iter = mImageTracker.Iter(); !iter.Done(); iter.Next()) {
+ imgIRequest* image = iter.Key();
+ if (aAnimating) {
+ image->IncrementAnimationConsumers();
+ } else {
+ image->DecrementAnimationConsumers();
+ }
+ }
+
+ // Update state.
+ mAnimatingImages = aAnimating;
+}
+
+void
+ImageTracker::RequestDiscardAll()
+{
+ for (auto iter = mImageTracker.Iter(); !iter.Done(); iter.Next()) {
+ iter.Key()->RequestDiscard();
+ }
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/base/ImageTracker.h
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* table of images used in a document, for batch locking/unlocking and
+ * animating */
+
+#ifndef mozilla_dom_ImageTracker
+#define mozilla_dom_ImageTracker
+
+#include "nsDataHashtable.h"
+#include "nsHashKeys.h"
+
+class imgIRequest;
+
+namespace mozilla {
+namespace dom {
+
+/*
+ * Image Tracking
+ *
+ * Style and content images register their imgIRequests with their document's
+ * image tracker, so that we can efficiently tell all descendant images when
+ * they are and are not visible. When an image is on-screen, we want to call
+ * LockImage() on it so that it doesn't do things like discarding frame data
+ * to save memory. The PresShell informs its document's image tracker whether
+ * its images should be locked or not via SetImageLockingState().
+ *
+ * See bug 512260.
+ */
+class ImageTracker
+{
+public:
+ ImageTracker();
+ ImageTracker(const ImageTracker&) = delete;
+ ImageTracker& operator=(const ImageTracker&) = delete;
+
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageTracker)
+
+ nsresult AddImage(imgIRequest* aImage);
+
+ enum { REQUEST_DISCARD = 0x1 };
+ nsresult RemoveImage(imgIRequest* aImage, uint32_t aFlags = 0);
+
+ // Makes the images on this document locked/unlocked. By default, the locking
+ // state is unlocked/false.
+ nsresult SetImageLockingState(bool aLocked);
+
+ // Makes the images on this document capable of having their animation
+ // active or suspended. An Image will animate as long as at least one of its
+ // owning Documents needs it to animate; otherwise it can suspend.
+ void SetImagesNeedAnimating(bool aAnimating);
+
+ void RequestDiscardAll();
+
+private:
+ ~ImageTracker();
+
+ nsDataHashtable<nsPtrHashKey<imgIRequest>, uint32_t> mImageTracker;
+ bool mLockingImages;
+ bool mAnimatingImages;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_ImageTracker
--- a/dom/base/ScriptSettings.cpp
+++ b/dom/base/ScriptSettings.cpp
@@ -781,18 +781,18 @@ AutoJSContext::AutoJSContext(MOZ_GUARD_O
: mCx(nullptr)
{
JS::AutoSuppressGCAnalysis nogc;
MOZ_ASSERT(!mCx, "mCx should not be initialized!");
MOZ_ASSERT(NS_IsMainThread());
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
- if (IsJSAPIActive()) {
- mCx = danger::GetJSContext();
+ if (dom::IsJSAPIActive()) {
+ mCx = dom::danger::GetJSContext();
} else {
mJSAPI.Init();
mCx = mJSAPI.cx();
}
}
AutoJSContext::operator JSContext*() const
{
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -178,16 +178,17 @@ EXPORTS.mozilla.dom += [
'EventSource.h',
'File.h',
'FileList.h',
'FileReader.h',
'FormData.h',
'FragmentOrElement.h',
'FromParser.h',
'ImageEncoder.h',
+ 'ImageTracker.h',
'ImportManager.h',
'Link.h',
'Location.h',
'MutableBlobStorage.h',
'NameSpaceConstants.h',
'Navigator.h',
'NodeInfo.h',
'NodeInfoInlines.h',
@@ -239,16 +240,17 @@ UNIFIED_SOURCES += [
'Element.cpp',
'EventSource.cpp',
'File.cpp',
'FileList.cpp',
'FileReader.cpp',
'FormData.cpp',
'FragmentOrElement.cpp',
'ImageEncoder.cpp',
+ 'ImageTracker.cpp',
'ImportManager.cpp',
'Link.cpp',
'Location.cpp',
'MultipartBlobImpl.cpp',
'MutableBlobStorage.cpp',
'Navigator.cpp',
'NodeInfo.cpp',
'NodeIterator.cpp',
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -207,16 +207,17 @@
#include "mozilla/dom/AnimatableBinding.h"
#include "mozilla/dom/AnonymousContent.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/DocumentFragment.h"
#include "mozilla/dom/DocumentTimeline.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/HTMLBodyElement.h"
#include "mozilla/dom/HTMLInputElement.h"
+#include "mozilla/dom/ImageTracker.h"
#include "mozilla/dom/MediaQueryList.h"
#include "mozilla/dom/NodeFilterBinding.h"
#include "mozilla/OwningNonNull.h"
#include "mozilla/dom/TabChild.h"
#include "mozilla/dom/UndoManager.h"
#include "mozilla/dom/WebComponentsBinding.h"
#include "mozilla/dom/CustomElementsRegistryBinding.h"
#include "mozilla/dom/CustomElementsRegistry.h"
@@ -1326,17 +1327,16 @@ nsIDocument::nsIDocument()
PR_INIT_CLIST(&mDOMMediaQueryLists);
}
// NOTE! nsDocument::operator new() zeroes out all members, so don't
// bother initializing members to 0.
nsDocument::nsDocument(const char* aContentType)
: nsIDocument()
- , mAnimatingImages(true)
, mViewportType(Unknown)
{
SetContentTypeInternal(nsDependentCString(aContentType));
if (gDocumentLeakPRLog)
MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug,
("DOCUMENT %p created", this));
@@ -1526,21 +1526,16 @@ nsDocument::~nsDocument()
}
delete mHeaderData;
ClearAllBoxObjects();
mPendingTitleChangeEvent.Revoke();
- // We don't want to leave residual locks on images. Make sure we're in an
- // unlocked state, and then clear the table.
- SetImageLockingState(false);
- mImageTracker.Clear();
-
mPlugins.Clear();
}
NS_INTERFACE_TABLE_HEAD(nsDocument)
NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
NS_INTERFACE_TABLE_BEGIN
NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(nsDocument, nsISupports, nsINode)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsINode)
@@ -3722,19 +3717,17 @@ nsDocument::DeleteShell()
}
if (nsPresContext* presContext = mPresShell->GetPresContext()) {
presContext->RefreshDriver()->CancelPendingEvents(this);
}
// When our shell goes away, request that all our images be immediately
// discarded, so we don't carry around decoded image data for a document we
// no longer intend to paint.
- for (auto iter = mImageTracker.Iter(); !iter.Done(); iter.Next()) {
- iter.Key()->RequestDiscard();
- }
+ ImageTracker()->RequestDiscardAll();
// Now that we no longer have a shell, we need to forget about any FontFace
// objects for @font-face rules that came from the style set.
RebuildUserFontSet();
mPresShell = nullptr;
mStyleSetFilled = false;
}
@@ -8716,17 +8709,17 @@ nsDocument::OnPageShow(bool aPersisted,
mIsShowing = true;
}
if (mAnimationController) {
mAnimationController->OnPageShow();
}
if (aPersisted) {
- SetImagesNeedAnimating(true);
+ ImageTracker()->SetImagesNeedAnimating(true);
}
UpdateVisibilityState();
nsCOMPtr<EventTarget> target = aDispatchStartTarget;
if (!target) {
target = do_QueryInterface(GetWindow());
}
@@ -8811,17 +8804,17 @@ nsDocument::OnPageHide(bool aPersisted,
if (mAnimationController) {
mAnimationController->OnPageHide();
}
// We do not stop the animations (bug 1024343)
// when the page is refreshing while being dragged out
nsDocShell* docShell = mDocumentContainer.get();
if (aPersisted && !(docShell && docShell->InFrameSwap())) {
- SetImagesNeedAnimating(false);
+ ImageTracker()->SetImagesNeedAnimating(false);
}
ExitPointerLock();
// Now send out a PageHide event.
nsCOMPtr<EventTarget> target = aDispatchStartTarget;
if (!target) {
target = do_QueryInterface(GetWindow());
@@ -10035,91 +10028,23 @@ nsIDocument::WarnOnceAbout(DocumentWarni
nsContentUtils::ReportToConsole(flags,
NS_LITERAL_CSTRING("DOM Core"), this,
nsContentUtils::eDOM_PROPERTIES,
kDocumentWarnings[aWarning],
aParams,
aParamsLength);
}
-nsresult
-nsDocument::AddImage(imgIRequest* aImage)
-{
- NS_ENSURE_ARG_POINTER(aImage);
-
- // See if the image is already in the hashtable. If it is, get the old count.
- uint32_t oldCount = 0;
- mImageTracker.Get(aImage, &oldCount);
-
- // Put the image in the hashtable, with the proper count.
- mImageTracker.Put(aImage, oldCount + 1);
-
- nsresult rv = NS_OK;
-
- // If this is the first insertion and we're locking images, lock this image
- // too.
- if (oldCount == 0 && mLockingImages) {
- rv = aImage->LockImage();
- }
-
- // If this is the first insertion and we're animating images, request
- // that this image be animated too.
- if (oldCount == 0 && mAnimatingImages) {
- nsresult rv2 = aImage->IncrementAnimationConsumers();
- rv = NS_SUCCEEDED(rv) ? rv2 : rv;
- }
-
- return rv;
-}
-
-nsresult
-nsDocument::RemoveImage(imgIRequest* aImage, uint32_t aFlags)
-{
- NS_ENSURE_ARG_POINTER(aImage);
-
- // Get the old count. It should exist and be > 0.
- uint32_t count = 0;
- DebugOnly<bool> found = mImageTracker.Get(aImage, &count);
- MOZ_ASSERT(found, "Removing image that wasn't in the tracker!");
- MOZ_ASSERT(count > 0, "Entry in the cache tracker with count 0!");
-
- // We're removing, so decrement the count.
- count--;
-
- // If the count is now zero, remove from the tracker.
- // Otherwise, set the new value.
- if (count != 0) {
- mImageTracker.Put(aImage, count);
- return NS_OK;
- }
-
- mImageTracker.Remove(aImage);
-
- nsresult rv = NS_OK;
-
- // Now that we're no longer tracking this image, unlock it if we'd
- // previously locked it.
- if (mLockingImages) {
- rv = aImage->UnlockImage();
- }
-
- // If we're animating images, remove our request to animate this one.
- if (mAnimatingImages) {
- nsresult rv2 = aImage->DecrementAnimationConsumers();
- rv = NS_SUCCEEDED(rv) ? rv2 : rv;
- }
-
- if (aFlags & REQUEST_DISCARD) {
- // Request that the image be discarded if nobody else holds a lock on it.
- // Do this even if !mLockingImages, because even if we didn't just unlock
- // this image, it might still be a candidate for discarding.
- aImage->RequestDiscard();
- }
-
- return rv;
+mozilla::dom::ImageTracker*
+nsIDocument::ImageTracker()
+{
+ if (!mImageTracker) {
+ mImageTracker = new mozilla::dom::ImageTracker;
+ }
+ return mImageTracker;
}
nsresult
nsDocument::AddPlugin(nsIObjectLoadingContent* aPlugin)
{
MOZ_ASSERT(aPlugin);
if (!mPlugins.PutEntry(aPlugin)) {
return NS_ERROR_OUT_OF_MEMORY;
@@ -10178,65 +10103,16 @@ nsDocument::NotifyMediaFeatureValuesChan
nsCOMPtr<nsIContent> content = iter.Get()->GetKey();
if (content->IsHTMLElement(nsGkAtoms::img)) {
auto* imageElement = static_cast<HTMLImageElement*>(content.get());
imageElement->MediaFeatureValuesChanged();
}
}
}
-nsresult
-nsDocument::SetImageLockingState(bool aLocked)
-{
- if (XRE_IsContentProcess() &&
- !Preferences::GetBool("image.mem.allow_locking_in_content_processes", true)) {
- return NS_OK;
- }
-
- // If there's no change, there's nothing to do.
- if (mLockingImages == aLocked)
- return NS_OK;
-
- // Otherwise, iterate over our images and perform the appropriate action.
- for (auto iter = mImageTracker.Iter(); !iter.Done(); iter.Next()) {
- imgIRequest* image = iter.Key();
- if (aLocked) {
- image->LockImage();
- } else {
- image->UnlockImage();
- }
- }
-
- // Update state.
- mLockingImages = aLocked;
-
- return NS_OK;
-}
-
-void
-nsDocument::SetImagesNeedAnimating(bool aAnimating)
-{
- // If there's no change, there's nothing to do.
- if (mAnimatingImages == aAnimating)
- return;
-
- // Otherwise, iterate over our images and perform the appropriate action.
- for (auto iter = mImageTracker.Iter(); !iter.Done(); iter.Next()) {
- imgIRequest* image = iter.Key();
- if (aAnimating) {
- image->IncrementAnimationConsumers();
- } else {
- image->DecrementAnimationConsumers();
- }
- }
-
- // Update state.
- mAnimatingImages = aAnimating;
-}
-
already_AddRefed<Touch>
nsIDocument::CreateTouch(nsGlobalWindow* aView,
EventTarget* aTarget,
int32_t aIdentifier,
int32_t aPageX, int32_t aPageY,
int32_t aScreenX, int32_t aScreenY,
int32_t aClientX, int32_t aClientY,
int32_t aRadiusX, int32_t aRadiusY,
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -89,16 +89,17 @@ class nsHtml5TreeOpExecutor;
class nsDocumentOnStack;
class nsISecurityConsoleMessage;
class nsPIBoxObject;
namespace mozilla {
class EventChainPreVisitor;
namespace dom {
class BoxObject;
+class ImageTracker;
class UndoManager;
struct LifecycleCallbacks;
class CallbackFunction;
struct FullscreenRequest : public LinkedListElement<FullscreenRequest>
{
explicit FullscreenRequest(Element* aElement);
FullscreenRequest(const FullscreenRequest&) = delete;
@@ -885,18 +886,16 @@ public:
GetPendingAnimationTracker() final override
{
return mPendingAnimationTracker;
}
virtual mozilla::PendingAnimationTracker*
GetOrCreatePendingAnimationTracker() override;
- void SetImagesNeedAnimating(bool aAnimating) override;
-
virtual void SuppressEventHandling(SuppressionType aWhat,
uint32_t aIncrease) override;
virtual void UnsuppressEventHandlingAndFireEvents(SuppressionType aWhat,
bool aFireEvents) override;
void DecreaseEventSuppression() {
MOZ_ASSERT(mEventsSuppressed);
@@ -979,20 +978,16 @@ public:
virtual Element *GetElementById(const nsAString& aElementId) override;
virtual const nsTArray<Element*>* GetAllElementsForId(const nsAString& aElementId) const override;
virtual Element *LookupImageElement(const nsAString& aElementId) override;
virtual void MozSetImageElement(const nsAString& aImageElementId,
Element* aElement) override;
- virtual nsresult AddImage(imgIRequest* aImage) override;
- virtual nsresult RemoveImage(imgIRequest* aImage, uint32_t aFlags) override;
- virtual nsresult SetImageLockingState(bool aLocked) override;
-
// AddPlugin adds a plugin-related element to mPlugins when the element is
// added to the tree.
virtual nsresult AddPlugin(nsIObjectLoadingContent* aPlugin) override;
// RemovePlugin removes a plugin-related element to mPlugins when the
// element is removed from the tree.
virtual void RemovePlugin(nsIObjectLoadingContent* aPlugin) override;
// GetPlugins returns the plugin-related elements from
// the frame and any subframes.
@@ -1412,22 +1407,16 @@ public:
bool mHasWarnedAboutBoxObjects:1;
bool mDelayFrameLoaderInitialization:1;
bool mSynchronousDOMContentLoaded:1;
bool mInXBLUpdate:1;
- // Whether we're currently holding a lock on all of our images.
- bool mLockingImages:1;
-
- // Whether we currently require our images to animate
- bool mAnimatingImages:1;
-
// Whether we're currently under a FlushPendingNotifications call to
// our presshell. This is used to handle flush reentry correctly.
bool mInFlush:1;
// Parser aborted. True if the parser of this document was forcibly
// terminated instead of letting it finish at its own pace.
bool mParserAborted:1;
@@ -1587,19 +1576,16 @@ private:
RefPtr<mozilla::dom::DOMImplementation> mDOMImplementation;
RefPtr<nsContentList> mImageMaps;
nsCString mScrollToRef;
uint8_t mScrolledToRefAlready : 1;
uint8_t mChangeScrollPosWhenScrollingToRef : 1;
- // Tracking for images in the document.
- nsDataHashtable< nsPtrHashKey<imgIRequest>, uint32_t> mImageTracker;
-
// Tracking for plugins in the document.
nsTHashtable< nsPtrHashKey<nsIObjectLoadingContent> > mPlugins;
RefPtr<mozilla::dom::UndoManager> mUndoManager;
RefPtr<mozilla::dom::DocumentTimeline> mDocumentTimeline;
mozilla::LinkedList<mozilla::dom::DocumentTimeline> mTimelines;
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -130,16 +130,17 @@ class DOMStringList;
class Element;
struct ElementCreationOptions;
struct ElementRegistrationOptions;
class Event;
class EventTarget;
class FontFaceSet;
class FrameRequestCallback;
struct FullscreenRequest;
+class ImageTracker;
class ImportManager;
class HTMLBodyElement;
struct LifecycleCallbackArgs;
class Link;
class Location;
class MediaQueryList;
class GlobalObject;
class NodeFilter;
@@ -2066,21 +2067,16 @@ public:
virtual mozilla::PendingAnimationTracker* GetPendingAnimationTracker() = 0;
// Gets the tracker for animations that are waiting to start and
// creates it if it doesn't already exist. As a result, the return value
// will never be nullptr.
virtual mozilla::PendingAnimationTracker*
GetOrCreatePendingAnimationTracker() = 0;
- // Makes the images on this document capable of having their animation
- // active or suspended. An Image will animate as long as at least one of its
- // owning Documents needs it to animate; otherwise it can suspend.
- virtual void SetImagesNeedAnimating(bool aAnimating) = 0;
-
enum SuppressionType {
eAnimationsOnly = 0x1,
// Note that suppressing events also suppresses animation frames, so
// there's no need to split out events in its own bitmask.
eEvents = 0x3,
};
@@ -2349,39 +2345,17 @@ public:
* throttled. We throttle requestAnimationFrame for documents which aren't
* visible (e.g. scrolled out of the viewport).
*/
bool ShouldThrottleFrameRequests();
// This returns true when the document tree is being teared down.
bool InUnlinkOrDeletion() { return mInUnlinkOrDeletion; }
- /*
- * Image Tracking
- *
- * Style and content images register their imgIRequests with their document
- * so that the document can efficiently tell all descendant images when they
- * are and are not visible. When an image is on-screen, we want to call
- * LockImage() on it so that it doesn't do things like discarding frame data
- * to save memory. The PresShell informs the document whether its images
- * should be locked or not via SetImageLockingState().
- *
- * See bug 512260.
- */
-
- // Add/Remove images from the document image tracker
- virtual nsresult AddImage(imgIRequest* aImage) = 0;
- // If the REQUEST_DISCARD flag is passed then if the lock count is zero we
- // will request the image be discarded now (instead of waiting).
- enum { REQUEST_DISCARD = 0x1 };
- virtual nsresult RemoveImage(imgIRequest* aImage, uint32_t aFlags = 0) = 0;
-
- // Makes the images on this document locked/unlocked. By default, the locking
- // state is unlocked/false.
- virtual nsresult SetImageLockingState(bool aLocked) = 0;
+ mozilla::dom::ImageTracker* ImageTracker();
virtual nsresult AddPlugin(nsIObjectLoadingContent* aPlugin) = 0;
virtual void RemovePlugin(nsIObjectLoadingContent* aPlugin) = 0;
virtual void GetPlugins(nsTArray<nsIObjectLoadingContent*>& aPlugins) = 0;
virtual nsresult AddResponsiveContent(nsIContent* aContent) = 0;
virtual void RemoveResponsiveContent(nsIContent* aContent) = 0;
virtual void NotifyMediaFeatureValuesChanged() = 0;
@@ -2922,16 +2896,19 @@ protected:
// which in turn holds a strong reference to this mNodeInfoManager.
nsNodeInfoManager* mNodeInfoManager;
RefPtr<mozilla::css::Loader> mCSSLoader;
RefPtr<mozilla::css::ImageLoader> mStyleImageLoader;
RefPtr<nsHTMLStyleSheet> mAttrStyleSheet;
RefPtr<nsHTMLCSSStyleSheet> mStyleAttrStyleSheet;
RefPtr<mozilla::SVGAttrAnimationRuleProcessor> mSVGAttrAnimationRuleProcessor;
+ // Tracking for images in the document.
+ RefPtr<mozilla::dom::ImageTracker> mImageTracker;
+
// The set of all object, embed, applet, video/audio elements or
// nsIObjectLoadingContent or nsIDocumentActivity for which this is the
// owner document. (They might not be in the document.)
// These are non-owning pointers, the elements are responsible for removing
// themselves when they go away.
nsAutoPtr<nsTHashtable<nsPtrHashKey<nsISupports> > > mActivityObservers;
// The set of all links that need their status resolved. Links must add themselves
--- a/dom/base/nsImageLoadingContent.cpp
+++ b/dom/base/nsImageLoadingContent.cpp
@@ -41,25 +41,27 @@
#include "nsSVGEffects.h"
#include "gfxPrefs.h"
#include "mozAutoDocUpdate.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/EventStates.h"
#include "mozilla/dom/Element.h"
+#include "mozilla/dom/ImageTracker.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/Preferences.h"
#ifdef LoadImage
// Undefine LoadImage to prevent naming conflict with Windows.
#undef LoadImage
#endif
using namespace mozilla;
+using namespace mozilla::dom;
#ifdef DEBUG_chb
static void PrintReqURL(imgIRequest* req) {
if (!req) {
printf("(null req)\n");
return;
}
@@ -1469,21 +1471,21 @@ nsImageLoadingContent::TrackImage(imgIRe
nsIFrame* frame = GetOurPrimaryFrame();
if ((frame && frame->GetVisibility() == Visibility::APPROXIMATELY_NONVISIBLE) ||
(!frame && !mFrameCreateCalled)) {
return;
}
if (aImage == mCurrentRequest && !(mCurrentRequestFlags & REQUEST_IS_TRACKED)) {
mCurrentRequestFlags |= REQUEST_IS_TRACKED;
- doc->AddImage(mCurrentRequest);
+ doc->ImageTracker()->AddImage(mCurrentRequest);
}
if (aImage == mPendingRequest && !(mPendingRequestFlags & REQUEST_IS_TRACKED)) {
mPendingRequestFlags |= REQUEST_IS_TRACKED;
- doc->AddImage(mPendingRequest);
+ doc->ImageTracker()->AddImage(mPendingRequest);
}
}
void
nsImageLoadingContent::UntrackImage(imgIRequest* aImage,
const Maybe<OnNonvisible>& aNonvisibleAction
/* = Nothing() */)
{
@@ -1496,32 +1498,34 @@ nsImageLoadingContent::UntrackImage(imgI
// We may not be in the document. If we outlived our document that's fine,
// because the document empties out the tracker and unlocks all locked images
// on destruction. But if we were never in the document we may need to force
// discarding the image here, since this is the only chance we have.
nsIDocument* doc = GetOurCurrentDoc();
if (aImage == mCurrentRequest) {
if (doc && (mCurrentRequestFlags & REQUEST_IS_TRACKED)) {
mCurrentRequestFlags &= ~REQUEST_IS_TRACKED;
- doc->RemoveImage(mCurrentRequest,
- aNonvisibleAction == Some(OnNonvisible::DISCARD_IMAGES)
- ? nsIDocument::REQUEST_DISCARD
- : 0);
+ doc->ImageTracker()->RemoveImage(
+ mCurrentRequest,
+ aNonvisibleAction == Some(OnNonvisible::DISCARD_IMAGES)
+ ? ImageTracker::REQUEST_DISCARD
+ : 0);
} else if (aNonvisibleAction == Some(OnNonvisible::DISCARD_IMAGES)) {
// If we're not in the document we may still need to be discarded.
aImage->RequestDiscard();
}
}
if (aImage == mPendingRequest) {
if (doc && (mPendingRequestFlags & REQUEST_IS_TRACKED)) {
mPendingRequestFlags &= ~REQUEST_IS_TRACKED;
- doc->RemoveImage(mPendingRequest,
- aNonvisibleAction == Some(OnNonvisible::DISCARD_IMAGES)
- ? nsIDocument::REQUEST_DISCARD
- : 0);
+ doc->ImageTracker()->RemoveImage(
+ mPendingRequest,
+ aNonvisibleAction == Some(OnNonvisible::DISCARD_IMAGES)
+ ? ImageTracker::REQUEST_DISCARD
+ : 0);
} else if (aNonvisibleAction == Some(OnNonvisible::DISCARD_IMAGES)) {
// If we're not in the document we may still need to be discarded.
aImage->RequestDiscard();
}
}
}
--- a/gfx/thebes/gfxSVGGlyphs.cpp
+++ b/gfx/thebes/gfxSVGGlyphs.cpp
@@ -26,16 +26,17 @@
#include "mozilla/LoadInfo.h"
#include "nsSVGUtils.h"
#include "nsHostObjectProtocolHandler.h"
#include "nsContentUtils.h"
#include "gfxFont.h"
#include "nsSMILAnimationController.h"
#include "gfxContext.h"
#include "harfbuzz/hb.h"
+#include "mozilla/dom/ImageTracker.h"
#define SVG_CONTENT_TYPE NS_LITERAL_CSTRING("image/svg+xml")
#define UTF8_CHARSET NS_LITERAL_CSTRING("utf-8")
using namespace mozilla;
typedef mozilla::dom::Element Element;
@@ -165,17 +166,17 @@ gfxSVGGlyphsDocument::SetupPresentation(
}
mDocument->FlushPendingNotifications(Flush_Layout);
nsSMILAnimationController* controller = mDocument->GetAnimationController();
if (controller) {
controller->Resume(nsSMILTimeContainer::PAUSE_IMAGE);
}
- mDocument->SetImagesNeedAnimating(true);
+ mDocument->ImageTracker()->SetImagesNeedAnimating(true);
mViewer = viewer;
mPresShell = presShell;
mPresShell->AddPostRefreshObserver(this);
return NS_OK;
}
--- a/image/SVGDocumentWrapper.cpp
+++ b/image/SVGDocumentWrapper.cpp
@@ -25,16 +25,17 @@
#include "nsSMILAnimationController.h"
#include "nsServiceManagerUtils.h"
#include "mozilla/dom/SVGSVGElement.h"
#include "nsSVGEffects.h"
#include "mozilla/dom/SVGAnimatedLength.h"
#include "nsMimeTypes.h"
#include "DOMSVGLength.h"
#include "nsDocument.h"
+#include "mozilla/dom/ImageTracker.h"
// undef the GetCurrentTime macro defined in WinBase.h from the MS Platform SDK
#undef GetCurrentTime
namespace mozilla {
using namespace dom;
using namespace gfx;
@@ -149,17 +150,17 @@ SVGDocumentWrapper::StartAnimation()
}
nsIDocument* doc = mViewer->GetDocument();
if (doc) {
nsSMILAnimationController* controller = doc->GetAnimationController();
if (controller) {
controller->Resume(nsSMILTimeContainer::PAUSE_IMAGE);
}
- doc->SetImagesNeedAnimating(true);
+ doc->ImageTracker()->SetImagesNeedAnimating(true);
}
}
void
SVGDocumentWrapper::StopAnimation()
{
// Can be called for animated images during shutdown, after we've
// already Observe()'d XPCOM shutdown and cleared out our mViewer pointer.
@@ -168,17 +169,17 @@ SVGDocumentWrapper::StopAnimation()
}
nsIDocument* doc = mViewer->GetDocument();
if (doc) {
nsSMILAnimationController* controller = doc->GetAnimationController();
if (controller) {
controller->Pause(nsSMILTimeContainer::PAUSE_IMAGE);
}
- doc->SetImagesNeedAnimating(false);
+ doc->ImageTracker()->SetImagesNeedAnimating(false);
}
}
void
SVGDocumentWrapper::ResetAnimation()
{
SVGSVGElement* svgElem = GetRootSVGElem();
if (!svgElem) {
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -190,16 +190,17 @@
#include "nsLayoutStylesheetCache.h"
#include "mozilla/layers/InputAPZContext.h"
#include "mozilla/layers/ScrollInputMethods.h"
#include "nsStyleSet.h"
#include "mozilla/StyleSetHandle.h"
#include "mozilla/StyleSetHandleInlines.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/StyleSheetInlines.h"
+#include "mozilla/dom/ImageTracker.h"
#ifdef ANDROID
#include "nsIDocShellTreeOwner.h"
#endif
#ifdef MOZ_B2G
#include "nsIHardwareKeyHandler.h"
#endif
@@ -10937,17 +10938,17 @@ PresShell::SetIsActive(bool aIsActive)
* dependent factors changes.
*/
nsresult
PresShell::UpdateImageLockingState()
{
// We're locked if we're both thawed and active.
bool locked = !mFrozen && mIsActive;
- nsresult rv = mDocument->SetImageLockingState(locked);
+ nsresult rv = mDocument->ImageTracker()->SetImageLockingState(locked);
if (locked) {
// Request decodes for visible image frames; we want to start decoding as
// quickly as possible when we get foregrounded to minimize flashing.
for (auto iter = mApproximatelyVisibleFrames.Iter(); !iter.Done(); iter.Next()) {
nsImageFrame* imageFrame = do_QueryFrame(iter.Get()->GetKey());
if (imageFrame) {
imageFrame->MaybeDecodeForPredictedSize();
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -28,16 +28,17 @@
#include "nsBidiUtils.h"
#include "nsLayoutUtils.h"
#include "imgIRequest.h"
#include "imgIContainer.h"
#include "CounterStyleManager.h"
#include "mozilla/dom/AnimationEffectReadOnlyBinding.h" // for PlaybackDirection
+#include "mozilla/dom/ImageTracker.h"
#include "mozilla/Likely.h"
#include "nsIURI.h"
#include "nsIDocument.h"
#include <algorithm>
using namespace mozilla;
static_assert((((1 << nsStyleStructID_Length) - 1) &
@@ -2006,17 +2007,17 @@ nsStyleImage::TrackImage(nsPresContext*
// Sanity
MOZ_ASSERT(!mImageTracked, "Already tracking image!");
MOZ_ASSERT(mType == eStyleImageType_Image,
"Can't track image when there isn't one!");
// Register the image with the document
nsIDocument* doc = aContext->Document();
if (doc) {
- doc->AddImage(mImage);
+ doc->ImageTracker()->AddImage(mImage);
}
// Mark state
#ifdef DEBUG
mImageTracked = true;
#endif
}
@@ -2026,17 +2027,17 @@ nsStyleImage::UntrackImage(nsPresContext
// Sanity
MOZ_ASSERT(mImageTracked, "Image not tracked!");
MOZ_ASSERT(mType == eStyleImageType_Image,
"Can't untrack image when there isn't one!");
// Unregister the image with the document
nsIDocument* doc = aContext->Document();
if (doc) {
- doc->RemoveImage(mImage);
+ doc->ImageTracker()->RemoveImage(mImage);
}
// Mark state
#ifdef DEBUG
mImageTracked = false;
#endif
}
@@ -3433,17 +3434,17 @@ nsStyleContentData::TrackImage(nsPresCon
MOZ_ASSERT(mType == eStyleContentType_Image,
"Trying to do image tracking on non-image!");
MOZ_ASSERT(mContent.mImage,
"Can't track image when there isn't one!");
// Register the image with the document
nsIDocument* doc = aContext->Document();
if (doc) {
- doc->AddImage(mContent.mImage);
+ doc->ImageTracker()->AddImage(mContent.mImage);
}
// Mark state
#ifdef DEBUG
mImageTracked = true;
#endif
}
@@ -3455,17 +3456,17 @@ nsStyleContentData::UntrackImage(nsPresC
MOZ_ASSERT(mType == eStyleContentType_Image,
"Trying to do image tracking on non-image!");
MOZ_ASSERT(mContent.mImage,
"Can't untrack image when there isn't one!");
// Unregister the image with the document
nsIDocument* doc = aContext->Document();
if (doc) {
- doc->RemoveImage(mContent.mImage);
+ doc->ImageTracker()->RemoveImage(mContent.mImage);
}
// Mark state
#ifdef DEBUG
mImageTracked = false;
#endif
}