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

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

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

Powered by Google App Engine
This is Rietveld 408576698