Bug 1855375: Basic implementation for Yelp Suggestions r=fluent-reviewers,flod,adw
[gecko.git] / image / Image.cpp
blob16f754f4907d04eb8735eac258b878776918db31
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/. */
6 #include "Image.h"
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"
20 // for Tie
21 #include "mozilla/layers/SharedSurfacesChild.h"
23 namespace mozilla {
24 namespace image {
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);
32 return ++sProviderId;
35 ///////////////////////////////////////////////////////////////////////////////
36 // Memory Reporting
37 ///////////////////////////////////////////////////////////////////////////////
39 ImageMemoryCounter::ImageMemoryCounter(imgRequest* aRequest,
40 SizeOfState& aState, bool aIsUsed)
41 : mProgress(UINT32_MAX),
42 mType(UINT16_MAX),
43 mIsUsed(aIsUsed),
44 mHasError(false),
45 mValidating(false) {
46 MOZ_ASSERT(aRequest);
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();
60 if (tracker) {
61 mProgress = tracker->GetProgress();
65 ImageMemoryCounter::ImageMemoryCounter(imgRequest* aRequest, Image* aImage,
66 SizeOfState& aState, bool aIsUsed)
67 : mProgress(UINT32_MAX),
68 mType(UINT16_MAX),
69 mIsUsed(aIsUsed),
70 mHasError(false),
71 mValidating(false) {
72 MOZ_ASSERT(aRequest);
73 MOZ_ASSERT(aImage);
75 // Extract metadata about the image.
76 nsCOMPtr<nsIURI> imageURL(aImage->GetURI());
77 if (imageURL) {
78 imageURL->GetSpec(mURI);
81 int32_t width = 0;
82 int32_t height = 0;
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();
92 if (tracker) {
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);
100 // Compute totals.
101 for (const SurfaceMemoryCounter& surfaceCounter : mSurfaces) {
102 mValues += surfaceCounter.Values();
106 ///////////////////////////////////////////////////////////////////////////////
107 // Image Base Types
108 ///////////////////////////////////////////////////////////////////////////////
110 bool ImageResource::GetSpecTruncatedTo1k(nsCString& aSpec) const {
111 static const size_t sMaxTruncatedLength = 1024;
113 mURI->GetSpec(aSpec);
114 if (sMaxTruncatedLength >= aSpec.Length()) {
115 return true;
118 aSpec.Truncate(sMaxTruncatedLength);
119 return false;
122 void ImageResource::CollectSizeOfSurfaces(
123 nsTArray<SurfaceMemoryCounter>& aCounters,
124 MallocSizeOf aMallocSizeOf) const {
125 SurfaceCache::CollectSizeOfSurfaces(ImageKey(this), aCounters, aMallocSizeOf);
128 // Constructor
129 ImageResource::ImageResource(nsIURI* aURI)
130 : mURI(aURI),
131 mInnerWindowId(0),
132 mAnimationConsumers(0),
133 mAnimationMode(kNormalAnimMode),
134 mInitialized(false),
135 mAnimating(false),
136 mError(false),
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) {
160 if (mError) {
161 return NS_ERROR_FAILURE;
164 NS_ENSURE_ARG_POINTER(aAnimationMode);
166 *aAnimationMode = mAnimationMode;
167 return NS_OK;
170 nsresult ImageResource::SetAnimationModeInternal(uint16_t aAnimationMode) {
171 if (mError) {
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;
182 return NS_OK;
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) {
194 return true;
197 // else, we can proceed with a refresh.
198 // But first, update our last refresh time:
199 mLastRefreshTime = aTime;
200 return false;
203 void ImageResource::EvaluateAnimation() {
204 if (!mAnimating && ShouldAnimate()) {
205 nsresult rv = StartAnimation();
206 mAnimating = NS_SUCCEEDED(rv);
207 } else if (mAnimating && !ShouldAnimate()) {
208 StopAnimation();
212 void ImageResource::SendOnUnlockedDraw(uint32_t aFlags) {
213 if (!mProgressTracker) {
214 return;
217 if (!(aFlags & FLAG_ASYNC_NOTIFY)) {
218 mProgressTracker->OnUnlockedDraw();
219 } else {
220 NotNull<RefPtr<ImageResource>> image = WrapNotNull(this);
221 nsCOMPtr<nsIEventTarget> eventTarget = mProgressTracker->GetEventTarget();
222 nsCOMPtr<nsIRunnable> ev = NS_NewRunnableFunction(
223 "image::ImageResource::SendOnUnlockedDraw", [=]() -> void {
224 RefPtr<ProgressTracker> tracker = image->GetProgressTracker();
225 if (tracker) {
226 tracker->OnUnlockedDraw();
229 eventTarget->Dispatch(CreateRenderBlockingRunnable(ev.forget()),
230 NS_DISPATCH_NORMAL);
234 #ifdef DEBUG
235 void ImageResource::NotifyDrawingObservers() {
236 if (!mURI || !NS_IsMainThread()) {
237 return;
240 if (!mURI->SchemeIs("resource") && !mURI->SchemeIs("chrome")) {
241 return;
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");
250 if (obs) {
251 nsAutoCString spec;
252 uri->GetSpec(spec);
253 obs->NotifyObservers(nullptr, "image-drawing",
254 NS_ConvertUTF8toUTF16(spec).get());
256 }));
258 #endif
260 } // namespace image
261 } // namespace mozilla