 Chromium Code Reviews
 Chromium Code Reviews Issue 1332053002:
  Fill incomplete images in SkCodec parent class  (Closed) 
  Base URL: https://skia.googlesource.com/skia.git@master
    
  
    Issue 1332053002:
  Fill incomplete images in SkCodec parent class  (Closed) 
  Base URL: https://skia.googlesource.com/skia.git@master| 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 "DMSrcSink.h" | 8 #include "DMSrcSink.h" | 
| 9 #include "SamplePipeControllers.h" | 9 #include "SamplePipeControllers.h" | 
| 10 #include "SkCodec.h" | 10 #include "SkCodec.h" | 
| (...skipping 10 matching lines...) Expand all Loading... | |
| 21 #include "SkPictureData.h" | 21 #include "SkPictureData.h" | 
| 22 #include "SkPictureRecorder.h" | 22 #include "SkPictureRecorder.h" | 
| 23 #include "SkRandom.h" | 23 #include "SkRandom.h" | 
| 24 #include "SkRecordDraw.h" | 24 #include "SkRecordDraw.h" | 
| 25 #include "SkRecorder.h" | 25 #include "SkRecorder.h" | 
| 26 #include "SkSVGCanvas.h" | 26 #include "SkSVGCanvas.h" | 
| 27 #include "SkScaledCodec.h" | 27 #include "SkScaledCodec.h" | 
| 28 #include "SkStream.h" | 28 #include "SkStream.h" | 
| 29 #include "SkTLogic.h" | 29 #include "SkTLogic.h" | 
| 30 #include "SkXMLWriter.h" | 30 #include "SkXMLWriter.h" | 
| 31 #include "SkScaledCodec.h" | |
| 32 #include "SkSwizzler.h" | |
| 31 | 33 | 
| 32 DEFINE_bool(multiPage, false, "For document-type backends, render the source" | 34 DEFINE_bool(multiPage, false, "For document-type backends, render the source" | 
| 33 " into multiple pages"); | 35 " into multiple pages"); | 
| 34 | 36 | 
| 35 static bool lazy_decode_bitmap(const void* src, size_t size, SkBitmap* dst) { | 37 static bool lazy_decode_bitmap(const void* src, size_t size, SkBitmap* dst) { | 
| 36 SkAutoTUnref<SkData> encoded(SkData::NewWithCopy(src, size)); | 38 SkAutoTUnref<SkData> encoded(SkData::NewWithCopy(src, size)); | 
| 37 return encoded && SkDEPRECATED_InstallDiscardablePixelRef(encoded, dst); | 39 return encoded && SkDEPRECATED_InstallDiscardablePixelRef(encoded, dst); | 
| 38 } | 40 } | 
| 39 | 41 | 
| 40 namespace DM { | 42 namespace DM { | 
| (...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 333 } | 335 } | 
| 334 canvas->drawBitmap(bitmap, 0, 0); | 336 canvas->drawBitmap(bitmap, 0, 0); | 
| 335 break; | 337 break; | 
| 336 } | 338 } | 
| 337 case kScanline_Mode: { | 339 case kScanline_Mode: { | 
| 338 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL , colorPtr, | 340 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL , colorPtr, | 
| 339 colorCountPtr)) { | 341 colorCountPtr)) { | 
| 340 return Error::Nonfatal("Could not start scanline decoder"); | 342 return Error::Nonfatal("Could not start scanline decoder"); | 
| 341 } | 343 } | 
| 342 | 344 | 
| 343 SkCodec::Result result = SkCodec::kUnimplemented; | 345 void* dst = bitmap.getAddr(0, 0); | 
| 346 size_t rowBytes = bitmap.rowBytes(); | |
| 347 uint32_t height = decodeInfo.height(); | |
| 344 switch (codec->getScanlineOrder()) { | 348 switch (codec->getScanlineOrder()) { | 
| 345 case SkCodec::kTopDown_SkScanlineOrder: | 349 case SkCodec::kTopDown_SkScanlineOrder: | 
| 346 case SkCodec::kBottomUp_SkScanlineOrder: | 350 case SkCodec::kBottomUp_SkScanlineOrder: | 
| 347 case SkCodec::kNone_SkScanlineOrder: | 351 case SkCodec::kNone_SkScanlineOrder: | 
| 348 result = codec->getScanlines(bitmap.getAddr(0, 0), | 352 codec->getScanlines(dst, height, rowBytes); | 
| 
msarett
2015/10/01 12:44:52
getScanlines() now fills when it cannot get all of
 | |
| 349 decodeInfo.height(), bitmap.rowBytes()); | |
| 350 break; | 353 break; | 
| 351 case SkCodec::kOutOfOrder_SkScanlineOrder: { | 354 case SkCodec::kOutOfOrder_SkScanlineOrder: { | 
| 352 for (int y = 0; y < decodeInfo.height(); y++) { | 355 for (int y = 0; y < decodeInfo.height(); y++) { | 
| 353 int dstY = codec->nextScanline(); | 356 int dstY = codec->nextScanline(y); | 
| 354 void* dstPtr = bitmap.getAddr(0, dstY); | 357 void* dstPtr = bitmap.getAddr(0, dstY); | 
| 355 result = codec->getScanlines(dstPtr, 1, bitmap.rowBytes( )); | 358 codec->getScanlines(dstPtr, 1, bitmap.rowBytes()); | 
| 
scroggo
2015/10/01 14:48:31
Don't we want to break out of the loop if 0 is ret
 
msarett
2015/10/01 18:14:13
We could do that.  But then we need to iterate ove
 
scroggo
2015/10/01 20:48:57
Oh yeah, now I remember talking about this, but I
 
msarett
2015/10/01 22:34:51
Acknowledged.
 | |
| 356 if (SkCodec::kSuccess != result && SkCodec::kIncompleteI nput != result) { | |
| 357 return SkStringPrintf("%s failed with error message %d", | |
| 358 fPath.c_str(), (int) result); | |
| 359 } | |
| 360 } | 359 } | 
| 361 break; | 360 break; | 
| 362 } | 361 } | 
| 363 } | 362 } | 
| 364 | 363 | 
| 365 switch (result) { | |
| 366 case SkCodec::kSuccess: | |
| 367 case SkCodec::kIncompleteInput: | |
| 368 break; | |
| 369 default: | |
| 370 return SkStringPrintf("%s failed with error message %d", | |
| 371 fPath.c_str(), (int) result); | |
| 372 } | |
| 373 canvas->drawBitmap(bitmap, 0, 0); | 364 canvas->drawBitmap(bitmap, 0, 0); | 
| 374 break; | 365 break; | 
| 375 } | 366 } | 
| 376 case kScanline_Subset_Mode: { | 367 case kScanline_Subset_Mode: { | 
| 377 //this mode decodes the image in divisor*divisor subsets, using a sc anline decoder | 368 //this mode decodes the image in divisor*divisor subsets, using a sc anline decoder | 
| 378 const int divisor = 2; | 369 const int divisor = 2; | 
| 379 const int w = decodeInfo.width(); | 370 const int w = decodeInfo.width(); | 
| 380 const int h = decodeInfo.height(); | 371 const int h = decodeInfo.height(); | 
| 381 if (divisor > w || divisor > h) { | 372 if (divisor > w || divisor > h) { | 
| 382 return Error::Nonfatal(SkStringPrintf("Cannot decode subset: div isor %d is too big" | 373 return Error::Nonfatal(SkStringPrintf("Cannot decode subset: div isor %d is too big" | 
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 423 // TODO (msarett): Support this mode for all scanlin e orderings. | 414 // TODO (msarett): Support this mode for all scanlin e orderings. | 
| 424 || SkCodec::kTopDown_SkScanlineOrder != codec->getSc anlineOrder()) { | 415 || SkCodec::kTopDown_SkScanlineOrder != codec->getSc anlineOrder()) { | 
| 425 if (x == 0 && y == 0) { | 416 if (x == 0 && y == 0) { | 
| 426 //first try, image may not be compatible | 417 //first try, image may not be compatible | 
| 427 return Error::Nonfatal("Could not start top-down sca nline decoder"); | 418 return Error::Nonfatal("Could not start top-down sca nline decoder"); | 
| 428 } else { | 419 } else { | 
| 429 return "Error scanline decoder is nullptr"; | 420 return "Error scanline decoder is nullptr"; | 
| 430 } | 421 } | 
| 431 } | 422 } | 
| 432 //skip to first line of subset | 423 //skip to first line of subset | 
| 433 const SkCodec::Result skipResult = codec->skipScanlines(y); | 424 if (!codec->skipScanlines(y)) { | 
| 434 switch (skipResult) { | 425 return Error::Nonfatal("Image is incomplete, could not g et scanlines"); | 
| 
scroggo
2015/10/01 14:48:31
Since we've returned an error, we will not be able
 
msarett
2015/10/01 18:14:13
Yeah the way the test is written now, we will only
 | |
| 435 case SkCodec::kSuccess: | |
| 436 case SkCodec::kIncompleteInput: | |
| 437 break; | |
| 438 default: | |
| 439 return SkStringPrintf("%s failed after attempting to skip %d scanlines" | |
| 440 "with error message %d", fPath.c_str(), y, ( int) skipResult); | |
| 441 } | 426 } | 
| 427 | |
| 442 //create and set size of subsetBm | 428 //create and set size of subsetBm | 
| 443 SkBitmap subsetBm; | 429 SkBitmap subsetBm; | 
| 444 SkIRect bounds = SkIRect::MakeWH(subsetWidth, subsetHeight); | 430 SkIRect bounds = SkIRect::MakeWH(subsetWidth, subsetHeight); | 
| 445 bounds.setXYWH(0, 0, currentSubsetWidth, currentSubsetHeight ); | 431 bounds.setXYWH(0, 0, currentSubsetWidth, currentSubsetHeight ); | 
| 446 SkAssertResult(largestSubsetBm.extractSubset(&subsetBm, boun ds)); | 432 SkAssertResult(largestSubsetBm.extractSubset(&subsetBm, boun ds)); | 
| 447 SkAutoLockPixels autlockSubsetBm(subsetBm, true); | 433 SkAutoLockPixels autlockSubsetBm(subsetBm, true); | 
| 448 const SkCodec::Result subsetResult = | 434 codec->getScanlines(buffer, currentSubsetHeight, rowBytes); | 
| 
scroggo
2015/10/01 14:48:31
Note that you do something different if skipScanli
 
msarett
2015/10/01 18:14:13
Acknowledged.
 | |
| 449 codec->getScanlines(buffer, currentSubsetHeight, row Bytes); | 435 | 
| 450 switch (subsetResult) { | |
| 451 case SkCodec::kSuccess: | |
| 452 case SkCodec::kIncompleteInput: | |
| 453 break; | |
| 454 default: | |
| 455 return SkStringPrintf("%s failed with error message %d", | |
| 456 fPath.c_str(), (int) subsetResult); | |
| 457 } | |
| 458 const size_t bpp = decodeInfo.bytesPerPixel(); | 436 const size_t bpp = decodeInfo.bytesPerPixel(); | 
| 459 /* | 437 /* | 
| 460 * we copy all the lines at once becuase when calling getSca nlines for | 438 * we copy all the lines at once becuase when calling getSca nlines for | 
| 
scroggo
2015/10/01 14:48:31
This isn't due to your CL, but it seems like this
 
msarett
2015/10/01 18:14:13
Yeah I'm a bit confused by this comment.  Removing
 | |
| 461 * interlaced pngs the entire image must be read regardless of the number | 439 * interlaced pngs the entire image must be read regardless of the number | 
| 462 * of lines requested. Reading an interlaced png in a loop, line-by-line, would | 440 * of lines requested. Reading an interlaced png in a loop, line-by-line, would | 
| 463 * decode the entire image height times, which is very slow | 441 * decode the entire image height times, which is very slow | 
| 464 * it is aknowledged that copying each line as you read it i n a loop | 442 * it is aknowledged that copying each line as you read it i n a loop | 
| 465 * may be faster for other types of images. Since this is a correctness test | 443 * may be faster for other types of images. Since this is a correctness test | 
| 466 * that's okay. | 444 * that's okay. | 
| 467 */ | 445 */ | 
| 468 char* bufferRow = buffer; | 446 char* bufferRow = buffer; | 
| 469 for (int subsetY = 0; subsetY < currentSubsetHeight; ++subse tY) { | 447 for (int subsetY = 0; subsetY < currentSubsetHeight; ++subse tY) { | 
| 470 memcpy(subsetBm.getAddr(0, subsetY), bufferRow + x*bpp, | 448 memcpy(subsetBm.getAddr(0, subsetY), bufferRow + x*bpp, | 
| (...skipping 16 matching lines...) Expand all Loading... | |
| 487 | 465 | 
| 488 // Decode odd stripes | 466 // Decode odd stripes | 
| 489 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL , colorPtr, | 467 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL , colorPtr, | 
| 490 colorCountPtr) | 468 colorCountPtr) | 
| 491 || SkCodec::kTopDown_SkScanlineOrder != codec->getScanlineOr der()) { | 469 || SkCodec::kTopDown_SkScanlineOrder != codec->getScanlineOr der()) { | 
| 492 // This mode was designed to test the new skip scanlines API in libjpeg-turbo. | 470 // This mode was designed to test the new skip scanlines API in libjpeg-turbo. | 
| 493 // Jpegs have kTopDown_SkScanlineOrder, and at this time, it is not interesting | 471 // Jpegs have kTopDown_SkScanlineOrder, and at this time, it is not interesting | 
| 494 // to run this test for image types that do not have this scanli ne ordering. | 472 // to run this test for image types that do not have this scanli ne ordering. | 
| 495 return Error::Nonfatal("Could not start top-down scanline decode r"); | 473 return Error::Nonfatal("Could not start top-down scanline decode r"); | 
| 496 } | 474 } | 
| 475 | |
| 497 for (int i = 0; i < numStripes; i += 2) { | 476 for (int i = 0; i < numStripes; i += 2) { | 
| 498 // Skip a stripe | 477 // Skip a stripe | 
| 499 const int linesToSkip = SkTMin(stripeHeight, height - i * stripe Height); | 478 const int linesToSkip = SkTMin(stripeHeight, height - i * stripe Height); | 
| 500 SkCodec::Result result = codec->skipScanlines(linesToSkip); | 479 if (!codec->skipScanlines(linesToSkip)) { | 
| 501 switch (result) { | 480 return Error::Nonfatal("Image is incomplete, could not get s canlines"); | 
| 
scroggo
2015/10/01 14:48:31
Not only was the image incomplete, but it was so i
 
msarett
2015/10/01 18:14:13
This could be improved as well.
 | |
| 502 case SkCodec::kSuccess: | |
| 503 case SkCodec::kIncompleteInput: | |
| 504 break; | |
| 505 default: | |
| 506 return SkStringPrintf("Cannot skip scanlines for %s.", f Path.c_str()); | |
| 507 } | 481 } | 
| 508 | 482 | 
| 509 // Read a stripe | 483 // Read a stripe | 
| 510 const int startY = (i + 1) * stripeHeight; | 484 const int startY = (i + 1) * stripeHeight; | 
| 511 const int linesToRead = SkTMin(stripeHeight, height - startY); | 485 const int linesToRead = SkTMin(stripeHeight, height - startY); | 
| 512 if (linesToRead > 0) { | 486 if (linesToRead > 0) { | 
| 513 result = codec->getScanlines(bitmap.getAddr(0, startY), | 487 if ((int) codec->getScanlines(bitmap.getAddr(0, startY), lin esToRead, | 
| 514 linesToRead, bitmap.rowBytes()); | 488 bitmap.rowBytes()) < linesToRead) { | 
| 515 switch (result) { | 489 return Error::Nonfatal("Image is incomplete, could not g et scanlines"); | 
| 516 case SkCodec::kSuccess: | |
| 517 case SkCodec::kIncompleteInput: | |
| 518 break; | |
| 519 default: | |
| 520 return SkStringPrintf("Cannot get scanlines for %s." , fPath.c_str()); | |
| 521 } | 490 } | 
| 522 } | 491 } | 
| 523 } | 492 } | 
| 524 | 493 | 
| 525 // Decode even stripes | 494 // Decode even stripes | 
| 526 const SkCodec::Result startResult = codec->startScanlineDecode(decod eInfo, nullptr, | 495 const SkCodec::Result startResult = codec->startScanlineDecode(decod eInfo, nullptr, | 
| 527 colorPtr, colorCountPtr); | 496 colorPtr, colorCountPtr); | 
| 528 if (SkCodec::kSuccess != startResult) { | 497 if (SkCodec::kSuccess != startResult) { | 
| 529 return "Failed to restart scanline decoder with same parameters. "; | 498 return "Failed to restart scanline decoder with same parameters. "; | 
| 530 } | 499 } | 
| 531 for (int i = 0; i < numStripes; i += 2) { | 500 for (int i = 0; i < numStripes; i += 2) { | 
| 532 // Read a stripe | 501 // Read a stripe | 
| 533 const int startY = i * stripeHeight; | 502 const int startY = i * stripeHeight; | 
| 534 const int linesToRead = SkTMin(stripeHeight, height - startY); | 503 const int linesToRead = SkTMin(stripeHeight, height - startY); | 
| 535 SkCodec::Result result = codec->getScanlines(bitmap.getAddr(0, s tartY), | 504 if ((int) codec->getScanlines(bitmap.getAddr(0, startY), linesTo Read, | 
| 536 linesToRead, bitmap.rowBytes()); | 505 bitmap.rowBytes()) < linesToRead) { | 
| 537 switch (result) { | 506 return Error::Nonfatal("Image is incomplete, could not get s canlines"); | 
| 538 case SkCodec::kSuccess: | |
| 539 case SkCodec::kIncompleteInput: | |
| 540 break; | |
| 541 default: | |
| 542 return SkStringPrintf("Cannot get scanlines for %s.", fP ath.c_str()); | |
| 543 } | 507 } | 
| 544 | 508 | 
| 545 // Skip a stripe | 509 // Skip a stripe | 
| 546 const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) * stripeHeight); | 510 const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) * stripeHeight); | 
| 547 if (linesToSkip > 0) { | 511 if (linesToSkip > 0) { | 
| 548 result = codec->skipScanlines(linesToSkip); | 512 if (!codec->skipScanlines(linesToSkip)) { | 
| 549 switch (result) { | 513 return Error::Nonfatal("Image is incomplete, could not g et scanlines"); | 
| 550 case SkCodec::kSuccess: | |
| 551 case SkCodec::kIncompleteInput: | |
| 552 break; | |
| 553 default: | |
| 554 return SkStringPrintf("Cannot skip scanlines for %s. ", fPath.c_str()); | |
| 555 } | 514 } | 
| 556 } | 515 } | 
| 557 } | 516 } | 
| 558 canvas->drawBitmap(bitmap, 0, 0); | 517 canvas->drawBitmap(bitmap, 0, 0); | 
| 559 break; | 518 break; | 
| 560 } | 519 } | 
| 561 case kSubset_Mode: { | 520 case kSubset_Mode: { | 
| 562 // Arbitrarily choose a divisor. | 521 // Arbitrarily choose a divisor. | 
| 563 int divisor = 2; | 522 int divisor = 2; | 
| 564 // Total width/height of the image. | 523 // Total width/height of the image. | 
| (...skipping 690 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1255 skr.visit<void>(i, drawsAsSingletonPictures); | 1214 skr.visit<void>(i, drawsAsSingletonPictures); | 
| 1256 } | 1215 } | 
| 1257 SkAutoTUnref<SkPicture> macroPic(macroRec.endRecordingAsPicture()); | 1216 SkAutoTUnref<SkPicture> macroPic(macroRec.endRecordingAsPicture()); | 
| 1258 | 1217 | 
| 1259 canvas->drawPicture(macroPic); | 1218 canvas->drawPicture(macroPic); | 
| 1260 return ""; | 1219 return ""; | 
| 1261 }); | 1220 }); | 
| 1262 } | 1221 } | 
| 1263 | 1222 | 
| 1264 } // namespace DM | 1223 } // namespace DM | 
| OLD | NEW |