Chromium Code Reviews| 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 // We do not need to check the return value. On an incomple te |
| 349 decodeInfo.height(), bitmap.rowBytes()); | 353 // image, memory will be filled with a default value. |
| 354 codec->getScanlines(dst, height, rowBytes); | |
| 350 break; | 355 break; |
| 351 case SkCodec::kOutOfOrder_SkScanlineOrder: { | 356 case SkCodec::kOutOfOrder_SkScanlineOrder: { |
| 352 for (int y = 0; y < decodeInfo.height(); y++) { | 357 for (int y = 0; y < decodeInfo.height(); y++) { |
| 353 int dstY = codec->nextScanline(); | 358 int dstY = codec->outputScanline(y); |
| 354 void* dstPtr = bitmap.getAddr(0, dstY); | 359 void* dstPtr = bitmap.getAddr(0, dstY); |
| 355 result = codec->getScanlines(dstPtr, 1, bitmap.rowBytes( )); | 360 // We complete the loop, even if this call begins to fai l |
| 356 if (SkCodec::kSuccess != result && SkCodec::kIncompleteI nput != result) { | 361 // due to incomplete image. This ensures any uninitiali zed |
| 357 return SkStringPrintf("%s failed with error message %d", | 362 // memory will be filled with the proper value. |
| 358 fPath.c_str(), (int) result); | 363 codec->getScanlines(dstPtr, 1, bitmap.rowBytes()); |
|
msarett
2015/10/01 18:14:14
Thanks for your thorough review of how the scanlin
scroggo
2015/10/01 20:48:58
I mentioned this as a response to an older comment
msarett
2015/10/01 22:34:51
Thanks for your thoughts. I'll respond to this as
| |
| 359 } | |
| 360 } | 364 } |
| 361 break; | 365 break; |
| 362 } | 366 } |
| 363 } | 367 } |
| 364 | 368 |
| 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); | 369 canvas->drawBitmap(bitmap, 0, 0); |
| 374 break; | 370 break; |
| 375 } | 371 } |
| 376 case kScanline_Subset_Mode: { | 372 case kScanline_Subset_Mode: { |
| 377 //this mode decodes the image in divisor*divisor subsets, using a sc anline decoder | 373 //this mode decodes the image in divisor*divisor subsets, using a sc anline decoder |
| 378 const int divisor = 2; | 374 const int divisor = 2; |
| 379 const int w = decodeInfo.width(); | 375 const int w = decodeInfo.width(); |
| 380 const int h = decodeInfo.height(); | 376 const int h = decodeInfo.height(); |
| 381 if (divisor > w || divisor > h) { | 377 if (divisor > w || divisor > h) { |
| 382 return Error::Nonfatal(SkStringPrintf("Cannot decode subset: div isor %d is too big" | 378 return Error::Nonfatal(SkStringPrintf("Cannot decode subset: div isor %d is too big" |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 422 colorCou ntPtr) | 418 colorCou ntPtr) |
| 423 // TODO (msarett): Support this mode for all scanlin e orderings. | 419 // TODO (msarett): Support this mode for all scanlin e orderings. |
| 424 || SkCodec::kTopDown_SkScanlineOrder != codec->getSc anlineOrder()) { | 420 || SkCodec::kTopDown_SkScanlineOrder != codec->getSc anlineOrder()) { |
| 425 if (x == 0 && y == 0) { | 421 if (x == 0 && y == 0) { |
| 426 //first try, image may not be compatible | 422 //first try, image may not be compatible |
| 427 return Error::Nonfatal("Could not start top-down sca nline decoder"); | 423 return Error::Nonfatal("Could not start top-down sca nline decoder"); |
| 428 } else { | 424 } else { |
| 429 return "Error scanline decoder is nullptr"; | 425 return "Error scanline decoder is nullptr"; |
| 430 } | 426 } |
| 431 } | 427 } |
| 432 //skip to first line of subset | 428 // Skip to the first line of subset. We ignore the result v alue here. |
| 433 const SkCodec::Result skipResult = codec->skipScanlines(y); | 429 // If the skip value fails, this will indicate an incomplete image. |
| 434 switch (skipResult) { | 430 // This means that the call to getScanlines() will also fail , but it |
| 435 case SkCodec::kSuccess: | 431 // will fill the buffer with a default value, so we can stil l draw the |
| 436 case SkCodec::kIncompleteInput: | 432 // image. |
| 437 break; | 433 codec->skipScanlines(y); |
| 438 default: | 434 |
| 439 return SkStringPrintf("%s failed after attempting to skip %d scanlines" | |
| 440 "with error message %d", fPath.c_str(), y, ( int) skipResult); | |
| 441 } | |
| 442 //create and set size of subsetBm | 435 //create and set size of subsetBm |
| 443 SkBitmap subsetBm; | 436 SkBitmap subsetBm; |
| 444 SkIRect bounds = SkIRect::MakeWH(subsetWidth, subsetHeight); | 437 SkIRect bounds = SkIRect::MakeWH(subsetWidth, subsetHeight); |
| 445 bounds.setXYWH(0, 0, currentSubsetWidth, currentSubsetHeight ); | 438 bounds.setXYWH(0, 0, currentSubsetWidth, currentSubsetHeight ); |
| 446 SkAssertResult(largestSubsetBm.extractSubset(&subsetBm, boun ds)); | 439 SkAssertResult(largestSubsetBm.extractSubset(&subsetBm, boun ds)); |
| 447 SkAutoLockPixels autlockSubsetBm(subsetBm, true); | 440 SkAutoLockPixels autlockSubsetBm(subsetBm, true); |
| 448 const SkCodec::Result subsetResult = | 441 codec->getScanlines(buffer, currentSubsetHeight, rowBytes); |
| 449 codec->getScanlines(buffer, currentSubsetHeight, row Bytes); | 442 |
| 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(); | 443 const size_t bpp = decodeInfo.bytesPerPixel(); |
| 459 /* | |
| 460 * we copy all the lines at once becuase when calling getSca nlines for | |
| 461 * 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 | |
| 463 * 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 | |
| 465 * may be faster for other types of images. Since this is a correctness test | |
| 466 * that's okay. | |
| 467 */ | |
| 468 char* bufferRow = buffer; | 444 char* bufferRow = buffer; |
| 469 for (int subsetY = 0; subsetY < currentSubsetHeight; ++subse tY) { | 445 for (int subsetY = 0; subsetY < currentSubsetHeight; ++subse tY) { |
| 470 memcpy(subsetBm.getAddr(0, subsetY), bufferRow + x*bpp, | 446 memcpy(subsetBm.getAddr(0, subsetY), bufferRow + x*bpp, |
| 471 currentSubsetWidth*bpp); | 447 currentSubsetWidth*bpp); |
| 472 bufferRow += rowBytes; | 448 bufferRow += rowBytes; |
| 473 } | 449 } |
| 474 | 450 |
| 475 subsetBm.notifyPixelsChanged(); | 451 subsetBm.notifyPixelsChanged(); |
| 476 canvas->drawBitmap(subsetBm, SkIntToScalar(x), SkIntToScalar (y)); | 452 canvas->drawBitmap(subsetBm, SkIntToScalar(x), SkIntToScalar (y)); |
| 477 } | 453 } |
| 478 } | 454 } |
| 479 break; | 455 break; |
| 480 } | 456 } |
| 481 case kStripe_Mode: { | 457 case kStripe_Mode: { |
| 482 const int height = decodeInfo.height(); | 458 const int height = decodeInfo.height(); |
| 483 // This value is chosen arbitrarily. We exercise more cases by choo sing a value that | 459 // This value is chosen arbitrarily. We exercise more cases by choo sing a value that |
| 484 // does not align with image blocks. | 460 // does not align with image blocks. |
| 485 const int stripeHeight = 37; | 461 const int stripeHeight = 37; |
| 486 const int numStripes = (height + stripeHeight - 1) / stripeHeight; | 462 const int numStripes = (height + stripeHeight - 1) / stripeHeight; |
| 487 | 463 |
| 488 // Decode odd stripes | 464 // Decode odd stripes |
| 489 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL , colorPtr, | 465 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL , colorPtr, |
| 490 colorCountPtr) | 466 colorCountPtr) |
| 491 || SkCodec::kTopDown_SkScanlineOrder != codec->getScanlineOr der()) { | 467 || SkCodec::kTopDown_SkScanlineOrder != codec->getScanlineOr der()) { |
| 492 // This mode was designed to test the new skip scanlines API in libjpeg-turbo. | 468 // 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 | 469 // 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. | 470 // 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"); | 471 return Error::Nonfatal("Could not start top-down scanline decode r"); |
| 496 } | 472 } |
| 473 | |
| 497 for (int i = 0; i < numStripes; i += 2) { | 474 for (int i = 0; i < numStripes; i += 2) { |
| 498 // Skip a stripe | 475 // Skip a stripe |
| 499 const int linesToSkip = SkTMin(stripeHeight, height - i * stripe Height); | 476 const int linesToSkip = SkTMin(stripeHeight, height - i * stripe Height); |
| 500 SkCodec::Result result = codec->skipScanlines(linesToSkip); | 477 codec->skipScanlines(linesToSkip); |
| 501 switch (result) { | |
| 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 } | |
| 508 | 478 |
| 509 // Read a stripe | 479 // Read a stripe |
| 510 const int startY = (i + 1) * stripeHeight; | 480 const int startY = (i + 1) * stripeHeight; |
| 511 const int linesToRead = SkTMin(stripeHeight, height - startY); | 481 const int linesToRead = SkTMin(stripeHeight, height - startY); |
| 512 if (linesToRead > 0) { | 482 if (linesToRead > 0) { |
| 513 result = codec->getScanlines(bitmap.getAddr(0, startY), | 483 codec->getScanlines(bitmap.getAddr(0, startY), linesToRead, bitmap.rowBytes()); |
| 514 linesToRead, bitmap.rowBytes()); | |
| 515 switch (result) { | |
| 516 case SkCodec::kSuccess: | |
| 517 case SkCodec::kIncompleteInput: | |
| 518 break; | |
| 519 default: | |
| 520 return SkStringPrintf("Cannot get scanlines for %s." , fPath.c_str()); | |
| 521 } | |
| 522 } | 484 } |
| 523 } | 485 } |
| 524 | 486 |
| 525 // Decode even stripes | 487 // Decode even stripes |
| 526 const SkCodec::Result startResult = codec->startScanlineDecode(decod eInfo, nullptr, | 488 const SkCodec::Result startResult = codec->startScanlineDecode(decod eInfo, nullptr, |
| 527 colorPtr, colorCountPtr); | 489 colorPtr, colorCountPtr); |
| 528 if (SkCodec::kSuccess != startResult) { | 490 if (SkCodec::kSuccess != startResult) { |
| 529 return "Failed to restart scanline decoder with same parameters. "; | 491 return "Failed to restart scanline decoder with same parameters. "; |
| 530 } | 492 } |
| 531 for (int i = 0; i < numStripes; i += 2) { | 493 for (int i = 0; i < numStripes; i += 2) { |
| 532 // Read a stripe | 494 // Read a stripe |
| 533 const int startY = i * stripeHeight; | 495 const int startY = i * stripeHeight; |
| 534 const int linesToRead = SkTMin(stripeHeight, height - startY); | 496 const int linesToRead = SkTMin(stripeHeight, height - startY); |
| 535 SkCodec::Result result = codec->getScanlines(bitmap.getAddr(0, s tartY), | 497 codec->getScanlines(bitmap.getAddr(0, startY), linesToRead, bitm ap.rowBytes()); |
| 536 linesToRead, bitmap.rowBytes()); | |
| 537 switch (result) { | |
| 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 } | |
| 544 | 498 |
| 545 // Skip a stripe | 499 // Skip a stripe |
| 546 const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) * stripeHeight); | 500 const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) * stripeHeight); |
| 547 if (linesToSkip > 0) { | 501 if (linesToSkip > 0) { |
| 548 result = codec->skipScanlines(linesToSkip); | 502 codec->skipScanlines(linesToSkip); |
| 549 switch (result) { | |
| 550 case SkCodec::kSuccess: | |
| 551 case SkCodec::kIncompleteInput: | |
| 552 break; | |
| 553 default: | |
| 554 return SkStringPrintf("Cannot skip scanlines for %s. ", fPath.c_str()); | |
| 555 } | |
| 556 } | 503 } |
| 557 } | 504 } |
| 558 canvas->drawBitmap(bitmap, 0, 0); | 505 canvas->drawBitmap(bitmap, 0, 0); |
| 559 break; | 506 break; |
| 560 } | 507 } |
| 561 case kSubset_Mode: { | 508 case kSubset_Mode: { |
| 562 // Arbitrarily choose a divisor. | 509 // Arbitrarily choose a divisor. |
| 563 int divisor = 2; | 510 int divisor = 2; |
| 564 // Total width/height of the image. | 511 // Total width/height of the image. |
| 565 const int W = codec->getInfo().width(); | 512 const int W = codec->getInfo().width(); |
| (...skipping 689 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1255 skr.visit<void>(i, drawsAsSingletonPictures); | 1202 skr.visit<void>(i, drawsAsSingletonPictures); |
| 1256 } | 1203 } |
| 1257 SkAutoTUnref<SkPicture> macroPic(macroRec.endRecordingAsPicture()); | 1204 SkAutoTUnref<SkPicture> macroPic(macroRec.endRecordingAsPicture()); |
| 1258 | 1205 |
| 1259 canvas->drawPicture(macroPic); | 1206 canvas->drawPicture(macroPic); |
| 1260 return ""; | 1207 return ""; |
| 1261 }); | 1208 }); |
| 1262 } | 1209 } |
| 1263 | 1210 |
| 1264 } // namespace DM | 1211 } // namespace DM |
| OLD | NEW |