Bug 1698238 return default dictionary from GetUserMediaRequest#getConstraints() if...
[gecko.git] / dom / base / ImageTracker.cpp
blobaf601e8cefee80c052df789a4d377622802d5407
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* table of images used in a document, for batch locking/unlocking and
8 * animating */
10 #include "ImageTracker.h"
12 #include "imgIContainer.h"
13 #include "imgIRequest.h"
14 #include "mozilla/Preferences.h"
15 #include "nsXULAppAPI.h"
17 namespace mozilla::dom {
19 ImageTracker::ImageTracker() : mLocking(false), mAnimating(true) {}
21 ImageTracker::~ImageTracker() { SetLockingState(false); }
23 nsresult ImageTracker::Add(imgIRequest* aImage) {
24 MOZ_ASSERT(aImage);
26 const nsresult rv = mImages.WithEntryHandle(aImage, [&](auto&& entry) {
27 nsresult rv = NS_OK;
28 if (entry) {
29 // The image is already in the hashtable. Increment its count.
30 uint32_t oldCount = entry.Data();
31 MOZ_ASSERT(oldCount > 0, "Entry in the image tracker with count 0!");
32 entry.Data() = oldCount + 1;
33 } else {
34 // A new entry was inserted - set the count to 1.
35 entry.Insert(1);
37 // If we're locking images, lock this image too.
38 if (mLocking) {
39 rv = aImage->LockImage();
42 // If we're animating images, request that this image be animated too.
43 if (mAnimating) {
44 nsresult rv2 = aImage->IncrementAnimationConsumers();
45 rv = NS_SUCCEEDED(rv) ? rv2 : rv;
49 return rv;
50 });
52 return rv;
55 nsresult ImageTracker::Remove(imgIRequest* aImage, uint32_t aFlags) {
56 NS_ENSURE_ARG_POINTER(aImage);
58 // Get the old count. It should exist and be > 0.
59 if (auto entry = mImages.Lookup(aImage)) {
60 MOZ_ASSERT(entry.Data() > 0, "Entry in the image tracker with count 0!");
61 // If the count becomes zero, remove it from the tracker.
62 if (--entry.Data() == 0) {
63 entry.Remove();
64 } else {
65 return NS_OK;
67 } else {
68 MOZ_ASSERT_UNREACHABLE("Removing image that wasn't in the tracker!");
69 return NS_OK;
72 nsresult rv = NS_OK;
74 // Now that we're no longer tracking this image, unlock it if we'd
75 // previously locked it.
76 if (mLocking) {
77 rv = aImage->UnlockImage();
80 // If we're animating images, remove our request to animate this one.
81 if (mAnimating) {
82 nsresult rv2 = aImage->DecrementAnimationConsumers();
83 rv = NS_SUCCEEDED(rv) ? rv2 : rv;
86 if (aFlags & REQUEST_DISCARD) {
87 // Request that the image be discarded if nobody else holds a lock on it.
88 // Do this even if !mLocking, because even if we didn't just unlock
89 // this image, it might still be a candidate for discarding.
90 aImage->RequestDiscard();
93 return rv;
96 nsresult ImageTracker::SetLockingState(bool aLocked) {
97 if (XRE_IsContentProcess() &&
98 !Preferences::GetBool("image.mem.allow_locking_in_content_processes",
99 true)) {
100 return NS_OK;
103 // If there's no change, there's nothing to do.
104 if (mLocking == aLocked) return NS_OK;
106 // Otherwise, iterate over our images and perform the appropriate action.
107 for (imgIRequest* image : mImages.Keys()) {
108 if (aLocked) {
109 image->LockImage();
110 } else {
111 image->UnlockImage();
115 // Update state.
116 mLocking = aLocked;
118 return NS_OK;
121 void ImageTracker::SetAnimatingState(bool aAnimating) {
122 // If there's no change, there's nothing to do.
123 if (mAnimating == aAnimating) return;
125 // Otherwise, iterate over our images and perform the appropriate action.
126 for (imgIRequest* image : mImages.Keys()) {
127 if (aAnimating) {
128 image->IncrementAnimationConsumers();
129 } else {
130 image->DecrementAnimationConsumers();
134 // Update state.
135 mAnimating = aAnimating;
138 void ImageTracker::RequestDiscardAll() {
139 for (imgIRequest* image : mImages.Keys()) {
140 image->RequestDiscard();
144 void ImageTracker::MediaFeatureValuesChangedAllDocuments(
145 const MediaFeatureChange& aChange) {
146 // Inform every content image used in the document that media feature values
147 // have changed. If the same image is used in multiple places, then we can
148 // end up informing them multiple times. Theme changes are rare though and we
149 // don't bother trying to ensure we only do this once per image.
151 // Pull the images out into an array and iterate over them, in case the
152 // image notifications do something that ends up modifying the table.
153 nsTArray<nsCOMPtr<imgIContainer>> images;
154 for (imgIRequest* req : mImages.Keys()) {
155 nsCOMPtr<imgIContainer> image;
156 req->GetImage(getter_AddRefs(image));
157 if (!image) {
158 continue;
160 images.AppendElement(image->Unwrap());
162 for (imgIContainer* image : images) {
163 image->MediaFeatureValuesChangedAllDocuments(aChange);
167 } // namespace mozilla::dom