1 /*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 /*
9 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
21 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
28 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include "SkCodecAnimation.h"
34 #include "SkCodecPriv.h"
35 #include "SkColorPriv.h"
36 #include "SkColorTable.h"
37 #include "SkGifCodec.h"
38 #include "SkStream.h"
39 #include "SkSwizzler.h"
40
41 #include <algorithm>
42
43 #define GIF87_STAMP "GIF87a"
44 #define GIF89_STAMP "GIF89a"
45 #define GIF_STAMP_LEN 6
46
47 /*
48 * Checks the start of the stream to see if the image is a gif
49 */
IsGif(const void * buf,size_t bytesRead)50 bool SkGifCodec::IsGif(const void* buf, size_t bytesRead) {
51 if (bytesRead >= GIF_STAMP_LEN) {
52 if (memcmp(GIF87_STAMP, buf, GIF_STAMP_LEN) == 0 ||
53 memcmp(GIF89_STAMP, buf, GIF_STAMP_LEN) == 0)
54 {
55 return true;
56 }
57 }
58 return false;
59 }
60
61 /*
62 * Error function
63 */
gif_error(const char * msg,SkCodec::Result result=SkCodec::kInvalidInput)64 static SkCodec::Result gif_error(const char* msg, SkCodec::Result result = SkCodec::kInvalidInput) {
65 SkCodecPrintf("Gif Error: %s\n", msg);
66 return result;
67 }
68
69 /*
70 * Assumes IsGif was called and returned true
71 * Creates a gif decoder
72 * Reads enough of the stream to determine the image format
73 */
NewFromStream(SkStream * stream)74 SkCodec* SkGifCodec::NewFromStream(SkStream* stream) {
75 std::unique_ptr<SkGifImageReader> reader(new SkGifImageReader(stream));
76 if (!reader->parse(SkGifImageReader::SkGIFSizeQuery)) {
77 // Fatal error occurred.
78 return nullptr;
79 }
80
81 // If no images are in the data, or the first header is not yet defined, we cannot
82 // create a codec. In either case, the width and height are not yet known.
83 if (0 == reader->imagesCount() || !reader->frameContext(0)->isHeaderDefined()) {
84 return nullptr;
85 }
86
87 // isHeaderDefined() will not return true if the screen size is empty.
88 SkASSERT(reader->screenHeight() > 0 && reader->screenWidth() > 0);
89
90 const auto alpha = reader->firstFrameHasAlpha() ? SkEncodedInfo::kBinary_Alpha
91 : SkEncodedInfo::kOpaque_Alpha;
92 // Use kPalette since Gifs are encoded with a color table.
93 // FIXME: Gifs can actually be encoded with 4-bits per pixel. Using 8 works, but we could skip
94 // expanding to 8 bits and take advantage of the SkSwizzler to work from 4.
95 const auto encodedInfo = SkEncodedInfo::Make(SkEncodedInfo::kPalette_Color, alpha, 8);
96
97 // Although the encodedInfo is always kPalette_Color, it is possible that kIndex_8 is
98 // unsupported if the frame is subset and there is no transparent pixel.
99 const auto colorType = reader->firstFrameSupportsIndex8() ? kIndex_8_SkColorType
100 : kN32_SkColorType;
101 // The choice of unpremul versus premul is arbitrary, since all colors are either fully
102 // opaque or fully transparent (i.e. kBinary), but we stored the transparent colors as all
103 // zeroes, which is arguably premultiplied.
104 const auto alphaType = reader->firstFrameHasAlpha() ? kUnpremul_SkAlphaType
105 : kOpaque_SkAlphaType;
106
107 const auto imageInfo = SkImageInfo::Make(reader->screenWidth(), reader->screenHeight(),
108 colorType, alphaType,
109 SkColorSpace::MakeSRGB());
110 return new SkGifCodec(encodedInfo, imageInfo, reader.release());
111 }
112
onRewind()113 bool SkGifCodec::onRewind() {
114 fReader->clearDecodeState();
115 return true;
116 }
117
SkGifCodec(const SkEncodedInfo & encodedInfo,const SkImageInfo & imageInfo,SkGifImageReader * reader)118 SkGifCodec::SkGifCodec(const SkEncodedInfo& encodedInfo, const SkImageInfo& imageInfo,
119 SkGifImageReader* reader)
120 : INHERITED(encodedInfo, imageInfo, nullptr)
121 , fReader(reader)
122 , fTmpBuffer(nullptr)
123 , fSwizzler(nullptr)
124 , fCurrColorTable(nullptr)
125 , fCurrColorTableIsReal(false)
126 , fFilledBackground(false)
127 , fFirstCallToIncrementalDecode(false)
128 , fDst(nullptr)
129 , fDstRowBytes(0)
130 , fRowsDecoded(0)
131 {
132 reader->setClient(this);
133 }
134
onGetFrameInfo()135 std::vector<SkCodec::FrameInfo> SkGifCodec::onGetFrameInfo() {
136 fReader->parse(SkGifImageReader::SkGIFFrameCountQuery);
137 const size_t size = fReader->imagesCount();
138 std::vector<FrameInfo> result(size);
139 for (size_t i = 0; i < size; i++) {
140 const SkGIFFrameContext* frameContext = fReader->frameContext(i);
141 result[i].fDuration = frameContext->delayTime();
142 result[i].fRequiredFrame = frameContext->getRequiredFrame();
143 result[i].fFullyReceived = frameContext->isComplete();
144 }
145 return result;
146 }
147
onGetRepetitionCount()148 int SkGifCodec::onGetRepetitionCount() {
149 fReader->parse(SkGifImageReader::SkGIFLoopCountQuery);
150 return fReader->loopCount();
151 }
152
153 static const SkColorType kXformSrcColorType = kRGBA_8888_SkColorType;
154
initializeColorTable(const SkImageInfo & dstInfo,size_t frameIndex)155 void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, size_t frameIndex) {
156 SkColorType colorTableColorType = dstInfo.colorType();
157 if (this->colorXform()) {
158 colorTableColorType = kXformSrcColorType;
159 }
160
161 sk_sp<SkColorTable> currColorTable = fReader->getColorTable(colorTableColorType, frameIndex);
162 fCurrColorTableIsReal = currColorTable;
163 if (!fCurrColorTableIsReal) {
164 // This is possible for an empty frame. Create a dummy with one value (transparent).
165 SkPMColor color = SK_ColorTRANSPARENT;
166 fCurrColorTable.reset(new SkColorTable(&color, 1));
167 } else if (this->colorXform() && !fXformOnDecode) {
168 SkPMColor dstColors[256];
169 const SkColorSpaceXform::ColorFormat dstFormat =
170 select_xform_format_ct(dstInfo.colorType());
171 const SkColorSpaceXform::ColorFormat srcFormat = select_xform_format(kXformSrcColorType);
172 const SkAlphaType xformAlphaType = select_xform_alpha(dstInfo.alphaType(),
173 this->getInfo().alphaType());
174 SkAssertResult(this->colorXform()->apply(dstFormat, dstColors, srcFormat,
175 currColorTable->readColors(),
176 currColorTable->count(), xformAlphaType));
177 fCurrColorTable.reset(new SkColorTable(dstColors, currColorTable->count()));
178 } else {
179 fCurrColorTable = std::move(currColorTable);
180 }
181 }
182
183
prepareToDecode(const SkImageInfo & dstInfo,SkPMColor * inputColorPtr,int * inputColorCount,const Options & opts)184 SkCodec::Result SkGifCodec::prepareToDecode(const SkImageInfo& dstInfo, SkPMColor* inputColorPtr,
185 int* inputColorCount, const Options& opts) {
186 // Check for valid input parameters
187 if (!conversion_possible(dstInfo, this->getInfo()) ||
188 !this->initializeColorXform(dstInfo, opts.fPremulBehavior))
189 {
190 return gif_error("Cannot convert input type to output type.\n", kInvalidConversion);
191 }
192
193 fXformOnDecode = false;
194 if (this->colorXform()) {
195 fXformOnDecode = apply_xform_on_decode(dstInfo.colorType(), this->getEncodedInfo().color());
196 if (fXformOnDecode) {
197 fXformBuffer.reset(new uint32_t[dstInfo.width()]);
198 sk_bzero(fXformBuffer.get(), dstInfo.width() * sizeof(uint32_t));
199 }
200 }
201
202 if (opts.fSubset) {
203 return gif_error("Subsets not supported.\n", kUnimplemented);
204 }
205
206 const size_t frameIndex = opts.fFrameIndex;
207 if (frameIndex > 0) {
208 switch (dstInfo.colorType()) {
209 case kIndex_8_SkColorType:
210 // FIXME: It is possible that a later frame can be decoded to index8, if it does one
211 // of the following:
212 // - Covers the entire previous frame
213 // - Shares a color table (and transparent index) with any prior frames that are
214 // showing.
215 // We must support index8 for the first frame to be backwards compatible on Android,
216 // but we do not (currently) need to support later frames as index8.
217 return gif_error("Cannot decode multiframe gif (except frame 0) as index 8.\n",
218 kInvalidConversion);
219 case kRGB_565_SkColorType:
220 // FIXME: In theory, we might be able to support this, but it's not clear that it
221 // is necessary (Chromium does not decode to 565, and Android does not decode
222 // frames beyond the first). Disabling it because it is somewhat difficult:
223 // - If there is a transparent pixel, and this frame draws on top of another frame
224 // (if the frame is independent with a transparent pixel, we should not decode to
225 // 565 anyway, since it is not opaque), we need to skip drawing the transparent
226 // pixels (see writeTransparentPixels in haveDecodedRow). We currently do this by
227 // first swizzling into temporary memory, then copying into the destination. (We
228 // let the swizzler handle it first because it may need to sample.) After
229 // swizzling to 565, we do not know which pixels in our temporary memory
230 // correspond to the transparent pixel, so we do not know what to skip. We could
231 // special case the non-sampled case (no need to swizzle), but as this is
232 // currently unused we can just not support it.
233 return gif_error("Cannot decode multiframe gif (except frame 0) as 565.\n",
234 kInvalidConversion);
235 default:
236 break;
237 }
238 }
239
240 fReader->parse((SkGifImageReader::SkGIFParseQuery) frameIndex);
241
242 if (frameIndex >= fReader->imagesCount()) {
243 return gif_error("frame index out of range!\n", kIncompleteInput);
244 }
245
246 if (!fReader->frameContext(frameIndex)->reachedStartOfData()) {
247 // We have parsed enough to know that there is a color map, but cannot
248 // parse the map itself yet. Exit now, so we do not build an incorrect
249 // table.
250 return gif_error("color map not available yet\n", kIncompleteInput);
251 }
252
253 fTmpBuffer.reset(new uint8_t[dstInfo.minRowBytes()]);
254
255 this->initializeColorTable(dstInfo, frameIndex);
256 this->initializeSwizzler(dstInfo, frameIndex);
257
258 SkASSERT(fCurrColorTable);
259 if (inputColorCount) {
260 *inputColorCount = fCurrColorTable->count();
261 }
262 copy_color_table(dstInfo, fCurrColorTable.get(), inputColorPtr, inputColorCount);
263
264 return kSuccess;
265 }
266
initializeSwizzler(const SkImageInfo & dstInfo,size_t frameIndex)267 void SkGifCodec::initializeSwizzler(const SkImageInfo& dstInfo, size_t frameIndex) {
268 const SkGIFFrameContext* frame = fReader->frameContext(frameIndex);
269 // This is only called by prepareToDecode, which ensures frameIndex is in range.
270 SkASSERT(frame);
271
272 const int xBegin = frame->xOffset();
273 const int xEnd = std::min(static_cast<int>(frame->xOffset() + frame->width()),
274 static_cast<int>(fReader->screenWidth()));
275
276 // CreateSwizzler only reads left and right of the frame. We cannot use the frame's raw
277 // frameRect, since it might extend beyond the edge of the frame.
278 SkIRect swizzleRect = SkIRect::MakeLTRB(xBegin, 0, xEnd, 0);
279
280 SkImageInfo swizzlerInfo = dstInfo;
281 if (this->colorXform()) {
282 swizzlerInfo = swizzlerInfo.makeColorType(kXformSrcColorType);
283 if (kPremul_SkAlphaType == dstInfo.alphaType()) {
284 swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaType);
285 }
286 }
287
288 // The default Options should be fine:
289 // - we'll ignore if the memory is zero initialized - unless we're the first frame, this won't
290 // matter anyway.
291 // - subsets are not supported for gif
292 // - the swizzler does not need to know about the frame.
293 // We may not be able to use the real Options anyway, since getPixels does not store it (due to
294 // a bug).
295 fSwizzler.reset(SkSwizzler::CreateSwizzler(this->getEncodedInfo(),
296 fCurrColorTable->readColors(), swizzlerInfo, Options(), &swizzleRect));
297 SkASSERT(fSwizzler.get());
298 }
299
300 /*
301 * Initiates the gif decode
302 */
onGetPixels(const SkImageInfo & dstInfo,void * pixels,size_t dstRowBytes,const Options & opts,SkPMColor * inputColorPtr,int * inputColorCount,int * rowsDecoded)303 SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo,
304 void* pixels, size_t dstRowBytes,
305 const Options& opts,
306 SkPMColor* inputColorPtr,
307 int* inputColorCount,
308 int* rowsDecoded) {
309 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCount, opts);
310 switch (result) {
311 case kSuccess:
312 break;
313 case kIncompleteInput:
314 // onStartIncrementalDecode treats this as incomplete, since it may
315 // provide more data later, but in this case, no more data will be
316 // provided, and there is nothing to draw. We also cannot return
317 // kIncompleteInput, which will make SkCodec attempt to fill
318 // remaining rows, but that requires an SkSwizzler, which we have
319 // not created.
320 return kInvalidInput;
321 default:
322 return result;
323 }
324
325 if (dstInfo.dimensions() != this->getInfo().dimensions()) {
326 return gif_error("Scaling not supported.\n", kInvalidScale);
327 }
328
329 fDst = pixels;
330 fDstRowBytes = dstRowBytes;
331
332 return this->decodeFrame(true, opts, rowsDecoded);
333 }
334
onStartIncrementalDecode(const SkImageInfo & dstInfo,void * pixels,size_t dstRowBytes,const SkCodec::Options & opts,SkPMColor * inputColorPtr,int * inputColorCount)335 SkCodec::Result SkGifCodec::onStartIncrementalDecode(const SkImageInfo& dstInfo,
336 void* pixels, size_t dstRowBytes,
337 const SkCodec::Options& opts,
338 SkPMColor* inputColorPtr,
339 int* inputColorCount) {
340 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCount, opts);
341 if (result != kSuccess) {
342 return result;
343 }
344
345 fDst = pixels;
346 fDstRowBytes = dstRowBytes;
347
348 fFirstCallToIncrementalDecode = true;
349
350 return kSuccess;
351 }
352
onIncrementalDecode(int * rowsDecoded)353 SkCodec::Result SkGifCodec::onIncrementalDecode(int* rowsDecoded) {
354 // It is possible the client has appended more data. Parse, if needed.
355 const auto& options = this->options();
356 const size_t frameIndex = options.fFrameIndex;
357 fReader->parse((SkGifImageReader::SkGIFParseQuery) frameIndex);
358
359 const bool firstCallToIncrementalDecode = fFirstCallToIncrementalDecode;
360 fFirstCallToIncrementalDecode = false;
361 return this->decodeFrame(firstCallToIncrementalDecode, options, rowsDecoded);
362 }
363
decodeFrame(bool firstAttempt,const Options & opts,int * rowsDecoded)364 SkCodec::Result SkGifCodec::decodeFrame(bool firstAttempt, const Options& opts, int* rowsDecoded) {
365 const SkImageInfo& dstInfo = this->dstInfo();
366 const size_t frameIndex = opts.fFrameIndex;
367 SkASSERT(frameIndex < fReader->imagesCount());
368 const SkGIFFrameContext* frameContext = fReader->frameContext(frameIndex);
369 if (firstAttempt) {
370 // rowsDecoded reports how many rows have been initialized, so a layer above
371 // can fill the rest. In some cases, we fill the background before decoding
372 // (or it is already filled for us), so we report rowsDecoded to be the full
373 // height.
374 bool filledBackground = false;
375 if (frameContext->getRequiredFrame() == kNone) {
376 // We may need to clear to transparent for one of the following reasons:
377 // - The frameRect does not cover the full bounds. haveDecodedRow will
378 // only draw inside the frameRect, so we need to clear the rest.
379 // - The frame is interlaced. There is no obvious way to fill
380 // afterwards for an incomplete image. (FIXME: Does the first pass
381 // cover all rows? If so, we do not have to fill here.)
382 // - There is no color table for this frame. In that case will not
383 // draw anything, so we need to fill.
384 if (frameContext->frameRect() != this->getInfo().bounds()
385 || frameContext->interlaced() || !fCurrColorTableIsReal) {
386 // fill ignores the width (replaces it with the actual, scaled width).
387 // But we need to scale in Y.
388 const int scaledHeight = get_scaled_dimension(dstInfo.height(),
389 fSwizzler->sampleY());
390 auto fillInfo = dstInfo.makeWH(0, scaledHeight);
391 fSwizzler->fill(fillInfo, fDst, fDstRowBytes, this->getFillValue(dstInfo),
392 opts.fZeroInitialized);
393 filledBackground = true;
394 }
395 } else {
396 // Not independent
397 if (!opts.fHasPriorFrame) {
398 // Decode that frame into pixels.
399 Options prevFrameOpts(opts);
400 prevFrameOpts.fFrameIndex = frameContext->getRequiredFrame();
401 prevFrameOpts.fHasPriorFrame = false;
402 // The prior frame may have a different color table, so update it and the
403 // swizzler.
404 this->initializeColorTable(dstInfo, prevFrameOpts.fFrameIndex);
405 this->initializeSwizzler(dstInfo, prevFrameOpts.fFrameIndex);
406
407 const Result prevResult = this->decodeFrame(true, prevFrameOpts, nullptr);
408 switch (prevResult) {
409 case kSuccess:
410 // Prior frame succeeded. Carry on.
411 break;
412 case kIncompleteInput:
413 // Prior frame was incomplete. So this frame cannot be decoded.
414 return kInvalidInput;
415 default:
416 return prevResult;
417 }
418
419 // Go back to using the correct color table for this frame.
420 this->initializeColorTable(dstInfo, frameIndex);
421 this->initializeSwizzler(dstInfo, frameIndex);
422 }
423 const auto* prevFrame = fReader->frameContext(frameContext->getRequiredFrame());
424 if (prevFrame->getDisposalMethod() == SkCodecAnimation::RestoreBGColor_DisposalMethod) {
425 SkIRect prevRect = prevFrame->frameRect();
426 if (prevRect.intersect(this->getInfo().bounds())) {
427 // Do the divide ourselves for left and top, since we do not want
428 // get_scaled_dimension to upgrade 0 to 1. (This is similar to SkSampledCodec's
429 // sampling of the subset.)
430 auto left = prevRect.fLeft / fSwizzler->sampleX();
431 auto top = prevRect.fTop / fSwizzler->sampleY();
432 void* const eraseDst = SkTAddOffset<void>(fDst, top * fDstRowBytes
433 + left * SkColorTypeBytesPerPixel(dstInfo.colorType()));
434 auto width = get_scaled_dimension(prevRect.width(), fSwizzler->sampleX());
435 auto height = get_scaled_dimension(prevRect.height(), fSwizzler->sampleY());
436 // fSwizzler->fill() would fill to the scaled width of the frame, but we want to
437 // fill to the scaled with of the width of the PRIOR frame, so we do all the
438 // scaling ourselves and call the static version.
439 SkSampler::Fill(dstInfo.makeWH(width, height), eraseDst,
440 fDstRowBytes, this->getFillValue(dstInfo), kNo_ZeroInitialized);
441 }
442 }
443 filledBackground = true;
444 }
445
446 fFilledBackground = filledBackground;
447 if (filledBackground) {
448 // Report the full (scaled) height, since the client will never need to fill.
449 fRowsDecoded = get_scaled_dimension(dstInfo.height(), fSwizzler->sampleY());
450 } else {
451 // This will be updated by haveDecodedRow.
452 fRowsDecoded = 0;
453 }
454 }
455
456 if (!fCurrColorTableIsReal) {
457 // Nothing to draw this frame.
458 return kSuccess;
459 }
460
461 // Note: there is a difference between the following call to SkGifImageReader::decode
462 // returning false and leaving frameDecoded false:
463 // - If the method returns false, there was an error in the stream. We still treat this as
464 // incomplete, since we have already decoded some rows.
465 // - If frameDecoded is false, that just means that we do not have enough data. If more data
466 // is supplied, we may be able to continue decoding this frame. We also treat this as
467 // incomplete.
468 // FIXME: Ensure that we do not attempt to continue decoding if the method returns false and
469 // more data is supplied.
470 bool frameDecoded = false;
471 if (!fReader->decode(frameIndex, &frameDecoded) || !frameDecoded) {
472 if (rowsDecoded) {
473 *rowsDecoded = fRowsDecoded;
474 }
475 return kIncompleteInput;
476 }
477
478 return kSuccess;
479 }
480
onGetFillValue(const SkImageInfo & dstInfo) const481 uint64_t SkGifCodec::onGetFillValue(const SkImageInfo& dstInfo) const {
482 // Note: Using fCurrColorTable relies on having called initializeColorTable already.
483 // This is (currently) safe because this method is only called when filling, after
484 // initializeColorTable has been called.
485 // FIXME: Is there a way to make this less fragile?
486 if (dstInfo.colorType() == kIndex_8_SkColorType && fCurrColorTableIsReal) {
487 // We only support index 8 for the first frame, for backwards
488 // compatibity on Android, so we are using the color table for the first frame.
489 SkASSERT(this->options().fFrameIndex == 0);
490 // Use the transparent index for the first frame.
491 const size_t transPixel = fReader->frameContext(0)->transparentPixel();
492 if (transPixel < (size_t) fCurrColorTable->count()) {
493 return transPixel;
494 }
495 // Fall through to return SK_ColorTRANSPARENT (i.e. 0). This choice is arbitrary,
496 // but we have to pick something inside the color table, and this one is as good
497 // as any.
498 }
499 // Using transparent as the fill value matches the behavior in Chromium,
500 // which ignores the background color.
501 // If the colorType is kIndex_8, and there was no color table (i.e.
502 // fCurrColorTableIsReal is false), this value (zero) corresponds to the
503 // only entry in the dummy color table provided to the client.
504 return SK_ColorTRANSPARENT;
505 }
506
applyXformRow(const SkImageInfo & dstInfo,void * dst,const uint8_t * src) const507 void SkGifCodec::applyXformRow(const SkImageInfo& dstInfo, void* dst, const uint8_t* src) const {
508 if (this->colorXform() && fXformOnDecode) {
509 fSwizzler->swizzle(fXformBuffer.get(), src);
510
511 const SkColorSpaceXform::ColorFormat dstFormat = select_xform_format(dstInfo.colorType());
512 const SkColorSpaceXform::ColorFormat srcFormat = select_xform_format(kXformSrcColorType);
513 const SkAlphaType xformAlphaType = select_xform_alpha(dstInfo.alphaType(),
514 this->getInfo().alphaType());
515 const int xformWidth = get_scaled_dimension(dstInfo.width(), fSwizzler->sampleX());
516 SkAssertResult(this->colorXform()->apply(dstFormat, dst, srcFormat, fXformBuffer.get(),
517 xformWidth, xformAlphaType));
518 } else {
519 fSwizzler->swizzle(dst, src);
520 }
521 }
522
haveDecodedRow(size_t frameIndex,const unsigned char * rowBegin,size_t rowNumber,unsigned repeatCount,bool writeTransparentPixels)523 bool SkGifCodec::haveDecodedRow(size_t frameIndex, const unsigned char* rowBegin,
524 size_t rowNumber, unsigned repeatCount, bool writeTransparentPixels)
525 {
526 const SkGIFFrameContext* frameContext = fReader->frameContext(frameIndex);
527 // The pixel data and coordinates supplied to us are relative to the frame's
528 // origin within the entire image size, i.e.
529 // (frameContext->xOffset, frameContext->yOffset). There is no guarantee
530 // that width == (size().width() - frameContext->xOffset), so
531 // we must ensure we don't run off the end of either the source data or the
532 // row's X-coordinates.
533 const size_t width = frameContext->width();
534 const int xBegin = frameContext->xOffset();
535 const int yBegin = frameContext->yOffset() + rowNumber;
536 const int xEnd = std::min(static_cast<int>(frameContext->xOffset() + width),
537 this->getInfo().width());
538 const int yEnd = std::min(static_cast<int>(frameContext->yOffset() + rowNumber + repeatCount),
539 this->getInfo().height());
540 // FIXME: No need to make the checks on width/xBegin/xEnd for every row. We could instead do
541 // this once in prepareToDecode.
542 if (!width || (xBegin < 0) || (yBegin < 0) || (xEnd <= xBegin) || (yEnd <= yBegin))
543 return true;
544
545 // yBegin is the first row in the non-sampled image. dstRow will be the row in the output,
546 // after potentially scaling it.
547 int dstRow = yBegin;
548
549 const int sampleY = fSwizzler->sampleY();
550 if (sampleY > 1) {
551 // Check to see whether this row or one that falls in the repeatCount is needed in the
552 // output.
553 bool foundNecessaryRow = false;
554 for (unsigned i = 0; i < repeatCount; i++) {
555 const int potentialRow = yBegin + i;
556 if (fSwizzler->rowNeeded(potentialRow)) {
557 dstRow = potentialRow / sampleY;
558 const int scaledHeight = get_scaled_dimension(this->dstInfo().height(), sampleY);
559 if (dstRow >= scaledHeight) {
560 return true;
561 }
562
563 foundNecessaryRow = true;
564 repeatCount -= i;
565
566 repeatCount = (repeatCount - 1) / sampleY + 1;
567
568 // Make sure the repeatCount does not take us beyond the end of the dst
569 if (dstRow + (int) repeatCount > scaledHeight) {
570 repeatCount = scaledHeight - dstRow;
571 SkASSERT(repeatCount >= 1);
572 }
573 break;
574 }
575 }
576
577 if (!foundNecessaryRow) {
578 return true;
579 }
580 } else {
581 // Make sure the repeatCount does not take us beyond the end of the dst
582 SkASSERT(this->dstInfo().height() >= yBegin);
583 repeatCount = SkTMin(repeatCount, (unsigned) (this->dstInfo().height() - yBegin));
584 }
585
586 if (!fFilledBackground) {
587 // At this point, we are definitely going to write the row, so count it towards the number
588 // of rows decoded.
589 // We do not consider the repeatCount, which only happens for interlaced, in which case we
590 // have already set fRowsDecoded to the proper value (reflecting that we have filled the
591 // background).
592 fRowsDecoded++;
593 }
594
595 // decodeFrame will early exit if this is false, so this method will not be
596 // called.
597 SkASSERT(fCurrColorTableIsReal);
598
599 // The swizzler takes care of offsetting into the dst width-wise.
600 void* dstLine = SkTAddOffset<void>(fDst, dstRow * fDstRowBytes);
601
602 // We may or may not need to write transparent pixels to the buffer.
603 // If we're compositing against a previous image, it's wrong, but if
604 // we're decoding an interlaced gif and displaying it "Haeberli"-style,
605 // we must write these for passes beyond the first, or the initial passes
606 // will "show through" the later ones.
607 const auto dstInfo = this->dstInfo();
608 if (writeTransparentPixels) {
609 this->applyXformRow(dstInfo, dstLine, rowBegin);
610 } else {
611 sk_bzero(fTmpBuffer.get(), dstInfo.minRowBytes());
612 this->applyXformRow(dstInfo, fTmpBuffer.get(), rowBegin);
613
614 const size_t offsetBytes = fSwizzler->swizzleOffsetBytes();
615 switch (dstInfo.colorType()) {
616 case kBGRA_8888_SkColorType:
617 case kRGBA_8888_SkColorType: {
618 uint32_t* dstPixel = SkTAddOffset<uint32_t>(dstLine, offsetBytes);
619 uint32_t* srcPixel = SkTAddOffset<uint32_t>(fTmpBuffer.get(), offsetBytes);
620 for (int i = 0; i < fSwizzler->swizzleWidth(); i++) {
621 // Technically SK_ColorTRANSPARENT is an SkPMColor, and srcPixel would have
622 // the opposite swizzle for the non-native swizzle, but TRANSPARENT is all
623 // zeroes, which is the same either way.
624 if (*srcPixel != SK_ColorTRANSPARENT) {
625 *dstPixel = *srcPixel;
626 }
627 dstPixel++;
628 srcPixel++;
629 }
630 break;
631 }
632 case kRGBA_F16_SkColorType: {
633 uint64_t* dstPixel = SkTAddOffset<uint64_t>(dstLine, offsetBytes);
634 uint64_t* srcPixel = SkTAddOffset<uint64_t>(fTmpBuffer.get(), offsetBytes);
635 for (int i = 0; i < fSwizzler->swizzleWidth(); i++) {
636 if (*srcPixel != 0) {
637 *dstPixel = *srcPixel;
638 }
639 dstPixel++;
640 srcPixel++;
641 }
642 break;
643 }
644 default:
645 SkASSERT(false);
646 break;
647 }
648 }
649
650 // Tell the frame to copy the row data if need be.
651 if (repeatCount > 1) {
652 const size_t bytesPerPixel = SkColorTypeBytesPerPixel(this->dstInfo().colorType());
653 const size_t bytesToCopy = fSwizzler->swizzleWidth() * bytesPerPixel;
654 void* copiedLine = SkTAddOffset<void>(dstLine, fSwizzler->swizzleOffsetBytes());
655 void* dst = copiedLine;
656 for (unsigned i = 1; i < repeatCount; i++) {
657 dst = SkTAddOffset<void>(dst, fDstRowBytes);
658 memcpy(dst, copiedLine, bytesToCopy);
659 }
660 }
661
662 return true;
663 }
664