Line data Source code
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/. */
6 :
7 : /* table of images used in a document, for batch locking/unlocking and
8 : * animating */
9 :
10 : #include "ImageTracker.h"
11 :
12 : namespace mozilla {
13 : namespace dom {
14 :
15 28 : ImageTracker::ImageTracker()
16 : : mLocking(false)
17 28 : , mAnimating(true)
18 : {
19 28 : }
20 :
21 0 : ImageTracker::~ImageTracker()
22 : {
23 0 : SetLockingState(false);
24 0 : }
25 :
26 : nsresult
27 24 : ImageTracker::Add(imgIRequest* aImage)
28 : {
29 24 : MOZ_ASSERT(aImage);
30 :
31 24 : nsresult rv = NS_OK;
32 48 : auto entry = mImages.LookupForAdd(aImage);
33 24 : if (entry) {
34 : // The image is already in the hashtable. Increment its count.
35 13 : uint32_t oldCount = entry.Data();
36 13 : MOZ_ASSERT(oldCount > 0, "Entry in the image tracker with count 0!");
37 13 : entry.Data() = oldCount + 1;
38 : } else {
39 : // A new entry was inserted - set the count to 1.
40 22 : entry.OrInsert([]() { return 1; });
41 :
42 : // If we're locking images, lock this image too.
43 11 : if (mLocking) {
44 11 : rv = aImage->LockImage();
45 : }
46 :
47 : // If we're animating images, request that this image be animated too.
48 11 : if (mAnimating) {
49 11 : nsresult rv2 = aImage->IncrementAnimationConsumers();
50 11 : rv = NS_SUCCEEDED(rv) ? rv2 : rv;
51 : }
52 : }
53 :
54 48 : return rv;
55 : }
56 :
57 : nsresult
58 14 : ImageTracker::Remove(imgIRequest* aImage, uint32_t aFlags)
59 : {
60 14 : NS_ENSURE_ARG_POINTER(aImage);
61 :
62 : // Get the old count. It should exist and be > 0.
63 14 : if (auto entry = mImages.Lookup(aImage)) {
64 14 : MOZ_ASSERT(entry.Data() > 0, "Entry in the image tracker with count 0!");
65 : // If the count becomes zero, remove it from the tracker.
66 14 : if (--entry.Data() == 0) {
67 1 : entry.Remove();
68 : } else {
69 13 : return NS_OK;
70 : }
71 : } else {
72 0 : MOZ_ASSERT_UNREACHABLE("Removing image that wasn't in the tracker!");
73 : return NS_OK;
74 : }
75 :
76 1 : nsresult rv = NS_OK;
77 :
78 : // Now that we're no longer tracking this image, unlock it if we'd
79 : // previously locked it.
80 1 : if (mLocking) {
81 1 : rv = aImage->UnlockImage();
82 : }
83 :
84 : // If we're animating images, remove our request to animate this one.
85 1 : if (mAnimating) {
86 1 : nsresult rv2 = aImage->DecrementAnimationConsumers();
87 1 : rv = NS_SUCCEEDED(rv) ? rv2 : rv;
88 : }
89 :
90 1 : if (aFlags & REQUEST_DISCARD) {
91 : // Request that the image be discarded if nobody else holds a lock on it.
92 : // Do this even if !mLocking, because even if we didn't just unlock
93 : // this image, it might still be a candidate for discarding.
94 0 : aImage->RequestDiscard();
95 : }
96 :
97 1 : return rv;
98 : }
99 :
100 : nsresult
101 7 : ImageTracker::SetLockingState(bool aLocked)
102 : {
103 9 : if (XRE_IsContentProcess() &&
104 2 : !Preferences::GetBool("image.mem.allow_locking_in_content_processes", true)) {
105 0 : return NS_OK;
106 : }
107 :
108 : // If there's no change, there's nothing to do.
109 7 : if (mLocking == aLocked)
110 0 : return NS_OK;
111 :
112 : // Otherwise, iterate over our images and perform the appropriate action.
113 7 : for (auto iter = mImages.Iter(); !iter.Done(); iter.Next()) {
114 0 : imgIRequest* image = iter.Key();
115 0 : if (aLocked) {
116 0 : image->LockImage();
117 : } else {
118 0 : image->UnlockImage();
119 : }
120 : }
121 :
122 : // Update state.
123 7 : mLocking = aLocked;
124 :
125 7 : return NS_OK;
126 : }
127 :
128 : void
129 21 : ImageTracker::SetAnimatingState(bool aAnimating)
130 : {
131 : // If there's no change, there's nothing to do.
132 21 : if (mAnimating == aAnimating)
133 0 : return;
134 :
135 : // Otherwise, iterate over our images and perform the appropriate action.
136 21 : for (auto iter = mImages.Iter(); !iter.Done(); iter.Next()) {
137 0 : imgIRequest* image = iter.Key();
138 0 : if (aAnimating) {
139 0 : image->IncrementAnimationConsumers();
140 : } else {
141 0 : image->DecrementAnimationConsumers();
142 : }
143 : }
144 :
145 : // Update state.
146 21 : mAnimating = aAnimating;
147 : }
148 :
149 : void
150 4 : ImageTracker::RequestDiscardAll()
151 : {
152 4 : for (auto iter = mImages.Iter(); !iter.Done(); iter.Next()) {
153 0 : iter.Key()->RequestDiscard();
154 : }
155 4 : }
156 :
157 : } // namespace dom
158 : } // namespace mozilla
|