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

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

Issue 2565323003: Move gif image decoder to SkCodec (Closed)
Patch Set: Created 4 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
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
11 * documentation and/or other materials provided with the distribution. 11 * documentation and/or other materials provided with the distribution.
12 * 12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */ 24 */
25 25
26 #include "platform/image-decoders/gif/GIFImageDecoder.h" 26 #include "platform/image-decoders/gif/GIFImageDecoder.h"
27 27
28 #include "platform/image-decoders/gif/GIFImageReader.h" 28 #include "base/logging.h"
29 #include "wtf/NotFound.h" 29 #include "wtf/NotFound.h"
30 #include "wtf/PtrUtil.h" 30 #include "wtf/PtrUtil.h"
31 #include <limits> 31 #include <limits>
32 32
33 namespace blink { 33 namespace blink {
34 34
35 GIFImageDecoder::GIFImageDecoder(AlphaOption alphaOption, 35 GIFImageDecoder::GIFImageDecoder(AlphaOption alphaOption,
36 ColorSpaceOption colorOptions, 36 ColorSpaceOption colorOptions,
37 sk_sp<SkColorSpace> targetColorSpace, 37 sk_sp<SkColorSpace> targetColorSpace,
38 size_t maxDecodedBytes) 38 size_t maxDecodedBytes)
39 : ImageDecoder(alphaOption, 39 : ImageDecoder(alphaOption,
40 colorOptions, 40 colorOptions,
41 std::move(targetColorSpace), 41 std::move(targetColorSpace),
42 maxDecodedBytes), 42 maxDecodedBytes),
43 m_repetitionCount(cAnimationLoopOnce) {} 43 m_currentBufferSawAlpha(false),
44 m_codec(),
45 m_segmentStream(new SegmentStream{}) {}
scroggo_chromium 2016/12/13 16:57:36 Why not make m_segmentStream a full member? Oh wa
cblume 2016/12/14 09:16:56 Your idea about a raw pointer makes sense to me.
scroggo_chromium 2016/12/14 17:49:23 NewFromStream deletes the object - not the memory.
cblume 2016/12/16 02:57:10 Done.
44 46
45 GIFImageDecoder::~GIFImageDecoder() {} 47 GIFImageDecoder::~GIFImageDecoder() {}
46 48
47 void GIFImageDecoder::onSetData(SegmentReader* data) { 49 void GIFImageDecoder::onSetData(SegmentReader* data) {
48 if (m_reader) 50 // Add the segment to our stream
49 m_reader->setData(data); 51 m_segmentStream->setReader(data, isAllDataReceived());
52
53 // If we don't have a SkCodec yet, create one from the stream
54 if (!m_codec) {
55 m_codec.reset(SkCodec::NewFromStream(m_segmentStream.get()));
56 }
50 } 57 }
51 58
52 int GIFImageDecoder::repetitionCount() const { 59 int GIFImageDecoder::repetitionCount() const {
60 CHECK(m_codec);
61
53 // This value can arrive at any point in the image data stream. Most GIFs 62 // This value can arrive at any point in the image data stream. Most GIFs
54 // in the wild declare it near the beginning of the file, so it usually is 63 // in the wild declare it near the beginning of the file, so it usually is
55 // set by the time we've decoded the size, but (depending on the GIF and the 64 // set by the time we've decoded the size, but (depending on the GIF and the
56 // packets sent back by the webserver) not always. If the reader hasn't 65 // packets sent back by the webserver) not always.
57 // seen a loop count yet, it will return cLoopCountNotSeen, in which case we
58 // should default to looping once (the initial value for
59 // |m_repetitionCount|).
60 // 66 //
61 // There are some additional wrinkles here. First, ImageSource::clear() 67 // SkCodec will parse forward in the file if the repetition count has not been
62 // may destroy the reader, making the result from the reader _less_ 68 // seen yet.
63 // authoritative on future calls if the recreated reader hasn't seen the 69
64 // loop count. We don't need to special-case this because in this case the 70 int repetitionCount = m_codec->getRepetitionCount();
65 // new reader will once again return cLoopCountNotSeen, and we won't 71 switch (repetitionCount) {
66 // overwrite the cached correct value. 72 case 0:
67 // 73 return cAnimationNone;
68 // Second, a GIF might never set a loop count at all, in which case we 74 case SkCodec::kRepetitionCountInfinite:
69 // should continue to treat it as a "loop once" animation. We don't need 75 return cAnimationLoopInfinite;
70 // special code here either, because in this case we'll never change 76 default:
71 // |m_repetitionCount| from its default value. 77 return repetitionCount;
72 // 78 }
73 // Third, we use the same GIFImageReader for counting frames and we might
74 // see the loop count and then encounter a decoding error which happens
75 // later in the stream. It is also possible that no frames are in the
76 // stream. In these cases we should just loop once.
77 if (isAllDataReceived() && parseCompleted() && m_reader->imagesCount() == 1)
78 m_repetitionCount = cAnimationNone;
79 else if (failed() || (m_reader && (!m_reader->imagesCount())))
80 m_repetitionCount = cAnimationLoopOnce;
81 else if (m_reader && m_reader->loopCount() != cLoopCountNotSeen)
82 m_repetitionCount = m_reader->loopCount();
83 return m_repetitionCount;
84 } 79 }
85 80
86 bool GIFImageDecoder::frameIsCompleteAtIndex(size_t index) const { 81 bool GIFImageDecoder::frameIsCompleteAtIndex(size_t index) const {
87 return m_reader && (index < m_reader->imagesCount()) && 82 CHECK(m_codec);
88 m_reader->frameContext(index)->isComplete(); 83
84 std::vector<SkCodec::FrameInfo> frameInfos = m_codec->getFrameInfo();
85
86 // If https://skia-review.googlesource.com/c/5635/ lands
87 if (index == 0) {
88 return (frameInfoes.size() >= 1 || m_segmentStream->isAtEnd);
scroggo_chromium 2016/12/13 16:57:36 frameInfos* m_segmentStream->isAtEnd()* - but doe
cblume 2016/12/14 09:16:56 Done. Yeah, we'll be wrong until the end of the s
scroggo_chromium 2016/12/14 17:49:23 My hope was that we didn't actually need to know w
cblume 2016/12/16 02:57:10 Done.
89 // Either We have found a second frame, which means frame 0 is complete,
90 // or we have all the data, the image could be a single-frame and complete.
91 }
92
93 return frameInfos.size() > index;
94
95 // If https://skia-review.googlesource.com/c/5703/ lands:
96 // if (frameInfos.size() < index) {
97 // // index out of bounds as far as we have parsed
98 // return false;
99 //}
100 //
101 // return frameInfos[index].fFullyReceived;
89 } 102 }
90 103
91 float GIFImageDecoder::frameDurationAtIndex(size_t index) const { 104 float GIFImageDecoder::frameDurationAtIndex(size_t index) const {
92 return (m_reader && (index < m_reader->imagesCount()) && 105 CHECK(m_codec);
93 m_reader->frameContext(index)->isHeaderDefined()) 106
94 ? m_reader->frameContext(index)->delayTime() 107 std::vector<SkCodec::FrameInfo> frameInfos = m_codec->getFrameInfo();
95 : 0; 108
109 if (frameInfos.size() < index) {
110 // index out of bounds as far as we have parsed
111 return 0;
112 }
113
114 return frameInfos[index].fDuration;
96 } 115 }
97 116
98 bool GIFImageDecoder::setFailed() { 117 void GIFImageDecoder::decodeSize() {
99 m_reader.reset(); 118 CHECK(m_codec);
100 return ImageDecoder::setFailed();
101 }
102 119
103 bool GIFImageDecoder::haveDecodedRow(size_t frameIndex, 120 SkImageInfo imageInfo = m_codec->getInfo();
104 GIFRow::const_iterator rowBegin, 121 setSize(imageInfo->width(), imageInfo->height);
105 size_t width,
106 size_t rowNumber,
107 unsigned repeatCount,
108 bool writeTransparentPixels) {
109 const GIFFrameContext* frameContext = m_reader->frameContext(frameIndex);
110 // The pixel data and coordinates supplied to us are relative to the frame's
111 // origin within the entire image size, i.e.
112 // (frameContext->xOffset, frameContext->yOffset). There is no guarantee
113 // that width == (size().width() - frameContext->xOffset), so
114 // we must ensure we don't run off the end of either the source data or the
115 // row's X-coordinates.
116 const int xBegin = frameContext->xOffset();
117 const int yBegin = frameContext->yOffset() + rowNumber;
118 const int xEnd = std::min(static_cast<int>(frameContext->xOffset() + width),
119 size().width());
120 const int yEnd = std::min(
121 static_cast<int>(frameContext->yOffset() + rowNumber + repeatCount),
122 size().height());
123 if (!width || (xBegin < 0) || (yBegin < 0) || (xEnd <= xBegin) ||
124 (yEnd <= yBegin))
125 return true;
126
127 const GIFColorMap::Table& colorTable =
128 frameContext->localColorMap().isDefined()
129 ? frameContext->localColorMap().getTable()
130 : m_reader->globalColorMap().getTable();
131
132 if (colorTable.isEmpty())
133 return true;
134
135 GIFColorMap::Table::const_iterator colorTableIter = colorTable.begin();
136
137 // Initialize the frame if necessary.
138 ImageFrame& buffer = m_frameBufferCache[frameIndex];
139 if (!initFrameBuffer(frameIndex))
140 return false;
141
142 const size_t transparentPixel = frameContext->transparentPixel();
143 GIFRow::const_iterator rowEnd = rowBegin + (xEnd - xBegin);
144 ImageFrame::PixelData* currentAddress = buffer.getAddr(xBegin, yBegin);
145
146 // We may or may not need to write transparent pixels to the buffer.
147 // If we're compositing against a previous image, it's wrong, and if
148 // we're writing atop a cleared, fully transparent buffer, it's
149 // unnecessary; but if we're decoding an interlaced gif and
150 // displaying it "Haeberli"-style, we must write these for passes
151 // beyond the first, or the initial passes will "show through" the
152 // later ones.
153 //
154 // The loops below are almost identical. One writes a transparent pixel
155 // and one doesn't based on the value of |writeTransparentPixels|.
156 // The condition check is taken out of the loop to enhance performance.
157 // This optimization reduces decoding time by about 15% for a 3MB image.
158 if (writeTransparentPixels) {
159 for (; rowBegin != rowEnd; ++rowBegin, ++currentAddress) {
160 const size_t sourceValue = *rowBegin;
161 if ((sourceValue != transparentPixel) &&
162 (sourceValue < colorTable.size())) {
163 *currentAddress = colorTableIter[sourceValue];
164 } else {
165 *currentAddress = 0;
166 m_currentBufferSawAlpha = true;
167 }
168 }
169 } else {
170 for (; rowBegin != rowEnd; ++rowBegin, ++currentAddress) {
171 const size_t sourceValue = *rowBegin;
172 if ((sourceValue != transparentPixel) &&
173 (sourceValue < colorTable.size()))
174 *currentAddress = colorTableIter[sourceValue];
175 else
176 m_currentBufferSawAlpha = true;
177 }
178 }
179
180 // Tell the frame to copy the row data if need be.
181 if (repeatCount > 1)
182 buffer.copyRowNTimes(xBegin, xEnd, yBegin, yEnd);
183
184 buffer.setPixelsChanged(true);
185 return true;
186 }
187
188 bool GIFImageDecoder::parseCompleted() const {
189 return m_reader && m_reader->parseCompleted();
190 }
191
192 bool GIFImageDecoder::frameComplete(size_t frameIndex) {
193 // Initialize the frame if necessary. Some GIFs insert do-nothing frames,
194 // in which case we never reach haveDecodedRow() before getting here.
195 ImageFrame& buffer = m_frameBufferCache[frameIndex];
196 if (!initFrameBuffer(frameIndex))
197 return false; // initFrameBuffer() has already called setFailed().
198
199 buffer.setStatus(ImageFrame::FrameComplete);
200
201 if (!m_currentBufferSawAlpha) {
202 // The whole frame was non-transparent, so it's possible that the entire
203 // resulting buffer was non-transparent, and we can setHasAlpha(false).
204 if (buffer.originalFrameRect().contains(IntRect(IntPoint(), size()))) {
205 buffer.setHasAlpha(false);
206 buffer.setRequiredPreviousFrameIndex(kNotFound);
207 } else if (buffer.requiredPreviousFrameIndex() != kNotFound) {
208 // Tricky case. This frame does not have alpha only if everywhere
209 // outside its rect doesn't have alpha. To know whether this is
210 // true, we check the start state of the frame -- if it doesn't have
211 // alpha, we're safe.
212 const ImageFrame* prevBuffer =
213 &m_frameBufferCache[buffer.requiredPreviousFrameIndex()];
214 ASSERT(prevBuffer->getDisposalMethod() !=
215 ImageFrame::DisposeOverwritePrevious);
216
217 // Now, if we're at a DisposeNotSpecified or DisposeKeep frame, then
218 // we can say we have no alpha if that frame had no alpha. But
219 // since in initFrameBuffer() we already copied that frame's alpha
220 // state into the current frame's, we need do nothing at all here.
221 //
222 // The only remaining case is a DisposeOverwriteBgcolor frame. If
223 // it had no alpha, and its rect is contained in the current frame's
224 // rect, we know the current frame has no alpha.
225 if ((prevBuffer->getDisposalMethod() ==
226 ImageFrame::DisposeOverwriteBgcolor) &&
227 !prevBuffer->hasAlpha() &&
228 buffer.originalFrameRect().contains(prevBuffer->originalFrameRect()))
229 buffer.setHasAlpha(false);
230 }
231 }
232
233 return true;
234 }
235
236 void GIFImageDecoder::clearFrameBuffer(size_t frameIndex) {
237 if (m_reader &&
238 m_frameBufferCache[frameIndex].getStatus() == ImageFrame::FramePartial) {
239 // Reset the state of the partial frame in the reader so that the frame
240 // can be decoded again when requested.
241 m_reader->clearDecodeState(frameIndex);
242 }
243 ImageDecoder::clearFrameBuffer(frameIndex);
244 } 122 }
245 123
246 size_t GIFImageDecoder::decodeFrameCount() { 124 size_t GIFImageDecoder::decodeFrameCount() {
247 parse(GIFFrameCountQuery); 125 std::vector<SkCodec::FrameInfo> frameInfos = m_codec->getFrameInfo();
248 // If decoding fails, |m_reader| will have been destroyed. Instead of 126 return frameInfos.size();
249 // returning 0 in this case, return the existing number of frames. This way
250 // if we get halfway through the image before decoding fails, we won't
251 // suddenly start reporting that the image has zero frames.
252 return failed() ? m_frameBufferCache.size() : m_reader->imagesCount();
253 } 127 }
254 128
255 void GIFImageDecoder::initializeNewFrame(size_t index) { 129 void GIFImageDecoder::initializeNewFrame(size_t index) {
256 ImageFrame* buffer = &m_frameBufferCache[index]; 130 CHECK(m_codec);
257 const GIFFrameContext* frameContext = m_reader->frameContext(index); 131
258 buffer->setOriginalFrameRect( 132 if (m_frameBufferCache.size() < index) {
scroggo_chromium 2016/12/13 16:57:36 I think you want <=, here and elsewhere. (And the
cblume 2016/12/14 09:16:56 Done. I think you are right that it is not needed.
259 intersection(frameContext->frameRect(), IntRect(IntPoint(), size()))); 133 // index out of bounds as far as we have parsed
260 buffer->setDuration(frameContext->delayTime()); 134 return;
261 buffer->setDisposalMethod(frameContext->getDisposalMethod()); 135 }
262 buffer->setRequiredPreviousFrameIndex( 136
263 findRequiredPreviousFrame(index, false)); 137 ImageFrame& frame = m_frameBufferCache[index];
138 std::vector<SkCodec::FrameInfo> frameInfos = m_codec->getFrameInfo();
scroggo_chromium 2016/12/13 16:57:36 Since we call this so often, I think we should con
cblume 2016/12/14 09:16:56 I like the idea of SkCodec having a method that re
139
140 frame.setOriginalFrameRect(size());
141 frame.setDuration(frameInfos[index].fDuration);
142 frame.setDisposalMethod(???);
143 // TODO: SkCodec doesn't expose the disposal method.
scroggo_chromium 2016/12/13 16:57:36 These might just be awkward during the transition.
cblume 2016/12/14 09:16:56 I agree. I'm hoping this stuff isn't handled by th
144 size_t requiredPreviousFrame = frameInfos[index].fRequiredFrame;
145 if (requiredPreviousFrame == SkCodec::kNone) {
146 requiredPreviousFrame = WTF::kNotFound;
147 }
148 frame.setRequiredPreviousFrameIndex(requiredPreviousFrame);
264 } 149 }
265 150
266 void GIFImageDecoder::decode(size_t index) { 151 void GIFImageDecoder::decode(size_t index) {
267 parse(GIFFrameCountQuery); 152 CHECK(m_codec);
268 153
269 if (failed()) 154 if (m_frameBufferCache.size() < index) {
155 // index out of bounds as far as we have parsed
270 return; 156 return;
157 }
271 158
272 updateAggressivePurging(index); 159 updateAggressivePurging(index);
273 160
274 Vector<size_t> framesToDecode = findFramesToDecode(index); 161 SkImageInfo imageInfo = m_codec->getInfo();
275 for (auto i = framesToDecode.rbegin(); i != framesToDecode.rend(); ++i) { 162 if (imageInfo.colorType() == kIndex8_SkColorType) {
276 if (!m_reader->decode(*i)) { 163 // imageInfo's color type may be influenced by the untrusted image file.
scroggo_chromium 2016/12/13 16:57:36 We report index8 if the GIF can support it (for th
cblume 2016/12/14 09:16:56 Done.
277 setFailed(); 164 // Index8 has special behavior when getting the pixels, which we do not yet
278 return; 165 // handle
279 } 166 return;
167 }
280 168
281 // If this returns false, we need more data to continue decoding. 169 SkCodec::Options getPixelsOptions;
282 if (!postDecodeProcessing(*i)) 170 getPixelsOptions.fFrameIndex = index;
283 break; 171 getPixelsOptions.fHasPriorFrame = false;
172
173 // TODO: On the second loop, can we avoid re-copying and decoding?
174 // Said another way, is there a way to know if we already populated this
scroggo_chromium 2016/12/13 16:57:36 Check frame.getStatus()?
cblume 2016/12/14 09:16:56 Hrmmm I seem to be able to check for empty, incomp
scroggo_chromium 2016/12/14 17:49:23 If i was purged, m_frameBufferCache[i] should be F
cblume 2016/12/16 02:57:10 I guess we have two types of "complete": completel
175 // frame?
176 ImageFrame& frame = m_frameBufferCache[index];
177 size_t requiredPreviousFrameIndex = frame.requiredPreviousFrameIndex();
178 if (requiredPreviousFrameIndex == WTF::kNotFound) {
scroggo_chromium 2016/12/13 16:57:36 I think you mean != WTF::kNotFound?
cblume 2016/12/14 09:16:56 Done.
179 getPixelsOptions.fHasPriorFrame = true;
180 ImageFrame& requiredPreviousFrame =
181 m_frameBufferCache[requiredPreviousFrameIndex];
182 frame.copyBitmapData(requiredPreviousFrame);
scroggo_chromium 2016/12/13 16:57:36 Doesn't this happen in initFrameBuffer? https://c
cblume 2016/12/14 09:16:56 Done.
scroggo_chromium 2016/12/14 17:49:23 D'oh, and then I told you not to call that method.
cblume 2016/12/16 02:57:10 I took another look again at initFrameBuffer. It c
scroggo_chromium 2016/12/16 15:03:47 I'd sync up with msarett@.
284 } 183 }
285 184
185 SkCodec::Result getPixelsResult =
scroggo_chromium 2016/12/13 16:57:36 You want to switch from getPixels() to startIncrem
cblume 2016/12/14 09:16:56 That makes sense. I'll have to research the behav
scroggo_chromium 2016/12/14 17:49:23 As I understand it, Blink waits until a frame afte
cblume 2016/12/16 02:57:10 Done.
186 m_codec->getPixels(imageInfo, frame.getPixels(), frame.rowBytes(),
187 &getPixelsOptions, nullptr, nullptr);
188 if (getPixelResult != kSuccess) {
scroggo_chromium 2016/12/13 16:57:36 kIncomplete is also okay, so long as it's the late
cblume 2016/12/14 09:16:56 Done.
189 setFailed();
190 return;
191 }
192
193 if (!postDecodeProcessing(index)) {
194 return;
195 }
196
197 // If we do not end up landing https://skia-review.googlesource.com/c/5635/
198 // ...
199
286 // It is also a fatal error if all data is received and we have decoded all 200 // It is also a fatal error if all data is received and we have decoded all
287 // frames available but the file is truncated. 201 // frames available but the file is truncated.
288 if (index >= m_frameBufferCache.size() - 1 && isAllDataReceived() && 202 if (index >= m_frameBufferCache.size() - 1 && isAllDataReceived()) {
289 m_reader && !m_reader->parseCompleted())
290 setFailed(); 203 setFailed();
291 }
292
293 void GIFImageDecoder::parse(GIFParseQuery query) {
294 if (failed())
295 return;
296
297 if (!m_reader) {
298 m_reader = makeUnique<GIFImageReader>(this);
299 m_reader->setData(m_data);
300 } 204 }
301
302 if (!m_reader->parse(query))
303 setFailed();
304 }
305
306 void GIFImageDecoder::onInitFrameBuffer(size_t frameIndex) {
307 m_currentBufferSawAlpha = false;
308 } 205 }
309 206
310 bool GIFImageDecoder::canReusePreviousFrameBuffer(size_t frameIndex) const { 207 bool GIFImageDecoder::canReusePreviousFrameBuffer(size_t frameIndex) const {
311 DCHECK(frameIndex < m_frameBufferCache.size()); 208 DCHECK(frameIndex < m_frameBufferCache.size());
312 return m_frameBufferCache[frameIndex].getDisposalMethod() != 209 return m_frameBufferCache[frameIndex].getDisposalMethod() !=
313 ImageFrame::DisposeOverwritePrevious; 210 ImageFrame::DisposeOverwritePrevious;
314 } 211 }
315 212
316 } // namespace blink 213 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698