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

Side by Side Diff: Source/core/platform/image-decoders/webp/WEBPImageDecoder.cpp

Issue 99103006: Moving GraphicsContext and dependencies from core to platform. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Final patch - fixes Android Created 7 years 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
(Empty)
1 /*
2 * Copyright (C) 2010 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "config.h"
30 #include "core/platform/image-decoders/webp/WEBPImageDecoder.h"
31
32 #include "RuntimeEnabledFeatures.h"
33 #include "platform/PlatformInstrumentation.h"
34
35 #if USE(QCMSLIB)
36 #include "qcms.h"
37 #endif
38
39 #if CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN)
40 #error Blink assumes a little-endian target.
41 #endif
42
43 #if SK_B32_SHIFT // Output little-endian RGBA pixels (Android).
44 inline WEBP_CSP_MODE outputMode(bool hasAlpha) { return hasAlpha ? MODE_rgbA : M ODE_RGBA; }
45 #else // Output little-endian BGRA pixels.
46 inline WEBP_CSP_MODE outputMode(bool hasAlpha) { return hasAlpha ? MODE_bgrA : M ODE_BGRA; }
47 #endif
48
49 namespace WebCore {
50
51 WEBPImageDecoder::WEBPImageDecoder(ImageSource::AlphaOption alphaOption,
52 ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption,
53 size_t maxDecodedBytes)
54 : ImageDecoder(alphaOption, gammaAndColorProfileOption, maxDecodedBytes)
55 , m_decoder(0)
56 , m_formatFlags(0)
57 , m_frameBackgroundHasAlpha(false)
58 #if USE(QCMSLIB)
59 , m_haveReadProfile(false)
60 , m_transform(0)
61 #endif
62 , m_demux(0)
63 , m_demuxState(WEBP_DEMUX_PARSING_HEADER)
64 , m_haveAlreadyParsedThisData(false)
65 , m_haveReadAnimationParameters(false)
66 , m_repetitionCount(cAnimationLoopOnce)
67 , m_decodedHeight(0)
68 {
69 }
70
71 WEBPImageDecoder::~WEBPImageDecoder()
72 {
73 clear();
74 }
75
76 void WEBPImageDecoder::clear()
77 {
78 #if USE(QCMSLIB)
79 if (m_transform)
80 qcms_transform_release(m_transform);
81 m_transform = 0;
82 #endif
83 WebPDemuxDelete(m_demux);
84 m_demux = 0;
85 clearDecoder();
86 }
87
88 void WEBPImageDecoder::clearDecoder()
89 {
90 WebPIDelete(m_decoder);
91 m_decoder = 0;
92 m_decodedHeight = 0;
93 m_frameBackgroundHasAlpha = false;
94 }
95
96 bool WEBPImageDecoder::isSizeAvailable()
97 {
98 if (!ImageDecoder::isSizeAvailable())
99 updateDemuxer();
100
101 return ImageDecoder::isSizeAvailable();
102 }
103
104 size_t WEBPImageDecoder::frameCount()
105 {
106 if (!updateDemuxer())
107 return 0;
108
109 return m_frameBufferCache.size();
110 }
111
112 ImageFrame* WEBPImageDecoder::frameBufferAtIndex(size_t index)
113 {
114 if (index >= frameCount())
115 return 0;
116
117 ImageFrame& frame = m_frameBufferCache[index];
118 if (frame.status() == ImageFrame::FrameComplete)
119 return &frame;
120
121 if (RuntimeEnabledFeatures::animatedWebPEnabled()) {
122 Vector<size_t> framesToDecode;
123 size_t frameToDecode = index;
124 do {
125 framesToDecode.append(frameToDecode);
126 frameToDecode = m_frameBufferCache[frameToDecode].requiredPreviousFr ameIndex();
127 } while (frameToDecode != kNotFound && m_frameBufferCache[frameToDecode] .status() != ImageFrame::FrameComplete);
128
129 ASSERT(m_demux);
130 for (size_t i = framesToDecode.size(); i > 0; --i) {
131 size_t frameIndex = framesToDecode[i - 1];
132 if ((m_formatFlags & ANIMATION_FLAG) && !initFrameBuffer(frameIndex) )
133 return 0;
134 WebPIterator webpFrame;
135 if (!WebPDemuxGetFrame(m_demux, frameIndex + 1, &webpFrame))
136 return 0;
137 PlatformInstrumentation::willDecodeImage("WEBP");
138 decode(webpFrame.fragment.bytes, webpFrame.fragment.size, false, fra meIndex);
139 PlatformInstrumentation::didDecodeImage();
140 WebPDemuxReleaseIterator(&webpFrame);
141
142 if (failed())
143 return 0;
144
145 // We need more data to continue decoding.
146 if (m_frameBufferCache[frameIndex].status() != ImageFrame::FrameComp lete)
147 break;
148 }
149
150 // It is also a fatal error if all data is received and we have decoded all
151 // frames available but the file is truncated.
152 if (index >= m_frameBufferCache.size() - 1 && isAllDataReceived() && m_d emux && m_demuxState != WEBP_DEMUX_DONE)
153 setFailed();
154
155 frame.notifyBitmapIfPixelsChanged();
156 return &frame;
157 }
158
159 ASSERT(!index);
160 PlatformInstrumentation::willDecodeImage("WEBP");
161 decode(reinterpret_cast<const uint8_t*>(m_data->data()), m_data->size(), fal se, index);
162 PlatformInstrumentation::didDecodeImage();
163 return failed() ? 0 : &frame;
164 }
165
166 void WEBPImageDecoder::setData(SharedBuffer* data, bool allDataReceived)
167 {
168 if (failed())
169 return;
170 ImageDecoder::setData(data, allDataReceived);
171 m_haveAlreadyParsedThisData = false;
172 }
173
174 int WEBPImageDecoder::repetitionCount() const
175 {
176 return failed() ? cAnimationLoopOnce : m_repetitionCount;
177 }
178
179 bool WEBPImageDecoder::frameIsCompleteAtIndex(size_t index) const
180 {
181 if (!RuntimeEnabledFeatures::animatedWebPEnabled())
182 return ImageDecoder::frameIsCompleteAtIndex(index);
183 if (!m_demux || m_demuxState <= WEBP_DEMUX_PARSING_HEADER)
184 return false;
185 if (!(m_formatFlags & ANIMATION_FLAG))
186 return ImageDecoder::frameIsCompleteAtIndex(index);
187 bool frameIsLoadedAtIndex = index < m_frameBufferCache.size();
188 return frameIsLoadedAtIndex;
189 }
190
191 float WEBPImageDecoder::frameDurationAtIndex(size_t index) const
192 {
193 return index < m_frameBufferCache.size() ? m_frameBufferCache[index].duratio n() : 0;
194 }
195
196 bool WEBPImageDecoder::updateDemuxer()
197 {
198 if (failed())
199 return false;
200
201 if (m_haveAlreadyParsedThisData)
202 return true;
203
204 m_haveAlreadyParsedThisData = true;
205
206 const unsigned webpHeaderSize = 20;
207 if (m_data->size() < webpHeaderSize)
208 return false; // Wait for headers so that WebPDemuxPartial doesn't retur n null.
209
210 WebPDemuxDelete(m_demux);
211 WebPData inputData = { reinterpret_cast<const uint8_t*>(m_data->data()), m_d ata->size() };
212 m_demux = WebPDemuxPartial(&inputData, &m_demuxState);
213 if (!m_demux)
214 return setFailed();
215
216 if (m_demuxState <= WEBP_DEMUX_PARSING_HEADER)
217 return false; // Not enough data for parsing canvas width/height yet.
218
219 bool hasAnimation = (m_formatFlags & ANIMATION_FLAG);
220 if (!ImageDecoder::isSizeAvailable()) {
221 m_formatFlags = WebPDemuxGetI(m_demux, WEBP_FF_FORMAT_FLAGS);
222 hasAnimation = (m_formatFlags & ANIMATION_FLAG);
223 if (hasAnimation && !RuntimeEnabledFeatures::animatedWebPEnabled())
224 return setFailed();
225 if (!setSize(WebPDemuxGetI(m_demux, WEBP_FF_CANVAS_WIDTH), WebPDemuxGetI (m_demux, WEBP_FF_CANVAS_HEIGHT)))
226 return setFailed();
227 }
228
229 ASSERT(ImageDecoder::isSizeAvailable());
230 const size_t newFrameCount = WebPDemuxGetI(m_demux, WEBP_FF_FRAME_COUNT);
231 if (hasAnimation && !m_haveReadAnimationParameters && newFrameCount) {
232 // As we have parsed at least one frame (even if partially),
233 // we must already have parsed the animation properties.
234 // This is because ANIM chunk always precedes ANMF chunks.
235 m_repetitionCount = WebPDemuxGetI(m_demux, WEBP_FF_LOOP_COUNT);
236 ASSERT(m_repetitionCount == (m_repetitionCount & 0xffff)); // Loop count is always <= 16 bits.
237 if (!m_repetitionCount)
238 m_repetitionCount = cAnimationLoopInfinite;
239 m_haveReadAnimationParameters = true;
240 }
241
242 const size_t oldFrameCount = m_frameBufferCache.size();
243 if (newFrameCount > oldFrameCount) {
244 m_frameBufferCache.resize(newFrameCount);
245 for (size_t i = oldFrameCount; i < newFrameCount; ++i) {
246 m_frameBufferCache[i].setPremultiplyAlpha(m_premultiplyAlpha);
247 if (!hasAnimation) {
248 ASSERT(!i);
249 m_frameBufferCache[i].setRequiredPreviousFrameIndex(kNotFound);
250 continue;
251 }
252 WebPIterator animatedFrame;
253 WebPDemuxGetFrame(m_demux, i + 1, &animatedFrame);
254 ASSERT(animatedFrame.complete == 1);
255 m_frameBufferCache[i].setDuration(animatedFrame.duration);
256 m_frameBufferCache[i].setDisposalMethod(animatedFrame.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND ? ImageFrame::DisposeOverwriteBgcolor : ImageFra me::DisposeKeep);
257 m_frameBufferCache[i].setAlphaBlendSource(animatedFrame.blend_method == WEBP_MUX_BLEND ? ImageFrame::BlendAtopPreviousFrame : ImageFrame::BlendAtopB gcolor);
258 IntRect frameRect(animatedFrame.x_offset, animatedFrame.y_offset, an imatedFrame.width, animatedFrame.height);
259 // Make sure the frameRect doesn't extend outside the buffer.
260 if (frameRect.maxX() > size().width())
261 frameRect.setWidth(size().width() - animatedFrame.x_offset);
262 if (frameRect.maxY() > size().height())
263 frameRect.setHeight(size().height() - animatedFrame.y_offset);
264 m_frameBufferCache[i].setOriginalFrameRect(frameRect);
265 m_frameBufferCache[i].setRequiredPreviousFrameIndex(findRequiredPrev iousFrame(i, !animatedFrame.has_alpha));
266 WebPDemuxReleaseIterator(&animatedFrame);
267 }
268 }
269
270 return true;
271 }
272
273 bool WEBPImageDecoder::initFrameBuffer(size_t frameIndex)
274 {
275 ImageFrame& buffer = m_frameBufferCache[frameIndex];
276 if (buffer.status() != ImageFrame::FrameEmpty) // Already initialized.
277 return true;
278
279 const size_t requiredPreviousFrameIndex = buffer.requiredPreviousFrameIndex( );
280 if (requiredPreviousFrameIndex == kNotFound) {
281 // This frame doesn't rely on any previous data.
282 if (!buffer.setSize(size().width(), size().height()))
283 return setFailed();
284 m_frameBackgroundHasAlpha = !buffer.originalFrameRect().contains(IntRect (IntPoint(), size()));
285 } else {
286 const ImageFrame& prevBuffer = m_frameBufferCache[requiredPreviousFrameI ndex];
287 ASSERT(prevBuffer.status() == ImageFrame::FrameComplete);
288
289 // Preserve the last frame as the starting state for this frame.
290 if (!buffer.copyBitmapData(prevBuffer))
291 return setFailed();
292
293 if (prevBuffer.disposalMethod() == ImageFrame::DisposeOverwriteBgcolor) {
294 // We want to clear the previous frame to transparent, without
295 // affecting pixels in the image outside of the frame.
296 const IntRect& prevRect = prevBuffer.originalFrameRect();
297 ASSERT(!prevRect.contains(IntRect(IntPoint(), size())));
298 buffer.zeroFillFrameRect(prevRect);
299 }
300
301 m_frameBackgroundHasAlpha = prevBuffer.hasAlpha() || (prevBuffer.disposa lMethod() == ImageFrame::DisposeOverwriteBgcolor);
302 }
303
304 buffer.setStatus(ImageFrame::FramePartial);
305 // The buffer is transparent outside the decoded area while the image is loa ding.
306 // The correct value of 'hasAlpha' for the frame will be set when it is full y decoded.
307 buffer.setHasAlpha(true);
308 return true;
309 }
310
311 size_t WEBPImageDecoder::clearCacheExceptFrame(size_t clearExceptFrame)
312 {
313 // If |clearExceptFrame| has status FrameComplete, we preserve that frame.
314 // Otherwise, we preserve a previous frame with status FrameComplete whose d ata is required
315 // to decode |clearExceptFrame|, either in initFrameBuffer() or ApplyPostPro cessing().
316 // All other frames can be cleared.
317 while ((clearExceptFrame < m_frameBufferCache.size()) && (m_frameBufferCache [clearExceptFrame].status() != ImageFrame::FrameComplete))
318 clearExceptFrame = m_frameBufferCache[clearExceptFrame].requiredPrevious FrameIndex();
319
320 return ImageDecoder::clearCacheExceptFrame(clearExceptFrame);
321 }
322
323 void WEBPImageDecoder::clearFrameBuffer(size_t frameIndex)
324 {
325 if (m_demux && m_demuxState >= WEBP_DEMUX_PARSED_HEADER && m_frameBufferCach e[frameIndex].status() == ImageFrame::FramePartial) {
326 // Clear the decoder state so that this partial frame can be decoded aga in when requested.
327 clearDecoder();
328 }
329 ImageDecoder::clearFrameBuffer(frameIndex);
330 }
331
332 #if USE(QCMSLIB)
333
334 void WEBPImageDecoder::createColorTransform(const char* data, size_t size)
335 {
336 if (m_transform)
337 qcms_transform_release(m_transform);
338 m_transform = 0;
339
340 qcms_profile* deviceProfile = ImageDecoder::qcmsOutputDeviceProfile();
341 if (!deviceProfile)
342 return;
343 qcms_profile* inputProfile = qcms_profile_from_memory(data, size);
344 if (!inputProfile)
345 return;
346
347 // We currently only support color profiles for RGB profiled images.
348 ASSERT(icSigRgbData == qcms_profile_get_color_space(inputProfile));
349 // The input image pixels are RGBA format.
350 qcms_data_type format = QCMS_DATA_RGBA_8;
351 // FIXME: Don't force perceptual intent if the image profile contains an int ent.
352 m_transform = qcms_transform_create(inputProfile, format, deviceProfile, QCM S_DATA_RGBA_8, QCMS_INTENT_PERCEPTUAL);
353
354 qcms_profile_release(inputProfile);
355 }
356
357 void WEBPImageDecoder::readColorProfile()
358 {
359 WebPChunkIterator chunkIterator;
360 if (!WebPDemuxGetChunk(m_demux, "ICCP", 1, &chunkIterator)) {
361 WebPDemuxReleaseChunkIterator(&chunkIterator);
362 return;
363 }
364
365 const char* profileData = reinterpret_cast<const char*>(chunkIterator.chunk. bytes);
366 size_t profileSize = chunkIterator.chunk.size;
367
368 // Only accept RGB color profiles from input class devices.
369 bool ignoreProfile = false;
370 if (profileSize < ImageDecoder::iccColorProfileHeaderLength)
371 ignoreProfile = true;
372 else if (!ImageDecoder::rgbColorProfile(profileData, profileSize))
373 ignoreProfile = true;
374 else if (!ImageDecoder::inputDeviceColorProfile(profileData, profileSize))
375 ignoreProfile = true;
376
377 if (!ignoreProfile)
378 createColorTransform(profileData, profileSize);
379
380 WebPDemuxReleaseChunkIterator(&chunkIterator);
381 }
382
383 #endif // USE(QCMSLIB)
384
385 void WEBPImageDecoder::applyPostProcessing(size_t frameIndex)
386 {
387 ImageFrame& buffer = m_frameBufferCache[frameIndex];
388 int width;
389 int decodedHeight;
390 if (!WebPIDecGetRGB(m_decoder, &decodedHeight, &width, 0, 0))
391 return; // See also https://bugs.webkit.org/show_bug.cgi?id=74062
392 if (decodedHeight <= 0)
393 return;
394
395 const IntRect& frameRect = buffer.originalFrameRect();
396 ASSERT_WITH_SECURITY_IMPLICATION(width == frameRect.width());
397 ASSERT_WITH_SECURITY_IMPLICATION(decodedHeight <= frameRect.height());
398 const int left = frameRect.x();
399 const int top = frameRect.y();
400
401 #if USE(QCMSLIB)
402 if ((m_formatFlags & ICCP_FLAG) && !ignoresGammaAndColorProfile()) {
403 if (!m_haveReadProfile) {
404 readColorProfile();
405 m_haveReadProfile = true;
406 }
407 for (int y = m_decodedHeight; y < decodedHeight; ++y) {
408 const int canvasY = top + y;
409 uint8_t* row = reinterpret_cast<uint8_t*>(buffer.getAddr(left, canva sY));
410 if (qcms_transform* transform = colorTransform())
411 qcms_transform_data_type(transform, row, row, width, QCMS_OUTPUT _RGBX);
412 uint8_t* pixel = row;
413 for (int x = 0; x < width; ++x, pixel += 4) {
414 const int canvasX = left + x;
415 buffer.setRGBA(canvasX, canvasY, pixel[0], pixel[1], pixel[2], p ixel[3]);
416 }
417 }
418 }
419 #endif // USE(QCMSLIB)
420
421 // During the decoding of current frame, we may have set some pixels to be t ransparent (i.e. alpha < 255).
422 // However, the value of each of these pixels should have been determined by blending it against the value
423 // of that pixel in the previous frame if alpha blend source was 'BlendAtopP reviousFrame'. So, we correct these
424 // pixels based on disposal method of the previous frame and the previous fr ame buffer.
425 // FIXME: This could be avoided if libwebp decoder had an API that used the previous required frame
426 // to do the alpha-blending by itself.
427 if ((m_formatFlags & ANIMATION_FLAG) && frameIndex && buffer.alphaBlendSourc e() == ImageFrame::BlendAtopPreviousFrame && buffer.requiredPreviousFrameIndex() != kNotFound) {
428 ImageFrame& prevBuffer = m_frameBufferCache[frameIndex - 1];
429 ASSERT(prevBuffer.status() == ImageFrame::FrameComplete);
430 ImageFrame::DisposalMethod prevDisposalMethod = prevBuffer.disposalMetho d();
431 if (prevDisposalMethod == ImageFrame::DisposeKeep) { // Restore transpar ent pixels to pixels in previous canvas.
432 for (int y = m_decodedHeight; y < decodedHeight; ++y) {
433 const int canvasY = top + y;
434 for (int x = 0; x < width; ++x) {
435 const int canvasX = left + x;
436 ImageFrame::PixelData& pixel = *buffer.getAddr(canvasX, canv asY);
437 // FIXME: Use alpha-blending when alpha is between 0 and 255 .
438 // Alpha-blending is being implemented in: https://bugs.webk it.org/show_bug.cgi?id=17022
439 if (!((pixel >> SK_A32_SHIFT) & 0xff)) {
440 ImageFrame::PixelData prevPixel = *prevBuffer.getAddr(ca nvasX, canvasY);
441 pixel = prevPixel;
442 }
443 }
444 }
445 } else if (prevDisposalMethod == ImageFrame::DisposeOverwriteBgcolor) {
446 const IntRect& prevRect = prevBuffer.originalFrameRect();
447 // We need to restore transparent pixels to as they were just after initFrame() call. That is:
448 // * Transparent if it belongs to prevRect <-- This is a no-op.
449 // * Pixel in the previous canvas otherwise <-- Need to restore.
450 for (int y = m_decodedHeight; y < decodedHeight; ++y) {
451 const int canvasY = top + y;
452 for (int x = 0; x < width; ++x) {
453 const int canvasX = left + x;
454 ImageFrame::PixelData& pixel = *buffer.getAddr(canvasX, canv asY);
455 // FIXME: Use alpha-blending when alpha is between 0 and 255 .
456 if (!((pixel >> SK_A32_SHIFT) & 0xff) && !prevRect.contains( IntPoint(canvasX, canvasY))) {
457 ImageFrame::PixelData prevPixel = *prevBuffer.getAddr(ca nvasX, canvasY);
458 pixel = prevPixel;
459 }
460 }
461 }
462 }
463 }
464
465 m_decodedHeight = decodedHeight;
466 buffer.setPixelsChanged(true);
467 }
468
469 bool WEBPImageDecoder::decode(const uint8_t* dataBytes, size_t dataSize, bool on lySize, size_t frameIndex)
470 {
471 if (failed())
472 return false;
473
474 if (!ImageDecoder::isSizeAvailable()) {
475 static const size_t imageHeaderSize = 30;
476 if (dataSize < imageHeaderSize)
477 return false;
478 int width, height;
479 WebPBitstreamFeatures features;
480 if (WebPGetFeatures(dataBytes, dataSize, &features) != VP8_STATUS_OK)
481 return setFailed();
482 width = features.width;
483 height = features.height;
484 m_formatFlags = features.has_alpha ? ALPHA_FLAG : 0;
485 if (!setSize(width, height))
486 return setFailed();
487 }
488
489 ASSERT(ImageDecoder::isSizeAvailable());
490 if (onlySize)
491 return true;
492
493 ASSERT(m_frameBufferCache.size() > frameIndex);
494 ImageFrame& buffer = m_frameBufferCache[frameIndex];
495 ASSERT(buffer.status() != ImageFrame::FrameComplete);
496
497 if (buffer.status() == ImageFrame::FrameEmpty) {
498 if (!buffer.setSize(size().width(), size().height()))
499 return setFailed();
500 buffer.setStatus(ImageFrame::FramePartial);
501 // The buffer is transparent outside the decoded area while the image is loading.
502 // The correct value of 'hasAlpha' for the frame will be set when it is fully decoded.
503 buffer.setHasAlpha(true);
504 buffer.setOriginalFrameRect(IntRect(IntPoint(), size()));
505 }
506
507 const IntRect& frameRect = buffer.originalFrameRect();
508 if (!m_decoder) {
509 WEBP_CSP_MODE mode = outputMode(m_formatFlags & ALPHA_FLAG);
510 if (!m_premultiplyAlpha)
511 mode = outputMode(false);
512 #if USE(QCMSLIB)
513 if ((m_formatFlags & ICCP_FLAG) && !ignoresGammaAndColorProfile())
514 mode = MODE_RGBA; // Decode to RGBA for input to libqcms.
515 #endif
516 WebPInitDecBuffer(&m_decoderBuffer);
517 m_decoderBuffer.colorspace = mode;
518 m_decoderBuffer.u.RGBA.stride = size().width() * sizeof(ImageFrame::Pixe lData);
519 m_decoderBuffer.u.RGBA.size = m_decoderBuffer.u.RGBA.stride * frameRect. height();
520 m_decoderBuffer.is_external_memory = 1;
521 m_decoder = WebPINewDecoder(&m_decoderBuffer);
522 if (!m_decoder)
523 return setFailed();
524 }
525
526 m_decoderBuffer.u.RGBA.rgba = reinterpret_cast<uint8_t*>(buffer.getAddr(fram eRect.x(), frameRect.y()));
527
528 switch (WebPIUpdate(m_decoder, dataBytes, dataSize)) {
529 case VP8_STATUS_OK:
530 applyPostProcessing(frameIndex);
531 buffer.setHasAlpha((m_formatFlags & ALPHA_FLAG) || m_frameBackgroundHasA lpha);
532 buffer.setStatus(ImageFrame::FrameComplete);
533 clearDecoder();
534 return true;
535 case VP8_STATUS_SUSPENDED:
536 if (!isAllDataReceived() && !frameIsCompleteAtIndex(frameIndex)) {
537 applyPostProcessing(frameIndex);
538 return false;
539 }
540 // FALLTHROUGH
541 default:
542 clear();
543 return setFailed();
544 }
545 }
546
547 } // namespace WebCore
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698