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

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

Powered by Google App Engine
This is Rietveld 408576698