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

Side by Side Diff: third_party/WebKit/Source/platform/image-decoders/ImageDecoder.cpp

Issue 2930513004: [WIP] Move ImageDecoders to SkCodec
Patch Set: Adding check for decoder creation Created 3 years, 6 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) Research In Motion Limited 2009-2010. All rights reserved. 2 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
3 * 3 *
4 * This library is free software; you can redistribute it and/or 4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public 5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either 6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version. 7 * version 2 of the License, or (at your option) any later version.
8 * 8 *
9 * This library is distributed in the hope that it will be useful, 9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details. 12 * Library General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU Library General Public License 14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to 15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA. 17 * Boston, MA 02110-1301, USA.
18 * 18 *
19 */ 19 */
20 20
21 #include "platform/image-decoders/ImageDecoder.h" 21 #include "platform/image-decoders/ImageDecoder.h"
22 22
23 #include <memory> 23 #include <memory>
24 #include "platform/RuntimeEnabledFeatures.h" 24 #include "platform/RuntimeEnabledFeatures.h"
25 #include "platform/graphics/BitmapImageMetrics.h" 25 #include "platform/graphics/BitmapImageMetrics.h"
26 #include "platform/image-decoders/FastSharedBufferReader.h"
27 #include "platform/image-decoders/bmp/BMPImageDecoder.h"
28 #include "platform/image-decoders/gif/GIFImageDecoder.h"
29 #include "platform/image-decoders/ico/ICOImageDecoder.h"
30 #include "platform/image-decoders/jpeg/JPEGImageDecoder.h"
31 #include "platform/image-decoders/png/PNGImageDecoder.h"
32 #include "platform/image-decoders/webp/WEBPImageDecoder.h"
33 #include "platform/instrumentation/PlatformInstrumentation.h" 26 #include "platform/instrumentation/PlatformInstrumentation.h"
34 #include "platform/wtf/PtrUtil.h" 27 #include "platform/wtf/PtrUtil.h"
28 #include "third_party/skia/include/core/SkImageInfo.h"
35 29
36 namespace blink { 30 namespace blink {
37 31
38 inline bool MatchesJPEGSignature(const char* contents) {
39 return !memcmp(contents, "\xFF\xD8\xFF", 3);
40 }
41
42 inline bool MatchesPNGSignature(const char* contents) {
43 return !memcmp(contents, "\x89PNG\r\n\x1A\n", 8);
44 }
45
46 inline bool MatchesGIFSignature(const char* contents) {
47 return !memcmp(contents, "GIF87a", 6) || !memcmp(contents, "GIF89a", 6);
48 }
49
50 inline bool MatchesWebPSignature(const char* contents) {
51 return !memcmp(contents, "RIFF", 4) && !memcmp(contents + 8, "WEBPVP", 6);
52 }
53
54 inline bool MatchesICOSignature(const char* contents) {
55 return !memcmp(contents, "\x00\x00\x01\x00", 4);
56 }
57
58 inline bool MatchesCURSignature(const char* contents) {
59 return !memcmp(contents, "\x00\x00\x02\x00", 4);
60 }
61
62 inline bool MatchesBMPSignature(const char* contents) {
63 return !memcmp(contents, "BM", 2);
64 }
65
66 static constexpr size_t kLongestSignatureLength = sizeof("RIFF????WEBPVP") - 1;
67
68 std::unique_ptr<ImageDecoder> ImageDecoder::Create( 32 std::unique_ptr<ImageDecoder> ImageDecoder::Create(
69 RefPtr<SegmentReader> data, 33 RefPtr<SegmentReader> data,
70 bool data_complete, 34 bool data_complete,
71 AlphaOption alpha_option, 35 AlphaOption alpha_option,
72 const ColorBehavior& color_behavior) { 36 const ColorBehavior& color_behavior) {
73 // At least kLongestSignatureLength bytes are needed to sniff the signature.
74 if (data->size() < kLongestSignatureLength)
75 return nullptr;
76
77 const size_t max_decoded_bytes = 37 const size_t max_decoded_bytes =
78 Platform::Current() ? Platform::Current()->MaxDecodedImageBytes() 38 Platform::Current() ? Platform::Current()->MaxDecodedImageBytes()
79 : kNoDecodedImageByteLimit; 39 : kNoDecodedImageByteLimit;
80 40
81 // Access the first kLongestSignatureLength chars to sniff the signature. 41 std::unique_ptr<ImageDecoder> decoder;
82 // (note: FastSharedBufferReader only makes a copy if the bytes are segmented)
83 char buffer[kLongestSignatureLength];
84 const FastSharedBufferReader fast_reader(data);
85 const char* contents =
86 fast_reader.GetConsecutiveData(0, kLongestSignatureLength, buffer);
87 42
88 std::unique_ptr<ImageDecoder> decoder; 43 decoder.reset(
89 if (MatchesJPEGSignature(contents)) { 44 new ImageDecoder(alpha_option, color_behavior, max_decoded_bytes));
90 decoder.reset(
91 new JPEGImageDecoder(alpha_option, color_behavior, max_decoded_bytes));
92 } else if (MatchesPNGSignature(contents)) {
93 decoder.reset(
94 new PNGImageDecoder(alpha_option, color_behavior, max_decoded_bytes));
95 } else if (MatchesGIFSignature(contents)) {
96 decoder.reset(
97 new GIFImageDecoder(alpha_option, color_behavior, max_decoded_bytes));
98 } else if (MatchesWebPSignature(contents)) {
99 decoder.reset(
100 new WEBPImageDecoder(alpha_option, color_behavior, max_decoded_bytes));
101 } else if (MatchesICOSignature(contents) || MatchesCURSignature(contents)) {
102 decoder.reset(
103 new ICOImageDecoder(alpha_option, color_behavior, max_decoded_bytes));
104 } else if (MatchesBMPSignature(contents)) {
105 decoder.reset(
106 new BMPImageDecoder(alpha_option, color_behavior, max_decoded_bytes));
107 }
108 45
109 if (decoder) 46 if (decoder)
110 decoder->SetData(std::move(data), data_complete); 47 decoder->SetData(std::move(data), data_complete);
111 48
112 return decoder; 49 return decoder;
113 } 50 }
114 51
115 bool ImageDecoder::HasSufficientDataToSniffImageType(const SharedBuffer& data) { 52 ImageDecoder::ImageDecoder(AlphaOption alpha_option,
116 return data.size() >= kLongestSignatureLength; 53 const ColorBehavior& color_behavior,
54 size_t max_decoded_bytes)
55 : premultiply_alpha_(alpha_option == kAlphaPremultiplied),
56 color_behavior_(color_behavior),
57 max_decoded_bytes_(max_decoded_bytes),
58 purge_aggressively_(false),
59 codec_() {}
60 void ImageDecoder::OnSetData(SegmentReader* data) {
61 if (data) {
62 if (!codec_) {
63 SkCodec* codec = SkCodec::NewFromData(data->GetAsSkData());
64 if (codec)
65 codec_.reset(codec);
66 else
67 return;
68 }
69 SkImageInfo image_info = codec_->getInfo();
70 SetSize(image_info.width(), image_info.height());
71 }
117 } 72 }
118 73
119 size_t ImageDecoder::FrameCount() { 74 size_t ImageDecoder::FrameCount() {
120 const size_t old_size = frame_buffer_cache_.size(); 75 const size_t old_size = frame_buffer_cache_.size();
121 const size_t new_size = DecodeFrameCount(); 76 const size_t new_size = codec_ ? codec_->getFrameCount() : 0;
122 if (old_size != new_size) { 77 if (old_size != new_size) {
123 frame_buffer_cache_.resize(new_size); 78 frame_buffer_cache_.resize(new_size);
124 for (size_t i = old_size; i < new_size; ++i) { 79 for (size_t i = old_size; i < new_size; ++i) {
125 frame_buffer_cache_[i].SetPremultiplyAlpha(premultiply_alpha_); 80 frame_buffer_cache_[i].SetPremultiplyAlpha(premultiply_alpha_);
126 InitializeNewFrame(i); 81 InitializeNewFrame(i);
127 } 82 }
128 } 83 }
129 return new_size; 84 return new_size;
130 } 85 }
131 86
87 void ImageDecoder::Decode(size_t index) {
88 if (!codec_)
89 return;
90
91 DCHECK(!Failed());
92 DCHECK_LT(index, frame_buffer_cache_.size());
93
94 UpdateAggressivePurging(index);
95 SkImageInfo imageInfo = codec_->getInfo()
96 .makeColorType(kN32_SkColorType)
97 .makeColorSpace(ColorSpaceForSkImages());
98
99 SkCodec::Options options;
100 options.fFrameIndex = index;
101 options.fZeroInitialized = SkCodec::kYes_ZeroInitialized;
102
103 ImageFrame& frame = frame_buffer_cache_[index];
104 if (frame.GetStatus() == ImageFrame::kFrameEmpty) {
105 size_t required_previous_frame_index = frame.RequiredPreviousFrameIndex();
106 if (required_previous_frame_index == WTF::kNotFound) {
107 frame.AllocatePixelData(Size().Width(), Size().Height(),
108 ColorSpaceForSkImages());
109 } else {
110 ImageFrame& required_previous_frame =
111 frame_buffer_cache_[required_previous_frame_index];
112
113 if (required_previous_frame.GetStatus() != ImageFrame::kFrameComplete)
114 Decode(required_previous_frame_index);
115
116 // We try to reuse |required_previous_frame| as starting state to avoid
117 // copying. If CanReusePreviousFrameBuffer returns false, we must copy
118 // the data since |required_previous_frame| is necessary to decode this
119 // or later frames. In that case copy the data instead.
120 if ((!CanReusePreviousFrameBuffer(index) ||
121 !frame.TakeBitmapDataIfWritable(&required_previous_frame)) &&
122 !frame.CopyBitmapData(required_previous_frame)) {
123 SetFailed();
124 return;
125 }
126 options.fHasPriorFrame = true;
127 }
128 }
129
130 SkCodec::Result result =
131 codec_->getPixels(imageInfo, frame.Bitmap().getPixels(),
132 frame.Bitmap().rowBytes(), &options, nullptr, nullptr);
133 switch (result) {
134 case SkCodec::kSuccess:
135 frame.SetPixelsChanged(true);
136 frame.SetStatus(ImageFrame::kFrameComplete);
137 PostDecodeProcessing(index);
138 break;
139 default:
140 SetFailed();
141 return;
142 }
143 }
144
145 bool ImageDecoder::SetFailed() {
146 codec_ = nullptr;
147 failed_ = true;
148 return false;
149 }
150
132 ImageFrame* ImageDecoder::FrameBufferAtIndex(size_t index) { 151 ImageFrame* ImageDecoder::FrameBufferAtIndex(size_t index) {
133 if (index >= FrameCount()) 152 if (index >= FrameCount())
134 return 0; 153 return 0;
135 154
136 ImageFrame* frame = &frame_buffer_cache_[index]; 155 ImageFrame* frame = &frame_buffer_cache_[index];
137 if (frame->GetStatus() != ImageFrame::kFrameComplete) { 156 if (frame->GetStatus() != ImageFrame::kFrameComplete) {
138 PlatformInstrumentation::WillDecodeImage(FilenameExtension()); 157 PlatformInstrumentation::WillDecodeImage(FilenameExtension());
139 Decode(index); 158 Decode(index);
140 PlatformInstrumentation::DidDecodeImage(); 159 PlatformInstrumentation::DidDecodeImage();
141 } 160 }
142 161
143 if (!has_histogrammed_color_space_) { 162 if (!has_histogrammed_color_space_) {
144 BitmapImageMetrics::CountImageGammaAndGamut(embedded_color_space_.get()); 163 BitmapImageMetrics::CountImageGammaAndGamut(embedded_color_space_.get());
145 has_histogrammed_color_space_ = true; 164 has_histogrammed_color_space_ = true;
146 } 165 }
147 166
148 frame->NotifyBitmapIfPixelsChanged(); 167 frame->NotifyBitmapIfPixelsChanged();
149 return frame; 168 return frame;
150 } 169 }
151 170
152 bool ImageDecoder::FrameHasAlphaAtIndex(size_t index) const { 171 bool ImageDecoder::FrameHasAlphaAtIndex(size_t index) const {
153 return !FrameIsCompleteAtIndex(index) || 172 return !FrameIsCompleteAtIndex(index) ||
154 frame_buffer_cache_[index].HasAlpha(); 173 frame_buffer_cache_[index].HasAlpha();
155 } 174 }
156 175
157 bool ImageDecoder::FrameIsCompleteAtIndex(size_t index) const { 176 bool ImageDecoder::FrameIsCompleteAtIndex(size_t index) const {
158 // Animated images override this method to return the status based on the data 177 if (!codec_)
159 // received for the queried frame. 178 return false;
160 return IsAllDataReceived(); 179
180 if (codec_->getFrameCount() <= (int)index)
181 return false;
182
183 if (frame_buffer_cache_.IsEmpty())
184 return false;
185
186 return frame_buffer_cache_[0].GetStatus() == ImageFrame::kFrameComplete;
187 }
188
189 float ImageDecoder::FrameDurationAtIndex(size_t index) const {
190 if (index < frame_buffer_cache_.size())
191 return frame_buffer_cache_[index].Duration();
192 return 0;
161 } 193 }
162 194
163 bool ImageDecoder::FrameIsDecodedAtIndex(size_t index) const { 195 bool ImageDecoder::FrameIsDecodedAtIndex(size_t index) const {
164 return index < frame_buffer_cache_.size() && 196 return index < frame_buffer_cache_.size() &&
165 frame_buffer_cache_[index].GetStatus() == ImageFrame::kFrameComplete; 197 frame_buffer_cache_[index].GetStatus() == ImageFrame::kFrameComplete;
166 } 198 }
167 199
168 size_t ImageDecoder::FrameBytesAtIndex(size_t index) const { 200 size_t ImageDecoder::FrameBytesAtIndex(size_t index) const {
169 if (index >= frame_buffer_cache_.size() || 201 if (index >= frame_buffer_cache_.size() ||
170 frame_buffer_cache_[index].GetStatus() == ImageFrame::kFrameEmpty) 202 frame_buffer_cache_[index].GetStatus() == ImageFrame::kFrameEmpty)
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
350 if (prev_buffer->GetDisposalMethod() == 382 if (prev_buffer->GetDisposalMethod() ==
351 ImageFrame::kDisposeOverwriteBgcolor) { 383 ImageFrame::kDisposeOverwriteBgcolor) {
352 // We want to clear the previous frame to transparent, without 384 // We want to clear the previous frame to transparent, without
353 // affecting pixels in the image outside of the frame. 385 // affecting pixels in the image outside of the frame.
354 const IntRect& prev_rect = prev_buffer->OriginalFrameRect(); 386 const IntRect& prev_rect = prev_buffer->OriginalFrameRect();
355 DCHECK(!prev_rect.Contains(IntRect(IntPoint(), Size()))); 387 DCHECK(!prev_rect.Contains(IntRect(IntPoint(), Size())));
356 buffer->ZeroFillFrameRect(prev_rect); 388 buffer->ZeroFillFrameRect(prev_rect);
357 } 389 }
358 } 390 }
359 391
360 OnInitFrameBuffer(frame_index);
361
362 // Update our status to be partially complete. 392 // Update our status to be partially complete.
363 buffer->SetStatus(ImageFrame::kFramePartial); 393 buffer->SetStatus(ImageFrame::kFramePartial);
364 394
365 return true; 395 return true;
366 } 396 }
367 397
398 int ImageDecoder::RepetitionCount() {
399 if (!codec_)
400 return kAnimationLoopOnce;
401
402 DCHECK(!Failed());
403
404 // packets sent back by the webserver) not always.
405 // SkCodec will parse forward in the file if the repetition count has not been
406 // seen yet.
407 int repetition_count = codec_->getRepetitionCount();
408 switch (repetition_count) {
409 case 0: {
410 size_t frame_count = codec_->getFrameCount();
411 if (IsAllDataReceived() && frame_count == 1)
412 return kAnimationNone;
413 return kAnimationLoopOnce;
414 }
415 case SkCodec::kRepetitionCountInfinite:
416 return kAnimationLoopInfinite;
417 default:
418 return repetition_count;
419 }
420 }
421
422 bool ImageDecoder::CanReusePreviousFrameBuffer(size_t index) const {
423 DCHECK(index < frame_buffer_cache_.size());
424
425 // If the current frame and the next frame depend on the same frame, we cannot
426 // reuse the old frame. We must preserve it for the next frame.
427 //
428 // However, if the current and next frame depend on different frames then we
429 // know the current frame is the last one to use the frame it depends on. That
430 // means the current frame can reuse the previous frame buffer.
431 //
432 // If we do not have information about the next frame yet, we cannot assume it
433 // is safe to reuse the previous frame buffer.
434
435 if (index + 1 >= frame_buffer_cache_.size())
436 return false;
437
438 const ImageFrame& frame = frame_buffer_cache_[index];
439 size_t required_frame_index = frame.RequiredPreviousFrameIndex();
440
441 const ImageFrame& next_frame = frame_buffer_cache_[index + 1];
442 size_t next_required_frame_index = next_frame.RequiredPreviousFrameIndex();
443
444 return required_frame_index != next_required_frame_index;
445 }
446
368 void ImageDecoder::UpdateAggressivePurging(size_t index) { 447 void ImageDecoder::UpdateAggressivePurging(size_t index) {
369 if (purge_aggressively_) 448 if (purge_aggressively_)
370 return; 449 return;
371 450
372 // We don't want to cache so much that we cause a memory issue. 451 // We don't want to cache so much that we cause a memory issue.
373 // 452 //
374 // If we used a LRU cache we would fill it and then on next animation loop 453 // If we used a LRU cache we would fill it and then on next animation loop
375 // we would need to decode all the frames again -- the LRU would give no 454 // we would need to decode all the frames again -- the LRU would give no
376 // benefit and would consume more memory. 455 // benefit and would consume more memory.
377 // So instead, simply purge unused frames if caching all of the frames of 456 // So instead, simply purge unused frames if caching all of the frames of
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
448 (prev_buffer->RequiredPreviousFrameIndex() == kNotFound)) 527 (prev_buffer->RequiredPreviousFrameIndex() == kNotFound))
449 ? kNotFound 528 ? kNotFound
450 : prev_frame; 529 : prev_frame;
451 case ImageFrame::kDisposeOverwritePrevious: 530 case ImageFrame::kDisposeOverwritePrevious:
452 default: 531 default:
453 NOTREACHED(); 532 NOTREACHED();
454 return kNotFound; 533 return kNotFound;
455 } 534 }
456 } 535 }
457 536
537 void ImageDecoder::InitializeNewFrame(size_t index) {
538 DCHECK(codec_);
539
540 ImageFrame& frame = frame_buffer_cache_[index];
541 // SkCodec does not inform us if only a portion of the image was updated
542 // in the current frame. Because of this, rather than correctly filling in
543 // the frame rect, we set the frame rect to be the image's full size.
544 IntSize fullImageSize = Size();
545 frame.SetOriginalFrameRect(IntRect(IntPoint(), fullImageSize));
546
547 SkCodec::FrameInfo frame_info;
548 memset(&frame_info, 0, sizeof(frame_info));
549 codec_->getFrameInfo(index, &frame_info);
550 frame.SetDuration(frame_info.fDuration);
551 frame.SetHasAlpha(!SkAlphaTypeIsOpaque(frame_info.fAlphaType));
552 size_t required_previous_frame_index = WTF::kNotFound;
553
554 if (frame_info.fRequiredFrame > 0) {
555 required_previous_frame_index =
556 static_cast<size_t>(frame_info.fRequiredFrame);
557 }
558
559 frame.SetRequiredPreviousFrameIndex(required_previous_frame_index);
560
561 // The disposal method is not required any more, but is left in place
562 // for the other image decoders that do not yet rely on SkCodec.
563 // For now, fill it with DisposeKeep.
564 frame.SetDisposalMethod(ImageFrame::kDisposeKeep);
565 }
566
458 ImagePlanes::ImagePlanes() { 567 ImagePlanes::ImagePlanes() {
459 for (int i = 0; i < 3; ++i) { 568 for (int i = 0; i < 3; ++i) {
460 planes_[i] = 0; 569 planes_[i] = 0;
461 row_bytes_[i] = 0; 570 row_bytes_[i] = 0;
462 } 571 }
463 } 572 }
464 573
465 ImagePlanes::ImagePlanes(void* planes[3], const size_t row_bytes[3]) { 574 ImagePlanes::ImagePlanes(void* planes[3], const size_t row_bytes[3]) {
466 for (int i = 0; i < 3; ++i) { 575 for (int i = 0; i < 3; ++i) {
467 planes_[i] = planes[i]; 576 planes_[i] = planes[i];
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
558 } 667 }
559 668
560 // For color spaces without an identifiable gamut, just fall through to 669 // For color spaces without an identifiable gamut, just fall through to
561 // sRGB. 670 // sRGB.
562 } 671 }
563 672
564 return SkColorSpace::MakeSRGB(); 673 return SkColorSpace::MakeSRGB();
565 } 674 }
566 675
567 } // namespace blink 676 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698