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

Side by Side Diff: src/codec/SkCodec_libgif.cpp

Issue 1386973002: Fix SkGifCodec to handle gifs where frameSize != imageSize (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 5 years, 2 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
« no previous file with comments | « src/codec/SkCodec_libgif.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/codec/SkCodec_libgif.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698