Coverage Report

Created: 2018-09-25 14:53

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