Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(63)

Side by Side Diff: third_party/WebKit/Source/core/fetch/ImageResource.cpp

Issue 2710113002: DO NOT SUBMIT really old prototype of sprite recognition for image replacement
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de) 2 Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
3 Copyright (C) 2001 Dirk Mueller (mueller@kde.org) 3 Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
4 Copyright (C) 2002 Waldo Bastian (bastian@kde.org) 4 Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
5 Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) 5 Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
6 Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. 6 Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
7 7
8 This library is free software; you can redistribute it and/or 8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public 9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either 10 License as published by the Free Software Foundation; either
(...skipping 11 matching lines...) Expand all
22 */ 22 */
23 23
24 #include "core/fetch/ImageResource.h" 24 #include "core/fetch/ImageResource.h"
25 25
26 #include "core/fetch/ImageResourceObserver.h" 26 #include "core/fetch/ImageResourceObserver.h"
27 #include "core/fetch/MemoryCache.h" 27 #include "core/fetch/MemoryCache.h"
28 #include "core/fetch/ResourceClient.h" 28 #include "core/fetch/ResourceClient.h"
29 #include "core/fetch/ResourceFetcher.h" 29 #include "core/fetch/ResourceFetcher.h"
30 #include "core/fetch/ResourceLoader.h" 30 #include "core/fetch/ResourceLoader.h"
31 #include "core/fetch/ResourceLoadingLog.h" 31 #include "core/fetch/ResourceLoadingLog.h"
32 #include "core/fetch/SubstituteData.h"
32 #include "core/svg/graphics/SVGImage.h" 33 #include "core/svg/graphics/SVGImage.h"
33 #include "platform/RuntimeEnabledFeatures.h" 34 #include "platform/RuntimeEnabledFeatures.h"
34 #include "platform/SharedBuffer.h" 35 #include "platform/SharedBuffer.h"
35 #include "platform/TraceEvent.h" 36 #include "platform/TraceEvent.h"
37 #include "platform/geometry/IntSize.h"
36 #include "platform/graphics/BitmapImage.h" 38 #include "platform/graphics/BitmapImage.h"
37 #include "public/platform/Platform.h" 39 #include "public/platform/Platform.h"
38 #include "public/platform/WebCachePolicy.h" 40 #include "public/platform/WebCachePolicy.h"
39 #include "wtf/CurrentTime.h" 41 #include "wtf/CurrentTime.h"
40 #include "wtf/HashCountedSet.h" 42 #include "wtf/HashCountedSet.h"
41 #include "wtf/StdLibExtras.h" 43 #include "wtf/StdLibExtras.h"
42 #include "wtf/Vector.h" 44 #include "wtf/Vector.h"
45 #include "wtf/text/StringToNumber.h"
46 #include <cstdio>
43 #include <memory> 47 #include <memory>
44 #include <v8.h> 48 #include <v8.h>
45 49
46 namespace blink { 50 namespace blink {
47 51
48 ImageResource* ImageResource::fetch(FetchRequest& request, ResourceFetcher* fetc her) 52 // Helper class that manages the state involved with attempting to load a
53 // placeholder for an image.
54 class ImageResource::PlaceholderLoaderJob : public GarbageCollectedFinalized<Pla ceholderLoaderJob> {
55 public:
56 explicit PlaceholderLoaderJob(ResourceFetcher*);
57 ~PlaceholderLoaderJob();
58
59 DECLARE_TRACE();
60
61 void onImageFetchComplete(ImageResource*);
62
63 private:
64 enum class State {
65 Range = 0,
66 CacheOnly,
67 Placeholder,
68 BypassCacheFull
69 };
70
71 void finish(ImageResource* image)
72 {
73 DCHECK_EQ(image->m_placeholderLoaderJob.get(), this);
74 image->m_placeholderLoaderJob = nullptr;
75 }
76
77 void onRangeFetchComplete(ImageResource*);
78 void doCacheOnlyFetch(ImageResource*);
79 void onCacheOnlyFetchComplete(ImageResource*);
80 void loadPlaceholderOrBypassCache(ImageResource*);
81 void doPlaceholderFetch(ImageResource*, const IntSize&);
82 void doBypassCacheFullFetch(ImageResource*);
83
84 State m_state;
85 Member<ResourceFetcher> m_fetcher;
86 IntSize m_dimensionsFromRange;
87 };
88
89 ImageResource::PlaceholderLoaderJob::PlaceholderLoaderJob(ResourceFetcher* fetch er)
90 : m_state(State::Range)
91 , m_fetcher(fetcher)
92 {
93 DCHECK(fetcher);
94 }
95
96 ImageResource::PlaceholderLoaderJob::~PlaceholderLoaderJob() {}
97
98 DEFINE_TRACE(ImageResource::PlaceholderLoaderJob)
99 {
100 visitor->trace(m_fetcher);
101 }
102
103 void ImageResource::PlaceholderLoaderJob::onImageFetchComplete(ImageResource* im age)
104 {
105 DCHECK(image);
106
107 switch (m_state) {
108 case State::Range:
109 onRangeFetchComplete(image);
110 break;
111 case State::CacheOnly:
112 onCacheOnlyFetchComplete(image);
113 break;
114 default:
115 finish(image);
116 break;
117 }
118 }
119
120 // Parses the values from a Content-Range response header of the form
121 // "bytes %u-%u/%u". Returns true iff parsing is successful.
122 static bool parseContentRangeHeader(const String& contentRange, uint64_t* rangeF irst, uint64_t* rangeLast, uint64_t* totalSize)
123 {
124 // Example Content-Range header: "bytes 0-2047/16366".
125 if (!contentRange.startsWith("bytes "))
126 return false;
127 size_t dashPos = contentRange.find('-', arraysize("bytes ") - 1);
128 if (dashPos == kNotFound)
129 return false;
130 size_t slashPos = contentRange.find('/', dashPos + 1);
131 if (slashPos == kNotFound)
132 return false;
133
134 const size_t rangeFirstPos = arraysize("bytes ") - 1, rangeLastPos = dashPos + 1, totalSizePos = slashPos + 1;
135 bool rangeFirstOk = false, rangeLastOk = false, totalSizeOk = false;
136 if (contentRange.is8Bit()) {
137 *rangeFirst = charactersToUInt64Strict(contentRange.characters8() + rang eFirstPos, dashPos - rangeFirstPos, &rangeFirstOk);
138 *rangeLast = charactersToUInt64Strict(contentRange.characters8() + range LastPos, slashPos - rangeLastPos, &rangeLastOk);
139 *totalSize = charactersToUInt64Strict(contentRange.characters8() + total SizePos, contentRange.length() - totalSizePos, &totalSizeOk);
140 } else {
141 *rangeFirst = charactersToUInt64Strict(contentRange.characters16() + ran geFirstPos, dashPos - rangeFirstPos, &rangeFirstOk);
142 *rangeLast = charactersToUInt64Strict(contentRange.characters16() + rang eLastPos, slashPos - rangeLastPos, &rangeLastOk);
143 *totalSize = charactersToUInt64Strict(contentRange.characters16() + tota lSizePos, contentRange.length() - totalSizePos, &totalSizeOk);
144 }
145 return rangeFirstOk && rangeLastOk && totalSizeOk;
146 }
147
148 // Returns true if |response| likely represents the entire resource instead of
149 // just a partial range.
150 static bool hasEntireResource(const ResourceResponse& response)
151 {
152 if (response.httpStatusCode() != 206)
153 return true;
154
155 const String& contentRangeHeader = response.httpHeaderField("content-range") ;
156 if (contentRangeHeader.isNull()) {
157 // If there's no Content-Range header, then assume that the response is
158 // the entire resource.
159 return true;
160 }
161
162 uint64_t rangeFirst, rangeLast, totalSize;
163 if (!parseContentRangeHeader(contentRangeHeader, &rangeFirst, &rangeLast, &t otalSize))
164 return false;
165
166 // Check if the returned range is the entire resource.
167 return rangeFirst == 0 && rangeLast + 1 == totalSize;
168 }
169
170 void ImageResource::PlaceholderLoaderJob::onRangeFetchComplete(ImageResource* im age)
171 {
172 DCHECK_EQ(State::Range, m_state);
173
174 // If the response consists of the entire image, e.g. if the image was
175 // smaller than the requested range or if the server responded with a 200
176 // response for the full image, then just use the full response to show the
177 // full image.
178 // Also avoid re-fetching requests that led to 204 responses, since those
179 // typically indicate that it was for a tracking request, and there's likely
180 // no point in attempting to re-fetch the image.
181 if ((image->response().httpStatusCode() == 204 || !image->willPaintBrokenIma ge()) && hasEntireResource(image->response())) {
182 image->setIsPlaceholder(false);
183 finish(image);
184 return;
185 }
186
187 if (image->hasImage())
188 m_dimensionsFromRange = image->getImage()->size();
189
190 if (image->response().wasCached() && image->response().httpStatusCode() == 2 06 && image->resourceRequest().getCachePolicy() != WebCachePolicy::BypassingCach e) {
191 // If the range response came from the cache, then that means that it
192 // was fresh in the cache and there's a chance that the entire image
193 // response is fresh and in the cache, so attempt to fetch the entire
194 // image from the cache.
195 doCacheOnlyFetch(image);
196 return;
197 }
198 loadPlaceholderOrBypassCache(image);
199 }
200
201 void ImageResource::PlaceholderLoaderJob::doCacheOnlyFetch(ImageResource* image)
202 {
203 m_state = State::CacheOnly;
204
205 ResourceRequest request = image->getOriginalResourceRequest();
206 request.setCachePolicy(WebCachePolicy::ReturnCacheDataDontLoad);
207 image->reload(m_fetcher.get(), request, SubstituteData());
208 }
209
210 void ImageResource::PlaceholderLoaderJob::onCacheOnlyFetchComplete(ImageResource * image)
211 {
212 DCHECK_EQ(State::CacheOnly, m_state);
213
214 if (!image->willPaintBrokenImage() && hasEntireResource(image->response())) {
215 image->setIsPlaceholder(false);
216 finish(image);
217 return;
218 }
219 loadPlaceholderOrBypassCache(image);
220 }
221
222 void ImageResource::PlaceholderLoaderJob::loadPlaceholderOrBypassCache(ImageReso urce* image)
223 {
224 if (!m_dimensionsFromRange.isEmpty()) {
225 doPlaceholderFetch(image, m_dimensionsFromRange);
226 return;
227 }
228 if (image->getOriginalResourceRequest().getCachePolicy() != WebCachePolicy:: ReturnCacheDataDontLoad) {
229 doBypassCacheFullFetch(image);
230 return;
231 }
232 // Return the broken image since there's nothing else that can be done here.
233 image->setIsPlaceholder(false);
234 finish(image);
235 }
236
237 static Vector<char> generatePlaceholderBox(const IntSize& dimensions)
238 {
239 DCHECK(!dimensions.isEmpty());
240
241 static const char kFormat[] = "<?xml version=\"1.0\" encoding=\"UTF-8\" stan dalone=\"no\"?>\n"
242 "<svg xmlns=\"http://www.w3.org/2000/svg\" wid th=\"%d\" height=\"%d\">\n"
243 "<rect width=\"100%%\" height=\"100%%\" style= \"fill:rgba(127,127,127,0.4);stroke-width:%d;stroke:black\" />\n"
244 "</svg>";
245 // Don't add the black border to tiny images, to avoid coloring the entire i mage black.
246 int strokeWidth = dimensions.width() >= 10 && dimensions.height() >= 10 ? 2 : 0;
247
248 int expectedResult = std::snprintf(nullptr, 0, kFormat, dimensions.width(), dimensions.height(), strokeWidth);
249 DCHECK_LE(0, expectedResult);
250 Vector<char> out(safeCast<size_t>(expectedResult) + 1 /* for trailing '\0' * /);
251 int result = std::snprintf(out.data(), out.size(), kFormat, dimensions.width (), dimensions.height(), strokeWidth);
252 DCHECK_EQ(expectedResult, result);
253 DCHECK_EQ('\0', out.last());
254 out.removeLast(); // Cut off the trailing '\0'.
255 return out;
256 }
257
258 void ImageResource::PlaceholderLoaderJob::doPlaceholderFetch(ImageResource* imag e, const IntSize& dimensions)
259 {
260 DCHECK(!dimensions.isEmpty());
261 m_state = State::Placeholder;
262
263 Vector<char> svgBox = generatePlaceholderBox(dimensions);
264 SubstituteData substituteData(SharedBuffer::adoptVector(svgBox), "image/svg+ xml", "utf-8", KURL(), LoadNormally);
265 DCHECK(image->isPlaceholder());
266 image->reload(m_fetcher.get(), image->getOriginalResourceRequest(), substitu teData);
267 }
268
269 void ImageResource::PlaceholderLoaderJob::doBypassCacheFullFetch(ImageResource* image)
270 {
271 m_state = State::BypassCacheFull;
272
273 // This reload is done bypassing the cache for several reasons:
274 //
275 // (1) CacheOnly fetches fail for sparse entries in the disk cache even if
276 // all the ranges of the full resource are available separately, so
277 // bypassing the cache here ensures that the full response is cached
278 // non-sparsely, so future fetches of the same image will be properly
279 // satisfied by the full cached response, reducing the cost of future
280 // fetches of this same image.
281 //
282 // (2) It's possible that the origin server doesn't understand ranges,
283 // and it returned a broken range, so bypassing the cache for this reload
284 // will hopefully return the full unbroken image instead of attempting to
285 // fetch the latter range of the image and combine that with the existing
286 // potentially broken range.
287 //
288 // TODO(sclittle): Investigate if the issue with (1) can be fixed, i.e. make
289 // the disk cache support sparse cache entries together with
290 // WebCachePolicy::ReturnCacheDataDontLoad.
291 ResourceRequest request = image->getOriginalResourceRequest();
292 request.setCachePolicy(WebCachePolicy::BypassingCache);
293 image->setIsPlaceholder(false);
294 image->reload(m_fetcher.get(), request, SubstituteData());
295 }
296
297 static void modifyRequestToFetchPlaceholderRange(ResourceRequest* request)
298 {
299 DCHECK_EQ(nullAtom, request->httpHeaderField("range"));
300
301 // Fetch the first few bytes of the image. This number is tuned to both (a)
302 // likely capture the entire image for small images and (b) likely contain t he
303 // dimensions for larger images.
304 // TODO(sclittle): Calculate the optimal value for this number.
305 request->setHTTPHeaderField("range", "bytes=0-2047");
306 }
307
308 static void unmodifyRequestToFetchPlaceholderRange(ResourceRequest* request)
309 {
310 DCHECK_EQ("bytes=0-2047", request->httpHeaderField("range"));
311 request->clearHTTPHeaderField("range");
312 }
313
314 Resource* ImageResource::ImageResourceFactory::create(const ResourceRequest& req uest, const ResourceLoaderOptions& options, const String&) const
315 {
316 if (m_isPlaceholder) {
317 ResourceRequest originalRequest = request;
318 unmodifyRequestToFetchPlaceholderRange(&originalRequest);
319 return new ImageResource(request, options, originalRequest, m_isPlacehol der);
320 }
321 return new ImageResource(request, options, request, m_isPlaceholder);
322 }
323
324 ImageResource* ImageResource::fetch(FetchRequest& request, ResourceFetcher* fetc her, PlaceholderRequestType placeholderRequestType)
49 { 325 {
50 if (request.resourceRequest().requestContext() == WebURLRequest::RequestCont extUnspecified) 326 if (request.resourceRequest().requestContext() == WebURLRequest::RequestCont extUnspecified)
51 request.mutableResourceRequest().setRequestContext(WebURLRequest::Reques tContextImage); 327 request.mutableResourceRequest().setRequestContext(WebURLRequest::Reques tContextImage);
52 if (fetcher->context().pageDismissalEventBeingDispatched()) { 328 if (fetcher->context().pageDismissalEventBeingDispatched()) {
53 KURL requestURL = request.resourceRequest().url(); 329 KURL requestURL = request.resourceRequest().url();
54 if (requestURL.isValid() && fetcher->context().canRequest(Resource::Imag e, request.resourceRequest(), requestURL, request.options(), request.forPreload( ), request.getOriginRestriction())) 330 if (requestURL.isValid() && fetcher->context().canRequest(Resource::Imag e, request.resourceRequest(), requestURL, request.options(), request.forPreload( ), request.getOriginRestriction()))
55 fetcher->context().sendImagePing(requestURL); 331 fetcher->context().sendImagePing(requestURL);
56 return nullptr; 332 return nullptr;
57 } 333 }
58 334
59 return toImageResource(fetcher->requestResource(request, ImageResourceFactor y())); 335 bool attemptPlaceholder = placeholderRequestType == PlaceholderRequestType:: AllowPlaceholder && request.url().protocolIsInHTTPFamily()
336 // Only issue range requests for GET requests, since that way it should
337 // be safe to re-issue the request without side effects.
338 && request.resourceRequest().httpMethod() == "GET"
339 // If the request already has a range request header, then don't
340 // overwrite that range header, and just attempt to fetch the image
341 // normally without generating a placeholder.
342 && request.resourceRequest().httpHeaderField("range").isNull();
343
344 if (attemptPlaceholder)
345 modifyRequestToFetchPlaceholderRange(&request.mutableResourceRequest());
346 ImageResource* image = toImageResource(fetcher->requestResource(request, Ima geResourceFactory(attemptPlaceholder)));
347
348 // Check if the image is loading a placeholder already, otherwise add a Plac eholderLoaderJob.
349 if (attemptPlaceholder && (image->isLoading() || image->stillNeedsLoad()) && image->isPlaceholder() && !image->m_placeholderLoaderJob)
350 image->m_placeholderLoaderJob = new PlaceholderLoaderJob(fetcher);
351
352 // If this image shouldn't be a placeholder but it is, then reload it as not a placeholder.
353 if (!attemptPlaceholder && image->isPlaceholder()) {
354 image->m_placeholderLoaderJob = nullptr;
355 // Note that the cache is not bypassed for this reload - it should be fi ne
356 // to use a cached copy if it exists.
357 image->setIsPlaceholder(false);
358 image->reload(fetcher, request.resourceRequest(), SubstituteData());
359 }
360 return image;
60 } 361 }
61 362
62 ImageResource::ImageResource(const ResourceRequest& resourceRequest, const Resou rceLoaderOptions& options) 363 ImageResource::ImageResource(const ResourceRequest& resourceRequest, const Resou rceLoaderOptions& options, const ResourceRequest& originalRequest, bool isPlaceh older)
63 : Resource(resourceRequest, Image, options) 364 : Resource(resourceRequest, Image, options)
64 , m_devicePixelRatioHeaderValue(1.0) 365 , m_devicePixelRatioHeaderValue(1.0)
65 , m_image(nullptr) 366 , m_image(nullptr)
66 , m_hasDevicePixelRatioHeaderValue(false) 367 , m_hasDevicePixelRatioHeaderValue(false)
368 , m_originalRequest(originalRequest)
369 , m_isPlaceholder(isPlaceholder)
370 , m_isSchedulingReload(false)
67 { 371 {
68 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(ResourceRequest) " << this; 372 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(ResourceRequest) " << this;
69 } 373 }
70 374
71 ImageResource::ImageResource(blink::Image* image, const ResourceLoaderOptions& o ptions) 375 ImageResource::ImageResource(blink::Image* image, const ResourceLoaderOptions& o ptions)
72 : Resource(ResourceRequest(""), Image, options) 376 : Resource(ResourceRequest(""), Image, options)
73 , m_devicePixelRatioHeaderValue(1.0) 377 , m_devicePixelRatioHeaderValue(1.0)
74 , m_image(image) 378 , m_image(image)
75 , m_hasDevicePixelRatioHeaderValue(false) 379 , m_hasDevicePixelRatioHeaderValue(false)
380 , m_originalRequest(resourceRequest())
381 , m_isPlaceholder(false)
382 , m_isSchedulingReload(false)
76 { 383 {
77 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(Image) " << this; 384 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(Image) " << this;
78 setStatus(Cached); 385 setStatus(Cached);
79 } 386 }
80 387
81 ImageResource::~ImageResource() 388 ImageResource::~ImageResource()
82 { 389 {
83 RESOURCE_LOADING_DVLOG(1) << "~ImageResource " << this; 390 RESOURCE_LOADING_DVLOG(1) << "~ImageResource " << this;
84 clearImage(); 391 clearImage();
85 } 392 }
86 393
87 DEFINE_TRACE(ImageResource) 394 DEFINE_TRACE(ImageResource)
88 { 395 {
89 visitor->trace(m_multipartParser); 396 visitor->trace(m_multipartParser);
397 visitor->trace(m_placeholderLoaderJob);
90 Resource::trace(visitor); 398 Resource::trace(visitor);
91 ImageObserver::trace(visitor); 399 ImageObserver::trace(visitor);
92 MultipartImageResourceParser::Client::trace(visitor); 400 MultipartImageResourceParser::Client::trace(visitor);
93 } 401 }
94 402
95 void ImageResource::checkNotify() 403 void ImageResource::checkNotify()
96 { 404 {
405 if (m_isSchedulingReload)
406 return;
407
408 if (m_placeholderLoaderJob)
409 m_placeholderLoaderJob->onImageFetchComplete(this);
410
411 if (m_isSchedulingReload || m_placeholderLoaderJob)
412 return;
413
97 notifyObserversInternal(MarkFinishedOption::ShouldMarkFinished); 414 notifyObserversInternal(MarkFinishedOption::ShouldMarkFinished);
98 Resource::checkNotify(); 415 Resource::checkNotify();
99 } 416 }
100 417
101 void ImageResource::notifyObserversInternal(MarkFinishedOption markFinishedOptio n) 418 void ImageResource::notifyObserversInternal(MarkFinishedOption markFinishedOptio n)
102 { 419 {
103 if (isLoading()) 420 if (isLoading())
104 return; 421 return;
105 422
106 for (auto* observer : m_observers.asVector()) { 423 for (auto* observer : m_observers.asVector()) {
107 if (m_observers.contains(observer)) { 424 if (m_observers.contains(observer)) {
108 if (markFinishedOption == MarkFinishedOption::ShouldMarkFinished) 425 if (markFinishedOption == MarkFinishedOption::ShouldMarkFinished)
109 markObserverFinished(observer); 426 markObserverFinished(observer);
110 observer->imageNotifyFinished(this); 427 observer->imageNotifyFinished(this);
111 } 428 }
112 } 429 }
113 } 430 }
114 431
115 void ImageResource::markObserverFinished(ImageResourceObserver* observer) 432 void ImageResource::markObserverFinished(ImageResourceObserver* observer)
116 { 433 {
434 if (m_isSchedulingReload || m_placeholderLoaderJob)
435 return;
436
117 if (m_observers.contains(observer)) { 437 if (m_observers.contains(observer)) {
118 m_finishedObservers.add(observer); 438 m_finishedObservers.add(observer);
119 m_observers.remove(observer); 439 m_observers.remove(observer);
120 } 440 }
121 } 441 }
122 442
123 void ImageResource::didAddClient(ResourceClient* client) 443 void ImageResource::didAddClient(ResourceClient* client)
124 { 444 {
125 DCHECK((m_multipartParser && isLoading()) || !data() || m_image); 445 DCHECK((m_multipartParser && isLoading()) || !data() || m_image);
126 Resource::didAddClient(client); 446 Resource::didAddClient(client);
(...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after
338 658
339 void ImageResource::clear() 659 void ImageResource::clear()
340 { 660 {
341 clearImage(); 661 clearImage();
342 clearData(); 662 clearData();
343 setEncodedSize(0); 663 setEncodedSize(0);
344 } 664 }
345 665
346 inline void ImageResource::createImage() 666 inline void ImageResource::createImage()
347 { 667 {
668 bool wantSVGImage = response().mimeType() == "image/svg+xml";
669 // It's possible for the existing |m_image| to be a bitmap image while the
670 // response is now an SVG image, or vice versa, when an image is reloaded.
671 // In these cases, clear and delete the existing image so that a new image
672 // of the correct type can be created and used instead.
673 if (m_image && m_image->isSVGImage() != wantSVGImage)
674 clearImage();
675
348 // Create the image if it doesn't yet exist. 676 // Create the image if it doesn't yet exist.
349 if (m_image) 677 if (m_image)
350 return; 678 return;
351 679
352 if (response().mimeType() == "image/svg+xml") { 680 if (wantSVGImage) {
353 m_image = SVGImage::create(this); 681 m_image = SVGImage::create(this);
354 } else { 682 } else {
355 m_image = BitmapImage::create(this); 683 m_image = BitmapImage::create(this);
356 } 684 }
357 } 685 }
358 686
359 inline void ImageResource::clearImage() 687 inline void ImageResource::clearImage()
360 { 688 {
361 if (!m_image) 689 if (!m_image)
362 return; 690 return;
(...skipping 29 matching lines...) Expand all
392 // to decode. 720 // to decode.
393 if (sizeAvailable == Image::SizeUnavailable && !allDataReceived) 721 if (sizeAvailable == Image::SizeUnavailable && !allDataReceived)
394 return; 722 return;
395 if (!m_image || m_image->isNull()) { 723 if (!m_image || m_image->isNull()) {
396 size_t size = encodedSize(); 724 size_t size = encodedSize();
397 clear(); 725 clear();
398 if (!errorOccurred()) 726 if (!errorOccurred())
399 setStatus(DecodeError); 727 setStatus(DecodeError);
400 if (!allDataReceived && loader()) 728 if (!allDataReceived && loader())
401 loader()->didFinishLoading(nullptr, monotonicallyIncreasingTime(), s ize); 729 loader()->didFinishLoading(nullptr, monotonicallyIncreasingTime(), s ize);
402 memoryCache()->remove(this); 730 // It's possible that the error could have been resolved by the
731 // didFinishLoading() call, so check again that the image is still in an
732 // error state before proceeding.
733 if (errorOccurred())
734 memoryCache()->remove(this);
403 } 735 }
404 736
405 // It would be nice to only redraw the decoded band of the image, but with t he current design 737 // It would be nice to only redraw the decoded band of the image, but with t he current design
406 // (decoding delayed until painting) that seems hard. 738 // (decoding delayed until painting) that seems hard.
407 notifyObservers(); 739 notifyObservers();
408 } 740 }
409 741
410 void ImageResource::updateImageAndClearBuffer() 742 void ImageResource::updateImageAndClearBuffer()
411 { 743 {
412 clearImage(); 744 clearImage();
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
527 } 859 }
528 860
529 if (m_image->animationPolicy() != newPolicy) { 861 if (m_image->animationPolicy() != newPolicy) {
530 m_image->resetAnimation(); 862 m_image->resetAnimation();
531 m_image->setAnimationPolicy(newPolicy); 863 m_image->setAnimationPolicy(newPolicy);
532 } 864 }
533 } 865 }
534 866
535 void ImageResource::reloadIfLoFi(ResourceFetcher* fetcher) 867 void ImageResource::reloadIfLoFi(ResourceFetcher* fetcher)
536 { 868 {
537 if (resourceRequest().loFiState() != WebURLRequest::LoFiOn) 869 if (!m_isPlaceholder && (resourceRequest().loFiState() != WebURLRequest::LoF iOn || (isLoaded() && !response().httpHeaderField("chrome-proxy").contains("q=lo w"))))
538 return; 870 return;
539 if (isLoaded() && !response().httpHeaderField("chrome-proxy").contains("q=lo w")) 871
540 return; 872 ResourceRequest reloadRequest = m_originalRequest;
541 setCachePolicyBypassingCache(); 873 reloadRequest.setCachePolicy(WebCachePolicy::BypassingCache);
542 setLoFiStateOff(); 874 reloadRequest.setLoFiState(WebURLRequest::LoFiOff);
875 m_isPlaceholder = false;
876 m_placeholderLoaderJob = nullptr;
877
878 reload(fetcher, reloadRequest, SubstituteData());
879 }
880
881 static void loadStaticResponse(ImageResource* resource, const SubstituteData& su bstituteData)
882 {
883 DCHECK(resource);
884 DCHECK(substituteData.isValid());
885
886 // This code was adapted from ResourceFetcher::resourceForStaticData().
887 ResourceResponse response(resource->resourceRequest().url(), substituteData. mimeType(), substituteData.content()->size(), substituteData.textEncoding(), Str ing());
888 response.setHTTPStatusCode(200);
889 response.setHTTPStatusText("OK");
890
891 resource->setNeedsSynchronousCacheHit(substituteData.forceSynchronousLoad()) ;
892 resource->responseReceived(response, nullptr);
893 resource->setDataBufferingPolicy(BufferData);
894 resource->setResourceBuffer(PassRefPtr<SharedBuffer>(substituteData.content( )));
895 resource->finish();
896 }
897
898 void ImageResource::reload(ResourceFetcher* fetcher, const ResourceRequest& requ est, const SubstituteData& substituteData)
899 {
900 DCHECK(!m_isSchedulingReload);
901 m_isSchedulingReload = true;
902
543 if (isLoading()) 903 if (isLoading())
544 loader()->cancel(); 904 loader()->cancel();
905 clearError();
545 clear(); 906 clear();
546 notifyObservers();
547 907
908 if (!substituteData.isValid()) {
909 // If the reload will be done asynchronously, notify observers to update
910 // the image's appearance while waiting for the async reload to
911 // complete.
912 notifyObservers();
913 }
548 setStatus(NotStarted); 914 setStatus(NotStarted);
915
916 DCHECK(m_isSchedulingReload);
917 m_isSchedulingReload = false;
918
919 setResourceRequest(request);
920
921 if (substituteData.isValid()) {
922 loadStaticResponse(this, substituteData);
923 return;
924 }
549 fetcher->startLoad(this); 925 fetcher->startLoad(this);
550 } 926 }
551 927
552 void ImageResource::changedInRect(const blink::Image* image, const IntRect& rect ) 928 void ImageResource::changedInRect(const blink::Image* image, const IntRect& rect )
553 { 929 {
554 if (!image || image != m_image) 930 if (!image || image != m_image)
555 return; 931 return;
556 notifyObservers(&rect); 932 notifyObservers(&rect);
557 } 933 }
558 934
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
593 if (response().wasFetchedViaServiceWorker()) 969 if (response().wasFetchedViaServiceWorker())
594 return response().serviceWorkerResponseType() != WebServiceWorkerRespons eTypeOpaque; 970 return response().serviceWorkerResponseType() != WebServiceWorkerRespons eTypeOpaque;
595 if (!getImage()->currentFrameHasSingleSecurityOrigin()) 971 if (!getImage()->currentFrameHasSingleSecurityOrigin())
596 return false; 972 return false;
597 if (passesAccessControlCheck(securityOrigin)) 973 if (passesAccessControlCheck(securityOrigin))
598 return true; 974 return true;
599 return !securityOrigin->taintsCanvas(response().url()); 975 return !securityOrigin->taintsCanvas(response().url());
600 } 976 }
601 977
602 } // namespace blink 978 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/fetch/ImageResource.h ('k') | third_party/WebKit/Source/core/fetch/ImageResourceTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698