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

Side by Side Diff: Source/core/platform/image-decoders/gif/GIFImageDecoder.cpp

Issue 15466003: Remove image decoder down sampling (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 7 years, 7 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) 2006 Apple Computer, Inc. All rights reserved. 2 * Copyright (C) 2006 Apple Computer, 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 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
60 decode(0, GIFSizeQuery); 60 decode(0, GIFSizeQuery);
61 61
62 return ImageDecoder::isSizeAvailable(); 62 return ImageDecoder::isSizeAvailable();
63 } 63 }
64 64
65 bool GIFImageDecoder::setSize(unsigned width, unsigned height) 65 bool GIFImageDecoder::setSize(unsigned width, unsigned height)
66 { 66 {
67 if (ImageDecoder::isSizeAvailable() && size() == IntSize(width, height)) 67 if (ImageDecoder::isSizeAvailable() && size() == IntSize(width, height))
68 return true; 68 return true;
69 69
70 if (!ImageDecoder::setSize(width, height)) 70 return ImageDecoder::setSize(width, height);
Peter Kasting 2013/05/20 23:04:24 It seems like we no longer need to override setSiz
Noel Gordon 2013/05/21 04:24:03 Yes I had wondered about that, and I wanted confir
71 return false;
72
73 prepareScaleDataIfNecessary();
74 return true;
75 } 71 }
76 72
77 size_t GIFImageDecoder::frameCount() 73 size_t GIFImageDecoder::frameCount()
78 { 74 {
79 decode(std::numeric_limits<unsigned>::max(), GIFFrameCountQuery); 75 decode(std::numeric_limits<unsigned>::max(), GIFFrameCountQuery);
80 return m_frameBufferCache.size(); 76 return m_frameBufferCache.size();
81 } 77 }
82 78
83 int GIFImageDecoder::repetitionCount() const 79 int GIFImageDecoder::repetitionCount() const
84 { 80 {
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
197 193
198 bool GIFImageDecoder::haveDecodedRow(unsigned frameIndex, const Vector<unsigned char>& rowBuffer, size_t width, size_t rowNumber, unsigned repeatCount, bool wri teTransparentPixels) 194 bool GIFImageDecoder::haveDecodedRow(unsigned frameIndex, const Vector<unsigned char>& rowBuffer, size_t width, size_t rowNumber, unsigned repeatCount, bool wri teTransparentPixels)
199 { 195 {
200 const GIFFrameContext* frameContext = m_reader->frameContext(frameIndex); 196 const GIFFrameContext* frameContext = m_reader->frameContext(frameIndex);
201 // The pixel data and coordinates supplied to us are relative to the frame's 197 // The pixel data and coordinates supplied to us are relative to the frame's
202 // origin within the entire image size, i.e. 198 // origin within the entire image size, i.e.
203 // (frameContext->xOffset, frameContext->yOffset). There is no guarantee 199 // (frameContext->xOffset, frameContext->yOffset). There is no guarantee
204 // that width == (size().width() - frameContext->xOffset), so 200 // that width == (size().width() - frameContext->xOffset), so
205 // we must ensure we don't run off the end of either the source data or the 201 // we must ensure we don't run off the end of either the source data or the
206 // row's X-coordinates. 202 // row's X-coordinates.
207 int xBegin = upperBoundScaledX(frameContext->xOffset); 203 int xBegin = frameContext->xOffset;
208 int yBegin = upperBoundScaledY(frameContext->yOffset + rowNumber); 204 int yBegin = frameContext->yOffset + rowNumber;
209 int xEnd = lowerBoundScaledX(std::min(static_cast<int>(frameContext->xOffset + width), size().width()) - 1, xBegin + 1) + 1; 205 int xEnd = std::min(static_cast<int>(frameContext->xOffset + width), size(). width());
210 int yEnd = lowerBoundScaledY(std::min(static_cast<int>(frameContext->yOffset + rowNumber + repeatCount), size().height()) - 1, yBegin + 1) + 1; 206 int yEnd = std::min(static_cast<int>(frameContext->yOffset + rowNumber + rep eatCount), size().height());
211 if (rowBuffer.isEmpty() || (xBegin < 0) || (yBegin < 0) || (xEnd <= xBegin) || (yEnd <= yBegin)) 207 if (rowBuffer.isEmpty() || (xBegin < 0) || (yBegin < 0) || (xEnd <= xBegin) || (yEnd <= yBegin))
212 return true; 208 return true;
213 209
214 // Get the colormap. 210 // Get the colormap.
215 const unsigned char* colorMap; 211 const unsigned char* colorMap;
216 unsigned colorMapSize; 212 unsigned colorMapSize;
217 if (frameContext->isLocalColormapDefined) { 213 if (frameContext->isLocalColormapDefined) {
218 colorMap = m_reader->localColormap(frameContext); 214 colorMap = m_reader->localColormap(frameContext);
219 colorMapSize = m_reader->localColormapSize(frameContext); 215 colorMapSize = m_reader->localColormapSize(frameContext);
220 } else { 216 } else {
221 colorMap = m_reader->globalColormap(); 217 colorMap = m_reader->globalColormap();
222 colorMapSize = m_reader->globalColormapSize(); 218 colorMapSize = m_reader->globalColormapSize();
223 } 219 }
224 if (!colorMap) 220 if (!colorMap)
225 return true; 221 return true;
226 222
227 // Initialize the frame if necessary. 223 // Initialize the frame if necessary.
228 ImageFrame& buffer = m_frameBufferCache[frameIndex]; 224 ImageFrame& buffer = m_frameBufferCache[frameIndex];
229 if ((buffer.status() == ImageFrame::FrameEmpty) && !initFrameBuffer(frameInd ex)) 225 if ((buffer.status() == ImageFrame::FrameEmpty) && !initFrameBuffer(frameInd ex))
230 return false; 226 return false;
231 227
232 ImageFrame::PixelData* currentAddress = buffer.getAddr(xBegin, yBegin); 228 ImageFrame::PixelData* currentAddress = buffer.getAddr(xBegin, yBegin);
233 // Write one row's worth of data into the frame. 229 // Write one row's worth of data into the frame.
234 for (int x = xBegin; x < xEnd; ++x) { 230 for (int x = xBegin; x < xEnd; ++x) {
235 const unsigned char sourceValue = rowBuffer[(m_scaled ? m_scaledColumns[ x] : x) - frameContext->xOffset]; 231 const unsigned char sourceValue = rowBuffer[x - frameContext->xOffset];
236 if ((!frameContext->isTransparent || (sourceValue != frameContext->tpixe l)) && (sourceValue < colorMapSize)) { 232 if ((!frameContext->isTransparent || (sourceValue != frameContext->tpixe l)) && (sourceValue < colorMapSize)) {
237 const size_t colorIndex = static_cast<size_t>(sourceValue) * 3; 233 const size_t colorIndex = static_cast<size_t>(sourceValue) * 3;
238 buffer.setRGBA(currentAddress, colorMap[colorIndex], colorMap[colorI ndex + 1], colorMap[colorIndex + 2], 255); 234 buffer.setRGBA(currentAddress, colorMap[colorIndex], colorMap[colorI ndex + 1], colorMap[colorIndex + 2], 255);
239 } else { 235 } else {
240 m_currentBufferSawAlpha = true; 236 m_currentBufferSawAlpha = true;
241 // We may or may not need to write transparent pixels to the buffer. 237 // We may or may not need to write transparent pixels to the buffer.
242 // If we're compositing against a previous image, it's wrong, and if 238 // If we're compositing against a previous image, it's wrong, and if
243 // we're writing atop a cleared, fully transparent buffer, it's 239 // we're writing atop a cleared, fully transparent buffer, it's
244 // unnecessary; but if we're decoding an interlaced gif and 240 // unnecessary; but if we're decoding an interlaced gif and
245 // displaying it "Haeberli"-style, we must write these for passes 241 // displaying it "Haeberli"-style, we must write these for passes
(...skipping 20 matching lines...) Expand all
266 if ((buffer.status() == ImageFrame::FrameEmpty) && !initFrameBuffer(frameInd ex)) 262 if ((buffer.status() == ImageFrame::FrameEmpty) && !initFrameBuffer(frameInd ex))
267 return false; // initFrameBuffer() has already called setFailed(). 263 return false; // initFrameBuffer() has already called setFailed().
268 264
269 buffer.setStatus(ImageFrame::FrameComplete); 265 buffer.setStatus(ImageFrame::FrameComplete);
270 buffer.setDuration(frameDuration); 266 buffer.setDuration(frameDuration);
271 buffer.setDisposalMethod(disposalMethod); 267 buffer.setDisposalMethod(disposalMethod);
272 268
273 if (!m_currentBufferSawAlpha) { 269 if (!m_currentBufferSawAlpha) {
274 // The whole frame was non-transparent, so it's possible that the entire 270 // The whole frame was non-transparent, so it's possible that the entire
275 // resulting buffer was non-transparent, and we can setHasAlpha(false). 271 // resulting buffer was non-transparent, and we can setHasAlpha(false).
276 if (buffer.originalFrameRect().contains(IntRect(IntPoint(), scaledSize() ))) 272 if (buffer.originalFrameRect().contains(IntRect(IntPoint(), size())))
277 buffer.setHasAlpha(false); 273 buffer.setHasAlpha(false);
278 else if (frameIndex) { 274 else if (frameIndex) {
279 // Tricky case. This frame does not have alpha only if everywhere 275 // Tricky case. This frame does not have alpha only if everywhere
280 // outside its rect doesn't have alpha. To know whether this is 276 // outside its rect doesn't have alpha. To know whether this is
281 // true, we check the start state of the frame -- if it doesn't have 277 // true, we check the start state of the frame -- if it doesn't have
282 // alpha, we're safe. 278 // alpha, we're safe.
283 // 279 //
284 // First skip over prior DisposeOverwritePrevious frames (since they 280 // First skip over prior DisposeOverwritePrevious frames (since they
285 // don't affect the start state of this frame) the same way we do in 281 // don't affect the start state of this frame) the same way we do in
286 // initFrameBuffer(). 282 // initFrameBuffer().
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
357 const GIFFrameContext* frameContext = m_reader->frameContext(frameIndex); 353 const GIFFrameContext* frameContext = m_reader->frameContext(frameIndex);
358 IntRect frameRect(frameContext->xOffset, frameContext->yOffset, frameContext ->width, frameContext->height); 354 IntRect frameRect(frameContext->xOffset, frameContext->yOffset, frameContext ->width, frameContext->height);
359 355
360 // Make sure the frameRect doesn't extend outside the buffer. 356 // Make sure the frameRect doesn't extend outside the buffer.
361 if (frameRect.maxX() > size().width()) 357 if (frameRect.maxX() > size().width())
362 frameRect.setWidth(size().width() - frameContext->xOffset); 358 frameRect.setWidth(size().width() - frameContext->xOffset);
363 if (frameRect.maxY() > size().height()) 359 if (frameRect.maxY() > size().height())
364 frameRect.setHeight(size().height() - frameContext->yOffset); 360 frameRect.setHeight(size().height() - frameContext->yOffset);
365 361
366 ImageFrame* const buffer = &m_frameBufferCache[frameIndex]; 362 ImageFrame* const buffer = &m_frameBufferCache[frameIndex];
367 int left = upperBoundScaledX(frameRect.x()); 363 buffer->setOriginalFrameRect(frameRect);
368 int right = lowerBoundScaledX(frameRect.maxX(), left);
369 int top = upperBoundScaledY(frameRect.y());
370 int bottom = lowerBoundScaledY(frameRect.maxY(), top);
371 buffer->setOriginalFrameRect(IntRect(left, top, right - left, bottom - top)) ;
372 364
373 if (!frameIndex) { 365 if (!frameIndex) {
374 // This is the first frame, so we're not relying on any previous data. 366 // This is the first frame, so we're not relying on any previous data.
375 if (!buffer->setSize(scaledSize().width(), scaledSize().height())) 367 if (!buffer->setSize(size().width(), size().height()))
376 return setFailed(); 368 return setFailed();
377 } else { 369 } else {
378 // The starting state for this frame depends on the previous frame's 370 // The starting state for this frame depends on the previous frame's
379 // disposal method. 371 // disposal method.
380 // 372 //
381 // Frames that use the DisposeOverwritePrevious method are effectively 373 // Frames that use the DisposeOverwritePrevious method are effectively
382 // no-ops in terms of changing the starting state of a frame compared to 374 // no-ops in terms of changing the starting state of a frame compared to
383 // the starting state of the previous frame, so skip over them. (If the 375 // the starting state of the previous frame, so skip over them. (If the
384 // first frame specifies this method, it will get treated like 376 // first frame specifies this method, it will get treated like
385 // DisposeOverwriteBgcolor below and reset to a completely empty image.) 377 // DisposeOverwriteBgcolor below and reset to a completely empty image.)
386 const ImageFrame* prevBuffer = &m_frameBufferCache[--frameIndex]; 378 const ImageFrame* prevBuffer = &m_frameBufferCache[--frameIndex];
387 ImageFrame::FrameDisposalMethod prevMethod = prevBuffer->disposalMethod( ); 379 ImageFrame::FrameDisposalMethod prevMethod = prevBuffer->disposalMethod( );
388 while (frameIndex && (prevMethod == ImageFrame::DisposeOverwritePrevious )) { 380 while (frameIndex && (prevMethod == ImageFrame::DisposeOverwritePrevious )) {
389 prevBuffer = &m_frameBufferCache[--frameIndex]; 381 prevBuffer = &m_frameBufferCache[--frameIndex];
390 prevMethod = prevBuffer->disposalMethod(); 382 prevMethod = prevBuffer->disposalMethod();
391 } 383 }
392 ASSERT(prevBuffer->status() == ImageFrame::FrameComplete); 384 ASSERT(prevBuffer->status() == ImageFrame::FrameComplete);
393 385
394 if ((prevMethod == ImageFrame::DisposeNotSpecified) || (prevMethod == Im ageFrame::DisposeKeep)) { 386 if ((prevMethod == ImageFrame::DisposeNotSpecified) || (prevMethod == Im ageFrame::DisposeKeep)) {
395 // Preserve the last frame as the starting state for this frame. 387 // Preserve the last frame as the starting state for this frame.
396 if (!buffer->copyBitmapData(*prevBuffer)) 388 if (!buffer->copyBitmapData(*prevBuffer))
397 return setFailed(); 389 return setFailed();
398 } else { 390 } else {
399 // We want to clear the previous frame to transparent, without 391 // We want to clear the previous frame to transparent, without
400 // affecting pixels in the image outside of the frame. 392 // affecting pixels in the image outside of the frame.
401 const IntRect& prevRect = prevBuffer->originalFrameRect(); 393 const IntRect& prevRect = prevBuffer->originalFrameRect();
402 const IntSize& bufferSize = scaledSize(); 394 const IntSize& bufferSize = size();
403 if (!frameIndex || prevRect.contains(IntRect(IntPoint(), scaledSize( )))) { 395 if (!frameIndex || prevRect.contains(IntRect(IntPoint(), size()))) {
404 // Clearing the first frame, or a frame the size of the whole 396 // Clearing the first frame, or a frame the size of the whole
405 // image, results in a completely empty image. 397 // image, results in a completely empty image.
406 if (!buffer->setSize(bufferSize.width(), bufferSize.height())) 398 if (!buffer->setSize(bufferSize.width(), bufferSize.height()))
407 return setFailed(); 399 return setFailed();
408 } else { 400 } else {
409 // Copy the whole previous buffer, then clear just its frame. 401 // Copy the whole previous buffer, then clear just its frame.
410 if (!buffer->copyBitmapData(*prevBuffer)) 402 if (!buffer->copyBitmapData(*prevBuffer))
411 return setFailed(); 403 return setFailed();
412 for (int y = prevRect.y(); y < prevRect.maxY(); ++y) { 404 for (int y = prevRect.y(); y < prevRect.maxY(); ++y) {
413 for (int x = prevRect.x(); x < prevRect.maxX(); ++x) 405 for (int x = prevRect.x(); x < prevRect.maxX(); ++x)
414 buffer->setRGBA(x, y, 0, 0, 0, 0); 406 buffer->setRGBA(x, y, 0, 0, 0, 0);
415 } 407 }
416 if ((prevRect.width() > 0) && (prevRect.height() > 0)) 408 if ((prevRect.width() > 0) && (prevRect.height() > 0))
417 buffer->setHasAlpha(true); 409 buffer->setHasAlpha(true);
418 } 410 }
419 } 411 }
420 } 412 }
421 413
422 // Update our status to be partially complete. 414 // Update our status to be partially complete.
423 buffer->setStatus(ImageFrame::FramePartial); 415 buffer->setStatus(ImageFrame::FramePartial);
424 416
425 // Reset the alpha pixel tracker for this frame. 417 // Reset the alpha pixel tracker for this frame.
426 m_currentBufferSawAlpha = false; 418 m_currentBufferSawAlpha = false;
427 return true; 419 return true;
428 } 420 }
429 421
430 } // namespace WebCore 422 } // namespace WebCore
OLDNEW
« no previous file with comments | « Source/core/platform/image-decoders/ImageDecoder.cpp ('k') | Source/core/platform/image-decoders/jpeg/JPEGImageDecoder.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698