| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de) | |
| 3 Copyright (C) 2001 Dirk Mueller (mueller@kde.org) | |
| 4 Copyright (C) 2002 Waldo Bastian (bastian@kde.org) | |
| 5 Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) | |
| 6 Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. | |
| 7 | |
| 8 This library is free software; you can redistribute it and/or | |
| 9 modify it under the terms of the GNU Library General Public | |
| 10 License as published by the Free Software Foundation; either | |
| 11 version 2 of the License, or (at your option) any later version. | |
| 12 | |
| 13 This library is distributed in the hope that it will be useful, | |
| 14 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 16 Library General Public License for more details. | |
| 17 | |
| 18 You should have received a copy of the GNU Library General Public License | |
| 19 along with this library; see the file COPYING.LIB. If not, write to | |
| 20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
| 21 Boston, MA 02110-1301, USA. | |
| 22 */ | |
| 23 | |
| 24 #include "sky/engine/core/fetch/ImageResource.h" | |
| 25 | |
| 26 #include "gen/sky/platform/RuntimeEnabledFeatures.h" | |
| 27 #include "sky/engine/core/fetch/ImageResourceClient.h" | |
| 28 #include "sky/engine/core/fetch/MemoryCache.h" | |
| 29 #include "sky/engine/core/fetch/ResourceClient.h" | |
| 30 #include "sky/engine/core/fetch/ResourceClientWalker.h" | |
| 31 #include "sky/engine/core/fetch/ResourceFetcher.h" | |
| 32 #include "sky/engine/core/frame/FrameView.h" | |
| 33 #include "sky/engine/core/rendering/RenderObject.h" | |
| 34 #include "sky/engine/platform/Logging.h" | |
| 35 #include "sky/engine/platform/SharedBuffer.h" | |
| 36 #include "sky/engine/platform/TraceEvent.h" | |
| 37 #include "sky/engine/platform/graphics/BitmapImage.h" | |
| 38 #include "sky/engine/wtf/CurrentTime.h" | |
| 39 #include "sky/engine/wtf/StdLibExtras.h" | |
| 40 | |
| 41 namespace blink { | |
| 42 | |
| 43 ImageResource::ImageResource(const ResourceRequest& resourceRequest) | |
| 44 : Resource(resourceRequest, Image) | |
| 45 , m_devicePixelRatioHeaderValue(1.0) | |
| 46 , m_image(nullptr) | |
| 47 , m_loadingMultipartContent(false) | |
| 48 , m_hasDevicePixelRatioHeaderValue(false) | |
| 49 { | |
| 50 WTF_LOG(Timers, "new ImageResource(ResourceRequest) %p", this); | |
| 51 setStatus(Unknown); | |
| 52 setCustomAcceptHeader(); | |
| 53 } | |
| 54 | |
| 55 ImageResource::ImageResource(blink::Image* image) | |
| 56 : Resource(ResourceRequest(""), Image) | |
| 57 , m_image(image) | |
| 58 { | |
| 59 WTF_LOG(Timers, "new ImageResource(Image) %p", this); | |
| 60 setStatus(Cached); | |
| 61 setLoading(false); | |
| 62 setCustomAcceptHeader(); | |
| 63 } | |
| 64 | |
| 65 ImageResource::ImageResource(const ResourceRequest& resourceRequest, blink::Imag
e* image) | |
| 66 : Resource(resourceRequest, Image) | |
| 67 , m_image(image) | |
| 68 { | |
| 69 WTF_LOG(Timers, "new ImageResource(ResourceRequest, Image) %p", this); | |
| 70 setStatus(Cached); | |
| 71 setLoading(false); | |
| 72 setCustomAcceptHeader(); | |
| 73 } | |
| 74 | |
| 75 ImageResource::~ImageResource() | |
| 76 { | |
| 77 WTF_LOG(Timers, "~ImageResource %p", this); | |
| 78 clearImage(); | |
| 79 } | |
| 80 | |
| 81 void ImageResource::load(ResourceFetcher* fetcher, const ResourceLoaderOptions&
options) | |
| 82 { | |
| 83 if (!fetcher || fetcher->autoLoadImages()) | |
| 84 Resource::load(fetcher, options); | |
| 85 else | |
| 86 setLoading(false); | |
| 87 } | |
| 88 | |
| 89 void ImageResource::didAddClient(ResourceClient* c) | |
| 90 { | |
| 91 if (m_data && !m_image && !errorOccurred()) { | |
| 92 createImage(); | |
| 93 m_image->setData(m_data, true); | |
| 94 } | |
| 95 | |
| 96 ASSERT(c->resourceClientType() == ImageResourceClient::expectedType()); | |
| 97 if (m_image && !m_image->isNull()) | |
| 98 static_cast<ImageResourceClient*>(c)->imageChanged(this); | |
| 99 | |
| 100 Resource::didAddClient(c); | |
| 101 } | |
| 102 | |
| 103 void ImageResource::didRemoveClient(ResourceClient* c) | |
| 104 { | |
| 105 ASSERT(c); | |
| 106 ASSERT(c->resourceClientType() == ImageResourceClient::expectedType()); | |
| 107 | |
| 108 m_pendingContainerSizeRequests.remove(static_cast<ImageResourceClient*>(c)); | |
| 109 | |
| 110 Resource::didRemoveClient(c); | |
| 111 } | |
| 112 | |
| 113 void ImageResource::switchClientsToRevalidatedResource() | |
| 114 { | |
| 115 ASSERT(resourceToRevalidate()); | |
| 116 ASSERT(resourceToRevalidate()->isImage()); | |
| 117 // Pending container size requests need to be transferred to the revalidated
resource. | |
| 118 if (!m_pendingContainerSizeRequests.isEmpty()) { | |
| 119 // A copy of pending size requests is needed as they are deleted during
Resource::switchClientsToRevalidateResouce(). | |
| 120 ContainerSizeRequests switchContainerSizeRequests; | |
| 121 for (ContainerSizeRequests::iterator it = m_pendingContainerSizeRequests
.begin(); it != m_pendingContainerSizeRequests.end(); ++it) | |
| 122 switchContainerSizeRequests.set(it->key, it->value); | |
| 123 Resource::switchClientsToRevalidatedResource(); | |
| 124 ImageResource* revalidatedImageResource = toImageResource(resourceToReva
lidate()); | |
| 125 for (ContainerSizeRequests::iterator it = switchContainerSizeRequests.be
gin(); it != switchContainerSizeRequests.end(); ++it) | |
| 126 revalidatedImageResource->setContainerSizeForRenderer(it->key, it->v
alue); | |
| 127 return; | |
| 128 } | |
| 129 | |
| 130 Resource::switchClientsToRevalidatedResource(); | |
| 131 } | |
| 132 | |
| 133 bool ImageResource::isSafeToUnlock() const | |
| 134 { | |
| 135 // Note that |m_image| holds a reference to |m_data| in addition to the one
held by the Resource parent class. | |
| 136 return !m_image || (m_image->hasOneRef() && m_data->refCount() == 2); | |
| 137 } | |
| 138 | |
| 139 void ImageResource::destroyDecodedDataIfPossible() | |
| 140 { | |
| 141 if (!hasClients() && !isLoading() && (!m_image || (m_image->hasOneRef() && m
_image->isBitmapImage()))) { | |
| 142 m_image = nullptr; | |
| 143 setDecodedSize(0); | |
| 144 } else if (m_image && !errorOccurred()) { | |
| 145 m_image->destroyDecodedData(true); | |
| 146 } | |
| 147 } | |
| 148 | |
| 149 void ImageResource::allClientsRemoved() | |
| 150 { | |
| 151 m_pendingContainerSizeRequests.clear(); | |
| 152 if (m_image && !errorOccurred()) | |
| 153 m_image->resetAnimation(); | |
| 154 Resource::allClientsRemoved(); | |
| 155 } | |
| 156 | |
| 157 blink::Image* ImageResource::image() | |
| 158 { | |
| 159 ASSERT(!isPurgeable()); | |
| 160 | |
| 161 if (m_image) | |
| 162 return m_image.get(); | |
| 163 | |
| 164 return blink::Image::nullImage(); | |
| 165 } | |
| 166 | |
| 167 blink::Image* ImageResource::imageForRenderer(const RenderObject* renderer) | |
| 168 { | |
| 169 ASSERT(!isPurgeable()); | |
| 170 | |
| 171 if (!m_image) | |
| 172 return blink::Image::nullImage(); | |
| 173 | |
| 174 return m_image.get(); | |
| 175 } | |
| 176 | |
| 177 void ImageResource::setContainerSizeForRenderer(const ImageResourceClient* rende
rer, const IntSize& containerSize) | |
| 178 { | |
| 179 if (containerSize.isEmpty()) | |
| 180 return; | |
| 181 ASSERT(renderer); | |
| 182 if (!m_image) { | |
| 183 m_pendingContainerSizeRequests.set(renderer, containerSize); | |
| 184 return; | |
| 185 } | |
| 186 | |
| 187 m_image->setContainerSize(containerSize); | |
| 188 } | |
| 189 | |
| 190 bool ImageResource::usesImageContainerSize() const | |
| 191 { | |
| 192 if (m_image) | |
| 193 return m_image->usesContainerSize(); | |
| 194 | |
| 195 return false; | |
| 196 } | |
| 197 | |
| 198 bool ImageResource::imageHasRelativeWidth() const | |
| 199 { | |
| 200 if (m_image) | |
| 201 return m_image->hasRelativeWidth(); | |
| 202 | |
| 203 return false; | |
| 204 } | |
| 205 | |
| 206 bool ImageResource::imageHasRelativeHeight() const | |
| 207 { | |
| 208 if (m_image) | |
| 209 return m_image->hasRelativeHeight(); | |
| 210 | |
| 211 return false; | |
| 212 } | |
| 213 | |
| 214 LayoutSize ImageResource::imageSizeForRenderer(const RenderObject* renderer, Siz
eType sizeType) | |
| 215 { | |
| 216 ASSERT(!isPurgeable()); | |
| 217 | |
| 218 if (!m_image) | |
| 219 return IntSize(); | |
| 220 | |
| 221 if (m_image->isBitmapImage() && (renderer && renderer->shouldRespectImageOri
entation() == RespectImageOrientation)) | |
| 222 return toBitmapImage(m_image.get())->sizeRespectingOrientation(); | |
| 223 | |
| 224 return m_image->size(); | |
| 225 } | |
| 226 | |
| 227 void ImageResource::computeIntrinsicDimensions(Length& intrinsicWidth, Length& i
ntrinsicHeight, FloatSize& intrinsicRatio) | |
| 228 { | |
| 229 if (m_image) | |
| 230 m_image->computeIntrinsicDimensions(intrinsicWidth, intrinsicHeight, int
rinsicRatio); | |
| 231 } | |
| 232 | |
| 233 void ImageResource::notifyObservers(const IntRect* changeRect) | |
| 234 { | |
| 235 ResourceClientWalker<ImageResourceClient> w(m_clients); | |
| 236 while (ImageResourceClient* c = w.next()) | |
| 237 c->imageChanged(this, changeRect); | |
| 238 } | |
| 239 | |
| 240 void ImageResource::clear() | |
| 241 { | |
| 242 prune(); | |
| 243 clearImage(); | |
| 244 m_pendingContainerSizeRequests.clear(); | |
| 245 setEncodedSize(0); | |
| 246 } | |
| 247 | |
| 248 void ImageResource::setCustomAcceptHeader() | |
| 249 { | |
| 250 DEFINE_STATIC_LOCAL(const AtomicString, acceptWebP, ("image/webp,*/*;q=0.8",
AtomicString::ConstructFromLiteral)); | |
| 251 setAccept(acceptWebP); | |
| 252 } | |
| 253 | |
| 254 inline void ImageResource::createImage() | |
| 255 { | |
| 256 // Create the image if it doesn't yet exist. | |
| 257 if (m_image) | |
| 258 return; | |
| 259 | |
| 260 m_image = BitmapImage::create(this); | |
| 261 | |
| 262 if (m_image) { | |
| 263 // Send queued container size requests. | |
| 264 if (m_image->usesContainerSize()) { | |
| 265 for (ContainerSizeRequests::iterator it = m_pendingContainerSizeRequ
ests.begin(); it != m_pendingContainerSizeRequests.end(); ++it) | |
| 266 setContainerSizeForRenderer(it->key, it->value); | |
| 267 } | |
| 268 m_pendingContainerSizeRequests.clear(); | |
| 269 } | |
| 270 } | |
| 271 | |
| 272 inline void ImageResource::clearImage() | |
| 273 { | |
| 274 // If our Image has an observer, it's always us so we need to clear the back
pointer | |
| 275 // before dropping our reference. | |
| 276 if (m_image) | |
| 277 m_image->setImageObserver(0); | |
| 278 m_image.clear(); | |
| 279 } | |
| 280 | |
| 281 void ImageResource::appendData(const char* data, int length) | |
| 282 { | |
| 283 Resource::appendData(data, length); | |
| 284 if (!m_loadingMultipartContent) | |
| 285 updateImage(false); | |
| 286 } | |
| 287 | |
| 288 void ImageResource::updateImage(bool allDataReceived) | |
| 289 { | |
| 290 TRACE_EVENT0("blink", "ImageResource::updateImage"); | |
| 291 | |
| 292 if (m_data) | |
| 293 createImage(); | |
| 294 | |
| 295 bool sizeAvailable = false; | |
| 296 | |
| 297 // Have the image update its data from its internal buffer. | |
| 298 // It will not do anything now, but will delay decoding until | |
| 299 // queried for info (like size or specific image frames). | |
| 300 if (m_image) | |
| 301 sizeAvailable = m_image->setData(m_data, allDataReceived); | |
| 302 | |
| 303 // Go ahead and tell our observers to try to draw if we have either | |
| 304 // received all the data or the size is known. Each chunk from the | |
| 305 // network causes observers to repaint, which will force that chunk | |
| 306 // to decode. | |
| 307 if (sizeAvailable || allDataReceived) { | |
| 308 if (!m_image || m_image->isNull()) { | |
| 309 error(errorOccurred() ? status() : DecodeError); | |
| 310 if (memoryCache()->contains(this)) | |
| 311 memoryCache()->remove(this); | |
| 312 return; | |
| 313 } | |
| 314 | |
| 315 // It would be nice to only redraw the decoded band of the image, but wi
th the current design | |
| 316 // (decoding delayed until painting) that seems hard. | |
| 317 notifyObservers(); | |
| 318 } | |
| 319 } | |
| 320 | |
| 321 void ImageResource::finishOnePart() | |
| 322 { | |
| 323 if (m_loadingMultipartContent) | |
| 324 clear(); | |
| 325 updateImage(true); | |
| 326 if (m_loadingMultipartContent) | |
| 327 m_data.clear(); | |
| 328 Resource::finishOnePart(); | |
| 329 } | |
| 330 | |
| 331 void ImageResource::error(Resource::Status status) | |
| 332 { | |
| 333 clear(); | |
| 334 Resource::error(status); | |
| 335 notifyObservers(); | |
| 336 } | |
| 337 | |
| 338 void ImageResource::responseReceived(const ResourceResponse& response) | |
| 339 { | |
| 340 if (m_loadingMultipartContent && m_data) | |
| 341 finishOnePart(); | |
| 342 else if (response.isMultipart()) | |
| 343 m_loadingMultipartContent = true; | |
| 344 if (RuntimeEnabledFeatures::clientHintsDprEnabled()) { | |
| 345 m_devicePixelRatioHeaderValue = response.httpHeaderField("DPR").toFloat(
&m_hasDevicePixelRatioHeaderValue); | |
| 346 if (!m_hasDevicePixelRatioHeaderValue || m_devicePixelRatioHeaderValue <
= 0.0) { | |
| 347 m_devicePixelRatioHeaderValue = 1.0; | |
| 348 m_hasDevicePixelRatioHeaderValue = false; | |
| 349 } | |
| 350 } | |
| 351 Resource::responseReceived(response); | |
| 352 } | |
| 353 | |
| 354 void ImageResource::decodedSizeChanged(const blink::Image* image, int delta) | |
| 355 { | |
| 356 if (!image || image != m_image) | |
| 357 return; | |
| 358 | |
| 359 setDecodedSize(decodedSize() + delta); | |
| 360 } | |
| 361 | |
| 362 void ImageResource::didDraw(const blink::Image* image) | |
| 363 { | |
| 364 if (!image || image != m_image) | |
| 365 return; | |
| 366 Resource::didAccessDecodedData(); | |
| 367 } | |
| 368 | |
| 369 bool ImageResource::shouldPauseAnimation(const blink::Image* image) | |
| 370 { | |
| 371 if (!image || image != m_image) | |
| 372 return false; | |
| 373 | |
| 374 return true; | |
| 375 } | |
| 376 | |
| 377 void ImageResource::animationAdvanced(const blink::Image* image) | |
| 378 { | |
| 379 if (!image || image != m_image) | |
| 380 return; | |
| 381 notifyObservers(); | |
| 382 } | |
| 383 | |
| 384 void ImageResource::changedInRect(const blink::Image* image, const IntRect& rect
) | |
| 385 { | |
| 386 if (!image || image != m_image) | |
| 387 return; | |
| 388 notifyObservers(&rect); | |
| 389 } | |
| 390 | |
| 391 bool ImageResource::currentFrameKnownToBeOpaque(const RenderObject* renderer) | |
| 392 { | |
| 393 blink::Image* image = imageForRenderer(renderer); | |
| 394 if (image->isBitmapImage()) | |
| 395 image->nativeImageForCurrentFrame(); // force decode | |
| 396 return image->currentFrameKnownToBeOpaque(); | |
| 397 } | |
| 398 | |
| 399 } // namespace blink | |
| OLD | NEW |