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

Side by Side Diff: third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp

Issue 1460523002: GIF decoding to Index8, unit tests and misusing unit test as benchmark (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 12 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) 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 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
101 } 101 }
102 102
103 ImageFrameGenerator::ImageFrameGenerator(const SkISize& fullSize, PassRefPtr<Sha redBuffer> data, bool allDataReceived, bool isMultiFrame) 103 ImageFrameGenerator::ImageFrameGenerator(const SkISize& fullSize, PassRefPtr<Sha redBuffer> data, bool allDataReceived, bool isMultiFrame)
104 : m_fullSize(fullSize) 104 : m_fullSize(fullSize)
105 , m_data(adoptRef(new ThreadSafeDataTransport())) 105 , m_data(adoptRef(new ThreadSafeDataTransport()))
106 , m_isMultiFrame(isMultiFrame) 106 , m_isMultiFrame(isMultiFrame)
107 , m_decodeFailedAndEmpty(false) 107 , m_decodeFailedAndEmpty(false)
108 , m_decodeCount(0) 108 , m_decodeCount(0)
109 , m_frameCount(0) 109 , m_frameCount(0)
110 , m_encodedData(nullptr) 110 , m_encodedData(nullptr)
111 , m_decoderCanDecodeToIndex8(false)
111 { 112 {
112 setData(data.get(), allDataReceived); 113 setData(data.get(), allDataReceived);
113 } 114 }
114 115
115 ImageFrameGenerator::~ImageFrameGenerator() 116 ImageFrameGenerator::~ImageFrameGenerator()
116 { 117 {
117 if (m_encodedData) 118 if (m_encodedData)
118 m_encodedData->unref(); 119 m_encodedData->unref();
119 ImageDecodingStore::instance().removeCacheIndexedByGenerator(this); 120 ImageDecodingStore::instance().removeCacheIndexedByGenerator(this);
120 } 121 }
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
168 // While m_encodedData is referenced, prevent disposing m_data and its c ontent. 169 // While m_encodedData is referenced, prevent disposing m_data and its c ontent.
169 // it is dereferenced in sharedSkDataReleaseCallback, called when m_enco dedData gets dereferenced. 170 // it is dereferenced in sharedSkDataReleaseCallback, called when m_enco dedData gets dereferenced.
170 m_data->ref(); 171 m_data->ref();
171 } 172 }
172 // Increase the reference, caller must decrease it. One reference is always kept by ImageFrameGenerator and released 173 // Increase the reference, caller must decrease it. One reference is always kept by ImageFrameGenerator and released
173 // in destructor. 174 // in destructor.
174 m_encodedData->ref(); 175 m_encodedData->ref();
175 return m_encodedData; 176 return m_encodedData;
176 } 177 }
177 178
178 bool ImageFrameGenerator::decodeAndScale(const SkImageInfo& info, size_t index, void* pixels, size_t rowBytes) 179 static bool copyIndex8PixelsTo(const SkBitmap& bitmap, const SkImageInfo& info, void* pixels, size_t rowBytes)
180 {
181 // This method is called for GIF animations, only for frames that, in first animation loop, get
182 // decoded to N32, but then are decoded to Index8 in later animation loop. I t is needed to return
183 // N32 pixels but internally GIF decoder produces and caches Index8 bitmap.
184 if (bitmap.colorType() != kIndex_8_SkColorType)
185 return false;
186 // GIF decoder always produce colortable with 256 entries.
187 ASSERT(bitmap.getColorTable() && bitmap.getColorTable()->count() == 256);
188
189 const SkPMColor* colors = bitmap.getColorTable()->readColors();
190 uint8_t* destination8 = (uint8_t*)pixels;
191 for (int j = 0; j < bitmap.height(); ++j) {
192 uint32_t* destination32 = (uint32_t*)destination8;
193 const uint8_t* source = bitmap.getAddr8(0, j);
194 const uint8_t* sourceEnd = source + bitmap.width();
195 while (source != sourceEnd)
196 *destination32++ = colors[*source++];
197 destination8 += rowBytes;
198 }
199 return true;
200 }
201
202 bool ImageFrameGenerator::decodeAndScale(const SkImageInfo& info, size_t index, void* pixels, size_t rowBytes, SkPMColor ctable[], int* ctableCount)
179 { 203 {
180 // This method is called to populate a discardable memory owned by Skia. 204 // This method is called to populate a discardable memory owned by Skia.
181 205
182 // Prevents concurrent decode or scale operations on the same image data. 206 // Prevents concurrent decode or scale operations on the same image data.
183 MutexLocker lock(m_decodeMutex); 207 MutexLocker lock(m_decodeMutex);
184 208
185 // This implementation does not support scaling so check the requested size. 209 // This implementation does not support scaling so check the requested size.
186 SkISize scaledSize = SkISize::Make(info.width(), info.height()); 210 SkISize scaledSize = SkISize::Make(info.width(), info.height());
187 ASSERT(m_fullSize == scaledSize); 211 ASSERT(m_fullSize == scaledSize);
188 212
189 if (m_decodeFailedAndEmpty) 213 if (m_decodeFailedAndEmpty)
190 return false; 214 return false;
191 215
192 TRACE_EVENT2("blink", "ImageFrameGenerator::decodeAndScale", "generator", th is, "decodeCount", m_decodeCount); 216 TRACE_EVENT2("blink", "ImageFrameGenerator::decodeAndScale", "generator", th is, "decodeCount", m_decodeCount);
193 217
194 m_externalAllocator = adoptPtr(new ExternalMemoryAllocator(info, pixels, row Bytes)); 218 m_externalAllocator = adoptPtr(new ExternalMemoryAllocator(info, pixels, row Bytes));
195 219
196 SkBitmap bitmap = tryToResumeDecode(scaledSize, index); 220 SkBitmap bitmap = tryToResumeDecode(scaledSize, index, info.colorType());
197 if (bitmap.isNull()) 221 if (bitmap.isNull())
198 return false; 222 return false;
199 223
200 // Don't keep the allocator because it contains a pointer to memory 224 // Don't keep the allocator because it contains a pointer to memory
201 // that we do not own. 225 // that we do not own.
202 m_externalAllocator.clear(); 226 m_externalAllocator.clear();
203 227
204 ASSERT(bitmap.width() == scaledSize.width()); 228 ASSERT(bitmap.width() == scaledSize.width());
205 ASSERT(bitmap.height() == scaledSize.height()); 229 ASSERT(bitmap.height() == scaledSize.height());
206 230
231 // If decoder cannot produce requested color type, return false.
232 if (bitmap.colorType() != info.colorType() && bitmap.colorType() != kIndex_8 _SkColorType)
233 return false;
234
207 bool result = true; 235 bool result = true;
208 SkAutoLockPixels bitmapLock(bitmap); 236 SkAutoLockPixels bitmapLock(bitmap);
209 // Check to see if decoder has written directly to the memory provided 237 // Check to see if decoder has written directly to the memory provided
210 // by Skia. If not make a copy. 238 // by Skia. If not make a copy.
211 if (bitmap.getPixels() != pixels) 239 if (bitmap.getPixels() != pixels) {
212 result = bitmap.copyPixelsTo(pixels, rowBytes * info.height(), rowBytes) ; 240 if (bitmap.colorType() == info.colorType()) {
241 result = bitmap.copyPixelsTo(pixels, rowBytes * info.height(), rowBy tes);
242 } else {
243 ASSERT(bitmap.colorType() == kIndex_8_SkColorType && info.colorType( ) == kN32_SkColorType);
244 result = copyIndex8PixelsTo(bitmap, info, pixels, rowBytes);
245 }
246 }
247 if (info.colorType() == kIndex_8_SkColorType && ctable && bitmap.getColorTab le()) {
248 memcpy(ctable, bitmap.getColorTable()->readColors(), bitmap.getColorTabl e()->count() * sizeof(SkPMColor));
249 }
250 if (ctableCount) {
251 // Based on SkImageGenerator API spec, ctableCount needs to be set to 0 for other types.
252 *ctableCount = (info.colorType() == kIndex_8_SkColorType && bitmap.getCo lorTable())
253 ? bitmap.getColorTable()->count()
254 : 0;
255 }
213 return result; 256 return result;
214 } 257 }
215 258
216 bool ImageFrameGenerator::decodeToYUV(SkISize componentSizes[3], void* planes[3] , size_t rowBytes[3]) 259 bool ImageFrameGenerator::decodeToYUV(SkISize componentSizes[3], void* planes[3] , size_t rowBytes[3])
217 { 260 {
218 // This method is called to populate a discardable memory owned by Skia. 261 // This method is called to populate a discardable memory owned by Skia.
219 262
220 // Prevents concurrent decode or scale operations on the same image data. 263 // Prevents concurrent decode or scale operations on the same image data.
221 MutexLocker lock(m_decodeMutex); 264 MutexLocker lock(m_decodeMutex);
222 265
(...skipping 25 matching lines...) Expand all
248 291
249 bool sizeUpdated = updateYUVComponentSizes(decoder.get(), componentSizes, Im ageDecoder::ActualSize); 292 bool sizeUpdated = updateYUVComponentSizes(decoder.get(), componentSizes, Im ageDecoder::ActualSize);
250 RELEASE_ASSERT(sizeUpdated); 293 RELEASE_ASSERT(sizeUpdated);
251 294
252 bool yuvDecoded = decoder->decodeToYUV(); 295 bool yuvDecoded = decoder->decodeToYUV();
253 if (yuvDecoded) 296 if (yuvDecoded)
254 setHasAlpha(0, false); // YUV is always opaque 297 setHasAlpha(0, false); // YUV is always opaque
255 return yuvDecoded; 298 return yuvDecoded;
256 } 299 }
257 300
258 SkBitmap ImageFrameGenerator::tryToResumeDecode(const SkISize& scaledSize, size_ t index) 301 SkBitmap ImageFrameGenerator::tryToResumeDecode(const SkISize& scaledSize, size_ t index, SkColorType outputColor)
aleksandar.stojiljkovic 2016/01/18 13:58:49 SkColorType outputColor is not necessary. Removed.
259 { 302 {
260 TRACE_EVENT1("blink", "ImageFrameGenerator::tryToResumeDecodeAndScale", "ind ex", static_cast<int>(index)); 303 TRACE_EVENT1("blink", "ImageFrameGenerator::tryToResumeDecodeAndScale", "ind ex", static_cast<int>(index));
261 304
262 ImageDecoder* decoder = 0; 305 ImageDecoder* decoder = 0;
263 const bool resumeDecoding = ImageDecodingStore::instance().lockDecoder(this, m_fullSize, &decoder); 306 const bool resumeDecoding = ImageDecodingStore::instance().lockDecoder(this, m_fullSize, &decoder);
264 ASSERT(!resumeDecoding || decoder); 307 ASSERT(!resumeDecoding || decoder);
265 308
266 SkBitmap fullSizeImage; 309 SkBitmap fullSizeImage;
267 bool complete = decode(index, &decoder, &fullSizeImage); 310 bool complete = decode(index, &decoder, &fullSizeImage, outputColor);
268 311
269 if (!decoder) 312 if (!decoder)
270 return SkBitmap(); 313 return SkBitmap();
271 if (index >= m_frameComplete.size()) 314 if (index >= m_frameComplete.size())
272 m_frameComplete.resize(index + 1); 315 m_frameComplete.resize(index + 1);
273 m_frameComplete[index] = complete; 316 m_frameComplete[index] = complete;
274 317
275 // If we are not resuming decoding that means the decoder is freshly 318 // If we are not resuming decoding that means the decoder is freshly
276 // created and we have ownership. If we are resuming decoding then 319 // created and we have ownership. If we are resuming decoding then
277 // the decoder is owned by ImageDecodingStore. 320 // the decoder is owned by ImageDecodingStore.
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
323 MutexLocker lock(m_alphaMutex); 366 MutexLocker lock(m_alphaMutex);
324 if (index >= m_hasAlpha.size()) { 367 if (index >= m_hasAlpha.size()) {
325 const size_t oldSize = m_hasAlpha.size(); 368 const size_t oldSize = m_hasAlpha.size();
326 m_hasAlpha.resize(index + 1); 369 m_hasAlpha.resize(index + 1);
327 for (size_t i = oldSize; i < m_hasAlpha.size(); ++i) 370 for (size_t i = oldSize; i < m_hasAlpha.size(); ++i)
328 m_hasAlpha[i] = true; 371 m_hasAlpha[i] = true;
329 } 372 }
330 m_hasAlpha[index] = hasAlpha; 373 m_hasAlpha[index] = hasAlpha;
331 } 374 }
332 375
333 bool ImageFrameGenerator::decode(size_t index, ImageDecoder** decoder, SkBitmap* bitmap) 376 bool ImageFrameGenerator::decode(size_t index, ImageDecoder** decoder, SkBitmap* bitmap, SkColorType outputColor)
334 { 377 {
335 TRACE_EVENT2("blink", "ImageFrameGenerator::decode", "width", m_fullSize.wid th(), "height", m_fullSize.height()); 378 TRACE_EVENT2("blink", "ImageFrameGenerator::decode", "width", m_fullSize.wid th(), "height", m_fullSize.height());
336 379
337 ASSERT(decoder); 380 ASSERT(decoder);
338 SharedBuffer* data = 0; 381 SharedBuffer* data = 0;
339 bool allDataReceived = false; 382 bool allDataReceived = false;
340 bool newDecoder = false; 383 bool newDecoder = false;
341 m_data->data(&data, &allDataReceived); 384 m_data->data(&data, &allDataReceived);
342 385
343 // Try to create an ImageDecoder if we are not given one. 386 // Try to create an ImageDecoder if we are not given one.
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
417 return false; 460 return false;
418 461
419 // Setting a dummy ImagePlanes object signals to the decoder that we want to do YUV decoding. 462 // Setting a dummy ImagePlanes object signals to the decoder that we want to do YUV decoding.
420 decoder->setData(data, allDataReceived); 463 decoder->setData(data, allDataReceived);
421 OwnPtr<ImagePlanes> dummyImagePlanes = adoptPtr(new ImagePlanes); 464 OwnPtr<ImagePlanes> dummyImagePlanes = adoptPtr(new ImagePlanes);
422 decoder->setImagePlanes(dummyImagePlanes.release()); 465 decoder->setImagePlanes(dummyImagePlanes.release());
423 466
424 return updateYUVComponentSizes(decoder.get(), componentSizes, ImageDecoder:: SizeForMemoryAllocation); 467 return updateYUVComponentSizes(decoder.get(), componentSizes, ImageDecoder:: SizeForMemoryAllocation);
425 } 468 }
426 469
470 bool ImageFrameGenerator::canDecodeTo(size_t index, SkColorType outputType)
471 {
472 if (m_decoderCanDecodeToIndex8) {
473 // Prevents concurrent decode or scale operations on the same image data .
474 MutexLocker lock(m_decodeMutex);
475 ImageDecoder* decoder = 0;
476 const bool decoderExist = ImageDecodingStore::instance().lockDecoder(thi s, m_fullSize, &decoder);
477 ASSERT(!decoderExist || decoder);
478 SharedBuffer* data = 0;
479 bool allDataReceived = false;
480 m_data->data(&data, &allDataReceived);
481 if (!decoderExist) {
482 if (m_imageDecoderFactory)
483 decoder = m_imageDecoderFactory->create().leakPtr();
484 if (!decoder)
485 decoder = ImageDecoder::create(*data, ImageDecoder::AlphaPremult iplied, ImageDecoder::GammaAndColorProfileApplied).leakPtr();
486 if (!decoder)
487 return (outputType == kIndex_8_SkColorType);
488 }
489 decoder->setData(data, allDataReceived);
490 bool canDecodeToIndex8 = decoder->canDecodeTo(index, static_cast<ImageFr ame::ColorType>(outputType));
491 decoder->setData(0, false); // Unref SharedBuffer from ImageDecoder.
492 if (decoderExist) {
493 ImageDecodingStore::instance().unlockDecoder(this, decoder);
494 } else {
495 ImageDecodingStore::instance().insertDecoder(this, PassOwnPtr<blink: :ImageDecoder>(adoptPtr(decoder)));
496 }
497 return (canDecodeToIndex8 && (outputType == kIndex_8_SkColorType));
498 }
499 return (outputType == kN32_SkColorType);
scroggo_chromium 2016/01/06 21:50:40 Would it make more sense to put this at the beginn
aleksandar.stojiljkovic 2016/01/18 13:58:49 Done.
500 }
501
502
427 } // namespace blink 503 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698