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

Side by Side Diff: Source/core/platform/graphics/chromium/ImageFrameGenerator.cpp

Issue 19838002: Reland change to enable deferred image decoding for animated GIFs (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: merved Created 7 years, 5 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 | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2012 Google Inc. All rights reserved. 2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 1. Redistributions of source code must retain the above copyright 7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright 9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
(...skipping 29 matching lines...) Expand all
40 40
41 namespace { 41 namespace {
42 42
43 skia::ImageOperations::ResizeMethod resizeMethod() 43 skia::ImageOperations::ResizeMethod resizeMethod()
44 { 44 {
45 return skia::ImageOperations::RESIZE_LANCZOS3; 45 return skia::ImageOperations::RESIZE_LANCZOS3;
46 } 46 }
47 47
48 } // namespace 48 } // namespace
49 49
50 ImageFrameGenerator::ImageFrameGenerator(const SkISize& fullSize, PassRefPtr<Sha redBuffer> data, bool allDataReceived) 50 ImageFrameGenerator::ImageFrameGenerator(const SkISize& fullSize, PassRefPtr<Sha redBuffer> data, bool allDataReceived, bool isMultiFrame)
51 : m_fullSize(fullSize) 51 : m_fullSize(fullSize)
52 , m_isMultiFrame(isMultiFrame)
52 , m_decodeFailedAndEmpty(false) 53 , m_decodeFailedAndEmpty(false)
53 , m_hasAlpha(true)
54 , m_decodeCount(ScaledImageFragment::FirstPartialImage) 54 , m_decodeCount(ScaledImageFragment::FirstPartialImage)
55 { 55 {
56 setData(data.get(), allDataReceived); 56 setData(data.get(), allDataReceived);
57 } 57 }
58 58
59 ImageFrameGenerator::~ImageFrameGenerator() 59 ImageFrameGenerator::~ImageFrameGenerator()
60 { 60 {
61 // FIXME: This check is not really thread-safe. This should be changed to: 61 // FIXME: This check is not really thread-safe. This should be changed to:
62 // ImageDecodingStore::removeCacheFromInstance(this); 62 // ImageDecodingStore::removeCacheFromInstance(this);
63 // Which uses a lock internally. 63 // Which uses a lock internally.
64 if (ImageDecodingStore::instance()) 64 if (ImageDecodingStore::instance())
65 ImageDecodingStore::instance()->removeCacheIndexedByGenerator(this); 65 ImageDecodingStore::instance()->removeCacheIndexedByGenerator(this);
66 } 66 }
67 67
68 void ImageFrameGenerator::setData(PassRefPtr<SharedBuffer> data, bool allDataRec eived) 68 void ImageFrameGenerator::setData(PassRefPtr<SharedBuffer> data, bool allDataRec eived)
69 { 69 {
70 m_data.setData(data.get(), allDataReceived); 70 m_data.setData(data.get(), allDataReceived);
71 } 71 }
72 72
73 void ImageFrameGenerator::copyData(RefPtr<SharedBuffer>* data, bool* allDataRece ived) 73 void ImageFrameGenerator::copyData(RefPtr<SharedBuffer>* data, bool* allDataRece ived)
74 { 74 {
75 SharedBuffer* buffer = 0; 75 SharedBuffer* buffer = 0;
76 m_data.data(&buffer, allDataReceived); 76 m_data.data(&buffer, allDataReceived);
77 if (buffer) 77 if (buffer)
78 *data = buffer->copy(); 78 *data = buffer->copy();
79 } 79 }
80 80
81 const ScaledImageFragment* ImageFrameGenerator::decodeAndScale(const SkISize& sc aledSize) 81 const ScaledImageFragment* ImageFrameGenerator::decodeAndScale(const SkISize& sc aledSize, size_t index)
82 { 82 {
83 // Prevents concurrent decode or scale operations on the same image data. 83 // Prevents concurrent decode or scale operations on the same image data.
84 // Multiple LazyDecodingPixelRefs can call this method at the same time. 84 // Multiple LazyDecodingPixelRefs can call this method at the same time.
85 MutexLocker lock(m_decodeMutex); 85 MutexLocker lock(m_decodeMutex);
86 if (m_decodeFailedAndEmpty) 86 if (m_decodeFailedAndEmpty)
87 return 0; 87 return 0;
88 88
89 const ScaledImageFragment* cachedImage = 0; 89 const ScaledImageFragment* cachedImage = 0;
90 90
91 cachedImage = tryToLockCompleteCache(scaledSize); 91 cachedImage = tryToLockCompleteCache(scaledSize, index);
92 if (cachedImage) 92 if (cachedImage)
93 return cachedImage; 93 return cachedImage;
94 94
95 TRACE_EVENT2("webkit", "ImageFrameGenerator::decodeAndScale", "generator", t his, "decodeCount", static_cast<int>(m_decodeCount)); 95 TRACE_EVENT2("webkit", "ImageFrameGenerator::decodeAndScale", "generator", t his, "decodeCount", static_cast<int>(m_decodeCount));
96 96
97 cachedImage = tryToScale(0, scaledSize); 97 cachedImage = tryToScale(0, scaledSize, index);
98 if (cachedImage) 98 if (cachedImage)
99 return cachedImage; 99 return cachedImage;
100 100
101 cachedImage = tryToResumeDecodeAndScale(scaledSize); 101 cachedImage = tryToResumeDecodeAndScale(scaledSize, index);
102 if (cachedImage) 102 if (cachedImage)
103 return cachedImage; 103 return cachedImage;
104 104
105 cachedImage = tryToDecodeAndScale(scaledSize); 105 cachedImage = tryToDecodeAndScale(scaledSize, index);
106 if (cachedImage) 106 if (cachedImage)
107 return cachedImage; 107 return cachedImage;
108 return 0; 108 return 0;
109 } 109 }
110 110
111 const ScaledImageFragment* ImageFrameGenerator::tryToLockCompleteCache(const SkI Size& scaledSize) 111 const ScaledImageFragment* ImageFrameGenerator::tryToLockCompleteCache(const SkI Size& scaledSize, size_t index)
112 { 112 {
113 const ScaledImageFragment* cachedImage = 0; 113 const ScaledImageFragment* cachedImage = 0;
114 if (ImageDecodingStore::instance()->lockCache(this, scaledSize, 0, &cachedIm age)) 114 if (ImageDecodingStore::instance()->lockCache(this, scaledSize, index, &cach edImage))
115 return cachedImage; 115 return cachedImage;
116 return 0; 116 return 0;
117 } 117 }
118 118
119 const ScaledImageFragment* ImageFrameGenerator::tryToScale(const ScaledImageFrag ment* fullSizeImage, const SkISize& scaledSize) 119 const ScaledImageFragment* ImageFrameGenerator::tryToScale(const ScaledImageFrag ment* fullSizeImage, const SkISize& scaledSize, size_t index)
120 { 120 {
121 TRACE_EVENT0("webkit", "ImageFrameGenerator::tryToScale"); 121 TRACE_EVENT0("webkit", "ImageFrameGenerator::tryToScale");
122 122
123 // If the requested scaled size is the same as the full size then exit 123 // If the requested scaled size is the same as the full size then exit
124 // early. This saves a cache lookup. 124 // early. This saves a cache lookup.
125 if (scaledSize == m_fullSize) 125 if (scaledSize == m_fullSize)
126 return 0; 126 return 0;
127 127
128 if (!fullSizeImage && !ImageDecodingStore::instance()->lockCache(this, m_ful lSize, 0, &fullSizeImage)) 128 if (!fullSizeImage && !ImageDecodingStore::instance()->lockCache(this, m_ful lSize, index, &fullSizeImage))
129 return 0; 129 return 0;
130 130
131 // This call allocates the DiscardablePixelRef and lock/unlocks it 131 // This call allocates the DiscardablePixelRef and lock/unlocks it
132 // afterwards. So the memory allocated to the scaledBitmap can be 132 // afterwards. So the memory allocated to the scaledBitmap can be
133 // discarded after this call. Need to lock the scaledBitmap and 133 // discarded after this call. Need to lock the scaledBitmap and
134 // check the pixels before using it next time. 134 // check the pixels before using it next time.
135 SkBitmap scaledBitmap = skia::ImageOperations::Resize(fullSizeImage->bitmap( ), resizeMethod(), scaledSize.width(), scaledSize.height(), &m_allocator); 135 SkBitmap scaledBitmap = skia::ImageOperations::Resize(fullSizeImage->bitmap( ), resizeMethod(), scaledSize.width(), scaledSize.height(), &m_allocator);
136 136
137 OwnPtr<ScaledImageFragment> scaledImage; 137 OwnPtr<ScaledImageFragment> scaledImage;
138 if (fullSizeImage->isComplete()) 138 if (fullSizeImage->isComplete())
139 scaledImage = ScaledImageFragment::createComplete(scaledSize, fullSizeIm age->index(), scaledBitmap); 139 scaledImage = ScaledImageFragment::createComplete(scaledSize, fullSizeIm age->index(), scaledBitmap);
140 else 140 else
141 scaledImage = ScaledImageFragment::createPartial(scaledSize, fullSizeIma ge->index(), nextGenerationId(), scaledBitmap); 141 scaledImage = ScaledImageFragment::createPartial(scaledSize, fullSizeIma ge->index(), nextGenerationId(), scaledBitmap);
142 ImageDecodingStore::instance()->unlockCache(this, fullSizeImage); 142 ImageDecodingStore::instance()->unlockCache(this, fullSizeImage);
143 return ImageDecodingStore::instance()->insertAndLockCache(this, scaledImage. release()); 143 return ImageDecodingStore::instance()->insertAndLockCache(this, scaledImage. release());
144 } 144 }
145 145
146 const ScaledImageFragment* ImageFrameGenerator::tryToResumeDecodeAndScale(const SkISize& scaledSize) 146 const ScaledImageFragment* ImageFrameGenerator::tryToResumeDecodeAndScale(const SkISize& scaledSize, size_t index)
147 { 147 {
148 TRACE_EVENT0("webkit", "ImageFrameGenerator::tryToResumeDecodeAndScale"); 148 TRACE_EVENT1("webkit", "ImageFrameGenerator::tryToResumeDecodeAndScale", "in dex", static_cast<int>(index));
149 149
150 ImageDecoder* cachedDecoder = 0; 150 ImageDecoder* cachedDecoder = 0;
151 151
152 if (!ImageDecodingStore::instance()->lockDecoder(this, m_fullSize, &cachedDe coder)) 152 if (!ImageDecodingStore::instance()->lockDecoder(this, m_fullSize, &cachedDe coder))
153 return 0; 153 return 0;
154 ASSERT(cachedDecoder); 154 ASSERT(cachedDecoder);
155 155
156 // Always generate a new image and insert it into cache. 156 // Always generate a new image and insert it into cache.
157 OwnPtr<ScaledImageFragment> fullSizeImage = decode(&cachedDecoder); 157 OwnPtr<ScaledImageFragment> fullSizeImage = decode(index, &cachedDecoder);
158
159 if (!fullSizeImage) {
160 // If decode has failed and resulted an empty image we can save work
161 // in the future by returning early.
162 m_decodeFailedAndEmpty = !m_isMultiFrame && cachedDecoder->failed();
163 ImageDecodingStore::instance()->unlockDecoder(this, cachedDecoder);
164 return 0;
165 }
166
158 const ScaledImageFragment* cachedImage = ImageDecodingStore::instance()->ins ertAndLockCache(this, fullSizeImage.release()); 167 const ScaledImageFragment* cachedImage = ImageDecodingStore::instance()->ins ertAndLockCache(this, fullSizeImage.release());
159 168
160 // If the image generated is complete then there is no need to keep 169 // If the image generated is complete then there is no need to keep
161 // the decoder. 170 // the decoder. The exception is multi-frame decoder which can generate
162 if (cachedImage->isComplete()) 171 // multiple complete frames.
172 if (cachedImage->isComplete() && !m_isMultiFrame)
163 ImageDecodingStore::instance()->removeDecoder(this, cachedDecoder); 173 ImageDecodingStore::instance()->removeDecoder(this, cachedDecoder);
164 else 174 else
165 ImageDecodingStore::instance()->unlockDecoder(this, cachedDecoder); 175 ImageDecodingStore::instance()->unlockDecoder(this, cachedDecoder);
166 176
167 if (m_fullSize == scaledSize) 177 if (m_fullSize == scaledSize)
168 return cachedImage; 178 return cachedImage;
169 return tryToScale(cachedImage, scaledSize); 179 return tryToScale(cachedImage, scaledSize, index);
170 } 180 }
171 181
172 const ScaledImageFragment* ImageFrameGenerator::tryToDecodeAndScale(const SkISiz e& scaledSize) 182 const ScaledImageFragment* ImageFrameGenerator::tryToDecodeAndScale(const SkISiz e& scaledSize, size_t index)
173 { 183 {
174 TRACE_EVENT0("webkit", "ImageFrameGenerator::tryToDecodeAndScale"); 184 TRACE_EVENT1("webkit", "ImageFrameGenerator::tryToDecodeAndScale", "index", static_cast<int>(index));
175 185
176 ImageDecoder* decoder = 0; 186 ImageDecoder* decoder = 0;
177 OwnPtr<ScaledImageFragment> fullSizeImage = decode(&decoder); 187 OwnPtr<ScaledImageFragment> fullSizeImage = decode(index, &decoder);
178 188
179 if (!decoder) 189 if (!decoder)
180 return 0; 190 return 0;
181 191
182 OwnPtr<ImageDecoder> decoderContainer = adoptPtr(decoder); 192 OwnPtr<ImageDecoder> decoderContainer = adoptPtr(decoder);
183 193
184 if (!fullSizeImage) { 194 if (!fullSizeImage) {
185 // If decode has failed and resulted an empty image we need to make 195 // If decode has failed and resulted an empty image we can save work
186 // sure we don't do wasted work in the future. 196 // in the future by returning early.
187 m_decodeFailedAndEmpty = decoderContainer->failed(); 197 m_decodeFailedAndEmpty = !m_isMultiFrame && decoderContainer->failed();
188 return 0; 198 return 0;
189 } 199 }
190 200
191 const ScaledImageFragment* cachedImage = ImageDecodingStore::instance()->ins ertAndLockCache(this, fullSizeImage.release()); 201 const ScaledImageFragment* cachedImage = ImageDecodingStore::instance()->ins ertAndLockCache(this, fullSizeImage.release());
192 202
193 // If image is complete then decoder is not needed in the future. 203 // If image is complete then decoder is not needed in the future.
194 // Otherwise save the decoder for later use. 204 // Otherwise save the decoder for later use. The exception is
195 if (!cachedImage->isComplete()) 205 // multi-frame decoder which can generate multiple complete frames.
206 if (!cachedImage->isComplete() || m_isMultiFrame)
196 ImageDecodingStore::instance()->insertDecoder(this, decoderContainer.rel ease(), DiscardablePixelRef::isDiscardable(cachedImage->bitmap().pixelRef())); 207 ImageDecodingStore::instance()->insertDecoder(this, decoderContainer.rel ease(), DiscardablePixelRef::isDiscardable(cachedImage->bitmap().pixelRef()));
197 208
198 if (m_fullSize == scaledSize) 209 if (m_fullSize == scaledSize)
199 return cachedImage; 210 return cachedImage;
200 return tryToScale(cachedImage, scaledSize); 211 return tryToScale(cachedImage, scaledSize, index);
201 } 212 }
202 213
203 PassOwnPtr<ScaledImageFragment> ImageFrameGenerator::decode(ImageDecoder** decod er) 214 PassOwnPtr<ScaledImageFragment> ImageFrameGenerator::decode(size_t index, ImageD ecoder** decoder)
204 { 215 {
205 TRACE_EVENT2("webkit", "ImageFrameGenerator::decode", "width", m_fullSize.wi dth(), "height", m_fullSize.height()); 216 TRACE_EVENT2("webkit", "ImageFrameGenerator::decode", "width", m_fullSize.wi dth(), "height", m_fullSize.height());
206 217
207 ASSERT(decoder); 218 ASSERT(decoder);
208 SharedBuffer* data = 0; 219 SharedBuffer* data = 0;
209 bool allDataReceived = false; 220 bool allDataReceived = false;
210 m_data.data(&data, &allDataReceived); 221 m_data.data(&data, &allDataReceived);
211 222
212 // Try to create an ImageDecoder if we are not given one. 223 // Try to create an ImageDecoder if we are not given one.
213 if (!*decoder) { 224 if (!*decoder) {
214 *decoder = ImageDecoder::create(*data, ImageSource::AlphaPremultiplied, ImageSource::GammaAndColorProfileApplied).leakPtr(); 225 *decoder = ImageDecoder::create(*data, ImageSource::AlphaPremultiplied, ImageSource::GammaAndColorProfileApplied).leakPtr();
215 226
216 if (!*decoder && m_imageDecoderFactory) 227 if (!*decoder && m_imageDecoderFactory)
217 *decoder = m_imageDecoderFactory->create().leakPtr(); 228 *decoder = m_imageDecoderFactory->create().leakPtr();
218 229
219 if (!*decoder) 230 if (!*decoder)
220 return nullptr; 231 return nullptr;
221 } 232 }
222 233
223 // TODO: this is very ugly. We need to refactor the way how we can pass a 234 // TODO: this is very ugly. We need to refactor the way how we can pass a
224 // memory allocator to image decoders. 235 // memory allocator to image decoders.
225 (*decoder)->setMemoryAllocator(&m_allocator); 236 if (!m_isMultiFrame)
237 (*decoder)->setMemoryAllocator(&m_allocator);
226 (*decoder)->setData(data, allDataReceived); 238 (*decoder)->setData(data, allDataReceived);
227 // If this call returns a newly allocated DiscardablePixelRef, then 239 // If this call returns a newly allocated DiscardablePixelRef, then
228 // ImageFrame::m_bitmap and the contained DiscardablePixelRef are locked. 240 // ImageFrame::m_bitmap and the contained DiscardablePixelRef are locked.
229 // They will be unlocked when ImageDecoder is destroyed since ImageDecoder 241 // They will be unlocked when ImageDecoder is destroyed since ImageDecoder
230 // owns the ImageFrame. Partially decoded SkBitmap is thus inserted into the 242 // owns the ImageFrame. Partially decoded SkBitmap is thus inserted into the
231 // ImageDecodingStore while locked. 243 // ImageDecodingStore while locked.
232 ImageFrame* frame = (*decoder)->frameBufferAtIndex(0); 244 ImageFrame* frame = (*decoder)->frameBufferAtIndex(index);
233 (*decoder)->setData(0, false); // Unref SharedBuffer from ImageDecoder. 245 (*decoder)->setData(0, false); // Unref SharedBuffer from ImageDecoder.
246 (*decoder)->clearCacheExceptFrame(index);
234 247
235 if (!frame || frame->status() == ImageFrame::FrameEmpty) 248 if (!frame || frame->status() == ImageFrame::FrameEmpty)
236 return nullptr; 249 return nullptr;
237 250
238 const bool isComplete = frame->status() == ImageFrame::FrameComplete; 251 const bool isComplete = frame->status() == ImageFrame::FrameComplete;
239 SkBitmap fullSizeBitmap = frame->getSkBitmap(); 252 SkBitmap fullSizeBitmap = frame->getSkBitmap();
240 { 253 {
241 MutexLocker lock(m_alphaMutex); 254 MutexLocker lock(m_alphaMutex);
242 m_hasAlpha = !fullSizeBitmap.isOpaque(); 255 if (index >= m_hasAlpha.size()) {
256 const size_t oldSize = m_hasAlpha.size();
257 m_hasAlpha.resize(index + 1);
258 for (size_t i = oldSize; i < m_hasAlpha.size(); ++i)
259 m_hasAlpha[i] = true;
260 }
261 m_hasAlpha[index] = !fullSizeBitmap.isOpaque();
243 } 262 }
244 ASSERT(fullSizeBitmap.width() == m_fullSize.width() && fullSizeBitmap.height () == m_fullSize.height()); 263 ASSERT(fullSizeBitmap.width() == m_fullSize.width() && fullSizeBitmap.height () == m_fullSize.height());
245 264
246 if (isComplete) 265 if (isComplete)
247 return ScaledImageFragment::createComplete(m_fullSize, 0, fullSizeBitmap ); 266 return ScaledImageFragment::createComplete(m_fullSize, index, fullSizeBi tmap);
248 267
249 // If the image is partial we need to return a copy. This is to avoid future 268 // If the image is partial we need to return a copy. This is to avoid future
250 // decode operations writing to the same bitmap. 269 // decode operations writing to the same bitmap.
251 SkBitmap copyBitmap; 270 SkBitmap copyBitmap;
252 fullSizeBitmap.copyTo(&copyBitmap, fullSizeBitmap.config(), &m_allocator); 271 fullSizeBitmap.copyTo(&copyBitmap, fullSizeBitmap.config(), &m_allocator);
253 return ScaledImageFragment::createPartial(m_fullSize, 0, nextGenerationId(), copyBitmap); 272 return ScaledImageFragment::createPartial(m_fullSize, index, nextGenerationI d(), copyBitmap);
254 } 273 }
255 274
256 bool ImageFrameGenerator::hasAlpha() 275 bool ImageFrameGenerator::hasAlpha(size_t index)
257 { 276 {
258 MutexLocker lock(m_alphaMutex); 277 MutexLocker lock(m_alphaMutex);
259 return m_hasAlpha; 278 if (index < m_hasAlpha.size())
279 return m_hasAlpha[index];
280 return true;
260 } 281 }
261 282
262 } // namespace WebCore 283 } // namespace WebCore
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698