1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "imgRequest.h"
9 #include "WebRenderImageProvider.h"
10 #include "nsIObserverService.h"
11 #include "nsRefreshDriver.h"
12 #include "nsContentUtils.h"
13 #include "mozilla/Atomics.h"
14 #include "mozilla/gfx/Point.h"
15 #include "mozilla/gfx/Rect.h"
16 #include "mozilla/gfx/SourceSurfaceRawData.h"
17 #include "mozilla/Services.h"
18 #include "mozilla/SizeOfState.h"
19 #include "mozilla/TimeStamp.h"
21 #include "mozilla/layers/SharedSurfacesChild.h"
26 WebRenderImageProvider::WebRenderImageProvider(const ImageResource
* aImage
)
27 : mProviderId(aImage
->GetImageProviderId()) {}
29 /* static */ ImageProviderId
WebRenderImageProvider::AllocateProviderId() {
30 // Callable on all threads.
31 static Atomic
<ImageProviderId
> sProviderId(0u);
35 ///////////////////////////////////////////////////////////////////////////////
37 ///////////////////////////////////////////////////////////////////////////////
39 ImageMemoryCounter::ImageMemoryCounter(imgRequest
* aRequest
,
40 SizeOfState
& aState
, bool aIsUsed
)
41 : mProgress(UINT32_MAX
),
48 // We don't have the image object yet, but we can get some information.
49 nsCOMPtr
<nsIURI
> imageURL
;
50 nsresult rv
= aRequest
->GetURI(getter_AddRefs(imageURL
));
51 if (NS_SUCCEEDED(rv
) && imageURL
) {
52 imageURL
->GetSpec(mURI
);
55 mType
= imgIContainer::TYPE_REQUEST
;
56 mHasError
= NS_FAILED(aRequest
->GetImageErrorCode());
57 mValidating
= !!aRequest
->GetValidator();
59 RefPtr
<ProgressTracker
> tracker
= aRequest
->GetProgressTracker();
61 mProgress
= tracker
->GetProgress();
65 ImageMemoryCounter::ImageMemoryCounter(imgRequest
* aRequest
, Image
* aImage
,
66 SizeOfState
& aState
, bool aIsUsed
)
67 : mProgress(UINT32_MAX
),
75 // Extract metadata about the image.
76 nsCOMPtr
<nsIURI
> imageURL(aImage
->GetURI());
78 imageURL
->GetSpec(mURI
);
83 aImage
->GetWidth(&width
);
84 aImage
->GetHeight(&height
);
85 mIntrinsicSize
.SizeTo(width
, height
);
87 mType
= aImage
->GetType();
88 mHasError
= aImage
->HasError();
89 mValidating
= !!aRequest
->GetValidator();
91 RefPtr
<ProgressTracker
> tracker
= aImage
->GetProgressTracker();
93 mProgress
= tracker
->GetProgress();
96 // Populate memory counters for source and decoded data.
97 mValues
.SetSource(aImage
->SizeOfSourceWithComputedFallback(aState
));
98 aImage
->CollectSizeOfSurfaces(mSurfaces
, aState
.mMallocSizeOf
);
101 for (const SurfaceMemoryCounter
& surfaceCounter
: mSurfaces
) {
102 mValues
+= surfaceCounter
.Values();
106 ///////////////////////////////////////////////////////////////////////////////
108 ///////////////////////////////////////////////////////////////////////////////
110 bool ImageResource::GetSpecTruncatedTo1k(nsCString
& aSpec
) const {
111 static const size_t sMaxTruncatedLength
= 1024;
113 mURI
->GetSpec(aSpec
);
114 if (sMaxTruncatedLength
>= aSpec
.Length()) {
118 aSpec
.Truncate(sMaxTruncatedLength
);
122 void ImageResource::CollectSizeOfSurfaces(
123 nsTArray
<SurfaceMemoryCounter
>& aCounters
,
124 MallocSizeOf aMallocSizeOf
) const {
125 SurfaceCache::CollectSizeOfSurfaces(ImageKey(this), aCounters
, aMallocSizeOf
);
129 ImageResource::ImageResource(nsIURI
* aURI
)
132 mAnimationConsumers(0),
133 mAnimationMode(kNormalAnimMode
),
137 mProviderId(WebRenderImageProvider::AllocateProviderId()) {}
139 ImageResource::~ImageResource() {
140 // Ask our ProgressTracker to drop its weak reference to us.
141 mProgressTracker
->ResetImage();
144 void ImageResource::IncrementAnimationConsumers() {
145 MOZ_ASSERT(NS_IsMainThread(),
146 "Main thread only to encourage serialization "
147 "with DecrementAnimationConsumers");
148 mAnimationConsumers
++;
151 void ImageResource::DecrementAnimationConsumers() {
152 MOZ_ASSERT(NS_IsMainThread(),
153 "Main thread only to encourage serialization "
154 "with IncrementAnimationConsumers");
155 MOZ_ASSERT(mAnimationConsumers
>= 1, "Invalid no. of animation consumers!");
156 mAnimationConsumers
--;
159 nsresult
ImageResource::GetAnimationModeInternal(uint16_t* aAnimationMode
) {
161 return NS_ERROR_FAILURE
;
164 NS_ENSURE_ARG_POINTER(aAnimationMode
);
166 *aAnimationMode
= mAnimationMode
;
170 nsresult
ImageResource::SetAnimationModeInternal(uint16_t aAnimationMode
) {
172 return NS_ERROR_FAILURE
;
175 NS_ASSERTION(aAnimationMode
== kNormalAnimMode
||
176 aAnimationMode
== kDontAnimMode
||
177 aAnimationMode
== kLoopOnceAnimMode
,
178 "Wrong Animation Mode is being set!");
180 mAnimationMode
= aAnimationMode
;
185 bool ImageResource::HadRecentRefresh(const TimeStamp
& aTime
) {
186 // Our threshold for "recent" is 1/2 of the default refresh-driver interval.
187 // This ensures that we allow for frame rates at least as fast as the
188 // refresh driver's default rate.
189 static TimeDuration recentThreshold
=
190 TimeDuration::FromMilliseconds(nsRefreshDriver::DefaultInterval() / 2.0);
192 if (!mLastRefreshTime
.IsNull() &&
193 aTime
- mLastRefreshTime
< recentThreshold
) {
197 // else, we can proceed with a refresh.
198 // But first, update our last refresh time:
199 mLastRefreshTime
= aTime
;
203 void ImageResource::EvaluateAnimation() {
204 if (!mAnimating
&& ShouldAnimate()) {
205 nsresult rv
= StartAnimation();
206 mAnimating
= NS_SUCCEEDED(rv
);
207 } else if (mAnimating
&& !ShouldAnimate()) {
212 void ImageResource::SendOnUnlockedDraw(uint32_t aFlags
) {
213 if (!mProgressTracker
) {
217 if (!(aFlags
& FLAG_ASYNC_NOTIFY
)) {
218 mProgressTracker
->OnUnlockedDraw();
220 NotNull
<RefPtr
<ImageResource
>> image
= WrapNotNull(this);
221 nsCOMPtr
<nsIEventTarget
> eventTarget
= GetMainThreadSerialEventTarget();
222 nsCOMPtr
<nsIRunnable
> ev
= NS_NewRunnableFunction(
223 "image::ImageResource::SendOnUnlockedDraw", [=]() -> void {
224 RefPtr
<ProgressTracker
> tracker
= image
->GetProgressTracker();
226 tracker
->OnUnlockedDraw();
229 eventTarget
->Dispatch(CreateRenderBlockingRunnable(ev
.forget()),
235 void ImageResource::NotifyDrawingObservers() {
236 if (!mURI
|| !NS_IsMainThread()) {
240 if (!mURI
->SchemeIs("resource") && !mURI
->SchemeIs("chrome")) {
244 // Record the image drawing for startup performance testing.
245 nsCOMPtr
<nsIURI
> uri
= mURI
;
246 nsContentUtils::AddScriptRunner(NS_NewRunnableFunction(
247 "image::ImageResource::NotifyDrawingObservers", [uri
]() {
248 nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService();
249 NS_WARNING_ASSERTION(obs
, "Can't get an observer service handle");
253 obs
->NotifyObservers(nullptr, "image-drawing",
254 NS_ConvertUTF8toUTF16(spec
).get());
261 } // namespace mozilla