OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkCodec_libgif.h" | 8 #include "SkCodec_libgif.h" |
9 #include "SkCodecPriv.h" | 9 #include "SkCodecPriv.h" |
10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
178 | 178 |
179 // Read the image descriptor | 179 // Read the image descriptor |
180 if (GIF_ERROR == DGifGetImageDesc(gif)) { | 180 if (GIF_ERROR == DGifGetImageDesc(gif)) { |
181 return false; | 181 return false; |
182 } | 182 } |
183 // If reading the image descriptor is successful, the image count will be | 183 // If reading the image descriptor is successful, the image count will be |
184 // incremented. | 184 // incremented. |
185 SkASSERT(gif->ImageCount >= 1); | 185 SkASSERT(gif->ImageCount >= 1); |
186 | 186 |
187 if (nullptr != codecOut) { | 187 if (nullptr != codecOut) { |
188 // Get fields from header | 188 SkISize size; |
189 const int32_t width = gif->SWidth; | 189 SkIRect frameRect; |
190 const int32_t height = gif->SHeight; | 190 if (!GetDimensions(gif, &size, &frameRect)) { |
191 if (width <= 0 || height <= 0) { | 191 gif_error("Invalid gif size.\n"); |
192 gif_error("Invalid dimensions.\n"); | |
193 return false; | |
194 } | 192 } |
| 193 bool frameIsSubset = (size != frameRect.size()); |
195 | 194 |
196 // Determine the recommended alpha type. The transIndex might be valid
if it less | 195 // Determine the recommended alpha type. The transIndex might be valid
if it less |
197 // than 256. We are not certain that the index is valid until we proces
s the color | 196 // than 256. We are not certain that the index is valid until we proces
s the color |
198 // table, since some gifs have color tables with less than 256 colors.
If | 197 // table, since some gifs have color tables with less than 256 colors.
If |
199 // there might be a valid transparent index, we must indicate that the i
mage has | 198 // there might be a valid transparent index, we must indicate that the i
mage has |
200 // alpha. | 199 // alpha. |
201 // In the case where we must support alpha, we have the option to set th
e | 200 // In the case where we must support alpha, we have the option to set th
e |
202 // suggested alpha type to kPremul or kUnpremul. Both are valid since t
he alpha | 201 // suggested alpha type to kPremul or kUnpremul. Both are valid since t
he alpha |
203 // component will always be 0xFF or the entire 32-bit pixel will be set
to zero. | 202 // component will always be 0xFF or the entire 32-bit pixel will be set
to zero. |
204 // We prefer kPremul because we support kPremul, and it is more efficien
t to use | 203 // We prefer kPremul because we support kPremul, and it is more efficien
t to use |
205 // kPremul directly even when kUnpremul is supported. | 204 // kPremul directly even when kUnpremul is supported. |
206 SkAlphaType alphaType = (transIndex < 256) ? kPremul_SkAlphaType : kOpaq
ue_SkAlphaType; | 205 SkAlphaType alphaType = (transIndex < 256) ? kPremul_SkAlphaType : kOpaq
ue_SkAlphaType; |
207 | 206 |
208 // Return the codec | 207 // Return the codec |
209 // kIndex is the most natural color type for gifs, so we set this as | 208 // kIndex is the most natural color type for gifs, so we set this as |
210 // the default. | 209 // the default. |
211 const SkImageInfo& imageInfo = SkImageInfo::Make(width, height, | 210 SkImageInfo imageInfo = SkImageInfo::Make(size.width(), size.height(), k
Index_8_SkColorType, |
212 kIndex_8_SkColorType, alphaType); | 211 alphaType); |
213 *codecOut = new SkGifCodec(imageInfo, streamDeleter.detach(), gif.detach
(), transIndex); | 212 *codecOut = new SkGifCodec(imageInfo, streamDeleter.detach(), gif.detach
(), transIndex, |
| 213 frameRect, frameIsSubset); |
214 } else { | 214 } else { |
215 SkASSERT(nullptr != gifOut); | 215 SkASSERT(nullptr != gifOut); |
216 streamDeleter.detach(); | 216 streamDeleter.detach(); |
217 *gifOut = gif.detach(); | 217 *gifOut = gif.detach(); |
218 } | 218 } |
219 return true; | 219 return true; |
220 } | 220 } |
221 | 221 |
222 /* | 222 /* |
223 * Assumes IsGif was called and returned true | 223 * Assumes IsGif was called and returned true |
224 * Creates a gif decoder | 224 * Creates a gif decoder |
225 * Reads enough of the stream to determine the image format | 225 * Reads enough of the stream to determine the image format |
226 */ | 226 */ |
227 SkCodec* SkGifCodec::NewFromStream(SkStream* stream) { | 227 SkCodec* SkGifCodec::NewFromStream(SkStream* stream) { |
228 SkCodec* codec = nullptr; | 228 SkCodec* codec = nullptr; |
229 if (ReadHeader(stream, &codec, nullptr)) { | 229 if (ReadHeader(stream, &codec, nullptr)) { |
230 return codec; | 230 return codec; |
231 } | 231 } |
232 return nullptr; | 232 return nullptr; |
233 } | 233 } |
234 | 234 |
235 SkGifCodec::SkGifCodec(const SkImageInfo& srcInfo, SkStream* stream, GifFileType
* gif, | 235 SkGifCodec::SkGifCodec(const SkImageInfo& srcInfo, SkStream* stream, GifFileType
* gif, |
236 uint32_t transIndex) | 236 uint32_t transIndex, const SkIRect& frameRect, bool frameIsSubset) |
237 : INHERITED(srcInfo, stream) | 237 : INHERITED(srcInfo, stream) |
238 , fGif(gif) | 238 , fGif(gif) |
239 , fSrcBuffer(new uint8_t[this->getInfo().width()]) | 239 , fSrcBuffer(new uint8_t[this->getInfo().width()]) |
240 // If it is valid, fTransIndex will be used to set fFillIndex. We don't kno
w if | 240 // If it is valid, fTransIndex will be used to set fFillIndex. We don't kno
w if |
241 // fTransIndex is valid until we process the color table, since fTransIndex
may | 241 // fTransIndex is valid until we process the color table, since fTransIndex
may |
242 // be greater than the size of the color table. | 242 // be greater than the size of the color table. |
243 , fTransIndex(transIndex) | 243 , fTransIndex(transIndex) |
244 // Default fFillIndex is 0. We will overwrite this if fTransIndex is valid,
or if | 244 // Default fFillIndex is 0. We will overwrite this if fTransIndex is valid,
or if |
245 // there is a valid background color. | 245 // there is a valid background color. |
246 , fFillIndex(0) | 246 , fFillIndex(0) |
247 , fFrameDims(SkIRect::MakeEmpty()) | 247 , fFrameRect(frameRect) |
248 , fFrameIsSubset(false) | 248 , fFrameIsSubset(frameIsSubset) |
249 , fColorTable(NULL) | 249 , fColorTable(NULL) |
250 , fSwizzler(NULL) | 250 , fSwizzler(NULL) |
251 {} | 251 {} |
252 | 252 |
253 bool SkGifCodec::onRewind() { | 253 bool SkGifCodec::onRewind() { |
254 GifFileType* gifOut = nullptr; | 254 GifFileType* gifOut = nullptr; |
255 if (!ReadHeader(this->stream(), nullptr, &gifOut)) { | 255 if (!ReadHeader(this->stream(), nullptr, &gifOut)) { |
256 return false; | 256 return false; |
257 } | 257 } |
258 | 258 |
(...skipping 17 matching lines...) Expand all Loading... |
276 // contain more than one image, we will simply decode the first image. | 276 // contain more than one image, we will simply decode the first image. |
277 GifRecordType recordType; | 277 GifRecordType recordType; |
278 do { | 278 do { |
279 // Get the current record type | 279 // Get the current record type |
280 if (GIF_ERROR == DGifGetRecordType(gif, &recordType)) { | 280 if (GIF_ERROR == DGifGetRecordType(gif, &recordType)) { |
281 return gif_error("DGifGetRecordType failed.\n", kInvalidInput); | 281 return gif_error("DGifGetRecordType failed.\n", kInvalidInput); |
282 } | 282 } |
283 switch (recordType) { | 283 switch (recordType) { |
284 case IMAGE_DESC_RECORD_TYPE: { | 284 case IMAGE_DESC_RECORD_TYPE: { |
285 *transIndex = find_trans_index(saveExt); | 285 *transIndex = find_trans_index(saveExt); |
| 286 |
286 // FIXME: Gif files may have multiple images stored in a single | 287 // FIXME: Gif files may have multiple images stored in a single |
287 // file. This is most commonly used to enable | 288 // file. This is most commonly used to enable |
288 // animations. Since we are leaving animated gifs as a | 289 // animations. Since we are leaving animated gifs as a |
289 // TODO, we will return kSuccess after decoding the | 290 // TODO, we will return kSuccess after decoding the |
290 // first image in the file. This is the same behavior | 291 // first image in the file. This is the same behavior |
291 // as SkImageDecoder_libgif. | 292 // as SkImageDecoder_libgif. |
292 // | 293 // |
293 // Most times this works pretty well, but sometimes it | 294 // Most times this works pretty well, but sometimes it |
294 // doesn't. For example, I have an animated test image | 295 // doesn't. For example, I have an animated test image |
295 // where the first image in the file is 1x1, but the | 296 // where the first image in the file is 1x1, but the |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
339 // not match one of the above cases. This should not be | 340 // not match one of the above cases. This should not be |
340 // reached. | 341 // reached. |
341 SkASSERT(false); | 342 SkASSERT(false); |
342 break; | 343 break; |
343 } | 344 } |
344 } while (TERMINATE_RECORD_TYPE != recordType); | 345 } while (TERMINATE_RECORD_TYPE != recordType); |
345 | 346 |
346 return gif_error("Could not find any images to decode in gif file.\n", kInva
lidInput); | 347 return gif_error("Could not find any images to decode in gif file.\n", kInva
lidInput); |
347 } | 348 } |
348 | 349 |
349 /* | 350 bool SkGifCodec::GetDimensions(GifFileType* gif, SkISize* size, SkIRect* frameRe
ct) { |
350 * A gif may contain many image frames, all of different sizes. | 351 // Get the encoded dimension values |
351 * This function checks if the frame dimensions are valid and corrects them if | 352 SavedImage* image = &gif->SavedImages[gif->ImageCount - 1]; |
352 * necessary. | 353 const GifImageDesc& desc = image->ImageDesc; |
353 */ | 354 int frameLeft = desc.Left; |
354 bool SkGifCodec::setFrameDimensions(const GifImageDesc& desc) { | 355 int frameTop = desc.Top; |
355 // Fail on non-positive dimensions | 356 int frameWidth = desc.Width; |
356 int32_t frameLeft = desc.Left; | 357 int frameHeight = desc.Height; |
357 int32_t frameTop = desc.Top; | 358 int width = gif->SWidth; |
358 int32_t frameWidth = desc.Width; | 359 int height = gif->SHeight; |
359 int32_t frameHeight = desc.Height; | 360 |
360 int32_t height = this->getInfo().height(); | 361 // Ensure that the decode dimensions are large enough to contain the frame |
361 int32_t width = this->getInfo().width(); | 362 width = SkTMax(width, frameWidth + frameLeft); |
362 if (frameWidth <= 0 || frameHeight <= 0) { | 363 height = SkTMax(height, frameHeight + frameTop); |
| 364 |
| 365 // All of these dimensions should be positive, as they are encoded as unsign
ed 16-bit integers. |
| 366 // It is unclear why giflib casts them to ints. We will go ahead and check
that they are |
| 367 // in fact positive. |
| 368 if (frameLeft < 0 || frameTop < 0 || frameWidth < 0 || frameHeight < 0 || wi
dth <= 0 || |
| 369 height <= 0) { |
363 return false; | 370 return false; |
364 } | 371 } |
365 | 372 |
366 // Treat the following cases as warnings and try to fix | 373 frameRect->setXYWH(frameLeft, frameTop, frameWidth, frameHeight); |
367 if (frameWidth > width) { | 374 size->set(width, height); |
368 gif_warning("Image frame too wide, shrinking.\n"); | |
369 frameWidth = width; | |
370 frameLeft = 0; | |
371 } else if (frameLeft + frameWidth > width) { | |
372 gif_warning("Shifting image frame to left to fit.\n"); | |
373 frameLeft = width - frameWidth; | |
374 } else if (frameLeft < 0) { | |
375 gif_warning("Shifting image frame to right to fit\n"); | |
376 frameLeft = 0; | |
377 } | |
378 if (frameHeight > height) { | |
379 gif_warning("Image frame too tall, shrinking.\n"); | |
380 frameHeight = height; | |
381 frameTop = 0; | |
382 } else if (frameTop + frameHeight > height) { | |
383 gif_warning("Shifting image frame up to fit.\n"); | |
384 frameTop = height - frameHeight; | |
385 } else if (frameTop < 0) { | |
386 gif_warning("Shifting image frame down to fit\n"); | |
387 frameTop = 0; | |
388 } | |
389 fFrameDims.setXYWH(frameLeft, frameTop, frameWidth, frameHeight); | |
390 | |
391 // Indicate if the frame dimensions do not match the header dimensions | |
392 if (this->getInfo().dimensions() != fFrameDims.size()) { | |
393 fFrameIsSubset = true; | |
394 } | |
395 | |
396 return true; | 375 return true; |
397 } | 376 } |
398 | 377 |
399 void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, SkPMColor* inp
utColorPtr, | 378 void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, SkPMColor* inp
utColorPtr, |
400 int* inputColorCount) { | 379 int* inputColorCount) { |
401 // Set up our own color table | 380 // Set up our own color table |
402 const uint32_t maxColors = 256; | 381 const uint32_t maxColors = 256; |
403 SkPMColor colorPtr[256]; | 382 SkPMColor colorPtr[256]; |
404 if (NULL != inputColorCount) { | 383 if (NULL != inputColorCount) { |
405 // We set the number of colors to maxColors in order to ensure | 384 // We set the number of colors to maxColors in order to ensure |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
458 // Check for valid input parameters | 437 // Check for valid input parameters |
459 if (opts.fSubset) { | 438 if (opts.fSubset) { |
460 // Subsets are not supported. | 439 // Subsets are not supported. |
461 return kUnimplemented; | 440 return kUnimplemented; |
462 } | 441 } |
463 if (!conversion_possible(dstInfo, this->getInfo())) { | 442 if (!conversion_possible(dstInfo, this->getInfo())) { |
464 return gif_error("Cannot convert input type to output type.\n", | 443 return gif_error("Cannot convert input type to output type.\n", |
465 kInvalidConversion); | 444 kInvalidConversion); |
466 } | 445 } |
467 | 446 |
468 | |
469 // We have asserted that the image count is at least one in ReadHeader(). | |
470 SavedImage* image = &fGif->SavedImages[fGif->ImageCount - 1]; | |
471 const GifImageDesc& desc = image->ImageDesc; | |
472 | |
473 // Check that the frame dimensions are valid and set them | |
474 if(!this->setFrameDimensions(desc)) { | |
475 return gif_error("Invalid dimensions for image frame.\n", kInvalidInput)
; | |
476 } | |
477 | |
478 // Initialize color table and copy to the client if necessary | 447 // Initialize color table and copy to the client if necessary |
479 this->initializeColorTable(dstInfo, inputColorPtr, inputColorCount); | 448 this->initializeColorTable(dstInfo, inputColorPtr, inputColorCount); |
480 return kSuccess; | 449 return kSuccess; |
481 } | 450 } |
482 | 451 |
483 SkCodec::Result SkGifCodec::initializeSwizzler(const SkImageInfo& dstInfo, | 452 SkCodec::Result SkGifCodec::initializeSwizzler(const SkImageInfo& dstInfo, |
484 ZeroInitialized zeroInit) { | 453 ZeroInitialized zeroInit) { |
485 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 454 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
486 fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex, | 455 fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex, |
487 colorPtr, dstInfo, zeroInit)); | 456 colorPtr, dstInfo, zeroInit)); |
488 if (nullptr != fSwizzler.get()) { | 457 if (nullptr != fSwizzler.get()) { |
489 return kSuccess; | 458 return kSuccess; |
490 } | 459 } |
491 return kUnimplemented; | 460 return kUnimplemented; |
492 } | 461 } |
493 | 462 |
494 SkCodec::Result SkGifCodec::readRow() { | 463 SkCodec::Result SkGifCodec::readRow() { |
495 if (GIF_ERROR == DGifGetLine(fGif, fSrcBuffer.get(), fFrameDims.width())) { | 464 if (GIF_ERROR == DGifGetLine(fGif, fSrcBuffer.get(), fFrameRect.width())) { |
496 return kIncompleteInput; | 465 return kIncompleteInput; |
497 } | 466 } |
498 return kSuccess; | 467 return kSuccess; |
499 } | 468 } |
500 | 469 |
501 /* | 470 /* |
502 * Initiates the gif decode | 471 * Initiates the gif decode |
503 */ | 472 */ |
504 SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo, | 473 SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo, |
505 void* dst, size_t dstRowBytes, | 474 void* dst, size_t dstRowBytes, |
506 const Options& opts, | 475 const Options& opts, |
507 SkPMColor* inputColorPtr, | 476 SkPMColor* inputColorPtr, |
508 int* inputColorCount) { | 477 int* inputColorCount) { |
509 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun
t, opts); | 478 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun
t, opts); |
510 if (kSuccess != result) { | 479 if (kSuccess != result) { |
511 return result; | 480 return result; |
512 } | 481 } |
513 | 482 |
514 if (dstInfo.dimensions() != this->getInfo().dimensions()) { | 483 if (dstInfo.dimensions() != this->getInfo().dimensions()) { |
515 return gif_error("Scaling not supported.\n", kInvalidScale); | 484 return gif_error("Scaling not supported.\n", kInvalidScale); |
516 } | 485 } |
517 | 486 |
518 // Initialize the swizzler | 487 // Initialize the swizzler |
519 if (fFrameIsSubset) { | 488 if (fFrameIsSubset) { |
520 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameDims.width(), fFr
ameDims.height()); | 489 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFr
ameRect.height()); |
521 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia
lized)) { | 490 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia
lized)) { |
522 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; | 491 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; |
523 } | 492 } |
524 | 493 |
525 // Fill the background | 494 // Fill the background |
526 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 495 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
527 SkSwizzler::Fill(dst, dstInfo, dstRowBytes, this->getInfo().height(), | 496 SkSwizzler::Fill(dst, dstInfo, dstRowBytes, this->getInfo().height(), |
528 fFillIndex, colorPtr, opts.fZeroInitialized); | 497 fFillIndex, colorPtr, opts.fZeroInitialized); |
529 | 498 |
530 // Modify the dst pointer | 499 // Modify the dst pointer |
531 const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(dstInfo.colorT
ype()); | 500 const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(dstInfo.colorT
ype()); |
532 dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameDims.top() + | 501 dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameRect.top() + |
533 dstBytesPerPixel * fFrameDims.left()); | 502 dstBytesPerPixel * fFrameRect.left()); |
534 } else { | 503 } else { |
535 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized)
) { | 504 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized)
) { |
536 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; | 505 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; |
537 } | 506 } |
538 } | 507 } |
539 | 508 |
540 // Check the interlace flag and iterate over rows of the input | 509 // Check the interlace flag and iterate over rows of the input |
541 uint32_t width = fFrameDims.width(); | 510 uint32_t width = fFrameRect.width(); |
542 uint32_t height = fFrameDims.height(); | 511 uint32_t height = fFrameRect.height(); |
543 if (fGif->Image.Interlace) { | 512 if (fGif->Image.Interlace) { |
544 // In interlace mode, the rows of input are rearranged in | 513 // In interlace mode, the rows of input are rearranged in |
545 // the output image. We a helper function to help us | 514 // the output image. We a helper function to help us |
546 // rearrange the decoded rows. | 515 // rearrange the decoded rows. |
547 for (uint32_t y = 0; y < height; y++) { | 516 for (uint32_t y = 0; y < height; y++) { |
548 if (kSuccess != this->readRow()) { | 517 if (kSuccess != this->readRow()) { |
549 // Recover from error by filling remainder of image | 518 // Recover from error by filling remainder of image |
550 memset(fSrcBuffer.get(), fFillIndex, width); | 519 memset(fSrcBuffer.get(), fFillIndex, width); |
551 for (; y < height; y++) { | 520 for (; y < height; y++) { |
552 void* dstRow = SkTAddOffset<void>(dst, | 521 void* dstRow = SkTAddOffset<void>(dst, |
(...skipping 26 matching lines...) Expand all Loading... |
579 SkCodec::Result SkGifCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, | 548 SkCodec::Result SkGifCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, |
580 const SkCodec::Options& opts, SkPMColor inputColorPtr[], int* inputColor
Count) { | 549 const SkCodec::Options& opts, SkPMColor inputColorPtr[], int* inputColor
Count) { |
581 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun
t, | 550 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun
t, |
582 this->options()); | 551 this->options()); |
583 if (kSuccess != result) { | 552 if (kSuccess != result) { |
584 return result; | 553 return result; |
585 } | 554 } |
586 | 555 |
587 // Initialize the swizzler | 556 // Initialize the swizzler |
588 if (fFrameIsSubset) { | 557 if (fFrameIsSubset) { |
589 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameDims.width(), fFr
ameDims.height()); | 558 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFr
ameRect.height()); |
590 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia
lized)) { | 559 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia
lized)) { |
591 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; | 560 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; |
592 } | 561 } |
593 } else { | 562 } else { |
594 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized)
) { | 563 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized)
) { |
595 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; | 564 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; |
596 } | 565 } |
597 } | 566 } |
598 | 567 |
599 return kSuccess; | 568 return kSuccess; |
600 } | 569 } |
601 | 570 |
602 SkCodec::Result SkGifCodec::onGetScanlines(void* dst, int count, size_t rowBytes
) { | 571 SkCodec::Result SkGifCodec::onGetScanlines(void* dst, int count, size_t rowBytes
) { |
603 if (fFrameIsSubset) { | 572 if (fFrameIsSubset) { |
604 // Fill the requested rows | 573 // Fill the requested rows |
605 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 574 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
606 SkSwizzler::Fill(dst, this->dstInfo(), rowBytes, count, fFillIndex, | 575 SkSwizzler::Fill(dst, this->dstInfo(), rowBytes, count, fFillIndex, |
607 colorPtr, this->options().fZeroInitialized); | 576 colorPtr, this->options().fZeroInitialized); |
608 | 577 |
609 // Do nothing for rows before the image frame | 578 // Do nothing for rows before the image frame |
610 // FIXME: nextScanline is not virtual, so using "INHERITED" does not cha
nge | 579 int rowsBeforeFrame = SkTMax(0, fFrameRect.top() - this->INHERITED::onNe
xtScanline()); |
611 // behavior. Was the intent to call this->INHERITED::onNextScanline()? S
ame | 580 count = SkTMax(0, count - rowsBeforeFrame); |
612 // for the next call down below. | 581 dst = SkTAddOffset<void>(dst, rowBytes * rowsBeforeFrame); |
613 int rowsBeforeFrame = fFrameDims.top() - this->INHERITED::nextScanline()
; | |
614 if (rowsBeforeFrame > 0) { | |
615 count = SkTMin(0, count - rowsBeforeFrame); | |
616 dst = SkTAddOffset<void>(dst, rowBytes * rowsBeforeFrame); | |
617 } | |
618 | 582 |
619 // Do nothing for rows after the image frame | 583 // Do nothing for rows after the image frame |
620 int rowsAfterFrame = this->INHERITED::nextScanline() + count - fFrameDim
s.bottom(); | 584 int rowsAfterFrame = SkTMax(0, |
621 if (rowsAfterFrame > 0) { | 585 this->INHERITED::onNextScanline() + count - fFrameRect.bottom())
; |
622 count = SkTMin(0, count - rowsAfterFrame); | 586 count = SkTMax(0, count - rowsAfterFrame); |
623 } | |
624 | 587 |
625 // Adjust dst pointer for left offset | 588 // Adjust dst pointer for left offset |
626 int bpp = SkColorTypeBytesPerPixel(this->dstInfo().colorType()) * fFrame
Dims.left(); | 589 int offset = SkColorTypeBytesPerPixel(this->dstInfo().colorType()) * fFr
ameRect.left(); |
627 dst = SkTAddOffset<void>(dst, bpp); | 590 dst = SkTAddOffset<void>(dst, offset); |
628 } | 591 } |
629 | 592 |
630 for (int i = 0; i < count; i++) { | 593 for (int i = 0; i < count; i++) { |
631 if (kSuccess != this->readRow()) { | 594 if (kSuccess != this->readRow()) { |
632 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 595 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
633 SkSwizzler::Fill(dst, this->dstInfo(), rowBytes, count - i, fFillInd
ex, colorPtr, | 596 SkSwizzler::Fill(dst, this->dstInfo().makeWH(fFrameRect.width(), |
634 this->options().fZeroInitialized); | 597 this->dstInfo().height()), rowBytes, count - i, fFillIndex,
colorPtr, |
635 return gif_error("Could not decode line\n", SkCodec::kIncompleteInpu
t); | 598 this->options().fZeroInitialized); |
| 599 return kIncompleteInput; |
636 } | 600 } |
637 fSwizzler->swizzle(dst, fSrcBuffer.get()); | 601 fSwizzler->swizzle(dst, fSrcBuffer.get()); |
638 dst = SkTAddOffset<void>(dst, rowBytes); | 602 dst = SkTAddOffset<void>(dst, rowBytes); |
639 } | 603 } |
640 return SkCodec::kSuccess; | 604 return kSuccess; |
641 } | 605 } |
642 | 606 |
643 SkCodec::SkScanlineOrder SkGifCodec::onGetScanlineOrder() const { | 607 SkCodec::SkScanlineOrder SkGifCodec::onGetScanlineOrder() const { |
644 if (fGif->Image.Interlace) { | 608 if (fGif->Image.Interlace) { |
645 return kOutOfOrder_SkScanlineOrder; | 609 return kOutOfOrder_SkScanlineOrder; |
646 } else { | 610 } else { |
647 return kTopDown_SkScanlineOrder; | 611 return kTopDown_SkScanlineOrder; |
648 } | 612 } |
649 } | 613 } |
650 | 614 |
651 int SkGifCodec::onNextScanline() const { | 615 int SkGifCodec::onNextScanline() const { |
| 616 int nextScanline = this->INHERITED::onNextScanline(); |
652 if (fGif->Image.Interlace) { | 617 if (fGif->Image.Interlace) { |
653 return get_output_row_interlaced(this->INHERITED::onNextScanline(), this
->dstInfo().height()); | 618 if (nextScanline < fFrameRect.top() || nextScanline >= fFrameRect.bottom
()) { |
654 } else { | 619 return nextScanline; |
655 return this->INHERITED::onNextScanline(); | 620 } |
| 621 return get_output_row_interlaced(nextScanline - fFrameRect.top(), fFrame
Rect.height()); |
656 } | 622 } |
| 623 return nextScanline; |
657 } | 624 } |
658 | 625 |
OLD | NEW |